Files
EVOLV/wiki/Functional-Overview.md
znetsixe 123ef6fca3 wiki + submodules: Functional Overview page + bump pumpingStation / generalFunctions / monster
Submodule pointers
- pumpingStation: realistic basin defaults, ramp-foot visual fix, manual-mode
  observability, new 02-Dashboard.json (charts + raw-output table), wiki
  Home/Reference-Examples with screenshots + demo GIF.
- generalFunctions: pumpingStation config schema defaults aligned with the
  new editor drag-in values; startLevel description corrected (ramp foot is
  inflowLevel, not startLevel).
- monster: examples cleanup — drop pre-refactor flows, ship single
  02-integrated-e2e.json.

Wiki
- New wiki/Functional-Overview.md: companion to Architecture covering the
  process side — what each node physically represents and which control
  objective it serves.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:52:36 +02:00

25 KiB
Raw Permalink Blame History

Functional Overview

code-ref view

Note

What each EVOLV node physically represents and what control objective it serves. Companion to Architecture, which describes the code shape; this page describes the process the code models. Read this when you want to know "what is actually happening in the water", not "what is happening in the JavaScript".


Plant-level process flow

Real water flows left to right through real equipment. EVOLV models a subset of that equipment as Node-RED nodes. The coloured nodes below are modelled by EVOLV; the grey ones are upstream / downstream of the EVOLV-modelled section.

flowchart LR
    inf["Influent"]:::extern
    scr["Coarse screens"]:::extern
    grit["Grit chamber"]:::extern
    ps1["Inlet lift station"]:::pc
    primary["Primary settler"]:::extern
    reactor["Aerobic reactor"]:::unit
    secondary["Secondary settler"]:::unit
    disinf["Disinfection / UV"]:::extern
    eff["Effluent"]:::extern
    sludge["Sludge handling"]:::extern

    inf --> scr --> grit --> ps1 --> primary --> reactor --> secondary --> disinf --> eff
    secondary -. RAS .-> reactor
    secondary -. WAS .-> sludge

    classDef pc fill:#0c99d9,color:#fff,stroke:#075a82,stroke-width:2px
    classDef unit fill:#50a8d9,color:#000,stroke:#2c7ba8,stroke-width:2px
    classDef extern fill:#f0f0f0,color:#666,stroke:#bbb,stroke-width:1px,stroke-dasharray:4 4

Plant step to EVOLV node mapping

Plant step What happens physically EVOLV node(s)
Inlet lift station Wet-well buffer; pumps raise water to plant elevation pumpingStation + machineGroupControl + rotatingMachine
Aerobic reactor Bacteria consume NH4, COD under aeration; O2 supplied by diffusers reactor + diffuser + measurement
Secondary settler Biomass settles by gravity; clean water overflows; sludge returns or is wasted settler + rotatingMachine (RAS pump)
Flow distribution Multi-valve manifold for effluent split, airflow distribution, RAS proportioning valveGroupControl + valve
Composite sampling Flow-proportional sample buildup for lab analysis monster + measurement
Telemetry to UI Time-series storage + dashboard provisioning dashboardAPI (Grafana) + Port 1 to InfluxDB

pumpingStation — wet-well lift station

Physical view

A wet-well buffer at low elevation. Inflow arrives by gravity from the upstream sewer; pumps lift water to plant elevation. Level is the controlled variable.

                  inflow
                    |
                    v
        +---------------------+
        |                     |  <-- overflow weir (safety, alarm)
        |                     |
        |  ~ ~ ~ ~ ~ ~ ~ ~ ~  |  <-- startLevel  (e.g. 80% of basin)
        |                     |
        |                     |  <-- band where 1 pump runs
        |                     |
        |  ~ ~ ~ ~ ~ ~ ~ ~ ~  |  <-- stopLevel   (e.g. 30%)
        |                     |
        |                     |  <-- band where pumps idle
        |                     |
        |  ___________________|  <-- dryRunLevel (cutoff, alarm)
        |  |    |    |    |   |
        |  v    v    v    v   |
        |  P1   P2   P3   P4  |
        +--|----|----|----|---+
           v    v    v    v
              outflow (to next stage)

Process variables

Variable Typical range Unit Source
Inflow Q_in 0 to 2000 m3/h gravity sewer; measured by inlet flow meter
Outflow Q_out 0 to 2000 m3/h sum of running pump flows
Level 0 to 5 m level sensor (radar, ultrasonic, hydrostatic)
Volume 0 to V_max m3 basin geometry × level
Predicted ETA full / empty seconds s (V_max V) / (Q_in Q_out)

