"""Module containing quantity classes."""
# Standard library imports
import math
import abc
from typing import Union, List
# Internal library imports
from aim2dat.units.constants import constants_data
class _BaseQuantity(abc.ABC):
_plot_labels = {}
def __init__(self, constants: Union[str, dict] = "CODATA_2022", base_unit: str = None):
if isinstance(constants, str):
constants = constants_data[constants]
self._derive_units(constants)
if base_unit is not None:
transf_val = self._units[base_unit]
for k in self._units.keys():
self._units[k] /= transf_val
def __getitem__(self, name: str) -> float:
return self._units.get(name.lower(), None)
def __getattr__(self, name: str) -> float:
return self[name]
@property
def available_units(self) -> List[str]:
"""
List of all available units.
"""
return list(self._units.keys())
def get_unit(self, unit: str) -> float:
"""
Return the value of the unit.
Parameters
----------
unit : str
Physical unit.
Returns
-------
float
Value of the unit.
"""
return self._units[unit.lower()]
@abc.abstractmethod
def _derive_units(self, constants: dict, base_unit: str):
pass
[docs]
class Length(_BaseQuantity):
"""
Length units.
"""
_plot_labels = {
"bohr": "Bohr",
"nm": "nm",
"ang": r"$\mathrm{\AA}$",
"angstrom": r"$\mathrm{\AA}$",
"m": "m",
"mm": "mm",
"micro_m": r"$\mathrm{\mu}$m",
"micron": r"$\mathrm{\mu}$m",
}
def _derive_units(self, constants: str):
self._units = {
"ang": 1.0,
"angstrom": 1.0,
"nm": 10.0,
"micro_m": 1.0e4,
"micron": 1.0e4,
"mm": 1.0e7,
"m": 1.0e10,
"bohr": (4.0e10 * math.pi * constants["eps0"] * constants["hbar"] ** 2.0)
/ (constants["me"] * constants["e"] ** 2.0),
}
[docs]
class Energy(_BaseQuantity):
"""
Energy units.
"""
_plot_labels = {
"rydberg": "Rydberg",
"hartree": "Ha",
"ha": "Ha",
"joule": "Joule",
"j": "Joule",
"kj_per_mol": r"kJ $\mathrm{mol}^{-1}$",
"ev": "eV",
"cal": "Cal",
}
def _derive_units(self, constants: str):
self._units = {
"ev": 1.0,
"hartree": (constants["me"] * constants["e"] ** 3.0)
/ (16.0 * math.pi**2.0 * constants["eps0"] ** 2.0 * constants["hbar"] ** 2.0),
"joule": 1.0 / constants["e"],
}
self._units["ha"] = self._units["hartree"]
self._units["rydberg"] = self._units["hartree"] / 2.0
self._units["j"] = self._units["joule"]
self._units["cal"] = 4.184 * self._units["joule"]
self._units["kj_per_mol"] = 1.0e3 * self._units["joule"] / constants["na"]
[docs]
class Force(_BaseQuantity):
"""Force units."""
_plot_labels = {
"ev_per_angstrom": r"eV $\mathrm{\AA}^{-1}$",
"ev_per_ang": r"eV $\mathrm{\AA}^{-1}$",
"hartree_per_bohr": r"Ha $\mathrm{Bohr}^{-1}$",
"ha_per_bohr": r"Ha $\mathrm{Bohr}^{-1}$",
}
def _derive_units(self, constants: str):
self._units = {
"ev_per_angstrom": 1.0,
"ev_per_ang": 1.0,
"hartree_per_bohr": (constants["me"] ** 2.0 * constants["e"] ** 5.0)
/ (16.0 * 4.0e10 * math.pi**3.0 * constants["eps0"] ** 3.0 * constants["hbar"] ** 4.0),
}
self._units["ha_per_bohr"] = self._units["hartree_per_bohr"]
[docs]
class Pressure(_BaseQuantity):
"""Pressure units."""
_plot_labels = {
"pa": "Pa",
"pascal": "Pa",
"bar": "bar",
"atm": "atm",
}
def _derive_units(self, constants: str):
self._units = {
"pa": 1.0 / (constants["e"] * 1.0e30),
}
self._units["pascal"] = self._units["pa"]
self._units["bar"] = self._units["pa"] * 1.0e5
self._units["atm"] = self._units["pa"] * 1.01325e5
[docs]
class Frequency(_BaseQuantity):
"""
Frequency units.
"""
_plot_labels = {
"hz": "Hz",
"khz": "kHz",
"mhz": "MHz",
"ghz": "GHz",
"thz": "THz",
"phz": "PHz",
}
def _derive_units(self, constants: str):
self._units = {"hz": 1.0 / (1.0e10 * math.sqrt(constants["e"] / constants["am"]))}
self._units["khz"] = 1.0e3 * self._units["hz"]
self._units["mhz"] = 1.0e6 * self._units["hz"]
self._units["ghz"] = 1.0e9 * self._units["hz"]
self._units["thz"] = 1.0e12 * self._units["hz"]
self._units["phz"] = 1.0e15 * self._units["hz"]
[docs]
class Wavevector(_BaseQuantity):
"""
Wavevector units.
"""
_plot_labels = {
"nm-1": r"nm$^{-1}$",
"angstrom-1": r"$\mathrm{\AA}^{-1}$",
"m-1": r"m$^{-1}$",
"cm-1": r"cm$^{-1}$",
"mm-1": r"mm$^{-1}$",
"micro_m-1": r"$\mathrm{\mu}$m$^{-1}$",
}
def _derive_units(self, constants: str):
self._units = {
"angstrom-1": 1.0,
"nm-1": 1.0e-1,
"micro_m-1": 1.0e-4,
"mm-1": 1.0e-7,
"cm-1": 1.0e-8,
"m-1": 1.0e-10,
}