|
| 1 | +''' |
| 2 | +Restricted direct ring-CCD. |
| 3 | +
|
| 4 | +See also the relevant dicussions in https://github.com/pyscf/pyscf/issues/1149 |
| 5 | +
|
| 6 | +Ref: Scuseria et al., J. Chem. Phys. 129, 231101 (2008) |
| 7 | +Ref: Masios et al., Phys. Rev. Lett. 131, 186401 (2023) |
| 8 | +
|
| 9 | +Original Source: |
| 10 | +Modified from pyscf/cc/rccsd_slow.py |
| 11 | +
|
| 12 | +Contact: |
| 13 | + |
| 14 | +''' |
| 15 | + |
| 16 | +from functools import reduce |
| 17 | +import numpy as np |
| 18 | +from pyscf.cc import ccsd |
| 19 | +from pyscf import lib |
| 20 | +from pyscf.ao2mo import _ao2mo |
| 21 | + |
| 22 | +einsum = lib.einsum |
| 23 | + |
| 24 | +def update_amps(cc, t1, t2, eris): |
| 25 | + # Ref: Masios et al., Phys. Rev. Lett. 131, 186401 (2023) Eq.(3) |
| 26 | + nocc, nvir = t1.shape |
| 27 | + t1[:] = 0.0 |
| 28 | + |
| 29 | + eris_ovvo = np.asarray(eris.ovvo) |
| 30 | + eris_ovov = np.asarray(eris.ovov) |
| 31 | + |
| 32 | + t2new = 2*einsum('iack, kjcb->iajb', eris_ovvo, t2) |
| 33 | + t2new += 2*einsum('ikac, jbck->iajb', t2, eris_ovvo) |
| 34 | + tmp = einsum('ikac, kcld->iald', t2, eris_ovov) |
| 35 | + t2new += 4*einsum('iald, ljdb->iajb', tmp, t2) |
| 36 | + t2new = t2new.transpose(0,2,1,3) |
| 37 | + |
| 38 | + t2new += np.asarray(eris.ovov).conj().transpose(0,2,1,3).copy() |
| 39 | + |
| 40 | + mo_e = eris.fock.diagonal().real |
| 41 | + eia = mo_e[:nocc,None] - mo_e[None,nocc:] |
| 42 | + eijab = lib.direct_sum('ia,jb->ijab',eia,eia) |
| 43 | + t2new /= eijab |
| 44 | + |
| 45 | + return t1, t2new |
| 46 | + |
| 47 | +def energy(cc, t1, t2, eris): |
| 48 | + # Ref: Scuseria et al., J. Chem. Phys. 129, 231101 (2008) Eq.(11) |
| 49 | + nocc, nvir = t1.shape |
| 50 | + fock = eris.fock |
| 51 | + eris_ovov = np.asarray(eris.ovov) |
| 52 | + e = 2*einsum('ijab,iajb', t2, eris_ovov) |
| 53 | + return e.real |
| 54 | + |
| 55 | +def init_amps(cc, eris): |
| 56 | + nocc = cc.nocc |
| 57 | + mo_e = eris.fock.diagonal().real |
| 58 | + eia = mo_e[:nocc,None] - mo_e[None,nocc:] |
| 59 | + eijab = lib.direct_sum('ia,jb->ijab', eia, eia) |
| 60 | + t1 = np.zeros_like(eris.fock[:nocc,nocc:]) |
| 61 | + |
| 62 | + eris_ovov = np.asarray(eris.ovov) |
| 63 | + t2 = eris_ovov.transpose(0,2,1,3).conj() / eijab |
| 64 | + cc.emp2 = 2*einsum('ijab,iajb', t2, eris_ovov) |
| 65 | + lib.logger.info(cc, 'Init t2, dMP2 energy = %.15g', cc.emp2) |
| 66 | + return cc.emp2, t1, t2 |
| 67 | + |
| 68 | +def ao2mo(cc, mo_coeff=None): |
| 69 | + return _ChemistsERIs(cc, mo_coeff) |
| 70 | + |
| 71 | +class _ChemistsERIs: |
| 72 | + def __init__(self, cc, mo_coeff=None, method='incore'): |
| 73 | + if mo_coeff is None: |
| 74 | + self.mo_coeff = mo_coeff = ccsd._mo_without_core(cc, cc.mo_coeff) |
| 75 | + else: |
| 76 | + self.mo_coeff = mo_coeff = ccsd._mo_without_core(cc, mo_coeff) |
| 77 | + dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ) |
| 78 | + fockao = cc._scf.get_hcore() + cc._scf.get_veff(cc.mol, dm) |
| 79 | + self.fock = reduce(np.dot, (mo_coeff.T, fockao, mo_coeff)) |
| 80 | + |
| 81 | + nocc = cc.nocc |
| 82 | + nmo = cc.nmo |
| 83 | + nvir = nmo - nocc |
| 84 | + # eri1 = ao2mo.incore.full(cc._scf._eri, mo_coeff) |
| 85 | + # eri1 = ao2mo.restore(1, eri1, nmo) |
| 86 | + mo = cc._scf.mo_coeff |
| 87 | + Lpq = cc._scf._cderi |
| 88 | + ijslice = (0, nocc, nocc, nmo) |
| 89 | + Lov = _ao2mo.nr_e2(Lpq, mo, ijslice, aosym='s2', mosym='s1') |
| 90 | + eris_ovov = Lov.T @ Lov |
| 91 | + self.ovov = eris_ovov.reshape(nocc, nvir, nocc, nvir) |
| 92 | + self.ovvo = self.ovov.transpose(0,1,3,2).copy() |
| 93 | + self.Lov = Lov |
| 94 | + |
| 95 | + |
| 96 | +class drCCD(ccsd.CCSD): |
| 97 | + init_amps = init_amps |
| 98 | + update_amps = update_amps |
| 99 | + energy = energy |
| 100 | + ao2mo = ao2mo |
| 101 | + |
| 102 | + |
| 103 | +if __name__ == '__main__': |
| 104 | + from pyscf import gto, dft, scf |
| 105 | + mol = gto.Mole() |
| 106 | + mol.verbose = 4 |
| 107 | + mol.atom = 'H 0 0 0; F 0 0 1.1' |
| 108 | + mol.basis = 'ccpvdz' |
| 109 | + |
| 110 | + mol.build() |
| 111 | + mf = scf.RHF(mol).density_fit() |
| 112 | + mf.kernel() |
| 113 | + |
| 114 | + mycc = drCCD(mf) |
| 115 | + e_drccd, _, t2 = mycc.kernel() |
| 116 | + from pyscf.gw import rpa |
| 117 | + myrpa = rpa.RPA(mf) |
| 118 | + e_rpa = myrpa.kernel() |
| 119 | + print(f"Difference between drccd and drpa: {e_drccd-e_rpa} Ha." ) |
0 commit comments