Control objective

Goal Mechanism
Keep level in operating band Schmitt-trigger hysteresis: start pumps at startLevel, stop at stopLevel
Avoid rapid pump cycling stopLevel strictly below startLevel (deadband)
Avoid overflow High-level alarm; safety controller can override
Avoid running dry Low-level cutoff stops all pumps
Stay near pump BEP Demand is shared by machineGroupControl using each pump's curve

EVOLV implementation

  • pumpingStation.configure() builds a BasinGeometry from config.basin plus a FlowAggregator that integrates volume from inflow / outflow measurements per tick.
  • Level + inflow + outflow arrive as measurement children with positions inflow, outflow, atequipment for the level.
  • The control strategy module picks one of several modes (level-based, flow-based, time-based). The level-based strategy implements the Schmitt trigger and shifted-ramp behaviour.
  • SafetyController guards against panic / dry-run / overfill conditions and can block dispatch.

rotatingMachine — single pump or compressor

Physical view

A centrifugal pump (or compressor) characterised by its supplier curves. Speed sets where on the curve the machine operates. The operating point is the intersection of pump curve and system curve.

     Q-H curve (head vs flow)         Q-P curve (power vs flow)
     ^                                 ^
   H |  *                            P |              *
     |    *                            |          *
     |       *  <-- BEP                |       *
     |          *                      |    *  <-- BEP region
     |             *                   | *
     |________________ Q                |____________________ Q
         flow [m3/h]                            flow [m3/h]

  Operating point = (system curve) intersect (pump curve at running speed)

Process variables

Variable Typical range Unit
Flow Q 1 to 1000 m3/h
Head H (or differential pressure) 1 to 100 m (or bar)
Power P 1 to 500 kW
Efficiency η 0.3 to 0.85
Speed N 0 to 100 % of rated

Physical state machine (water-side)

stateDiagram-v2
    [*] --> off
    off --> warmingup: cmd.startup
    warmingup --> operational: warmup time elapsed
    operational --> accelerating: setpoint changes
    accelerating --> operational: target reached
    operational --> decelerating: setpoint reduced
    decelerating --> operational: target reached
    operational --> coolingdown: cmd.shutdown
    coolingdown --> off: cooldown time elapsed
    operational --> emergencystop: cmd.estop
    warmingup --> emergencystop: cmd.estop
    emergencystop --> off: cmd.reset

Control objective

Goal Mechanism
Deliver commanded flow / speed Internal FSM ramps speed up / down within configured rates
Predict outputs before sensors react Q + P + η predicted from speed + measured pressure differential via characteristic curves
Detect drift drift/ module compares predicted vs measured; fires HealthStatus levels 0..3
Protect during warmup / cooldown Some transitions are non-interruptible (configurable per machine)

EVOLV implementation

  • curves/ module loads supplier characteristic curves (Q-H, Q-P, Q-η); supports multi-dataset assets.
  • prediction/ module interpolates curve values at current operating point.
  • state/ module owns the FSM with configurable warmup / cooldown / ramp times.
  • drift/ module assesses prediction quality and emits HealthStatus.

machineGroupControl — multi-pump load sharing

Physical view

Multiple pumps share a common discharge header. The group operating point is where the sum of pump curves intersects the system curve. The load-sharing problem is: which pumps run at what speed to deliver demand at the lowest combined power.

   Pump A curve     Pump B curve     Pump C curve
        ^                ^                ^
        |                |                |
        +-> share Q_A -->+-> share Q_B -->+-> share Q_C
                              |
                       sum = Q_demand
                              v
                      total power = P_A + P_B + P_C
                       minimize subject to per-pump curve constraints

Process variables

Variable Source
Group demand Q_d Inbound from parent (pumpingStation, UI, scheduler)
Per-pump setpoint Computed each tick
Pressure (downstream) Measurement child, position downstream
Group totals (flow, power, efficiency) Sum / weighted average of per-pump predictions

Control objective

Goal Mechanism
Deliver Q_d at lowest total power GroupOperatingPoint solver picks per-pump shares
Avoid frequent pump start / stop Hysteresis on pump count + NCog switching metric
Stay near per-pump BEP Penalise operating points far from BEP in the solver
Settle latest demand if upstream fires faster than children absorb DemandDispatcher (LatestWinsGate) keeps only the freshest dispatch in flight

EVOLV implementation

  • dispatch/DemandDispatcher wraps a LatestWinsGate so a rapid stream of demands collapses to the most recent.
  • efficiency/groupEfficiency computes mean group efficiency at the current shares.
  • totals/TotalsCalculator aggregates flow / power across active machines.

