Custom Plotting Example

This example walks through source/bind/python/cea/samples/sample_plots.py, which sweeps equivalence ratio and initial reactant temperature for an H2/O2mixture, solves HP equilibrium at each condition, stores the results, and then produces summary plots. The emphasis is on setting up the inputs, calling the solver in a nested loop, and querying values from the solution object.

Imports and constants

Start by bringing in NumPy, timing utilities, and the CEA bindings. The script uses cea.units for unit conversions and normalizes enthalpy inline with cea.R.

import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime

import cea

start = datetime.now()

Define the sweep and mixtures

The script defines a fixed pressure, a range of initial temperatures, and a range of equivalence ratios. It then declares reactant and product mixtures for H2/O2.

p0 = cea.units.atm_to_bar(1.0)  # Fixed-pressure state (bar)
n_T0 = 350
T0 = np.linspace(300.0, 2000.0, n_T0)

reac = cea.Mixture(["H2", "O2"])
prod = cea.Mixture(["H", "H2", "H2O", "O", "O2", "OH"])

n_phi = 310
phi = np.linspace(0.5, 2.0, n_phi)

Set up the solver and storage arrays

Create the equilibrium solver and an associated solution object. The results are stored in pre-allocated arrays so each nested-loop iteration only writes values.

solver = cea.EqSolver(prod, reactants=reac)
soln = cea.EqSolution(solver)

X, Y = np.meshgrid(T0, phi)
T_vals = np.zeros((n_phi, n_T0))
H_vals = np.zeros((n_phi, n_T0))
H2_vals = np.zeros((n_phi, n_T0))
H2O_vals = np.zeros((n_phi, n_T0))
O_vals = np.zeros((n_phi, n_T0))
O2_vals = np.zeros((n_phi, n_T0))
OH_vals = np.zeros((n_phi, n_T0))
convg_vals = np.zeros((n_phi, n_T0))

Solve in a nested loop and query values

The core of the script is a nested loop: the outer loop sweeps equivalence ratio, computes a reactant weight vector once per ratio, and the inner loop sweeps the initial temperature. Inside the inner loop, it computes the fixed enthalpy, invokes the HP equilibrium solve, and then queries the solution fields.

for i in range(len(phi)):
    of_ratio = reac.weight_eq_ratio_to_of_ratio(
        np.array([0.0, 1.0]), np.array([1.0, 0.0]), phi[i]
    )
    weights = reac.of_ratio_to_weights(
        np.array([0.0, 1.0]), np.array([1.0, 0.0]), of_ratio
    )
    for j in range(len(T0)):
        h0 = reac.calc_property(cea.ENTHALPY, weights, T0[j]) / cea.R
        solver.solve(soln, cea.HP, p0, h0, weights)

        convg_vals[i, j] = soln.converged
        if soln.converged:
            T_vals[i, j] = soln.T
            H_vals[i, j] = soln.mole_fractions["H"]
            H2_vals[i, j] = soln.mole_fractions["H2"]
            H2O_vals[i, j] = soln.mole_fractions["H2O"]
            O_vals[i, j] = soln.mole_fractions["O"]
            O2_vals[i, j] = soln.mole_fractions["O2"]
            OH_vals[i, j] = soln.mole_fractions["OH"]
        else:
            print("Not converged for phi = ", phi[i], " and T0 = ", T0[j])

This is the pattern to reuse in your own sweeps: set up the arrays, loop over the state grid, call solve, then read the scalar and dictionary-style fields from soln and store them for later use.

Plotting summary

After the arrays are filled, the script uses matplotlib to create contour plots of reaction temperature and species mole fractions. The plotting code lives at the end of the script and can be kept as-is or adapted to new data products.