#!/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.
'''
density fitting MP2, 3-center integrals incore.
'''
import h5py
import ctypes
import numpy as np
import scipy.linalg
from functools import reduce
from pyscf import lib
from pyscf.lib import logger
from pyscf.ao2mo import _ao2mo
from pyscf import df
from pyscf.mp import dfmp2, ump2
from pyscf.mp.ump2 import make_rdm1, make_rdm2, _mo_splitter
from pyscf import __config__
WITH_T2 = getattr(__config__, 'mp_dfump2_with_t2', True)
THRESH_LINDEP = getattr(__config__, 'mp_dfump2_thresh_lindep', 1e-10)
libmp = dfmp2.libmp
[docs]
def kernel(mp, mo_energy=None, mo_coeff=None, eris=None, with_t2=WITH_T2, verbose=None):
log = logger.new_logger(mp, verbose)
if eris is None: eris = mp.ao2mo()
nocc, nvir, naux = eris.nocc, eris.nvir, eris.naux
nvirmax = max(nvir)
split_mo_energy = mp.split_mo_energy()
occ_energy = [x[1] for x in split_mo_energy]
vir_energy = [x[2] for x in split_mo_energy]
mem_avail = mp.max_memory - lib.current_memory()[0]
if with_t2:
t2 = (np.zeros((nocc[0],nocc[0],nvir[0],nvir[0]), dtype=eris.dtype),
np.zeros((nocc[0],nocc[1],nvir[0],nvir[1]), dtype=eris.dtype),
np.zeros((nocc[1],nocc[1],nvir[1],nvir[1]), dtype=eris.dtype))
t2_ptr = [x.ctypes.data_as(ctypes.c_void_p) for x in t2]
mem_avail -= sum([x.size for x in t2]) * eris.dsize / 1e6
else:
t2 = None
t2_ptr = [lib.c_null_ptr()] * 3
if mem_avail < 0:
log.error('Insufficient memory for holding t2 incore. Please rerun with `with_t2 = False`.')
raise MemoryError
emp2_ss = emp2_os = 0
drv = libmp.MP2_contract_d
# determine occ blksize
if isinstance(eris.ovL[0], np.ndarray): # incore ovL
occ_blksize = nocc
else: # outcore ovL
# 3*V^2 (for C driver) + 2*[O]XV (for iaL & jaL) = mem
occ_blksize = int(np.floor((mem_avail*0.6*1e6/eris.dsize - 3*nvirmax**2)/(2*naux*nvirmax)))
occ_blksize = [min(nocc[s], max(1, occ_blksize)) for s in [0,1]]
log.debug('occ blksize for %s loop: %d/%d %d/%d', mp.__class__.__name__,
occ_blksize[0], nocc[0], occ_blksize[1], nocc[1])
cput1 = (logger.process_clock(), logger.perf_counter())
emp2_ss = emp2_os = 0
# same spin
drv = libmp.MP2_contract_d
for s in [0,1]:
s_t2 = 0 if s == 0 else 2
moevv = lib.asarray(vir_energy[s][:,None] + vir_energy[s], order='C')
for ibatch,(i0,i1) in enumerate(lib.prange(0,nocc[s],occ_blksize[s])):
nocci = i1-i0
iaL = eris.get_occ_blk(s,i0,i1)
for jbatch,(j0,j1) in enumerate(lib.prange(0,nocc[s],occ_blksize[s])):
noccj = j1-j0
if ibatch == jbatch:
jbL = iaL
else:
jbL = eris.get_occ_blk(s,j0,j1)
ed = np.zeros(1, dtype=np.float64)
ex = np.zeros(1, dtype=np.float64)
moeoo_block = np.asarray(
occ_energy[s][i0:i1,None] + occ_energy[s][j0:j1], order='C')
s2symm = 1
t2_ex = True
drv(
ed.ctypes.data_as(ctypes.c_void_p),
ex.ctypes.data_as(ctypes.c_void_p),
ctypes.c_int(s2symm),
iaL.ctypes.data_as(ctypes.c_void_p),
jbL.ctypes.data_as(ctypes.c_void_p),
ctypes.c_int(i0), ctypes.c_int(j0),
ctypes.c_int(nocci), ctypes.c_int(noccj),
ctypes.c_int(nocc[s]), ctypes.c_int(nvir[s]), ctypes.c_int(naux),
moeoo_block.ctypes.data_as(ctypes.c_void_p),
moevv.ctypes.data_as(ctypes.c_void_p),
t2_ptr[s_t2], ctypes.c_int(t2_ex)
)
emp2_ss += (ed[0] + ex[0]) * 0.5
jbL = None
iaL = None
cput1 = log.timer_debug1('(sa,sb) = (%d,%d) i-block [%d:%d]/%d' % (s,s,i0,i1,nocc[s]),
*cput1)
# opposite spin
sa, sb = 0, 1
drv = libmp.MP2_OS_contract_d
moevv = lib.asarray(vir_energy[sa][:,None] + vir_energy[sb], order='C')
for ibatch,(i0,i1) in enumerate(lib.prange(0,nocc[sa],occ_blksize[sa])):
nocci = i1-i0
iaL = eris.get_occ_blk(sa,i0,i1)
for jbatch,(j0,j1) in enumerate(lib.prange(0,nocc[sb],occ_blksize[sb])):
noccj = j1-j0
jbL = eris.get_occ_blk(sb,j0,j1)
ed = np.zeros(1, dtype=np.float64)
moeoo_block = np.asarray(
occ_energy[sa][i0:i1,None] + occ_energy[sb][j0:j1], order='C')
drv(
ed.ctypes.data_as(ctypes.c_void_p),
iaL.ctypes.data_as(ctypes.c_void_p),
jbL.ctypes.data_as(ctypes.c_void_p),
ctypes.c_int(i0), ctypes.c_int(j0),
ctypes.c_int(nocci), ctypes.c_int(noccj),
ctypes.c_int(nocc[sa]), ctypes.c_int(nocc[sb]),
ctypes.c_int(nvir[sa]), ctypes.c_int(nvir[sb]),
ctypes.c_int(naux),
moeoo_block.ctypes.data_as(ctypes.c_void_p),
moevv.ctypes.data_as(ctypes.c_void_p),
t2_ptr[1]
)
emp2_os += ed[0]
jbL = None
iaL = None
cput1 = log.timer_debug1('(sa,sb) = (%d,%d) i-block [%d:%d]/%d' % (sa,sb,i0,i1,nocc[sa]),
*cput1)
emp2_ss = emp2_ss.real
emp2_os = emp2_os.real
emp2 = lib.tag_array(emp2_ss+emp2_os, e_corr_ss=emp2_ss, e_corr_os=emp2_os)
return emp2, t2
[docs]
class DFUMP2(dfmp2.DFMP2):
_keys = dfmp2.DFMP2._keys
get_nocc = ump2.get_nocc
get_nmo = ump2.get_nmo
get_frozen_mask = ump2.get_frozen_mask
def __init__(self, mf, frozen=None, mo_coeff=None, mo_occ=None, mo_energy=None):
dfmp2.DFMP2.__init__(self, mf, frozen, mo_coeff, mo_occ, mo_energy)
[docs]
def split_mo_coeff(self, mo_coeff=None):
if mo_coeff is None: mo_coeff = self.mo_coeff
masks = _mo_splitter(self)
return [[mo_coeff[s][:,m] for m in masks[s]] for s in [0,1]]
[docs]
def split_mo_energy(self, mo_energy=None):
if mo_energy is None: mo_energy = self.mo_energy
masks = _mo_splitter(self)
return [[mo_energy[s][m] for m in masks[s]] for s in [0,1]]
[docs]
def split_mo_occ(self, mo_occ=None):
if mo_occ is None: mo_occ = self.mo_occ
masks = _mo_splitter(self)
return [[mo_occ[s][m] for m in masks[s]] for s in [0,1]]
[docs]
def ao2mo(self, mo_coeff=None, ovL=None, ovL_to_save=None):
return _make_df_eris(self, mo_coeff, ovL, ovL_to_save)
[docs]
def make_rdm1(self, t2=None, ao_repr=False, with_frozen=True):
if t2 is None:
t2 = self.t2
assert t2 is not None
return make_rdm1(self, t2, ao_repr=ao_repr, with_frozen=with_frozen)
[docs]
def make_rdm2(self, t2=None, ao_repr=False):
if t2 is None:
t2 = self.t2
assert t2 is not None
return make_rdm2(self, t2, ao_repr=ao_repr)
[docs]
def nuc_grad_method(self):
raise NotImplementedError
# For non-canonical MP2
[docs]
def update_amps(self, t2, eris):
raise NotImplementedError
[docs]
def init_amps(self, mo_energy=None, mo_coeff=None, eris=None, with_t2=WITH_T2):
return kernel(self, mo_energy, mo_coeff, eris, with_t2)
UMP2 = DFUMP2
from pyscf import scf
scf.uhf.UHF.DFMP2 = DFUMP2
del (WITH_T2)
def _make_df_eris(mp, mo_coeff=None, ovL=None, ovL_to_save=None, verbose=None):
log = logger.new_logger(mp, verbose)
with_df = getattr(mp, 'with_df', None)
assert( with_df is not None )
if with_df._cderi is None:
log.debug('Caching ovL-type integrals directly')
if with_df.auxmol is None:
with_df.auxmol = df.addons.make_auxmol(with_df.mol, with_df.auxbasis)
else:
log.debug('Caching ovL-type integrals by transforming saved AO 3c integrals.')
if mo_coeff is None: mo_coeff = mp.mo_coeff
split_mo_coeff = mp.split_mo_coeff()
occ_coeff = [x[1] for x in split_mo_coeff]
vir_coeff = [x[2] for x in split_mo_coeff]
# determine incore or outcore
nocc = np.asarray([x.shape[1] for x in occ_coeff])
nvir = np.asarray([x.shape[1] for x in vir_coeff])
naux = with_df.auxmol.nao_nr()
if ovL is not None:
if isinstance(ovL, (np.ndarray,list,tuple)):
outcore = False
elif isinstance(ovL, str):
outcore = True
else:
log.error('Unknown data type %s for input `ovL` (should be np.ndarray or str).',
type(ovL))
raise TypeError
else:
mem_now = mp.max_memory - lib.current_memory()[0]
mem_df = sum(nocc*nvir)*naux*8/1024**2.
log.debug('ao2mo est mem= %.2f MB avail mem= %.2f MB', mem_df, mem_now)
# DEBUG:
if mp.force_outcore:
outcore = True
else:
outcore = (ovL_to_save is not None) or (mem_now*0.8 < mem_df)
log.debug('ovL-type integrals are cached %s', 'outcore' if outcore else 'incore')
if outcore:
eris = _DFOUTCOREERIS(with_df, occ_coeff, vir_coeff, mp.max_memory,
ovL=ovL, ovL_to_save=ovL_to_save,
verbose=log.verbose, stdout=log.stdout)
else:
eris = _DFINCOREERIS(with_df, occ_coeff, vir_coeff, mp.max_memory,
ovL=ovL,
verbose=log.verbose, stdout=log.stdout)
eris.build()
return eris
class _DFINCOREERIS:
def __init__(self, with_df, occ_coeff, vir_coeff, max_memory, ovL=None,
verbose=None, stdout=None):
self.with_df = with_df
self.occ_coeff = occ_coeff
self.vir_coeff = vir_coeff
self.max_memory = max_memory
self.verbose = verbose
self.stdout = stdout
self.dtype = np.result_type(*self.occ_coeff)
assert( self.dtype == np.float64 ) # FIXME: support complex
self.dsize = 8
self.ovL = ovL
@property
def nocc(self):
return [x.shape[1] for x in self.occ_coeff]
@property
def nvir(self):
return [x.shape[1] for x in self.vir_coeff]
@property
def naux(self):
return self.ovL[0].shape[-1]
def build(self):
log = logger.new_logger(self)
if self.ovL is None:
if self.with_df._cderi is None:
self.ovL = _init_mp_df_eris_direct(self.with_df, self.occ_coeff, self.vir_coeff,
self.max_memory, log=log)
else:
self.ovL = _init_mp_df_eris(self.with_df, self.occ_coeff, self.vir_coeff,
self.max_memory, log=log)
def get_occ_blk(self, s,i0,i1):
nvir, naux = self.nvir[s], self.naux
return np.asarray(self.ovL[s][i0*nvir:i1*nvir], order='C').reshape(i1-i0,nvir,naux)
def get_ov_blk(self, s,ia0,ia1):
return np.asarray(self.ovL[s][ia0:ia1], order='C')
class _DFOUTCOREERIS(_DFINCOREERIS):
def __init__(self, with_df, occ_coeff, vir_coeff, max_memory, ovL=None, ovL_to_save=None,
verbose=None, stdout=None):
_DFINCOREERIS.__init__(self, with_df, occ_coeff, vir_coeff, max_memory, None,
verbose, stdout)
self._ovL = ovL
self._ovL_to_save = ovL_to_save
def build(self):
log = logger.new_logger(self)
with_df = self.with_df
if self._ovL is None:
if isinstance(self._ovL_to_save, str):
self.feri = lib.H5FileWrap(self._ovL_to_save, 'w')
else:
self.feri = lib.H5TmpFile()
log.debug('ovL is saved to %s', self.feri.filename)
if with_df._cderi is None:
_init_mp_df_eris_direct(with_df, self.occ_coeff, self.vir_coeff, self.max_memory,
h5obj=self.feri, log=log)
else:
_init_mp_df_eris(with_df, self.occ_coeff, self.vir_coeff, self.max_memory,
h5obj=self.feri, log=log)
self.ovL = [self.feri[f'ovL{s}'] for s in [0,1]]
elif isinstance(self._ovL, str):
self.feri = h5py.File(self._ovL, 'r')
log.debug('ovL is read from %s', self.feri.filename)
assert( 'ovL0' in self.feri and 'ovL1' in self.feri )
self.ovL = [self.feri[f'ovL{s}'] for s in [0,1]]
else:
raise RuntimeError
def _init_mp_df_eris(with_df, occ_coeff, vir_coeff, max_memory, h5obj=None, log=None):
if log is None: log = logger.new_logger(with_df)
nao = occ_coeff[0].shape[0]
nocc = np.asarray([x.shape[1] for x in occ_coeff])
nvir = np.asarray([x.shape[1] for x in vir_coeff])
noccmax = max(nocc)
nvirmax = max(nvir)
nmo = [nocc[s] + nvir[s] for s in [0,1]]
nao_pair = nao**2
naux = with_df.get_naoaux()
dtype = np.result_type(*occ_coeff)
assert( dtype == np.float64 )
dsize = 8
mo = [np.asarray(np.hstack((occ_coeff[s],vir_coeff[s])), order='F') for s in [0,1]]
mem_avail = max_memory - lib.current_memory()[0]
if h5obj is None: # incore
ovL = [np.empty((nocc[s]*nvir[s],naux), dtype=dtype) for s in [0,1]]
mem_avail -= sum(nocc*nvir)*naux * dsize/1e6
else:
ovL = []
for s in [0,1]:
ovL_shape = (nocc[s]*nvir[s],naux)
ovL.append(h5obj.create_dataset(f'ovL{s}', ovL_shape, dtype=dtype,
chunks=(1,*ovL_shape[1:])))
if isinstance(ovL, np.ndarray):
# incore: batching aux (OV + Nao_pair) * [X] = M
mem_auxblk = (nao_pair+noccmax*nvirmax) * dsize/1e6
aux_blksize = min(naux, max(1, int(np.floor(mem_avail*0.5 / mem_auxblk))))
log.debug('aux blksize for incore ao2mo: %d/%d', aux_blksize, naux)
buf = np.empty(aux_blksize*noccmax*nvirmax, dtype=dtype)
ijslice = [(0, nocc[s], nocc[s], nmo[s]) for s in [0,1]]
p1 = 0
for Lpq in with_df.loop(blksize=aux_blksize):
p0, p1 = p1, p1+Lpq.shape[0]
for s in [0,1]:
out = _ao2mo.nr_e2(Lpq, mo[s], ijslice[s], aosym='s2', out=buf)
ovL[s][:,p0:p1] = out.T
out = None
Lpq = None
buf = None
else:
# outcore: batching occ [O]XV and aux ([O]V + Nao_pair)*[X]
mem_occblk = naux*nvirmax * dsize/1e6
occ_blksize = min(noccmax, max(1, int(np.floor(mem_avail*0.6 / mem_occblk))))
mem_auxblk = (occ_blksize*nvirmax+nao_pair) * dsize/1e6
aux_blksize = min(naux, max(1, int(np.floor(mem_avail*0.3 / mem_auxblk))))
log.debug('occ blksize for outcore ao2mo: %d/%d', occ_blksize, noccmax)
log.debug('aux blksize for outcore ao2mo: %d/%d', aux_blksize, naux)
buf = np.empty(naux*occ_blksize*nvirmax, dtype=dtype)
buf2 = np.empty(aux_blksize*occ_blksize*nvirmax, dtype=dtype)
for s in [0,1]:
for i0,i1 in lib.prange(0,nocc[s],occ_blksize):
nocci = i1-i0
ijslice = (i0,i1,nocc[s],nmo[s])
p1 = 0
OvL = np.ndarray((nocci*nvir[s],naux), dtype=dtype, buffer=buf)
for Lpq in with_df.loop(blksize=aux_blksize):
p0, p1 = p1, p1+Lpq.shape[0]
out = _ao2mo.nr_e2(Lpq, mo[s], ijslice, aosym='s2', out=buf2)
OvL[:,p0:p1] = out.T
Lpq = out = None
# this avoids slow operations like ovL[i0:i1,:,p0:p1] = ...
ovL[s][i0*nvir[s]:i1*nvir[s]] = OvL
OvL = None
buf = buf2 = None
return ovL
def _init_mp_df_eris_direct(with_df, occ_coeff, vir_coeff, max_memory, h5obj=None, log=None):
from pyscf import gto
from pyscf.df.incore import fill_2c2e
from pyscf.ao2mo.outcore import balance_partition
if log is None: log = logger.new_logger(with_df)
mol = with_df.mol
auxmol = with_df.auxmol
nbas = mol.nbas
nao = occ_coeff[0].shape[0]
nocc = np.asarray([x.shape[1] for x in occ_coeff])
nvir = np.asarray([x.shape[1] for x in vir_coeff])
noccmax = max(nocc)
nvirmax = max(nvir)
nmo = [nocc[s] + nvir[s] for s in [0,1]]
nao_pair = nao*(nao+1)//2
naoaux = auxmol.nao_nr()
dtype = np.result_type(*occ_coeff)
assert( dtype == np.float64 )
dsize = 8
mo = [np.asarray(np.hstack((occ_coeff[s],vir_coeff[s])), order='F') for s in [0,1]]
ijslice = [(0, nocc[s], nocc[s], nmo[s]) for s in [0,1]]
tspans = np.zeros((5,2))
tnames = ['j2c', 'j3c', 'xform', 'save', 'fit']
tick = (logger.process_clock(), logger.perf_counter())
# precompute for fitting
j2c = fill_2c2e(mol, auxmol)
try:
m2c = scipy.linalg.cholesky(j2c, lower=True)
tag = 'cd'
except scipy.linalg.LinAlgError:
e, u = np.linalg.eigh(j2c)
cond = abs(e).max() / abs(e).min()
keep = abs(e) > THRESH_LINDEP
log.debug('cond(j2c) = %g', cond)
log.debug('keep %d/%d cderi vectors', np.count_nonzero(keep), keep.size)
e = e[keep]
u = u[:,keep]
m2c = lib.dot(u*e**-0.5, u.T.conj())
tag = 'eig'
j2c = None
naux = m2c.shape[1]
tock = (logger.process_clock(), logger.perf_counter())
tspans[0] += np.asarray(tock) - np.asarray(tick)
mem_avail = max_memory - lib.current_memory()[0]
incore = h5obj is None
if incore:
ovL = [np.empty((nocc[s]*nvir[s],naux), dtype=dtype) for s in [0,1]]
mem_avail -= sum([x.size for x in ovL]) * dsize / 1e6
else:
ovL = []
for s in [0,1]:
ovL_shape = (nocc[s]*nvir[s],naux)
ovL.append( h5obj.create_dataset(f'ovL{s}', ovL_shape, dtype=dtype,
chunks=(1,*ovL_shape[1:])) )
h5tmp = lib.H5TmpFile()
Lov0 = []
for s in [0,1]:
Lov0_shape = (naoaux,nocc[s]*nvir[s])
Lov0.append( h5tmp.create_dataset(f'Lov0{s}', Lov0_shape, dtype=dtype,
chunks=(1,*Lov0_shape[1:])) )
# buffer
mem_blk = nao_pair*2 * dsize / 1e6
aux_blksize = max(1, min(naoaux, int(np.floor(mem_avail*0.7 / mem_blk))))
auxshl_range = balance_partition(auxmol.ao_loc, aux_blksize)
auxlen = max([x[2] for x in auxshl_range])
log.info('mem_avail = %.2f mem_blk = %.2f auxlen = %d', mem_avail, mem_blk, auxlen)
buf0 = np.empty(auxlen*nao_pair, dtype=dtype)
buf0T = np.empty(auxlen*nao_pair, dtype=dtype)
# precompute for j3c
comp = 1
aosym = 's2ij'
int3c = gto.moleintor.ascint3(mol._add_suffix('int3c2e'))
atm_f, bas_f, env_f = gto.mole.conc_env(mol._atm, mol._bas, mol._env,
auxmol._atm, auxmol._bas, auxmol._env)
ao_loc_f = gto.moleintor.make_loc(bas_f, int3c)
cintopt = gto.moleintor.make_cintopt(atm_f, bas_f, env_f, int3c)
def calc_j3c_ao(kshl0, kshl1):
shls_slice = (0, nbas, 0, nbas, nbas+kshl0, nbas+kshl1)
pqL = gto.moleintor.getints3c(int3c, atm_f, bas_f, env_f, shls_slice, comp,
aosym, ao_loc_f, cintopt, out=buf0)
Lpq = lib.transpose(pqL, out=buf0T)
pqL = None
return Lpq
# transform
k1 = 0
for auxshl_rg in auxshl_range:
kshl0, kshl1, dk = auxshl_rg
k0, k1 = k1, k1+dk
log.debug('kshl = [%d:%d/%d] [%d:%d/%d]', kshl0, kshl1, auxmol.nbas, k0, k1, naoaux)
tick = (logger.process_clock(), logger.perf_counter())
lpq = calc_j3c_ao(kshl0, kshl1)
tock = (logger.process_clock(), logger.perf_counter())
tspans[1] += np.asarray(tock) - np.asarray(tick)
for s in [0,1]:
lov = _ao2mo.nr_e2(lpq, mo[s], ijslice[s], aosym='s2', out=buf0)
tick = (logger.process_clock(), logger.perf_counter())
tspans[2] += np.asarray(tick) - np.asarray(tock)
if incore:
ovl = lib.transpose(lov, out=buf0T)
ovL[s][:,k0:k1] = ovl
ovl = None
else:
Lov0[s][k0:k1] = lov
lov = None
tock = (logger.process_clock(), logger.perf_counter())
tspans[3] += np.asarray(tock) - np.asarray(tick)
lpq = None
buf0 = buf0T = None
tick = (logger.process_clock(), logger.perf_counter())
# fit
if tag == 'cd': drv = getattr(libmp, 'trisolve_parallel_grp', None)
if incore:
if tag == 'cd':
if drv is None:
for s in [0,1]:
scipy.linalg.solve_triangular(m2c, ovL[s].T, lower=True,
overwrite_b=True, check_finite=False).T
else:
assert m2c.flags.f_contiguous
grpfac = 10
for s in [0,1]:
drv(
m2c.ctypes.data_as(ctypes.c_void_p),
ovL[s].ctypes.data_as(ctypes.c_void_p),
ctypes.c_int(naux),
ctypes.c_int(nocc[s]*nvir[s]),
ctypes.c_int(grpfac)
)
else:
mem_blk = nvirmax*naux * dsize/1e6
occ_blksize0 = max(1, min(noccmax, int(np.floor(mem_avail*0.5/mem_blk))))
buf = np.empty(occ_blksize0*nvirmax*naux, dtype=dtype)
for s in [0,1]:
occ_blksize = min(nocc[s], occ_blksize0)
ovL[s] = ovL[s].reshape(-1)
nvxao = nvir[s]*naoaux
nvx = nvir[s]*naux
for i0,i1 in lib.prange(0,nocc[s],occ_blksize):
nocci = i1-i0
out = np.ndarray((nocci*nvir[s],naux), dtype=dtype, buffer=buf)
lib.dot(ovL[s][i0*nvxao:i1*nvxao].reshape(nocci*nvir[s],naoaux), m2c, c=out)
ovL[s][i0*nvx:i1*nvx] = out.reshape(-1)
ovL[s] = ovL[s][:nocc[s]*nvx].reshape(nocc[s]*nvir[s],naux)
buf = None
else:
mem_blk = nvirmax*naoaux * dsize / 1e6
occ_blksize0 = max(1, min(noccmax, int(np.floor(mem_avail*0.4/mem_blk))))
for s in [0,1]:
occ_blksize = min(nocc[s], occ_blksize0)
nvxao = nvir[s]*naoaux
nvx = nvir[s]*naux
for i0,i1 in lib.prange(0, nocc[s], occ_blksize):
nocci = i1-i0
ivL = np.asarray(Lov0[s][:,i0*nvir[s]:i1*nvir[s]].T, order='C')
if tag == 'cd':
if drv is None:
ivL = scipy.linalg.solve_triangular(m2c, ivL.T, lower=True,
overwrite_b=True, check_finite=False).T
else:
assert m2c.flags.f_contiguous
grpfac = 10
drv(
m2c.ctypes.data_as(ctypes.c_void_p),
ivL.ctypes.data_as(ctypes.c_void_p),
ctypes.c_int(naux),
ctypes.c_int(nocci*nvir[s]),
ctypes.c_int(grpfac)
)
else:
ivL = lib.dot(ivL.reshape(nocci*nvir[s],naoaux), m2c)
ovL[s][i0*nvir[s]:i1*nvir[s]] = ivL
for s in [0,1]:
del h5tmp[f'Lov0{s}']
h5tmp.close()
Lov0 = None
tock = (logger.process_clock(), logger.perf_counter())
tspans[4] += np.asarray(tock) - np.asarray(tick)
for tspan,tname in zip(tspans,tnames):
log.debug('ao2mo CPU time for %-10s %9.2f sec wall time %9.2f sec', tname, *tspan)
log.info('')
return ovL
if __name__ == '__main__':
from pyscf import scf
from pyscf import gto
mol = gto.Mole()
mol.verbose = 0
mol.atom = [
[8 , (0. , 0. , 0.)],
[1 , (0. , -0.757 , 0.587)],
[1 , (0. , 0.757 , 0.587)]]
mol.basis = 'cc-pvdz'
mol.charge = 1
mol.spin = 1
mol.build()
mf = scf.UHF(mol).run()
pt = DFUMP2(mf)
emp2, t2 = pt.kernel()
print(emp2 - -0.15321910988237386)
pt.with_df = df.DF(mol)
pt.with_df.auxbasis = 'weigend'
emp2, t2 = pt.kernel()
print(emp2 - -0.15345631939967935)
mf = scf.density_fit(scf.UHF(mol), 'weigend')
mf.kernel()
pt = DFUMP2(mf)
emp2, t2 = pt.kernel()
print(emp2 - -0.15325911974166384)
pt.with_df = df.DF(mol)
pt.with_df.auxbasis = df.make_auxbasis(mol, mp2fit=True)
emp2, t2 = pt.kernel()
print(emp2 - -0.15302393704336487)
pt.frozen = 2
emp2, t2 = pt.kernel()
print(emp2 - -0.09563606544882836)