Beispiel #1
0
    def doexact( self, chempot_imp=0.0 ):
    
        OneRDM = self.helper.construct1RDM_loc( self.doSCF, self.umat )
        self.energy   = 0.0
        self.imp_1RDM = []
        self.dmetOrbs = []
        if ( self.doDET == True ) and ( self.doDET_NO == True ):
            self.NOvecs = []
            self.NOdiag = []
        
        maxiter = len( self.impClust )
        if ( self.TransInv == True ):
            maxiter = 1
            
        remainingOrbs = np.ones( [ len( self.impClust[ 0 ] ) ], dtype=float )
        
        for counter in range( maxiter ):
        
            impurityOrbs = self.impClust[ counter ]
            numImpOrbs   = np.sum( impurityOrbs )
            if ( self.BATH_ORBS == None ):
                numBathOrbs = numImpOrbs
            else:
                numBathOrbs = self.BATH_ORBS[ counter ]
            numBathOrbs, loc2dmet, core1RDM_dmet = self.helper.constructbath( OneRDM, impurityOrbs, numBathOrbs )
            if ( self.BATH_ORBS == None ):
                core_cutoff = 0.01
            else:
                core_cutoff = 0.5
            for cnt in range(len(core1RDM_dmet)):
                if ( core1RDM_dmet[ cnt ] < core_cutoff ):
                    core1RDM_dmet[ cnt ] = 0.0
                elif ( core1RDM_dmet[ cnt ] > 2.0 - core_cutoff ):
                    core1RDM_dmet[ cnt ] = 2.0
                else:
                    print "Bad DMET bath orbital selection: trying to put a bath orbital with occupation", core1RDM_dmet[ cnt ], "into the environment :-(."
                    assert( 0 == 1 )

            Norb_in_imp  = numImpOrbs + numBathOrbs
            Nelec_in_imp = int(round(self.ints.Nelec - np.sum( core1RDM_dmet )))
            core1RDM_loc = np.dot( np.dot( loc2dmet, np.diag( core1RDM_dmet ) ), loc2dmet.T )
            
            self.dmetOrbs.append( loc2dmet[ :, :Norb_in_imp ] ) # Impurity and bath orbitals only
            assert( Norb_in_imp <= self.Norb )
            dmetOEI  = self.ints.dmet_oei(  loc2dmet, Norb_in_imp )
            dmetFOCK = self.ints.dmet_fock( loc2dmet, Norb_in_imp, core1RDM_loc )
            dmetTEI  = self.ints.dmet_tei(  loc2dmet, Norb_in_imp )
            
            if ( self.NI_hack == True ):
                dmetTEI[:,:,:,numImpOrbs:]=0.0
                dmetTEI[:,:,numImpOrbs:,:]=0.0
                dmetTEI[:,numImpOrbs:,:,:]=0.0
                dmetTEI[numImpOrbs:,:,:,:]=0.0
            
                umat_rotated = np.dot(np.dot(loc2dmet.T, self.umat), loc2dmet)
                umat_rotated[:numImpOrbs,:numImpOrbs]=0.0
                dmetOEI += umat_rotated[:Norb_in_imp,:Norb_in_imp]
                dmetFOCK = np.array( dmetOEI, copy=True )
            
            print "DMET::exact : Performing a (", Norb_in_imp, "orb,", Nelec_in_imp, "el ) DMET active space calculation."
            if ( self.method == 'ED' ):
                import chemps2
                IMP_energy, IMP_1RDM = chemps2.solve( 0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp, numImpOrbs, chempot_imp )
            if ( self.method == 'CC' ):
                import pyscf_cc
                assert( Nelec_in_imp % 2 == 0 )
                DMguessRHF = self.ints.dmet_init_guess_rhf( loc2dmet, Norb_in_imp, Nelec_in_imp/2, numImpOrbs, chempot_imp )
                IMP_energy, IMP_1RDM = pyscf_cc.solve( 0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp, numImpOrbs, DMguessRHF, self.CC_E_TYPE, chempot_imp )
            if ( self.method == 'MP2' ):
                import pyscf_mp2
                assert( Nelec_in_imp % 2 == 0 )
                DMguessRHF = self.ints.dmet_init_guess_rhf( loc2dmet, Norb_in_imp, Nelec_in_imp/2, numImpOrbs, chempot_imp )
                IMP_energy, IMP_1RDM = pyscf_mp2.solve( 0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp, numImpOrbs, DMguessRHF, chempot_imp )
            self.energy += IMP_energy
            self.imp_1RDM.append( IMP_1RDM )
            if ( self.doDET == True ) and ( self.doDET_NO == True ):
                RDMeigenvals, RDMeigenvecs = np.linalg.eigh( IMP_1RDM[ :numImpOrbs, :numImpOrbs ] )
                self.NOvecs.append( RDMeigenvecs )
                self.NOdiag.append( RDMeigenvals )
                
            remainingOrbs -= impurityOrbs
        
        if ( self.doDET == True ) and ( self.doDET_NO == True ):
            self.NOrotation = self.constructNOrotation()
        
        Nelectrons = 0.0
        for counter in range( maxiter ):
            Nelectrons += np.trace( self.imp_1RDM[counter][ :self.imp_size[counter], :self.imp_size[counter] ] )
        if ( self.TransInv == True ):
            Nelectrons = Nelectrons * len( self.impClust )
            self.energy = self.energy * len( self.impClust )
            remainingOrbs[:] = 0
            
        # When an incomplete impurity tiling is used for the Hamiltonian, self.energy should be augmented with the remaining HF part
        if ( np.sum( remainingOrbs ) != 0 ):
        
            if ( self.CC_E_TYPE == 'CASCI' ):
                '''
                If CASCI is passed as CC energy type, the energy of the one and only full impurity Hamiltonian is returned.
                The one-electron integrals of this impurity Hamiltonian is the full Fock operator of the CORE orbitals!
                The constant part of the energy still needs to be added: sum_occ ( 2 * OEI[occ,occ] + JK[occ,occ] )
                                                                         = einsum( core1RDM_loc, OEI ) + 0.5 * einsum( core1RDM_loc, JK )
                                                                         = 0.5 * einsum( core1RDM_loc, OEI + FOCK )
                '''
                assert( maxiter == 1 )
                transfo = np.eye( self.Norb, dtype=float )
                totalOEI  = self.ints.dmet_oei(  transfo, self.Norb )
                totalFOCK = self.ints.dmet_fock( transfo, self.Norb, core1RDM_loc )
                self.energy += 0.5 * np.einsum( 'ij,ij->', core1RDM_loc, totalOEI + totalFOCK )
                Nelectrons = np.trace( self.imp_1RDM[ 0 ] ) + np.trace( core1RDM_loc ) # Because full active space is used to compute the energy
            else:
                transfo = np.eye( self.Norb, dtype=float )
                totalOEI  = self.ints.dmet_oei(  transfo, self.Norb )
                totalFOCK = self.ints.dmet_fock( transfo, self.Norb, OneRDM )
                self.energy += 0.5 * np.einsum( 'ij,ij->', OneRDM[remainingOrbs==1,:], \
                         totalOEI[remainingOrbs==1,:] + totalFOCK[remainingOrbs==1,:] )
                Nelectrons += np.trace( (OneRDM[remainingOrbs==1,:])[:,remainingOrbs==1] )
            remainingOrbs[ remainingOrbs==1 ] -= 1
        assert( np.all( remainingOrbs == 0 ) )
            
        self.energy += self.ints.const()
        return Nelectrons
