Skip to content

Commit

Permalink
Merge pull request #106 from TheoChem-VU/92-include-spell-checking-mo…
Browse files Browse the repository at this point in the history
…dule

92 include spell checking module
  • Loading branch information
YHordijk authored Feb 6, 2024
2 parents 51bb5c1 + 29b857d commit 10ffff0
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/tcutility/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ def ensure_2d(x, transposed=False):
return x


from tcutility import constants, formula, geometry, log, molecule, results, slurm, data # noqa: F401, E402
from tcutility import constants, formula, geometry, log, molecule, results, slurm, data, analysis, spell_check # noqa: F401, E402
1 change: 1 addition & 0 deletions src/tcutility/data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import atom, functionals, basis_sets, cosmo, molecules # noqa: F401
32 changes: 32 additions & 0 deletions src/tcutility/data/basis_sets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
available_basis_sets = {
'ADF': [
'SZ',
'DZ',
'DZP',
'TZP',
'TZ2P',
'QZ4P',
'mTZ2P',
'AUG/ASZ',
'AUG/ADZ',
'AUG/ADZP',
'AUG/ATZP',
'AUG/ATZ2P',
'Corr/TZ3P',
'Corr/QZ6P',
'Corr/ATZ3P',
'Corr/AQZ6P',
'ET/ET-pVQZ',
'ET/ET-QZ3P',
'ET/ET-QZ3P-1DIFFUSE',
'ET/ET-QZ3P-2DIFFUSE',
'ET/ET-QZ3P-3DIFFUSE',
'TZ2P-J',
'QZ4P-J',
'POLTDDFT/DZ',
'POLTDDFT/DZP',
'POLTDDFT/TZP',
],
'BAND': {},
'ORCA': {},
}
99 changes: 99 additions & 0 deletions src/tcutility/data/cosmo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
available_solvents = [
'Vacuum',
'AceticAcid',
'Acetone',
'Acetonitrile',
'Ammonia',
'Aniline',
'Benzene',
'BenzylAlcohol',
'Bromoform',
'Butanol',
'isoButanol',
'tertButanol',
'CarbonDisulfide',
'CarbonTetrachloride',
'Chloroform',
'Cyclohexane',
'Cyclohexanone',
'Dichlorobenzene',
'DiethylEther',
'Dioxane',
'DMFA',
'DMSO',
'Ethanol',
'EthylAcetate',
'Dichloroethane',
'EthyleneGlycol',
'Formamide',
'FormicAcid',
'Glycerol',
'HexamethylPhosphoramide',
'Hexane',
'Hydrazine',
'Methanol',
'MethylEthylKetone',
'Dichloromethane',
'Methylformamide',
'Methypyrrolidinone',
'Nitrobenzene',
'Nitrogen',
'Nitromethane',
'PhosphorylChloride',
'IsoPropanol',
'Pyridine',
'Sulfolane',
'Tetrahydrofuran',
'Toluene',
'Triethylamine',
'TrifluoroaceticAcid',
'Water',
'CH3COOH',
'CH3COCH3',
'CH3CN',
'NH3',
'C6H5NH2',
'C6H6',
'C6H5CH2OH',
'CHBr3',
'C4H9OH',
'(CH3)2CHCH2OH',
'(CH3)3COH',
'CS2',
'CCl4',
'CHCl3',
'C6H12',
'C6H10O',
'C6H4Cl2',
'(CH3CH2)2O',
'C4H8O2',
'(CH3)2NCHO',
'(CH3)2SO',
'CH3CH2OH',
'CH3COOCH2CH3',
'ClCH2CH2Cl',
'HOCH2CH2OH',
'HCONH2',
'HCOOH',
'C3H8O3',
'C6H18N3OP',
'C6H14',
'N2H4',
'CH3OH',
'CH3CH2COCH3',
'CH2Cl2',
'HCONHCH3',
'C5H9NO',
'C6H5NO2',
'N2',
'CH3NO2',
'POCl3',
'(CH3)2CHOH',
'C5H5N',
'C4H8SO2',
'C4H8O',
'C6H5CH3',
'(CH3CH2)3N',
'CF3COOH',
'H2O'
]
50 changes: 43 additions & 7 deletions src/tcutility/data/functionals.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,66 @@
import os
from tcutility import results, log
from tcutility import results, log, spell_check


j = os.path.join


