Skip to content
Edit on GitHub

The chemistry solver

verifiedAgainst f1eaefe · verifiedOn 2026-09-10 · the automated staleness banner is planned, not built.

VoxelSandbox.Chemistry is a plain-C# control-volume solver: given a VesselCharge, temperature, volume, baked reaction definitions, and a supplied energy increment, it proposes one fixed simulation tick and either returns the complete next state or refuses it. VesselSolver is the transaction owner. It validates the whole request before chemistry moves, evaluates every reaction from the same charge snapshot, projects their competing extents together, resolves reaction and applied heat through any phase boundary, then verifies pressure and mass conservation. The result is deliberately independent of Unity and host math libraries, so the same state and inputs produce the same calculation in an EditMode fixture, an in-world vessel, or a future authoritative server.

Symbol File Responsibility
VesselSolver Chemistry/VesselSolver.cs:81 Owns the all-or-nothing tick: validation, canonical reaction order, coupled proposal/application, thermal resolution, pressure and mass checks
ReactionEvaluator.TryEvaluate Chemistry/ReactionEvaluator.cs:94 Forms temperature-corrected thermodynamics, Q, Arrhenius rate, surface term, and signed net rate for one reaction at one charge snapshot
DeterministicSubstepping Chemistry/DeterministicSubstepping.cs:10 Converts the predicted limiting-reagent fraction into an equal-duration power-of-two count from 1 to 64
ReactionExtentMath Chemistry/ReactionExtentMath.cs:21 Clamps ξ = r·dt by the limiting consumed species, then preflights and applies Δn = ν·ξ without a partial mutation
PhaseTransitionMath Chemistry/PhaseTransition.cs:81 Transfers moles at a solid/liquid or liquid/gas boundary and returns residual energy for the next thermal step
DeterministicMath Chemistry/DeterministicMath.cs:12 Fixed-coefficient IEEE-754 implementations of Exp, Ln, Pow, and Sqrt, with no System.Math or Unity dependency
ProcessTimeScale Chemistry/ProcessTimeScale.cs:10 One global policy: 20 simulation ticks/s and a 60× multiplier on kinetic rates only
flowchart TD
  INPUT["VesselCharge + T + V\ntick input"]
  VALIDATE["VesselSolver\nvalidate and canonicalise"]
  STEPS["DeterministicSubstepping\npower-of-two substeps"]
  EVAL["ReactionEvaluator\nthermo, Q, kinetics"]
  PROJECT["VesselSolver\ncoupled extent projection"]
  EXTENT["ReactionExtentMath\nclamp then apply Δn"]
  THERMAL["VesselSolver\nreaction + applied energy"]
  PHASE["PhaseTransitionMath\nlatent heat at boundary"]
  RESULT["VesselTickResult\nT, pressure, heat, mass drift"]
  EVENTS["ScienceEventBuffer\nappend after accepted tick"]

  INPUT --> VALIDATE --> STEPS --> EVAL --> PROJECT --> EXTENT --> THERMAL --> PHASE --> EVAL
  PHASE --> RESULT
  RESULT --> EVENTS

VesselSolver.TryAdvanceTick (VesselSolver.cs:106) exposes convenience overloads, including an event-recording path and a phase-aware path. All lead to TryAdvanceTickCore (:215). Before entering the substep loop, it rejects bad inputs, a reaction set larger than 128, unsorted/invalid phase-transition data, invalid event capacity, and a duplicate reaction id. It measures initial mass and ideal-gas pressure before changing the charge.

For a full tick, ProcessTimeScale.ProcessSecondsPerSimulationTick is 3 process seconds: 60 / 20. TryChooseSubstepCount predicts the most demanding reaction and DeterministicSubstepping.TryCalculateSubstepCount quantises upward to 1, 2, 4, ..., 64, so a normal substep changes its limiting reagent by at most 5%. The thermal-energy cap adds a second bound: aggregate reaction heat may move temperature by at most 10% in one substep. Both limits are stated approximations, not hidden physical claims.

Each substep begins with ReactionEvaluator.TryEvaluate (ReactionEvaluator.cs:94). It uses ideal-gas partial pressure for gas activity and unit activity for pure solids/liquids, produces ΔrH, ΔrG, K, Q, the Arrhenius constant, and r = k·Πaᵢ^orderᵢ·S·(1 − Q/K). A missing reactant in the intended direction is a valid state that makes CanProceed false; missing catalogue thermodynamics or an out-of-range Shomate evaluation is an error.

