Source code for tcutility.results.dftb
from tcutility.results import cache, Result
from tcutility import ensure_list, constants
[docs]
def get_calc_settings(info: Result) -> Result:
"""
Function to read useful calculation settings from kf reader
"""
assert info.engine == "dftb", f"This function reads DFTB data, not {info.engine} data"
if info.input.task == 'PESScan':
return Result()
assert "dftb.rkf" in info.files, f'Missing dftb.rkf file, [{", ".join([": ".join(item) for item in info.files.items()])}]'
ret = Result()
# set the calculation task at a higher level
ret.task = info.input.task
return ret
[docs]
def get_properties(info: Result) -> Result:
"""Function to get properties from an DFTB calculation.
Args:
info: Result object containing DFTB properties.
Returns:
:Result object containing properties from the DFTB calculation:
- **energy.bond (float)** – bonding energy (|kcal/mol|).
"""
assert info.engine == "dftb", f"This function reads DFTB data, not {info.engine} data"
if info.input.task == 'PESScan':
return Result()
assert "dftb.rkf" in info.files, f'Missing dftb.rkf file, [{", ".join([": ".join(item) for item in info.files.items()])}]'
reader_dftb = cache.get(info.files["dftb.rkf"])
ret = Result()
# properties are not given as in ADF. Instead you must first know which index each key is at. For example we might have:
# (Properties, SubType(k)) == Coulomb
# therefore, to get the Coulomb energy we first have to know the index k
# we therefore first loop through every subtype entry and store the substypes in order in a list
# we also store the main type (e.g. 'Energy', 'Gradient', ...) and the value
number_of_properties = reader_dftb.read("Properties", "nEntries")
subtypes = []
types = []
values = []
for i in range(1, number_of_properties + 1):
subtypes.append(reader_dftb.read("Properties", f"Subtype({i})").strip())
types.append(reader_dftb.read("Properties", f"Type({i})").strip())
if types[-1] == 'Energy':
values.append(reader_dftb.read("Properties", f"Value({i})") * constants.HA2KCALMOL)
else:
values.append(reader_dftb.read("Properties", f"Value({i})"))
# then simply add the properties to ret
for typ, subtyp, value in zip(types, subtypes, values):
ret[typ.replace(" ", "_")][subtyp] = value
if ret.energy['DFTB Final Energy']:
ret.energy.bond = ret.energy['DFTB Final Energy']
# we also read vibrations
if ('Vibrations', 'nNormalModes') in reader_dftb:
ret.vibrations.number_of_modes = reader_dftb.read("Vibrations", "nNormalModes")
ret.vibrations.frequencies = ensure_list(reader_dftb.read("Vibrations", "Frequencies[cm-1]"))
if ("Vibrations", "Intensities[km/mol]") in reader_dftb:
ret.vibrations.intensities = ensure_list(reader_dftb.read("Vibrations", "Intensities[km/mol]"))
ret.vibrations.number_of_imag_modes = len([freq for freq in ret.vibrations.frequencies if freq < 0])
ret.vibrations.character = "minimum" if ret.vibrations.number_of_imag_modes == 0 else "transitionstate"
ret.vibrations.modes = []
for i in range(ret.vibrations.number_of_modes):
ret.vibrations.modes.append(reader_dftb.read("Vibrations", f"NoWeightNormalMode({i+1})"))
if ("Thermodynamics", "Gibbs free Energy") in reader_dftb:
ret.energy.gibbs = reader_dftb.read("Thermodynamics", "Gibbs free Energy") * constants.HA2KCALMOL
ret.energy.enthalpy = reader_dftb.read("Thermodynamics", "Enthalpy") * constants.HA2KCALMOL
ret.energy.nuclear_internal = reader_dftb.read("Thermodynamics", "Internal Energy total") * constants.HA2KCALMOL
return ret