Files
reactor/wiki/Reference-Contracts.md
znetsixe 6b8ae5cfc3 docs(wiki): regenerate topic-contract AUTOGEN block via wiki-gen
Replaces the agent-written placeholder inside Reference-Contracts.md with
the authoritative table generated from src/commands/index.js. Both the
BEGIN and END markers are normalized to the canonical form used by
`@evolv/wiki-gen`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 10:11:49 +02:00

12 KiB
Raw Blame History

Reference — Contracts

code-ref

Note

Full topic contract, configuration schema, and child-registration filters for reactor. Source of truth: src/commands/index.js, src/specificClass.js configure(), and the schema at generalFunctions/src/configs/reactor.json.

Pending full node review (2026-05). Content reflects CONTRACT.md and current source only.

For an intuitive overview, return to the Home.


Topic contract

The registry lives in src/commands/index.js. Each descriptor maps a canonical msg.topic to its handler; aliases emit a one-time deprecation warning the first time they fire.

Canonical topic Aliases Payload Unit Effect
data.clock clock any Push the simulation clock tick (timestamp / dt) to the ASM solver.
data.fluent Fluent object Push the influent stream (payload: {F: flow m3/h, C: [concentrations mg/L]}).
data.otr OTR any Push the current oxygen-transfer rate into the reactor.
data.temperature Temperature any Push the current reactor temperature.
data.dispersion Dispersion any Push a dispersion/mixing parameter update.
child.register registerChild any Register a child node (settler / measurement) with this reactor.

Modes / sources / actions

reactor has no mode, no action allow-lists, no source gating. All topics are accepted as long as the payload shape is valid. (Contrast with rotatingMachine, which gates every input through a mode × source matrix.)


Data model — getOutput() shape

Composed each tick by src/specificClass.js getOutput(). Used to build the Port-1 InfluxDB payload; Port 0 carries the engine's getEffluent envelope directly.

Port-0 process payload

The engine's effluent envelope, emitted on every successful updateState advance:

{
  "topic": "Fluent",
  "payload": { "inlet": 0, "F": <m³/d>, "C": [<13 species, mg/L>] },
  "timestamp": <ms since epoch>
}

For a PFR an additional message is sent before the Fluent on the same port each advance:

{
  "topic": "GridProfile",
  "payload": {
    "grid": [[<13 cells of n_x>]],
    "n_x": <int>,
    "d_x": <m>,
    "length": <m>,
    "species": ["S_O","S_I","S_S","S_NH","S_N2","S_NO","S_HCO","X_I","X_S","X_H","X_STO","X_A","X_TS"],
    "timestamp": <ms since epoch>
  }
}

Port-1 telemetry — scalar keys

Key Type Unit Source
flow_total number m³/d sum(Fs) from effluent envelope
temperature number °C engine.temperature
S_O number mg/L effluent C[0] — capped to saturation by _capDissolvedOxygen
S_I number mg/L effluent C[1]
S_S number mg/L effluent C[2]
S_NH number mg/L effluent C[3]
S_N2 number mg/L effluent C[4]
S_NO number mg/L effluent C[5]
S_HCO number mmol/L effluent C[6] — alkalinity
X_I number mg/L effluent C[7]
X_S number mg/L effluent C[8]
X_H number mg/L effluent C[9]
X_STO number mg/L effluent C[10]
X_A number mg/L effluent C[11]
X_TS number mg/L effluent C[12]

Non-finite species values are omitted from the output (the Number.isFinite guard in getOutput); they are not emitted as null. Pick one convention per consumer (absent vs null) and document it — see .claude/rules/output-coverage.md.

Species ordering

The 13-species vector is fixed:

Index Key Group
0 S_O soluble
1 S_I soluble
2 S_S soluble
3 S_NH soluble
4 S_N2 soluble
5 S_NO soluble
6 S_HCO soluble
7 X_I particulate
8 X_S particulate
9 X_H particulate
10 X_STO particulate
11 X_A particulate
12 X_TS particulate

Don't reshuffle — getOutput() and _flattenEngineConfig() both depend on this exact order, as does additional_nodes/settling-basin and the downstream settler node.

Status badge

getStatusBadge() in src/specificClass.js:

<EngineType>  T=<°C>.X C  F=<m³/d>.XX m³/d  S_O=<mg/L>.XX mg/L

Engine type is the constructor name with Reactor_ stripped (so CSTR or PFR). Badge is always green-dot (no FSM-driven state).


Configuration schema — editor form to config keys

Source of truth: generalFunctions/src/configs/reactor.json plus nodeClass.buildDomainConfig (src/nodeClass.js).

General (config.general)

Form field Config key Default Notes
Name general.name Reactor Human-readable.
(auto-assigned) general.id null Node-RED node id.
Default unit general.unit null Unused by the reactor's own logic (the engines pick up units from the schema's rules.unit strings); kept for parent compatibility.
Log enabled general.logging.enabled true Master switch.
Log level general.logging.logLevel info debug / info / warn / error.

Functionality (config.functionality)

Form field Config key Default Notes
Position vs parent functionality.positionVsParent atEquipment Used in the child-register payload that goes UP to whatever parent registers this reactor. Enum: upstream / atEquipment / downstream.
(hidden) functionality.softwareType reactor Constant.
(hidden) functionality.role Biological reactor for wastewater treatment Constant.

Reactor (config.reactor)

