Files
EVOLV/.agents/function-anchors/rotatingMachine/ANCHOR-rotatingMachine.md
znetsixe 6a6c04d34b Migrate to new Gitea instance (gitea.wbd-rd.nl)
- Update all submodule URLs from gitea.centraal.wbd-rd.nl to gitea.wbd-rd.nl
- Add settler as proper submodule in .gitmodules
- Add agent skills, function anchors, decisions, and improvements
- Add Docker configuration and scripts
- Add manuals and third_party docs
- Update .gitignore with secrets and build artifacts
- Remove stale .tgz build artifact

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:07:04 +01:00

25 KiB

Rotating Machine Function Anchor

0) Connection Map (At a Glance)

  • Node type: rotatingMachine (nodes/rotatingMachine/rotatingMachine.js:1, nodes/rotatingMachine/rotatingMachine.html:16)
  • Consumes parent/control topics: setMode, execSequence, execMovement, flowMovement, emergencystop, simulateMeasurement, registerChild, showWorkingCurves, CoG (nodes/rotatingMachine/src/nodeClass.js:267)
  • Publishes periodic outputs:
    • Output 0: process payload (nodes/rotatingMachine/src/nodeClass.js:249)
    • Output 1: influx payload (nodes/rotatingMachine/src/nodeClass.js:251)
    • Output 2: registration/control plumbing (registerChild) (nodes/rotatingMachine/src/nodeClass.js:222)
  • Cross-node integrations (direct observed):
    • Registered/managed by machineGroupControl as machine, which then commands each machine via handleInput('parent', ...) (nodes/machineGroupControl/src/specificClass.js:50, nodes/machineGroupControl/src/specificClass.js:711, nodes/machineGroupControl/src/specificClass.js:1028)
    • Can be orchestrated by pumpingStation via execSequence and movement commands (nodes/pumpingStation/src/specificClass.js:296, nodes/pumpingStation/src/specificClass.js:297)
    • Dashboard/test flows inject simulateMeasurement and consume process output topics (nodes/rotatingMachine/examples/basic.flow.json:380, nodes/rotatingMachine/examples/basic.flow.json:412)
  • Admin/UI endpoints:
    • GET /rotatingMachine/menu.js
    • GET /rotatingMachine/configData.js (nodes/rotatingMachine/rotatingMachine.js:17, nodes/rotatingMachine/rotatingMachine.js:27)

1) Unit Table (Anchor Starts Here)