def get(functional_name: str):
def get(functional_name: str) -> results.Result:
'''
Return information about a given functional.
Args:
functional_name: the name of the functional. It should exist in the get_available_functionals keys.
functional_name: the name of the functional. It should exist in the :func:`get_available_functionals` keys.
Return:
A :class:`results.Result` object containing information about the functional if it exists. Else it will return ``None``.
A |Result| object containing information about the functional if it exists. Else it will return ``None``.
.. seealso::
:func:`get_available_functionals` for an overview of the information returned.
'''
return functionals.get(functional_name)

spell_check.check(functional_name, functionals.keys(), caller_level=3)
return functionals[functional_name]

def functional_name_from_path_safe_name(path_safe_name: str):

def functional_name_from_path_safe_name(path_safe_name: str) -> results.Result:
'''
Return information about a given functional given its path-safe name.
This can be useful when you want to know the functional from a path name.
Return:
A |Result| object containing information about the functional if it exists. Else it will return ``None``.
.. seealso::
:func:`get_available_functionals` for an overview of the information returned.
'''
for functional, functional_info in functionals.items():
if path_safe_name == functional_info.path_safe_name:
return functional


def get_available_functionals():
'''
Function that returns a dictionary of all available XC-functionals.
Returns:
: A |Result| object containing information about all available XC-functionals.
The functional names are stored as the keys and the functional information is stored as the values.
The values contain the following information:
- ``name`` **(str)** - the name of the functional.
- ``path_safe_name`` **(str)** - the name of the functional made suitable for file paths.
This name is the same as the normal name, but without parentheses. Asterisks are replaced with lower-case ``s``.
- ``name_no_disp`` **(str)** - the name of functional without the dispersion correction.
- ``category`` **(str)** - the category the functional belongs to.
- ``dispersion`` **(str)** - the dispersion correction part of the functional name.
- ``dispersion_name`` **(str)** - the name of the dispersion correction as it would be written in ADF.
- ``includes_disp`` **(bool)** - whether the functional already includes a dispersion correction.
- ``use_libxc`` **(bool)** - whether the functional is from the LibXC library.
- ``available_in_adf`` **(bool)** - whether the functional is available in ADF.
- ``available_in_band`` **(bool)** - whether the functional is available in BAND.
- ``available_in_orca`` **(bool)** - whether the functional is available in ORCA.
- ``adf_settings`` **(|Result|)** - the settings that are used to select the functional in the ADF input.
'''
def set_dispersion(func):
disp_map = {
Expand Down Expand Up @@ -115,6 +150,7 @@ def set_functional(func):
lines = file.readlines()

for line in lines:
# there can be empty lines
if not line.strip():
continue

Expand Down Expand Up @@ -154,4 +190,4 @@ def set_functional(func):


if __name__ == '__main__':
log.log(get('OLYP'))
log.log(get('LYP'))
48 changes: 39 additions & 9 deletions src/tcutility/job/adf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from scm import plams
from tcutility import log, results, formula
from tcutility.data import functionals
from tcutility import log, results, formula, spell_check, data
from tcutility.job.ams import AMSJob
import os

Expand All @@ -12,11 +11,11 @@ class ADFJob(AMSJob):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._functional = None
self.solvent('vacuum')
self.basis_set('TZ2P')
self.quality('Good')
self.SCF_convergence(1e-8)
self.single_point()
self.solvent('vacuum')

def __str__(self):
return f'{self._task}({self._functional}/{self._basis_set}), running in {os.path.join(os.path.abspath(self.rundir), self.name)}'
Expand All @@ -29,8 +28,16 @@ def basis_set(self, typ: str = 'TZ2P', core: str = 'None'):
typ: the type of basis-set to use. Default is TZ2P.
core: the size of the frozen core approximation. Default is None.
Raises:
ValueError: if the basis-set name or core is incorrect.
.. note:: If the selected functional is the r2SCAN-3c functional, then the basis-set will be set to mTZ2P.
.. seealso::
:mod:`tcutility.data.basis_sets` for an overview of the available basis-sets in ADF.
'''
spell_check.check(typ, data.basis_sets.available_basis_sets['ADF'], ignore_case=True)
spell_check.check(core, ['None', 'Small', 'Large'], ignore_case=True)
if self._functional == 'r2SCAN-3c' and typ != 'mTZ2P':
log.warn(f'Basis set {typ} is not allowed with r2SCAN-3c, switching to mTZ2P.')
typ = 'mTZ2P'
Expand All @@ -56,7 +63,7 @@ def multiplicity(self, val: int):
3) triplet
4) ...
The multiplicity is equal to 2*S+1 for spin-polarization of S.
The multiplicity is equal to 2*S+1 for spin-polarization S.
'''
self.settings.input.adf.SpinPolarization = (val - 1)//2
if val != 1:
Expand All @@ -74,7 +81,11 @@ def quality(self, val: str = 'Good'):
Args:
val: the numerical quality value to set to. This is the same as the ones used in the ADF GUI. Defaults to Good.
Raises:
ValueError: if the quality value is incorrect.
'''
spell_check.check(val, ['Basic', 'Normal', 'Good', 'VeryGood', 'Excellent'], ignore_case=True)
self.settings.input.adf.NumericalQuality = val

def SCF_convergence(self, thresh: float = 1e-8):
Expand All @@ -91,10 +102,16 @@ def functional(self, funtional_name: str, dispersion: str = None):
Set the functional to be used by the calculation. This also sets the dispersion if it is specified in the functional name.
Args:
funtional_name: the name of the functional. The value can be the same as the ones used in the ADF GUI. For a full list of functionals please see :func:`functionals.get_available_functionals`.
funtional_name: the name of the functional. The value can be the same as the ones used in the ADF GUI.
dispersion: dispersion setting to use with the functional. This is used when you want to use a functional from LibXC.
Raises:
ValueError: if the functional name is not recognized.
.. note:: Setting the functional to r2SCAN-3c will automatically set the basis-set to mTZ2P.
.. seealso::
:mod:`tcutility.data.functionals` for an overview of the available functionals in ADF.
'''
# before adding the new functional we should clear any previous functional settings
self.settings.input.adf.pop('XC', None)
Expand All @@ -111,11 +128,11 @@ def functional(self, funtional_name: str, dispersion: str = None):
log.error('There are two functionals called SSB-D, please use "GGA:SSB-D" or "MetaGGA:SSB-D".')
return

if not functionals.get(functional):
if not data.functionals.get(functional):
log.warn(f'XC-functional {functional} not found. Please ask a TheoCheM developer to add it. Adding functional as LibXC.')
self.settings.input.adf.XC.LibXC = functional
else:
func = functionals.get(functional)
func = data.functionals.get(functional)
self.settings.input.adf.update(func.adf_settings)

def relativity(self, level: str = 'Scalar'):
Expand All @@ -124,7 +141,11 @@ def relativity(self, level: str = 'Scalar'):
Args:
level: the level to set. Can be the same as the values in the ADF GUI and documentation. By default it is set to Scalar.
Raises:
ValueError: if the relativistic correction level is not correct.
'''
spell_check.check(level, ['Scalar', 'None', 'Spin-Orbit'], ignore_case=True)
self.settings.input.adf.relativity.level = level

def solvent(self, name: str = None, eps: float = None, rad: float = None, use_klamt: bool = False):
Expand All @@ -136,8 +157,15 @@ def solvent(self, name: str = None, eps: float = None, rad: float = None, use_kl
eps: the dielectric constant of your solvent. You can use this in place of the solvent name if you need more control over COSMO.
rad: the radius of the solvent molecules. You can use this in place of the solvent name if you need more control over COSMO.
use_klamt: whether to use the klamt atomic radii. This is usually used when you have charged species (?).
Raises:
ValueError: if the solvent name is given, but incorrect.
.. seealso::
:mod:`tcutility.data.cosmo` for an overview of the available solvent names and formulas.
'''
if name:
spell_check.check(name, data.cosmo.available_solvents, ignore_case=True, insertion_cost=0.3)
self._solvent = name
else:
self._solvent = f'COSMO(eps={eps} rad={rad})'
Expand Down Expand Up @@ -318,5 +346,7 @@ def run(self):
job.rundir = 'tmp/SN2/EDA'
job.molecule('../../../test/fixtures/xyz/pyr.xyz')
job.sbatch(p='tc', ntasks_per_node=15)
job.functional('OLYP')
job.basis_set('DZP')
job.solvent('')
job.basis_set('tz2p')
job.quality('veryGood')
job.functional('LYP-D3BJ')
Loading

0 comments on commit 10ffff0

Please sign in to comment.