Skip to content

Commit

Permalink
Update dft_parser; Add tests for dft_parser
Browse files Browse the repository at this point in the history
  • Loading branch information
sunqm committed Mar 23, 2024
1 parent fb77fd8 commit aedaecc
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 12 deletions.
20 changes: 12 additions & 8 deletions pyscf/dft/dft_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@
@lru_cache(128)
def parse_dft(dft_method):
''' conventional dft method ->
(xc, enable nlc, dispersion, with 3-body dispersion)
(xc, enable nlc, (xc for dftd3, dispersion version, with 3-body dispersion))
'''
if not isinstance(dft_method, str):
return dft_method, None, None, False
return dft_method, None, (dft_method, None, False)
method_lower = dft_method.lower()
xc = dft_method
disp = None

# special cases:
# - wb97x-d is not supported yet
Expand All @@ -53,24 +51,30 @@ def parse_dft(dft_method):
if method_lower == 'wb97x-d3bj':
return 'wb97x-v', False, ('wb97x', 'd3bj', False)

# J. Chem. Theory Comput. 2013, 9, 1, 263272
# J. Chem. Theory Comput. 2013, 9, 1, 263-272
if method_lower in ['wb97x-d3']:
raise NotImplementedError('wb97x-d3 is not supported yet.')

if method_lower.endswith('-3c'):
raise NotImplementedError('*-3c methods are not supported yet.')

xc = dft_method
disp = None
for d in DISP_VERSIONS:
if method_lower.endswith(d):
disp = d
xc = method_lower.replace(f'-{d}','')
return xc, None, (xc, disp, False)
if method_lower.endswith(d+'2b'):
disp = d
xc = method_lower.replace(f'-{d}2b', '')
return xc, None, (xc, disp, False)
if method_lower.endswith(d+'atm'):
disp = d
xc = method_lower.replace(f'-{d}atm', '')
return xc, None, (xc, disp, True)

if disp is not None:
if xc in ('b97m', 'wb97m', 'wb97x'):
return xc+'-v', False, (xc, disp, False)
else:
return xc, None, (xc, disp, False)

return xc, None, (xc, None, False)
9 changes: 6 additions & 3 deletions pyscf/dft/libxc.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,9 +923,9 @@ def is_gga(xc_code):
@lru_cache(100)
def is_nlc(xc_code):
enable_nlc = dft_parser.parse_dft(xc_code)[1]
if enable_nlc is False:
if not (enable_nlc is None and enable_nlc):
return False

