def update(self, Da, Db, orbs): from pyquante2.utils import ao2mo nalpha = self.geo.nup() nbeta = self.geo.ndown() norbs = len(orbs) # Da.shape[0] E0 = self.geo.nuclear_repulsion() h = self.i1.T + self.i1.V E1 = 0.5 * trace2(Da + Db, h) Ja, Ka = self.i2.get_j(Da), self.i2.get_k(Da) Jb, Kb = self.i2.get_j(Db), self.i2.get_k(Db) Fa = h + Ja + Jb - Ka Fb = h + Ja + Jb - Kb E2 = 0.5 * (trace2(Fa, Da) + trace2(Fb, Db)) self.energy = E0 + E1 + E2 # print (self.energy,E1,E2,E0) Fa = ao2mo(Fa, orbs) Fb = ao2mo(Fb, orbs) # Building the approximate Fock matrices in the MO basis F = 0.5 * (Fa + Fb) K = Fb - Fa # The Fock matrix now looks like # F-K | F + K/2 | F # --------------------------------- # F + K/2 | F | F - K/2 # --------------------------------- # F | F - K/2 | F + K # Make explicit slice objects to simplify this do = slice(0, nbeta) so = slice(nbeta, nalpha) uo = slice(nalpha, norbs) F[do, do] -= K[do, do] F[uo, uo] += K[uo, uo] F[do, so] += 0.5 * K[do, so] F[so, do] += 0.5 * K[so, do] F[so, uo] -= 0.5 * K[so, uo] F[uo, so] -= 0.5 * K[uo, so] E, cmo = np.linalg.eigh(F) c = np.dot(orbs, cmo) self.orbe = E self.orbs = c return c
def update_gvb_ci_coeffs(Uocc, h, Js, Ks, f, a, b, ncore, nopen, npair, orbs_per_shell, verbose=False): """\ coeffs = update_gvb_ci_coeffs(Uocc,h,Js,Ks,f,a,b,ncore,nopen,npair, orbs_per_shell,verbose=False) """ # consider reusing the transformed MO integral elements from ROTION # (or moving the module there) coeffs = np.zeros((2 * npair, ), 'd') nsh = len(f) ncoresh = 1 if ncore else 0 hmo = ao2mo(h, Uocc) Jmo = [ao2mo(J, Uocc) for J in Js] Kmo = [ao2mo(K, Uocc) for K in Ks] for i in range(npair): ish = ncoresh + nopen + i jsh = ish + 1 iorb = orbs_per_shell[ish][0] jorb = orbs_per_shell[jsh][0] H11 = 2 * hmo[iorb, iorb] + Jmo[ish][iorb, iorb] H22 = 2 * hmo[jorb, jorb] + Jmo[jsh][jorb, jorb] K12 = Kmo[ish][jorb, jorb] # == Kmo[jsh][iorb,iorb] (checked) for k in range(nsh): if k == ish or k == jsh: continue H11 += f[k] * (2 * Jmo[ksh][iorb, iorb] - Kmo[ksh][iorb, iorb]) H22 += f[k] * (2 * Jmo[ksh][jorb, jorb] - Kmo[ksh][jorb, jorb]) H = np.zeros((2, 2), 'd') H[0, 1] = H[1, 0] = K12 H[0, 0] = H11 H[1, 1] = H22 if verbose: print("GVB CI Matrix for pair %d\n%s" % (i, H)) E, C = np.linalg.eigh(H) if verbose: print("GVB CI Eigenvector for pair %d\n%s" % (i, C)) print("GVB CI Eigenvalues for pair %d\n%s" % (i, E)) coeffs[2 * i:(2 * i + 2)] = C[0] return coeffs
def update(self,Da,Db,orbs): from pyquante2.utils import ao2mo nalpha = self.geo.nup() nbeta = self.geo.ndown() norbs = len(orbs) # Da.shape[0] E0 = self.geo.nuclear_repulsion() h = self.i1.T + self.i1.V E1 = 0.5*trace2(Da+Db,h) Ja,Ka = self.i2.get_j(Da),self.i2.get_k(Da) Jb,Kb = self.i2.get_j(Db),self.i2.get_k(Db) Fa = h + Ja + Jb - Ka Fb = h + Ja + Jb - Kb E2 = 0.5*(trace2(Fa,Da)+trace2(Fb,Db)) self.energy = E0+E1+E2 #print (self.energy,E1,E2,E0) Fa = ao2mo(Fa,orbs) Fb = ao2mo(Fb,orbs) # Building the approximate Fock matrices in the MO basis F = 0.5*(Fa+Fb) K = Fb-Fa # The Fock matrix now looks like # F-K | F + K/2 | F # --------------------------------- # F + K/2 | F | F - K/2 # --------------------------------- # F | F - K/2 | F + K # Make explicit slice objects to simplify this do = slice(0,nbeta) so = slice(nbeta,nalpha) uo = slice(nalpha,norbs) F[do,do] -= K[do,do] F[uo,uo] += K[uo,uo] F[do,so] += 0.5*K[do,so] F[so,do] += 0.5*K[so,do] F[so,uo] -= 0.5*K[so,uo] F[uo,so] -= 0.5*K[uo,so] E,cmo = np.linalg.eigh(F) c = np.dot(orbs,cmo) self.orbe = E self.orbs = c return c
def recompute_energy(Uocc,h,Js,Ks,f,a,b,nocc,shell): """\ This is a helper routine to compute the GVB/ROHF energy expression. This routine should not be used in production code, since these terms are computed in ROTION. Eel,Eone = recompute_energy(Uocc,h,Js,Ks,f,a,b,nocc,shell) """ nsh = len(f) hmo = ao2mo(h,Uocc) Jmo = [ao2mo(J,Uocc) for J in Js] Kmo = [ao2mo(K,Uocc) for K in Ks] Eone = sum(f[shell[i]]*hmo[i,i] for i in range(nocc)) Fmo = [f[i]*hmo + sum(a[i,j]*Jmo[j] + b[i,j]*Kmo[j] for j in range(nsh)) for i in range(nsh)] Eel = Eone + sum(Fmo[shell[i]][i,i] for i in range(nocc)) return Eel,Eone
def update_gvb_ci_coeffs(Uocc,h,Js,Ks,f,a,b,ncore,nopen,npair,orbs_per_shell, verbose=False): """\ coeffs = update_gvb_ci_coeffs(Uocc,h,Js,Ks,f,a,b,ncore,nopen,npair, orbs_per_shell,verbose=False) """ # consider reusing the transformed MO integral elements from ROTION # (or moving the module there) coeffs = np.zeros((2*npair,),'d') nsh = len(f) ncoresh = 1 if ncore else 0 hmo = ao2mo(h,Uocc) Jmo = [ao2mo(J,Uocc) for J in Js] Kmo = [ao2mo(K,Uocc) for K in Ks] for i in range(npair): ish = ncoresh+nopen+i jsh = ish+1 iorb = orbs_per_shell[ish][0] jorb = orbs_per_shell[jsh][0] H11 = 2*hmo[iorb,iorb] + Jmo[ish][iorb,iorb] H22 = 2*hmo[jorb,jorb] + Jmo[jsh][jorb,jorb] K12 = Kmo[ish][jorb,jorb] # == Kmo[jsh][iorb,iorb] (checked) for k in range(nsh): if k == ish or k == jsh: continue H11 += f[k]*(2*Jmo[ksh][iorb,iorb]-Kmo[ksh][iorb,iorb]) H22 += f[k]*(2*Jmo[ksh][jorb,jorb]-Kmo[ksh][jorb,jorb]) H = np.zeros((2,2),'d') H[0,1] = H[1,0] = K12 H[0,0] = H11 H[1,1] = H22 if verbose: print("GVB CI Matrix for pair %d\n%s" % (i,H)) E,C = np.linalg.eigh(H) if verbose: print("GVB CI Eigenvector for pair %d\n%s" % (i,C)) print("GVB CI Eigenvalues for pair %d\n%s" % (i,E)) coeffs[2*i:(2*i+2)] = C[0] return coeffs
def ROTION(Uocc, h, Js, Ks, f, a, b, nocc, shell, verbose=False): """\ Eel,Eone,Uocc = ROTION(Uocc,h,Js,Ks,f,a,b,nocc,shell,verbose) """ nsh = len(f) hmo = ao2mo(h, Uocc) Jmo = [ao2mo(J, Uocc) for J in Js] Kmo = [ao2mo(K, Uocc) for K in Ks] Eone = sum(f[shell[i]] * hmo[i, i] for i in range(nocc)) Fmo = [ f[i] * hmo + sum(a[i, j] * Jmo[j] + b[i, j] * Kmo[j] for j in range(nsh)) for i in range(nsh) ] Eel = Eone + sum(Fmo[shell[i]][i, i] for i in range(nocc)) Delta = np.zeros((nocc, nocc), 'd') for i in range(nocc): ish = shell[i] for j in range(i): jsh = shell[j] if ish == jsh: continue # ish is now guaranteed to be larger than 0 Jij = Jmo[ish][j, j] Kij = Kmo[ish][j, j] Gij = 2*(a[ish,ish]+a[jsh,jsh]-2*a[ish,jsh])*Kij \ + (b[ish,ish]+b[jsh,jsh]-2*b[ish,jsh])*(Jij+Kij) D0 = -(Fmo[jsh][i,j]-Fmo[ish][i,j])/\ (Fmo[jsh][i,i]-Fmo[ish][i,i]-Fmo[jsh][j,j]+Fmo[ish][j,j]\ +Gij) Delta[i, j] = D0 Delta[j, i] = -D0 if verbose: print("ROTION Delta Matrix") print(Delta) if nsh > 1: eD = expm(Delta) Uocc = np.dot(Uocc, eD) return Eel, Eone, Uocc
def ROTION(Uocc,h,Js,Ks,f,a,b,nocc,shell,verbose=False): """\ Eel,Eone,Uocc = ROTION(Uocc,h,Js,Ks,f,a,b,nocc,shell,verbose) """ nsh = len(f) hmo = ao2mo(h,Uocc) Jmo = [ao2mo(J,Uocc) for J in Js] Kmo = [ao2mo(K,Uocc) for K in Ks] Eone = sum(f[shell[i]]*hmo[i,i] for i in range(nocc)) Fmo = [f[i]*hmo + sum(a[i,j]*Jmo[j] + b[i,j]*Kmo[j] for j in range(nsh)) for i in range(nsh)] Eel = Eone + sum(Fmo[shell[i]][i,i] for i in range(nocc)) Delta = np.zeros((nocc,nocc),'d') for i in range(nocc): ish = shell[i] for j in range(i): jsh = shell[j] if ish == jsh: continue # ish is now guaranteed to be larger than 0 Jij = Jmo[ish][j,j] Kij = Kmo[ish][j,j] Gij = 2*(a[ish,ish]+a[jsh,jsh]-2*a[ish,jsh])*Kij \ + (b[ish,ish]+b[jsh,jsh]-2*b[ish,jsh])*(Jij+Kij) D0 = -(Fmo[jsh][i,j]-Fmo[ish][i,j])/\ (Fmo[jsh][i,i]-Fmo[ish][i,i]-Fmo[jsh][j,j]+Fmo[ish][j,j]\ +Gij) Delta[i,j] = D0 Delta[j,i] = -D0 if verbose: print("ROTION Delta Matrix") print(Delta) if nsh > 1: eD = expm(Delta) Uocc = np.dot(Uocc,eD) return Eel,Eone,Uocc
def OCBSE(U,h,Js,Ks,f,a,b,orbs_per_shell,virt): """\ U = OCBSE(U,h,Js,Ks,f,a,b,orbs_per_shell,virt) Perform an Orthogonality Constrained Basis Set Expansion to mix the occupied orbitals with the virtual orbitals. See Bobrowicz/Goddard Sect 5.1. """ Unew = np.zeros(U.shape,'d') nsh = len(f) for i,orbs in enumerate(orbs_per_shell): space = list(orbs) + list(virt) Fi = f[i]*h + sum(a[i,j]*Js[j]+b[i,j]*Ks[j] for j in range(nsh)) Fi = ao2mo(Fi,U[:,space]) Ei,Ci = np.linalg.eigh(Fi) Ui = np.dot(U[:,space],Ci) Unew[:,space] = Ui return Unew