fix: fully configure PS basin + add node-completeness rule
Some checks failed
CI / lint-and-test (push) Has been cancelled
Some checks failed
CI / lint-and-test (push) Has been cancelled
Basin undersized (10m³) for sinus peak (126 m³/h) → overflow → 122%. Now 30 m³ with 4m height, all PS fields set. New rule: always configure every field of every node. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -576,15 +576,37 @@ def build_process_tab():
|
||||
"hasDistance": False, "distance": 0, "distanceUnit": "m",
|
||||
"distanceDescription": "",
|
||||
"processOutputFormat": "process", "dbaseOutputFormat": "influxdb",
|
||||
# PS in levelbased mode — sinus inflow fills the basin, pumps start
|
||||
# when level > startLevel, stop when level < stopLevel.
|
||||
# === FULLY CONFIGURED PS — every field explicitly set ===
|
||||
# Rule: ALWAYS configure ALL node fields. Defaults are for
|
||||
# schema validation, not for realistic operation.
|
||||
#
|
||||
# Basin geometry: 30 m³, 4 m tall → surfaceArea = 7.5 m²
|
||||
# Sized so peak sinus inflow (0.035 m³/s = 126 m³/h) takes
|
||||
# ~6 min to fill from startLevel to overflow → pumps have time.
|
||||
"controlMode": "levelbased",
|
||||
"basinVolume": 10, "basinHeight": 3,
|
||||
"startLevel": 1.2, "stopLevel": 0.6,
|
||||
"minFlowLevel": 0.6, "maxFlowLevel": 2.8,
|
||||
"heightInlet": 2.5, "heightOutlet": 0.2, "heightOverflow": 2.8,
|
||||
# Volume-based safeties ON, time-based OFF (time guard fires too
|
||||
# aggressively with the sinus demo's small basin + high peak inflow).
|
||||
"basinVolume": 30,
|
||||
"basinHeight": 4,
|
||||
"heightInlet": 3.5,
|
||||
"heightOutlet": 0.3,
|
||||
"heightOverflow": 3.8,
|
||||
"inletPipeDiameter": 0.3,
|
||||
"outletPipeDiameter": 0.3,
|
||||
# Level-based control thresholds
|
||||
"startLevel": 2.0, # pumps ON above 2.0 m (50% of height)
|
||||
"stopLevel": 1.0, # pumps OFF below 1.0 m (25% of height)
|
||||
"minFlowLevel": 1.0, # 0% pump demand at this level
|
||||
"maxFlowLevel": 3.5, # 100% pump demand at this level
|
||||
# Hydraulics
|
||||
"refHeight": "NAP",
|
||||
"minHeightBasedOn": "outlet",
|
||||
"basinBottomRef": 0,
|
||||
"staticHead": 12,
|
||||
"maxDischargeHead": 24,
|
||||
"pipelineLength": 80,
|
||||
"defaultFluid": "wastewater",
|
||||
"temperatureReferenceDegC": 15,
|
||||
"maxInflowRate": 200,
|
||||
# Safety guards
|
||||
"enableDryRunProtection": True,
|
||||
"enableOverfillProtection": True,
|
||||
"dryRunThresholdPercent": 5,
|
||||
@@ -613,7 +635,7 @@ def build_process_tab():
|
||||
"const qOut = find('flow.measured.downstream.') || find('flow.measured.out.');\n"
|
||||
"// Compute derived metrics\n"
|
||||
"// Basin capacity = basinVolume (config). Don't hardcode — read it once.\n"
|
||||
"if (!context.get('maxVol')) context.set('maxVol', 10.0); // basinVolume from PS config\n"
|
||||
"if (!context.get('maxVol')) context.set('maxVol', 30.0); // basinVolume from PS config\n"
|
||||
"const maxVol = context.get('maxVol');\n"
|
||||
"const fillPct = vol != null ? Math.min(100, Math.max(0, Math.round(Number(vol) / maxVol * 100))) : null;\n"
|
||||
"const netM3h = (c.netFlow != null) ? Number(c.netFlow) * 3600 : null;\n"
|
||||
@@ -1094,11 +1116,11 @@ def build_ui_tab():
|
||||
# ===== Basin charts + gauges (fill %, level, net flow) =====
|
||||
# Gauge segment definitions (reused for both pages)
|
||||
TANK_SEGMENTS = [
|
||||
{"color": "#f44336", "from": 0}, # red: below stopLevel
|
||||
{"color": "#ff9800", "from": 0.6}, # orange: between stop and start
|
||||
{"color": "#2196f3", "from": 1.2}, # blue: normal operating
|
||||
{"color": "#ff9800", "from": 2.5}, # orange: approaching overflow
|
||||
{"color": "#f44336", "from": 2.8}, # red: overflow zone
|
||||
{"color": "#f44336", "from": 0}, # red: below stopLevel (1.0 m)
|
||||
{"color": "#ff9800", "from": 1.0}, # orange: between stop and start
|
||||
{"color": "#2196f3", "from": 2.0}, # blue: normal operating (startLevel)
|
||||
{"color": "#ff9800", "from": 3.5}, # orange: approaching overflow
|
||||
{"color": "#f44336", "from": 3.8}, # red: overflow zone (heightOverflow)
|
||||
]
|
||||
FILL_SEGMENTS = [
|
||||
{"color": "#f44336", "from": 0},
|
||||
@@ -1131,7 +1153,7 @@ def build_ui_tab():
|
||||
"gtype": "gauge-tank", "gstyle": "Rounded",
|
||||
"title": "Level", "units": "m",
|
||||
"prefix": "", "suffix": " m",
|
||||
"min": 0, "max": 3,
|
||||
"min": 0, "max": 4,
|
||||
"segments": TANK_SEGMENTS,
|
||||
"width": 2, "height": 5, "order": 2,
|
||||
"icon": "", "sizeGauge": 20, "sizeGap": 2, "sizeSegments": 10,
|
||||
|
||||
Reference in New Issue
Block a user