import time
import sys
import numpy as np
import scipy
from fcdmft.solver import gmres
import pyscf
import pyscf.cc
from pyscf.lib import logger
from pyscf.cc.eom_uccsd import amplitudes_to_vector_ip, amplitudes_to_vector_ea
from pyscf.cc.eom_uccsd import vector_to_amplitudes_ip, vector_to_amplitudes_ea
from pyscf import lib
from mpi4py import MPI
'''
MPI UCCSD Green's function
'''
rank = MPI.COMM_WORLD.Get_rank()
size = MPI.COMM_WORLD.Get_size()
comm = MPI.COMM_WORLD
[docs]
def greens_b_singles_ea_alpha(t1, p):
t1a, t1b = t1
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < nocca:
return -t1a[p,:]
else:
p = p-nocca
result = np.zeros((nvira,), dtype=ds_type)
result[p] = 1.0
return result
[docs]
def greens_b_singles_ea_beta(t1, p):
t1a, t1b = t1
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < noccb:
return -t1b[p,:]
else:
p = p-noccb
result = np.zeros((nvirb,), dtype=ds_type)
result[p] = 1.0
return result
[docs]
def greens_b_doubles_ea_alpha(t2, p):
t2aa, t2ab, t2bb = t2
nocca, _, nvira, _ = t2aa.shape
noccb, _, nvirb, _ = t2bb.shape
ds_type = t2aa.dtype
if p < nocca:
return -t2aa[p,:,:,:], -t2ab[p,:,:,:]
else:
return np.zeros((nocca,nvira,nvira), dtype=ds_type), \
np.zeros((noccb,nvira,nvirb), dtype=ds_type)
[docs]
def greens_b_doubles_ea_beta(t2, p):
t2aa, t2ab, t2bb = t2
nocca, _, nvira, _ = t2aa.shape
noccb, _, nvirb, _ = t2bb.shape
ds_type = t2aa.dtype
if p < noccb:
return -t2ab[:,p,:,:].transpose(0,2,1), -t2bb[p,:,:,:]
else:
return np.zeros((nocca,nvirb,nvira), dtype=ds_type), \
np.zeros((noccb,nvirb,nvirb), dtype=ds_type)
[docs]
def greens_b_vector_ea_uhf(cc, p):
b1a = greens_b_singles_ea_alpha(cc.t1, p)
b1b = greens_b_singles_ea_beta(cc.t1, p)
b2aaa, b2bab = greens_b_doubles_ea_alpha(cc.t2, p)
b2aba, b2bbb = greens_b_doubles_ea_beta(cc.t2, p)
return amplitudes_to_vector_ea(
[b1a, b1b], [b2aaa, b2aba, b2bab, b2bbb],
)
[docs]
def greens_b_fullvector_ea_uhf(cc, p):
b1a = greens_b_singles_ea_alpha(cc.t1, p)
b1b = greens_b_singles_ea_beta(cc.t1, p)
b2aaa, b2bab = greens_b_doubles_ea_alpha(cc.t2, p)
b2aba, b2bbb = greens_b_doubles_ea_beta(cc.t2, p)
return b1a,b1b,b2aaa,b2bab,b2aba,b2bbb
[docs]
def greens_e_singles_ea_alpha(t1, t2, l1, l2, p):
t1a, t1b = t1
t2aa, t2ab, t2bb = t2
l1a, l1b = l1
l2aa, l2ab, l2bb = l2
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < nocca:
return l1a[p, :]
else:
p = p-nocca
result = np.zeros((nvira,), dtype=ds_type)
result[p] = -1.0
result += lib.einsum('ia,i->a', l1a, t1a[:,p])
result += 0.5*lib.einsum('klca,klc->a', l2aa, t2aa[:,:,:,p])
result += lib.einsum('lkac,lkc->a', l2ab, t2ab[:,:,p,:])
return result
[docs]
def greens_e_singles_ea_beta(t1, t2, l1, l2, p):
t1a, t1b = t1
t2aa, t2ab, t2bb = t2
l1a, l1b = l1
l2aa, l2ab, l2bb = l2
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < noccb:
return l1b[p, :]
else:
p = p-noccb
result = np.zeros((nvirb,), dtype=ds_type)
result[p] = -1.0
result += lib.einsum('ia,i->a', l1b, t1b[:,p])
result += 0.5*lib.einsum('klca,klc->a', l2bb, t2bb[:,:,:,p])
result += lib.einsum('klca,klc->a', l2ab, t2ab[:,:,:,p])
return result
[docs]
def greens_e_doubles_ea_alpha(t1, l1, l2, p):
t1a, t1b = t1
l1a, l1b = l1
l2aa, l2ab, l2bb = l2
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < nocca:
return 0.5*l2aa[p,:,:,:], l2ab[p,:,:,:]
else:
p = p-nocca
evec_aaa = np.zeros((nocca,nvira,nvira), dtype=ds_type)
evec_aaa[:,p,:] += -0.5*l1a
evec_aaa[:,:,p] += 0.5*l1a
evec_aaa += 0.5*lib.einsum('k,jkba->jab',t1a[:,p], l2aa)
evec_bab = np.zeros((noccb,nvira,nvirb), dtype=ds_type)
evec_bab[:,p,:] += -l1b
evec_bab += lib.einsum('k,kjab->jab',t1a[:,p], l2ab)
return evec_aaa, evec_bab
[docs]
def greens_e_doubles_ea_beta(t1, l1, l2, p):
t1a, t1b = t1
l1a, l1b = l1
l2aa, l2ab, l2bb = l2
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < noccb:
return l2ab[:,p,:,:].transpose(0,2,1), 0.5*l2bb[p,:,:,:]
else:
p = p-noccb
evec_bbb = np.zeros((noccb,nvirb,nvirb), dtype=ds_type)
evec_bbb[:,p,:] += -0.5*l1b
evec_bbb[:,:,p] += 0.5*l1b
evec_bbb += 0.5*lib.einsum('k,jkba->jab',t1b[:,p], l2bb)
evec_aba = np.zeros((nocca,nvirb,nvira), dtype=ds_type)
evec_aba[:,p,:] += -l1a
evec_aba += lib.einsum('k,jkba->jab',t1b[:,p], l2ab)
return evec_aba, evec_bbb
[docs]
def greens_e_vector_ea_uhf(cc, p):
e1a = greens_e_singles_ea_alpha(cc.t1, cc.t2, cc.l1, cc.l2, p)
e1b = greens_e_singles_ea_beta(cc.t1, cc.t2, cc.l1, cc.l2, p)
e2aaa, e2bab = greens_e_doubles_ea_alpha(cc.t1, cc.l1, cc.l2, p)
e2aba, e2bbb = greens_e_doubles_ea_beta(cc.t1, cc.l1, cc.l2, p)
return amplitudes_to_vector_ea(
[e1a, e1b], [e2aaa, e2aba, e2bab, e2bbb],
)
[docs]
def greens_e_fullvector_ea_uhf(cc, p):
e1a = greens_e_singles_ea_alpha(cc.t1, cc.t2, cc.l1, cc.l2, p)
e1b = greens_e_singles_ea_beta(cc.t1, cc.t2, cc.l1, cc.l2, p)
e2aaa, e2bab = greens_e_doubles_ea_alpha(cc.t1, cc.l1, cc.l2, p)
e2aba, e2bbb = greens_e_doubles_ea_beta(cc.t1, cc.l1, cc.l2, p)
return e1a,e1b,e2aaa,e2bab,e2aba,e2bbb
[docs]
def greens_b_singles_ip_alpha(t1, p):
t1a, t1b = t1
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < nocca:
result = np.zeros((nocca,), dtype=ds_type)
result[p] = 1.0
return result
else:
p = p-nocca
return t1a[:,p]
[docs]
def greens_b_singles_ip_beta(t1, p):
t1a, t1b = t1
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < noccb:
result = np.zeros((noccb,), dtype=ds_type)
result[p] = 1.0
return result
else:
p = p-noccb
return t1b[:,p]
[docs]
def greens_b_doubles_ip_alpha(t2, p):
t2aa, t2ab, t2bb = t2
nocca, _, nvira, _ = t2aa.shape
noccb, _, nvirb, _ = t2bb.shape
ds_type = t2aa.dtype
if p < nocca:
return np.zeros((nocca,nocca,nvira), dtype=ds_type), \
np.zeros((nocca,noccb,nvirb), dtype=ds_type)
else:
p = p-nocca
return -t2aa[:,:,p,:], -t2ab[:,:,p,:]
[docs]
def greens_b_doubles_ip_beta(t2, p):
t2aa, t2ab, t2bb = t2
nocca, _, nvira, _ = t2aa.shape
noccb, _, nvirb, _ = t2bb.shape
ds_type = t2aa.dtype
if p < noccb:
return np.zeros((noccb,nocca,nvira), dtype=ds_type), \
np.zeros((noccb,noccb,nvirb), dtype=ds_type)
else:
p = p-noccb
return -t2ab[:,:,:,p].transpose(1,0,2), -t2bb[:,:,p,:]
[docs]
def greens_b_vector_ip_uhf(cc, p):
b1a = greens_b_singles_ip_alpha(cc.t1, p)
b1b = greens_b_singles_ip_beta(cc.t1, p)
b2aaa, b2abb = greens_b_doubles_ip_alpha(cc.t2, p)
b2baa, b2bbb = greens_b_doubles_ip_beta(cc.t2, p)
return amplitudes_to_vector_ip(
[b1a, b1b], [b2aaa, b2baa, b2abb, b2bbb],
)
[docs]
def greens_b_fullvector_ip_uhf(cc, p):
b1a = greens_b_singles_ip_alpha(cc.t1, p)
b1b = greens_b_singles_ip_beta(cc.t1, p)
b2aaa, b2abb = greens_b_doubles_ip_alpha(cc.t2, p)
b2baa, b2bbb = greens_b_doubles_ip_beta(cc.t2, p)
return b1a,b1b,b2aaa,b2abb,b2baa,b2bbb
[docs]
def greens_e_singles_ip_alpha(t1, t2, l1, l2, p):
t1a, t1b = t1
t2aa, t2ab, t2bb = t2
l1a, l1b = l1
l2aa, l2ab, l2bb = l2
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < nocca:
result = np.zeros((nocca,), dtype=ds_type)
result[p] = -1.0
result += lib.einsum('ic,c->i',l1a,t1a[p,:])
result += 0.5*lib.einsum('ilcd,lcd->i',l2aa,t2aa[p,:,:,:])
result += lib.einsum('ilcd,lcd->i',l2ab,t2ab[p,:,:,:])
return result
else:
p = p-nocca
return -l1a[:,p]
[docs]
def greens_e_singles_ip_beta(t1, t2, l1, l2, p):
t1a, t1b = t1
t2aa, t2ab, t2bb = t2
l1a, l1b = l1
l2aa, l2ab, l2bb = l2
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < noccb:
result = np.zeros((noccb,), dtype=ds_type)
result[p] = -1.0
result += lib.einsum('ic,c->i',l1b,t1b[p,:])
result += 0.5*lib.einsum('ilcd,lcd->i',l2bb,t2bb[p,:,:,:])
result += lib.einsum('lidc,ldc->i',l2ab,t2ab[:,p,:,:])
return result
else:
p = p-noccb
return -l1b[:,p]
[docs]
def greens_e_doubles_ip_alpha(t1, l1, l2, p):
t1a, t1b = t1
l1a, l1b = l1
l2aa, l2ab, l2bb = l2
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < nocca:
evec_aaa = np.zeros((nocca, nocca, nvira), dtype=ds_type)
evec_aaa[p, :, :] += -0.5*l1a
evec_aaa[:, p, :] += 0.5*l1a
evec_aaa += 0.5*lib.einsum('c,ijcb->ijb',t1a[p,:],l2aa)
evec_abb = np.zeros((nocca, noccb, nvirb), dtype=ds_type)
evec_abb[p, :, :] += -l1b
evec_abb += lib.einsum('c,ijcb->ijb',t1a[p,:],l2ab)
return -evec_aaa, -evec_abb
else:
p = p-nocca
return 0.5*l2aa[:,:,p,:], l2ab[:,:,p,:]
[docs]
def greens_e_doubles_ip_beta(t1, l1, l2, p):
t1a, t1b = t1
l1a, l1b = l1
l2aa, l2ab, l2bb = l2
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
ds_type = t1a.dtype
if p < noccb:
evec_bbb = np.zeros((noccb, noccb, nvirb), dtype=ds_type)
evec_bbb[p, :, :] += -0.5*l1b
evec_bbb[:, p, :] += 0.5*l1b
evec_bbb += 0.5*lib.einsum('c,ijcb->ijb',t1b[p,:],l2bb)
evec_baa = np.zeros((noccb, nocca, nvira), dtype=ds_type)
evec_baa[p, :, :] += -l1a
evec_baa += lib.einsum('c,jibc->ijb',t1b[p,:],l2ab)
return -evec_baa, -evec_bbb
else:
p = p-noccb
return l2ab[:,:,:,p].transpose(1,0,2), 0.5*l2bb[:,:,p,:]
[docs]
def greens_e_vector_ip_uhf(cc, p):
e1a = greens_e_singles_ip_alpha(cc.t1, cc.t2, cc.l1, cc.l2, p)
e1b = greens_e_singles_ip_beta(cc.t1, cc.t2, cc.l1, cc.l2, p)
e2aaa, e2abb = greens_e_doubles_ip_alpha(cc.t1, cc.l1, cc.l2, p)
e2baa, e2bbb = greens_e_doubles_ip_beta(cc.t1, cc.l1, cc.l2, p)
return amplitudes_to_vector_ip(
[e1a, e1b], [e2aaa, e2baa, e2abb, e2bbb],
)
[docs]
def greens_e_fullvector_ip_uhf(cc, p):
e1a = greens_e_singles_ip_alpha(cc.t1, cc.t2, cc.l1, cc.l2, p)
e1b = greens_e_singles_ip_beta(cc.t1, cc.t2, cc.l1, cc.l2, p)
e2aaa, e2abb = greens_e_doubles_ip_alpha(cc.t1, cc.l1, cc.l2, p)
e2baa, e2bbb = greens_e_doubles_ip_beta(cc.t1, cc.l1, cc.l2, p)
return e1a,e1b,e2aaa,e2abb,e2baa,e2bbb
[docs]
def greens_func_multiply(ham, vector, linear_part, **kwargs):
return np.array(ham(vector, **kwargs) + linear_part * vector)
[docs]
def greens_func_multiply_mor(ham, vector, linear_part):
return np.array(np.dot(ham, vector) + linear_part * vector)
[docs]
class UCCGF(object):
def __init__(self, mycc, tol=1e-4, verbose=None):
self._cc = mycc
self.tol = tol
if verbose:
self.verbose = verbose
else:
self.verbose = self._cc.verbose
self.stdout = sys.stdout
[docs]
def ipccsd_ao(self, ps, omega_list, mo_coeff, broadening, MOR=False, omega_mor=None):
'''
Compute IP-CCSD-GF in AO basis (parallelize over orbitals)
'''
eomip = pyscf.cc.eom_uccsd.EOMIP(self._cc)
eomip_imds = eomip.make_imds()
diag = eomip.get_diag()
t1a, t1b = self._cc.t1
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
nmoa = nocca+nvira
nmob = noccb+nvirb
nmo = nmoa
shapea = nocca + nocca*nocca*nvira + nocca*noccb*nvirb
shapeb = noccb + noccb*noccb*nvirb + noccb*nocca*nvira
e_vector_moa = np.zeros([nmo,shapea],dtype=np.complex128)
e_vector_mob = np.zeros([nmo,shapeb],dtype=np.complex128)
for i in range(nmo):
e_vector_mo = greens_e_vector_ip_uhf(self._cc, i)
e1, e2 = vector_to_amplitudes_ip(e_vector_mo, (nmoa,nmob), (nocca,noccb))
e1a, e1b = e1
e2aaa, e2baa, e2abb, e2bbb = e2
e_vector_moa[i,:] = np.hstack((e1a, e2aaa.ravel(), e2abb.ravel()))
e_vector_mob[i,:] = np.hstack((e1b, e2baa.ravel(), e2bbb.ravel()))
e_vector_aoa = lib.einsum("pi,ix->px", mo_coeff[0][ps,:], e_vector_moa)
e_vector_aob = lib.einsum("pi,ix->px", mo_coeff[1][ps,:], e_vector_mob)
b_vector_moa = np.zeros([shapea,nmo],dtype=np.complex128)
b_vector_mob = np.zeros([shapeb,nmo],dtype=np.complex128)
for i in range(nmo):
b_vector_mo = greens_b_vector_ip_uhf(self._cc, i)
b1, b2 = vector_to_amplitudes_ip(b_vector_mo, (nmoa,nmob), (nocca,noccb))
b1a, b1b = b1
b2aaa, b2baa, b2abb, b2bbb = b2
b_vector_moa[:,i] = np.hstack((b1a, b2aaa.ravel(), b2abb.ravel()))
b_vector_mob[:,i] = np.hstack((b1b, b2baa.ravel(), b2bbb.ravel()))
b_vector_aoa = lib.einsum("xi,ip->xp", b_vector_moa, mo_coeff[0].T[:,ps])
b_vector_aob = lib.einsum("xi,ip->xp", b_vector_mob, mo_coeff[1].T[:,ps])
comm.Barrier()
segsize = len(ps) // size
if rank >= size-(len(ps)-segsize*size):
start = rank * segsize + rank-(size-(len(ps)-segsize*size))
stop = min(len(ps), start+segsize+1)
else:
start = rank * segsize
stop = min(len(ps), start+segsize)
gf_ao = np.zeros((2, stop-start, len(ps), len(omega_list)), dtype=np.complex128)
if MOR:
omega_comp = omega_mor
else:
omega_comp = omega_list
for ip in range(start,stop):
p = ps[ip]
b1a = b_vector_aoa[:,ip][:nocca]
b2aaa = b_vector_aoa[:,ip][nocca:nocca+nocca*nocca*nvira].reshape(nocca,nocca,nvira)
b2abb = b_vector_aoa[:,ip][nocca+nocca*nocca*nvira:].reshape(nocca,noccb,nvirb)
b1b = b_vector_aob[:,ip][:noccb]
b2baa = b_vector_aob[:,ip][noccb:noccb+noccb*nocca*nvira].reshape(noccb,nocca,nvira)
b2bbb = b_vector_aob[:,ip][noccb+noccb*nocca*nvira:].reshape(noccb,noccb,nvirb)
b1 = (b1a, b1b)
b2 = (b2aaa, b2baa, b2abb, b2bbb)
b_vector_ao = amplitudes_to_vector_ip(b1, b2)
if MOR:
X_vec = np.zeros((len(b_vector_ao), len(omega_mor)), dtype=complex)
x0 = None
for iomega in range(len(omega_comp))[::-1]:
curr_omega = omega_comp[iomega]
def matr_multiply(vector, args=None):
return greens_func_multiply(eomip.matvec, vector, curr_omega - 1j * broadening, imds=eomip_imds)
diag_w = diag + curr_omega-1j*broadening
if x0 is None or MOR:
x0 = b_vector_ao/diag_w
solver = gmres.GMRES(matr_multiply, b_vector_ao, x0, diag_w, tol=self.tol)
cput1 = (time.process_time(), time.perf_counter())
sol = solver.solve().reshape(-1)
cput1 = logger.timer(self, 'IPGF orbital p = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
ip+1,len(ps),iomega+1,len(omega_comp),solver.niter,rank), *cput1)
x0 = sol
if MOR:
# Construct MOR subspace vectors
X_vec[:,iomega] = sol
if not MOR:
sol1, sol2 = vector_to_amplitudes_ip(sol, (nmoa,nmob), (nocca,noccb))
sol1a, sol1b = sol1
sol2aaa, sol2baa, sol2abb, sol2bbb = sol2
sol_a = np.hstack((sol1a, sol2aaa.ravel(), sol2abb.ravel()))
sol_b = np.hstack((sol1b, sol2baa.ravel(), sol2bbb.ravel()))
for iq, q in enumerate(ps):
gf_ao[0,ip-start,iq,iomega] = -np.dot(e_vector_aoa[iq,:], sol_a)
gf_ao[1,ip-start,iq,iomega] = -np.dot(e_vector_aob[iq,:], sol_b)
if MOR:
# QR decomposition to orthorgonalize X_vec
S_vec, R_vec = scipy.linalg.qr(X_vec, mode='economic')
# Construct reduced order model
n_mor = len(omega_mor)
HS = np.zeros_like(S_vec)
for i in range(n_mor):
HS[:,i] = greens_func_multiply(eomip.matvec, S_vec[:,i], 0., imds=eomip_imds)
# Reduced Hamiltonian, b_vector, diag
H_mor = np.dot(S_vec.T.conj(), HS)
b_vector_mor = np.dot(S_vec.T.conj(), b_vector_ao)
diag_mor = H_mor.diagonal()
x0 = None
for iomega in range(len(omega_list))[::-1]:
curr_omega = omega_list[iomega]
def matr_multiply_mor(vector, args=None):
return greens_func_multiply_mor(H_mor, vector, curr_omega - 1j * broadening)
diag_w = diag_mor + curr_omega-1j*broadening
if x0 is None:
x0 = b_vector_mor/diag_w
solver = gmres.GMRES(matr_multiply_mor, b_vector_mor, x0, diag_w, tol=self.tol*0.01)
cput1 = (time.process_time(), time.perf_counter())
sol = solver.solve().reshape(-1)
#cput1 = logger.timer(self, 'MOR IPGF orbital p = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
# ip+1,len(ps),iomega+1,len(omega_list),solver.niter,rank), *cput1)
x0 = sol
sol_full = np.dot(S_vec, sol)
sol1, sol2 = vector_to_amplitudes_ip(sol_full, (nmoa,nmob), (nocca,noccb))
sol1a, sol1b = sol1
sol2aaa, sol2baa, sol2abb, sol2bbb = sol2
sol_a = np.hstack((sol1a, sol2aaa.ravel(), sol2abb.ravel()))
sol_b = np.hstack((sol1b, sol2baa.ravel(), sol2bbb.ravel()))
for iq, q in enumerate(ps):
gf_ao[0,ip-start,iq,iomega] = -np.dot(e_vector_aoa[iq,:], sol_a)
gf_ao[1,ip-start,iq,iomega] = -np.dot(e_vector_aob[iq,:], sol_b)
comm.Barrier()
gf_ao_gather = comm.gather(gf_ao.transpose(1,0,2,3))
if rank == 0:
gf_ao_gather = np.vstack(gf_ao_gather).transpose(1,0,2,3)
comm.Barrier()
gf_ao_gather = comm.bcast(gf_ao_gather,root=0)
return gf_ao_gather
[docs]
def eaccsd_ao(self, ps, omega_list, mo_coeff, broadening, MOR=False, omega_mor=None):
'''
Compute EA-CCSD-GF in AO basis (parallelize over orbitals)
'''
eomea = pyscf.cc.eom_uccsd.EOMEA(self._cc)
eomea_imds = eomea.make_imds()
diag = eomea.get_diag()
t1a, t1b = self._cc.t1
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
nmoa = nocca+nvira
nmob = noccb+nvirb
nmo = nmoa
shapea = nvira + nvira*nocca*nvira + nvira*noccb*nvirb
shapeb = nvirb + nvirb*nocca*nvira + nvirb*noccb*nvirb
e_vector_moa = np.zeros([nmo,shapea],dtype=np.complex128)
e_vector_mob = np.zeros([nmo,shapeb],dtype=np.complex128)
for i in range(nmo):
e_vector_mo = greens_e_vector_ea_uhf(self._cc, i)
e1, e2 = vector_to_amplitudes_ea(e_vector_mo, (nmoa,nmob), (nocca,noccb))
e1a, e1b = e1
e2aaa, e2aba, e2bab, e2bbb = e2
e_vector_moa[i,:] = np.hstack((e1a, e2aaa.ravel(), e2bab.ravel()))
e_vector_mob[i,:] = np.hstack((e1b, e2aba.ravel(), e2bbb.ravel()))
e_vector_aoa = lib.einsum("pi,ix->px", mo_coeff[0][ps,:], e_vector_moa)
e_vector_aob = lib.einsum("pi,ix->px", mo_coeff[1][ps,:], e_vector_mob)
b_vector_moa = np.zeros([shapea,nmo],dtype=np.complex128)
b_vector_mob = np.zeros([shapeb,nmo],dtype=np.complex128)
for i in range(nmo):
b_vector_mo = greens_b_vector_ea_uhf(self._cc, i)
b1, b2 = vector_to_amplitudes_ea(b_vector_mo, (nmoa,nmob), (nocca,noccb))
b1a, b1b = b1
b2aaa, b2aba, b2bab, b2bbb = b2
b_vector_moa[:,i] = np.hstack((b1a, b2aaa.ravel(), b2bab.ravel()))
b_vector_mob[:,i] = np.hstack((b1b, b2aba.ravel(), b2bbb.ravel()))
b_vector_aoa = lib.einsum("xi,ip->xp", b_vector_moa, mo_coeff[0].T[:,ps])
b_vector_aob = lib.einsum("xi,ip->xp", b_vector_mob, mo_coeff[1].T[:,ps])
comm.Barrier()
segsize = len(ps) // size
if rank < len(ps)-segsize*size:
start = rank * segsize + rank
stop = min(len(ps), start+segsize+1)
else:
start = rank * segsize + len(ps)-segsize*size
stop = min(len(ps), start+segsize)
gf_ao = np.zeros((2, len(ps), stop-start, len(omega_list)), dtype=np.complex128)
if MOR:
omega_comp = omega_mor
else:
omega_comp = omega_list
for ip in range(start,stop):
p = ps[ip]
b1a = b_vector_aoa[:,ip][:nvira]
b2aaa = b_vector_aoa[:,ip][nvira:nvira+nvira*nocca*nvira].reshape(nocca,nvira,nvira)
b2bab = b_vector_aoa[:,ip][nvira+nvira*nocca*nvira:].reshape(noccb,nvira,nvirb)
b1b = b_vector_aob[:,ip][:nvirb]
b2aba = b_vector_aob[:,ip][nvirb:nvirb+nocca*nvirb*nvira].reshape(nocca,nvirb,nvira)
b2bbb = b_vector_aob[:,ip][nvirb+nocca*nvirb*nvira:].reshape(noccb,nvirb,nvirb)
b1 = (b1a, b1b)
b2 = (b2aaa, b2aba, b2bab, b2bbb)
b_vector_ao = amplitudes_to_vector_ea(b1, b2)
if MOR:
X_vec = np.zeros((len(b_vector_ao), len(omega_mor)), dtype=complex)
x0 = None
for iomega in range(len(omega_comp)):
curr_omega = omega_comp[iomega]
def matr_multiply(vector, args=None):
return greens_func_multiply(eomea.matvec, vector, -curr_omega - 1j * broadening, imds=eomea_imds)
diag_w = diag + (-curr_omega-1j*broadening)
if x0 is None or MOR:
x0 = b_vector_ao/diag_w
solver = gmres.GMRES(matr_multiply, b_vector_ao, x0, diag_w, tol=self.tol)
cput1 = (time.process_time(), time.perf_counter())
sol = solver.solve().reshape(-1)
cput1 = logger.timer(self, 'EAGF orbital q = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
ip+1,len(ps),iomega+1,len(omega_comp),solver.niter,rank), *cput1)
x0 = sol
if MOR:
# Construct MOR subspace vectors
X_vec[:,iomega] = sol
if not MOR:
sol1, sol2 = vector_to_amplitudes_ea(sol, (nmoa,nmob), (nocca,noccb))
sol1a, sol1b = sol1
sol2aaa, sol2aba, sol2bab, sol2bbb = sol2
sol_a = np.hstack((sol1a, sol2aaa.ravel(), sol2bab.ravel()))
sol_b = np.hstack((sol1b, sol2aba.ravel(), sol2bbb.ravel()))
for iq, q in enumerate(ps):
gf_ao[0,iq,ip-start,iomega] = np.dot(e_vector_aoa[iq,:], sol_a)
gf_ao[1,iq,ip-start,iomega] = np.dot(e_vector_aob[iq,:], sol_b)
if MOR:
# QR decomposition to orthorgonalize X_vec
S_vec, R_vec = scipy.linalg.qr(X_vec, mode='economic')
# Construct reduced order model
n_mor = len(omega_mor)
HS = np.zeros_like(S_vec)
for i in range(n_mor):
HS[:,i] = greens_func_multiply(eomea.matvec, S_vec[:,i], 0., imds=eomea_imds)
# Reduced Hamiltonian, b_vector, diag
H_mor = np.dot(S_vec.T.conj(), HS)
b_vector_mor = np.dot(S_vec.T.conj(), b_vector_ao)
diag_mor = H_mor.diagonal()
x0 = None
for iomega in range(len(omega_list)):
curr_omega = omega_list[iomega]
def matr_multiply_mor(vector, args=None):
return greens_func_multiply_mor(H_mor, vector, -curr_omega - 1j * broadening)
diag_w = diag_mor + (-curr_omega-1j*broadening)
if x0 is None:
x0 = b_vector_mor/diag_w
solver = gmres.GMRES(matr_multiply_mor, b_vector_mor, x0, diag_w, tol=self.tol*0.01)
cput1 = (time.process_time(), time.perf_counter())
sol = solver.solve().reshape(-1)
#cput1 = logger.timer(self, 'MOR EAGF orbital q = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
# ip+1,len(ps),iomega+1,len(omega_list),solver.niter,rank), *cput1)
x0 = sol
sol_full = np.dot(S_vec, sol)
sol1, sol2 = vector_to_amplitudes_ea(sol_full, (nmoa,nmob), (nocca,noccb))
sol1a, sol1b = sol1
sol2aaa, sol2aba, sol2bab, sol2bbb = sol2
sol_a = np.hstack((sol1a, sol2aaa.ravel(), sol2bab.ravel()))
sol_b = np.hstack((sol1b, sol2aba.ravel(), sol2bbb.ravel()))
for iq, q in enumerate(ps):
gf_ao[0,iq,ip-start,iomega] = np.dot(e_vector_aoa[iq,:], sol_a)
gf_ao[1,iq,ip-start,iomega] = np.dot(e_vector_aob[iq,:], sol_b)
comm.Barrier()
gf_ao_gather = comm.gather(gf_ao.transpose(2,0,1,3))
if rank == 0:
gf_ao_gather = np.vstack(gf_ao_gather).transpose(1,2,0,3)
comm.Barrier()
gf_ao_gather = comm.bcast(gf_ao_gather,root=0)
return gf_ao_gather
[docs]
def ipccsd_mo(self, ps, qs, omega_list, broadening, MOR=False, omega_mor=None):
'''
Compute IP-CCSD-GF in MO basis
'''
eomip = pyscf.cc.eom_uccsd.EOMIP(self._cc)
eomip_imds = eomip.make_imds()
diag = eomip.get_diag()
e_vector = list()
t1a, t1b = self._cc.t1
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
nmoa = nocca+nvira
nmob = noccb+nvirb
for q in qs:
e_vector.append(greens_e_vector_ip_uhf(self._cc, q))
segsize = len(ps) // size
if rank >= size-(len(ps)-segsize*size):
start = rank * segsize + rank-(size-(len(ps)-segsize*size))
stop = min(len(ps), start+segsize+1)
else:
start = rank * segsize
stop = min(len(ps), start+segsize)
gfvals = np.zeros((2, stop-start, len(qs), len(omega_list)), dtype=np.complex128)
if MOR:
omega_comp = omega_mor
else:
omega_comp = omega_list
for ip in range(start,stop):
p = ps[ip]
b_vector = greens_b_vector_ip_uhf(self._cc, p)
if MOR:
X_vec = np.zeros((len(b_vector), len(omega_mor)), dtype=complex)
for iomega in range(len(omega_comp)):
curr_omega = omega_comp[iomega]
def matr_multiply(vector, args=None):
return greens_func_multiply(eomip.matvec, vector, curr_omega - 1j * broadening, imds=eomip_imds)
diag_w = diag + curr_omega - 1j*broadening
x0 = b_vector/diag_w
solver = gmres.GMRES(matr_multiply, b_vector, x0, diag_w, tol=self.tol)
cput1 = (time.process_time(), time.perf_counter())
sol = solver.solve().reshape(-1)
if MOR:
# Construct MOR subspace vectors
X_vec[:,iomega] = sol
cput1 = logger.timer(self, 'IPGF orbital p = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
ip+1,len(ps),iomega+1,len(omega_comp),solver.niter,rank), *cput1)
x0 = sol
if not MOR:
sol1, sol2 = vector_to_amplitudes_ip(sol, (nmoa,nmob), (nocca,noccb))
sol1a, sol1b = sol1
sol2aaa, sol2baa, sol2abb, sol2bbb = sol2
sol_a = np.hstack((sol1a, sol2aaa.ravel(), sol2abb.ravel()))
sol_b = np.hstack((sol1b, sol2baa.ravel(), sol2bbb.ravel()))
for iq, q in enumerate(qs):
e1, e2 = vector_to_amplitudes_ip(e_vector[iq], (nmoa,nmob), (nocca,noccb))
e1a, e1b = e1
e2aaa, e2baa, e2abb, e2bbb = e2
e_vector_a = np.hstack((e1a, e2aaa.ravel(), e2abb.ravel()))
e_vector_b = np.hstack((e1b, e2baa.ravel(), e2bbb.ravel()))
gfvals[0,ip-start,iq,iomega] = -np.dot(e_vector_a, sol_a)
gfvals[1,ip-start,iq,iomega] = -np.dot(e_vector_b, sol_b)
if MOR:
# QR decomposition to orthorgonalize X_vec
S_vec, R_vec = scipy.linalg.qr(X_vec, mode='economic')
# Construct reduced order model
n_mor = len(omega_mor)
HS = np.zeros_like(S_vec)
for i in range(n_mor):
HS[:,i] = greens_func_multiply(eomip.matvec, S_vec[:,i], 0., imds=eomip_imds)
# Reduced Hamiltonian, b_vector, diag
H_mor = np.dot(S_vec.T.conj(), HS)
b_vector_mor = np.dot(S_vec.T.conj(), b_vector)
diag_mor = H_mor.diagonal()
for iomega in range(len(omega_list)):
curr_omega = omega_list[iomega]
def matr_multiply_mor(vector, args=None):
return greens_func_multiply_mor(H_mor, vector, curr_omega - 1j * broadening)
diag_w = diag_mor + curr_omega - 1j*broadening
x0 = b_vector_mor/diag_w
solver = gmres.GMRES(matr_multiply_mor, b_vector_mor, x0, diag_w, tol=self.tol*0.01)
cput1 = (time.process_time(), time.perf_counter())
sol = solver.solve().reshape(-1)
#cput1 = logger.timer(self, 'MOR IPGF orbital p = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
# ip+1,len(ps),iomega+1,len(omega_list),solver.niter,rank), *cput1)
x0 = sol
sol_full = np.dot(S_vec, sol)
sol1, sol2 = vector_to_amplitudes_ip(sol_full, (nmoa,nmob), (nocca,noccb))
sol1a, sol1b = sol1
sol2aaa, sol2baa, sol2abb, sol2bbb = sol2
sol_a = np.hstack((sol1a, sol2aaa.ravel(), sol2abb.ravel()))
sol_b = np.hstack((sol1b, sol2baa.ravel(), sol2bbb.ravel()))
for iq, q in enumerate(qs):
e1, e2 = vector_to_amplitudes_ip(e_vector[iq], (nmoa,nmob), (nocca,noccb))
e1a, e1b = e1
e2aaa, e2baa, e2abb, e2bbb = e2
e_vector_a = np.hstack((e1a, e2aaa.ravel(), e2abb.ravel()))
e_vector_b = np.hstack((e1b, e2baa.ravel(), e2bbb.ravel()))
gfvals[0,ip-start,iq,iomega] = -np.dot(e_vector_a, sol_a)
gfvals[1,ip-start,iq,iomega] = -np.dot(e_vector_b, sol_b)
comm.Barrier()
gfvals_gather = comm.gather(gfvals.transpose(1,0,2,3))
if rank == 0:
gfvals_gather = np.vstack(gfvals_gather).transpose(1,0,2,3)
comm.Barrier()
gfvals_gather = comm.bcast(gfvals_gather,root=0)
return gfvals_gather
[docs]
def eaccsd_mo(self, ps, qs, omega_list, broadening, MOR=False, omega_mor=None):
'''
Compute EA-CCSD-GF in MO basis
'''
eomea = pyscf.cc.eom_uccsd.EOMEA(self._cc)
eomea_imds = eomea.make_imds()
diag = eomea.get_diag()
e_vector = list()
t1a, t1b = self._cc.t1
nocca, nvira = t1a.shape
noccb, nvirb = t1b.shape
nmoa = nocca+nvira
nmob = noccb+nvirb
for p in ps:
e_vector.append(greens_e_vector_ea_uhf(self._cc, p))
segsize = len(qs) // size
if rank < len(qs)-segsize*size:
start = rank * segsize + rank
stop = min(len(qs), start+segsize+1)
else:
start = rank * segsize + len(qs)-segsize*size
stop = min(len(qs), start+segsize)
gfvals = np.zeros((2, len(ps), stop-start, len(omega_list)), dtype=np.complex128)
if MOR:
omega_comp = omega_mor
else:
omega_comp = omega_list
for iq in range(start,stop):
q = qs[iq]
b_vector = greens_b_vector_ea_uhf(self._cc, q)
if MOR:
X_vec = np.zeros((len(b_vector), len(omega_mor)), dtype=complex)
for iomega in range(len(omega_comp)):
curr_omega = omega_comp[iomega]
def matr_multiply(vector, args=None):
return greens_func_multiply(eomea.matvec, vector, -curr_omega - 1j * broadening, imds=eomea_imds)
diag_w = diag + (-curr_omega - 1j*broadening)
x0 = b_vector/diag_w
solver = gmres.GMRES(matr_multiply, b_vector, x0, diag_w, tol=self.tol)
cput1 = (time.process_time(), time.perf_counter())
sol = solver.solve().reshape(-1)
if MOR:
# Construct MOR subspace vectors
X_vec[:,iomega] = sol
cput1 = logger.timer(self, 'EAGF orbital q = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
iq+1,len(qs),iomega+1,len(omega_comp),solver.niter,rank), *cput1)
x0 = sol
if not MOR:
sol1, sol2 = vector_to_amplitudes_ea(sol, (nmoa,nmob), (nocca,noccb))
sol1a, sol1b = sol1
sol2aaa, sol2aba, sol2bab, sol2bbb = sol2
sol_a = np.hstack((sol1a, sol2aaa.ravel(), sol2bab.ravel()))
sol_b = np.hstack((sol1b, sol2aba.ravel(), sol2bbb.ravel()))
for ip, p in enumerate(ps):
e1, e2 = vector_to_amplitudes_ea(e_vector[ip], (nmoa,nmob), (nocca,noccb))
e1a, e1b = e1
e2aaa, e2aba, e2bab, e2bbb = e2
e_vector_a = np.hstack((e1a, e2aaa.ravel(), e2bab.ravel()))
e_vector_b = np.hstack((e1b, e2aba.ravel(), e2bbb.ravel()))
gfvals[0,ip,iq-start,iomega] = np.dot(e_vector_a, sol_a)
gfvals[1,ip,iq-start,iomega] = np.dot(e_vector_b, sol_b)
if MOR:
# QR decomposition to orthorgonalize X_vec
S_vec, R_vec = scipy.linalg.qr(X_vec, mode='economic')
# Construct reduced order model
n_mor = len(omega_mor)
HS = np.zeros_like(S_vec)
for i in range(n_mor):
HS[:,i] = greens_func_multiply(eomea.matvec, S_vec[:,i], 0., imds=eomea_imds)
# Reduced Hamiltonian, b_vector, diag
H_mor = np.dot(S_vec.T.conj(), HS)
b_vector_mor = np.dot(S_vec.T.conj(), b_vector)
diag_mor = H_mor.diagonal()
for iomega in range(len(omega_list)):
curr_omega = omega_list[iomega]
def matr_multiply_mor(vector, args=None):
return greens_func_multiply_mor(H_mor, vector, -curr_omega - 1j * broadening)
diag_w = diag_mor + (-curr_omega - 1j*broadening)
x0 = b_vector_mor/diag_w
solver = gmres.GMRES(matr_multiply_mor, b_vector_mor, x0, diag_w, tol=self.tol*0.01)
cput1 = (time.process_time(), time.perf_counter())
sol = solver.solve().reshape(-1)
#cput1 = logger.timer(self, 'MOR EAGF orbital q = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
# iq+1,len(qs),iomega+1,len(omega_list),solver.niter,rank), *cput1)
x0 = sol
sol_full = np.dot(S_vec, sol)
sol1, sol2 = vector_to_amplitudes_ea(sol_full, (nmoa,nmob), (nocca,noccb))
sol1a, sol1b = sol1
sol2aaa, sol2aba, sol2bab, sol2bbb = sol2
sol_a = np.hstack((sol1a, sol2aaa.ravel(), sol2bab.ravel()))
sol_b = np.hstack((sol1b, sol2aba.ravel(), sol2bbb.ravel()))
for ip, p in enumerate(ps):
e1, e2 = vector_to_amplitudes_ea(e_vector[ip], (nmoa,nmob), (nocca,noccb))
e1a, e1b = e1
e2aaa, e2aba, e2bab, e2bbb = e2
e_vector_a = np.hstack((e1a, e2aaa.ravel(), e2bab.ravel()))
e_vector_b = np.hstack((e1b, e2aba.ravel(), e2bbb.ravel()))
gfvals[0,ip,iq-start,iomega] = np.dot(e_vector_a, sol_a)
gfvals[1,ip,iq-start,iomega] = np.dot(e_vector_b, sol_b)
comm.Barrier()
gfvals_gather = comm.gather(gfvals.transpose(2,0,1,3))
if rank == 0:
gfvals_gather = np.vstack(gfvals_gather).transpose(1,2,0,3)
comm.Barrier()
gfvals_gather = comm.bcast(gfvals_gather,root=0)
return gfvals_gather
[docs]
def get_gf(self, p, q, omega_list, broadening):
return (self.ipccsd_mo(p, q, omega_list, broadening),
self.eaccsd_mo(p, q, omega_list, broadening))
if __name__ == '__main__':
from pyscf import gto, scf, cc
mol = gto.M(
atom = 'O 0 0 0',
basis = '6-31G',
spin = 2,
verbose = 5,
)
mf = scf.UHF(mol)
mf.kernel()
mycc = cc.UCCSD(mf)
mycc.kernel()
mycc.solve_lambda()
myccgf = UCCGF(mycc, tol=1e-4)
omega = np.linspace(-1.0, 1.0, 201)
omega_mor = np.linspace(-1.0, 0., 20)
eta = 0.02
nmo = len(mf.mo_energy[0])
ps = np.arange(nmo)
qs = np.arange(nmo)
gf_ip_mor = myccgf.ipccsd_mo(ps, qs, omega, eta, MOR=True, omega_mor=omega_mor).conj()
print ('--- UCCGF MOR IP ---')
for i in range(len(omega)):
print (omega[i], -np.trace(gf_ip_mor[0,:,:,i].imag)/np.pi, -np.trace(gf_ip_mor[1,:,:,i].imag)/np.pi)
gf_ip_full = myccgf.ipccsd_mo(ps, qs, omega, eta).conj()
print ('--- UCCGF Full IP ---')
for i in range(len(omega)):
print (omega[i], -np.trace(gf_ip_full[0,:,:,i].imag)/np.pi, -np.trace(gf_ip_full[1,:,:,i].imag)/np.pi)
omega_mor = np.linspace(0, 1, 20)
gf_ea_mor = myccgf.eaccsd_mo(ps, qs, omega, eta, MOR=True, omega_mor=omega_mor)
print ('--- UCCGF MOR EA ---')
for i in range(len(omega)):
print (omega[i], -np.trace(gf_ea_mor[0,:,:,i].imag)/np.pi, -np.trace(gf_ea_mor[1,:,:,i].imag)/np.pi)
gf_ea_full = myccgf.eaccsd_mo(ps, qs, omega, eta)
print ('--- UCCGF Full EA ---')
for i in range(len(omega)):
print (omega[i], -np.trace(gf_ea_full[0,:,:,i].imag)/np.pi, -np.trace(gf_ea_full[1,:,:,i].imag)/np.pi)