def get_energy(self, b): self.iter += 1 ba = b[:self.nbf] bb = b[self.nbf:] self.Hoepa = get_Hoep(ba, self.H0, self.Gij) self.Hoepb = get_Hoep(bb, self.H0, self.Gij) self.orbea, self.orbsa = geigh(self.Hoepa, self.S) self.orbeb, self.orbsb = geigh(self.Hoepb, self.S) if self.etemp: self.Da, entropya = mkdens_fermi(2 * self.nalpha, self.orbea, self.orbsa, self.etemp) self.Db, entropyb = mkdens_fermi(2 * self.nbeta, self.orbeb, self.orbsb, self.etemp) self.entropy = 0.5 * (entropya + entropyb) else: self.Da = mkdens(self.orbsa, 0, self.nalpha) self.Db = mkdens(self.orbsb, 0, self.nbeta) self.entropy = 0 J = getJ(self.Ints, self.Da + self.Db) Ka = getK(self.Ints, self.Da) Kb = getK(self.Ints, self.Db) self.Fa = self.h + J - Ka self.Fb = self.h + J - Kb self.energy = 0.5*(trace2(self.h+self.Fa,self.Da) + trace2(self.h+self.Fb,self.Db))\ + self.Enuke + self.entropy if self.iter == 1 or self.iter % 10 == 0: logging.debug("%4d %10.5f %10.5f" % (self.iter, self.energy, dot(b, b))) return self.energy
def update_density(self): from PyQuante.LA2 import mkdens if self.start: self.start = False else: self.Da = mkdens(self.orbsa, 0, self.nalpha) self.Db = mkdens(self.orbsb, 0, self.nbeta)
def update_density(self): from PyQuante.LA2 import mkdens if self.start: self.start = False else: self.Da = mkdens(self.orbsa,0,self.nalpha) self.Db = mkdens(self.orbsb,0,self.nbeta)
def get_energy(self,b): self.iter += 1 ba = b[:self.nbf] bb = b[self.nbf:] self.Hoepa = get_Hoep(ba,self.H0,self.Gij) self.Hoepb = get_Hoep(bb,self.H0,self.Gij) self.orbea,self.orbsa = geigh(self.Hoepa,self.S) self.orbeb,self.orbsb = geigh(self.Hoepb,self.S) if self.etemp: self.Da,entropya = mkdens_fermi(2*self.nalpha,self.orbea,self.orbsa, self.etemp) self.Db,entropyb = mkdens_fermi(2*self.nbeta,self.orbeb,self.orbsb, self.etemp) self.entropy = 0.5*(entropya+entropyb) else: self.Da = mkdens(self.orbsa,0,self.nalpha) self.Db = mkdens(self.orbsb,0,self.nbeta) self.entropy=0 J = getJ(self.Ints,self.Da+self.Db) Ka = getK(self.Ints,self.Da) Kb = getK(self.Ints,self.Db) self.Fa = self.h + J - Ka self.Fb = self.h + J - Kb self.energy = 0.5*(trace2(self.h+self.Fa,self.Da) + trace2(self.h+self.Fb,self.Db))\ + self.Enuke + self.entropy if self.iter == 1 or self.iter % 10 == 0: logging.debug("%4d %10.5f %10.5f" % (self.iter,self.energy,dot(b,b))) return self.energy
def update(self, **kwargs): from PyQuante.Ints import getJ, getK from PyQuante.LA2 import geigh, mkdens from PyQuante.rohf import ao2mo from PyQuante.hartree_fock import get_energy from PyQuante.NumWrap import eigh, matrixmultiply if self.orbs is None: self.orbe, self.orbs = geigh(self.h, self.S) Da = mkdens(self.orbs, 0, self.nalpha) Db = mkdens(self.orbs, 0, self.nbeta) Ja = getJ(self.ERI, Da) Jb = getJ(self.ERI, Db) Ka = getK(self.ERI, Da) Kb = getK(self.ERI, Db) Fa = self.h + Ja + Jb - Ka Fb = self.h + Ja + Jb - Kb energya = get_energy(self.h, Fa, Da) energyb = get_energy(self.h, Fb, Db) self.energy = (energya + energyb) / 2 + self.Enuke Fa = ao2mo(Fa, self.orbs) Fb = ao2mo(Fb, self.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, self.nbeta) so = slice(self.nbeta, self.nalpha) uo = slice(self.nalpha, self.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] self.orbe, mo_orbs = eigh(F) self.orbs = matrixmultiply(self.orbs, mo_orbs) return
def update(self,**opts): from PyQuante.Ints import getJ,getK from PyQuante.LA2 import geigh,mkdens from PyQuante.rohf import ao2mo from PyQuante.hartree_fock import get_energy from PyQuante.NumWrap import eigh,matrixmultiply if self.orbs is None: self.orbe,self.orbs = geigh(self.h, self.S) Da = mkdens(self.orbs,0,self.nalpha) Db = mkdens(self.orbs,0,self.nbeta) Ja = getJ(self.ERI,Da) Jb = getJ(self.ERI,Db) Ka = getK(self.ERI,Da) Kb = getK(self.ERI,Db) Fa = self.h+Ja+Jb-Ka Fb = self.h+Ja+Jb-Kb energya = get_energy(self.h,Fa,Da) energyb = get_energy(self.h,Fb,Db) self.energy = (energya+energyb)/2 + self.Enuke Fa = ao2mo(Fa,self.orbs) Fb = ao2mo(Fb,self.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,self.nbeta) so = slice(self.nbeta,self.nalpha) uo = slice(self.nalpha,self.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] self.orbe,mo_orbs = eigh(F) self.orbs = matrixmultiply(self.orbs,mo_orbs) return
def test_mol(mol,**opts): basis_data = opts.get('basis_data',None) do_python_tests = opts.get('do_python_tests',True) make_hf_driver(mol,basis_data=basis_data) if do_python_tests: bfs = getbasis(mol,basis_data) S= getS(bfs) T = getT(bfs) V = getV(bfs,mol) Ints = get2ints(bfs) nclosed,nopen = mol.get_closedopen() enuke = mol.get_enuke() assert nopen==0 h = T+V orbe,orbs = GHeigenvectors(h,S) print "Eval of h: ", print orbe for i in range(10): D = mkdens(orbs,0,nclosed) J = getJ(Ints,D) K = getK(Ints,D) orbe,orbs = GHeigenvectors(h+2*J-K,S) eone = TraceProperty(D,h) ej = TraceProperty(D,J) ek = TraceProperty(D,K) energy = enuke+2*eone+2*ej-ek print i,energy,enuke,eone,ej,ek return
def __init__(self, solver): # Solver is a pointer to a HF or a DFT calculation that has # already converged self.solver = solver self.bfs = self.solver.bfs self.nbf = len(self.bfs) self.S = self.solver.S self.h = self.solver.h self.Ints = self.solver.Ints self.molecule = self.solver.molecule self.nel = self.molecule.get_nel() self.nclosed, self.nopen = self.molecule.get_closedopen() self.Enuke = self.molecule.get_enuke() self.norb = self.nbf self.orbs = self.solver.orbs self.orbe = self.solver.orbe self.Gij = [] for g in xrange(self.nbf): gmat = zeros((self.nbf, self.nbf), 'd') self.Gij.append(gmat) gbf = self.bfs[g] for i in xrange(self.nbf): ibf = self.bfs[i] for j in xrange(i + 1): jbf = self.bfs[j] gij = three_center(ibf, gbf, jbf) gmat[i, j] = gij gmat[j, i] = gij D0 = mkdens(self.orbs, 0, self.nclosed) J0 = getJ(self.Ints, D0) Vfa = (2.0 * (self.nel - 1.0) / self.nel) * J0 self.H0 = self.h + Vfa self.b = zeros(self.nbf, 'd') return
def __init__(self,solver): # Solver is a pointer to a HF or a DFT calculation that has # already converged self.solver = solver self.bfs = self.solver.bfs self.nbf = len(self.bfs) self.S = self.solver.S self.h = self.solver.h self.Ints = self.solver.Ints self.molecule = self.solver.molecule self.nel = self.molecule.get_nel() self.nclosed, self.nopen = self.molecule.get_closedopen() self.Enuke = self.molecule.get_enuke() self.norb = self.nbf self.orbs = self.solver.orbs self.orbe = self.solver.orbe self.Gij = [] for g in range(self.nbf): gmat = zeros((self.nbf,self.nbf),'d') self.Gij.append(gmat) gbf = self.bfs[g] for i in range(self.nbf): ibf = self.bfs[i] for j in range(i+1): jbf = self.bfs[j] gij = three_center(ibf,gbf,jbf) gmat[i,j] = gij gmat[j,i] = gij D0 = mkdens(self.orbs,0,self.nclosed) J0 = getJ(self.Ints,D0) Vfa = (2.0*(self.nel-1.0)/self.nel)*J0 self.H0 = self.h + Vfa self.b = zeros(self.nbf,'d') return
def get_exx_energy(b,nbf,nel,nocc,ETemp,Enuke,S,h,Ints,H0,Gij,**opts): """Computes the energy for the OEP/HF functional Options: return_flag 0 Just return the energy 1 Return energy, orbe, orbs 2 Return energy, orbe, orbs, F """ return_flag = opts.get('return_flag',0) Hoep = get_Hoep(b,H0,Gij) orbe,orbs = geigh(Hoep,S) if ETemp: efermi = get_efermi(nel,orbe,ETemp) occs = get_fermi_occs(efermi,orbe,ETemp) D = mkdens_occs(orbs,occs) entropy = get_entropy(occs,ETemp) else: D = mkdens(orbs,0,nocc) F = get_fock(D,Ints,h) energy = trace2(h+F,D)+Enuke if ETemp: energy += entropy iref = nel/2 gap = 627.51*(orbe[iref]-orbe[iref-1]) logging.debug("EXX Energy, B, Gap: %10.5f %10.5f %10.5f" % (energy,sqrt(dot(b,b)),gap)) #logging.debug("%s" % orbe) if return_flag == 1: return energy,orbe,orbs elif return_flag == 2: return energy,orbe,orbs,F return energy
def get_exx_energy(b, nbf, nel, nocc, ETemp, Enuke, S, h, Ints, H0, Gij, **opts): """Computes the energy for the OEP/HF functional Options: return_flag 0 Just return the energy 1 Return energy, orbe, orbs 2 Return energy, orbe, orbs, F """ return_flag = opts.get('return_flag', 0) Hoep = get_Hoep(b, H0, Gij) orbe, orbs = geigh(Hoep, S) if ETemp: efermi = get_efermi(nel, orbe, ETemp) occs = get_fermi_occs(efermi, orbe, ETemp) D = mkdens_occs(orbs, occs) entropy = get_entropy(occs, ETemp) else: D = mkdens(orbs, 0, nocc) F = get_fock(D, Ints, h) energy = trace2(h + F, D) + Enuke if ETemp: energy += entropy iref = nel / 2 gap = 627.51 * (orbe[iref] - orbe[iref - 1]) logging.debug("EXX Energy, B, Gap: %10.5f %10.5f %10.5f" % (energy, sqrt(dot(b, b)), gap)) #logging.debug("%s" % orbe) if return_flag == 1: return energy, orbe, orbs elif return_flag == 2: return energy, orbe, orbs, F return energy
def test_mol(mol, **opts): basis_data = opts.get('basis_data', None) do_python_tests = opts.get('do_python_tests', True) make_hf_driver(mol, basis_data=basis_data) if do_python_tests: bfs = getbasis(mol, basis_data) S = getS(bfs) T = getT(bfs) V = getV(bfs, mol) Ints = get2ints(bfs) nclosed, nopen = mol.get_closedopen() enuke = mol.get_enuke() assert nopen == 0 h = T + V orbe, orbs = GHeigenvectors(h, S) print "Eval of h: ", print orbe for i in range(10): D = mkdens(orbs, 0, nclosed) J = getJ(Ints, D) K = getK(Ints, D) orbe, orbs = GHeigenvectors(h + 2 * J - K, S) eone = TraceProperty(D, h) ej = TraceProperty(D, J) ek = TraceProperty(D, K) energy = enuke + 2 * eone + 2 * ej - ek print i, energy, enuke, eone, ej, ek return
def get_os_dens(orbs,f,noccsh): istart = iend = 0 nsh = len(f) Ds = [ ] assert len(f) == len(noccsh) for ish in xrange(nsh): iend += noccsh[ish] Ds.append(mkdens(orbs,istart,iend)) istart = iend return Ds
def __init__(self, solver): # Solver is a pointer to a UHF calculation that has # already converged self.solver = solver self.bfs = self.solver.bfs self.nbf = len(self.bfs) self.S = self.solver.S self.h = self.solver.h self.Ints = self.solver.Ints self.molecule = self.solver.molecule self.nel = self.molecule.get_nel() self.nalpha, self.nbeta = self.molecule.get_alphabeta() self.Enuke = self.molecule.get_enuke() self.norb = self.nbf self.orbsa = self.solver.orbsa self.orbsb = self.solver.orbsb self.orbea = self.solver.orbea self.orbeb = self.solver.orbeb self.Gij = [] for g in xrange(self.nbf): gmat = zeros((self.nbf, self.nbf), 'd') self.Gij.append(gmat) gbf = self.bfs[g] for i in xrange(self.nbf): ibf = self.bfs[i] for j in xrange(i + 1): jbf = self.bfs[j] gij = three_center(ibf, gbf, jbf) gmat[i, j] = gij gmat[j, i] = gij D0 = mkdens(self.orbsa, 0, self.nalpha) + mkdens( self.orbsb, 0, self.nbeta) J0 = getJ(self.Ints, D0) Vfa = ((self.nel - 1.) / self.nel) * J0 self.H0 = self.h + Vfa self.b = zeros(2 * self.nbf, 'd') return
def pyq1_dft(atomtuples=[(2, (0, 0, 0))], basis='6-31G**', maxit=10, xcname='SVWN'): from PyQuante import Ints, settings, Molecule from PyQuante.dft import getXC from PyQuante.MG2 import MG2 as MolecularGrid from PyQuante.LA2 import mkdens, geigh, trace2 from PyQuante.Ints import getJ print("PyQ1 DFT run") atoms = Molecule('Pyq1', atomlist=atomtuples) bfs = Ints.getbasis(atoms, basis=basis) S, h, Ints = Ints.getints(bfs, atoms) nclosed, nopen = nel // 2, nel % 2 assert nopen == 0 enuke = atoms.get_enuke() grid_nrad = settings.DFTGridRadii grid_fineness = settings.DFTGridFineness gr = MolecularGrid(atoms, grid_nrad, grid_fineness) gr.set_bf_amps(bfs) orbe, orbs = geigh(h, S) eold = 0 for i in range(maxit): D = mkdens(orbs, 0, nclosed) gr.setdens(D) J = getJ(Ints, D) Exc, Vxc = getXC(gr, nel, functional=xcname) F = h + 2 * J + Vxc orbe, orbs = geigh(F, S) Ej = 2 * trace2(D, J) Eone = 2 * trace2(D, h) energy = Eone + Ej + Exc + enuke print(i, energy, Eone, Ej, Exc, enuke) if np.isclose(energy, eold): break eold = energy return energy
def get_energy(self,b): self.iter += 1 self.Hoep = get_Hoep(b,self.H0,self.Gij) self.orbe,self.orbs = geigh(self.Hoep,self.S) if self.etemp: self.D,self.entropy = mkdens_fermi(self.nel,self.orbe,self.orbs, self.etemp) else: self.D = mkdens(self.orbs,0,self.nclosed) self.entropy=0 self.F = get_fock(self.D,self.Ints,self.h) self.energy = trace2(self.h+self.F,self.D)+self.Enuke + self.entropy if self.iter == 1 or self.iter % 10 == 0: logging.debug("%4d %10.5f %10.5f" % (self.iter,self.energy,dot(b,b))) return self.energy
def __init__(self,solver): # Solver is a pointer to a UHF calculation that has # already converged self.solver = solver self.bfs = self.solver.bfs self.nbf = len(self.bfs) self.S = self.solver.S self.h = self.solver.h self.Ints = self.solver.Ints self.molecule = self.solver.molecule self.nel = self.molecule.get_nel() self.nalpha, self.nbeta = self.molecule.get_alphabeta() self.Enuke = self.molecule.get_enuke() self.norb = self.nbf self.orbsa = self.solver.orbsa self.orbsb = self.solver.orbsb self.orbea = self.solver.orbea self.orbeb = self.solver.orbeb self.Gij = [] for g in range(self.nbf): gmat = zeros((self.nbf,self.nbf),'d') self.Gij.append(gmat) gbf = self.bfs[g] for i in range(self.nbf): ibf = self.bfs[i] for j in range(i+1): jbf = self.bfs[j] gij = three_center(ibf,gbf,jbf) gmat[i,j] = gij gmat[j,i] = gij D0 = mkdens(self.orbsa,0,self.nalpha)+mkdens(self.orbsb,0,self.nbeta) J0 = getJ(self.Ints,D0) Vfa = ((self.nel-1.)/self.nel)*J0 self.H0 = self.h + Vfa self.b = zeros(2*self.nbf,'d') return
def pyq1_dft(atomtuples=[(2,(0,0,0))],basis = '6-31G**',maxit=10, xcname='SVWN'): from PyQuante import Ints,settings,Molecule from PyQuante.dft import getXC from PyQuante.MG2 import MG2 as MolecularGrid from PyQuante.LA2 import mkdens,geigh,trace2 from PyQuante.Ints import getJ print ("PyQ1 DFT run") atoms = Molecule('Pyq1',atomlist=atomtuples) bfs = Ints.getbasis(atoms,basis=basis) S,h,Ints = Ints.getints(bfs,atoms) nclosed,nopen = nel//2,nel%2 assert nopen==0 enuke = atoms.get_enuke() grid_nrad = settings.DFTGridRadii grid_fineness = settings.DFTGridFineness gr = MolecularGrid(atoms,grid_nrad,grid_fineness) gr.set_bf_amps(bfs) orbe,orbs = geigh(h,S) eold = 0 for i in range(maxit): D = mkdens(orbs,0,nclosed) gr.setdens(D) J = getJ(Ints,D) Exc,Vxc = getXC(gr,nel,functional=xcname) F = h+2*J+Vxc orbe,orbs = geigh(F,S) Ej = 2*trace2(D,J) Eone = 2*trace2(D,h) energy = Eone + Ej + Exc + enuke print (i,energy,Eone,Ej,Exc,enuke) if np.isclose(energy,eold): break eold = energy return energy
def get_energy(self, b): self.iter += 1 self.Hoep = get_Hoep(b, self.H0, self.Gij) self.orbe, self.orbs = geigh(self.Hoep, self.S) if self.etemp: self.D, self.entropy = mkdens_fermi(self.nel, self.orbe, self.orbs, self.etemp) else: self.D = mkdens(self.orbs, 0, self.nclosed) self.entropy = 0 self.F = get_fock(self.D, self.Ints, self.h) self.energy = trace2(self.h + self.F, self.D) + self.Enuke + self.entropy if self.iter == 1 or self.iter % 10 == 0: logging.debug("%4d %10.5f %10.5f" % (self.iter, self.energy, dot(b, b))) return self.energy
def simple_hf(atoms,S,h,Ints): from PyQuante.LA2 import mkdens from PyQuante.hartree_fock import get_energy orbe,orbs = geigh(h,S) nclosed,nopen = atoms.get_closedopen() enuke = atoms.get_enuke() nocc = nclosed eold = 0 for i in range(15): D = mkdens(orbs,0,nocc) G = get2JmK(Ints,D) F = h+G orbe,orbs = geigh(F,S) energy = get_energy(h,F,D,enuke) 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
def simple_hf(atoms, S, h, Ints): from PyQuante.LA2 import mkdens from PyQuante.hartree_fock import get_energy orbe, orbs = geigh(h, S) nclosed, nopen = atoms.get_closedopen() enuke = atoms.get_enuke() nocc = nclosed eold = 0 for i in range(15): D = mkdens(orbs, 0, nocc) G = get2JmK(Ints, D) F = h + G orbe, orbs = geigh(F, S) energy = get_energy(h, F, D, enuke) 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
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 pyq1_rohf(atomtuples=[(2, (0, 0, 0))], basis='6-31G**', maxit=10, mult=3): from PyQuante import Ints, settings, Molecule from PyQuante.hartree_fock import get_energy from PyQuante.MG2 import MG2 as MolecularGrid from PyQuante.LA2 import mkdens, geigh, trace2, simx from PyQuante.Ints import getJ, getK print("PyQ1 ROHF run") atoms = Molecule('Pyq1', atomlist=atomtuples, multiplicity=mult) bfs = Ints.getbasis(atoms, basis=basis) S, h, I2e = Ints.getints(bfs, atoms) nbf = norbs = len(bfs) nel = atoms.get_nel() nalpha, nbeta = atoms.get_alphabeta() enuke = atoms.get_enuke() orbe, orbs = geigh(h, S) eold = 0 for i in range(maxit): Da = mkdens(orbs, 0, nalpha) Db = mkdens(orbs, 0, nbeta) Ja = getJ(I2e, Da) Jb = getJ(I2e, Db) Ka = getK(I2e, Da) Kb = getK(I2e, 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) < 1e-5: break eold = energy Fa = simx(Fa, orbs) Fb = simx(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 = np.linalg.eigh(F) orbs = np.dot(orbs, mo_orbs) 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
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" print energy, "(benchmark = -1.122956)"
def update_density(self): from PyQuante.LA2 import mkdens self.D = 2*mkdens(self.orbs,0,self.nclosed)
def pyq1_rohf(atomtuples=[(2,(0,0,0))],basis = '6-31G**',maxit=10,mult=3): from PyQuante import Ints,settings,Molecule from PyQuante.hartree_fock import get_energy from PyQuante.MG2 import MG2 as MolecularGrid from PyQuante.LA2 import mkdens,geigh,trace2,simx from PyQuante.Ints import getJ,getK print ("PyQ1 ROHF run") atoms = Molecule('Pyq1',atomlist=atomtuples,multiplicity=mult) bfs = Ints.getbasis(atoms,basis=basis) S,h,I2e = Ints.getints(bfs,atoms) nbf = norbs = len(bfs) nel = atoms.get_nel() nalpha,nbeta = atoms.get_alphabeta() enuke = atoms.get_enuke() orbe,orbs = geigh(h,S) eold = 0 for i in range(maxit): Da = mkdens(orbs,0,nalpha) Db = mkdens(orbs,0,nbeta) Ja = getJ(I2e,Da) Jb = getJ(I2e,Db) Ka = getK(I2e,Da) Kb = getK(I2e,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) < 1e-5: break eold = energy Fa = simx(Fa,orbs) Fb = simx(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 = np.linalg.eigh(F) orbs = np.dot(orbs,mo_orbs) return energy,orbe,orbs
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 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 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 update_density(self): from PyQuante.LA2 import mkdens self.D = 2 * mkdens(self.orbs, 0, self.nclosed)
def rhf(mol, bfs, S, Hcore, Ints, mu=0, MaxIter=100, eps_SCF=1E-4, _diis_=True): ########################################################## ## Get the system information ########################################################## # size nbfs = len(bfs) # get the nuclear energy enuke = mol.get_enuke() # determine the number of electrons # and occupation numbers nelec = mol.get_nel() nclosed, nopen = mol.get_closedopen() nocc = nclosed # orthogonalization matrix X = SymOrthCutoff(S) if _ee_inter_ == 0: print '\t\t ===================================================' print '\t\t == Electrons-Electrons interactions desactivated ==' print '\t\t ===================================================' if nopen != 0: print '\t\t =================================================================' print '\t\t Warning : using restricted HF with open shell is not recommended' print "\t\t Use only if you know what you're doing" print '\t\t =================================================================' # get a first DM #D = np.zeros((nbfs,nbfs)) L, C = scla.eigh(Hcore, b=S) D = mkdens(C, 0, nocc) # initialize the old energy eold = 0. # initialize the DIIS if _diis_: avg = DIIS(S) #print '\t SCF Calculations' for iiter in range(MaxIter): # form the G matrix from the # density matrix and the 2electron integrals G = get2JmK(Ints, D) # form the Fock matrix F = Hcore + _ee_inter_ * G + mu # if DIIS if _diis_: F = avg.getF(F, D) # orthogonalize the Fock matrix Fp = np.dot(X.T, np.dot(F, X)) # diagonalize the Fock matrix Lp, Cp = scla.eigh(Fp) # form the density matrix in the OB if nopen == 0: Dp = mkdens(Cp, 0, nocc) else: Dp = mkdens_spinavg(Cp, nclosed, nopen) # pass the eigenvector back to the AO C = np.dot(X, Cp) # form the density matrix in the AO if nopen == 0: D = mkdens(C, 0, nocc) #else: # D = mkdens_spinavg(C,nclosed,nopen) # compute the total energy e = np.sum(D * (Hcore + F)) + enuke print "\t\t Iteration: %d Energy: %f EnergyVar: %f" % ( iiter, e.real, np.abs((e - eold).real)) # stop if done if (np.abs(e - eold) < eps_SCF): break else: eold = e if iiter < MaxIter: print( "\t\t SCF for HF has converged in %d iterations, Final energy %1.3f Ha\n" % (iiter, e.real)) else: print("\t\t SCF for HF has failed to converge after %d iterations") # compute the density matrix in the # eigenbasis of F P = np.dot(Cp.T, np.dot(Dp, Cp)) #print D return Lp, C, Cp, F, Fp, D, Dp, P, X
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 rhf(mol, bfs, S, Hcore, Ints, MaxIter=100, eps_SCF=1E-4, _diis_=True): ########################################################## ## Get the system information ########################################################## # size nbfs = len(bfs) # get the nuclear energy enuke = mol.get_enuke() # determine the number of electrons # and occupation numbers nelec = mol.get_nel() nclosed, nopen = mol.get_closedopen() nocc = nclosed if nopen != 0: print '\t\t =================================================================' print '\t\t Warning : using restricted HF with open shell is not recommended' print "\t\t Use only if you know what you're doing" print '\t\t =================================================================' # get a first DM #D = np.zeros((nbfs,nbfs)) L, C = scla.eigh(Hcore, b=S) D = mkdens(C, 0, nocc) # initialize the old energy eold = 0. # initialize the DIIS if _diis_: avg = DIIS(S) #print '\t SCF Calculations' for iiter in range(MaxIter): # form the G matrix from the # density matrix and the 2electron integrals G = get2JmK_mpi(Ints, D) # form the Fock matrix F = Hcore + G # if DIIS if _diis_: F = avg.getF(F, D) # diagonalize the Fock matrix L, C = scla.eigh(F, b=S) # new density mtrix D = mkdens(C, 0, nocc) # compute the total energy e = np.sum(D * (Hcore + F)) + enuke print "\t\t Iteration: %d Energy: %f EnergyVar: %f" % ( iiter, e.real, np.abs((e - eold).real)) # stop if done if (np.abs(e - eold) < eps_SCF): break else: eold = e if iiter < MaxIter - 1: print( "\t\t SCF for HF has converged in %d iterations, Final energy %1.3f Ha\n" % (iiter, e.real)) else: print("\t\t SCF for HF has failed to converge after %d iterations") sys.exit() # compute the density matrix in the # eigenabsis of the Fock matrix # orthogonalization matrix X = SymOrthCutoff(S) Xm1 = np.linalg.inv(X) # density matrix in ortho basis Dp = np.dot(Xm1, np.dot(D, Xm1.T)) # eigenvector in ortho basis Cp = np.dot(Xm1, C) # density matrix P = np.dot(Cp.T, np.dot(Dp, Cp)) # done return L, C, P
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 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