Checking for missing content type metadata ...
This resource contains content types with missing metadata required to make it public or discoverable. Show missing content type metadata.
Click on the edit button ( ) below to edit this resource.
Checking for non-preferred file/folder path names (may take a long time depending on the number of files/folders) ...
This resource contains some files/folders that have non-preferred characters in their name. Show non-conforming files/folders.
This resource contains content types with files that need to be updated to match with metadata changes. Show content type files that need updating.
A bidirectional SWMM–MODFLOW 6 coupling for groundwater, stormwater, and sanitary-sewer exchange under sea-level rise
| Authors: |
|
|
|---|---|---|
| Owners: |
|
This resource does not have an owner who is an active HydroShare user. Contact CUAHSI (help@cuahsi.org) for information on this resource. |
| Type: | Resource | |
| Storage: | The size of this resource is 30.7 MB | |
| Created: | Jul 31, 2026 at 1:52 p.m. (UTC) | |
| Last updated: | Jul 31, 2026 at 2:59 p.m. (UTC) | |
| Citation: | See how to cite this resource |
| Sharing Status: | Public |
|---|---|
| Views: | 105 |
| Downloads: | 14 |
| +1 Votes: | Be the first one to this. |
| Comments: | No comments (yet) |
Abstract
A bidirectional coupling of EPA SWMM and MODFLOW 6 that exchanges fluxes at a daily stress period through the MODFLOW API: subcatchment infiltration becomes groundwater recharge, groundwater drainage is injected into SWMM junctions, and head-based leakage into sanitary sewers is applied through the MODFLOW WEL package.
Subject Keywords
Coverage
Spatial
Temporal
| Start Date: | |
|---|---|
| End Date: |
Content
README.md
MODFLOW-SWMM Coupling
Bidirectional coupling of SWMM (stormwater/sewer) and MODFLOW 6 (groundwater) for daily-timestep coastal-flood and sea-level-rise modeling. Originally developed for Bowers Beach, Delaware.
Three exchanges happen every stress period (1 day):
- SWMM → MODFLOW: subcatchment infiltration becomes MODFLOW recharge (spatially proportioned to grid cells, lagged one day).
- MODFLOW → SWMM: groundwater drainage from coupled cells injected into SWMM junctions.
- MODFLOW ↔ sanitary nodes: head-based leakage into pipes via the MODFLOW
WEL package. Sanitary nodes are identified from the SWMM
[DWF]section.
Installation
The coupling requires patched builds of PySWMM and the SWMM toolkit.
Vanilla pyswmm from PyPI does not expose the groundwater hooks and will fail
at the MODFLOW→SWMM exchange. requirements.txt is a reference list only — do
not install from it.
bash
bash env/setup.sh
conda activate pyflo
This creates the pyflo conda env from env/environment.yml, then clones and
builds three forks pinned by commit
(solver,
toolkit,
pyswmm). It ends by running
env/verify_install.py, which asserts the groundwater setter round-trips, so a
silent half-install cannot slip through.
MODFLOW 6 binaries for all three platforms ship in exe/ and are auto-detected;
pass --dll-path to override.
| Platform | Status |
|---|---|
| macOS (Intel / Apple Silicon) | Verified end-to-end |
| Linux | Expected to work, not yet tested |
| Windows | Untested — needs WSL2, or Git Bash + MS C++ Build Tools |
| ARM Linux (incl. ARM WSL2) | Not supported — no MODFLOW 6 linux-arm64 build |
Windows notes
`setup.sh` is a bash script and will not run in `cmd.exe` or PowerShell. **WSL2 (recommended).** `wsl --install`, then install [Miniforge](https://github.com/conda-forge/miniforge), clone into the Linux filesystem (`~/`, not `/mnt/c/...`), and run the two commands above. **Git Bash + MSVC (native).** Install [Git for Windows](https://git-scm.com/download/win), [MS C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) ("Desktop development with C++" — `swmm-toolkit` compiles the SWMM C engine), and Miniforge. Enable conda in Git Bash once with `"$(conda info --base)/Scripts/conda.exe" init bash`, then run the two commands above. The script detects Windows, skips the Unix-only compiler setup, and converts paths with `cygpath` for `pip`. **Untested** — please open an issue with the output if it fails.Running a simulation
One scenario per invocation. Run from the repository root — default input paths are relative to it.
bash
python main.py run-simulation --scenario baseline
For the SLR scenario (CHD 1.2 m instead of 0.0 m), edit the head value in
modflow_ws/Bowers_beach.chd first, then run with --scenario slr. The
scenario tag is appended to every output filename, so runs never collide.
--scenario output filename suffix (default: baseline)
--model-name MODFLOW model name (default: Bowers_beach)
--log-level DEBUG | INFO | WARNING | ERROR (default: INFO)
--dll-path path to libmf6.{dylib,so,dll} (auto-detected)
--no-validate-first skip the pre-run setup validation
Input-path flags (--modflow-workspace, --swmm-input,
--subcatchments-shapefile, --nodes-shapefile, --well-csv) default to the
Bowers Beach files. python main.py validate-setup checks inputs without
simulating; --help lists everything.
A run always writes logs/simulation_<scenario>.log. Redirecting the console as
well captures MODFLOW's own output and the node-mapping summary, which Python
does not log:
bash
mkdir -p logs
python main.py run-simulation --scenario baseline > logs/console_baseline.log 2>&1 &
Outputs
results/
├── sanitary_nodes.csv # node-to-cell mapping
└── simulation/
├── gw_head_differences_<scenario>.csv
├── gw_head_differences_<scenario>.png
├── subcatchment_gwt_elev_ft_<scenario>.csv
├── subcatchment_max_infil_depth_<scenario>.csv
├── subcatchment_max_infil_depth_<scenario>.png
├── subcatchment_water_table_<scenario>.png
├── mean_water_table_<scenario>.tif
└── mean_groundwater_depth_map_<scenario>.png
run-simulation writes the CSVs, the .tif and mean_groundwater_depth_map.
The other three PNGs come from a separate, manual step:
bash
python plots/time_series_plots.py --scenario baseline
These do not refresh when you re-run a simulation. Re-run this command after any run whose figures you intend to use, or they will silently show the previous run's results.
MODFLOW also writes modflow_ws/*.lst, *.hds, *.cbc; SWMM writes
swmm_inp/Bowers_beach.rpt and .out. None of results/ is tracked by git.
Adapting to a new study area
The coupling logic is generic; the inputs are not.
- Replace the MODFLOW model in
modflow_ws/and the SWMM.inpinswmm_inp/. Set--model-nameif it isn'tBowers_beach. - Replace the two shapefiles the coupling reads. Columns are indexed by
name, so a missing one raises a bare
KeyError:
| Shapefile | Geometry | Required columns |
|---|---|---|
delineation_shpfile.shp |
subcatchment polygons | id (= SWMM subcatchment name), Area (acres) |
swmm_junc_out.shp |
junction/outfall points | NAME (= SWMM node name), X, Y |
Shapefiles and the MODFLOW grid must share one projected CRS in the same
units as delr/delc. Nodes are placed by raw coordinate arithmetic
(col = (x - xmin)/delr) with no reprojection; a mismatch appears as a flood
of "nodes outside MODFLOW grid bounds" warnings in the console log rather
than an error. Both are PCSWMM exports of the same model as the .inp, so
re-export them together.
3. Sanitary nodes are detected automatically from the [DWF] section of the
.inp — no code change needed. The classifier seeds from those and
propagates through the pipe network. Run python main.py validate-setup once
to generate results/sanitary_nodes.csv and print a coupling report.
4. Scenarios: edit the CHD value in modflow_ws/Bowers_beach.chd and pass
any tag via --scenario.
Tests
bash
pytest tests/ -q
21 tests covering drainage routing (separate vs. combined sewers, mass conservation), node-inflow accumulation and reset semantics, and head-based sanitary leakage. They need no MODFLOW solve and no SWMM run, and finish in about a second.
Project layout
main.py CLI entry point
env/ setup.sh, environment.yml, verify_install.py
src/ coupled_simulation.py, validation.py, postprocess.py,
core/ (coupling components), utils/ (loaders, geolocation,
proportioning, classifier)
plots/ plotting source only — figures go to results/simulation/
tests/ pytest suite
modflow_ws/ MODFLOW 6 workspace swmm_inp/ SWMM .inp + outputs
shp_files/ subcatchment + node shapefiles
exe/ MODFLOW 6 binaries tutorial/ Bowers_beach_tutorial.ipynb
results/ generated outputs, not tracked
Troubleshooting
No CMAKE_C_COMPILER could be found — you ran conda env create directly
instead of bash env/setup.sh. This cannot be fixed from environment.yml.
gw_set_state missing / setGroundwaterState fails — vanilla pyswmm is
shadowing the fork:
bash
conda activate pyflo
pip uninstall -y pyswmm swmm-toolkit
bash env/setup.sh --skip-env
Build picks the wrong Python or CMake — another conda env or Homebrew is
ahead on PATH. If building by hand, export PATH="$CONDA_PREFIX/bin:$PATH"
after activating.
Citation
If you use this software, please cite it using the metadata from the CITATION.cff file.
Alternatively, use the "Cite this repository" button in the GitHub sidebar to export the citation in APA or BibTeX format.
License
Released under the MIT License — free to use, modify, and redistribute, including commercially, provided the copyright notice and licence text are retained.
The MODFLOW 6 binaries in exe/ are USGS software in the public domain and are
redistributed unchanged. The patched SWMM forks are built from source at install
time and are not covered by this licence; they carry the licences of their
upstream projects (see Reference).
Reference
SWMM's underlying source is US EPA public domain; Austin's forks and our coupling build on that base.The swmm_getGWaterState / swmm_setGWaterState API that makes this coupling
possible is Austin Farnum's work. Our
forks descend directly from his repositories with his commits and authorship
intact; our additions fix compilation and complete the Python binding. Every
change is visible as a diff against his code:
solver,
toolkit,
pyswmm.
Credits
Funding Agencies
This resource was created using funding from the following sources:
| Agency Name | Award Title | Award Number |
|---|---|---|
| National Science Foundation (NSF) | CUAHSI Hydroinformatics Innovation Fellowship | EAR-1849458 |
How to Cite
MIT License. Copyright (c) 2026 Omowumi Erukubami and Austin Farnum. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files, to deal in the software without restriction, provided the above copyright notice and this permission notice are included in all copies. The full licence text is in the LICENSE file included with this resource.
https://opensource.org/license/mit
Comments
There are currently no comments
New Comment