Source code for libICEpost.src.thermophysicalModels.specie.reactions.ReactionModel.Equilibrium

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

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

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

import numpy as np
from typing import Iterable, Literal
import cantera as ct

from enum import Enum

from libICEpost.src.base.dataStructures.Dictionary import Dictionary
from .ReactionModel import ReactionModel
from libICEpost.src.thermophysicalModels.specie.specie.Mixture import Mixture

from libICEpost.src.thermophysicalModels.thermoModels.ThermoState import ThermoState

from libICEpost.src.base.Functions.runtimeWarning import runtimeWarning

from libICEpost.Database import database

#############################################################################
[docs] class _equilibriumComputationMethods(Enum): average = "average" burntGas = "burntGas" adiabatiFlame = "adiabaticFlame"
############################################################################# # MAIN CLASSES # #############################################################################
[docs] class Equilibrium(ReactionModel): """ Reaction model based on computation of chemical equilibrium which CANTERA. Attributes: oxidiser (Molecule): The oxidiser reactants (Mixture):The mixture of the reactants products (Mixture): The mixture of products of the reaction specie (list[Molecule]): The molecules to consider in the equilibrium mechanism (str): The path where the mechanism in yaml is stored """ _ReactionType:str = None """The type for reactions to lookup for in the database""" _reactor:ct.Solution """The ractor used to compute equilibrium in CANTERA""" _mechamism:str """The path of the mechanism""" #########################################################################
[docs] @classmethod def fromDictionary(cls, dictionary:dict): """ Constructs from dictionary Args: dictionary (dict): The dictionary from which constructing: reactants (Mixture): the mixture of reactants mechanism (str): The path where is stored the chemical mechanism to use (yaml) """ cls.checkType(dictionary, dict, "dictionary") dictionary = Dictionary(**dictionary) out = cls( reactants=dictionary.lookup("reactants", varType=Mixture), mechanism=dictionary.lookup("mechanism", varType=str), method=dictionary.lookup("method", varType=str), state=(dictionary.lookupOrDefault("state", default=ThermoState())) ) return out
######################################################################### #Properties: @property def mechanism(self) -> str: """ The path where the mechanism is stored. """ return self._mechanism @property def method(self): """ The method used to compute the equilibrium. """ return self._method.value ######################################################################### #Constructor: def __init__(self, reactants:Mixture, mechanism:str, *, method:Literal["average","adiabatiFlame","burntGas"], state:ThermoState): """ Constuct from the reactants and the chemical mechanism to use for computation of equilibrium with cantera. Args: reactants (Mixture): the mixture of reactants mechanism (str): The path where is stored the chemical mechanism to use (yaml) method (Literal["average","adiabatiFlame","burntGas"]): Which method to use to compute the equilibrium: average: Use the average in-cylinder temperature T (equilibrate(TP)) adiabaticFlame: Compute the equilibrium at adiabatic flame temperature (equilibrate(HP) at Tu) burntGas: Compute the equilibrium at burnt gas temperature (equilibrate(TP) at Tb) state (ThermoState): Thermodynamic state to update the reaction model. """ self.checkType(mechanism, str, "mechanism") self._mechanism = mechanism self._method = _equilibriumComputationMethods(method) #Construct the reactor self._reactor = ct.Solution(self.mechanism) super().__init__(reactants, state=state) ######################################################################### #Operators: ######################################################################### #Methods:
[docs] def _update(self, reactants:Mixture=None, *, state:ThermoState) -> bool: """ Method to update the products. Args: reactants (Mixture, optional): Update mixture of reactants. Defaults to None. state (ThermoState): Thermodynamic state to update the reaction model. Returns: bool: wether the system was updated """ #Update reactants and state, return False if nothing changed: if not super()._update(reactants, state=state): return False for s in self.reactants: if not s.specie.name in self._reactor.species_names: raise ValueError( f"Cannot compute chemical equilibrium: " + f"specie {s.specie.name} not found in mechanism. " + f"Avaliable species are:\n\t" + "\n\t".join(self._reactor.species_names) ) #Update composition Y = np.zeros((len(self._reactor.species_names), 1)) for s in self.reactants: Y[self._reactor.species_index(s.specie.name)] = s.Y self._reactor.Y = Y #Update thermo props if self._method == _equilibriumComputationMethods.adiabatiFlame: T, P = self._state["Tu"], self._state["p"] elif self._method == _equilibriumComputationMethods.burntGas: T, P = self._state["Tb"], self._state["p"] elif self._method == _equilibriumComputationMethods.average: T, P = self._state["T"], self._state["p"] if np.isnan(T): runtimeWarning("Equilibrium: found nan temperature. Setting to 300K.", stack=False) T = 300. if np.isnan(P): runtimeWarning("Equilibrium: found nan pressure. Setting to 1bar.", stack=False) P = 300. self._reactor.TP = T, P if self._method == _equilibriumComputationMethods.adiabatiFlame: self._reactor.equilibrate("HP") else: self._reactor.equilibrate("TP") #Update products mols = [database.chemistry.specie.Molecules[mol] for mol in self._reactor.species_names] Y = self._reactor.Y self._products.update(mols, Y, fracType="mass") #Updated return True
######################################################################### #Add to selection table ReactionModel.addToRuntimeSelectionTable(Equilibrium)