def test_project_mo_nr2nr(self): nao = mol.nao_nr() c = numpy.random.random((nao, nao)) c1 = addons.project_mo_nr2nr(mol, c, mol) self.assertAlmostEqual(abs(c - c1).max(), 0, 12) numpy.random.seed(15) nao = mol.nao_nr() mo1 = numpy.random.random((nao, nao)) mo2 = addons.project_mo_nr2nr(mol, [mo1, mo1], mol_dz) self.assertAlmostEqual(abs(mo2[0]).sum(), 83.436359425591888, 11) self.assertAlmostEqual(abs(mo2[1]).sum(), 83.436359425591888, 11)
def test_project_mo_nr2nr(self): nao = mol.nao_nr() c = numpy.random.random((nao,nao)) c1 = addons.project_mo_nr2nr(mol, c, mol) self.assertAlmostEqual(abs(c-c1).max(), 0, 12) numpy.random.seed(15) nao = mol.nao_nr() mo1 = numpy.random.random((nao,nao)) mo2 = addons.project_mo_nr2nr(mol, [mo1,mo1], mol_dz) self.assertAlmostEqual(abs(mo2[0]).sum(), 83.436359425591888, 11) self.assertAlmostEqual(abs(mo2[1]).sum(), 83.436359425591888, 11)
def init_guess_by_minao(mol): '''Generate initial guess density matrix based on ANO basis, then project the density matrix to the basis set defined by ``mol`` Returns: Density matrix, 2D ndarray Examples: >>> from pyscf import gto, scf >>> mol = gto.M(atom='H 0 0 0; H 0 0 1.1') >>> scf.hf.init_guess_by_minao(mol) array([[ 0.94758917, 0.09227308], [ 0.09227308, 0.94758917]]) ''' from pyscf.scf import atom_hf from pyscf.scf import addons def minao_basis(symb): basis_add = pyscf.gto.basis.load('ano', symb) occ = [] basis_new = [] for l in range(4): ndocc, nfrac = atom_hf.frac_occ(symb, l) if ndocc > 0: occ.extend([2]*ndocc*(2*l+1)) if nfrac > 1e-15: occ.extend([nfrac]*(2*l+1)) ndocc += 1 if ndocc > 0: basis_new.append([l] + [b[:ndocc+1] for b in basis_add[l][1:]]) return occ, basis_new atmlst = set([pyscf.gto.mole._rm_digit(pyscf.gto.mole._symbol(k)) for k in mol._basis.keys()]) basis = {} occdic = {} for symb in atmlst: if symb != 'GHOST': occ_add, basis_add = minao_basis(symb) occdic[symb] = occ_add basis[symb] = basis_add occ = [] new_atom = [] for ia in range(mol.natm): symb = mol.atom_pure_symbol(ia) if symb != 'GHOST': occ.append(occdic[symb]) new_atom.append(mol._atom[ia]) occ = numpy.hstack(occ) pmol = pyscf.gto.Mole() pmol._atm, pmol._bas, pmol._env = pmol.make_env(new_atom, basis, []) c = addons.project_mo_nr2nr(pmol, 1, mol) dm = numpy.dot(c*occ, c.T) # normalize eletron number # s = mol.intor_symmetric('cint1e_ovlp_sph') # dm *= mol.nelectron / (dm*s).sum() return dm
def init_guess_by_atom(mol): '''Generate initial guess density matrix from superposition of atomic HF density matrix. The atomic HF is occupancy averaged RHF Returns: Density matrix, 2D ndarray ''' import copy from pyscf.scf import atom_hf from pyscf.scf import addons atm_scf = atom_hf.get_atm_nrhf(mol) mo = [] mo_occ = [] for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb != 'GHOST': if symb in atm_scf: e_hf, e, c, occ = atm_scf[symb] else: symb = mol.atom_pure_symbol(ia) e_hf, e, c, occ = atm_scf[symb] mo.append(c) mo_occ.append(occ) mo = scipy.linalg.block_diag(*mo) mo_occ = numpy.hstack(mo_occ) pmol = copy.copy(mol) pmol.cart = False c = addons.project_mo_nr2nr(pmol, mo, mol) dm = numpy.dot(c * mo_occ, c.T) for k, v in atm_scf.items(): logger.debug1(mol, 'Atom %s, E = %.12g', k, v[0]) return dm
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None): mol = mf.mol occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) if fock_ao is None: if h1e is None: h1e = mf.get_hcore() dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = h1e + mf.get_veff(mol, dm0) fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) g = fock[viridx[:, None], occidx] * 2 foo = fock[occidx[:, None], occidx] fvv = fock[viridx[:, None], viridx] h_diag = (fvv.diagonal().reshape(-1, 1) - foo.diagonal()) * 2 # To project Hessians from another basis if different basis sets are used # in newton solver and underlying mean-filed solver. if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol): mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol) if hasattr(mf, 'xc') and hasattr(mf, '_numint'): if mf.grids.coords is None: mf.grids.build() hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin > 0) + 1) rho0, vxc, fxc = mf._numint.cache_xc_kernel(mol, mf.grids, mf.xc, mo_coeff, mo_occ, 0) dm0 = None #mf.make_rdm1(mo_coeff, mo_occ) else: hyb = None def h_op(x): x = x.reshape(nvir, nocc) x2 = numpy.einsum('sp,sq->pq', fvv, x) * 2 x2 -= numpy.einsum('sp,rp->rs', foo, x) * 2 d1 = reduce(numpy.dot, (mo_coeff[:, viridx], x, mo_coeff[:, occidx].T)) dm1 = d1 + d1.T if hyb is None: vj, vk = mf.get_jk(mol, dm1) v1 = vj - vk * .5 else: v1 = mf._numint.nr_rks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, 1, rho0, vxc, fxc) if abs(hyb) < 1e-10: v1 += mf.get_j(mol, dm1) else: vj, vk = mf.get_jk(mol, dm1) v1 += vj - vk * (hyb * .5) x2 += reduce(numpy.dot, (mo_coeff[:, viridx].T, v1, mo_coeff[:, occidx])) * 4 return x2.reshape(-1) return g.reshape(-1), h_op, h_diag.reshape(-1)
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None): mol = mf.mol occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) if fock_ao is None: if h1e is None: h1e = mf.get_hcore() dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = h1e + mf.get_veff(mol, dm0) fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) g = fock[viridx[:,None],occidx] * 2 foo = fock[occidx[:,None],occidx] fvv = fock[viridx[:,None],viridx] h_diag = (fvv.diagonal().reshape(-1,1)-foo.diagonal()) * 2 # To project Hessians from another basis if different basis sets are used # in newton solver and underlying mean-filed solver. if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol): mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol) if hasattr(mf, 'xc') and hasattr(mf, '_numint'): if mf.grids.coords is None: mf.grids.build() hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin>0)+1) rho0, vxc, fxc = mf._numint.cache_xc_kernel(mol, mf.grids, mf.xc, mo_coeff, mo_occ, 0) dm0 = None #mf.make_rdm1(mo_coeff, mo_occ) else: hyb = None def h_op(x): x = x.reshape(nvir,nocc) x2 = numpy.einsum('sp,sq->pq', fvv, x) * 2 x2-= numpy.einsum('sp,rp->rs', foo, x) * 2 d1 = reduce(numpy.dot, (mo_coeff[:,viridx], x, mo_coeff[:,occidx].T)) dm1 = d1 + d1.T if hyb is None: v1 = mf.get_veff(mol, dm1) else: v1 = mf._numint.nr_rks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, 1, rho0, vxc, fxc) if abs(hyb) < 1e-10: v1 += mf.get_j(mol, dm1) else: vj, vk = mf.get_jk(mol, dm1) v1 += vj - vk * hyb * .5 x2 += reduce(numpy.dot, (mo_coeff[:,viridx].T, v1, mo_coeff[:,occidx])) * 4 return x2.reshape(-1) return g.reshape(-1), h_op, h_diag.reshape(-1)
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None, with_symmetry=True): mol = mf.mol occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbo = mo_coeff[:,occidx] orbv = mo_coeff[:,viridx] if with_symmetry and mol.symmetry: orbsym = hf_symm.get_orbsym(mol, mo_coeff) sym_forbid = orbsym[viridx].reshape(-1,1) != orbsym[occidx] if fock_ao is None: if h1e is None: h1e = mf.get_hcore() dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = h1e + mf.get_veff(mol, dm0) fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) g = fock[viridx[:,None],occidx] * 2 foo = fock[occidx[:,None],occidx] fvv = fock[viridx[:,None],viridx] h_diag = (fvv.diagonal().reshape(-1,1)-foo.diagonal()) * 2 if with_symmetry and mol.symmetry: g[sym_forbid] = 0 h_diag[sym_forbid] = 0 # To project Hessians from another basis if different basis sets are used # in newton solver and underlying mean-filed solver. if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol): mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol) vind = _gen_rhf_response(mf, mo_coeff, mo_occ, singlet=None, hermi=1) def h_op(x): x = x.reshape(nvir,nocc) if with_symmetry and mol.symmetry: x = x.copy() x[sym_forbid] = 0 x2 = numpy.einsum('ps,sq->pq', fvv, x) #x2-= .5*numpy.einsum('ps,rp->rs', foo, x) #x2-= .5*numpy.einsum('sp,rp->rs', foo, x) x2-= numpy.einsum('ps,rp->rs', foo, x) # *2 for double occupancy d1 = reduce(numpy.dot, (orbv, x*2, orbo.T.conj())) dm1 = d1 + d1.T.conj() v1 = vind(dm1) x2 += reduce(numpy.dot, (orbv.T.conj(), v1, orbo)) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2.reshape(-1) * 2 return g.reshape(-1), h_op, h_diag.reshape(-1)
def test_project_dm_nr2nr(self): nao = mol.nao_nr() dm = numpy.random.random((nao, nao)) dm = dm + dm.T x1 = addons.project_dm_nr2nr(mol, dm, mol) self.assertAlmostEqual(abs(dm - x1).max(), 0, 12) numpy.random.seed(15) mo = numpy.random.random((nao, 10)) mo1 = addons.project_mo_nr2nr(mol, mo, mol_dz) dm = numpy.dot(mo, mo.T) dmref = numpy.dot(mo1, mo1.T) dm1 = addons.project_dm_nr2nr(mol, [dm, dm], mol_dz) self.assertAlmostEqual(abs(dmref - dm1[0]).max(), 0, 11) self.assertAlmostEqual(abs(dmref - dm1[1]).max(), 0, 11) self.assertAlmostEqual(lib.finger(dm1[0]), 73.603267455214876, 11)
def test_project_dm_nr2nr(self): nao = mol.nao_nr() dm = numpy.random.random((nao,nao)) dm = dm + dm.T x1 = addons.project_dm_nr2nr(mol, dm, mol) self.assertAlmostEqual(abs(dm-x1).max(), 0, 12) numpy.random.seed(15) mo = numpy.random.random((nao,10)) mo1 = addons.project_mo_nr2nr(mol, mo, mol_dz) dm = numpy.dot(mo, mo.T) dmref = numpy.dot(mo1, mo1.T) dm1 = addons.project_dm_nr2nr(mol, [dm,dm], mol_dz) self.assertAlmostEqual(abs(dmref-dm1[0]).max(), 0, 11) self.assertAlmostEqual(abs(dmref-dm1[1]).max(), 0, 11) self.assertAlmostEqual(lib.finger(dm1[0]), 73.603267455214876, 11)
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None): mol = mf.mol occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) if fock_ao is None: if h1e is None: h1e = mf.get_hcore() dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = h1e + mf.get_veff(mol, dm0) focka = reduce(numpy.dot, (mo_coeff[0].T, fock_ao[0], mo_coeff[0])) fockb = reduce(numpy.dot, (mo_coeff[1].T, fock_ao[1], mo_coeff[1])) g = numpy.hstack((focka[viridxa[:, None], occidxa].reshape(-1), fockb[viridxb[:, None], occidxb].reshape(-1))) h_diaga = (focka[viridxa, viridxa].reshape(-1, 1) - focka[occidxa, occidxa]) h_diagb = (fockb[viridxb, viridxb].reshape(-1, 1) - fockb[occidxb, occidxb]) h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1))) if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol): mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol), addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol)) if hasattr(mf, 'xc') and hasattr(mf, '_numint'): if mf.grids.coords is None: mf.grids.build() hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin > 0) + 1) rho0, vxc, fxc = mf._numint.cache_xc_kernel(mol, mf.grids, mf.xc, mo_coeff, mo_occ, 1) #dm0 =(numpy.dot(mo_coeff[0]*mo_occ[0], mo_coeff[0].T), # numpy.dot(mo_coeff[1]*mo_occ[1], mo_coeff[1].T)) dm0 = None else: hyb = None def h_op(x): x1a = x[:nvira * nocca].reshape(nvira, nocca) x1b = x[nvira * nocca:].reshape(nvirb, noccb) x2a = numpy.einsum('rp,rq->pq', focka[viridxa[:, None], viridxa], x1a) x2a -= numpy.einsum('sq,ps->pq', focka[occidxa[:, None], occidxa], x1a) x2b = numpy.einsum('rp,rq->pq', fockb[viridxb[:, None], viridxb], x1b) x2b -= numpy.einsum('sq,ps->pq', fockb[occidxb[:, None], occidxb], x1b) d1a = reduce(numpy.dot, (mo_coeff[0][:, viridxa], x1a, mo_coeff[0][:, occidxa].T)) d1b = reduce(numpy.dot, (mo_coeff[1][:, viridxb], x1b, mo_coeff[1][:, occidxb].T)) dm1 = numpy.array((d1a + d1a.T, d1b + d1b.T)) if hyb is None: vj, vk = mf.get_jk(mol, dm1) v1 = vj[0] + vj[1] - vk else: v1 = mf._numint.nr_uks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, 1, rho0, vxc, fxc) if abs(hyb) < 1e-10: vj = mf.get_j(mol, dm1) v1 += vj[0] + vj[1] else: vj, vk = mf.get_jk(mol, dm1) v1 += vj[0] + vj[1] - vk * hyb x2a += reduce( numpy.dot, (mo_coeff[0][:, viridxa].T, v1[0], mo_coeff[0][:, occidxa])) x2b += reduce( numpy.dot, (mo_coeff[1][:, viridxb].T, v1[1], mo_coeff[1][:, occidxb])) return numpy.hstack((x2a.ravel(), x2b.ravel())) return g, h_op, h_diag
def fproj(mo): if project: return addons.project_mo_nr2nr(chk_mol, mo, mol) else: return mo
def init_guess_by_minao(mol): '''Generate initial guess density matrix based on ANO basis, then project the density matrix to the basis set defined by ``mol`` Returns: Density matrix, 2D ndarray Examples: >>> from pyscf import gto, scf >>> mol = gto.M(atom='H 0 0 0; H 0 0 1.1') >>> scf.hf.init_guess_by_minao(mol) array([[ 0.94758917, 0.09227308], [ 0.09227308, 0.94758917]]) ''' from pyscf.scf import atom_hf from pyscf.scf import addons def minao_basis(symb, nelec_ecp): basis_add = pyscf.gto.basis.load('ano', symb) occ = [] basis_new = [] # coreshl defines the core shells to be removed in the initial guess coreshl = pyscf.gto.ecp.core_configuration(nelec_ecp) #coreshl = (0,0,0,0) # it keeps all core electrons in the initial guess for l in range(4): ndocc, nfrac = atom_hf.frac_occ(symb, l) if coreshl[l] > 0: occ.extend([0]*coreshl[l]*(2*l+1)) if ndocc > coreshl[l]: occ.extend([2]*(ndocc-coreshl[l])*(2*l+1)) if nfrac > 1e-15: occ.extend([nfrac]*(2*l+1)) ndocc += 1 if ndocc > 0: basis_new.append([l] + [b[:ndocc+1] for b in basis_add[l][1:]]) return occ, basis_new atmlst = set([mol.atom_symbol(ia) for ia in range(mol.natm)]) nelec_ecp_dic = {} for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb not in nelec_ecp_dic: nelec_ecp_dic[symb] = mol.atom_nelec_core(ia) basis = {} occdic = {} for symb in atmlst: if symb != 'GHOST': nelec_ecp = nelec_ecp_dic[symb] stdsymb = pyscf.gto.mole._std_symbol(symb) occ_add, basis_add = minao_basis(stdsymb, nelec_ecp) occdic[symb] = occ_add basis[symb] = basis_add occ = [] new_atom = [] for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb != 'GHOST': occ.append(occdic[symb]) new_atom.append(mol._atom[ia]) occ = numpy.hstack(occ) pmol = pyscf.gto.Mole() pmol._atm, pmol._bas, pmol._env = pmol.make_env(new_atom, basis, []) c = addons.project_mo_nr2nr(pmol, 1, mol) dm = numpy.dot(c*occ, c.T) # normalize eletron number # s = mol.intor_symmetric('cint1e_ovlp_sph') # dm *= mol.nelectron / (dm*s).sum() return dm
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None, with_symmetry=True): mo_coeff0 = mo_coeff mol = mf.mol if getattr(mf, '_scf', None) and mf._scf.mol != mol: #TODO: construct vind with dual-basis treatment, (see also JCP, 118, 9497) # To project Hessians from another basis if different basis sets are used # in newton solver and underlying mean-filed solver. mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol) occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbo = mo_coeff[:,occidx] orbv = mo_coeff[:,viridx] if with_symmetry and mol.symmetry: orbsym = hf_symm.get_orbsym(mol, mo_coeff) sym_forbid = orbsym[viridx,None] != orbsym[occidx] if fock_ao is None: # dm0 is the density matrix in projected basis. Computing fock in # projected basis. dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = mf.get_fock(h1e, dm=dm0) fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff)) else: # If fock is given, it corresponds to main basis. It needs to be # diagonalized with the mo_coeff of the main basis. fock = reduce(numpy.dot, (mo_coeff0.conj().T, fock_ao, mo_coeff0)) g = fock[viridx[:,None],occidx] * 2 foo = fock[occidx[:,None],occidx] fvv = fock[viridx[:,None],viridx] h_diag = (fvv.diagonal().real[:,None] - foo.diagonal().real) * 2 if with_symmetry and mol.symmetry: g[sym_forbid] = 0 h_diag[sym_forbid] = 0 vind = _gen_rhf_response(mf, mo_coeff, mo_occ, singlet=None, hermi=1) def h_op(x): x = x.reshape(nvir,nocc) if with_symmetry and mol.symmetry: x = x.copy() x[sym_forbid] = 0 x2 = numpy.einsum('ps,sq->pq', fvv, x) #x2-= .5*numpy.einsum('ps,rp->rs', foo, x) #x2-= .5*numpy.einsum('sp,rp->rs', foo, x) x2-= numpy.einsum('ps,rp->rs', foo, x) # *2 for double occupancy d1 = reduce(numpy.dot, (orbv, x*2, orbo.conj().T)) dm1 = d1 + d1.conj().T v1 = vind(dm1) x2 += reduce(numpy.dot, (orbv.conj().T, v1, orbo)) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2.ravel() * 2 return g.reshape(-1), h_op, h_diag.reshape(-1)
def fproj(mo): if project: mo = addons.project_mo_nr2nr(chk_mol, mo, mol) norm = numpy.einsum('pi,pi->i', mo.conj(), s.dot(mo)) mo /= numpy.sqrt(norm) return mo
def project_to_atomic_orbitals(mol, basname): '''projected AO = |bas><bas|ANO> ''' from pyscf.scf.addons import project_mo_nr2nr from pyscf.scf import atom_hf from pyscf.gto.ecp import core_configuration def search_atm_l(atm, l): bas_ang = atm._bas[:, gto.ANG_OF] ao_loc = atm.ao_loc_nr() idx = [] for ib in numpy.where(bas_ang == l)[0]: idx.extend(range(ao_loc[ib], ao_loc[ib + 1])) return idx # Overlap of ANO and ECP basis def ecp_ano_det_ovlp(atm_ecp, atm_ano, ecpcore): ecp_ao_loc = atm_ecp.ao_loc_nr() ano_ao_loc = atm_ano.ao_loc_nr() ecp_ao_dim = ecp_ao_loc[1:] - ecp_ao_loc[:-1] ano_ao_dim = ano_ao_loc[1:] - ano_ao_loc[:-1] ecp_bas_l = [[atm_ecp.bas_angular(i)] * d for i, d in enumerate(ecp_ao_dim)] ano_bas_l = [[atm_ano.bas_angular(i)] * d for i, d in enumerate(ano_ao_dim)] ecp_bas_l = numpy.hstack(ecp_bas_l) ano_bas_l = numpy.hstack(ano_bas_l) ecp_idx = [] ano_idx = [] for l in range(4): nocc, nfrac = atom_hf.frac_occ(stdsymb, l) if nfrac > 1e-15: nocc += 1 if nocc == 0: break i0 = ecpcore[l] * (2 * l + 1) i1 = nocc * (2 * l + 1) ecp_idx.append(numpy.where(ecp_bas_l == l)[0][:i1 - i0]) ano_idx.append(numpy.where(ano_bas_l == l)[0][i0:i1]) ecp_idx = numpy.hstack(ecp_idx) ano_idx = numpy.hstack(ano_idx) s12 = gto.intor_cross('int1e_ovlp', atm_ecp, atm_ano)[ecp_idx][:, ano_idx] return numpy.linalg.det(s12) nelec_ecp_dic = {} for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb not in nelec_ecp_dic: nelec_ecp_dic[symb] = mol.atom_nelec_core(ia) aos = {} atm = gto.Mole() atmp = gto.Mole() for symb in mol._basis.keys(): stdsymb = gto.mole._std_symbol(symb) atm._atm, atm._bas, atm._env = \ atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, []) atm.cart = mol.cart s0 = atm.intor_symmetric('int1e_ovlp') if 'GHOST' in symb.upper(): aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal())) continue basis_add = gto.basis.load(basname, stdsymb) atmp._atm, atmp._bas, atmp._env = \ atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, []) atmp.cart = mol.cart nelec_ecp = nelec_ecp_dic[symb] if nelec_ecp > 0: ecpcore = core_configuration(nelec_ecp) # Comparing to ANO valence basis, to check whether the ECP basis set has # reasonable AO-character contraction. The ANO valence AO should have # significant overlap to ECP basis if the ECP basis has AO-character. if abs(ecp_ano_det_ovlp(atm, atmp, ecpcore)) > .1: aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal())) continue else: ecpcore = [0] * 4 ano = project_mo_nr2nr(atmp, 1, atm) rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0)) c = rm_ano.copy() for l in range(param.L_MAX): idx = numpy.asarray(search_atm_l(atm, l)) nbf_atm_l = len(idx) if nbf_atm_l == 0: break idxp = numpy.asarray(search_atm_l(atmp, l)) if l < 4: idxp = idxp[ecpcore[l]:] nbf_ano_l = len(idxp) if mol.cart: degen = (l + 1) * (l + 2) // 2 else: degen = l * 2 + 1 if nbf_atm_l > nbf_ano_l > 0: # For angular l, first place the projected ANO, then the rest AOs. sdiag = reduce( numpy.dot, (rm_ano[:, idx].T, s0, rm_ano[:, idx])).diagonal() nleft = (nbf_atm_l - nbf_ano_l) // degen shell_average = numpy.einsum('ij->i', sdiag.reshape(-1, degen)) shell_rest = numpy.argsort(-shell_average)[:nleft] idx_rest = [] for k in shell_rest: idx_rest.extend(idx[k * degen:(k + 1) * degen]) c[:, idx[:nbf_ano_l]] = ano[:, idxp] c[:, idx[nbf_ano_l:]] = rm_ano[:, idx_rest] elif nbf_ano_l >= nbf_atm_l > 0: # More ANOs than the mol basis functions c[:, idx] = ano[:, idxp[:nbf_atm_l]] sdiag = numpy.einsum('pi,pq,qi->i', c, s0, c) c *= 1. / numpy.sqrt(sdiag) aos[symb] = c nao = mol.nao_nr() c = numpy.zeros((nao, nao)) p1 = 0 for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb in mol._basis: ano = aos[symb] else: ano = aos[mol.atom_pure_symbol(ia)] p0, p1 = p1, p1 + ano.shape[1] c[p0:p1, p0:p1] = ano return c
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None, with_symmetry=True): mol = mf.mol mo_coeff0 = mo_coeff if getattr(mf, '_scf', None) and mf._scf.mol != mol: #TODO: construct vind with dual-basis treatment, (see also JCP, 118, 9497) mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol), addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol)) occidxa = numpy.where(mo_occ[0]>0)[0] occidxb = numpy.where(mo_occ[1]>0)[0] viridxa = numpy.where(mo_occ[0]==0)[0] viridxb = numpy.where(mo_occ[1]==0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:,occidxa] orbob = mo_coeff[1][:,occidxb] orbva = mo_coeff[0][:,viridxa] orbvb = mo_coeff[1][:,viridxb] if with_symmetry and mol.symmetry: orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) sym_forbida = orbsyma[viridxa,None] != orbsyma[occidxa] sym_forbidb = orbsymb[viridxb,None] != orbsymb[occidxb] sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel())) if fock_ao is None: dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = mf.get_fock(h1e, dm=dm0) focka = reduce(numpy.dot, (mo_coeff[0].conj().T, fock_ao[0], mo_coeff[0])) fockb = reduce(numpy.dot, (mo_coeff[1].conj().T, fock_ao[1], mo_coeff[1])) else: focka = reduce(numpy.dot, (mo_coeff0[0].conj().T, fock_ao[0], mo_coeff0[0])) fockb = reduce(numpy.dot, (mo_coeff0[1].conj().T, fock_ao[1], mo_coeff0[1])) fooa = focka[occidxa[:,None],occidxa] fvva = focka[viridxa[:,None],viridxa] foob = fockb[occidxb[:,None],occidxb] fvvb = fockb[viridxb[:,None],viridxb] g = numpy.hstack((focka[viridxa[:,None],occidxa].ravel(), fockb[viridxb[:,None],occidxb].ravel())) h_diaga = fvva.diagonal().real[:,None] - fooa.diagonal().real h_diagb = fvvb.diagonal().real[:,None] - foob.diagonal().real h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1))) if with_symmetry and mol.symmetry: g[sym_forbid] = 0 h_diag[sym_forbid] = 0 vind = _gen_uhf_response(mf, mo_coeff, mo_occ, hermi=1) def h_op(x): if with_symmetry and mol.symmetry: x = x.copy() x[sym_forbid] = 0 x1a = x[:nvira*nocca].reshape(nvira,nocca) x1b = x[nvira*nocca:].reshape(nvirb,noccb) x2a = numpy.einsum('pr,rq->pq', fvva, x1a) x2a-= numpy.einsum('sq,ps->pq', fooa, x1a) x2b = numpy.einsum('pr,rq->pq', fvvb, x1b) x2b-= numpy.einsum('sq,ps->pq', foob, x1b) d1a = reduce(numpy.dot, (orbva, x1a, orboa.conj().T)) d1b = reduce(numpy.dot, (orbvb, x1b, orbob.conj().T)) dm1 = numpy.array((d1a+d1a.conj().T,d1b+d1b.conj().T)) v1 = vind(dm1) x2a += reduce(numpy.dot, (orbva.conj().T, v1[0], orboa)) x2b += reduce(numpy.dot, (orbvb.conj().T, v1[1], orbob)) x2 = numpy.hstack((x2a.ravel(), x2b.ravel())) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2 return g, h_op, h_diag
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None, with_symmetry=True): mol = mf.mol mo_coeff0 = mo_coeff if getattr(mf, '_scf', None) and mf._scf.mol != mol: #TODO: construct vind with dual-basis treatment, (see also JCP, 118, 9497) mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol), addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol)) occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] if with_symmetry and mol.symmetry: orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) sym_forbida = orbsyma[viridxa, None] != orbsyma[occidxa] sym_forbidb = orbsymb[viridxb, None] != orbsymb[occidxb] sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel())) if fock_ao is None: if getattr(mf, '_scf', None) and mf._scf.mol != mol: h1e = mf.get_hcore(mol) dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = mf.get_fock(h1e, dm=dm0) focka = reduce(numpy.dot, (mo_coeff[0].conj().T, fock_ao[0], mo_coeff[0])) fockb = reduce(numpy.dot, (mo_coeff[1].conj().T, fock_ao[1], mo_coeff[1])) else: focka = reduce(numpy.dot, (mo_coeff0[0].conj().T, fock_ao[0], mo_coeff0[0])) fockb = reduce(numpy.dot, (mo_coeff0[1].conj().T, fock_ao[1], mo_coeff0[1])) fooa = focka[occidxa[:, None], occidxa] fvva = focka[viridxa[:, None], viridxa] foob = fockb[occidxb[:, None], occidxb] fvvb = fockb[viridxb[:, None], viridxb] g = numpy.hstack((focka[viridxa[:, None], occidxa].ravel(), fockb[viridxb[:, None], occidxb].ravel())) h_diaga = fvva.diagonal().real[:, None] - fooa.diagonal().real h_diagb = fvvb.diagonal().real[:, None] - foob.diagonal().real h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1))) if with_symmetry and mol.symmetry: g[sym_forbid] = 0 h_diag[sym_forbid] = 0 vind = _gen_uhf_response(mf, mo_coeff, mo_occ, hermi=1) def h_op(x): if with_symmetry and mol.symmetry: x = x.copy() x[sym_forbid] = 0 x1a = x[:nvira * nocca].reshape(nvira, nocca) x1b = x[nvira * nocca:].reshape(nvirb, noccb) x2a = numpy.einsum('pr,rq->pq', fvva, x1a) x2a -= numpy.einsum('sq,ps->pq', fooa, x1a) x2b = numpy.einsum('pr,rq->pq', fvvb, x1b) x2b -= numpy.einsum('sq,ps->pq', foob, x1b) d1a = reduce(numpy.dot, (orbva, x1a, orboa.conj().T)) d1b = reduce(numpy.dot, (orbvb, x1b, orbob.conj().T)) dm1 = numpy.array((d1a + d1a.conj().T, d1b + d1b.conj().T)) v1 = vind(dm1) x2a += reduce(numpy.dot, (orbva.conj().T, v1[0], orboa)) x2b += reduce(numpy.dot, (orbvb.conj().T, v1[1], orbob)) x2 = numpy.hstack((x2a.ravel(), x2b.ravel())) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2 return g, h_op, h_diag
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None): mol = mf.mol occidxa = numpy.where(mo_occ[0]>0)[0] occidxb = numpy.where(mo_occ[1]>0)[0] viridxa = numpy.where(mo_occ[0]==0)[0] viridxb = numpy.where(mo_occ[1]==0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) if fock_ao is None: if h1e is None: h1e = mf.get_hcore() dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = h1e + mf.get_veff(mol, dm0) focka = reduce(numpy.dot, (mo_coeff[0].T, fock_ao[0], mo_coeff[0])) fockb = reduce(numpy.dot, (mo_coeff[1].T, fock_ao[1], mo_coeff[1])) g = numpy.hstack((focka[viridxa[:,None],occidxa].reshape(-1), fockb[viridxb[:,None],occidxb].reshape(-1))) h_diaga =(focka[viridxa,viridxa].reshape(-1,1) - focka[occidxa,occidxa]) h_diagb =(fockb[viridxb,viridxb].reshape(-1,1) - fockb[occidxb,occidxb]) h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1))) if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol): mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol), addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol)) if hasattr(mf, 'xc') and hasattr(mf, '_numint'): if mf.grids.coords is None: mf.grids.build() hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin>0)+1) rho0, vxc, fxc = mf._numint.cache_xc_kernel(mol, mf.grids, mf.xc, mo_coeff, mo_occ, 1) #dm0 =(numpy.dot(mo_coeff[0]*mo_occ[0], mo_coeff[0].T), # numpy.dot(mo_coeff[1]*mo_occ[1], mo_coeff[1].T)) dm0 = None else: hyb = None def h_op(x): x1a = x[:nvira*nocca].reshape(nvira,nocca) x1b = x[nvira*nocca:].reshape(nvirb,noccb) x2a = numpy.einsum('rp,rq->pq', focka[viridxa[:,None],viridxa], x1a) x2a -= numpy.einsum('sq,ps->pq', focka[occidxa[:,None],occidxa], x1a) x2b = numpy.einsum('rp,rq->pq', fockb[viridxb[:,None],viridxb], x1b) x2b -= numpy.einsum('sq,ps->pq', fockb[occidxb[:,None],occidxb], x1b) d1a = reduce(numpy.dot, (mo_coeff[0][:,viridxa], x1a, mo_coeff[0][:,occidxa].T)) d1b = reduce(numpy.dot, (mo_coeff[1][:,viridxb], x1b, mo_coeff[1][:,occidxb].T)) dm1 = numpy.array((d1a+d1a.T,d1b+d1b.T)) if hyb is None: v1 = mf.get_veff(mol, dm1) else: v1 = mf._numint.nr_uks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, 1, rho0, vxc, fxc) if abs(hyb) < 1e-10: vj = mf.get_j(mol, dm1) v1 += vj[0] + vj[1] else: vj, vk = mf.get_jk(mol, dm1) v1 += vj[0]+vj[1] - vk * hyb * .5 x2a += reduce(numpy.dot, (mo_coeff[0][:,viridxa].T, v1[0], mo_coeff[0][:,occidxa])) x2b += reduce(numpy.dot, (mo_coeff[1][:,viridxb].T, v1[1], mo_coeff[1][:,occidxb])) return numpy.hstack((x2a.ravel(), x2b.ravel())) return g, h_op, h_diag
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None, with_symmetry=True): mol = mf.mol if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol): mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol), addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol)) occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] if with_symmetry and mol.symmetry: orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) sym_forbida = orbsyma[viridxa].reshape(-1, 1) != orbsyma[occidxa] sym_forbidb = orbsymb[viridxb].reshape(-1, 1) != orbsymb[occidxb] sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel())) if fock_ao is None: if h1e is None: h1e = mf.get_hcore() dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = h1e + mf.get_veff(mol, dm0) focka = reduce(numpy.dot, (mo_coeff[0].T, fock_ao[0], mo_coeff[0])) fockb = reduce(numpy.dot, (mo_coeff[1].T, fock_ao[1], mo_coeff[1])) fooa = focka[occidxa[:, None], occidxa] fvva = focka[viridxa[:, None], viridxa] foob = fockb[occidxb[:, None], occidxb] fvvb = fockb[viridxb[:, None], viridxb] g = numpy.hstack((focka[occidxa[:, None], viridxa].T.ravel(), fockb[occidxb[:, None], viridxb].T.ravel())) h_diaga = focka[viridxa, viridxa].reshape(-1, 1) - focka[occidxa, occidxa] h_diagb = fockb[viridxb, viridxb].reshape(-1, 1) - fockb[occidxb, occidxb] h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1))) if with_symmetry and mol.symmetry: g[sym_forbid] = 0 h_diag[sym_forbid] = 0 vind = _gen_uhf_response(mf, mo_coeff, mo_occ, hermi=1) def h_op(x): if with_symmetry and mol.symmetry: x = x.copy() x[sym_forbid] = 0 x1a = x[:nvira * nocca].reshape(nvira, nocca) x1b = x[nvira * nocca:].reshape(nvirb, noccb) x2a = numpy.einsum('pr,rq->pq', fvva, x1a) x2a -= numpy.einsum('sq,ps->pq', fooa, x1a) x2b = numpy.einsum('pr,rq->pq', fvvb, x1b) x2b -= numpy.einsum('sq,ps->pq', foob, x1b) d1a = reduce(numpy.dot, (orbva, x1a, orboa.T.conj())) d1b = reduce(numpy.dot, (orbvb, x1b, orbob.T.conj())) dm1 = numpy.array((d1a + d1a.T.conj(), d1b + d1b.T.conj())) v1 = vind(dm1) x2a += reduce(numpy.dot, (orbva.T.conj(), v1[0], orboa)) x2b += reduce(numpy.dot, (orbvb.T.conj(), v1[1], orbob)) x2 = numpy.hstack((x2a.ravel(), x2b.ravel())) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2 return g, h_op, h_diag
def init_guess_by_minao(mol): '''Generate initial guess density matrix based on ANO basis, then project the density matrix to the basis set defined by ``mol`` Returns: Density matrix, 2D ndarray Examples: >>> from pyscf import gto, scf >>> mol = gto.M(atom='H 0 0 0; H 0 0 1.1') >>> scf.hf.init_guess_by_minao(mol) array([[ 0.94758917, 0.09227308], [ 0.09227308, 0.94758917]]) ''' from pyscf.scf import atom_hf from pyscf.scf import addons def minao_basis(symb, nelec_ecp): basis_add = gto.basis.load('ano', symb) occ = [] basis_new = [] # coreshl defines the core shells to be removed in the initial guess coreshl = gto.ecp.core_configuration(nelec_ecp) #coreshl = (0,0,0,0) # it keeps all core electrons in the initial guess for l in range(4): ndocc, nfrac = atom_hf.frac_occ(symb, l) if coreshl[l] > 0: occ.extend([0] * coreshl[l] * (2 * l + 1)) if ndocc > coreshl[l]: occ.extend([2] * (ndocc - coreshl[l]) * (2 * l + 1)) if nfrac > 1e-15: occ.extend([nfrac] * (2 * l + 1)) ndocc += 1 if ndocc > 0: basis_new.append([l] + [b[:ndocc + 1] for b in basis_add[l][1:]]) return occ, basis_new atmlst = set([mol.atom_symbol(ia) for ia in range(mol.natm)]) nelec_ecp_dic = {} for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb not in nelec_ecp_dic: nelec_ecp_dic[symb] = mol.atom_nelec_core(ia) basis = {} occdic = {} for symb in atmlst: if symb != 'GHOST': nelec_ecp = nelec_ecp_dic[symb] stdsymb = gto.mole._std_symbol(symb) occ_add, basis_add = minao_basis(stdsymb, nelec_ecp) occdic[symb] = occ_add basis[symb] = basis_add occ = [] new_atom = [] for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb != 'GHOST': occ.append(occdic[symb]) new_atom.append(mol._atom[ia]) occ = numpy.hstack(occ) pmol = gto.Mole() pmol._atm, pmol._bas, pmol._env = pmol.make_env(new_atom, basis, []) c = addons.project_mo_nr2nr(pmol, 1, mol) dm = numpy.dot(c * occ, c.T) # normalize eletron number # s = mol.intor_symmetric('int1e_ovlp') # dm *= mol.nelectron / (dm*s).sum() return dm
def project_to_atomic_orbitals(mol, basname): '''projected AO = |bas><bas|ANO> ''' from pyscf.scf.addons import project_mo_nr2nr from pyscf.gto.ecp import core_configuration def search_atm_l(atm, l): idx = [] p0 = 0 for ib, b in enumerate(atm._bas): l0 = atm.bas_angular(ib) nctr = atm.bas_nctr(ib) if l0 == l: idx.extend(range(p0,p0+(2*l+1)*nctr)) p0 += (2*l0+1) * nctr return idx aos = {} atm = gto.Mole() atmp = gto.Mole() for symb in mol._basis.keys(): stdsymb = gto.mole._std_symbol(symb) atm._atm, atm._bas, atm._env = \ atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, []) if 'GHOST' in symb.upper(): aos[symb] = numpy.eye(atm.nao_nr()) continue s0 = atm.intor_symmetric('cint1e_ovlp_sph') basis_add = gto.basis.load(basname, stdsymb) atmp._atm, atmp._bas, atmp._env = \ atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, []) ano = project_mo_nr2nr(atmp, 1, atm) rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0)) nelec_ecp = 0 if mol._ecp: if symb in mol._ecp: nelec_ecp = mol._ecp[symb][0] elif stdsymb in mol._ecp: nelec_ecp = mol._ecp[stdsymb][0] ecpcore = core_configuration(nelec_ecp) c = rm_ano.copy() for l in range(param.L_MAX): idx = numpy.asarray(search_atm_l(atm, l)) if len(idx) == 0: break idxp = numpy.asarray(search_atm_l(atmp, l)) if l < 4: idxp = idxp[ecpcore[l]:] if len(idx) > len(idxp) > 0: # For angular l, first place the projected ANO, then the rest AOs. sdiag = reduce(numpy.dot, (rm_ano[:,idx].T, s0, rm_ano[:,idx])).diagonal() nleft = (len(idx) - len(idxp)) // (2*l+1) shell_average = numpy.einsum('ij->i', sdiag.reshape(-1,l*2+1)) shell_rest = numpy.argsort(-shell_average)[:nleft] idx_rest = [] for k in shell_rest: idx_rest.extend(idx[k*(2*l+1):(k+1)*(2*l+1)]) c[:,idx[:len(idxp)]] = ano[:,idxp] c[:,idx[len(idxp):]] = rm_ano[:,idx_rest] elif len(idxp) >= len(idx) > 0: # More ANOs than the mol basis functions c[:,idx] = ano[:,idxp[:len(idx)]] aos[symb] = c nao = mol.nao_nr() c = numpy.zeros((nao,nao)) p0 = 0 for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb in mol._basis: ano = aos[symb] else: symb = mol.atom_pure_symbol(ia) ano = aos[symb] p1 = p0 + ano.shape[1] c[p0:p1,p0:p1] = ano p0 = p1 return c
def project_to_atomic_orbitals(mol, basname): '''projected AO = |bas><bas|ANO> ''' from pyscf.scf.addons import project_mo_nr2nr from pyscf.scf import atom_hf from pyscf.gto.ecp import core_configuration def search_atm_l(atm, l): bas_ang = atm._bas[:,gto.ANG_OF] ao_loc = atm.ao_loc_nr() idx = [] for ib in numpy.where(bas_ang == l)[0]: idx.extend(range(ao_loc[ib], ao_loc[ib+1])) return idx # Overlap of ANO and ECP basis def ecp_ano_det_ovlp(atm_ecp, atm_ano, ecpcore): ecp_ao_loc = atm_ecp.ao_loc_nr() ano_ao_loc = atm_ano.ao_loc_nr() ecp_ao_dim = ecp_ao_loc[1:] - ecp_ao_loc[:-1] ano_ao_dim = ano_ao_loc[1:] - ano_ao_loc[:-1] ecp_bas_l = [[atm_ecp.bas_angular(i)]*d for i,d in enumerate(ecp_ao_dim)] ano_bas_l = [[atm_ano.bas_angular(i)]*d for i,d in enumerate(ano_ao_dim)] ecp_bas_l = numpy.hstack(ecp_bas_l) ano_bas_l = numpy.hstack(ano_bas_l) nelec_core = 0 ecp_occ_tmp = [] ecp_idx = [] ano_idx = [] for l in range(4): nocc, frac = atom_hf.frac_occ(stdsymb, l) l_occ = [2] * ((nocc-ecpcore[l])*(2*l+1)) if frac > 1e-15: l_occ.extend([frac] * (2*l+1)) nocc += 1 if nocc == 0: break nelec_core += 2 * ecpcore[l] * (2*l+1) i0 = ecpcore[l] * (2*l+1) i1 = nocc * (2*l+1) ecp_idx.append(numpy.where(ecp_bas_l==l)[0][:i1-i0]) ano_idx.append(numpy.where(ano_bas_l==l)[0][i0:i1]) ecp_occ_tmp.append(l_occ[:i1-i0]) ecp_idx = numpy.hstack(ecp_idx) ano_idx = numpy.hstack(ano_idx) ecp_occ = numpy.zeros(atm_ecp.nao_nr()) ecp_occ[ecp_idx] = numpy.hstack(ecp_occ_tmp) nelec_valence_left = int(gto.mole.charge(stdsymb) - nelec_core - sum(ecp_occ[ecp_idx])) if nelec_valence_left > 0: logger.warn(mol, 'Characters of %d valence electrons are not identified.\n' 'It can affect the "meta-lowdin" localization method ' 'and the population analysis of SCF method.\n' 'Adjustment to the core/valence partition may be needed ' '(see function lo.nao.set_atom_conf)\nto get reasonable ' 'local orbitals or Mulliken population.\n', nelec_valence_left) # Return 0 to force the projection to ANO basis return 0 else: s12 = gto.intor_cross('int1e_ovlp', atm_ecp, atm_ano)[ecp_idx][:,ano_idx] return numpy.linalg.det(s12) nelec_ecp_dic = {} for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb not in nelec_ecp_dic: nelec_ecp_dic[symb] = mol.atom_nelec_core(ia) aos = {} atm = gto.Mole() atmp = gto.Mole() for symb in mol._basis.keys(): stdsymb = gto.mole._std_symbol(symb) atm._atm, atm._bas, atm._env = \ atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, []) atm.cart = mol.cart atm._built = True s0 = atm.intor_symmetric('int1e_ovlp') if gto.is_ghost_atom(symb): aos[symb] = numpy.diag(1./numpy.sqrt(s0.diagonal())) continue basis_add = gto.basis.load(basname, stdsymb) atmp._atm, atmp._bas, atmp._env = \ atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, []) atmp.cart = mol.cart atmp._built = True if symb in nelec_ecp_dic and nelec_ecp_dic[symb] > 0: if not PROJECT_ECP_BASIS: # If ECP basis has good atomic character, ECP basis can be used in the # localization/population analysis directly. Otherwise project ECP basis to # ANO basis. continue ecpcore = core_configuration(nelec_ecp_dic[symb]) # Comparing to ANO valence basis, to check whether the ECP basis set has # reasonable AO-character contraction. The ANO valence AO should have # significant overlap to ECP basis if the ECP basis has AO-character. if abs(ecp_ano_det_ovlp(atm, atmp, ecpcore)) > .1: aos[symb] = numpy.diag(1./numpy.sqrt(s0.diagonal())) continue else: ecpcore = [0] * 4 ano = project_mo_nr2nr(atmp, numpy.eye(atmp.nao_nr()), atm) rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0)) c = rm_ano.copy() for l in range(param.L_MAX): idx = numpy.asarray(search_atm_l(atm, l)) nbf_atm_l = len(idx) if nbf_atm_l == 0: break idxp = numpy.asarray(search_atm_l(atmp, l)) if l < 4: idxp = idxp[ecpcore[l]:] nbf_ano_l = len(idxp) if mol.cart: degen = (l + 1) * (l + 2) // 2 else: degen = l * 2 + 1 if nbf_atm_l > nbf_ano_l > 0: # For angular l, first place the projected ANO, then the rest AOs. sdiag = reduce(numpy.dot, (rm_ano[:,idx].T, s0, rm_ano[:,idx])).diagonal() nleft = (nbf_atm_l - nbf_ano_l) // degen shell_average = numpy.einsum('ij->i', sdiag.reshape(-1,degen)) shell_rest = numpy.argsort(-shell_average)[:nleft] idx_rest = [] for k in shell_rest: idx_rest.extend(idx[k*degen:(k+1)*degen]) c[:,idx[:nbf_ano_l]] = ano[:,idxp] c[:,idx[nbf_ano_l:]] = rm_ano[:,idx_rest] elif nbf_ano_l >= nbf_atm_l > 0: # More ANOs than the mol basis functions c[:,idx] = ano[:,idxp[:nbf_atm_l]] sdiag = numpy.einsum('pi,pq,qi->i', c, s0, c) c *= 1./numpy.sqrt(sdiag) aos[symb] = c nao = mol.nao_nr() c = numpy.zeros((nao,nao)) p1 = 0 for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb in mol._basis: ano = aos[symb] else: ano = aos[mol.atom_pure_symbol(ia)] p0, p1 = p1, p1 + ano.shape[1] c[p0:p1,p0:p1] = ano return c
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None, with_symmetry=True): mo_coeff0 = mo_coeff mol = mf.mol if getattr(mf, '_scf', None) and mf._scf.mol != mol: #TODO: construct vind with dual-basis treatment, (see also JCP, 118, 9497) # To project Hessians from another basis if different basis sets are used # in newton solver and underlying mean-filed solver. mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol) occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) orbo = mo_coeff[:, occidx] orbv = mo_coeff[:, viridx] if with_symmetry and mol.symmetry: orbsym = hf_symm.get_orbsym(mol, mo_coeff) sym_forbid = orbsym[viridx, None] != orbsym[occidx] if fock_ao is None: # dm0 is the density matrix in projected basis. Computing fock in # projected basis. if getattr(mf, '_scf', None) and mf._scf.mol != mol: h1e = mf.get_hcore(mol) dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = mf.get_fock(h1e, dm=dm0) fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff)) else: # If fock is given, it corresponds to main basis. It needs to be # diagonalized with the mo_coeff of the main basis. fock = reduce(numpy.dot, (mo_coeff0.conj().T, fock_ao, mo_coeff0)) g = fock[viridx[:, None], occidx] * 2 foo = fock[occidx[:, None], occidx] fvv = fock[viridx[:, None], viridx] h_diag = (fvv.diagonal().real[:, None] - foo.diagonal().real) * 2 if with_symmetry and mol.symmetry: g[sym_forbid] = 0 h_diag[sym_forbid] = 0 vind = _gen_rhf_response(mf, mo_coeff, mo_occ, singlet=None, hermi=1) def h_op(x): x = x.reshape(nvir, nocc) if with_symmetry and mol.symmetry: x = x.copy() x[sym_forbid] = 0 x2 = numpy.einsum('ps,sq->pq', fvv, x) #x2-= .5*numpy.einsum('ps,rp->rs', foo, x) #x2-= .5*numpy.einsum('sp,rp->rs', foo, x) x2 -= numpy.einsum('ps,rp->rs', foo, x) # *2 for double occupancy d1 = reduce(numpy.dot, (orbv, x * 2, orbo.conj().T)) dm1 = d1 + d1.conj().T v1 = vind(dm1) x2 += reduce(numpy.dot, (orbv.conj().T, v1, orbo)) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2.ravel() * 2 return g.reshape(-1), h_op, h_diag.reshape(-1)
def project_to_atomic_orbitals(mol, basname): '''projected AO = |bas><bas|ANO> ''' from pyscf.scf.addons import project_mo_nr2nr from pyscf.scf import atom_hf from pyscf.gto.ecp import core_configuration def search_atm_l(atm, l): bas_ang = atm._bas[:, gto.ANG_OF] ao_loc = atm.ao_loc_nr() idx = [] for ib in numpy.where(bas_ang == l)[0]: idx.extend(range(ao_loc[ib], ao_loc[ib + 1])) return idx # Overlap of ANO and ECP basis def ecp_ano_det_ovlp(atm_ecp, atm_ano, ecpcore): ecp_ao_loc = atm_ecp.ao_loc_nr() ano_ao_loc = atm_ano.ao_loc_nr() ecp_ao_dim = ecp_ao_loc[1:] - ecp_ao_loc[:-1] ano_ao_dim = ano_ao_loc[1:] - ano_ao_loc[:-1] ecp_bas_l = [[atm_ecp.bas_angular(i)] * d for i, d in enumerate(ecp_ao_dim)] ano_bas_l = [[atm_ano.bas_angular(i)] * d for i, d in enumerate(ano_ao_dim)] ecp_bas_l = numpy.hstack(ecp_bas_l) ano_bas_l = numpy.hstack(ano_bas_l) nelec_core = 0 ecp_occ_tmp = [] ecp_idx = [] ano_idx = [] for l in range(4): nocc, frac = atom_hf.frac_occ(stdsymb, l) l_occ = [2] * ((nocc - ecpcore[l]) * (2 * l + 1)) if frac > 1e-15: l_occ.extend([frac] * (2 * l + 1)) nocc += 1 if nocc == 0: break nelec_core += 2 * ecpcore[l] * (2 * l + 1) i0 = ecpcore[l] * (2 * l + 1) i1 = nocc * (2 * l + 1) ecp_idx.append(numpy.where(ecp_bas_l == l)[0][:i1 - i0]) ano_idx.append(numpy.where(ano_bas_l == l)[0][i0:i1]) ecp_occ_tmp.append(l_occ[:i1 - i0]) ecp_idx = numpy.hstack(ecp_idx) ano_idx = numpy.hstack(ano_idx) ecp_occ = numpy.zeros(atm_ecp.nao_nr()) ecp_occ[ecp_idx] = numpy.hstack(ecp_occ_tmp) nelec_valence_left = int( gto.charge(stdsymb) - nelec_core - sum(ecp_occ[ecp_idx])) if nelec_valence_left > 0: logger.warn( mol, 'Characters of %d valence electrons are not identified.\n' 'It can affect the "meta-lowdin" localization method ' 'and the population analysis of SCF method.\n' 'Adjustment to the core/valence partition may be needed ' '(see function lo.nao.set_atom_conf)\nto get reasonable ' 'local orbitals or Mulliken population.\n', nelec_valence_left) # Return 0 to force the projection to ANO basis return 0 else: s12 = gto.intor_cross('int1e_ovlp', atm_ecp, atm_ano)[ecp_idx][:, ano_idx] return numpy.linalg.det(s12) nelec_ecp_dic = {} for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb not in nelec_ecp_dic: nelec_ecp_dic[symb] = mol.atom_nelec_core(ia) aos = {} atm = gto.Mole() atmp = gto.Mole() for symb in mol._basis.keys(): stdsymb = gto.mole._std_symbol(symb) atm._atm, atm._bas, atm._env = \ atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, []) atm.cart = mol.cart atm._built = True s0 = atm.intor_symmetric('int1e_ovlp') if gto.is_ghost_atom(symb): aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal())) continue basis_add = gto.basis.load(basname, stdsymb) atmp._atm, atmp._bas, atmp._env = \ atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, []) atmp.cart = mol.cart atmp._built = True if symb in nelec_ecp_dic and nelec_ecp_dic[symb] > 0: # If ECP basis has good atomic character, ECP basis can be used in the # localization/population analysis directly. Otherwise project ECP # basis to ANO basis. if not PROJECT_ECP_BASIS: continue ecpcore = core_configuration(nelec_ecp_dic[symb]) # Comparing to ANO valence basis, to check whether the ECP basis set has # reasonable AO-character contraction. The ANO valence AO should have # significant overlap to ECP basis if the ECP basis has AO-character. if abs(ecp_ano_det_ovlp(atm, atmp, ecpcore)) > .1: aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal())) continue else: ecpcore = [0] * 4 # MINAO for heavier elements needs to be used with pseudo potential if (basname.upper() == 'MINAO' and gto.charge(stdsymb) > 36 and symb not in nelec_ecp_dic): raise RuntimeError( 'Basis MINAO has to be used with ecp for heavy elements') ano = project_mo_nr2nr(atmp, numpy.eye(atmp.nao_nr()), atm) rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0)) c = rm_ano.copy() for l in range(param.L_MAX): idx = numpy.asarray(search_atm_l(atm, l)) nbf_atm_l = len(idx) if nbf_atm_l == 0: break idxp = numpy.asarray(search_atm_l(atmp, l)) if l < 4: idxp = idxp[ecpcore[l]:] nbf_ano_l = len(idxp) if mol.cart: degen = (l + 1) * (l + 2) // 2 else: degen = l * 2 + 1 if nbf_atm_l > nbf_ano_l > 0: # For angular l, first place the projected ANO, then the rest AOs. sdiag = reduce( numpy.dot, (rm_ano[:, idx].T, s0, rm_ano[:, idx])).diagonal() nleft = (nbf_atm_l - nbf_ano_l) // degen shell_average = numpy.einsum('ij->i', sdiag.reshape(-1, degen)) shell_rest = numpy.argsort(-shell_average)[:nleft] idx_rest = [] for k in shell_rest: idx_rest.extend(idx[k * degen:(k + 1) * degen]) c[:, idx[:nbf_ano_l]] = ano[:, idxp] c[:, idx[nbf_ano_l:]] = rm_ano[:, idx_rest] elif nbf_ano_l >= nbf_atm_l > 0: # More ANOs than the mol basis functions c[:, idx] = ano[:, idxp[:nbf_atm_l]] sdiag = numpy.einsum('pi,pq,qi->i', c, s0, c) c *= 1. / numpy.sqrt(sdiag) aos[symb] = c nao = mol.nao_nr() c = numpy.zeros((nao, nao)) p1 = 0 for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb in mol._basis: ano = aos[symb] else: ano = aos[mol.atom_pure_symbol(ia)] p0, p1 = p1, p1 + ano.shape[1] c[p0:p1, p0:p1] = ano return c
def project_to_atomic_orbitals(mol, basname): '''projected AO = |bas><bas|ANO> ''' from pyscf.scf.addons import project_mo_nr2nr from pyscf.gto.ecp import core_configuration def search_atm_l(atm, l): idx = [] p0 = 0 for ib, b in enumerate(atm._bas): l0 = atm.bas_angular(ib) nctr = atm.bas_nctr(ib) if l0 == l: idx.extend(range(p0, p0 + (2 * l + 1) * nctr)) p0 += (2 * l0 + 1) * nctr return idx aos = {} atm = gto.Mole() atmp = gto.Mole() for symb in mol._basis.keys(): stdsymb = gto.mole._std_symbol(symb) atm._atm, atm._bas, atm._env = \ atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, []) if 'GHOST' in symb.upper(): aos[symb] = numpy.eye(atm.nao_nr()) continue s0 = atm.intor_symmetric('cint1e_ovlp_sph') basis_add = gto.basis.load(basname, stdsymb) atmp._atm, atmp._bas, atmp._env = \ atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, []) ano = project_mo_nr2nr(atmp, 1, atm) rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0)) nelec_ecp = 0 if mol._ecp: if symb in mol._ecp: nelec_ecp = mol._ecp[symb][0] elif stdsymb in mol._ecp: nelec_ecp = mol._ecp[stdsymb][0] ecpcore = core_configuration(nelec_ecp) c = rm_ano.copy() for l in range(param.L_MAX): idx = numpy.asarray(search_atm_l(atm, l)) if len(idx) == 0: break idxp = numpy.asarray(search_atm_l(atmp, l)) if l < 4: idxp = idxp[ecpcore[l]:] if len(idx) > len(idxp) > 0: # For angular l, first place the projected ANO, then the rest AOs. sdiag = reduce( numpy.dot, (rm_ano[:, idx].T, s0, rm_ano[:, idx])).diagonal() nleft = (len(idx) - len(idxp)) // (2 * l + 1) shell_average = numpy.einsum('ij->i', sdiag.reshape(-1, l * 2 + 1)) shell_rest = numpy.argsort(-shell_average)[:nleft] idx_rest = [] for k in shell_rest: idx_rest.extend(idx[k * (2 * l + 1):(k + 1) * (2 * l + 1)]) c[:, idx[:len(idxp)]] = ano[:, idxp] c[:, idx[len(idxp):]] = rm_ano[:, idx_rest] elif len(idxp) >= len( idx) > 0: # More ANOs than the mol basis functions c[:, idx] = ano[:, idxp[:len(idx)]] aos[symb] = c nao = mol.nao_nr() c = numpy.zeros((nao, nao)) p0 = 0 for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb in mol._basis: ano = aos[symb] else: symb = mol.atom_pure_symbol(ia) ano = aos[symb] p1 = p0 + ano.shape[1] c[p0:p1, p0:p1] = ano p0 = p1 return c