Subcatchments#
Note
Engine: OpenSWMM 6 — refactored. This page documents the
openswmm.engine.Subcatchments class. Legacy SWMM 5 users
access subcatchments through the enum-driven getValue /
setValue API on openswmm.legacy.engine.Solver — see
Legacy SWMM 5 Solver.
Sub-areas of urban land that produce runoff in response to rainfall.
The Subcatchments class is the entry point for reading and
writing subcatchment geometry, infiltration parameters, landuse
coverage, and per-step hydrology state.
Reference: openswmm_subcatchments.h.
Class signature#
class Subcatchments:
def __init__(self, solver: Solver) -> None: ...
A single Subcatchments instance covers every subcatchment in
the model. Address by string id or integer index.
Key methods#
Identity#
Method |
Returns |
|---|---|
|
Number of subcatchments. |
|
Integer index for a string id. |
|
String id for an integer index. |
|
Append a new subcatchment. |
Geometry & connectivity#
Method |
Action / returns |
|---|---|
|
Total subcatchment area. |
|
Characteristic flow width. |
|
Average surface slope. |
|
Impervious-area fraction (0–100%). |
|
Receiving node index. |
|
Receiving subcatchment (chained routing). |
|
Rain gage index that drives this subcatchment. |
Surface roughness & depression storage#
Method |
Action / returns |
|---|---|
|
Manning’s n over impervious area. |
|
Manning’s n over pervious area. |
|
Depression storage on impervious area. |
|
Depression storage on pervious area. |
Infiltration#
The infiltration model is selected globally in [OPTIONS] INFILTRATION.
Setters write the parameters appropriate for the active model.
Method |
Action / returns |
|---|---|
|
Active |
|
Max + min infiltration rate, decay constant, regen. |
|
Suction head, conductivity, initial deficit. |
|
SCS Curve Number. |
Per-step hydrology state#
Method |
Returns |
|---|---|
|
Current rainfall intensity over the subcatchment. |
|
Current runoff flow leaving the subcatchment. |
|
Groundwater contribution to the receiving node. |
|
Surface evaporation flux. |
|
Infiltration flux. |
|
Snowpack water-equivalent depth. |
Cumulative statistics#
Method |
Returns |
|---|---|
|
Total precipitation depth so far. |
|
Total runoff volume so far. |
|
Peak runoff seen so far. |
For a richer cumulative-statistics surface (peak rates, durations, quality components) see Statistics.
Forcing#
Method |
Action |
|---|---|
|
Override rainfall for this subcatchment this step (one-shot). |
For sticky cross-step rainfall overrides, use
Forcing.subcatch_rainfall() (see Advanced forcing).
Landuse coverage & water quality#
Method |
Action / returns |
|---|---|
|
Fraction of subcatchment covered by landuse |
|
Pollutant |
|
Pollutant |
End-to-end example#
from openswmm.engine import Solver, Subcatchments
with Solver("site_drainage.inp", "site_drainage.rpt", "site_drainage.out") as s:
sc = Subcatchments(s)
print(f"{sc.count()} subcatchments")
# describe each subcatchment
for i in range(sc.count()):
print(
f" {sc.get_id(i):<12} "
f"area={sc.get_area(i):7.3f} "
f"imperv={sc.get_imperv_pct(i):4.1f}% "
f"outlet={sc.get_outlet(i)}"
)
# accumulate runoff per subcatchment
total = [0.0] * sc.count()
dt = s.get_routing_step()
while s.step():
for i in range(sc.count()):
total[i] += sc.get_runoff(i) * dt
for i, vol in enumerate(total):
print(f" {sc.get_id(i):<12} runoff vol = {vol:.3f}")
Common recipes#
Override rainfall on one subcatchment for the run#
One-shot per step:
s1 = sc.get_index("S1")
while s.step():
sc.set_rainfall(s1, 0.5) # in/hr or mm/hr per RAINFALL units
Sticky:
from openswmm.engine import Forcing, ForcingMode
forcing = Forcing(s)
forcing.subcatch_rainfall("S1", 0.5, ForcingMode.REPLACE, persist=True)
while s.step():
pass
forcing.clear_all()
Switch infiltration model parameters at runtime#
# Change Horton parameters before initialize()
s.open()
sc.set_infil_horton(
sc.get_index("S1"),
f0=3.0, # initial rate
fmin=0.05, # final rate
decay=4.0, # /hr
regen=7.0, # /day
)
s.initialize()
Sweep multiple coverage fractions for sensitivity analysis#
# Snippet only — wrap in a loop over scenarios.
sc.set_coverage("S1", lu_idx=0, fraction=0.4) # 40% landuse 0
sc.set_coverage("S1", lu_idx=1, fraction=0.6) # 60% landuse 1
# remaining must sum to ≤ 1.0; the engine fills the residual with default
Per-subcatchment runoff coefficient (post-run summary)#
for i in range(sc.count()):
precip = sc.get_stat_precip(i)
runoff = sc.get_stat_runoff_vol(i) / max(sc.get_area(i), 1e-12)
rc = (runoff / precip) if precip > 0 else 0.0
print(f" {sc.get_id(i):<12} precip={precip:.3f} runoff={runoff:.3f} RC={rc:.3f}")
Bulk arrays#
The Subcatchments class does not (yet) expose bulk-array
accessors. Vectorise across the population manually:
import numpy as np
runoff = np.zeros(sc.count())
while s.step():
for i in range(sc.count()):
runoff[i] += sc.get_runoff(i)
If you need a strictly faster path, fall back to the
OutputReader after the run and use the bulk subcatchment
methods (Output reader (binary .out file)) — that’s typically fastest for
post-processing.
EngineState requirements & exceptions#
Method group |
Required state |
Notes |
|---|---|---|
identity / count |
|
Identity is fixed at parse time. |
geometry / infiltration setters |
|
Modify before |
hydrology accessors ( |
|
Need at least one runoff step. |
cumulative statistics |
|
Accumulated since simulation start. |
|
|
One-shot. |
quality accessors |
|
Require at least one pollutant in the model. |
Common EngineError codes:
INVALID_INDEX— index out of range.NOT_FOUND— string id not in the model.INVALID_TYPE— landuse / infiltration mismatch.
See also#
Rain gages — rainfall sources that drive subcatchment runoff.
Advanced forcing — sticky overrides on rainfall and evaporation.
Pollutants — the pollutants you can query via
get_quality().Statistics — richer accumulated subcatchment metrics.
Output reader (binary .out file) — post-run subcatchment time series.