# identify nlc by xc_code itself if enable_nlc is None
if isinstance(xc_code, str):
if xc_code.isdigit():
return _itrf.LIBXC_is_nlc(ctypes.c_int(int(xc_code)))
Expand Down Expand Up @@ -1092,7 +1092,6 @@ def parse_xc(description):
(hybrid, alpha, omega), ((libxc-Id, fac), (libxc-Id, fac), ...)
''' # noqa: E501

description = dft_parser.parse_dft(description)[0]
hyb = [0, 0, 0] # hybrid, alpha, omega (== SR_HF, LR_HF, omega)
if description is None:
return tuple(hyb), ()
Expand All @@ -1111,6 +1110,8 @@ def parse_xc(description):
'To restore the VWN5 definition, you can put the setting '
'"B3LYP_WITH_VWN5 = True" in pyscf_conf.py')

description = dft_parser.parse_dft(description)[0]

def assign_omega(omega, hyb_or_sr, lr=0):
if hyb[2] == omega or omega == 0:
hyb[0] += hyb_or_sr
Expand Down Expand Up @@ -1237,6 +1238,8 @@ def possible_c_for(key):
parse_token(token, 'C')
else:
for token in description.replace('-', '+-').replace(';+', ';').split('+'):
# dftd3 cannot be used in a custom xc description
assert '-d3' not in token
parse_token(token, 'compound XC', search_xc_alias=True)
if hyb[2] == 0: # No omega is assigned. LR_HF is 0 for normal Coulomb operator
hyb[1] = 0
Expand Down
14 changes: 14 additions & 0 deletions pyscf/dft/test/test_libxc.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,20 @@ def test_m06(self):
self.assertAlmostEqual(abs(numpy.hstack([fxc[i] for i in [0,1,2,4,6,9]])-fxc_ref).max(), 0, 7)
self.assertAlmostEqual(abs(numpy.hstack([kxc[i] for i in [0,1,2,3,5,7,10,12,15,19]])-kxc_ref).max(), 0, 6)

def test_dft_parser(self):
from pyscf.dft.dft_parser import parse_dft
self.assertEqual(parse_dft('wb97m-d3bj'), ('wb97m-v', False, ('wb97m', 'd3bj', False)))
self.assertEqual(dft.libxc.parse_xc('wb97m-d3bj')[1][0][0] == 531)
self.assertTrue(not dft.libxc.is_nlc('wb97m-d3bj'))

self.assertEqual(parse_dft('wb97-d3zerom'), ('wb97', None, ('wb97', 'd3zerom', False)))
self.assertTrue(not dft.libxc.is_nlc('wb97-d3zerom'))

self.assertEqual(parse_dft('wb97m-d3bjatm'), ('wb97m-v', False, ('wb97m', 'd3bj', True)))
self.assertTrue(not dft.libxc.is_nlc('wb97m-d3bjatm'))

self.assertEqual(parse_dft('wb97x-d3zero2b'), ('wb97x-v', False, ('wb97x', 'd3zero', False)))
self.assertTrue(not dft.libxc.is_nlc('wb97x-d3zero2b'))

if __name__ == "__main__":
print("Test libxc")
Expand Down
10 changes: 9 additions & 1 deletion pyscf/dft/xcfun.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import numpy
from pyscf import lib
from pyscf.dft.xc.utils import remove_dup, format_xc_code
from pyscf.dft import xc_deriv
from pyscf.dft import xc_deriv, dft_parser
from pyscf import __config__

_itrf = lib.load_library('libxcfun_itrf')
Expand Down Expand Up @@ -318,6 +318,9 @@ def is_gga(xc_code):
VV10_XC.update([(5000+i, VV10_XC[key]) for i, key in enumerate(VV10_XC)])

def is_nlc(xc_code):
enable_nlc = dft_parser.parse_dft(xc_code)[1]
if not (enable_nlc is None and enable_nlc):
return False
fn_facs = parse_xc(xc_code)[1]
return any(xid >= 5000 for xid, c in fn_facs)

Expand Down Expand Up @@ -420,6 +423,8 @@ def parse_xc(description):
elif not isinstance(description, str): #isinstance(description, (tuple,list)):
return parse_xc('%s,%s' % tuple(description))

description = dft_parser.parse_dft(description)[0]

def assign_omega(omega, hyb_or_sr, lr=0):
if hyb[2] == omega or omega == 0:
hyb[0] += hyb_or_sr
Expand All @@ -430,6 +435,7 @@ def assign_omega(omega, hyb_or_sr, lr=0):
hyb[2] = omega
else:
raise ValueError('Different values of omega found for RSH functionals')

fn_facs = []
def parse_token(token, suffix, search_xc_alias=False):
if token:
Expand Down Expand Up @@ -503,6 +509,8 @@ def parse_token(token, suffix, search_xc_alias=False):
parse_token(token, 'C')
else:
for token in description.replace('-', '+-').replace(';+', ';').split('+'):
# dftd3 cannot be used in a custom xc description
assert '-d3' not in token
parse_token(token, 'XC', search_xc_alias=True)
if hyb[2] == 0: # No omega is assigned. LR_HF is 0 for normal Coulomb operator
hyb[1] = 0
Expand Down

0 comments on commit aedaecc

Please sign in to comment.