valveGroupControl — multi-valve flow distribution

Physical view

Multiple valves on a distribution manifold. Each valve has a flow coefficient K_v that varies with position. The group must split a total available flow between branches.

                upstream pressure P_up
                       |
                       v
                  +---+---+---+
                  |   |   |   |
                  v   v   v   v
                  Kv1 Kv2 Kv3 Kv4    <-- per-valve K_v
                  |   |   |   |
                  Q1  Q2  Q3  Q4     <-- per-branch flow

  Q_i = K_v_i * sqrt(P_up - P_branch_i)
  sum(Q_i) = Q_available  (from upstream flow source)

Process variables

Variable Typical range Unit
Valve position 0 to 100 %
K_v at full open 1 to 1000 m3/h / sqrt(bar)
Differential pressure across valve 0.1 to 5 bar
Per-branch flow split percentage of total %

Control objective

Goal Mechanism
Achieve target per-branch flow split Solve per-valve K_v from inverse characteristic
Respect upstream availability Read total flow from registered flow source (pumpingStation, MGC, etc.)
Honour valve position limits Clamp K_v to physical valve range

Note on softwareType registration

valveGroupControl.configure() registers five softwareTypes — valve, machine, machinegroup, pumpingstation, valvegroupcontrol. Only valve is a true S88 child. The other four are flow-source registrations: VGC reads their flow output to know how much it has to distribute.


reactor — bioreactor (ASM kinetics)

Physical view

A tank where bacteria consume substrate under aeration. Continuous-flow operation (CSTR or PFR). The state of the reactor is described by 13 ASM state variables (soluble + particulate fractions of organic matter, ammonia, nitrate, biomass, alkalinity, oxygen).

                 air from diffuser
                       |
                       v   bubbles
        Q_in   +-------+-------+   Q_out
   ---->|     ~  ~  ~  ~  ~  ~ |---->
        |    ~  ~  ~  ~  ~  ~  |
   C_in |  ~     ~  ~  ~     ~ | C_out
        |    ~  ~  ~  ~  ~  ~  |
        |     ~  ~  ~  ~  ~  ~ |
        +----------------------+

  Mass balance per ASM component i:
    V * dC_i/dt = Q_in * C_in_i  -  Q_out * C_out_i  +  V * r_i(C, T, DO, ...)
                  inflow term     outflow term       reaction term

Process variables

Variable Typical range Unit
Volume V 100 to 10000 m3
Hydraulic retention time HRT 4 to 24 h
Sludge retention time SRT 5 to 30 d
MLSS 2000 to 5000 mg/L
Temperature 5 to 30 degC
DO setpoint 1 to 3 mg/L
NH4 effluent target < 1 mg/L
NO3 effluent 0 to 15 mg/L

Control objective

Goal Mechanism
Maintain DO setpoint DO measurement → diffuser airflow loop (closed externally)
Achieve effluent quality Manage HRT via reactor inflow, SRT via WAS rate
Operate stably across temperature Kinetics are temperature-corrected via Arrhenius factors

Engine choice

Engine When to use
CSTR Single well-mixed tank or short reactor
PFR Long, narrow plug-flow reactor; discretised into grid cells along the flow path

Set via config.reactor_type.

EVOLV implementation

  • kinetics/baseEngine.js — common state vector + boundary-condition handling.
  • kinetics/cstr.js — single-zone integrator.
  • kinetics/pfr.js — multi-zone PFR with a grid.
  • Diffuser fires data.otr on its emitter; reactor subscribes and treats OTR as an O2 source term.
  • Downstream settler subscribes to reactor stateChange; the settler reads effluent composition each tick.

settler — secondary clarifier

Physical view

A wide, shallow tank where biomass settles by gravity. A sludge blanket forms at the bottom; clean water overflows the rim at the top. A return-pump sucks settled sludge back to the reactor; a smaller waste stream removes excess (WAS).

                  Q_in (from reactor)
                  + biomass C_in
                       |
                       v
        +------------------------------+
        |        clean water           |---> overflow Q_out
        |                              |     low TSS
        |  - - - - - - - - - - - - -   |  <-- top of sludge blanket
        |    (settling zone)           |
        |  = = = = = = = = = = = = =   |
        |     compacting biomass       |
        |  ###########################  |  <-- sludge blanket
        +-----------+---+--------------+
                    |   |
                    v   v
                 underflow  to reactor (RAS)
                 high TSS   small bleed (WAS)

