"""C-DFT features based on condensed Fukui indices calculated with xtb."""
from typing import Optional, Tuple
from bonafide.features.xtb_fukui_misc import (
Xtb3DAtomCdftCondensedFukuiDual,
Xtb3DAtomCdftCondensedFukuiMinus,
Xtb3DAtomCdftCondensedFukuiPlus,
Xtb3DAtomCdftCondensedFukuiZero,
)
from bonafide.utils.base_featurizer import BaseFeaturizer
from bonafide.utils.cdft_redox_mixin import CdftLocalRedoxMixin
[docs]
class _Xtb3DAtomCdftLocal(BaseFeaturizer, CdftLocalRedoxMixin):
"""Parent feature factory for calculating C-DFT descriptors based on condensed Fukui indices
calculated with xtb.
"""
def __init__(self) -> None:
self.extraction_mode = "single"
super().__init__()
[docs]
def _wrap_fukui(
self, factory: type, fukui_feature_name: str
) -> Tuple[Optional[float], Optional[str]]:
"""Calculate the condensed Fukui indices with xtb.
The calculation is performed with the feature factory class of the respective Fukui
coefficient.
Parameters
----------
factory : type
The feature factory class to be used for the Fukui calculation.
fukui_feature_name : str
The name of the Fukui feature to be calculated.
Returns
-------
Tuple[Optional[float], Optional[str]]
The calculated Fukui value and an error message.
"""
fukui = None
error_message = None
# Save the initial feature name
_feature_name = self.feature_name
# Initialize the calculation of the Fukui values. In case they were already calculated
# in a previous feature calculation, they are automatically fetched from the cache.
calc = factory()
# Temporarily set the feature name to calculate the Fukui value
params = self.__dict__
params["feature_name"] = fukui_feature_name
# Get the Fukui value
fukui, error_message = calc(**params)
# Reset the feature name back to the actual feature name
self.feature_name = _feature_name
return fukui, error_message
[docs]
class Xtb3DAtomCdftLocalElectrophilicityFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_electrophilicity_fmo", calculated
with xtb.
The index of this feature is 566 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_electrophilicity_fmo`` feature."""
# Calculate the Fukui plus value which is required for the calculation of this feature
fukui_plus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiPlus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_plus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_electrophilicity = self.global_feature_cache[self.conformer_idx][
"xtb3D-global-electrophilicity_fmo"
]
assert isinstance(global_electrophilicity, (int, float)) # for type checker
assert isinstance(fukui_plus, (int, float)) # for type checker
local_electrophilicity = round(number=global_electrophilicity * fukui_plus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_electrophilicity
[docs]
class Xtb3DAtomCdftLocalElectrophilicityRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_electrophilicity_redox", calculated
with xtb.
The index of this feature is 567 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_electrophilicity_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui plus value which is required for the calculation of this feature
fukui_plus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiPlus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_plus",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_electrophilicity = self.global_feature_cache[self.conformer_idx][
"global-electrophilicity_redox"
]
assert isinstance(global_electrophilicity, (int, float)) # for type checker
assert isinstance(fukui_plus, (int, float)) # for type checker
local_electrophilicity = round(number=global_electrophilicity * fukui_plus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_electrophilicity
[docs]
class Xtb3DAtomCdftLocalHardnessMinusFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hardness_minus_fmo", calculated with
xtb.
The index of this feature is 568 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hardness_minus_fmo`` feature."""
# Calculate the Fukui minus value which is required for the calculation of this feature
fukui_minus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiMinus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_minus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_hardness = self.global_feature_cache[self.conformer_idx]["xtb3D-global-hardness_fmo"]
assert isinstance(global_hardness, (int, float)) # for type checker
assert isinstance(fukui_minus, (int, float)) # for type checker
local_hardness_minus = round(number=global_hardness * fukui_minus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hardness_minus
[docs]
class Xtb3DAtomCdftLocalHardnessMinusRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hardness_minus_redox", calculated
with xtb.
The index of this feature is 569 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hardness_minus_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui minus value which is required for the calculation of this feature
fukui_minus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiMinus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_minus",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_hardness = self.global_feature_cache[self.conformer_idx]["global-hardness_redox"]
assert isinstance(global_hardness, (int, float)) # for type checker
assert isinstance(fukui_minus, (int, float)) # for type checker
local_hardness_minus = round(number=global_hardness * fukui_minus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hardness_minus
[docs]
class Xtb3DAtomCdftLocalHardnessPlusFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hardness_plus_fmo", calculated with
xtb.
The index of this feature is 570 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hardness_plus_fmo`` feature."""
# Calculate the Fukui plus value which is required for the calculation of this feature
fukui_plus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiPlus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_plus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_hardness = self.global_feature_cache[self.conformer_idx]["xtb3D-global-hardness_fmo"]
assert isinstance(global_hardness, (int, float)) # for type checker
assert isinstance(fukui_plus, (int, float)) # for type checker
local_hardness_plus = round(number=global_hardness * fukui_plus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hardness_plus
[docs]
class Xtb3DAtomCdftLocalHardnessPlusRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hardness_plus_redox", calculated with
xtb.
The index of this feature is 571 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hardness_plus_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui plus value which is required for the calculation of this feature
fukui_plus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiPlus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_plus",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_hardness = self.global_feature_cache[self.conformer_idx]["global-hardness_redox"]
assert isinstance(global_hardness, (int, float)) # for type checker
assert isinstance(fukui_plus, (int, float)) # for type checker
local_hardness_plus = round(number=global_hardness * fukui_plus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hardness_plus
[docs]
class Xtb3DAtomCdftLocalHardnessZeroFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hardness_zero_fmo", calculated with
xtb.
The index of this feature is 572 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hardness_zero_fmo`` feature."""
# Calculate the Fukui zero value which is required for the calculation of this feature
fukui_zero, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiZero,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_zero",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_hardness = self.global_feature_cache[self.conformer_idx]["xtb3D-global-hardness_fmo"]
assert isinstance(global_hardness, (int, float)) # for type checker
assert isinstance(fukui_zero, (int, float)) # for type checker
local_hardness_zero = round(number=global_hardness * fukui_zero, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hardness_zero
[docs]
class Xtb3DAtomCdftLocalHardnessZeroRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hardness_zero_redox", calculated with
xtb.
The index of this feature is 573 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hardness_zero_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui zero value which is required for the calculation of this feature
fukui_zero, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiZero,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_zero",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_hardness = self.global_feature_cache[self.conformer_idx]["global-hardness_redox"]
assert isinstance(global_hardness, (int, float)) # for type checker
assert isinstance(fukui_zero, (int, float)) # for type checker
local_hardness_zero = round(number=global_hardness * fukui_zero, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hardness_zero
[docs]
class Xtb3DAtomCdftLocalHyperhardnessFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hyperhardness_fmo", calculated with
xtb.
The index of this feature is 574 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hyperhardness_fmo`` feature."""
# Calculate the dual descriptor which is required for the calculation of this feature
fukui_dual, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiDual,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_dual",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_hardness = self.global_feature_cache[self.conformer_idx]["xtb3D-global-hardness_fmo"]
assert isinstance(global_hardness, (int, float)) # for type checker
assert isinstance(fukui_dual, (int, float)) # for type checker
local_hyperhardness = round(number=global_hardness**2 * fukui_dual, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hyperhardness
[docs]
class Xtb3DAtomCdftLocalHyperhardnessRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hyperhardness_redox", calculated with
xtb.
The index of this feature is 575 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hyperhardness_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the dual descriptor which is required for the calculation of this feature
fukui_dual, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiDual,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_dual",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_hardness = self.global_feature_cache[self.conformer_idx]["global-hardness_redox"]
assert isinstance(global_hardness, (int, float)) # for type checker
assert isinstance(fukui_dual, (int, float)) # for type checker
local_hyperhardness = round(number=global_hardness**2 * fukui_dual, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hyperhardness
[docs]
class Xtb3DAtomCdftLocalHypersoftnessFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hypersoftness_fmo", calculated with
xtb.
The index of this feature is 576 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hypersoftness_fmo`` feature."""
# Calculate the dual descriptor which is required for the calculation of this feature
fukui_dual, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiDual,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_dual",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_softness = self.global_feature_cache[self.conformer_idx]["xtb3D-global-softness_fmo"]
assert isinstance(global_softness, (int, float)) # for type checker
assert isinstance(fukui_dual, (int, float)) # for type checker
local_hypersoftness = round(number=global_softness**2 * fukui_dual, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hypersoftness
[docs]
class Xtb3DAtomCdftLocalHypersoftnessRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_hypersoftness_redox", calculated with
xtb.
The index of this feature is 577 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_hypersoftness_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the dual descriptor which is required for the calculation of this feature
fukui_dual, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiDual,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_dual",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_softness = self.global_feature_cache[self.conformer_idx]["global-softness_redox"]
assert isinstance(global_softness, (int, float)) # for type checker
assert isinstance(fukui_dual, (int, float)) # for type checker
local_hypersoftness = round(number=global_softness**2 * fukui_dual, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_hypersoftness
[docs]
class Xtb3DAtomCdftLocalNucleophilicityFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_nucleophilicity_fmo", calculated with
xtb.
The index of this feature is 578 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_nucleophilicity_fmo`` feature."""
# Calculate the Fukui minus value which is required for the calculation of this feature
fukui_minus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiMinus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_minus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_nucleophilicity = self.global_feature_cache[self.conformer_idx][
"xtb3D-global-nucleophilicity_fmo"
]
assert isinstance(global_nucleophilicity, (int, float)) # for type checker
assert isinstance(fukui_minus, (int, float)) # for type checker
local_nucleophilicity = round(number=global_nucleophilicity * fukui_minus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_nucleophilicity
[docs]
class Xtb3DAtomCdftLocalNucleophilicityRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_nucleophilicity_redox", calculated
with xtb.
The index of this feature is 579 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_nucleophilicity_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui minus value which is required for the calculation of this feature
fukui_minus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiMinus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_minus",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_nucleophilicity = self.global_feature_cache[self.conformer_idx][
"global-nucleophilicity_redox"
]
assert isinstance(global_nucleophilicity, (int, float)) # for type checker
assert isinstance(fukui_minus, (int, float)) # for type checker
local_nucleophilicity = round(number=global_nucleophilicity * fukui_minus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_nucleophilicity
[docs]
class Xtb3DAtomCdftLocalRelativeElectrophilicity(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_relative_electrophilicity",
calculated with xtb.
The index of this feature is 580 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_relative_electrophilicity`` feature."""
# Calculate the Fukui minus value which is required for the calculation of this feature
fukui_minus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiMinus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_minus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui plus value which is required for the calculation of this feature
fukui_plus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiPlus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_plus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
assert isinstance(fukui_minus, (int, float)) # for type checker
assert isinstance(fukui_plus, (int, float)) # for type checker
try:
relative_electrophilicity = round(number=fukui_plus / fukui_minus, ndigits=6)
except ZeroDivisionError:
self._err = (
"cannot be calculated because the Fukui minus coefficient (denominator) is zero"
)
return
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = relative_electrophilicity
[docs]
class Xtb3DAtomCdftLocalRelativeNucleophilicity(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_relative_nucleophilicity", calculated
with xtb.
The index of this feature is 581 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_relative_nucleophilicity`` feature."""
# Calculate the Fukui minus value which is required for the calculation of this feature
fukui_minus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiMinus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_minus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui plus value which is required for the calculation of this feature
fukui_plus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiPlus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_plus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
assert isinstance(fukui_minus, (int, float)) # for type checker
assert isinstance(fukui_plus, (int, float)) # for type checker
try:
relative_nucleophilicity = round(number=fukui_minus / fukui_plus, ndigits=6)
except ZeroDivisionError:
self._err = (
"cannot be calculated because the Fukui plus coefficient (denominator) is zero"
)
return
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = relative_nucleophilicity
[docs]
class Xtb3DAtomCdftLocalSoftnessMinusFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_softness_minus_fmo", calculated with
xtb.
The index of this feature is 582 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_softness_minus_fmo`` feature."""
# Calculate the Fukui minus value which is required for the calculation of this feature
fukui_minus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiMinus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_minus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_softness = self.global_feature_cache[self.conformer_idx]["xtb3D-global-softness_fmo"]
assert isinstance(global_softness, (int, float)) # for type checker
assert isinstance(fukui_minus, (int, float)) # for type checker
local_softness_minus = round(number=global_softness * fukui_minus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_softness_minus
[docs]
class Xtb3DAtomCdftLocalSoftnessMinusRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_softness_minus_redox", calculated
with xtb.
The index of this feature is 583 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_softness_minus_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui minus value which is required for the calculation of this feature
fukui_minus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiMinus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_minus",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_softness = self.global_feature_cache[self.conformer_idx]["global-softness_redox"]
assert isinstance(global_softness, (int, float)) # for type checker
assert isinstance(fukui_minus, (int, float)) # for type checker
local_softness_minus = round(number=global_softness * fukui_minus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_softness_minus
[docs]
class Xtb3DAtomCdftLocalSoftnessPlusFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_softness_plus_fmo", calculated with
xtb.
The index of this feature is 584 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_softness_plus_fmo`` feature."""
# Calculate the Fukui plus value which is required for the calculation of this feature
fukui_plus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiPlus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_plus",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_softness = self.global_feature_cache[self.conformer_idx]["xtb3D-global-softness_fmo"]
assert isinstance(global_softness, (int, float)) # for type checker
assert isinstance(fukui_plus, (int, float)) # for type checker
local_softness_plus = round(number=global_softness * fukui_plus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_softness_plus
[docs]
class Xtb3DAtomCdftLocalSoftnessPlusRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_softness_plus_redox", calculated with
xtb.
The index of this feature is 585 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_softness_plus_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui plus value which is required for the calculation of this feature
fukui_plus, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiPlus,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_plus",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_softness = self.global_feature_cache[self.conformer_idx]["global-softness_redox"]
assert isinstance(global_softness, (int, float)) # for type checker
assert isinstance(fukui_plus, (int, float)) # for type checker
local_softness_plus = round(number=global_softness * fukui_plus, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_softness_plus
[docs]
class Xtb3DAtomCdftLocalSoftnessZeroFmo(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_softness_zero_fmo", calculated with
xtb.
The index of this feature is 586 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_softness_zero_fmo`` feature."""
# Calculate the Fukui zero value which is required for the calculation of this feature
fukui_zero, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiZero,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_zero",
)
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_softness = self.global_feature_cache[self.conformer_idx]["xtb3D-global-softness_fmo"]
assert isinstance(global_softness, (int, float)) # for type checker
assert isinstance(fukui_zero, (int, float)) # for type checker
local_softness_zero = round(number=global_softness * fukui_zero, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_softness_zero
[docs]
class Xtb3DAtomCdftLocalSoftnessZeroRedox(_Xtb3DAtomCdftLocal):
"""Feature factory for the 3D atom feature "cdft_local_softness_zero_redox", calculated with
xtb.
The index of this feature is 587 (see the ``list_atom_features()`` and
``list_bond_features()`` method). The corresponding configuration settings can be found
under "xtb" in the _feature_config.toml file.
"""
def __init__(self) -> None:
super().__init__()
[docs]
def calculate(self) -> None:
"""Calculate the ``xtb3D-atom-cdft_local_softness_zero_redox`` feature."""
# Check if energies of all three redox states are available
error_message = self._check_energy_data()
if error_message is not None:
self._err = error_message
return
# Calculate the Fukui zero value which is required for the calculation of this feature
fukui_zero, error_message = self._wrap_fukui(
factory=Xtb3DAtomCdftCondensedFukuiZero,
fukui_feature_name="xtb3D-atom-cdft_condensed_fukui_zero",
)
if error_message is not None:
self._err = error_message
return
# Calculate global descriptors based on ionization potential and electron affinity and
# write them to the global feature cache
error_message = self._calculate_global_descriptors_redox()
if error_message is not None:
self._err = error_message
return
# Calculate the desired value and write it to the results dictionary
global_softness = self.global_feature_cache[self.conformer_idx]["global-softness_redox"]
assert isinstance(global_softness, (int, float)) # for type checker
assert isinstance(fukui_zero, (int, float)) # for type checker
local_softness_zero = round(number=global_softness * fukui_zero, ndigits=6)
if self.atom_bond_idx not in self.results:
self.results[self.atom_bond_idx] = {}
self.results[self.atom_bond_idx][self.feature_name] = local_softness_zero