#!/usr/bin/env python
# Copyright 2014-2018 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>
#
'''
Effective core potential (ECP)
This module exposes some ecp integration functions from the C implementation.
Reference for ecp integral computation
* Analytical integration
J. Chem. Phys. 65, 3826 (1976); https://doi.org/10.1063/1.432900
J. Chem. Phys. 111, 8778 (1999); https://doi.org/10.1063/1.480225
J. Comput. Phys. 44, 289 (1981); https://doi.org/10.1016/0021-9991(81)90053-X
* Numerical integration
J. Comput. Chem. 27, 1009 (2006); https://doi.org/10.1002/jcc.20410
Chem. Phys. Lett. 296, 445 (1998); https://doi.org/10.1016/S0009-2614(98)01077-X
'''
import ctypes
import numpy
from pyscf import lib
from pyscf.gto import moleintor
from pyscf.data.elements import ELEMENTS
libecp = moleintor.libcgto
libecp.ECPscalar_cache_size.restype = ctypes.c_int
[docs]
def type1_by_shell(mol, shls, cart=False):
li = mol.bas_angular(shls[0])
lj = mol.bas_angular(shls[1])
if cart:
fn = libecp.ECPtype1_cart
di = (li+1)*(li+2)//2 * mol.bas_nctr(shls[0])
dj = (lj+1)*(lj+2)//2 * mol.bas_nctr(shls[1])
else:
fn = libecp.ECPtype1_sph
di = (li*2+1) * mol.bas_nctr(shls[0])
dj = (lj*2+1) * mol.bas_nctr(shls[1])
cache_size = libecp.ECPscalar_cache_size(
ctypes.c_int(1), (ctypes.c_int*2)(*shls),
mol._atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.natm),
mol._bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.nbas),
mol._env.ctypes.data_as(ctypes.c_void_p))
cache = numpy.empty(cache_size)
buf = numpy.zeros((di,dj), order='F')
fn(buf.ctypes.data_as(ctypes.c_void_p),
(ctypes.c_int*2)(*shls),
mol._ecpbas.ctypes.data_as(ctypes.c_void_p),
ctypes.c_int(len(mol._ecpbas)),
mol._atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.natm),
mol._bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.nbas),
mol._env.ctypes.data_as(ctypes.c_void_p), lib.c_null_ptr(),
cache.ctypes.data_as(ctypes.c_void_p))
return buf
[docs]
def type2_by_shell(mol, shls, cart=False):
li = mol.bas_angular(shls[0])
lj = mol.bas_angular(shls[1])
if cart:
fn = libecp.ECPtype2_cart
di = (li+1)*(li+2)//2 * mol.bas_nctr(shls[0])
dj = (lj+1)*(lj+2)//2 * mol.bas_nctr(shls[1])
else:
fn = libecp.ECPtype2_sph
di = (li*2+1) * mol.bas_nctr(shls[0])
dj = (lj*2+1) * mol.bas_nctr(shls[1])
cache_size = libecp.ECPscalar_cache_size(
ctypes.c_int(1), (ctypes.c_int*2)(*shls),
mol._atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.natm),
mol._bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.nbas),
mol._env.ctypes.data_as(ctypes.c_void_p))
cache = numpy.empty(cache_size)
buf = numpy.zeros((di,dj), order='F')
fn(buf.ctypes.data_as(ctypes.c_void_p),
(ctypes.c_int*2)(*shls),
mol._ecpbas.ctypes.data_as(ctypes.c_void_p),
ctypes.c_int(len(mol._ecpbas)),
mol._atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.natm),
mol._bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.nbas),
mol._env.ctypes.data_as(ctypes.c_void_p), lib.c_null_ptr(),
cache.ctypes.data_as(ctypes.c_void_p))
return buf
AS_ECPBAS_OFFSET= 18
AS_NECPBAS = 19
[docs]
def so_by_shell(mol, shls):
'''Spin-orbit coupling ECP in spinor basis
i/2 <Pauli_matrix dot l U(r)>
'''
li = mol.bas_angular(shls[0])
lj = mol.bas_angular(shls[1])
di = (li*4+2) * mol.bas_nctr(shls[0])
dj = (lj*4+2) * mol.bas_nctr(shls[1])
bas = numpy.vstack((mol._bas, mol._ecpbas))
mol._env[AS_ECPBAS_OFFSET] = len(mol._bas)
mol._env[AS_NECPBAS] = len(mol._ecpbas)
buf = numpy.zeros((di,dj), order='F', dtype=numpy.complex128)
cache = numpy.empty(buf.size*48+100000)
fn = libecp.ECPso_spinor
fn(buf.ctypes.data_as(ctypes.c_void_p),
(ctypes.c_int*2)(di, dj),
(ctypes.c_int*2)(*shls),
mol._atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.natm),
bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.nbas),
mol._env.ctypes.data_as(ctypes.c_void_p), lib.c_null_ptr(),
cache.ctypes.data_as(ctypes.c_void_p))
return buf
[docs]
def core_configuration(nelec_core, atom_symbol=None):
conf_dic = {
0 : '0s0p0d0f',
2 : '1s0p0d0f',
10: '2s1p0d0f',
18: '3s2p0d0f',
28: '3s2p1d0f',
36: '4s3p1d0f',
46: '4s3p2d0f',
54: '5s4p2d0f',
60: '4s3p2d1f',
68: '5s4p2d1f',
78: '5s4p3d1f',
92: '5s4p3d2f',
}
# Core configurations for f-in-core ECPs defined in the following references
# 10.1007/BF00528565 , 10.1007/s00214-005-0629-0 , 10.1007/s00214-009-0584-2
elements_4f = ELEMENTS[57:71]
elements_5f = ELEMENTS[89:103]
if atom_symbol in elements_4f:
# TODO: fix La3+ and Ce4+ ECP46MWB f-in-core ECPs
for i in range(47, 59):
conf_dic[i] = '4s3p2d1f'
if atom_symbol in elements_5f:
# TODO: fix Ac3+, Th4+, Pa5+ and U6+ ECP78MWB f-in-core ECPs
for i in range(79, 91):
conf_dic[i] = '5s4p3d2f'
if nelec_core not in conf_dic:
raise RuntimeError('Core configuration for %d core electrons is not available.' % nelec_core)
coreshell = [int(x) for x in conf_dic[nelec_core][::2]]
return coreshell
if __name__ == '__main__':
from pyscf import gto, scf
mol = gto.M(atom='''
Cu 0. 0. 0.
H 0. 0. -1.56
H 0. 0. 1.56
''',
basis={'Cu':'lanl2dz', 'H':'sto3g'},
ecp = {'cu':'lanl2dz'},
#basis={'Cu':'crenbs', 'H':'sto3g'},
#ecp = {'cu':'crenbs'},
charge=-1,
verbose=4)
mf = scf.RHF(mol)
print(mf.kernel(), -196.09477546034623)
mol = gto.M(atom='''
Na 0. 0. 0.
H 0. 0. 1.
''',
basis={'Na':'lanl2dz', 'H':'sto3g'},
ecp = {'Na':'lanl2dz'},
verbose=0)
mf = scf.RHF(mol)
print(mf.kernel(), -0.45002315562861461)