Python bindings for the OpenSWMM stormwater modelling engine.
Project description
OpenSWMM Engine
Open Storm Water Management Model — Next-Generation Computational Engine
Overview
OpenSWMM Engine is a community-driven, open-source continuation of the EPA Storm Water Management Model (SWMM). SWMM is a dynamic hydrology–hydraulic–water quality simulation model used for single-event or long-term (continuous) simulation of runoff quantity and quality from primarily urban areas.
This project preserves and advances the rich legacy of SWMM by developing high-quality, QA/QC'd code while building an active community for sustainable maintenance and improvement. The community is actively working with organizations including ASCE's Environmental and Water Resources Institute (EWRI) and Water Environment Federation (WEF) to ensure the long-term sustainability of the SWMM codebase.
What's New in v6.0.0
OpenSWMM Engine v6.0.0 is a major modernization of the SWMM computational engine. Key improvements include:
Architecture & Performance
- Data-Oriented Design — Core data structures refactored to Structure of Arrays (SoA) layout for cache efficiency and SIMD-friendly computation.
- Reentrant Engine — Global state eliminated; all simulation state encapsulated in an opaque
SWMM_Enginehandle, enabling multiple independent simulations in the same process. - Plugin-Based I/O — Output and report writing abstracted through a plugin interface. Plugins receive read-only simulation snapshots on a dedicated I/O thread.
- C++20 Codebase — New engine written in modern C++20; legacy EPA SWMM 5.x solver preserved unmodified in
src/legacy/.
New C API
A comprehensive, domain-split C API replaces the monolithic legacy interface:
| Header | Domain |
|---|---|
openswmm_engine.h |
Engine lifecycle, error codes, state machine |
openswmm_model.h |
Model building, validation, serialization, options |
openswmm_nodes.h |
Junctions, outfalls, storage, dividers |
openswmm_links.h |
Conduits, pumps, orifices, weirs, outlets |
openswmm_subcatchments.h |
Subcatchments, infiltration, coverage |
openswmm_gages.h |
Rain gages (timeseries and file sources) |
openswmm_pollutants.h |
Pollutant definitions and runtime injection |
openswmm_tables.h |
Time series, curves, and patterns |
openswmm_inflows.h |
External inflows, DWF, RDII |
openswmm_controls.h |
Control rules and direct link actions |
openswmm_infrastructure.h |
Transects, streets, inlets, LID controls |
openswmm_spatial.h |
CRS, coordinates, polylines, polygons |
openswmm_quality.h |
Landuse, buildup, washoff, treatment |
openswmm_massbalance.h |
Continuity errors and cumulative flux totals |
openswmm_callbacks.h |
Progress, warning, and step callbacks |
openswmm_hotstart.h |
Hot start file save/load/modify |
openswmm_statistics.h |
Node, link, and subcatchment statistics |
openswmm_geopackage.h |
GeoPackage I/O — observed data, result queries (optional) |
Additional Features
- Hot Start API — Save, load, modify, and query hot start files through a transparent C ABI.
- CRS Support — Coordinate reference system specification via OPTIONS for spatial data.
- User Flags — Custom USER_FLAGS section for user-defined metadata on objects.
- GeoPackage I/O — Optional SQLite-based spatial persistence for model definitions, simulation results, observed data, and network topology (see GeoPackage below).
- Input Plugin Interface —
IInputPluginallows alternative file formats (GeoPackage, HDF5, databases) to replace the.inptext format. Plugins implementread()andwrite()and are discovered viaIPluginComponentInfo. - Plugin SDK — Header-only development kit for building input/output/report plugins. Plugins advertise capabilities via
has_input(),has_output(),has_report()booleans and support optional registration. - HEC-22 Inlet Analysis — Street inlet capture, grate and curb inlets (from SWMM 5.2).
- Variable Speed Pumps — Type5 pump curves with speed scaling.
- New Storage Shapes — Conical and pyramidal shapes with elliptical/rectangular bases.
Process Formulation Enhancements
The following physics-based and numerical improvements are available or being designed for backward-compatible integration. Each addresses a known simplification or performance limitation in the current SWMM formulation.
Implemented
-
Semi-Implicit Node Continuity — The legacy SWMM dynamic wave solver uses a two-branch explicit scheme for node depth updates, switching abruptly between free-surface and surcharged formulations. This can cause oscillations at the surcharge transition boundary. The new
SEMI_IMPLICITformulation unifies both regimes into a single equation that implicitly accounts for the pressure-flow coupling via thesumdqdhterm in the denominator. This eliminates the discontinuous branch and improves convergence stability, particularly for rapidly filling/draining systems. Enabled viaNODE_CONTINUITY SEMI_IMPLICITin the[OPTIONS]section (default). -
Anderson Acceleration for Picard Iteration — The standard Picard fixed-point iteration used in dynamic wave routing converges slowly for stiff surcharge transitions, often requiring 8-12 iterations. Anderson acceleration (depth-2 mixing) uses the residual history from the previous two iterates to compute an optimal linear combination, typically reducing iteration counts by 25-50%. Each saved iteration avoids the full hot path (geometry, momentum, scatter, node update), so the speedup compounds with other performance optimizations. Physical safeguards ensure non-negative depths; nodes that violate bounds fall back to standard Picard automatically. Enabled via
ANDERSON_ACCEL YESin the[OPTIONS]section (default: NO).
In Development
-
Spatially Explicit Overland Flow & Groundwater — SWMM currently has one-way feedback between hydrology and hydraulics: flooded nodes pond over a user-specified area and are reintroduced locally. In reality, surcharge flows traverse the terrain and may re-enter the network at a downstream node. The new module couples a 2D overland flow grid with the 1D pipe network, enabling spatially explicit green infrastructure placement, terrain-routed surcharge, and lateral groundwater flow exchanges, etc.
-
Dynamic Preissmann Slot — Standard SWMM uses a fixed-width slot for pressurized conduit transitions, which can cause numerical instability at the open-channel/pressure interface. A dynamic slot formulation smooths the transition with a geometry-dependent slot width, improving stability for rapidly filling/draining conduits.
-
Spatially Explicit Inlets — Current inlets are attributes of conduits, limiting bypass routing and preventing backflow or series-inlet configurations. The redesign promotes inlets to mode-switching junction nodes that actively capture street flow when the gutter spread exceeds a threshold and revert to passive junctions otherwise.
-
LID as Storage Nodes — Current LID units lack hydraulic feedback: no backpressure from the drainage network, no bidirectional flow, and no control-structure integration. The redesign maps LID layers (surface, media, gravel) onto an extended storage node using a reduced-physics kinematic Richards ODE — a simplified 1D formulation that captures gravity-driven percolation and capillary redistribution between discrete layers without the computational cost of a full 3D variably-saturated solver. This provides physically meaningful moisture dynamics while remaining compatible with SWMM's routing timestep, and enables elevation-mapped underdrain links with full network coupling.
-
Physics-Based Initial Abstraction Recovery — SWMM's seasonal RTK calibration for RDII confounds infrastructure leakage fraction with soil moisture state, requiring 12 monthly parameter sets. The new formulation tracks initial abstraction capacity as an exponential decay/recovery process. During dry periods, available capacity recovers with additive time-based and temperature-dependent rate components:
$$IA_{avail}(t+\Delta t) = IA_{max} - \bigl(IA_{max} - IA_{avail}(t)\bigr) \cdot e^{-k_{rec}(T),\Delta t}, \qquad k_{rec}(T) = k_0 + k_T \cdot e^{,\theta,(T - T_{ref})}$$
The base rate $k_0$ captures gravity drainage and capillary redistribution that occur regardless of temperature, while $k_T \cdot e^{\theta(T-T_{ref})}$ captures thermally-driven evapotranspiration. During storms, capacity is depleted: $IA_{avail}(t+\Delta t) = IA_{avail}(t) \cdot e^{-k_{dep},\Delta P}$. Recovery is suppressed when $T < T_{freeze}$, producing emergent seasonal variation (high winter RDII, low summer RDII) from a single RTK set per sewershed — no monthly parameter tables required.
Input File Extensions
The new engine extends the standard SWMM .inp format with several new sections while remaining fully backward-compatible with existing input files. Below is a complete .inp snippet demonstrating all new features:
;; EXTENSION OPTIONS — new and custom keys in [OPTIONS]
;; Standard SWMM options work as before. Any unrecognized key is stored
;; in an extension map accessible at runtime via the C/Python API.
[OPTIONS]
FLOW_UNITS CFS
INFILTRATION HORTON
FLOW_ROUTING DYNWAVE
START_DATE 01/01/2024
START_TIME 00:00:00
END_DATE 01/02/2024
END_TIME 00:00:00
ROUTING_STEP 00:00:30
REPORT_STEP 00:05:00
;; New built-in options (v6.0.0)
CRS EPSG:4326
NODE_CONTINUITY SEMI_IMPLICIT
ANDERSON_ACCEL YES
;; Extension options — stored automatically, readable by plugins
MY_STABILITY_FACTOR 1.05
PLUGIN_LOG_LEVEL DEBUG
;; USER FLAGS — typed custom metadata on any model object
;; Define a schema of flag names with type and default value.
;; Supported types: BOOLEAN, INTEGER, REAL, STRING.
[USER_FLAGS]
;;Name Type Default Description
INSPECTED BOOLEAN NO 'Has the asset been field-inspected?'
PRIORITY INTEGER 0 'Maintenance priority (0=none, 1=low, 5=critical)'
ROUGHNESS_ADJ REAL 1.0 'Roughness calibration multiplier'
ASSET_ID STRING "" 'External asset management system ID'
;; Assign flag values to individual objects.
;; ObjectType can be NODE, LINK, SUBCATCHMENT, or GAGE.
[USER_FLAG_VALUES]
;;ObjectType ObjectName FlagName Value
NODE J1 INSPECTED YES
NODE J1 PRIORITY 3
NODE J2 ASSET_ID "AM-00412"
LINK C1 ROUGHNESS_ADJ 1.12
LINK C1 INSPECTED YES
LINK C2 PRIORITY 1
SUBCATCHMENT S1 INSPECTED NO
SUBCATCHMENT S1 ASSET_ID "AM-00501"
;; PLUGINS — load output/report plugins at runtime
;; Each line: <shared-library-path> [arg1 arg2 ...]
;; The first token is the path to a .so / .dylib / .dll.
;; Remaining tokens are passed to the plugin's initialize() method.
[PLUGINS]
;; Write time-series results to HDF5 instead of (or alongside) the .out file
./plugins/hdf5_output.so file="results.h5" compress=9
;; Write a custom CSV summary report after simulation
./plugins/csv_report.dylib file="summary.csv" delimiter=","
;; Multiple plugins can be loaded — they run concurrently on the I/O thread
./plugins/netcdf_output.so file="results.nc" variables="depth,flow"
How Each Feature Works
Extension Options — Any keyword the parser does not recognize in [OPTIONS] is stored in options.ext_options and can be read at runtime:
# Python
val = solver.get_option("MY_STABILITY_FACTOR") # "1.05"
/* C API */
char buf[256];
swmm_options_get(engine, "MY_STABILITY_FACTOR", buf, sizeof(buf));
User Flags — Flags attach structured metadata to objects for asset management, calibration tracking, or custom workflows. Plugins can read them during validate() or prepare() from the SimulationContext.
Plugins — Shared libraries loaded from the [PLUGINS] section implement one or both of:
| Interface | Purpose | Thread |
|---|---|---|
IOutputPlugin |
Write time-series results at each reporting step | I/O thread |
IReportPlugin |
Write summary statistics after simulation ends | Main thread |
Each plugin library exports a single entry point:
extern "C" openswmm::IPluginComponentInfo* openswmm_plugin_info(void);
The engine calls the plugin through a managed lifecycle:
initialize(args) → validate(ctx) → prepare(ctx) → update(snapshot)... → finalize(ctx)
└─ write_summary(ctx) [report plugins]
Output plugins receive a SimulationSnapshot — a read-only deep copy of simulation state safe to consume on the I/O thread while the main simulation advances.
Custom Sections — Plugins and embedders can also register handlers for entirely new .inp sections via the C++ SectionRegistry API:
engine.registry().register_custom("MY_CUSTOM_DATA",
[](SimulationContext& ctx, const std::vector<std::string>& lines) {
for (const auto& line : lines) {
// parse and store in ctx or plugin-managed storage
}
});
This allows the .inp to contain:
[MY_CUSTOM_DATA]
;;ID Param1 Param2
OBJ_1 42.0 enabled
OBJ_2 17.5 disabled
The two built-in plugins (DefaultOutputPlugin for .out and DefaultReportPlugin for .rpt) are always available and require no [PLUGINS] entry. The Plugin SDK headers are in include/openswmm/plugin_sdk/.
GeoPackage I/O
The optional openswmm_geopackage library provides OGC GeoPackage (SQLite + spatial extensions) as an alternative to the text .inp and binary .out formats. A single .gpkg file serves as a complete project container:
- Model input — Nodes (POINT), links (LINESTRING), subcatchments (MULTIPOLYGON), rain gages, options, curves, timeseries, patterns, pollutants, and transects stored as GeoPackage feature and attribute tables with full CRS support.
- Network topology — Explicit
node_linksandsubcatch_routingtables enable SQL-based graph traversal (upstream traces, contributing area, connectivity validation) via recursive CTEs. - Multi-run results — Multiple simulation runs coexist in one file, each keyed by
simulation_idwith engine version recorded. Per-timestep results and summary statistics are stored in a relational timeseries model inspired by the Observations Data Model (ODM). - Observed / sensor data — Independent measured timeseries for calibration workflows. Series can be linked to model objects for sim-vs-observed comparison and goodness-of-fit queries.
The library is built when OPENSWMM_WITH_GEOPACKAGE=ON and requires SQLite3:
cmake -B build -DOPENSWMM_WITH_GEOPACKAGE=ON -DOPENSWMM_BUILD_TESTS=ON
cmake --build build
Plugin Architecture
GeoPackage I/O is implemented as three plugins behind a single IPluginComponentInfo:
| Plugin | Interface | Role |
|---|---|---|
GeoPackageInputPlugin |
IInputPlugin |
Read/write model definitions (.gpkg replaces .inp) |
GeoPackageOutputPlugin |
IOutputPlugin |
Write per-timestep results during simulation |
GeoPackageReportPlugin |
IReportPlugin |
Write summary statistics and continuity errors |
The plugin is discoverable via the standard openswmm_plugin_info() C export and advertises all three capabilities (has_input(), has_output(), has_report() all return true). Registration is supported via register_plugin() / registered() on the IPluginComponentInfo interface.
C API for External Consumers
The openswmm_geopackage.h C API provides read access to models, results, and topology, plus read-write access to observed data with bulk vector operations and transaction support:
#include <openswmm/engine/openswmm_geopackage.h>
SWMM_Gpkg gpkg = swmm_gpkg_open("model.gpkg");
// Read model metadata
int nodes = swmm_gpkg_node_count(gpkg, "run_1");
// Bulk-read simulation results
double times[1000], values[1000];
int n = swmm_gpkg_read_result_ts(gpkg, "run_1", "NODE", "J1",
"depth", times, values, 1000);
// Read summary statistics
double max_depth;
swmm_gpkg_read_summary(gpkg, "run_1", "NODE", "J1", "max_depth", &max_depth);
// Import observed data (bulk write in a transaction for speed)
swmm_gpkg_begin(gpkg);
int sid = swmm_gpkg_create_observed_series(gpkg, "USGS_flow",
"flow", "LINK", "C1", "USGS NWIS", "CMS");
const char* ts[] = {"2026-01-15T08:00:00Z", "2026-01-15T09:00:00Z"};
double vals[] = {1.5, 2.3};
swmm_gpkg_write_observed_values(gpkg, sid, ts, vals, NULL, 2);
swmm_gpkg_commit(gpkg);
// Read observed data back
double read_vals[100];
int count = swmm_gpkg_read_observed_values(gpkg, sid, NULL, 0,
read_vals, 100);
swmm_gpkg_close(gpkg);
Testing & Quality
- Google Test — All unit tests migrated from Boost.Test to Google Test 1.15.2.
- Comprehensive Test Suite — Legacy engine (73+ tests), legacy output (41 tests), and new engine unit tests.
- Multi-Platform CI — GitHub Actions pipelines for Windows, Linux, and macOS (Intel + ARM64).
- Doxygen API Docs — All 19 public C API headers fully documented with Doxygen conventions.
Project Structure
openswmm.engine/
├── include/openswmm/
│ ├── engine/ # New engine public C API headers (19 headers)
│ └── legacy/ # Legacy SWMM 5.x public headers
├── src/
│ ├── engine/ # New C++20 engine implementation
│ │ └── input/geopackage/ # Optional GeoPackage I/O library
│ ├── legacy/engine/ # Original EPA SWMM 5.x solver (preserved unmodified)
│ ├── legacy/output/ # Original binary output reader
│ ├── plugin_sdk/ # Header-only plugin development kit
│ └── cli/ # Command-line interface
├── tests/
│ ├── unit/legacy/ # Legacy solver and output tests (Google Test)
│ ├── unit/engine/ # New engine unit tests
│ ├── regression/ # Regression tests (new vs. legacy)
│ └── benchmarks/ # Performance benchmarks (Google Benchmark)
├── python/ # Python bindings (Cython + scikit-build)
├── docs/ # Doxygen config and technical manuals
├── cmake/ # CMake helper modules
└── .github/workflows/ # CI/CD pipelines
Prerequisites
| Requirement | Version |
|---|---|
| CMake | 3.21 or higher |
| C compiler | C17 support (GCC 10+, Clang 12+, MSVC 19.29+) |
| C++ compiler | C++20 support (GCC 10+, Clang 14+, MSVC 19.29+) |
| vcpkg | 2025.02.14 (for test dependencies) |
| Python | 3.9–3.13 (optional, for bindings) |
| Ninja | Recommended for Linux/macOS builds |
Build Instructions
C/C++ Engine
# Clone the repository
git clone https://github.com/HydroCouple/openswmm.engine.git
cd openswmm.engine
# Bootstrap vcpkg (for test dependencies)
git clone https://github.com/microsoft/vcpkg.git
./vcpkg/bootstrap-vcpkg.sh # or bootstrap-vcpkg.bat on Windows
# Configure and build using a platform preset
# Available presets: Windows, Windows-debug, Linux, Linux-debug, Darwin, Darwin-debug
export VCPKG_ROOT=$(pwd)/vcpkg
cmake --preset=<platform> -B build
cmake --build build --config Release
# Build with tests enabled
cmake --preset=<platform>-debug -B build-debug -DOPENSWMM_BUILD_TESTS=ON
cmake --build build-debug --config Debug
# Build with optional GeoPackage I/O support
cmake --preset=<platform> -B build -DOPENSWMM_WITH_GEOPACKAGE=ON
cmake --build build --config Release
Running Tests
# Run all C++ unit tests
ctest --test-dir build-debug -C Debug --output-on-failure
# Run with verbose output
ctest --test-dir build-debug -C Debug --output-on-failure -V
Packaging
# Create distributable archives (ZIP + TGZ)
cmake --build build --target package
Python Bindings
The Python bindings use scikit-build-core (≥ 0.10) as the build backend, with Cython extensions compiled via CMake.
Prerequisites
pip install "scikit-build-core>=0.10" "cython>=3.0.12" "numpy>=1.21.0"
Install (release)
cd python
pip install . --no-build-isolation
Editable / development install
cd python
pip install -e . --no-build-isolation
The editable install uses scikit-build-core's redirect mode: .py sources are served directly from the source tree while compiled .so/.pyd files are kept in sync via CMake on import.
Debug build
cd python
DEBUG=1 pip install -e . --no-build-isolation
Build a wheel locally
cd python
python -m build --wheel --no-isolation
# Wheel appears in dist/
Cross-platform wheels (CI)
cd python
cibuildwheel
# Wheels for all supported platforms land in wheelhouse/
Environment variables
| Variable | Purpose |
|---|---|
VCPKG_ROOT |
Path to a vcpkg checkout. When set, the vcpkg toolchain file is loaded automatically. |
OPENSWMM_ENGINE_INSTALL_PREFIX |
Path to a pre-built OpenSWMM engine install. Skips building the engine from source (used in CI to avoid redundant rebuilds). |
DEBUG |
Set to 1 to switch CMAKE_BUILD_TYPE to Debug. |
CMAKE_ARGS |
Extra -DFOO=BAR flags forwarded to every CMake configure. |
SKBUILD_CMAKE_ARGS |
scikit-build-core's own CMake flag override channel. |
Example — vcpkg + pre-built engine:
export VCPKG_ROOT=/path/to/vcpkg
export OPENSWMM_ENGINE_INSTALL_PREFIX=/path/to/engine/install
pip install . --no-build-isolation
Example — extra CMake flags:
export CMAKE_ARGS="-DOPENSWMM_BUILD_2D=ON"
pip install . --no-build-isolation
Run Python tests
cd python
python -m pytest -v tests
Python Usage
The openswmm package provides Cython bindings for the full C API.
Domain objects are constructed by passing an active Solver instance.
Running a Simulation
from openswmm.engine import Solver, Nodes, Links, Subcatchments, Gages
# Context manager handles open/initialize/start and end/report/close/destroy
with Solver("model.inp", "model.rpt", "model.out") as s:
nodes = Nodes(s)
links = Links(s)
subcatchments = Subcatchments(s)
gages = Gages(s)
while s.step():
# Per-element access by name or integer index
depth = nodes.get_depth("J1")
flow = links.get_flow("C1")
runoff = subcatchments.get_runoff("S1")
# NumPy bulk access (single memcpy — fast)
all_depths = nodes.get_depths_bulk() # shape (n_nodes,)
all_flows = links.get_flows_bulk() # shape (n_links,)
# Runtime forcing
nodes.set_lateral_inflow("J2", 0.5)
gages.set_rainfall(0, 25.4)
Advanced Forcing with Persistence
from openswmm.engine import Solver, Nodes, Forcing, ForcingMode, ForcingTarget
with Solver("model.inp", "model.rpt", "model.out") as s:
nodes = Nodes(s)
forcing = Forcing(s)
j1 = nodes.get_index("J1")
# Apply a persistent lateral inflow (held every step until cleared)
forcing.node_lat_inflow(j1, 1.5, ForcingMode.REPLACE, persist=True)
# Additive forcing (added to model-computed value)
forcing.gage_rainfall(0, 10.0, ForcingMode.ADD, persist=True)
while s.step():
pass
# Clear specific object or all forcing
forcing.clear(ForcingTarget.NODE, j1)
forcing.clear_all()
Programmatic Model Building (No .inp File)
from openswmm.engine import (
ModelBuilder, Nodes, Links,
NodeType, LinkType, XSectShape,
)
m = ModelBuilder()
# Add objects
m.add_node("J1", NodeType.JUNCTION)
m.add_node("J2", NodeType.JUNCTION)
m.add_node("OUT1", NodeType.OUTFALL)
m.add_link("C1", LinkType.CONDUIT)
m.add_link("C2", LinkType.CONDUIT)
# Set geometry
m.set_node_invert(0, 10.0)
m.set_node_invert(1, 8.0)
m.set_node_invert(2, 5.0)
m.set_link_nodes(0, 0, 1) # C1: J1 -> J2
m.set_link_nodes(1, 1, 2) # C2: J2 -> OUT1
m.set_link_length(0, 400.0)
m.set_link_length(1, 400.0)
m.set_link_roughness(0, 0.013)
m.set_link_roughness(1, 0.013)
m.set_link_xsect(0, XSectShape.CIRCULAR, 1.0)
m.set_link_xsect(1, XSectShape.CIRCULAR, 1.0)
# Set simulation options
m.set_option("FLOW_UNITS", "CFS")
m.set_option("ROUTING_MODEL", "DYNWAVE")
m.set_option("START_DATE", "01/01/2024")
m.set_option("END_DATE", "01/02/2024")
# Validate, finalize, and simulate
m.validate()
m.finalize()
solver = m.to_solver()
solver.start()
while solver.step():
pass
solver.end()
# Optionally write to .inp for inspection
m.write("generated_model.inp")
solver.destroy()
Reading Binary Output Files
from openswmm.engine import OutputReader, OutNodeVar, OutLinkVar
with OutputReader("model.out") as out:
# Query metadata
print(f"Nodes: {out.get_node_count()}")
print(f"Links: {out.get_link_count()}")
print(f"Periods: {out.get_period_count()}")
print(f"Report step: {out.get_report_step()} sec")
# List object IDs
for i in range(out.get_node_count()):
print(f" Node {i}: {out.get_node_id(i)}")
# Read all node depths at each reporting period
for t in range(out.get_period_count()):
depths = out.get_node_result(t, OutNodeVar.DEPTH) # float32 array
flows = out.get_link_result(t, OutLinkVar.FLOW) # float32 array
print(f" Period {t}: max depth = {depths.max():.3f}")
# Time series for a single node
node_depths = out.get_node_series(
node_idx=0,
var=OutNodeVar.DEPTH,
start_period=0,
end_period=out.get_period_count() - 1,
)
Hot Start Save and Restore
from openswmm.engine import Solver, HotStart
# Run part of a simulation and save state
with Solver("model.inp", "model.rpt", "model.out") as s:
for _ in range(100):
if not s.step():
break
HotStart.save(s, "checkpoint.hsf")
# Later: restore from hot start
hs = HotStart.open("checkpoint.hsf")
# Optionally modify state before applying
hs.set_node_depth("J1", 2.5)
with Solver("model.inp", "model.rpt", "model2.out") as s2:
hs.apply(s2)
while s2.step():
pass
hs.close()
Mass Balance and Statistics
from openswmm.engine import Solver, MassBalance, Statistics, RunoffTotal
with Solver("model.inp", "model.rpt", "model.out") as s:
while s.step():
pass
mb = MassBalance(s)
stats = Statistics(s)
# Continuity errors
print(f"Runoff error: {mb.get_runoff_continuity_error():.4f}%")
print(f"Routing error: {mb.get_routing_continuity_error():.4f}%")
# Cumulative totals
precip = mb.get_runoff_total(RunoffTotal.RAINFALL)
runoff = mb.get_runoff_total(RunoffTotal.RUNOFF)
print(f"Total precip: {precip:.2f}, Total runoff: {runoff:.2f}")
# Per-object statistics
print(f"Node 0 max depth: {stats.node_max_depth(0):.3f}")
print(f"Link 0 max flow: {stats.link_max_flow(0):.3f}")
For the full API reference, see the documentation.
Libraries Built
| Target | Description |
|---|---|
openswmm_legacy_engine |
Original EPA SWMM 5.x solver (shared library) |
openswmm_legacy_output |
Original SWMM binary output reader (shared library) |
openswmm_engine |
New refactored C++20 engine (shared library) |
openswmm_geopackage |
GeoPackage I/O (static library, optional — requires SQLite3) |
openswmm_plugin_sdk |
Header-only plugin SDK (INTERFACE library) |
openswmm_cli |
Command-line executable |
Documentation
API documentation is auto-generated with Doxygen and deployed to GitHub Pages:
OpenSWMM Engine API Documentation
The documentation includes:
- Full C API reference with parameter descriptions and usage notes
- Technical reference manuals (Hydrology, Hydraulics, Water Quality)
- User manual with modeling capabilities and examples
- Architecture design decisions and implementation plan
Contributing
Contributions are welcome. Please:
- Fork the repository and create a feature branch.
- Ensure all tests pass (
ctestfor C++,pytestfor Python). - Follow existing code style and naming conventions.
- Submit a pull request against the
developbranch.
License
This project is licensed under the MIT License — see LICENSE for details.
Copyright 2026 HydroCouple. Original EPA SWMM material is in the public domain under 17 USC § 105.
Acknowledgements
OpenSWMM builds on the foundational work of the EPA Storm Water Management Model, originally developed by Lewis A. Rossman at the U.S. EPA Office of Research and Development. See docs/authors.md for the complete list of authors and contributors.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openswmm-6.0.0.dev0.tar.gz.
File metadata
- Download URL: openswmm-6.0.0.dev0.tar.gz
- Upload date:
- Size: 6.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4843623bf7e08d5036130a0e8cbb7eea14778b46b84d032ddacfe2b7a9786c17
|
|
| MD5 |
d9a90fdc0363fdfd83ce2346561e3de9
|
|
| BLAKE2b-256 |
64ebe8b44b69f3d6039129a3d478d5ef23c5def5a66913cc19f954b577806fba
|
File details
Details for the file openswmm-6.0.0.dev0-cp313-cp313-macosx_26_0_arm64.whl.
File metadata
- Download URL: openswmm-6.0.0.dev0-cp313-cp313-macosx_26_0_arm64.whl
- Upload date:
- Size: 3.8 MB
- Tags: CPython 3.13, macOS 26.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0acc51f8338e20cf98e7df40fe2a59dc788deb7c2e4668f955ff354224c341d
|
|
| MD5 |
aa427874bb759c56645ce013a1ed4778
|
|
| BLAKE2b-256 |
168186163c1cd63ef40083bbe43141861ded2ad202640380c92f14cf4ee734e2
|
File details
Details for the file openswmm-6.0.0.dev0-cp313-cp313-macosx_15_0_x86_64.whl.
File metadata
- Download URL: openswmm-6.0.0.dev0-cp313-cp313-macosx_15_0_x86_64.whl
- Upload date:
- Size: 4.5 MB
- Tags: CPython 3.13, macOS 15.0+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e238222f44da0443b1efc6f60bb32504056db279095855c5625a18b81313b3a4
|
|
| MD5 |
efd6c11bb62731462a6bf2639763f817
|
|
| BLAKE2b-256 |
c2abd8a61e19597c988ded10023e3c67ef6736dda77cf22eaea3041e65a21a6e
|
File details
Details for the file openswmm-6.0.0.dev0-cp313-cp313-macosx_15_0_arm64.whl.
File metadata
- Download URL: openswmm-6.0.0.dev0-cp313-cp313-macosx_15_0_arm64.whl
- Upload date:
- Size: 4.0 MB
- Tags: CPython 3.13, macOS 15.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9716e3b0926b27cee5593159fe31825058d9917f63b492e5baa724de03575f5d
|
|
| MD5 |
8a9983a0349a925eb22a9a56b585c1fd
|
|
| BLAKE2b-256 |
bda587f06131954dad8d8b99714e6fbd5195de67c3e06d5e7181bcfacca92bd8
|