def get_Xmat( self, mf1RDM, ddt_mf1RDM ): #Subroutine to calculate the X-matrix to propagate embedding orbitals #Initialize X-matrix self.Xmat = np.zeros( [self.Nsites, self.Nsites], dtype=complex ) #Index of orbitals in the site-basis corresponding to the environment envindx = np.setdiff1d( np.arange(self.Nsites), self.impindx) #Eigenvalues of environment part of mf1RDM self.env1RDM_evals = np.diag( np.real( utils.rot1el( mf1RDM[ envindx[:,None], envindx ], self.rotmat[ envindx, self.Nimp: ] ) ) ) #Calculate X-matrix setting diagonal, core-core, and virtual virtual terms to zero #Matrix of one over the difference in embedding orbital eigenvalues #Set redundant terms to zero, ie diagonal, core-core, and virtual-virtual eval_dif = np.zeros( [ self.Nsites-self.Nimp, self.Nsites-self.Nimp ] ) for b in range(self.Nimp,self.Nsites): for a in range(self.Nimp,self.Nsites): if( a != b and not ( a in self.corerange and b in self.corerange ) and not ( a in self.virtrange and b in self.virtrange ) ): eval_dif[ b-self.Nimp, a-self.Nimp ] = 1.0 / ( self.env1RDM_evals[a-self.Nimp] - self.env1RDM_evals[b-self.Nimp] ) #Rotate time-derivative of mean-field 1RDM self.Xmat[ self.Nimp:, self.Nimp: ] = utils.rot1el( 1j*ddt_mf1RDM[ envindx[:,None], envindx ], self.rotmat[ envindx, self.Nimp: ] ) #Multiply difference in eigenalues and rotated time-derivative matrix self.Xmat[ self.Nimp:, self.Nimp: ] = np.multiply( eval_dif, self.Xmat[ self.Nimp:, self.Nimp: ] )
def get_Hemb( self, h_site, V_site, hamtype=0, hubsite_indx=None ): #Subroutine to the get the 1 and 2 e- terms of the Hamiltonian in the embedding basis #Transformation accounts for interaction with the core #Also calculates 1 e- term with only 1/2 interaction with the core - this is used in calculation of DMET energy #remove the virtual states from the rotation matrix #the rotation matrix is of form ( site basis fcns ) x ( impurities, virtual, bath, core ) rotmat_small = np.delete( self.rotmat, np.s_[self.Nimp:self.Nimp+self.Nvirt], 1 ) #rotate the 1 e- terms, h_emb currently ( impurities, bath, core ) x ( impurities, bath, core ) h_emb = utils.rot1el( h_site, rotmat_small ) #define 1 e- term of size ( impurities, bath ) x ( impurities, bath ) that will only have 1/2 interaction with the core self.h_emb_halfcore = np.copy( h_emb[ :2*self.Nimp, :2*self.Nimp ] ) #rotate the 2 e- terms if( hamtype == 0 ): #General hamiltonian, V_emb currently ( impurities, bath, core ) ^ 4 V_emb = utils.rot2el_chem( V_site, rotmat_small ) elif( hamtype == 1 ): #Hubbard hamiltonian rotmat_vsmall = rotmat_small[ hubsite_indx, :2*self.Nimp ] #remove core states from rotation matrix self.V_emb = V_site*np.einsum( 'ap,cp,pb,pd->abcd', utils.adjoint( rotmat_vsmall ), utils.adjoint( rotmat_vsmall ), rotmat_vsmall, rotmat_vsmall ) #augment the impurity/bath 1e- terms from contribution of coulomb and exchange terms btwn impurity/bath and core #and augment the 1 e- term with only half the contribution from the core to be used in DMET energy calculation if( hamtype == 0 ): #General hamiltonian for core in range( 2*self.Nimp, 2*self.Nimp+self.Ncore ): h_emb[ :2*self.Nimp, :2*self.Nimp ] = h_emb[ :2*self.Nimp, :2*self.Nimp ] + 2*V_emb[ :2*self.Nimp, :2*self.Nimp, core, core ] - V_emb[ :2*self.Nimp, core, core, :2*self.Nimp ] self.h_emb_halfcore += V_emb[ :2*self.Nimp, :2*self.Nimp, core, core ] - 0.5*V_emb[ :2*self.Nimp, core, core, :2*self.Nimp ] elif( hamtype == 1): #Hubbard hamiltonian core_int = V_site * np.einsum( 'ap,pb,p->ab', utils.adjoint( rotmat_vsmall ), rotmat_vsmall, np.einsum( 'pe,ep->p',rotmat_small[hubsite_indx,2*self.Nimp:], utils.adjoint( rotmat_small[hubsite_indx,2*self.Nimp:] ) ) ) h_emb[ :2*self.Nimp, :2*self.Nimp ] += core_int self.h_emb_halfcore += 0.5*core_int #calculate the energy associated with core-core interactions, setting it numerically to a real number since it always will be Ecore = 0 for core1 in range( 2*self.Nimp, 2*self.Nimp+self.Ncore ): Ecore += 2*h_emb[ core1, core1 ] if( hamtype == 0 ): #General hamiltonian for core2 in range( 2*self.Nimp, 2*self.Nimp+self.Ncore ): Ecore += 2*V_emb[ core1, core1, core2, core2 ] - V_emb[ core1, core2, core2, core1 ] if( hamtype == 1): #Hubbard hamiltonian vec = np.einsum( 'pe,ep->p',rotmat_small[hubsite_indx,2*self.Nimp:],utils.adjoint( rotmat_small[hubsite_indx,2*self.Nimp:] ) ) Ecore += V_site * np.einsum( 'p,p', vec, vec ) self.Ecore = Ecore.real #shrink h_emb and V_emb arrays to only include the impurity and bath self.h_emb = h_emb[ :2*self.Nimp, :2*self.Nimp ] if( hamtype == 0 ): #General hamiltonian self.V_emb = V_emb[ :2*self.Nimp, :2*self.Nimp, :2*self.Nimp, :2*self.Nimp ]
def get_Hemb(h_site, rotmat, Nimp, Nsites, Nele): Ncore = round(Nele / 2) - Nimp Nvirt = Nsites - 2 * Nimp - Ncore rotmat_small = np.delete(rotmat, np.s_[Nimp:Nimp + Nvirt], 1) h_emb = utils.rot1el(h_site, rotmat_small) Ecore = 0.0 for core in range(2 * Nimp, 2 * Nimp + Ncore): Ecore += h_emb[core, core] h_emb = h_emb[:2 * Nimp, :2 * Nimp] return h_emb, core
def one_rk_step2(mf1RDM, CIcoeffs, Nsites, Nele, h_site, Nimp, delt, rotmat): iddt_mf1RDM = utils.commutator(h_site, mf1RDM) change_mf1RDM = -1j * delt * iddt_mf1RDM evals = np.copy( np.real( np.diag(utils.rot1el(mf1RDM[Nimp:, Nimp:], rotmat[Nimp:, Nimp:])))) #####grr#### #chk1, chk2 = get_rotmat( mf1RDM, Nsites, Nimp ) #print(rotmat[Nimp:,Nimp:]) #print() #print(chk1[Nimp:,Nimp:]) #print() #print(evals) #print() #print(chk2) #print() #print('------------------') #print() ############ Xmat, Xmat_sml = get_Xmat(mf1RDM, iddt_mf1RDM, rotmat, evals, Nsites, Nele, Nimp) change_rotmat = -1j * delt * np.dot(rotmat, Xmat) h_emb, Ecore = get_Hemb(h_site, rotmat, Nimp, Nsites, Nele) V_emb = np.zeros([2 * Nimp, 2 * Nimp, 2 * Nimp, 2 * Nimp], dtype=complex) Ecore = 0.0 change_CIcoeffs = -1j * delt * applyham_pyscf.apply_ham_pyscf_fully_complex( CIcoeffs, h_emb - Xmat_sml, V_emb, Nimp, Nimp, 2 * Nimp, Ecore) return change_mf1RDM, change_CIcoeffs, change_rotmat