# Reference — Examples ![code-ref](https://img.shields.io/badge/code--ref-0e34403-blue) > [!NOTE] > Every example flow shipped under `nodes/reactor/examples/`, plus how to load them, what they show, and the debug recipes that go with them. Live source: `nodes/reactor/examples/`. > > Pending full node review (2026-05). The current flows predate the standard 3-tier example-flow rework that `rotatingMachine` has completed; planned upgrade is tracked in the EVOLV superproject memory ("Example Flows" TODO). --- ## Shipped examples | File | Tier | Dependencies | What it shows | |:---|:---:|:---|:---| | `basic.flow.json` | 1 | EVOLV only | Single CSTR with one inlet. Inject `data.fluent` to set influent, `data.clock` to advance the integrator; watch `Fluent` effluent on Port 0 and InfluxDB scalars on Port 1. | | `integration.flow.json` | 2 | EVOLV only | Upstream `reactor` → `reactor` → `settler` chain. The downstream reactor registers the upstream via `child.register positionVsParent=upstream`; on each upstream `stateChange` the downstream pulls effluent and advances. | | `edge.flow.json` | 3 | EVOLV only | PFR with axial dispersion (`data.dispersion`) and multi-inlet (`n_inlets > 1`). Emits both `GridProfile` and `Fluent` per advance. | > [!IMPORTANT] > **Screenshots needed.** Editor capture of each example flow. Save as `wiki/_partial-screenshots/reactor/{01-basic-cstr,02-chain,03-pfr-edge}.png`. Replace these callouts with image links once captured. The legacy `additional_nodes/recirculation-pump` and `additional_nodes/settling-basin` Node-RED nodes are shipped from this repo but are not yet refactored to BaseDomain — they aren't part of these examples. --- ## Loading a flow ### Via the editor 1. Open the Node-RED editor at `http://localhost:1880`. 2. Menu → Import → drag the JSON file. 3. Click Deploy. ### Via the Admin API ```bash curl -X POST -H 'Content-Type: application/json' \ --data @nodes/reactor/examples/basic.flow.json \ http://localhost:1880/flows ``` --- ## Example — Basic CSTR Single-reactor flow with one inlet and the minimum set of inputs needed to drive nitrification. ### What to do after deploy 1. Inject `data.temperature` with `payload: 15` (or whatever process T you want). Optional — default is 20 °C. 2. Inject `data.fluent` with: ```json { "topic": "data.fluent", "payload": { "inlet": 0, "F": 1000, "C": [0, 30, 70, 25, 0, 0, 5, 1000, 100, 2000, 0, 200, 3500] } } ``` Note `C[11] = 200` (X_A — autotroph biomass). If you copy the HTML default of `0.001`, nitrification never starts. 3. If `kla > 0` is configured, you can skip OTR injection; the engine aerates internally. Otherwise inject `data.otr` with a positive scalar. 4. Inject `data.clock` repeatedly (or rely on the periodic tick — `tickInterval = 1000` ms wall-clock). Each advance integrates `n_iter = floor(speedUpFactor · Δt / timeStep_days)` internal steps. 5. Watch the debug tap on Port 0: `Fluent` envelopes with the 13-species effluent. `S_NH` should fall, `S_NO` should rise — nitrification is proceeding. > [!IMPORTANT] > **GIF needed.** Demo recording of `S_NH` ↓ / `S_NO` ↑ over 30 simulated days. Save as `wiki/_partial-gifs/reactor/01-basic-cstr.gif`. --- ## Example — Reactor chain Upstream → downstream coupling demo. The downstream reactor registers the upstream via: ```json { "topic": "child.register", "payload": "", "positionVsParent": "upstream" } ``` On every upstream `stateChange`, `engine._connectReactor` triggers downstream `updateState`. That call first reads `upstream.getEffluent` into the downstream's `Fs[0]` / `Cs_in[0]`, then integrates. So one `data.clock` to the upstream advances the whole chain. > [!NOTE] > Pending full node review (2026-05). The flow currently in `integration.flow.json` may not yet conform to the multi-tab layout standard (Process Plant / Dashboard UI / Demo Drivers / Setup) described in `.claude/rules/node-red-flow-layout.md` — planned upgrade tracked in the EVOLV "Example Flows" TODO. --- ## Example — PFR edge Plug-flow reactor with axial discretization. After deploy: 1. Inject `data.dispersion` with `payload: ` to set the axial dispersion coefficient `D`. 2. Inject one or more `data.fluent` messages with distinct `inlet` indices (0..`n_inlets − 1`). 3. Drive with `data.clock` as usual. 4. Watch Port 0: each advance emits a `GridProfile` **before** the `Fluent`. The grid has `n_x` rows, 13 columns each. 5. Add a `measurement` child with `asset.type = 'quantity (oxygen)'` and a numeric `positionVsParent` (e.g. `5` for 5 m from the inlet). On each measurement event the PFR engine writes the value into the nearest grid cell's `S_O`. Stability tips: - `Pe_local = d_x · sum(Fs) / (D · A)` must be `< 2` — if you see `Local Peclet number ... is too high!`, either increase `resolution_L` (more cells, smaller `d_x`) or raise `D`. - `Co_D = D · timeStep / d_x²` must be `< 0.5` for the explicit FD scheme — if you see `Courant number ... is too high!`, decrease `timeStep`. --- ## Debug recipes | Symptom | First thing to check | Where to look | |:---|:---|:---| | `S_NH` stays at its initial value — nitrification not proceeding | `initialState.X_A` is effectively zero (HTML default is `0.001` mg/L). Set to `~50` or higher to seed autotrophs. | `reactor.html` ↔ `generalFunctions/src/configs/reactor.json` `initialState.X_A` | | `Fluent` payload `F = 0` | No `data.fluent` arrived, or `Fs[0]` is still 0 (no inlet flow). Check the message payload shape: `{inlet, F, C}`. | `src/commands/handlers.js` `dataFluent`, engine `setInfluent` | | `Fluent` payload appears, but `C` array is all zeros / unchanged | `data.clock` not arriving, or `n_iter = 0` (timestamp delta too small for the configured `timeStep`). Bump `speedUpFactor` or check that clock injects are firing. | `engine.updateState` in `baseEngine.js` | | PFR `GridProfile` not emitted | `reactor.reactor_type` is `CSTR` — only PFR has a grid profile. | `nodeClass._emitOutputs`, `pfr.getGridProfile` | | `temperature` ignored | Payload is non-numeric, or wrapped as `{value: ...}` with `value` non-finite. Look for `Invalid temperature input: ` in the log. | `baseEngine.js` `setTemperature` setter | | Temperature child measurement not reconciling | The child's `asset.type` must be exactly `'temperature'` and `positionVsParent = atEquipment`. Anything else logs `Type '' not recognized for measured update.` | `baseEngine.js` `_updateMeasurement` | | `Local Peclet number ... is too high!` warning on every PFR `updateState` | Either `D` is too small, or `d_x` is too large. Increase `resolution_L` or set a larger dispersion. | `pfr.updateState` Peclet guard | | `Courant number ... is too high!` warning | `timeStep` is too large for the configured `D`. Reduce it. | `pfr.updateState` Courant guard | | Settler downstream not updating | Settler must subscribe to the **reactor's `emitter`**, not `reactor.measurements.emitter`. Historical bug in `settler/src/specificClass.js` `_connectReactor` (fixed 2026-03-02). | upstream chain wiring, `settler._connectReactor` | | `wiki:datamodel` autogen script slow / timing out | `mathjs` cold-start is ~13 s. The current 60 s wrapper sometimes times out. | known limitation; fall back to the hand-curated Concrete sample in `CONTRACT.md` `Home.md` | | `reactor_type: 'pfr'` (lowercase) silently runs CSTR | Schema validator lowercases the enum; `_buildEngine` calls `.toUpperCase()` to compensate. If you stripped that guard, lowercase `pfr` falls through to the default branch (CSTR). | `src/specificClass.js` `_buildEngine` | | `data.otr` value ignored | `reactor.kla > 0`. The engine prefers internal `kla · (sat − S_O)` over external OTR. Set `kla = NaN` to enable external OTR. | `cstr.tick` / `pfr.tick` `klaIsNaN` branch | > Never ship `enableLog: 'debug'` in a demo — the kinetics engines log per-step on debug, which fills the container log within seconds. --- ## Docker compose snippet To bring up Node-RED + InfluxDB with EVOLV nodes pre-loaded: ```yaml # docker-compose.yml (extract) services: nodered: build: ./docker/nodered ports: ['1880:1880'] volumes: - ./docker/nodered/data:/data/evolv influxdb: image: influxdb:2.7 ports: ['8086:8086'] ``` Full file: [EVOLV/docker-compose.yml](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/docker-compose.yml). --- ## Related pages | Page | Why | |:---|:---| | [Home](Home) | Intuitive overview | | [Reference — Contracts](Reference-Contracts) | Topic + config + child filters | | [Reference — Architecture](Reference-Architecture) | Code map, kinetics engines, integration sequence | | [Reference — Limitations](Reference-Limitations) | Known issues and open questions | | [settler — Examples](https://gitea.wbd-rd.nl/RnD/settler/wiki/Reference-Examples) | The typical downstream Unit | | [EVOLV — Topology Patterns](https://gitea.wbd-rd.nl/RnD/EVOLV/wiki/Topology-Patterns) | Where reactor fits in a larger plant |