Files
reactor/wiki/Reference-Examples.md
znetsixe cb49bb8b4d docs(wiki): full 5-page wiki matching the rotatingMachine reference format
Replaces the prior stub/partial wiki with a Home + Reference-{Architecture,
Contracts,Examples,Limitations} + _Sidebar structure. Topic-contract and
data-model sections wrapped in AUTOGEN markers for the future wiki-gen tool.
Source-vs-spec contradictions surfaced and flagged inline (not silently
fixed). Pending-review notes mark sections that need a full node review.

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

9.1 KiB

Reference — Examples

code-ref

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 reactorreactorsettler 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

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:
    {
      "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 &middot; &Delta;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:

{
  "topic": "child.register",
  "payload": "<upstream-reactor-node-id>",
  "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: <m²/d> to set the axial dispersion coefficient D.
  2. Inject one or more data.fluent messages with distinct inlet indices (0..n_inlets &minus; 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 &middot; sum(Fs) / (D &middot; 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 &middot; 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.htmlgeneralFunctions/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: <raw> 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 '<x>' 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 &middot; (sat &minus; 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:

# 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.


Page Why
Home Intuitive overview
Reference — Contracts Topic + config + child filters
Reference — Architecture Code map, kinetics engines, integration sequence
Reference — Limitations Known issues and open questions
settler — Examples The typical downstream Unit
EVOLV — Topology Patterns Where reactor fits in a larger plant