Modeling combustion

IdealGases allows us to perform simple combustion calculations. The following functions are useful utilites to do so.

Calculating stoichiometric fuel-oxidizer ratio

For an arbitrary fuel of type $\genfuel$ we can write a general equation representing the combustion of 1 mole of fuel,

\[\genfuel + n_{\mathrm{O}_2} \mathrm{O}_2 \longrightarrow n_{\mathrm{CO}_2} \mathrm{CO}_2 + n_{\mathrm{H}_2\mathrm{O}} \mathrm{H}_2\mathrm{O} + n_{\mathrm{N}_2} \mathrm{N}_2 \]

where the number of moles of the different species is given by balancing the reaction:

\[\begin{aligned} n_{\rm{CO_2}} &= x_{\mathrm{C}} \tag{1}\\ n_{\rm{H_2O}} &= \frac{x_{\mathrm{H}}}{2}\\ n_{\rm{N_2}} &= \frac{x_{\mathrm{N}}}{2}\\ n_{\rm{O_2}} &= x_{\mathrm{C}} + \frac{x_{\mathrm{H}}}{4} - \frac{x_{\mathrm{O}}}{2}. \end{aligned}\]

The molar fuel-oxygen ratio $f$ is then $\displaystyle{\frac{1}{n_{\rm{O_2}}}}$. If the oxidzier is not pure oxygen then the stoichiometric molar fuel-oxidizer ratio is given by $\displaystyle{f_{\text{stoich.}}=\frac{X_{\rm{O_2}}}{n_{\rm{O_2}} }}$, where $X_{\rm{O_2}}$ is the mole fraction of oxygen in the oxidizer (e.g., $X_{\rm{O_2}} \approx 0.21$ in dry air).

This reaction can also be written as

\[\genfuel \longrightarrow n_{\mathrm{CO}_2} \mathrm{CO}_2 + n_{\mathrm{H}_2\mathrm{O}} \mathrm{H}_2\mathrm{O} + n_{\mathrm{N}_2} \mathrm{N}_2 - n_{\mathrm{O}_2} \mathrm{O}_2 \]

which can be read as "the complete combustion of 1 mole of fuel $(\genfuel)$ consumes $n_{\mathrm{O}_2}$ moles of $\mathrm{O}_2$ and produces $n_{\mathrm{CO}_2}$ moles of $\mathrm{CO}_2$, $n_{\mathrm{H}_2\mathrm{O}}$ moles of $\mathrm{H}_2\mathrm{O}$, and $n_{\mathrm{N}_2}$ moles of $\mathrm{N}_2$".

IdealGases.fuelbreakdownFunction
fuelbreakdown(fuel::String)

Returns the number of C, H, O, and N atoms that the fuel is composed of.

Examples


julia> IdealGases.fuelbreakdown("CH4")' #transpose is simply to save space in the docs
1×4 adjoint(::Vector{Float64}) with eltype Float64:
 1.0  4.0  0.0  0.0

julia> IdealGases.fuelbreakdown("C12H23.5")'
1×4 adjoint(::Vector{Float64}) with eltype Float64:
 12.0  23.5  0.0  0.0

julia> IdealGases.fuelbreakdown("CH3COOH")'
1×4 adjoint(::Vector{Float64}) with eltype Float64:
 2.0  4.0  2.0  0.0

julia> IdealGases.fuelbreakdown("CH3CH2OH")'
1×4 adjoint(::Vector{Float64}) with eltype Float64:
 2.0  6.0  1.0  0.0
source
IdealGases.stoich_molar_fuel_oxy_ratioFunction
stoich_molar_fuel_oxy_ratio(fuel::AbstractString)

Calculates the molar fuel-oxygen ratio for stoichiometric combustion.

Examples

julia> using IdealGases

julia> IdealGases.stoich_molar_fuel_oxy_ratio("CH4")
0.5

