#!/usr/bin/env python
# Copyright 2017-2021 The PySCF Developers. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Authors: James D. McClain
# Timothy Berkelbach <tim.berkelbach@gmail.com>
#
#import numpy as np
from itertools import product
from pyscf import lib
from pyscf.lib import logger
from pyscf.pbc.lib import kpts_helper
import numpy
from pyscf.lib.parameters import LARGE_DENOM # noqa
from pyscf.pbc.mp.kmp2 import (get_frozen_mask, get_nocc, get_nmo,
padded_mo_coeff, padding_k_idx) # noqa
from pyscf.pbc.cc.kccsd_rhf import _get_epq
from pyscf.pbc.cc.kccsd_t_rhf import _get_epqr
#einsum = numpy.einsum
einsum = lib.einsum
#################################################
# FOLLOWING: #
# J. Gauss and J. F. Stanton, #
# J. Chem. Phys. 103, 3561 (1995) Table III #
#################################################
### Section (a)
[docs]
def make_tau(cc, t2, t1, t1p, kconserv, fac=1., out=None):
nkpts, nocc, nvir = t1.shape
tau1 = numpy.ndarray(t2.shape, dtype=t2.dtype, buffer=out)
tau1[:] = t2
for ki in range(nkpts):
for ka in range(nkpts):
for kj in range(nkpts):
kb = kconserv[ki,ka,kj]
tmp = numpy.zeros((nocc,nocc,nvir,nvir),dtype=t2.dtype)
if ki == ka and kj == kb:
tmp += einsum('ia,jb->ijab',t1[ki],t1p[kj])
if ki == kb and kj == ka:
tmp -= einsum('ib,ja->ijab',t1[ki],t1p[kj])
if kj == ka and ki == kb:
tmp -= einsum('ja,ib->ijab',t1[kj],t1p[ki])
if kj == kb and ki == ka:
tmp += einsum('jb,ia->ijab',t1[kj],t1p[ki])
tau1[ki,kj,ka] += fac*0.5*tmp
return tau1
[docs]
def cc_Fvv(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
fov = eris.fock[:,:nocc,nocc:].copy()
fvv = eris.fock[:,nocc:,nocc:].copy()
# <o(k1)v(k2)||v(k3)v(k4)> = <v(k2)o(k1)||v(k4)v(k3)> = -<v(k2)o(k1)||v(k3)v(k4)>
eris_vovv = -eris.ovvv.transpose(1,0,2,4,3,5,6)
tau_tilde = make_tau(cc,t2,t1,t1,kconserv,fac=0.5)
Fae = numpy.zeros(fvv.shape, t1.dtype)
#kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts)
for ka in range(nkpts):
Fae[ka] += fvv[ka]
Fae[ka] += -0.5*einsum('me,ma->ae',fov[ka],t1[ka])
for km in range(nkpts):
Fae[ka] += einsum('mf,amef->ae',t1[km],eris_vovv[ka,km,ka])
for kn in range(nkpts):
#kb = kconserv[km,ka,kn]
Fae[ka] += -0.5*einsum('mnaf,mnef->ae',tau_tilde[km,kn,ka],
eris.oovv[km,kn,ka])
return Fae
[docs]
def cc_Foo(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
fov = eris.fock[:,:nocc,nocc:].copy()
foo = eris.fock[:,:nocc,:nocc].copy()
tau_tilde = make_tau(cc,t2,t1,t1,kconserv,fac=0.5)
Fmi = numpy.zeros(foo.shape, t1.dtype)
for km in range(nkpts):
Fmi[km] += foo[km]
Fmi[km] += 0.5*einsum('me,ie->mi',fov[km],t1[km])
for kn in range(nkpts):
Fmi[km] += einsum('ne,mnie->mi',t1[kn],eris.ooov[km,kn,km])
for ke in range(nkpts):
Fmi[km] += 0.5*einsum('inef,mnef->mi',tau_tilde[km,kn,ke],
eris.oovv[km,kn,ke])
return Fmi
[docs]
def cc_Fov(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
fov = eris.fock[:,:nocc,nocc:].copy()
Fme = numpy.zeros(fov.shape, t1.dtype)
for km in range(nkpts):
Fme[km] += fov[km]
for kf in range(nkpts):
kn = kf
Fme[km] -= einsum('nf,mnfe->me',t1[kf],eris.oovv[km,kn,kf])
return Fme
[docs]
def cc_Woooo(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
tau = make_tau(cc,t2,t1,t1,kconserv)
Wmnij = eris.oooo.copy()
for km in range(nkpts):
for kn in range(nkpts):
# Since it's not enough just to switch i and j and need to create the k_i and k_j
# so that P(ij) switches both i,j and k_i,k_j
# t1[ k_j, j, e ] * v[ k_m, k_n, k_i, m, n, i, e ] -> tmp[ k_i, k_j, m, n, i, j ]
# Here, x = k_j and y = k_i
tmp = einsum('xje,ymnie->yxmnij',t1,eris.ooov[km,kn])
tmp = tmp - tmp.transpose(1,0,2,3,5,4)
ki = numpy.arange(nkpts)
kj = kconserv[km,ki,kn]
kij = (ki,kj)
Wmnij[km,kn,:] += 0.25*einsum('yxijef,xmnef->ymnij',tau[kij],eris.oovv[km,kn])
for ki in range(nkpts):
kj = kconserv[km,ki,kn]
Wmnij[km,kn,ki] += tmp[ki,kj]
return Wmnij
[docs]
def cc_Wvvvv(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
eris_vovv = - eris.ovvv.transpose(1,0,2,4,3,5,6)
tau = make_tau(cc,t2,t1,t1,kconserv)
Wabef = eris.vvvv.copy()
for ka in range(nkpts):
for kb in range(nkpts):
km = numpy.arange(nkpts).tolist()
kn = kconserv[ka,km,kb].tolist()
kmn = (km,kn)
Wabef[ka,kb] += 0.25*einsum('xmnab,xymnef->yabef',tau.transpose(2,0,1,3,4,5,6)[ka][kmn],eris.oovv[kmn])
for ke in range(nkpts):
km = kb
tmp = einsum('mb,amef->abef',t1[kb],eris_vovv[ka,km,ke])
km = ka
tmp -= einsum('ma,bmef->abef',t1[ka],eris_vovv[kb,km,ke])
Wabef[ka,kb,ke] += -tmp
# km + kn - ka = kb
# => kn = ka - km + kb
return Wabef
[docs]
def cc_Wovvo(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
eris_ovvo = numpy.zeros(shape=(nkpts,nkpts,nkpts,nocc,nvir,nvir,nocc),dtype=t2.dtype)
eris_oovo = numpy.zeros(shape=(nkpts,nkpts,nkpts,nocc,nocc,nvir,nocc),dtype=t2.dtype)
for km in range(nkpts):
for kb in range(nkpts):
for ke in range(nkpts):
kj = kconserv[km,ke,kb]
# <mb||je> -> -<mb||ej>
eris_ovvo[km,kb,ke] = -eris.ovov[km,kb,kj].transpose(0,1,3,2)
# <mn||je> -> -<mn||ej>
# let kb = kn as a dummy variable
eris_oovo[km,kb,ke] = -eris.ooov[km,kb,kj].transpose(0,1,3,2)
Wmbej = eris_ovvo.copy()
for km in range(nkpts):
for kb in range(nkpts):
for ke in range(nkpts):
kj = kconserv[km,ke,kb]
Wmbej[km,kb,ke] += einsum('jf,mbef->mbej',t1[kj,:,:],eris.ovvv[km,kb,ke])
Wmbej[km,kb,ke] += -einsum('nb,mnej->mbej',t1[kb,:,:],eris_oovo[km,kb,ke])
temp = numpy.zeros([nkpts, nocc, nocc, nvir, nvir], dtype=t2.dtype)
for kn in range(nkpts):
kf = kconserv[km,ke,kn]
temp[kn] = -0.5*t2[kj,kn,kf].copy()
if kn == kb and kf == kj:
temp[kn] -= einsum('jf,nb->jnfb', t1[kj], t1[kn])
Wmbej[km,kb,ke] += einsum('xjnfb, xmnef->mbej', temp, eris.oovv[km,:,ke])
return Wmbej
[docs]
def cc_Wovvo_jk(cc, t1, t2, eris, kconserv):
nkpts, nocc, nvir = t1.shape
Wmbej = eris.ovvo.copy()
for km in range(nkpts):
for kb in range(nkpts):
for ke in range(nkpts):
kj = kconserv[km,ke,kb]
Wmbej[km,kb,ke] += einsum('jf,mbef->mbej',t1[kj,:,:],eris.ovvv[km,kb,ke])
Wmbej[km,kb,ke] += -einsum('nb,mnej->mbej',t1[kb,:,:],eris.oovo[km,kb,ke])
for kn in range(nkpts):
kf = kconserv[km,ke,kn]
Wmbej[km,kb,ke] += -0.5*einsum('jnfb,mnef->mbej',t2[kj,kn,kf],
eris.oovv[km,kn,ke])
if kn == kb and kf == kj:
Wmbej[km,kb,ke] += -einsum('jf,nb,mnef->mbej',t1[kj],t1[kn],
eris.oovv[km,kn,ke])
return Wmbej
### Section (b)
[docs]
def Fvv(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
ccFov = cc_Fov(cc,t1,t2,eris,kconserv)
Fae = cc_Fvv(cc,t1,t2,eris,kconserv)
for km in range(nkpts):
Fae[km] -= 0.5*einsum('ma,me->ae', t1[km], ccFov[km])
return Fae
[docs]
def Foo(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
ccFov = cc_Fov(cc,t1,t2,eris,kconserv)
Fmi = cc_Foo(cc,t1,t2,eris,kconserv)
for km in range(nkpts):
Fmi[km] += 0.5*einsum('ie,me->mi',t1[km],ccFov[km])
return Fmi
[docs]
def Fov(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
Fme = cc_Fov(cc,t1,t2,eris,kconserv)
return Fme
[docs]
def Woooo(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
tau = make_tau(cc,t2,t1,t1,kconserv)
Wmnij = cc_Woooo(cc,t1,t2,eris,kconserv)
for km in range(nkpts):
for kn in range(nkpts):
for ki in range(nkpts):
kj = kconserv[km ,ki, kn]
Wmnij[km, kn, ki] += 0.25*einsum('xijef,xmnef->mnij',tau[ki, kj, :],
eris.oovv[km, kn, :])
return Wmnij
[docs]
def Wvvvv(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
tau = make_tau(cc,t2,t1,t1,kconserv)
Wabef = cc_Wvvvv(cc,t1,t2,eris,kconserv)
for ka, kb, ke in kpts_helper.loop_kkk(nkpts):
#kf = kconserv[ka, ke, kb]
for km in range(nkpts):
kn = kconserv[ka, km, kb]
Wabef[ka, kb, ke] += 0.25*einsum('mnab,mnef->abef',tau[km, kn, ka],
eris.oovv[km, kn, ke])
return Wabef
[docs]
def Wovvo(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
Wmbej = cc_Wovvo(cc,t1,t2,eris,kconserv)
for km, kb, ke in kpts_helper.loop_kkk(nkpts):
kj = kconserv[km, ke, kb]
for kn in range(nkpts):
kf = kconserv[km, ke, kn]
Wmbej[km, kb, ke] -= 0.5*einsum('jnfb,mnef->mbej',t2[kj, kn, kf],
eris.oovv[km, kn, ke])
return Wmbej
# Indices in the following can be safely permuted.
[docs]
def Wooov(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
Wmnie = eris.ooov.copy()
for km, kn, ki in kpts_helper.loop_kkk(nkpts):
kf = ki
Wmnie[km, kn, ki] += einsum('if,mnfe->mnie',t1[ki], eris.oovv[km, kn, kf])
return Wmnie
[docs]
def Wvovv(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
Wamef = numpy.empty((nkpts, nkpts, nkpts, nvir, nocc, nvir, nvir), dtype=eris.ovvv.dtype)
for ka, km, ke in kpts_helper.loop_kkk(nkpts):
kn = ka
Wamef[ka, km, ke] = -eris.ovvv[km, ka, ke].transpose(1, 0, 2, 3)
Wamef[ka, km, ke] -= einsum('na,nmef->amef',t1[kn],eris.oovv[kn, km, ke])
return Wamef
[docs]
def Wovoo(cc,t1,t2,eris,kconserv):
nkpts, nocc, nvir = t1.shape
Wmbij = eris.ovoo.copy()
for km, kb, ki in kpts_helper.loop_kkk(nkpts):
kj = kconserv[km, ki, kb]
for kn in range(nkpts):
Wmbij[km, kb, ki] += einsum('mnie,jnbe->mbij', eris.ooov[km, kn, ki], t2[kj, kn, kb])
Wmbij[km, kb, ki] += einsum('ie,mbej->mbij', t1[ki], -eris.ovov[km, kb, kj].transpose(0, 1, 3, 2))
for kf in range(nkpts):
kn = kconserv[kb, kj, kf]
Wmbij[km, kb, ki] -= einsum('ie,njbf,mnef->mbij', t1[ki], t2[kn, kj, kb], eris.oovv[km, kn, ki])
# P(ij)
for kn in range(nkpts):
Wmbij[km, kb, ki] -= einsum('mnje,inbe->mbij', eris.ooov[km, kn, kj], t2[ki, kn, kb])
Wmbij[km, kb, ki] -= einsum('je,mbei->mbij', t1[kj], -eris.ovov[km, kb, ki].transpose(0, 1, 3, 2))
for kf in range(nkpts):
kn = kconserv[kb, ki, kf]
Wmbij[km, kb, ki] += einsum('je,nibf,mnef->mbij', t1[kj], t2[kn, ki, kb], eris.oovv[km, kn, kj])
FFov = Fov(cc,t1,t2,eris,kconserv)
WWoooo = Woooo(cc,t1,t2,eris,kconserv)
tau = make_tau(cc,t2,t1,t1,kconserv)
for km, kb, ki in kpts_helper.loop_kkk(nkpts):
kj = kconserv[km, ki, kb]
Wmbij[km, kb, ki] -= einsum('me,ijbe->mbij', FFov[km], t2[ki, kj, kb])
Wmbij[km, kb, ki] -= einsum('nb,mnij->mbij', t1[kb], WWoooo[km, kb, ki])
for km, kb, ki in kpts_helper.loop_kkk(nkpts):
kj = kconserv[km, ki, kb]
Wmbij[km, kb, ki] += 0.5 * einsum('xmbef,xijef->mbij', eris.ovvv[km, kb, :], tau[ki, kj, :])
return Wmbij
[docs]
def Wvvvo(cc,t1,t2,eris,kconserv,WWvvvv=None):
nkpts, nocc, nvir = t1.shape
FFov = Fov(cc,t1,t2,eris,kconserv)
if WWvvvv is None:
WWvvvv = Wvvvv(cc,t1,t2,eris,kconserv)
eris_ovvo = numpy.zeros(shape=(nkpts,nkpts,nkpts,nocc,nvir,nvir,nocc),dtype=t2.dtype)
for km in range(nkpts):
for kb in range(nkpts):
for ke in range(nkpts):
kj = kconserv[km,ke,kb]
eris_ovvo[km,kb,ke] = -eris.ovov[km,kb,kj].transpose(0,1,3,2)
tmp1 = numpy.zeros((nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc),dtype=t2.dtype)
tmp2 = numpy.zeros((nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc),dtype=t2.dtype)
for ka, kb, ke in kpts_helper.loop_kkk(nkpts):
ki = kconserv[ka,ke,kb]
tmp2[ka,kb,ke] += einsum('ma,mbei->abei',t1[ka],eris_ovvo[ka,kb,ke])
for kn in range(nkpts):
tmp2[ka,kb,ke] -= einsum('ma,nibf,mnef->abei',t1[ka],t2[kn,ki,kb],eris.oovv[ka,kn,ke])
for km in range(nkpts):
tmp1[ka,kb,ke] += einsum('mbef,miaf->abei',eris.ovvv[km,kb,ke],t2[km,ki,ka])
tau = make_tau(cc,t2,t1,t1,kconserv)
Wabei = -tmp1 + tmp1.transpose(1,0,2,4,3,5,6)
Wabei -= tmp2 - tmp2.transpose(1,0,2,4,3,5,6)
for ka, kb, ke in kpts_helper.loop_kkk(nkpts):
ki = kconserv[ka, ke, kb]
Wabei[ka, kb, ke] += eris.ovvv[ki, ke, kb].conj().transpose(3, 2, 1, 0)
Wabei[ka, kb, ke] += einsum('if,abef->abei',t1[ki],WWvvvv[ka, kb, ke])
Wabei[ka, kb, ke] -= einsum('me,miab->abei',FFov[ke],t2[ke, ki, ka])
for km in range(nkpts):
kn = kconserv[ka, km, kb]
Wabei[ka, kb, ke] += 0.5 * einsum('nmie,mnab->abei',
eris.ooov[kn, km, ki],
tau[km, kn, ka])
return Wabei
[docs]
def get_full_t3p2(mycc, t1, t2, eris):
'''Build the entire T3[2] array in memory.
'''
nkpts = mycc.nkpts
nocc = mycc.nocc
nmo = mycc.nmo
nvir = nmo - nocc
kconserv = mycc.khelper.kconserv
def get_wijkabc(ki, kj, kk, ka, kb, kc):
'''Build T3[2] for `ijkabc` at a given set of k-points'''
km = kconserv[kc, kk, kb]
kf = kconserv[kk, kc, kj]
ret = einsum('kjcf,ifab->ijkabc', t2[kk,kj,kc], eris.ovvv[ki,kf,ka].conj())
ret = ret - einsum('jima,mkbc->ijkabc', eris.ooov[kj,ki,km].conj(), t2[km,kk,kb])
return ret
#fock = eris.fock
#fov = fock[:, :nocc, nocc:]
#foo = numpy.array([fock[ikpt, :nocc, :nocc].diagonal() for ikpt in range(nkpts)])
#fvv = numpy.array([fock[ikpt, nocc:, nocc:].diagonal() for ikpt in range(nkpts)])
mo_energy_occ = numpy.array([eris.mo_energy[ki][:nocc] for ki in range(nkpts)])
mo_energy_vir = numpy.array([eris.mo_energy[ki][nocc:] for ki in range(nkpts)])
mo_e_o = mo_energy_occ
mo_e_v = mo_energy_vir
# Get location of padded elements in occupied and virtual space
nonzero_opadding, nonzero_vpadding = padding_k_idx(mycc, kind="split")
t3 = numpy.empty((nkpts,nkpts,nkpts,nkpts,nkpts,nocc,nocc,nocc,nvir,nvir,nvir),
dtype=t2.dtype)
for ki, kj, kk, ka, kb in product(range(nkpts), repeat=5):
kc = kpts_helper.get_kconserv3(mycc._scf.cell, mycc.kpts,
[ki, kj, kk, ka, kb])
# Perform P(abc)
t3[ki,kj,kk,ka,kb] = get_wijkabc(ki,kj,kk,ka,kb,kc)
t3[ki,kj,kk,ka,kb] += get_wijkabc(ki,kj,kk,kb,kc,ka).transpose(0,1,2,5,3,4)
t3[ki,kj,kk,ka,kb] += get_wijkabc(ki,kj,kk,kc,ka,kb).transpose(0,1,2,4,5,3)
# Perform P(ijk)
t3 = (t3.transpose(0,1,2,3,4,5,6,7,8,9,10) +
t3.transpose(1,2,0,3,4,6,7,5,8,9,10) +
t3.transpose(2,0,1,3,4,7,5,6,8,9,10))
for ki, kj, kk in product(range(nkpts), repeat=3):
eijk = _get_epqr([0,nocc,ki,mo_e_o,nonzero_opadding],
[0,nocc,kj,mo_e_o,nonzero_opadding],
[0,nocc,kk,mo_e_o,nonzero_opadding])
for ka, kb in product(range(nkpts), repeat=2):
kc = kpts_helper.get_kconserv3(mycc._scf.cell, mycc.kpts,
[ki, kj, kk, ka, kb])
eabc = _get_epqr([0,nvir,ka,mo_e_v,nonzero_vpadding],
[0,nvir,kb,mo_e_v,nonzero_vpadding],
[0,nvir,kc,mo_e_v,nonzero_vpadding],
fac=[-1.,-1.,-1.])
eijkabc = eijk[:, :, :, None, None, None] + eabc[None, None, None, :, :, :]
t3[ki,kj,kk,ka,kb] /= eijkabc
return t3
[docs]
def get_t3p2_imds_slow(cc, t1, t2, eris=None, t3p2_ip_out=None, t3p2_ea_out=None):
"""Calculates T1, T2 amplitudes corrected by second-order T3 contribution
and intermediates used in IP/EA-CCSD(T)a
Args:
cc (:obj:`KGCCSD`):
Object containing coupled-cluster results.
t1 (:obj:`ndarray`):
T1 amplitudes.
t2 (:obj:`ndarray`):
T2 amplitudes from which the T3[2] amplitudes are formed.
eris (:obj:`_PhysicistsERIs`):
Antisymmetrized electron-repulsion integrals in physicist's notation.
t3p2_ip_out (:obj:`ndarray`):
Store results of the intermediate used in IP-EOM-CCSD(T)a.
t3p2_ea_out (:obj:`ndarray`):
Store results of the intermediate used in EA-EOM-CCSD(T)a.
Returns:
delta_ccsd (float):
Difference of perturbed and unperturbed CCSD ground-state energy,
energy(T1 + T1[2], T2 + T2[2]) - energy(T1, T2)
pt1 (:obj:`ndarray`):
Perturbatively corrected T1 amplitudes.
pt2 (:obj:`ndarray`):
Perturbatively corrected T2 amplitudes.
Reference:
D. A. Matthews, J. F. Stanton "A new approach to approximate..."
JCP 145, 124102 (2016); DOI:10.1063/1.4962910, Equation 14
Shavitt and Bartlett "Many-body Methods in Physics and Chemistry"
2009, Equation 10.33
"""
if eris is None:
eris = cc.ao2mo()
fock = eris.fock
nkpts, nocc, nvir = t1.shape
kconserv = cc.khelper.kconserv
fov = [fock[ikpt, :nocc, nocc:] for ikpt in range(nkpts)]
#foo = [fock[ikpt, :nocc, :nocc].diagonal() for ikpt in range(nkpts)]
#fvv = [fock[ikpt, nocc:, nocc:].diagonal() for ikpt in range(nkpts)]
mo_energy_occ = numpy.array([eris.mo_energy[ki][:nocc] for ki in range(nkpts)])
mo_energy_vir = numpy.array([eris.mo_energy[ki][nocc:] for ki in range(nkpts)])
# Get location of padded elements in occupied and virtual space
nonzero_opadding, nonzero_vpadding = padding_k_idx(cc, kind="split")
mo_e_o = mo_energy_occ
mo_e_v = mo_energy_vir
ccsd_energy = cc.energy(t1, t2, eris)
dtype = numpy.result_type(t1, t2)
if t3p2_ip_out is None:
t3p2_ip_out = numpy.zeros((nkpts,nkpts,nkpts,nocc,nvir,nocc,nocc), dtype=dtype)
Wmcik = t3p2_ip_out
if t3p2_ea_out is None:
t3p2_ea_out = numpy.zeros((nkpts,nkpts,nkpts,nvir,nvir,nvir,nocc), dtype=dtype)
Wacek = t3p2_ea_out
t3 = get_full_t3p2(cc, t1, t2, eris)
pt1 = numpy.zeros((nkpts, nocc, nvir), dtype=dtype)
for ki in range(nkpts):
ka = ki
for km, kn, ke in product(range(nkpts), repeat=3):
pt1[ki] += 0.25 * lib.einsum('mnef,imnaef->ia', eris.oovv[km,kn,ke], t3[ki,km,kn,ka,ke])
eia = _get_epq([0,nocc,ki,mo_e_o,nonzero_opadding],
[0,nvir,ka,mo_e_v,nonzero_vpadding],
fac=[1.0,-1.0])
pt1[ki] /= eia
pt2 = numpy.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=dtype)
for ki, kj, ka in product(range(nkpts), repeat=3):
kb = kconserv[ki,ka,kj]
for km in range(nkpts):
pt2[ki,kj,ka] += lib.einsum('ijmabe,me->ijab', t3[ki,kj,km,ka,kb], fov[km])
for ke in range(nkpts):
kf = kconserv[km,ke,kb]
pt2[ki,kj,ka] += 0.5 * lib.einsum('ijmaef,mbfe->ijab', t3[ki,kj,km,ka,ke], eris.ovvv[km,kb,kf])
kf = kconserv[km,ke,ka]
pt2[ki,kj,ka] -= 0.5 * lib.einsum('ijmbef,mafe->ijab', t3[ki,kj,km,kb,ke], eris.ovvv[km,ka,kf])
for kn in range(nkpts):
pt2[ki,kj,ka] -= 0.5 * lib.einsum('inmabe,nmje->ijab', t3[ki,kn,km,ka,kb], eris.ooov[kn,km,kj])
pt2[ki,kj,ka] += 0.5 * lib.einsum('jnmabe,nmie->ijab', t3[kj,kn,km,ka,kb], eris.ooov[kn,km,ki])
eia = _get_epq([0,nocc,ki,mo_e_o,nonzero_opadding],
[0,nvir,ka,mo_e_v,nonzero_vpadding],
fac=[1.0,-1.0])
ejb = _get_epq([0,nocc,kj,mo_e_o,nonzero_opadding],
[0,nvir,kb,mo_e_v,nonzero_vpadding],
fac=[1.0,-1.0])
eijab = eia[:, None, :, None] + ejb[:, None, :]
pt2[ki,kj,ka] /= eijab
pt1 += t1
pt2 += t2
for ki, kj, kk, ka, kb in product(range(nkpts), repeat=5):
kc = kpts_helper.get_kconserv3(cc._scf.cell, cc.kpts,
[ki, kj, kk, ka, kb])
tmp = t3[ki,kj,kk,ka,kb]
km = kconserv[ki,kc,kk]
ke = kconserv[ka,kk,kc]
Wmcik[km,kc,ki] += 0.5*lib.einsum('ijkabc,mjab->mcik', tmp, eris.oovv[km,kj,ka])
Wacek[ka,kc,ke] += -0.5*lib.einsum('ijkabc,ijeb->acek', tmp, eris.oovv[ki,kj,ke])
delta_ccsd_energy = cc.energy(pt1, pt2, eris) - ccsd_energy
logger.info(cc, 'CCSD energy T3[2] correction : %14.8e', delta_ccsd_energy)
return delta_ccsd_energy, pt1, pt2, Wmcik, Wacek