diff --git a/src/specificClass.js b/src/specificClass.js index bf98c45..7dcc278 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -784,9 +784,15 @@ class MachineGroup { const debugInfo = bestResult.bestCombination.map(({ machineId, flow }) => `${machineId}: ${flow.toFixed(2)} units`).join(" | "); this.logger.debug(`Moving to demand: ${Qd.toFixed(2)} -> Pumps: [${debugInfo}] => Total Power: ${bestResult.bestPower.toFixed(2)}`); - //store the total delivered power + // Store the optimizer's INTENT on AT_EQUIPMENT (what we + // commanded). DOWNSTREAM is reserved for the live aggregate + // written by handlePressureChange — PS subscribes to that + // for net-flow computation and must see what pumps are + // actually delivering, not the planned target. Writing + // bestFlow to DOWNSTREAM here would clobber the live value + // every handleInput tick (see ps-mgc-flow-contract test). this._writeMeasurement("power", "predicted", POSITIONS.AT_EQUIPMENT, bestResult.bestPower, this.unitPolicy.canonical.power); - this._writeMeasurement("flow", "predicted", POSITIONS.DOWNSTREAM, bestResult.bestFlow, this.unitPolicy.canonical.flow); + this._writeMeasurement("flow", "predicted", POSITIONS.AT_EQUIPMENT, bestResult.bestFlow, this.unitPolicy.canonical.flow); this.measurements.type("efficiency").variant("predicted").position(POSITIONS.AT_EQUIPMENT).value(bestResult.bestFlow / bestResult.bestPower); this.measurements.type("Ncog").variant("predicted").position(POSITIONS.AT_EQUIPMENT).value(bestResult.bestCog); @@ -1120,9 +1126,11 @@ class MachineGroup { this.logger.debug(`Priority control for demand: ${totalFlow.toFixed(2)} -> Active pumps: [${debugInfo}] => Total Power: ${totalPower.toFixed(2)}`); - // Store measurements + // Store the planned distribution as INTENT on AT_EQUIPMENT. + // DOWNSTREAM (live aggregate) is owned by handlePressureChange. + // Writing the plan here would clobber PS's outflow signal. this._writeMeasurement("power", "predicted", POSITIONS.AT_EQUIPMENT, totalPower, this.unitPolicy.canonical.power); - this._writeMeasurement("flow", "predicted", POSITIONS.DOWNSTREAM, totalFlow, this.unitPolicy.canonical.flow); + this._writeMeasurement("flow", "predicted", POSITIONS.AT_EQUIPMENT, totalFlow, this.unitPolicy.canonical.flow); this.measurements.type("efficiency").variant("predicted").position(POSITIONS.AT_EQUIPMENT).value(totalFlow / totalPower); this.measurements.type("Ncog").variant("predicted").position(POSITIONS.AT_EQUIPMENT).value(totalCog); @@ -1247,8 +1255,12 @@ class MachineGroup { } }); + // Write to AT_EQUIPMENT not DOWNSTREAM. handlePressureChange + // is the canonical writer of DOWNSTREAM (the live aggregate + // that PS subscribes to for outflow). See optimalControl + // comment above. this._writeMeasurement("power", "predicted", POSITIONS.AT_EQUIPMENT, totalPower.reduce((a, b) => a + b, 0), this.unitPolicy.canonical.power); - this._writeMeasurement("flow", "predicted", POSITIONS.DOWNSTREAM, totalFlow.reduce((a, b) => a + b, 0), this.unitPolicy.canonical.flow); + this._writeMeasurement("flow", "predicted", POSITIONS.AT_EQUIPMENT, totalFlow.reduce((a, b) => a + b, 0), this.unitPolicy.canonical.flow); if(totalPower.reduce((a, b) => a + b, 0) > 0){ this.measurements.type("efficiency").variant("predicted").position(POSITIONS.AT_EQUIPMENT).value(totalFlow.reduce((a, b) => a + b, 0) / totalPower.reduce((a, b) => a + b, 0));