Source code for thermosteam._thermo

# -*- coding: utf-8 -*-
# BioSTEAM: The Biorefinery Simulation and Techno-Economic Analysis Modules
# Copyright (C) 2020, Yoel Cortes-Pena <yoelcortes@gmail.com>
# 
# This module is under the UIUC open-source license. See 
# github.com/BioSTEAMDevelopmentGroup/biosteam/blob/master/LICENSE.txt
# for license details.
"""
"""
from . import equilibrium as eq
from ._chemical import Chemical
from ._chemicals import Chemicals
from .mixture import Mixture, ideal_mixture
from .utils import read_only, cucumber
from ._settings import settings

__all__ = ('Thermo',)


[docs]@cucumber # Just means you can pickle it @read_only class Thermo: """ Create a Thermo object that defines a thermodynamic property package Parameters ---------- chemicals : Chemicals or Iterable[str] Pure component chemical data. mixture : Mixture, optional Calculates mixture properties. Gamma : ActivityCoefficients subclass, optional Class for computing activity coefficients. Phi : FugacityCoefficients subclass, optional Class for computing fugacity coefficients. PCF : PoyntingCorrectionFactor subclass, optional Class for computing poynting correction factors. Examples -------- >>> from thermosteam import Thermo >>> Thermo(['Ethanol', 'Water']) Thermo(chemicals=CompiledChemicals([Ethanol, Water]), mixture=Mixture(rule='ideal mixing', ..., rigorous_energy_balance=True, include_excess_energies=False), Gamma=DortmundActivityCoefficients, Phi=IdealFugacityCoefficients, PCF=IdealPoyintingCorrectionFactors) Attributes ---------- chemicals : Chemicals or Iterable[str] Pure component chemical data. mixture : Mixture, optional Calculates mixture properties. Gamma : ActivityCoefficients subclass, optional Class for computing activity coefficients. Phi : FugacityCoefficients subclass, optional Class for computing fugacity coefficients. PCF : PoyntingCorrectionFactor subclass, optional Class for computing poynting correction factors. """ __slots__ = ('chemicals', 'mixture', 'Gamma', 'Phi', 'PCF', 'ideal_equilibrium_thermo') def __init__(self, chemicals, mixture=None, Gamma=eq.DortmundActivityCoefficients, Phi=eq.IdealFugacityCoefficients, PCF=eq.IdealPoyintingCorrectionFactors): if not isinstance(chemicals, Chemicals): chemicals = Chemicals(chemicals) if mixture: assert isinstance(mixture, Mixture), ( f"mixture must be a '{Mixture.__name__}' object") else: mixture = ideal_mixture(chemicals) chemicals.compile() if settings._debug: issubtype = issubclass assert issubtype(Gamma, eq.ActivityCoefficients), ( f"Gamma must be a '{eq.ActivityCoefficients.__name__}' subclass") assert issubtype(Phi, eq.FugacityCoefficients), ( f"Phi must be a '{eq.FugacityCoefficients.__name__}' subclass") assert issubtype(PCF, eq.PoyintingCorrectionFactors), ( f"PCF must be a '{eq.PoyintingCorrectionFactors.__name__}' subclass") setattr = object.__setattr__ if (Gamma is eq.IdealActivityCoefficients and Phi is eq.IdealFugacityCoefficients and PCF is eq.IdealPoyintingCorrectionFactors): ideal = self else: cls = self.__class__ ideal = cls.__new__(cls) setattr(ideal, 'chemicals', chemicals) setattr(ideal, 'mixture', mixture) setattr(ideal, 'Gamma', eq.IdealActivityCoefficients) setattr(ideal, 'Phi', eq.IdealFugacityCoefficients) setattr(ideal, 'PCF', eq.IdealPoyintingCorrectionFactors) setattr(ideal, 'ideal_equilibrium_thermo', ideal) setattr(self, 'chemicals', chemicals) setattr(self, 'mixture', mixture) setattr(self, 'Gamma', Gamma) setattr(self, 'Phi', Phi) setattr(self, 'PCF', PCF) setattr(self, 'ideal_equilibrium_thermo', ideal) @property def equilibrium_model(self): if self.ideal_equilibrium_thermo is self: return "Raoult's law" elif self.Gamma in (eq.UNIFACActivityCoefficients, eq.DortmundActivityCoefficients): return "modified Raoult's law" else: return "unknown" def as_chemical(self, chemical): isa = isinstance if isa(chemical, str): try: chemical = self.chemicals.retrieve(chemical) except: chemical = Chemical(chemical) elif not isa(chemical, Chemical): raise ValueError('can only convert string to chemical') return chemical def subgroup(self, IDs): chemicals = self.chemicals.subgroup(IDs) return type(self)(chemicals, None, self.Gamma, self.Phi, self.PCF) def __repr__(self): return f"{type(self).__name__}(chemicals={self.chemicals}, mixture={self.mixture}, Gamma={self.Gamma.__name__}, Phi={self.Phi.__name__}, PCF={self.PCF.__name__})" def show(self): try: mixture_info = self.mixture._info().replace('\n', '\n ') except: mixture_info = str(self.mixture) print(f"{type(self).__name__}(\n" f" chemicals={self.chemicals},\n" f" mixture={mixture_info},\n" f" Gamma={self.Gamma.__name__},\n" f" Phi={self.Phi.__name__},\n" f" PCF={self.PCF.__name__}\n" ")") _ipython_display_ = show