OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
Chapter 12: Running Models from Python and Plugins

Everything the other chapters do from a deck and a command line can be done from Python, and several things can only be done from Python: forcing a model from a live data source, stepping it under a controller, reading a result set without writing a file. This chapter is the map from a modelling task to the interface that performs it.

Three interfaces exist, and they are layers of one engine rather than alternatives:

Interface What it is Reach for it when
The command line openswmm model.inp model.rpt model.out the deck is the whole experiment
The Python package openswmm.engine, a Cython binding over the C API the run is one step in a script: sweeps, forcing, post-processing
A plugin a shared library the engine loads and calls back the behaviour belongs inside every run, including runs someone else starts

When the command line is enough

A deck plus a report is a complete experiment, and the runner that produced every simulated figure in this manual is exactly that: scripts/build_manual_figures.py upserts a few [OPTIONS] lines into a copy of a deck, runs the binary, and reads the report and the binary output. Nothing in this manual's comparisons needs more.

Two things the command line cannot do: change a model while it is running, and see a result before the run ends.

Driving a run from Python

The package exposes the engine as a solver you open, step and close. The canonical shape is the context manager, which guarantees the close:

from openswmm.engine import Solver
with Solver("model.inp", "model.rpt", "model.out") as solver:
for elapsed in solver.steps(): # a timedelta since the start
pass
print(solver.routing_error())

steps() advances one routing step per iteration and yields the elapsed time as a timedelta, so a controller reads state, decides, writes back and continues. step() is the same thing one step at a time. The routing error is a fraction, not a percentage — a gate that asserts it is below 0.5 is asserting 50 %, not half a percent.

The guide pages carry the worked forms, and each is a short page:

Task Guide page
Install the package install
The first run, end to end quickstart
Open, step, close, and the state machine solver
Build a model with no input file model_builder
Prescribe rainfall, evaporation and temperature at runtime forcing
Read nodes, links and subcatchments while stepping nodes, links, subcatchments
Cross-section geometry without a model xsect_geometry
The 2D surface: mesh, depths, velocities 2d
Water quality, reactions, age and heat quality, reactions, water_age, heat
Process components from Python process_components
Read a binary output file after the run output_reader
Hot start files hotstart
Mass balance and statistics massbalance, statistics
Plot results plotting
Read and write GeoPackage geopackage

The full class and method reference is the Python Bindings API Reference.

A caution about the state machine. A solver is past OPENED as soon as the context manager enters; several setters are refused after that point because the engine has already resolved the model. The solver page lists which, and Chapter 5 of the Engine Manual gives the same sequence for the C API, where the states are explicit.

Three things worth doing from Python

A parameter sweep that never writes a deck. The model builder makes the network in memory, so a sweep over a design variable is a loop rather than a directory of near-identical files. The comparisons in this manual are the same idea run from the deck side: upsert the keys, run, read.

Forcing from outside the model. Prescribed rainfall, evaporation and temperature enter after the rain-snow split of Hydrology 2, §2.1.6 — override replaces the gage's value and addition augments it, and neither is scaled by the gage or subcatchment factors. That is what lets a live feed or a downscaled climate series drive an existing deck with its gages left in place.

Reading the 2D surface without the file. A coupled run's mesh state is addressable while it steps: depth, velocity and species per cell. The result file is written for later analysis, not required for it, and it is not readable while the run is in progress — there is no flush and no single-writer-multiple-reader mode.

When the behaviour belongs in a plugin

A plugin is loaded by the engine and called back during the run, so it acts on every run of a model rather than on the runs a particular script starts. The engine ships built-in plugins for input, output, reporting and state IO, and a project names extra ones in [PLUGINS] (Section: [PLUGINS]). Discovery, version resolution and the callback sequence are in Chapter 5 of the Engine Manual, §5.8.

The rule of thumb:

  • A process component adds physics — reactions, heat, water age, transport — and is configured from a file the deck names in [PROCESS_COMPONENTS] (Section: [PROCESS_COMPONENTS]). Chapter 9: multi-species reactions configures one.
  • An output or report plugin changes what a run writes without changing what it computes.
  • A solver plugin replaces a kernel. The 2D backends are selected this way; a backend that a build does not carry is refused at open rather than silently ignored.

Where to go next

Authoring and observing the extended Python API

Open a solver explicitly before authoring: the solver context manager starts simulation, so editing-only tables must be changed before entering the runtime state. solver.transport exposes dispersion configuration and authored rows; solver.transport_matrix reports which process classes are available in each domain, with reasons when unavailable.

solver.surface2d.groundwater supplies aquifer rows, node exchange, SI state arrays and water/species ledgers. Its .transport view edits groundwater parameters, sorption, initial quality, boundary quality and source terms. solver.surface2d.quality edits land-use coverage, initial buildup and curb length. Table snapshots are immutable; arrays are owned copies. Aquifer hydrology authoring uses project units while runtime hydrology uses SI. See the groundwater guide and surface-quality guide for each field's units.

ModelEditor.delete_nodes, .delete_links, .delete_subcatchments and .delete_gages validate all pre-edit indices before a batch deletion and return cascade impacts. Reacquire element views after structural edits. Views retain their solver and raise Python exceptions after it closes or is destroyed.

OutputReader(path, live=True) can read complete periods during a run; refresh() updates the period count and timestamp cache. Staged serialization uses solver.write_staged(final_path, mapper); publication and rollback remain the caller's responsibility. See the editing and live-output guide and native-call safety guide for the contracts.