Support SWMM by reading topology from the companion .inp file
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 48/100
Research direction
Start with src/modelskill/model/adapters/_inp.py and _res1d.py, especially _simplify_colnames, then inspect the extension constructor tables and the committed tests/testdata/swmm.out and swmm.inp fixtures. Resolve how pollutant columns are named and which SWMM link sections are supported before implementing the required .inp topology path. Done means SWMM loading no longer raises for duplicate quality columns, topology and lengths come from the fixture, and the relevant extension-accounting tests pass.
Written by the indexing model from the issue text.
Description
SWMM results are refused today because the reach connectivity is missing from the .out file. It is not a mikeio1d gap — the data is not in the file, and it is in the companion .inp input file, which sits next to every SWMM result. Everything below was verified against the committed tests/testdata/swmm.out and the swmm.inp in DHI/mikeio1d's testdata.
The topology is in the .inp, and it pairs exactly
swmm.inp is in the same upstream directory our four existing fixtures came from (MIT, commit d937466, recorded in tests/testdata/README.md), so it can be vendored the same way.
swmm.out |
swmm.inp |
match | |
|---|---|---|---|
| reaches / links | 13 | 13 [CONDUITS] |
exact |
| nodes | 14 | 13 [JUNCTIONS] + 1 [OUTFALLS] (18) |
exact |
[CONDUITS] gives Name From Node To Node Length, so it supplies both connectivity and real reach lengths:
[CONDUITS]
;;Name From Node To Node Length Roughness ...
;;-------------- ---------------- ---------------- ---------- ----------
1 9 10 400 0.01
4 19 20 200 0.01
...
There is no fallback if the .inp is absent. In the .out alone, every reach reports StartNodeIndex == -1, node xcoord/ycoord are nan, geometry is NodePoint(x=nan, y=nan), chainages is a single -1e-30 sentinel, length is 0, and structures is empty. So no geometric reconstruction is possible — the .inp is required, not optional.
Node and reach timeseries load fine, so only the topology is missing.
Blocker: _simplify_colnames raises on every SWMM node
This has to be fixed before any of the above matters. mikeio1d reports each pollutant as SWMM_NODE_QUAL with no pollutant identity attached, so a node with two pollutants yields two identically named columns:
>>> Res1D("swmm.out").nodes["9"].to_dataframe().columns
[..., 'SWMM_NODE_QUAL:9', 'SWMM_NODE_QUAL:9']
_simplify_colnames in src/modelskill/model/adapters/_res1d.py requires exactly one column per quantity, so it raises:
ValueError: There must be exactly one column per quantity, found [('SWMM_NODE_QUAL:9', 'SWMM_NODE_QUAL'), ('SWMM_NODE_QUAL:9', 'SWMM_NODE_QUAL')]
The same happens for SWMM_LINK_QUAL on reaches.
The only source of the pollutant names is the .inp [POLLUTANTS] section, which from_swmm would already be reading. In the fixture it lists TSS then Lead, and Lead declares a co-pollutant fraction of 0.2 against TSS. The two columns hold 15.720075 and 3.144015 — exactly 0.2×, which confirms column order follows [POLLUTANTS] order in this file.
What is not established is whether that ordering is guaranteed across SWMM versions and models. That decides the naming:
SWMM_NODE_QUAL_TSS/SWMM_NODE_QUAL_Lead— useful, but confidently wrong if the order ever differsSWMM_NODE_QUAL_1/_2— always correct, tells the user nothing
Worth checking the SWMM binary output format spec before choosing.
Sketch
Network.from_swmm(out, inp, *, nodes=None, reaches=None), withinprequired.- Extend
src/modelskill/model/adapters/_inp.py(added for EPANET in #687) with a[CONDUITS]reader. The section reader already handles[SECTION]headers,;-prefixed comments and whitespace-delimited rows. - The reach adapter needs connectivity from the parsed rows rather than from
reach.start_node.Res1DReachalready accepts the start/endRes1DNodeobjects and only usesreach.start_nodeto validate them, and it gained alengthoverride in #687 — so this is a narrower change than it looks. - Other SWMM link types (
[PUMPS],[ORIFICES],[WEIRS],[OUTLETS]) all putName From-Node To-Nodein their first three columns and carry no length. The fixture has none of them, so supporting them would be unverified; decide whether to read them or refuse a model that uses them. .outmoves out of_UNSUPPORTED_EXTENSIONSinto its own extension set, and_EXTENSION_CONSTRUCTORSgains thefrom_swmmmapping.test_every_mikeio1d_extension_is_accounted_forkeeps the tables honest.
Related limits
- SWMM link quantities (
SWMM_LINK_FLOW,DEPTH,VELOCITY,CAPACITY, …) sit on single-gridpoint reaches, which produce no breakpoints, so they are unreachable for the same reason EPANET's are — #680. Node quantities are unaffected, so a SWMM network would be usable viaNodeObservationfrom day one. [COORDINATES]gives node x/y, butNetworkNodecarries no coordinates today, so that is out of scope.- MOUSE and Water Hammer remain refused for lack of any fixture — #686.
Supersedes #688, which claimed this was blocked on a fixture that turned out to exist.
- Dominant language
- Python
- Stars
- 56
- Forks
- 9
- Avg merge
- 57m
- Merged PRs (30d)
- 3
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from DHI/modelskill
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
DHI/modelskill#628 ·
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
DHI/modelskill#706 · 2 comments ·
-
Difficulty 5/5 Over a week Newbie friendliness 20/100
DHI/modelskill#700 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
DHI/modelskill#697 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 55/100
DHI/modelskill#686 · 1 comment ·
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100