From 3a820df7f2ef37499347fdca842acec40c5ec765 Mon Sep 17 00:00:00 2001 From: HorriblePerson555 <47578455+HorriblePerson555@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:45:53 +0200 Subject: [PATCH 1/8] Non-functioning prototype with partial rotating machine integration --- src/specificClass.js | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index bd5af1b..ebd08bf 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -32,6 +32,7 @@ class Reactor { this.upstreamReactor = null; this.downstreamReactor = null; + this.returnPump = null; this.asm = new ASM3(); @@ -72,10 +73,14 @@ class Reactor { * @returns {object} Effluent data object (msg), defaults to inlet 0. */ get getEffluent() { // getter for Effluent, defaults to inlet 0 - if (isArray(this.state.at(-1))) { - return { topic: "Fluent", payload: { inlet: 0, F: math.sum(this.Fs), C: this.state.at(-1) }, timestamp: this.currentTime }; + const Cs = isArray(this.state.at(-1)) ? this.state.at(-1) : this.state; + const effluent = [{ topic: "Fluent", payload: { inlet: 0, F: math.sum(this.Fs), C: Cs }, timestamp: this.currentTime }]; + if (this.returnPump) { + const recirculationFlow = this.returnPump.measurements.type("flow").variant("measured").position("atEquipement").getValue(); + effluent[0].F -= recirculationFlow; + effluent.push({ topic: "Fluent", payload: { inlet: 1, F: recirculationFlow, C: Cs }, timestamp: this.currentTime }); } - return { topic: "Fluent", payload: { inlet: 0, F: math.sum(this.Fs), C: this.state }, timestamp: this.currentTime }; + return effluent; } /** @@ -105,13 +110,17 @@ class Reactor { registerChild(child, softwareType) { switch (softwareType) { case "measurement": - this.logger.debug(`Registering measurement child.`); + this.logger.debug(`Registering measurement child...`); this._connectMeasurement(child); break; case "reactor": - this.logger.debug(`Registering reactor child.`); + this.logger.debug(`Registering reactor child...`); this._connectReactor(child); break; + case "machine": + this.logger.debug(`Registering rotating machine child...`); + this._connectRotatingMachine(child); + break; default: this.logger.error(`Unrecognized softwareType: ${softwareType}`); @@ -150,7 +159,7 @@ class Reactor { return; } - if (reactorChild.functionality.positionVsParent != "upstream") { + if (reactorChild.config.functionality.positionVsParent != "upstream") { this.logger.warn("Reactor children of reactors should always be upstream."); } @@ -158,6 +167,7 @@ class Reactor { this.logger.warn("Significant grid sizing discrepancies between adjacent reactors! Change resolutions to match reactors grid step, or implement boundary value interpolation."); } + // set upstream and downstream reactor variable in current and child nodes respectively for easy access this.upstreamReactor = reactorChild; reactorChild.downstreamReactor = this; @@ -167,6 +177,16 @@ class Reactor { }); } + _connectRotatingMachine(rotatingMachineChild) { + if (!rotatingMachineChild) { + this.logger.warn("Invalid rotating machine provided."); + return; + } + + if (rotatingMachineChild.config.functionality.positionVsParent == "downstream") { + this.returnPump = rotatingMachineChild; + } + } _updateMeasurement(measurementType, value, position, context) { this.logger.debug(`---------------------- updating ${measurementType} ------------------ `); @@ -190,7 +210,7 @@ class Reactor { const day2ms = 1000 * 60 * 60 * 24; if (this.upstreamReactor) { - this.setInfluent = this.upstreamReactor.getEffluent; + this.setInfluent = this.upstreamReactor.getEffluent[0]; // grab main effluent upstream reactor } let n_iter = Math.floor(this.speedUpFactor * (newTime-this.currentTime) / (this.timeStep*day2ms)); -- 2.49.1 From 018215934eee871f64a765da311812f6cdd8f21c Mon Sep 17 00:00:00 2001 From: HorriblePerson555 <47578455+HorriblePerson555@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:37:29 +0200 Subject: [PATCH 2/8] Fix recirculation flow measurement to use getCurrentValue and handle undefined values --- src/specificClass.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index ebd08bf..44f41af 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -76,8 +76,8 @@ class Reactor { const Cs = isArray(this.state.at(-1)) ? this.state.at(-1) : this.state; const effluent = [{ topic: "Fluent", payload: { inlet: 0, F: math.sum(this.Fs), C: Cs }, timestamp: this.currentTime }]; if (this.returnPump) { - const recirculationFlow = this.returnPump.measurements.type("flow").variant("measured").position("atEquipement").getValue(); - effluent[0].F -= recirculationFlow; + const recirculationFlow = this.returnPump.measurements.type("flow").variant("measured").position("atEquipement").getCurrentValue(); + effluent[0].F -= recirculationFlow || 0; effluent.push({ topic: "Fluent", payload: { inlet: 1, F: recirculationFlow, C: Cs }, timestamp: this.currentTime }); } return effluent; -- 2.49.1 From 7b38c2f51a0e1eb2fb00e6657129357292776a31 Mon Sep 17 00:00:00 2001 From: HorriblePerson555 <47578455+HorriblePerson555@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:32:21 +0200 Subject: [PATCH 3/8] Refactor recirculation flow calculation to ensure non-negative flow rates and correct measurement position --- src/specificClass.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index 44f41af..3f62914 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -76,9 +76,11 @@ class Reactor { const Cs = isArray(this.state.at(-1)) ? this.state.at(-1) : this.state; const effluent = [{ topic: "Fluent", payload: { inlet: 0, F: math.sum(this.Fs), C: Cs }, timestamp: this.currentTime }]; if (this.returnPump) { - const recirculationFlow = this.returnPump.measurements.type("flow").variant("measured").position("atEquipement").getCurrentValue(); - effluent[0].F -= recirculationFlow || 0; - effluent.push({ topic: "Fluent", payload: { inlet: 1, F: recirculationFlow, C: Cs }, timestamp: this.currentTime }); + const recirculationFlow = this.returnPump.measurements.type("flow").variant("measured").position("atequipment").getCurrentValue(); + const F_main = Math.max(effluent[0].payload.F - recirculationFlow, 0); + const F_side_constrained = effluent[0].payload.F < recirculationFlow ? effluent[0].payload.F : recirculationFlow; + effluent[0].payload.F = F_main; + effluent.push({ topic: "Fluent", payload: { inlet: 1, F: F_side_constrained, C: Cs }, timestamp: this.currentTime }); } return effluent; } -- 2.49.1 From 6de4f9ec3e3eae0d1926adad6e4629fdc765e54b Mon Sep 17 00:00:00 2001 From: HorriblePerson555 <47578455+HorriblePerson555@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:02:41 +0200 Subject: [PATCH 4/8] Fix recirculation flow calculation to prevent negative flow rates and improve variable naming --- src/specificClass.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index 3f62914..75edd08 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -76,11 +76,12 @@ class Reactor { const Cs = isArray(this.state.at(-1)) ? this.state.at(-1) : this.state; const effluent = [{ topic: "Fluent", payload: { inlet: 0, F: math.sum(this.Fs), C: Cs }, timestamp: this.currentTime }]; if (this.returnPump) { - const recirculationFlow = this.returnPump.measurements.type("flow").variant("measured").position("atequipment").getCurrentValue(); + const recirculationFlow = this.returnPump.measurements.type("flow").variant("measured").position("atEquipment").getCurrentValue(); + // constrain flow to prevent negatives const F_main = Math.max(effluent[0].payload.F - recirculationFlow, 0); - const F_side_constrained = effluent[0].payload.F < recirculationFlow ? effluent[0].payload.F : recirculationFlow; + const F_sidestream = effluent[0].payload.F < recirculationFlow ? effluent[0].payload.F : recirculationFlow; effluent[0].payload.F = F_main; - effluent.push({ topic: "Fluent", payload: { inlet: 1, F: F_side_constrained, C: Cs }, timestamp: this.currentTime }); + effluent.push({ topic: "Fluent", payload: { inlet: 1, F: F_sidestream, C: Cs }, timestamp: this.currentTime }); } return effluent; } -- 2.49.1 From eb787ec47f96cdfa967b570c60e32bb0e4232dda Mon Sep 17 00:00:00 2001 From: "p.vanderwilt" Date: Wed, 22 Oct 2025 14:40:56 +0200 Subject: [PATCH 5/8] Minor bug fix and change in report level when encountering invalid children --- src/specificClass.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index 75edd08..c53d76d 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -132,7 +132,7 @@ class Reactor { _connectMeasurement(measurementChild) { if (!measurementChild) { - this.logger.warn("Invalid measurement provided."); + this.logger.error("Invalid measurement provided."); return; } @@ -158,7 +158,7 @@ class Reactor { _connectReactor(reactorChild) { if (!reactorChild) { - this.logger.warn("Invalid reactor provided."); + this.logger.error("Invalid reactor provided."); return; } @@ -182,11 +182,12 @@ class Reactor { _connectRotatingMachine(rotatingMachineChild) { if (!rotatingMachineChild) { - this.logger.warn("Invalid rotating machine provided."); + this.logger.error("Invalid rotating machine provided."); return; } if (rotatingMachineChild.config.functionality.positionVsParent == "downstream") { + rotatingMachineChild.upstreamReactor = this; this.returnPump = rotatingMachineChild; } } -- 2.49.1 From 4680b984181be1a98f38b87ec8e9e88b7ce626f8 Mon Sep 17 00:00:00 2001 From: "p.vanderwilt" Date: Thu, 23 Oct 2025 17:16:10 +0200 Subject: [PATCH 6/8] minor variable name changes --- src/specificClass.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index c53d76d..ae8025e 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -121,8 +121,8 @@ class Reactor { this._connectReactor(child); break; case "machine": - this.logger.debug(`Registering rotating machine child...`); - this._connectRotatingMachine(child); + this.logger.debug(`Registering machine child...`); + this._connectMachine(child); break; default: @@ -174,21 +174,21 @@ class Reactor { this.upstreamReactor = reactorChild; reactorChild.downstreamReactor = this; - reactorChild.emitter.on("stateChange", (data) => { + reactorChild.emitter.on("stateChange", (eventData) => { this.logger.debug(`State change of upstream reactor detected.`); - this.updateState(data); + this.updateState(eventData); }); } - _connectRotatingMachine(rotatingMachineChild) { - if (!rotatingMachineChild) { + _connectMachine(machineChild) { + if (!machineChild) { this.logger.error("Invalid rotating machine provided."); return; } - if (rotatingMachineChild.config.functionality.positionVsParent == "downstream") { - rotatingMachineChild.upstreamReactor = this; - this.returnPump = rotatingMachineChild; + if (machineChild.config.functionality.positionVsParent == "downstream") { + machineChild.upstreamReactor = this; + this.returnPump = machineChild; } } -- 2.49.1 From e6923f2916380785a1b63c46af7c1f8fcd011a4e Mon Sep 17 00:00:00 2001 From: "p.vanderwilt" Date: Fri, 31 Oct 2025 11:54:28 +0100 Subject: [PATCH 7/8] Refactor child registration and connection methods to handle invalid inputs and improve readability --- src/specificClass.js | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index ae8025e..1966d56 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -14,6 +14,7 @@ const S_O_INDEX = 0; const NUM_SPECIES = 13; const BC_PADDING = 2; const DEBUG = false; +const DAY2MS = 1000 * 60 * 60 * 24; class Reactor { /** @@ -28,7 +29,6 @@ class Reactor { this.measurements = new MeasurementContainer(); this.upstreamReactor = null; this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility - this.parent = []; // Gets assigned via child registration this.upstreamReactor = null; this.downstreamReactor = null; @@ -111,6 +111,11 @@ class Reactor { } registerChild(child, softwareType) { + if(!child) { + this.logger.error(`Invalid ${softwareType} child provided.`); + return; + } + switch (softwareType) { case "measurement": this.logger.debug(`Registering measurement child...`); @@ -131,11 +136,6 @@ class Reactor { } _connectMeasurement(measurementChild) { - if (!measurementChild) { - this.logger.error("Invalid measurement provided."); - return; - } - const position = measurementChild.config.functionality.positionVsParent; const measurementType = measurementChild.config.asset.type; const eventName = `${measurementType}.measured.${position}`; @@ -157,11 +157,6 @@ class Reactor { _connectReactor(reactorChild) { - if (!reactorChild) { - this.logger.error("Invalid reactor provided."); - return; - } - if (reactorChild.config.functionality.positionVsParent != "upstream") { this.logger.warn("Reactor children of reactors should always be upstream."); } @@ -181,11 +176,6 @@ class Reactor { } _connectMachine(machineChild) { - if (!machineChild) { - this.logger.error("Invalid rotating machine provided."); - return; - } - if (machineChild.config.functionality.positionVsParent == "downstream") { machineChild.upstreamReactor = this; this.returnPump = machineChild; @@ -211,20 +201,18 @@ class Reactor { * @param {number} newTime - New time to update reactor state to, in milliseconds since epoch. */ updateState(newTime = Date.now()) { // expect update with timestamp - const day2ms = 1000 * 60 * 60 * 24; - if (this.upstreamReactor) { this.setInfluent = this.upstreamReactor.getEffluent[0]; // grab main effluent upstream reactor } - let n_iter = Math.floor(this.speedUpFactor * (newTime-this.currentTime) / (this.timeStep*day2ms)); + let n_iter = Math.floor(this.speedUpFactor * (newTime-this.currentTime) / (this.timeStep*DAY2MS)); if (n_iter) { let n = 0; while (n < n_iter) { this.tick(this.timeStep); n += 1; } - this.currentTime += n_iter * this.timeStep * day2ms / this.speedUpFactor; + this.currentTime += n_iter * this.timeStep * DAY2MS / this.speedUpFactor; this.emitter.emit("stateChange", this.currentTime); } } -- 2.49.1 From 3828e43c12562e14703cbf49e829ab9ad16ce5b1 Mon Sep 17 00:00:00 2001 From: "p.vanderwilt" Date: Thu, 6 Nov 2025 14:51:06 +0100 Subject: [PATCH 8/8] Refactor reactor node configuration to remove n_inlets and simplify inlet handling --- reactor.html | 13 ------------- src/nodeClass.js | 1 - src/specificClass.js | 20 +++++++++++++------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/reactor.html b/reactor.html index 9d1574f..cdca7c7 100644 --- a/reactor.html +++ b/reactor.html @@ -11,7 +11,6 @@ length: { value: 0.}, resolution_L: { value: 0.}, alpha: {value: 0}, - n_inlets: { value: 1, required: true}, kla: { value: null }, S_O_init: { value: 0., required: true }, @@ -58,10 +57,6 @@ type:"num", types:["num"] }); - $("#node-input-n_inlets").typedInput({ - type:"num", - types:["num"] - }); $("#node-input-length").typedInput({ type:"num", types:["num"] @@ -128,10 +123,6 @@ if (isNaN(volume) || volume <= 0) { RED.notify("Fluid volume not set correctly", {type: "error"}); } - let n_inlets = parseInt($("#node-input-n_inlets").typedInput("value")); - if (isNaN(n_inlets) || n_inlets < 1) { - RED.notify("Number of inlets not set correctly", {type: "error"}); - } } }); @@ -165,10 +156,6 @@ -
- - -

Internal mass transfer calculation (optional)

diff --git a/src/nodeClass.js b/src/nodeClass.js index a9e53d3..3abe037 100644 --- a/src/nodeClass.js +++ b/src/nodeClass.js @@ -88,7 +88,6 @@ class nodeClass { length: parseFloat(uiConfig.length), resolution_L: parseInt(uiConfig.resolution_L), alpha: parseFloat(uiConfig.alpha), - n_inlets: parseInt(uiConfig.n_inlets), kla: parseFloat(uiConfig.kla), initialState: [ parseFloat(uiConfig.S_O_init), diff --git a/src/specificClass.js b/src/specificClass.js index 1966d56..18ac54a 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -1,5 +1,5 @@ const ASM3 = require('./reaction_modules/asm3_class.js'); -const { create, all, isArray } = require('mathjs'); +const { create, all, isArray, i } = require('mathjs'); const { assertNoNaN } = require('./utils.js'); const { childRegistrationUtils, logger, MeasurementContainer } = require('generalFunctions'); const EventEmitter = require('events'); @@ -38,8 +38,8 @@ class Reactor { this.volume = config.volume; // fluid volume reactor [m3] - this.Fs = Array(config.n_inlets).fill(0); // fluid debits per inlet [m3 d-1] - this.Cs_in = Array.from(Array(config.n_inlets), () => new Array(NUM_SPECIES).fill(0)); // composition influents + this.Fs = [0]; // fluid debits per inlet [m3 d-1] + this.Cs_in = [Array(NUM_SPECIES).fill(0)]; // composition influents this.OTR = 0.0; // oxygen transfer rate [g O2 d-1 m-3] this.temperature = 20; // temperature [C] @@ -55,9 +55,15 @@ class Reactor { * @param {object} input - Input object (msg) containing payload with inlet index, flow rate, and concentrations. */ set setInfluent(input) { - let index_in = input.payload.inlet; - this.Fs[index_in] = input.payload.F; - this.Cs_in[index_in] = input.payload.C; + const i_in = input.payload.inlet; + if (this.Fs.length <= i_in) { + this.logger.debug(`Adding new inlet index ${i_in}.`); + this.Fs.push(0); + this.Cs_in.push(Array(NUM_SPECIES).fill(0)); + this.setInfluent = input; + } + this.Fs[i_in] = input.payload.F; + this.Cs_in[i_in] = input.payload.C; } /** @@ -177,7 +183,7 @@ class Reactor { _connectMachine(machineChild) { if (machineChild.config.functionality.positionVsParent == "downstream") { - machineChild.upstreamReactor = this; + machineChild.upstreamSource = this; this.returnPump = machineChild; } } -- 2.49.1