# -*- coding: utf-8 -*-
"""Localize the unit handling."""
import pint
# Default units to use for a dimensionality
_default_units = {
"[current] * [time]": [
"e",
],
"[current] * [length] * [time]": [
"D",
"e*Å",
"e*a_0",
"e*nm",
],
"dimensionless": [
"degree",
],
"[length]": [
"Å",
"pm",
"nm",
"um",
"a_0",
],
"[length] ** 2": [
"Å^2",
"pm^2",
"nm^2",
"um^2",
"a_0^2",
],
"[length] ** 3": [
"Å^3",
"pm^3",
"nm^3",
"um^3",
"a_0^2",
],
"1 / [length]": [
"1/Å",
"1/pm",
"1/nm",
"1/um",
"1/a_0",
],
"[length] ** 2 * [mass]": [
"10^-40*g*cm^2",
"Da*Å^2",
"Da*a_0^2",
],
"[length] ** 2 * [mass] / [substance] / [time] ** 2": [
"kJ/mol",
"kcal/mol",
"eV",
"E_h",
"Ry",
],
"[length] ** 2 * [mass] / [time] ** 2": [
"kJ/mol",
"kcal/mol",
"eV",
"E_h",
"Ry",
],
"[length] * [mass] / [substance] / [time] ** 2": [
"kcal/mol/Å",
"kJ/mol/Å",
"eV/Å",
],
"[length] * [mass] / [time] ** 2": [
"kcal/mol/Å",
"kJ/mol/Å",
"eV/Å",
],
"[length] / [time] ** 2": [
"m/s^2",
"ft/s^2",
"Å/fs^2",
],
"[length] ** 2 * [mass] / [substance] / [temperature] / [time] ** 2": [
"J/K/mol",
"cal/K/mol",
],
"[mass]": [
"Da",
"amu",
"g",
"kg",
"tonne",
"lb",
"ton",
],
"[mass] / [length] ** 3": [
"g/mL",
"kg/L",
"kg/m^3",
"g/mol/Å^3",
"g/mol/A_0^3",
],
"[mass] / [length] / [time] ** 2": [
"Pa",
"atm",
"bar",
"psi",
"ksi",
],
"[mass] / [time] ** 2": [
"mdyne/Å",
"N/m",
],
"1 / [time] ** 2": [
"mdyne/Å/Da",
"N/m/Da",
],
"[substance]": [
"mol",
],
"[temperature]": [
"K",
"°C",
"°F",
"°R",
],
"[time]": [
"fs",
"ps",
"ns",
"us",
"ms",
"s",
],
}
# Unit handling!
ureg = pint.UnitRegistry(auto_reduce_dimensions=True)
ureg.default_format = "~P"
pint.set_application_registry(ureg)
Q_ = ureg.Quantity
units_class = ureg("1 km").__class__
_d = pint.Context("chemistry")
factor = ureg.mol / ureg.avogadro_number
_d.add_transformation("", "[substance]", lambda ureg, x: x * factor)
_d.add_transformation("[substance]", "", lambda ureg, x: x / factor)
_d.add_transformation("1 / [substance]", "", lambda ureg, x: x * factor)
_d.add_transformation("", "1 / [substance]", lambda ureg, x: x / factor)
_d.add_transformation("[mass] / [substance]", "[mass]", lambda ureg, x: x * factor)
_d.add_transformation("[mass]", "[mass] / [substance]", lambda ureg, x: x / factor)
# kJ/mol/Å --> eV/Å
_d.add_transformation(
"[length] * [mass] / [substance] / [time] ** 2",
"[length] * [mass] / [time] ** 2",
lambda ureg, x: x * factor,
)
_d.add_transformation(
"[length] * [mass] / [time] ** 2",
"[length] * [mass] / [substance] / [time] ** 2",
lambda ureg, x: x / factor,
)
# kJ/mol --> eV
_d.add_transformation(
"[length] ** 2 * [mass] / [substance] / [time] ** 2",
"[length] ** 2 * [mass] / [time] ** 2",
lambda ureg, x: x * factor,
)
_d.add_transformation(
"[length] ** 2 * [mass] / [time] ** 2",
"[length] ** 2 * [mass] / [substance] / [time] ** 2",
lambda ureg, x: x / factor,
)
# kJ/mol/K --> eV/K
_d.add_transformation(
"[length] ** 2 * [mass] / [substance] / [temperature] / [time] ** 2",
"[length] ** 2 * [mass] / [temperature] / [time] ** 2",
lambda ureg, x: x * factor,
)
_d.add_transformation(
"[length] ** 2 * [mass] / [temperature] / [time] ** 2",
"[length] ** 2 * [mass] / [substance] / [temperature] / [time] ** 2",
lambda ureg, x: x / factor,
)
# kJ/mol/Å^2 --> eV/Å^2
_d.add_transformation(
"[mass] / [substance] / [time] ** 2",
"[mass] / [time] ** 2",
lambda ureg, x: x * factor,
)
# eV/Å^2 --> kJ/mol/Å^2
_d.add_transformation(
"[mass] / [time] ** 2",
"[mass] / [substance] / [time] ** 2",
lambda ureg, x: x / factor,
)
# kJ/mol/Å^3 --> eV/Å^3
_d.add_transformation(
"[mass] / [length] / [substance] / [time] ** 2",
"[mass] / [length] / [time] ** 2",
lambda ureg, x: x * factor,
)
# eV/Å^3 --> kJ/mol/Å^3
_d.add_transformation(
"[mass] / [length] / [time] ** 2",
"[mass] / [length] / [substance] / [time] ** 2",
lambda ureg, x: x / factor,
)
# kJ/mol/Å^4 --> eV/Å^4
_d.add_transformation(
"[mass] / [length] ** 2 / [substance] / [time] ** 2",
"[mass] / [length] ** 2 / [time] ** 2",
lambda ureg, x: x * factor,
)
# eV/Å^4 --> kJ/mol/Å^4
_d.add_transformation(
"[mass] / [length] ** 2 / [time] ** 2",
"[mass] / [length] ** 2 / [substance] / [time] ** 2",
lambda ureg, x: x / factor,
)
# kJ/mol*Å^6 --> eV*Å^6
_d.add_transformation(
"[length] ** 8 * [mass] / [substance] / [time] ** 2",
"[length] ** 8 * [mass] / [time] ** 2",
lambda ureg, x: x * factor,
)
# eV*Å^6 --> kJ/mol*Å^6
_d.add_transformation(
"[length] ** 8 * [mass] / [time] ** 2",
"[length] ** 8 * [mass] / [substance] / [time] ** 2",
lambda ureg, x: x / factor,
)
ureg.add_context(_d)
ureg.enable_contexts("chemistry")
[docs]
def default_units(units_or_dimensions):
"""Return the default units.
Parameters
----------
units_or_dimensions : str
The units or dimensionality.
Returns
-------
[str]
The list of unit strings.
"""
if units_or_dimensions == "all":
result = []
for values in _default_units.values():
result.extend(values)
return result
if "[" in units_or_dimensions or units_or_dimensions == "dimensionless":
dimensionality = units_or_dimensions
else:
dimensionality = str(Q_(units_or_dimensions).dimensionality)
if dimensionality in _default_units:
return _default_units[dimensionality]
else:
result = []
try:
for units in ureg.get_compatible_units(dimensionality):
result.append(f"{units:~P}")
tmp = "\n\t".join(result)
print(
f"Automatic defaults for '{units_or_dimensions}' ({dimensionality}) "
f"\n\t{tmp}"
)
except Exception:
print(
f"Warning: can't handle units '{units_or_dimensions}' --> "
f"{dimensionality} for default units."
)
return result
if __name__ == "__main__": # pragma: no cover
E = Q_(1.0, "kcal/mol")
E2 = E.to("eV")
print(f"{E:~} = {E2:~.4}")
print()
E2 = E.to("kJ/mol")
print(f"{E:~} = {E2:~.4}")
print()
E = Q_(1.0, "eV")
E2 = E.to("kcal/mol")
print(f"{E:~} = {E2:~.4}")
print()
E2 = E.to("kJ/mol")
print(f"{E:~} = {E2:~.4}")
print()
E = Q_(1.0, "mol")
E2 = E.to("")
print(f"{E:~} = {E2:~.4}")
print()
E = Q_(6.022e23, "")
E2 = E.to("mol")
print(f"{E:~} = {E2:~.4}")
print()
E = Q_(1, "kcal/mol/angstrom")
E2 = E.to("eV/angstrom")
print(f"{E:~} = {E2:~.4}")
print()
E = Q_(1, "eV/angstrom")
E2 = E.to("kcal/mol/angstrom")
print(f"{E:~} = {E2:~.4}")
print()