def MakeVlocForRdm(NewRdm, nOcc, EmbFock, h0_for_vloc): # okay... we have the target eigensystem. We now still # need an operator EmbFock + vloc which generates it as # a ground state density. The condition here is that # # dot(h0_for_vloc, vloc1) =: K v # # has the same eigensystem as the one we're calculating, # or, equivalently, that it commutes with the rdm we have. # We assert that the resulting Fock matrix does not have # components mixing occupied and virtual orbitals, which is # equivalent. # Note that we cannot assume that F is diagonal in the target rdm # eigenvectors, because the eigensystem is degenerate # (has only 0 and 1 evs) # # Also note that in general vloc has not enough variational # freedom to represent arbitrary eigensystems, so technically we # are returning the best approximation which is possible. ew, ev = la.eigh(NewRdm) O, V = ev[:, nOcc:], ev[:, :nOcc] lhs = mdot(O.T, EmbFock, V).flatten() VlocSize = h0_for_vloc.shape[-1] h0_for_vloc_reshape = h0_for_vloc.reshape((nEmb, nEmb, VlocSize)) K = einsum("ro,rsp,sv->ovp", O, h0_for_vloc_reshape, V).reshape(O.shape[1] * V.shape[1], VlocSize) rhs = -la.lstsq(K, lhs)[0] return dot(h0_for_vloc_reshape, rhs)
def MakeFockOp(Rdm, CoreH, Int2e_Frs, ORB_OCC, Int2e_4ix=None, Orb=None, ExchFactor=1.): """make closed-shell/spin ensemble Fock matrix: f[rs] = h[rs] + j[rs] - .5 k[rs]. where j[rs] = (rs|tu) rdm[tu] and k[rs] = (rs|tu) rdm[su] Return (f, j, k).""" assert(Int2e_Frs is None or Int2e_4ix is None) if Int2e_Frs is not None: if Orb is None: OccNum,Orb = eigh(-Rdm); OccNum *= -1. else: OccNum = diag(mdot(Orb.T, Rdm, Orb)) # filter out occupation numbers slightly broken due to rounding. OccNum[OccNum < 0.] = 0. OccNum[OccNum > ORB_OCC] = ORB_OCC nFit, nOrb = Int2e_Frs.shape[0], Int2e_Frs.shape[1] # make coulomb. gamma = einsum("Frs,rs",Int2e_Frs, Rdm) j = einsum("Frs,F",Int2e_Frs,gamma) # make exchange -- first need to find the occupied orbitals. nOcc = len([o for o in OccNum if abs(o-ORB_OCC)<1e-8]) OccOrb = Orb[:,:nOcc] * OccNum[:nOcc]**.5 k1 = einsum("Frs,si->Fir", Int2e_Frs, OccOrb).reshape((nFit * nOcc, nOrb)) k = dot(k1.T, k1) else: assert(Int2e_4ix is not None) j = einsum("rstu,tu",Int2e_4ix, Rdm) k = einsum("rtsu,tu",Int2e_4ix, Rdm) Fock = CoreH + j - (ExchFactor/ORB_OCC) * k return Fock, j, k
def MakeVlocForRdm(NewRdm, nOcc, EmbFock, h0_for_vloc): # okay... we have the target eigensystem. We now still # need an operator EmbFock + vloc which generates it as # a ground state density. The condition here is that # # dot(h0_for_vloc, vloc1) =: K v # # has the same eigensystem as the one we're calculating, # or, equivalently, that it commutes with the rdm we have. # We assert that the resulting Fock matrix does not have # components mixing occupied and virtual orbitals, which is # equivalent. # Note that we cannot assume that F is diagonal in the target rdm # eigenvectors, because the eigensystem is degenerate # (has only 0 and 1 evs) # # Also note that in general vloc has not enough variational # freedom to represent arbitrary eigensystems, so technically we # are returning the best approximation which is possible. ew,ev = la.eigh(NewRdm) O,V = ev[:,nOcc:], ev[:,:nOcc] lhs = mdot(O.T,EmbFock,V).flatten() VlocSize = h0_for_vloc.shape[-1] h0_for_vloc_reshape = h0_for_vloc.reshape((nEmb,nEmb,VlocSize)) K = einsum("ro,rsp,sv->ovp",O,h0_for_vloc_reshape,V).reshape(O.shape[1]*V.shape[1],VlocSize) rhs = -la.lstsq(K,lhs)[0] return dot(h0_for_vloc_reshape,rhs)
def RunVcorUpdate(VcorLarge): #assert(np.allclose(VcorLarge[1::2, ::2],0.)) #assert(np.allclose(VcorLarge[ ::2,1::2],0.)) with Log.Section("lmf","FULL SYSTEM -- MEAN FIELD CALCULATION", 1): #vFock = self.FullSystem.FockT[0] - self.FullSystem.CoreH[0] self.FullSystem.CoreH[0] = FullCoreH_Unpatched[0] + VcorLarge #self.FullSystem.FockT[0] = self.FullSystem.CoreH[0] + vFock self.FullSystem.FockT[0] = FullCoreH_Unpatched[0] + VcorLarge # ^- this adds the changed vloc also to the FockT initial guess. # required if iterations are disabled. FullSystemHfResult = self.FullSystem._RunHf(Log=Log) FullSystemHfResult = self.FullSystem jgr = self.RunFragments(FullSystemHfResult, Log) jgr.MeanFieldEnergy = FullSystemHfResult.MeanFieldEnergy jgr.TotalEnergy = jgr.TotalElecEnergy + self.FullSystem.CoreEnergy self.FitCorrelationPotentials(jgr, FullSystemHfResult, PrintEmb) # now: add changed potentials to large system, and run again. dVcorLarge = np.zeros(VcorLarge.shape) assert(g.VcorType == "Local" or g.VcorType == "Diagonal") for (Fragment, VcorFull) in zip(self.Fragments, jgr.FragmentPotentials): nImp = len(Fragment.Sites) Vcor = Fragment.Factor * VcorFull[:nImp,:nImp] for Replica in Fragment.Replicas: VcorR = mdot(Replica.Trafo, Vcor, Replica.Trafo.T) E = list(enumerate(Replica.Sites)) for (i,iSite),(j,jSite) in it.product(E,E): dVcorLarge[iSite,jSite] += VcorR[i,j] return dVcorLarge, jgr, FullSystemHfResult
def TransformToEmb(self, OrbL, InpT, OrbR): """return Op[k,l] = OrbL[r,k]^* Op[r,s] OrbR[s,l], where Op: T x U x U is a periodically symmetric operator expressed in the super-cell x unit-cell basis, and OrbL/OrbR are one-particle transformations with the super-cell basis as row dimension.""" nSitesU, nSitesS = self.nSitesU, self.nSites assert (InpT.shape == (self.nUnitCells, nSitesU, nSitesU) or InpT.shape == (nSitesS, nSitesU)) assert (OrbL.shape[0] == nSitesS and OrbR.shape[0] == nSitesS) Op = InpT.reshape((self.nUnitCells, nSitesU, nSitesU)) def FindRequiredTs(Op): # make a list of Ts we need to consider in the transformation. # if Op[iT,:,:] is zero, then we can skip the T. iTs = [] for iT in range(self.nUnitCells): if not np.allclose(Op[iT, :, :], 0.): iTs.append(iT) return np.array(iTs) iOpTs = FindRequiredTs(Op) #print "iTs with support: %i of %i: %s" % (len(iOpTs), self.nUnitCells, iOpTs) Out = np.zeros((OrbL.shape[1], OrbR.shape[1]), Op.dtype) if len(iOpTs) >= .3 * self.nUnitCells: Op = InpT.reshape((nSitesS, nSitesU)) for (i, ijk) in enumerate(self.iTs): RowI = self._ConstructTranslatedRows(Op, ijk).T # ^- that's the Op[nSitesU*i:nSitesU*(i+1),:] subset of the # operator expressed in the full nSitesS x nSitesS basis. # (see FSuperCell._ExpandFull) Out += mdot(np.conj(OrbL[nSitesU * i:nSitesU * (i + 1), :].T), RowI, OrbR) elif 1: Op = Op[iOpTs, :, :] OrbR = OrbR.reshape((self.nUnitCells, nSitesU, OrbR.shape[1])) for (i, ijk) in enumerate(self.iTs): PF, I = self._MakeUnitCellPhasesForT_Restricted(ijk, iOpTs) RowIR = np.einsum("t,trs,trl->sl", PF, Op, OrbR[I, :, :]) Out += np.einsum( "rk,rl->kl", np.conj(OrbL[nSitesU * i:nSitesU * (i + 1), :]), RowIR) else: nT = len(iOpTs) Op = Op[iOpTs, :, :].reshape((nT * nSitesU, nSitesU)) nOrbR = OrbR.shape[1] OrbR = OrbR.reshape((self.nUnitCells, nSitesU, nOrbR)) PermShape = (nT * nSitesU, nOrbR) PfShape = (nT, 1, 1) for (i, ijk) in enumerate(self.iTs): PF, I = self._MakeUnitCellPhasesForT_Restricted(ijk, iOpTs) RowIR = np.dot(Op.T, (PF.reshape(PfShape) * OrbR[I, :, :]).reshape(PermShape)) Out += np.dot( np.conj(OrbL[nSitesU * i:nSitesU * (i + 1), :].T), RowIR) return Out
def TransformToEmb(self, OrbL, InpT, OrbR): """return Op[k,l] = OrbL[r,k]^* Op[r,s] OrbR[s,l], where Op: T x U x U is a periodically symmetric operator expressed in the super-cell x unit-cell basis, and OrbL/OrbR are one-particle transformations with the super-cell basis as row dimension.""" nSitesU, nSitesS = self.nSitesU, self.nSites assert(InpT.shape == (self.nUnitCells, nSitesU, nSitesU) or InpT.shape == (nSitesS, nSitesU)) assert(OrbL.shape[0] == nSitesS and OrbR.shape[0] == nSitesS) Op = InpT.reshape((self.nUnitCells, nSitesU, nSitesU)) def FindRequiredTs(Op): # make a list of Ts we need to consider in the transformation. # if Op[iT,:,:] is zero, then we can skip the T. iTs = [] for iT in range(self.nUnitCells): if not np.allclose(Op[iT,:,:], 0.): iTs.append(iT) return np.array(iTs) iOpTs = FindRequiredTs(Op) #print "iTs with support: %i of %i: %s" % (len(iOpTs), self.nUnitCells, iOpTs) Out = np.zeros((OrbL.shape[1],OrbR.shape[1]),Op.dtype) if len(iOpTs) >= .3 * self.nUnitCells: Op = InpT.reshape((nSitesS, nSitesU)) for (i,ijk) in enumerate(self.iTs): RowI = self._ConstructTranslatedRows(Op, ijk).T # ^- that's the Op[nSitesU*i:nSitesU*(i+1),:] subset of the # operator expressed in the full nSitesS x nSitesS basis. # (see FSuperCell._ExpandFull) Out += mdot(np.conj(OrbL[nSitesU*i:nSitesU*(i+1),:].T), RowI, OrbR) elif 0: Op = Op[iOpTs,:,:] OrbR = OrbR.reshape((self.nUnitCells, nSitesU, OrbR.shape[1])) for (i,ijk) in enumerate(self.iTs): PF,I = self._MakeUnitCellPhasesForT_Restricted(ijk,iOpTs) RowIR = np.einsum("t,trs,trl->sl",PF,Op,OrbR[I,:,:]) Out += np.einsum("rk,rl->kl",np.conj(OrbL[nSitesU*i:nSitesU*(i+1),:]), RowIR) else: nT = len(iOpTs) Op = Op[iOpTs,:,:].reshape((nT*nSitesU,nSitesU)) nOrbR = OrbR.shape[1] OrbR = OrbR.reshape((self.nUnitCells, nSitesU, nOrbR)) PermShape = (nT*nSitesU,nOrbR) PfShape = (nT,1,1) for (i,ijk) in enumerate(self.iTs): PF,I = self._MakeUnitCellPhasesForT_Restricted(ijk,iOpTs) RowIR = np.dot(Op.T, (PF.reshape(PfShape)*OrbR[I,:,:]).reshape(PermShape)) Out += np.dot(np.conj(OrbL[nSitesU*i:nSitesU*(i+1),:].T), RowIR) return Out
def MakeIdempotentApproxRdm(TargetRdm): # make a idempotent density matrix which exactly # coincides with TargetRdm on the imp x imp subset. A = TargetRdm[:nImp, :nImp] C = TargetRdm[nImp:, nImp:] assert (A.shape == C.shape) C = np.eye(A.shape[0]) - A # ^- # WARNING: at this moment this does assume that the embedding # basis is constructed as full Smh basis, i.e., that the hole # state corresponding to imp site i is at nImp + i. For other # cases we need additional rotations on C (not simply overwrite # it) and fix the eigenvalues in some other way. def MakeRho(A, B, C): return np.vstack( [np.hstack([A, B]), np.hstack([np.conj(B.T), C])]) L = nImp ewA, evA = la.eigh(A) ewC, evC = la.eigh(C) basis = MakeRho(evA, zeros_like(A), evC) R = mdot(basis.T, TargetRdm, basis) M = 0. * basis M[:L, :L] = diag(ewA) M[L:, L:] = diag(ewC) ewB = (ewA - ewA**2)**.5 # ^- we can still put in random phases here and retain an # idempotent target matrix. we get them from the # transformation of the target density matrix, hopefully # in such a way that also the off-diagonals are not way off, # even if we are only fitting on ImpRdm instead of FullRdm. # (see idempotency_gen.py) # # This freedom may be related to the freedom in choosing orbital # occupation. ewB_ref = np.diag(R[nImp:, :nImp][::-1, :]) ewB *= np.sign(ewB_ref) M[L:, :L] = np.diag(ewB)[::-1, :] M[:L, L:] = np.conj(M[L:, :L]).T rho = dot(basis, np.dot(M, basis.T)) assert (np.allclose(np.dot(rho, rho) - rho, 0.0)) # ^- will work for HF in HF, but not for FCI in HF return rho
def MakeIdempotentApproxRdm(TargetRdm): # make a idempotent density matrix which exactly # coincides with TargetRdm on the imp x imp subset. A = TargetRdm[:nImp,:nImp] C = TargetRdm[nImp:,nImp:] assert(A.shape == C.shape) C = np.eye(A.shape[0]) - A # ^- # WARNING: at this moment this does assume that the embedding # basis is constructed as full Smh basis, i.e., that the hole # state corresponding to imp site i is at nImp + i. For other # cases we need additional rotations on C (not simply overwrite # it) and fix the eigenvalues in some other way. def MakeRho(A,B,C): return np.vstack([np.hstack([A,B]),np.hstack([np.conj(B.T),C])]) L = nImp ewA,evA = la.eigh(A) ewC,evC = la.eigh(C) basis = MakeRho(evA,zeros_like(A),evC) R = mdot(basis.T, TargetRdm, basis) M = 0.*basis M[:L,:L] = diag(ewA) M[L:,L:] = diag(ewC) ewB = (ewA - ewA**2)**.5 # ^- we can still put in random phases here and retain an # idempotent target matrix. we get them from the # transformation of the target density matrix, hopefully # in such a way that also the off-diagonals are not way off, # even if we are only fitting on ImpRdm instead of FullRdm. # (see idempotency_gen.py) # # This freedom may be related to the freedom in choosing orbital # occupation. ewB_ref = np.diag(R[nImp:,:nImp][::-1,:]) ewB *= np.sign(ewB_ref) M[L:,:L] = np.diag(ewB)[::-1,:] M[:L,L:] = np.conj(M[L:,:L]).T rho = dot(basis,np.dot(M,basis.T)) assert(np.allclose(np.dot(rho,rho)-rho,0.0)) # ^- will work for HF in HF, but not for FCI in HF return rho
def GetImpRdmFitAnalytical(RdmHl, nImp, VLOC_TYPE, VLOC_FIT_TYPE): # this does the same as resmin, but # solves the target fitting equation analyically. # note that we can setup an equivalent routine for fullrdm fit. assert(VLOC_TYPE == "Local") # ^- we could do Diagonal/ImpRdm by making an idempotent # approximation to a RDM obtained by taking the previous HF # RDM and just fixing the diagonal entries to the CI RDM. def MakeIdempotentApproxRdm(TargetRdm): # make a idempotent density matrix which exactly # coincides with TargetRdm on the imp x imp subset. A = TargetRdm[:nImp,:nImp] C = TargetRdm[nImp:,nImp:] assert(A.shape == C.shape) C = np.eye(A.shape[0]) - A # ^- # WARNING: at this moment this does assume that the embedding # basis is constructed as full Smh basis, i.e., that the hole # state corresponding to imp site i is at nImp + i. For other # cases we need additional rotations on C (not simply overwrite # it) and fix the eigenvalues in some other way. def MakeRho(A,B,C): return np.vstack([np.hstack([A,B]),np.hstack([np.conj(B.T),C])]) L = nImp ewA,evA = la.eigh(A) ewC,evC = la.eigh(C) basis = MakeRho(evA,zeros_like(A),evC) R = mdot(basis.T, TargetRdm, basis) M = 0.*basis M[:L,:L] = diag(ewA) M[L:,L:] = diag(ewC) ewB = (ewA - ewA**2)**.5 # ^- we can still put in random phases here and retain an # idempotent target matrix. we get them from the # transformation of the target density matrix, hopefully # in such a way that also the off-diagonals are not way off, # even if we are only fitting on ImpRdm instead of FullRdm. # (see idempotency_gen.py) # # This freedom may be related to the freedom in choosing orbital # occupation. ewB_ref = np.diag(R[nImp:,:nImp][::-1,:]) ewB *= np.sign(ewB_ref) M[L:,:L] = np.diag(ewB)[::-1,:] M[:L,L:] = np.conj(M[L:,:L]).T rho = dot(basis,np.dot(M,basis.T)) assert(np.allclose(np.dot(rho,rho)-rho,0.0)) # ^- will work for HF in HF, but not for FCI in HF return rho def MakeVlocForRdm(NewRdm, nOcc, EmbFock, h0_for_vloc): # okay... we have the target eigensystem. We now still # need an operator EmbFock + vloc which generates it as # a ground state density. The condition here is that # # dot(h0_for_vloc, vloc1) =: K v # # has the same eigensystem as the one we're calculating, # or, equivalently, that it commutes with the rdm we have. # We assert that the resulting Fock matrix does not have # components mixing occupied and virtual orbitals, which is # equivalent. # Note that we cannot assume that F is diagonal in the target rdm # eigenvectors, because the eigensystem is degenerate # (has only 0 and 1 evs) # # Also note that in general vloc has not enough variational # freedom to represent arbitrary eigensystems, so technically we # are returning the best approximation which is possible. ew,ev = la.eigh(NewRdm) O,V = ev[:,nOcc:], ev[:,:nOcc] lhs = mdot(O.T,EmbFock,V).flatten() VlocSize = h0_for_vloc.shape[-1] h0_for_vloc_reshape = h0_for_vloc.reshape((nEmb,nEmb,VlocSize)) K = einsum("ro,rsp,sv->ovp",O,h0_for_vloc_reshape,V).reshape(O.shape[1]*V.shape[1],VlocSize) rhs = -la.lstsq(K,lhs)[0] return dot(h0_for_vloc_reshape,rhs) # get number of orbitals we need to occupy in embedded HF. fOcc = np.trace(RdmHl) nOcc = int(fOcc+.5) assert(abs(fOcc - nOcc) < 1e-8) if VLOC_FIT_TYPE == "ImpRdm": # make an idempotent density matrix which exactly # coincides with RdmHl on the Imp x Imp part. FitRdmHf = MakeIdempotentApproxRdm(RdmHl) elif VLOC_FIT_TYPE == "FullRdm": # make the best idempotent approximation to the FCI # RDM. That's simply the matrix with the same natural # orbitals, but all occupation numbers rounded to 0 # (if < .5) or 1 (if > .5). if 0: OccNum,NatOrb = la.eigh(-RdmHl); OccNum *= -1. OccNumHf = zeros_like(OccNum) OccNumHf[:nOcc] = 1. FitRdmHf = mdot(NatOrb, diag(OccNumHf), NatOrb.T) # ^- okay.. that is not *entirely* right: # here we first approximate the target RDM, and then # approximate the potential changes required to most # closely obtain the target RDM as a HF solution. FitRdmHf = RdmHl else: # not supported. assert(0) def TestMakeVlocForRdm(): vloc = MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc) NewF = EmbFock + vloc ew,ev = la.eigh(NewF) TestRdm = mdot(ev[:,:nOcc], ev[:,:nOcc].T) print TestRdm-FitRdmHf return MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc)
def TestMakeVlocForRdm(): vloc = MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc) NewF = EmbFock + vloc ew,ev = la.eigh(NewF) TestRdm = mdot(ev[:,:nOcc], ev[:,:nOcc].T) print TestRdm-FitRdmHf
def GetImpRdmFitAnalytical(RdmHl, nImp, VLOC_TYPE, VLOC_FIT_TYPE): # this does the same as resmin, but # solves the target fitting equation analyically. # note that we can setup an equivalent routine for fullrdm fit. assert (VLOC_TYPE == "Local") # ^- we could do Diagonal/ImpRdm by making an idempotent # approximation to a RDM obtained by taking the previous HF # RDM and just fixing the diagonal entries to the CI RDM. def MakeIdempotentApproxRdm(TargetRdm): # make a idempotent density matrix which exactly # coincides with TargetRdm on the imp x imp subset. A = TargetRdm[:nImp, :nImp] C = TargetRdm[nImp:, nImp:] assert (A.shape == C.shape) C = np.eye(A.shape[0]) - A # ^- # WARNING: at this moment this does assume that the embedding # basis is constructed as full Smh basis, i.e., that the hole # state corresponding to imp site i is at nImp + i. For other # cases we need additional rotations on C (not simply overwrite # it) and fix the eigenvalues in some other way. def MakeRho(A, B, C): return np.vstack( [np.hstack([A, B]), np.hstack([np.conj(B.T), C])]) L = nImp ewA, evA = la.eigh(A) ewC, evC = la.eigh(C) basis = MakeRho(evA, zeros_like(A), evC) R = mdot(basis.T, TargetRdm, basis) M = 0. * basis M[:L, :L] = diag(ewA) M[L:, L:] = diag(ewC) ewB = (ewA - ewA**2)**.5 # ^- we can still put in random phases here and retain an # idempotent target matrix. we get them from the # transformation of the target density matrix, hopefully # in such a way that also the off-diagonals are not way off, # even if we are only fitting on ImpRdm instead of FullRdm. # (see idempotency_gen.py) # # This freedom may be related to the freedom in choosing orbital # occupation. ewB_ref = np.diag(R[nImp:, :nImp][::-1, :]) ewB *= np.sign(ewB_ref) M[L:, :L] = np.diag(ewB)[::-1, :] M[:L, L:] = np.conj(M[L:, :L]).T rho = dot(basis, np.dot(M, basis.T)) assert (np.allclose(np.dot(rho, rho) - rho, 0.0)) # ^- will work for HF in HF, but not for FCI in HF return rho def MakeVlocForRdm(NewRdm, nOcc, EmbFock, h0_for_vloc): # okay... we have the target eigensystem. We now still # need an operator EmbFock + vloc which generates it as # a ground state density. The condition here is that # # dot(h0_for_vloc, vloc1) =: K v # # has the same eigensystem as the one we're calculating, # or, equivalently, that it commutes with the rdm we have. # We assert that the resulting Fock matrix does not have # components mixing occupied and virtual orbitals, which is # equivalent. # Note that we cannot assume that F is diagonal in the target rdm # eigenvectors, because the eigensystem is degenerate # (has only 0 and 1 evs) # # Also note that in general vloc has not enough variational # freedom to represent arbitrary eigensystems, so technically we # are returning the best approximation which is possible. ew, ev = la.eigh(NewRdm) O, V = ev[:, nOcc:], ev[:, :nOcc] lhs = mdot(O.T, EmbFock, V).flatten() VlocSize = h0_for_vloc.shape[-1] h0_for_vloc_reshape = h0_for_vloc.reshape((nEmb, nEmb, VlocSize)) K = einsum("ro,rsp,sv->ovp", O, h0_for_vloc_reshape, V).reshape(O.shape[1] * V.shape[1], VlocSize) rhs = -la.lstsq(K, lhs)[0] return dot(h0_for_vloc_reshape, rhs) # get number of orbitals we need to occupy in embedded HF. fOcc = np.trace(RdmHl) nOcc = int(fOcc + .5) assert (abs(fOcc - nOcc) < 1e-8) if VLOC_FIT_TYPE == "ImpRdm": # make an idempotent density matrix which exactly # coincides with RdmHl on the Imp x Imp part. FitRdmHf = MakeIdempotentApproxRdm(RdmHl) elif VLOC_FIT_TYPE == "FullRdm": # make the best idempotent approximation to the FCI # RDM. That's simply the matrix with the same natural # orbitals, but all occupation numbers rounded to 0 # (if < .5) or 1 (if > .5). if 0: OccNum, NatOrb = la.eigh(-RdmHl) OccNum *= -1. OccNumHf = zeros_like(OccNum) OccNumHf[:nOcc] = 1. FitRdmHf = mdot(NatOrb, diag(OccNumHf), NatOrb.T) # ^- okay.. that is not *entirely* right: # here we first approximate the target RDM, and then # approximate the potential changes required to most # closely obtain the target RDM as a HF solution. FitRdmHf = RdmHl else: # not supported. assert (0) def TestMakeVlocForRdm(): vloc = MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc) NewF = EmbFock + vloc ew, ev = la.eigh(NewF) TestRdm = mdot(ev[:, :nOcc], ev[:, :nOcc].T) print TestRdm - FitRdmHf return MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc)
def TestMakeVlocForRdm(): vloc = MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc) NewF = EmbFock + vloc ew, ev = la.eigh(NewF) TestRdm = mdot(ev[:, :nOcc], ev[:, :nOcc].T) print TestRdm - FitRdmHf
def GetRdm(self): #return 2.0 * dot(self.Orbs[:,:nOcc], self.Orbs[:,:nOcc].T) return mdot(self.Orbs, diag(self.OccNumbers), self.Orbs.T)
def _TestSuperCells(): from numpy import set_printoptions, nan set_printoptions(precision=5,linewidth=10060,suppress=True,threshold=nan) if 1: L = 12 nImp = 1 Hub1d = FHubbardModel1d(nImp, {'t': 1., 'U': 4.}) sc = FSuperCell(Hub1d, [L/nImp], [-1]) sc = FSuperCell(Hub1d, [L/nImp], [np.exp(.221j)]) #sc = FSuperCell(Hub1d, [L/nImp], [1]) else: #Lx,Ly = 320,120 # ^- FIXME: putting lots of sites there crashes the program. (out of memory) #nImpX,nImpY = 2,1 PhaseShift = None FCls = FTestModel2d #FCls = FHubbardModel2dSquare Lx,Ly=4,3 #PhaseShift=[-1.,-1.] # anti-periodic boundary conditions PhaseShift=[1.,1.] # periodic boundary conditions PhaseShift=[np.exp(.2j),np.exp(-.72j)] # wtf-like boundary conditions nImpX,nImpY = 2,1 #nImpX,nImpY = 1,1 nImp = nImpX * nImpY Hub2dSq = FCls((nImpX,nImpY), {'t': 1., 'U': 4.}) sc = FSuperCell(Hub2dSq, [Lx/nImpX,Ly/nImpY], PhaseShift) #sc = FSuperCell(Hub1d, [L/nImp,L/nImp], None) #sc = FSuperCell(Hub1d, [L/nImp,L/nImp], None) CoreH = sc.MakeTijMatrix() #print "CoreH via super cells:\n%s" % repr(CoreH) print "CoreH spectrum:\n%s" % la.eigh(CoreH)[0] #Orb = sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), (0,0)) #print "RealSpaceOrb k == (0,0):\n%s" % Orb #print "norm(orb) == ", la.norm(Orb) SymBasis = np.hstack([sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), ijk) for ijk in sc.iKs]) print "symmetry adapted basis:\n%s" % SymBasis #print "sc.nUnitCells = ", sc.nUnitCells #print "sc.nSites = ", sc.nSites #print "SymBasis.shape = ", SymBasis.shape print "norm( dot(conj(SymBasis.T),SymBasis) - eye(nSites) ): %s" % (la.norm( np.dot(np.conj(SymBasis.T),SymBasis) - np.eye(sc.nSites) )) print "CoreH via super cells:\n%s" % CoreH print "CoreH in symmetry basis:\n%s" % (mdot(np.conj(SymBasis.T), CoreH, SymBasis)) #print "CoreH -- 1site transformed:\n%s" % (mdot(CoreH, SymBasis)) nSitesS = SymBasis.shape[1] nSitesU = nImp nUnitCells = nSitesS/nSitesU CoreH_K = sc.TransformToK(CoreH[:nSitesS,:nSitesU]) print "And via .TransformToK:\n%s" % CoreH_K CoreH_SymUqBt = sc.TransformToT(CoreH_K) print "...back to t-space:\n%s" % CoreH_SymUqBt print "difference norm to orig: %.2e" % la.norm(CoreH_SymUqBt - CoreH[:nSitesS,:nSitesU]) raise SystemExit #raise Exception("^- that does not look very diagonal (note: works with pbc and apbc, in both directions)") nSitesU = len(sc.Model.UnitCell) nSitesS = len(sc.Sites) #for ijk in sc.iKs.T: #Orb = sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), ijk) #print "ev x evT for ijk = %s:\n%s" % (ijk, np.dot(Orb,np.conj(Orb.T))) CoreH_SymUq = CoreH[:nSitesU,:nSitesS] print "symmetry unique part of CoreH:\n%s" % CoreH_SymUq CoreH_R = np.zeros((nSitesS,nSitesS),complex) for (i,ijk) in enumerate(sc.iTs.T): CoreH_R[nSitesU*i:nSitesU*(i+1),:] = sc._ConstructTranslatedRows(CoreH_SymUq, ijk) print "CoreH orig:\n%s" % CoreH print "CoreH reconstructed:\n%s" % CoreH_R print "difference norm to orig: %.2e" % la.norm(CoreH_R - CoreH)
def _TestSuperCells(): from numpy import set_printoptions, nan set_printoptions(precision=5, linewidth=10060, suppress=True, threshold=nan) if 1: L = 12 nImp = 1 Hub1d = FHubbardModel1d(nImp, {'t': 1., 'U': 4.}) sc = FSuperCell(Hub1d, [L / nImp], [-1]) sc = FSuperCell(Hub1d, [L / nImp], [np.exp(.221j)]) #sc = FSuperCell(Hub1d, [L/nImp], [1]) else: #Lx,Ly = 320,120 # ^- FIXME: putting lots of sites there crashes the program. (out of memory) #nImpX,nImpY = 2,1 PhaseShift = None FCls = FTestModel2d #FCls = FHubbardModel2dSquare Lx, Ly = 4, 3 #PhaseShift=[-1.,-1.] # anti-periodic boundary conditions PhaseShift = [1., 1.] # periodic boundary conditions PhaseShift = [np.exp(.2j), np.exp(-.72j)] # wtf-like boundary conditions nImpX, nImpY = 2, 1 #nImpX,nImpY = 1,1 nImp = nImpX * nImpY Hub2dSq = FCls((nImpX, nImpY), {'t': 1., 'U': 4.}) sc = FSuperCell(Hub2dSq, [Lx / nImpX, Ly / nImpY], PhaseShift) #sc = FSuperCell(Hub1d, [L/nImp,L/nImp], None) #sc = FSuperCell(Hub1d, [L/nImp,L/nImp], None) CoreH = sc.MakeTijMatrix() #print "CoreH via super cells:\n%s" % repr(CoreH) print "CoreH spectrum:\n%s" % la.eigh(CoreH)[0] #Orb = sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), (0,0)) #print "RealSpaceOrb k == (0,0):\n%s" % Orb #print "norm(orb) == ", la.norm(Orb) SymBasis = np.hstack([ sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), ijk) for ijk in sc.iKs ]) print "symmetry adapted basis:\n%s" % SymBasis #print "sc.nUnitCells = ", sc.nUnitCells #print "sc.nSites = ", sc.nSites #print "SymBasis.shape = ", SymBasis.shape print "norm( dot(conj(SymBasis.T),SymBasis) - eye(nSites) ): %s" % ( la.norm(np.dot(np.conj(SymBasis.T), SymBasis) - np.eye(sc.nSites))) print "CoreH via super cells:\n%s" % CoreH print "CoreH in symmetry basis:\n%s" % (mdot(np.conj(SymBasis.T), CoreH, SymBasis)) #print "CoreH -- 1site transformed:\n%s" % (mdot(CoreH, SymBasis)) nSitesS = SymBasis.shape[1] nSitesU = nImp nUnitCells = nSitesS / nSitesU CoreH_K = sc.TransformToK(CoreH[:nSitesS, :nSitesU]) print "And via .TransformToK:\n%s" % CoreH_K CoreH_SymUqBt = sc.TransformToT(CoreH_K) print "...back to t-space:\n%s" % CoreH_SymUqBt print "difference norm to orig: %.2e" % la.norm(CoreH_SymUqBt - CoreH[:nSitesS, :nSitesU]) raise SystemExit #raise Exception("^- that does not look very diagonal (note: works with pbc and apbc, in both directions)") nSitesU = len(sc.Model.UnitCell) nSitesS = len(sc.Sites) #for ijk in sc.iKs.T: #Orb = sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), ijk) #print "ev x evT for ijk = %s:\n%s" % (ijk, np.dot(Orb,np.conj(Orb.T))) CoreH_SymUq = CoreH[:nSitesU, :nSitesS] print "symmetry unique part of CoreH:\n%s" % CoreH_SymUq CoreH_R = np.zeros((nSitesS, nSitesS), complex) for (i, ijk) in enumerate(sc.iTs.T): CoreH_R[nSitesU * i:nSitesU * (i + 1), :] = sc._ConstructTranslatedRows(CoreH_SymUq, ijk) print "CoreH orig:\n%s" % CoreH print "CoreH reconstructed:\n%s" % CoreH_R print "difference norm to orig: %.2e" % la.norm(CoreH_R - CoreH)