Beispiel #2
0
    def hl_solver (self, chempot=0., threshold=1.0e-12):
#        energy = self.mol.energy_nuc()
        energy = 0.
        nelec  = 0.

        rdm_ao  = np.dot(self.cf, self.cf.T)
        AX_val  = np.dot(self.Sf, self.A_val)
        rdm_val = np.dot(AX_val.T, np.dot(rdm_ao, AX_val))

        print ( "shapes" )
        print ( "cf",self.cf.shape )
        print ( "rdm_ao",rdm_ao.shape )
        print ( "AX_val",AX_val.shape )
        print ( "rdm_val",rdm_val.shape )

        if(not self.parallel):
           myrange = range(self.nimp)
        else:
           from mpi4py import MPI
           comm = MPI.COMM_WORLD
           rank = MPI.COMM_WORLD.Get_rank()
           size = MPI.COMM_WORLD.Get_size()
           myrange = range(rank,rank+1)

        for i in myrange:
            # prepare orbital indexing
            imp_val   = np.zeros((self.nvl,), dtype=bool)
            imp_val_  = np.zeros((self.nvl,), dtype=bool)
            if self.nc > 0:
                imp_core  = np.zeros((self.nc,),  dtype=bool)
                imp_core_ = np.zeros((self.nc,),  dtype=bool)
            if self.nvt > 0:
                imp_virt  = np.zeros((self.nvt,), dtype=bool)
                imp_virt_ = np.zeros((self.nvt,), dtype=bool)
            for k in range(self.mol.natm):
                if self.imp_atx[i][k]:
                    imp_val[self.at_val == k]   = True
                    if self.nc > 0:
                        imp_core[self.at_core == k] = True
                    if self.nvt > 0:
                        imp_virt[self.at_virt == k] = True
                if self.imp_at[i][k]:
                    imp_val_[self.at_val == k]   = True
                    if self.nc > 0:
                        imp_core_[self.at_core == k] = True
                    if self.nvt > 0:
                        imp_virt_[self.at_virt == k] = True
            print("imp val", imp_val)

            # embedding
            cf_tmp, ncore, nact, ImpOrbs_x = \
                embedding.embedding (rdm_val, imp_val, \
                                     threshold=self.thresh, \
                                     transform_imp='hf')
            print("Doing EMBEDDING")
            print("cf_tmp", cf_tmp)
            print("ncore, nact", ncore, nact)
            print("ImpOrbs_x", ImpOrbs_x)
            cf_tmp = np.dot(self.A_val, cf_tmp)
            print("cf_tmp", cf_tmp)

            # localize imp+bath orbitals
            if self.method == 'dmrg':
                XR = np.random.rand(nact,nact)
                XR -= XR.T
                XS = sla.expm(0.01*XR)
                cf_ib = np.dot(cf_tmp[:,ncore:ncore+nact], XS)
                # loc = localizer.localizer (self.mol, cf_ib, 'boys')
                # loc.verbose = 5
                # cf_ib = loc.optimize(threshold=1.0e-5)
                # del loc
                cf_ib = lo.Boys(mol, cd_ib).kernel()

                R = np.dot(cf_ib.T, \
                           np.dot(self.Sf, cf_tmp[:,ncore:ncore+nact]))
                print ( np.allclose(np.dot(cf_tmp[:,ncore:ncore+nact], \
                                         ImpOrbs_x), \
                                  np.dot(cf_ib, np.dot(R, ImpOrbs_x))) )
                ImpOrbs_x = np.dot(R, ImpOrbs_x)
                cf_tmp[:,ncore:ncore+nact] = cf_ib
                print ( cf_ib )

            # prepare ImpOrbs
            ni_val = nact
            nj_val = np.count_nonzero(imp_val_)
            if self.nc > 0:
                ni_core = np.count_nonzero(imp_core)
                nj_core = np.count_nonzero(imp_core_)
            else:
                ni_core = nj_core = 0
            if self.nvt > 0:
                ni_virt = np.count_nonzero(imp_virt)
                nj_virt = np.count_nonzero(imp_virt_)
            else:
                ni_virt = nj_virt = 0

            ii = 0
            ImpOrbs = np.zeros((ni_val+ni_core+ni_virt,\
                                nj_val+nj_core+nj_virt,))
            if self.nc > 0:
                j = 0
                for i in range(self.nc):
                    if imp_core[i] and imp_core_[i]:
                        ImpOrbs[j,ii] = 1.
                        ii += 1
                    if imp_core[i]:
                        j += 1
            j = 0
            for i in range(self.nvl):
                if imp_val[i] and imp_val_[i]:
                    ImpOrbs[ni_core:ni_core+ni_val,ii] = ImpOrbs_x[:,j]
                    ii += 1
                if imp_val[i]:
                    j += 1
            if self.nvt > 0:
                j = 0
                for i in range(self.nvt):
                    if imp_virt[i] and imp_virt_[i]:
                        ImpOrbs[ni_core+ni_val+j,ii] = 1.
                        ii += 1
                    if imp_virt[i]:
                        j += 1

            # prepare orbitals
            cf_core = cf_virt = None
            if self.nc > 0:
                cf_core = self.A_core[:,imp_core]
            if self.nvt > 0:
                cf_virt = self.A_virt[:,imp_virt]
            cf_val = cf_tmp[:,ncore:ncore+nact]

            if cf_core is not None and cf_virt is not None:
                cf = np.hstack ((cf_core, cf_val, cf_virt,))
            elif cf_core is not None:
                cf = np.hstack ((cf_core, cf_val,))
            elif cf_virt is not None:
                cf = np.hstack ((cf_val, cf_virt,))
            else:
                cf = cf_val

            # prepare core
            if self.nc > 0:
                Ac_ = self.A_core[:,~(imp_core)]
                X_core = np.hstack((Ac_, cf_tmp[:,:ncore],))
            else:
                X_core = cf_tmp[:,:ncore]

            n_orth = cf.shape[1]
            if cf_virt is not None:
                n_orth -= cf_virt.shape[1]
            print("x-core", X_core)
            print("cf b4 solver", cf)
            print("imporbs", ImpOrbs)

            if self.method == 'hf':
                nel_, en_ = \
                    pyscf_hf.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth)

            elif self.method == 'cc':
                nel_, en_ = \
                    pyscf_cc.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth,FrozenPot=self.FrozenPot)

            elif self.method == 'ccsd(t)':
                nel_, en_ = \
                    pyscf_ccsdt.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth)

            elif self.method == 'mp2':
                nel_, en_ = \
                    pyscf_mp2.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth,FrozenPot=self.FrozenPot)


            elif self.method == 'dfmp2':
                nel_, en_ = \
                    pyscf_dfmp2.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth,FrozenPot=self.FrozenPot, mf_tot=self.mf_tot)

            elif self.method == 'dfmp2_testing':
                nel_, en_ = \
                    dfmp2_testing.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth,FrozenPot=self.FrozenPot, mf_tot=self.mf_tot)

            elif self.method == 'dfmp2_testing2':
                # print(self.mol)
                # print(2*(self.nup-X_core.shape[1]))
                # print(X_core.shape)
                # print(cf.shape)
                # print(ImpOrbs.shape)
                # print(n_orth)
                nel_, en_ = \
                    dfmp2_testing2.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth,FrozenPot=self.FrozenPot ) #, mf_tot=self.mf_tot)

            elif self.method == 'dfmp2_testing3':
                nel_, en_ = \
                    dfmp2_testing3.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth,FrozenPot=self.FrozenPot, mf_tot=self.mf_tot)

            elif self.method == 'dfmp2_testing4':
                nel_, en_ = \
                    dfmp2_testing4.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth,FrozenPot=self.FrozenPot, mf_tot=self.mf_tot)


            elif self.method == 'fci':
                nel_, en_ = \
                    pyscf_fci.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth)

            elif self.method == 'dmrg':
                nel_, en_ = \
                    dmrg.solve (self.mol, \
                                2*(self.nup-X_core.shape[1]), \
                                X_core, cf, ImpOrbs, chempot=chempot, \
                                n_orth=n_orth)

            nelec  += nel_
            energy += en_

        if(self.parallel):
           nelec_tot  = comm.reduce(nelec, op=MPI.SUM,root=0)
           energy_tot = comm.reduce(energy,op=MPI.SUM,root=0)
           if(rank==0):
              energy_tot    += self.mol.energy_nuc()+self.e_core
           nelec  = comm.bcast(nelec_tot, root=0)
           energy = comm.bcast(energy_tot,root=0)
           comm.barrier()
           if(rank==0): print ( 'DMET energy = ', energy )
        else:
           energy+=self.mol.energy_nuc()+self.e_core
           print ( 'DMET energy = ', energy )

        return nelec
