Waterschap Brabantse Delta · R&D-lab · uitleg

EVOLV · reactor — één klok-tick door een ASM3-actiefslibtank

eigenaar R&D-lab laatst getest 2026-07-17 versie 2.0 concept
reactor is de biologische-procesmodule van EVOLV: een beluchte actiefslibtank die de ASM3-kinetiek (Activated Sludge Model No. 3) over de tijd integreert. Hij neemt een influentstroom (fluent) in, rekent per klok-tick de biokinetiek en zuurstofoverdracht door, en levert een effluentstroom plus telemetrie. De fysica zit in een verwisselbare engine — een volledig gemengde tank (CSTR) of een propstroomreactor (PFR). De node is tick-gestuurd: hij vordert de integrator alleen als er een klok-tick verstrijkt. Deze pagina volgt letterlijk wat de code doet aan de hand van één klok-tick, een interactieve CSTR-respons met de échte ASM3-parameters, en een node-voorberekend PFR-profiel.

Doel & rol in de keten

reactor is een S88-Unit (lane L4, kleur #50a8d9; nodes/reactor/CLAUDE.md, S88-classificatietabel). De domeinklasse omschrijft zichzelf als "biological reactor orchestrator (Unit-level)" (src/specificClass.js:10-14). Het gemodelleerde proces is een beluchte actiefslibtank: heterotrofe groei, opslag (storage), autotrofe nitrificatie, hydrolyse en endogene ademhaling — geen SBR-/batch-fasering.

In de keten neemt de reactor een influent (fluent) in en levert een effluent op poort 0. Reactoren kunnen in serie staan: een downstream reactor registreert een upstream reactor als kind en trekt diens effluent binnen als influent (src/kinetics/baseEngine.js:114-118,130). Nageschakelde eenheden in additional_nodes/ — een nabezinktank (settling-basin) en een recirculatiepomp (recirculation-pump) — zijn legacy losse nodes (zie de aandachtspunten).

Rode draad door de hele pagina: één klok-tick van een voorbeeld-CSTR — voorbeeldreactor volume 1000 m³, timeStep 1 s, influent F = 100 m³/d met o.a. S_S (opgelost substraat) en S_NH (ammonium). Alle live-getallen op deze pagina zijn met node tegen de échte asm3_class.js + cstr.js/pfr.js doorgerekend (parity exact; testcases als commentaar in de pagina-JS).

Praat met deze node

Het I/O-contract in één oogopslag: kies een verb, stel de velden in, kopieer het exacte injecteerbare msg, en klik Injecteer ▸ om te zien wat er uit de drie poorten komt — met live doorgerekende effluentwaarden op de voorbeeld-CSTR (V 1000 m³). De data-verbs dragen geen unit-descriptor, dus de registry normaliseert niets: mg/L, m³/d en °C bereiken de engine rauw. Elke bewering draagt een pad:regel-chip. Poortlabels ["process","dbase","parent"].

Stuurinput · 1 poort
Bericht
Poortenoutput · 3 poorten
Volledige poort-referentie
Poortcontract (labels ["process","dbase","parent"], reactor.html:61-63). Emissie in nodeClass._emitOutputs() (src/nodeClass.js:41-50). Domeineenheden: mg/L (mmol/L voor S_HCO), m³/d, °C.
PoortLabelBelangrijkste keys
0process Bij PFR eerst {topic:'GridProfile', payload:{grid, n_x, d_x, length, species, timestamp}} (src/kinetics/pfr.js:25-35); daarna het effluent {topic:'Fluent', payload:{inlet:0, F, C}, timestamp} met F = math.sum(Fs) en C = de laatste toestand (CSTR: hele 13-vector; PFR: laatste grid-slice via state.at(-1)) (src/kinetics/baseEngine.js:60-63).
1dbase Zelfde snapshot via de influxdb-formatter uit getOutput(): flow_total, temperature, en per species — alleen als Number.isFiniteS_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 (src/specificClass.js:7-8,101-104). Omzetbaar naar frost/json/csv.
2parent In _emitOutputs altijd null (src/nodeClass.js:46,49). De startup-child.register- handshake naar de ouder zit in BaseNodeAdapter (generalFunctions), niet in reactor-code (aanname — niet in dit submodule geverifieerd).

Wie praat met wie

De parent staat boven, de kinderen onder. Registratie en telemetrie lopen via draden; kind-measurements en de upstream-effluent komen als in-process events binnen (op de engine-emitter). De nageschakelde settling-basin + recirculation-pump zijn een legacy zijtak: losse nodes op de oude node.on('input')/msg.topic-stijl, geen 3-lagen-patroon.

parent (controller / reactor) parent reactor deze node · S88 Unit settling-basin · recirc-pump legacy additional_nodes (msg.topic) measurement temperature / oxygen upstream reactor effluent → influent (serie) p2 registratie p0/p1 → proces / Influx in-process events (measurement/engine emitter) Fluent (legacy topic)
registratie · via draad (poort 2) telemetrie · via draad (poort 0/1) in-process events · measurement/engine-emitter legacy zijtak · msg.topic

Kinderen worden via ChildRouter aangesloten (src/specificClass.js:28-29). Een measurement-kind abonneert op <type>.measured.<position> op zijn emitter; herkend wordt temperature.measured.atEquipmentengine.temperature (src/kinetics/baseEngine.js:100-126), en op PFR extra quantity (oxygen).measured.<distance> → DO in de dichtstbijzijnde grid-cel (src/kinetics/pfr.js:67-79). Een reactor-kind wordt de upstream reactor: bij elke updateState wordt diens getEffluent als influent ingetrokken (src/kinetics/baseEngine.js:114-118,130).

De reis van één klok-tick

Klik een stap in de lijst (of gebruik ◀ ▶). Boven zie je waar in de pijplijn je bent; rechts wat er gebeurt, een concreet getal van de voorbeeld-CSTR op dat punt, en het codepad. De hele reis wordt in gang gezet door één klok-tick — zonder tick vordert de integrator niet.

CSTR-respons over de tijd, interactief

Een volledig gemengde tank (CSTR, V = 1000 m³) krijgt vanaf de editor-startconcentraties een influent F = 100 m³/d. Elke stap is de Forward-Euler dC = (inflow + outflow + reaction + transfer)·Δt met reaction = ASM3.compute_dC en de zuurstofoverdracht alléén op S_O. Dit is de échte 13-species / 12-reactie ASM3 @20 °C-parameterset — geen vereenvoudiging; de reken-kern is met node tegen asm3_class.js + cstr.js gevalideerd (trajectorie-parity exact). Schuif het influent-substraat, de kla en de temperatuur; zie hoe substraat wordt afgebroken en hoe de opgeloste zuurstof reageert.

300 mg/L
200
20 °C

PFR-profiel over de lengte (node-voorberekend)

De propstroomreactor (PFR) mengt niet: substraat, ammonium en zuurstof variëren langs de reactorlengte. Elke cel volgt advectie − dispersie − reactie − transfer, met een gegeneraliseerde Danckwerts-inlaat (α) en een Neumann-uitlaat. Omdat de PFR-operatoren (mathjs-diagonalen, in-place-aliasing in _makeDoperator) fragiel zijn om live in de browser te herbouwen, is dit profiel node-voorberekend met de échte Reactor_PFR (n_x = 10, length = 10 m, α = 0,5, D = 5 m²/d, externe OTR = 50, T = 20 °C, ~4 dagen ingelopen) en hier statisch ingebed — geen live-plot.

Wat de code doet — kaarten

CSTR vs PFR
CSTR = één perfect-gemengde 13-vector, Forward-Euler (cstr.js:12-24). PFR = een n_x × 13-grid met expliciete finite-difference: advectie (−ΣF/(A·dx)·D_op·state) + dispersie (D/dx²·D2_op·state) + reactie + transfer (pfr.js:48-65). Randvoorwaarden: gegeneraliseerde Danckwerts aan de inlaat bij flow>0, Neumann (no-flux) aan de uitlaat (pfr.js:83-92). De PFR waarschuwt bij lokaal Péclet ≥ 2 en Courant ≥ 0,5 (pfr.js:41-44).
ASM3 in het kort
13 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) en 12 reacties: hydrolyse; heterotrofe aerobe/anoxische opslag & groei; endogene en opslag-ademhaling; autotrofe nitrificatie; autotrofe ademhaling (asm3_class.js:171-197). Kinetiek via Monod c/(K+c) + inverse-Monod K/(K+c), temperatuur via k·exp(θ·(T−20)). De 12×13-stoichiometrie is hard-gecodeerd en getransponeerd; compute_dC = stoiᵀ·rates (asm3_class.js:101-120,205-208).
Zuurstof: kla of externe OTR
OTR = kla·(S_O,sat − S_O), met de verzadiging als 3e-graads polynoom in T (14.652 − 0.41022·T + 7.991e-3·T² + 7.7774e-5·T³) (baseEngine.js:67-74). Is kla NaN, dan wordt de extern gezette OTR-waarde gebruikt (cstr.js:17-19, pfr.js:54-56). Na elke stap wordt S_O begrensd op [0, verzadiging] (baseEngine.js:76-85).
⚠ Eenheidsvalkuil timeStep & kla
timeStep is seconden in de UI, maar de integrator werkt in dagen: this.timeStep = (1/86400)·config.timeStep (baseEngine.js:40). Het JSON-schema waarschuwt hier expliciet voor (configs/reactor.json:138-145). Losstaand: kla staat in het schema als 1/h terwijl de tijdbasis dagen is; er is geen h→d-omrekening in de code gezien (CONTRACT.md:16-19). aanname mogelijke inconsistentie — niet in runtime geverifieerd.
Dode / legacy code
src/reaction_modules/asm3_class Koch.js is een alternatieve parameterset (Koch et al. 2000: k_H=9, k_STO=12, nu_NO=0.5) — niet geïmporteerd; de engines laden asm3_class.js (baseEngine.js:4). De bestandsnaam bevat een spatie en wijkt van de conventie af. De additional_nodes/ (settling-basin, recirculation-pump) volgen het 3-lagen-patroon niet: node.on('input') + switch(msg.topic) + console.log bij een onbekende topic (additional_nodes/*.js:30-31).
NaN op poort 1
getOutput() filtert niet-eindige species eruit, maar flow_total/temperature gaan via Number(...) en kunnen NaN worden zonder effluent/temperatuur (src/specificClass.js:97-100). aanname onzeker of formatMsg die twee velden alsnog wegfiltert — niet in runtime geverifieerd.

Configuratie

UI-defaults in reactor.html:17-58; schema/defaults in nodes/generalFunctions/src/configs/reactor.json. De adapter mapt via buildDomainConfig (src/nodeClass.js:19-36), het domein plat via _flattenEngineConfig (src/specificClass.js:38-56).

Belangrijkste editor-velden. De HTML-default van volume is 0., terwijl het JSON-schema 1000 geeft — de schema-default vult aan wat de editor leeg laat. Volledige defaults/enums: configs/reactor.json.
VeldDefault (html / json)Betekenis
reactor_typeCSTRkeuze engine CSTR|PFR (configs/reactor.json:76-85; specificClass.js:58-68)
volume (m³)0. / 1000reactorvolume (baseEngine.js:30)
length (m, PFR)0. / 10reactorlengte (pfr.js:10)
resolution_L (PFR)0. / 10aantal ruimtelijke cellen n_x (pfr.js:11)
alpha (PFR)0 / 0.5inlaat-BC-parameter (α=0 Danckwerts, α=1 Dirichlet) (pfr.js:14,86)
n_inlets1 / 1aantal inlaten (baseEngine.js:32-33)
kla (1/h)null / 0zuurstofoverdrachtscoëfficiënt; NaN ⇒ externe OTR (baseEngine.js:37, cstr.js:17-19)
timeStep (s)1 / 1integratie-tijdstap; intern → dagen via (1/86400)·timeStep (baseEngine.js:40)
speedUpFactor1 / 1versnelling t.o.v. realtime (baseEngine.js:41,131-134)
S_*_init / X_*_initzie reactor.html:27-3913 startconcentraties (mg/L; mmol/L voor S_HCO)

Resterende velden (asset/FROST-identiteit uuid/model/frostServer/geo, output-formaten process|json|csv resp. influxdb|frost|json|csv, logging, positionVsParent) staan in reactor.html:41-58 + configs/reactor.json.

Kernformules

Alleen formules die letterlijk zo in de code staan. De ASM3-reactieterm gaat in een massabalans per engine-type; de zuurstofoverdracht drijft de S_O-transfer.

compute_dC=stoi_matrixT·rates , monod(c,K)=cK+c , k(T)=k·eθ·(T20)
symboolbetekeniseenheidherkomst
stoi_matrix12×13 stoichiometrie (fracties, yields, N-/TSS-/ladingsparameters), getransponeerdasm3_class.js:101-120
rates12 procesreactiesnelheden (Monod/inverse-Monod × Arrhenius)mg/(L·d)asm3_class.js:171-197
θtemperatuurcoëfficiënt, uit 2 ijkpunten ln(k1/k2)/(T1−T2)1/°Casm3_class.js:149-163
dC=( FiVCin ΣFiVC +reaction+transfer)·Δt , OTR=kla·(SO,satSO)
symboolbetekeniseenheidherkomst
Fi / Vinlaatdebiet / reactorvolumem³/d · m³cstr.js:13-14
transferzuurstofoverdracht, alleen op index S_Omg/(L·d)cstr.js:16-19
Δttijdstap, intern in dagendbaseEngine.js:40
SO,satverzadigings-DO, 3e-graads polynoom in Tmg/LbaseEngine.js:72-74

Verder lezen

Bron statische code-analyse van de werkkopie RnD/EVOLV (super-repo 74c4089, 2026-07-03) — submodule reactor geanalyseerd @ 18394c3b5ef2, plus het feitendossier van deze analyse. Analysedatum 2026-07-17.
Versheids-check op 2026-07-17 is git fetch gedraaid; de geanalyseerde HEAD (18394c3) is gelijk aan origin/main en er staan geen open fix-branches voor deze node open — de brief is volledig code-geverifieerd.
Methode statische code-analyse; elk feit draagt een pad:regel-verwijzing. De CSTR-respons en de console-payloads zijn getrouwe herimplementaties, vooraf met node tegen asm3_class.js + cstr.js doorgerekend (ASM3-parity exact, CSTR-trajectorie-parity exact; testcases als commentaar in de pagina-JS). Het PFR-profiel is node-voorberekend met de échte Reactor_PFR en statisch ingebed. Illustratieve aannames (voorbeeldreactor, influentsamenstelling) zijn expliciet gelabeld.
Beperking beschrijft de geanalyseerde revisie; gedrag op andere branches of deployments kan afwijken.
Contact R&D-lab · lab.wbd-rd.nl