The tick does not apply reactions one at a time. TryAdvanceCoupledReactionSubstep (VesselSolver.cs:443) derives every proposed extent from one snapshot, then finds one conservative scale for shared-reagent availability and the aggregate heat budget. Only then does ReactionExtentMath.TryApplyExtent (ReactionExtentMath.cs:93) mutate the charge. The three-pass apply validates every resulting quantity, reserves any trace-ledger capacity, and finally writes all species; a rejected extent leaves no half-reaction behind.

Heat is then resolved in sequence. TryResolveThermalEnergy (VesselSolver.cs:773) first heats or cools to the next reachable transition temperature, asks PhaseTransitionMath.TryResolveAtTransition (PhaseTransition.cs:88) to spend latent heat at constant temperature, then carries remaining energy onward. A substep therefore cannot jump across melting or boiling. Once all substeps finish, the solver calculates post-tick pressure, compares mass before/after against its absolute-plus-relative tolerance, and only then appends science events.

  1. A tick is a transaction. Validate capacity and inputs before mutation; preflight an extent before adjustment; record ScienceEvents only after mass conservation passes. An expected invalid simulation request returns false with a VesselTickResult.Error, not a partly-updated charge.
  2. Reaction order cannot be catalogue order. TryBuildCanonicalReactionOrder (VesselSolver.cs:649) sorts on physical definition fields and treats the id only as the final tie-breaker. Renumbering a reaction must not change its chemistry.
  3. Competing reactions read one state. Keep the snapshot proposal plus one shared scale in the coupled-substep path. Sequentially applying one reaction before evaluating its neighbour would make results depend on ordering and can overspend a shared reagent.
  4. No negative moles. All callers must clamp through ReactionExtentMath.TryClampExtent (ReactionExtentMath.cs:30); TryApplyExtent deliberately proves that invariant again before writing.
  5. Only kinetics are accelerated. The 60× ProcessRateMultiplier is applied to ReactionEvaluator’s net rate. Do not scale $K$, pressure, heat capacity, voltage, or energy a second time.
  6. Do not reintroduce host math. DeterministicMath exists because save determinism cannot rest on a platform libm. New solver transcendental work must use it and preserve fixed evaluation order.
  7. Phase boundaries consume energy before temperature changes. Keep transitions in ascending stable key order and retain the heat-to-boundary → latent heat → residual-energy sequence.
  • Upstream: VoxelSandbox.Data bakes authored SubstanceDefinition and ReactionDefinition assets into the SubstanceTable and ChemicalReaction[] that this assembly accepts. See Catalogues & authoring.
  • Downstream: VoxelSandbox.Industry’s VesselDomain owns a ScienceVesselRun, drives it at the 20 Hz simulation cadence from wall-clock deltas, and supplies environment heat as the solver’s applied-energy input. The Unity VesselRuntime is just its MonoBehaviour bridge.
  • Evidence and tests: Assets/_Game/Tests/EditMode/Chemistry/VesselSolverTests.cs, DeterministicSubsteppingTests.cs, ReactionExtentMathTests.cs, and ThermalEnergyMathTests.cs exercise the transaction, substep, non-negative-moles, and latent-heat contracts. The thermodynamic and kinetic evidence belongs in Docs/CHEMISTRY_FOUNDATIONS.md §28.4–28.9 and Docs/CHEMISTRY_SOURCES.md.
  • Catalogues & authoring — the Unity authoring layer that creates the solver’s immutable inputs.
  • Add a scientific route — a worked example of adding a source-backed substance/reaction without inventing kinetics.
  • Docs/MASTERPLAN.md §28.4–28.9 and §36.1; Docs/CHEMISTRY_FOUNDATIONS.md §28.7 for the tick’s first-law and reaction-extent contracts.

User-contributed notes

Corrections, clarifications, and practical tips for this page. Anonymous is fine — a name is optional. Basic Markdown works: **bold**, *italic*, `code`, and links.

Notes policy

Notes are lightly filtered for spam and may be edited or removed. Keep them about this page — no support requests, no personal data, nothing you would not publish. Links are limited and marked nofollow.

  1. Loading notes…