Beispiel #3
0
    def doexact( self, chempot_imp=0.0 ):
        
        OneRDM = self.helper.construct1RDM_loc( self.doSCF, self.umat )
        self.energy   = 0.0
        self.imp_1RDM = []
        self.dmetOrbs = []
        if ( self.doDET == True ) and ( self.doDET_NO == True ):
            self.NOvecs = []
            self.NOdiag = []
        
        maxiter = len( self.impClust )
        if ( self.TransInv == True ):
            maxiter = 1
            
        remainingOrbs = np.ones( [ len( self.impClust[ 0 ] ) ], dtype=float )
        
        for counter in range( maxiter ):
            
            flag_rhf = np.sum(self.impClust[ counter ]) < 0
            impurityOrbs = np.abs(self.impClust[ counter ])
            numImpOrbs   = np.sum( impurityOrbs )
            if ( self.BATH_ORBS == None ):
                numBathOrbs = numImpOrbs
            else:
                numBathOrbs = self.BATH_ORBS[ counter ]
            numBathOrbs, loc2dmet, core1RDM_dmet = self.helper.constructbath( OneRDM, impurityOrbs, numBathOrbs )
            
            if ( self.BATH_ORBS == None ):
                core_cutoff = 0.01
            else:
                core_cutoff = 0.5
            for cnt in range(len(core1RDM_dmet)):
                if ( core1RDM_dmet[ cnt ] < core_cutoff ):
                    core1RDM_dmet[ cnt ] = 0.0
                elif ( core1RDM_dmet[ cnt ] > 2.0 - core_cutoff ):
                    core1RDM_dmet[ cnt ] = 2.0
                else:
                    print "Bad DMET bath orbital selection: trying to put a bath orbital with occupation", core1RDM_dmet[ cnt ], "into the environment :-(."
                    assert( 0 == 1 )
                    
            Norb_in_imp  = numImpOrbs + numBathOrbs
            Nelec_in_imp = int(round(self.ints.Nelec - np.sum( core1RDM_dmet )))
            core1RDM_loc = np.dot( np.dot( loc2dmet, np.diag( core1RDM_dmet ) ), loc2dmet.T )
            
            self.dmetOrbs.append( loc2dmet[ :, :Norb_in_imp ] ) # Impurity and bath orbitals only
            assert( Norb_in_imp <= self.Norb )
            dmetOEI  = self.ints.dmet_oei(  loc2dmet, Norb_in_imp )
            dmetFOCK = self.ints.dmet_fock( loc2dmet, Norb_in_imp, core1RDM_loc )
            dmetTEI  = self.ints.dmet_tei(  loc2dmet, Norb_in_imp )
            
            if ( self.NI_hack == True ):
                dmetTEI[:,:,:,numImpOrbs:]=0.0
                dmetTEI[:,:,numImpOrbs:,:]=0.0
                dmetTEI[:,numImpOrbs:,:,:]=0.0
                dmetTEI[numImpOrbs:,:,:,:]=0.0
            
                umat_rotated = np.dot(np.dot(loc2dmet.T, self.umat), loc2dmet)
                umat_rotated[:numImpOrbs,:numImpOrbs]=0.0
                dmetOEI += umat_rotated[:Norb_in_imp,:Norb_in_imp]
                dmetFOCK = np.array( dmetOEI, copy=True )
            
            # print "DMET::exact : Performing a (", Norb_in_imp, "orb,", Nelec_in_imp, "el ) DMET active space calculation."
            if ( flag_rhf ):
                import pyscf_rhf
                DMguessRHF = self.ints.dmet_init_guess_rhf( loc2dmet, Norb_in_imp, Nelec_in_imp/2, numImpOrbs, chempot_imp )
                IMP_energy, IMP_1RDM = pyscf_rhf.solve( 0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp, numImpOrbs, DMguessRHF, chempot_imp )
            elif ( self.method == 'ED' ):
                print "no chemps2 solver"
                #import chemps2
                #IMP_energy, IMP_1RDM = chemps2.solve( 0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp, numImpOrbs, chempot_imp )
            elif ( self.method == 'CC' ):
                import pyscf_cc
                assert( Nelec_in_imp % 2 == 0 )
                DMguessRHF = self.ints.dmet_init_guess_rhf( loc2dmet, Norb_in_imp, Nelec_in_imp/2, numImpOrbs, chempot_imp )
                IMP_energy, IMP_1RDM = pyscf_cc.solve( 0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp, numImpOrbs, DMguessRHF, self.CC_E_TYPE, chempot_imp )
            elif ( self.method == 'FCI' ):
                import pyscf_fci
                assert( Nelec_in_imp % 2 == 0)
                DMguessRHF = self.ints.dmet_init_guess_rhf( loc2dmet, Norb_in_imp, Nelec_in_imp/2, numImpOrbs, chempot_imp )
                IMP_energy, IMP_1RDM = pyscf_fci.solve( 0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp, numImpOrbs, DMguessRHF, chempot_imp)
            elif ( self.method == 'MP2' ):
                import pyscf_mp2
                assert( Nelec_in_imp % 2 == 0 )
                DMguessRHF = self.ints.dmet_init_guess_rhf( loc2dmet, Norb_in_imp, Nelec_in_imp/2, numImpOrbs, chempot_imp )
                IMP_energy, IMP_1RDM = pyscf_mp2.solve( 0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp, numImpOrbs, DMguessRHF, chempot_imp )
            self.energy += IMP_energy
            self.imp_1RDM.append( IMP_1RDM )
            if ( self.doDET == True ) and ( self.doDET_NO == True ):
                RDMeigenvals, RDMeigenvecs = np.linalg.eigh( IMP_1RDM[ :numImpOrbs, :numImpOrbs ] )
                self.NOvecs.append( RDMeigenvecs )
                self.NOdiag.append( RDMeigenvals )
                
            remainingOrbs -= impurityOrbs
        
        if ( self.doDET == True ) and ( self.doDET_NO == True ):
            self.NOrotation = self.constructNOrotation()
        
        Nelectrons = 0.0
        
        for counter in range( maxiter ):
            Nelectrons += np.trace( self.imp_1RDM[counter][ :self.imp_size[counter], :self.imp_size[counter] ] )
        if ( self.TransInv == True ):
            Nelectrons = Nelectrons * len( self.impClust )
            self.energy = self.energy * len( self.impClust )
            remainingOrbs[:] = 0
            
        # When an incomplete impurity tiling is used for the Hamiltonian, self.energy should be augmented with the remaining HF part
        if ( np.sum( remainingOrbs ) != 0 ):
        
            if ( self.CC_E_TYPE == 'CASCI' ):
                '''
                If CASCI is passed as CC energy type, the energy of the one and only full impurity Hamiltonian is returned.
                The one-electron integrals of this impurity Hamiltonian is the full Fock operator of the CORE orbitals!
                The constant part of the energy still needs to be added: sum_occ ( 2 * OEI[occ,occ] + JK[occ,occ] )
                                                                         = einsum( core1RDM_loc, OEI ) + 0.5 * einsum( core1RDM_loc, JK )
                                                                         = 0.5 * einsum( core1RDM_loc, OEI + FOCK )
                '''
                assert( maxiter == 1 )
                transfo = np.eye( self.Norb, dtype=float )
                totalOEI  = self.ints.dmet_oei(  transfo, self.Norb )
                totalFOCK = self.ints.dmet_fock( transfo, self.Norb, core1RDM_loc )
                self.energy += 0.5 * np.einsum( 'ij,ij->', core1RDM_loc, totalOEI + totalFOCK )
                Nelectrons = np.trace( self.imp_1RDM[ 0 ] ) + np.trace( core1RDM_loc ) # Because full active space is used to compute the energy
            else:
                #transfo = np.eye( self.Norb, dtype=float )
                #totalOEI  = self.ints.dmet_oei(  transfo, self.Norb )
                #totalFOCK = self.ints.dmet_fock( transfo, self.Norb, OneRDM )
                #self.energy += 0.5 * np.einsum( 'ij,ij->', OneRDM[remainingOrbs==1,:], \
                #         totalOEI[remainingOrbs==1,:] + totalFOCK[remainingOrbs==1,:] )
                #Nelectrons += np.trace( (OneRDM[remainingOrbs==1,:])[:,remainingOrbs==1] )

                assert (np.array_equal(self.ints.active, np.ones([self.ints.mol.nao_nr()], dtype=int)))

                from pyscf import scf
                from types import MethodType
                mol_ = self.ints.mol
                mf_  = scf.RHF(mol_)

                impOrbs = remainingOrbs==1
                xorb = np.dot(mf_.get_ovlp(), self.ints.ao2loc)
                hc  = -chempot_imp * np.dot(xorb[:,impOrbs], xorb[:,impOrbs].T)
                dm0 = np.dot(self.ints.ao2loc, np.dot(OneRDM, self.ints.ao2loc.T))

                def mf_hcore (self, mol=None):
                    if mol is None: mol = self.mol
                    return scf.hf.get_hcore(mol) + hc
                mf_.get_hcore = MethodType(mf_hcore, mf_)
                mf_.scf(dm0)
                assert (mf_.converged)

                rdm1 = mf_.make_rdm1()
                jk   = mf_.get_veff(dm=rdm1)

                xorb = np.dot(mf_.get_ovlp(), self.ints.ao2loc)
                rdm1 = np.dot(xorb.T, np.dot(rdm1, xorb))
                oei  = np.dot(self.ints.ao2loc.T, np.dot(mf_.get_hcore()-hc, self.ints.ao2loc))
                jk   = np.dot(self.ints.ao2loc.T, np.dot(jk, self.ints.ao2loc))

                ImpEnergy = \
                   + 0.50 * np.einsum('ji,ij->', rdm1[:,impOrbs], oei[impOrbs,:]) \
                   + 0.50 * np.einsum('ji,ij->', rdm1[impOrbs,:], oei[:,impOrbs]) \
                   + 0.25 * np.einsum('ji,ij->', rdm1[:,impOrbs], jk[impOrbs,:]) \
                   + 0.25 * np.einsum('ji,ij->', rdm1[impOrbs,:], jk[:,impOrbs])
                self.energy += ImpEnergy
                Nelectrons += np.trace(rdm1[np.ix_(impOrbs,impOrbs)])

            remainingOrbs[ remainingOrbs==1 ] -= 1
        assert( np.all( remainingOrbs == 0 ) )
        
        self.energy += self.ints.const()
        return Nelectrons
