#!/usr/bin/env python
# Copyright 2014-2025 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.
import numpy as np
from pyscf import lib
from pyscf.lib import logger
from pyscf import df
from pyscf.cc import uccsd
from pyscf.cc import ccsd
from pyscf.cc import dfccsd
from pyscf import __config__
MEMORYMIN = getattr(__config__, 'cc_ccsd_memorymin', 2000)
[docs]
class UCCSD(uccsd.UCCSD):
_keys = {'with_df'}
def __init__(self, mf, frozen=None, mo_coeff=None, mo_occ=None):
uccsd.UCCSD.__init__(self, mf, frozen, mo_coeff, mo_occ)
if getattr(mf, 'with_df', None):
self.with_df = mf.with_df
else:
self.with_df = df.DF(mf.mol)
self.with_df.auxbasis = df.make_auxbasis(mf.mol, mp2fit=True)
[docs]
def reset(self, mol=None):
self.with_df.reset(mol)
return uccsd.UCCSD.reset(self, mol)
[docs]
def ao2mo(self, mo_coeff=None):
return _make_df_eris(self, mo_coeff)
def _add_vvvv(self, t1, t2, eris, out=None, with_ovvv=False, t2sym=None):
assert (not self.direct)
return uccsd.UCCSD._add_vvvv(self, t1, t2, eris, out, with_ovvv, t2sym)
def _add_vvVV(self, t1, t2, eris, out=None):
assert (not self.direct)
return uccsd.UCCSD._add_vvVV(self, t1, t2, eris, out)
to_gpu = lib.to_gpu
class _ChemistsERIs(uccsd._ChemistsERIs):
def _contract_vvvv_t2(self, mycc, t2, direct=False, out=None, verbose=None):
assert (not direct)
return dfccsd._contract_vvvv_t2(mycc, self.mol, self.vvL, self.vvL, t2, out, verbose)
def _contract_VVVV_t2(self, mycc, t2, direct=False, out=None, verbose=None):
assert (not direct)
return dfccsd._contract_vvvv_t2(mycc, self.mol, self.VVL, self.VVL, t2, out, verbose)
def _contract_vvVV_t2(self, mycc, t2, direct=False, out=None, verbose=None):
assert (not direct)
return dfccsd._contract_vvvv_t2(mycc, self.mol, self.vvL, self.VVL, t2, out, verbose)
def _cp(a):
return np.asarray(a, order='C')
def _make_df_eris(mycc, mo_coeff=None):
assert mycc._scf.istype('UHF')
cput0 = (logger.process_clock(), logger.perf_counter())
log = logger.Logger(mycc.stdout, mycc.verbose)
eris = _ChemistsERIs()
eris._common_init_(mycc, mo_coeff)
moa, mob = eris.mo_coeff
nocca, noccb = eris.nocc
nao = moa.shape[0]
nmoa = moa.shape[1]
nmob = mob.shape[1]
nvira = nmoa - nocca
nvirb = nmob - noccb
nvira_pair = nvira * (nvira + 1) // 2
nvirb_pair = nvirb * (nvirb + 1) // 2
with_df = mycc.with_df
naux = eris.naux = with_df.get_naoaux()
# --- Three-center integrals
# (L|aa)
Loo = np.empty((naux, nocca, nocca))
Lov = np.empty((naux, nocca, nvira))
Lvo = np.empty((naux, nvira, nocca))
# (L|bb)
LOO = np.empty((naux, noccb, noccb))
LOV = np.empty((naux, noccb, nvirb))
LVO = np.empty((naux, nvirb, noccb))
# --- Four-center integrals
eris.feri = lib.H5TmpFile()
# (aa|aa)
eris.oooo = eris.feri.create_dataset('oooo', (nocca,nocca,nocca,nocca), 'f8')
eris.oovv = eris.feri.create_dataset('oovv', (nocca,nocca,nvira,nvira), 'f8', chunks=(nocca,nocca,1,nvira))
eris.ovoo = eris.feri.create_dataset('ovoo', (nocca,nvira,nocca,nocca), 'f8', chunks=(nocca,1,nocca,nocca))
eris.ovvo = eris.feri.create_dataset('ovvo', (nocca,nvira,nvira,nocca), 'f8', chunks=(nocca,1,nvira,nocca))
eris.ovov = eris.feri.create_dataset('ovov', (nocca,nvira,nocca,nvira), 'f8', chunks=(nocca,1,nocca,nvira))
# (bb|bb)
eris.OOOO = eris.feri.create_dataset('OOOO', (noccb,noccb,noccb,noccb), 'f8')
eris.OOVV = eris.feri.create_dataset('OOVV', (noccb,noccb,nvirb,nvirb), 'f8', chunks=(noccb,noccb,1,nvirb))
eris.OVOO = eris.feri.create_dataset('OVOO', (noccb,nvirb,noccb,noccb), 'f8', chunks=(noccb,1,noccb,noccb))
eris.OVVO = eris.feri.create_dataset('OVVO', (noccb,nvirb,nvirb,noccb), 'f8', chunks=(noccb,1,nvirb,noccb))
eris.OVOV = eris.feri.create_dataset('OVOV', (noccb,nvirb,noccb,nvirb), 'f8', chunks=(noccb,1,noccb,nvirb))
# (aa|bb)
eris.ooOO = eris.feri.create_dataset('ooOO', (nocca,nocca,noccb,noccb), 'f8')
eris.ooVV = eris.feri.create_dataset('ooVV', (nocca,nocca,nvirb,nvirb), 'f8', chunks=(nocca,nocca,1,nvirb))
eris.ovOO = eris.feri.create_dataset('ovOO', (nocca,nvira,noccb,noccb), 'f8', chunks=(nocca,1,noccb,noccb))
eris.ovVO = eris.feri.create_dataset('ovVO', (nocca,nvira,nvirb,noccb), 'f8', chunks=(nocca,1,nvirb,noccb))
eris.ovOV = eris.feri.create_dataset('ovOV', (nocca,nvira,noccb,nvirb), 'f8', chunks=(nocca,1,noccb,nvirb))
# (bb|aa)
eris.OOvv = eris.feri.create_dataset('OOvv', (noccb,noccb,nvira,nvira), 'f8', chunks=(noccb,noccb,1,nvira))
eris.OVoo = eris.feri.create_dataset('OVoo', (noccb,nvirb,nocca,nocca), 'f8', chunks=(noccb,1,nocca,nocca))
eris.OVvo = eris.feri.create_dataset('OVvo', (noccb,nvirb,nvira,nocca), 'f8', chunks=(noccb,1,nvira,nocca))
# nrow ~ 4e9/8/blockdim to ensure hdf5 chunk < 4GB
chunks = (min(nvira_pair, int(4e8 / with_df.blockdim)), min(naux, with_df.blockdim))
eris.vvL = eris.feri.create_dataset('vvL', (nvira_pair,naux), 'f8', chunks=chunks)
chunks = (min(nvirb_pair, int(4e8 / with_df.blockdim)), min(naux, with_df.blockdim))
eris.VVL = eris.feri.create_dataset('VVL', (nvirb_pair,naux), 'f8', chunks=chunks)
# Transform three-center integrals to MO basis
p1 = 0
for eri1 in with_df.loop():
eri1 = lib.unpack_tril(eri1).reshape(-1, nao, nao)
# (L|aa)
Lpq = lib.einsum('Lab,ap,bq->Lpq', eri1, moa, moa)
p0, p1 = p1, p1 + Lpq.shape[0]
blk = np.s_[p0:p1]
Loo[blk] = Lpq[:, :nocca, :nocca]
Lov[blk] = Lpq[:, :nocca, nocca:]
Lvo[blk] = Lpq[:, nocca:, :nocca]
eris.vvL[:, p0:p1] = lib.pack_tril(Lpq[:, nocca:, nocca:]).T
# (L|bb)
Lpq = None
Lpq = lib.einsum('Lab,ap,bq->Lpq', eri1, mob, mob)
LOO[blk] = Lpq[:, :noccb, :noccb]
LOV[blk] = Lpq[:, :noccb, noccb:]
LVO[blk] = Lpq[:, noccb:, :noccb]
eris.VVL[:, p0:p1] = lib.pack_tril(Lpq[:, noccb:, noccb:]).T
Lpq = None
Loo = Loo.reshape(naux, nocca * nocca)
Lov = Lov.reshape(naux, nocca * nvira)
Lvo = Lvo.reshape(naux, nocca * nvira)
LOO = LOO.reshape(naux, noccb * noccb)
LOV = LOV.reshape(naux, noccb * nvirb)
LVO = LVO.reshape(naux, noccb * nvirb)
eris.oooo[:] = lib.ddot(Loo.T, Loo).reshape(nocca,nocca,nocca,nocca)
eris.ovoo[:] = lib.ddot(Lov.T, Loo).reshape(nocca,nvira,nocca,nocca)
eris.ovvo[:] = lib.ddot(Lov.T, Lvo).reshape(nocca,nvira,nvira,nocca)
eris.ovov[:] = lib.ddot(Lov.T, Lov).reshape(nocca,nvira,nocca,nvira)
eris.OVoo[:] = lib.ddot(LOV.T, Loo).reshape(noccb,nvirb,nocca,nocca)
eris.OVvo[:] = lib.ddot(LOV.T, Lvo).reshape(noccb,nvirb,nvira,nocca)
Lvo = None
eris.OOOO[:] = lib.ddot(LOO.T, LOO).reshape(noccb,noccb,noccb,noccb)
eris.OVOO[:] = lib.ddot(LOV.T, LOO).reshape(noccb,nvirb,noccb,noccb)
eris.OVVO[:] = lib.ddot(LOV.T, LVO).reshape(noccb,nvirb,nvirb,noccb)
eris.OVOV[:] = lib.ddot(LOV.T, LOV).reshape(noccb,nvirb,noccb,nvirb)
eris.ooOO[:] = lib.ddot(Loo.T, LOO).reshape(nocca,nocca,noccb,noccb)
eris.ovOO[:] = lib.ddot(Lov.T, LOO).reshape(nocca,nvira,noccb,noccb)
eris.ovVO[:] = lib.ddot(Lov.T, LVO).reshape(nocca,nvira,nvirb,noccb)
eris.ovOV[:] = lib.ddot(Lov.T, LOV).reshape(nocca,nvira,noccb,nvirb)
LVO = None
mem_now = lib.current_memory()[0]
max_memory = max(0, mycc.max_memory - mem_now)
# eris.oovv
blksize = max(ccsd.BLKMIN, int((max_memory*.9e6/8-nocca**2*nvira_pair)/(nocca**2+naux)))
oovv_tril = np.empty((nocca * nocca, nvira_pair))
for p0, p1 in lib.prange(0, nvira_pair, blksize):
oovv_tril[:, p0:p1] = lib.ddot(Loo.T, _cp(eris.vvL[p0:p1]).T)
eris.oovv[:] = lib.unpack_tril(oovv_tril).reshape(nocca, nocca, nvira, nvira)
oovv_tril = None
# eris.ooVV
blksize = max(ccsd.BLKMIN, int((max_memory*.9e6/8-nocca**2*nvirb_pair)/(nocca**2+naux)))
oovv_tril = np.empty((nocca * nocca, nvirb_pair))
for p0, p1 in lib.prange(0, nvirb_pair, blksize):
oovv_tril[:, p0:p1] = lib.ddot(Loo.T, _cp(eris.VVL[p0:p1]).T)
eris.ooVV[:] = lib.unpack_tril(oovv_tril).reshape(nocca, nocca, nvirb, nvirb)
oovv_tril = Loo = None
mem_now = lib.current_memory()[0]
max_memory = max(0, mycc.max_memory - mem_now)
# eris.OOvv
blksize = max(ccsd.BLKMIN, int((max_memory*.9e6/8-noccb**2*nvira_pair)/(noccb**2+naux)))
oovv_tril = np.empty((noccb * noccb, nvira_pair))
for p0, p1 in lib.prange(0, nvira_pair, blksize):
oovv_tril[:, p0:p1] = lib.ddot(LOO.T, _cp(eris.vvL[p0:p1]).T)
eris.OOvv[:] = lib.unpack_tril(oovv_tril).reshape(noccb, noccb, nvira, nvira)
oovv_tril = None
# eris.OOVV
blksize = max(ccsd.BLKMIN, int((max_memory*.9e6/8-noccb**2*nvirb_pair)/(noccb**2+naux)))
oovv_tril = np.empty((noccb * noccb, nvirb_pair))
for p0, p1 in lib.prange(0, nvirb_pair, blksize):
oovv_tril[:, p0:p1] = lib.ddot(LOO.T, _cp(eris.VVL[p0:p1]).T)
eris.OOVV[:] = lib.unpack_tril(oovv_tril).reshape(noccb, noccb, nvirb, nvirb)
oovv_tril = LOO = None
mem_now = lib.current_memory()[0]
max_memory = max(0, mycc.max_memory - mem_now)
Lov = Lov.reshape(naux, nocca, nvira)
LOV = LOV.reshape(naux, noccb, nvirb)
# eris.ovvv
vblk = max(nocca, int((max_memory*.15e6/8)/(nocca*nvira_pair)))
vvblk = int(min(nvira_pair, 4e8/nocca, max(4, (max_memory*.8e6/8)/(vblk*nocca+naux))))
eris.ovvv = eris.feri.create_dataset('ovvv', (nocca, nvira, nvira_pair), 'f8', chunks=(nocca, 1, vvblk))
for q0, q1 in lib.prange(0, nvira_pair, vvblk):
vvL = _cp(eris.vvL[q0:q1])
for p0, p1 in lib.prange(0, nvira, vblk):
tmpLov = Lov[:, :, p0:p1].reshape(naux, -1)
eris.ovvv[:, p0:p1, q0:q1] = lib.ddot(tmpLov.T, vvL.T).reshape(nocca, p1 - p0, q1 - q0)
vvL = None
# eris.ovVV
vblk = max(nocca, int((max_memory*.15e6/8)/(nocca*nvirb_pair)))
vvblk = int(min(nvirb_pair, 4e8/nocca, max(4, (max_memory*.8e6/8)/(vblk*nocca+naux))))
eris.ovVV = eris.feri.create_dataset('ovVV', (nocca, nvira, nvirb_pair), 'f8', chunks=(nocca, 1, vvblk))
for q0, q1 in lib.prange(0, nvirb_pair, vvblk):
vvL = _cp(eris.VVL[q0:q1])
for p0, p1 in lib.prange(0, nvira, vblk):
tmpLov = Lov[:, :, p0:p1].reshape(naux, -1)
eris.ovVV[:, p0:p1, q0:q1] = lib.ddot(tmpLov.T, vvL.T).reshape(nocca, p1 - p0, q1 - q0)
vvL = None
Lov = None
mem_now = lib.current_memory()[0]
max_memory = max(0, mycc.max_memory - mem_now)
# eris.OVvv
vblk = max(noccb, int((max_memory*.15e6/8)/(noccb*nvira_pair)))
vvblk = int(min(nvira_pair, 4e8/noccb, max(4, (max_memory*.8e6/8)/(vblk*noccb+naux))))
eris.OVvv = eris.feri.create_dataset('OVvv', (noccb, nvirb, nvira_pair), 'f8', chunks=(noccb, 1, vvblk))
for q0, q1 in lib.prange(0, nvira_pair, vvblk):
vvL = _cp(eris.vvL[q0:q1])
for p0, p1 in lib.prange(0, nvirb, vblk):
tmpLov = LOV[:, :, p0:p1].reshape(naux, -1)
eris.OVvv[:, p0:p1, q0:q1] = lib.ddot(tmpLov.T, vvL.T).reshape(noccb, p1 - p0, q1 - q0)
vvL = None
# eris.OVVV
vblk = max(noccb, int((max_memory*.15e6/8)/(noccb*nvirb_pair)))
vvblk = int(min(nvirb_pair, 4e8/noccb, max(4, (max_memory*.8e6/8)/(vblk*noccb+naux))))
eris.OVVV = eris.feri.create_dataset('OVVV', (noccb, nvirb, nvirb_pair), 'f8', chunks=(noccb, 1, vvblk))
for q0, q1 in lib.prange(0, nvirb_pair, vvblk):
vvL = _cp(eris.VVL[q0:q1])
for p0, p1 in lib.prange(0, nvirb, vblk):
tmpLov = LOV[:, :, p0:p1].reshape(naux, -1)
eris.OVVV[:, p0:p1, q0:q1] = lib.ddot(tmpLov.T, vvL.T).reshape(noccb, p1 - p0, q1 - q0)
vvL = None
LOV = None
log.timer('DF-UCCSD integral transformation', *cput0)
return eris
if __name__ == '__main__':
from pyscf import gto
from pyscf import scf
mol = gto.Mole()
mol.atom = [
[8 , (0. , 0. , 0.)],
[1 , (0. , -0.757 , 0.587)],
[1 , (0. , 0.757 , 0.587)]]
mol.basis = 'cc-pvdz'
mol.build()
mf = scf.UHF(mol).density_fit('weigend').run()
mycc = UCCSD(mf).run()
print(mycc.e_corr - -0.2133709727796199)
print("IP energies... (right eigenvector)")
e,v = mycc.ipccsd(nroots=8)
print(e)
print(e[0] - 0.4336428577342009)
print(e[2] - 0.5188000951518845)
print(e[4] - 0.6785158684375829)
print("EA energies... (right eigenvector)")
e,v = mycc.eaccsd(nroots=8)
print(e)
print(e[0] - 0.1673013569134136)
print(e[2] - 0.2399984284491973)
print(e[4] - 0.5096018470162480)
e, v = mycc.eeccsd(nroots=4)
print(e[0] - 0.2757563806054133)
print(e[1] - 0.2757563806171079)
print(e[2] - 0.2757563806183815)
print(e[3] - 0.3006896721085447)