Signal/Field Represents Asset Type Default Unit Accepted Units Source of Truth Produced By Consumed By Fallback/Degraded Behavior
pressure.measured.* pressure input (upstream/downstream) measurement child (pressure) mbar any convertible via MeasurementContainer nodes/rotatingMachine/src/specificClass.js:48, nodes/rotatingMachine/src/specificClass.js:708 real child sensors and virtual dashboard child pressure dimension for curve selection (predict*.fDimension) if missing, pressure dimension forced to minimum (0) (nodes/rotatingMachine/src/specificClass.js:552)
flow.predicted.downstream predicted flow at discharge rotating machine general.unit from config convertible (m3/h, l/s, etc.) nodes/rotatingMachine/src/specificClass.js:53, nodes/rotatingMachine/src/specificClass.js:423 calcFlow() output formatting, status text, parent/group logic forced 0 if non-operational or no curve (nodes/rotatingMachine/src/specificClass.js:415, nodes/rotatingMachine/src/specificClass.js:429)
flow.predicted.atEquipment same flow at equipment point rotating machine general.unit convertible nodes/rotatingMachine/src/specificClass.js:53, nodes/rotatingMachine/src/specificClass.js:424 calcFlow() efficiency calculations forced 0 if non-operational/no curve
power.predicted.atEquipment predicted power draw rotating machine kW convertible (W, kW) nodes/rotatingMachine/src/specificClass.js:54, nodes/rotatingMachine/src/specificClass.js:448 calcPower() efficiency calculations, status text forced 0 if non-operational/no curve
ctrl.predicted.atEquipment predicted control position for requested flow rotating machine unitless (%) semantic numeric nodes/rotatingMachine/src/specificClass.js:482 calcCtrl() flowmovement command path returns 0 if no curve
temperature.measured.atEquipment process temp for density lookup machine fluid context C default, converted to K when used convertible init at 15 C (nodes/rotatingMachine/src/specificClass.js:149) init + measurement updates CoolProp density input if missing conversion, efficiency can degrade silently
atmPressure.measured.atEquipment atmospheric pressure for density lookup machine fluid context Pa convertible init at 101325 Pa (nodes/rotatingMachine/src/specificClass.js:151) init CoolProp density input fallback density 1000 kg/m3 on CoolProp error (nodes/rotatingMachine/src/specificClass.js:867)
efficiency.* specific flow (flow/power) derived metric implicit unitless ratio numeric nodes/rotatingMachine/src/specificClass.js:878, nodes/rotatingMachine/src/specificClass.js:881 calcEfficiency() output and BEP distance metrics unchanged if power/flow are zero
specificEnergyConsumption.* power per flow derived metric implicit numeric nodes/rotatingMachine/src/specificClass.js:879, nodes/rotatingMachine/src/specificClass.js:882 calcEfficiency() output consumers unchanged if power/flow zero
nHydraulicEfficiency.* hydraulic-efficiency-like metric derived metric unitless numeric nodes/rotatingMachine/src/specificClass.js:884 calcEfficiency() diagnostic output skipped if pressure/flow/power conversions unavailable
cog, NCog, NCogPercent efficiency-curve peak indicators derived curve metrics unitless numeric nodes/rotatingMachine/src/specificClass.js:796, nodes/rotatingMachine/src/specificClass.js:948 calcCog(), getOutput() group optimization, dashboards retains last computed values
effDistFromPeak, effRelDistFromPeak distance from best-efficiency point derived unitless numeric nodes/rotatingMachine/src/specificClass.js:924, nodes/rotatingMachine/src/specificClass.js:962 calcDistanceBEP() output consumers remains last computed value
runtime, maintenanceTime, moveTimeleft, state movement/state telemetry state machine h/s/enum numeric/string nodes/rotatingMachine/src/specificClass.js:943 state module output/status/parent control depends on state module behavior

2) Class Identity

  • Runtime registration + endpoints: nodes/rotatingMachine/rotatingMachine.js
  • Node-RED wrapper/routing: nodes/rotatingMachine/src/nodeClass.js
  • Domain/mechanical logic: nodes/rotatingMachine/src/specificClass.js
  • Editor UI/defaults: nodes/rotatingMachine/rotatingMachine.html
  • Default config schema/validation rules: nodes/generalFunctions/src/configs/rotatingMachine.json

3) Configuration Contract

UI Field Runtime Path Default Validation/Coercion Behavior Impact Source
speed stateConfig.movement.speed 1 Number(uiConfig.speed) movement progression speed nodes/rotatingMachine/rotatingMachine.html:22, nodes/rotatingMachine/src/nodeClass.js:91
startup/warmup/shutdown/cooldown stateConfig.time.* 0 Number(...) sequence transition durations nodes/rotatingMachine/rotatingMachine.html:23, nodes/rotatingMachine/src/nodeClass.js:95
movementMode stateConfig.movement.mode staticspeed raw string state movement model selection nodes/rotatingMachine/rotatingMachine.html:27, nodes/rotatingMachine/src/nodeClass.js:92
unit config.general.unit + config.asset.unit UI empty, config default l/s direct assign then config init base flow unit for measurements and outputs nodes/rotatingMachine/src/nodeClass.js:50, nodes/generalFunctions/src/configs/rotatingMachine.json:18
model config.asset.model UI empty, config default Unknown direct assign curve loading via loadCurve(model) nodes/rotatingMachine/src/nodeClass.js:62, nodes/rotatingMachine/src/specificClass.js:18
logging fields config.general.logging.* enableLog=false, logLevel=error in UI; config default enabled/info direct assign runtime verbosity nodes/rotatingMachine/rotatingMachine.html:39, nodes/rotatingMachine/src/nodeClass.js:51
positionVsParent config.functionality.positionVsParent UI empty, config default atEquipment direct assign + default in schema registration topology to parent nodes/rotatingMachine/src/nodeClass.js:66, nodes/generalFunctions/src/configs/rotatingMachine.json:74
Mode/action/source rules config.mode.* schema defaults configUtils validation into Set semantics command gating nodes/generalFunctions/src/configs/rotatingMachine.json:231, nodes/rotatingMachine/src/specificClass.js:269
Sequences config.sequences.* schema defaults configUtils validation machine state transitions nodes/generalFunctions/src/configs/rotatingMachine.json:360, nodes/rotatingMachine/src/specificClass.js:363

