Skip to content

Commit a0441a1

Browse files
committed
fixed kmp2 added broken dfcc2
1 parent 12799a6 commit a0441a1

File tree

2 files changed

+299
-4
lines changed

2 files changed

+299
-4
lines changed

pyscf/cc/dfrcc2.py

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
import numpy as np
2+
from pyscf import lib
3+
from pyscf.lib import logger
4+
from pyscf.ao2mo import _ao2mo
5+
from pyscf import __config__
6+
from pyscf.cc import ccsd
7+
from pyscf.cc.ccsd import _ChemistsERIs
8+
9+
BLKMIN = getattr(__config__, 'cc_ccsd_blkmin', 4)
10+
MEMORYMIN = getattr(__config__, 'cc_ccsd_memorymin', 2000)
11+
'''
12+
CC2 T2 equations
13+
+'iajb'
14+
+'cajb,ic->ijab'
15+
-'ikjb,ka->ijab'
16+
+'iadb,jd->ijab'
17+
-'iajl,lb->ijab'
18+
-'ckjb,ic,ka->ijab'
19+
+'cadb,ic,jd->ijab'
20+
-'cajl,ic,lb->ijab'
21+
-'ikdb,ka,jd->ijab'
22+
+'ikjl,ka,lb->ijab'
23+
-'iadl,jd,lb->ijab'
24+
-'ckdb,ic,ka,jd->ijab'
25+
+'ckjl,ic,ka,lb->ijab'
26+
-'cadl,ic,jd,lb->ijab'
27+
+'ikdl,ka,jd,lb->ijab'
28+
+'ckdl,ic,ak,jd,lb->ijab'
29+
'''
30+
31+
def form_t2i(cc, t1, eris, i):
32+
Loo = eris.Loo
33+
Lov = eris.Lov
34+
Lvv = eris.Lvv
35+
nocc, nvir = t1.shape
36+
mo_e_o = eris.mo_energy[:nocc]
37+
mo_e_v = eris.mo_energy[nocc:] + cc.level_shift
38+
eia = mo_e_o[:,None] - mo_e_v
39+
t2i = lib.einsum('La,Ljb->jab', Lov[:, i, :], Lov)
40+
t2i += lib.einsum('Lca,Ljb,c->jab', Lvv, Lov, t1[i])
41+
t2i -= lib.einsum('Lk,Ljb,ka->jab', Loo[:, i, :], Lov, t1)
42+
t2i += lib.einsum('La,Ldb,jd->jab', Lov[:, i, :], Lvv, t1)
43+
t2i -= lib.einsum('La,Ljl,lb->jab', Lov[:, i, :], Loo, t1)
44+
t2i -= lib.einsum('Lkc,Ljb,c,ka->jab', Lov, Lov, t1[i], t1) # transpose o->v, v->o
45+
t2i += lib.einsum('Lca,Ldb,c,jd->jab', Lvv, Lvv, t1[i], t1)
46+
t2i -= lib.einsum('Lca,Ljl,c,lb->jab', Lvv, Loo, t1[i], t1)
47+
t2i -= lib.einsum('Lk,Ldb,ka,jd->jab', Loo[:, i, :], Lvv, t1, t1)
48+
t2i += lib.einsum('Lk,Ljl,ka,lb->jab', Loo[:, i, :], Loo, t1, t1)
49+
t2i -= lib.einsum('La,Lld,jd,lb->jab', Lov[:, i, :], Lov, t1, t1) # transpose o->v, v->o
50+
t2i -= lib.einsum('Lkc,Ldb,c,ka,jd->jab', Lov, Lvv, t1[i], t1, t1) # transpose
51+
t2i += lib.einsum('Lkc,Ljl,c,ka,lb->jab', Lov, Loo, t1[i], t1, t1) # transpose
52+
t2i -= lib.einsum('Lca,Lld,c,jd,lb->jab', Lvv, Lov, t1[i], t1, t1) # transpose
53+
t2i += lib.einsum('Lk,Lld,ka,jd,lb->jab', Loo[:, i, :], Lov, t1, t1, t1) # transpose
54+
t2i += lib.einsum('Lkc,Lld,c,ka,jd,lb->jab', Lov, Lov, t1[i], t1, t1, t1) # transpose
55+
ejab = lib.direct_sum('jb+a->jab', eia, eia[i])
56+
t2i /= ejab
57+
return t2i
58+
59+
60+
def energy(cc, t1=None, eris=None):
61+
'''RCCSD correlation energy'''
62+
if t1 is None: t1 = cc.t1
63+
if eris is None: eris = cc.ao2mo()
64+
65+
nocc, nvir = t1.shape
66+
fock = eris.fock
67+
68+
Lov = eris.Lov
69+
Lvv = eris.Lvv
70+
71+
mo_e_o = eris.mo_energy[:nocc]
72+
mo_e_v = eris.mo_energy[nocc:] + cc.level_shift
73+
eia = mo_e_o[:,None] - mo_e_v
74+
75+
e = 2*np.einsum('ia,ia', fock[:nocc,nocc:], t1)
76+
e += 2*lib.einsum('Lia,Ljb,ia,jb', Lov, Lov, t1, t1)
77+
e += -lib.einsum('Lib,Lja,ia,jb', Lov, Lov, t1, t1)
78+
for i in range(nocc):
79+
t2i = form_t2i(cc, t1, eris, i)
80+
e += 2*lib.einsum('jab,La,Ljb', t2i, Lov[:, i, :], Lov)
81+
e += -lib.einsum('jab,Lb,Lja', t2i, Lov[:, i, :], Lov)
82+
83+
if abs(e.imag) > 1e-4:
84+
logger.warn(cc, 'Non-zero imaginary part found in RCCSD energy %s', e)
85+
return e.real
86+
87+
def update_t1(cc, t1, eris):
88+
# Ref: Hirata et al., J. Chem. Phys. 120, 2581 (2004) Eqs.(35)-(36)
89+
assert(isinstance(eris, ccsd._ChemistsERIs))
90+
nocc, nvir = t1.shape
91+
naux = eris.naux
92+
fock = eris.fock
93+
mo_e_o = eris.mo_energy[:nocc]
94+
mo_e_v = eris.mo_energy[nocc:] + cc.level_shift
95+
Loo = eris.Loo
96+
Lov = eris.Lov
97+
Lvv = eris.Lvv
98+
99+
fov = fock[:nocc,nocc:].copy()
100+
foo = fock[:nocc,:nocc].copy()
101+
fvv = fock[nocc:,nocc:].copy()
102+
103+
eia = mo_e_o[:,None] - mo_e_v
104+
105+
Foo = foo.copy()
106+
Fvv = fvv.copy()
107+
Fov = fov.copy()
108+
Fov += 2*lib.einsum('Lkc,Lld,ld->kc', Lov, Lov, t1)
109+
Fov -= lib.einsum('Lkd,Llc,ld->kc', Lov, Lov, t1)
110+
111+
t1new = np.zeros_like(t1)
112+
# T2 contractions
113+
for i in range(nocc):
114+
t2i = form_t2i(cc, t1, eris, i)
115+
116+
Foo[:, i] += 2*lib.einsum('Lkc,Lld,lcd->k', Lov, Lov, t2i)
117+
Foo[:, i] -= lib.einsum('Lkd,Llc,lcd->k', Lov, Lov, t2i)
118+
119+
vov = lib.einsum('Lc,Lld->cld', Lov[:, i, :], Lov)
120+
Fvv -= 2*lib.einsum('cld,lad->ac', vov, t2i)
121+
Fvv += lib.einsum('dlc,lad->ac', vov, t2i)
122+
123+
t1new += 2*lib.einsum('c,ica->ia', Fov[i], t2i)
124+
t1new[i] += -lib.einsum('kc,kca->a', Fov, t2i)
125+
t1new[i] += 2*lib.einsum('Lkd,Lac,kcd->a', Lov, Lvv, t2i)
126+
t1new[i] += -lib.einsum('Lkc,Lad,kcd->a', Lov, Lvv, t2i)
127+
t1new +=-2*lib.einsum('Llc,Li,lac->ia', Lov,Loo[:, i, :], t2i)
128+
t1new += lib.einsum('Lc,Lli,lac->ia', Lov[:, i, :], Loo, t2i)
129+
130+
Foo += 2*lib.einsum('Lkc,Lld,ic,ld->k', Lov, Lov, t1, t1)
131+
Foo -= lib.einsum('Lkd,Llc,ic,ld->k', Lov, Lov, t1, t1)
132+
Fvv -= 2*lib.einsum('Lkc,Lld,ka,ld->ac', Lov, Lov, t1, t1)
133+
Fvv += lib.einsum('Lkd,Llc,la,ld->ac', Lov, Lov, t1, t1)
134+
Foo[np.diag_indices(nocc)] -= mo_e_o
135+
Fvv[np.diag_indices(nvir)] -= mo_e_v
136+
137+
# T1 equation
138+
t1new +=-2*np.einsum('kc,ka,ic->ia', fov, t1, t1)
139+
t1new += np.einsum('ac,ic->ia', Fvv, t1)
140+
t1new += -np.einsum('ki,ka->ia', Foo, t1)
141+
t1new += np.einsum('kc,ic,ka->ia', Fov, t1, t1)
142+
t1new += fov.conj()
143+
t1new += 2*lib.einsum('Lkc,Lia,kc->ia', Lov, Lov, t1)
144+
t1new += -lib.einsum('Lki,Lac,kc->ia', Loo, Lvv, t1)
145+
t1new += 2*lib.einsum('Lkd,Lac,kd,ic->ia', Lov, Lvv, t1, t1)
146+
t1new += -lib.einsum('Lkc,Lad,kd,ic->ia', Lov, Lvv, t1, t1)
147+
t1new +=-2*lib.einsum('Llc,Lki,lc,ka->ia', Lov, Loo, t1, t1)
148+
t1new += lib.einsum('Lkc,Lli,lc,ka->ia', Lov, Loo, t1, t1)
149+
150+
t1new /= eia
151+
152+
return t1new
153+
154+
def update_amps(cc, t1, eris):
155+
t1new = update_t1(cc, t1, eris)
156+
return t1new
157+
158+
def amplitudes_to_vector(t1, out=None):
159+
nocc, nvir = t1.shape
160+
nov = nocc * nvir
161+
size = nov
162+
vector = np.ndarray(size, t1.dtype, buffer=out)
163+
vector = t1.ravel()
164+
return vector
165+
166+
def vector_to_amplitudes(vector, nmo, nocc):
167+
nvir = nmo - nocc
168+
nov = nocc * nvir
169+
t1 = vector.reshape((nocc, nvir))
170+
return t1
171+
172+
# t1: ia
173+
# t2: ijab
174+
def kernel(mycc, eris=None, t1=None, t2=None, max_cycle=50, tol=1e-8,
175+
tolnormt=1e-6, verbose=None):
176+
log = logger.new_logger(mycc, verbose)
177+
if eris is None:
178+
eris = mycc.ao2mo(mycc.mo_coeff)
179+
if t1 is None:
180+
t1 = mycc.get_init_guess(eris)
181+
182+
cput1 = cput0 = (logger.process_clock(), logger.perf_counter())
183+
eold = 0
184+
eccsd = mycc.energy(t1, eris)
185+
log.info('Init E_corr(CCSD) = %.15g', eccsd)
186+
187+
if isinstance(mycc.diis, lib.diis.DIIS):
188+
adiis = mycc.diis
189+
elif mycc.diis:
190+
adiis = lib.diis.DIIS(mycc, mycc.diis_file, incore=mycc.incore_complete)
191+
adiis.space = mycc.diis_space
192+
else:
193+
adiis = None
194+
195+
conv = False
196+
for istep in range(max_cycle):
197+
t1new = mycc.update_amps(t1, eris)
198+
print(t1)
199+
print(t1new)
200+
tmpvec = mycc.amplitudes_to_vector(t1new)
201+
print(tmpvec)
202+
tmpvec -= mycc.amplitudes_to_vector(t1)
203+
print(tmpvec)
204+
normt = np.linalg.norm(tmpvec)
205+
tmpvec = None
206+
if mycc.iterative_damping < 1.0:
207+
alpha = mycc.iterative_damping
208+
t1new = (1-alpha) * t1 + alpha * t1new
209+
t1 = t1new
210+
t1new = None
211+
t1 = mycc.run_diis(t1, istep, normt, eccsd-eold, adiis)
212+
eold, eccsd = eccsd, mycc.energy(t1, eris)
213+
log.info('cycle = %d E_corr(CCSD) = %.15g dE = %.9g norm(t1) = %.6g',
214+
istep+1, eccsd, eccsd - eold, normt)
215+
cput1 = log.timer('CCSD iter', *cput1)
216+
if abs(eccsd-eold) < tol and normt < tolnormt:
217+
conv = True
218+
break
219+
log.timer('CCSD', *cput0)
220+
return conv, eccsd, t1
221+
222+
def _make_df_eris(cc, mo_coeff=None):
223+
eris = _ChemistsERIs()
224+
eris._common_init_(cc, mo_coeff)
225+
nocc = eris.nocc
226+
nmo = eris.fock.shape[0]
227+
nvir = nmo - nocc
228+
with_df = cc._scf.with_df
229+
naux = eris.naux = with_df.get_naoaux()
230+
231+
Loo = np.empty((naux,nocc,nocc))
232+
Lov = np.empty((naux,nocc,nvir))
233+
Lvv = np.empty((naux,nvir,nvir))
234+
mo = np.asarray(eris.mo_coeff, order='F')
235+
ijslice = (0, nmo, 0, nmo)
236+
p1 = 0
237+
Lpq = None
238+
for k, eri1 in enumerate(with_df.loop()):
239+
Lpq = _ao2mo.nr_e2(eri1, mo, ijslice, aosym='s2', mosym='s1', out=Lpq)
240+
p0, p1 = p1, p1 + Lpq.shape[0]
241+
Lpq = Lpq.reshape(p1-p0,nmo,nmo)
242+
Loo[p0:p1] = Lpq[:,:nocc,:nocc]
243+
Lov[p0:p1] = Lpq[:,:nocc,nocc:]
244+
Lvv[p0:p1] = Lpq[:,nocc:,nocc:]
245+
Lpq = None
246+
eris.Loo = Loo
247+
eris.Lov = Lov
248+
eris.Lvv = Lvv
249+
250+
return eris
251+
252+
class DFRCC2(ccsd.CCSD):
253+
'''restricted CCSD with IP-EOM, EA-EOM, EE-EOM, and SF-EOM capabilities
254+
255+
Ground-state CCSD is performed in optimized ccsd.CCSD and EOM is performed here.
256+
'''
257+
energy = energy
258+
kernel = kernel
259+
update_amps = update_amps
260+
261+
def update_amps(cc, t1, eris):
262+
t1new = update_t1(cc, t1, eris)
263+
return t1new
264+
265+
def get_init_guess(self, eris=None):
266+
if eris is None:
267+
eris = self.ao2mo(self.mo_coeff)
268+
nocc = self.nocc
269+
mo_e = eris.mo_energy
270+
eia = mo_e[:nocc,None] - mo_e[None,nocc:]
271+
t1 = eris.fock[:nocc,nocc:] / eia
272+
return t1
273+
274+
def amplitudes_to_vector(self, t1, out=None):
275+
return amplitudes_to_vector(t1, out)
276+
277+
def vector_to_amplitudes(self, vec, nmo=None, nocc=None):
278+
if nocc is None: nocc = self.nocc
279+
if nmo is None: nmo = self.nmo
280+
return vector_to_amplitudes(vec, nmo, nocc)
281+
282+
def run_diis(self, t1, istep, normt, de, adiis):
283+
if (adiis and
284+
istep >= self.diis_start_cycle and
285+
abs(de) < self.diis_start_energy_diff):
286+
vec = self.amplitudes_to_vector(t1)
287+
t1 = self.vector_to_amplitudes(adiis.update(vec))
288+
logger.debug1(self, 'DIIS for step %d', istep)
289+
return t1
290+
291+
def ao2mo(self, mo_coeff=None):
292+
return _make_df_eris(self, mo_coeff)

pyscf/pbc/mp/kmp2.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,6 @@ def kernel(mp, mo_energy, mo_coeff, verbose=logger.NOTE, with_t2=WITH_T2):
7979
mem_usage += (nkpts**2 * naux * nocc * nvir) * 16 / 1e6
8080
if with_t2:
8181
mem_usage += (nkpts**3 * (nocc * nvir)**2) * 16 / 1e6
82-
if mem_usage > mem_avail:
83-
raise MemoryError('Insufficient memory! MP2 memory usage %d MB (currently available %d MB)'
84-
% (mem_usage, mem_avail))
8582

8683
eia = np.zeros((nocc,nvir))
8784
eijab = np.zeros((nocc,nocc,nvir,nvir))
@@ -98,7 +95,13 @@ def kernel(mp, mo_energy, mo_coeff, verbose=logger.NOTE, with_t2=WITH_T2):
9895
nonzero_opadding, nonzero_vpadding = padding_k_idx(mp, kind="split")
9996

10097
if with_t2:
101-
t2 = np.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=complex)
98+
if mem_usage > mem_avail:
99+
ft2 = lib.H5TmpFile()
100+
t2 = ft2.create_dataset('t2', (nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=complex)
101+
# raise MemoryError('Insufficient memory! MP2 memory usage %d MB (currently available %d MB)'
102+
# % (mem_usage, mem_avail))
103+
else:
104+
t2 = np.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=complex)
102105
else:
103106
t2 = None
104107

0 commit comments

Comments
 (0)