def solve_ERI(OEI, TEI, DMguess, numPairs): mol = gto.Mole() mol.build(verbose=3) mol.atom.append(('C', (0, 0, 0))) mol.nelectron = 2 * numPairs L = OEI.shape[0] mf = scf.RHF(mol) mf.get_hcore = lambda *args: OEI mf.get_ovlp = lambda *args: np.eye(L) mf._eri = ao2mo.restore(8, TEI, L) mf.scf(DMguess) DMloc = np.dot(np.dot(mf.mo_coeff, np.diag(mf.mo_occ)), mf.mo_coeff.T) if (mf.converged == False): mf = rhf_newtonraphson.solve(mf, dm_guess=DMloc) DMloc = np.dot(np.dot(mf.mo_coeff, np.diag(mf.mo_occ)), mf.mo_coeff.T) return DMloc
def solve( CONST, OEI, FOCK, TEI, Norb, Nel, Nimp, DMguessRHF, chempot_imp=0.0 ): # Augment the FOCK operator with the chemical potential FOCKcopy = FOCK.copy() if (chempot_imp != 0.0): for orb in range(Nimp): FOCKcopy[ orb, orb ] -= chempot_imp # Get the RHF solution mol = gto.Mole() mol.build( verbose=0 ) mol.atom.append(('C', (0, 0, 0))) mol.nelectron = Nel mol.incore_anyway = True mf = scf.RHF( mol ) mf.get_hcore = lambda *args: FOCKcopy mf.get_ovlp = lambda *args: np.eye( Norb ) mf._eri = ao2mo.restore(8, TEI, Norb) mf.scf( DMguessRHF ) DMloc = np.dot(np.dot( mf.mo_coeff, np.diag( mf.mo_occ )), mf.mo_coeff.T ) if ( mf.converged == False ): mf = rhf_newtonraphson.solve( mf, dm_guess=DMloc ) DMloc = np.dot(np.dot( mf.mo_coeff, np.diag( mf.mo_occ )), mf.mo_coeff.T ) ERHF = mf.hf_energy RDM1 = mf.make_rdm1() JK = mf.get_veff(None, dm=RDM1) # To calculate the impurity energy, rescale the JK matrix with a factor 0.5 to avoid double counting: 0.5 * ( OEI + FOCK ) = OEI + 0.5 * JK ImpurityEnergy = CONST \ + 0.25 * np.einsum('ji,ij->', RDM1[:,:Nimp], FOCK[:Nimp,:] + OEI[:Nimp,:]) \ + 0.25 * np.einsum('ji,ij->', RDM1[:Nimp,:], FOCK[:,:Nimp] + OEI[:,:Nimp]) \ + 0.25 * np.einsum('ji,ij->', RDM1[:,:Nimp], JK[:Nimp,:]) \ + 0.25 * np.einsum('ji,ij->', RDM1[:Nimp,:], JK[:,:Nimp]) return ( ImpurityEnergy, RDM1 )
def RHF(self): ''' Restricted Hartree-Fock ''' Nimp = self.Nimp FOCK = self.FOCK.copy() if (self.chempot != 0.0): for orb in range(Nimp): FOCK[orb, orb] -= self.chempot mol = gto.Mole() mol.build(verbose = 0) mol.atom.append(('C', (0, 0, 0))) mol.nelectron = self.Nel mol.incore_anyway = True mf = scf.RHF(mol) mf.get_hcore = lambda *args: FOCK mf.get_ovlp = lambda *args: np.eye(self.Norb) mf._eri = ao2mo.restore(8, self.TEI, self.Norb) mf.scf(self.DMguess) DMloc = np.dot(np.dot(mf.mo_coeff, np.diag(mf.mo_occ)), mf.mo_coeff.T) if ( mf.converged == False ): mf = rhf_newtonraphson.solve( mf, dm_guess=DMloc) DMloc = np.dot(np.dot(mf.mo_coeff, np.diag(mf.mo_occ)), mf.mo_coeff.T) ERHF = mf.e_tot RDM1 = mf.make_rdm1() jk = mf.get_veff(None, dm=RDM1) # To calculate the impurity energy, rescale the JK matrix with a factor 0.5 to avoid double counting: 0.5 * ( OEI + FOCK ) = OEI + 0.5 * JK ImpurityEnergy = 0.5*np.einsum('ij,ij->', RDM1[:Nimp,:], self.OEI[:Nimp,:] + FOCK[:Nimp,:]) \ + 0.5*np.einsum('ij,ij->', RDM1[:Nimp,:], jk[:Nimp,:]) return (ImpurityEnergy, ERHF, RDM1)
N -1.323645520078 -1.013034361391 0.000000000000 C -2.609849686479 -1.716498251901 0.000000000000 H -2.689209473523 -2.357766508547 0.889337124082 H -2.689209473523 -2.357766508547 -0.889337124082 H -3.397445032059 -0.956544015308 0.000000000000 H 3.126343795339 -1.409688574359 0.000000000000 H 2.260091440174 -2.714879611857 -0.890143668130 H 2.260091440174 -2.714879611857 0.890143668130 H 2.453380552599 3.037434448146 0.000000000000 H -1.400292735506 3.159575123448 0.000000000000 H -0.135202960256 4.062674697502 0.897532201407 H -0.135202960256 4.062674697502 -0.897532201407 ''' mol.basis = '6-31g' mol.symmetry = 1 mol.charge = 0 mol.spin = 0 #2*S; multiplicity-1 mol.build() mf = scf.RHF( mol ) mf.verbose = 4 mf.max_cycle = 1 mf.scf() DMloc = np.dot(np.dot( mf.mo_coeff, np.diag( mf.mo_occ )), mf.mo_coeff.T ) if ( mf.converged == False ): mf = rhf_newtonraphson.solve( mf, dm_guess=DMloc ) DMloc = np.dot(np.dot( mf.mo_coeff, np.diag( mf.mo_occ )), mf.mo_coeff.T )
def solve(CONST, OEI, FOCK, TEI, Norb, Nel, Nimp, DMguessRHF, energytype='LAMBDA', chempot_imp=0.0, printoutput=True): assert ((energytype == 'LAMBDA') or (energytype == 'LAMBDA_AMP') or (energytype == 'LAMBDA_ZERO') or (energytype == 'CASCI')) # Killing output if necessary if (printoutput == False): sys.stdout.flush() old_stdout = sys.stdout.fileno() new_stdout = os.dup(old_stdout) devnull = os.open('/dev/null', os.O_WRONLY) os.dup2(devnull, old_stdout) os.close(devnull) # Augment the FOCK operator with the chemical potential FOCKcopy = FOCK.copy() if (chempot_imp != 0.0): for orb in range(Nimp): FOCKcopy[orb, orb] -= chempot_imp # Get the RHF solution mol = gto.Mole() mol.build(verbose=0) mol.atom.append(('C', (0, 0, 0))) mol.nelectron = Nel mol.incore_anyway = True mf = scf.RHF(mol) mf.get_hcore = lambda *args: FOCKcopy mf.get_ovlp = lambda *args: np.eye(Norb) mf._eri = ao2mo.restore(8, TEI, Norb) mf.scf(DMguessRHF) DMloc = np.dot(np.dot(mf.mo_coeff, np.diag(mf.mo_occ)), mf.mo_coeff.T) if (mf.converged == False): mf = rhf_newtonraphson.solve(mf, dm_guess=DMloc) DMloc = np.dot(np.dot(mf.mo_coeff, np.diag(mf.mo_occ)), mf.mo_coeff.T) # Check the RHF solution assert (Nel % 2 == 0) numPairs = Nel / 2 FOCKloc = FOCKcopy + np.einsum( 'ijkl,ij->kl', TEI, DMloc) - 0.5 * np.einsum('ijkl,ik->jl', TEI, DMloc) eigvals, eigvecs = np.linalg.eigh(FOCKloc) idx = eigvals.argsort() eigvals = eigvals[idx] eigvecs = eigvecs[:, idx] print "psi4cc::solve : RHF h**o-lumo gap =", eigvals[numPairs] - eigvals[ numPairs - 1] DMloc2 = 2 * np.dot(eigvecs[:, :numPairs], eigvecs[:, :numPairs].T) print "Two-norm difference of 1-RDM(RHF) and 1-RDM(FOCK(RHF)) =", np.linalg.norm( DMloc - DMloc2) # Get the CC solution from pyscf ccsolver = ccsd.CCSD(mf) ccsolver.verbose = 5 ECORR, t1, t2 = ccsolver.ccsd() ERHF = mf.hf_energy ECCSD = ERHF + ECORR # Compute the impurity energy if (energytype == 'CASCI'): # The 2-RDM is not required # Active space energy is computed with the Fock operator of the core (not rescaled) print "ECCSD =", ECCSD ccsolver.solve_lambda() pyscfRDM1 = ccsolver.make_rdm1() # MO space pyscfRDM1 = 0.5 * (pyscfRDM1 + pyscfRDM1.T) # Symmetrize pyscfRDM1 = np.dot(mf.mo_coeff, np.dot(pyscfRDM1, mf.mo_coeff.T)) # From MO to localized space ImpurityEnergy = ECCSD if (chempot_imp != 0.0): # [FOCK - FOCKcopy]_{ij} = chempot_imp * delta(i,j) * delta(i \in imp) ImpurityEnergy += np.einsum('ij,ij->', FOCK - FOCKcopy, pyscfRDM1) else: # Compute the DMET impurity energy based on the lambda equations if (energytype == 'LAMBDA'): ccsolver.solve_lambda() pyscfRDM1 = ccsolver.make_rdm1() # MO space pyscfRDM2 = ccsolver.make_rdm2() # MO space if (energytype == 'LAMBDA_AMP'): # Overwrite lambda tensors with t-amplitudes pyscfRDM1 = ccsolver.make_rdm1(t1, t2, t1, t2) # MO space pyscfRDM2 = ccsolver.make_rdm2(t1, t2, t1, t2) # MO space if (energytype == 'LAMBDA_ZERO'): # Overwrite lambda tensors with 0.0 fake_l1 = np.zeros(t1.shape, dtype=float) fake_l2 = np.zeros(t2.shape, dtype=float) pyscfRDM1 = ccsolver.make_rdm1(t1, t2, fake_l1, fake_l2) # MO space pyscfRDM2 = ccsolver.make_rdm2(t1, t2, fake_l1, fake_l2) # MO space pyscfRDM1 = 0.5 * (pyscfRDM1 + pyscfRDM1.T) # Symmetrize # Print a few to things to double check ''' print "Do we understand how the 1-RDM is stored?", np.linalg.norm( np.einsum('ii->', pyscfRDM1) - Nel ) print "Do we understand how the 2-RDM is stored?", np.linalg.norm( np.einsum('ijkk->ij', pyscfRDM2) / (Nel - 1.0) - pyscfRDM1 ) ''' # Change the pyscfRDM1/2 from MO space to localized space pyscfRDM1 = np.dot(mf.mo_coeff, np.dot(pyscfRDM1, mf.mo_coeff.T)) pyscfRDM2 = np.einsum('ai,ijkl->ajkl', mf.mo_coeff, pyscfRDM2) pyscfRDM2 = np.einsum('bj,ajkl->abkl', mf.mo_coeff, pyscfRDM2) pyscfRDM2 = np.einsum('ck,abkl->abcl', mf.mo_coeff, pyscfRDM2) pyscfRDM2 = np.einsum('dl,abcl->abcd', mf.mo_coeff, pyscfRDM2) ECCSDbis = CONST + np.einsum( 'ij,ij->', FOCKcopy, pyscfRDM1) + 0.5 * np.einsum('ijkl,ijkl->', TEI, pyscfRDM2) print "ECCSD1 =", ECCSD print "ECCSD2 =", ECCSDbis # To calculate the impurity energy, rescale the JK matrix with a factor 0.5 to avoid double counting: 0.5 * ( OEI + FOCK ) = OEI + 0.5 * JK ImpurityEnergy = CONST \ + 0.25 * np.einsum('ij,ij->', pyscfRDM1[:Nimp,:], FOCK[:Nimp,:] + OEI[:Nimp,:]) \ + 0.25 * np.einsum('ij,ij->', pyscfRDM1[:,:Nimp], FOCK[:,:Nimp] + OEI[:,:Nimp]) \ + 0.125 * np.einsum('ijkl,ijkl->', pyscfRDM2[:Nimp,:,:,:], TEI[:Nimp,:,:,:]) \ + 0.125 * np.einsum('ijkl,ijkl->', pyscfRDM2[:,:Nimp,:,:], TEI[:,:Nimp,:,:]) \ + 0.125 * np.einsum('ijkl,ijkl->', pyscfRDM2[:,:,:Nimp,:], TEI[:,:,:Nimp,:]) \ + 0.125 * np.einsum('ijkl,ijkl->', pyscfRDM2[:,:,:,:Nimp], TEI[:,:,:,:Nimp]) # Reviving output if necessary if (printoutput == False): sys.stdout.flush() os.dup2(new_stdout, old_stdout) os.close(new_stdout) return (ImpurityEnergy, pyscfRDM1)
C 1.177413455163 -1.426586745678 -3.035930309273 C 2.308221759410 -0.727692905561 -2.604000392388 C 0.000000000000 -0.698863692631 -3.485659405234 C -0.000000000000 0.698863692631 -3.485659405234 C 2.604000385623 -2.308221792277 -0.727692910676 C 3.035930522186 -1.177413550960 -1.426586813835 C 2.604000385623 -2.308221792277 0.727692910676 C 3.035930522186 -1.177413550960 1.426586813835 C 3.485659767723 0.000000000000 -0.698863749657 C 3.485659767723 0.000000000000 0.698863749657 C 2.308221759410 0.727692905561 -2.604000392388 C 1.177413455163 1.426586745678 -3.035930309273 ''' mol.basis = 'sto-3g' mol.symmetry = 0 mol.charge = 0 mol.spin = 0 #2*S; multiplicity-1 mol.build() # Perform RHF calculation mf = scf.RHF(mol) mf.verbose = 4 mf.scf() Energy1 = mf.e_tot # Redo with Newton-Raphson --> start from 'minao' guess mf = rhf_newtonraphson.solve(mf, safe_guess=True) Energy2 = mf.e_tot assert (abs(Energy1 - Energy2) < 1e-9)
def CAS(self, CAS, CAS_MO, Orbital_optimization = False, solver = 'FCI'): ''' CASSCF with FCI or DMRG solver from BLOCK or CheMPS2 ''' Norb = self.Norb Nimp = self.Nimp FOCK = self.FOCK.copy() if (self.chempot != 0.0): for orb in range(Nimp): FOCK[orb, orb] -= self.chempot mol = gto.Mole() mol.build(verbose = 0) mol.atom.append(('C', (0, 0, 0))) mol.nelectron = self.Nel mol.incore_anyway = True mf = scf.RHF( mol ) mf.get_hcore = lambda *args: FOCK mf.get_ovlp = lambda *args: np.eye(Norb) mf._eri = ao2mo.restore(8, self.TEI, Norb) mf.scf(self.DMguess) DMloc = np.dot(np.dot(mf.mo_coeff, np.diag(mf.mo_occ)), mf.mo_coeff.T) if ( mf.converged == False ): mf = rhf_newtonraphson.solve( mf, dm_guess=DMloc) DMloc = np.dot(np.dot(mf.mo_coeff, np.diag(mf.mo_occ)), mf.mo_coeff.T) if CAS == None: CAS_nelec = self.Nel CAS_norb = Norb CAS = 'full' else: CAS_nelec = CAS[0] CAS_norb = CAS[1] print(" Active space: ", CAS) # Replace FCI solver by DMRG solver in CheMPS2 or BLOCK if Orbital_optimization == True: mc = mcscf.CASSCF(mf, CAS_norb, CAS_nelec) else: mc = mcscf.CASCI(mf, CAS_norb, CAS_nelec) if solver == 'CheMPS2': mc.fcisolver = dmrgscf.CheMPS2(mol) elif solver == 'Block': mc.fcisolver = dmrgscf.DMRGCI(mol) if CAS_MO is not None: print(" Active space MOs: ", CAS_MO) mo = mc.sort_mo(CAS_MO) ECAS = mc.kernel(mo)[0] else: ECAS = mc.kernel()[0] ###### Get RDM1 + RDM2 ##### CAS_norb = mc.ncas core_norb = mc.ncore CAS_nelec = mc.nelecas core_MO = mc.mo_coeff[:,:core_norb] CAS_MO = mc.mo_coeff[:,core_norb:core_norb+CAS_norb] casdm1 = mc.fcisolver.make_rdm12(mc.ci, CAS_norb, CAS_nelec)[0] #in CAS space # Transform the casdm1 (in CAS space) to casdm1ortho (orthonormal space). casdm1ortho = np.einsum('ap,pq->aq', CAS_MO, casdm1) casdm1ortho = np.einsum('bq,aq->ab', CAS_MO, casdm1ortho) coredm1 = np.dot(core_MO, core_MO.T) * 2 #in localized space RDM1 = coredm1 + casdm1ortho casdm2 = mc.fcisolver.make_rdm12(mc.ci, CAS_norb, CAS_nelec)[1] #in CAS space # Transform the casdm2 (in CAS space) to casdm2ortho (orthonormal space). casdm2ortho = np.einsum('ap,pqrs->aqrs', CAS_MO, casdm2) casdm2ortho = np.einsum('bq,aqrs->abrs', CAS_MO, casdm2ortho) casdm2ortho = np.einsum('cr,abrs->abcs', CAS_MO, casdm2ortho) casdm2ortho = np.einsum('ds,abcs->abcd', CAS_MO, casdm2ortho) coredm2 = np.zeros([Norb, Norb, Norb, Norb]) #in AO coredm2 += np.einsum('pq,rs-> pqrs',coredm1,coredm1) coredm2 -= 0.5*np.einsum('ps,rq-> pqrs',coredm1,coredm1) effdm2 = np.zeros([Norb, Norb, Norb, Norb]) #in AO effdm2 += 2*np.einsum('pq,rs-> pqrs',casdm1ortho,coredm1) effdm2 -= np.einsum('ps,rq-> pqrs',casdm1ortho,coredm1) RDM2 = coredm2 + casdm2ortho + effdm2 ImpurityEnergy = 0.50 * np.einsum('ij,ij->', RDM1[:Nimp,:], FOCK[:Nimp,:] + self.OEI[:Nimp,:]) \ + 0.125 * np.einsum('ijkl,ijkl->', RDM2[:Nimp,:,:,:], self.TEI[:Nimp,:,:,:]) \ + 0.125 * np.einsum('ijkl,ijkl->', RDM2[:,:Nimp,:,:], self.TEI[:,:Nimp,:,:]) \ + 0.125 * np.einsum('ijkl,ijkl->', RDM2[:,:,:Nimp,:], self.TEI[:,:,:Nimp,:]) \ + 0.125 * np.einsum('ijkl,ijkl->', RDM2[:,:,:,:Nimp], self.TEI[:,:,:,:Nimp]) return (ImpurityEnergy, ECAS, RDM1)