4) Input/Output Contract

4.1 Input topics (nodeClass)

Topic Payload schema Handler Side effects
registerChild payload=<nodeId>, optional positionVsParent registers child source via childRegistrationUtils starts measurement event wiring (nodes/rotatingMachine/src/nodeClass.js:268)
setMode payload=<mode> setMode() updates command policy mode
execSequence {source, action, parameter} handleInput() executes state sequence
execMovement {source, action, setpoint} handleInput() moves position
flowMovement {source, action, setpoint} handleInput() converts flow->ctrl then moves
emergencystop {source, action} handleInput() emergency sequence attempt
simulateMeasurement {type, position, value, unit, timestamp?} measurement update handlers updates virtual pressure or measured values
showWorkingCurves any immediate response on output 0 emits curve/cog debug payload
CoG any immediate response on output 0 calls m.showCoG() (method currently not defined in specificClass)

4.2 Output ports

Port Message type Source
0 formatted process message from flattened measurements + state fields nodes/rotatingMachine/src/nodeClass.js:250
1 formatted influxdb message nodes/rotatingMachine/src/nodeClass.js:251
2 registration to parent: {topic:'registerChild', payload:id, positionVsParent} nodes/rotatingMachine/src/nodeClass.js:222

4.3 Admin endpoints

Endpoint Purpose Source
/rotatingMachine/menu.js dynamic editor menu script (asset, logger, position) nodes/rotatingMachine/rotatingMachine.js:17
/rotatingMachine/configData.js dynamic default/config script nodes/rotatingMachine/rotatingMachine.js:27

5) Mode, State, and Control Model

  • Modes: auto, virtualControl, fysicalControl (nodes/generalFunctions/src/configs/rotatingMachine.json:233)
  • Mode gate enforcement:
    • isValidActionForMode(action, mode) (nodes/rotatingMachine/src/specificClass.js:279)
    • isValidSourceForMode(source, mode) (nodes/rotatingMachine/src/specificClass.js:269)
  • Actions supported by handler: execsequence, execmovement, flowmovement, entermaintenance, exitmaintenance, emergencystop, statuscheck (nodes/rotatingMachine/src/specificClass.js:303)
  • Operational states for active prediction: operational, warmingup, accelerating, decelerating (nodes/rotatingMachine/src/specificClass.js:739)
  • Sequence defaults: startup/shutdown/emergencystop/maintenance flows defined in config schema (nodes/generalFunctions/src/configs/rotatingMachine.json:365)

6) End-to-End Execution Flow

  1. Node registration instantiates nodeClass, then Specific (Machine).
  2. Machine constructor loads model curve, initializes predictors/state/measurements, creates virtual pressure children, and subscribes to state events.
  3. nodeClass starts delayed child registration (output 2) and 1-second tick/status loops.
  4. Incoming topics route through switch(msg.topic) to mode changes, movement/sequence commands, child registration, and simulated measurements.
  5. Child measurement events update parent measurement container and dispatch typed handlers.
  6. Pressure updates set predictor dimension, recompute flow/power/efficiency/CoG/BEP metrics.
  7. Each tick emits formatted process + influx messages.

