Install
openclaw skills install swmm-climateDeterministic rainfall/climate formatting for SWMM. Use when converting timestamped rainfall CSV files into SWMM-ready [TIMESERIES] lines and [RAINGAGES] helper snippets for swmm-builder.
openclaw skills install swmm-climatePart of Agentic SWMM — install the project first for the executable toolchain (aiswmm CLI, SWMM solver, MCP servers).
[TIMESERIES] text lines[RAINGAGES] section.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/hrOptional extensions:
station_id (or another column via --station-column) to carry multiple stations in one file.--input and/or using --input-glob.--window-start and --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: only mm_per_hr accepted.convert_to_mm_per_hr: supported units are converted to mm_per_hr..dat input contractFor 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:
--timestamp-policy strict default; optional sort).scripts/format_rainfall.py
timeseries text block for SWMMscripts/build_raingage_section.py
[RAINGAGES] snippet referencing a timeseries name.--station-id to choose one station’s series.[TIMESERIES])MCP wrapper location:
mcp/swmm-climate/server.jsExposed tools:
format_rainfallbuild_raingage_sectionpython3 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
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.
| 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 |
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
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
}
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
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.
swmm-builder path in this repo still assembles a single raingage reference per build step.