Swmm climate
Skill Zhonghao1995/agentic-swmm-workflow/skills/swmm-climate
Agentic SWMM is an automated, auditable, and memory-informed framework for reproducible stormwater modelling, integrating QGIS and EPA SWMM through the aiswmm runtime, reusable Skills, and MCP interfaces, with QA verification, provenance tracking, calibration support, and Codex, Hermes, Claude code as well as OpenClaw compatibility
npx -y skills add Zhonghao1995/agentic-swmm-workflow --skill swmm-climateAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Deterministic rainfall/climate formatting for SWMM. Use when converting timestamped rainfall CSV files into SWMM-ready [TIMESERIES] lines and [RAINGAGES] helper snippets for swmm-builder.
SKILL.md
6.9 KB, as published. Nobody here has run it
SWMM Climate (MVP rainfall layer)
Part of Agentic SWMM — install the project first for the executable toolchain (aiswmm CLI, SWMM solver, MCP servers).
What this skill provides
- Deterministic conversion from simple rainfall CSV to:
- SWMM
[TIMESERIES]text lines - structured JSON manifest for audit/provenance
- SWMM
- Deterministic helper generation for SWMM
[RAINGAGES]section. - MCP wrapper for agentic use.
Input CSV contract
format_rainfall.py expects a header row and at minimum:
timestamp: date-time string, default format%Y-%m-%d %H:%Mrainfall_mm_per_hr: rainfall intensity in mm/hr
Optional extensions:
station_id(or another column via--station-column) to carry multiple stations in one file.- Batch mode by repeating
--inputand/or using--input-glob. - Event window slicing via
--window-startand--window-end(inclusive).
Accepted rainfall units (--value-units):
mm_per_hr(aliases:mm/hr,mm/h)in_per_hr(aliases:in/hr,in/h)
Unit policy (--unit-policy):
strict: onlymm_per_hraccepted.convert_to_mm_per_hr: supported units are converted tomm_per_hr.
SWMM .dat input contract
For SWMM-native rainfall .dat files (e.g. <series> YYYY M D HH MM value),
use --input-dat <path> and declare row units via --dat-value-units:
mm_per_hr,in_per_hr(intensities)mm_per_day,in_per_day(24h volumes; divided by 24 to mm/hr)
In .dat mode the --window-start / --window-end filters expect %Y-%m-%d.
Use --default-station-id to override the series token taken from the .dat row.
--input-dat may be repeated to batch multiple .dat files but cannot be mixed
with --input / --input-glob.
Via the MCP tool, pass inputDatPaths: [<path>] and datValueUnits: "mm_per_day" (or another supported unit) instead of inputCsvPath.
Temporal validation:
- duplicate timestamps are rejected per station/series.
- timestamp monotonicity is checked per station (
--timestamp-policy strictdefault; optionalsort).
Scripts
scripts/format_rainfall.py- Reads rainfall CSV and writes:
timeseriestext block for SWMM- machine-readable JSON summary
- Reads rainfall CSV and writes:
scripts/build_raingage_section.py- Builds SWMM
[RAINGAGES]snippet referencing a timeseries name. - For rainfall JSON with multiple stations, use
--station-idto choose one station’s series.
- Builds SWMM
Outputs
- Timeseries text file (SWMM-ready body for
[TIMESERIES]) - JSON summary with:
- source path + SHA256
- timestamp range
- row count
- timeseries name
- Raingage snippet text file + JSON summary.
MCP
MCP wrapper location:
mcp/swmm-climate/server.js
Exposed tools:
format_rainfallbuild_raingage_section
Example commands
python3 skills/swmm-climate/scripts/format_rainfall.py \
--input skills/swmm-climate/examples/rainfall_event.csv \
--out-json runs/swmm-climate/example_rainfall.json \
--out-timeseries runs/swmm-climate/example_timeseries.txt \
--series-name TS_EVENT
python3 skills/swmm-climate/scripts/format_rainfall.py \
--input skills/swmm-climate/examples/rainfall_multi_station.csv \
--station-column station_id \
--series-name-template 'TS_EVENT_{station_safe}' \
--out-json runs/swmm-climate/example_multi_station.json \
--out-timeseries runs/swmm-climate/example_multi_station.txt
python3 skills/swmm-climate/scripts/format_rainfall.py \
--input skills/swmm-climate/examples/rainfall_batch_rg1.csv \
--input skills/swmm-climate/examples/rainfall_batch_rg2.csv \
--window-start '2025-06-01 00:05' \
--window-end '2025-06-01 00:15' \
--series-name TS_BATCH \
--out-json runs/swmm-climate/example_batch_windowed.json \
--out-timeseries runs/swmm-climate/example_batch_windowed.txt
python3 skills/swmm-climate/scripts/build_raingage_section.py \
--gage-id RG1 \
--rainfall-json runs/swmm-climate/example_multi_station.json \
--station-id RG1 \
--interval-min 5 \
--out-text runs/swmm-climate/example_raingage.txt \
--out-json runs/swmm-climate/example_raingage.json
Design storms
Use design_storm.py to synthesise a hyetograph from a return period and IDF coefficients
when no measured rainfall data exists. The output format matches format_rainfall.py so
build_inp --rainfall-json consumes it unchanged.
Methods
| Method | When to use | Required inputs |
|---|---|---|
chicago (Keifer-Chu) | IDF formula coefficients available | --form, coefficient flags, --return-period, --duration |
alternating_block | Explicit IDF table (duration → intensity) | --idf-csv or --idf-json, --duration |
IDF formula forms (chicago method)
CN form (--form CN): q = 167·A1·(1+C·lgP)/(t+b)^n [L/s/ha → converted to mm/hr]
Flags: --a1, --C, --b, --n
Generic form (--form generic): i = a/(t+b)^c [mm/hr]
Flags: --a-coeff, --b, --c-exp
Example — 2-year Chicago hyetograph (CN form, 120 min, 5-min timestep)
python3 skills/swmm-climate/scripts/design_storm.py \
--method chicago \
--form CN \
--a1 10.0 \
--C 0.811 \
--b 11.0 \
--n 0.711 \
--return-period 2 \
--duration 120 \
--dt 5 \
--out-json runs/swmm-climate/storm_p2y.json \
--out-timeseries runs/swmm-climate/storm_p2y.txt
Executed output:
{
"ok": true,
"out_json": "/tmp/design_storm_test/storm_p2y.json",
"out_timeseries": "/tmp/design_storm_test/storm_p2y.txt",
"series_name": "TS_DESIGN_P2Y_120MIN",
"series_names": [
"TS_DESIGN_P2Y_120MIN"
],
"rows": 24,
"stations": 1,
"interval_minutes": 5
}
Example — alternating-block from an IDF table (inline JSON)
python3 skills/swmm-climate/scripts/design_storm.py \
--method alternating_block \
--idf-json '[{"duration_min":5,"intensity_mm_per_hr":60},{"duration_min":10,"intensity_mm_per_hr":45},{"duration_min":30,"intensity_mm_per_hr":28},{"duration_min":60,"intensity_mm_per_hr":18},{"duration_min":120,"intensity_mm_per_hr":11}]' \
--duration 120 \
--dt 5 \
--return-period 2 \
--out-json runs/swmm-climate/storm_ab_p2y.json \
--out-timeseries runs/swmm-climate/storm_ab_p2y.txt
MCP tool
generate_design_storm on the swmm-climate MCP server (third tool after format_rainfall
and build_raingage_section). Pass camelCase equivalents: method, duration, outJson,
outTimeseries, form, returnPeriod, dt, r, a1, cCoeff, b, n, aCoeff,
cExp, idfCsv, idfJson, seriesName.
Known limitations
- MVP focuses on rainfall intensity and raingage section helper only.
- No temperature/evaporation/wind climatology conversion in this pass.
swmm-builderpath in this repo still assembles a single raingage reference per build step.