7) Full Function Inventory

7.1 nodes/rotatingMachine/rotatingMachine.js

Function Purpose Source
module export init register Node-RED node type and admin endpoints nodes/rotatingMachine/rotatingMachine.js:5

7.2 nodes/rotatingMachine/src/nodeClass.js

Function Purpose Key effects Source
constructor boot wrapper lifecycle load config, create source, start loops/handlers nodes/rotatingMachine/src/nodeClass.js:16
_loadConfig map UI config to runtime config builds general/asset/functionality; builds outputUtils nodes/rotatingMachine/src/nodeClass.js:44
_setupSpecificClass build Machine with movement/time state config instantiates Specific; stores on node.source nodes/rotatingMachine/src/nodeClass.js:77
_bindEvents placeholder no-op currently nodes/rotatingMachine/src/nodeClass.js:112
_updateNodeStatus compose Node-RED status icon/text warns once for missing pressure init; includes flow/power/state nodes/rotatingMachine/src/nodeClass.js:116
_registerChild announce self to parent sends registerChild on output 2 after 100ms nodes/rotatingMachine/src/nodeClass.js:217
_startTickLoop periodic work 1s _tick; 1s status refresh nodes/rotatingMachine/src/nodeClass.js:230
_tick periodic output generation formatMsg(process) + formatMsg(influxdb) send to outputs 0/1 nodes/rotatingMachine/src/nodeClass.js:246
_attachInputHandler route inbound topics dispatches all command/simulation/register/show topics nodes/rotatingMachine/src/nodeClass.js:260
_attachCloseHandler shutdown cleanup clears intervals nodes/rotatingMachine/src/nodeClass.js:357

7.3 nodes/rotatingMachine/src/specificClass.js

