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 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 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 solve(self, H, **kwargs): from PyQuante.LA2 import geigh from PyQuante.fermi_dirac import mkdens_fermi self.orbe, self.orbs = geigh(H, self.S) self.D, self.entropy = mkdens_fermi(self.nel, self.orbe, self.orbs, self.etemp) return self.D, self.entropy
def solve(self,H,**opts): from PyQuante.LA2 import geigh from PyQuante.fermi_dirac import mkdens_fermi self.orbe,self.orbs = geigh(H,self.S) self.D,self.entropy = mkdens_fermi(self.nel,self.orbe, self.orbs,self.etemp) return self.D,self.entropy
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 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 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 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 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 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 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 solve(self,H,**opts): from PyQuante.LA2 import mkdens_spinavg,simx,geigh from PyQuante.NumWrap import matrixmultiply,eigh if self.first_iteration: self.first_iteration = False self.orbe,self.orbs = geigh(H,self.S) else: Ht = simx(H,self.orbs) if self.pass_nroots: self.orbe,orbs = self.solver(Ht,self.nroots) else: self.orbe,orbs = self.solver(Ht) self.orbs = matrixmultiply(self.orbs,orbs) self.D = mkdens_spinavg(self.orbs,self.nclosed,self.nopen) self.entropy = 0 return self.D,self.entropy
def solve(self, H, **kwargs): from PyQuante.LA2 import mkdens_spinavg, simx, geigh from PyQuante.NumWrap import matrixmultiply, eigh if self.first_iteration: self.first_iteration = False self.orbe, self.orbs = geigh(H, self.S) else: Ht = simx(H, self.orbs) if self.pass_nroots: self.orbe, orbs = self.solver(Ht, self.nroots) else: self.orbe, orbs = self.solver(Ht) self.orbs = matrixmultiply(self.orbs, orbs) self.D = mkdens_spinavg(self.orbs, self.nclosed, self.nopen) self.entropy = 0 return self.D, self.entropy
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 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 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_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
def solve(self,H,**opts): from PyQuante.LA2 import geigh,mkdens_spinavg self.orbe,self.orbs = geigh(H,self.S) self.D = mkdens_spinavg(self.orbs,self.nclosed,self.nopen) self.entropy = 0 return self.D,self.entropy
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 solve(self, H, **kwargs): from PyQuante.LA2 import geigh, mkdens_spinavg self.orbe, self.orbs = geigh(H, self.S) self.D = mkdens_spinavg(self.orbs, self.nclosed, self.nopen) self.entropy = 0 return self.D, self.entropy
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
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"