Source code for mirgecom.transport

r"""
:mod:`mirgecom.transport` provides methods/utils for transport properties.

Transport Models
^^^^^^^^^^^^^^^^
This module is designed provide Transport Model objects used to compute and
manage the transport properties in viscous flows.  The transport properties
currently implemented are the dynamic viscosity ($\mu$), the bulk viscosity
($\mu_{B}$), the thermal conductivity ($\kappa$), and the species diffusivities
($d_{\alpha}$).

.. autoclass:: GasTransportVars
.. autoclass:: TransportModel
.. autoclass:: SimpleTransport
.. autoclass:: PowerLawTransport
.. autoclass:: MixtureAveragedTransport
.. autoclass:: ArtificialViscosityTransportDiv
.. autoclass:: ArtificialViscosityTransportDiv2
.. autoclass:: ArtificialViscosityTransportDiv3

Exceptions
^^^^^^^^^^
.. autoexception:: TransportModelError
"""

__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 Optional
from dataclasses import dataclass
from arraycontext import dataclass_array_container
import numpy as np
from meshmode.mesh import BTAG_ALL, BTAG_NONE  # noqa
from meshmode.dof_array import DOFArray
from mirgecom.fluid import ConservedVars
from mirgecom.eos import GasEOS, GasDependentVars


