Source code for mirgecom.eos

"""
:mod:`mirgecom.eos` provides implementations of gas equations of state.

Equations of State
^^^^^^^^^^^^^^^^^^
This module is designed provide Equation of State objects used to compute and
manage the relationships between and among state and thermodynamic variables.

.. autoclass:: GasDependentVars
.. autoclass:: MixtureDependentVars
.. autoclass:: GasEOS
.. autoclass:: MixtureEOS
.. autoclass:: IdealSingleGas
.. autoclass:: PyrometheusMixture

Exceptions
^^^^^^^^^^
.. autoexception:: TemperatureSeedMissingError
.. autoexception:: MixtureEOSNeededError
"""

__copyright__ = """
Copyright (C) 2021 University of Illinois Board of Trustees
"""

__license__ = """
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from typing import Union, Optional
from dataclasses import dataclass
from abc import ABCMeta, abstractmethod
from arraycontext import dataclass_array_container
import numpy as np
from meshmode.dof_array import DOFArray
from mirgecom.fluid import ConservedVars, make_conserved


[docs] class TemperatureSeedMissingError(Exception): """Indicate that EOS is inappropriately called without seeding temperature.""" pass
[docs] class MixtureEOSNeededError(Exception): """Indicate that a mixture EOS is required for model evaluation.""" pass
[docs] @dataclass_array_container @dataclass(frozen=True, eq=False) class GasDependentVars: """State-dependent quantities for :class:`GasEOS`. Prefer individual methods for model use, use this structure for visualization or probing. .. attribute:: temperature .. attribute:: pressure .. attribute:: speed_of_sound .. attribute:: smoothness_mu .. attribute:: smoothness_kappa .. attribute:: smoothness_beta .. attribute:: smoothness_d """ temperature: DOFArray pressure: DOFArray speed_of_sound: DOFArray smoothness_mu: DOFArray smoothness_kappa: DOFArray smoothness_d: DOFArray smoothness_beta: DOFArray
[docs] @dataclass_array_container @dataclass(frozen=True, eq=False) class MixtureDependentVars(GasDependentVars): """Mixture state-dependent quantities for :class:`MixtureEOS`. ..attribute:: species_enthalpies """ species_enthalpies: DOFArray
[docs] class GasEOS(metaclass=ABCMeta): r"""Abstract interface to equation of state class. Equation of state (EOS) classes are responsible for computing relations between fluid or gas state variables. Each interface call takes an :class:`~mirgecom.fluid.ConservedVars` object array representing the simulation state quantities. Each EOS class implementation should document its own state data requirements. .. automethod:: pressure .. automethod:: temperature .. automethod:: sound_speed .. automethod:: internal_energy .. automethod:: gas_const .. automethod:: dependent_vars .. automethod:: total_energy .. automethod:: kinetic_energy .. automethod:: gamma .. automethod:: get_internal_energy .. automethod:: get_density """
[docs] @abstractmethod def pressure(self, cv: ConservedVars, temperature: DOFArray): """Get the gas pressure."""
[docs] @abstractmethod def temperature(self, cv: ConservedVars, temperature_seed: Optional[DOFArray] = None) -> DOFArray: """Get the gas temperature."""
[docs] @abstractmethod def sound_speed(self, cv: ConservedVars, temperature: DOFArray): """Get the gas sound speed."""
[docs] @abstractmethod def gas_const(self, cv: Optional[ConservedVars] = None, temperature: Optional[DOFArray] = None, species_mass_fractions: Optional[np.ndarray] = None) -> DOFArray: r"""Get the specific gas constant ($R_s$)."""
@abstractmethod def heat_capacity_cp(self, cv: ConservedVars, temperature: DOFArray): r"""Get the specific heat capacity at constant pressure ($C_p$).""" @abstractmethod def heat_capacity_cv(self, cv: ConservedVars, temperature: DOFArray): r"""Get the specific heat capacity at constant volume ($C_v$)."""
[docs] @abstractmethod def internal_energy(self, cv: ConservedVars): """Get the thermal energy of the gas."""
[docs] @abstractmethod def total_energy(self, cv: ConservedVars, pressure: DOFArray, temperature: DOFArray): """Get the total (thermal + kinetic) energy for the gas."""
[docs] @abstractmethod def kinetic_energy(self, cv: ConservedVars): """Get the kinetic energy for the gas."""
[docs] @abstractmethod def gamma(self, cv: Optional[ConservedVars] = None, temperature: Optional[DOFArray] = None): """Get the ratio of gas specific heats Cp/Cv."""
[docs] @abstractmethod def get_density(self, pressure, temperature, species_mass_fractions: Optional[DOFArray] = None): """Get the density from pressure, and temperature."""
[docs] @abstractmethod def get_internal_energy(self, temperature: DOFArray, species_mass_fractions: Optional[np.ndarray] = None) -> DOFArray: """Get the fluid internal energy from temperature."""
[docs] def dependent_vars( self, cv: ConservedVars, temperature_seed: Optional[DOFArray] = None, smoothness_mu: Optional[DOFArray] = None, smoothness_kappa: Optional[DOFArray] = None, smoothness_d: Optional[DOFArray] = None, smoothness_beta: Optional[DOFArray] = None) -> GasDependentVars: """Get an agglomerated array of the dependent variables. Certain implementations of :class:`GasEOS` (e.g. :class:`MixtureEOS`) may raise :exc:`TemperatureSeedMissingError` if *temperature_seed* is not given. """ temperature = self.temperature(cv, temperature_seed) # MJA, it doesn't appear that we can have a None field embedded inside DV, # make a dummy smoothness in this case zeros = cv.array_context.np.zeros_like(cv.mass) if smoothness_mu is None: smoothness_mu = zeros if smoothness_kappa is None: smoothness_kappa = zeros if smoothness_d is None: smoothness_d = zeros if smoothness_beta is None: smoothness_beta = zeros return GasDependentVars( temperature=temperature, pressure=self.pressure(cv, temperature), speed_of_sound=self.sound_speed(cv, temperature), smoothness_mu=smoothness_mu, smoothness_kappa=smoothness_kappa, smoothness_d=smoothness_d, smoothness_beta=smoothness_beta )
[docs] class MixtureEOS(GasEOS): r"""Abstract interface to gas mixture equation of state class. This EOS base class extends the GasEOS base class to include the necessary interface for dealing with gas mixtures. .. automethod:: get_density .. automethod:: get_species_molecular_weights .. automethod:: get_production_rates .. automethod:: species_enthalpies .. automethod:: get_species_source_terms .. automethod:: get_temperature_seed """
[docs] @abstractmethod def get_temperature_seed( self, cv: ConservedVars, temperature_seed: Optional[Union[float, DOFArray]] = None) -> DOFArray: r"""Get a constant and uniform guess for the gas temperature. This function returns an appropriately sized `DOFArray` for the temperature field that will be used as a starting point for the solve to find the actual temperature field of the gas. """
[docs] @abstractmethod def get_density(self, pressure: DOFArray, # type: ignore[override] temperature: DOFArray, species_mass_fractions: np.ndarray): """Get the density from pressure, temperature, and species fractions (Y)."""
[docs] @abstractmethod def get_species_molecular_weights(self): """Get the species molecular weights."""
[docs] @abstractmethod def species_enthalpies(self, cv: ConservedVars, temperature: DOFArray): """Get the species specific enthalpies."""
[docs] @abstractmethod def get_production_rates(self, cv: ConservedVars, temperature: DOFArray): """Get the production rate for each species."""
[docs] @abstractmethod def get_species_source_terms(self, cv: ConservedVars, temperature: DOFArray): r"""Get the species mass source terms to be used on the RHS for chemistry."""
def dependent_vars( self, cv: ConservedVars, temperature_seed: Optional[DOFArray] = None, smoothness_mu: Optional[DOFArray] = None, smoothness_kappa: Optional[DOFArray] = None, smoothness_d: Optional[DOFArray] = None, smoothness_beta: Optional[DOFArray] = None) -> MixtureDependentVars: """Get an agglomerated array of the dependent variables. Certain implementations of :class:`GasEOS` (e.g. :class:`MixtureEOS`) may raise :exc:`TemperatureSeedMissingError` if *temperature_seed* is not given. """ temperature = self.temperature(cv, temperature_seed) # MJA, it doesn't appear that we can have a None field embedded inside DV, # make a dummy smoothness in this case zeros = cv.array_context.np.zeros_like(cv.mass) if smoothness_mu is None: smoothness_mu = zeros if smoothness_kappa is None: smoothness_kappa = zeros if smoothness_d is None: smoothness_d = zeros if smoothness_beta is None: smoothness_beta = zeros return MixtureDependentVars( temperature=temperature, pressure=self.pressure(cv, temperature), speed_of_sound=self.sound_speed(cv, temperature), species_enthalpies=self.species_enthalpies(cv, temperature), smoothness_mu=smoothness_mu, smoothness_kappa=smoothness_kappa, smoothness_d=smoothness_d, smoothness_beta=smoothness_beta )
[docs] class IdealSingleGas(GasEOS): r"""Ideal gas law single-component gas ($p = \rho{R}{T}$). The specific gas constant, R, defaults to the air-like 287.1 J/(kg*K), but can be set according to simulation units and materials. Each interface call expects that the :class:`~mirgecom.fluid.ConservedVars` object representing the simulation conserved quantities contains at least the canonical conserved quantities mass ($\rho$), energy ($\rho{E}$), and momentum ($\rho\vec{V}$). .. automethod:: __init__ .. automethod:: gamma .. automethod:: heat_capacity_cp .. automethod:: heat_capacity_cv .. automethod:: gas_const .. automethod:: get_density .. automethod:: kinetic_energy .. automethod:: internal_energy .. automethod:: pressure .. automethod:: sound_speed .. automethod:: temperature .. automethod:: total_energy .. automethod:: get_internal_energy .. automethod:: dependent_vars """
[docs] def __init__(self, gamma=1.4, gas_const=287.1): """Initialize Ideal Gas EOS parameters.""" self._gamma = gamma self._gas_const = gas_const
[docs] def gamma(self, cv: Optional[ConservedVars] = None, temperature: Optional[DOFArray] = None) -> DOFArray: """Get specific heat ratio Cp/Cv. Parameters ---------- cv: :class:`~mirgecom.fluid.ConservedVars` Unused for this EOS temperature: :class:`~meshmode.dof_array.DOFArray` Unused for this EOS """ return self._gamma
[docs] def heat_capacity_cp(self, cv: Optional[ConservedVars] = None, temperature: Optional[DOFArray] = None) -> DOFArray: r"""Get specific heat capacity at constant pressure ($C_p$). Parameters ---------- cv: :class:`~mirgecom.fluid.ConservedVars` Unused for this EOS temperature: :class:`~meshmode.dof_array.DOFArray` Unused for this EOS """ return self._gas_const * self._gamma / (self._gamma - 1)
[docs] def heat_capacity_cv(self, cv: Optional[ConservedVars] = None, temperature: Optional[DOFArray] = None) -> DOFArray: r"""Get specific heat capacity at constant volume ($C_v$). Parameters ---------- cv: :class:`~mirgecom.fluid.ConservedVars` Unused for this EOS temperature: :class:`~meshmode.dof_array.DOFArray` Unused for this EOS """ return self._gas_const / (self._gamma - 1)
[docs] def gas_const(self, cv: Optional[ConservedVars] = None, temperature: Optional[DOFArray] = None, species_mass_fractions: Optional[np.ndarray] = None) -> DOFArray: """Get specific gas constant R. Parameters ---------- cv: :class:`~mirgecom.fluid.ConservedVars` Unused for this EOS temperature: :class:`~meshmode.dof_array.DOFArray` Unused for this EOS species_mass_fractions: numpy.ndarray Unused for this EOS """ return self._gas_const
[docs] def get_density(self, pressure: DOFArray, temperature: DOFArray, species_mass_fractions: Optional[DOFArray] = None) -> DOFArray: r"""Get gas density from pressure and temperature. The gas density is calculated as: .. math:: \rho = \frac{p}{R_s T} Parameters ---------- species_mass_fractions: numpy.ndarray Unused for this EOS """ return pressure / (self._gas_const * temperature)
[docs] def kinetic_energy(self, cv: ConservedVars) -> DOFArray: r"""Get kinetic energy of gas. The kinetic energy is calculated as: .. math:: k = \frac{1}{2\rho}(\rho\vec{V} \cdot \rho\vec{V}) """ mom = cv.momentum return (0.5 * np.dot(mom, mom) / cv.mass)
[docs] def internal_energy(self, cv: ConservedVars) -> DOFArray: r"""Get internal thermal energy of gas. The internal energy (e) is calculated as: .. math:: e = \rho{E} - \frac{1}{2\rho}(\rho\vec{V} \cdot \rho\vec{V}) """ return (cv.energy - self.kinetic_energy(cv))
[docs] def pressure(self, cv: ConservedVars, temperature: Optional[DOFArray] = None) -> DOFArray: r"""Get thermodynamic pressure of the gas. Gas pressure (p) is calculated from the internal energy (e) as: .. math:: p = (\gamma - 1)e Parameters ---------- temperature: :class:`~meshmode.dof_array.DOFArray` Unused for this EOS """ return self.internal_energy(cv) * (self._gamma - 1.0)
[docs] def sound_speed(self, cv: ConservedVars, temperature: Optional[DOFArray] = None) -> DOFArray: r"""Get the speed of sound in the gas. The speed of sound (c) is calculated as: .. math:: c = \sqrt{\frac{\gamma{p}}{\rho}} Parameters ---------- temperature: :class:`~meshmode.dof_array.DOFArray` Unused for this EOS """ actx = cv.array_context return actx.np.sqrt(self._gamma / cv.mass * self.pressure(cv))
[docs] def temperature(self, cv: ConservedVars, temperature_seed: Optional[DOFArray] = None) -> DOFArray: r"""Get the thermodynamic temperature of the gas. The thermodynamic temperature (T) is calculated from the internal energy (e) and specific gas constant (R) as: .. math:: T = \frac{(\gamma - 1)e}{R\rho} Parameters ---------- temperature_seed: float or :class:`~meshmode.dof_array.DOFArray` Unused for this EOS. """ return ( (((self._gamma - 1.0) / self._gas_const) * self.internal_energy(cv) / cv.mass) )
[docs] def total_energy(self, cv: ConservedVars, pressure: DOFArray, temperature: Optional[DOFArray] = None) -> DOFArray: r""" Get gas total energy from mass, pressure, and momentum. The total energy density (rhoE) is calculated from the mass density (rho) , pressure (p) , and momentum (rhoV) as: .. math:: \rho{E} = \frac{p}{(\gamma - 1)} + \frac{1}{2}\rho(\vec{v} \cdot \vec{v}) .. note:: The total_energy function computes cv.energy from pressure, mass, and momentum in this case. In general in the EOS we need DV = EOS(CV), and inversions CV = EOS(DV). This is one of those inversion interfaces. Parameters ---------- cv: :class:`~mirgecom.fluid.ConservedVars` The conserved variables pressure: :class:`~meshmode.dof_array.DOFArray` The fluid pressure temperature: :class:`~meshmode.dof_array.DOFArray` Unused for this EOS Returns ------- :class:`~meshmode.dof_array.DOFArray` The total energy of the fluid (i.e. internal + kinetic) """ return (pressure / (self._gamma - 1.0) + self.kinetic_energy(cv))
[docs] def get_internal_energy(self, temperature: DOFArray, species_mass_fractions: Optional[DOFArray] = None) -> DOFArray: r"""Get the gas thermal energy from temperature. The gas internal energy $e$ is calculated from: .. math:: e = \frac{R_s T}{\left(\gamma - 1\right)} Parameters ---------- species_mass_fractions: Unused for this EOS """ return self._gas_const * temperature / (self._gamma - 1)
[docs] class PyrometheusMixture(MixtureEOS): r"""Ideal gas mixture ($p = \rho{R}_\mathtt{mix}{T}$). This is the :mod:`pyrometheus`-based EOS. Please refer to the :any:`documentation of Pyrometheus <pyrometheus>` for underlying implementation details. Each interface call expects that the :class:`mirgecom.fluid.ConservedVars` object representing the simulation conserved quantities contains at least the canonical conserved quantities mass ($\rho$), energy ($\rho{E}$), and momentum ($\rho\vec{V}$), and the vector of species masses, ($\rho{Y}_\alpha$). .. important:: When using this EOS, users should take care to match solution initialization with the appropriate units that are used in the user-provided `Cantera` mechanism input files. .. automethod:: __init__ .. automethod:: pressure .. automethod:: temperature .. automethod:: sound_speed .. automethod:: internal_energy .. automethod:: gas_const .. automethod:: dependent_vars .. automethod:: total_energy .. automethod:: kinetic_energy .. automethod:: heat_capacity_cv .. automethod:: heat_capacity_cp .. automethod:: gamma .. automethod:: get_internal_energy .. automethod:: get_density .. automethod:: get_species_molecular_weights .. automethod:: get_production_rates .. automethod:: species_enthalpies .. automethod:: get_species_source_terms .. automethod:: get_temperature_seed """
[docs] def __init__(self, pyrometheus_mech, temperature_guess=300.0): """Initialize Pyrometheus-based EOS with mechanism class. Parameters ---------- pyrometheus_mech: :class:`~pyrometheus.thermochem_example.Thermochemistry` The :mod:`pyrometheus` mechanism :class:`~pyrometheus.thermochem_example.Thermochemistry` object that is generated by the user with a call to *pyrometheus.get_thermochem_class*. To create the mechanism object, users need to provide a mechanism input file. Several example mechanisms are provided in `mirgecom/mechanisms/` and can be used through the :meth:`mirgecom.mechanisms.get_mechanism_input`. tguess: float This provides a constant starting temperature for the Newton iterations used to find the mixture temperature. It defaults to 300.0 Kelvin. This parameter is important for the performance and proper function of the code. Users should set a tguess that is close to the average temperature of the simulated domain. """ self._pyrometheus_mech = pyrometheus_mech self._tguess = temperature_guess
[docs] def get_temperature_seed(self, cv: ConservedVars, temperature_seed: Optional[DOFArray] = None) -> DOFArray: """Get a *cv*-shaped array with which to seed temperature calcuation. Parameters ---------- cv: :class:`~mirgecom.fluid.ConservedVars` :class:`~mirgecom.fluid.ConservedVars` used to conjure the required shape for the returned temperature guess. temperature_seed: float or :class:`~meshmode.dof_array.DOFArray` Optional data from which to seed temperature calculation. Returns ------- :class:`~meshmode.dof_array.DOFArray` The temperature with which to seed the Newton solver in :module:thermochemistry. """ tseed = self._tguess if temperature_seed is not None: tseed = temperature_seed return tseed if isinstance(tseed, DOFArray) else tseed * (0*cv.mass + 1.0)
[docs] def heat_capacity_cp(self, cv: ConservedVars, temperature: DOFArray) -> DOFArray: r"""Get mixture-averaged specific heat capacity at constant pressure.""" y = cv.species_mass_fractions return \ self._pyrometheus_mech.get_mixture_specific_heat_cp_mass(temperature, y)
[docs] def heat_capacity_cv(self, cv: ConservedVars, temperature: DOFArray) -> DOFArray: r"""Get mixture-averaged specific heat capacity at constant volume.""" y = cv.species_mass_fractions cp = self._pyrometheus_mech.get_mixture_specific_heat_cp_mass(temperature, y) rspec = self.gas_const(species_mass_fractions=y) return cp - rspec
[docs] def gamma(self, cv: ConservedVars, # type: ignore[override] temperature: DOFArray) -> DOFArray: r"""Get mixture-averaged heat capacity ratio, $\frac{C_p}{C_p - R_s}$.""" y = cv.species_mass_fractions cp = self._pyrometheus_mech.get_mixture_specific_heat_cp_mass(temperature, y) rspec = self.gas_const(species_mass_fractions=y) return cp / (cp - rspec)
[docs] def gas_const(self, cv: Optional[ConservedVars] = None, temperature: Optional[DOFArray] = None, species_mass_fractions: Optional[np.ndarray] = None) -> DOFArray: r"""Get specific gas constant $R_s$. The mixture specific gas constant is calculated as .. math:: R_s = \frac{R}{\sum{\frac{{Y}_\alpha}{{M}_\alpha}}} by the :mod:`pyrometheus` mechanism provided by the user. In this equation, ${M}_\alpha$ are the species molar masses and R is the universal gas constant. """ if cv is not None: from warnings import warn warn("Passing CV to eos.gas_const will be deprecated in Q1 2024.", stacklevel=2) y = species_mass_fractions if cv is None else cv.species_mass_fractions return self._pyrometheus_mech.get_specific_gas_constant(y)
[docs] def kinetic_energy(self, cv: ConservedVars) -> DOFArray: r"""Get kinetic (i.e. not internal) energy of gas. The kinetic energy is calculated as: .. math:: k = \frac{1}{2\rho}(\rho\vec{V} \cdot \rho\vec{V}) """ mom = cv.momentum return (0.5 * np.dot(mom, mom) / cv.mass)
[docs] def internal_energy(self, cv: ConservedVars) -> DOFArray: r"""Get internal thermal energy of gas. The internal energy ($e$) is calculated as: .. math:: e = \rho{E} - \frac{1}{2\rho}(\rho\vec{V} \cdot \rho\vec{V}) """ return (cv.energy - self.kinetic_energy(cv))
[docs] def get_density(self, pressure: DOFArray, # type: ignore[override] temperature: DOFArray, species_mass_fractions: np.ndarray) -> DOFArray: r"""Get the density from pressure, temperature, and species fractions (Y).""" return self._pyrometheus_mech.get_density(pressure, temperature, species_mass_fractions)
[docs] def get_internal_energy(self, temperature: DOFArray, # type: ignore[override] species_mass_fractions: np.ndarray) -> DOFArray: r"""Get the gas thermal energy from temperature, and species fractions (Y). The gas internal energy $e$ is calculated from: .. math:: e = R_s T \sum{Y_\alpha e_\alpha} """ return self._pyrometheus_mech.get_mixture_internal_energy_mass( temperature, species_mass_fractions)
def get_enthalpy(self, temperature: DOFArray, species_mass_fractions: np.ndarray) -> DOFArray: r"""Get the gas enthalpy from temperature, and species fractions (Y). The enthalpy of the gas mixture $h$ is calculated from: .. math:: h = \sum{Y_\alpha h_\alpha} """ return self._pyrometheus_mech.get_mixture_enthalpy_mass( temperature, species_mass_fractions)
[docs] def get_species_molecular_weights(self): """Get the species molecular weights.""" return self._pyrometheus_mech.wts
# return self._pyrometheus_mech.molecular_weights
[docs] def species_enthalpies(self, cv: ConservedVars, temperature: DOFArray) -> DOFArray: """Get the species specific enthalpies.""" spec_r = self._pyrometheus_mech.gas_constant/self._pyrometheus_mech.wts # spec_r = (self._pyrometheus_mech.gas_constant # / self._pyrometheus_mech.molecular_weights) return (spec_r * temperature * self._pyrometheus_mech.get_species_enthalpies_rt(temperature))
[docs] def get_production_rates(self, cv: ConservedVars, temperature: DOFArray) -> np.ndarray: r"""Get the chemical production rates for each species.""" y = cv.species_mass_fractions return self._pyrometheus_mech.get_net_production_rates( cv.mass, temperature, y)
[docs] def pressure(self, cv: ConservedVars, temperature: DOFArray) -> DOFArray: r"""Get thermodynamic pressure of the gas. Gas pressure ($p$) is calculated using ideal gas law: .. math:: p = \rho R_{mix} T """ y = cv.species_mass_fractions return self._pyrometheus_mech.get_pressure(cv.mass, temperature, y)
[docs] def sound_speed(self, cv: ConservedVars, temperature: DOFArray) -> DOFArray: r"""Get the speed of sound in the gas. The speed of sound ($c$) is calculated as: .. math:: c = \sqrt{\frac{\gamma_{\mathtt{mix}}{p}}{\rho}} """ actx = cv.array_context return actx.np.sqrt((self.gamma(cv, temperature) * self.pressure(cv, temperature)) / cv.mass)
[docs] def temperature(self, cv: ConservedVars, temperature_seed: Optional[DOFArray] = None) -> DOFArray: r"""Get the thermodynamic temperature of the gas. The thermodynamic temperature ($T$) is calculated iteratively with Newton-Raphson method from the mixture internal energy ($e$) as: .. math:: e(T) = \sum_i e_i(T) Y_i Parameters ---------- temperature_seed: float or :class:`~meshmode.dof_array.DOFArray` Data from which to seed temperature calculation. """ # For mixtures, the temperature calculation *must* be seeded. This # check catches any actual temperature calculation that did not # provide a seed. if temperature_seed is None: raise TemperatureSeedMissingError("MixtureEOS.get_temperature" "requires a *temperature_seed*.") tseed = self.get_temperature_seed(cv, temperature_seed) y = cv.species_mass_fractions e = self.internal_energy(cv) / cv.mass return self._pyrometheus_mech.get_temperature(e, tseed, y)
[docs] def total_energy(self, cv: ConservedVars, pressure: DOFArray, temperature: DOFArray) -> DOFArray: r""" Get gas total energy from mass, pressure, and momentum. The total energy density ($\rho E$) is calculated from the mass density ($\rho$) , pressure ($p$) , and momentum ($\rho\vec{V}$) as: .. math:: \rho E = \frac{p}{(\gamma_{\mathtt{mix}} - 1)} + \frac{1}{2}\rho(\vec{v} \cdot \vec{v}) .. note:: The total_energy function computes cv.energy from pressure, mass, and momentum in this case. In general in the EOS we need DV = EOS(CV), and inversions CV = EOS(DV). This is one of those inversion interfaces. """ y = cv.species_mass_fractions return (cv.mass * self.get_internal_energy(temperature, y) + self.kinetic_energy(cv))
[docs] def get_species_source_terms(self, cv: ConservedVars, temperature: DOFArray): r"""Get the species mass source terms to be used on the RHS for chemistry. Returns ------- :class:`~mirgecom.fluid.ConservedVars` Chemistry source terms """ omega = self.get_production_rates(cv, temperature) w = self.get_species_molecular_weights() dim = cv.dim species_sources = w * omega rho_source = 0 * cv.mass mom_source = 0 * cv.momentum energy_source = 0 * cv.energy return make_conserved(dim, rho_source, energy_source, mom_source, species_sources)