Skip to content

Random reaction networks, Van de Vusse CSTR, and Gillespie SSA (#65) - #72

Merged
tjkessler merged 2 commits into
mainfrom
feature/reaction-random-cstr-gillespie
Oct 15, 2026
Merged

tjkessler merged 2 commits into
mainfrom
feature/reaction-random-cstr-gillespie

Conversation

@tjkessler

Copy link
Copy Markdown
Owner

Refs #65. Fifth PR for the reaction-network datasets. Stacked on #71 (→ #70 → #69). Merge in order #69 → #70 → #71 → this one. Each PR retargets to main when the one below it merges, and CI starts then.

Changes

random_network.sample_random_network(...) builds the composition first, so every sampled reaction is element-balanced by construction.

  • Compositions: the bare elements come first, then each new species is the union of two existing species, with unique compositions and at most max_atoms atoms.
  • Candidates: every reaction with equal element totals, at most max_order reactants, and at most two products, enumerated in a fixed order.
  • Draws: num_reactions candidates without replacement and log-uniform rates, all from one seeded torch.Generator. A seed reproduces the network exactly.
  • Unique compositions rule out 1 → 1 isomerizations, so max_order=1 gives a linear dissociation network. That network uses the exact matrix-exponential integrator.
  • SampledReactionNetwork records the seed, every parameter, and the candidate count, and has a JSON-safe to_dict.

cstr.van_de_vusse_cstr() / VanDeVusseCSTR models A → B → C and 2 A → D with Klatt & Engell (1998) Arrhenius kinetics. Time is in hours and concentrations in mol/L.

  • The literature balance is dc_A/dt ⊃ −k3 c_A², while mass action on 2 A → D consumes two A per event, so the pre-exponential here is k3⁰/2. A test checks the balance against the literature formula.
  • Inputs are reactor temperature (no energy balance) and dilution rate F/V, either constant or as per-interval schedules.
  • rhs computes N r(c; T) + D (c_feed − c). simulate runs RK4 under piecewise-constant inputs, and steady_state uses damped Newton.
  • The nominal benchmark point (114.2 °C, F/V = 14.19 1/h, c_A0 = 5.1) reproduces c_A ≈ 2.14, c_B ≈ 1.09 (Chen, Kremling & Allgöwer 1995).

gillespie.gillespie_ssa(...) is the seeded direct-method SSA on molecule counts.

  • Propensities are a_j = k_j V^{1−o_j} ∏ n_s(n_s−1)…, consistent with the ODE rates in ReactionSystem.reaction_rates.
  • The run stops at t_end, at an absorbing state, or at max_events (marked truncated=True).
  • SSATrajectory.counts_on_grid / concentrations_on_grid and bin_to_grid hold the last value onto a regular grid.

Tests

  • 20 seeds of random networks are all element-balanced, with unique compositions and order ≤ 2. Seeds reproduce exactly, provenance survives a JSON round trip, and rates stay in range. max_order=1 gives a linear dissociation network, and RK4 on a sampled network conserves elements to 1e-10.
  • The CSTR hits the benchmark operating point, the dc_A/dt and dc_D/dt balances match the literature, and simulation converges to the Newton steady state, which is linearly stable. Piecewise-constant inputs reach each regime's steady state, and batched simulation works.
  • For the SSA:
    • propensities match hand-computed values (dimerization needs two molecules, zeroth-order scales with V);
    • a seed reproduces the event path exactly;
    • monomer units are conserved along every path;
    • SSA vs ODE error shrinks with volume (V = 40 vs 2000, three fixed seeds, error < 0.05 and at least 2× smaller);
    • an absorbing state stops the run, max_events truncates it, and grid binning holds the last value.

Verification (macOS arm64, Python 3.13)

  • ruff check and ruff format --check on src/ tests/ pass.
  • pytest -n auto -m "not slow and not distributed and not ray" --cov=koopman_graph --cov-fail-under=90: 3469 passed, 26 skipped, 97.27%. random_network.py and gillespie.py are at 100% and cstr.py at 98%.
  • sphinx-build -W --keep-going passes.

🤖 Generated with Claude Code

Refs #65. Fills in koopman_graph.datasets.reaction.random_network, .cstr,
and .gillespie:

- random_network: sample_random_network builds compositions first (bare
  elements, then unique unions of existing species), enumerates every
  element-balanced reaction with order <= max_order and <= 2 products, and
  draws reactions and log-uniform rates from one seeded generator.
  SampledReactionNetwork records the seed and parameters.
- cstr: VanDeVusseCSTR with Klatt & Engell (1998) Arrhenius kinetics (the
  2A -> D pre-exponential is halved so mass action matches the literature
  balance), temperature and dilution-rate inputs with piecewise-constant
  schedules, RK4 simulation, and a Newton steady state that reproduces
  the benchmark operating point (c_A ~ 2.14, c_B ~ 1.09 at 114.2 C).
- gillespie: seeded direct-method SSA with mass-action propensities
  (falling factorials, V^(1-order)) that converge to the ODE as V grows,
  absorbing-state and max_events handling, and last-value-hold binning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.99329% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/koopman_graph/datasets/reaction/cstr.py 96.93% 1 Missing and 2 partials ⚠️
Files with missing lines Coverage Δ
src/koopman_graph/datasets/reaction/__init__.py 100.00% <100.00%> (ø)
src/koopman_graph/datasets/reaction/gillespie.py 100.00% <100.00%> (ø)
.../koopman_graph/datasets/reaction/random_network.py 100.00% <100.00%> (ø)
src/koopman_graph/datasets/reaction/cstr.py 96.93% <96.93%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Base automatically changed from feature/reaction-catalog-oracles to main October 15, 2026 21:04
@tjkessler
tjkessler merged commit 5536069 into main Oct 15, 2026
13 checks passed
@tjkessler
tjkessler deleted the feature/reaction-random-cstr-gillespie branch October 15, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant