Skip to content

ct.Reaction(reactants=..., products=...) treats species appearing on both sides as a third-body collider #2115

@rwest

Description

@rwest

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    InputInput parsing and conversion (for example, ck2yaml)

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions