9
9
BLKMIN = getattr (__config__ , 'cc_ccsd_blkmin' , 4 )
10
10
MEMORYMIN = getattr (__config__ , 'cc_ccsd_memorymin' , 2000 )
11
11
12
- def update_t1 (cc , t1 , t2 , eris ):
12
+ def energy (mycc , t1 = None , eris = None ):
13
+ '''CCSD correlation energy'''
14
+ if t1 is None : t1 = mycc .t1
15
+ if eris is None : eris = mycc .ao2mo ()
16
+
17
+ nocc , nvir = t1 .shape
18
+ fock = eris .fock
19
+ mo_e_o = eris .mo_energy [:nocc ]
20
+ mo_e_v = eris .mo_energy [nocc :] + mycc .level_shift
21
+ eia = mo_e_o [:,None ] - mo_e_v
22
+ Lov = eris .Lov
23
+ Bov = make_Bov (mycc , t1 , eris )
24
+ e = np .einsum ('ia,ia' , fock [:nocc ,nocc :], t1 ) * 2
25
+ for i in range (nocc ):
26
+ t2i = lib .einsum ('La,Ljb->jab' , Bov [:, i , :], Bov )
27
+ ejab = lib .direct_sum ('a,jb->jab' , eia [i , :], eia )
28
+ t2i /= ejab
29
+ taui = t2i + lib .einsum ('a,jb->jab' , t1 [i , :], t1 )
30
+ e += 2 * lib .einsum ('jab,La,Ljb' , taui , Lov [:, i , :], Lov )
31
+ e -= lib .einsum ('iab,Lia,Lb' , taui , Lov , Lov [:, i , :])
32
+
33
+ if abs (e .imag ) > 1e-4 :
34
+ logger .warn (mycc , 'Non-zero imaginary part found in CCSD energy %s' , e )
35
+ return e .real
36
+
37
+ def update_t1 (cc , t1 , eris ):
13
38
# Ref: Hirata et al., J. Chem. Phys. 120, 2581 (2004) Eqs.(35)-(36)
14
39
assert (isinstance (eris , ccsd ._ChemistsERIs ))
15
40
nocc , nvir = t1 .shape
16
41
fock = eris .fock
17
42
mo_e_o = eris .mo_energy [:nocc ]
18
43
mo_e_v = eris .mo_energy [nocc :] + cc .level_shift
19
44
45
+ eia = mo_e_o [:,None ] - mo_e_v
46
+
47
+ Loo = eris .Loo
48
+ Lov = eris .Lov
49
+ Lvv = eris .Lvv
50
+
51
+ Bov = make_Bov (cc , t1 , eris )
52
+
53
+ foo = fock [:nocc ,:nocc ].copy ()
20
54
fov = fock [:nocc ,nocc :].copy ()
55
+ fvv = fock [nocc :,nocc :].copy ()
21
56
22
- Foo = imd .cc_Foo (t1 ,t2 ,eris )
23
- Fvv = imd .cc_Fvv (t1 ,t2 ,eris )
24
- Fov = imd .cc_Fov (t1 ,t2 ,eris )
57
+ Fki = np .zeros_like (foo )
58
+ Fac = np .zeros_like (fvv )
59
+ Fkc = np .zeros_like (fov )
60
+ for i in range (nocc ):
61
+ t2i = lib .einsum ('La,Ljb->jab' , Bov [:, i , :], Bov )
62
+ ejab = lib .direct_sum ('a,jb->jab' , eia [i , :], eia )
63
+ t2i /= ejab
64
+ Fki [:, i ] += 2 * lib .einsum ('Lkc,Lld,lcd->k' , Lov , Lov , t2i )
65
+ Fki [:, i ] -= lib .einsum ('Lkd,Llc,lcd->k' , Lov , Lov , t2i )
66
+ Fac += - 2 * lib .einsum ('Lc,Lld,lad->ac' , Lov [:, i , :], Lov , t2i )
67
+ Fac += lib .einsum ('Ld,Llc,lad->ac' , Lov [:, i , :], Lov , t2i )
68
+ Fki += 2 * lib .einsum ('Lkc,Lld,ic,ld->ki' , Lov , Lov , t1 , t1 )
69
+ Fki -= lib .einsum ('Lkd,Llc,ic,ld->ki' , Lov , Lov , t1 , t1 )
70
+ Fac -= 2 * lib .einsum ('Lkc,Lld,ka,ld->ac' , Lov , Lov , t1 , t1 )
71
+ Fac += lib .einsum ('Lkd,Llc,ka,ld->ac' , Lov , Lov , t1 , t1 )
72
+ Fkc = 2 * np .einsum ('Lkc,Lld,ld->kc' , Lov , Lov , t1 )
73
+ Fkc -= np .einsum ('Lkd,Llc,ld->kc' , Lov , Lov , t1 )
74
+ Fki += foo
75
+ Fac += fvv
76
+ Fkc += fov
77
+ Foo = Fki
78
+ Fvv = Fac
79
+ Fov = Fkc
25
80
26
81
# Move energy terms to the other side
27
82
Foo [np .diag_indices (nocc )] -= mo_e_o
28
83
Fvv [np .diag_indices (nvir )] -= mo_e_v
29
84
30
- Loo = eris .Loo
31
- Lov = eris .Lov
32
- Lvv = eris .Lvv
33
-
34
- eia = mo_e_o [:,None ] - mo_e_v
35
-
36
85
# T1 equation
37
86
t1new = - 2 * np .einsum ('kc,ka,ic->ia' , fov , t1 , t1 )
38
87
t1new += np .einsum ('ac,ic->ia' , Fvv , t1 )
39
88
t1new += - np .einsum ('ki,ka->ia' , Foo , t1 )
40
- t1new += 2 * np .einsum ('kc,kica->ia' , Fov , t2 )
41
- t1new += - np .einsum ('kc,ikca->ia' , Fov , t2 )
89
+ for i in range (nocc ):
90
+ t2i = lib .einsum ('La,Ljb->jab' , Bov [:, i , :], Bov )
91
+ ejab = lib .direct_sum ('a,jb->jab' , eia [i , :], eia )
92
+ t2i /= ejab
93
+ t1new += 2 * lib .einsum ('c,ica->ia' , Fov [i , :], t2i )
94
+ t1new [i , :] += - lib .einsum ('kc,kca->a' , Fov , t2i )
95
+ t1new [i , :] += 2 * lib .einsum ('Lkd,Lac,kcd->a' , Lov , Lvv , t2i )
96
+ t1new [i , :] += - lib .einsum ('Lkc,Lad,kcd->a' , Lov , Lvv , t2i )
97
+ t1new += - 2 * lib .einsum ('Llc,Li,lac->ia' , Lov , Loo [:, i , :], t2i )
98
+ t1new += lib .einsum ('Lc,Lli,lac->ia' , Lov [:, i , :], Loo , t2i )
99
+
42
100
t1new += np .einsum ('kc,ic,ka->ia' , Fov , t1 , t1 )
43
101
t1new += fov .conj ()
44
102
t1new += 2 * np .einsum ('Lkc,Lia,kc->ia' , Lov , Lov , t1 )
45
103
t1new += - np .einsum ('Lki,Lac,kc->ia' , Loo , Lvv , t1 )
46
- t1new += 2 * lib .einsum ('Lkd,Lac,ikcd->ia' , Lov , Lvv , t2 )
47
- t1new += - lib .einsum ('Lkc,Lad,ikcd->ia' , Lov , Lvv , t2 )
48
104
t1new += 2 * lib .einsum ('Lkd,Lac,kd,ic->ia' , Lov , Lvv , t1 , t1 )
49
105
t1new += - lib .einsum ('Lkc,Lad,kd,ic->ia' , Lov , Lvv , t1 , t1 )
50
- t1new += - 2 * lib .einsum ('Llc,Lki,klac->ia' , Lov , Loo , t2 )
51
- t1new += lib .einsum ('Lkc,Lli,klac->ia' , Lov , Loo , t2 )
52
106
t1new += - 2 * lib .einsum ('Llc,Lki,lc,ka->ia' , Lov , Loo , t1 , t1 )
53
107
t1new += lib .einsum ('Lkc,Lli,lc,ka->ia' , Lov , Loo , t1 , t1 )
54
108
55
109
t1new /= eia
56
110
57
111
return t1new
58
112
59
- def update_t2 (cc , t1 , t2 , eris ):
60
- # Ref: Hirata et al., J. Chem. Phys. 120, 2581 (2004) Eqs.(35)-(36)
61
- assert (isinstance (eris , ccsd ._ChemistsERIs ))
62
- nocc , nvir = t1 .shape
63
- fock = eris .fock
64
- mo_e_o = eris .mo_energy [:nocc ]
65
- mo_e_v = eris .mo_energy [nocc :] + cc .level_shift
66
-
67
- fov = fock [:nocc ,nocc :].copy ()
68
- foo = fock [:nocc ,:nocc ].copy ()
69
- fvv = fock [nocc :,nocc :].copy ()
70
-
71
- Foo = imd .cc_Foo (t1 ,t2 ,eris )
72
- Fvv = imd .cc_Fvv (t1 ,t2 ,eris )
73
-
74
- # Move energy terms to the other side
75
- Foo [np .diag_indices (nocc )] -= mo_e_o
76
- Fvv [np .diag_indices (nvir )] -= mo_e_v
77
-
78
- Loo = eris .Loo
79
- Lov = eris .Lov
80
- Lvv = eris .Lvv
81
-
82
- # T2 equation
83
- tmp2 = lib .einsum ('Lki,Lbc,ka->abic' , Loo , Lvv , - t1 )
84
- tmp2 += lib .einsum ('Lia,Lbc->acib' , Lov , Lvv ).conj ()
85
- tmp = lib .einsum ('abic,jc->ijab' , tmp2 , t1 )
86
- t2new = tmp + tmp .transpose (1 ,0 ,3 ,2 )
87
- tmp2 = lib .einsum ('Lkc,Lia,jc->akij' , Lov , Lov , t1 )
88
- tmp2 += lib .einsum ('Lia,Ljk->akij' , Lov , Loo ).conj ()
89
- tmp = lib .einsum ('akij,kb->ijab' , tmp2 , t1 )
90
- t2new -= tmp + tmp .transpose (1 ,0 ,3 ,2 )
91
- t2new += lib .einsum ('Lia,Ljb->ijab' , Lov , Lov ).conj ()
92
- Woooo2 = lib .einsum ('Lij,Lkl->ikjl' , Loo , Loo )
93
- Woooo2 += lib .einsum ('Llc,Lki,jc->klij' , Lov , Loo , t1 )
94
- Woooo2 += lib .einsum ('Lkc,Llj,ic->klij' , Lov , Loo , t1 )
95
- Woooo2 += lib .einsum ('Lkc,Lld,ic,jd->klij' , Lov , Lov , t1 , t1 )
96
- t2new += lib .einsum ('klij,ka,lb->ijab' , Woooo2 , t1 , t1 )
97
- Wvvvv = lib .einsum ('Lkc,Lbd,ka->abcd' , Lov , Lvv , - t1 )
98
- Wvvvv = Wvvvv + Wvvvv .transpose (1 ,0 ,3 ,2 )
99
- Wvvvv += lib .einsum ('Lab,Lcd->acbd' , Lvv , Lvv )
100
- t2new += lib .einsum ('abcd,ic,jd->ijab' , Wvvvv , t1 , t1 )
101
- Lvv2 = fvv - np .einsum ('kc,ka->ac' , fov , t1 )
102
- Lvv2 -= np .diag (np .diag (fvv ))
103
- tmp = lib .einsum ('ac,ijcb->ijab' , Lvv2 , t2 )
104
- t2new += (tmp + tmp .transpose (1 ,0 ,3 ,2 ))
105
- Loo2 = foo + np .einsum ('kc,ic->ki' , fov , t1 )
106
- Loo2 -= np .diag (np .diag (foo ))
107
- tmp = lib .einsum ('ki,kjab->ijab' , Loo2 , t2 )
108
- t2new -= (tmp + tmp .transpose (1 ,0 ,3 ,2 ))
109
-
110
- eia = mo_e_o [:,None ] - mo_e_v
111
- eijab = lib .direct_sum ('ia,jb->ijab' ,eia ,eia )
112
- t2new /= eijab
113
-
114
- return t2new
113
+ def make_Bov (cc , t1 , eris ):
114
+ nocc = eris .nocc
115
+ nmo = eris .fock .shape [0 ]
116
+ nvir = nmo - nocc
117
+ naux = cc ._scf .with_df .get_naoaux ()
118
+ C = eris .mo_coeff .copy ()
119
+ X = C [:, nocc :] - lib .einsum ('ui,ia->ua' , C [:, :nocc ], t1 )
120
+ Y = C [:, :nocc ] + lib .einsum ('ua,ia->ui' , C [:, nocc :], t1 )
121
+ C [:, :nocc ] = Y
122
+ C [:, nocc :] = X
123
+ Bov = np .empty ((naux ,nocc ,nvir ))
124
+ ijslice = (0 , nmo , 0 , nmo )
125
+ Lpq = None
126
+ p1 = 0
127
+ for eri1 in cc ._scf .with_df .loop ():
128
+ Lpq = _ao2mo .nr_e2 (eri1 , C , ijslice , aosym = 's2' , out = Lpq ).reshape (- 1 ,nmo ,nmo )
129
+ p0 , p1 = p1 , p1 + Lpq .shape [0 ]
130
+ Bov [p0 :p1 ] = Lpq [:,:nocc ,nocc :]
131
+ return Bov
115
132
116
133
def make_t2 (cc , t1 , eris ):
117
134
nocc = eris .nocc
@@ -139,15 +156,9 @@ def make_t2(cc, t1, eris):
139
156
t2 /= eijab
140
157
return t2
141
158
142
- def update_amps (cc , t1 , t2 , eris ):
143
- t2 = make_t2 (cc , t1 , eris )
144
- t1new = update_t1 (cc , t1 , t2 , eris )
145
- t2new = make_t2 (cc , t1new , eris )
146
- # Compare t2_t1 with t2
147
- print ("T2 COMPARE" )
148
- #print(np.allclose(t2_t1, t2))
149
- #t2new = update_t2(cc, t1, t2, eris)
150
- return t1new , t2new
159
+ def update_amps (cc , t1 , eris ):
160
+ t1new = update_t1 (cc , t1 , eris )
161
+ return t1new
151
162
152
163
# t1: ia
153
164
# t2: ijab
@@ -156,14 +167,17 @@ def kernel(mycc, eris=None, t1=None, t2=None, max_cycle=50, tol=1e-8,
156
167
log = logger .new_logger (mycc , verbose )
157
168
if eris is None :
158
169
eris = mycc .ao2mo (mycc .mo_coeff )
159
- if t1 is None and t2 is None :
160
- t1 , t2 = mycc .get_init_guess (eris )
161
- elif t2 is None :
162
- t2 = mycc .get_init_guess (eris )[1 ]
170
+ if t1 is None :
171
+ mo_e = eris .mo_energy
172
+ nocc = mycc .nocc
173
+ eia = mo_e [:nocc ,None ] - mo_e [None ,nocc :]
174
+ t1 = eris .fock [:nocc ,nocc :] / eia
175
+ if t2 is None :
176
+ t2 = make_t2 (mycc , t1 , eris )
163
177
164
178
cput1 = cput0 = (logger .process_clock (), logger .perf_counter ())
165
179
eold = 0
166
- eccsd = mycc .energy (t1 , t2 , eris )
180
+ eccsd = mycc .energy (t1 , eris )
167
181
log .info ('Init E_corr(CCSD) = %.15g' , eccsd )
168
182
169
183
if isinstance (mycc .diis , lib .diis .DIIS ):
@@ -176,7 +190,8 @@ def kernel(mycc, eris=None, t1=None, t2=None, max_cycle=50, tol=1e-8,
176
190
177
191
conv = False
178
192
for istep in range (max_cycle ):
179
- t1new , t2new = mycc .update_amps (t1 , t2 , eris )
193
+ t1new = mycc .update_amps (t1 , eris )
194
+ t2new = make_t2 (mycc , t1new , eris )
180
195
tmpvec = mycc .amplitudes_to_vector (t1new , t2new )
181
196
tmpvec -= mycc .amplitudes_to_vector (t1 , t2 )
182
197
normt = np .linalg .norm (tmpvec )
@@ -189,7 +204,7 @@ def kernel(mycc, eris=None, t1=None, t2=None, max_cycle=50, tol=1e-8,
189
204
t1 , t2 = t1new , t2new
190
205
t1new = t2new = None
191
206
t1 , t2 = mycc .run_diis (t1 , t2 , istep , normt , eccsd - eold , adiis )
192
- eold , eccsd = eccsd , mycc .energy (t1 , t2 , eris )
207
+ eold , eccsd = eccsd , mycc .energy (t1 , eris )
193
208
log .info ('cycle = %d E_corr(CCSD) = %.15g dE = %.9g norm(t1,t2) = %.6g' ,
194
209
istep + 1 , eccsd , eccsd - eold , normt )
195
210
cput1 = log .timer ('CCSD iter' , * cput1 )
@@ -198,15 +213,84 @@ def kernel(mycc, eris=None, t1=None, t2=None, max_cycle=50, tol=1e-8,
198
213
break
199
214
log .timer ('CCSD' , * cput0 )
200
215
return conv , eccsd , t1 , t2
216
+ '''
217
+ def kernel(mycc, eris=None, t1=None, max_cycle=50, tol=1e-8,
218
+ tolnormt=1e-6, verbose=None):
219
+ log = logger.new_logger(mycc, verbose)
220
+ if eris is None:
221
+ eris = mycc.ao2mo(mycc.mo_coeff)
222
+ if t1 is None:
223
+ mo_e = eris.mo_energy
224
+ nocc = mycc.nocc
225
+ eia = mo_e[:nocc,None] - mo_e[None,nocc:]
226
+ t1 = eris.fock[:nocc,nocc:] / eia
227
+
228
+ cput1 = cput0 = (logger.process_clock(), logger.perf_counter())
229
+ eold = 0
230
+ # t2 = make_t2(mycc, t1, eris)
231
+ eccsd = mycc.energy(t1, eris)
232
+ log.info('Init E_corr(CCSD) = %.15g', eccsd)
233
+
234
+ if isinstance(mycc.diis, lib.diis.DIIS):
235
+ adiis = mycc.diis
236
+ elif mycc.diis:
237
+ adiis = lib.diis.DIIS(mycc, mycc.diis_file, incore=mycc.incore_complete)
238
+ adiis.space = mycc.diis_space
239
+ else:
240
+ adiis = None
201
241
242
+ conv = False
243
+ for istep in range(max_cycle):
244
+ t1new = mycc.update_amps(t1, eris)
245
+ tmpvec = mycc.amplitudes_to_vector(t1new)
246
+ tmpvec -= mycc.amplitudes_to_vector(t1)
247
+ normt = np.linalg.norm(tmpvec)
248
+ normt += np.linalg.norm(make_t2(mycc, t1new, eris).ravel() - make_t2(mycc, t1, eris).ravel())
249
+ tmpvec = None
250
+ if mycc.iterative_damping < 1.0:
251
+ alpha = mycc.iterative_damping
252
+ t1new = (1-alpha) * t1 + alpha * t1new
253
+ t1 = t1new
254
+ t1new = None
255
+ t1 = mycc.run_diis(t1, istep, normt, eccsd-eold, adiis)
256
+ eold, eccsd = eccsd, mycc.energy(t1, eris)
257
+ log.info('cycle = %d E_corr(CCSD) = %.15g dE = %.9g norm(t1,t2) = %.6g',
258
+ istep+1, eccsd, eccsd - eold, normt)
259
+ cput1 = log.timer('CCSD iter', *cput1)
260
+ if abs(eccsd-eold) < tol and normt < tolnormt:
261
+ conv = True
262
+ break
263
+ log.timer('CCSD', *cput0)
264
+ return conv, eccsd, t1
265
+ '''
202
266
class DFRCC2 (ccsd .CCSD ):
203
267
'''restricted CCSD with IP-EOM, EA-EOM, EE-EOM, and SF-EOM capabilities
204
268
205
269
Ground-state CCSD is performed in optimized ccsd.CCSD and EOM is performed here.
206
270
'''
271
+ energy = energy
207
272
kernel = kernel
208
273
update_amps = update_amps
274
+ '''
275
+ def amplitudes_to_vector(self, t1, out=None):
276
+ vector = np.ndarray(t1.size, t1.dtype, buffer=out)
277
+ vector = t1.ravel()
278
+ return vector
279
+
280
+ def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
281
+ if nocc is None: nocc = self.nocc
282
+ if nmo is None: nmo = self.nmo
283
+ return vector.reshape(nocc,nmo-nocc)
209
284
285
+ def run_diis(self, t1, istep, normt, de, adiis):
286
+ if (adiis and
287
+ istep >= self.diis_start_cycle and
288
+ abs(de) < self.diis_start_energy_diff):
289
+ vec = self.amplitudes_to_vector(t1)
290
+ t1 = self.vector_to_amplitudes(adiis.update(vec))
291
+ logger.debug1(self, 'DIIS for step %d', istep)
292
+ return t1
293
+ '''
210
294
def ao2mo (self , mo_coeff = None ):
211
295
cput0 = (logger .process_clock (), logger .perf_counter ())
212
296
log = logger .Logger (self .stdout , self .verbose )
0 commit comments