Process variables

Variable Typical range Unit
Surface area 50 to 2000 m2
Depth 3 to 5 m
Surface loading rate (SLR) 0.5 to 2 m/h
RAS flow 50 to 150 % of inflow
WAS flow 1 to 5 % of inflow
Effluent TSS < 30 mg/L
Underflow TSS 6000 to 12000 mg/L

Control objective

Goal Mechanism
Keep sludge blanket below overflow weir RAS pump rate adjusted to inflow
Maintain reactor MLSS target WAS rate set as fraction of inflow
Avoid blanket carryover Limit SLR; alarm on rising blanket level

EVOLV implementation

  • settler._connectReactor attaches emitter.on('stateChange', ...) to the upstream reactor, pulling effluent composition each tick.
  • settler._connectMachine registers the RAS pump (a rotatingMachine) as a child.
  • Settling-velocity model (Takács or Vesilind) is in the settler's src/; see Settling Models.

diffuser — aeration device

Physical view

A perforated panel or membrane at the bottom of the reactor that releases fine bubbles. Bubbles rise through the water column; oxygen dissolves into the water across the gas-liquid interface.

                   reactor side
                  ~  ~  ~  ~  ~          dissolved O2 enters water
                  ~  ~  ~  ~  ~
                   o o o o o o    <-- bubbles rising
                    o o o o o o
                     o o o o o
                      ooo ooo
                       ooo  oo
                +----[========]----+  <-- diffuser membrane / panel
                | |  | |  | |  | | |     compressed air manifold
                +-+--+-+--+-+--+-+-+
                                ^
                          air inflow
                       (from blower upstream)

Process variables

Variable Typical range Unit
Airflow per diffuser 1 to 10 Nm3/h
Header pressure 0.3 to 0.7 bar
Water depth (above diffuser) 4 to 6 m
K_La (volumetric mass-transfer coefficient) 1 to 20 1/h
Alpha factor (wastewater vs clean water) 0.5 to 0.9
OTR (oxygen transfer rate) 1 to 5 kg-O2/h per diffuser

Control objective

Goal Mechanism
Deliver enough OTR to meet reactor DO setpoint Modulate airflow via upstream blower / valve
Distribute air evenly across panels Manifold sizing; sometimes a valveGroupControl on the air side
Avoid over-aeration (energy waste) DO feedback loop

EVOLV implementation

  • diffuser reads headerPressure, water depth, airflow as inputs.
  • Computes OTR from K_La (configurable, supplier-specific), alpha factor, water properties.
  • Emits data.otr on its emitter. Reactor subscribes via emitter.on('otr', ...) — this is not a child-register handshake.

valve — single valve actuator

Physical view

A control valve in a pipe. Position 0..100% maps to K_v via the valve's characteristic curve (linear, equal-percentage, or quick-opening). Flow through the valve obeys Q = K_v * sqrt(dP).

        flow      +---+         flow
        ----------|   |----------->
                  | =====   <-- closure element (plug, ball, disc, gate)
                  |   |
                  +---+
                    ^
                  position 0..100%

  position --(characteristic curve)--> K_v
  Q = K_v * sqrt(P_up - P_down)

Process variables

Variable Typical range Unit
Position 0 to 100 %
K_v at full open 1 to 1000 m3/h / sqrt(bar)
Differential pressure 0.1 to 5 bar
Stroke time (close to open) 10 to 60 s

Physical state machine

valve shares the rotatingMachine state model. States: off, idle, warmingup, operational, accelerating (opening / closing), decelerating, coolingdown, emergencystop, maintenance. warmingup and coolingdown are protected (cannot be aborted).

Control objective

Goal Mechanism
Reach commanded position Move at the configured reactionSpeed rate
Avoid water hammer Limit how fast position changes
Provide flow feedback to upstream Computed Q from current K_v and measured dP

EVOLV implementation

  • valve registers measurement children for position / pressure feedback.
  • Inherits the shared FSM (generalFunctions state config) with rotatingMachine.
  • Characteristic curve is supplier-specific and loaded similarly to pump curves.

measurement — sensor signal conditioning

Physical view

