def CAS(self, solver = 'FCI'): ''' CASCI/CASSCF with FCI or DMRG solver ''' Nimp = self.Nimp FOCKcopy = self.FOCK.copy() - self.chempot self.mol.nelectron = self.Nel self.mf.__init__(self.mol) self.mf.get_hcore = lambda *args: FOCKcopy self.mf.get_ovlp = lambda *args: np.eye(self.Norb) self.mf._eri = ao2mo.restore(8, self.TEI, self.Norb) self.mf.scf(self.DMguess) DMloc = np.dot(np.dot(self.mf.mo_coeff, np.diag(self.mf.mo_occ)), self.mf.mo_coeff.T) if (self.mf.converged == False): self.mf.newton().kernel(dm0=DMloc) DMloc = np.dot(np.dot(self.mf.mo_coeff, np.diag(self.mf.mo_occ)), self.mf.mo_coeff.T) if self.cas == None: cas_nelec = self.Nel cas_norb = self.Norb else: cas_nelec = self.cas[0] cas_norb = self.cas[1] # Updating mc object from the new mf, mol objects self.mc.mol = self.mol self.mc._scf = self.mf self.mc.ncas = cas_norb nelecb = (cas_nelec - self.mol.spin)//2 neleca = cas_nelec - nelecb self.mc.nelecas = (neleca, nelecb) ncorelec = self.mol.nelectron - (self.mc.nelecas[0] + self.mc.nelecas[1]) assert(ncorelec % 2 == 0) self.mc.ncore = ncorelec // 2 self.mc.mo_coeff = self.mf.mo_coeff self.mc.mo_energy = self.mf.mo_energy # Define FCI solver if solver == 'CheMPS2': self.mc.fcisolver = dmrgscf.CheMPS2(self.mol) elif solver == 'FCI' and self.e_shift != None: target_SS = 0.5*self.twoS*(0.5*self.twoS + 1) self.mc.fix_spin_(shift = self.e_shift, ss = target_SS) if self.mo is not None and self.solver in ['CASSCF', 'DMRG-SCF']: e_tot, e_cas, civec = self.mc.kernel(self.mo)[:3] elif self.molist is not None: mo = self.mc.sort_mo(self.molist) e_tot, e_cas, civec = self.mc.kernel(mo)[:3] else: e_tot, e_cas, civec = self.mc.kernel()[:3] if self.mc.converged == False: print(' WARNING: The solver is not converged') if solver not in ['CheMPS2', 'Block']: self.SS = self.mc.fcisolver.spin_square(civec, cas_norb, self.mc.nelecas)[0] # Save mo for the next iterations self.mo = self.mc.mo_coeff self.mo_nat = self.mc.cas_natorb()[0] ###### Get RDM1 + RDM2 ##### core_norb = self.mc.ncore core_MO = self.mc.mo_coeff[:,:core_norb] active_MO = self.mc.mo_coeff[:,core_norb:core_norb+cas_norb] casdm1_mo, casdm2_mo = self.mc.fcisolver.make_rdm12(self.mc.ci, cas_norb, self.mc.nelecas) #in CAS(MO) space # Transform the casdm1_mo to local basis casdm1 = lib.einsum('ap,pq->aq', active_MO, casdm1_mo) casdm1 = lib.einsum('bq,aq->ab', active_MO, casdm1) coredm1 = np.dot(core_MO, core_MO.T) * 2 #in local basis RDM1 = coredm1 + casdm1 # Transform the casdm2_mo to local basis casdm2 = lib.einsum('ap,pqrs->aqrs', active_MO, casdm2_mo) casdm2 = lib.einsum('bq,aqrs->abrs', active_MO, casdm2) casdm2 = lib.einsum('cr,abrs->abcs', active_MO, casdm2) casdm2 = lib.einsum('ds,abcs->abcd', active_MO, casdm2) coredm2 = np.zeros([self.Norb, self.Norb, self.Norb, self.Norb]) coredm2 += lib.einsum('pq,rs-> pqrs',coredm1,coredm1) coredm2 -= 0.5*lib.einsum('ps,rq-> pqrs',coredm1,coredm1) effdm2 = np.zeros([self.Norb, self.Norb, self.Norb, self.Norb]) effdm2 += 2*lib.einsum('pq,rs-> pqrs',casdm1,coredm1) effdm2 -= lib.einsum('ps,rq-> pqrs',casdm1,coredm1) RDM2 = coredm2 + casdm2 + effdm2 # Compute the impurity energy ImpurityEnergy = 0.50 * lib.einsum('ij,ij->', RDM1[:Nimp,:], self.FOCK[:Nimp,:] + self.OEI[:Nimp,:]) \ + 0.125 * lib.einsum('ijkl,ijkl->', RDM2[:Nimp,:,:,:], self.TEI[:Nimp,:,:,:]) \ + 0.125 * lib.einsum('ijkl,ijkl->', RDM2[:,:Nimp,:,:], self.TEI[:,:Nimp,:,:]) \ + 0.125 * lib.einsum('ijkl,ijkl->', RDM2[:,:,:Nimp,:], self.TEI[:,:,:Nimp,:]) \ + 0.125 * lib.einsum('ijkl,ijkl->', RDM2[:,:,:,:Nimp], self.TEI[:,:,:,:Nimp]) # Compute total energy e_cell = self.kmf_ecore + ImpurityEnergy return (e_cell, e_tot, RDM1)
def test_mc2step_6o6e(self): mc = mcscf.CASSCF(m, 6, 6) mc.fcisolver = dmrgscf.CheMPS2(mol) emc = mc.mc2step()[0] self.assertAlmostEqual(emc, -108.980105451388, 7)
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)
def test_mc2step_4o4e(self): mc = mcscf.CASSCF(m, 4, 4) mc.fcisolver = dmrgscf.CheMPS2(mol) emc = mc.mc2step()[0] self.assertAlmostEqual(emc, -108.913786407955, 7)
max_cycle_micro=1, conv_tol=1e-5, conv_tol_grad=1e-4).run() # # Note: the stream operations are applied in the above line. This one line # code is equivalent to the following serial statements # #mc = mcscf.CASSCF(mf, 6, 6) #mc.max_cycle_macro = 5 #mc.max_cycle_micro = 1 #mc.conv_tol = 1e-5 #mc.conv_tol_grad = 1e-4 #mc.kernel() mo = mc.mo_coeff mol.stdout.write('\n*********** Call DMRGSCF **********\n') # # Use CheMPS2 program as the FCI Solver # mc = mcscf.CASSCF(mf, 8, 8) mc.fcisolver = dmrgscf.CheMPS2(mol) mc.fcisolver.dmrg_e_convergence = 1e-9 emc = mc.mc2step(mo)[0] # # Use Block program as the FCI Solver # mc = dmrgscf.dmrgci.DMRGSCF(mf, 8, 8) emc = mc.kernel(mo)[0] print(emc)