Swmm Climate

Other

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.

Install

openclaw skills install swmm-climate

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
  • 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:%M
  • rainfall_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 --input and/or using --input-glob.
  • Event window slicing via --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.

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 strict default; optional sort).

Scripts

  • scripts/format_rainfall.py
    • Reads rainfall CSV and writes:
      • timeseries text block for SWMM
      • machine-readable JSON summary
  • scripts/build_raingage_section.py
    • Builds SWMM [RAINGAGES] snippet referencing a timeseries name.
    • For rainfall JSON with multiple stations, use --station-id to choose one station’s series.

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_rainfall
  • build_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

MethodWhen to useRequired inputs
chicago (Keifer-Chu)IDF formula coefficients available--form, coefficient flags, --return-period, --duration
alternating_blockExplicit 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.

MVP limitations

  • MVP focuses on rainfall intensity and raingage section helper only.
  • No temperature/evaporation/wind climatology conversion in this pass.
  • swmm-builder path in this repo still assembles a single raingage reference per build step.