Skip to content

Commit

Permalink
misc. optimizations; add lru_cache to more places
Browse files Browse the repository at this point in the history
  • Loading branch information
rkingsbury committed Nov 4, 2023
1 parent 19e674b commit 45c0077
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 15 deletions.
13 changes: 9 additions & 4 deletions src/pyEQL/engines.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,15 +672,20 @@ def get_activity_coefficient(self, solution, solute):

# translate the species into keys that phreeqc will understand
k = standardize_formula(solute)
el = k.split("[")[0]
chg = k.split("[")[1].split("]")[0]
spl = k.split("[")
el = spl[0]
chg = spl[1].split("]")[0]
if chg[-1] == "1":
chg = chg[0] # just pass + or -, not +1 / -1
k = el + chg

# calculate the molal scale activity coefficient
print(k)
act = ppsol.activity(k, "mol") / ppsol.molality(k, "mol")
try:
act = ppsol.activity(k, "mol") / ppsol.molality(k, "mol")
except ZeroDivisionError:
# assume this means the solute does not exist
logger.warning(f"Solute {solute} not found in solution. returning 0 activity")
act = 0

# remove the PPSol from the phreeqcpython instance
self._destroy_ppsol(ppsol)
Expand Down
30 changes: 19 additions & 11 deletions src/pyEQL/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,11 @@ def __init__(
# create a logger attached to this class
# self.logger = logging.getLogger(type(self).__name__)

# per-instance cache of get_property calls
self.get_property = lru_cache(maxsize=None)(self._get_property)
# per-instance cache of get_property and other calls that do not depend
# on composition
# see https://rednafi.com/python/lru_cache_on_methods/
self.get_property = lru_cache()(self._get_property)
self.get_molar_conductivity = lru_cache()(self._get_molar_conductivity)

# initialize the volume recalculation flag
self.volume_update_required = False
Expand Down Expand Up @@ -342,6 +345,10 @@ def temperature(self, temperature: str):
# recalculate the volume
self.volume_update_required = True

# clear any cached solute properties that may depend on temperature
self.get_property.cache_clear()
self.get_molar_conductivity.cache_clear()

@property
def pressure(self) -> Quantity:
"""Return the hydrostatic pressure of the solution in atm."""
Expand Down Expand Up @@ -584,14 +591,16 @@ def viscosity_kinematic(self) -> Quantity:
a1 = ureg.Quantity(params["a1"]["value"]).magnitude
b0 = ureg.Quantity(params["b0"]["value"]).magnitude
b1 = ureg.Quantity(params["b1"]["value"]).magnitude

# compute the delta G parameters
temperature = self.temperature.to("degC").magnitude
G_123 = a0 + a1 * (temperature) ** 0.75
G_23 = b0 + b1 * (temperature) ** 0.5
else:
# TODO - fall back to the Jones-Dole model! There are currently no eyring parameters in the database!
# proceed with the coefficients equal to zero and log a warning
logger.warning("Viscosity coefficients for %s not found. Viscosity will be approximate." % salt.formula)

# compute the delta G parameters
temperature = self.temperature.to("degC").magnitude
G_123 = a0 + a1 * (temperature) ** 0.75
G_23 = b0 + b1 * (temperature) ** 0.5
logger.info("Viscosity coefficients for %s not found. Viscosity will be approximate." % salt.formula)
G_123 = G_23 = 0

# get the kinematic viscosity of water, returned by IAPWS in m2/s
nu_w = self.water_substance.nu
Expand Down Expand Up @@ -848,7 +857,6 @@ def total_dissolved_solids(self) -> Quantity:
continue
tds += self.get_amount(s, "mg/L")

# return tds + self.start_uncharged_TDS
return tds

@property
Expand Down Expand Up @@ -885,7 +893,7 @@ def debye_length(self) -> Quantity:
"""
# to preserve dimensionality, convert the ionic strength into mol/L units
ionic_strength = self.ionic_strength.magnitude * ureg.Quantity("mol/L")
ionic_strength = ureg.Quantity(self.ionic_strength.magnitude, "mol/L")
dielectric_constant = self.dielectric_constant

debye_length = (
Expand Down Expand Up @@ -2204,7 +2212,7 @@ def get_transport_number(self, solute, activity_correction=False) -> Quantity:

return (numerator / denominator).to("dimensionless")

def get_molar_conductivity(self, solute: str) -> Quantity:
def _get_molar_conductivity(self, solute: str) -> Quantity:
"""
Calculate the molar (equivalent) conductivity for a solute.
Expand Down
2 changes: 2 additions & 0 deletions src/pyEQL/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
"""

from collections import UserDict
from functools import lru_cache

from pymatgen.core.ion import Ion


@lru_cache
def standardize_formula(formula: str):
"""
Convert a chemical formula into standard form.
Expand Down

0 comments on commit 45c0077

Please sign in to comment.