Offline flow tracing#
FlowTracer estimates upstream or downstream flow paths and travel times
from completed hydraulic output or supplied averages. It owns its topology,
works independently of a live solver, and closes through a with block.
All dimensional inputs and results use SI units, even when the source output
uses US units.
Analytical example#
from openswmm.engine import (
FlowTracer, TraceNode, TraceLink, TraceNodeAverage, TraceLinkAverage,
TraceDirection, TraceTerminal, NodeType,
)
nodes = [TraceNode("S"), TraceNode("O", NodeType.OUTFALL)]
links = [TraceLink("SO", from_node=0, to_node=1, length_m=30)]
with FlowTracer(nodes, links) as trace:
trace.set_averages(
[TraceNodeAverage(lateral_in_m3s=1), TraceNodeAverage()],
[TraceLinkAverage(net_flow_m3s=1, absolute_flow_m3s=1,
absolute_velocity_mps=1)],
)
downstream = trace.estimate("S")
assert downstream.nodes[1].time_s == 30
assert downstream.summary.terminal[TraceTerminal.OUTFALL] == 1
upstream = trace.estimate("O", TraceDirection.UPSTREAM)
Results are immutable snapshots in topology order and remain valid after the
handle closes. trace.node_ids, trace.link_ids, and trace.topology
describe that order. trace.averages returns node/link snapshots that can be
restored with set_averages(..., info=trace.info). Native numerical defaults
are available through FlowTracer.default_options() and can be adjusted
with dataclasses.replace before passing them as options=.
Completed output and caching#
For a real model, supply every node and link with matching IDs, node/link
types, physical link lengths, endpoints, and appropriate TraceNodeFlags.
The reader matches output records by ID, regardless of their row order.
with FlowTracer(nodes, links) as trace:
trace.prepare("completed.out")
result = trace.estimate("S")
An optional HDF5 cache requires a verified content fingerprint. For example,
compute SHA-256 from the completed output bytes and pass its hexadecimal
digest as fingerprint= alongside cache_path="completed.trace.h5".
Recompute the digest whenever the output changes; a path or timestamp is not
a content fingerprint. Caching reports TraceStatus.NO_HDF5 when the
engine was built without HDF5; uncached tracing remains available.
Interpreting results and errors#
TraceResult contains nodes, links, and summary. Passage ratios
may exceed one where flow recirculates. Times are estimates under frozen
average flows, not particle arrival times. Unknown times remain NaN;
time_coverage and TraceFlags distinguish partial timing, reversal,
unreachable elements, and trapped circulation. Index
summary.terminal with TraceTerminal for terminal accounting.
terminal_kind is None for results without a terminal classification.
prepare and estimate accept progress(fraction, stage). Returning
true cancels and raises TraceError with code == TraceStatus.CANCELLED.
A callback exception is re-raised after the native operation stops. Long
native operations release the GIL, but each handle permits only one operation
at a time: concurrent or callback access to that handle raises RuntimeError.
Use separate handles for independent analyses. Native tracing failures raise
TraceError with a TraceStatus code; closed handles raise RuntimeError.