heating_value.ipynb (Source)

Heating values

Use Cantera's thermodynamic data to calculate the lower heating value (LHV) and higher heating value (HHV) of methane and other fuels.

Heating value of Methane

The complete reaction for heating methane is:

$\mathrm{CH_4+2O_2\rightarrow CO_2+2H_2O}$

We compute the lower heating value (LHV) as the difference in enthalpy (per kg mixture) between reactants and products at constant temperature and pressure, divided by the mass fraction of fuel in the reactants.

In [1]:
import cantera as ct

print(f"Using Cantera version: {ct.__version__}")
Using Cantera version: 2.6.0a4
In [3]:
gas = ct.Solution("gri30.yaml")

# Set reactants state
gas.TPX = 298, 101325, "CH4:1, O2:2"
h1 = gas.enthalpy_mass
Y_CH4 = gas["CH4"].Y[0]  # returns an array, of which we only want the first element

# set state to complete combustion products without changing T or P
gas.TPX = None, None, "CO2:1, H2O:2"
h2 = gas.enthalpy_mass

LHV = -(h2 - h1) / Y_CH4 / 1e6
print(f"LHV = {LHV:.3f} MJ/kg")
LHV = 50.025 MJ/kg

The LHV is calculated assuming that water remains in the gas phase. However, more energy can be extracted from the mixture if this water is condensed. This value is the higher heating value (HHV).

The ideal gas mixture model used here cannot calculate this contribution directly. However, Cantera also has a non-ideal equation of state which can be used to compute this contribution.

In [4]:
water = ct.Water()
# Set liquid water state, with vapor fraction x = 0
water.TQ = 298, 0
h_liquid = water.h
# Set gaseous water state, with vapor fraction x = 1
water.TQ = 298, 1
h_gas = water.h

# Calculate higher heating value
Y_H2O = gas["H2O"].Y[0]
HHV = -(h2 - h1 + (h_liquid - h_gas) * Y_H2O) / Y_CH4 / 1e6
print(f"HHV = {HHV:.3f} MJ/kg")
HHV = 55.511 MJ/kg

Generalizing to arbitrary species

We can generalize this calculation by determining the composition of the products automatically rather than directly specifying the product composition. This can be done by computing the elemental mole fractions of the reactants mixture and noting that for complete combustion, all of the carbon ends up as $\mathrm{CO}_2$, all of the hydrogen ends up as $\mathrm{H}_2\mathrm{O}$, and all of the nitrogen ends up as $\mathrm{N}_2$. From this, we can compute the ratio of these species in the products.

In [5]:
def heating_value(fuel):
    """Returns the LHV and HHV for the specified fuel"""
    gas.TP = 298, ct.one_atm
    gas.set_equivalence_ratio(1.0, fuel, "O2:1.0")
    h1 = gas.enthalpy_mass
    Y_fuel = gas[fuel].Y[0]

    # complete combustion products
    X_products = {
        "CO2": gas.elemental_mole_fraction("C"),
        "H2O": 0.5 * gas.elemental_mole_fraction("H"),
        "N2": 0.5 * gas.elemental_mole_fraction("N"),

    gas.TPX = None, None, X_products
    Y_H2O = gas["H2O"].Y[0]
    h2 = gas.enthalpy_mass
    LHV = -(h2 - h1) / Y_fuel / 1e6
    HHV = -(h2 - h1 + (h_liquid - h_gas) * Y_H2O) / Y_fuel / 1e6
    return LHV, HHV

fuels = ["H2", "CH4", "C2H6", "C3H8", "NH3", "CH3OH"]
print("fuel   LHV (MJ/kg)   HHV (MJ/kg)")
for fuel in fuels:
    LHV, HHV = heating_value(fuel)
    print(f"{fuel:8s} {LHV:7.3f}      {HHV:7.3f}")
fuel   LHV (MJ/kg)   HHV (MJ/kg)
H2       119.952      141.780
CH4       50.025       55.511
C2H6      47.511       51.901
C3H8      46.352       50.343
NH3       18.604       22.479
CH3OH     21.104       23.851