Links#
Note
Engine: OpenSWMM 6 — refactored. This page documents the
openswmm.engine.Links collection and the
openswmm.engine._links.Link wrapper. Legacy SWMM 5 users
access links through the enum-driven getValue / setValue API
on openswmm.legacy.engine.Solver — see
Legacy SWMM 5 Solver.
Conduits, pumps, orifices, weirs, and outlets — every connection between two nodes. The shape mirrors Nodes:
from openswmm.engine import Solver
with Solver("model.inp") as s:
s.links # → Links collection
s.links["C1"] # → Link wrapper
s.links[0] # → Link wrapper (by index)
Reference: openswmm_links.h.
Quickstart#
# Indexing.
c1 = s.links["C1"]
# Iteration.
for link in s.links:
print(link.id, link.type.name, link.length)
# Per-object property access.
print(c1.flow, c1.depth, c1.velocity)
c1.control_setting = 0.5
c1.closed = True
# Topology — yields Node wrappers, not bare indices.
print(c1.from_node.id, "->", c1.to_node.id)
# Bulk numpy access.
flows = s.links.flows # np.ndarray
s.links.flows = flows * 0.95
# Cross-section.
c1.xsect = (XSectShape.CIRCULAR, 1.0, 0.0, 0.0, 0.0)
print(c1.xsect.shape, c1.xsect.g1)
# Type-specific sub-views — raise AttributeError on wrong type.
s.links["P1"].pump.curve = 0
s.links["W1"].weir.type = WeirType.TRANSVERSE
s.links["OR1"].orifice.type = OrificeType.BOTTOM
s.links["OUT1"].outlet.rating_type = OutletRatingType.FUNCTIONAL_HEAD
# Stats.
print(s.links["C1"].stats.max_flow, s.links["C1"].stats.max_velocity)
Collection: Links#
Operation |
What it does |
|---|---|
|
Current link count. |
|
Returns a |
|
Yields a fresh |
|
String → int. Raises |
|
Int → string. Raises |
|
Append a link. Returns the |
|
Remove the most recently added link. |
|
Rename in place. Invalidates wrappers. |
Bulk numpy properties#
Property |
Mode |
What it carries |
|---|---|---|
|
read/write |
Per-link flow rate. |
|
read-only |
Water depth. |
|
read-only |
|
|
read-only |
Flow / full-flow ratio. |
|
read-only |
|
|
read-only |
|
|
read-only |
|
|
read-only |
Hydraulic power (for pumps). |
|
read-only |
String ids as |
For per-pollutant concentrations:
s.links.qualities("TSS") # str id or int index
For pump statistics in bulk:
cycles, on_time, volume = s.links.pump_stats()
Wrapper: Link#
Property |
Type |
Mode |
Meaning |
|---|---|---|---|
|
|
read-only |
|
|
|
read-only |
|
|
|
read-only |
CONDUIT / PUMP / ORIFICE / WEIR / OUTLET. |
|
|
read-only |
Upstream node wrapper. |
|
|
read-only |
Downstream node wrapper. |
|
|
read/write |
Conduit length (other types use slot for type-specific data). |
|
|
read/write |
|
|
|
read-only |
Computed from invert elevations. |
|
|
read/write |
|
|
|
read/write |
|
|
|
read/write |
Assign |
|
|
read/write |
|
|
|
read-only |
|
|
|
read-only |
|
|
|
read/write |
|
|
|
read/write |
|
|
|
read/write |
|
|
mixed |
read/write |
Conduit-flavoured knobs. |
Methods:
Method |
What it does |
|---|---|
|
Reconnect this link. Accepts indices, ids, or |
|
Concentration of |
Cross-section: XSection#
link.xsect returns an XSection view. Access individual
fields by attribute, the snapshot tuple via as_tuple(), or rewrite
all five fields by assigning a tuple:
x = c1.xsect
print(x.shape, x.g1, x.g2, x.g3, x.g4)
shape, g1, g2, g3, g4 = x.as_tuple()
c1.xsect = (XSectShape.CIRCULAR, 1.0, 0.0, 0.0, 0.0)
The shape is a XSectShape enum; the four g parameters are
shape-specific (diameter, width, height, depth, …).
Type-specific sub-views#
Each link type exposes a small sub-namespace; accessing the wrong one
raises AttributeError:
# PUMP only.
p = s.links["P1"]
p.pump.curve = 0 # curve index
p.pump.init_state = True # starts on
p.pump.startup_depth = 1.0
p.pump.shutoff_depth = 0.1
# WEIR only.
w = s.links["W1"]
w.weir.type = WeirType.TRANSVERSE
w.weir.crest_height = 0.5
w.weir.discharge_coeff = 3.33
w.weir.end_contractions = 2
# ORIFICE only.
o = s.links["OR1"]
o.orifice.type = OrificeType.BOTTOM
o.orifice.open_close_rate = 0.5 # 1 / second
# OUTLET only.
out = s.links["OUT1"]
out.outlet.rating_type = OutletRatingType.FUNCTIONAL_HEAD
out.outlet.expon = 0.5
Statistics sub-view#
Every link carries a .stats view; pump-specific entries raise
BadParamError (which is also a ValueError) on non-pump
links:
c1 = s.links["C1"]
print(c1.stats.max_flow)
print(c1.stats.max_velocity)
print(c1.stats.max_filling)
print(c1.stats.vol_flow)
print(c1.stats.surcharge_time)
p1 = s.links["P1"]
print(p1.stats.pump_cycles)
print(p1.stats.pump_on_time)
print(p1.stats.pump_volume)
These values are only meaningful after Solver.end().
Staleness, equality, repr#
Same contract as Node:
Adding, removing, renaming, or converting links invalidates every
Linkminted before. Access raisesStaleObjectError.a == bisTruewhenaandbwrap the same(solver, index)pair; hashing is consistent.repr(link)includes the captured id and index.
See also#
Running a simulation — Solver — where
s.linkscomes from.Nodes —
Link.from_node/Link.to_nodereturnNodewrappers.Control rules — runtime control of link
control_settingandtarget_setting.Error handling, edge cases & debugging — every exception type referenced on this page.