Source code for pyEQL.salt_ion_match
"""
pyEQL salt matching library.
This file contains functions that allow a pyEQL Solution object composed of
individual species (usually ions) to be mapped to a solution of one or more
salts. This mapping is necessary because some parameters (such as activity
coefficient data) can only be determined for salts (e.g. NaCl) and not individual
species (e.g. Na+)
:copyright: 2013-2024 by Ryan S. Kingsbury
:license: LGPL, see LICENSE for more details.
"""
from monty.json import MSONable
from pymatgen.core.ion import Ion
from pyEQL.utils import standardize_formula
[docs]
class Salt(MSONable):
"""Class to represent a salt."""
def __init__(self, cation, anion):
"""
Create a Salt object based on its component ions.
Parameters:
cation, anion: (str) Chemical formula of the cation and anion, respectively.
Returns:
Salt : An object representing the properties of the salt
Examples:
>>> Salt('Na+','Cl-').formula
'NaCl'
>>> Salt('Mg++','Cl-').formula
'MgCl2'
"""
# create pymatgen Ion objects
pmg_cat = Ion.from_formula(cation)
pmg_an = Ion.from_formula(anion)
# standardize the cation and anion formulas
self.cation = standardize_formula(cation)
self.anion = standardize_formula(anion)
# get the charges on cation and anion
self.z_cation = pmg_cat.charge
self.z_anion = pmg_an.charge
# assign stoichiometric coefficients by finding a common multiple
self.nu_cation = int(abs(self.z_anion))
self.nu_anion = int(abs(self.z_cation))
# if both coefficients are the same, set each to one
if self.nu_cation == self.nu_anion:
self.nu_cation = 1
self.nu_anion = 1
# start building the formula, cation first
salt_formula = ""
if self.nu_cation > 1:
# add parentheses if the cation is a polyatomic ion
if len(pmg_cat.elements) > 1:
salt_formula += "("
salt_formula += self.cation.split("[")[0]
salt_formula += ")"
else:
salt_formula += self.cation.split("[")[0]
salt_formula += str(self.nu_cation)
else:
salt_formula += self.cation.split("[")[0]
if self.nu_anion > 1:
# add parentheses if the anion is a polyatomic ion
if len(pmg_an.elements) > 1:
salt_formula += "("
salt_formula += self.anion.split("[")[0]
salt_formula += ")"
else:
salt_formula += self.anion.split("[")[0]
salt_formula += str(self.nu_anion)
else:
salt_formula += self.anion.split("[")[0]
self.formula = salt_formula
# TODO - consider whether this should be adjusted to be based on total concentrations or not
# NOTE: speciating the solution results in a decrease in the overall ionic strength, because some of the
# Mg+2 is converted to monovalent complexes like MgOH+. Hence, the activity coefficients deviate a bit from
# the published values.
[docs]
def get_effective_molality(self, ionic_strength):
r"""Calculate the effective molality according to [mistry]_.
.. math:: 2 I \over (\nu_+ z_+^2 + \nu_- z_- ^2)
Args:
ionic_strength: Quantity
The ionic strength of the parent solution, mol/kg
Returns:
Quantity: the effective molality of the salt in the parent solution
References:
.. [mistry] Mistry, K. H.; Hunter, H. a.; Lienhard V, J. H. Effect of composition and nonideal solution behavior
on desalination calculations for mixed electrolyte solutions with comparison to seawater. Desalination
2013, 318, 34-47.
"""
m_effective = 2 * ionic_strength / (self.nu_cation * self.z_cation**2 + self.nu_anion * self.z_anion**2)
return m_effective.to("mol/kg")