Source code for pyscf.pbc.gto.pseudo.pp_int

#!/usr/bin/env python
# Copyright 2014-2018,2021 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>
#

'''Analytic PP integrals.  See also pyscf/pbc/gto/pesudo/pp.py

For GTH/HGH PPs, see:
    Goedecker, Teter, Hutter, PRB 54, 1703 (1996)
    Hartwigsen, Goedecker, and Hutter, PRB 58, 3641 (1998)
'''

import ctypes
import numpy
import scipy.special
from pyscf import lib
from pyscf import gto
from pyscf import __config__
from pyscf.pbc.lib.kpts_helper import gamma_point

EPS_PPL = getattr(__config__, "pbc_gto_pseudo_eps_ppl", 1e-2)
HL_TABLE_SLOTS = 7
ATOM_OF        = 0
ANG_OF         = 1
HL_DIM_OF      = 2
HL_DATA_OF     = 3
HL_OFFSET0     = 4
HF_OFFSET1     = 5
HF_OFFSET2     = 6

libpbc = lib.load_library('libpbc')

[docs] def get_pp_loc_part1(cell, kpts=None): '''PRB, 58, 3641 Eq (1), integrals associated to erf ''' raise NotImplementedError
[docs] def get_gth_vlocG_part1(cell, Gv): '''PRB, 58, 3641 Eq (5) first term ''' from pyscf.pbc import tools coulG = tools.get_coulG(cell, Gv=Gv) G2 = numpy.einsum('ix,ix->i', Gv, Gv) G0idx = numpy.where(G2==0)[0] if cell.dimension != 2 or cell.low_dim_ft_type == 'inf_vacuum': vlocG = numpy.zeros((cell.natm, len(G2))) for ia in range(cell.natm): Zia = cell.atom_charge(ia) symb = cell.atom_symbol(ia) # Note the signs -- potential here is positive vlocG[ia] = Zia * coulG if symb in cell._pseudo: pp = cell._pseudo[symb] rloc, nexp, cexp = pp[1:3+1] vlocG[ia] *= numpy.exp(-0.5*rloc**2 * G2) # alpha parameters from the non-divergent Hartree+Vloc G=0 term. vlocG[ia,G0idx] = -2*numpy.pi*Zia*rloc**2 elif cell.dimension == 2: # The following 2D ewald summation is taken from: # Minary, Tuckerman, Pihakari, Martyna J. Chem. Phys. 116, 5351 (2002) vlocG = numpy.zeros((cell.natm,len(G2))) b = cell.reciprocal_vectors() inv_area = numpy.linalg.norm(numpy.cross(b[0], b[1]))/(2*numpy.pi)**2 lzd2 = cell.vol * inv_area / 2 lz = lzd2*2. G2[G0idx] = 1e200 Gxy = numpy.linalg.norm(Gv[:,:2],axis=1) Gz = abs(Gv[:,2]) for ia in range(cell.natm): Zia = cell.atom_charge(ia) symb = cell.atom_symbol(ia) if symb not in cell._pseudo: vlocG[ia] = Zia * coulG continue pp = cell._pseudo[symb] rloc, nexp, cexp = pp[1:3+1] ew_eta = 1./numpy.sqrt(2)/rloc JexpG2 = 4*numpy.pi / G2 * numpy.exp(-G2/(4*ew_eta**2)) fac = 4*numpy.pi / G2 * numpy.cos(Gz*lzd2) JexpG2 -= fac * numpy.exp(-Gxy*lzd2) eta_z1 = (ew_eta**2 * lz + Gxy) / (2.*ew_eta) eta_z2 = (ew_eta**2 * lz - Gxy) / (2.*ew_eta) JexpG2 += fac * 0.5*(numpy.exp(-eta_z1**2)*scipy.special.erfcx(eta_z2) + numpy.exp(-eta_z2**2)*scipy.special.erfcx(eta_z1)) vlocG[ia,:] = Zia * JexpG2 JexpG0 = ( - numpy.pi * lz**2 / 2. * scipy.special.erf( ew_eta * lzd2 ) + numpy.pi/ew_eta**2 * scipy.special.erfc(ew_eta*lzd2) - numpy.sqrt(numpy.pi)*lz/ew_eta * numpy.exp( - (ew_eta*lzd2)**2 ) ) vlocG[ia,G0idx] = -2*numpy.pi*Zia*rloc**2 + Zia*JexpG0 else: raise NotImplementedError('Low dimension ft_type %s' ' not implemented for dimension %d' % (cell.low_dim_ft_type, cell.dimension)) return vlocG
# part2 Vnuc - Vloc
[docs] def get_pp_loc_part2(cell, kpts=None): '''PRB, 58, 3641 Eq (1), integrals associated to C1, C2, C3, C4 ''' if kpts is None or gamma_point(kpts): vpploc = [get_pp_loc_part2_gamma(cell)] else: from pyscf.pbc.df.aft import _IntPPBuilder vpploc = _IntPPBuilder(cell, kpts).get_pp_loc_part2() if kpts is None or numpy.shape(kpts) == (3,): vpploc = vpploc[0] return vpploc
[docs] def get_pp_loc_part2_gamma(cell): from pyscf.pbc.df import incore from pyscf.pbc.gto import build_neighbor_list_for_shlpairs, free_neighbor_list fake_cells = {} for cn in range(1, 5): fake_cell = fake_cell_vloc(cell, cn) fake_cell.precision = EPS_PPL if fake_cell.nbas > 0: fake_cells[cn] = fake_cell if not fake_cells: if any(cell.atom_symbol(ia) in cell._pseudo for ia in range(cell.natm)): pass else: lib.logger.warn(cell, 'cell.pseudo was specified but its elements %s ' 'were not found in the system.', cell._pseudo.keys()) return 0 intors = ('int3c2e', 'int3c1e', 'int3c1e_r2_origk', 'int3c1e_r4_origk', 'int3c1e_r6_origk') kptij_lst = numpy.zeros((1,2,3)) Ls = cell.get_lattice_Ls() buf = None for i, (cn, fake_cell) in enumerate(fake_cells.items()): neighbor_list = build_neighbor_list_for_shlpairs(fake_cell, cell, Ls) v = incore.aux_e2_sum_auxbas(cell, fake_cell, intors[cn], aosym='s2', comp=1, kptij_lst=kptij_lst, neighbor_list=neighbor_list) if i == 0: buf = v else: buf = numpy.add(buf, v, out=buf) v = None free_neighbor_list(neighbor_list) vpploc = lib.unpack_tril(buf) return vpploc
# TODO add k-point sampling
[docs] def vpploc_part2_nuc_grad(cell, dm, kpts=None): ''' Nuclear gradients of the 2nd part of the local part of the GTH pseudo potential, contracted with the density matrix. ''' from pyscf.pbc.df import incore from pyscf.pbc.gto import build_neighbor_list_for_shlpairs, free_neighbor_list if kpts is not None and not gamma_point(kpts): raise NotImplementedError("k-point sampling not available") if kpts is None: kpts_lst = numpy.zeros((1,3)) else: kpts_lst = numpy.reshape(kpts, (-1,3)) kptij_lst = numpy.hstack((kpts_lst,kpts_lst)).reshape(-1,2,3) intors = ('int3c2e_ip1', 'int3c1e_ip1', 'int3c1e_ip1_r2_origk', 'int3c1e_ip1_r4_origk', 'int3c1e_ip1_r6_origk') Ls = cell.get_lattice_Ls() count = 0 grad = 0 for cn in range(1, 5): fakecell = fake_cell_vloc(cell, cn) fakecell.precision = EPS_PPL if fakecell.nbas > 0: neighbor_list = build_neighbor_list_for_shlpairs(fakecell, cell, Ls) buf = incore.int3c1e_nuc_grad(cell, fakecell, dm, intors[cn], kptij_lst=kptij_lst, neighbor_list=neighbor_list) if count == 0: grad = buf else: grad = numpy.add(grad, buf, out=grad) buf = None count += 1 free_neighbor_list(neighbor_list) grad *= -2 return grad
def _prepare_hl_data(fakecell, hl_blocks): offset = [0] * 3 hl_table = numpy.empty((len(hl_blocks),HL_TABLE_SLOTS), order='C', dtype=numpy.int32) hl_data = [] ptr = 0 for ib, hl in enumerate(hl_blocks): hl_table[ib,ATOM_OF] = fakecell._bas[ib,0] hl_table[ib,ANG_OF] = l = fakecell.bas_angular(ib) hl_dim = hl.shape[0] hl_table[ib,HL_DIM_OF], hl_table[ib,HL_DATA_OF] = hl_dim, ptr ptr += hl_dim**2 hl_data.extend(list(hl.ravel())) nd = 2 * l + 1 for i in range(hl_dim): hl_table[ib, i+HL_OFFSET0] = offset[i] offset[i] += nd hl_data = numpy.asarray(hl_data, order='C', dtype=numpy.double) return hl_table, hl_data # TODO add k-point sampling def _contract_ppnl(cell, fakecell, hl_blocks, ppnl_half, comp=1, kpts=None): from pyscf.pbc.gto import NeighborListOpt if kpts is None: kpts_lst = numpy.zeros((1,3)) else: kpts_lst = numpy.reshape(kpts, (-1,3)) hl_table, hl_data = _prepare_hl_data(fakecell, hl_blocks) opt = NeighborListOpt(fakecell) opt.build(fakecell, cell) shls_slice = (0, cell.nbas, 0, cell.nbas) key = 'cart' if cell.cart else 'sph' ao_loc = gto.moleintor.make_loc(cell._bas, key) ppnl = [] nao = cell.nao_nr() nao_pair = nao * (nao+1) // 2 for k, kpt in enumerate(kpts_lst): ppnl_half0 = ppnl_half1 = ppnl_half2 = None if len(ppnl_half[0]) > 0: ppnl_half0 = ppnl_half[0][k] if len(ppnl_half[1]) > 0: ppnl_half1 = ppnl_half[1][k] if len(ppnl_half[2]) > 0: ppnl_half2 = ppnl_half[2][k] if gamma_point(kpt): if ppnl_half0 is not None: ppnl_half0 = ppnl_half0.real if ppnl_half1 is not None: ppnl_half1 = ppnl_half1.real if ppnl_half2 is not None: ppnl_half2 = ppnl_half2.real buf = numpy.empty([nao_pair], order='C', dtype=numpy.double) fill = getattr(libpbc, 'ppnl_fill_gs2') else: buf = numpy.empty([nao_pair], order='C', dtype=numpy.complex128) raise NotImplementedError ppnl_half0 = numpy.asarray(ppnl_half0, order='C') ppnl_half1 = numpy.asarray(ppnl_half1, order='C') ppnl_half2 = numpy.asarray(ppnl_half2, order='C') drv = getattr(libpbc, "contract_ppnl", None) try: drv(fill, buf.ctypes.data_as(ctypes.c_void_p), ppnl_half0.ctypes.data_as(ctypes.c_void_p), ppnl_half1.ctypes.data_as(ctypes.c_void_p), ppnl_half2.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(comp), (ctypes.c_int*4)(*shls_slice), ao_loc.ctypes.data_as(ctypes.c_void_p), hl_table.ctypes.data_as(ctypes.c_void_p), hl_data.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(len(hl_blocks)), opt._this) except Exception as e: raise RuntimeError(f"Failed to compute non-local pseudo-potential.\n{e}") ppnl_k = lib.unpack_tril(buf) ppnl.append(ppnl_k) if kpts is None or numpy.shape(kpts) == (3,): ppnl = ppnl[0] return ppnl # TODO add k-point sampling def _contract_ppnl_nuc_grad(cell, fakecell, dms, hl_blocks, ppnl_half, ppnl_half_ip2, comp=3, kpts=None, hl_table=None, hl_data=None): from pyscf.pbc.gto import NeighborListOpt if kpts is None: kpts_lst = numpy.zeros((1,3)) else: kpts_lst = numpy.reshape(kpts, (-1,3)) if hl_table is None: hl_table, hl_data = _prepare_hl_data(fakecell, hl_blocks) opt = NeighborListOpt(fakecell) opt.build(fakecell, cell) nkpts = len(kpts_lst) nao = cell.nao dms = dms.reshape(nkpts, nao, nao) shls_slice = (0, cell.nbas, 0, cell.nbas) bas = numpy.asarray(cell._bas, order='C', dtype=numpy.int32) key = 'cart' if cell.cart else 'sph' ao_loc = gto.moleintor.make_loc(bas, key) grad = [] for k, kpt in enumerate(kpts_lst): dm = dms[k] naux = [0] * 3 ppnl_half0 = ppnl_half1 = ppnl_half2 = None if len(ppnl_half[0]) > 0: ppnl_half0 = ppnl_half[0][k] naux[0] = ppnl_half0.shape[0] if len(ppnl_half[1]) > 0: ppnl_half1 = ppnl_half[1][k] naux[1] = ppnl_half1.shape[0] if len(ppnl_half[2]) > 0: ppnl_half2 = ppnl_half[2][k] naux[2] = ppnl_half2.shape[0] ppnl_half_ip2_0 = ppnl_half_ip2_1 = ppnl_half_ip2_2 = None if len(ppnl_half_ip2[0]) > 0: ppnl_half_ip2_0 = ppnl_half_ip2[0][k] assert naux[0] == ppnl_half_ip2_0.shape[1] if len(ppnl_half_ip2[1]) > 0: ppnl_half_ip2_1 = ppnl_half_ip2[1][k] assert naux[1] == ppnl_half_ip2_1.shape[1] if len(ppnl_half_ip2[2]) > 0: ppnl_half_ip2_2 = ppnl_half_ip2[2][k] assert naux[2] == ppnl_half_ip2_2.shape[1] naux = numpy.asarray(naux, dtype=numpy.int32) if gamma_point(kpt): dm = dm.real if ppnl_half0 is not None: ppnl_half0 = ppnl_half0.real ppnl_half_ip2_0 = ppnl_half_ip2_0.real if ppnl_half1 is not None: ppnl_half1 = ppnl_half1.real ppnl_half_ip2_1 = ppnl_half_ip2_1.real if ppnl_half2 is not None: ppnl_half2 = ppnl_half2.real ppnl_half_ip2_2 = ppnl_half_ip2_2.real grad_k = numpy.zeros([cell.natm, comp], order='C', dtype=numpy.double) fill = getattr(libpbc, 'ppnl_nuc_grad_fill_gs1') else: grad_k = numpy.empty([cell.natm, comp], order='C', dtype=numpy.complex128) raise NotImplementedError dm = numpy.asarray(dm, order='C') ppnl_half0 = numpy.asarray(ppnl_half0, order='C') ppnl_half1 = numpy.asarray(ppnl_half1, order='C') ppnl_half2 = numpy.asarray(ppnl_half2, order='C') ppnl_half_ip2_0 = numpy.asarray(ppnl_half_ip2_0, order='C') ppnl_half_ip2_1 = numpy.asarray(ppnl_half_ip2_1, order='C') ppnl_half_ip2_2 = numpy.asarray(ppnl_half_ip2_2, order='C') drv = getattr(libpbc, "contract_ppnl_nuc_grad", None) try: drv(fill, grad_k.ctypes.data_as(ctypes.c_void_p), dm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(comp), ppnl_half0.ctypes.data_as(ctypes.c_void_p), ppnl_half1.ctypes.data_as(ctypes.c_void_p), ppnl_half2.ctypes.data_as(ctypes.c_void_p), ppnl_half_ip2_0.ctypes.data_as(ctypes.c_void_p), ppnl_half_ip2_1.ctypes.data_as(ctypes.c_void_p), ppnl_half_ip2_2.ctypes.data_as(ctypes.c_void_p), hl_table.ctypes.data_as(ctypes.c_void_p), hl_data.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(len(hl_blocks)), naux.ctypes.data_as(ctypes.c_void_p), (ctypes.c_int*4)(*shls_slice), ao_loc.ctypes.data_as(ctypes.c_void_p), bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(cell.natm), opt._this) except Exception as e: raise RuntimeError(f"Failed to compute non-local pp nuclear gradient.\n{e}") grad.append(grad_k) grad_tot = 0 if nkpts == 1: grad_tot = grad[0] else: for k in range(nkpts): grad_tot += grad[k] grad_tot = grad_tot.real return grad_tot
[docs] def get_pp_nl(cell, kpts=None): if kpts is None: kpts_lst = numpy.zeros((1,3)) else: kpts_lst = numpy.reshape(kpts, (-1,3)) nkpts = len(kpts_lst) fakecell, hl_blocks = fake_cell_vnl(cell) ppnl_half = _int_vnl(cell, fakecell, hl_blocks, kpts_lst) nao = cell.nao_nr() if gamma_point(kpts_lst): return _contract_ppnl(cell, fakecell, hl_blocks, ppnl_half, kpts=kpts) buf = numpy.empty((3*9*nao), dtype=numpy.complex128) # We set this equal to zeros in case hl_blocks loop is skipped # and ppnl is returned ppnl = numpy.zeros((nkpts,nao,nao), dtype=numpy.complex128) for k, kpt in enumerate(kpts_lst): offset = [0] * 3 for ib, hl in enumerate(hl_blocks): l = fakecell.bas_angular(ib) nd = 2 * l + 1 hl_dim = hl.shape[0] ilp = numpy.ndarray((hl_dim,nd,nao), dtype=numpy.complex128, buffer=buf) for i in range(hl_dim): p0 = offset[i] ilp[i] = ppnl_half[i][k][p0:p0+nd] offset[i] = p0 + nd ppnl[k] += numpy.einsum('ilp,ij,jlq->pq', ilp.conj(), hl, ilp) if abs(kpts_lst).sum() < 1e-9: # gamma_point: ppnl = ppnl.real if kpts is None or numpy.shape(kpts) == (3,): ppnl = ppnl[0] return ppnl
[docs] def vppnl_nuc_grad(cell, dm, kpts=None): ''' Nuclear gradients of the non-local part of the GTH pseudo potential, contracted with the density matrix. ''' if kpts is None: kpts_lst = numpy.zeros((1,3)) else: kpts_lst = numpy.reshape(kpts, (-1,3)) fakecell, hl_blocks = fake_cell_vnl(cell) intors = ('int1e_ipovlp', 'int1e_r2_origi_ip2', 'int1e_r4_origi_ip2') ppnl_half = _int_vnl(cell, fakecell, hl_blocks, kpts_lst) ppnl_half_ip2 = _int_vnl(cell, fakecell, hl_blocks, kpts_lst, intors, comp=3) # int1e_ipovlp computes ip1 so multiply -1 to get ip2 if len(ppnl_half_ip2[0]) > 0: for k, kpt in enumerate(kpts_lst): ppnl_half_ip2[0][k] *= -1 grad = _contract_ppnl_nuc_grad(cell, fakecell, dm, hl_blocks, ppnl_half, ppnl_half_ip2, kpts=kpts) grad *= -2 return grad
[docs] def fake_cell_vloc(cell, cn=0, atm_id=None): '''Generate fake cell for V_{loc}. Each term of V_{loc} (erf, C_1, C_2, C_3, C_4) is a gaussian type function. The integral over V_{loc} can be transfered to the 3-center integrals, in which the auxiliary basis is given by the fake cell. The kwarg cn indiciates which term to generate for the fake cell. If cn = 0, the erf term is generated. C_1,..,C_4 are generated with cn = 1..4 ''' if atm_id is None: atm_id = numpy.arange(cell.natm) else: atm_id = numpy.asarray(atm_id) natm = len(atm_id) fake_env = [cell.atom_coords()[atm_id].ravel()] fake_atm = cell._atm[atm_id].copy().reshape(natm,-1) fake_atm[:,gto.PTR_COORD] = numpy.arange(0, natm*3, 3) ptr = natm * 3 fake_bas = [] half_sph_norm = .5/numpy.pi**.5 for ia, atm in enumerate(atm_id): if cell.atom_charge(atm) == 0: # pass ghost atoms continue symb = cell.atom_symbol(atm) if cn == 0: if symb in cell._pseudo: pp = cell._pseudo[symb] rloc, nexp, cexp = pp[1:3+1] alpha = .5 / rloc**2 else: alpha = 1e16 norm = half_sph_norm / gto.gaussian_int(2, alpha) fake_env.append([alpha, norm]) fake_bas.append([ia, 0, 1, 1, 0, ptr, ptr+1, 0]) ptr += 2 elif symb in cell._pseudo: pp = cell._pseudo[symb] rloc, nexp, cexp = pp[1:3+1] if cn <= nexp: alpha = .5 / rloc**2 norm = cexp[cn-1]/rloc**(cn*2-2) / half_sph_norm fake_env.append([alpha, norm]) fake_bas.append([ia, 0, 1, 1, 0, ptr, ptr+1, 0]) ptr += 2 fakecell = cell.copy(deep=False) fakecell._atm = numpy.asarray(fake_atm, dtype=numpy.int32).reshape(-1, gto.ATM_SLOTS) fakecell._bas = numpy.asarray(fake_bas, dtype=numpy.int32).reshape(-1, gto.BAS_SLOTS) fakecell._env = numpy.asarray(numpy.hstack(fake_env), dtype=numpy.double) return fakecell
# sqrt(Gamma(l+1.5)/Gamma(l+2i+1.5)) _PLI_FAC = 1/numpy.sqrt(numpy.array(( (1, 3.75 , 59.0625 ), # l = 0, (1, 8.75 , 216.5625 ), # l = 1, (1, 15.75, 563.0625 ), # l = 2, (1, 24.75, 1206.5625), # l = 3, (1, 35.75, 2279.0625), # l = 4, (1, 48.75, 3936.5625), # l = 5, (1, 63.75, 6359.0625), # l = 6, (1, 80.75, 9750.5625))))# l = 7,
[docs] def fake_cell_vnl(cell): '''Generate fake cell for V_{nl}. gaussian function p_i^l Y_{lm} ''' fake_env = [cell.atom_coords().ravel()] fake_atm = cell._atm.copy() fake_atm[:,gto.PTR_COORD] = numpy.arange(0, cell.natm*3, 3) ptr = cell.natm * 3 fake_bas = [] hl_blocks = [] for ia in range(cell.natm): if cell.atom_charge(ia) == 0: # pass ghost atoms continue symb = cell.atom_symbol(ia) if symb in cell._pseudo: pp = cell._pseudo[symb] # nproj_types = pp[4] for l, (rl, nl, hl) in enumerate(pp[5:]): if nl > 0: alpha = .5 / rl**2 norm = gto.gto_norm(l, alpha) fake_env.append([alpha, norm]) fake_bas.append([ia, l, 1, 1, 0, ptr, ptr+1, 0]) # # Function p_i^l (PRB, 58, 3641 Eq 3) is (r^{2(i-1)})^2 square normalized to 1. # But here the fake basis is square normalized to 1. A factor ~ p_i^l / p_1^l # is attached to h^l_ij (for i>1,j>1) so that (factor * fake-basis * r^{2(i-1)}) # is normalized to 1. The factor is # r_l^{l+(4-1)/2} sqrt(Gamma(l+(4-1)/2)) sqrt(Gamma(l+3/2)) # ------------------------------------------ = ---------------------------------- # r_l^{l+(4i-1)/2} sqrt(Gamma(l+(4i-1)/2)) sqrt(Gamma(l+2i-1/2)) r_l^{2i-2} # fac = numpy.array([_PLI_FAC[l,i]/rl**(i*2) for i in range(nl)]) hl = numpy.einsum('i,ij,j->ij', fac, numpy.asarray(hl), fac) hl_blocks.append(hl) ptr += 2 fakecell = cell.copy(deep=False) fakecell._atm = numpy.asarray(fake_atm, dtype=numpy.int32) fakecell._bas = numpy.asarray(fake_bas, dtype=numpy.int32).reshape(-1, gto.BAS_SLOTS) fakecell._env = numpy.asarray(numpy.hstack(fake_env), dtype=numpy.double) return fakecell, hl_blocks
def _int_vnl(cell, fakecell, hl_blocks, kpts, intors=None, comp=1): '''Vnuc - Vloc''' if intors is None: intors = ['int1e_ovlp', 'int1e_r2_origi', 'int1e_r4_origi'] rcut = max(cell.rcut, fakecell.rcut) Ls = cell.get_lattice_Ls(rcut=rcut) nimgs = len(Ls) expkL = numpy.asarray(numpy.exp(1j*numpy.dot(kpts, Ls.T)), order='C') nkpts = len(kpts) fill = getattr(libpbc, 'PBCnr2c_fill_ks1') # TODO add screening cintopt = lib.c_null_ptr() def int_ket(_bas, intor): if len(_bas) == 0: return [] intor = cell._add_suffix(intor) atm, bas, env = gto.conc_env(cell._atm, cell._bas, cell._env, fakecell._atm, _bas, fakecell._env) atm = numpy.asarray(atm, dtype=numpy.int32) bas = numpy.asarray(bas, dtype=numpy.int32) env = numpy.asarray(env, dtype=numpy.double) natm = len(atm) nbas = len(bas) shls_slice = (cell.nbas, nbas, 0, cell.nbas) ao_loc = gto.moleintor.make_loc(bas, intor) ni = ao_loc[shls_slice[1]] - ao_loc[shls_slice[0]] nj = ao_loc[shls_slice[3]] - ao_loc[shls_slice[2]] if comp == 1: out = numpy.empty((nkpts,ni,nj), dtype=numpy.complex128) else: out = numpy.empty((nkpts,comp,ni,nj), dtype=numpy.complex128) fintor = getattr(gto.moleintor.libcgto, intor) drv = libpbc.PBCnr2c_drv drv(fintor, fill, out.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(nkpts), ctypes.c_int(comp), ctypes.c_int(nimgs), Ls.ctypes.data_as(ctypes.c_void_p), expkL.ctypes.data_as(ctypes.c_void_p), (ctypes.c_int*4)(*(shls_slice[:4])), ao_loc.ctypes.data_as(ctypes.c_void_p), cintopt, atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(natm), bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(nbas), env.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(env.size)) return out hl_dims = numpy.asarray([len(hl) for hl in hl_blocks]) out = (int_ket(fakecell._bas[hl_dims>0], intors[0]), int_ket(fakecell._bas[hl_dims>1], intors[1]), int_ket(fakecell._bas[hl_dims>2], intors[2])) return out