Water age ([WATER_AGE_SOURCES])#
Note
Engine: OpenSWMM 6 — refactored.
solver.water_age is the editable view over the [WATER_AGE_SOURCES]
table of the model.age component: a global age per source
pathway, plus per-node overrides for the two pathways that take node
scope. All values are hours, the config file’s own unit.
Reference: openswmm_water_age.h.
Quickstart#
from openswmm.engine import Solver, WaterAgeSource
with Solver("model.inp") as s:
print(s.water_age.enabled) # [OPTIONS] WATER_AGE
s.water_age.globals[WaterAgeSource.RAINFALL] = 0.0
s.water_age.globals[WaterAgeSource.GW] = 720.0 # hours
s.water_age.globals[WaterAgeSource.EXTERNAL_INFLOW] = -6.0
s.water_age.node_overrides.set(WaterAgeSource.DWF, "J1", 12.0)
for row in s.water_age.node_overrides:
print(row.source, row.node_index, row.hours)
s.water_age.save("model.age")
Note
Edits are live: the loaders re-read the table every step, so a mid-simulation write takes effect on the next routing step.
Global source ages#
WaterAge.globals maps WaterAgeSource to float hours
and supports len(), iteration, in, and int | str keys.
Source |
Pathway |
|---|---|
|
Rainfall-derived water. |
|
Dry-weather flow. Takes node scope. |
|
Groundwater. |
|
Rainfall-derived infiltration and inflow. |
|
|
|
Interface file. |
|
Water present at |
Important
Negative values are legal. A negative source age extracts age-volume rather than adding it, and the result is clamped so the computed age never goes below zero. Do not add a client-side non-negative guard — it would reject a modelling construct the engine supports deliberately. (Contrast Initial quality ([INITIAL_QUALITY]), where pollutant values must be non-negative.)
The C enum’s trailing COUNT = 7 sentinel is deliberately not mirrored
in Python: len(WaterAgeSource) is the count.
Node overrides#
WaterAge.node_overrides is a row-indexed sequence of
WaterAgeOverride named tuples
(source, node_index, hours). Row order is stable across edits within
a session.
Operation |
Behaviour |
|---|---|
|
Number of override rows. |
|
One |
|
Add or update the row for |
|
Delete by key, not by row index. |
Warning
Only WaterAgeSource.DWF and WaterAgeSource.EXTERNAL_INFLOW
accept node scope — the parser’s own rule. Any other source is
refused, not silently folded into the global value.
Setting the same (source, node) pair twice is an update, so an editor
can change a value it just wrote. Negative hours are legal here too.
Saving#
WaterAge.save() writes the current table as a
[WATER_AGE_SOURCES] component file — the model.age format the
water-age component parses on the next open. It accepts str or any
os.PathLike.
from pathlib import Path
s.water_age.save(Path("scenarios") / "baseline.age")
See also#
Heat transport (fluxes, solar, cloud, source temperature) — the same source/override table shape, in degC.
Initial quality ([INITIAL_QUALITY]) — seeding
__WATER_AGE__per element.External inflows — the DWF and
[INFLOWS]pathways that take node scope.Process components ([PROCESS_COMPONENTS]) — registering the
model.ageconfig path.Error handling, edge cases & debugging — what a refused write raises.