Merge origin/basin-docs-update: per-mode SVG + stopLevel hysteresis + shifted ramp
Reconciles the 7-commit basin-docs-update feature branch (which never
landed on main before the platform refactor) with the post-refactor
architecture on development. Each basin-docs feature ported into the
relevant concern module:
control/levelBased.js
- stopLevel Schmitt-trigger + dead-band keep-alive
- Shifted ramp (arm % → hold @ 100% → ramp down to shiftLevel)
- Linear vs log up-curve (curveType + logCurveFactor)
measurement/flowAggregator.js
- Predicted-volume overflow clamp + spill flow stream
- Cumulative overflowVolume + underflowVolume
- Hard floor at 0 + dry-run-on-transition handling
basin/thresholdValidator.js
- computeSafetyPoints exposes dryRunLevel + highVolumeSafetyLevel
- startLevel ≤ inflowLevel invariant added
measurement/calibration.js + commands/
- Manual q_out path (set.outflow / q_out alias)
safety/safetyController.js
- Accepts both legacy + new high-volume threshold names
UI:
pumpingStation.html — restored the side-panel + SVG mode-preview block,
added defaults for stopLevel/shiftLevel/shiftArmPercent/levelCurveType/
logCurveFactor/enableShiftedRamp.
src/editor/* — basin-docs' 7-file modular editor (replaces single
src/editor.js, which is deleted).
pumpingStation.js — admin endpoint serves editor/:file.
Tests: 130/130 pass (125 basic + 5 integration). Two basin-docs test
files added: nodeClass-config.test.js, basic-dashboard-flow.test.js,
shifted-ramp-end-to-end.test.js. One pre-refactor control-levelBased
test adapted to match basin-docs canonical "no-shutdown in dead zone"
behaviour.
Human-review items (see commit context):
- rampFoot = inflowLevel (matches basin-docs test); basin-docs source
used rampFoot = startLevel. Domain owner: confirm intent.
- Naming kept dual (overfillLevel + highVolumeSafetyLevel).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,8 @@ class BasinGeometry {
|
||||
const inflowLevel = basinConfig.inflowLevel;
|
||||
const outflowLevel = basinConfig.outflowLevel;
|
||||
const overflowLevel = basinConfig.overflowLevel;
|
||||
const inletPipeDiameter = basinConfig.inletPipeDiameter;
|
||||
const outletPipeDiameter = basinConfig.outletPipeDiameter;
|
||||
const minHeightBasedOn = hydraulicsConfig?.minHeightBasedOn;
|
||||
|
||||
const surfaceArea = volEmptyBasin / heightBasin;
|
||||
@@ -33,6 +35,8 @@ class BasinGeometry {
|
||||
this._inflowLevel = inflowLevel;
|
||||
this._outflowLevel = outflowLevel;
|
||||
this._overflowLevel = overflowLevel;
|
||||
this._inletPipeDiameter = inletPipeDiameter;
|
||||
this._outletPipeDiameter = outletPipeDiameter;
|
||||
this._surfaceArea = surfaceArea;
|
||||
this._maxVol = maxVol;
|
||||
this._maxVolAtOverflow = maxVolAtOverflow;
|
||||
@@ -47,6 +51,8 @@ class BasinGeometry {
|
||||
get inflowLevel() { return this._inflowLevel; }
|
||||
get outflowLevel() { return this._outflowLevel; }
|
||||
get overflowLevel() { return this._overflowLevel; }
|
||||
get inletPipeDiameter() { return this._inletPipeDiameter; }
|
||||
get outletPipeDiameter() { return this._outletPipeDiameter; }
|
||||
get surfaceArea() { return this._surfaceArea; }
|
||||
get maxVol() { return this._maxVol; }
|
||||
get maxVolAtOverflow() { return this._maxVolAtOverflow; }
|
||||
@@ -77,6 +83,8 @@ class BasinGeometry {
|
||||
inflowLevel: this._inflowLevel,
|
||||
outflowLevel: this._outflowLevel,
|
||||
overflowLevel: this._overflowLevel,
|
||||
inletPipeDiameter: this._inletPipeDiameter,
|
||||
outletPipeDiameter: this._outletPipeDiameter,
|
||||
surfaceArea: this._surfaceArea,
|
||||
maxVol: this._maxVol,
|
||||
maxVolAtOverflow: this._maxVolAtOverflow,
|
||||
|
||||
Reference in New Issue
Block a user