Combustion#

Examining combustion problems (and chemical equilibrium problems) generally requires calculating thermodynamic properties of chemical species.

Cantera makes it easy to both work with mixtures and pure components, and determine their thermodynamic properties, but it requires you to first load a model containing some model for these (typically represented as a set of coefficients for a high-order polynomial).

Built-in models#

Fortunately, Cantera comes with a few built-in models meant to be used for air, hydrogen/oxygen combustion, and natural gas combustion, which provide quick access to properties for many species:

from textwrap import wrap
import cantera as ct
# Models built into Cantera with commonly used gas species

models = ['air.yaml', 'h2o2.yaml', 'gri30.yaml']

for model in models:
    gas = ct.Solution(model)
    
    print(f"Species in '{model}' model:")
    lines = wrap(' '.join(gas.species_names), width=60, break_long_words=False)
    for line in lines:
        print(line)
    print()
Species in 'air.yaml' model:
O O2 N NO NO2 N2O N2 AR

Species in 'h2o2.yaml' model:
H2 H O O2 OH H2O HO2 H2O2 AR N2

Species in 'gri30.yaml' model:
H2 H O O2 OH H2O HO2 H2O2 C CH CH2 CH2(S) CH3 CH4 CO CO2 HCO
CH2O CH2OH CH3O CH3OH C2H C2H2 C2H3 C2H4 C2H5 C2H6 HCCO
CH2CO HCCOH N NH NH2 NH3 NNH NO NO2 N2O HNO CN HCN H2CN HCNN
HCNO HOCN HNCO NCO N2 AR C3H7 C3H8 CH2CHO CH3CHO

We will frequently use the gri30.yaml model, which is the GRI-Mech 3.0 model originally developed to model natural gas combustion [SGF+99].

Cantera also comes with a large database of thermodynamic properties for gases, which originally came from NASA [GM71, MGaMAR93].

Due to the large number of components present, and the sometimes-unusual naming, it may be a bit challenging to easily find a compound you are looking for; the easiest way may be to search the full file available online.

species = {S.name: S for S in ct.Species.list_from_file('nasa_gas.yaml')}

print('Number of species: ', len(species))
Number of species:  748

Let’s say that we want to consider the complete combustion of gasoline in air. Gasoline is a very complex mixture of large hydrocarbons, without a fixed composition, but we can model it as a mixture of n-heptane (C\(_{7}\)H\(_{16}\)) and isooctane (C\(_{8}\)H\(_{18}\)). (These actually represent 0 and 100 on the octane rating.)

After searching the NASA database, we find these species as C7H16,n-heptane and C8H18,isooctane, so we can extract them, the components of air, and the complete combustion products:

complete_species = [species[S] for S in (
    'C7H16,n-heptane', 'C8H18,isooctane', 'O2', 'N2', 'CO2', 'H2O'
    )]
gas = ct.Solution(thermo='IdealGas', species=complete_species)

Then, we can specify a stoichiometric mixture of 87% isooctane \ 13% n-heptane by mole, at standard conditions:

gas.TP = 298.15, ct.one_atm
gas.set_equivalence_ratio(
    1.0, 'C7H16,n-heptane: 0.13, C8H18,isooctane: 0.87',
    'O2: 1.0, N2: 3.76'
    )
gas()
       temperature   298.15 K
          pressure   1.0132e+05 Pa
           density   1.2366 kg/m^3
  mean mol. weight   30.254 kg/kmol
   phase of matter   gas

                          1 kg             1 kmol     
                     ---------------   ---------------
          enthalpy       -1.2168e+05       -3.6813e+06  J
   internal energy       -2.0362e+05       -6.1603e+06  J
           entropy            6718.8        2.0327e+05  J/K
    Gibbs function       -2.1249e+06       -6.4285e+07  J
 heat capacity c_p            1051.1             31800  J/K
 heat capacity c_v            776.28             23485  J/K

                      mass frac. Y      mole frac. X     chem. pot. / RT
                     ---------------   ---------------   ---------------
   C7H16,n-heptane         0.0072279         0.0021822           -133.37
   C8H18,isooctane          0.055143          0.014604           -145.48
                O2           0.21847           0.20656           -26.251
                N2           0.71916           0.77666           -23.298
     [   +2 minor]                 0                 0  

Then, we can determine the equilibrium composition and adiabatic flame temperature, after complete combustion:

