94 lines
4.1 KiB
JavaScript
94 lines
4.1 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
const test = require('node:test');
|
||
|
|
const assert = require('node:assert/strict');
|
||
|
|
|
||
|
|
const MachineGroup = require('../../src/specificClass');
|
||
|
|
const Machine = require('../../../rotatingMachine/src/specificClass');
|
||
|
|
const baseCurve = require('../../../generalFunctions/datasets/assetData/curves/hidrostal-H05K-S03R.json');
|
||
|
|
|
||
|
|
/**
|
||
|
|
* After fixing rotatingMachine + MGC to use hydraulic efficiency
|
||
|
|
* (η = Q·ΔP / P_shaft) instead of raw flow/power, every BEP-related output
|
||
|
|
* on MGC should be in the dimensionless 0..1 range and respond to demand
|
||
|
|
* changes. This check ties the whole chain together:
|
||
|
|
* - per-machine cog updates after equalize
|
||
|
|
* - group efficiency measurement is hydraulic (matches scale of cogs)
|
||
|
|
* - calcDistanceBEP(eff, mean(cog), min(cog)) is non-degenerate
|
||
|
|
*/
|
||
|
|
|
||
|
|
const stateConfig = {
|
||
|
|
time: { starting: 0, warmingup: 0, stopping: 0, coolingdown: 0 },
|
||
|
|
movement: { speed: 1200, mode: 'staticspeed', maxSpeed: 1800 },
|
||
|
|
};
|
||
|
|
|
||
|
|
function machineConfig(id, label) {
|
||
|
|
return {
|
||
|
|
general: { logging: { enabled: false, logLevel: 'error' }, name: label, id, unit: 'm3/h' },
|
||
|
|
functionality: { softwareType: 'machine', role: 'rotationaldevicecontroller' },
|
||
|
|
asset: { model: 'hidrostal-H05K-S03R', unit: 'm3/h' },
|
||
|
|
mode: {
|
||
|
|
current: 'auto',
|
||
|
|
allowedActions: { auto: ['execsequence', 'execmovement', 'flowmovement', 'statuscheck'] },
|
||
|
|
allowedSources: { auto: ['parent', 'GUI'] },
|
||
|
|
},
|
||
|
|
sequences: {
|
||
|
|
startup: ['starting', 'warmingup', 'operational'],
|
||
|
|
shutdown: ['stopping', 'coolingdown', 'idle'],
|
||
|
|
emergencystop: ['emergencystop', 'off'],
|
||
|
|
},
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function groupConfig() {
|
||
|
|
return {
|
||
|
|
general: { logging: { enabled: false, logLevel: 'error' }, name: 'TestGroup' },
|
||
|
|
functionality: { softwareType: 'machinegroup', role: 'groupcontroller' },
|
||
|
|
mode: { current: 'optimalcontrol' },
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
async function setupGroupWithTwoPumps() {
|
||
|
|
const m1 = new Machine(machineConfig(1, 'pump-1'), stateConfig);
|
||
|
|
const m2 = new Machine(machineConfig(2, 'pump-2'), stateConfig);
|
||
|
|
m1.config.asset.machineCurve = baseCurve;
|
||
|
|
m2.config.asset.machineCurve = baseCurve;
|
||
|
|
await m1.handleInput('parent', 'execSequence', 'startup');
|
||
|
|
await m2.handleInput('parent', 'execSequence', 'startup');
|
||
|
|
|
||
|
|
const mgc = new MachineGroup(groupConfig(), stateConfig);
|
||
|
|
// Mutate the existing machines object — replacing the reference would
|
||
|
|
// strand operatingPoint/totals/efficiency on the original empty bag.
|
||
|
|
mgc.machines[1] = m1;
|
||
|
|
mgc.machines[2] = m2;
|
||
|
|
// Set header (system) pressure differential: 800/1200 mbar => 400 mbar = 40 kPa
|
||
|
|
mgc.measurements.type('pressure').variant('measured').position('upstream').value(80000, Date.now(), 'Pa');
|
||
|
|
mgc.measurements.type('pressure').variant('measured').position('downstream').value(120000, Date.now(), 'Pa');
|
||
|
|
mgc.operatingPoint.equalize();
|
||
|
|
return { mgc, m1, m2 };
|
||
|
|
}
|
||
|
|
|
||
|
|
test('after equalize, each child cog is a dimensionless 0..1 hydraulic efficiency', async () => {
|
||
|
|
const { m1, m2 } = await setupGroupWithTwoPumps();
|
||
|
|
// Trigger updatePosition by setting ctrl explicitly
|
||
|
|
m1.updatePosition();
|
||
|
|
m2.updatePosition();
|
||
|
|
for (const m of [m1, m2]) {
|
||
|
|
assert.ok(Number.isFinite(m.cog), `cog must be finite, got ${m.cog}`);
|
||
|
|
assert.ok(m.cog >= 0 && m.cog <= 1.0,
|
||
|
|
`cog must be a 0..1 hydraulic efficiency, got ${m.cog}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
test('operatingPoint.headerDiffPa is set by equalize and matches measured differential', async () => {
|
||
|
|
const { mgc, m1 } = await setupGroupWithTwoPumps();
|
||
|
|
// Equalize reads from host measurements; falls back to children when
|
||
|
|
// header is missing. Either path should produce headerDiffPa > 0.
|
||
|
|
// headerDiff must equal the measured differential (40 kPa) once any
|
||
|
|
// pressure source is populated.
|
||
|
|
assert.equal(mgc.operatingPoint.headerDiffPa, 40000,
|
||
|
|
`headerDiffPa should equal downstream-upstream = 40000 Pa, got ${mgc.operatingPoint.headerDiffPa}`);
|
||
|
|
// Sanity: the host's child reference is still consumable for diagnostics.
|
||
|
|
void m1.measurements;
|
||
|
|
});
|