2-D surface routing#
Note
Engine: OpenSWMM 6 — refactored. This page documents the
openswmm.engine._2d.Surface2D view. It is only available when
the C/C++ engine was built with OPENSWMM_BUILD_2D=ON and the loaded
model defines a 2D mesh. Guard for it with
openswmm.engine.HAS_2D (build-time) and
Surface2D.is_active (per-model).
The 2-D surface-routing module overlays a triangular mesh on the 1-D
drainage network and advances the shallow-water surface state with a
CVODE solver, exchanging flow with 1-D nodes at coupling points. The
Surface2D view hangs off the Solver as a
lazy attribute and addresses the live mesh:
from openswmm.engine import Solver, HAS_2D
with Solver("mesh_model.inp") as s:
if HAS_2D and s.surface2d.is_active:
surf = s.surface2d # → Surface2D
surf.n_triangles # mesh size
surf.get_depth(0) # state at triangle 0
Reference: openswmm_2d.h.
Quickstart#
from openswmm.engine import Solver, HAS_2D, SurfaceForcingMode, ForcingPersist
with Solver("mesh_model.inp") as s:
if not (HAS_2D and s.surface2d.is_active):
raise RuntimeError("model has no active 2D surface")
surf = s.surface2d
# Drive the whole mesh with steady rain that survives every step.
surf.force_rainfall_uniform(
30.0, # mm/hr
mode=SurfaceForcingMode.OVERRIDE,
persist=ForcingPersist.PERSIST,
)
for _ in s.steps():
pass
depths = surf.get_depths() # numpy (n_triangles,)
mb = surf.get_mass_balance()
print("continuity error:", mb["continuity_error"])
Mesh geometry & topology#
The mesh is fixed for the run. Vertices carry (x, y, z) coordinates;
triangles carry area, Manning’s n, centroid, and adjacency. Indices are
zero-based.
Member |
What it returns |
|---|---|
|
Mesh size (properties). |
|
|
|
Scalar |
|
Set a vertex ground elevation. |
|
|
|
Triangle area. |
|
|
|
Manning’s n (the setter rejects non-positive values). |
|
|
|
|
|
|
Coupling to 1-D nodes#
Where the mesh exchanges flow with the 1-D network:
Member |
What it returns |
|---|---|
|
Number of coupling points (properties). |
|
SWMM node index coupled to a vertex ( |
|
Couple a vertex to a 1-D node by id ( |
|
Coupling discharge coefficient ( |
|
Coupling exchange area in m² ( |
|
SWMM node index coupled to a triangle ( |
Runtime state#
Per-triangle state is read either one triangle at a time or as bulk
float64 arrays of shape (n_triangles,). Bulk getters release the
GIL.
Member |
Scope |
Meaning |
|---|---|---|
|
one / bulk |
Water depth on the triangle. |
|
one / bulk |
Total head (water-surface elevation). |
|
one |
Current rainfall source. |
|
one |
Net source term (rain − evap ± coupling). |
|
one / bulk |
Exchange flux with the coupled 1-D node. |
|
bulk |
Heads reconstructed at vertices ( |
|
bulk |
Render-oriented signed water depths at all vertices
( |
|
bulk |
Normal flux on every triangle edge. |
|
bulk |
Time-invariant edge lengths and outward unit normals. |
Aggregate scalars (properties): max_depth, total_volume
(Σ depth × area), total_exchange_flow, and the last-advance solver
counters cvode_steps and cvode_last_step.
Forcing#
Inject rainfall, evaporation, or a coupling flux onto the mesh. Each forcing setter is keyword-compatible with the 1-D Advanced forcing view but uses the 2-D-specific enums:
mode (
SurfaceForcingMode) —OVERRIDE(default) replaces the computed source;ADDadds to it.persist (
ForcingPersist) —RESET(default) applies for the next step only;PERSISTkeeps the forcing active every step until cleared.
Method |
Forces … |
|---|---|
|
Rainfall on one triangle. |
|
Rainfall on every triangle. |
|
Evaporation on one triangle. |
|
Evaporation on every triangle. |
|
Coupling flux on one triangle. |
|
Remove every 2-D forcing. |
Mass balance & continuity#
get_mass_balance() returns a dict[str, float] of cumulative
volumetric terms (all m³) plus the dimensionless continuity_error:
Key |
Term |
|---|---|
|
Surface storage at the start / end. |
|
Cumulative rainfall input. |
|
Flow exchanged with the 1-D network, each direction. |
|
Flow across outfall boundaries. |
|
Flow across open mesh-edge boundaries. |
|
Cumulative evaporation loss. |
|
Global closure error as a fraction. |
The scalar Surface2D.continuity_error is the same closure error.
Cumulative per-triangle envelopes are available after the run:
Method |
Envelope (per triangle) |
|---|---|
|
Maximum depth reached. |
|
Maximum velocity magnitude. |
|
Maximum absolute continuity residual (m³/s). |
Solver tolerances#
The CVODE integrator is tuned through three read/write properties:
dry_depth— depth (m) below which a triangle is treated as dry.rel_tolerance— CVODE relative tolerance.abs_tolerance— CVODE absolute tolerance.
surf.dry_depth = 1e-4
surf.rel_tolerance = 1e-6
surf.abs_tolerance = 1e-8
Boundary conditions#
Open mesh edges carry a boundary condition selected per
(triangle, edge) pair, where edge is 0, 1, or 2. The
type is a SurfaceBoundaryType: WALL (closed), NORMAL_FLOW,
SPECIFIED_STAGE, SPECIFIED_FLOW, or RATING_CURVE.
Member |
What it does |
|---|---|
|
Number of boundary edges (property). |
|
Read / set the BC type. |
|
Boundary head (SPECIFIED_STAGE). |
|
Boundary slope (NORMAL_FLOW). |
|
Prescribed flow per metre (SPECIFIED_FLOW). |
|
Cumulative flux across the edge. |
|
Instantaneous flow across the edge. |
|
Name the timeseries driving a SPECIFIED_STAGE edge. |
|
Name the timeseries driving a SPECIFIED_FLOW edge. |
|
Name the rating curve driving a RATING_CURVE edge. |
Edge conveyance#
A per-edge conveyance factor in [0, 1] throttles flow across internal
edges (1.0 = unrestricted, 0.0 = closed):
Member |
What it does |
|---|---|
|
Read / set one edge’s factor. |
|
All factors as a numpy array. |
|
Reset every edge to 1.0. |
EngineState & exceptions#
State queries (get_depth, get_mass_balance, the *_bulk getters)
are only meaningful while the simulation is running or after it ends;
calling them before Solver.start() or when the 2-D module did not run
raises a RuntimeError. Forcing setters require an active 2-D module.
Always gate access with Surface2D.is_active, and guard the import
itself with openswmm.engine.HAS_2D so code degrades gracefully on
builds without 2-D support.
See also#
Advanced forcing — the 1-D runtime-forcing view; the 2-D setters mirror its mode/persist semantics.
Nodes — the 1-D nodes the mesh couples to.
Mass balance — 1-D mass-balance terms.
Error handling, edge cases & debugging — exception types referenced here.