Form field Config key Schema default Range / unit Notes
Reactor type reactor.reactor_type CSTR enum: CSTR / PFR Selected once at configure(). _buildEngine calls .toUpperCase() so pfr and PFR both resolve.
Volume reactor.volume 1000 m³, > 0 Used by mass balance and (PFR) surface-area derivation.
Length reactor.length 10 m, > 0 PFR only. Sets axial extent and grid pitch (d_x = length / n_x).
Resolution reactor.resolution_L 10 integer &ge; 1 PFR only. Grid cell count n_x.
Alpha reactor.alpha 0.5 0..1 PFR only. Inlet boundary blend: 0 = pure Danckwerts, 1 = fully mixed inlet.
Inlets reactor.n_inlets 1 integer &ge; 1 Fs[] / Cs_in[] array size.
kLa reactor.kla 0 1/h, &ge; 0; set NaN to disable Enables internal aeration OTR = kla &middot; (sat(T) &minus; S_O). When NaN, data.otr is honoured instead.
Time step reactor.timeStep 0.001 &ge; 0.0001 Schema declares unit h; baseEngine.js converts by &divide; 86400 (treating it as seconds). See Limitations — timeStep unit mismatch.
Speed-up factor reactor.speedUpFactor 1 &ge; 1 Multiplies wall-clock Δt when computing n_iter. 2 means twice as many internal steps per second.

Initial state (config.initialState)

13 starting concentrations, all written into the engine's state (CSTR: single row; PFR: replicated across all n_x grid cells at construction).

Form field Config key Schema default HTML default Unit Notes
Initial S_O initialState.S_O 0 check editor mg/L Capped to saturation on the first tick.
Initial S_I initialState.S_I 30 check editor mg/L Inert soluble COD.
Initial S_S initialState.S_S 70 check editor mg/L Readily biodegradable substrate.
Initial S_NH initialState.S_NH 25 check editor mg/L Ammonium — declines with nitrification.
Initial S_N2 initialState.S_N2 0 check editor mg/L Dinitrogen.
Initial S_NO initialState.S_NO 0 check editor mg/L Nitrate / nitrite.
Initial S_HCO initialState.S_HCO 5 check editor mmol/L Alkalinity.
Initial X_I initialState.X_I 1000 check editor mg/L Inert particulate COD.
Initial X_S initialState.X_S 100 check editor mg/L Slowly biodegradable substrate.
Initial X_H initialState.X_H 2000 check editor mg/L Heterotrophic biomass.
Initial X_STO initialState.X_STO 0 check editor mg/L Stored COD in biomass.
Initial X_A initialState.X_A 200 0.001 mg/L Footgun. HTML default in reactor.html (per CONTRACT.md) is effectively zero, disabling nitrification. Always verify the deployed form value.
Initial X_TS initialState.X_TS 3500 check editor mg/L Total suspended solids — drives downstream settler split.

Warning

The HTML form supplies its own defaults; for fields where they differ from the schema (notably X_A), the HTML wins at deploy time. Either match the schema in the HTML or audit every deployed flow.

Unit policy

reactor does not declare a UnitPolicy in specificClass. Units are carried in the schema's rules.unit strings (m³, m, 1/h, mg/L, mmol/L) and consumed by the engines without normalisation through MeasurementContainer's canonical-unit rule. Notable internal conversions:

Quantity What the engine uses internally Where converted
timeStep days baseEngine.js line ~40: timeStep = config.timeStep / 86400
Fs m³/d (assumed by mass-balance formulas) not converted — the caller is expected to push m³/d on data.fluent
temperature °C stored as supplied (Celsius); _calcOxygenSaturation(T) expects °C

This is a known divergence from the platform-wide canonical-unit rule (Pa / m³/s / W / K). Tracked.


Child registration

Source: src/specificClass.js configure() (ChildRouter wiring) + BaseReactorEngine._connectMeasurement / _connectReactor.

Software type Filter Wired to Side-effect
measurement asset.type = 'temperature', positionVsParent = atEquipment engine._connectMeasurement_updateMeasurement Writes engine.temperature. CSTR only honours this.
measurement asset.type = 'quantity (oxygen)', positionVsParent = <numeric distance> engine._connectMeasurementReactor_PFR._updateMeasurement PFR only. Maps measurement to nearest grid cell by clamp(round(pos / length &times; n_x), 0, n_x &minus; 1). Writes into state[cell][S_O_INDEX].
reactor positionVsParent = 'upstream' engine._connectReactor Subscribes to upstream reactor's stateChange. Each event triggers downstream updateState, which pulls upstream getEffluent into Fs[0] / Cs_in[0] before integrating.

Not a child: diffuser

diffuser (Equipment Module) is not registered as a reactor child. It feeds aeration via the data.otr topic on Port 0. No child-registration handshake is involved. If you want the diffuser's OTR to drive the reactor, wire the diffuser's process output to the reactor's input directly.

Unrecognised softwareType

BaseReactorEngine.registerChild logs Unrecognized softwareType: <x> and drops the registration. There is no valve, rotatingMachine, etc. acceptance path.


Page Why
Home Intuitive overview
Reference — Architecture Code map, integration sequence, kinetics
Reference — Examples Shipped flows + debug recipes
Reference — Limitations Known issues and open questions
EVOLV — Topic Conventions Platform-wide topic rules
EVOLV — Telemetry Port 0 / 1 / 2 InfluxDB layout