#!/usr/bin/env python
# Copyright 2014-2020 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.
#
# Author: Qiming Sun <osirpt.sun@gmail.com>
#
import numpy
from pyscf import lib
from pyscf.lib import logger
from pyscf.cc import ccsd_lambda
einsum = lib.einsum
[docs]
def kernel(mycc, eris=None, t1=None, t2=None, l1=None, l2=None,
max_cycle=50, tol=1e-8, verbose=logger.INFO):
if eris is None: eris = mycc.ao2mo()
return ccsd_lambda.kernel(mycc, eris, t1, t2, l1, l2, max_cycle, tol,
verbose, make_intermediates, update_lambda)
# l2, t2 as ijab
# update L1, L2
[docs]
def update_lambda(mycc, t1, t2, l1, l2, eris, imds):
time0 = logger.process_clock(), logger.perf_counter()
log = logger.Logger(mycc.stdout, mycc.verbose)
nocc, nvir = t1.shape
fov = eris.fock[:nocc,nocc:]
mo_e_o = eris.mo_energy[:nocc]
mo_e_v = eris.mo_energy[nocc:] + mycc.level_shift
v1 = imds.v1 - numpy.diag(mo_e_v)
v2 = imds.v2 - numpy.diag(mo_e_o)
l1new = numpy.zeros_like(l1)
l2new = numpy.zeros_like(l2)
mba = einsum('klca,klcb->ba', l2, t2) * .5
mij = einsum('kicd,kjcd->ij', l2, t2) * .5
m3 = einsum('klab,ijkl->ijab', l2, numpy.asarray(imds.woooo))
tau = t2 + einsum('ia,jb->ijab', t1, t1) * 2
tmp = einsum('ijcd,klcd->ijkl', l2, tau)
oovv = numpy.asarray(eris.oovv)
m3 += einsum('klab,ijkl->ijab', oovv, tmp) * .25
tmp = einsum('ijcd,kd->ijck', l2, t1)
m3 -= einsum('kcba,ijck->ijab', eris.ovvv, tmp)
m3 += einsum('ijcd,cdab->ijab', l2, eris.vvvv) * .5
l2new += oovv
l2new += m3
fov1 = fov + einsum('kjcb,kc->jb', oovv, t1)
tmp = einsum('ia,jb->ijab', l1, fov1)
tmp+= einsum('kica,jcbk->ijab', l2, numpy.asarray(imds.wovvo))
tmp = tmp - tmp.transpose(1,0,2,3)
l2new += tmp - tmp.transpose(0,1,3,2)
tmp = einsum('ka,ijkb->ijab', l1, eris.ooov)
tmp+= einsum('ijca,cb->ijab', l2, v1)
tmp1vv = mba + einsum('ka,kb->ba', l1, t1)
tmp+= einsum('ca,ijcb->ijab', tmp1vv, oovv)
l2new -= tmp - tmp.transpose(0,1,3,2)
tmp = einsum('ic,jcba->jiba', l1, eris.ovvv)
tmp+= einsum('kiab,jk->ijab', l2, v2)
tmp1oo = mij + einsum('ic,kc->ik', l1, t1)
tmp-= einsum('ik,kjab->ijab', tmp1oo, oovv)
l2new += tmp - tmp.transpose(1,0,2,3)
l1new += fov
l1new += einsum('jb,ibaj->ia', l1, eris.ovvo)
l1new += einsum('ib,ba->ia', l1, v1)
l1new -= einsum('ja,ij->ia', l1, v2)
l1new -= einsum('kjca,icjk->ia', l2, imds.wovoo)
l1new -= einsum('ikbc,bcak->ia', l2, imds.wvvvo)
l1new += einsum('ijab,jb->ia', m3, t1)
l1new += einsum('jiba,bj->ia', l2, imds.w3)
tmp =(t1 + einsum('kc,kjcb->jb', l1, t2)
- einsum('bd,jd->jb', tmp1vv, t1)
- einsum('lj,lb->jb', mij, t1))
l1new += numpy.einsum('jiba,jb->ia', oovv, tmp)
l1new += numpy.einsum('icab,bc->ia', eris.ovvv, tmp1vv)
l1new -= numpy.einsum('jika,kj->ia', eris.ooov, tmp1oo)
tmp = fov - einsum('kjba,jb->ka', oovv, t1)
l1new -= numpy.einsum('ik,ka->ia', mij, tmp)
l1new -= numpy.einsum('ca,ic->ia', mba, tmp)
eia = lib.direct_sum('i-j->ij', mo_e_o, mo_e_v)
l1new /= eia
l2new /= lib.direct_sum('ia+jb->ijab', eia, eia)
time0 = log.timer_debug1('update l1 l2', *time0)
return l1new, l2new
if __name__ == '__main__':
from pyscf import gto
from pyscf import scf
from pyscf.cc import gccsd
mol = gto.Mole()
mol.atom = [
[8 , (0. , 0. , 0.)],
[1 , (0. , -0.757 , 0.587)],
[1 , (0. , 0.757 , 0.587)]]
mol.basis = '631g'
mol.spin = 0
mol.build()
mf = scf.RHF(mol).run()
mf0 = mf
mf = scf.addons.convert_to_ghf(mf)
mycc = gccsd.GCCSD(mf)
eris = mycc.ao2mo()
mycc.kernel(eris=eris)
l1, l2 = mycc.solve_lambda(mycc.t1, mycc.t2, eris=eris)
l1 = mycc.spin2spatial(l1, mycc.mo_coeff.orbspin)
l2 = mycc.spin2spatial(l2, mycc.mo_coeff.orbspin)
print(lib.finger(l1[0]) --0.0030030170069977758)
print(lib.finger(l1[1]) --0.0030030170069977758)
print(lib.finger(l2[0]) --0.041444910588788492 )
print(lib.finger(l2[1]) - 0.1077575086912813 )
print(lib.finger(l2[2]) --0.041444910588788492 )
print(abs(l2[1]-l2[1].transpose(1,0,2,3)-l2[0]).max())
print(abs(l2[1]-l2[1].transpose(0,1,3,2)-l2[0]).max())
from pyscf.cc import ccsd
mycc0 = ccsd.CCSD(mf0)
eris0 = mycc0.ao2mo()
mycc0.kernel(eris=eris0)
t1 = mycc0.t1
t2 = mycc0.t2
imds = ccsd_lambda.make_intermediates(mycc0, t1, t2, eris0)
l1, l2 = ccsd_lambda.update_lambda(mycc0, t1, t2, t1, t2, eris0, imds)
l1ref, l2ref = ccsd_lambda.update_lambda(mycc0, t1, t2, l1, l2, eris0, imds)
t1 = mycc.spatial2spin(t1, mycc.mo_coeff.orbspin)
t2 = mycc.spatial2spin(t2, mycc.mo_coeff.orbspin)
l1 = mycc.spatial2spin(l1, mycc.mo_coeff.orbspin)
l2 = mycc.spatial2spin(l2, mycc.mo_coeff.orbspin)
imds = make_intermediates(mycc, t1, t2, eris)
l1, l2 = update_lambda(mycc, t1, t2, l1, l2, eris, imds)
l1 = mycc.spin2spatial(l1, mycc.mo_coeff.orbspin)
l2 = mycc.spin2spatial(l2, mycc.mo_coeff.orbspin)
print(abs(l1[0]-l1ref).max())
print(abs(l2[1]-l2ref).max())