Compare commits

..

1 Commits

Author SHA1 Message Date
znetsixe
0e8cab5d3f B3.3 follow-up: drop _unitView mirror; use UnitPolicy property bags directly
UnitPolicy now exposes canonical/output/curve as both methods AND
frozen property bags, so this.unitPolicy = this.constructor.unitPolicy
works directly. Removes the 14-line _unitView assembly in configure().
specificClass.js 336→318. 77/77 tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:13:18 +02:00
3 changed files with 25 additions and 43 deletions

View File

@@ -115,8 +115,8 @@ async function equalFlowControl(ctx, Qd, _powerCap = Infinity, priorityList = nu
} }
} }
const fUnit = mgc._unitView.canonical.power; const fUnit = mgc.unitPolicy.canonical.power;
const flUnit = mgc._unitView.canonical.flow; const flUnit = mgc.unitPolicy.canonical.flow;
mgc.operatingPoint.writeOwn('power', 'predicted', POSITIONS.AT_EQUIPMENT, totalPower, fUnit); mgc.operatingPoint.writeOwn('power', 'predicted', POSITIONS.AT_EQUIPMENT, totalPower, fUnit);
mgc.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, totalFlow, flUnit); mgc.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, totalFlow, flUnit);
mgc.measurements.type('efficiency').variant('predicted').position(POSITIONS.AT_EQUIPMENT).value(totalFlow / totalPower); mgc.measurements.type('efficiency').variant('predicted').position(POSITIONS.AT_EQUIPMENT).value(totalFlow / totalPower);
@@ -189,16 +189,16 @@ async function prioPercentageControl(ctx, input, priorityList = null) {
const totalPower = []; const totalPower = [];
const totalFlow = []; const totalFlow = [];
Object.values(mgc.machines).forEach(machine => { Object.values(mgc.machines).forEach(machine => {
const p = mgc.operatingPoint.readChild(machine, 'power', 'predicted', POSITIONS.AT_EQUIPMENT, mgc._unitView.canonical.power); const p = mgc.operatingPoint.readChild(machine, 'power', 'predicted', POSITIONS.AT_EQUIPMENT, mgc.unitPolicy.canonical.power);
const f = mgc.operatingPoint.readChild(machine, 'flow', 'predicted', POSITIONS.DOWNSTREAM, mgc._unitView.canonical.flow); const f = mgc.operatingPoint.readChild(machine, 'flow', 'predicted', POSITIONS.DOWNSTREAM, mgc.unitPolicy.canonical.flow);
if (p !== null) totalPower.push(p); if (p !== null) totalPower.push(p);
if (f !== null) totalFlow.push(f); if (f !== null) totalFlow.push(f);
}); });
const sumP = totalPower.reduce((a, b) => a + b, 0); const sumP = totalPower.reduce((a, b) => a + b, 0);
const sumF = totalFlow.reduce((a, b) => a + b, 0); const sumF = totalFlow.reduce((a, b) => a + b, 0);
mgc.operatingPoint.writeOwn('power', 'predicted', POSITIONS.AT_EQUIPMENT, sumP, mgc._unitView.canonical.power); mgc.operatingPoint.writeOwn('power', 'predicted', POSITIONS.AT_EQUIPMENT, sumP, mgc.unitPolicy.canonical.power);
mgc.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, sumF, mgc._unitView.canonical.flow); mgc.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, sumF, mgc.unitPolicy.canonical.flow);
if (sumP > 0) { if (sumP > 0) {
mgc.measurements.type('efficiency').variant('predicted').position(POSITIONS.AT_EQUIPMENT).value(sumF / sumP); mgc.measurements.type('efficiency').variant('predicted').position(POSITIONS.AT_EQUIPMENT).value(sumF / sumP);
} }

View File

