A Basic Model Interface (BMI) wrapper for EPA SWMM5 (the Storm Water Management Model), built on top of pyswmm.
It exposes a running SWMM simulation through the standard BMI calls (initialize,
update, get_value, set_value, finalize, …) so that SWMM can be driven
step-by-step, coupled to other models, and run inside
eWaterCycle.
pip install swmm-bmiOr install from a clone of this repository:
pip install .Dependencies (pyswmm, bmipy, numpy, pyyaml) are installed automatically.
pyswmm bundles the SWMM5 C library via swmm-toolkit, so no separate SWMM
installation is required.
The wrapper is initialized with a small JSON config file that points to a SWMM
.inp input file. All model parameters and timing (start/end dates, routing step,
flow units) are read from the .inp file itself.
If you need to use a data file.dat, give it the same filename as the input file, but replace the suffix.
example_config.json:
{
"inp_file": "example_model.inp"
}A relative inp_file path is resolved relative to the config file's location.
Driving the model from Python:
import numpy as np
from swmm_bmi import SwmmBmi
model = SwmmBmi()
model.initialize("example_config.json")
# Step through the whole simulation
n_nodes = model.get_grid_size(1)
while model.get_current_time() < model.get_end_time():
model.update()
depth = model.get_value("node_depth", np.empty(n_nodes))
model.finalize()See demo_swmm_bmi.ipynb for a full worked example that
inspects the BMI metadata, runs the bundled example_model.inp, plots the
results, and injects external lateral inflow.
Each BMI variable is backed by one of four SWMM element types, addressed as separate BMI grids. Values are reported/accepted in SI units regardless of the model's own flow-unit system.
| Grid | Element type |
|---|---|
| 0 | subcatchments |
| 1 | nodes |
| 2 | links |
| 3 | rain gages |
Output variables (get_value):
| Variable | Grid | Units |
|---|---|---|
subcatchment_runoff |
subcatchments | m3 s-1 |
node_depth |
nodes | m |
node_flooding |
nodes | m3 s-1 |
link_flow |
links | m3 s-1 |
precipitation |
rain gages | in hr-1 / mm hr-1 |
Input variables (set_value):
| Variable | Grid | Units | Notes |
|---|---|---|---|
node_lateral_inflow |
nodes | m3 s-1 | Injected via pyswmm's Node.generated_inflow; held constant until the next set_value. |
precipitation |
rain gages | in hr-1 / mm hr-1 | Units follow the model's flow-unit system (US → in/hr, SI → mm/hr). |
precipitation appears in both tables: rain-gage rates can be read back with
get_value and overridden with set_value.
A typical eWaterCycle coupling pre-computes forcing externally and injects it each
timestep with set_value("node_lateral_inflow", values) or
set_value("precipitation", values), then calls update().
The included Dockerfile packages the model and serves its BMI over
grpc4bmi, which lets other tools (such as
eWaterCycle) talk to the model running in an isolated container.
Build the container:
docker build -t swmm-grpc4bmi:v0.0.1 .Test it from Python:
from grpc4bmi.bmi_client_docker import BmiClientDocker
model = BmiClientDocker("swmm-grpc4bmi:v0.0.1", work_dir="/tmp", delay=1)
print(model.get_component_name())
del modelInspect the container interactively:
docker run -it swmm-grpc4bmi:v0.0.1 bashTo push to the GitHub container registry (set up an access token first — see the GitHub Packages documentation):
docker build -t ghcr.io/ewatercycle/swmm-grpc4bmi:v0.0.1 .
docker push ghcr.io/ewatercycle/swmm-grpc4bmi:v0.0.1Remember to mark the package as public before others can pull it.
swmm-bmi is distributed under the terms of the
Apache-2.0 license.