Water quality (landuse, buildup, washoff, treatment)#
Note
Engine: OpenSWMM 6 — refactored. Documents
openswmm.engine.Quality.
The Quality class manages water-quality processes that act
on top of the pollutant list (see Pollutants):
Landuse — categorical surface types attached to subcatchments.
Buildup — pollutant accumulation on the surface during dry weather.
Washoff — release of accumulated pollutants during runoff events.
Treatment — node-based concentration reductions (settling, removal, custom expressions).
Sweeping — periodic mechanical removal of buildup.
Reference: openswmm_quality.h.
Class signature#
class Quality:
def __init__(self, solver: Solver) -> None: ...
Key methods#
Landuse#
Method |
Action / returns |
|---|---|
|
Number of registered landuses. |
|
Integer index for a landuse string id. |
|
String id for an integer index. |
|
Days between street sweepings. |
|
Fraction of buildup removed per sweep. |
Buildup#
Method |
Action / returns |
|---|---|
|
Configure |
|
Returns a dict of the active buildup model parameters. |
Washoff#
Method |
Action / returns |
|---|---|
|
Configure |
|
Returns a dict of the active washoff model parameters. |
Treatment#
Method |
Action / returns |
|---|---|
|
Set a treatment expression at a node for pollutant |
|
Retrieve the expression text. |
|
Remove the treatment. |
Treatment expressions are full SWMM math expressions evaluated each
step — e.g. "R = 0.85 * EXP(-0.05 * HRT)" for first-order
removal in a settling tank.
End-to-end example#
from openswmm.engine import (
Solver, Quality, Pollutants, Nodes,
BuildupFunc, WashoffFunc,
)
with Solver("water_quality.inp", "wq.rpt", "wq.out") as s:
q = Quality(s)
polls = Pollutants(s)
nodes = Nodes(s)
s.open()
# Strengthen TSS buildup on RESIDENTIAL landuse
lu = q.landuse_index("RESIDENTIAL")
tss = polls.get_index("TSS")
q.buildup_set(
lu, tss,
func=int(BuildupFunc.SAT),
c1=80.0, # max buildup (lb/acre)
c2=10.0, # half-saturation time (days)
normalizer=0, # buildup per unit area
)
# Add settling-tank treatment at outfall OUT1
q.treatment_set(
nodes.get_index("OUT1"),
tss,
"R = 0.85 * EXP(-0.05 * HRT)",
)
s.initialize()
s.start()
while s.step():
pass
s.end()
Common recipes#
Add street sweeping to a landuse#
lu = q.landuse_index("RESIDENTIAL")
q.landuse_set_sweep_interval(lu, 7.0) # weekly
q.landuse_set_sweep_removal(lu, 0.4) # 40% removed per sweep
Remove a treatment expression mid-edit#
q.treatment_clear(nodes.get_index("OUT1"), polls.get_index("TSS"))
Inspect the active buildup parameters#
params = q.buildup_get(q.landuse_index("RESIDENTIAL"),
polls.get_index("TSS"))
print(params) # → {'func': 'SAT', 'c1': 80.0, 'c2': 10.0, ...}
Run a sensitivity sweep on washoff coefficient#
for c1 in [0.005, 0.01, 0.02, 0.05]:
# Re-open / re-edit / re-run pattern
with Solver("model.inp", f"sweep_{c1}.rpt", f"sweep_{c1}.out") as s:
q = Quality(s); polls = Pollutants(s)
s.open()
q.washoff_set(
q.landuse_index("RESIDENTIAL"),
polls.get_index("TSS"),
func=int(WashoffFunc.EXP),
c1=c1,
c2=2.0,
cleaning_efficiency=0.0,
bmp_efficiency=0.0,
)
s.initialize(); s.start()
while s.step():
pass
s.end()
EngineState requirements & exceptions#
Method group |
Required state |
Notes |
|---|---|---|
landuse identity / count |
|
n/a |
buildup / washoff setters |
|
Apply before |
sweep parameter setters |
|
Mid-run changes are honoured at the next sweep. |
treatment setters |
|
Treatment expressions are compiled at |
Common EngineError codes:
INVALID_INDEX— landuse / pollutant / node out of range.INVALID_TYPE— function code or expression rejected by the parser; the message includes the offending text.
See also#
Pollutants — the pollutant list this module operates on.
Subcatchments — assign landuse coverage fractions (
Subcatchments.set_coverage()).Output reader (binary .out file) — post-run pollutant time series.