[docs] class TransportModelError(Exception): """Indicate that transport model is required for model evaluation.""" pass
[docs] @dataclass_array_container @dataclass(frozen=True, eq=False) class GasTransportVars: """State-dependent quantities for :class:`TransportModel`. Prefer individual methods for model use, use this structure for visualization or probing. .. attribute:: bulk_viscosity .. attribute:: viscosity .. attribute:: thermal_conductivity .. attribute:: species_diffusivity """ bulk_viscosity: np.ndarray viscosity: np.ndarray thermal_conductivity: np.ndarray species_diffusivity: np.ndarray
[docs] class TransportModel: r"""Abstract interface to thermo-diffusive transport model class. Transport model classes are responsible for computing relations between fluid or gas state variables and thermo-diffusive transport properties for those fluids. .. automethod:: bulk_viscosity .. automethod:: viscosity .. automethod:: thermal_conductivity .. automethod:: species_diffusivity .. automethod:: volume_viscosity .. automethod:: transport_vars """
[docs] def bulk_viscosity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the bulk viscosity for the gas (${\mu}_{B}$).""" raise NotImplementedError()
[docs] def viscosity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the gas dynamic viscosity, $\mu$.""" raise NotImplementedError()
[docs] def volume_viscosity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the 2nd coefficent of viscosity, $\lambda$.""" raise NotImplementedError()
[docs] def thermal_conductivity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the gas thermal_conductivity, $\kappa$.""" raise NotImplementedError()
[docs] def species_diffusivity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the vector of species diffusivities, ${d}_{\alpha}$.""" raise NotImplementedError()
[docs] def transport_vars(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> GasTransportVars: r"""Compute the transport properties from the conserved state.""" return GasTransportVars( bulk_viscosity=self.bulk_viscosity(cv=cv, dv=dv, eos=eos), viscosity=self.viscosity(cv=cv, dv=dv, eos=eos), thermal_conductivity=self.thermal_conductivity(cv=cv, dv=dv, eos=eos), species_diffusivity=self.species_diffusivity(cv=cv, dv=dv, eos=eos) )
[docs] class SimpleTransport(TransportModel): r"""Transport model with uniform, constant properties. Inherits from (and implements) :class:`TransportModel`. .. automethod:: __init__ .. automethod:: bulk_viscosity .. automethod:: viscosity .. automethod:: volume_viscosity .. automethod:: thermal_conductivity .. automethod:: species_diffusivity """
[docs] def __init__(self, bulk_viscosity=0, viscosity=0, thermal_conductivity=0, species_diffusivity=None): """Initialize uniform, constant transport properties.""" if species_diffusivity is None: species_diffusivity = np.empty((0,), dtype=object) self._mu_bulk = bulk_viscosity self._mu = viscosity self._kappa = thermal_conductivity self._d_alpha = species_diffusivity
[docs] def bulk_viscosity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the bulk viscosity for the gas, $\mu_{B}$.""" return self._mu_bulk*(0*cv.mass + 1.0)
[docs] def viscosity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the gas dynamic viscosity, $\mu$.""" return self._mu*(0*cv.mass + 1.0)
[docs] def volume_viscosity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the 2nd viscosity coefficent, $\lambda$. In this transport model, the second coefficient of viscosity is defined as: .. math:: \lambda = \left(\mu_{B} - \frac{2\mu}{3}\right) """ return (self._mu_bulk - 2 * self._mu / 3)*(0*cv.mass + 1.0)
[docs] def thermal_conductivity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the gas thermal_conductivity, $\kappa$.""" return self._kappa*(0*cv.mass + 1.0)
[docs] def species_diffusivity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the vector of species diffusivities, ${d}_{\alpha}$.""" return self._d_alpha*(0*cv.mass + 1.0)
[docs] class PowerLawTransport(TransportModel): r"""Transport model with simple power law properties. Inherits from (and implements) :class:`TransportModel` based on a temperature-dependent power law. .. automethod:: __init__ .. automethod:: bulk_viscosity .. automethod:: viscosity .. automethod:: volume_viscosity .. automethod:: thermal_conductivity .. automethod:: species_diffusivity """ # air-like defaults here
[docs] def __init__(self, alpha=0.6, beta=4.093e-7, sigma=2.5, n=.666, species_diffusivity=None, lewis=None): """Initialize power law coefficients and parameters. Parameters ---------- alpha: float The bulk viscosity parameter. The default value is "air". beta: float The dynamic viscosity linear parameter. The default value is "air". n: float The temperature exponent for dynamic viscosity. The default value is "air". sigma: float The heat conductivity linear parameter. The default value is "air". lewis: numpy.ndarray If required, the Lewis number specify the relation between the thermal conductivity and the species diffusivities. The input array must have a shape of "nspecies". """ if species_diffusivity is None and lewis is None: species_diffusivity = np.empty((0,), dtype=object) self._alpha = alpha self._beta = beta self._sigma = sigma self._n = n self._d_alpha = species_diffusivity self._lewis = lewis
[docs] def bulk_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the bulk viscosity for the gas, $\mu_{B}$. .. math:: \mu_{B} = \alpha\mu """ return self._alpha * self.viscosity(cv, dv)
# TODO: Should this be memoized? Avoid multiple calls?
[docs] def viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the gas dynamic viscosity, $\mu$. $\mu = \beta{T}^n$ """ return self._beta * dv.temperature**self._n
[docs] def volume_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the 2nd viscosity coefficent, $\lambda$. In this transport model, the second coefficient of viscosity is defined as: .. math:: \lambda = \left(\alpha - \frac{2}{3}\right)\mu """ return (self._alpha - 2.0/3.0) * self.viscosity(cv, dv)
[docs] def thermal_conductivity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the gas thermal conductivity, $\kappa$. .. math:: \kappa = \sigma\mu{C}_{v} """ return ( self._sigma * self.viscosity(cv, dv) * eos.heat_capacity_cv(cv, dv.temperature) )
[docs] def species_diffusivity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the vector of species diffusivities, ${d}_{\alpha}$. The species diffusivities can be either (1) specified directly or (2) using user-imposed Lewis number $Le$ w/shape "nspecies" In the latter, it is then evaluate based on the heat capacity at constant pressure $C_p$ and the thermal conductivity $\kappa$ as: .. math:: d_{\alpha} = \frac{\kappa}{\rho \; Le \; C_p} """ if self._lewis is not None: return (self._sigma * self.viscosity(cv, dv)/( cv.mass*self._lewis*eos.gamma(cv, dv.temperature)) ) return self._d_alpha*(0*cv.mass + 1.)
[docs] class MixtureAveragedTransport(TransportModel): r"""Transport model with mixture averaged transport properties. Inherits from (and implements) :class:`TransportModel` based on a temperature-dependent fit from Pyrometheus/Cantera weighted by the mixture composition. The mixture-averaged rules used follow those discussed in chapter 12 from [Kee_2003]_. .. automethod:: __init__ .. automethod:: bulk_viscosity .. automethod:: viscosity .. automethod:: volume_viscosity .. automethod:: thermal_conductivity .. automethod:: species_diffusivity """
[docs] def __init__(self, pyrometheus_mech, alpha=0.6, factor=1.0, lewis=None, epsilon=1e-4, singular_diffusivity=1e-6): r"""Initialize mixture averaged transport coefficients and parameters. 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`. alpha: float The bulk viscosity parameter. The default value is "air". factor: float Scaling factor to artifically scale up or down the transport coefficients. The default is to keep the physical value, i.e., 1.0. lewis: numpy.ndarray If required, the Lewis number specify the relation between the thermal conductivity and the species diffusivities. The input array must have a shape of "nspecies". epsilon: float Parameter to avoid single-species case where $Y_i \to 1$ that may lead to singular division in the mixture rule. If $1 - Y_i < \epsilon$, a prescribed diffusivity is used instead. Default to 1e-4. singular_diffusivity: float Diffusivity for the singular case. The actual number should't matter since, in the single-species case, diffusion is proportional to a nearly zero-gradient. Default to 1e-6 for all species. """ self._pyro_mech = pyrometheus_mech self._alpha = alpha self._factor = factor self._lewis = lewis self._epsilon = epsilon self._singular_diffusivity = singular_diffusivity if self._lewis is not None: if (len(self._lewis) != self._pyro_mech.num_species): raise ValueError("Lewis number should match number of species")
[docs] def viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the mixture dynamic viscosity, $\mu^{(m)}$. The viscosity depends on the mixture composition given by $X_k$ mole fraction and pure species viscosity $\mu_k$ of the individual species. The latter depends on the temperature and it is evaluated by Pyrometheus. .. math:: \mu^{(m)} = \sum_{k=1}^{K} \frac{X_k \mu_k}{\sum_{j=1}^{K} X_j\phi_{kj}} .. math:: \phi_{kj} = \frac{1}{\sqrt{8}} \left( 1 + \frac{W_k}{W_j} \right)^{-\frac{1}{2}} \left( 1 + \left[ \frac{\mu_k}{\mu_j} \right]^{\frac{1}{2}} \left[ \frac{W_j}{W_k} \right]^{\frac{1}{4}} \right)^2 """ return ( self._factor*self._pyro_mech.get_mixture_viscosity_mixavg( dv.temperature, cv.species_mass_fractions) )
[docs] def bulk_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the bulk viscosity for the gas, $\mu_{B}$. .. math:: \mu_{B} = \alpha\mu """ return self._alpha*self.viscosity(cv, dv)
[docs] def volume_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the 2nd viscosity coefficent, $\lambda$. In this transport model, the second coefficient of viscosity is defined as: .. math:: \lambda = \left(\alpha - \frac{2}{3}\right)\mu """ return (self._alpha - 2.0/3.0)*self.viscosity(cv, dv)
[docs] def thermal_conductivity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the gas thermal_conductivity, $\kappa$. The thermal conductivity can be obtained from Pyrometheus using a mixture averaged rule considering the species heat conductivities and mole fractions: .. math:: \kappa = \frac{1}{2} \left( \sum_{k=1}^{K} X_k \lambda_k + \frac{1}{\sum_{k=1}^{K} \frac{X_k}{\lambda_k} }\right) """ return self._factor*(self._pyro_mech.get_mixture_thermal_conductivity_mixavg( dv.temperature, cv.species_mass_fractions,))
[docs] def species_diffusivity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the vector of species diffusivities, ${d}_{i}$. The species diffusivities can be obtained directly from Pyrometheus using a mixture averaged rule considering the species binary mass diffusivities $d_{ij}$ and the mass fractions $Y_i$ .. math:: d_{i}^{(m)} = \frac{1 - Y_i}{\sum_{j\ne i} \frac{X_j}{d_{ij}}} In regions with a single species, the above equation is ill-conditioned and a constant diffusivity is used instead. The user can prescribe an array with the Lewis number $Le$ for each species. Then, it is used together with the mixture termal conductivity and the heat capacity at constant pressure $C_p$ to yield the diffusivity. .. math:: d_{i} = \frac{\kappa}{\rho \; Le \; C_p} """ if self._lewis is not None: return (self.thermal_conductivity(cv, dv, eos)/( cv.mass*self._lewis*eos.heat_capacity_cp(cv, dv.temperature)) ) actx = cv.mass.array_context diffusivity = self._pyro_mech.get_species_mass_diffusivities_mixavg( dv.pressure, dv.temperature, cv.species_mass_fractions) for i in range(0, self._pyro_mech.num_species): # where "1-Yi < epsilon" means "Y_i -> 1.0" diffusivity[i] = \ actx.np.where( actx.np.less(1.0 - cv.species_mass_fractions[i], self._epsilon), self._singular_diffusivity, diffusivity[i] ) return self._factor*diffusivity
[docs] class ArtificialViscosityTransportDiv(TransportModel): r"""Transport model for add artificial viscosity. Inherits from (and implements) :class:`TransportModel`. Takes a physical transport model and adds the artificial viscosity contribution to it. Defaults to simple transport with inviscid settings. This is equivalent to inviscid flow with artifical viscosity enabled. .. automethod:: __init__ .. automethod:: bulk_viscosity .. automethod:: viscosity .. automethod:: volume_viscosity .. automethod:: thermal_conductivity .. automethod:: species_diffusivity """
[docs] def __init__(self, av_mu, av_prandtl, physical_transport=None, av_species_diffusivity=None): """Initialize uniform, constant transport properties.""" if physical_transport is None: self._physical_transport = SimpleTransport() else: self._physical_transport = physical_transport if av_species_diffusivity is None: av_species_diffusivity = np.empty((0,), dtype=object) self._av_mu = av_mu self._av_prandtl = av_prandtl
def av_viscosity(self, cv, dv, eos): r"""Get the artificial viscosity for the gas.""" actx = cv.array_context return self._av_mu*actx.np.sqrt(np.dot(cv.velocity, cv.velocity) + dv.speed_of_sound**2)
[docs] def bulk_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the bulk viscosity for the gas, $\mu_{B}$.""" return self._physical_transport.bulk_viscosity(cv, dv)
[docs] def viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the gas dynamic viscosity, $\mu$.""" return (dv.smoothness_mu*self.av_viscosity(cv, dv, eos) + self._physical_transport.viscosity(cv, dv))
[docs] def volume_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the 2nd viscosity coefficent, $\lambda$. In this transport model, the second coefficient of viscosity is defined as: $\lambda = \left(\mu_{B} - \frac{2\mu}{3}\right)$ """ return (dv.smoothness_mu*self.av_viscosity(cv, dv, eos) + self._physical_transport.volume_viscosity(cv, dv))
[docs] def thermal_conductivity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the gas thermal_conductivity, $\kappa$.""" mu = self.av_viscosity(cv, dv, eos) av_kappa = (dv.smoothness_mu*mu * eos.heat_capacity_cp(cv, dv.temperature)/self._av_prandtl) return \ av_kappa + self._physical_transport.thermal_conductivity(cv, dv, eos)
[docs] def species_diffusivity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the vector of species diffusivities, ${d}_{\alpha}$.""" return self._physical_transport.species_diffusivity(cv, dv, eos)
[docs] class ArtificialViscosityTransportDiv2(TransportModel): r"""Transport model for add artificial viscosity. Inherits from (and implements) :class:`TransportModel`. Takes a physical transport model and adds the artificial viscosity contribution to it. Defaults to simple transport with inviscid settings. This is equivalent to inviscid flow with artifical viscosity enabled. .. automethod:: __init__ .. automethod:: bulk_viscosity .. automethod:: viscosity .. automethod:: volume_viscosity .. automethod:: thermal_conductivity .. automethod:: species_diffusivity """
[docs] def __init__(self, av_mu, av_kappa, av_beta, av_prandtl, physical_transport=None, av_species_diffusivity=None): """Initialize uniform, constant transport properties.""" if physical_transport is None: self._physical_transport = SimpleTransport() else: self._physical_transport = physical_transport if av_species_diffusivity is None: av_species_diffusivity = np.empty((0,), dtype=object) self._av_mu = av_mu self._av_beta = av_beta self._av_kappa = av_kappa self._av_prandtl = av_prandtl
def av_mu(self, cv, dv, eos): r"""Get the shear artificial viscosity for the gas.""" actx = cv.array_context return (self._av_mu * cv.mass * actx.np.sqrt(np.dot(cv.velocity, cv.velocity) + dv.speed_of_sound**2)) def av_beta(self, cv, dv, eos): r"""Get the shear artificial viscosity for the gas.""" actx = cv.array_context return (self._av_beta * cv.mass * actx.np.sqrt(np.dot(cv.velocity, cv.velocity) + dv.speed_of_sound**2)) def av_kappa(self, cv, dv, eos): r"""Get the shear artificial viscosity for the gas.""" actx = cv.array_context return (self._av_kappa * cv.mass * actx.np.sqrt(np.dot(cv.velocity, cv.velocity) + dv.speed_of_sound**2))
[docs] def bulk_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the bulk viscosity for the gas, $\mu_{B}$.""" actx = cv.array_context smoothness_beta = actx.np.where( actx.np.greater(dv.smoothness_beta, 0.), dv.smoothness_beta, 0.) return (smoothness_beta*self.av_beta(cv, dv, eos) + self._physical_transport.bulk_viscosity(cv, dv))
[docs] def viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the gas dynamic viscosity, $\mu$.""" actx = cv.array_context smoothness_mu = actx.np.where( actx.np.greater(dv.smoothness_mu, 0.), dv.smoothness_mu, 0.) return (smoothness_mu*self.av_mu(cv, dv, eos) + self._physical_transport.viscosity(cv, dv))
[docs] def volume_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the 2nd viscosity coefficent, $\lambda$. In this transport model, the second coefficient of viscosity is: $\lambda = \left(\mu_{B} - \frac{2\mu}{3}\right)$ """ actx = cv.array_context smoothness_mu = actx.np.where( actx.np.greater(dv.smoothness_mu, 0.), dv.smoothness_mu, 0.) smoothness_beta = actx.np.where( actx.np.greater(dv.smoothness_beta, 0.), dv.smoothness_beta, 0.) return (smoothness_beta*self.av_beta(cv, dv, eos) - 2*smoothness_mu*self.av_mu(cv, dv, eos)/3 + self._physical_transport.volume_viscosity(cv, dv))
[docs] def thermal_conductivity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the gas thermal_conductivity, $\kappa$.""" cp = eos.heat_capacity_cp(cv, dv.temperature) actx = cv.array_context smoothness_beta = actx.np.where( actx.np.greater(dv.smoothness_beta, 0.), dv.smoothness_beta, 0.) smoothness_kappa = actx.np.where( actx.np.greater(dv.smoothness_kappa, 0.), dv.smoothness_kappa, 0.) av_kappa = ( cp*(smoothness_beta*self.av_beta(cv, dv, eos)/self._av_prandtl + smoothness_kappa*self.av_kappa(cv, dv, eos)) ) return (av_kappa + self._physical_transport.thermal_conductivity(cv, dv, eos))
[docs] def species_diffusivity(self, cv: ConservedVars, dv: Optional[GasDependentVars] = None, eos: Optional[GasEOS] = None) -> DOFArray: r"""Get the vector of species diffusivities, ${d}_{\alpha}$.""" return self._physical_transport.species_diffusivity(cv, dv, eos)
[docs] class ArtificialViscosityTransportDiv3(TransportModel): r"""Transport model for add artificial viscosity. Inherits from (and implements) :class:`TransportModel`. Takes a physical transport model and adds the artificial viscosity contribution to it. Defaults to simple transport with inviscid settings. This is equivalent to inviscid flow with artifical viscosity enabled. .. automethod:: __init__ .. automethod:: bulk_viscosity .. automethod:: viscosity .. automethod:: volume_viscosity .. automethod:: thermal_conductivity .. automethod:: species_diffusivity """
[docs] def __init__(self, av_mu, av_kappa, av_beta, av_d, av_prandtl, physical_transport=None, av_species_diffusivity=None): """Initialize uniform, constant transport properties.""" if physical_transport is None: self._physical_transport = SimpleTransport() else: self._physical_transport = physical_transport if av_species_diffusivity is None: av_species_diffusivity = np.empty((0,), dtype=object) self._av_mu = av_mu self._av_beta = av_beta self._av_kappa = av_kappa self._av_d = av_d self._av_prandtl = av_prandtl
def av_mu(self, cv, dv, eos): r"""Get the shear artificial viscosity for the gas.""" actx = cv.array_context return (self._av_mu * cv.mass * actx.np.sqrt(np.dot(cv.velocity, cv.velocity) + dv.speed_of_sound**2)) def av_beta(self, cv, dv, eos): r"""Get the shear artificial viscosity for the gas.""" actx = cv.array_context return (self._av_beta * cv.mass * actx.np.sqrt(np.dot(cv.velocity, cv.velocity) + dv.speed_of_sound**2)) def av_kappa(self, cv, dv, eos): r"""Get the shear artificial viscosity for the gas.""" actx = cv.array_context return (self._av_kappa * cv.mass * actx.np.sqrt(np.dot(cv.velocity, cv.velocity) + dv.speed_of_sound**2)) def av_d(self, cv, dv, eos): r"""Get the shear artificial viscosity for the gas.""" actx = cv.array_context return (self._av_d * actx.np.sqrt(np.dot(cv.velocity, cv.velocity) + dv.speed_of_sound**2))
[docs] def bulk_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the bulk viscosity for the gas, $\mu_{B}$.""" actx = cv.array_context smoothness_beta = actx.np.where( actx.np.greater(dv.smoothness_beta, 0.), dv.smoothness_beta, 0.) return (smoothness_beta*self.av_beta(cv, dv, eos) + self._physical_transport.bulk_viscosity(cv, dv))
[docs] def viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the gas dynamic viscosity, $\mu$.""" actx = cv.array_context smoothness_mu = actx.np.where( actx.np.greater(dv.smoothness_mu, 0.), dv.smoothness_mu, 0.) return (smoothness_mu*self.av_mu(cv, dv, eos) + self._physical_transport.viscosity(cv, dv))
[docs] def volume_viscosity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the 2nd viscosity coefficent, $\lambda$. In this transport model, the second coefficient of viscosity is: $\lambda = \left(\mu_{B} - \frac{2\mu}{3}\right)$ """ actx = cv.array_context smoothness_mu = actx.np.where( actx.np.greater(dv.smoothness_mu, 0.), dv.smoothness_mu, 0.) smoothness_beta = actx.np.where( actx.np.greater(dv.smoothness_beta, 0.), dv.smoothness_beta, 0.) return (smoothness_beta*self.av_beta(cv, dv, eos) - 2*smoothness_mu*self.av_mu(cv, dv, eos)/3 + self._physical_transport.volume_viscosity(cv, dv))
[docs] def thermal_conductivity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the gas thermal_conductivity, $\kappa$.""" cp = eos.heat_capacity_cp(cv, dv.temperature) actx = cv.array_context smoothness_beta = actx.np.where( actx.np.greater(dv.smoothness_beta, 0.), dv.smoothness_beta, 0.) smoothness_kappa = actx.np.where( actx.np.greater(dv.smoothness_kappa, 0.), dv.smoothness_kappa, 0.) av_kappa = ( cp*(smoothness_beta*self.av_beta(cv, dv, eos)/self._av_prandtl + smoothness_kappa*self.av_kappa(cv, dv, eos)) ) return (av_kappa + self._physical_transport.thermal_conductivity(cv, dv, eos))
[docs] def species_diffusivity(self, cv: ConservedVars, # type: ignore[override] dv: GasDependentVars, eos: GasEOS) -> DOFArray: r"""Get the vector of species diffusivities, ${d}_{\alpha}$.""" actx = cv.array_context smoothness_d = actx.np.where( actx.np.greater(dv.smoothness_d, 0.), dv.smoothness_d, 0.) return (smoothness_d*self.av_d(cv, dv, eos) + self._physical_transport.species_diffusivity(cv, dv, eos))