Function Purpose Key effects Source
constructor initialize machine domain object config/curve/predictors/state/measurement/events/virtual children nodes/rotatingMachine/src/specificClass.js:7
_initVirtualPressureChildren create simulated upstream/downstream pressure children registers virtual measurement children nodes/rotatingMachine/src/specificClass.js:104
_init seed base measurements and min/max flow sets temperature, atmPressure, curve min/max nodes/rotatingMachine/src/specificClass.js:147
_updateState enforce non-operational flow = 0 overwrites predicted flow when inactive nodes/rotatingMachine/src/specificClass.js:163
registerChild subscribe to child measurement events stores real pressure child IDs, updates measurements, calls handlers nodes/rotatingMachine/src/specificClass.js:173
_callMeasurementHandler typed measurement dispatch pressure/flow/temp handlers + fallback nodes/rotatingMachine/src/specificClass.js:212
assessDrift compare measured vs predicted windows delegates to nrmse.assessDrift nodes/rotatingMachine/src/specificClass.js:237
reverseCurve flip x/y arrays used for flow->ctrl predictor nodes/rotatingMachine/src/specificClass.js:252
updateConfig apply validated config patch merges via configUtils nodes/rotatingMachine/src/specificClass.js:264
isValidSourceForMode mode source gate checks configured allowed set nodes/rotatingMachine/src/specificClass.js:269
isValidActionForMode mode action gate checks configured allowed set nodes/rotatingMachine/src/specificClass.js:279
handleInput main command dispatcher executes sequence/movement/status commands nodes/rotatingMachine/src/specificClass.js:289
abortMovement cancel current movement delegates to state abort if available nodes/rotatingMachine/src/specificClass.js:345
setMode update current mode validates against schema enum values nodes/rotatingMachine/src/specificClass.js:351
executeSequence run state sequence transitions through configured states; updatePosition at end nodes/rotatingMachine/src/specificClass.js:363
setpoint move to numeric target validates non-negative number then state.moveTo nodes/rotatingMachine/src/specificClass.js:394
calcFlow predict flow from current curve and ctrl position writes predicted flow measurements nodes/rotatingMachine/src/specificClass.js:413
calcPower predict power from current curve and ctrl position writes predicted power measurement nodes/rotatingMachine/src/specificClass.js:438
inputFlowCalcPower estimate power from requested flow flow->ctrl->power chained prediction nodes/rotatingMachine/src/specificClass.js:460
calcCtrl estimate ctrl for desired flow writes predicted ctrl nodes/rotatingMachine/src/specificClass.js:478
getMeasuredPressure choose pressure basis for prediction differential preferred; then downstream; then upstream; else 0 nodes/rotatingMachine/src/specificClass.js:496
_getPreferredPressureValue pressure source priority resolver real child > virtual child > aggregated position value nodes/rotatingMachine/src/specificClass.js:570
getPressureInitializationStatus pressure readiness status model upstream/downstream/differential flags nodes/rotatingMachine/src/specificClass.js:600
updateSimulatedMeasurement write dashboard-sim values pressure route via virtual child; others dispatch typed handler nodes/rotatingMachine/src/specificClass.js:617
handleMeasuredFlow reconcile measured flow availability/consistency returns matched/single measurement or null nodes/rotatingMachine/src/specificClass.js:644
handleMeasuredPower read measured power returns value or null with error nodes/rotatingMachine/src/specificClass.js:685
updateMeasuredTemperature temp update hook currently log-only nodes/rotatingMachine/src/specificClass.js:698
updateMeasuredPressure pressure update hook stores pressure, recomputes pressure basis and position metrics nodes/rotatingMachine/src/specificClass.js:703
updateMeasuredFlow flow update hook stores measured flow if operational; mirrors predicted flow value nodes/rotatingMachine/src/specificClass.js:718
_isOperationalState operational predicate active states used by prediction guards nodes/rotatingMachine/src/specificClass.js:737
updatePosition core recompute pipeline on movement/state changes calc flow/power -> efficiency -> cog -> BEP distance nodes/rotatingMachine/src/specificClass.js:745
calcDistanceFromPeak abs distance metric absolute efficiency delta nodes/rotatingMachine/src/specificClass.js:767
calcRelativeDistanceFromPeak normalized distance metric interpolation to [0,1] nodes/rotatingMachine/src/specificClass.js:771
showWorkingCurves debugging snapshot of current curve context returns current curves + metrics nodes/rotatingMachine/src/specificClass.js:779
calcCog compute peak efficiency point on current curve updates cog, NCog, indexes, minEfficiency nodes/rotatingMachine/src/specificClass.js:796
calcEfficiencyCurve derive efficiency curve and peak/min from aligned power/flow arrays nodes/rotatingMachine/src/specificClass.js:817
calcFlowPower convenience combined prediction calls calcFlow and calcPower nodes/rotatingMachine/src/specificClass.js:845
calcEfficiency compute efficiency family metrics CoolProp density path + fallback + writes derived metrics nodes/rotatingMachine/src/specificClass.js:854
updateCurve replace machine curve at runtime validates config and updates predictors nodes/rotatingMachine/src/specificClass.js:897
getCompleteCurve return full loaded curves power+flow input curves nodes/rotatingMachine/src/specificClass.js:910
getCurrentCurves return currently selected pressure curve slices current flow/power curves nodes/rotatingMachine/src/specificClass.js:916
calcDistanceBEP write BEP distance metrics updates absDistFromPeak, relDistFromPeak nodes/rotatingMachine/src/specificClass.js:924
getOutput flatten and enrich output object adds state/runtime/ctrl/mode/cog/drift/eff-distance nodes/rotatingMachine/src/specificClass.js:936

8) Calculations and Capability Matrix

  • Curve-backed capabilities:
    • flow prediction (nq) via predictFlow
    • power prediction (np) via predictPower
    • control inversion (flow->ctrl) via reversed nq
  • Pressure basis selection order:
    1. real differential (downstream - upstream)
    2. real/virtual downstream only
    3. real/virtual upstream only
    4. fallback 0 (minimum pressure behavior)
  • Availability-first behavior:
    • missing pressure does not stop operation; it degrades predictions and warns.
    • CoolProp failure does not stop operation; density fallback is used.
    • non-operational states force predicted flow/power to zero.
  • BEP indicators:
    • computes peak efficiency index and normalized CoG (NCog) for optimization usage by parent/group controllers.

