Source code for pyscf.mrpt.nevpt2

#!/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.
#
# Authors: Sheng Guo
#          Qiming Sun <osirpt.sun@gmail.com>
#

import ctypes

import tempfile
from functools import reduce
import numpy
import h5py
from pyscf import lib
from pyscf.lib import logger
from pyscf import fci
from pyscf.mcscf import casci, mc1step, mc_ao2mo
from pyscf import ao2mo
from pyscf.ao2mo import _ao2mo

libmc = lib.load_library('libmcscf')

NUMERICAL_ZERO = 1e-14
# Ref JCP 117, 9138 (2002); DOI:10.1063/1.1515317

# h1e is the CAS space effective 1e hamiltonian
# h2e is the CAS space 2e integrals in  notation # a' -> p # b' -> q # c' -> r
# d' -> s

[docs] def make_a16(h1e, h2e, dms, civec, norb, nelec, link_index=None): dm3 = dms['3'] #dm4 = dms['4'] if 'f3ca' in dms and 'f3ac' in dms: f3ca = dms['f3ca'] f3ac = dms['f3ac'] else: if isinstance(nelec, (int, numpy.integer)): neleca = nelecb = nelec//2 else: neleca, nelecb = nelec if link_index is None: link_indexa = fci.cistring.gen_linkstr_index(range(norb), neleca) link_indexb = fci.cistring.gen_linkstr_index(range(norb), nelecb) else: link_indexa, link_indexb = link_index eri = h2e.transpose(0,2,1,3) f3ca = _contract4pdm('NEVPTkern_cedf_aedf', eri, civec, norb, nelec, (link_indexa,link_indexb)) f3ac = _contract4pdm('NEVPTkern_aedf_ecdf', eri, civec, norb, nelec, (link_indexa,link_indexb)) a16 = -numpy.einsum('ib,rpqiac->pqrabc', h1e, dm3) a16 += numpy.einsum('ia,rpqbic->pqrabc', h1e, dm3) a16 -= numpy.einsum('ci,rpqbai->pqrabc', h1e, dm3) # qjkiac = acqjki + delta(ja)qcki + delta(ia)qjkc - delta(qc)ajki - delta(kc)qjai #:a16 -= numpy.einsum('kbij,rpqjkiac->pqrabc', h2e, dm4) a16 -= f3ca.transpose(1,4,0,2,5,3) # c'a'acb'b -> a'b'c'abc a16 -= numpy.einsum('kbia,rpqcki->pqrabc', h2e, dm3) a16 -= numpy.einsum('kbaj,rpqjkc->pqrabc', h2e, dm3) a16 += numpy.einsum('cbij,rpqjai->pqrabc', h2e, dm3) fdm2 = numpy.einsum('kbij,rpajki->prab' , h2e, dm3) for i in range(norb): a16[:,i,:,:,:,i] += fdm2 #:a16 += numpy.einsum('ijka,rpqbjcik->pqrabc', h2e, dm4) a16 += f3ac.transpose(1,2,0,4,3,5) # c'a'b'bac -> a'b'c'abc #:a16 -= numpy.einsum('kcij,rpqbajki->pqrabc', h2e, dm4) a16 -= f3ca.transpose(1,2,0,4,3,5) # c'a'b'bac -> a'b'c'abc a16 += numpy.einsum('jbij,rpqiac->pqrabc', h2e, dm3) a16 -= numpy.einsum('cjka,rpqbjk->pqrabc', h2e, dm3) a16 += numpy.einsum('jcij,rpqbai->pqrabc', h2e, dm3) return a16
[docs] def make_a22(h1e, h2e, dms, civec, norb, nelec, link_index=None): dm2 = dms['2'] dm3 = dms['3'] #dm4 = dms['4'] if 'f3ca' in dms and 'f3ac' in dms: f3ca = dms['f3ca'] f3ac = dms['f3ac'] else: if isinstance(nelec, (int, numpy.integer)): neleca = nelecb = nelec//2 else: neleca, nelecb = nelec if link_index is None: link_indexa = fci.cistring.gen_linkstr_index(range(norb), neleca) link_indexb = fci.cistring.gen_linkstr_index(range(norb), nelecb) else: link_indexa, link_indexb = link_index eri = h2e.transpose(0,2,1,3) f3ca = _contract4pdm('NEVPTkern_cedf_aedf', eri, civec, norb, nelec, (link_indexa,link_indexb)) f3ac = _contract4pdm('NEVPTkern_aedf_ecdf', eri, civec, norb, nelec, (link_indexa,link_indexb)) a22 = -numpy.einsum('pb,kipjac->ijkabc', h1e, dm3) a22 -= numpy.einsum('pa,kibjpc->ijkabc', h1e, dm3) a22 += numpy.einsum('cp,kibjap->ijkabc', h1e, dm3) a22 += numpy.einsum('cqra,kibjqr->ijkabc', h2e, dm3) a22 -= numpy.einsum('qcpq,kibjap->ijkabc', h2e, dm3) # qjprac = acqjpr + delta(ja)qcpr + delta(ra)qjpc - delta(qc)ajpr - delta(pc)qjar #a22 -= numpy.einsum('pqrb,kiqjprac->ijkabc', h2e, dm4) a22 -= f3ac.transpose(1,5,0,2,4,3) # c'a'acbb' fdm2 = numpy.einsum('pqrb,kiqcpr->ikbc', h2e, dm3) for i in range(norb): a22[:,i,:,i,:,:] -= fdm2 a22 -= numpy.einsum('pqab,kiqjpc->ijkabc', h2e, dm3) a22 += numpy.einsum('pcrb,kiajpr->ijkabc', h2e, dm3) a22 += numpy.einsum('cqrb,kiqjar->ijkabc', h2e, dm3) #a22 -= numpy.einsum('pqra,kibjqcpr->ijkabc', h2e, dm4) a22 -= f3ac.transpose(1,3,0,4,2,5) # c'a'bb'ac -> a'b'c'abc #a22 += numpy.einsum('rcpq,kibjaqrp->ijkabc', h2e, dm4) a22 += f3ca.transpose(1,3,0,4,2,5) # c'a'bb'ac -> a'b'c'abc a22 += 2.0*numpy.einsum('jb,kiac->ijkabc', h1e, dm2) a22 += 2.0*numpy.einsum('pjrb,kiprac->ijkabc', h2e, dm3) fdm2 = numpy.einsum('pa,kipc->ikac', h1e, dm2) fdm2 -= numpy.einsum('cp,kiap->ikac', h1e, dm2) fdm2 -= numpy.einsum('cqra,kiqr->ikac', h2e, dm2) fdm2 += numpy.einsum('qcpq,kiap->ikac', h2e, dm2) fdm2 += numpy.einsum('pqra,kiqcpr->ikac', h2e, dm3) fdm2 -= numpy.einsum('rcpq,kiaqrp->ikac', h2e, dm3) for i in range(norb): a22[:,i,:,:,i,:] += fdm2 * 2 return a22
[docs] def make_a17(h1e,h2e,dm2,dm3): h1e = h1e - numpy.einsum('mjjn->mn',h2e) a17 = -numpy.einsum('pi,cabi->abcp',h1e,dm2)\ -numpy.einsum('kpij,cabjki->abcp',h2e,dm3) return a17
[docs] def make_a19(h1e,h2e,dm1,dm2): h1e = h1e - numpy.einsum('mjjn->mn',h2e) a19 = -numpy.einsum('pi,ai->ap',h1e,dm1)\ -numpy.einsum('kpij,ajki->ap',h2e,dm2) return a19
[docs] def make_a23(h1e,h2e,dm1,dm2,dm3): a23 = -numpy.einsum('ip,caib->abcp',h1e,dm2)\ -numpy.einsum('pijk,cajbik->abcp',h2e,dm3)\ +2.0*numpy.einsum('bp,ca->abcp',h1e,dm1)\ +2.0*numpy.einsum('pibk,caik->abcp',h2e,dm2) return a23
[docs] def make_a25(h1e,h2e,dm1,dm2): a25 = -numpy.einsum('pi,ai->ap',h1e,dm1)\ -numpy.einsum('pijk,jaik->ap',h2e,dm2)\ +2.0*numpy.einsum('ap->pa',h1e)\ +2.0*numpy.einsum('piaj,ij->ap',h2e,dm1) return a25
[docs] def make_hdm3(dm1,dm2,dm3,hdm1,hdm2): delta = numpy.eye(dm3.shape[0]) hdm3 = - numpy.einsum('pb,qrac->pqrabc',delta,hdm2)\ - numpy.einsum('br,pqac->pqrabc',delta,hdm2)\ + numpy.einsum('bq,prac->pqrabc',delta,hdm2)*2.0\ + numpy.einsum('ap,bqcr->pqrabc',delta,dm2)*2.0\ - numpy.einsum('ap,cr,bq->pqrabc',delta,delta,dm1)*4.0\ + numpy.einsum('cr,bqap->pqrabc',delta,dm2)*2.0\ - numpy.einsum('bqapcr->pqrabc',dm3)\ + numpy.einsum('ar,pc,bq->pqrabc',delta,delta,dm1)*2.0\ - numpy.einsum('ar,bqcp->pqrabc',delta,dm2) return hdm3
[docs] def make_hdm2(dm1,dm2): delta = numpy.eye(dm2.shape[0]) dm2 = numpy.einsum('ikjl->ijkl',dm2) -numpy.einsum('jk,il->ijkl',delta,dm1) hdm2 = numpy.einsum('klij->ijkl',dm2)\ + numpy.einsum('il,kj->ijkl',delta,dm1)\ + numpy.einsum('jk,li->ijkl',delta,dm1)\ - 2.0*numpy.einsum('ik,lj->ijkl',delta,dm1)\ - 2.0*numpy.einsum('jl,ki->ijkl',delta,dm1)\ - 2.0*numpy.einsum('il,jk->ijkl',delta,delta)\ + 4.0*numpy.einsum('ik,jl->ijkl',delta,delta) return hdm2
[docs] def make_hdm1(dm1): delta = numpy.eye(dm1.shape[0]) hdm1 = 2.0*delta-dm1.transpose(1,0) return hdm1
[docs] def make_a3(h1e,h2e,dm1,dm2,hdm1): delta = numpy.eye(dm2.shape[0]) a3 = numpy.einsum('ia,ip->pa',h1e,hdm1)\ + 2.0*numpy.einsum('ijka,pj,ik->pa',h2e,delta,dm1)\ - numpy.einsum('ijka,jpik->pa',h2e,dm2) return a3
[docs] def make_k27(h1e,h2e,dm1,dm2): k27 = -numpy.einsum('ai,pi->pa',h1e,dm1)\ -numpy.einsum('iajk,pkij->pa',h2e,dm2)\ +numpy.einsum('iaji,pj->pa',h2e,dm1) return k27
[docs] def make_a7(h1e,h2e,dm1,dm2,dm3): #This dm2 and dm3 need to be in the form of norm order delta = numpy.eye(dm2.shape[0]) # a^+_ia^+_ja_ka^l = E^i_lE^j_k -\delta_{j,l} E^i_k rm2 = numpy.einsum('iljk->ijkl',dm2) - numpy.einsum('ik,jl->ijkl',dm1,delta) # E^{i,j,k}_{l,m,n} = E^{i,j}_{m,n}E^k_l -\delta_{k,m}E^{i,j}_{l,n}- \delta_{k,n}E^{i,j}_{m,l} # = E^i_nE^j_mE^k_l -\delta_{j,n}E^i_mE^k_l -\delta_{k,m}E^{i,j}_{l,n} -\delta_{k,n}E^{i,j}_{m,l} rm3 = numpy.einsum('injmkl->ijklmn',dm3)\ - numpy.einsum('jn,imkl->ijklmn',delta,dm2)\ - numpy.einsum('km,ijln->ijklmn',delta,rm2)\ - numpy.einsum('kn,ijml->ijklmn',delta,rm2) a7 = -numpy.einsum('bi,pqia->pqab',h1e,rm2)\ -numpy.einsum('ai,pqbi->pqab',h1e,rm2)\ -numpy.einsum('kbij,pqkija->pqab',h2e,rm3) \ -numpy.einsum('kaij,pqkibj->pqab',h2e,rm3) \ -numpy.einsum('baij,pqij->pqab',h2e,rm2) return rm2, a7
[docs] def make_a9(h1e,h2e,hdm1,hdm2,hdm3): a9 = numpy.einsum('ib,pqai->pqab',h1e,hdm2) a9 += numpy.einsum('ijib,pqaj->pqab',h2e,hdm2)*2.0 a9 -= numpy.einsum('ijjb,pqai->pqab',h2e,hdm2) a9 -= numpy.einsum('ijkb,pkqaij->pqab',h2e,hdm3) a9 += numpy.einsum('ia,pqib->pqab',h1e,hdm2) a9 -= numpy.einsum('ijja,pqib->pqab',h2e,hdm2) a9 -= numpy.einsum('ijba,pqji->pqab',h2e,hdm2) a9 += numpy.einsum('ijia,pqjb->pqab',h2e,hdm2)*2.0 a9 -= numpy.einsum('ijka,pqkjbi->pqab',h2e,hdm3) return a9
[docs] def make_a12(h1e,h2e,dm1,dm2,dm3): a12 = numpy.einsum('ia,qpib->pqab',h1e,dm2)\ - numpy.einsum('bi,qpai->pqab',h1e,dm2)\ + numpy.einsum('ijka,qpjbik->pqab',h2e,dm3)\ - numpy.einsum('kbij,qpajki->pqab',h2e,dm3)\ - numpy.einsum('bjka,qpjk->pqab',h2e,dm2)\ + numpy.einsum('jbij,qpai->pqab',h2e,dm2) return a12
[docs] def make_a13(h1e,h2e,dm1,dm2,dm3): delta = numpy.eye(dm3.shape[0]) a13 = -numpy.einsum('ia,qbip->pqab',h1e,dm2) a13 += numpy.einsum('pa,qb->pqab',h1e,dm1)*2.0 a13 += numpy.einsum('bi,qiap->pqab',h1e,dm2) a13 -= numpy.einsum('pa,bi,qi->pqab',delta,h1e,dm1)*2.0 a13 -= numpy.einsum('ijka,qbjpik->pqab',h2e,dm3) a13 += numpy.einsum('kbij,qjapki->pqab',h2e,dm3) a13 += numpy.einsum('blma,qmlp->pqab',h2e,dm2) a13 += numpy.einsum('kpma,qbkm->pqab',h2e,dm2)*2.0 a13 -= numpy.einsum('bpma,qm->pqab',h2e,dm1)*2.0 a13 -= numpy.einsum('lbkl,qkap->pqab',h2e,dm2) a13 -= numpy.einsum('ap,mbkl,qlmk->pqab',delta,h2e,dm2)*2.0 a13 += numpy.einsum('ap,lbkl,qk->pqab',delta,h2e,dm1)*2.0 return a13
[docs] def Sr(mc,ci,dms, eris=None, verbose=None): #The subspace S_r^{(-1)} mo_core, mo_cas, mo_virt = _extract_orbs(mc, mc.mo_coeff) dm1 = dms['1'] dm2 = dms['2'] dm3 = dms['3'] #dm4 = dms['4'] ncore = mo_core.shape[1] ncas = mo_cas.shape[1] nocc = ncore + ncas if eris is None: h1e = mc.h1e_for_cas()[0] h2e = ao2mo.restore(1, mc.ao2mo(mo_cas), ncas).transpose(0,2,1,3) h2e_v = ao2mo.incore.general(mc._scf._eri,[mo_virt,mo_cas,mo_cas,mo_cas],compact=False) h2e_v = h2e_v.reshape(mo_virt.shape[1],ncas,ncas,ncas).transpose(0,2,1,3) core_dm = numpy.dot(mo_core,mo_core.T) *2 core_vhf = mc.get_veff(mc.mol,core_dm) h1e_v = reduce(numpy.dot, (mo_virt.T, mc.get_hcore()+core_vhf , mo_cas)) h1e_v -= numpy.einsum('mbbn->mn',h2e_v) else: h1e = eris['h1eff'][ncore:nocc,ncore:nocc] h2e = eris['ppaa'][ncore:nocc,ncore:nocc].transpose(0,2,1,3) h2e_v = eris['ppaa'][nocc:,ncore:nocc].transpose(0,2,1,3) h1e_v = eris['h1eff'][nocc:,ncore:nocc] - numpy.einsum('mbbn->mn',h2e_v) if getattr(mc.fcisolver, 'nevpt_intermediate', None): a16 = mc.fcisolver.nevpt_intermediate('A16',ncas,mc.nelecas,ci) else: a16 = make_a16(h1e,h2e, dms, ci, ncas, mc.nelecas) a17 = make_a17(h1e,h2e,dm2,dm3) a19 = make_a19(h1e,h2e,dm1,dm2) ener = numpy.einsum('ipqr,pqrabc,iabc->i',h2e_v,a16,h2e_v)\ + numpy.einsum('ipqr,pqra,ia->i',h2e_v,a17,h1e_v)*2.0\ + numpy.einsum('ip,pa,ia->i',h1e_v,a19,h1e_v) norm = numpy.einsum('ipqr,rpqbac,iabc->i',h2e_v,dm3,h2e_v)\ + numpy.einsum('ipqr,rpqa,ia->i',h2e_v,dm2,h1e_v)*2.0\ + numpy.einsum('ip,pa,ia->i',h1e_v,dm1,h1e_v) return _norm_to_energy(norm, ener, mc.mo_energy[nocc:])
[docs] def Si(mc, ci, dms, eris=None, verbose=None): #Subspace S_i^{(1)} mo_core, mo_cas, mo_virt = _extract_orbs(mc, mc.mo_coeff) dm1 = dms['1'] dm2 = dms['2'] dm3 = dms['3'] #dm4 = dms['4'] ncore = mo_core.shape[1] ncas = mo_cas.shape[1] nocc = ncore + ncas if eris is None: h1e = mc.h1e_for_cas()[0] h2e = ao2mo.restore(1, mc.ao2mo(mo_cas), ncas).transpose(0,2,1,3) h2e_v = ao2mo.incore.general(mc._scf._eri,[mo_cas,mo_core,mo_cas,mo_cas],compact=False) h2e_v = h2e_v.reshape(ncas,ncore,ncas,ncas).transpose(0,2,1,3) core_dm = numpy.dot(mo_core,mo_core.T) *2 core_vhf = mc.get_veff(mc.mol,core_dm) h1e_v = reduce(numpy.dot, (mo_cas.T, mc.get_hcore()+core_vhf , mo_core)) else: h1e = eris['h1eff'][ncore:nocc,ncore:nocc] h2e = eris['ppaa'][ncore:nocc,ncore:nocc].transpose(0,2,1,3) h2e_v = eris['ppaa'][ncore:nocc,:ncore].transpose(0,2,1,3) h1e_v = eris['h1eff'][ncore:nocc,:ncore] if getattr(mc.fcisolver, 'nevpt_intermediate', None): #mc.fcisolver.make_a22(ncas, state) a22 = mc.fcisolver.nevpt_intermediate('A22',ncas,mc.nelecas,ci) else: a22 = make_a22(h1e,h2e, dms, ci, ncas, mc.nelecas) a23 = make_a23(h1e,h2e,dm1,dm2,dm3) a25 = make_a25(h1e,h2e,dm1,dm2) delta = numpy.eye(ncas) dm3_h = numpy.einsum('abef,cd->abcdef',dm2,delta)*2\ - dm3.transpose(0,1,3,2,4,5) dm2_h = numpy.einsum('ab,cd->abcd',dm1,delta)*2\ - dm2.transpose(0,1,3,2) dm1_h = 2*delta- dm1.transpose(1,0) ener = numpy.einsum('qpir,pqrabc,baic->i',h2e_v,a22,h2e_v)\ + numpy.einsum('qpir,pqra,ai->i',h2e_v,a23,h1e_v)*2.0\ + numpy.einsum('pi,pa,ai->i',h1e_v,a25,h1e_v) norm = numpy.einsum('qpir,rpqbac,baic->i',h2e_v,dm3_h,h2e_v)\ + numpy.einsum('qpir,rpqa,ai->i',h2e_v,dm2_h,h1e_v)*2.0\ + numpy.einsum('pi,pa,ai->i',h1e_v,dm1_h,h1e_v) return _norm_to_energy(norm, ener, -mc.mo_energy[:ncore])
[docs] def Sijrs(mc, eris, verbose=None): mo_core, mo_cas, mo_virt = _extract_orbs(mc, mc.mo_coeff) ncore = mo_core.shape[1] nvirt = mo_virt.shape[1] ncas = mo_cas.shape[1] nocc = ncore + ncas if eris is None: erifile = tempfile.NamedTemporaryFile(dir=lib.param.TMPDIR) feri = ao2mo.outcore.general(mc.mol, (mo_core,mo_virt,mo_core,mo_virt), erifile.name, verbose=mc.verbose) else: feri = eris['cvcv'] eia = mc.mo_energy[:ncore,None] -mc.mo_energy[None,nocc:] norm = 0 e = 0 with ao2mo.load(feri) as cvcv: for i in range(ncore): djba = (eia.reshape(-1,1) + eia[i].reshape(1,-1)).ravel() gi = numpy.asarray(cvcv[i*nvirt:(i+1)*nvirt]) gi = gi.reshape(nvirt,ncore,nvirt).transpose(1,2,0) t2i = (gi.ravel()/djba).reshape(ncore,nvirt,nvirt) # 2*ijab-ijba theta = gi*2 - gi.transpose(0,2,1) norm += numpy.einsum('jab,jab', gi, theta) e += numpy.einsum('jab,jab', t2i, theta) return norm, e
[docs] def Sijr(mc, dms, eris, verbose=None): #Subspace S_ijr^{(1)} mo_core, mo_cas, mo_virt = _extract_orbs(mc, mc.mo_coeff) dm1 = dms['1'] dm2 = dms['2'] ncore = mo_core.shape[1] ncas = mo_cas.shape[1] nocc = ncore + ncas if eris is None: h1e = mc.h1e_for_cas()[0] h2e = ao2mo.restore(1, mc.ao2mo(mo_cas), ncas).transpose(0,2,1,3) h2e_v = ao2mo.incore.general(mc._scf._eri,[mo_virt,mo_core,mo_cas,mo_core],compact=False) h2e_v = h2e_v.reshape(mo_virt.shape[1],ncore,ncas,ncore).transpose(0,2,1,3) else: h1e = eris['h1eff'][ncore:nocc,ncore:nocc] h2e = eris['ppaa'][ncore:nocc,ncore:nocc].transpose(0,2,1,3) h2e_v = eris['pacv'][:ncore].transpose(3,1,2,0) if 'h1' in dms: hdm1 = dms['h1'] else: hdm1 = make_hdm1(dm1) a3 = make_a3(h1e,h2e,dm1,dm2,hdm1) # We sum norm and h only over i <= j (or j <= i instead). # See Eq. (13) and (A2) in https://doi.org/10.1063/1.1515317 # This implementation is still somewhat wasteful in terms of memory, # as we only need about half of norm and h in the end. ci_diag = numpy.diag_indices(ncore) ci_triu = numpy.triu_indices(ncore) norm = 2.0*numpy.einsum('rpji,raji,pa->rji',h2e_v,h2e_v,hdm1)\ - 1.0*numpy.einsum('rpji,raij,pa->rji',h2e_v,h2e_v,hdm1) norm += norm.transpose(0, 2, 1) norm[:, ci_diag[0], ci_diag[1]] *= 0.5 h = 2.0*numpy.einsum('rpji,raji,pa->rji',h2e_v,h2e_v,a3)\ - 1.0*numpy.einsum('rpji,raij,pa->rji',h2e_v,h2e_v,a3) h += h.transpose(0, 2, 1) h[:, ci_diag[0], ci_diag[1]] *= 0.5 diff = mc.mo_energy[nocc:,None,None] - mc.mo_energy[None,:ncore,None] - mc.mo_energy[None,None,:ncore] norm_tri = norm[:, ci_triu[0], ci_triu[1]] h_tri = h[:, ci_triu[0], ci_triu[1]] diff_tri = diff[:, ci_triu[0], ci_triu[1]] return _norm_to_energy(norm_tri, h_tri, diff_tri)
[docs] def Srsi(mc, dms, eris, verbose=None): #Subspace S_ijr^{(1)} mo_core, mo_cas, mo_virt = _extract_orbs(mc, mc.mo_coeff) dm1 = dms['1'] dm2 = dms['2'] ncore = mo_core.shape[1] ncas = mo_cas.shape[1] nocc = ncore + ncas nvirt = mo_virt.shape[1] if eris is None: h1e = mc.h1e_for_cas()[0] h2e = ao2mo.restore(1, mc.ao2mo(mo_cas), ncas).transpose(0,2,1,3) h2e_v = ao2mo.incore.general(mc._scf._eri,[mo_virt,mo_core,mo_virt,mo_cas],compact=False) h2e_v = h2e_v.reshape(mo_virt.shape[1],ncore,mo_virt.shape[1],ncas).transpose(0,2,1,3) else: h1e = eris['h1eff'][ncore:nocc,ncore:nocc] h2e = eris['ppaa'][ncore:nocc,ncore:nocc].transpose(0,2,1,3) h2e_v = eris['pacv'][nocc:].transpose(3,0,2,1) k27 = make_k27(h1e,h2e,dm1,dm2) # We sum norm and h only over r <= s. # See Eq. (12) and (26) in https://doi.org/10.1063/1.1515317 # This implementation is still somewhat wasteful in terms of memory, # as we only need about half of norm and h in the end. vi_diag = numpy.diag_indices(nvirt) vi_triu = numpy.triu_indices(nvirt) norm = 2.0*numpy.einsum('rsip,rsia,pa->rsi',h2e_v,h2e_v,dm1)\ - 1.0*numpy.einsum('rsip,sria,pa->rsi',h2e_v,h2e_v,dm1) norm += norm.transpose(1, 0, 2) norm[vi_diag] *= 0.5 h = 2.0*numpy.einsum('rsip,rsia,pa->rsi',h2e_v,h2e_v,k27)\ - 1.0*numpy.einsum('rsip,sria,pa->rsi',h2e_v,h2e_v,k27) h += h.transpose(1, 0, 2) h[vi_diag] *= 0.5 diff = mc.mo_energy[nocc:,None,None] + mc.mo_energy[None,nocc:,None] - mc.mo_energy[None,None,:ncore] return _norm_to_energy(norm[vi_triu], h[vi_triu], diff[vi_triu])
[docs] def Srs(mc, dms, eris=None, verbose=None): #Subspace S_rs^{(-2)} mo_core, mo_cas, mo_virt = _extract_orbs(mc, mc.mo_coeff) dm1 = dms['1'] dm2 = dms['2'] dm3 = dms['3'] ncore = mo_core.shape[1] ncas = mo_cas.shape[1] nocc = ncore + ncas if mo_virt.shape[1] ==0: return 0, 0 if eris is None: h1e = mc.h1e_for_cas()[0] h2e = ao2mo.restore(1, mc.ao2mo(mo_cas), ncas).transpose(0,2,1,3) h2e_v = ao2mo.incore.general(mc._scf._eri,[mo_virt,mo_cas,mo_virt,mo_cas],compact=False) h2e_v = h2e_v.reshape(mo_virt.shape[1],ncas,mo_virt.shape[1],ncas).transpose(0,2,1,3) else: h1e = eris['h1eff'][ncore:nocc,ncore:nocc] h2e = eris['ppaa'][ncore:nocc,ncore:nocc].transpose(0,2,1,3) h2e_v = eris['papa'][nocc:,:,nocc:].transpose(0,2,1,3) # a7 is very sensitive to the accuracy of HF orbital and CI wfn rm2, a7 = make_a7(h1e,h2e,dm1,dm2,dm3) norm = 0.5*numpy.einsum('rsqp,rsba,pqba->rs',h2e_v,h2e_v,rm2) h = 0.5*numpy.einsum('rsqp,rsba,pqab->rs',h2e_v,h2e_v,a7) diff = mc.mo_energy[nocc:,None] + mc.mo_energy[None,nocc:] return _norm_to_energy(norm, h, diff)
[docs] def Sij(mc, dms, eris, verbose=None): #Subspace S_ij^{(-2)} mo_core, mo_cas, mo_virt = _extract_orbs(mc, mc.mo_coeff) dm1 = dms['1'] dm2 = dms['2'] dm3 = dms['3'] ncore = mo_core.shape[1] ncas = mo_cas.shape[1] nocc = ncore + ncas if mo_core.size ==0 : return 0.0, 0 if eris is None: h1e = mc.h1e_for_cas()[0] h2e = ao2mo.restore(1, mc.ao2mo(mo_cas), ncas).transpose(0,2,1,3) h2e_v = ao2mo.incore.general(mc._scf._eri,[mo_cas,mo_core,mo_cas,mo_core],compact=False) h2e_v = h2e_v.reshape(ncas,ncore,ncas,ncore).transpose(0,2,1,3) else: h1e = eris['h1eff'][ncore:nocc,ncore:nocc] h2e = eris['ppaa'][ncore:nocc,ncore:nocc].transpose(0,2,1,3) h2e_v = eris['papa'][:ncore,:,:ncore].transpose(1,3,0,2) if 'h1' in dms: hdm1 = dms['h1'] else: hdm1 = make_hdm1(dm1) if 'h2' in dms: hdm2 = dms['h2'] else: hdm2 = make_hdm2(dm1,dm2) if 'h3' in dms: hdm3 = dms['h3'] else: hdm3 = make_hdm3(dm1,dm2,dm3,hdm1,hdm2) # a9 is very sensitive to the accuracy of HF orbital and CI wfn a9 = make_a9(h1e,h2e,hdm1,hdm2,hdm3) norm = 0.5*numpy.einsum('qpij,baij,pqab->ij',h2e_v,h2e_v,hdm2) h = 0.5*numpy.einsum('qpij,baij,pqab->ij',h2e_v,h2e_v,a9) diff = mc.mo_energy[:ncore,None] + mc.mo_energy[None,:ncore] return _norm_to_energy(norm, h, -diff)
[docs] def Sir(mc, dms, eris, verbose=None): #Subspace S_il^{(0)} mo_core, mo_cas, mo_virt = _extract_orbs(mc, mc.mo_coeff) dm1 = dms['1'] dm2 = dms['2'] dm3 = dms['3'] ncore = mo_core.shape[1] ncas = mo_cas.shape[1] nocc = ncore + ncas if eris is None: h1e = mc.h1e_for_cas()[0] h2e = ao2mo.restore(1, mc.ao2mo(mo_cas), ncas).transpose(0,2,1,3) h2e_v1 = ao2mo.incore.general(mc._scf._eri,[mo_virt,mo_core,mo_cas,mo_cas],compact=False) h2e_v1 = h2e_v1.reshape(mo_virt.shape[1],ncore,ncas,ncas).transpose(0,2,1,3) h2e_v2 = ao2mo.incore.general(mc._scf._eri,[mo_virt,mo_cas,mo_cas,mo_core],compact=False) h2e_v2 = h2e_v2.reshape(mo_virt.shape[1],ncas,ncas,ncore).transpose(0,2,1,3) else: h1e = eris['h1eff'][ncore:nocc,ncore:nocc] h2e = eris['ppaa'][ncore:nocc,ncore:nocc].transpose(0,2,1,3) h2e_v1 = eris['ppaa'][nocc:,:ncore].transpose(0,2,1,3) h2e_v2 = eris['papa'][nocc:,:,:ncore].transpose(0,3,1,2) h1e_v = eris['h1eff'][nocc:,:ncore] norm = numpy.einsum('rpiq,raib,qpab->ir',h2e_v1,h2e_v1,dm2)*2.0\ - numpy.einsum('rpiq,rabi,qpab->ir',h2e_v1,h2e_v2,dm2)\ - numpy.einsum('rpqi,raib,qpab->ir',h2e_v2,h2e_v1,dm2)\ + numpy.einsum('raqi,rabi,qb->ir',h2e_v2,h2e_v2,dm1)*2.0\ - numpy.einsum('rpqi,rabi,qbap->ir',h2e_v2,h2e_v2,dm2)\ + numpy.einsum('rpqi,raai,qp->ir',h2e_v2,h2e_v2,dm1)\ + numpy.einsum('rpiq,ri,qp->ir',h2e_v1,h1e_v,dm1)*4.0\ - numpy.einsum('rpqi,ri,qp->ir',h2e_v2,h1e_v,dm1)*2.0\ + numpy.einsum('ri,ri->ir',h1e_v,h1e_v)*2.0 a12 = make_a12(h1e,h2e,dm1,dm2,dm3) a13 = make_a13(h1e,h2e,dm1,dm2,dm3) h = numpy.einsum('rpiq,raib,pqab->ir',h2e_v1,h2e_v1,a12)*2.0\ - numpy.einsum('rpiq,rabi,pqab->ir',h2e_v1,h2e_v2,a12)\ - numpy.einsum('rpqi,raib,pqab->ir',h2e_v2,h2e_v1,a12)\ + numpy.einsum('rpqi,rabi,pqab->ir',h2e_v2,h2e_v2,a13) diff = mc.mo_energy[:ncore,None] - mc.mo_energy[None,nocc:] return _norm_to_energy(norm, h, -diff)
[docs] class NEVPT(lib.StreamObject): '''Strongly contracted NEVPT2 Attributes: root : int To control which state to compute if multiple roots or state-average wfn were calculated in CASCI/CASSCF compressed_mps : bool compressed MPS perturber method for DMRG-SC-NEVPT2 Examples: >>> mf = gto.M('N 0 0 0; N 0 0 1.4', basis='6-31g').apply(scf.RHF).run() >>> mc = mcscf.CASSCF(mf, 4, 4).run() >>> NEVPT(mc).kernel() -0.14058324991532101 ''' _keys = { 'ncore', 'root', 'compressed_mps', 'e_corr', 'canonicalized', 'onerdm', }.union(casci.CASBase._keys, mc1step.CASSCF._keys) def __init__(self, mc, root=0): self.__dict__.update(mc.__dict__) self.ncore = mc.ncore self._mc = mc self.root = root self.compressed_mps = False ################################################## # don't modify the following attributes, they are not input options self.e_corr = None self.canonicalized = False nao, nmo = mc.mo_coeff.shape self.onerdm = numpy.zeros((nao,nao))
[docs] def reset(self, mol=None): if mol is not None: self.mol = mol self._mc.reset(mol) return self
[docs] def get_hcore(self): return self._mc.get_hcore()
[docs] def canonicalize(self, mo_coeff=None, ci=None, eris=None, sort=False, cas_natorb=False, casdm1=None, verbose=logger.NOTE): return self._mc.canonicalize(mo_coeff, ci, eris, sort, cas_natorb, casdm1, verbose)
[docs] def get_veff(self, mol=None, dm=None, hermi=1): return self._mc.get_veff(mol, dm, hermi)
[docs] def h1e_for_cas(self, mo_coeff=None, ncas=None, ncore=None): return self._mc.h1e_for_cas(mo_coeff, ncas, ncore)
[docs] def load_ci(self, root=None): '''Hack me to load CI wfn from disk''' if root is None: root = self.root if self.fcisolver.nroots == 1: return self.ci else: return self.ci[root]
[docs] def for_dmrg(self): '''Some preprocess for dmrg-nevpt''' if not self._mc.natorb: logger.warn(self, '''\ DRMG-MCSCF orbitals are not natural orbitals in active space. It's recommended to rerun DMRG-CASCI with mc.natorb before calling DMRG-NEVPT2. See discussions in github issue https://github.com/pyscf/pyscf/issues/698 and example examples/dmrg/32-dmrg_casscf_nevpt2_for_FeS.py''') return self
[docs] def compress_approx(self,maxM=500, nevptsolver=None, tol=1e-7, stored_integral =False): '''SC-NEVPT2 with compressed perturber Kwargs : maxM : int DMRG bond dimension Examples: >>> mf = gto.M('N 0 0 0; N 0 0 1.4', basis='6-31g').apply(scf.RHF).run() >>> mc = dmrgscf.DMRGSCF(mf, 4, 4).run() >>> NEVPT(mc, root=0).compress_approx(maxM=100).kernel() -0.14058324991532101 References: J. Chem. Theory Comput. 12, 1583 (2016), doi:10.1021/acs.jctc.5b01225 J. Chem. Phys. 146, 244102 (2017), doi:10.1063/1.4986975 ''' #TODO #Some preprocess for compressed perturber if getattr(self.fcisolver, 'nevpt_intermediate', None): logger.info(self, 'Use compressed mps perturber as an approximation') else: msg = 'Compressed mps perturber can be only used with DMRG wave function' logger.error(self, msg) raise RuntimeError(msg) self.nevptsolver = nevptsolver self.maxM = maxM self.tol = tol self.stored_integral = stored_integral self.canonicalized = True self.compressed_mps = True self.for_dmrg() return self
[docs] def kernel(self): from pyscf.mcscf.addons import StateAverageFCISolver if isinstance(self.fcisolver, StateAverageFCISolver): raise RuntimeError('State-average FCI solver object cannot be used ' 'in NEVPT2 calculation.\nA separated multi-root ' 'CASCI calculation is required for NEVPT2 method. ' 'See examples/mrpt/41-for_state_average.py.') if getattr(self._mc, 'frozen', None) is not None: raise NotImplementedError if isinstance(self.verbose, logger.Logger): log = self.verbose else: log = logger.Logger(self.stdout, self.verbose) time0 = (logger.process_clock(), logger.perf_counter()) ncore = self.ncore ncas = self.ncas nocc = ncore + ncas #By defaut, _mc is canonicalized for the first root. #For SC-NEVPT based on compressed MPS perturber functions, _mc was already canonicalized. if (not self.canonicalized): # Need to assign roots differently if we have more than one root # See issue #1081 (https://github.com/pyscf/pyscf/issues/1081) for more details self.mo_coeff, single_ci_vec, self.mo_energy = self.canonicalize( self.mo_coeff, ci=self.load_ci(), cas_natorb=True, verbose=self.verbose) if self.fcisolver.nroots == 1: self.ci = single_ci_vec else: self.ci[self.root] = single_ci_vec if getattr(self.fcisolver, 'nevpt_intermediate', None): logger.info(self, 'DMRG-NEVPT') dm1, dm2, dm3 = self.fcisolver._make_dm123(self.load_ci(),ncas,self.nelecas,None) else: dm1, dm2, dm3 = fci.rdm.make_dm123('FCI3pdm_kern_sf', self.load_ci(), self.load_ci(), ncas, self.nelecas) dm4 = None dms = { '1': dm1, '2': dm2, '3': dm3, '4': dm4, # 'h1': hdm1, 'h2': hdm2, 'h3': hdm3 } time1 = log.timer('3pdm, 4pdm', *time0) eris = _ERIS(self, self.mo_coeff) time1 = log.timer('integral transformation', *time1) if not getattr(self.fcisolver, 'nevpt_intermediate', None): # regular FCI solver link_indexa = fci.cistring.gen_linkstr_index(range(ncas), self.nelecas[0]) link_indexb = fci.cistring.gen_linkstr_index(range(ncas), self.nelecas[1]) aaaa = eris['ppaa'][ncore:nocc,ncore:nocc].copy() f3ca = _contract4pdm('NEVPTkern_cedf_aedf', aaaa, self.load_ci(), ncas, self.nelecas, (link_indexa,link_indexb)) f3ac = _contract4pdm('NEVPTkern_aedf_ecdf', aaaa, self.load_ci(), ncas, self.nelecas, (link_indexa,link_indexb)) dms['f3ca'] = f3ca dms['f3ac'] = f3ac time1 = log.timer('eri-4pdm contraction', *time1) if self.compressed_mps: from pyscf.dmrgscf.nevpt_mpi import DMRG_COMPRESS_NEVPT if self.stored_integral: #Stored perturbation integral and read them again. For debugging purpose. perturb_file = DMRG_COMPRESS_NEVPT(self, maxM=self.maxM, root=self.root, nevptsolver=self.nevptsolver, tol=self.tol, nevpt_integral='nevpt_perturb_integral') else: perturb_file = DMRG_COMPRESS_NEVPT(self, maxM=self.maxM, root=self.root, nevptsolver=self.nevptsolver, tol=self.tol) fh5 = h5py.File(perturb_file, 'r') e_Si = fh5['Vi/energy'][()] #The definition of norm changed. #However, there is no need to print out it. #Only perturbation energy is wanted. norm_Si = fh5['Vi/norm'][()] e_Sr = fh5['Vr/energy'][()] norm_Sr = fh5['Vr/norm'][()] fh5.close() logger.note(self, "Sr (-1)', E = %.14f", e_Sr ) logger.note(self, "Si (+1)', E = %.14f", e_Si ) else: norm_Sr , e_Sr = Sr(self, self.load_ci(), dms, eris) logger.note(self, "Sr (-1)', E = %.14f", e_Sr ) time1 = log.timer("space Sr (-1)'", *time1) norm_Si , e_Si = Si(self, self.load_ci(), dms, eris) logger.note(self, "Si (+1)', E = %.14f", e_Si ) time1 = log.timer("space Si (+1)'", *time1) norm_Sijrs, e_Sijrs = Sijrs(self, eris) logger.note(self, "Sijrs (0) , E = %.14f", e_Sijrs) time1 = log.timer('space Sijrs (0)', *time1) norm_Sijr , e_Sijr = Sijr(self, dms, eris) logger.note(self, "Sijr (+1) , E = %.14f", e_Sijr) time1 = log.timer('space Sijr (+1)', *time1) norm_Srsi , e_Srsi = Srsi(self, dms, eris) logger.note(self, "Srsi (-1) , E = %.14f", e_Srsi) time1 = log.timer('space Srsi (-1)', *time1) norm_Srs , e_Srs = Srs(self, dms, eris) logger.note(self, "Srs (-2) , E = %.14f", e_Srs ) time1 = log.timer('space Srs (-2)', *time1) norm_Sij , e_Sij = Sij(self, dms, eris) logger.note(self, "Sij (+2) , E = %.14f", e_Sij ) time1 = log.timer('space Sij (+2)', *time1) norm_Sir , e_Sir = Sir(self, dms, eris) logger.note(self, "Sir (0)' , E = %.14f", e_Sir ) time1 = log.timer("space Sir (0)'", *time1) nevpt_e = e_Sr + e_Si + e_Sijrs + e_Sijr + e_Srsi + e_Srs + e_Sij + e_Sir logger.note(self, "Nevpt2 Energy = %.15f", nevpt_e) log.timer('SC-NEVPT2', *time0) self.e_corr = nevpt_e return nevpt_e
[docs] def kernel(mc, *args, **kwargs): return sc_nevpt(mc, *args, **kwargs)
[docs] def sc_nevpt(mc, ci=None, verbose=None): import warnings with warnings.catch_warnings(): warnings.simplefilter("once") warnings.warn('API updates: function sc_nevpt is deprecated feature. ' 'It will be removed in future release.\n' 'It is recommended to run NEVPT2 with new function ' 'mrpt.NEVPT(mc).kernel()') if ci is not None: warnings.warn('API updates: The kwarg "ci" has no effects. ' 'Use mrpt.NEVPT(mc,root=?) for excited state.') return NEVPT(mc).kernel()
# register NEVPT2 in MCSCF casci.CASBase.NEVPT2 = NEVPT def _contract4pdm(kern, eri, civec, norb, nelec, link_index=None): if isinstance(nelec, (int, numpy.integer)): neleca = nelecb = nelec//2 else: neleca, nelecb = nelec if link_index is None: link_indexa = fci.cistring.gen_linkstr_index(range(norb), neleca) link_indexb = fci.cistring.gen_linkstr_index(range(norb), nelecb) else: link_indexa, link_indexb = link_index na,nlinka = link_indexa.shape[:2] nb,nlinkb = link_indexb.shape[:2] fdm2 = numpy.empty((norb,norb,norb,norb)) fdm3 = numpy.empty((norb,norb,norb,norb,norb,norb)) eri = numpy.ascontiguousarray(eri) libmc.NEVPTcontract(getattr(libmc, kern), fdm2.ctypes.data_as(ctypes.c_void_p), fdm3.ctypes.data_as(ctypes.c_void_p), eri.ctypes.data_as(ctypes.c_void_p), civec.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(norb), ctypes.c_int(na), ctypes.c_int(nb), ctypes.c_int(nlinka), ctypes.c_int(nlinkb), link_indexa.ctypes.data_as(ctypes.c_void_p), link_indexb.ctypes.data_as(ctypes.c_void_p)) for i in range(norb): for j in range(i): fdm3[j,:,i] = fdm3[i,:,j].transpose(1,0,2,3) fdm3[j,i,i,:] += fdm2[j,:] fdm3[j,:,i,j] -= fdm2[i,:] return fdm3 def _extract_orbs(mc, mo_coeff): ncore = mc.ncore ncas = mc.ncas nocc = ncore + ncas mo_core = mo_coeff[:,:ncore] mo_cas = mo_coeff[:,ncore:nocc] mo_vir = mo_coeff[:,nocc:] return mo_core, mo_cas, mo_vir def _norm_to_energy(norm, h, diff): idx = abs(norm) > NUMERICAL_ZERO ener_t = -(norm[idx] / (diff[idx] + h[idx]/norm[idx])).sum() norm_t = norm.sum() return norm_t, ener_t def _ERIS(mc, mo, method='incore'): nmo = mo.shape[1] ncore = mc.ncore ncas = mc.ncas mem_incore, mem_outcore, mem_basic = mc_ao2mo._mem_usage(ncore, ncas, nmo) mem_now = lib.current_memory()[0] if (method == 'incore' and mc._scf._eri is not None and (mem_incore+mem_now < mc.max_memory*.9) or mc.mol.incore_anyway): ppaa, papa, pacv, cvcv = trans_e1_incore(mc, mo) else: max_memory = max(2000, mc.max_memory-mem_now) ppaa, papa, pacv, cvcv = \ trans_e1_outcore(mc, mo, max_memory=max_memory, verbose=mc.verbose) dmcore = numpy.dot(mo[:,:ncore], mo[:,:ncore].T) vj, vk = mc._scf.get_jk(mc.mol, dmcore) vhfcore = reduce(numpy.dot, (mo.T, vj*2-vk, mo)) eris = {} eris['vhf_c'] = vhfcore eris['ppaa'] = ppaa eris['papa'] = papa eris['pacv'] = pacv eris['cvcv'] = cvcv eris['h1eff'] = reduce(numpy.dot, (mo.T, mc.get_hcore(), mo)) + vhfcore return eris # see mcscf.mc_ao2mo
[docs] def trans_e1_incore(mc, mo): eri_ao = mc._scf._eri ncore = mc.ncore ncas = mc.ncas nmo = mo.shape[1] nocc = ncore + ncas nav = nmo - ncore eri1 = ao2mo.incore.half_e1(eri_ao, (mo[:,:nocc],mo[:,ncore:]), compact=False) load_buf = lambda r0,r1: eri1[r0*nav:r1*nav] ppaa, papa, pacv, cvcv = _trans(mo, ncore, ncas, load_buf) return ppaa, papa, pacv, cvcv
[docs] def trans_e1_outcore(mc, mo, max_memory=None, ioblk_size=256, tmpdir=None, verbose=0): time0 = (logger.process_clock(), logger.perf_counter()) mol = mc.mol log = logger.Logger(mc.stdout, verbose) ncore = mc.ncore ncas = mc.ncas nao, nmo = mo.shape nao_pair = nao*(nao+1)//2 nocc = ncore + ncas nvir = nmo - nocc nav = nmo - ncore if tmpdir is None: tmpdir = lib.param.TMPDIR swapfile = tempfile.NamedTemporaryFile(dir=tmpdir) ao2mo.outcore.half_e1(mol, (mo[:,:nocc],mo[:,ncore:]), swapfile.name, max_memory=max_memory, ioblk_size=ioblk_size, verbose=log, compact=False) fswap = h5py.File(swapfile.name, 'r') klaoblks = len(fswap['0']) def load_buf(r0,r1): if mol.verbose >= logger.DEBUG1: time1[:] = logger.timer(mol, 'between load_buf', *tuple(time1)) buf = numpy.empty(((r1-r0)*nav,nao_pair)) col0 = 0 for ic in range(klaoblks): dat = fswap['0/%d'%ic] col1 = col0 + dat.shape[1] buf[:,col0:col1] = dat[r0*nav:r1*nav] col0 = col1 if mol.verbose >= logger.DEBUG1: time1[:] = logger.timer(mol, 'load_buf', *tuple(time1)) return buf time0 = logger.timer(mol, 'halfe1', *time0) time1 = [logger.process_clock(), logger.perf_counter()] ao_loc = numpy.array(mol.ao_loc_nr(), dtype=numpy.int32) cvcvfile = tempfile.NamedTemporaryFile(dir=tmpdir) with lib.H5TmpFile(cvcvfile.name, 'w') as f5: cvcv = f5.create_dataset('eri_mo', (ncore*nvir,ncore*nvir), 'f8') ppaa, papa, pacv = _trans(mo, ncore, ncas, load_buf, cvcv, ao_loc)[:3] time0 = logger.timer(mol, 'trans_cvcv', *time0) fswap.close() return ppaa, papa, pacv, cvcvfile
def _trans(mo, ncore, ncas, fload, cvcv=None, ao_loc=None): nao, nmo = mo.shape nocc = ncore + ncas nvir = nmo - nocc nav = nmo - ncore if cvcv is None: cvcv = numpy.zeros((ncore*nvir,ncore*nvir)) pacv = numpy.empty((nmo,ncas,ncore*nvir)) aapp = numpy.empty((ncas,ncas,nmo*nmo)) papa = numpy.empty((nmo,ncas,nmo*ncas)) vcv = numpy.empty((nav,ncore*nvir)) apa = numpy.empty((ncas,nmo*ncas)) vpa = numpy.empty((nav,nmo*ncas)) app = numpy.empty((ncas,nmo*nmo)) for i in range(ncore): buf = fload(i, i+1) klshape = (0, ncore, nocc, nmo) _ao2mo.nr_e2(buf, mo, klshape, aosym='s4', mosym='s1', out=vcv, ao_loc=ao_loc) cvcv[i*nvir:(i+1)*nvir] = vcv[ncas:] pacv[i] = vcv[:ncas] klshape = (0, nmo, ncore, nocc) _ao2mo.nr_e2(buf[:ncas], mo, klshape, aosym='s4', mosym='s1', out=apa, ao_loc=ao_loc) papa[i] = apa for i in range(ncas): buf = fload(ncore+i, ncore+i+1) klshape = (0, ncore, nocc, nmo) _ao2mo.nr_e2(buf, mo, klshape, aosym='s4', mosym='s1', out=vcv, ao_loc=ao_loc) pacv[ncore:,i] = vcv klshape = (0, nmo, ncore, nocc) _ao2mo.nr_e2(buf, mo, klshape, aosym='s4', mosym='s1', out=vpa, ao_loc=ao_loc) papa[ncore:,i] = vpa klshape = (0, nmo, 0, nmo) _ao2mo.nr_e2(buf[:ncas], mo, klshape, aosym='s4', mosym='s1', out=app, ao_loc=ao_loc) aapp[i] = app ppaa = lib.transpose(aapp.reshape(ncas**2,-1)) return (ppaa.reshape(nmo,nmo,ncas,ncas), papa.reshape(nmo,ncas,nmo,ncas), pacv.reshape(nmo,ncas,ncore,nvir), cvcv) if __name__ == '__main__': from pyscf import gto from pyscf import scf from pyscf import mcscf mol = gto.Mole() mol.verbose = 0 mol.output = None mol.atom = [ ['O', ( 0., 0. , 0. )], ['O', ( 0., 0. , 1.207 )], ] mol.basis = '6-31g' mol.spin = 2 mol.build() m = scf.RHF(mol) m.conv_tol = 1e-20 ehf = m.scf() mc = mcscf.CASCI(m, 6, 8) mc.fcisolver.conv_tol = 1e-14 ci_e = mc.kernel()[0] mc.verbose = 4 print(ci_e) #dm1, dm2, dm3, dm4 = fci.rdm.make_dm1234('FCI4pdm_kern_sf', # mc.ci, mc.ci, mc.ncas, mc.nelecas) print(sc_nevpt(mc), -0.169785157128082) mol = gto.Mole() mol.verbose = 0 mol.output = None mol.atom = [ ['H', ( 0., 0. , 0. )], ['H', ( 0., 0. , 0.8 )], ['H', ( 0., 0. , 2. )], ['H', ( 0., 0. , 2.8 )], ['H', ( 0., 0. , 4. )], ['H', ( 0., 0. , 4.8 )], ['H', ( 0., 0. , 6. )], ['H', ( 0., 0. , 6.8 )], ['H', ( 0., 0. , 8. )], ['H', ( 0., 0. , 8.8 )], ['H', ( 0., 0. , 10. )], ['H', ( 0., 0. , 10.8 )], ['H', ( 0., 0. , 12 )], ['H', ( 0., 0. , 12.8 )], ] mol.basis = {'H': 'sto-3g'} mol.build() m = scf.RHF(mol) m.conv_tol = 1e-20 ehf = m.scf() mc = mcscf.CASCI(m,8,10) mc.fcisolver.conv_tol = 1e-14 mc.kernel() mc.verbose = 4 print(sc_nevpt(mc), -0.094164359938171)