Migrating from PySWMM
Your PySWMM experience travels well, though changing the import is only the
first step. swmmrs borrows familiar workflows and embeds a different solver.
Ownership, lifecycle states, typed exceptions, and views tied to one project
generation need attention during migration. It is not a drop-in replacement.
Common translations
| Task | PySWMM shape | swmmrs shape |
|---|---|---|
| Open a model | Simulation("model.inp") |
Simulation("model.inp") |
| Get a node | Nodes(simulation)["J1"] |
simulation.nodes["J1"] |
| Get a link | Links(simulation)["C1"] |
simulation.links["C1"] |
| Get a subcatchment | Subcatchments(simulation)["S1"] |
simulation.subcatchments["S1"] |
| Iterate | for step in simulation |
for current_time in simulation |
| Set callback cadence | simulation.step_advance(300) |
simulation.step_advance(300) or a timedelta |
| Apply a link control | link.target_setting = value |
link.target_setting = value while RUNNING |
| Post-run binary query | Output(...) |
OutputReader("model.out") with typed family or bulk queries. |
Start with object access. The collections now belong to the simulation:
from swmmrs import Simulation
with Simulation("model.inp", "model.rpt", "model.out") as simulation:
node = simulation.nodes["J1"]
link = simulation.links["C1"]
for current_time in simulation:
if node.depth > 4.0:
link.target_setting = 1.0
simulation.end()
simulation.report()
Important differences
Collections belong to the simulation
Do not construct separate Nodes, Links, or Subcatchments adapters. Access collections through the owning Simulation. IDs are case-insensitive, and collections preserve configured order.
The loop body is the callback
Put inspection and controls directly in the iterator or caller-owned stepping
loop. There is no callback-registration system to wire up. step_advance()
controls how often that Python logic runs.
Lifecycle failures are typed
Catch ValidationError for rejected Python inputs, LifecycleError for invalid operation order, and SolverError for native solver failures. A failed project generation should be closed, not restarted.
Live views can become stale
A node, link, or collection remains valid across advances in one project generation. It raises StaleViewError after close() or after open() creates a replacement generation. Reacquire views from the current simulation.
Output reading uses typed structured results
OutputReader opens a finalized or incomplete .out file independently of Simulation.
Family methods return immutable OutputTimeSeries values; bulk reads return a
shared nominal time axis plus ordered OutputValueSeries columns. Exact names
are case-sensitive, ranges are half-open, and pollutant columns use explicit
PollutantAttribute selectors. See Read binary output.
Migration checklist
- Replace standalone collection constructors with
simulation.<collection>access. - Choose one advancement owner: iterator, manual stepping, or
execute(). - Move registered callbacks into the advancement loop.
- Check units before assigning or combining external values.
- Copy statistics before
end()and snapshots before closing when later code needs them. - Replace PySWMM
Outputcalls with typed family methods orSeriesSelectionbulk queries, and chooselow_memorydeliberately. - Give every concurrent simulation distinct report and output paths.
PySWMM remains the mature choice when an application requires its callback ecosystem or broader compatibility surface. See the PySWMM documentation for its authoritative API.