gas.equilibrate('HP')
gas()
       temperature   2403.1 K
          pressure   1.0132e+05 Pa
           density   0.14506 kg/m^3
  mean mol. weight   28.604 kg/kmol
   phase of matter   gas

                          1 kg             1 kmol     
                     ---------------   ---------------
          enthalpy       -1.2168e+05       -3.4806e+06  J
   internal energy       -8.2019e+05       -2.3461e+07  J
           entropy            9614.1          2.75e+05  J/K
    Gibbs function       -2.3225e+07       -6.6433e+08  J
 heat capacity c_p            1474.8             42186  J/K
 heat capacity c_v            1184.2             33872  J/K

                      mass frac. Y      mole frac. X     chem. pot. / RT
                     ---------------   ---------------   ---------------
   C7H16,n-heptane        1.0681e-11        3.0489e-12           -131.47
                O2        3.7548e-11        3.3566e-11           -53.551
                N2           0.71916           0.73431           -27.884
               CO2           0.19218           0.12491           -54.508
               H2O          0.088662           0.14078           -42.372
     [   +1 minor]        8.7243e-15        2.1846e-15  

Finding other models#

You might face a problem that requires thermodynamic properties for compounds not available in the built-in models. In that case, you might need to find an entire model that contains the compound(s) of interest, or at least the thermodynamic parameters for each species.

You may find models for particular systems by searching the combustion/thermodynamics literature (i.e., Google Scholar). These models, either available as supplementary material for a journal article or via a research group’s website, typically come in the older Chemkin format, which needs to be converted to Cantera’s YAML format.

Another powerful source of thermodynamics information is the Reaction Mechanism Generator (RMG) Molecule Search [AGG12, GAGW16, MG13], which offers the ability to both search for information in its databases but also estimate properties for any molecule.

For example, say we want to calculate thermodynamic properties for toluene (C\(_6\)H\(_5\)CH\(_3\), or C\(_7\)H\(_8\)). You can go to the RMG Molecule Search, enter toluene in the “Species Identifier” field and hit tab. Then, after the site responds, click “Search Thermochemistry”. This brings up multiple entries for this molecule.

Let’s use the “USC-Mech_ii” result. This includes the CHEMKIN format NASA Polynomial:

! USC-Mech-ii
C7H8                    C   7H   8          G   100.000  5000.000 1073.72      1
 9.30667130E+00 3.36713230E-02-1.41158452E-05 2.69973752E-09-1.93204076E-13    2
 5.79813528E+02-2.68610894E+01 2.05719474E+00 3.12152776E-02 3.04758250E-05    3
-5.05435593E-08 1.81542493E-11 3.83493690E+03 1.65378111E+01                   4

which contains the elemental composition (7 C and 8 H), the phase (G: gas), the temperature ranges for applicability of this model, and 14 polynomials used to obtain the standard-state specific heat, enthalpy, and entropy as a function of temperature. The first seven coefficients are for the upper temperature range (specified by the middle and high temperatures, 1073.72 and 5000 K here), and the next seven coefficients are for the lower temperature range (100 to 1073.72 K here).

We can take this information and create a Cantera Species object, with the name C6H5CH3:

species_toluene = ct.Species.from_yaml(
'''name: C6H5CH3
composition: {C: 7, H: 8}
thermo:
  model: NASA7
  temperature-ranges: [100.00, 1073.72, 5000.00]
  data:
  - [2.05719474e+00, 3.12152776E-02, 3.04758250E-05, -5.05435593E-08, 
     1.81542493E-11, 3.83493690E+03, 1.65378111E+01]
  - [9.30667130E+00, 3.36713230E-02, -1.41158452E-05, 2.69973752E-09, 
    -1.93204076E-13, 5.79813528E+02, -2.68610894E+01]'''
    )

Then, we can create a new model that contains toluene (C6H5CH3), as well as the components of air and the complete combustion products:

species = {S.name: S for S in ct.Species.list_from_file('gri30.yaml')}
complete_species = [species[S] for S in ('O2', 'N2', 'CO2', 'H2O')]
complete_species += [species_toluene]
                                         
gas = ct.Solution(thermo='IdealGas', species=complete_species)

gas.TP = 298.15, ct.one_atm
gas.set_equivalence_ratio(1.0, 'C6H5CH3: 1.0', 'O2: 1.0, N2: 3.76')
gas.equilibrate('HP')
gas()
       temperature   2502.7 K
          pressure   1.0132e+05 Pa
           density   0.14423 kg/m^3
  mean mol. weight   29.619 kg/kmol
   phase of matter   gas

                          1 kg             1 kmol     
                     ---------------   ---------------
          enthalpy             37684        1.1162e+06  J
   internal energy       -6.6486e+05       -1.9692e+07  J
           entropy            9365.6         2.774e+05  J/K
    Gibbs function       -2.3402e+07       -6.9313e+08  J
 heat capacity c_p            1422.6             42136  J/K
 heat capacity c_v            1141.9             33821  J/K

                      mass frac. Y      mole frac. X     chem. pot. / RT
                     ---------------   ---------------   ---------------
                O2        7.4923e-10        6.9353e-10           -50.677
                N2           0.71379           0.75468           -27.993
               CO2           0.23195           0.15611           -53.742
               H2O          0.054257          0.089206           -42.539
           C6H5CH3        2.3972e-10        7.7059e-11           -90.259