Problem description
When constructing a ct.Reaction using the reactants/products dict form, any species that appears in both dicts with equal stoichiometry (a net spectator or surface catalyst — one that is consumed and immediately regenerated) is silently re-interpreted as a third-body collider. This corrupts the reaction's input_data: the equation string has the spectator's stoichiometry doubled, and a spurious efficiencies entry is added. The corrupted input_data cannot be round-tripped — writing it to YAML and loading it back raises a CanteraError.
The bug affects ArrheniusRate, InterfaceArrheniusRate, and StickingArrheniusRate (tested on 3.1.0 and 3.2.0).
Steps to reproduce
Run the following script (also attached):
import cantera as ct
print(f"Cantera version: {ct.__version__}")
# A + B <=> C + B (B is a net spectator: appears once on each side)
rxn = ct.Reaction(
reactants={"A": 1, "B": 1},
products={"C": 1, "B": 1},
rate=ct.InterfaceArrheniusRate(1e13, 0, 0),
)
print(dict(rxn.input_data))
Behavior
Actual output:
Cantera version: 3.2.0
{'equation': 'A + B + B <=> B + C + B',
'rate-constant': {'A': 10000000000000.0, 'b': 0.0, 'Ea': 0.0},
'efficiencies': {'B': 1.0}}
Expected output (no change to stoichiometry, no efficiencies key):
{'equation': 'A + B <=> C + B',
'rate-constant': {'A': 10000000000000.0, 'b': 0.0, 'Ea': 0.0}}
B has been added an extra time on each side (stoichiometry incorrectly doubled) and a spurious efficiencies: {B: 1.0} entry has appeared. The same behaviour occurs with ArrheniusRate and StickingArrheniusRate. For higher stoichiometry — e.g. reactants={"A": 1, "B": 2}, products={"C": 1, "B": 2} — the collider is always added with stoichiometry 1 regardless, giving A + 2 B + B <=> 2 B + C + B.
Workaround: passing the same reaction as an equation string produces correct output:
rxn = ct.Reaction(
equation="A + B <=> C + B",
rate=ct.InterfaceArrheniusRate(1e13, 0, 0),
)
# {'equation': 'A + B <=> B + C', 'rate-constant': {...}} ✓
Round-trip failure: writing the corrupted input_data to a YAML file and loading it back raises:
CanteraError: Reaction '2 B + A <=> C + 2 B' specifies efficiency parameters
but does not involve third body colliders.
(For surface reactions. Gas-phase reactions fail similarly because the dict simultaneously contains rate-constant and efficiencies, which are mutually exclusive.)
System information
- Cantera version: 3.1.0 and 3.2.0 (both affected)
- OS: macOS 15.3 (darwin)
- Python version: 3.11
Attachments
See attached cantera_spectator_bug.py for a complete script covering all affected rate types and demonstrating the workaround.
Additional context
We encountered this while writing a Cantera YAML serialiser for RMG-Py (Reaction Mechanism Generator). Surface reactions from the Surface_Abstraction_Beta kinetics family involve a hydrogen-donor species that is regenerated, so it appears on both sides of the equation — e.g. XCOH + XCHOH <=> XCHO + XCHOH. This triggered the misclassification for every such reaction, and the resulting YAML files could not be loaded by Cantera. We have applied a workaround in the RMG writer layer, but it would be cleaner to fix this in the ct.Reaction constructor.
cantera_spectator_bug.py
Issue drafted in collaboration with Claude Code
Problem description
When constructing a
ct.Reactionusing thereactants/productsdict form, any species that appears in both dicts with equal stoichiometry (a net spectator or surface catalyst — one that is consumed and immediately regenerated) is silently re-interpreted as a third-body collider. This corrupts the reaction'sinput_data: the equation string has the spectator's stoichiometry doubled, and a spuriousefficienciesentry is added. The corruptedinput_datacannot be round-tripped — writing it to YAML and loading it back raises aCanteraError.The bug affects
ArrheniusRate,InterfaceArrheniusRate, andStickingArrheniusRate(tested on 3.1.0 and 3.2.0).Steps to reproduce
Run the following script (also attached):
Behavior
Actual output:
Expected output (no change to stoichiometry, no
efficiencieskey):Bhas been added an extra time on each side (stoichiometry incorrectly doubled) and a spuriousefficiencies: {B: 1.0}entry has appeared. The same behaviour occurs withArrheniusRateandStickingArrheniusRate. For higher stoichiometry — e.g.reactants={"A": 1, "B": 2}, products={"C": 1, "B": 2}— the collider is always added with stoichiometry 1 regardless, givingA + 2 B + B <=> 2 B + C + B.Workaround: passing the same reaction as an equation string produces correct output:
Round-trip failure: writing the corrupted
input_datato a YAML file and loading it back raises:(For surface reactions. Gas-phase reactions fail similarly because the dict simultaneously contains
rate-constantandefficiencies, which are mutually exclusive.)System information
Attachments
See attached
cantera_spectator_bug.pyfor a complete script covering all affected rate types and demonstrating the workaround.Additional context
We encountered this while writing a Cantera YAML serialiser for RMG-Py (Reaction Mechanism Generator). Surface reactions from the
Surface_Abstraction_Betakinetics family involve a hydrogen-donor species that is regenerated, so it appears on both sides of the equation — e.g.XCOH + XCHOH <=> XCHO + XCHOH. This triggered the misclassification for every such reaction, and the resulting YAML files could not be loaded by Cantera. We have applied a workaround in the RMG writer layer, but it would be cleaner to fix this in thect.Reactionconstructor.cantera_spectator_bug.py
Issue drafted in collaboration with Claude Code