Skip to content

Build a NetworkModelResult straight from a result file - #699

Draft
jpalm3r wants to merge 3 commits into
read-sqlitefrom
network-model-from-path
Draft

Build a NetworkModelResult straight from a result file#699
jpalm3r wants to merge 3 commits into
read-sqlitefrom
network-model-from-path

Conversation

@jpalm3r

@jpalm3r jpalm3r commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

NetworkModelResult was the only model result class that could not be built from a file. PointModelResult, GridModelResult, DfsuModelResult and even the network's own NodeModelResult all take a path, so a network workflow needed an extra import and an extra line for no reason.

network_model = ms.NetworkModelResult("model.res1d", item="WaterLevel")
multi_obs = ms.NodeObservation.from_multiple(data="calibration.dfs0", db="model.sqlite")
cc = ms.match(multi_obs, network_model)

A Network still works, unchanged.

The extension picks the constructor

ADR-012 keeps one Network constructor per modelling product, and rejected guessing the product from the file. This reads the extension anyway, one layer up, for the reason that objection does not reach here: the tables already map each extension to exactly one product — .res is EPANET's and nobody else's — and the answer is reported in mr.network. Unreadable formats come back with the refusal messages already written for them, so .out still explains where SWMM keeps its topology. The ADR records the exemption.

Network.from_mike / from_epanet stay the only way in when a file needs named companions or selective loading, and the guide says so.

An EPANET file collects its companions

An EPANET run writes up to three files, and the .res alone gives no reach lengths at all — so a network built from the path would silently be one on which reach matching cannot work. A path picks up the .resx and .inp sharing its folder and stem.

The companion validation already refuses a .resx from a different run. Since these were never asked for, a failure now names the file that was picked up and the explicit call that skips it.

Bug fix: companion names arrive in two encodings

Found on a real MIKE+ EPANET model. mikeio1d decodes .res text as UTF-8 but .resx text as the Windows ANSI codepage, so a node named ØST in one file is ØST in the other:

The '.resx' companion holds nodes ['TOELHØJVEJ1', 'TOELHØJVEJ2',
'Vandværk_Vest', 'ØST'] that are absent from the '.res' network, so
the two files do not describe the same model.

The four Danish tank names were enough to make one model look like two. This predates the path constructor — from_epanet(res, resx=...) fails identically — and the louder half was not the worse half: the merge looks companions up by the main file's name, so had validation passed, those tanks would have lost their Volume and Volume Percentage without a word.

A companion is now keyed by the main file's names. The repair is used only when it produces a name the .res actually has, so a companion from a genuinely different model still raises as before.

Notes for review

  • The path branch imports modelskill.network inside the branch, so modelskill.model.network stays importable without networkx and mikeio1d (ADR-010).
  • The encoding to re-read as is a guess — cp1252 then latin-1 — which is why a candidate is checked against the main file before it is used. A wrong guess falls back to the name as it came.
  • Tests cover the extension mapping, companion discovery with each subset of the three files, and the name repair. The encoding tests use fakes; no fixture with non-ASCII names is committed.

Stack created with GitHub Stacks CLIGive Feedback 💬

@jpalm3r jpalm3r changed the title network model from path Build a NetworkModelResult straight from a result file Aug 10, 2026
@jpalm3r jpalm3r closed this Aug 10, 2026
@jpalm3r
jpalm3r force-pushed the network-model-from-path branch from 74700cd to db99d3c Compare August 10, 2026 13:26
@jpalm3r jpalm3r reopened this Aug 10, 2026
@jpalm3r
jpalm3r force-pushed the network-model-from-path branch 2 times, most recently from 37bda9e to a5dec82 Compare August 10, 2026 14:02
jpalm3r and others added 3 commits August 11, 2026 10:45
Adds Network.from_path, which picks the right constructor from the file
extension and, for EPANET, finds the .resx and .inp companions sitting
beside the .res file rather than making the caller name them.

Companion locations are also re-keyed by the main file's spelling. mikeio1d
can hand back a mis-decoded name when the two files were written with
different text encodings, which left a node unmatched even though both
files described it. Names that already match, or that no re-reading
explains, are left alone, so a companion from a genuinely different model
still fails to match rather than being forced onto the wrong location.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Constructing a model result from a file meant importing Network, loading
it, then passing it in. Hand NetworkModelResult the path instead and it
loads the network itself via Network.from_path; the loaded network stays
reachable afterwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jpalm3r
jpalm3r force-pushed the network-model-from-path branch from a5dec82 to 1510e81 Compare August 11, 2026 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant