Source code for bonafide.utils.cdft_redox_mixin
"""Helper methods for calculating C-DFT redox descriptors."""
from typing import Dict, List, Optional, Tuple, Union, cast
from bonafide.utils.global_properties import (
calculate_global_cdft_descriptors_redox,
)
[docs]
class CdftLocalRedoxMixin:
"""Mixin class to provide functionality required for calculating local C-DFT descriptors based
on the ionization potential and electron affinity.
Attributes
----------
conformer_idx : int
The index of the conformer in the molecule vault.
energy_n : Tuple[Optional[float], str]
The energy of the actual molecule that was calculated or provided by the user as value
unit pair. The first entry of the tuple is ``None`` if the energy data is not available.
energy_n_minus1 : Tuple[Optional[float], str]
The energy of the one-electron-oxidized molecule that was calculated or provided by the
user as value unit pair. The first entry of the tuple is ``None`` if the energy data is not
available.
energy_n_plus1 : Tuple[Optional[float], str]
The energy of the one-electron-reduced molecule that was calculated or provided by the
user as value unit pair. The first entry of the tuple is ``None`` if the energy data is not
available.
global_feature_cache : List[Dict[str, Optional[Union[str, bool, int, float]]]]
The cache of global features for each conformer. The individual list entries are
dictionaries with the feature names as keys and feature values as values.
"""
conformer_idx: int
energy_n: Tuple[Optional[float], str]
energy_n_minus1: Tuple[Optional[float], str]
energy_n_plus1: Tuple[Optional[float], str]
global_feature_cache: List[Dict[str, Optional[Union[str, bool, int, float]]]]
[docs]
def _check_energy_data(self) -> Optional[str]:
"""Check if the required energy data is available for all three redox states.
Returns
-------
Optional[str]
An error message if any of the required energy data is missing, otherwise ``None``.
"""
_errmsg = None
_state_map = {"n": self.energy_n, "n-1": self.energy_n_minus1, "n+1": self.energy_n_plus1}
for state_id, energy in _state_map.items():
if energy is None:
_errmsg = (
f"for requesting data from '{self.__class__.__name__}', energy data for all "
"three redox states (actual molecule, one-electron-reduced, "
"one-electron-oxidized form) is required but is not available for the "
f"'{state_id}' state. Attach precomputed energy data or calculate it from "
"scratch (see the attach_energy() and calculate_electronic_structure() "
"methods)"
)
break
return _errmsg
[docs]
def _calculate_global_descriptors_redox(self) -> Optional[str]:
"""Calculate the global C-DFT descriptors and store them in the global feature cache.
Returns
-------
Optional[str]
An error message if the calculation of the global descriptors failed, otherwise
``None``.
"""
# Check if the global descriptors have already been calculated
if "global-ionization_potential" in self.global_feature_cache[self.conformer_idx]:
return None
# Calculate all data
_energy_n = cast(Tuple[float, str], self.energy_n) # for type checker
_energy_n_minus1 = cast(Tuple[float, str], self.energy_n_minus1) # for type checker
_energy_n_plus1 = cast(Tuple[float, str], self.energy_n_plus1) # for type checker
(
error_message,
ionization_potential,
electron_affinity,
chem_potential,
hardness,
softness,
electrophilicity,
nucleophilicity,
) = calculate_global_cdft_descriptors_redox(
energy_n=_energy_n,
energy_n_minus1=_energy_n_minus1,
energy_n_plus1=_energy_n_plus1,
)
if error_message is not None:
return error_message
# Write the data to the global feature cache
self.global_feature_cache[self.conformer_idx]["global-ionization_potential"] = (
ionization_potential
)
self.global_feature_cache[self.conformer_idx]["global-electron_affinity"] = (
electron_affinity
)
self.global_feature_cache[self.conformer_idx]["global-chem_potential_redox"] = (
chem_potential
)
self.global_feature_cache[self.conformer_idx]["global-hardness_redox"] = hardness
self.global_feature_cache[self.conformer_idx]["global-softness_redox"] = softness
self.global_feature_cache[self.conformer_idx]["global-electrophilicity_redox"] = (
electrophilicity
)
self.global_feature_cache[self.conformer_idx]["global-nucleophilicity_redox"] = (
nucleophilicity
)
return None