Beispiel #4
0
    def doexact(self, chempot_imp=0.0):
        OneRDM = self.helper.construct1RDM_loc(
            self.doSCF, self.umat
        )  #HP: construct 1rdm (in AO) for the total system from the Fock matrix in local ao basis. projected on atoms?
        self.energy = 0.0  #This OneRDM will be used to construct the bath
        self.imp_1RDM = []
        self.dmetOrbs = []
        if (self.doDET == True) and (self.doDET_NO == True):
            self.NOvecs = []
            self.NOdiag = []

        maxiter = len(self.impClust)
        if (self.TransInv == True):
            maxiter = 1

        remainingOrbs = np.ones([len(self.impClust[0])], dtype=float)

        E_frag = []  #HP: to export fragment energies
        for counter in range(maxiter):

            flag_rhf = np.sum(
                self.impClust[counter]
            ) < 0  # the elements of self.impClust can be diffent to 1 and negative?
            impurityOrbs = np.abs(self.impClust[counter])
            numImpOrbs = np.sum(impurityOrbs)
            if (self.BATH_ORBS != None and self.BATH_ORBS[counter] != 0):
                numBathOrbs = self.BATH_ORBS[counter]
            else:
                numBathOrbs = numImpOrbs

            numBathOrbs, loc2dmet, core1RDM_dmet = self.helper.constructbath(
                OneRDM, impurityOrbs, numBathOrbs)
            if (self.BATH_ORBS == None):
                core_cutoff = 0.01
            else:
                core_cutoff = 0.5
            for cnt in range(len(core1RDM_dmet)):
                if (core1RDM_dmet[cnt] < core_cutoff):
                    core1RDM_dmet[cnt] = 0.0
                elif (core1RDM_dmet[cnt] > 2.0 - core_cutoff):
                    core1RDM_dmet[cnt] = 2.0
                else:
                    print(
                        "Bad DMET bath orbital selection: trying to put a bath orbital with occupation",
                        core1RDM_dmet[cnt], "into the environment :-(.")
                    assert (0 == 1)

            Norb_in_imp = numImpOrbs + numBathOrbs
            Nelec_in_imp = int(round(self.ints.Nelec - np.sum(core1RDM_dmet)))
            core1RDM_loc = np.dot(np.dot(loc2dmet, np.diag(core1RDM_dmet)),
                                  loc2dmet.T)
            self.dmetOrbs.append(
                loc2dmet[:, :Norb_in_imp])  # Impurity and bath orbitals only
            assert (Norb_in_imp <= self.Norb)
            dmetOEI = self.ints.dmet_oei(loc2dmet, Norb_in_imp)
            dmetFOCK = self.ints.dmet_fock(loc2dmet, Norb_in_imp, core1RDM_loc)
            dmetTEI = self.ints.dmet_tei(loc2dmet, Norb_in_imp)

            if (self.NI_hack == True):
                dmetTEI[:, :, :, numImpOrbs:] = 0.0
                dmetTEI[:, :, numImpOrbs:, :] = 0.0
                dmetTEI[:, numImpOrbs:, :, :] = 0.0
                dmetTEI[numImpOrbs:, :, :, :] = 0.0

                umat_rotated = np.dot(np.dot(loc2dmet.T, self.umat), loc2dmet)
                umat_rotated[:numImpOrbs, :numImpOrbs] = 0.0
                dmetOEI += umat_rotated[:Norb_in_imp, :Norb_in_imp]
                dmetFOCK = np.array(dmetOEI, copy=True)

            print("DMET::exact : Performing a (", Norb_in_imp, "orb,",
                  Nelec_in_imp, "el ) DMET active space calculation.")
            if (flag_rhf):
                import pyscf_rhf
                DMguessRHF = self.ints.dmet_init_guess_rhf(
                    loc2dmet, Norb_in_imp, Nelec_in_imp // 2, numImpOrbs,
                    chempot_imp)
                IMP_energy, IMP_1RDM = pyscf_rhf.solve(
                    0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp,
                    numImpOrbs, DMguessRHF, self.CC_E_TYPE, chempot_imp)
            elif (flag_rhf and self.UHF == True):
                import pyscf_uhf
                DMguessRHF = self.ints.dmet_init_guess_rhf(
                    loc2dmet, Norb_in_imp, Nelec_in_imp // 2, numImpOrbs,
                    chempot_imp)
                IMP_energy, IMP_1RDM = pyscf_uhf.solve(0.0, dmetOEI, dmetFOCK,
                                                       dmetTEI, Norb_in_imp,
                                                       Nelec_in_imp,
                                                       numImpOrbs, DMguessRHF,
                                                       chempot_imp)
            elif (self.method == 'ED'):
                import chemps2
                IMP_energy, IMP_1RDM = chemps2.solve(0.0, dmetOEI, dmetFOCK,
                                                     dmetTEI, Norb_in_imp,
                                                     Nelec_in_imp, numImpOrbs,
                                                     chempot_imp)
            elif (self.method == 'CC'):
                import pyscf_cc
                assert (Nelec_in_imp % 2 == 0)
                DMguessRHF = self.ints.dmet_init_guess_rhf(
                    loc2dmet, Norb_in_imp, Nelec_in_imp // 2, numImpOrbs,
                    chempot_imp)
                IMP_energy, IMP_1RDM = pyscf_cc.solve(
                    0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp,
                    numImpOrbs, DMguessRHF, self.CC_E_TYPE, chempot_imp)
            elif (self.method == 'MP2'):
                import pyscf_mp2
                assert (Nelec_in_imp % 2 == 0)
                DMguessRHF = self.ints.dmet_init_guess_rhf(
                    loc2dmet, Norb_in_imp, Nelec_in_imp // 2, numImpOrbs,
                    chempot_imp)
                IMP_energy, IMP_1RDM = pyscf_mp2.solve(0.0, dmetOEI, dmetFOCK,
                                                       dmetTEI, Norb_in_imp,
                                                       Nelec_in_imp,
                                                       numImpOrbs, DMguessRHF,
                                                       chempot_imp)
            elif (self.method == 'CASSCF'):
                import pyscf_casscf
                assert (Nelec_in_imp % 2 == 0)
                DMguessRHF = self.ints.dmet_init_guess_rhf(
                    loc2dmet, Norb_in_imp, Nelec_in_imp // 2, numImpOrbs,
                    chempot_imp)
                IMP_energy, IMP_1RDM, MOmf, MO, MOnat, OccNum = pyscf_casscf.solve(
                    0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp,
                    numImpOrbs, self.impCAS, self.CASlist, DMguessRHF,
                    self.CC_E_TYPE, chempot_imp)

                self.MOmf = MOmf
                self.MO = MO  #the MO is updated eveytime the CASSCF solver called
                self.MOnat = MOnat
                self.loc2dmet = loc2dmet  #similar to MO		[:,:Norb_in_imp]
                self.OccNum = OccNum
            elif (self.method == 'RHF'):
                import pyscf_rhf
                assert (Nelec_in_imp % 2 == 0)
                DMguessRHF = self.ints.dmet_init_guess_rhf(
                    loc2dmet, Norb_in_imp, Nelec_in_imp // 2, numImpOrbs,
                    chempot_imp)
                IMP_energy, IMP_1RDM = pyscf_rhf.solve(
                    0.0, dmetOEI, dmetFOCK, dmetTEI, Norb_in_imp, Nelec_in_imp,
                    numImpOrbs, DMguessRHF, self.CC_E_TYPE, chempot_imp)
            self.energy += IMP_energy
            E_frag.append(IMP_energy)
            self.imp_1RDM.append(IMP_1RDM)
            if (self.doDET == True) and (self.doDET_NO == True):
                RDMeigenvals, RDMeigenvecs = np.linalg.eigh(
                    IMP_1RDM[:numImpOrbs, :numImpOrbs])
                self.NOvecs.append(RDMeigenvecs)
                self.NOdiag.append(RDMeigenvals)

            remainingOrbs -= impurityOrbs

        if (self.doDET == True) and (self.doDET_NO == True):
            self.NOrotation = self.constructNOrotation()

        Nelectrons = 0.0
        Nefrag = []
        for counter in range(maxiter):
            Nelectrons += np.trace(
                self.imp_1RDM[counter]
                [:self.imp_size[counter], :self.imp_size[counter]])
            Nefrag.append(
                np.trace(self.imp_1RDM[counter]
                         [:self.imp_size[counter], :self.imp_size[counter]]))

        if (self.TransInv == True):
            Nelectrons = Nelectrons * len(self.impClust)
            self.energy = self.energy * len(self.impClust)
            remainingOrbs[:] = 0

