From 77a09a4b630ff93eb31923ab08c06f279718cad7 Mon Sep 17 00:00:00 2001 From: cortespea Date: Mon, 13 Nov 2023 08:12:45 -0600 Subject: [PATCH] improvements to CEOS implementation --- .../equilibrium/activity_coefficients.py | 29 +++++++++++----- .../equilibrium/fugacity_coefficients.py | 34 +++++++++++++------ 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/thermosteam/equilibrium/activity_coefficients.py b/thermosteam/equilibrium/activity_coefficients.py index 1e2b2a9a..a3d563e0 100644 --- a/thermosteam/equilibrium/activity_coefficients.py +++ b/thermosteam/equilibrium/activity_coefficients.py @@ -484,22 +484,29 @@ class GCEOSActivityCoefficients(ActivityCoefficients): """ __slots__ = ('_chemicals', '_eos') EOS = None # type[GCEOSMIX] Subclasses must implement this attribute. + chemsep_db = None # Optional[str] Name of chemsep data base for interaction parameters. + cache = None # [dict] Subclasses must implement this attribute. - def __init__(self, chemicals): - self.chemicals = chemicals + def __new__(cls, chemicals): + chemicals = tuple(chemicals) + cache = cls.cache + if chemicals in cache: + return cache[chemicals] + else: + self = super().__new__(cls) + self._chemicals = chemicals + cache[chemicals] = self + return self @classmethod def subclass(cls, EOS, name=None): if name is None: name = EOS.__name__[:-3] + 'ActivityCoefficients' - return type(name, (cls,), dict(EOS=EOS)) + return type(name, (cls,), dict(EOS=EOS, cache={})) @property def chemicals(self): """tuple[Chemical] All chemicals involved in the calculation of fugacity coefficients.""" return self._chemicals - @chemicals.setter - def chemicals(self, chemicals): - self._chemicals = tuple(chemicals) def eos(self, zs, T, P): if zs.__class__ is np.ndarray: zs = [float(i) for i in zs] @@ -507,10 +514,13 @@ def eos(self, zs, T, P): self._eos = eos = self._eos.to_TP_zs_fast(T=T, P=P, zs=zs, only_l=True, full_alphas=False) except: data = tmo.ChemicalData(self.chemicals) - try: - kijs = IPDB.get_ip_asymmetric_matrix('ChemSep PR', data.CASs, 'kij') - except: + if self.chemsep_db is None: kijs = None + else: + try: + kijs = IPDB.get_ip_asymmetric_matrix(self.chemsep_db, data.CASs, 'kij') + except: + kijs = None self._eos = eos = self.EOS( zs=zs, T=T, P=P, Tcs=data.Tcs, Pcs=data.Pcs, omegas=data.omegas, kijs=kijs, only_l=True @@ -539,5 +549,6 @@ def __call__(self, x, T, P=101325): clsnames.append(clsname) dct[clsname] = cls +dct['PRActivityCoefficients'].chemsep_db = 'ChemSep PR' __all__ = (*__all__, *clsnames) del dct, clsnames \ No newline at end of file diff --git a/thermosteam/equilibrium/fugacity_coefficients.py b/thermosteam/equilibrium/fugacity_coefficients.py index 9b7ea739..7723f044 100644 --- a/thermosteam/equilibrium/fugacity_coefficients.py +++ b/thermosteam/equilibrium/fugacity_coefficients.py @@ -31,9 +31,6 @@ class FugacityCoefficients: """ __slots__ = () - def __init__(self, chemicals): - self.chemicals = chemicals - def __repr__(self): chemicals = ", ".join([i.ID for i in self.chemicals]) return f"<{type(self).__name__}([{chemicals}])>" @@ -51,6 +48,9 @@ class IdealFugacityCoefficients(FugacityCoefficients): """ __slots__ = ('_chemicals') + def __init__(self, chemicals): + self.chemicals = chemicals + @property def chemicals(self): """tuple[Chemical] All chemicals involved in the calculation of fugacity coefficients.""" @@ -75,19 +75,29 @@ class GCEOSFugacityCoefficients(FugacityCoefficients): """ __slots__ = ('_chemicals', '_eos') EOS = None # type[GCEOSMIX] Subclasses must implement this attribute. + cache = None # [dict] Subclasses must implement this attribute. + chemsep_db = None # Optional[str] Name of chemsep data base for interaction parameters. + + def __new__(cls, chemicals): + chemicals = tuple(chemicals) + cache = cls.cache + if chemicals in cache: + return cache[chemicals] + else: + self = super().__new__(cls) + self._chemicals = chemicals + cache[chemicals] = self + return self @classmethod def subclass(cls, EOS, name=None): if name is None: name = EOS.__name__[:-3] + 'FugacityCoefficients' - return type(name, (cls,), dict(EOS=EOS)) + return type(name, (cls,), dict(EOS=EOS, cache={})) @property def chemicals(self): """tuple[Chemical] All chemicals involved in the calculation of fugacity coefficients.""" return self._chemicals - @chemicals.setter - def chemicals(self, chemicals): - self._chemicals = tuple(chemicals) def eos(self, zs, T, P): if zs.__class__ is np.ndarray: zs = [float(i) for i in zs] @@ -95,10 +105,13 @@ def eos(self, zs, T, P): self._eos = eos = self._eos.to_TP_zs_fast(T=T, P=P, zs=zs, only_g=True, full_alphas=False) except: data = tmo.ChemicalData(self.chemicals) - try: - kijs = IPDB.get_ip_asymmetric_matrix('ChemSep PR', data.CASs, 'kij') - except: + if self.chemsep_db is None: kijs = None + else: + try: + kijs = IPDB.get_ip_asymmetric_matrix(self.chemsep_db, data.CASs, 'kij') + except: + kijs = None self._eos = eos = self.EOS( zs=zs, T=T, P=P, Tcs=data.Tcs, Pcs=data.Pcs, omegas=data.omegas, kijs=kijs, only_g=True @@ -127,5 +140,6 @@ def __call__(self, x, T, P=101325): clsnames.append(clsname) dct[clsname] = cls +dct['PRFugacityCoefficients'].chemsep_db = 'ChemSep PR' __all__ = (*__all__, *clsnames) del dct, clsnames