# reactor — Contract Hand-maintained for Phase 6; the `## Inputs` table is generated from `src/commands/index.js` (see Phase 9 generator). Keep ≤ 80 lines. ## Inputs (msg.topic on Port 0) | Canonical | Aliases (deprecated) | Payload | Effect | |---|---|---|---| | `data.clock` | `clock` | `msg.timestamp` (ms since epoch) | Calls `source.updateState(timestamp)` — advances the ASM kinetics integrator by `n_iter` time steps that fit between `currentTime` and the supplied timestamp (scaled by `speedUpFactor`). | | `data.fluent` | `Fluent` | `{ inlet: number, F: number, C: number[13] }` | Writes the per-inlet flow rate (`F`, m³/d) and concentration vector (`C`) into `engine.Fs[inlet]` / `engine.Cs_in[inlet]`. | | `data.otr` | `OTR` | numeric | Sets the externally-supplied oxygen transfer rate (used when `kla` is NaN). | | `data.temperature` | `Temperature` | numeric or `{ value: number }` | Sets `engine.temperature` (°C). Non-numeric payloads are warned and ignored. | | `data.dispersion` | `Dispersion` | numeric | PFR only — sets the axial dispersion coefficient `D` (m²/d). | | `child.register` | `registerChild` | child node id (string) | Looks up the sibling node via `RED.nodes.getNode(id)` and delegates to `source.childRegistrationUtils.registerChild` with `msg.positionVsParent`. | Aliases log a one-time deprecation warning the first time they fire. ## Outputs (msg.topic on Port 0/1/2) - **Port 0 (process):** every tick emits the engine's effluent: `{ topic: 'Fluent', payload: { inlet: 0, F, C: number[13] }, timestamp }`. For a PFR an additional `{ topic: 'GridProfile', payload: { grid, n_x, d_x, length, species, timestamp } }` message goes out on the same port before the effluent. - **Port 1 (InfluxDB telemetry):** formatted via `outputUtils.formatMsg(..., 'influxdb')` from `getOutput()` — carries `flow_total`, `temperature`, and one field per ASM3 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`). - **Port 2 (registration):** at startup the node sends one `{ topic: 'child.register', payload: , positionVsParent, distance }` to its parent. ## Events emitted by `source.emitter` - `stateChange` — fires after every `updateState()` that advances the integrator. Payload is the new `currentTime` (ms since epoch). Downstream reactors register via `child.register` and subscribe to this event to pull the upstream effluent on each advance. - `output-changed` — base notification fired by `updateState()` so the BaseNodeAdapter pipeline pushes outputs (currently used only as a heartbeat; effluent is emitted directly from the periodic tick). ## Children accepted - `measurement` — subscribes to `.measured.` on the child's `measurements.emitter`. Recognised reconciliations: `temperature.measured.atEquipment` writes `engine.temperature`; PFR additionally honours `quantity (oxygen).measured.` to reconcile dissolved-oxygen concentration into the nearest grid cell. - `reactor` — registers as the upstream reactor; the downstream `updateState` pulls the upstream effluent into `Fs[0]` / `Cs_in[0]` before integrating.