some major design choises updated
This commit is contained in:
@@ -21,7 +21,13 @@ class pumpingStation {
|
|||||||
|
|
||||||
// init basin object in pumping station
|
// init basin object in pumping station
|
||||||
this.basin = {};
|
this.basin = {};
|
||||||
this.state = { direction:"", netDownstream:0, netUpstream:0, seconds:0}; // init state object of pumping station to see whats going on
|
this.state = {
|
||||||
|
direction: "steady",
|
||||||
|
netFlow: 0,
|
||||||
|
flowSource: null,
|
||||||
|
seconds: null,
|
||||||
|
remainingSource: null
|
||||||
|
}; // init state object of pumping station to see whats going on
|
||||||
|
|
||||||
// Initialize basin-specific properties and calculate used parameters
|
// Initialize basin-specific properties and calculate used parameters
|
||||||
this.initBasinProperties();
|
this.initBasinProperties();
|
||||||
@@ -211,12 +217,80 @@ class pumpingStation {
|
|||||||
//go through all the functions that require time based checks or updates
|
//go through all the functions that require time based checks or updates
|
||||||
this._updateVolumePrediction("out"); //check for changes in outgoing flow
|
this._updateVolumePrediction("out"); //check for changes in outgoing flow
|
||||||
this._updateVolumePrediction("in"); // check for changes in incomming flow
|
this._updateVolumePrediction("in"); // check for changes in incomming flow
|
||||||
//calc the most important values back to determine state and net up or downstream flow
|
|
||||||
this._calcNetFlow();
|
|
||||||
this._calcTimeRemaining();
|
|
||||||
|
|
||||||
|
//calc the most important values back to determine state and net up or downstream flow
|
||||||
|
this._calcNetFlow();
|
||||||
|
const {time:timeleft, source:variant} = this._calcTimeRemaining();
|
||||||
|
|
||||||
|
|
||||||
|
this.logger.debug(`Remaining time ${timeleft}, based on variant ${variant} `);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_calcTimeRemaining(){
|
||||||
|
//init timeRemaining
|
||||||
|
const winningTime = {time:0,source:""};
|
||||||
|
|
||||||
|
//calculate time left prioritise flow based variant
|
||||||
|
const { time: flowTime, variant: flowVariant } = this._selectBestRemainingTimeFlowVariant();
|
||||||
|
|
||||||
|
//if flow doesnt work then use level based varianti to calc timeleft
|
||||||
|
if(flowVariant == null){
|
||||||
|
const {time: levelTime, variant: levelVariant} = this._selectBestRemainingTimeLevelVariant();
|
||||||
|
winningTime.time = levelTime;
|
||||||
|
winningTime.source = levelVariant;
|
||||||
|
if(levelVariant == null){
|
||||||
|
winningTime.time = null;
|
||||||
|
winningTime.source = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
winningTime.time = flowTime;
|
||||||
|
winningTime.source = flowVariant;
|
||||||
|
}
|
||||||
|
|
||||||
|
return winningTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select remaining time based on flow + level variation measured or predicted and give back {time:0,variant:null};
|
||||||
|
_selectBestRemainingTimeFlowVariant(){
|
||||||
|
|
||||||
|
//define variants
|
||||||
|
const remainingTimeVariants = [
|
||||||
|
{ flowVariant: "measured", levelVariant: "measured" },
|
||||||
|
{ flowVariant: "measured", levelVariant: "predicted" },
|
||||||
|
{ flowVariant: "predicted", levelVariant: "measured" },
|
||||||
|
{ flowVariant: "predicted", levelVariant: "predicted" }
|
||||||
|
];
|
||||||
|
|
||||||
|
let remainingT = null;
|
||||||
|
|
||||||
|
for (const variant of remainingTimeVariants) {
|
||||||
|
const candidate = this._calcRemainingTimeBasedOnFlow(variant);
|
||||||
|
if (candidate != null) {
|
||||||
|
remainingT = candidate;
|
||||||
|
return {time:remainingT,variant:variant};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {time:0,variant:null};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select remaining time based only on level variation measured or predicted and give back {time:0,variant:null};
|
||||||
|
_selectBestRemainingTimeLevelVariant(){
|
||||||
|
|
||||||
|
//define variants (in sequence of priority first measured then predicted etc...)
|
||||||
|
const remainingTimeVariants = ["measured","predicted"];
|
||||||
|
|
||||||
|
let remainingT = null;
|
||||||
|
|
||||||
|
for (const variant of remainingTimeVariants) {
|
||||||
|
const candidate = this._calcRemainingTimeBasedOnLevel(variant);
|
||||||
|
if (candidate != null) {
|
||||||
|
remainingT = candidate;
|
||||||
|
return {time:remainingT,variant:variant};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {time:0,variant:null};
|
||||||
|
}
|
||||||
|
|
||||||
_callMeasurementHandler(measurementType, value, position, context) {
|
_callMeasurementHandler(measurementType, value, position, context) {
|
||||||
switch (measurementType) {
|
switch (measurementType) {
|
||||||
@@ -319,33 +393,96 @@ class pumpingStation {
|
|||||||
this.logger.warn(`Can't calculate netflow without the proper measurements or predictions`);
|
this.logger.warn(`Can't calculate netflow without the proper measurements or predictions`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_calcRemainingTime(level,variant){
|
//@params : params : example {flowVariant: "predicted",levelVariant: "measured"};
|
||||||
|
_calcRemainingTimeBasedOnFlow(params){
|
||||||
|
const {flowVariant,levelVariant} = params;
|
||||||
|
this.logger.debug(`${flowVariant} - ${levelVariant} `);
|
||||||
|
|
||||||
|
if( flowVariant === null || levelVariant === null ){
|
||||||
|
this.logger.warn(`Cant calculate remaining time without needed variants`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const { heightOverflow, heightOutlet, surfaceArea } = this.basin;
|
const { heightOverflow, heightOutlet, surfaceArea } = this.basin;
|
||||||
const flowDiff = this.measurements.type("flow").variant(variant).difference({ from: "downstream", to: "upstream", unit: "m3/s" });
|
const levelexists = this.measurements.type("level").variant(levelVariant).exists({ position: "atEquipment", requireValues: true });
|
||||||
|
const flowOutExists = this.measurements.type("flow").variant(flowVariant).exists({ position: "out", requireValues: true });
|
||||||
|
const flowInExists = this.measurements.type("flow").variant(flowVariant).exists({ position: "in", requireValues: true });
|
||||||
|
let secondsRemaining = 0;
|
||||||
|
|
||||||
|
if( ! flowOutExists || ! flowInExists || ! levelexists){
|
||||||
|
this.logger.warn(`Cant calculate remaining time without needed parameters ${flowOutExists} , ${flowInExists} , ${levelexists}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const flowDiff = this.measurements.type("flow").variant(flowVariant).difference({ from: "downstream", to: "upstream", unit: "m3/s" });
|
||||||
|
const level = this.measurements.type("level").variant(levelVariant).type('atEquipment').getCurrentValue('m');
|
||||||
|
let remainingHeight = 0;
|
||||||
|
|
||||||
switch(true){
|
switch(true){
|
||||||
|
|
||||||
case(flowDiff>0):
|
case(flowDiff>0):
|
||||||
remainingHeight = Math.max(heightOverflow - level, 0);
|
remainingHeight = Math.max(heightOverflow - level, 0);
|
||||||
this.state.seconds = remainingHeight * surfaceArea / flowDiff;
|
secondsRemaining = remainingHeight * surfaceArea / flowDiff;
|
||||||
break;
|
return secondsRemaining;
|
||||||
|
|
||||||
case(flowDiff<0):
|
case(flowDiff<0):
|
||||||
remainingHeight = Math.max(level - heightOutlet, 0);
|
remainingHeight = Math.max(level - heightOutlet, 0);
|
||||||
this.state.seconds = remainingHeight * surfaceArea / Math.abs(flowDiff);
|
secondsRemaining = remainingHeight * surfaceArea / Math.abs(flowDiff);
|
||||||
break;
|
return secondsRemaining;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.logger.debug(`doing nothing with level calc`)
|
this.logger.debug(`Flowdiff is 0 not doing anything.`);
|
||||||
|
return secondsRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_calcDirection(flowDiff){
|
//@params : variant : example "predicted","measured"
|
||||||
|
_calcRemainingTimeBasedOnLevel(variant){
|
||||||
|
|
||||||
|
const levelObj = this.measurements.type("level").variant(variant).position("atEquipment");
|
||||||
|
const level = levelObj.getCurrentValue("m");
|
||||||
|
const prevLevel = levelObj.getLaggedValue(2, "m"); // { value, timestamp, unit }
|
||||||
|
const measurement = levelObj.get();
|
||||||
|
const latestTimestamp = measurement?.getLatestTimestamp();
|
||||||
|
|
||||||
|
if (level === null || !prevLevel || latestTimestamp == null) {
|
||||||
|
this.logger.warn(`no flowdiff ${level}, previous level ${prevLevel}, latestTimestamp ${latestTimestamp} found escaping`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deltaSeconds = (latestTimestamp - prevLevel.timestamp) / 1000;
|
||||||
|
if (deltaSeconds <= 0) {
|
||||||
|
this.logger.warn(`Level fallback: invalid Δt=${deltaSeconds} , LatestTimestamp : ${latestTimestamp}, PrevTimestamp : ${prevLevel.timestamp}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lvlDiff = level - prevLevel.value;
|
||||||
|
const lvlRate = Math.abs(lvlDiff / deltaSeconds); // m/s
|
||||||
|
|
||||||
|
switch(true){
|
||||||
|
|
||||||
|
case(lvlRate>0):
|
||||||
|
remainingHeight = Math.max(heightOverflow - level, 0);
|
||||||
|
secondsRemaining = remainingHeight / lvlRate; // seconds
|
||||||
|
return secondsRemaining;
|
||||||
|
|
||||||
|
case(lvlRate<0):
|
||||||
|
remainingHeight = Math.max(level - heightOutlet, 0);
|
||||||
|
secondsRemaining = remainingHeight / lvlRate;
|
||||||
|
return secondsRemaining;
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.logger.debug(`Flowdiff is 0 not doing anything.`);
|
||||||
|
return secondsRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Give a flowDifference and calculate direction => spits out filling , draining or stable
|
||||||
|
_calcDirectionBasedOnFlow(flowDiff){
|
||||||
|
|
||||||
let direction = null;
|
let direction = null;
|
||||||
|
|
||||||
@@ -370,9 +507,9 @@ class pumpingStation {
|
|||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
_calcNetFlowFromLevelDiff() {
|
_calcNetFlowFromLevelDiff(variant) {
|
||||||
const { surfaceArea } = this.basin;
|
const { surfaceArea } = this.basin;
|
||||||
const levelObj = this.measurements.type("level").variant("measured").position("atEquipment");
|
const levelObj = this.measurements.type("level").variant(variant).position("atEquipment");
|
||||||
const level = levelObj.getCurrentValue("m");
|
const level = levelObj.getCurrentValue("m");
|
||||||
const prevLevel = levelObj.getLaggedValue(2, "m"); // { value, timestamp, unit }
|
const prevLevel = levelObj.getLaggedValue(2, "m"); // { value, timestamp, unit }
|
||||||
const measurement = levelObj.get();
|
const measurement = levelObj.get();
|
||||||
|
|||||||
Reference in New Issue
Block a user