Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
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 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
Exemple #5
0
    def update(self,**kwargs):
        from PyQuante.LA2 import trace2
        from PyQuante.Ints import getJ
        from PyQuante.dft import getXC

        #self.DoAveraging = kwargs.get('DoAveraging',True)
        #if self.DoAveraging:
        #    self.Averager = DIIS(self.S)

        if self.DoAveraging and self.dmat is not None:
            self.F = self.Averager.getF(self.F,self.dmat)
        self.dmat,self.entropy = self.solver.solve(self.F,**kwargs)
        D = self.dmat
        
        self.gr.setdens(D)
        self.J = getJ(self.ERI,D)
        self.Ej = 2*trace2(D,self.J)

        self.Exc,self.XC = getXC(self.gr,self.nel,
                                 functional=self.functional)

        self.Eone = 2*trace2(D,self.h)

        self.F = self.h+2*self.J+self.XC
        self.energy = self.Eone + self.Ej + self.Exc + self.Enuke + self.entropy
        return
Exemple #6
0
 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
Exemple #7
0
 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
Exemple #8
0
 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
Exemple #9
0
 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
Exemple #10
0
    def update(self, **kwargs):
        from PyQuante.LA2 import trace2
        from PyQuante.Ints import getJ
        from PyQuante.dft import getXC

        #self.DoAveraging = kwargs.get('DoAveraging',True)
        #if self.DoAveraging:
        #    self.Averager = DIIS(self.S)

        if self.DoAveraging and self.dmat is not None:
            self.F = self.Averager.getF(self.F, self.dmat)
        self.dmat, self.entropy = self.solver.solve(self.F, **kwargs)
        D = self.dmat

        self.gr.setdens(D)
        self.J = getJ(self.ERI, D)
        self.Ej = 2 * trace2(D, self.J)

        self.Exc, self.XC = getXC(self.gr,
                                  self.nel,
                                  functional=self.functional)

        self.Eone = 2 * trace2(D, self.h)

        self.F = self.h + 2 * self.J + self.XC
        self.energy = self.Eone + self.Ej + self.Exc + self.Enuke + self.entropy
        return
Exemple #11
0
def get_os_hams(Ints,Ds):
    # GVB2P5 did this a little more efficiently; they stored
    # 2J-K for the core, then J,K for each open shell. Didn't
    # seem worth it here, so I'm jst storing J,K separately
    Hs = []
    for D in Ds:
        Hs.append(getJ(Ints,D))
        Hs.append(getK(Ints,D))
    return Hs
Exemple #12
0
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
Exemple #13
0
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
Exemple #14
0
    def update(self, **kwargs):
        from PyQuante.LA2 import trace2
        from PyQuante.Ints import getJ, getK

        if self.DoAveraging and self.dmat is not None:
            self.F = self.Averager.getF(self.F, self.dmat)
        self.dmat, self.entropy = self.solver.solve(self.F, **kwargs)
        D = self.dmat

        self.J = getJ(self.ERI, D)
        self.Ej = 2 * trace2(D, self.J)
        self.K = getK(self.ERI, D)
        self.Exc = -trace2(D, self.K)
        self.Eone = 2 * trace2(D, self.h)
        self.F = self.h + 2 * self.J - self.K
        self.energy = self.Eone + self.Ej + self.Exc + self.Enuke + self.entropy
        return
Exemple #15
0
    def update(self,**opts):
        from PyQuante.LA2 import trace2
        from PyQuante.Ints import getJ,getK

        if self.DoAveraging and self.dmat is not None:
            self.F = self.Averager.getF(self.F,self.dmat)
        self.dmat,self.entropy = self.solver.solve(self.F,**opts)
        D = self.dmat
        
        self.J = getJ(self.ERI,D)
        self.Ej = 2*trace2(D,self.J)
        self.K = getK(self.ERI,D)
        self.Exc = -trace2(D,self.K)
        self.Eone = 2*trace2(D,self.h)
        self.F = self.h + 2*self.J - self.K
        self.energy = self.Eone + self.Ej + self.Exc + self.Enuke + self.entropy
        return
Exemple #16
0
    def update(self,**opts):
        from PyQuante.LA2 import trace2
        from PyQuante.Ints import getJ
        from PyQuante.dft import getXC

        self.dmat,self.entropy = self.solver.solve(self.F,**opts)
        D = self.dmat
        
        self.gr.setdens(D)
        self.J = getJ(self.ERI,D)
        self.Ej = 2*trace2(D,self.J)

        self.Exc,self.XC = getXC(self.gr,self.nel,self.bfgrid,
                                 functional=self.functional)

        self.Eone = 2*trace2(D,self.h)

        self.F = self.h+2*self.J+self.XC
        self.energy = self.Eone + self.Ej + self.Exc + self.Enuke + self.entropy
        return
Exemple #17
0
    def update(self, **kwargs):
        from PyQuante.LA2 import trace2
        from PyQuante.Ints import getJ, getK

        self.amat, entropya = self.solvera.solve(self.Fa)
        self.bmat, entropyb = self.solverb.solve(self.Fb)

        Da = self.amat
        Db = self.bmat

        D = Da + Db
        self.entropy = 0.5 * (entropya + entropyb)

        self.J = getJ(self.ERI, D)
        self.Ej = 0.5 * trace2(D, self.J)
        self.Ka = getK(self.ERI, Da)
        self.Kb = getK(self.ERI, Db)
        self.Exc = -0.5 * (trace2(Da, self.Ka) + trace2(Db, self.Kb))
        self.Eone = trace2(D, self.h)
        self.Fa = self.h + self.J - self.Ka
        self.Fb = self.h + self.J - self.Kb
        self.energy = self.Eone + self.Ej + self.Exc + self.Enuke + self.entropy
        return
Exemple #18
0
    def update(self,**opts):
        from PyQuante.LA2 import trace2
        from PyQuante.Ints import getJ,getK

        self.amat,entropya = self.solvera.solve(self.Fa)
        self.bmat,entropyb = self.solverb.solve(self.Fb)

        Da = self.amat
        Db = self.bmat

        D = Da+Db
        self.entropy = 0.5*(entropya+entropyb)

        self.J = getJ(self.ERI,D)
        self.Ej = 0.5*trace2(D,self.J)
        self.Ka = getK(self.ERI,Da)
        self.Kb = getK(self.ERI,Db)
        self.Exc = -0.5*(trace2(Da,self.Ka)+trace2(Db,self.Kb))
        self.Eone = trace2(D,self.h)
        self.Fa = self.h + self.J - self.Ka
        self.Fb = self.h + self.J - self.Kb
        self.energy = self.Eone + self.Ej + self.Exc + self.Enuke + self.entropy
        return
Exemple #19
0
 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
Exemple #20
0
 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
Exemple #21
0
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)
Exemple #22
0
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
Exemple #23
0
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
Exemple #24
0
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
Exemple #25
0
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
Exemple #26
0
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
Exemple #27
0
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
Exemple #28
0
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)
Exemple #29
0
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