Source code for libICEpost.src.thermophysicalModels.thermoModels.thermoMixture.ThermoMixture

#####################################################################
#                                 DOC                               #
#####################################################################

"""
@author: F. Ramognino       <federico.ramognino@polimi.it>
Last update:        12/06/2023
"""

#####################################################################
#                               IMPORT                              #
#####################################################################

from __future__ import annotations

from libICEpost.src.base.Utilities import Utilities
from libICEpost.src.base.dataStructures.Dictionary import Dictionary

from libICEpost.src.thermophysicalModels.specie.specie.Mixture import Mixture

from libICEpost.Database import _DatabaseClass
from libICEpost.Database.chemistry.thermo import database

from .mixingRules.EquationOfState.EquationOfStateMixing import EquationOfStateMixing
from .mixingRules.Thermo.ThermoMixing import ThermoMixing

from libICEpost.src.thermophysicalModels.specie.thermo.EquationOfState.EquationOfState import EquationOfState
from libICEpost.src.thermophysicalModels.specie.thermo.Thermo.Thermo import Thermo

from . import mixingRules

#############################################################################
#                               MAIN CLASSES                                #
#############################################################################
[docs] class ThermoMixture(Utilities): """ Class for computing thermodynamic data of a mixture. Attributes: mix (Mixture): The composition of the mixture. EoS (EquationOfState): The equation of state of the mixture. Thermo (Thermo): The thermodynamic model of the mixture. """ _mix:Mixture """The composition of the mixture""" _EoS:EquationOfStateMixing """The equation of state of the mixture""" _Thermo:ThermoMixing """The thermodynamic model of the mixture""" _db:_DatabaseClass = database.chemistry.thermo """Database of thermodynamic data""" ######################################################################### #Properties: @property def mix(self) -> Mixture: """ The composition of the mixture (Mixture). """ return self._mix ################################ @property def db(self) -> _DatabaseClass: """ Database of thermodynamic data (reference to database.chemistry.thermo) """ return self._db ################################ @property def Thermo(self) -> Thermo: """ Thermodynamic data of this mixture. """ return self._Thermo.Thermo ################################ @property def EoS(self) -> EquationOfState: """ The equation of state of this mixture. Returns: EquationOfState """ return self._EoS.EoS ######################################################################### #Constructor: def __init__(self, mixture: Mixture, thermoType: dict[str,str], **thermoData): """ Construct new instance of thermodynamic model of mixture from the mixture composition and mixingRule Args: mixture (Mixture): The composition of the mixture. thermoType (dict[str,str]): The types of thermodynamic models. Required are: - Thermo - EquationOfState **thermoData: Additional data for the thermodynamic models. """ self.checkType(mixture, Mixture, "mixture") self.checkMap(thermoType, str, str, "thermoType") #Copy the mixture self._mix = mixture.copy() #Lookup the Thermo and EoS types thermoType = Dictionary(**thermoType) ThermoType = thermoType.lookup("Thermo") EoSType = thermoType.lookup("EquationOfState") #Set the Thermo and EoS thermoData:Dictionary = Dictionary(thermoData) self._Thermo = mixingRules.ThermoMixing.selector(ThermoType + "Mixing", thermoData.lookupOrDefault(ThermoType + "Dict", Dictionary()).update(mixture=self._mix)) self._EoS = mixingRules.EquationOfStateMixing.selector(EoSType + "Mixing", thermoData.lookupOrDefault(EoSType + "Dict", Dictionary()).update(mixture=self._mix)) self._Thermo._mix = self._mix #Set the reference to the mixture self._EoS._mix = self._mix #Set the reference to the mixture ######################################################################### #Operators:
[docs] def __repr__(self) -> str: """Dict-like representation with thermodynamic model classes and mixture""" out = \ { "EoS":self.EoS.__class__.__name__, "Thermo":self.Thermo.__class__.__name__, "mixture":self.mix } return ThermoMixture.__name__ + repr(out)
####################################
[docs] def __str__(self) -> str: """Printing the type of thermodynamic models and the mixture""" str = f"Equation of state: {self.EoS.__class__.__name__}\n" + \ f"Thermo model: {self.Thermo.__class__.__name__}\n" + \ f"Mixture:\n{self.mix.__str__()}" return str
######################################################################### #Member functions: #NOTE: the derivatives of thermodynamic quantities (p,T,rho) # are defined only in the equation of state, as they are not # affected by the specific thermo. Similarly, hf is only in # thermo.
[docs] def update(self, mixture:Mixture=None) -> ThermoMixture: """ Update the mixture composition Args: mixture (Mixture, optional): The new mixture. Defaults to None. Returns: ThermoMixture: self """ if not mixture is None: self._mix.update(mixture.species, mixture.Y, fracType="mass") #Update mixture self._Thermo.update(self.mix) #Update Thermo (even if it has same reference, better to update) self._EoS.update(self.mix) #Update EoS (even if it has same reference, better to update) return self
################################
[docs] def dcpdT(self, p:float, T:float) -> float: """ dcp/dT [J/kg/K^2] """ return self.Thermo.dcpdT(p, T) + self.EoS.dcpdT(p, T)
################################
[docs] def ha(self, p:float, T:float) -> float: """ Absolute enthalpy [J/kg] """ try: return self.Thermo.ha(p, T) + self.EoS.h(p, T) except NotImplementedError: #Internal energy-based Thermo return self.Thermo.ua(p, T) + p/self.EoS.rho(p, T) + self.EoS.h(p, T)
################################
[docs] def hs(self, p:float, T:float) -> float: """ Sensible enthalpy [J/kg] """ try: return self.Thermo.hs(p, T) + self.EoS.h(p, T) except NotImplementedError: #Internal energy-based Thermo return self.Thermo.us(p, T) + p/self.EoS.rho(p, T) + self.EoS.h(p, T)
################################
[docs] def ua(self, p:float, T:float) -> float: """ Absolute internal energy [J/kg] """ try: return self.Thermo.ua(p, T) + self.EoS.u(p, T) except NotImplementedError: #Entalpy-based Thermo return self.Thermo.ha(p, T) - p/self.EoS.rho(p, T) + self.EoS.u(p, T)
################################
[docs] def us(self, p:float, T:float) -> float: """ Sensible internal energy [J/kg] """ try: return self.Thermo.us(p, T) + self.EoS.u(p, T) except NotImplementedError: #Entalpy-based Thermo return self.Thermo.hs(p, T) - p/self.EoS.rho(p, T) + self.EoS.u(p, T)
################################
[docs] def cp(self, p:float, T:float) -> float: """ Constant pressure heat capacity [J/kg/K] """ return self.Thermo.cp(p, T) + self.EoS.cp(p, T)
################################
[docs] def cv(self, p:float, T:float) -> float: """ Constant volume heat capacity [J/kg/K] """ return self.cp(p, T) - self.EoS.cpMcv(p, T)
################################
[docs] def gamma(self, p:float, T:float) -> float: """ Heat capacity ratio cp/cv [-] """ return self.cp(p, T)/self.cv(p, T)