A field sensor (level meter, flow meter, pressure transducer, DO probe, ...) outputs a raw signal. EVOLV's measurement node wraps that signal: scales it from instrument units (mA, mV, raw counts) to engineering units, smooths it, rejects outliers, and publishes the result to a parent process node.

   Sensor          4-20 mA (or digital, or MQTT)
   in the pipe  -----------------+
                                 |
                                 v
                  +--------------------------------+
                  |  measurement node              |
                  |                                |
                  |  raw input                     |
                  |     |                          |
                  |     v   scaling (mA -> EU)     |
                  |     v   smoothing              |
                  |     v   outlier rejection      |
                  |     v   calibration offset     |
                  |                                |
                  +-------+------------------------+
                          |
                          v   data.<type>
                  parent process node
                  (pumpingStation, reactor, ...)

Three input modes

Mode Source When to use
analog 4-20 mA, 0-10 V, raw scaled value Direct PLC / IO-card analog input
digital Boolean (on / off, ok / fault) Limit switches, status contacts
MQTT External MQTT broker topic Field bus, sensor with its own gateway

Process variables (examples)

Type Typical range Unit Example sensor
level 0 to 5 m radar level meter
flow 0 to 2000 m3/h electromagnetic flowmeter
pressure 0 to 10 bar piezo pressure transmitter
temperature 5 to 40 degC PT100 RTD
DO 0 to 10 mg/L optical dissolved-O2 probe
NH4 0 to 50 mg/L ion-selective electrode
TSS 0 to 5000 mg/L optical turbidity sensor

Control objective

Goal Mechanism
Deliver trustworthy values to parent Pipeline: scaling → smoothing → outlier → publish
Survive sensor faults Outlier rejection + sticky-last-good behaviour
Calibrate against reference cmd.calibrate triggers a calibration cycle

monster — composite sampling

Physical view

A virtual composite sampler: imagine a small bucket beside the pipe. Every time a unit volume of water flows past, a unit dose of that water is added to the bucket. After a sampling period (e.g. 24 h) the bucket contains a flow-proportional composite of every concentration over that period.

       ____________________
      |    sampling bucket  |    <-- accumulated sample
      |        ~~~~~~        |
      |        ~~~~~         |
      |        ~             |
      |_____________________|
              |
              | sampling dose dV at every flow increment
              v
  -----++------------------------+----->    main pipe
       |  (flow Q, conc C)         flow
       v
   dV = (Q * dt / total_flow_target) * sample_volume
   composite_C(t) = integral( C(s) * dV(s) ) / total_dV

Process variables

Variable Typical range Unit
Sampling period 1 to 24 h
Bucket volume target 2 to 10 L
Sample doses per period 24 to 96
Output composite concentration as configured per parameter mg/L, NTU, …

Control objective

Goal Mechanism
Build a representative composite sample over the period Flow-proportional dosing
Produce reportable averages Each tick, accumulate flow-weighted concentration
Reset for next period At end of period, emit composite and reset bucket

Gotchas

Gotcha Detail
assetType must be "flow" exactly Sub-types like "flow-electromagnetic" are silently ignored by monster's child router
constraints.flowmeter not forwarded Toggling proportional-vs-time mode has no runtime effect in current code. Tracked in .claude/refactor/OPEN_QUESTIONS.md

dashboardAPI — Grafana provisioning

Physical view

There is none. dashboardAPI does not model any piece of water-treatment equipment. It is a utility that auto-generates Grafana dashboards from a node's softwareType + measurements, so operators see the right panels per equipment without hand-building dashboard JSON.

Operational role

Trigger Effect
Any EVOLV node sends child.register to dashboardAPI dashboardAPI composes a dashboard JSON from the template for that softwareType and POSTs an upsert to Grafana
Telemetry arrives in InfluxDB (Port 1 of process nodes) Grafana panels query InfluxDB and render the trends

dashboardAPI is the one node in the platform that does not extend BaseDomain (it is a passive HTTP bridge). See .claude/refactor/OPEN_QUESTIONS.md.


Where it all fits

If you imagine a wastewater plant from inlet to outlet, every EVOLV node is a piece of equipment you would see on a P&ID. The software's job is to model that equipment well enough that:

  1. Operators can run the plant without watching the water directly (predictions + telemetry).
  2. New plants can be commissioned by composing standard nodes (no bespoke control code).
  3. Anomalies surface as HealthStatus flags before they become operator problems.

See Topology Patterns for how to assemble these nodes into a working plant.


Page Why
Home Top-level node map and S88 hierarchy
Topology Patterns Standard assemblies of these nodes
Architecture The code counterpart of this page
Topic Conventions How process variables travel between nodes
Telemetry How process variables land in InfluxDB and Grafana
ASM Models The reactor's biological kinetics in detail
Pump Affinity Laws Pump curve physics
Settling Models Settler physics
Signal Processing — Sensors Measurement node pipeline