—
Plot CH₄ chemical equilibrium vs temperature for various pressures (at high temperatures).#
This script computes the chemical equilibrium of methane (CH₄) for various temperatures and pressures using Cantera. It plots the molar concentration of the main species in the equilibrium state as a function of temperature.
The mechanism used is the one from ./data/mechanisms/Goutier2025. Thermodynamic data comes from [GRCDatabase] and [Burcat], and have been extended to 50 000 K, by fixing Cantera’s extrapolation at high temperature. Moreover, C+, C++, C+++ and electrons have been added to the mechanism, with thermodynamic data computed using [MinPlasCalc] (& [minplascalcPaper]).
Note that Cantera extrapolates the thermodynamic data if T is outside the range of validity of the thermodynamic data. This can lead to unphysical results, especially at high temperatures. See the following issue for more details: Cantera/cantera#270
Import the required libraries.#
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from cantera import Solution, SolutionArray
from matplotlib.lines import Line2D
from rizer.misc.utils import get_path_to_data
sns.set_theme("talk")
Define the parameters for the plot.#
# Define the temperature range.
T_min = 0 # [°C]
T_max = 50_000 # [°C]
temperatures = np.linspace(T_min + 273.15, T_max + 273.15, 1000) # [K]
# Define the species to plot.
species_to_plot = [
"e-",
"H",
"H+",
"H2",
# "H2+",
"C",
"C(soot)",
"C(s)",
"C+",
"C++",
"C+++",
# "CH",
# "CH+",
# "CH2",
# "CH2+",
# "CH3",
# "CH3+",
"CH4",
# "CH4+",
# "C2",
# "C2+",
# "C2H",
# "C2H+",
"C2H2",
# "C2H2+",
# "C2H3",
# "C2H3+",
# "C2H4",
# "C2H4+",
# "C2H5",
# "C2H5+",
# "C2H6",
# "C2H6+",
# "C6H6",
]
# Define the pressures to plot.
pressures = [1, 100] # atm
# Style linestyle for the various pressures.
linestyles = ["-", "--"]
if len(linestyles) != len(pressures):
raise ValueError(
"The number of linestyles must be equal to the number of pressures."
)
Define some parameters for the plot.#
# Nice labels for the species.
labels = {
"e-": r"$\mathrm{e}^-$",
"H": r"$\mathrm{H}$",
"H+": r"$\mathrm{H}^+$",
"H2": r"$\mathrm{H}_2$",
"H2+": r"$\mathrm{H}_2^+$",
"C": r"$\mathrm{C}$",
"C(soot)": r"$\mathrm{C}(\mathrm{soot})$",
"C(s)": r"$\mathrm{C}(s)$",
"C+": r"$\mathrm{C}^+$",
"C++": r"$\mathrm{C}^{++}$",
"C+++": r"$\mathrm{C}^{3+}$",
"CH": r"$\mathrm{CH}$",
"CH+": r"$\mathrm{CH}^+$",
"CH2": r"$\mathrm{CH}_2$",
"CH2+": r"$\mathrm{CH}_2^+$",
"CH3": r"$\mathrm{CH}_3$",
"CH3+": r"$\mathrm{CH}_3^+$",
"CH4": r"$\mathrm{CH}_4$",
"CH4+": r"$\mathrm{CH}_4^+$",
"C2": r"$\mathrm{C}_2$",
"C2+": r"$\mathrm{C}_2^+$",
"C2H": r"$\mathrm{C}_2\mathrm{H}$",
"C2H+": r"$\mathrm{C}_2\mathrm{H}^+$",
"C2H2": r"$\mathrm{C}_2\mathrm{H}_2$",
"C2H2+": r"$\mathrm{C}_2\mathrm{H}_2^+$",
"C2H3": r"$\mathrm{C}_2\mathrm{H}_3$",
"C2H3+": r"$\mathrm{C}_2\mathrm{H}_3^+$",
"C2H4": r"$\mathrm{C}_2\mathrm{H}_4$",
"C2H4+": r"$\mathrm{C}_2\mathrm{H}_4^+$",
"C2H5": r"$\mathrm{C}_2\mathrm{H}_5$",
"C2H5+": r"$\mathrm{C}_2\mathrm{H}_5^+$",
"C2H6": r"$\mathrm{C}_2\mathrm{H}_6$",
"C2H6+": r"$\mathrm{C}_2\mathrm{H}_6^+$",
"C6H6": r"$\mathrm{C}_6\mathrm{H}_6$",
}
# Create legends for the various pressures.
legend_elements = [
Line2D([0], [0], color="k", linestyle=linestyles[i], lw=2, label=f"{p} atm")
for i, p in enumerate(pressures)
]
Define the gas object.#
gas = Solution(
get_path_to_data(
"mechanisms",
"Goutier2025",
"CH4_to_C2H2.yaml",
),
name="gas",
)
Compute and plot the equilibrium states.#
# Define the figure and axis.
fig, ax = plt.subplots(figsize=(12, 8), layout="constrained")
for i, pressure_atm in enumerate(pressures):
# Convert the pressure to Pa.
P = pressure_atm * 101325 # Pa
# Define the initial state as pure methane at 1 atm and 273.15 K.
gas.TPX = 273.15, P, {"CH4": 1}
states = SolutionArray(gas)
# Calculate the equilibrium states.
for T in temperatures:
gas.TP = T, P
gas.equilibrate("TP")
states.append(gas.state)
# Plot the results.
style = linestyles[i] # Linestyle for the current pressure.
others_x = np.ones_like(temperatures) # Total molar fraction of the other species.
for species in species_to_plot:
# Molar fraction of the species.
if species not in gas.species_names:
print(f"Species {species} not in mechanism.")
continue
molar_fraction = states(species).X[:, 0]
ax.plot(
states.T - 273.15,
molar_fraction * 100,
style,
label=labels[species],
)
# Update the total molar fraction of the other species.
others_x -= molar_fraction
# Add labels on curves, at the maximum of the curves,
# with the same color as the curve, only for the first pressure.
if i == 0:
y_val = np.max(molar_fraction) * 100
x_val = states.T[np.argmax(states(species).X)] - 273.15
ax.text(
x=x_val,
y=y_val + 1,
s=labels[species],
color=ax.lines[-1].get_color(),
fontsize=30,
ha="center",
)
# Plot the total molar fraction of the other species.
ax.plot(
states.T - 273.15,
others_x * 100,
style,
color="k",
label=r"$\mathrm{others}$",
)
# Add label on the curve, at the maximum of the curve,
# with the same color as the curve, only for the first pressure.
if i == 0:
y_val = float(np.max(others_x) * 100)
x_val = states.T[np.argmax(others_x)] - 273.15
ax.text(
x=x_val,
y=y_val + 1,
s=r"$\mathrm{others}$",
color=ax.lines[-1].get_color(),
fontsize=30,
ha="center",
)
# Reset the color cycle.
ax.set_prop_cycle(None) # type: ignore[call-overload]
ax.legend(handles=legend_elements, loc="upper right")
ax.set_xlabel("T [°C]")
ax.set_ylabel("x [%]")
title = "Equilibrium molar concentration [%] vs temperature [°C] of methane "
ax.set_title(title, fontsize=20)
ax.set_xlim(T_min, T_max)
plt.show()
![Equilibrium molar concentration [%] vs temperature [°C] of methane](../../_images/sphx_glr_plot_methane_equilibrium_composition_high_temperature_001.png)
Species C(soot) not in mechanism.
Species C(s) not in mechanism.
Species C(soot) not in mechanism.
Species C(s) not in mechanism.
Total running time of the script: (0 minutes 0.500 seconds)