def rohf_wag(atoms,noccsh=None,f=None,a=None,b=None,**kwargs): """\ rohf(atoms,noccsh=None,f=None,a=None,b=None,**kwargs): Restricted open shell HF driving routine atoms A Molecule object containing the system of interest """ ConvCriteria = kwargs.get('ConvCriteria',settings.ConvergenceCriteria) MaxIter = kwargs.get('MaxIter',settings.MaxIter) DoAveraging = kwargs.get('DoAveraging',settings.Averaging) verbose = kwargs.get('verbose') bfs = getbasis(atoms,**kwargs) S,h,Ints = getints(bfs,atoms,**kwargs) nel = atoms.get_nel() orbs = kwargs.get('orbs') if orbs is None: orbe,orbs = geigh(h,nS) nclosed,nopen = atoms.get_closedopen() nocc = nopen+nclosed if not noccsh: noccsh = get_noccsh(nclosed,nopen) nsh = len(noccsh) nbf = norb = len(bfs) if not f: f,a,b = get_fab(nclosed,nopen) if verbose: print "ROHF calculation" print "nsh = ",nsh print "noccsh = ",noccsh print "f = ",f print "a_ij: " for i in xrange(nsh): for j in xrange(i+1): print a[i,j], print print "b_ij: " for i in xrange(nsh): for j in xrange(i+1): print b[i,j], print enuke = atoms.get_enuke() energy = eold = 0. for i in xrange(MaxIter): Ds = get_os_dens(orbs,f,noccsh) Hs = get_os_hams(Ints,Ds) orbs = rotion(orbs,h,Hs,f,a,b,noccsh) orbe,orbs = ocbse(orbs,h,Hs,f,a,b,noccsh) orthogonalize(orbs,S) # Compute the energy eone = sum(f[ish]*trace2(Ds[ish],h) for ish in xrange(nsh)) energy = enuke+eone+sum(orbe[:nocc]) print energy,eone if abs(energy-eold) < ConvCriteria: break eold = energy return energy,orbe,orbs
def __init__(self,molecule,basis_set,**opts): from PyQuante.Ints import getints integrals = opts.get("integrals",None) nbf = len(basis_set) if integrals: self.S, self.h, self.ERI = integrals else: self.S, self.h, self.ERI = getints(basis_set.get(),molecule) return
def main(): atoms = Molecule('h2',[(1,(1.,0,0)),(1,(-1.,0,0))]) bfs = getbasis(atoms) S,h,Ints = getints(bfs,atoms) en,orbe,orbs = rhf(atoms,integrals=(S,h,Ints)) occs = [1.]+[0.]*9 Ecis = CIS(Ints,orbs,orbe,1,9,en) return Ecis[0]
def main(): atoms = Molecule('h2',[(1,(1.,0,0)),(1,(-1.,0,0))]) bfs = getbasis(atoms) nel = atoms.get_nel() nbf = len(bfs) nocc = nel/2 S,h,Ints = getints(bfs,atoms) en,orbe,orbs = rhf(atoms,integrals=(S,h,Ints),) emp2 = MP2(Ints,orbs,orbe,nocc,nbf-nocc) return en+emp2
def test_exx(): logging.basicConfig(filename='test_exx.log', level=logging.INFO, format="%(message)s", filemode='w') logging.info("Testing EXX functions") logging.info(time.asctime()) h2o = Molecule('H2O', atomlist = [(8,(0,0,0)), # the geo corresponds to the (1,(0.959,0,0)),# one that Yang used (1,(-.230,0.930,0))], units = 'Angstrom') h2 = Molecule('H2', atomlist = [(1,(0.,0.,0.7)),(1,(0.,0.,-0.7))], units = 'Bohr') he = Molecule('He',atomlist = [(2,(0,0,0))]) ne = Molecule('Ne',atomlist = [(10,(0,0,0))]) ohm = Molecule('OH-',atomlist = [(8,(0.0,0.0,0.0)), (1,(0.971,0.0,0.0))], units = 'Angstrom', charge = -1) be = Molecule('Be',atomlist = [(4,(0.0,0.0,0.0))], units = 'Angstrom') lih = Molecule('LiH', atomlist = [(1,(0,0,1.5)),(3,(0,0,-1.5))], units = 'Bohr') #for atoms in [h2,he,be,lih,ohm,ne,h2o]: for atoms in [h2,lih]: logging.info("--%s--" % atoms.name) # Caution: the rydberg molecules (He, Ne) will need a # much much larger basis set than the default returned # by getbasis (which is 6-31G**) bfs = getbasis(atoms) S,h,Ints = getints(bfs,atoms) enhf,orbehf,orbshf = rhf(atoms,integrals=(S,h,Ints)) logging.info("HF total energy = %f"% enhf) enlda,orbelda,orbslda = dft(atoms, integrals=(S,h,Ints), bfs = bfs) logging.info("LDA total energy = %f" % enlda) energy,orbe_exx,orbs_exx = exx(atoms,orbslda, integrals=(S,h,Ints), bfs = bfs, verbose=True, opt_method="BFGS") logging.info("EXX total energy = %f" % energy) return
def main(): atoms = Molecule('He', [(2,( .0000000000, .0000000000, .0000000000))], units='Angstroms') bfs = getbasis(atoms) nel = atoms.get_nel() nbf = len(bfs) nocc = nel/2 S,h,Ints = getints(bfs,atoms) en,orbe,orbs = rhf(atoms,integrals=(S,h,Ints)) emp2 = MP2(Ints,orbs,orbe,nocc,nbf-nocc) return en+emp2
def main(**opts): do_oep_an = opts.get('do_oep_an',True) mol = Molecule('LiH',[(1,(0,0,1.5)),(3,(0,0,-1.5))],units = 'Bohr') bfs = getbasis(mol) S,h,Ints = getints(bfs,mol) E_hf,orbe_hf,orbs_hf = rhf(mol,bfs=bfs,integrals=(S,h,Ints), DoAveraging=True) if do_oep_an: E_exx,orbe_exx,orbs_exx = oep_hf_an(mol,orbs_hf,bfs=bfs, integrals=(S,h,Ints)) else: E_exx,orbe_exx,orbs_exx = oep_hf(mol,orbs_hf,bfs=bfs, integrals=(S,h,Ints)) return E_exx
def __init__(self,natom, R, basis_input="ccpvtz",LDA=False): if basis_input =='2dp': basis_data='6-311g++(2d,2p)' elif basis_input =='3dp': basis_data='6-311g++(3d,3p)' elif basis_input =='3df': basis_data='6-311g++(3df,3pd)' elif basis_input =='ccpvtz': basis_data="ccpvtz" elif basis_input =='631ss': basis_data = '6-31g**++' elif basis_input =='ccpvdz': basis_data="ccpvdz" elif basis_input =='p6311ss': basis_data = '6-311g**' elif basis_input =='juho_': basis_data = 'juho_' elif basis_input =='1s': basis_data = 'sto-6g' atoms = Molecule('H2',atomlist=[(natom,(0,0,0)),(natom,(R,0,0))]) self.bfs = getbasis(atoms,basis_data) self.S, self.h, self.Ints = getints(self.bfs, atoms) M = len(self.S) ist, dict_ist = index_double(M) M2 = len(ist) UH_g = zeros((M2,M2),float) UF_g = zeros((M2,M2),float) for il,(i,j) in enumerate(ist): UH_g[il] = fetch_jints(self.Ints,i,j,M) UF_g[il] = fetch_kints(self.Ints,i,j,M) #Diagonalize GTO: H2+ basis self.eival, self.eivec = geigh(self.h,self.S) #h0 within H2+ basis h0 = trans_2matrix(self.h,self.eivec) #UH and UF within H2+ basis: T1[ad,il]*UH_g(ijkl)*T1.T[jk,bc] UH = trans_4matrix(UH_g, self.eivec) UF = trans_4matrix(UF_g, self.eivec) self.inputs = (2*h0,2*UH,2*UF) if LDA: self.gr = gto_lda_inputs(self.bfs,atoms)
def main(): LiH = Molecule('lih', [(3,( .0000000000, .0000000000, .0000000000)), (1,( .0000000000, .0000000000,1.629912))], units='Angstroms') bfs = getbasis(LiH) nbf = len(bfs) nocc,nopen = LiH.get_closedopen() assert nopen==0 S,h,Ints = getints(bfs,LiH) en,orbe,orbs = rhf(LiH,integrals=(S,h,Ints)) print "SCF completed, E = ",en emp2 = MP2(Ints,orbs,orbe,nocc,nbf-nocc) print "MP2 correction = ",emp2 print "Final energy = ",en+emp2 return en+emp2
def test_old(): from PyQuante.Molecule import Molecule from PyQuante.Ints import getbasis,getints from PyQuante.hartree_fock import rhf logging.basicConfig(level=logging.DEBUG,format="%(message)s") #mol = Molecule('HF',[('H',(0.,0.,0.)),('F',(0.,0.,0.898369))], # units='Angstrom') mol = Molecule('LiH',[(1,(0,0,1.5)),(3,(0,0,-1.5))],units = 'Bohr') bfs = getbasis(mol) S,h,Ints = getints(bfs,mol) print "after integrals" E_hf,orbe_hf,orbs_hf = rhf(mol,bfs=bfs,integrals=(S,h,Ints),DoAveraging=True) print "RHF energy = ",E_hf E_exx,orbe_exx,orbs_exx = exx(mol,orbs_hf,bfs=bfs,integrals=(S,h,Ints)) return
def test_grad(atoms,**opts): basis = opts.get('basis',None) verbose = opts.get('verbose',False) bfs = getbasis(atoms,basis) S,h,Ints = getints(bfs,atoms) nel = atoms.get_nel() enuke = atoms.get_enuke() energy, orbe, orbs = dft(atoms,return_flag=1) nclosed,nopen = atoms.get_closedopen() D = mkdens_spinavg(orbs,nclosed,nopen) # Now set up a minigrid on which to evaluate the density and gradients: npts = opts.get('npts',1) d = opts.get('d',1e-4) # generate any number of random points, and compute # analytical and numeric gradients: print "Computing Grad Rho for Molecule %s" % atoms.name maxerr = -1 for i in range(npts): x,y,z = rand_xyz() rho = get_rho(x,y,z,D,bfs) rho_px = get_rho(x+d,y,z,D,bfs) rho_mx = get_rho(x-d,y,z,D,bfs) rho_py = get_rho(x,y+d,z,D,bfs) rho_my = get_rho(x,y-d,z,D,bfs) rho_pz = get_rho(x,y,z+d,D,bfs) rho_mz = get_rho(x,y,z-d,D,bfs) gx,gy,gz = get_grad_rho(x,y,z,D,bfs) gx_num = (rho_px-rho_mx)/2/d gy_num = (rho_py-rho_my)/2/d gz_num = (rho_pz-rho_mz)/2/d dx,dy,dz = gx-gx_num,gy-gy_num,gz-gz_num error = sqrt(dx*dx+dy*dy+dz*dz) maxerr = max(error,maxerr) print " Point %10.6f %10.6f %10.6f %10.6f" % (x,y,z,error) print " Numerical %10.6f %10.6f %10.6f" % (gx_num,gy_num,gz_num) print " Analytic %10.6f %10.6f %10.6f" % (gx,gy,gz) print "The maximum error in the gradient calculation is ",maxerr return
def main(): atoms = Molecule('ch4', [(6,( .0000000000, .0000000000, .0000000000)), (1,( .0000000000, .0000000000,1.0836058890)), (1,(1.0216334297, .0000000000,-.3612019630)), (1,(-.5108167148, .8847605034,-.3612019630)), (1,(-.5108167148,-.8847605034,-.3612019630))], units='Angstroms') bfs = getbasis(atoms) nel = atoms.get_nel() nbf = len(bfs) nocc = nel/2 S,h,Ints = getints(bfs,atoms) en,orbe,orbs = rhf(atoms,integrals=(S,h,Ints)) print "SCF completed, E = ",en emp2 = MP2(Ints,orbs,orbe,nocc,nbf-nocc) print "MP2 correction = ",emp2 print "Final energy = ",en+emp2 return en+emp2
def test(file): # Make a test molecule for the calculation p = QMFile(file,mol=1) h2 = p.get_mol() #h2 = Molecule('h2',[(1,(1.,0,0)),(1,(-1.,0,0))]) # Get a basis set and compute the integrals. # normally the routine will do this automatically, but we # do it explicitly here so that we can pass the same set # of integrals into the CI code and thus not recompute them. bfs = getbasis(h2) S,h,Ints = getints(bfs,h2) # Compute the HF wave function for our molecule en,orbe,orbs = rhf(h2, integrals=(S,h,Ints) ) print "SCF completed, E = ",en print " orbital energies " PRINT (orbe) # Compute the occupied and unoccupied orbitals, used in the # CIS program to generate the excitations nclosed,nopen = h2.get_closedopen() nbf = len(bfs) nocc = nclosed+nopen nvirt = nbf-nocc # Call the CI program: #Ecis = CIS(Ints,orbs,orbe,nocc,nvirt,en) #print "Ecis = ",Ecis print orbs CIS_H = CISMatrix(Ints, orbs, en, orbe, nocc, nvirt) EN, U = linalg.eig(CIS_H) EE = EN; EE.sort() print " CIS Energies [eV]" PRINT ( EE )#* UNITS.HartreeToElectronVolt) print " First excited state energy = %20.4f" % min(EN) return
from PyQuante.TestMolecules import h2 from PyQuante.LA2 import geigh,mkdens from PyQuante.Ints import get2JmK,getbasis,getints from PyQuante.Convergence import DIIS from PyQuante.hartree_fock import get_energy bfs = getbasis(h2,basis="3-21g") nclosed,nopen = h2.get_closedopen() nocc = nclosed nel = h2.get_nel() S,h,Ints = getints(bfs,h2) orbe,orbs = geigh(h,S) enuke = h2.get_enuke() eold = 0 avg = DIIS(S) for i in range(20): D = mkdens(orbs,0,nocc) G = get2JmK(Ints,D) F = h+G F = avg.getF(F,D) orbe,orbs = geigh(F,S) energy = get_energy(h,F,D,enuke) print i,energy,energy-eold if abs(energy-eold)<1e-5: break eold = energy print "Converged"
def EN2(molecule,**opts):# "General wrapper for the simple CI method" nalpha,nbeta = molecule.get_alphabeta() bfs = getbasis(molecule) S,h,Ints = getints(bfs,molecule) energy,(orbea,orbeb),(orbsa,orbsb) = uhf(molecule,integrals=(S,h,Ints), bfs=bfs,**opts) EHF = energy print "The Hatree-Fock energy is ",EHF #compute the transformed molecular orbital integrals aamoints, nbf = TransformInts(Ints,orbsa,orbsa, nalpha) bbmoints, nbf = TransformInts(Ints,orbsb,orbsb, nbeta) abmoints, nbf = TransformInts(Ints,orbsa,orbsb, nalpha) #Initialize the fractional occupations: Yalpha = zeros((nbf),'d') Ybeta = zeros((nbf),'d') #set up the occupied and virtual orbitals aoccs = range(nalpha) boccs = range(nbeta) avirt = range(nalpha,nbf) #numbers of alpha virtual orbitals bvirt = range(nbeta,nbf) #numbers of beta virtual orbitals ######## Computation of the primary energy correction ######### #Set initial correction terms to zero Ec1 = 0. sum = 0. z = 1. #compute correction term for two alpha electrons for a in aoccs: for b in xrange(a): for r in avirt: for s in xrange(nalpha,r): arbs = aamoints[ijkl2intindex(a,r,b,s)] asbr = aamoints[ijkl2intindex(a,s,b,r)] rraa = aamoints[ijkl2intindex(r,r,a,a)] - \ aamoints[ijkl2intindex(r,a,a,r)] rrbb = aamoints[ijkl2intindex(r,r,b,b)] - \ aamoints[ijkl2intindex(r,b,b,r)] ssaa = aamoints[ijkl2intindex(s,s,a,a)] - \ aamoints[ijkl2intindex(s,a,a,s)] ssbb = aamoints[ijkl2intindex(s,s,b,b)] - \ aamoints[ijkl2intindex(s,b,b,s)] rrss = aamoints[ijkl2intindex(r,r,s,s)] - \ aamoints[ijkl2intindex(r,s,s,r)] aabb = aamoints[ijkl2intindex(a,a,b,b)] - \ aamoints[ijkl2intindex(a,b,b,a)] eigendif = (orbea[r] + orbea[s] - orbea[a] - orbea[b]) delcorr = (-rraa - rrbb - ssaa - ssbb + rrss + aabb) delta = eigendif + delcorr*z Eio = (arbs - asbr) x = -Eio/delta if abs(x) > 1: print "Warning a large x value has been ",\ "discovered with x = ",x x = choose(x < 1, (1,x)) x = choose(x > -1, (-1,x)) sum += x*x Yalpha[a] -= x*x Yalpha[b] -= x*x Yalpha[r] += x*x Yalpha[s] += x*x Ec1 += x*Eio #compute correction term for two beta electrons for a in boccs: for b in xrange(a): for r in bvirt: for s in xrange(nbeta,r): arbs = bbmoints[ijkl2intindex(a,r,b,s)] asbr = bbmoints[ijkl2intindex(a,s,b,r)] rraa = bbmoints[ijkl2intindex(r,r,a,a)] - \ bbmoints[ijkl2intindex(r,a,a,r)] rrbb = bbmoints[ijkl2intindex(r,r,b,b)] - \ bbmoints[ijkl2intindex(r,b,b,r)] ssaa = bbmoints[ijkl2intindex(s,s,a,a)] - \ bbmoints[ijkl2intindex(s,a,a,s)] ssbb = bbmoints[ijkl2intindex(s,s,b,b)] - \ bbmoints[ijkl2intindex(s,b,b,s)] rrss = bbmoints[ijkl2intindex(r,r,s,s)] - \ bbmoints[ijkl2intindex(r,s,s,r)] aabb = bbmoints[ijkl2intindex(a,a,b,b)] - \ bbmoints[ijkl2intindex(a,b,b,a)] eigendif = (orbeb[r] + orbeb[s] - orbeb[a] - orbeb[b]) delcorr = (-rraa - rrbb - ssaa - ssbb + rrss + aabb) delta = eigendif + delcorr*z Eio = (arbs - asbr) x = -Eio/delta if abs(x) > 1: print "Warning a large x value has ",\ "been discovered with x = ",x x = choose(x < 1, (1,x)) x = choose(x > -1, (-1,x)) sum += x*x Ybeta[a] -= x*x Ybeta[b] -= x*x Ybeta[r] += x*x Ybeta[s] += x*x Ec1 += x*Eio #compute correction term for one alpha and one beta electron for a in aoccs: for b in boccs: for r in avirt: for s in bvirt: arbs = abmoints[ijkl2intindex(a,r,b,s)] rraa = aamoints[ijkl2intindex(r,r,a,a)] - \ aamoints[ijkl2intindex(r,a,a,r)] rrbb = abmoints[ijkl2intindex(r,r,b,b)] aass = abmoints[ijkl2intindex(a,a,s,s)] ssbb = bbmoints[ijkl2intindex(s,s,b,b)] - \ bbmoints[ijkl2intindex(s,b,b,s)] rrss = abmoints[ijkl2intindex(r,r,s,s)] aabb = abmoints[ijkl2intindex(a,a,b,b)] eigendif = (orbea[r] + orbeb[s] - orbea[a] - orbeb[b]) delcorr = (-rraa - rrbb - aass - ssbb + rrss + aabb) delta = eigendif + delcorr*z Eio = arbs x = -Eio/delta if abs(x) > 1: print "Warning a large x value has ",\ "been discovered with x = ",x x = choose(x < 1, (1,x)) x = choose(x > -1, (-1,x)) sum += x*x Yalpha[a] -= x*x Ybeta[b] -= x*x Yalpha[r] += x*x Ybeta[s] += x*x Ec1 += x*Eio #compute the fractional occupations of the occupied orbitals for a in aoccs: Yalpha[a] = 1 + Yalpha[a] for b in boccs: Ybeta[b] = 1 + Ybeta[b] #for a in xrange(nbf): #print "For alpha = ",a,"the fractional occupation is ",Yalpha[a] #print "For beta = ",a,"the fractional occupation is ",Ybeta[a] #print the energy and its corrections E = energy + Ec1 print "The total sum of excitations is ",sum print "The primary correlation correction is ",Ec1 print "The total energy is ", E return E
def oep_uhf_an(atoms,orbsa,orbsb,**opts): """oep_hf - Form the optimized effective potential for HF exchange. Implementation of Wu and Yang's Approximate Newton Scheme from J. Theor. Comp. Chem. 2, 627 (2003). oep_uhf(atoms,orbs,**opts) atoms A Molecule object containing a list of the atoms orbs A matrix of guess orbitals Options ------- bfs None The basis functions to use for the wfn pbfs None The basis functions to use for the pot basis_data None The basis data to use to construct bfs integrals None The one- and two-electron integrals to use If not None, S,h,Ints """ maxiter = opts.get('maxiter',100) tol = opts.get('tol',1e-5) ETemp = opts.get('ETemp',False) bfs = opts.get('bfs',None) if not bfs: basis = opts.get('basis',None) bfs = getbasis(atoms,basis) # The basis set for the potential can be set different from # that used for the wave function pbfs = opts.get('pbfs',None) if not pbfs: pbfs = bfs npbf = len(pbfs) integrals = opts.get('integrals',None) if integrals: S,h,Ints = integrals else: S,h,Ints = getints(bfs,atoms) nel = atoms.get_nel() nclosed,nopen = atoms.get_closedopen() nalpha,nbeta = nclosed+nopen,nclosed Enuke = atoms.get_enuke() # Form the OEP using Yang/Wu, PRL 89 143002 (2002) nbf = len(bfs) norb = nbf ba = zeros(npbf,'d') bb = zeros(npbf,'d') # Form and store all of the three-center integrals # we're going to need. # These are <ibf|gbf|jbf> (where 'bf' indicates basis func, # as opposed to MO) # N^3 storage -- obviously you don't want to do this for # very large systems Gij = [] for g in range(npbf): gmat = zeros((nbf,nbf),'d') Gij.append(gmat) gbf = pbfs[g] for i in range(nbf): ibf = bfs[i] for j in range(i+1): jbf = bfs[j] gij = three_center(ibf,gbf,jbf) gmat[i,j] = gij gmat[j,i] = gij # Compute the Fermi-Amaldi potential based on the LDA density. # We're going to form this matrix from the Coulombic matrix that # arises from the input orbitals. D0 and J0 refer to the density # matrix and corresponding Coulomb matrix D0 = mkdens(orbsa,0,nalpha)+mkdens(orbsb,0,nbeta) J0 = getJ(Ints,D0) Vfa = ((nel-1.)/nel)*J0 H0 = h + Vfa eold = 0 for iter in range(maxiter): Hoepa = get_Hoep(ba,H0,Gij) Hoepb = get_Hoep(ba,H0,Gij) orbea,orbsa = geigh(Hoepa,S) orbeb,orbsb = geigh(Hoepb,S) if ETemp: efermia = get_efermi(2*nalpha,orbea,ETemp) occsa = get_fermi_occs(efermia,orbea,ETemp) Da = mkdens_occs(orbsa,occsa) efermib = get_efermi(2*nbeta,orbeb,ETemp) occsb = get_fermi_occs(efermib,orbeb,ETemp) Db = mkdens_occs(orbsb,occsb) entropy = 0.5*(get_entropy(occsa,ETemp)+get_entropy(occsb,ETemp)) else: Da = mkdens(orbsa,0,nalpha) Db = mkdens(orbsb,0,nbeta) J = getJ(Ints,Da) + getJ(Ints,Db) Ka = getK(Ints,Da) Kb = getK(Ints,Db) energy = (trace2(2*h+J-Ka,Da)+trace2(2*h+J-Kb,Db))/2\ +Enuke if ETemp: energy += entropy if abs(energy-eold) < tol: break else: eold = energy logging.debug("OEP AN Opt: %d %f" % (iter,energy)) # Do alpha and beta separately # Alphas dV_ao = J-Ka-Vfa dV = matrixmultiply(orbsa,matrixmultiply(dV_ao,transpose(orbsa))) X = zeros((nbf,nbf),'d') c = zeros(nbf,'d') for k in range(nbf): Gk = matrixmultiply(orbsa,matrixmultiply(Gij[k], transpose(orbsa))) for i in range(nalpha): for a in range(nalpha,norb): c[k] += dV[i,a]*Gk[i,a]/(orbea[i]-orbea[a]) for l in range(nbf): Gl = matrixmultiply(orbsa,matrixmultiply(Gij[l], transpose(orbsa))) for i in range(nalpha): for a in range(nalpha,norb): X[k,l] += Gk[i,a]*Gl[i,a]/(orbea[i]-orbea[a]) # This should actually be a pseudoinverse... ba = solve(X,c) # Betas dV_ao = J-Kb-Vfa dV = matrixmultiply(orbsb,matrixmultiply(dV_ao,transpose(orbsb))) X = zeros((nbf,nbf),'d') c = zeros(nbf,'d') for k in range(nbf): Gk = matrixmultiply(orbsb,matrixmultiply(Gij[k], transpose(orbsb))) for i in range(nbeta): for a in range(nbeta,norb): c[k] += dV[i,a]*Gk[i,a]/(orbeb[i]-orbeb[a]) for l in range(nbf): Gl = matrixmultiply(orbsb,matrixmultiply(Gij[l], transpose(orbsb))) for i in range(nbeta): for a in range(nbeta,norb): X[k,l] += Gk[i,a]*Gl[i,a]/(orbeb[i]-orbeb[a]) # This should actually be a pseudoinverse... bb = solve(X,c) logging.info("Final OEP energy = %f" % energy) return energy,(orbea,orbeb),(orbsa,orbsb)
def oep_hf_an(atoms,orbs,**opts): """oep_hf - Form the optimized effective potential for HF exchange. Implementation of Wu and Yang's Approximate Newton Scheme from J. Theor. Comp. Chem. 2, 627 (2003). oep_hf(atoms,orbs,**opts) atoms A Molecule object containing a list of the atoms orbs A matrix of guess orbitals Options ------- bfs None The basis functions to use for the wfn pbfs None The basis functions to use for the pot basis_data None The basis data to use to construct bfs integrals None The one- and two-electron integrals to use If not None, S,h,Ints """ maxiter = opts.get('maxiter',100) tol = opts.get('tol',1e-5) bfs = opts.get('bfs',None) if not bfs: basis = opts.get('basis',None) bfs = getbasis(atoms,basis) # The basis set for the potential can be set different from # that used for the wave function pbfs = opts.get('pbfs',None) if not pbfs: pbfs = bfs npbf = len(pbfs) integrals = opts.get('integrals',None) if integrals: S,h,Ints = integrals else: S,h,Ints = getints(bfs,atoms) nel = atoms.get_nel() nocc,nopen = atoms.get_closedopen() Enuke = atoms.get_enuke() # Form the OEP using Yang/Wu, PRL 89 143002 (2002) nbf = len(bfs) norb = nbf bp = zeros(nbf,'d') bvec = opts.get('bvec',None) if bvec: assert len(bvec) == npbf b = array(bvec) else: b = zeros(npbf,'d') # Form and store all of the three-center integrals # we're going to need. # These are <ibf|gbf|jbf> (where 'bf' indicates basis func, # as opposed to MO) # N^3 storage -- obviously you don't want to do this for # very large systems Gij = [] for g in range(npbf): gmat = zeros((nbf,nbf),'d') Gij.append(gmat) gbf = pbfs[g] for i in range(nbf): ibf = bfs[i] for j in range(i+1): jbf = bfs[j] gij = three_center(ibf,gbf,jbf) gmat[i,j] = gij gmat[j,i] = gij # Compute the Fermi-Amaldi potential based on the LDA density. # We're going to form this matrix from the Coulombic matrix that # arises from the input orbitals. D0 and J0 refer to the density # matrix and corresponding Coulomb matrix D0 = mkdens(orbs,0,nocc) J0 = getJ(Ints,D0) Vfa = (2*(nel-1.)/nel)*J0 H0 = h + Vfa b = zeros(nbf,'d') eold = 0 for iter in range(maxiter): Hoep = get_Hoep(b,H0,Gij) orbe,orbs = geigh(Hoep,S) D = mkdens(orbs,0,nocc) Vhf = get2JmK(Ints,D) energy = trace2(2*h+Vhf,D)+Enuke if abs(energy-eold) < tol: break else: eold = energy logging.debug("OEP AN Opt: %d %f" % (iter,energy)) dV_ao = Vhf-Vfa dV = matrixmultiply(transpose(orbs),matrixmultiply(dV_ao,orbs)) X = zeros((nbf,nbf),'d') c = zeros(nbf,'d') Gkt = zeros((nbf,nbf),'d') for k in range(nbf): # This didn't work; in fact, it made things worse: Gk = matrixmultiply(transpose(orbs),matrixmultiply(Gij[k],orbs)) for i in range(nocc): for a in range(nocc,norb): c[k] += dV[i,a]*Gk[i,a]/(orbe[i]-orbe[a]) for l in range(nbf): Gl = matrixmultiply(transpose(orbs),matrixmultiply(Gij[l],orbs)) for i in range(nocc): for a in range(nocc,norb): X[k,l] += Gk[i,a]*Gl[i,a]/(orbe[i]-orbe[a]) # This should actually be a pseudoinverse... b = solve(X,c) logging.info("Final OEP energy = %f" % energy) return energy,orbe,orbs
def oep(atoms,orbs,energy_func,grad_func=None,**opts): """oep - Form the optimized effective potential for a given energy expression oep(atoms,orbs,energy_func,grad_func=None,**opts) atoms A Molecule object containing a list of the atoms orbs A matrix of guess orbitals energy_func The function that returns the energy for the given method grad_func The function that returns the force for the given method Options ------- verbose False Output terse information to stdout (default) True Print out additional information ETemp False Use ETemp value for finite temperature DFT (default) float Use (float) for the electron temperature bfs None The basis functions to use. List of CGBF's basis_data None The basis data to use to construct bfs integrals None The one- and two-electron integrals to use If not None, S,h,Ints """ verbose = opts.get('verbose',False) ETemp = opts.get('ETemp',False) opt_method = opts.get('opt_method','BFGS') bfs = opts.get('bfs',None) if not bfs: basis = opts.get('basis',None) bfs = getbasis(atoms,basis) # The basis set for the potential can be set different from # that used for the wave function pbfs = opts.get('pbfs',None) if not pbfs: pbfs = bfs npbf = len(pbfs) integrals = opts.get('integrals',None) if integrals: S,h,Ints = integrals else: S,h,Ints = getints(bfs,atoms) nel = atoms.get_nel() nocc,nopen = atoms.get_closedopen() Enuke = atoms.get_enuke() # Form the OEP using Yang/Wu, PRL 89 143002 (2002) nbf = len(bfs) norb = nbf bp = zeros(nbf,'d') bvec = opts.get('bvec',None) if bvec: assert len(bvec) == npbf b = array(bvec) else: b = zeros(npbf,'d') # Form and store all of the three-center integrals # we're going to need. # These are <ibf|gbf|jbf> (where 'bf' indicates basis func, # as opposed to MO) # N^3 storage -- obviously you don't want to do this for # very large systems Gij = [] for g in range(npbf): gmat = zeros((nbf,nbf),'d') Gij.append(gmat) gbf = pbfs[g] for i in range(nbf): ibf = bfs[i] for j in range(i+1): jbf = bfs[j] gij = three_center(ibf,gbf,jbf) gmat[i,j] = gij gmat[j,i] = gij # Compute the Fermi-Amaldi potential based on the LDA density. # We're going to form this matrix from the Coulombic matrix that # arises from the input orbitals. D0 and J0 refer to the density # matrix and corresponding Coulomb matrix D0 = mkdens(orbs,0,nocc) J0 = getJ(Ints,D0) Vfa = (2*(nel-1.)/nel)*J0 H0 = h + Vfa b = fminBFGS(energy_func,b,grad_func, (nbf,nel,nocc,ETemp,Enuke,S,h,Ints,H0,Gij), logger=logging) energy,orbe,orbs = energy_func(b,nbf,nel,nocc,ETemp,Enuke, S,h,Ints,H0,Gij,return_flag=1) return energy,orbe,orbs
def rohf(atoms,**opts): """\ rohf(atoms,**opts) - Restriced Open Shell Hartree Fock atoms A Molecule object containing the molecule """ ConvCriteria = opts.get('ConvCriteria',1e-5) MaxIter = opts.get('MaxIter',40) DoAveraging = opts.get('DoAveraging',True) averaging = opts.get('averaging',0.95) verbose = opts.get('verbose',True) bfs = opts.get('bfs',None) if not bfs: basis_data = opts.get('basis_data',None) bfs = getbasis(atoms,basis_data) nbf = len(bfs) integrals = opts.get('integrals', None) if integrals: S,h,Ints = integrals else: S,h,Ints = getints(bfs,atoms) nel = atoms.get_nel() nalpha,nbeta = atoms.get_alphabeta() S,h,Ints = getints(bfs,atoms) orbs = opts.get('orbs',None) if orbs is None: orbe,orbs = geigh(h,S) norbs = nbf enuke = atoms.get_enuke() eold = 0. if verbose: print "ROHF calculation on %s" % atoms.name if verbose: print "Nbf = %d" % nbf if verbose: print "Nalpha = %d" % nalpha if verbose: print "Nbeta = %d" % nbeta if verbose: print "Averaging = %s" % DoAveraging print "Optimization of HF orbitals" for i in xrange(MaxIter): if verbose: print "SCF Iteration:",i,"Starting Energy:",eold Da = mkdens(orbs,0,nalpha) Db = mkdens(orbs,0,nbeta) if DoAveraging: if i: Da = averaging*Da + (1-averaging)*Da0 Db = averaging*Db + (1-averaging)*Db0 Da0 = Da Db0 = Db Ja = getJ(Ints,Da) Jb = getJ(Ints,Db) Ka = getK(Ints,Da) Kb = getK(Ints,Db) Fa = h+Ja+Jb-Ka Fb = h+Ja+Jb-Kb energya = get_energy(h,Fa,Da) energyb = get_energy(h,Fb,Db) eone = (trace2(Da,h) + trace2(Db,h))/2 etwo = (trace2(Da,Fa) + trace2(Db,Fb))/2 energy = (energya+energyb)/2 + enuke print i,energy,eone,etwo,enuke if abs(energy-eold) < ConvCriteria: break eold = energy Fa = ao2mo(Fa,orbs) Fb = ao2mo(Fb,orbs) # Building the approximate Fock matrices in the MO basis F = 0.5*(Fa+Fb) K = Fb-Fa # The Fock matrix now looks like # F-K | F + K/2 | F # --------------------------------- # F + K/2 | F | F - K/2 # --------------------------------- # F | F - K/2 | F + K # Make explicit slice objects to simplify this do = slice(0,nbeta) so = slice(nbeta,nalpha) uo = slice(nalpha,norbs) F[do,do] -= K[do,do] F[uo,uo] += K[uo,uo] F[do,so] += 0.5*K[do,so] F[so,do] += 0.5*K[so,do] F[so,uo] -= 0.5*K[so,uo] F[uo,so] -= 0.5*K[uo,so] orbe,mo_orbs = eigh(F) orbs = matrixmultiply(orbs,mo_orbs) if verbose: print "Final ROHF energy for system %s is %f" % (atoms.name,energy) return energy,orbe,orbs
def oep(atoms, orbs, energy_func, grad_func=None, **opts): """oep - Form the optimized effective potential for a given energy expression oep(atoms,orbs,energy_func,grad_func=None,**opts) atoms A Molecule object containing a list of the atoms orbs A matrix of guess orbitals energy_func The function that returns the energy for the given method grad_func The function that returns the force for the given method Options ------- verbose False Output terse information to stdout (default) True Print out additional information ETemp False Use ETemp value for finite temperature DFT (default) float Use (float) for the electron temperature bfs None The basis functions to use. List of CGBF's basis_data None The basis data to use to construct bfs integrals None The one- and two-electron integrals to use If not None, S,h,Ints """ verbose = opts.get('verbose', False) ETemp = opts.get('ETemp', False) opt_method = opts.get('opt_method', 'BFGS') bfs = opts.get('bfs', None) if not bfs: basis = opts.get('basis', None) bfs = getbasis(atoms, basis) # The basis set for the potential can be set different from # that used for the wave function pbfs = opts.get('pbfs', None) if not pbfs: pbfs = bfs npbf = len(pbfs) integrals = opts.get('integrals', None) if integrals: S, h, Ints = integrals else: S, h, Ints = getints(bfs, atoms) nel = atoms.get_nel() nocc, nopen = atoms.get_closedopen() Enuke = atoms.get_enuke() # Form the OEP using Yang/Wu, PRL 89 143002 (2002) nbf = len(bfs) norb = nbf bp = zeros(nbf, 'd') bvec = opts.get('bvec', None) if bvec: assert len(bvec) == npbf b = array(bvec) else: b = zeros(npbf, 'd') # Form and store all of the three-center integrals # we're going to need. # These are <ibf|gbf|jbf> (where 'bf' indicates basis func, # as opposed to MO) # N^3 storage -- obviously you don't want to do this for # very large systems Gij = [] for g in xrange(npbf): gmat = zeros((nbf, nbf), 'd') Gij.append(gmat) gbf = pbfs[g] for i in xrange(nbf): ibf = bfs[i] for j in xrange(i + 1): jbf = bfs[j] gij = three_center(ibf, gbf, jbf) gmat[i, j] = gij gmat[j, i] = gij # Compute the Fermi-Amaldi potential based on the LDA density. # We're going to form this matrix from the Coulombic matrix that # arises from the input orbitals. D0 and J0 refer to the density # matrix and corresponding Coulomb matrix D0 = mkdens(orbs, 0, nocc) J0 = getJ(Ints, D0) Vfa = (2 * (nel - 1.) / nel) * J0 H0 = h + Vfa b = fminBFGS(energy_func, b, grad_func, (nbf, nel, nocc, ETemp, Enuke, S, h, Ints, H0, Gij), logger=logging) energy, orbe, orbs = energy_func(b, nbf, nel, nocc, ETemp, Enuke, S, h, Ints, H0, Gij, return_flag=1) return energy, orbe, orbs
def H2O_Molecule(tst,info,auX,auZ): H2O = Molecule('H2O', [('O', ( 0.0, 0.0, 0.0)), ('H', ( auX, 0.0, auZ)), ('H', (-auX, 0.0, auZ))], units='Bohr') # Get a better energy estimate if dft: print "# info=%s A.U.=(%g,%g) " % (info,auX,auZ) edft,orbe2,orbs2 = dft(H2O,functional='SVWN') bfs= getbasis(H2O,basis_data=basis_data) #S is overlap of 2 basis funcs #h is (kinetic+nucl) 1 body term #ints is 2 body terms S,h,ints=getints(bfs,H2O) #enhf is the Hartee-Fock energy #orbe is the orbital energies #orbs is the orbital overlaps enhf,orbe,orbs=rhf(H2O,integrals=(S,h,ints)) enuke = Molecule.get_enuke(H2O) # print "orbe=%d" % len(orbe) temp = matrixmultiply(h,orbs) hmol = matrixmultiply(transpose(orbs),temp) MOInts = TransformInts(ints,orbs) if single: print "h = \n",h print "S = \n",S print "ints = \n",ints print "orbe = \n",orbe print "orbs = \n",orbs print "" print "Index 0: 1 or 2 in the paper, Index 1: 3 or 4 in the paper (for pqrs)" print "" print "hmol = \n",hmol print "MOInts:" print "I,J,K,L = PQRS order: Cre1,Cre2,Ann1,Ann2" if 1: print "tst=%d info=%s nuc=%.9f Ehf=%.9f" % (tst,info,enuke,enhf), cntOrbs = 0 maxOrb = 0 npts = len(hmol[:]) for i in xrange(npts): for j in range(i,npts): if abs(hmol[i,j]) > 1.0e-7: print "%d,%d=%.9f" % (i,j,hmol[i,j]), cntOrbs += 1 if i > maxOrb: maxOrb = i if j > maxOrb: maxOrb = j nbf,nmo = orbs.shape mos = range(nmo) for i in mos: for j in xrange(i+1): ij = i*(i+1)/2+j for k in mos: for l in xrange(k+1): kl = k*(k+1)/2+l if ij >= kl: ijkl = ijkl2intindex(i,j,k,l) if abs(MOInts[ijkl]) > 1.0e-7: print "%d,%d,%d,%d=%.9f" % (l,i,j,k,MOInts[ijkl]), cntOrbs += 1 if i > maxOrb: maxOrb = i if j > maxOrb: maxOrb = j print "" return (maxOrb,cntOrbs)
def rohf(atoms, **kwargs): """\ rohf(atoms,**kwargs) - Restriced Open Shell Hartree Fock atoms A Molecule object containing the molecule """ ConvCriteria = kwargs.get('ConvCriteria', settings.ConvergenceCriteria) MaxIter = kwargs.get('MaxIter', settings.MaxIter) DoAveraging = kwargs.get('DoAveraging', settings.Averaging) averaging = kwargs.get('averaging', settings.MixingFraction) verbose = kwargs.get('verbose') bfs = getbasis(atoms, **kwargs) nbf = len(bfs) S, h, Ints = getints(bfs, atoms, **kwargs) nel = atoms.get_nel() nalpha, nbeta = atoms.get_alphabeta() orbs = kwargs.get('orbs') if orbs is None: orbe, orbs = geigh(h, S) norbs = nbf enuke = atoms.get_enuke() eold = 0. if verbose: print "ROHF calculation on %s" % atoms.name if verbose: print "Nbf = %d" % nbf if verbose: print "Nalpha = %d" % nalpha if verbose: print "Nbeta = %d" % nbeta if verbose: print "Averaging = %s" % DoAveraging print "Optimization of HF orbitals" for i in xrange(MaxIter): if verbose: print "SCF Iteration:", i, "Starting Energy:", eold Da = mkdens(orbs, 0, nalpha) Db = mkdens(orbs, 0, nbeta) if DoAveraging: if i: Da = averaging * Da + (1 - averaging) * Da0 Db = averaging * Db + (1 - averaging) * Db0 Da0 = Da Db0 = Db Ja = getJ(Ints, Da) Jb = getJ(Ints, Db) Ka = getK(Ints, Da) Kb = getK(Ints, Db) Fa = h + Ja + Jb - Ka Fb = h + Ja + Jb - Kb energya = get_energy(h, Fa, Da) energyb = get_energy(h, Fb, Db) eone = (trace2(Da, h) + trace2(Db, h)) / 2 etwo = (trace2(Da, Fa) + trace2(Db, Fb)) / 2 energy = (energya + energyb) / 2 + enuke print i, energy, eone, etwo, enuke if abs(energy - eold) < ConvCriteria: break eold = energy Fa = ao2mo(Fa, orbs) Fb = ao2mo(Fb, orbs) # Building the approximate Fock matrices in the MO basis F = 0.5 * (Fa + Fb) K = Fb - Fa # The Fock matrix now looks like # F-K | F + K/2 | F # --------------------------------- # F + K/2 | F | F - K/2 # --------------------------------- # F | F - K/2 | F + K # Make explicit slice objects to simplify this do = slice(0, nbeta) so = slice(nbeta, nalpha) uo = slice(nalpha, norbs) F[do, do] -= K[do, do] F[uo, uo] += K[uo, uo] F[do, so] += 0.5 * K[do, so] F[so, do] += 0.5 * K[so, do] F[so, uo] -= 0.5 * K[so, uo] F[uo, so] -= 0.5 * K[uo, so] orbe, mo_orbs = eigh(F) orbs = matrixmultiply(orbs, mo_orbs) if verbose: print "Final ROHF energy for system %s is %f" % (atoms.name, energy) return energy, orbe, orbs
def oep_uhf_an(atoms, orbsa, orbsb, **kwargs): """oep_hf - Form the optimized effective potential for HF exchange. Implementation of Wu and Yang's Approximate Newton Scheme from J. Theor. Comp. Chem. 2, 627 (2003). oep_uhf(atoms,orbs,**kwargs) atoms A Molecule object containing a list of the atoms orbs A matrix of guess orbitals Options ------- bfs None The basis functions to use for the wfn pbfs None The basis functions to use for the pot basis_data None The basis data to use to construct bfs integrals None The one- and two-electron integrals to use If not None, S,h,Ints """ maxiter = kwargs.get('maxiter', settings.OEPIters) tol = kwargs.get('tol', settings.OEPTolerance) ETemp = kwargs.get('ETemp', settings.DFTElectronTemperature) bfs = getbasis(atoms, **kwargs) # The basis set for the potential can be set different from # that used for the wave function pbfs = kwargs.get('pbfs') if not pbfs: pbfs = bfs npbf = len(pbfs) S, h, Ints = getints(bfs, atoms, **kwargs) nel = atoms.get_nel() nclosed, nopen = atoms.get_closedopen() nalpha, nbeta = nclosed + nopen, nclosed Enuke = atoms.get_enuke() # Form the OEP using Yang/Wu, PRL 89 143002 (2002) nbf = len(bfs) norb = nbf ba = zeros(npbf, 'd') bb = zeros(npbf, 'd') # Form and store all of the three-center integrals # we're going to need. # These are <ibf|gbf|jbf> (where 'bf' indicates basis func, # as opposed to MO) # N^3 storage -- obviously you don't want to do this for # very large systems Gij = [] for g in xrange(npbf): gmat = zeros((nbf, nbf), 'd') Gij.append(gmat) gbf = pbfs[g] for i in xrange(nbf): ibf = bfs[i] for j in xrange(i + 1): jbf = bfs[j] gij = three_center(ibf, gbf, jbf) gmat[i, j] = gij gmat[j, i] = gij # Compute the Fermi-Amaldi potential based on the LDA density. # We're going to form this matrix from the Coulombic matrix that # arises from the input orbitals. D0 and J0 refer to the density # matrix and corresponding Coulomb matrix D0 = mkdens(orbsa, 0, nalpha) + mkdens(orbsb, 0, nbeta) J0 = getJ(Ints, D0) Vfa = ((nel - 1.) / nel) * J0 H0 = h + Vfa eold = 0 for iter in xrange(maxiter): Hoepa = get_Hoep(ba, H0, Gij) Hoepb = get_Hoep(ba, H0, Gij) orbea, orbsa = geigh(Hoepa, S) orbeb, orbsb = geigh(Hoepb, S) if ETemp: efermia = get_efermi(2 * nalpha, orbea, ETemp) occsa = get_fermi_occs(efermia, orbea, ETemp) Da = mkdens_occs(orbsa, occsa) efermib = get_efermi(2 * nbeta, orbeb, ETemp) occsb = get_fermi_occs(efermib, orbeb, ETemp) Db = mkdens_occs(orbsb, occsb) entropy = 0.5 * (get_entropy(occsa, ETemp) + get_entropy(occsb, ETemp)) else: Da = mkdens(orbsa, 0, nalpha) Db = mkdens(orbsb, 0, nbeta) J = getJ(Ints, Da) + getJ(Ints, Db) Ka = getK(Ints, Da) Kb = getK(Ints, Db) energy = (trace2(2*h+J-Ka,Da)+trace2(2*h+J-Kb,Db))/2\ +Enuke if ETemp: energy += entropy if abs(energy - eold) < tol: break else: eold = energy logging.debug("OEP AN Opt: %d %f" % (iter, energy)) # Do alpha and beta separately # Alphas dV_ao = J - Ka - Vfa dV = matrixmultiply(orbsa, matrixmultiply(dV_ao, transpose(orbsa))) X = zeros((nbf, nbf), 'd') c = zeros(nbf, 'd') for k in xrange(nbf): Gk = matrixmultiply(orbsa, matrixmultiply(Gij[k], transpose(orbsa))) for i in xrange(nalpha): for a in xrange(nalpha, norb): c[k] += dV[i, a] * Gk[i, a] / (orbea[i] - orbea[a]) for l in xrange(nbf): Gl = matrixmultiply(orbsa, matrixmultiply(Gij[l], transpose(orbsa))) for i in xrange(nalpha): for a in xrange(nalpha, norb): X[k, l] += Gk[i, a] * Gl[i, a] / (orbea[i] - orbea[a]) # This should actually be a pseudoinverse... ba = solve(X, c) # Betas dV_ao = J - Kb - Vfa dV = matrixmultiply(orbsb, matrixmultiply(dV_ao, transpose(orbsb))) X = zeros((nbf, nbf), 'd') c = zeros(nbf, 'd') for k in xrange(nbf): Gk = matrixmultiply(orbsb, matrixmultiply(Gij[k], transpose(orbsb))) for i in xrange(nbeta): for a in xrange(nbeta, norb): c[k] += dV[i, a] * Gk[i, a] / (orbeb[i] - orbeb[a]) for l in xrange(nbf): Gl = matrixmultiply(orbsb, matrixmultiply(Gij[l], transpose(orbsb))) for i in xrange(nbeta): for a in xrange(nbeta, norb): X[k, l] += Gk[i, a] * Gl[i, a] / (orbeb[i] - orbeb[a]) # This should actually be a pseudoinverse... bb = solve(X, c) logger.info("Final OEP energy = %f" % energy) return energy, (orbea, orbeb), (orbsa, orbsb)
def oep_hf_an(atoms, orbs, **kwargs): """oep_hf - Form the optimized effective potential for HF exchange. Implementation of Wu and Yang's Approximate Newton Scheme from J. Theor. Comp. Chem. 2, 627 (2003). oep_hf(atoms,orbs,**kwargs) atoms A Molecule object containing a list of the atoms orbs A matrix of guess orbitals Options ------- bfs None The basis functions to use for the wfn pbfs None The basis functions to use for the pot basis_data None The basis data to use to construct bfs integrals None The one- and two-electron integrals to use If not None, S,h,Ints """ maxiter = kwargs.get('maxiter', settings.OEPIters) tol = kwargs.get('tol', settings.OEPTolerance) bfs = getbasis(atoms, **kwargs) # The basis set for the potential can be set different from # that used for the wave function pbfs = kwargs.get('pbfs') if not pbfs: pbfs = bfs npbf = len(pbfs) S, h, Ints = getints(bfs, atoms) nel = atoms.get_nel() nocc, nopen = atoms.get_closedopen() Enuke = atoms.get_enuke() # Form the OEP using Yang/Wu, PRL 89 143002 (2002) nbf = len(bfs) norb = nbf bp = zeros(nbf, 'd') bvec = kwargs.get('bvec') if bvec: assert len(bvec) == npbf b = array(bvec) else: b = zeros(npbf, 'd') # Form and store all of the three-center integrals # we're going to need. # These are <ibf|gbf|jbf> (where 'bf' indicates basis func, # as opposed to MO) # N^3 storage -- obviously you don't want to do this for # very large systems Gij = [] for g in xrange(npbf): gmat = zeros((nbf, nbf), 'd') Gij.append(gmat) gbf = pbfs[g] for i in xrange(nbf): ibf = bfs[i] for j in xrange(i + 1): jbf = bfs[j] gij = three_center(ibf, gbf, jbf) gmat[i, j] = gij gmat[j, i] = gij # Compute the Fermi-Amaldi potential based on the LDA density. # We're going to form this matrix from the Coulombic matrix that # arises from the input orbitals. D0 and J0 refer to the density # matrix and corresponding Coulomb matrix D0 = mkdens(orbs, 0, nocc) J0 = getJ(Ints, D0) Vfa = (2 * (nel - 1.) / nel) * J0 H0 = h + Vfa b = zeros(nbf, 'd') eold = 0 for iter in xrange(maxiter): Hoep = get_Hoep(b, H0, Gij) orbe, orbs = geigh(Hoep, S) D = mkdens(orbs, 0, nocc) Vhf = get2JmK(Ints, D) energy = trace2(2 * h + Vhf, D) + Enuke if abs(energy - eold) < tol: break else: eold = energy logging.debug("OEP AN Opt: %d %f" % (iter, energy)) dV_ao = Vhf - Vfa dV = matrixmultiply(transpose(orbs), matrixmultiply(dV_ao, orbs)) X = zeros((nbf, nbf), 'd') c = zeros(nbf, 'd') Gkt = zeros((nbf, nbf), 'd') for k in xrange(nbf): # This didn't work; in fact, it made things worse: Gk = matrixmultiply(transpose(orbs), matrixmultiply(Gij[k], orbs)) for i in xrange(nocc): for a in xrange(nocc, norb): c[k] += dV[i, a] * Gk[i, a] / (orbe[i] - orbe[a]) for l in xrange(nbf): Gl = matrixmultiply(transpose(orbs), matrixmultiply(Gij[l], orbs)) for i in xrange(nocc): for a in xrange(nocc, norb): X[k, l] += Gk[i, a] * Gl[i, a] / (orbe[i] - orbe[a]) # This should actually be a pseudoinverse... b = solve(X, c) logger.info("Final OEP energy = %f" % energy) return energy, orbe, orbs
print "%d %f" % (i,energy) if abs(energy-eold) < 1e-4: break eold = energy print "Final HF energy for system %s is %f" % (atoms.name,energy) return energy,orbe,orbs # Data Li_x1 = -0.200966 H_x1 = 1.399033 Li_x2 = -0.351691 H_x2 = 2.448309 # Construct a molecule: LiH1 = Molecule('LiH1',[('Li',(Li_x1,0,0)),('H',(H_x1,0,0))],units='Angs') bfs1 = getbasis(LiH1) S1,h1,Ints1 = getints(bfs1,LiH1) simple_hf(LiH1,S1,h1,Ints1) # Make another molecule LiH2 = Molecule('LiH2',[('Li',(Li_x2,0,0)),('H',(H_x2,0,0))],units='Angs') bfs2 = getbasis(LiH2) S2,h2,Ints2 = getints(bfs2,LiH2) simple_hf(LiH2,S2,h2,Ints2) # Make a superset of the two basis sets: bfs_big = bfs1 + bfs2 # and make a basis set with it: S1a,h1a,Ints1a = getints(bfs_big,LiH1) simple_hf(LiH1,S1a,h1a,Ints1a) # The energy is slightly lower, which shows the additional functions are
def __init__(self,molecule,basis_set,**kwargs): from PyQuante.Ints import getints integrals = kwargs.get("integrals") nbf = len(basis_set) self.S, self.h, self.ERI = getints(basis_set.get(),molecule,**kwargs) return
eold = energy print "Final HF energy for system %s is %f" % (atoms.name, energy) return energy, orbe, orbs # Data Li_x1 = -0.200966 H_x1 = 1.399033 Li_x2 = -0.351691 H_x2 = 2.448309 # Construct a molecule: LiH1 = Molecule('LiH1', [('Li', (Li_x1, 0, 0)), ('H', (H_x1, 0, 0))], units='Angs') bfs1 = getbasis(LiH1) S1, h1, Ints1 = getints(bfs1, LiH1) simple_hf(LiH1, S1, h1, Ints1) # Make another molecule LiH2 = Molecule('LiH2', [('Li', (Li_x2, 0, 0)), ('H', (H_x2, 0, 0))], units='Angs') bfs2 = getbasis(LiH2) S2, h2, Ints2 = getints(bfs2, LiH2) simple_hf(LiH2, S2, h2, Ints2) # Make a superset of the two basis sets: bfs_big = bfs1 + bfs2 # and make a basis set with it: S1a, h1a, Ints1a = getints(bfs_big, LiH1) simple_hf(LiH1, S1a, h1a, Ints1a) # The energy is slightly lower, which shows the additional functions are