"""
pyEQL Solute class.
This file contains functions and methods for managing properties of
individual solutes. The Solute class contains methods for accessing
ONLY those properties that DO NOT depend on solution composition.
Solute properties such as activity coefficient or concentration
that do depend on compsition are accessed via Solution class methods.
:copyright: 2013-2023 by Ryan S. Kingsbury
:license: LGPL, see LICENSE for more details.
"""
from dataclasses import asdict, dataclass, field
from typing import Literal, Optional
import numpy as np
from pymatgen.core.ion import Ion
[docs]@dataclass
class Datum:
"""Document containing data for a single computed or experimental property."""
value: str
reference: Optional[str] = None
data_type: Literal["computed", "experimental", "fitted", "unknown"] = "unknown"
@property
def magnitude(self):
return float(self.value.split(" ")[0])
@property
def unit(self):
return self.value.split(" ")[-1]
@property
def uncertainty(self):
if len(self.value.split(" ")) > 3:
return float(self.value.split(" ")[2])
return np.nan
[docs] def as_dict(self):
return dict(asdict(self).items())
[docs]@dataclass
class Solute:
"""
represent each chemical species as an object containing its formal charge,
transport numbers, concentration, activity, etc.
Args:
formula : str
Chemical formula for the solute.
Charged species must contain a + or - and (for polyvalent solutes) a number representing the net charge (e.g. 'SO4-2').
"""
formula: str
charge: int
molecular_weight: str
elements: list
chemsys: str
pmg_ion: Ion
formula_html: str
formula_latex: str
formula_hill: str
formula_pretty: str
oxi_state_guesses: tuple
n_atoms: int
n_elements: int
size: dict = field(
default_factory=lambda: {
"radius_ionic": None,
"radius_hydrated": None,
"radius_vdw": None,
"molar_volume": None,
}
)
thermo: dict = field(default_factory=lambda: {"ΔG_hydration": None, "ΔG_formation": None})
transport: dict = field(default_factory=lambda: {"diffusion_coefficient": None})
model_parameters: dict = field(
default_factory=lambda: {
"activity_pitzer": {"Beta0": None, "Beta1": None, "Beta2": None, "Cphi": None, "Max_C": None},
"molar_volume_pitzer": {
"Beta0": None,
"Beta1": None,
"Beta2": None,
"Cphi": None,
"V_o": None,
"Max_C": None,
},
"viscosity_jones_dole": {"B": None},
}
)
[docs] def as_dict(self):
return dict(asdict(self).items())
# set output of the print() statement
def __str__(self):
return (
"Species "
+ str(self.formula)
+ " MW="
+ str(self.mw)
+ " Formal Charge="
+ str(self.charge)
+ " Amount= "
+ str(self.moles)
)