def compute_F(P, Hcore, X, Ints, mu=0): # get the matrix of 2J-K for a given fixed P # P is here given in the non- orthonormal basis G = get2JmK(Ints, P) # pass the G matrix in the orthonormal basis Gp = simx(G, X, 'T') # form the Fock matrix in the orthonomral basis F = Hcore + _ee_inter_ * Gp + mu return F
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_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 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
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 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