Chemical Reactions
MFIX-Exa categorizes chemical reactions into two classes:
Eulerian reactions are homogeneous fluid reactions, reactions that only reference fluid species. These reactions are calculated by looping over grid cells, and are defined in units of moles per second per cubic meter \([mol \cdot s^{-1} \cdot m^{-3}]\).
Lagrangian reactions include homogeneous particle reactions and heterogeneous fluid-particle reactions. These reactions are calculated by looping over each particle, and are defined in units of moles per second \([mol \cdot s^{-1}]\).
Users implement reaction rates by modifying the header file,
src/usr/mfix_usr_reactions_rates_K.H
.
The operator()
method for the EulerianReactionRates
class gets two
arguments, reactions
and fluid
, which are two classes from which the user
can extract the data needed to implement the corresponding rates.
class EulerianReactionRates
{
public:
/**
* Reactions class gives access to the following reactions quantities:
* - reaction_idx("reaction_name"), with reaction_name a string matching one of the reactions defined in inputs
* - rate(q), with q an integer from 0 to number of Eulerian reactions - 1
* - rate("reaction_name"), with reaction_name a string matching one of the reactions defined in inputs
* - time(), the current simulation time
* - dt(), the current simulation time step
* - cell_volume(), this cell geometric volume
* - vfrac(), this cell geometric volume fraction
*
* Fluid class gives access to the following fluid quantities:
* - shear_viscosity()
* - volume_fraction()
* - density()
* - velocity() and velocity(dir), with dir an integer from 0 to 2
* - thermodynamic_pressure()
* - temperature()
* - specific_enthalpy()
* - species_idx("species_name"), with species_name a string matching one of the fluid species defined in inputs
* - mass_fraction(n), with n an integer from 0 to number of fluid species - 1
* - mass_fraction("species_name"), with species_name a string matching one of the fluid species defined in inputs
* - molar_concentration(n), with n an integer from 0 to number of fluid species - 1
* - molar_concentration("species_name"), with species_name a string matching one of the fluid species defined in inputs
* - molar_mass(n), with n an integer from 0 to number of fluid species - 1
* - molar_mass("species_name"), with species_name a string matching one of the fluid species defined in inputs
* - average_molar_mass()
* - mole_fraction(n), with n an integer from 0 to number of fluid species - 1
* - mole_fraction("species_name"), with species_name a string matching one of the fluid species defined in inputs
*/
template <class Reactions, class Fluid>
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void operator() (Reactions& reactions,
const Fluid& fluid) const
{
// User defined Eulerian reactions rates go here
}
};
The operator()
of the LagrangianReactionRates
class contains a third argument,
solids
, which is a class containing data for the particle involved in the reaction.
class LagrangianReactionRates
{
public:
/**
* Reactions class gives access to the following reactions quantities:
* - reaction_idx("reaction_name"), with reaction_name a string matching one of the reactions defined in inputs
* - rate(q), with q an integer from 0 to max number of Lagrangian reactions - 1
* - rate("reaction_name"), with reaction_name a string matching one of the reactions defined in inputs
* - time(), the current simulation time
* - dt(), the current simulation time step
* - cell_volume(), cell geometric volume of cell containing this particle
* - vfrac(), geometric volume fraction of cell containing this particle
*
* Fluid class gives access to the following fluid quantities:
* - shear_viscosity()
* - volume_fraction()
* - density()
* - velocity() and velocity(dir), with dir an integer from 0 to 2
* - thermodynamic_pressure()
* - temperature()
* - specific_enthalpy()
* - species_idx("species_name"), with species_name a string matching one of the fluid species defined in inputs
* - mass_fraction(n), with n an integer from 0 to max number of fluid species
* - mass_fraction("species_name"), with species_name a string matching one of the fluid species defined in inputs
* - molar_concentration(n), with n an integer from 0 to max number of fluid species - 1
* - molar_concentration("species_name"), with species_name a string matching one of the fluid species defined in inputs
* - molar_mass(n), with n an integer from 0 to max number of fluid species - 1
* - molar_mass("species_name"), with species_name a string matching one of the fluid species defined in inputs
* - average_molar_mass()
* - mole_fraction(n), with n an integer from 0 to max number of fluid species - 1
* - mole_fraction("species_name"), with species_name a string matching one of the fluid species defined in inputs
*
* Solids class gives access to the following solids quantities:
* - id()
* - cpu()
* - position() and position(dir), with dir an integer from 0 to 2
* - radius()
* - volume()
* - density()
* - mass()
* - oneOverI(), inverse of the particle momentum of inertia
* - statistical_weight()
* - velocity() and velocity(dir), with dir an integer from 0 to 2
* - temperature()
* - specific_heat_capacity()
* - species_idx("species_name"), with species_name a string matching one of the solids species defined in inputs
* - mass_fraction(n), with n an integer from 0 to max number of solids species - 1
* - mass_fraction("species_name"), with species_name a string matching one of the solids species defined in inputs
* - molar_concentration(n), with n an integer from 0 to max number of solids species - 1
* - molar_concentration("species_name"), with species_name a string matching one of the solids species defined in inputs
* - molar_mass(n), with n an integer from 0 to max number of solids species - 1
* - molar_mass("species_name"), with species_name a string matching one of the solids species defined in inputs
* - average_molar_mass()
* - mole_fraction(n), with n an integer from 0 to max number of solids species - 1
* - mole_fraction("species_name"), with species_name a string matching one of the solids species defined in inputs
*/
template <class Reactions, class Fluid, class Solids>
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void operator() (Reactions& reactions,
const Fluid& fluid,
const Solids& solids) const
{
// User defined Lagrangian reactions rates go here
}
};
To simply defining chemical reactions, fluid and solids species-related quantities
can be accessed by calling the variable function with the species name specified
in the inputs file. For example, if the fluid contains a species called CO
,
then the species mass fraction for CO
can be accessed as follows:
// Mass fraction of CO species
amrex::Real const X_CO = fluid.mass_fraction("CO");
This feature allows users to write readable reaction rates, especially when the number of chemical species is large. However, at runtime this approach requires the solver to search for the species index associated with the name. The computational cost of the search can be non-trivial because it is performed for each iteration of the chemistry solver every time step, for all grid cells and all particles.
A python-script is provided that substitutes the string references with their
corresponding indices to remove the runtime search. The tool is run by passing
the inputs
file and the reaction header, mfix_usr_reactions_rates_K.H
.
The tool creates a backup copy of the original reaction header, appending a time stamp
for when the tool was run, before applying the optimizations.
Example usage:
python tools/Chemistry/optimize_usr_rates.py inputs mfix/src/usr/mfix_usr_reactions_rates_K.H
Example rates UDFs
The following code shows a simple reaction rate for methane combustion.
The molar concentrations for oxygen (O2
) and methane (CH4
) are accessed
using the names provided in the inputs file. Similarly, the reaction rate
is stored using the name given in the inputs file.
# Fluid model settings
# -----------------------------------------------------------------------
fluid.solve = fluid
fluid.species = CH4 O2 CO2 H2O N2
fluid.thermodynamic_pressure = 101325.
fluid.reference_temperature = 298.15
fluid.species = Air Vapor
fluid.viscosity.molecular = constant
fluid.viscosity.molecular.constant = 1.86e-5
fluid.specific_heat = mixture
fluid.thermal_conductivity = constant
fluid.thermal_conductivity.constant = 0.02662
# Chemical reactions:
# -----------------------------------------------------------------------
chemistry.solve = AdiabaticFlame
chemistry.AdiabaticFlame.reaction = CH4(g) + 2O2(g) --> CO2(g) + 2H2O(g)
class EulerianReactionRates
{
public:
AMREX_GPU_HOST_DEVICE
EulerianReactionRates () = default;
template <class Reactions, class Fluid>
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void operator() (Reactions& reactions,
const Fluid& fluid) const
{
// Adiabatic flame:
// CH4 + 2O2 --> CO2 + 2H2O (mol/m^3.s)
//---------------------------------------------------------------------//
// Note: The CH4 combustion rate is artificial and used for the
// adiabatic flame test case.
amrex::Real const c_O2 = fluid.molar_concentration("O2"); // [mol/m^3]
amrex::Real const c_CH4 = fluid.molar_concentration("CH4"); // [mol/m^3]
amrex::Real k0(2.0e-1); // reaction rate coefficient
reactions.rate("AdiabaticFlame") = k0 * c_O2 * c_CH4;
}
};