#HungPham
        print('Fragment energies:', E_frag)
        print('Fragment electrons:', Nefrag)
        E1 = self.energy
        print('DEBUG Energy before adding up envi contribution:', E1)

        # When an incomplete impurity tiling is used for the Hamiltonian, self.energy should be augmented with the remaining HF part
        if (np.sum(remainingOrbs) != 0):

            if (self.CC_E_TYPE == 'CASCI'):
                '''
                If CASCI is passed as CC energy type, the energy of the one and only full impurity Hamiltonian is returned.
                The one-electron integrals of this impurity Hamiltonian is the full Fock operator of the CORE orbitals!
                The constant part of the energy still needs to be added: sum_occ ( 2 * OEI[occ,occ] + JK[occ,occ] )
                                                                         = einsum( core1RDM_loc, OEI ) + 0.5 * einsum( core1RDM_loc, JK )
                                                                         = 0.5 * einsum( core1RDM_loc, OEI + FOCK )
                '''
                assert (maxiter == 1)
                print("-----NOTE: CASCI or Single embedding is used-----")
                transfo = np.eye(self.Norb, dtype=float)
                totalOEI = self.ints.dmet_oei(transfo, self.Norb)
                totalFOCK = self.ints.dmet_fock(transfo, self.Norb,
                                                core1RDM_loc)
                self.energy += 0.5 * np.einsum('ij,ij->', core1RDM_loc,
                                               totalOEI + totalFOCK)
                Nelectrons = np.trace(self.imp_1RDM[0]) + np.trace(
                    core1RDM_loc
                )  # Because full active space is used to compute the energy
            else:
                #transfo = np.eye( self.Norb, dtype=float )
                #totalOEI  = self.ints.dmet_oei(  transfo, self.Norb )
                #totalFOCK = self.ints.dmet_fock( transfo, self.Norb, OneRDM )
                #self.energy += 0.5 * np.einsum( 'ij,ij->', OneRDM[remainingOrbs==1,:], \
                #         totalOEI[remainingOrbs==1,:] + totalFOCK[remainingOrbs==1,:] )
                #Nelectrons += np.trace( (OneRDM[remainingOrbs==1,:])[:,remainingOrbs==1] )

                assert (np.array_equal(
                    self.ints.active,
                    np.ones([self.ints.mol.nao_nr()], dtype=int)))

                from pyscf import scf
                from types import MethodType
                mol_ = self.ints.mol
                mf_ = scf.RHF(mol_)

                impOrbs = remainingOrbs == 1
                xorb = np.dot(mf_.get_ovlp(), self.ints.ao2loc)
                hc = -chempot_imp * np.dot(xorb[:, impOrbs], xorb[:,
                                                                  impOrbs].T)
                dm0 = np.dot(self.ints.ao2loc,
                             np.dot(OneRDM, self.ints.ao2loc.T))

                def mf_hcore(self, mol=None):
                    if mol is None: mol = self.mol
                    return scf.hf.get_hcore(mol) + hc

                mf_.get_hcore = MethodType(mf_hcore, mf_)
                mf_.scf(dm0)
                assert (mf_.converged)

                rdm1 = mf_.make_rdm1()
                jk = mf_.get_veff(dm=rdm1)

                xorb = np.dot(mf_.get_ovlp(), self.ints.ao2loc)
                rdm1 = np.dot(xorb.T, np.dot(rdm1, xorb))
                oei = np.dot(self.ints.ao2loc.T,
                             np.dot(mf_.get_hcore() - hc, self.ints.ao2loc))
                jk = np.dot(self.ints.ao2loc.T, np.dot(jk, self.ints.ao2loc))

                ImpEnergy = \
                   + 0.50 * np.einsum('ji,ij->', rdm1[:,impOrbs], oei[impOrbs,:]) \
                   + 0.50 * np.einsum('ji,ij->', rdm1[impOrbs,:], oei[:,impOrbs]) \
                   + 0.25 * np.einsum('ji,ij->', rdm1[:,impOrbs], jk[impOrbs,:]) \
                   + 0.25 * np.einsum('ji,ij->', rdm1[impOrbs,:], jk[:,impOrbs])
                self.energy += ImpEnergy
                Nelectrons += np.trace(rdm1[np.ix_(impOrbs, impOrbs)])

            remainingOrbs[remainingOrbs == 1] -= 1
        assert (np.all(remainingOrbs == 0))

        print('Energy decomposition for debug:', E1, self.energy - E1,
              self.energy)  #HP: for debug
        print('Nuclear potential:', self.ints.const())
        self.energy += self.ints.const()
        return Nelectrons