julia> IdealGases.stoich_molar_fuel_oxy_ratio("C12H23")
0.056338028169014086
source
IdealGases.stoich_molar_FORFunction
stoich_molar_FOR(fuel::AbstractSpecies, oxidizer::AbstractSpecies)

Calculates the molar fuel-oxidizer ratio for stoichiometeric combustion for and arbitrary fuel and oxidizer.

Examples

julia> CH4 = species_in_spdict("CH4");

julia> IdealGases.stoich_molar_FOR(CH4)
0.104738
source
IdealGases.stoich_FORFunction
stoich_FOR(fuel::AbstractSpecies, oxidizer::AbstractSpecies=DryAir)

Calculates the mass fuel-oxidizer ratio for stoichiometeric combustion for and arbitrary fuel and oxidizer.

Examples

julia> IdealGases.stoich_FOR(CH4)
0.05800961333050494
source
IdealGases.reaction_change_fractionFunction
reaction_change_fraction(fuel::String)

Returns the mass fraction change due to complete combustion

Assume fuel of type CᵢHⱼOₖNₗ , then

  CᵢHⱼOₖNₗ + n(O2) * O2 ---> n(CO2)*CO2 + n(H2O)*H2O + n(N2)*N2
⟹CᵢHⱼOₖNₗ              ---> n(CO2)*CO2 + n(H2O)*H2O + n(N2)*N2 - n(O2)*O2 

Examples

julia> reaction_change_fraction("CH4")
Dict{String, Float64} with 4 entries:
  "O2"  => -3.98926
  "H2O" => 2.24595
  "CO2" => 2.74331
  "N2"  => 0.0
source
IdealGases.reaction_change_molar_fractionFunction
reaction_change_molar_fraction(fuel::AbstractString)

Returns the mole fraction change due to complete combustion of one mole of the specified fuel

Assume fuel of type CᵢHⱼOₖNₗ , then

    CᵢHⱼOₖNₗ + n(O2) * O2 ---> n(CO2)*CO2 + n(H2O)*H2O + n(N2)*N2
   ⟹CᵢHⱼOₖNₗ              ---> n(CO2)*CO2 + n(H2O)*H2O + n(N2)*N2 - n(O2)*O2 

Examples

julia> IdealGases.reaction_change_molar_fraction("CH4")
4-element Vector{Float64}:
  1.0
  0.0
  2.0
 -2.0
source

Vitiated gas composition

If we consider lean combustion (i.e., more oxygen present than required to completely react with the fuel) we can write the above equation for some molar fuel-oxygen (or more generally oxidizer) ratio $(f \leq f_{\mathrm{stoich.}})$ as follows

\[ \begin{aligned} f \times \genfuel+ 1\times \mathrm{O}_2 &\longrightarrow f n_{\mathrm{CO}_2} \mathrm{CO}_2 &+& f n_{\mathrm{H}_2\mathrm{O}} \mathrm{H}_2\mathrm{O} &+& f n_{\mathrm{N}_2} \mathrm{N}_2 &+&\left(1 - fn_{\mathrm{O}_2}\right) \mathrm{O}_2 \\ f \times \genfuel + 1\times \mathrm{O}_2 &\longrightarrow f x_{\mathrm{C}} \mathrm{CO}_2 &+& f \frac{x_{\mathrm{H}}}{2} \mathrm{H}_2\mathrm{O} &+& f \frac{x_{\mathrm{N}}}{2}\mathrm{N}_2 &+&\left(1 - \frac{f}{f_{\mathrm{stoich.}}}\right)\mathrm{O}_2. \end{aligned}\]

where $\fst = 1/n_{\mathrm{O}_2}$ for oxy-combustion. More generally for some oxidzer that has $X_{\rm{O_2}}$ moles of oxygen per mole of oxidizer,