9) Error Handling and Safeguards

  • Invalid actions/sources are rejected by mode gates, with warnings (nodes/rotatingMachine/src/specificClass.js:297).
  • Invalid setpoint (<0 or non-number) is rejected in setpoint() (nodes/rotatingMachine/src/specificClass.js:398).
  • Missing curve model disables predictor objects but keeps class alive (nodes/rotatingMachine/src/specificClass.js:27).
  • Missing pressure initialization surfaces Node-RED warning ring status (nodes/rotatingMachine/src/nodeClass.js:126).
  • simulateMeasurement rejects non-finite values and unsupported types (nodes/rotatingMachine/src/nodeClass.js:312).

10) Test Evidence Matrix

Test file Covered behavior
nodes/rotatingMachine/test/basic/constructor.basic.test.js constructor curve/no-curve behavior and output shape
nodes/rotatingMachine/test/basic/mode-and-input.basic.test.js setMode, handleInput validation, operational-state predicate
nodes/rotatingMachine/test/edge/error-paths.edge.test.js negative setpoint resilience, status failure path
nodes/rotatingMachine/test/edge/nodeClass-routing.edge.test.js input-topic routing, pressure initialization status warning, curve/CoG reply routing
nodes/rotatingMachine/test/integration/sequences.integration.test.js startup sequence and movement execution
nodes/rotatingMachine/test/integration/registration.integration.test.js child registration and pressure event propagation
nodes/rotatingMachine/test/integration/pressure-initialization.integration.test.js explicit pressure init combinations and real-vs-virtual pressure priority
nodes/rotatingMachine/test/integration/coolprop.integration.test.js efficiency path with CoolProp and medium-pressure initialization behavior
nodes/rotatingMachine/test/integration/basic-flow-dashboard.integration.test.js example-flow parser/wiring contracts for dashboard topics

11) Invariants (Anchor Truth)

  • specificClass is the mechanical/logic source of truth; nodeClass is routing/lifecycle only.
  • Prediction calculations must be curve-backed when curve exists, and availability-first fallback when it does not.
  • Pressure selection priority is real sensor > virtual dashboard > aggregated fallback.
  • Command execution must remain mode-gated by both action and source.
  • Output shape must keep process/influx separation and parent registration on output port 2.
  • Operational-state gating must continue to prevent active prediction outputs in inactive states.

12) Known Gaps / Risks (Current Implementation)

  • nodeClass routes topic CoG to m.showCoG(), but showCoG is not present in specificClass (runtime risk on that topic): nodes/rotatingMachine/src/nodeClass.js:340.
  • handleInput('emergencystop') calls sequence "emergencyStop", but config default key is "emergencystop" (case/name mismatch risk): nodes/rotatingMachine/src/specificClass.js:327, nodes/generalFunctions/src/configs/rotatingMachine.json:381.
  • _setupSpecificClass uses machineConfig.eneableLog (typo) for state logging config; likely not intended: nodes/rotatingMachine/src/nodeClass.js:86.
  • Label expression can evaluate unexpectedly because + and || precedence are mixed: nodes/rotatingMachine/rotatingMachine.html:58.

13) Change Checklist

When changing rotatingMachine logic, update all of:

  1. Runtime logic in nodes/rotatingMachine/src/specificClass.js.
  2. Node-RED routing/lifecycle in nodes/rotatingMachine/src/nodeClass.js.
  3. UI defaults/fields in nodes/rotatingMachine/rotatingMachine.html.
  4. Config schema and mode/action/source/sequence defaults in nodes/generalFunctions/src/configs/rotatingMachine.json.
  5. Example flow contracts in nodes/rotatingMachine/examples/*.flow.json.
  6. Tests under nodes/rotatingMachine/test/ (basic, edge, integration).