@@ -7,22 +7,22 @@
const { statusBadge, POSITIONS } = require('generalFunctions'); const { statusBadge, POSITIONS } = require('generalFunctions');
function _outputUnitForType(unitView, type) { function _outputUnitForType(unitPolicy, type) {
switch (String(type || '').toLowerCase()) { switch (String(type || '').toLowerCase()) {
case 'flow': return unitView.output.flow; case 'flow': return unitPolicy.output.flow;
case 'power': return unitView.output.power; case 'power': return unitPolicy.output.power;
case 'pressure': return unitView.output.pressure; case 'pressure': return unitPolicy.output.pressure;
case 'temperature': return unitView.output.temperature; case 'temperature': return unitPolicy.output.temperature;
default: return null; default: return null;
} }
} }
function getOutput(mgc) { function getOutput(mgc) {
const out = {}; const out = {};
const { measurements, _unitView, mode, scaling, absDistFromPeak, relDistFromPeak } = mgc; const { measurements, unitPolicy, mode, scaling, absDistFromPeak, relDistFromPeak } = mgc;
measurements.getTypes().forEach(type => { measurements.getTypes().forEach(type => {
measurements.getVariants(type).forEach(variant => { measurements.getVariants(type).forEach(variant => {
const unit = _outputUnitForType(_unitView, type); const unit = _outputUnitForType(unitPolicy, type);
const read = (pos) => measurements.type(type).variant(variant).position(pos).getCurrentValue(unit || undefined); const read = (pos) => measurements.type(type).variant(variant).position(pos).getCurrentValue(unit || undefined);
const dn = read(POSITIONS.DOWNSTREAM); const dn = read(POSITIONS.DOWNSTREAM);
const at = read(POSITIONS.AT_EQUIPMENT); const at = read(POSITIONS.AT_EQUIPMENT);
@@ -46,9 +46,9 @@ function getOutput(mgc) {
function getStatusBadge(mgc) { function getStatusBadge(mgc) {
const totalFlow = mgc.measurements.type('flow').variant('predicted').position(POSITIONS.AT_EQUIPMENT) const totalFlow = mgc.measurements.type('flow').variant('predicted').position(POSITIONS.AT_EQUIPMENT)
.getCurrentValue(mgc._unitView.output.flow) ?? 0; .getCurrentValue(mgc.unitPolicy.output.flow) ?? 0;
const totalPower = mgc.measurements.type('power').variant('predicted').position(POSITIONS.AT_EQUIPMENT) const totalPower = mgc.measurements.type('power').variant('predicted').position(POSITIONS.AT_EQUIPMENT)
.getCurrentValue(mgc._unitView.output.power) ?? 0; .getCurrentValue(mgc.unitPolicy.output.power) ?? 0;
const totalCapacity = mgc.dynamicTotals?.flow?.max ?? 0; const totalCapacity = mgc.dynamicTotals?.flow?.max ?? 0;
const available = Object.values(mgc.machines).filter(m => { const available = Object.values(mgc.machines).filter(m => {
const s = m?.state?.getCurrentState?.(); const s = m?.state?.getCurrentState?.();

View File

@@ -36,24 +36,6 @@ class MachineGroup extends BaseDomain {
// tests still write directly (matches the pumpingStation pattern). // tests still write directly (matches the pumpingStation pattern).
this.machines = {}; this.machines = {};
// groupOps/totals/optimizer modules expect the legacy object-style
// policy (ctx.unitPolicy.canonical.flow). UnitPolicy on BaseDomain
// exposes canonical()/output() methods, so build a compatible view.
this._unitView = Object.freeze({
canonical: Object.freeze({
flow: this.unitPolicy.canonical('flow'),
pressure: this.unitPolicy.canonical('pressure'),
power: this.unitPolicy.canonical('power'),
temperature: this.unitPolicy.canonical('temperature'),
}),
output: Object.freeze({
flow: this.unitPolicy.output('flow'),
pressure: this.unitPolicy.output('pressure'),
power: this.unitPolicy.output('power'),
temperature: this.unitPolicy.output('temperature'),
}),
});
this.scaling = this.config.scaling.current; this.scaling = this.config.scaling.current;
this.mode = this.config.mode.current; this.mode = this.config.mode.current;
this.absDistFromPeak = 0; this.absDistFromPeak = 0;
@@ -71,12 +53,12 @@ class MachineGroup extends BaseDomain {
this.operatingPoint = new GroupOperatingPoint({ this.operatingPoint = new GroupOperatingPoint({
measurements: this.measurements, measurements: this.measurements,
machines: this.machines, machines: this.machines,
unitPolicy: this._unitView, unitPolicy: this.unitPolicy,
logger: this.logger, logger: this.logger,
}); });
this.totals = new TotalsCalculator({ this.totals = new TotalsCalculator({
machines: this.machines, machines: this.machines,
unitPolicy: this._unitView, unitPolicy: this.unitPolicy,
logger: this.logger, logger: this.logger,
operatingPoint: this.operatingPoint, operatingPoint: this.operatingPoint,
isMachineActive: (id) => this.isMachineActive(id), isMachineActive: (id) => this.isMachineActive(id),
@@ -165,8 +147,8 @@ class MachineGroup extends BaseDomain {
handlePressureChange() { handlePressureChange() {
this.operatingPoint.equalize(); this.operatingPoint.equalize();
const totals = this.calcDynamicTotals(); const totals = this.calcDynamicTotals();
const fUnit = this._unitView.canonical.flow; const fUnit = this.unitPolicy.canonical.flow;
const pUnit = this._unitView.canonical.power; const pUnit = this.unitPolicy.canonical.power;
this.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, totals.flow.act, fUnit); this.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, totals.flow.act, fUnit);
// Mirror live aggregate onto DOWNSTREAM — PS subscribes here for the // Mirror live aggregate onto DOWNSTREAM — PS subscribes here for the
// outflow signal. See preserve-tests/ps-mgc-flow-contract regression. // outflow signal. See preserve-tests/ps-mgc-flow-contract regression.
@@ -227,8 +209,8 @@ class MachineGroup extends BaseDomain {
} }
// INTENT lands on AT_EQUIPMENT only; DOWNSTREAM is the live aggregate. // INTENT lands on AT_EQUIPMENT only; DOWNSTREAM is the live aggregate.
this.operatingPoint.writeOwn('power', 'predicted', POSITIONS.AT_EQUIPMENT, bestResult.bestPower, this._unitView.canonical.power); this.operatingPoint.writeOwn('power', 'predicted', POSITIONS.AT_EQUIPMENT, bestResult.bestPower, this.unitPolicy.canonical.power);
this.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, bestResult.bestFlow, this._unitView.canonical.flow); this.operatingPoint.writeOwn('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('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); this.measurements.type('Ncog').variant('predicted').position(POSITIONS.AT_EQUIPMENT).value(bestResult.bestCog);
@@ -314,8 +296,8 @@ class MachineGroup extends BaseDomain {
finally { this._shutdownInFlight.delete(id); } finally { this._shutdownInFlight.delete(id); }
} }
})); }));
const fUnit = this._unitView.canonical.flow; const fUnit = this.unitPolicy.canonical.flow;
const pUnit = this._unitView.canonical.power; const pUnit = this.unitPolicy.canonical.power;
this.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.DOWNSTREAM, 0, fUnit); this.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.DOWNSTREAM, 0, fUnit);
this.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, 0, fUnit); this.operatingPoint.writeOwn('flow', 'predicted', POSITIONS.AT_EQUIPMENT, 0, fUnit);
this.operatingPoint.writeOwn('power', 'predicted', POSITIONS.AT_EQUIPMENT, 0, pUnit); this.operatingPoint.writeOwn('power', 'predicted', POSITIONS.AT_EQUIPMENT, 0, pUnit);
@@ -323,8 +305,8 @@ class MachineGroup extends BaseDomain {
} }
_canonicalToOutputFlow(value) { _canonicalToOutputFlow(value) {
const from = this._unitView.canonical.flow; const from = this.unitPolicy.canonical.flow;
const to = this._unitView.output.flow; const to = this.unitPolicy.output.flow;
if (!from || !to || from === to) return value; if (!from || !to || from === to) return value;
return convert(value).from(from).to(to); return convert(value).from(from).to(to);
} }