Add recirculation pump node with input handling and flow management
This commit is contained in:
57
additional_nodes/recirculation-pump.html
Normal file
57
additional_nodes/recirculation-pump.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType("recirculation-pump", {
|
||||
category: "WWTP",
|
||||
color: "#e4a363",
|
||||
defaults: {
|
||||
name: { value: "" },
|
||||
F2: { value: 0, required: true },
|
||||
inlet: { value: 1, required: true }
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 2,
|
||||
outputLabels: ["Main effluent", "Recirculation effluent"],
|
||||
icon: "font-awesome/fa-random",
|
||||
label: function() {
|
||||
return this.name || "Recirculation pump";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
$("#node-input-F2").typedInput({
|
||||
type:"num",
|
||||
types:["num"]
|
||||
});
|
||||
$("#node-input-inlet").typedInput({
|
||||
type:"num",
|
||||
types:["num"]
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
let debit = parseFloat($("#node-input-F2").typedInput("value"));
|
||||
if (isNaN(volume) || debit < 0) {
|
||||
RED.notify("Debit is not set correctly", {type: "error"});
|
||||
}
|
||||
let inlet = parseInt($("#node-input-n_inlets").typedInput("value"));
|
||||
if (isNaN(inlet) || inlet < 1) {
|
||||
RED.notify("Number of inlets not set correctly", {type: "error"});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="recirculation-pump">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-F2"><i class="fa fa-tag"></i> Recirculation debit [m3 s-1]</label>
|
||||
<input type="text" id="node-input-F2" placeholder="m3 s-1">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-inlet"><i class="fa fa-tag"></i> Assigned inlet recirculation</label>
|
||||
<input type="text" id="node-input-inlet" placeholder="#">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="recirculation-pump">
|
||||
<p>Recirculation-pump for splitting streams</p>
|
||||
</script>
|
||||
38
additional_nodes/recirculation-pump.js
Normal file
38
additional_nodes/recirculation-pump.js
Normal file
@@ -0,0 +1,38 @@
|
||||
module.exports = function(RED) {
|
||||
function recirculation(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
|
||||
let name = config.name;
|
||||
let F2 = parseFloat(config.F2);
|
||||
let inlet = parseInt(config.inlet);
|
||||
|
||||
node.on('input', function(msg, send, done) {
|
||||
switch (msg.topic) {
|
||||
case "Fluent":
|
||||
// conserve volume flow debit
|
||||
let F1 = msg.payload.F;
|
||||
let F_diff = Math.max(F1 - F2, 0);
|
||||
let F2_corr = F1 < F2 ? F1 : F2;
|
||||
|
||||
let msg_F1 = structuredClone(msg);
|
||||
msg_F1.payload.F = F_diff;
|
||||
|
||||
let msg_F2 = structuredClone(msg);
|
||||
msg_F2.payload.F = F2_corr;
|
||||
msg_F2.payload.inlet = inlet;
|
||||
|
||||
send([msg_F1, msg_F2]);
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown topic: " + msg.topic);
|
||||
}
|
||||
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
RED.nodes.registerType("recirculation-pump", recirculation);
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType("advanced-reactor", {
|
||||
category: 'WWTP',
|
||||
color: '#c4cce0',
|
||||
category: "WWTP",
|
||||
color: "#c4cce0",
|
||||
defaults: {
|
||||
name: { value: "" },
|
||||
volume: { value: 0., required: true},
|
||||
|
||||
@@ -34,7 +34,9 @@ module.exports = function(RED) {
|
||||
break;
|
||||
case "Fluent":
|
||||
reactor.setInfluent = msg;
|
||||
reactor.updateState(msg.timestamp);
|
||||
if (msg.payload.inlet == 0){
|
||||
reactor.updateState(msg.timestamp);
|
||||
}
|
||||
break;
|
||||
case "OTR":
|
||||
reactor.setOTR = msg;
|
||||
|
||||
6
dependencies/reactor_class.js
vendored
6
dependencies/reactor_class.js
vendored
@@ -10,7 +10,7 @@ class Reactor_CSTR {
|
||||
|
||||
this.Vl = volume; // fluid volume reactor [m3]
|
||||
this.Fs = Array(n_inlets).fill(0.0); // fluid debits per inlet [m3 d-1]
|
||||
this.Cs_in = Array.from(Array(n_inlets), () => new Array(13)).fill(0.0); // composition influent
|
||||
this.Cs_in = Array.from(Array(n_inlets), () => new Array(13).fill(0.0)); // composition influents
|
||||
this.OTR = 0.0; // oxygen transfer rate [g O2 d-1]
|
||||
|
||||
this.currentTime = Date.now(); // milliseconds since epoch [ms]
|
||||
@@ -51,8 +51,8 @@ class Reactor_CSTR {
|
||||
|
||||
tick_fe(time_step) { // tick reactor state using forward Euler method
|
||||
const r = this.asm.compute_dC(this.state);
|
||||
const dC_in = math.multiply(this.Cs_in, this.Fs/this.Vl)[0];
|
||||
const dC_out = math.multiply(this.state, math.sum(this.Fs)/this.Vl);
|
||||
const dC_in = math.multiply(math.divide([this.Fs], this.Vl), this.Cs_in)[0];
|
||||
const dC_out = math.multiply(math.sum(this.Fs)/this.Vl, this.state);
|
||||
const T_O = Array(13).fill(0.0);
|
||||
T_O[0] = this.OTR;
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
},
|
||||
"node-red": {
|
||||
"nodes": {
|
||||
"advanced-reactor": "advanced-reactor.js"
|
||||
"advanced-reactor": "advanced-reactor.js",
|
||||
"recirculation-pump": "additional_nodes/recirculation-pump.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
Reference in New Issue
Block a user