def eeccsd(self, nroots=1): cput0 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) size = self.nee() nroots = min(nroots,size) self._eeconv, self.eee, evecs = eig(self.eeccsd_matvec, size=size, nroots=nroots, verbose=log) if self._eeconv: logger.info(self, 'EE-CCSD converged') else: logger.info(self, 'EE-CCSD not converge') for n in range(nroots): logger.info(self, 'root %d E(EE-CCSD) = %.16g', n, self.eee.real[n]) log.timer('EE-CCSD', *cput0) return self.eee.real[:nroots], evecs
# ----------------------------------------------------------------------------- # Determine Hamiltonian Function def Hx(x): print(x.shape) x_reshape = np.reshape(x,guessShape) tmp1 = einsum('ijk,nqks->ijnqs',LHBlock,x_reshape) # Could be 'ijk,mpir->jkmpr' tmp2 = einsum('jlmn,ijnqs->ilmqs',W[2],tmp1) tmp3 = einsum('lopq,ilmqs->imops',W[2],tmp2) finalVec = einsum('ros,imops->mpir',RHBlock,tmp3) print(finalVec.ravel().shape) return -finalVec.ravel() def precond(dx,e,x0): return dx # ----------------------------------------------------------------------------- # Solve Eigenproblem u,v = eig(Hx,initGuess,precond) # PH - Add tolerance here? E = -u/nBond print('\tEnergy from Optimization = {}'.format(E)) # ------------------------------------------------------------------------------ # Reshape result into state psi = np.reshape(v,(d,d,a[0],a[0])) # s_l s_(l+1) a_(l-1) a_(l+1) psi = np.transpose(psi,(2,0,1,3)) # a_(l-1) s_l a_(l+1) s_(l+1) psi = np.reshape(psi,(a[0]*d,a[0]*d)) # ------------------------------------------------------------------------------ # Canonicalize state U,S,V = np.linalg.svd(psi) A = np.reshape(U,(a[0],d,-1)) A = A[:,:,:a[1]] A = np.swapaxes(A,0,1) B = np.reshape(V,(-1,d,a[0])) B = B[:a[1],:,:]
def runEigenSolver(H): # PH - Do for left eigenvec u, v = eig(H[0], H[1], H[2]) return -u, v
F = einsum('bxc,abcy->xya', np.conj(wfn_rs), tmp_sum2) # Create Function to give Hx def opt_fun(x): x_reshape = np.reshape(x, wfn_ls.shape) in_sum1 = einsum('ijk,lmk->ijlm', F, x_reshape) in_sum2 = einsum('njol,ijlm->noim', W[2], in_sum1) fin_sum = einsum('pnm,noim->opi', LHBlock, in_sum2) return -np.reshape(fin_sum, -1) def precond(dx, e, x0): return dx # Solve Eigenvalue Problem w/ Davidson Algorithm init_guess = np.reshape(wfn_ls, -1) u, v = eig(opt_fun, init_guess, precond, tol=tol) E = u / nBond print('\tEnergy at Left Site = {}'.format(E)) wfn_ls = np.reshape(v, wfn_ls.shape) # Push Gauge to right site------------------------------------------------ (n1, n2, n3) = wfn_ls.shape M_reshape = np.reshape(wfn_ls, (n1 * n2, n3)) (U, s, V) = np.linalg.svd(M_reshape, full_matrices=False) wfn_ls = np.reshape(U, (n1, n2, n3)) wfn_rs = einsum('i,ij,kjl->kil', s, V, wfn_rs) # Calculate Inner f Block tmp_sum1 = einsum('jlp,ijk->iklp', LHBlock, np.conj(wfn_ls)) tmp_sum2 = einsum('lmin,iklp->kmnp', W[2], tmp_sum1) F = einsum('npq,kmnp->kmq', wfn_ls, tmp_sum2) # Create Function to give Hx
x_reshape = np.reshape(x,wfn1_ls.shape) in_sum1 = einsum('ijk,lmk->ijlm',F1,x_reshape) in_sum2 = einsum('njol,ijlm->noim',W1[2],in_sum1) fin_sum = einsum('pnm,noim->opi',LHBlock1,in_sum2) return -np.reshape(fin_sum,-1) def opt_fun2(x): x_reshape = np.reshape(x,wfn2_ls.shape) in_sum1 = einsum('ijk,lmk->ijlm',F2,x_reshape) in_sum2 = einsum('njol,ijlm->noim',W2[2],in_sum1) fin_sum = einsum('pnm,noim->opi',LHBlock2,in_sum2) return -np.reshape(fin_sum,-1) def precond(dx,e,x0): return dx # Solve Eigenvalue Problem w/ Davidson Algorithm init_guess1 = np.reshape(wfn1_ls,-1) u1,v1 = eig(opt_fun1,init_guess1,precond,tol=tol) E1 = u1/nBond init_guess2 = np.reshape(wfn2_ls,-1) u2,v2 = eig(opt_fun2,init_guess2,precond,tol=tol) E2 = u2/nBond if verbose > 1: print('\tEnergy at Left Site = {},{},{},{}'.format(E1,E2,(E2-E1)/(2.*ds),J_TDL)) wfn1_ls = np.reshape(v1,wfn1_ls.shape) wfn2_ls = np.reshape(v2,wfn2_ls.shape) # Push Gauge to right site------------------------------------------------ (n1,n2,n3) = wfn1_ls.shape M1_reshape = np.reshape(wfn1_ls,(n1*n2,n3)) (U1,s1,V1) = np.linalg.svd(M1_reshape,full_matrices=False) wfn1_ls = np.reshape(U1,(n1,n2,n3)) wfn1_rs = einsum('i,ij,kjl->kil',s1,V1,wfn1_rs) (n1,n2,n3) = wfn2_ls.shape
def Hlx(x): x_reshape = np.reshape(x, guessShape) tmp1 = einsum('ijk,nqks->ijnqs', LHBlockl, x_reshape) # Could be 'ijk,mpir->jkmpr' tmp2 = einsum('jlmn,ijnqs->ilmqs', Wl[2], tmp1) tmp3 = einsum('lopq,ilmqs->imops', Wl[2], tmp2) finalVec = einsum('ros,imops->mpir', RHBlockl, tmp3) return -finalVec.ravel() def precond(dx, e, x0): return dx # ----------------------------------------------------------------------------- # Solve Eigenproblem u, v = eig(Hx, initGuess, precond) # PH - Add tolerance here? E = -u / nBond # Left ul, vl = eig(Hlx, initGuessl, precond) # PH - Add tolerance here? El = -u / nBond # PH - Figure out normalization v = v / np.sum(v) vl = vl / (np.dot(vl, v)) # ------------------------------------------------------------------------------ # Reshape result into state psi = np.reshape(v, (d, d, a[0], a[0])) # s_l s_(l+1) a_(l-1) a_(l+1) psi = np.transpose(psi, (2, 0, 1, 3)) # a_(l-1) s_l a_(l+1) s_(l+1) psi = np.reshape(psi, (a[0] * d, a[0] * d)) # Left lpsi = np.reshape(vl, (d, d, a[0], a[0])) # s_l s_(l+1) a_(l-1) a_(l+1) lpsi = np.transpose(lpsi, (2, 0, 1, 3)) # a_(l-1) s_l a_(l+1) s_(l+1)
print(wfn_ls.shape) wfn_rs = np.pad(B, ((0, a[1] - n3), (0, 0), (0, a[0] - n1)), 'constant') print(wfn_rs.shape) wfn2 = np.einsum('ijk,klm->ijlm', wfn_ls, wfn_rs) print(wfn2) mps_shape = wfn2.shape def dot_flat(x): return np.reshape( dot_twosite(LHBlock, RHBlock, W[2], W[2], x.reshape(mps_shape)), -1) def precond(dx, e, x0): return dx energy, wfn0 = eig(dot_flat, wfn2.ravel(), precond) print(energy) wfn0 = wfn0.reshape((a[-1] * d, a[-1] * d)) # Do SVD of the unit cell a.append(min(maxBondDim, a[-1] * d)) U, S, V = np.linalg.svd(wfn0, full_matrices=True) U = np.reshape(U, (a[-2], d, -1)) V = np.reshape(V, (-1, d, a[-2])) U = U[:, :, :a[-1]] S = S[:a[-1]] V = V[:a[-1], :, :] A = U B = V LBlock = np.einsum('il,ijk,ljm->km', LBlock, A[-1], A[-1].conj()) RBlock = np.einsum('ijk,ljm,km->il', B[-1], B[-1].conj(), RBlock) LnormBlock = np.einsum('i,ijk->k', LnormBlock, A[-1])
def eaccsd(self, nroots=1, koopmans=False, guess=None, partition=None): '''Calculate (N+1)-electron charged excitations via EA-EOM-CCSD. Kwargs: See ipccd() ''' cput0 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) size = self.nea() nroots = min(nroots,size) if partition: partition = partition.lower() assert partition in ['mp','full'] self.ea_partition = partition if partition == 'full': self._eaccsd_diag_matrix2 = self.vector_to_amplitudes_ea(self.eaccsd_diag())[1] adiag = self.eaccsd_diag() user_guess = False if guess: user_guess = True assert len(guess) == nroots for g in guess: assert g.size == size else: guess = [] if koopmans: for n in range(nroots): g = np.zeros(size) g[n] = 1.0 guess.append(g) else: idx = adiag.argsort()[:nroots] for i in idx: g = np.zeros(size) g[i] = 1.0 guess.append(g) def precond(r, e0, x0): return r/(e0-adiag+1e-12) if user_guess or koopmans: def pickeig(w, v, nr, x0): idx = np.argmax( np.abs(np.dot(np.array(guess).conj(),np.array(x0).T)), axis=1 ) return w[idx].real, v[:,idx].real, idx eea, evecs = eig(self.eaccsd_matvec, guess, precond, pick=pickeig, nroots=nroots, verbose=7) else: eea, evecs = eig(self.eaccsd_matvec, guess, precond, nroots=nroots, verbose=7) self.eea = eea.real if nroots == 1: eea, evecs = [self.eea], [evecs] nvir = self.nmo - self.nocc for n, en, vn in zip(range(nroots), eea, evecs): logger.info(self, 'EA root %d E = %.16g qpwt = %0.6g', n, en, np.linalg.norm(vn[:nvir])**2) log.timer('EA-CCSD', *cput0) if nroots == 1: return eea[0], evecs[0] else: return eea, evecs
def ipccsd(self, nroots=1, koopmans=False, guess=None, partition=None): '''Calculate (N-1)-electron charged excitations via IP-EOM-CCSD. Kwargs: nroots : int Number of roots (eigenvalues) requested partition : bool or str Use a matrix-partitioning for the doubles-doubles block. Can be None, 'mp' (Moller-Plesset, i.e. orbital energies on the diagonal), or 'full' (full diagonal elements). koopmans : bool Calculate Koopmans'-like (quasiparticle) excitations only, targeting via overlap. guess : list of ndarray List of guess vectors to use for targeting via overlap. ''' cput0 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) size = self.nip() nroots = min(nroots,size) if partition: partition = partition.lower() assert partition in ['mp','full'] self.ip_partition = partition if partition == 'full': self._ipccsd_diag_matrix2 = self.vector_to_amplitudes_ip(self.ipccsd_diag())[1] adiag = self.ipccsd_diag() user_guess = False if guess: user_guess = True assert len(guess) == nroots for g in guess: assert g.size == size else: guess = [] if koopmans: for n in range(nroots): g = np.zeros(size) g[self.nocc-n-1] = 1.0 guess.append(g) else: idx = adiag.argsort()[:nroots] for i in idx: g = np.zeros(size) g[i] = 1.0 guess.append(g) def precond(r, e0, x0): return r/(e0-adiag+1e-12) if user_guess or koopmans: def pickeig(w, v, nr, x0): idx = np.argmax( np.abs(np.dot(np.array(guess).conj(),np.array(x0).T)), axis=1 ) return w[idx].real, v[:,idx].real, idx eip, evecs = eig(self.ipccsd_matvec, guess, precond, pick=pickeig, nroots=nroots, verbose=7) else: eip, evecs = eig(self.ipccsd_matvec, guess, precond, nroots=nroots, verbose=7) self.eip = eip.real if nroots == 1: eip, evecs = [self.eip], [evecs] for n, en, vn in zip(range(nroots), eip, evecs): logger.info(self, 'IP root %d E = %.16g qpwt = %0.6g', n, en, np.linalg.norm(vn[:self.nocc])**2) log.timer('IP-CCSD', *cput0) if nroots == 1: return eip[0], evecs[0] else: return eip, evecs