\[\begin{aligned} f \genfuel + \mathrm{Oxidizer} \longrightarrow f x_{\mathrm{C}} \mathrm{CO}_2 + f \frac{x_{\mathrm{H}}}{2} \mathrm{H}_2\mathrm{O} + f \frac{x_{\mathrm{N}}}{2}\mathrm{N}_2 &+\mathrm{Oxidizer}\\ & - \left(\frac{f X_{\mathrm{O}_2}}{\fst}\right)\mathrm{O}_2. \end{aligned}\]

IdealGases.vitiated_mixtureFunction
vitiated_mixture(fuel::AbstractSpecies, oxidizer::AbstractSpecies, 
FAR::Float64, ηburn::Float64=1.0)

Calculates the composition of a burnt gas mixture. Defaults to stoichiometric conditions if FAR is not specified. vitiated_mixture returns the number of moles of each species present in the burnt gas mixture after combustion at the specified FAR. Note the sum of result in general will not sum to 1.

Examples

julia> CH4 = species_in_spdict("CH4");

julia> Air = IdealGases.DryAir;

julia> IdealGases.vitiated_mixture(CH4, Air, 0.04)
Dict{Any, Any} with 6 entries:
  "O2"  => 0.0650337
  "CH4" => 0.0
  "Ar"  => 0.009365
  "H2O" => 0.144442
  "CO2" => 0.0725401
  "N2"  => 0.78084

julia> IdealGases.vitiated_mixture(CH4, Air)
Dict{Any, Any} with 6 entries:
  "O2"  => 0.0
  "CH4" => 0.0
  "Ar"  => 0.009365
  "H2O" => 0.209476
  "CO2" => 0.105057
  "N2"  => 0.78084

See here for some explanation of the background.

source
vitiated_mixture(fuel::AbstractString, oxidizer::AbstractString, 
FAR::Float64, ηburn::Float64=1.0)

Convenience function that finds fuel and oxidizer from thermo database

source
IdealGases.vitiated_speciesFunction
vitiated_species(fuel::AbstractSpecies, oxidizer::AbstractSpecies, 
FAR::Float64, ηburn::Float64=1.0, name::AbstractString="vitiated species")

Returns a composite_species that represents the burnt gas mixture at the specified FAR. If no FAR is provided stoichiometeric conditions are assumed.

Examples

julia> IdealGases.vitiated_species(CH4, Air, 0.05, name = "CH4-Air-0.05")
Composite Species: "CH4-Air-0.05"
MW = 27.89510190126262 g/mol
with composition:
 Species        Xᵢ
      O2   0.02653
      Ar   0.00859
     H2O   0.16560
     CO2   0.08309
      N2   0.71619
------------------
       Σ   1.00000
source
IdealGases.fixed_fuel_vitiated_speciesFunction
fixed_fuel_vitiated_species(fuel, oxidizer, ηburn::Float64=1.0)

Returns a function burntgas(FAR::Float64) that is specific to the fuel and oxidizer combination provided. This gives a highly performant function that can simply be called at any given FAR for that specific fuel+oxidizer combo.

This is ~4x faster than doing burntgas(FAR) = vitiated_species("CH4", "Air", FAR)

Examples

julia> burntgas = IdealGases.fixed_fuel_vitiated_species(CH4, Air)
(::IdealGases.var"#burntgas#52"{species, composite_species, Vector{Float64}, Vector{Float64}, Float64}) (generic function with 1 method)

julia> burntgas(0.05)
Composite Species: "burntgas(CH4 + Dry Air; 0.05)"
MW = 27.89510190126262 g/mol
with composition:
 Species        Xᵢ
      O2   0.02653
      Ar   0.00859
     H2O   0.16560
     CO2   0.08309
      N2   0.71619
------------------
       Σ   1.00000

julia> gas1 = Gas1D(burntgas(0.02)) #Returns a Gas1D intialized with the burnt gas properties
Gas1D(burntgas(CH4 + Dry Air; 0.02); MW = 28.51473501878705 g/mol)
at T = 298.15 K; P = 101.325 kPa
source