diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index cd57ed263..e854ab5b1 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -36,7 +36,7 @@ jobs: version: "1.8.27" - name: Install dependencies - run: uv sync --group dev --group docs --group networks + run: uv sync --group dev --group docs --group network - name: Build documentation run: just docs diff --git a/.github/workflows/full_test.yml b/.github/workflows/full_test.yml index 341923a71..bd2621ead 100644 --- a/.github/workflows/full_test.yml +++ b/.github/workflows/full_test.yml @@ -38,7 +38,7 @@ jobs: enable-cache: true - name: Install dependencies - run: uv sync --group test --group networks --no-dev + run: uv sync --group test --group network --no-dev - name: Install pandas 2.x if: matrix.pandas-version == 'pandas2' @@ -57,7 +57,7 @@ jobs: - name: Test run: just test - build-no-networks: + build-no-network: runs-on: ubuntu-latest steps: @@ -71,7 +71,7 @@ jobs: python-version: "3.12" enable-cache: true - - name: Install dependencies (without networks) + - name: Install dependencies (without network) run: uv sync --group test --no-dev - name: Test diff --git a/.github/workflows/notebooks_test.yml b/.github/workflows/notebooks_test.yml index ef39a8eb8..aaa4d5ba8 100644 --- a/.github/workflows/notebooks_test.yml +++ b/.github/workflows/notebooks_test.yml @@ -24,7 +24,7 @@ jobs: python-version: "3.14" enable-cache: true - name: Install dependencies - run: uv sync --group test --group notebooks --group networks --no-dev + run: uv sync --group test --group notebooks --group network --no-dev - name: Test notebooks run: | uv run pytest tests/notebooks/ diff --git a/adr/010-optional-domain-dependencies.md b/adr/010-optional-domain-dependencies.md index c67cab5b9..fc5e9dc89 100644 --- a/adr/010-optional-domain-dependencies.md +++ b/adr/010-optional-domain-dependencies.md @@ -56,7 +56,10 @@ Installation: `pip install modelskill modelskill-network` **Open Questions:** - Should `modelskill[all]` install all optional model types? -- How to handle version constraints for optional dependencies? +- How to handle version constraints for optional dependencies? Answered for network + support by [ADR-013](013-network-topology-in-mikeio1d.md): the `network` extra names a + minimum mikeio1d, because the topology layer ships there. Network support requires + whatever Python that release requires. - Should optional dependencies be tested in CI for every commit or separately? ## Status Notes diff --git a/adr/012-network-format-constructors.md b/adr/012-network-format-constructors.md index 324959247..8a863068a 100644 --- a/adr/012-network-format-constructors.md +++ b/adr/012-network-format-constructors.md @@ -1,9 +1,19 @@ # ADR-012: One Network Constructor per Modelling Product -**Status**: Draft +**Status**: Accepted, narrowed by [ADR-013](013-network-topology-in-mikeio1d.md) **Date**: 2026-08 +## Narrowed by ADR-013 + +The constructors, the companion arguments, the extension tables, the coverage test and the +`.inp` reader are mikeio1d's. It replaced `from_mike` and `from_epanet` with one +`Network.open` that reads the extension. Naming a constructor after the product that wrote +the file is still the rule, and mikeio1d applies it. + +`NetworkModelResult` hands a path to mikeio1d. The refusal messages for `.out`, `.resx` +and the formats without a fixture are written there. + ## Context `Network` is built from result files read through mikeio1d, whose single `Res1D` class opens nine extensions across five products — MIKE 1D (`.res1d`), MIKE 11 (`.res11`), MOUSE (`.prf`, `.crf`, `.xrf`), EPANET (`.res`), SWMM (`.out`), Water Hammer (`.whr`), and `.resx`, which is shared by the last three. There is no per-format reader and no per-format constructor argument, so from mikeio1d's side all nine look alike. modelskill's constructor was named `from_res1d`, and its extension guard was briefly widened to accept everything mikeio1d could read — making the name promise one format while reading nine. diff --git a/adr/013-network-topology-in-mikeio1d.md b/adr/013-network-topology-in-mikeio1d.md new file mode 100644 index 000000000..8968fe06a --- /dev/null +++ b/adr/013-network-topology-in-mikeio1d.md @@ -0,0 +1,59 @@ +# ADR-013: The Network Topology Layer Belongs to mikeio1d + +**Status**: Accepted + +**Date**: 2026-08 + +## Context + +`modelskill.network` had grown to roughly 630 lines of topology: the abstract node/reach/breakpoint types, a `Res1D` adapter, one constructor per modelling product, the `.resx` and `.inp` companions, +tables of which extensions we refuse and why, a networkx graph carrying reach lengths and boundary edges, an alias map, and `find`/`recall`/`to_dataset` on top. `NetworkModelResult` uses five members +of `Network`, two of them private, and never traverses the graph. mikeio1d's `experimental.to_networkx` converts the same files in 25 lines and ignores gridpoints. + +That leaves us on the far side of the line ADR-001 drew for mikeio, where we call `mikeio.read()` and stop, modelling no dfsu geometry and policing no format list. `Res1D` reads nine extensions across +five products. Our tables decide which of the nine we accept, and a test fails our CI when a mikeio1d release adds a tenth. The fixtures those tables are checked against are copies of mikeio1d's own: +`network.res1d`, `network_cali.res11`, `epanet.res/.resx/.inp`. + +## Decision + +mikeio1d gains an optional network module that builds and owns `Network`. modelskill requires it and consumes what it produces. + +| Owner | Pieces | +|---|---| +| mikeio1d | abstract types and `BasicNode`/`BasicReach`, the `Res1D` adapter, `Network.open`, the `.resx` and `.inp` companions, the extension policy tables, graph construction with its length and boundary semantics, the alias map, `find`, `recall`, `to_dataframe`, `to_dataset` | +| modelskill | `NetworkModelResult`, `NodeModelResult`, `NodeObservation`, `ReachObservation`, matching | + +`NetworkModelResult` takes a `Network` the upstream module built, or a path it hands to that module. The module is an extra there, carrying networkx and xarray, so `to_dataset()` ships with the class. +modelskill's `network` extra requires a mikeio1d release new enough to contain it. + +Original IDs become the only identifier a user handles: `NodeObservation.at` takes a node name or a `(reach, distance)` pair, and no longer an integer. The alias integers stay an internal index, +because the ID space mixes names and break points and a tuple cannot be an xarray coordinate value. A saved comparer records the original ID with the integer beside it as `node_index`, so reloading +does not depend on the numbering the installed mikeio1d handed out. + +The loader's output over six fixture loads was recorded before anything moved — graph edges with their lengths and boundary flags, the alias map, the dataframe, and every answer `find` and `recall` +give. Those snapshots are the upstream module's acceptance test. Phase 1 landed as mikeio1d [#247](https://github.com/DHI/mikeio1d/pull/247), merged 2026-08-19. The snapshots pass there unchanged +twice: against the code moved verbatim, and again after the two product constructors collapsed into `Network.open`. + +modelskill 1.4.0 waits for the mikeio1d release carrying the module, which is not out yet. + +## Alternatives Considered + +**Keep the layer here.** Defensible while the API is private. Costs a format matrix, an EPANET `.inp` parser and a graph contract for traversals we never perform. + +**Move only the constructors and companions**, leaving the graph and the abstract types here. Splits the format knowledge from the topology it produces, and leaves `Res1DReach` here as the single +adapter for a plug point with no second implementation. + +**A separate `modelskill-network` package.** Rejected in ADR-010 for fragmenting the install. It would still own format knowledge that belongs with mikeio1d. + +**Ask mikeio1d to guarantee stable node numbering** instead of dropping integers from our API. Puts a promise on someone else's release process, to protect a number users should not be handling. + +## Consequences + +- ADR-012 is narrowed: the constructors, the companion arguments, the extension tables and the coverage test become mikeio1d's. Naming a constructor after the product that wrote the file is still the + rule, and mikeio1d applies it. +- ADR-010's open question about version constraints for optional dependencies is answered for this feature: the `network` extra pins a minimum mikeio1d, and network support requires whatever Python + that release requires. +- A hand-built network needs mikeio1d installed, since `BasicNode`/`BasicReach` move too. That costs a .NET dependency for users who touch no MIKE file, which only matters for tests and for a backend + nobody has written. +- Dropping `at=` breaks a signature that shipped in the 1.4.0a3 alpha only, while the network module is opt-in and absent from the API reference. Removing it after 1.4.0 would cost more. +- Releases become coupled in one direction: a fix to network file reading ships on mikeio1d's schedule. A format mikeio1d adds no longer breaks our CI. diff --git a/adr/README.md b/adr/README.md index 59b6d3bf2..fe0639ba0 100644 --- a/adr/README.md +++ b/adr/README.md @@ -30,7 +30,8 @@ Each ADR follows this structure: - [ADR-009](009-factory-pattern.md) - Factory pattern for type detection - [ADR-010](010-optional-domain-dependencies.md) - Optional dependencies for domain-specific model types (Draft) - [ADR-011](011-vertical-pre-extracted-columns.md) - VerticalModelResult ingests pre-extracted columns -- [ADR-012](012-network-format-constructors.md) - One Network constructor per modelling product (Draft) +- [ADR-012](012-network-format-constructors.md) - One Network constructor per modelling product (narrowed by ADR-013) +- [ADR-013](013-network-topology-in-mikeio1d.md) - The network topology layer belongs to mikeio1d ## Contributing diff --git a/docs/images/res1d_network_mapping.png b/docs/images/res1d_network_mapping.png deleted file mode 100644 index 2930e9914..000000000 Binary files a/docs/images/res1d_network_mapping.png and /dev/null differ diff --git a/docs/user-guide/network.qmd b/docs/user-guide/network.qmd index a769d9c16..5130778ac 100644 --- a/docs/user-guide/network.qmd +++ b/docs/user-guide/network.qmd @@ -7,17 +7,18 @@ jupyter: python3 ::: {.callout-warning collapse="true"} ## Extra dependencies required -Network support depends on libraries that are **not** installed -by default, e.g. `networkx`. You can install them alongside `modelskill` using the _networks_ extra: +Network support depends on `mikeio1d`, which reads the result files and builds +the network, and which is **not** installed by default. Install it alongside +`modelskill` with the _network_ extra: ```bash -uv pip install modelskill[networks] +uv pip install modelskill[network] ``` or ```bash -uv add modelskill[networks] +uv add modelskill[network] ``` ::: @@ -25,382 +26,71 @@ uv add modelskill[networks] ```{python} # | echo: false -import pandas as pd -import numpy as np -from typing import Any -from modelskill.network import Network, NetworkNode, NetworkReach, ReachBreakPoint - - -class ExampleNode(NetworkNode): - """Node backed by an in-memory DataFrame, e.g. model output.""" - - def __init__(self, node_id: str, data: pd.DataFrame): - self._id = node_id - self._data = data - - @property - def id(self) -> str: - return self._id - - @property - def data(self) -> pd.DataFrame: - return self._data - - @property - def boundary(self) -> dict[str, Any]: - return {} - - -class ExampleReach(NetworkReach): - """Reach connecting two nodes with a given length.""" - - def __init__( - self, - reach_id: str, - start: NetworkNode, - end: NetworkNode, - length: float, - breakpoints: list | None = None, - ): - self._id = reach_id - self._start = start - self._end = end - self._length = length - self._breakpoints = breakpoints or [] - - @property - def id(self) -> str: - return self._id - - @property - def start(self) -> NetworkNode: - return self._start - - @property - def end(self) -> NetworkNode: - return self._end - - @property - def length(self) -> float: - return self._length - - @property - def breakpoints(self) -> list: - return self._breakpoints - - -class ExampleBreakPoint(ReachBreakPoint): - def __init__(self, reach_id: str, distance: float, data: pd.DataFrame): - self._id = (reach_id, distance) - self._data = data - - @property - def id(self): - return self._id - - @property - def data(self): - return self._data - - -# Synthetic model output covering the observation period -model_time = pd.date_range("1994-08-07 16:00", periods=180, freq="1min") -t = np.linspace(0, 2 * np.pi, len(model_time)) - -df1 = pd.DataFrame({"WaterLevel": 194.0 + np.sin(t)}, index=model_time) -df2 = pd.DataFrame({"WaterLevel": 193.8 + 0.8 * np.sin(t)}, index=model_time) -df3 = pd.DataFrame({"WaterLevel": 193.6 + 0.6 * np.sin(t)}, index=model_time) -df4 = pd.DataFrame({"WaterLevel": 193.9 + 0.9 * np.sin(t)}, index=model_time) - -node_s1 = ExampleNode("sensor_1", df1) -node_s2 = ExampleNode("sensor_2", df2) -node_s3 = ExampleNode("sensor_3", df3) - -bp = ExampleBreakPoint("r1", 200.0, df4) -reach1 = ExampleReach("r1", node_s1, node_s2, length=500.0, breakpoints=[bp]) -reach2 = ExampleReach("r2", node_s2, node_s3, length=300.0) -network = Network(reaches=[reach1, reach2]) -``` - -A **Network** represents a 1D pipe or river network as a directed graph: nodes hold timeseries data (e.g. water level at a junction) and reaches carry the topology and reach length between them. Break points along a reach (e.g. cross-section chainages) are supported as observation locations too. - -The typical workflow is: - -``` -Network → NetworkModelResult → match() → Comparer -``` - -## Building a Network - -You can build a `Network` object by loading it from a supported network result file. Reading these files relies on [mikeio1d](https://github.com/DHI/mikeio1d), so install the `networks` dependency group first. - -There is one constructor per product that writes the file: - -| Constructor | Extensions | Product | -|---|---|---| -| `Network.from_mike` | `.res1d`, `.res11` | MIKE 1D, MIKE 11 | -| `Network.from_epanet` | `.res`, plus optional `.resx` and `.inp` | EPANET | - -The remaining formats mikeio1d can open cannot be turned into a `Network`, and say so when you try: - -| Extension | Why not | -|---|---| -| `.out` (SWMM) | The reach connectivity is not in the `.out` at all — it lives in the companion `.inp` input file, which modelskill does not read yet ([#689](https://github.com/DHI/modelskill/issues/689)). | -| `.resx` | Not a network on its own. It holds extra results for the network defined in the sibling `.res`, so pass it as `from_epanet(res, resx=...)` instead. | -| `.prf`, `.crf`, `.xrf` (MOUSE), `.whr` (Water Hammer) | No test fixture exists for these formats, so support cannot be verified. [Open an issue](https://github.com/DHI/modelskill/issues) if you need one. | - -### From a network result file - -The quickest way to get a `Network` is from the path to a result file: - -```{python} -# | echo: false - path_to_res1d = "../../tests/testdata/network.res1d" -path_to_res11 = "../../tests/testdata/network_cali.res11" -path_to_epanet = "../../tests/testdata/epanet.res" path_to_sensor_data_1 = "../../tests/testdata/network_sensor_1.csv" path_to_sensor_data_2 = "../../tests/testdata/network_sensor_2.csv" ``` -```{python} -from modelskill.network import Network - -network = Network.from_mike(path_to_res1d) -network -``` +A **network** is a 1D pipe or river network read as a graph: nodes hold timeseries +data (water level at a junction, say), reaches carry the topology and the length +between them, and break points along a reach are locations in their own right. -or a `mikeio1d.Res1D` that has already been opened: +The workflow is the usual four steps, with the network standing in for a grid or a +mesh: -```python -from mikeio1d import Res1D - -res = Res1D(path_to_res1d) -network = Network.from_mike(res) ``` - -MIKE 11 files work the same way. Note that MIKE 11 keeps its timeseries on reach gridpoints rather than on nodes, so the nodes of such a network carry no data of their own: - -```{python} -Network.from_mike(path_to_res11) +result file → NetworkModelResult → match() → Comparer ``` -EPANET results use `from_epanet`: - -```{python} -Network.from_epanet(path_to_epanet) -``` - -#### EPANET companion files - -An EPANET run writes more than one file, and the `.res` is not the whole picture: - -| File | What it adds | -|---|---| -| `.res` | The network and its main timeseries. Required. | -| `.resx` | Extra results — tank volume and pump energy. Merged onto matching nodes. | -| `.inp` | The model input. The only one of the three carrying reach lengths. | - -Pass the companions alongside the result file to get a fuller network: +## Where the network comes from -```{python} -# | echo: false -path_to_epanet_resx = "../../tests/testdata/epanet.resx" -path_to_epanet_inp = "../../tests/testdata/epanet.inp" -``` - -```{python} -network_epanet = Network.from_epanet( - path_to_epanet, - resx=path_to_epanet_resx, - inp=path_to_epanet_inp, -) -network_epanet -``` +Reading the file and building the graph is [mikeio1d](https://github.com/DHI/mikeio1d)'s +job, not modelskill's. `Network.open` reads MIKE 1D (`.res1d`), MIKE 11 (`.res11`) +and EPANET (`.res`) results, finds the EPANET companion files, and says so when a +format cannot be turned into a network. See its documentation for the companions, +for loading only part of a large file, and for `find`/`recall` between the names the +model uses and the graph's own integers. -`Volume` and `Volume Percentage` come from the `.resx`, and the reach lengths from the `.inp`: +modelskill takes the file path directly, and opens it for you: ```{python} -sorted( - d["length"] - for *_, d in network_epanet.graph.edges(data=True) - if d["length"] is not None -) -``` - -::: {.callout-warning} -## EPANET reach geometry is limited - -EPANET is a link-node model, and mikeio1d reports no length and a single synthetic gridpoint for each reach. So for an EPANET network: - -* without `inp=`, every edge of `network.graph` has `length=None`. A length-weighted `networkx` call then fails rather than returning a meaningless number — shortest-path treats the edge as unreachable, and anything that sums the weights raises `TypeError`. The attribute is always present, since `networkx` defaults a missing weight to `1`. With `inp=`, only pumps and valves stay `None`, since `[PIPES]` is the one section carrying lengths -* reaches have no breakpoints, so a `ReachObservation` cannot be matched — use `NodeObservation` instead -* `find(reach=..., distance=)` never resolves; only `distance="start"` and `distance="end"` work - -For the same reason, `resx=` merges node quantities only. Its reach-level quantities — pump energy, efficiency and costs — have no breakpoint to live on, which is tracked in [#680](https://github.com/DHI/modelskill/issues/680). - -Node timeseries, `to_dataframe()`, `to_dataset()`, `find(node=...)` and `recall()` are unaffected. -::: - -A MIKE 1D network contains multiple levels that are unified into a generic network structure as depicted in the image below. The image introduces concepts like _find_, _recall_ and _boundary_ which are explained in the following sections. - -![How a Res1D file maps to a Network object. Reaches and nodes are re-indexed as integers; boundary nodes expose `find()`/`recall()` round-trip lookups.](../images/res1d_network_mapping.png) - -#### Selective loading - -Large result files can contain thousands of nodes and gridpoints. Loading all of that data into memory is slow and may cause memory issues — especially when you only need the timeseries at a handful of nodes where observations exist. - -Both constructors accept the same two optional arguments to restrict what gets loaded: - -| Argument | Type | Effect | -|---|---|---| -| `nodes` | `None` \| `str` \| `list[str]` | Control which nodes have timeseries data loaded. `None` (default) loads all nodes; `[]` skips all node data; a name or list loads only those nodes. | -| `reaches` | `None` \| `str` \| `list[str]` | Control which reaches have intermediate gridpoint data populated. `None` (default) loads everything; `[]` skips all gridpoints; a name or list of names loads only those reaches. | - -::: {.callout-note} -Selective loading only controls **which timeseries are held in memory**. The full network topology (nodes, reaches, lengths) is always constructed so that `find()`, `recall()`, and graph algorithms still work on the complete network. -::: - -The most memory-efficient setup — useful when you only care about specific junction nodes — is to pass the node IDs you need and skip all intermediate gridpoints with `reaches=[]`: - -```{python} -network_subset = Network.from_mike( - path_to_res1d, - nodes=["78", "46"], - reaches=[], -) -network_subset -``` - -If you also need gridpoint data along a particular reach, pass its name (or a list of names): - -```{python} -network_subset = Network.from_mike( - path_to_res1d, - nodes=["78", "46"], - reaches=["94l1"], -) -network_subset -``` - -When only some nodes are loaded, `to_dataframe()` and `to_dataset()` only contain columns for those nodes — the rest are graph-connected but data-free: - -```{python} -network_subset.to_dataframe(sel="WaterLevel").head() -``` - -## Inspecting the Network - -### Available quantities - -```{python} -network.quantities -``` - -### Underlying graph - -The network exposes a `networkx.Graph` so you can use any NetworkX algorithm or -plotting function directly: - -```{python} -# | echo: false - -plot_kwargs = { - "font_size": 6, - "node_size": 130, - "node_color": "white", - "edgecolors": "black", - "with_labels": True, -} -``` - -```{python} -import networkx as nx -import matplotlib.pyplot as plt - -fig, ax = plt.subplots(figsize=(10, 9), layout="tight") -nx.draw(network.graph, ax=ax, **plot_kwargs) -plt.show() -``` - -### Timeseries data - -```{python} -# Multi-index DataFrame: columns are (node, quantity) -network.to_dataframe().head() -``` +import modelskill as ms -```{python} -# Select a single quantity -network.to_dataframe(sel="WaterLevel").head() +mr = ms.NetworkModelResult(path_to_res1d, name="MyModel", item="WaterLevel") +mr ``` -## Looking up node IDs - -After construction, nodes are re-labelled as integers. Use `find()` to go from original coordinates to the integer ID and `recall()` to go back. - -::: {.callout-tip} -When creating `NodeObservation` objects for skill assessment you generally do **not** need to call `find()`. You can pass the original string ID as `node=`, and `NetworkModelResult` will resolve it for you during matching. For breakpoints, use `at=(reach, distance)` rather than `node=`. See [Skill assessment workflow](#skill-assessment-workflow) for details. -::: +Open the network yourself when you need to name EPANET companion files, or to keep +memory down on a large model by reading only the locations you will score: ```{python} -# Look up a named node by its original id -node_id = network.find(node="117") -print(f"Node '117' → integer id {node_id}") +from mikeio1d.network import Network -# Recover the original label -print(network.recall(node_id)) -``` - -```{python} -# Look up a break point by reach + chainage -bp_id = network.find(reach="94l1", distance=21.285) -print(f"Break point (94l1, 21.285) → integer id {bp_id}") -print(network.recall(bp_id)) -``` - -```{python} -# Node batch lookup -ids = network.find(node=["20", "113", "38"]) -print(ids) -``` - -```{python} -# Reach lookup -ids = network.find(reach="58l1", distance="start") -print(ids) -ids = network.find(reach="58l1", distance=[51.456, 77.185]) -print(ids) -ids = network.find(reach="58l1", distance=["start", 77.185]) -print(ids) +network = Network.open(path_to_res1d, nodes=["78", "46"], reaches=["94l1"]) +ms.NetworkModelResult(network, name="MyModel", item="WaterLevel") ``` ## Skill assessment workflow -### 1. Wrap the Network in a NetworkModelResult - -```{python} -import modelskill as ms -from modelskill.model.network import NetworkModelResult +### 1. The model result -mr = NetworkModelResult(network, name="MyModel", item="WaterLevel") -mr -``` +`mr` above is the model side of the comparison, holding one quantity over every +location the file was read for. ### 2. Create NodeObservations and compute skill `NodeObservation` accepts a file path directly; the observation name is taken from the filename. -The `at=` argument can be specified in three ways, depending on what information you have at hand. +The `at=` argument takes either of two forms, depending on what you have at hand. ::: {.callout-note} ## MIKE 1D vocabulary vs the modelskill API -In MIKE 1D, "nodes" are the named connection points in the 1D network (manholes, junctions, outfalls) while "reaches" are the pipe or channel segments that connect them. The modelskill API uses `NodeObservation` more broadly: the `at=` argument accepts either a node ID (int or string) **or** a `(reach_id, distance)` breakpoint tuple that identifies a specific chainage along a reach. If you only need a reach-level quantity (uniform across the reach), use `ReachObservation` with `reach=` instead. +In MIKE 1D, "nodes" are the named connection points in the 1D network (manholes, junctions, outfalls) while "reaches" are the pipe or channel segments that connect them. The modelskill API uses `NodeObservation` more broadly: the `at=` argument accepts either the node's name **or** a `(reach_id, distance)` break point tuple that identifies a specific chainage along a reach. If you only need a reach-level quantity (uniform across the reach), use `ReachObservation` with `reach=` instead. ::: -#### Option A — original string alias +#### Option A — the node's name -Pass the original node identifier from the source format (e.g. the Res1D node name) as a plain string. The `NetworkModelResult` resolves it to the correct integer ID at match time, so you do not need to call `network.find()` yourself: +Pass the node's name in the model, e.g. the Res1D node name. It is resolved against the network at match time: ```{python} obs_1 = ms.NodeObservation(path_to_sensor_data_1, at="78") @@ -411,26 +101,26 @@ cc.skill() ``` ::: {.callout-note} -Resolution happens inside `ms.match()`. If the string is not found in the network's alias map a `ValueError` is raised with a clear message indicating which alias could not be resolved. +Resolution happens inside `ms.match()`. A name the network does not hold raises a `ValueError` that names the near misses. ::: #### Option B — breakpoint by `(reach, distance)` tuple When your observation sits at a chainage along a reach rather than at a named junction node, you can use the `at` argument and pass a `(reach_id, distance)` tuple. The `NetworkModelResult` looks up the corresponding breakpoint at match time: -```python -obs_bp = ms.NodeObservation(path_to_sensor_data_1, at=("94l1", 21.285)) +```{python} +obs_bp = ms.NodeObservation(path_to_sensor_data_1, at=("94l1", 42.57)) cc = ms.match(obs=obs_bp, mod=mr) cc.skill() ``` -The tuple form is equivalent to calling `network.find(reach="94l1", distance=21.285)` beforehand and is resolved during matching. +The tuple form is equivalent to calling `network.find(reach="94l1", distance=42.57)` beforehand, and is resolved during matching. ::: {.callout-note} ## Chainage tolerance -Breakpoint distances are matched with a tolerance of **1 × 10⁻³** (i.e. ±0.001 in whatever distance units the network uses). This means that small floating-point discrepancies between the distance you type and the value stored in the network are handled gracefully. If no breakpoint falls within that tolerance a `ValueError` is raised. +Break point distances are matched within the tolerance mikeio1d uses to decide two chainages are the same place, so small floating-point discrepancies between the distance you type and the value stored in the network are handled gracefully. If no break point falls within it, a `ValueError` is raised, as it is when the break point exists but carries no data for the quantity you are scoring - MIKE 1D stores water level and discharge at alternating grid points along a reach. ::: ### 3. Using ReachObservation for reach-uniform quantities @@ -447,7 +137,7 @@ obs_q Pass the observation to `ms.match()` exactly as you would a `NodeObservation`. modelskill resolves which breakpoint to use automatically: ```{python} -mr_q = NetworkModelResult(network, name="MyModel", item="Discharge") +mr_q = ms.NetworkModelResult(network, name="MyModel", item="Discharge") cc_q = ms.match(obs=obs_q, mod=mr_q) cc_q.skill() ``` @@ -456,131 +146,6 @@ cc_q.skill() Use `ReachObservation` when your measured quantity is representative of the whole reach (e.g. discharge, which is constant along a reach in steady flow). If you need to compare a quantity that varies spatially along the reach (e.g. water level at a specific chainage), use a `NodeObservation` with a `(reach, distance)` tuple instead (see [Option B](#option-b-breakpoint-by-reach-distance-tuple) above). ::: -## Development - -### Custom network formats - -In case you have your network data in a format that is not included in [Building a Network](#building-a-network), you can assemble a `Network` object by subclassing the abstract base classes `NetworkNode` and `NetworkReach`. - -`NetworkNode` requires three properties: `id`, `data`, and `boundary`. -`NetworkReach` requires four: `id`, `start`, `end`, and `breakpoints`. - -`NetworkReach.length` is optional and defaults to `None`. Reach length matters in some domains (rivers, sewer networks) and not in others (link-node water distribution models), so override it only where a length exists. Where it is left undefined, the reach contributes an edge with `length=None` to `network.graph`, which keeps length-weighted graph algorithms from quietly treating the reach as free. Nothing else in modelskill reads the length — matching and extraction work from break point distances alone. - - -The following is a simple implementation example: - -```python -import pandas as pd -import numpy as np -from typing import Any -from modelskill.network import NetworkNode, NetworkReach, Network - - -class ExampleNode(NetworkNode): - """Node backed by an in-memory DataFrame, e.g. model output.""" - - def __init__(self, node_id: str, data: pd.DataFrame): - self._id = node_id - self._data = data - - @property - def id(self) -> str: - return self._id - - @property - def data(self) -> pd.DataFrame: - return self._data - - @property - def boundary(self) -> dict[str, Any]: - return {} - - -class ExampleReach(NetworkReach): - """Reach connecting two nodes with a given length.""" - - def __init__( - self, reach_id: str, start: NetworkNode, end: NetworkNode, length: float, - breakpoints: list | None = None, - ): - self._id = reach_id - self._start = start - self._end = end - self._length = length - self._breakpoints = breakpoints or [] - - @property - def id(self) -> str: - return self._id - - @property - def start(self) -> NetworkNode: - return self._start - - @property - def end(self) -> NetworkNode: - return self._end - - @property - def length(self) -> float: - return self._length - - @property - def breakpoints(self) -> list: - return self._breakpoints -``` - -::: {.callout-tip} -The three abstract properties that **every** `NetworkNode` subclass must implement are `id`, `data` and `boundary`. If `boundary` is not relevant for your use case, define the property to return an empty dictionary, as in the example above. Similarly, a `NetworkReach` with no intermediate points can return an empty `breakpoints` list, and one with no meaningful length can leave the `length` property out altogether. -::: - - -```{python} -from modelskill.network import Network - -# df1, df2 and df3 are DataFrame objects that are loaded in memory -node_s1 = ExampleNode("sensor_1", df1) -node_s2 = ExampleNode("sensor_2", df2) -node_s3 = ExampleNode("sensor_3", df3) - -reach1 = ExampleReach("r1", node_s1, node_s2, length=500.0) -reach2 = ExampleReach("r2", node_s2, node_s3, length=300.0) - -network = Network(reaches=[reach1, reach2]) -network -``` - -### Adding break points along a reach - -Break points represent intermediate chainage locations on a reach (e.g. cross-sections). Subclass `ReachBreakPoint` the same way — implement `id` (a `(reach_id, distance)` tuple) and `data`: - -```python -from modelskill.network import ReachBreakPoint - - -class ExampleBreakPoint(ReachBreakPoint): - def __init__(self, reach_id: str, distance: float, data: pd.DataFrame): - self._id = (reach_id, distance) - self._data = data - - @property - def id(self): - return self._id - - @property - def data(self): - return self._data - - -# df4 is a DataFrame object that has been loaded in memory -bp = ExampleBreakPoint("r1", 200.0, df4) -reach1 = ExampleReach("r1", node_s1, node_s2, length=500.0, breakpoints=[bp]) -reach2 = ExampleReach("r2", node_s2, node_s3, length=300.0) -network = Network(reaches=[reach1, reach2]) -``` - - ## See also * [API reference — NetworkModelResult](../api/NetworkModelResult.qmd) diff --git a/justfile b/justfile index d027887a5..e33c86c5c 100644 --- a/justfile +++ b/justfile @@ -23,9 +23,9 @@ test: typecheck: uv run mypy src/ --config-file pyproject.toml -# Run doctests in metrics.py +# Run doctests in metrics.py and types.py doctest: - uv run pytest src/modelskill/metrics.py --doctest-modules + uv run pytest src/modelskill/metrics.py src/modelskill/types.py --doctest-modules # Generate HTML coverage report coverage: diff --git a/notebooks/Collection_systems_network.ipynb b/notebooks/Collection_systems_network.ipynb index 89e9962e0..5291a0e84 100644 --- a/notebooks/Collection_systems_network.ipynb +++ b/notebooks/Collection_systems_network.ipynb @@ -1,1629 +1,1894 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "fdb0d0b9", - "metadata": {}, - "outputs": [], - "source": [ - "import modelskill as ms\n", - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "import networkx as nx\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from modelskill.network import Network" - ] - }, - { - "cell_type": "markdown", - "id": "b643e568", - "metadata": {}, - "source": [ - "# 1D network workflow\n", - "\n", - "This notebook shows how to use `modelskill` to evaluate model results from 1D network simulations, such as collection systems or river networks. The workflow follows the same four-step pattern used elsewhere in `modelskill`: define model results → define observations → match → compare.\n", - "\n", - "## Loading network results\n", - "\n", - "The `Network` class organises data from a network simulation (e.g. a sewer system or a river) into a form that `modelskill` can work with. It stores time-series data for every node and break point in the network, and exposes the topology via a `networkx` graph.\n", - "\n", - "### Loading from a supported format\n", - "\n", - "The easiest way to create a `Network` is to load it directly from a supported file format. Currently **Res1D** (MIKE 1D) is supported:\n", - "\n", - "```python\n", - "from modelskill.network import Network\n", - "\n", - "network = Network.from_mike(\"path/to/results.res1d\")\n", - "``` \n", - "\n", - "### Custom network format\n", - "\n", - "For other simulation tools you can build a `Network` from your own data by subclassing the abstract base classes `NetworkNode` and `NetworkEdge`. Notice that this approach requires that you build the logic to generate a list of `NetworkEdge` to pass it to the network.\n", - "\n", - "```python\n", - "from modelskill.network import Network, NetworkNode, NetworkEdge\n", - "\n", - "class MyNode(NetworkNode): ...\n", - "\n", - "class MyEdge(NetworkEdge): ...\n", - "\n", - "\n", - "def generate_list_of_edges(a_network: CustomNetwork) -> list[MyEdge]: ...\n", - "\n", - "\n", - "edges = generate_list_of_edges(custom_network)\n", - "\n", - "network = Network(edges)\n", - "``` \n", - "\n", - "#### Break points\n", - "\n", - "Edges can optionally contain **break points** — intermediate locations along a reach (e.g. cross-section chainages) that carry their own time-series data. You can include them with subclass `EdgeBreakPoint`.\n", - "\n", - "### Example" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "cd363bae", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\n", - "Reaches: 118\n", - "Nodes: 259\n", - "Quantities: ['WaterLevel', 'Discharge']\n", - "Time: 1994-08-07 16:35:00 - 1994-08-07 18:35:00" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "network = Network.from_mike(\"../tests/testdata/network.res1d\")\n", - "network" - ] - }, - { - "cell_type": "markdown", - "id": "33a451d3", - "metadata": {}, - "source": [ - "All time-series data stored in the network can be accessed as an `xarray.Dataset` with `to_dataset()`. The dataset has one variable per physical quantity and uses the network's integer node IDs as the `node` coordinate:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "2a2d7414", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset> Size: 231kB\n",
-              "Dimensions:     (time: 110, node: 259)\n",
-              "Coordinates:\n",
-              "  * time        (time) datetime64[ns] 880B 1994-08-07T16:35:00 ... 1994-08-07...\n",
-              "  * node        (node) int64 2kB 0 1 2 3 4 5 6 7 ... 252 253 254 255 256 257 258\n",
-              "Data variables:\n",
-              "    WaterLevel  (time, node) float32 114kB 195.4 194.7 nan ... 188.5 nan nan\n",
-              "    Discharge   (time, node) float32 114kB nan nan 5.72e-06 ... nan 0.01692 0.0
" - ], - "text/plain": [ - " Size: 231kB\n", - "Dimensions: (time: 110, node: 259)\n", - "Coordinates:\n", - " * time (time) datetime64[ns] 880B 1994-08-07T16:35:00 ... 1994-08-07...\n", - " * node (node) int64 2kB 0 1 2 3 4 5 6 7 ... 252 253 254 255 256 257 258\n", - "Data variables:\n", - " WaterLevel (time, node) float32 114kB 195.4 194.7 nan ... 188.5 nan nan\n", - " Discharge (time, node) float32 114kB nan nan 5.72e-06 ... nan 0.01692 0.0" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "network.to_dataset()" - ] - }, - { - "cell_type": "markdown", - "id": "a972271a", - "metadata": {}, - "source": [ - "`Network` also exposes the underlying `networkx.Graph` via the `graph` property. This graph contains the full network topology — each graph node stores the node's data and boundary metadata — making it straightforward to run graph-based analyses (shortest path, connectivity checks, etc.):" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "06e8c2cb", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "network.graph" - ] - }, - { - "cell_type": "markdown", - "id": "885523e1", - "metadata": {}, - "source": [ - "Querying the underlying `networkx` graph lets you run topology-based analyses (e.g. shortest path, connected components) directly on the network. The visualisation below plots the graph, highlighting boundary/junction nodes with a thicker outline:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "1d068e44", - "metadata": {}, - "outputs": [], - "source": [ - "def plot_network(g: nx.Graph):\n", - "\n", - " g = g.copy()\n", - " lengths = nx.get_edge_attributes(g, \"length\")\n", - " max_len = max(lengths.values()) if lengths else 1.0\n", - " nx.set_edge_attributes(\n", - " g,\n", - " {e: v / max_len for e, v in lengths.items()},\n", - " \"norm_length\",\n", - " )\n", - "\n", - " widthmap = [2 if 'boundary' in g.nodes[node] else 1 for node in g.nodes()]\n", - " plot_kwargs = {\n", - " \"font_size\": 6,\n", - " \"node_size\": 130,\n", - " \"node_color\": \"white\",\n", - " \"edgecolors\": \"black\",\n", - " \"linewidths\": widthmap,\n", - " \"with_labels\": True,\n", - " }\n", - " fig, ax = plt.subplots(1, 1, sharey=True, layout=\"tight\", figsize=(10, 9))\n", - "\n", - " n = g.number_of_nodes()\n", - " k = 10 / np.sqrt(n) # increase multiplier (5, 10, ...) until nodes stop overlapping\n", - "\n", - " pos = nx.kamada_kawai_layout(g, weight=\"norm_length\", scale=10)\n", - " nx.draw(g, ax=ax, pos=pos, **plot_kwargs)\n", - "\n", - " # Set limits explicitly AFTER draw, otherwise matplotlib auto-scales them away\n", - " xs, ys = zip(*pos.values())\n", - " pad = 0.5\n", - " ax.set_xlim(min(xs) - pad, max(xs) + pad)\n", - " ax.set_ylim(min(ys) - pad, max(ys) + pad)\n", - " plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "53ab2b9c", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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RYTw2cLVjc65JUc2ep24lIgvHEYf4u0fCEsiA5KDQQO2h2kRnOSf+8EC1j9lyhRbNssjhSS58HrEkBef4QeiGGEfvX3+O4XoA5xScoNxMvmfv31UQiLC1T/YB1pw+YFC3FciFwjtDwtmBg3JTU9peTjU5D97uF4Q7uQph48zy0cohs+Zd8xZf7TI94MD06ZNO6adWhz26NByBlYYuGAgiOsg3LaSEHiPj3hJqR2YEOkFiW4hhDiGCDtmCO5EwhERGV5wU9SIAmsS2uJYh9BXCj2RfkGubKJV+xG1iG/cSt9KjWJptErCUfXtuWJBoSnfZzu5B1EoRK0kAs41bq13eNkeioD5ZSFuEO+JtJvCcaWXMt8TyW0fkTaIK4QVRbl89W7/wFUnn5pIBvLOCaUOt4oKPxDmiGsEezjkmfDp6667zsKYY4U8M+iCW83gR/QyCXOmLVly6QoM1HDOE/ku5JxyjXBOyA1PLu/6WAIRjXPvCfd4Z3CEKJKw6CaKgygHivv5QROEe0Z0+sWxx3H844QQQmR6+LovVaqU+/777+3vr7/+2p166qnu0ksvtdfh1Vdfdc2bN7fne/fudX///bdbsmSJu+OOO9yYMWPs9REjRriWLVum4Z4Ikbk+l8cdd1zC0/OZnDZtmnvhhRfcwoUL3T///GOvn3jiia527drunnvucVdddZXLkiXLYW/HokWL3MqVK93u3btdrly5XJkyZdwll1xy2PvE/K+99pobPXq0++GHH+xvvmuKFStm3x2NGjVyJ598cmT6gwcPum3btrldu3a5nDlzurx587rjjz8+yTJ/+eUXN3bsWLd69Wr3xx9/uBw5crjChQu72267zRUqVMj9F3bu3Om2b99uxyxPnjy2reLoU6tWLbsO3nrrLTv3119/vRs+fLjLmjWrGzBggHvppZfst+eBBx5wF154oVu8eLHr0qWLO+2009xPP/3kPv/8c1tO48aN3euvv35YnyMhUhuJbiGEOEbgBr1atWr2vGrVqm7BggVu3bp1dkMzefLkQ6bnhnn9+vWuV69e7osvvnAVKlSw18uXL29/CyHSFsTq77//bgIVoXi4QluItARh3bNnT/sdatGihbv//vttwGjKlClu0KBB7pRTTnHffPONO//8893cuXNdtmzZbD4GaJhu+fLlkUGnN99809188806oSLdom9nIYQ4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EOXKlcu98sorrn379lalP7olnhBCCCGEEOmZNBHdiEgP4iya/v37uwceeCAiVrwgo43XlClTrL91eLowr732mgknxByttoD2WtHTIYoAkQ1M79cTb3viEW57RTssBHw0VatWdVdffbWrU6eO/U3P7e7du9tymb5cuXIxlx09H8KfdmW0Dvv000/dqaeeekgbslhi/e2337Z2atWrVzdx7GEZDFI0a9bMBhJSWo7nnXfesZZfCCeEK8scPXq0tQfzQnnWrFkpinj45JNPkvQepyVbeIBm2rRpbuDAgdZvPBFoEUe7sy+++CIyqBGGwQAGC7yAvuiii9z48ePdTz/9ZP3R2Q9anHG82E7fTo5jxf4cOHAg5noR+Exz22232SAR13aePHnsGqtXr54dZ3/dHevwmURojxo1Kmav+2j4fDIPg0MDBgxIlW0UQgghhBAiw4rucE9s3MAwa9eutf9xqr1o3rFjh/3PTTduKW4oQs1P50GkI5qaNGlif//1118R8RieDrww3rZtm/2PGPLribc98cAx9iDkYokynF3EcteuXe1vBPfIkSNdnz59bN2I2FhEz4fg6N27tzmEuLrsB+56SmIdhxynG5ea5x6ca3qL814sopfjwZ1kGxC4MHTo0IjLDS1btkzIufe92tknD/vroSfz6aef7mrXru0qVKhg105yzjnLQUT369fPRC8ufjSdO3eOnGt6oXMt0YvdD8B42Df6muOcsw3w3nvvuXHjxh2yTKIhcOErVapkQr9Hjx42uMAx4ZytW7fO+spzzhYvXuyOZfjMM8jBoM2VV15p1xjHnwEbok8YGOLBsQaOJ+f4iiuucPnz53fTp0+3AREhhBBCCCEyAmkiugmP9rz11ltJ3lu2bJmFniJQ5s6da47h1KlT3b59++x9XDFEJg6on46b87vvvttCkHlwM897vI5YQjiHp0OMI6h4nbBV71LiRCJA421PeP4w4X3Yv3+/hV57WK53fxGMfsCB13H6CNGGcJhzcvMVLlzYlo+Yw/3jOITD3uOJ9dy5c7saNWrYcy8gAQcZ4rm30csBjhEh4LjzfhufeOIJ9+WXX0amCTvXyYl4lk/kAqLfD7LgOH/22We2b2PHjnV33HGHbTMDE4k452wLgwsPP/ywhdWHzynnHAceOPZETnCNJccll1ziJkyYEPk7Wsh///33JrZ/++03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47gkl3bxb2Efhg0bZmHxhND7fG0GKqiNwICKj2bgumDQ4tZbb7UoC17neUoDM0IIIYQQQqRHjuOftO4VLo4N/vrrL/fHH3+4HDlyuJNPPvlfL2f16tXu5ZdfdkuXLnW7du1yp556qitRooS766673MUXX5zQMgYPHuw6deoU+fv44493N954o7v66qtd9uzZ3a+//urGjRvnli1bFpnm9NNPdwsXLnSlSpWKvNa7d2/39NNPu1WrVrn8+fMntO7du3e7Cy+80FWrVs2NGTPGXnvmmWfcI488Yu/FYubMme711193p5xyinvppZfcHXfc4R544AFbDlx//fX2/4wZM+z/yy+/3J100klu/vz5LlH++ecfO47ly5d348ePjznNn3/+6d588033zTff2LHnPBYsWNA1atQo7v4zT9u2bW1f27VrZ/vKtoXZvn27Gz16tHvjjTfs2PO1lDdvXjsnLVu2dGeffXbC+yGEEEIIIUR6QqJbHLOMGjXK3X333W7//v0pTlukSBH3zjvvuOLFiyd5fcuWLa5s2bLuzDPPdHPnzjVhntLAw8033+wWLVrkPvvsM1eyZEl7fdKkSa5x48Zu7dq1rnDhwvYaAxQMKMBDDz1k0w4fPtyEN6L3/PPPt3WeeOKJrlChQm7Tpk2ucuXK7n//+5/tG+KYda1bt85deumlkcEChC3TnXPOOfb3ww8/bIMNMGjQINe1a1f3008/ubPOOiuy3evXr3dDhgxxr7zyituxY8ch+5U1a1Z30003uY4dO7oqVapEXv/hhx9c/fr13cqVK92wYcNc8+bNUzzWQgghhBBCZCrS2moXIi356aefLK+bcPdYOeeEQlPcLLkCbuR00/qKNlhUeI+XP/3ll19a+Duh1HPmzEnyHn3Faf3VpUuXyGuxCrx5wuHlTMe2UpCNwmsU0yP83k8fqyAbRdxiQQ414dwUywtvR6wCffEeVBfnGBDGzz7REs7nvQshhBBCCHGsIadbCOfM7SYU+5dffnF79+51uXLlcqVLl7ZHIhBe3rBhQ/f111+bI92qVStznAlbxzXGef78888tFHvChAmuUqVKhyzjvvvuc2PHjrXpDyf8ntDyjRs3usWLF7vjjjvO3XbbbeYw46YDTjfrY3uuuOIK17dvX9tGnGzc7qFDhyZx6NlGlvH4449bWHvdunXdwYMH7T1cdRz5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uG7durlPPvnELV261BUqVMjEOKK7SpUqNh3F1p544gn33XffuTZt2lhYOuK7bt26kdBzIYQQQgghMjMS3UKIf8Xdd9/t3njjDffpp59GwshTAgFOJfPFixe7smXL6sgLIYQQQohMj8LLhRD/in79+lnl8lq1armVK1emOP2QIUNMcPfs2VOCWwghhBBCHDNIdAsh/hWnn366mzNnjuVnV6hQwT344IMWOh7m4MGDbsaMGe6aa65xHTt2tAfh50IIIYQQQhwrKLxciKNEEATuo48+cqNGjTIxunv3bnfqqae6YsWKuRYtWphQPe644zL88d+xY4fr2rWre/XVV91ff/3lypUrZ/ne+/btc19//bUVW6O9GAKcdmGIc3LBwxXNhRBCCCGEyKxIdAtxFMT22LFj3TPPPGOiMx7kND/wwAOuSZMmGVp8L1u2zJxs3woMENS5cuUyFxzB/dNPPyWZ59Zbb3VjxoxxWbNmTYMtFkIIIYQQIvWQ1STEEeTvv/92rVq1cnfcccchgjtaWH/11VcmPgm5xgXOiKxfv95de+21EcF97rnnuqefftpt2bLFbd++3Xp5Mw3F1m677baIuz1+/HjXvn17G6AQQgghhBAiMyOnW4gjBAKyZcuWFk7uoWXWPffc4+rVq+dOOeUU61M9ZcoU98ILL7gvvvgiMh3TUGgsvTrev//+u/v555/d3r17LUT8vPPOcyeccIK7/vrr3TvvvGPTXHbZZfY8T548cZfz9ttvuwYNGtjgBLz77rtWiE0IIYQQQojMikS3EEeIV155xUQ3nHjiiRZi3rhx45jTbtu2zb388svukUceibjcr7/+uoWap6dBhEWLFtkAwZtvvhkRynD22WebeB46dKj9TQ43YebJCW4P/blbt25tz2+44QYT4kIIIYQQQmRWJLqFOEIC9cILL3Tfffed/T1x4kTXqFGjJNMcOHDAKnk///zzbu7cuUneI++5QIECbvny5S5HjhxH7ZwQ9v3hhx+a6Ie8efO6atWq2f9htm7daqJ64cKF1oO7bdu25mSTo03YOG49Odk43+w7205BNcLIOQ6Eks+aNcv16tXLwsjh/ffft5Zh7OuqVatsHTj7P/zwgznnQgghhBBCZEZUxUiIIwDi1AvuKlWqmOAmJPvqq6+213G977//frdu3TqrYH7++edbETEqfhO2PXr0aAvN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tlEIIYQQQogjjUS3EOKos3XrVlegQAHXs2dP16NHj4TnGzlypDniK1ascMWLFz+q2yiEEEIIIcTRQC3DhBBHnVdeecVagjVt2tRVqFDB5ciRwy1fvtz98ccfrkaNGq5q1ar2P5XM4Y477nCXXnqpGzNmjOV0v/TSSzpLQgghhBAiQyLRLYQ46gwfPtw1btzY3O533nnHNWjQwF4/4YQT3Lhx49zChQtd165d3YABAyLzjBo1yl6n8BrPyfUWQgghhBAioyHRLYQ4qhw8eNCtXbvW3GxE9hlnnBF5j0Jq+fPnt+cnnniiy5Ll/76ScMVbt27trr76anfOOee433//3ULUhRBCCCGEyGhkTesNEEJkbvbu3Wv/J9f6a//+/a53795uxIgR9vfTTz9tLcXI5b7pppvsNVqKCSGEEEIIkdGQ0y2EOKqccsop5lzv3Lkz7jR33XWXa9eunStatKj9jeCGEiVKuH/++cee08tbCCGEEEKIjIZEtxDi6H7JZMniypcv76ZPnx7z/UcffdQVLlzYcr49u3btsv+3bNnitm3b5goWLJgkLF0IIYQQQoiMgsLLhRBHnbZt27qWLVu6H374wbVv394tXbrUrVy50vp19+nTx1WpUsXNnz/fVapUyT3xxBOuWbNmbvv27W7fvn1W4fyBBx6I5HsLIYQQQgiRkVCfbiFEquR1U7n85ptvjuRtJwI9vZ966in3888/uzPPPPOobqMQQgghhBBHA1lHQoijDkXUnnzySTdy5EhzsoMgSKi3d9++fd3DDz8swS2EEEIIITIsCi8XQqQKFEvbuHGj6969u1Ul79atmytZsuQh0/34449u0KBBbsiQIa5NmzbukUce0RkSQgghhBAZFoWXCyFSFcLLEd703b7yyitd7dq1Xa5cudzu3bvdvHnz3KxZs6xSOdM8+OCDVvlcCCGEEEKIjIpEtxAi1aFA2pQpU9xLL71kRdUolnb88ce7s846y6qZN2nSxFqNCSGEEEIIkdGR6BZCpDnkeF977bWW+z116tS03hwhhBBCCCGOGCqkJoRIcwghL1GihOV6CyGEEEIIkZlQITUhRLoA0f3CCy+4v//+251wwgkus/H999+7GTNmWC77wYMH3WmnneaqV6/uLr/8cuWtCyGEEEJkYiS6hRDpRnQfOHDArV271p5nBv755x/35ptv2mDCBx98EHOaCy+80LVr187dfvvtFl4vhBBCCCEyF8rpFkKkCzZv3uzy5ctnOd033nijy+hQjZ2CcO+8805C0yO+Z86c6c4999yjvm1CCCGEECL1UE63ECJdQOVyWocRhp3R+euvv6wVWlhwFytWzD3zzDPmeH/44YfulVdecZUrV468v3z5cgs1/+WXX9Joq4UQQgghxNFATrcQIt1QsWJFV7x4cTdmzBiX0di2bZsJ6TfeeMOtWrXK/fnnn1aVnVZohJffeeedMXO3Fy9ebI74mjVr7O+yZcu6zz77zGXNquwfIYQQQojMgES3ECLdgDD97rvvTHRmFHbt2uU6d+7sXnvtNfv75ptvdkWKFDGB/dNPP7nJkyebAL/pppvc0KFDzdGP5tdff3WVKlVyP/74o/09bdo0V69evVTfFyGEEEIIceSR6BZCpBv69+/v+vXr53bu3JkhKnpv2bLFXX311W79+vWue/furkWLFi5v3rxJpnn//fddy5Yt3c8//+xOPPFEc7ZPOeUUK572xx9/uKpVq7pHH33U8rmvu+46m6dWrVru3XffTaO9EkIIIYQQRxLFLwoh0gWEYtMuDOe4TZs21lLrzDPPdHXr1nVFixZ16Q3c6xtuuMFc6o8++siVKlUq5nRUYv/222+tVdgll1xibcJwtV988UV3zjnnRKa79tpr3fnnn29u95w5c9wPP/zgChcunIp7JIQQQgghjgYqpCaESPMq388995wrWbKk69mzp702fPhw99RTT7kHHnjACpBdc8017u233zZhnl4qrTds2NBca4qlxRPcQEX2k08+2RUsWNA1a9bM/f777xY+f//997saNWq4jz/+2KbLkiWLa968eWS+JUuWpMq+CCGEEEKIo4tEtxAizaAnN4XD7r33Xrdy5cq40+H8kuNMwTEqgx8O+/fvN5FMKDhO+n+BAmm33HKLtfWaPXu2tTYrV66c+/zzz829JlSc91nP888/7ypUqGAPenUTgv7FF1/Y+xs3bnR9+vRx48ePt333hJ1vQuyFEEIIIUTGR+HlQog0gfBpWmQRnu0h9Jq8aMKsDxw4YGL2pZdeihQYmzRpkonRGTNmuBNOOCHusv/55x/LiaZqOLnS/A1UBEe8k0995ZVXHlbeOK2+ENk41Z727dvb/4jw+fPnm6P90EMPubfeesvWvWzZMhP9tAbLmTOnGz16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EEKIq0WV7iQMlWwHY7GCg8wQzsePH7c+Vmf/RqxyO9j+vXz5cgsuy5Url6U8796928QtFWxn00a8IJLptQZmbBNYhjAGQsm2bdsW7ftlf0uXLvUeeOABr0iRIjZPm30QnAYEXvEYPdcIHTcrG2s5CwQEsfF4v379bB43iwjY6N18bXrFqazzPrHGI765TqWd16KffcmSJeYKkOAObVxOQaALxOGS6zlfCA90C0G0YxDuxznmoL3iamEhicWv/fv3mzsjuI1DCCGEEEKECT6RZGnatCk+abuULFnS9/HHH9v9Fy9e9JUuXdr3559/+vLly+fLkiWL/zk//PCDr379+lfc7z///OMrWrSo79FHH41035w5c3wpU6b0v+bo0aP9jx88eNB333332f1Vq1b1zZs3z/fjjz/6zp075zt69KhvwoQJvsKFC9vjNWrU8P3+++/+527cuNF30003+fd7xx13+HLmzOk7ceJErI7Dt99+67v11lt9N954o38f7nL77bf7unbt6vvuu+/+1bEVSZsyZcr4z4G//vrL17JlS9+OHTv8j1eoUMGXIUMG38qVK+02vx/HSy+95D+XOGf/LUeOHPG9/PLLvkyZMkU6F3m9Pn36+A4dOhRHn1IIIYQQQiQFVOlOwtSrV89/nQpzVEFm9DuTzDx9+nQLLmMON33VVPMC52YHQmI5fc7t2rWzXte3337bK1mypNewYUOzagMjuwhvc1CxxqpOKjgVa/q+M2TIYAnoWM47dOjgZc+e3RKhqXYHpoSzb3qrXRAalXTGejFTm/70K0GVm89JNZxeXDeWjD51quVU9fk89KaL8CEwMI1k+2Do16a6TduBc42434ObAQ/O5REbeA6J+ZzntGjUrl3bfovY13GD8JugdYJWEIL+yE4QQgghhBBhQEKrfnH1UNHOnDmzVdFuuOGGSJW8wAp169atfcmTJ/dNnTr1ivtj2+HDh19WLQ6+tGjRwqroV2Lnzp2+hQsX+mbMmOH74IMPrBIeE3Pnzo1USafamCxZMl/NmjV9K1as8F24cMHe49mzZ33vvfeeVSvZrly5cr5Tp07Ze2rWrJnd161bt1gcQRGqcI6682jBggX+SjfnD78bOH36tK98+fJ2vUuXLr7Vq1f7Ll265MufP38kBwnnVkxQTX/88cftdzh48GDfr7/+GuV2v/32my8iIsLO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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plot_network(network.graph)" - ] - }, - { - "cell_type": "markdown", - "id": "5d3030f5", - "metadata": {}, - "source": [ - "Notice that in the visualisation above, some graph nodes have a thicker outline — these are the *nodes* (junctions and boundaries), while the others are *break points* along each reach.\n", - "\n", - "#### Mapping original IDs to integer IDs\n", - "\n", - "Internally, the `Network` relabels all nodes and break points with consecutive integers for efficient indexing. The original IDs used by the simulation tool are preserved and can be looked up with `find()`:\n", - "\n", - "In this Res1D example the original node IDs are strings. `find(node=...)` returns the corresponding integer ID:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "d9d23a8b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "252" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "network.find(node=\"98\")" - ] - }, - { - "cell_type": "markdown", - "id": "ae495c5d", - "metadata": {}, - "source": [ - "Break points are identified in the original network by the edge (reach) they belong to and their distance from the start node.\n", - "\n", - "> **Note:** The current `Network` implementation assumes a directed edge, so distance is always measured from the start node." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "30c88717", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "131" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "network.find(reach=\"44l1\", distance=44.841)" - ] - }, + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "fdb0d0b9", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:00.197602Z", + "iopub.status.busy": "2026-08-25T14:20:00.197216Z", + "iopub.status.idle": "2026-08-25T14:20:02.473745Z", + "shell.execute_reply": "2026-08-25T14:20:02.471396Z" + } + }, + "outputs": [], + "source": [ + "import modelskill as ms\n", + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "import networkx as nx\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from mikeio1d.network import Network" + ] + }, + { + "cell_type": "markdown", + "id": "b643e568", + "metadata": {}, + "source": [ + "# 1D network workflow\n", + "\n", + "This notebook shows how to use `modelskill` to evaluate model results from 1D network simulations, such as collection systems or river networks. The workflow follows the same four-step pattern used elsewhere in `modelskill`: define model results → define observations → match → compare.\n", + "\n", + "## Loading network results\n", + "\n", + "The `Network` class organises data from a network simulation (e.g. a sewer system or a river) into a form that `modelskill` can work with. It stores time-series data for every node and break point in the network, and exposes the topology via a `networkx` graph.\n", + "\n", + "It comes from [mikeio1d](https://github.com/DHI/mikeio1d), which reads the result files, and it arrives with `modelskill[network]`.\n", + "\n", + "### Loading from a supported format\n", + "\n", + "`Network.open` reads MIKE 1D (`.res1d`), MIKE 11 (`.res11`) and EPANET (`.res`) results:\n", + "\n", + "```python\n", + "from mikeio1d.network import Network\n", + "\n", + "network = Network.open(\"path/to/results.res1d\")\n", + "```\n", + "\n", + "It also takes the arguments for reading only part of a large file, and for naming the EPANET companion files. See mikeio1d's documentation for those, and for building a network from a format it does not read.\n", + "\n", + "### Break points\n", + "\n", + "A reach can carry **break points** — intermediate locations along it (e.g. cross-section chainages) with their own time-series data. They are locations you can compare against, addressed by their reach and their distance along it.\n", + "\n", + "### Example" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cd363bae", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:02.477942Z", + "iopub.status.busy": "2026-08-25T14:20:02.477210Z", + "iopub.status.idle": "2026-08-25T14:20:03.381839Z", + "shell.execute_reply": "2026-08-25T14:20:03.377494Z" + } + }, + "outputs": [ { - "cell_type": "markdown", - "id": "a7e41a31", - "metadata": {}, - "source": [ - "Multiple IDs can be looked up in a single call. For break points, each distance value corresponds to the edge at the same position in the `edge` list (one-to-one pairing):" + "data": { + "text/plain": [ + "\n", + "Reaches: 118\n", + "Nodes: 495\n", + "Quantities: ['WaterLevel', 'Discharge']\n", + "Time: 1994-08-07 16:35:00 - 1994-08-07 18:35:00" ] - }, + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "network = Network.open(\"../tests/testdata/network.res1d\")\n", + "network" + ] + }, + { + "cell_type": "markdown", + "id": "33a451d3", + "metadata": {}, + "source": [ + "All time-series data stored in the network can be accessed as an `xarray.Dataset` with `to_dataset()`. The dataset has one variable per physical quantity, and the `node` coordinate is the graph's own integer index. Alongside it, `name`, `reach` and `distance` carry the names the model gave each location, so a column can be read without holding on to the network:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2a2d7414", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:03.387636Z", + "iopub.status.busy": "2026-08-25T14:20:03.387172Z", + "iopub.status.idle": "2026-08-25T14:20:03.730978Z", + "shell.execute_reply": "2026-08-25T14:20:03.729115Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 10, - "id": "e25a4ba8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "([241, 3, 40], [131, 133])" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset> Size: 498kB\n",
+       "Dimensions:     (time: 110, node: 495)\n",
+       "Coordinates:\n",
+       "  * time        (time) datetime64[ns] 880B 1994-08-07T16:35:00 ... 1994-08-07...\n",
+       "  * node        (node) int64 4kB 0 1 2 3 4 5 6 7 ... 488 489 490 491 492 493 494\n",
+       "    name        (node) <U17 34kB '100' '99' '' '' '' '101' ... '' '' '' '' '' ''\n",
+       "    reach       (node) <U10 20kB '' '' '100l1' ... 'Pump:115p1' 'Pump:115p1'\n",
+       "    distance    (node) float64 4kB nan nan 0.0 23.84 ... 1.0 0.0 41.21 82.43\n",
+       "Data variables:\n",
+       "    WaterLevel  (time, node) float32 218kB 195.4 194.7 195.4 ... 193.8 nan 195.0\n",
+       "    Discharge   (time, node) float32 218kB nan nan nan 5.72e-06 ... nan 0.0 nan
" ], - "source": [ - "network.find(node=[\"92\", \"101\", \"113\"]), network.find(reach=[\"44l1\", \"45l1\"], distance=[44.841, 37.206])" + "text/plain": [ + " Size: 498kB\n", + "Dimensions: (time: 110, node: 495)\n", + "Coordinates:\n", + " * time (time) datetime64[ns] 880B 1994-08-07T16:35:00 ... 1994-08-07...\n", + " * node (node) int64 4kB 0 1 2 3 4 5 6 7 ... 488 489 490 491 492 493 494\n", + " name (node) " ] - }, + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "network.graph" + ] + }, + { + "cell_type": "markdown", + "id": "885523e1", + "metadata": {}, + "source": [ + "Querying the underlying `networkx` graph lets you run topology-based analyses (e.g. shortest path, connected components) directly on the network. The visualisation below plots the graph, highlighting boundary/junction nodes with a thicker outline:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1d068e44", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:03.742500Z", + "iopub.status.busy": "2026-08-25T14:20:03.742219Z", + "iopub.status.idle": "2026-08-25T14:20:03.748104Z", + "shell.execute_reply": "2026-08-25T14:20:03.746842Z" + } + }, + "outputs": [], + "source": [ + "def network_layout(network):\n", + " \"\"\"Place every graph node: named nodes from the reach skeleton, break points\n", + " interpolated along the reach that carries them.\n", + "\n", + " The graph joins a named node to the break point at the same chainage with a\n", + " zero-length edge, so a layout that reads edge lengths as distances cannot be\n", + " run over the graph itself. The skeleton of named nodes carries the reach\n", + " lengths without those edges, and every break point has a chainage that says\n", + " where along its reach it belongs.\n", + " \"\"\"\n", + " skeleton = nx.Graph()\n", + " for reach in network.reaches.values():\n", + " skeleton.add_edge(reach.start.id, reach.end.id, length=reach.length or 1.0)\n", + " named = nx.kamada_kawai_layout(skeleton, weight=\"length\")\n", + "\n", + " graph_id = {a: n for n, a in nx.get_node_attributes(network.graph, \"alias\").items()}\n", + " pos = {graph_id[name]: np.asarray(p) for name, p in named.items()}\n", + " for reach_id, reach in network.reaches.items():\n", + " start, end = np.asarray(named[reach.start.id]), np.asarray(named[reach.end.id])\n", + " span = reach.end_distance - reach.start_distance\n", + " for bp in reach.breakpoints:\n", + " if bp.distance is None: # a reach end whose chainage is unknown\n", + " fraction = 1.0\n", + " elif span == 0:\n", + " fraction = 0.0\n", + " else:\n", + " fraction = (bp.distance - reach.start_distance) / span\n", + " pos[graph_id[(reach_id, bp.distance)]] = start + fraction * (end - start)\n", + " return pos\n", + "\n", + "\n", + "def plot_network(network, ax=None):\n", + " \"\"\"Draw the network: named nodes as large circles, break points as small ones.\"\"\"\n", + " graph = network.graph\n", + " pos = network_layout(network)\n", + "\n", + " # recall() says what each integer stands for: a named node, or a break point\n", + " # given as a reach and a distance along it.\n", + " kinds = network.recall(list(graph))\n", + " nodes = [n for n, kind in zip(graph, kinds) if \"node\" in kind]\n", + " breakpoints = [n for n, kind in zip(graph, kinds) if \"node\" not in kind]\n", + "\n", + " if ax is None:\n", + " _, ax = plt.subplots(figsize=(10, 9), layout=\"tight\")\n", + " nx.draw_networkx_edges(graph, pos, ax=ax, edge_color=\"0.55\", width=0.8)\n", + " # break points first, so a break point coincident with a node hides beneath it\n", + " nx.draw_networkx_nodes(graph, pos, ax=ax, nodelist=breakpoints, node_size=14,\n", + " node_color=\"white\", edgecolors=\"0.45\", linewidths=0.6)\n", + " nx.draw_networkx_nodes(graph, pos, ax=ax, nodelist=nodes, node_size=55,\n", + " node_color=\"white\", edgecolors=\"black\", linewidths=1.4)\n", + " ax.set_aspect(\"equal\")\n", + " ax.set_axis_off()\n", + " return ax" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "53ab2b9c", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:03.752735Z", + "iopub.status.busy": "2026-08-25T14:20:03.752107Z", + "iopub.status.idle": "2026-08-25T14:20:04.992453Z", + "shell.execute_reply": "2026-08-25T14:20:04.991033Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 11, - "id": "cb1ae550", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "({'node': '98'},\n", - " {'reach': '45l1', 'distance': 37.20599457458005},\n", - " [{'node': '98'}, {'reach': '45l1', 'distance': 37.20599457458005}])" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "network.recall(252), network.recall(133), network.recall([252, 133]) " + "data": { + "image/png": "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", + "text/plain": [ + "
" ] - }, + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_network(network);" + ] + }, + { + "cell_type": "markdown", + "id": "5d3030f5", + "metadata": {}, + "source": [ + "Notice that in the visualisation above, the large, heavy circles are the *nodes* (junctions and boundaries), while the small ones strung along each reach are its *break points*. A break point coincident with a node — the first and last gridpoint of a reach — sits beneath that node's circle, which is where it physically is.\n", + "\n", + "#### Mapping original IDs to integer IDs\n", + "\n", + "Internally, the `Network` relabels all nodes and break points with consecutive integers for efficient indexing. The original IDs used by the simulation tool are preserved and can be looked up with `find()`:\n", + "\n", + "In this Res1D example the original node IDs are strings. `find(node=...)` returns the corresponding integer ID:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "d9d23a8b", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:04.995517Z", + "iopub.status.busy": "2026-08-25T14:20:04.995321Z", + "iopub.status.idle": "2026-08-25T14:20:05.000066Z", + "shell.execute_reply": "2026-08-25T14:20:04.998667Z" + } + }, + "outputs": [ { - "cell_type": "markdown", - "id": "41ca197f", - "metadata": {}, - "source": [ - "## Integration with `modelskill`\n", - "\n", - "Wrap a `Network` in a `NetworkModelResult` to make it compatible with the standard `modelskill` comparison workflow. The `item` argument selects which quantity to use when more than one is available in the network:" + "data": { + "text/plain": [ + "478" ] - }, + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "network.find(node=\"98\")" + ] + }, + { + "cell_type": "markdown", + "id": "ae495c5d", + "metadata": {}, + "source": [ + "Break points are identified in the original network by the edge (reach) they belong to and their distance from the start node.\n", + "\n", + "> **Note:** The current `Network` implementation assumes a directed edge, so distance is always measured from the start node." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "30c88717", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.002631Z", + "iopub.status.busy": "2026-08-25T14:20:05.002358Z", + "iopub.status.idle": "2026-08-25T14:20:05.007373Z", + "shell.execute_reply": "2026-08-25T14:20:05.005888Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 13, - "id": "edec2e5a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - ": WaterLevel" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "network_model = ms.NetworkModelResult(network, item=\"WaterLevel\")\n", - "network_model" + "data": { + "text/plain": [ + "240" ] - }, + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "network.find(reach=\"44l1\", distance=44.841)" + ] + }, + { + "cell_type": "markdown", + "id": "a7e41a31", + "metadata": {}, + "source": [ + "Multiple IDs can be looked up in a single call. For break points, each distance value corresponds to the edge at the same position in the `edge` list (one-to-one pairing):" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "e25a4ba8", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.009708Z", + "iopub.status.busy": "2026-08-25T14:20:05.009423Z", + "iopub.status.idle": "2026-08-25T14:20:05.015680Z", + "shell.execute_reply": "2026-08-25T14:20:05.014411Z" + } + }, + "outputs": [ { - "cell_type": "markdown", - "id": "5905e267", - "metadata": {}, - "source": [ - "To evaluate the model we need observations at network nodes. These are represented by `NodeObservation`, which requires an integer node ID obtained via `Network.find()`.\n", - "\n", - "In this example we create synthetic sensor observations by extracting data from the network dataset and adding random noise to simulate real-world measurement error and timing jitter:" + "data": { + "text/plain": [ + "([455, 5, 68], [240, 244])" ] - }, + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "network.find(node=[\"92\", \"101\", \"113\"]), network.find(reach=[\"44l1\", \"45l1\"], distance=[44.841, 37.206])" + ] + }, + { + "cell_type": "markdown", + "id": "c4f36cfd", + "metadata": {}, + "source": [ + "Use `recall()` to translate integer IDs back to the original identifiers. This is useful when you want to know which original node or break point corresponds to a given integer ID:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "cb1ae550", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.018483Z", + "iopub.status.busy": "2026-08-25T14:20:05.018235Z", + "iopub.status.idle": "2026-08-25T14:20:05.024805Z", + "shell.execute_reply": "2026-08-25T14:20:05.022827Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 14, - "id": "817e1800", - "metadata": {}, - "outputs": [], - "source": [ - "ds = network.to_dataset()\n", - "\n", - "# Script to generate dummy sensor data\n", - "sensor_1 = ds[\"WaterLevel\"].sel(node=30).to_pandas().rename(\"water_level@sens1\")\n", - "sensor_2 = ds[\"WaterLevel\"].sel(node=54).to_pandas().rename(\"water_level@sens2\")\n", - "sensor_3 = ds[\"WaterLevel\"].sel(node=71).to_pandas().rename(\"water_level@sens3\")\n", - "\n", - "perfect_sensors = [sensor_1, sensor_2, sensor_3]\n", - "real_sensors = []\n", - "\n", - "for n, sensor in enumerate(perfect_sensors, start=1):\n", - " sensor += np.random.normal(0, 0.1, len(sensor))\n", - " sensor.index = [sensor.index[i] + pd.Timedelta(s, unit=\"s\") for i, s in enumerate(np.random.uniform(-10, 10, len(sensor)))]\n", - " sensor.sort_index(inplace=True)\n", - " if n == 2:\n", - " sensor = sensor.iloc[30:]\n", - " if n == 3:\n", - " sensor = pd.concat([sensor.iloc[:50], sensor.iloc[70:]])\n", - "\n", - " real_sensors.append(sensor)\n", - " sensor.to_csv(f\"../tests/testdata/network_sensor_{n}.csv\")\n", - "\n", - "sensor_1 = real_sensors[0]\n", - "sensor_2 = real_sensors[1]\n", - "sensor_3 = real_sensors[2]" + "data": { + "text/plain": [ + "({'reach': '47l1', 'distance': 26.7092518454833},\n", + " {'reach': '1l1', 'distance': 0.0},\n", + " [{'reach': '47l1', 'distance': 26.7092518454833},\n", + " {'reach': '1l1', 'distance': 0.0}])" ] - }, + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "network.recall(252), network.recall(133), network.recall([252, 133]) " + ] + }, + { + "cell_type": "markdown", + "id": "41ca197f", + "metadata": {}, + "source": [ + "## Integration with `modelskill`\n", + "\n", + "Wrap a `Network` in a `NetworkModelResult` to make it compatible with the standard `modelskill` comparison workflow. The `item` argument selects which quantity to use when more than one is available in the network:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "edec2e5a", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.028134Z", + "iopub.status.busy": "2026-08-25T14:20:05.027832Z", + "iopub.status.idle": "2026-08-25T14:20:05.040168Z", + "shell.execute_reply": "2026-08-25T14:20:05.038998Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 15, - "id": "66d1b420", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nbiasrmseurmsemaeccsir2
observation
water_level@sens2800.0072410.0972850.0970150.0777890.8507820.0005010.721882
\n", - "
" - ], - "text/plain": [ - " n bias rmse urmse mae cc \\\n", - "observation \n", - "water_level@sens2 80 0.007241 0.097285 0.097015 0.077789 0.850782 \n", - "\n", - " si r2 \n", - "observation \n", - "water_level@sens2 0.000501 0.721882 " - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# The name is taken from the name of the series\n", - "node_id = network.find(reach=\"117l1\", distance=48.7)\n", - "single_obs = ms.NodeObservation(sensor_2, at=node_id)\n", - "cmp = ms.match(single_obs, network_model)\n", - "cmp.skill()" + "data": { + "text/plain": [ + ": WaterLevel" ] - }, + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "network_model = ms.NetworkModelResult(network, item=\"WaterLevel\")\n", + "network_model" + ] + }, + { + "cell_type": "markdown", + "id": "5905e267", + "metadata": {}, + "source": [ + "To evaluate the model we need observations at network nodes. These are represented by `NodeObservation`, which is addressed the way the model names the location: a node's name, or a break point as a `(reach, distance)` pair. The integers the graph uses are an internal index, and observations never mention them.\n", + "\n", + "In this example we create synthetic sensor observations by extracting data from the network dataset and adding random noise to simulate real-world measurement error and timing jitter:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "817e1800", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.043090Z", + "iopub.status.busy": "2026-08-25T14:20:05.042858Z", + "iopub.status.idle": "2026-08-25T14:20:05.064739Z", + "shell.execute_reply": "2026-08-25T14:20:05.063884Z" + } + }, + "outputs": [], + "source": [ + "ds = network.to_dataset()\n", + "\n", + "# Script to generate dummy sensor data. Two sensors sit at named nodes and one\n", + "# at a break point along a reach, which is the pair of forms an observation takes.\n", + "sensor_locations = [\"98\", (\"117l1\", 48.7), \"101\"]\n", + "\n", + "\n", + "def graph_id(at):\n", + " if isinstance(at, str):\n", + " return network.find(node=at)\n", + " reach, distance = at\n", + " return network.find(reach=reach, distance=distance)\n", + "\n", + "\n", + "sensor_1, sensor_2, sensor_3 = (\n", + " ds[\"WaterLevel\"].sel(node=graph_id(at)).to_pandas().rename(f\"water_level@sens{n}\")\n", + " for n, at in enumerate(sensor_locations, start=1)\n", + ")\n", + "\n", + "perfect_sensors = [sensor_1, sensor_2, sensor_3]\n", + "real_sensors = []\n", + "\n", + "for n, sensor in enumerate(perfect_sensors, start=1):\n", + " sensor += np.random.normal(0, 0.1, len(sensor))\n", + " sensor.index = [sensor.index[i] + pd.Timedelta(s, unit=\"s\") for i, s in enumerate(np.random.uniform(-10, 10, len(sensor)))]\n", + " sensor.sort_index(inplace=True)\n", + " if n == 2:\n", + " sensor = sensor.iloc[30:]\n", + " if n == 3:\n", + " sensor = pd.concat([sensor.iloc[:50], sensor.iloc[70:]])\n", + "\n", + " real_sensors.append(sensor)\n", + " sensor.to_csv(f\"../tests/testdata/network_sensor_{n}.csv\")\n", + "\n", + "sensor_1 = real_sensors[0]\n", + "sensor_2 = real_sensors[1]\n", + "sensor_3 = real_sensors[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "66d1b420", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.067278Z", + "iopub.status.busy": "2026-08-25T14:20:05.067089Z", + "iopub.status.idle": "2026-08-25T14:20:05.115372Z", + "shell.execute_reply": "2026-08-25T14:20:05.114441Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 16, - "id": "ed1f9094", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nbiasrmseurmsemaeccsir2
observation
network_sensor_2800.0072410.0972850.0970150.0777890.8507820.0005010.721882
\n", - "
" - ], - "text/plain": [ - " n bias rmse urmse mae cc \\\n", - "observation \n", - "network_sensor_2 80 0.007241 0.097285 0.097015 0.077789 0.850782 \n", - "\n", - " si r2 \n", - "observation \n", - "network_sensor_2 0.000501 0.721882 " - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nbiasrmseurmsemaeccsir2
observation
water_level@sens2790.0112470.1060830.1054850.0825450.851650.0005450.720208
\n", + "
" ], - "source": [ - "# The name is taken from the name of the file\n", - "path_to_sensor2 = \"../tests/testdata/network_sensor_2.csv\"\n", - "single_obs = ms.NodeObservation(path_to_sensor2, at=node_id)\n", - "cmp = ms.match(single_obs, network_model)\n", - "cmp.skill()" + "text/plain": [ + " n bias rmse urmse mae cc \\\n", + "observation \n", + "water_level@sens2 79 0.011247 0.106083 0.105485 0.082545 0.85165 \n", + "\n", + " si r2 \n", + "observation \n", + "water_level@sens2 0.000545 0.720208 " ] - }, + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The name is taken from the name of the series\n", + "# sensor 2 sits at a break point, addressed by its reach and distance along it\n", + "at = (\"117l1\", 48.7)\n", + "single_obs = ms.NodeObservation(sensor_2, at=at)\n", + "cmp = ms.match(single_obs, network_model)\n", + "cmp.skill()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "ed1f9094", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.117280Z", + "iopub.status.busy": "2026-08-25T14:20:05.117046Z", + "iopub.status.idle": "2026-08-25T14:20:05.150538Z", + "shell.execute_reply": "2026-08-25T14:20:05.149228Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 17, - "id": "de621fec", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nbiasrmseurmsemaeccsir2
observation
Sensor 2800.0072410.0972850.0970150.0777890.8507820.0005010.721882
\n", - "
" - ], - "text/plain": [ - " n bias rmse urmse mae cc si \\\n", - "observation \n", - "Sensor 2 80 0.007241 0.097285 0.097015 0.077789 0.850782 0.000501 \n", - "\n", - " r2 \n", - "observation \n", - "Sensor 2 0.721882 " - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nbiasrmseurmsemaeccsir2
observation
network_sensor_2790.0112470.1060830.1054850.0825450.851650.0005450.720208
\n", + "
" ], - "source": [ - "# The name is passed\n", - "single_obs = ms.NodeObservation(path_to_sensor2, at=node_id, name=\"Sensor 2\")\n", - "cmp = ms.match(single_obs, network_model)\n", - "cmp.skill()" + "text/plain": [ + " n bias rmse urmse mae cc \\\n", + "observation \n", + "network_sensor_2 79 0.011247 0.106083 0.105485 0.082545 0.85165 \n", + "\n", + " si r2 \n", + "observation \n", + "network_sensor_2 0.000545 0.720208 " ] - }, - { - "cell_type": "markdown", - "id": "2357349d", - "metadata": {}, - "source": [ - "### Plotting" - ] - }, + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The name is taken from the name of the file\n", + "path_to_sensor2 = \"../tests/testdata/network_sensor_2.csv\"\n", + "single_obs = ms.NodeObservation(path_to_sensor2, at=at)\n", + "cmp = ms.match(single_obs, network_model)\n", + "cmp.skill()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "de621fec", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.152192Z", + "iopub.status.busy": "2026-08-25T14:20:05.152048Z", + "iopub.status.idle": "2026-08-25T14:20:05.176449Z", + "shell.execute_reply": "2026-08-25T14:20:05.175587Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 18, - "id": "923a1d93", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsEAAAK9CAYAAADFUbHOAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQAAvQ9JREFUeJzs3Qd4U1X/B/BvWzopbUFahpa9BAUUEFwUlTJUFBeKtICCoFRx/eUV90BBRMXRgmhlOABFBKsiKihliIrSFxFQpogyymoLpenK//mda/qmpSNpxr03+X6eJ8ab5tyc3Cblm5PfPSfAarVaQURERETkRwL17gARERERkbcxBBMRERGR32EIJiIiIiK/wxBMRERERH6HIZiIiIiI/A5DMBERERH5HYZgIiIiIvI7DMFERERE5HcYgomIiIjI7zAEExH5gT59+qgLERFpGIKJSFcffvghAgIC8Mknn5z2sy5duqifffvtt6f9rFmzZrjooouceqy0tDTMmTMHnrBnzx7V12nTpnlk/77ixIkTePLJJ3HOOeegbt26OOOMM9C1a1fce++9+Oeff+CLSktL1evummuuQXx8vHre8vwnTZqEgoICvbtH5LcYgolIV5dccom6XrNmTbnbc3NzsXnzZtSpUwdr164t97O//vpLXWxtjRCCqWZFRUXo3bs3XnzxRVx66aV4+eWX8cgjj+D888/HBx98gD/++MMnD2N+fj5uu+02ZGdn484778T06dNxwQUXqA8DAwcOhNVq1buLRH6pjt4dICL/1rRpU7Rs2fK0EPz999+rcHDTTTed9jPbtrMh2BOKi4vVSB/VbMmSJdi4cSPef/993HrrreV+JiOihYWFpj2M8hqQ/oeFhZ32s5CQEPVBzv6bizvuuAMtWrRQQXjFihXo27evl3tMRBwJJiLdSZiVcHTq1Kmy2yQ0dOrUSY2UrV+/vlzQlJ9J6cHFF1+stmfPno3LL78ccXFxCA0NRceOHTFjxoxyjyGB47fffsOqVatUW7nY18geP34c9913n/q6WvbRpk0bvPDCC+Ue177kQUbzWrdure67ZcsWh5+rxWJRwUf2L23l8SZMmKBut5Gvyi+77LLT2kpfzjzzTNx4443lbpO+yLGSANaoUSOMHTsWx44dc7hPtXncBQsWoFu3bqhXrx6ioqJw7rnn4tVXX612/zt37lTXtt+bPem77Mfetm3b1GM2aNBA/bx79+749NNPy91HRvbldyKviQceeACxsbGq3OC6665TI6/2NmzYgP79+6Nhw4YIDw9XH75uv/32cvc5efIkHnzwwbLXQfv27dXvu+JorTzm3XffrQK9HHu575dfflnp85YQXFnpjvRRbN26tdrjRkSewZFgIjJECH733Xfxww8/lAVT28iZXHJyclRpROfOnct+1qFDB1VPKiTwShCRmkspn8jIyMC4ceNUeEtJSVH3kaB4zz33IDIyEo8++qi6TQKj7evqhIQE/P333ypASr3xunXrMHHiROzfv1+1tSehW0Yux4wZo8KPhDRHRoPlPtJHGcmWtmeffTZ+/fVXvPLKK6oUQEZKxc0334ynnnoKBw4cQOPGjcvaSzupm73lllvKbpP+ShCUr9vHjx+P3bt344033lAfKuQ4BQcHO/x7cPRxv/76awwdOhRXXHGF+qBgC3LyeFLbW5XmzZur63nz5uGxxx5TQbIq8oFFwrKE74cfflgFW6kfHzx4MD7++OOyAGkjv9v69eurDxjyYUV+ZxJSFy5cqH5+6NAh9OvXT4Vk2V9MTIy63+LFi8v2IUFXfj9Sgz5q1ChVq7x8+XI89NBD6rUhvyd7K1euVH2Sx5FgLR+0nCHHWUhbItKBlYhIZ7/99psMs1mfffZZtV1UVGStW7eude7cuWq7UaNG1tTUVPX/ubm51qCgIOsdd9xR1j4/P/+0ffbv39/aqlWrcrd16tTJmpCQcNp95XHl8f74449ytz/88MPqsfbu3au2d+/erfoZFRVlPXToULn72n724osvVvk83333XWtgYKB19erV5W6fOXOmart27Vq1/fvvv6vt119/vdz9xo0bZ42MjCx7vrIfud/7779f7n5ffvnlabfL867sudtz9HHvvfdedQyKi4utzpD27du3V4/RvHlz68iRI63p6enWgwcPnnbfK664wnruuedaCwoKym4rLS21XnTRRda2bduW3TZ79my1v759+6qf29x///3qd3f8+HG1/cknn6j7/fTTT1X2b8mSJeo+kyZNKnf7jTfeaA0ICLDu2LGj7Da5n/wu5bVbW9JnOY7Hjh2r9T6IqPZYDkFEupMRURnVtdX6/ve//1VfS9u+QpZr28lxUitcUlJSrh5Yvtq2kVHjw4cPq5HdXbt2qe2afPTRR+pE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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nbiasrmseurmsemaeccsir2
observation
Sensor 2790.0112470.1060830.1054850.0825450.851650.0005450.720208
\n", + "
" ], - "source": [ - "cmp = ms.match(single_obs, network_model)\n", - "cmp.plot()\n", - "cmp.plot.timeseries();" + "text/plain": [ + " n bias rmse urmse mae cc si \\\n", + "observation \n", + "Sensor 2 79 0.011247 0.106083 0.105485 0.082545 0.85165 0.000545 \n", + "\n", + " r2 \n", + "observation \n", + "Sensor 2 0.720208 " ] - }, + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The name is passed\n", + "single_obs = ms.NodeObservation(path_to_sensor2, at=at, name=\"Sensor 2\")\n", + "cmp = ms.match(single_obs, network_model)\n", + "cmp.skill()" + ] + }, + { + "cell_type": "markdown", + "id": "2357349d", + "metadata": {}, + "source": [ + "### Plotting" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "923a1d93", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.178104Z", + "iopub.status.busy": "2026-08-25T14:20:05.177945Z", + "iopub.status.idle": "2026-08-25T14:20:05.761740Z", + "shell.execute_reply": "2026-08-25T14:20:05.760245Z" + } + }, + "outputs": [ { - "cell_type": "markdown", - "id": "02e77cf0", - "metadata": {}, - "source": [ - "## Multiple sensors\n", - "\n", - "When you have observations at several nodes you can use `NodeObservation.from_multiple()` to create a list of `NodeObservation` objects. Pass `nodes` as a `dict` mapping each node ID to either a column name/index within a shared `data` source, or to a separate data source entirely:" + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsEAAAK9CAYAAADFUbHOAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQAAo6FJREFUeJzs3XlcVPX+x/HXgDMgKLhBZIEaaeaClLZcK7WuaFa23O6tLLesa4tmu2nlbb1pZWUL2maaXjPLm5W31MwWyrJ+lERllqKmlghugCAMMOf3x4mJQcABhpkz8H4+HjzqzJw55zMzqO/5zvd8PzbDMAxERERERJqRkEAXICIiIiLibwrBIiIiItLsKASLiIiISLOjECwiIiIizY5CsIiIiIg0OwrBIiIiItLsKASLiIiISLOjECwiIiIizY5CsIiIiIg0OwrBIiLNwKBBgxg0aFCgyxARsQyFYBEJqDfeeAObzcayZcsOu69Pnz7YbDY+/vjjw+5LSEigf//+dTrX7NmzmT9/fn1LrdW2bduw2WzMnDmzUY7fVBw8eJD77ruPXr16ERkZSfv27UlOTubmm2/m999/D3R5jcLlcjF//nwuvPBC4uPjiYyMpFevXjz88MMUFxcHujyRZkshWEQC6swzzwTg888/97g9Pz+fH374gRYtWrB27VqP+3bs2MGOHTvcj/VWY4ZgObLS0lIGDBjA448/zllnncWTTz7J3Xffzcknn8xrr73GL7/8EugSG0VRURFXX301ubm5XH/99cyaNYtTTz2V++67j2HDhmEYRqBLFGmWWgS6ABFp3jp27EiXLl0OC8FffvklhmHwj3/847D7KrbrGoIbQ1lZGS6XK9BlBIW3336b9evXs2jRIq688kqP+4qLi3E6nQGqrOFcLhdOp5Pw8PDD7nM4HKxdu9bjm4t//vOfdO7cmfvuu481a9YwePBgf5YrImgkWEQs4Mwzz2T9+vUcOnTIfdvatWvp2bMnw4YNY926dR5Bc+3atdhsNs444wwA5s2bxznnnENsbCxhYWH06NGDOXPmeJyjc+fO/Pjjj3z66afYbDZsNpvHHNkDBw5wyy23EB8fT1hYGMcffzyPPvqox3krT3mYNWsWiYmJhIWFsWHDBq+fa0lJCffddx/HH388YWFhxMfHM3nyZEpKStz79OrVi7PPPvuwx7pcLo455hj+/ve/e9w2a9YsevbsSXh4OEcddRTXXXcd+/fv97qm+pz39ddfp2/fvrRu3ZqoqCh69+7N008/Xevxs7KyANzvW2Xh4eFERUV53LZx40b+/ve/065dO8LDw+nXrx/vvvuuxz7z58/HZrOxdu1abrvtNmJiYoiMjOSSSy4hNzfXY9/09HSGDh1Khw4daNmyJV26dGHcuHEe+xQWFnL77be7fw9OOOEEZs6cedhorc1mY+LEiSxatIiePXsSFhbGypUrq33eDoej2qk7l1xyCQA//fRTtY8TkcalkWARCbgzzzyThQsX8tVXX7mDacXIWf/+/cnLy+OHH34gKSnJfV/37t1p3749AHPmzKFnz55ceOGFtGjRguXLl3PjjTficrmYMGECALNmzeKmm26iVatW3HPPPQAcddRRgPl19cCBA/ntt9+47rrrSEhI4IsvvmDq1Kns2rWLWbNmedQ7b948iouLGT9+PGFhYbRr186r0WCXy8WFF17I559/zvjx4znxxBP5/vvveeqpp/jll194++23Abj88su5//77yc7OJi4uzv34zz//nN9//50rrrjCfdt1113H/Pnzufrqq5k0aRJbt27lueeeY/369axduxa73e71++DteVevXs2IESP461//yqOPPgqYQW7t2rXcfPPNNR6/U6dOACxYsIB7770Xm81W474//vgjZ5xxBscccwxTpkwhMjKSN954g4svvpj//ve/7gBZ4aabbqJt27bcd999bNu2jVmzZjFx4kSWLFkCQE5ODkOGDCEmJoYpU6bQpk0btm3bxltvveU+hmEYXHjhhXz88cdcc801JCcns2rVKu68805+++03nnrqKY9zfvTRR7zxxhtMnDiRDh060LlzZy9e5T9lZ2cD0KFDhzo9TkR8xBARCbAff/zRAIyHHnrIMAzDKC0tNSIjI41XX33VMAzDOOqoo4zU1FTDMAwjPz/fCA0NNf75z3+6H19UVHTYMYcOHWocd9xxHrf17NnTGDhw4GH7PvTQQ0ZkZKTxyy+/eNw+ZcoUIzQ01Ni+fbthGIaxdetWAzCioqKMnJwcj30r7nv88cdrfJ4LFy40QkJCjM8++8zj9ueff94AjLVr1xqGYRg///yzARjPPvusx3433nij0apVK/fz/eyzzwzAWLRokcd+K1euPOz2gQMHVvvcK/P2vDfffLMRFRVllJWV1Xq8qoqKiowTTjjBAIxOnToZY8eONebOnWvs3r37sH3/+te/Gr179zaKi4vdt7lcLqN///5G165d3bfNmzfPAIzBgwcbLpfLffutt95qhIaGGgcOHDAMwzCWLVtmAMb//d//1Vjf22+/bQDGww8/7HH73//+d8NmsxmbN2923wYYISEhxo8//lin16CywYMHG1FRUcb+/fvrfQwRqT9NhxCRgDvxxBNp3769e67vd999R2Fhofsr5P79+7svjvvyyy8pLy/3mA/csmVL9//n5eWxZ88eBg4cyJYtW8jLyzvi+d98803OOuss2rZty549e9w/gwcPpry8nLS0NI/9L730UmJiYur8PN98801OPPFEunfv7nGec845B8C9Cka3bt1ITk52j2IClJeXs3TpUoYPH+5+vm+++SbR0dGkpKR4HK9v3760atWq2lU1auPtedu0aUNhYSGrV6+u0/FbtmzJV199xZ133gmYUxmuueYajj76aG666Sb3lJB9+/bx0Ucfcdlll1FQUOB+Xnv37mXo0KFs2rSJ3377zePY48eP9xhZPuussygvL+fXX3911wzwv//9j9LS0mrre//99wkNDWXSpEket99+++0YhsGKFSs8bh84cCA9evSo02tQ4ZFHHuHDDz9kxowZ7tpExL8UgkUk4Gw2G/3793fP/V27di2xsbEcf/zxgGcIrvhv5RC8du1aBg8eTGRkJG3atCEmJoa7774bwKsQvGnTJlauXElMTIzHT8XFSjk5OR77d+nSpV7Pc9OmTfz444+Hnadbt26Hnefyyy9n7dq17rD3ySefkJOTw+WXX+5xvLy8PGJjYw875sGDBw+r2xvenPfGG2+kW7duDBs2jGOPPZZx48bVOB+2qujoaB577DG2bdvGtm3bmDt3LieccALPPfccDz30EACbN2/GMAymTZt22PO67777DnutwFwyr7K2bdsCuOdGDxw4kEsvvZQHHniADh06cNFFFzFv3jyPudi//vorHTt2pHXr1h7HOvHEE933V1bf34MlS5Zw7733cs0113DDDTfU6xgi0nCaEywilnDmmWeyfPlyvv/++8OupO/fv797Xubnn39Ox44dOe644wDzYqu//vWvdO/enSeffJL4+HgcDgfvv/8+Tz31lNdzdVNSUpg8eXK191eE1AqVR57rwuVy0bt3b5588slq74+Pj3f//+WXX87UqVN58803ueWWW3jjjTeIjo7m3HPP9ThebGwsixYtqvZ49Rmt9ua8sbGxZGRksGrVKlasWMGKFSuYN28eo0eP5tVXX/X6XJ06dWLcuHFccsklHHfccSxatIiHH37Y/Z7dcccdDB06tNrHVnxAqhAaGlrtfsYfF7TZbDaWLl3KunXrWL58OatWrWLcuHE88cQTrFu3jlatWnldd4X6/B6sXr2a0aNHc/755/P888/X+fEi4jsKwSJiCZXXC167di233HKL+76+ffsSFhbGJ598wldffcV5553nvm/58uWUlJTw7rvveowGVjcVoKYLsRITEzl48GCjL1OVmJjId999x1//+tdaLwoDc5Tx1FNPZcmSJUycOJG33nqLiy++mLCwMI/jffjhh5xxxhn1Dub1OS+YKx4MHz6c4cOH43K5uPHGG3nhhReYNm3aYQH1SNq2bUtiYiI//PADgPsDjt1u9/l7cvrpp3P66afz73//m9dee42rrrqK119/nWuvvZZOnTrx4YcfUlBQ4DEavHHjRuDPC/vq66uvvuKSSy6hX79+vPHGG7RooX+CRQJJ0yFExBL69etHeHg4ixYt4rfffvMYCQ4LC+Pkk08mNTWVwsJCj6kQFSOARqUlrPLy8pg3b95h54iMjOTAgQOH3X7ZZZfx5ZdfsmrVqsPuO3DgAGVlZQ15ah7n+e2333jppZcOu+/QoUMUFhZ63Hb55Zezbt06XnnlFfbs2eMxJaHieOXl5e5pBJWVlZVV+1y9caTz7t2712M7JCTEvXJH5ekFVX333Xfs2bPnsNt//fVXNmzYwAknnACYI82DBg3ihRdeYNeuXYftX3XpM2/s37//sGXOkpOTPWo+77zzKC8v57nnnvPY76mnnsJmszFs2LA6n7fCTz/9xPnnn0/nzp353//+57MPLSJSf/oYKiKW4HA4OOWUU/jss88ICwujb9++Hvf379+fJ554AvCcDzxkyBD3qOR1113HwYMHeemll4iNjT0sQPXt25c5c+bw8MMPc/zxxxMbG8s555zDnXfeybvvvssFF1zA2LFj6du3L4WFhXz//fcsXbqUbdu2eb2M1Zo1a6pthXvxxRczatQo3njjDa6//no+/vhjzjjjDMrLy9m4cSNvvPEGq1atol+/fu7HXHbZZdxxxx3ccccdtGvX7rBR0YEDB3Ldddcxffp0MjIyGDJkCHa7nU2bNvHmm2/y9NNPe6zt660jnffaa69l3759nHPOORx77LH8+uuvPPvssyQnJ7vnz1Zn9erV3HfffVx44YWcfvrptGrVii1btvDKK69QUlLC/fff7943NTWVM888k969e/PPf/6T4447jt27d/Pll1+yc+dOvvvuuzo9p1dffZXZs2dzySWXkJiYSEFBAS+99BJRUVHubxaGDx/O2WefzT333MO2bdvo06cPH3zwAe+88w633HILiYmJdTpnhYKCAoYOHcr+/fu58847ee+99zzuT0xM5C9/+Uu9ji0iDRDQtSlERCqZOnWqARj9+/c/7L633nrLAIzWrVsftjTXu+++ayQlJRnh4eFG586djUcffdR45ZVXDMDYunWre7/s7Gzj/PPPN1q3bm0AHkuGFRQUGFOnTjWOP/54w+FwGB06dDD69+9vzJw503A6nYZh1L4MWsV9Nf0sXLjQMAzDcDqdxqOPPmr07NnTCAsLM9q2bWv07dvXeOCBB4y8vLzDjnvGGWcYgHHttdfW+Lq9+OKLRt++fY2WLVsarVu3Nnr37m1MnjzZ+P333937eLNEmrfnXbp0qTFkyBAjNjbWcDgcRkJCgnHdddcZu3btqvWYW7ZsMf71r38Zp59+uhEbG2u0aNHCiImJMc4//3zjo48+Omz/rKwsY/To0UZcXJxht9uNY445xrjggguMpUuXuvepWCKt6tJnH3/8sQEYH3/8sWEYhvHtt98aI0aMMBISEoywsDAjNjbWuOCCC4z09HSPxxUUFBi33nqr0bFjR8Nutxtdu3Y1Hn/8cY/l1wzDXCJtwoQJtT7fCkf63RgzZoxXxxER37IZhpqWi4iIiEjzojnBIiIiItLsKASLiIiISLOjECwiIiIizY5CsIiIiIg0OwrBIiIiItLsKASLiIiISLOjZhn15HK5+P3332nduvUR25+KiIiISOMzDIOCggI6duxISEjtY71aJ7iedu7cSXx8fKDLEBERERHOAf4HtARs7Nixg2OPPbbWR2gkuJ5at24NwI4dO4iKivLLOXNzcwGIiYnxy/msXIcValAdqiMY6rBCDapDdQRDHVaoQXXUr45PPgnl8ssjKC62MXjwIT788M+cVhuF4HqqmAIRFRXltxBcXFzsPmcgWaEOK9SgOlRHMNRhhRpUh+oIhjqsUIPqqHsda9bA5ZdDcTFccAG88kopsbF4NVVVF8aJiIiISNBZs8YMvhUBeOlSCAvz/vEKwSIiIiISVBoagEEhWERERESCiC8CMCgEi4iIiEiQ8FUABl0Y5xeGYVBeXk5ZWVmDjlNaWgr8OUk8UKxQhxVqUB3WqsNutxMaGur384qIiH/4MgCDQnCjMgyDAwcOkJubS3l5eYOPV3GM/Pz8Bh8r2OuwQg2qw3p1tGnThri4uICcW0REGo+vAzAoBDeq7OxsDhw44F5GrUWLFg3qLlcxyma3231VYtDWYYUaVId16jAMg6KiInJycgA0Iiwi0oSkpdkZNcq3ARgUghtNeXk5eXl5xMTE0KFDB58cs+If9kAHHSvUYYUaVIe16mjZsiUAOTk5tG3b9ojtMkVExPrMANzG5wEYFIIbLDc3t9r5j6WlpZSVlREWFuYeHWuohs4p9hUr1GGFGkB1VBXoOux2O+Xl5eTm5loiBFd0OmruNYDqqEp1eLJCHVaoAVRHZWlpdkaOjKakxEZKSgmzZ+eRl1f7YwoKCrw+fuD/lQgyqamp9OjRg1NOOSXQpYhIFQ2ZbiQiItZRMQJcUhLCwIEFzJ2b57MR4AoaCa6jCRMmMGHCBPLz84mOjiYmJqbaVn7FxcXk5+djt9t9/tVwoL/yrmCFOqxQA6iOqgJVR3l5OaGhoURFRWG324mNjQ1IHVVZoQ4r1ACqoyrV4ckKdVihBmjedaxZg3sOcEpKCXPnHiI+3rs6wsPDvT6PRoJFRERExBKqrgLRGCPAFRSCRURERCTgGmMZtNooBEu9HTx4kPvuu49zzz2Xdu3aYbPZmD9/vtePX7JkCSNHjqRr167YbDYGDRrUaLWKiIiIdfk7AINCsDTAnj17ePDBB/npp5/o06dPnR8/Z84c3nnnHeLj42nbtm0jVCgiIiJWF4gADLowThrg6KOPZteuXcTFxZGenl7nFTMWLlzIMcccQ0hICL169WqkKkVERMSqAhWAQSPB0gBhYWFetajNy8tj48aN5FVZ3C8+Pt4Sa7mKiIiI/wUyAINCsPjBsmXLOPHEE1m2bFmgSxERERELCHQABk2H8DvDgKKi+j22ovGcL5dgjYgA9RcQERERf7FCAAaFYL8rKoJWrer7aN83IDh4ECIjfX5YD2PHjmXs2LGNexIRERGxPKsEYNB0CBERERHxAysFYNBIsN9FRJijr/VR+sd8CF+2pI2I8NmhRERERKpltQAMCsF+Z7PVf/pBY8wJFhEREWlMVgzAoOkQ4gc1LZEmIiIiTZtVAzBoJFga6LnnnuPAgQP8/vvvACxfvpydO3cCcNNNNxEdHc2yZcu4+uqrmTdvnscFcmlpaaSlpQGQm5tLYWEhDz/8MAADBgxgwIAB/n0yIiIi4jNWDsCgECwNNHPmTH799Vf39ltvvcVbb70FwMiRI4mOjq7xsR999BEPPPCAx23Tpk0D4L777lMIFhERCVJWD8CgECwNtG3btiPuU9MSaffffz/333+/z2sSERGRwAmGAAyaEywiIiIiPhIsARgUgkVERETEB4IpAINCsIiIiIg0ULAFYFAIFhEREZEGCMYADArBIiIiIlJPwRqAQSFYREREROohmAMwKASLiIiISB0FewAGhWARERERqYOmEIBBIVhEREREvNRUAjAoBIuIiIiIF5pSAAaFYBERERE5gqYWgEEhWERERERq0RQDMCgEi4iIiEgNmmoABoVg8YEff/yRkSNHcswxxxAWFkbHjh0ZOXIkGzZsCOixREREpP7S0uxNNgCDQrA00FtvvcXJJ5/MmjVruPrqq5k9ezbXXHMNH330ESeffDLvvPNOQI4lIiIi9ZeWZmfUqDZNNgADtAh0AcEuNzeX4uLiw24vLS2lvLyc0tJSQkNDfXKusrIynxynoSrqyMrKYtSoUXTp0oWPPvqImJgY9z433ngjZ599NiNHjuSbb76hS5cutR6zrsey2msRaKrDVPHnbt++fYSEBP4zfm5ubqBLsEQNoDqqUh2erFCHFWoAa9SRlmZn5MhoSkpspKSUMHt2Hnl5gamlrq9HQUGB1/sG/l+JIJOamkqPHj045ZRTAlaDYRgUFhYCUFhYiGEYAanjySefpKioiDlz5niEVoAOHTowe/ZsDh48yJNPPunXY4mIiEj9VIwAl5SEMHBgAXPn5jW5EeAKNiNQCSrI5efnEx0dTV5eHlFRUYfdX1xczNatW+nSpQvh4eE+OWdpaSmGYTDvo49ZvH07M/r1Y0p6OiMSEhg/dAg2m80n5/GmDoDOnTvjcDjYunVrjftWjNru2LGj1mMec8wxdTpWRQ12u70ez8B3VIe16qj4cxcVFYXdbic2NjYgdVTIyckBCGgdVqhBdaiOYKjDCjUEuo7KF8GlpJQwd24e8fHB9XocKZ9VppHgIFNUVMTi7dv5NCmZYVlb+DQpmcXbt1NUVOTXOvLy8vj999/p06dPrfslJSWxc+fOWr+e8OWxREREpO6qrgLRlEeAKygEB5nIyEhm9OtHmx3bOXB8V9rsMEeEIyMj/VpHRRBt3bp1rftV3F9bcPXlsURERKRumvIyaLVRCA4yhYWFTElP50B8Am02b+JAfAJT0tPdc4T9xdtAWlBQgM1mo0OHDuzbt4/s7Gz3T94fs+zrcywRERFpuOYagEEhOOhEREQwIiGBgZkZrEg8joGZGYxISCAiIsKvdURHR9OxY0cyMzNr3S8zM5Njjz0Wh8PB3/72N44++mj3z80331zvY4mIiEjDNOcADFoiLejYbDbGDx3CyKIiIiMjee+EbkRERPjtorjKhg8fzgsvvMDnn3/OmWeeedj9n332Gdu2beO2224D4IknnmD//v3u+zt27FjvY4mIiEj9NfcADBoJDko2m809BzgyMjIgARjgjjvuICIiguuuu469e/d63Ldv3z6uv/56oqKimDhxIgB9+/Zl8ODB7p8ePXrU+1giIiJSPwrAJo0ES70df/zxLFiwgBEjRtC7d2+uueYaunTpwrZt25g7dy779+/n9ddfP2KjDF8fS0RERKqnAPwnhWBpkEsvvZRvv/2W6dOn8/LLL5OTk4PL5SI8PJxvvvnGY7TXn8cSERERTwrAnjQdQhqsV69eLFq0iF27dlFeXs6rr75KSUkJM2bMCOixRERExKQAfDiNBIvPjR49ml27djFlyhSOPfZYHnnkEUscS0REpDlSAK6eQrA0irvuuou77rrLcscSERFpThSAa6bpECIiIiJNkAJw7RSCRURERJoYBeAjUwgWERERaUIUgL2jECwiIiLSRCgAe08hWERERKQJUACuG4VgERERkSCnAFx3CsEiIiIiQUwBuH4UgkVERESCVHMNwIZhUFhYCEBhYSGGYdT5GGqWISIiImJhLpeLzMxMsrOziYuLIykpiZCQkGYdgF9c9QGLt29nRr9+TElPZ0RCAuOHDqnTcRSCpVFs27aNLl26MG/ePMaOHRvockRERIJWZmYmy5cvx+l04nA4ANi7N7lZBmCAoqIiFm/fzqdJyQzL2sKBpGTIzGBkUVGdjqPpEFIvCxYswGazVfszZcqUah/z/vvvc//99/u30HpwuVw89thjdOnShfDwcJKSkli8eHGdjvHhhx9yzjnnEB0dTevWrenbty9Llizx2OfgwYPccsstHHvssYSFhXHiiScyZ84cXz4Vr7lcLubMmUNycjItW7akffv2nHPOOXz33XeH7Vff12b+/Pk1/s5kZ2d77LtkyRJGjhxJ165dsdlsDBo0yFdPVUQk6GRnZ+N0OklMTMTpdLJihbPZBmCAyMhIZvTrR5sd2zlwfFfa7DBHhCMjI+t0HI0ES4M8+OCDdOnSxeO2Xr160alTJw4dOoTdbnff/v7775Oammr5IHzPPfcwY8YM/vnPf3LKKafwzjvvcOWVV2Kz2bjiiiuO+Ph58+ZxzTXXkJKSwiOPPEJoaCg///wzO3bscO9TXl7O0KFDSU9PZ8KECXTt2pVVq1Zx4403sn//fu6+++7GfIqHGTduHIsWLWL06NFMnDiRwsJC1q9fT05Ojsd+DX1toPrfmTZt2nhsz5kzh2+++YZTTjmFvXv3Nui5iYgEu7i4OBwOB1lZWezY0Y3XX+9HSUnzDMBgzgGekp7OgaRk2mzexIH4BKakp/PeCd3qdiBD6iUvL88AjLy8vGrvP3TokLFhwwbj0KFDPjun0+k0nE6nz47XkDpefvllAzD+7//+z+vHTZgwwfDVr1xjvRY7d+407Ha7MWHCBPdtLpfLOOuss4xjjz3WKCsrq7WOrVu3Gi1btjQmTZpU63neeOMNAzDmzp3rcfull15qhIeHG7t3765T3TW9HoAxb968Wh+7ZMkSAzDeeuutWvfz5rWp7X2ZN2+e178z27dvN8rLyw3DMIyePXsaAwcOPOJjDOPPP3c7d+6s82vYGHbv3h3wOqxQg+pQHcFQhxVqqKmO8vJyY/369cYjj3xlhIWVG2AYF1xgGMXF/q0jEKqrw+VyGc+vWGkMfOFF48tvvjUGvvCi8fyKlYbL5TpiPqtM0yGkUWzbtg2bzcb8+fMBGDt2LKmpqQAeX4NX2LVrFxs3bqS0tLTGYxqGQefOnbnooosOu6+4uJjo6Giuu+66BtX9zjvvUFpayo033ui+zWazccMNN7Bz506+/PLLWh///PPPU15ezoMPPgiYUx6Maq5Y/eyzzwAOGz294oorKC4u5p133gEgJyeHmJgYBg0a5HGczZs3ExkZyeWXX16/J1rJk08+yamnnsoll1yCy+VyX21bVUNfm8oKCgooLy+v8f74+HhCQvTXk4gIQEhICHv3JvPgg6dSUhLSbEeAK9hsNsYPHcJ7V13J6SefxHtXXcn4oUM8coU39K+MNEheXh579uzx+KnOddddR0pKCgALFy50/1SYOnUqJ554Ir/99luN57LZbIwcOZIVK1awb98+j/uWL19Ofn4+I0eOdN9Wta6afkpKStyPWb9+PZGRkZx44okexz/11FPd99fmww8/pHv37rz//vsce+yxtG7dmvbt2zNt2jRcLpd7v5KSEkJDQ90XOFSIiIgA4JtvvgEgNjaWOXPm8Omnn/Lss88C5rzcsWPH0rp1a2bPnl1rPUeSn5/P119/zSmnnMLdd99NdHQ0rVq14rjjjuONN97w2Lehr02Fs88+m6ioKCIiIrjwwgvZtGlTg56DiFiDy+UiIyODlStXkpGR4fF3njRMc10FojY2m809BzgyMrLOARg0J9j/DAPqePWiW8UoaaV5tg0WEQH1+MWpMHjw4MNuq27k8y9/+QvdunVj9erVHkG1rkaPHs2///1vli5dyvjx4923/+c//6Fz586ceeaZ7ttiYmK8OmblFSx27drFUUcdddgfpqOPPhqA33//vdZjbdq0idDQUK6++momT55Mnz59eOutt3j44YcpKytj+vTpAJxwwgmUl5ezbt06j5orRogrfxj4+9//zogRI5g6dSrDhg3jnXfeYe3atbz99tu0b9/eq+dYk6ysLAzD4PXXX6dFixY89thjREdH8/TTT3PFFVcQFRXFueee65PXJiIigrFjx7pD8DfffMOTTz5J//79+fbbb4mPj2/QcxGRwKpuBYPk5OTAFtUEKAA3HoVgfysqglat6vVQH0bfPx08CHW8mrKy1NRUunWr40T0asyfP989daI23bp147TTTmPx4sXuELxv3z5WrFjB5MmTPQLa6tWrvTp3z5493f9/6NAhwqr52yU8PNx9f20OHjyIy+VixowZ3HXXXQBceuml7Nu3j6effpq7776b1q1bc+WVV/Lggw8ybtw4UlNT6dq1Kx988IF7ZLfqeZ577jk++eQT/v73v/PLL78watSow6aFFBUVVTud5ODBgx4j9KGhobRt29Z9H8DevXtZt24dp512GgAXXnghXbp04eGHH3aH4Ia+NpdddhmXXXaZe/viiy9m6NChDBgwgH//+988//zztT5eRKyt8goGWVlZh636InWnANy4AjodIi0tjeHDh9OxY0dsNhtvv/22x/27d+9m7NixdOzYkYiICM4999wavzo1DINhw4ZVe5zq9v3Xv/7F0UcfTcuWLRk8eLC+kq2nU089lcGDB3v8NLbRo0fzxRdf8OuvvwLw5ptvUlpayqhRozz2q1pXTT8VI5kALVu29JgeUaG4uNh9f20q7h8xYoTH7SNGjODQoUPuKQNxcXG8++67lJSUMGTIELp06cKdd97pnvLQqsoHpXbt2vHMM8+QmZlJdHQ0zzzzzGHnnjlzJjExMR4/ADfddJPHbSeddNJh9Xbp0sUdgCvOP3z4cL7++mvKysp88tpU58wzz+S0007jww8/rPNjRcRaKq9g4HA4iIuLC3RJQU0BuPEFdCS4sLCQPn36MG7cOP72t7953GcYBhdffDF2u5133nmHqKgonnzySQYPHsyGDRsOWwtu1qxZXs8Heeyxx3jmmWd49dVX6dKlC9OmTWPo0KFs2LDBParVaCIizNHXeqgY5bP7ejpEkLniiiu49dZbWbx4MdOmTeM///kP/fr144QTTvDYz9tRiOjoaHeAO/roo/n4448xDOOwC/cAOnbsWOuxOnbsyKZNmzjqqKM8bo+NjQVg//797tsGDBjAli1b+P77791/FiqmFFQ3ur5q1Sr3MXbu3HnYsmIjR45k4MCBHrelpKRw5513MmTIn110KofViudTtd6KmktLSyksLCQ6OrrBr01N4uPj+fnnn+v1WBGxjqSkJACPrmZSP2lpdkaNUgBubAENwcOGDWPYsGHV3rdp0ybWrVvHDz/84P66es6cOcTFxbF48WKuvfZa974ZGRk88cQTpKene4zqVccwDGbNmsW9997r/jp5wYIFHHXUUbz99tter3VabzZb/acfNMacYD+qz6T16rRr145hw4axePFiRo8ezdq1a5k1a9Zh+x3pd6FC5TnBycnJvPzyy/z000/06NHDvc9XX33lvr82ffv2ZdOmTfz2228cd9xx7tsrwm3VecqhoaEex6wYEa06or5y5UpefvllJk+ezKJFixgzZgxfffUVLVr8+Uf4uOOOO+yDAECPHj1qHKHv2LEjcXFx1V6Q+PvvvxMeHk7r1q2Bhr82NdmyZYvX87dFxLpCQkI0B9gHzADcRgHYDyw7J7jia9fKI7MhISGEhYXx+eefu0NwUVERV155JampqV599bJ161ays7M9QkF0dDSnnXYaX375ZY0huKSkxOOr4Pz8fAByc3PdXwdXVlpaSnl5OaWlpYSGhnrxjI+s4mvpQCsrK3Mvb1VWVlbtPNSK2ypeA/jzvczNzT1sFHPXrl3k5eWRmJjo1Uj3FVdcwYgRI7j99tsJDQ3l0ksvPayOFStWePV8evTo4X7seeedh91u57nnnuPpp58GzA9Oc+bM4ZhjjuGUU05x77tr1y727dvnEXYvvfRSXn/9dV588UUeeughwLxi+pVXXqFdu3YkJSXVuAxcbm4ujz76KL1792bgwIHu/Q4cOMC1117LKaecwgMPPMBZZ53F8OHDeeihh7j33nuB2n83Kr8H1fnHP/7Bs88+y4oVK9x/Lvbs2cM777zD2WefTXl5OeXl5V69NhV1VPd+5ubmHhZ2V6xYwTfffMPEiRNrrNEwDAzDqPU5VKj4c7dv3z5LLLGWm5sb6BIsUQOojqpUhycr1GGFGtLS7IwcGU1JiY2UlBJmz84jLy8wtVjh9YC611FQUOD1vpYNwd27dychIYGpU6fywgsvEBkZyVNPPcXOnTvdX78C3HrrrfTv37/atWOrU/EVedWvf4866qhavz6fPn06DzzwQD2eiVQ4+eSTAfM9S0lJITQ01L3O7b333svChQv55Zdf6Ny58xGPNWzYMNq3b89///tfzj33XPd0g8r++te/1rnGY489lptuuoknn3yS0tJS+vXrx7vvvsvnn3/Oq6++6vGBpqLmn376icTERMC8oOycc87hscceY+/evSQlJfHuu++ydu1aZs+e7XFh2V//+ldOO+00jj/+eLKzs5k7dy4HDx5k2bJlHgHutttuY+/evaxYsYLQ0FCGDh3KuHHjmD59OsOHD6dPnz51fp6VTZ48maVLl3L55Zdz8803Ex0dzYsvvkhpaal7vWNvX5uKEFzd+zlw4ED69OlD3759iY6OZv369cyfP5/4+Hj3RYQVPvvsM/dKGXv27KGoqIhHHnkEgLPOOouzzjqrQc9ZRMRqKkaAS0psDBxYwNy5hzQCXFeGQfh//lOX/a0BMJYtW+ZxW3p6utGnTx8DMEJDQ42hQ4caw4YNM84991zDMAzjnXfeMY4//nijoKCg1uNUtnbtWgMwfv/9d4/b//GPfxiXXXZZjY8rLi428vLy3D87duxQx7haun9t3br1sG5lZWVlxk033WTExMQYNpvNo3vcmDFjDMDYunWr1zVcf/31BmC89tprDXk6hykvLzceeeQRo1OnTobD4TB69uxp/Oc//zlsv4qaf/nlF4/bCwoKjJtvvtmIi4szHA6H0bt372off+uttxrHHXecERYWZsTExBhXXnmlkZWV5bHPO++8YwDGE0884XF7fn6+0alTJ6NPnz7u34v6dowzDMPIysoyLrnkEiMqKspo2bKlcc455xhff/11nV+bijqqez/vueceIzk52YiOjjbsdruRkJBg3HDDDUZ2dvZh57nvvvsMoNqf++67r8bnoY5x1qxBdaiOYKgjkDV8+KFhhIcbBhhGSkqxsX27dd6Tim51K1asMNavX+/u5unvOo5o507DGDLEyPvj3wpvOsbZDKOaRV0DwGazsWzZMi6++OLD7svLy8PpdBITE8Npp51Gv379SE1N5ZZbbuGZZ57xGDUrLy8nJCSEs846i08++eSwY23ZsoXExETWr1/vMXdp4MCBJCcnu7/mPZL8/Hyio6PJy8sjKirqsPuLi4vZunUrXbp08dnFdo1yYVyQ1lFaWsodd9zBvHnzyM7OdjeZCEQdoPfEKnVU/LmLiorCbrdX+w2BP+Xk5AAEtA4r1KA6VEcw1BGoGqquAjF7dg5hYdZ5T37//XeP9Z+HDx/u17nfR3xfDAMWL4YJE+DAAfLDwoguKakxn1UW+ElzXoiOjiYmJoZNmzaRnp7unvowZcoUMjMzycjIcP8APPXUU8ybN6/aY3Xp0oW4uDjWrFnjvi0/P5+vvvqKv/zlL43+XMQ3iouLee2117j00ksDFoBFREQaIhiWQau8/rPT6bTW+s9798Lll8NVV8GBA9CvH3z+udcPD+ic4IMHD7J582b39tatW8nIyKBdu3YkJCTw5ptvEhMTQ0JCAt9//z0333wzF198sXu5p7i4uGovhktISKBLly7u7e7duzN9+nQuueQSbDYbt9xyCw8//DBdu3Z1L5HWsWPHakehxVpycnL48MMPeeONN9i7dy8333xzoEsSERGps2AIwGDh9Z/few+uvRaysyE0FP71L5g6FY7QuKmygIbg9PR0zj77bPf2bbfdBsCYMWOYP38+u3bt4rbbbmP37t0cffTRjB49mmnTptX5PD///DN5lS6vnDx5MoWFhYwfP54DBw5w5pln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4MABdu3axcqVK9m7dy/HHXecx37R0dF07dqVAQMGsHTpUjZu3MiyZcuqPeZnn31GTk4OCQkJtGjRghYtWvDrr79y++2309kKAfPAAXOI8e9/h717zbbH6elw550QGhro6pq9qqtAKACLiIgEJ8tOh6gsOjoaMC+WS09P56GHHqpxX8MwMAzD4yK2ykaNGsXgwYM9bhs6dCijRo3i6quv9l3R9fHhh3D11bBzp9n2eMoUuO8+cyRYAq66ZdACcRGciIiINFxAQ/DBgwfZvHmze3vr1q1kZGTQrl07EhISePPNN4mJiSEhIYHvv/+em2++mYsvvpghQ4YAsGXLFpYsWcKQIUOIiYlh586dzJgxg5YtW3Leeee5j9u9e3emT5/OJZdcQvv27Wnfvr1HHXa7nbi4OE444QT/PPGqiorMwPvss+a22h5bjtYBFhERaVoCGoLT09M5++yz3dsVF56NGTOG+fPns2vXLm677TZ2797N0UcfzejRo5k2bZp7//DwcD777DNmzZrF/v37OeqooxgwYABffPGFxwTqn3/+mTyrDtlVbXt8ww3w+OPq+mYhCsAiIiJNT0BD8KBBgzAMo8b7J02aVOsKDh07duT9998/4nlqOwfAtm3bjngMn3M64aGH4JFHzK5vHTvCK6+o65vFKACLiIg0TUExJ7jJ+fFHc/T322/N7SuvhOeeU9c3i1EAFhERabosvTpEk1NeDk88YbY9/vZbtT22MAVgERGRpk0jwf6ybRuMGQNpaeb2sGHw8svmNAixFAVgERGRpk8jwY3NMMy5vr17mwE4MhJefBHee08B2IIUgEVERJoHjQQ3pt27zbbHy5eb22ecAa++ComJga1LqqUALCIi0nxoJLixVLQ9Xr7cbHbx6KPw6acKwBalACwiItK8aCTY1w4cgEmTYOFCczspyfz/pKSAliU1UwAWERFpfjQS7EsffmjO/V240Gx7PHUqfP21ArCFKQCLiIg0TxoJ9oWqbY8TE822x/37B7YuqZUCsIiISPOlkeCGSk+Hk076MwDfcANkZCgAW5wCsIiISPOmkeCGSklR2+MgowAsIiIiGgluKJcLRoyA779XAA4CCsAiIiICGgluuFdegauvDnQV4gUFYBEREamgkeCGuvTSQFcgXlAAFhERkcoUgqXJUwAWERGRqhSCpUlTABYREZHqKARLk6UA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TqeysrJUWlqq48ePa+PGjcrMzFRCQoJeeOEFt/137NihV155RRUVFSooKNBbb72lvLw8Sdc/3aGwsFAHDx7U0aNH9eabb8putyslJUWpqanKzs7WlClT9M477+jYsWN6//339dJLL2nDhg23zJmdna1//vOfeuGFF/S9731PERERrud69+6tzZs36x//+IfKy8v1xBNP6PTp026v7969u3bv3q2PP/5Y//nPfxpduZ09e7a2bt2qBQsWqKKiQr///e/12muvac6cOa25tADgM5RgAGih3r17a8+ePbr99ts1fvx49ezZU48//rgeeOAB7dy5U126dHHbf/bs2dqzZ4/uvvtuPf/881q8eLGysrIkXf+c29dff11Dhw7VnXfeqS1btmj9+vXq2rWrpOu/DGLKlCmaPXu2+vTpo3HjxumDDz5QcnLyLXP26tVL9913n/bv3+92K4QkPf300xo4cKCysrJ0//33Ky4uTuPGjXPbZ86cOQoNDVVaWppiYmIavV944MCB+tOf/qTVq1fr61//up555hk999xzmjp1aguu6PVfzNHS1wBAW9hMS97dAQCAF6SkpOgXv/hFi4qwzWZTcXFxg/IuXS/Vd911V7v6ldUAPIuVYACAX3344YdyOByaMmVKi187ceJEJSYmuh6vXLlSnTt31t/+9jdPRgTQDrESDAAISIcPH5YkhYaGqkePHpKu/3a+G/c2R0dH66tf/arf8gGwNkowAAAAgg63QwAAACDoUIIBAAAQdCjBAAAACDqUYAAAAAQdSjAAAACCDiUYAAAAQYcSDAAAgKBDCQYAAEDQ+T/0xovxi9dvUwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" ] + }, + "metadata": {}, + "output_type": "display_data" }, { - "cell_type": "code", - "execution_count": 19, - "id": "752261bf", - "metadata": {}, - "outputs": [], - "source": [ - "sensor_df = pd.concat(real_sensors, axis=1)" + "data": { + "image/png": "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", + "text/plain": [ + "
" ] - }, + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cmp = ms.match(single_obs, network_model)\n", + "cmp.plot()\n", + "cmp.plot.timeseries();" + ] + }, + { + "cell_type": "markdown", + "id": "02e77cf0", + "metadata": {}, + "source": [ + "## Multiple sensors\n", + "\n", + "When you have observations at several nodes you can use `NodeObservation.from_multiple()` to create a list of `NodeObservation` objects. Pass `nodes` as a `dict` mapping each node ID to either a column name/index within a shared `data` source, or to a separate data source entirely:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "752261bf", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.765128Z", + "iopub.status.busy": "2026-08-25T14:20:05.764941Z", + "iopub.status.idle": "2026-08-25T14:20:05.775259Z", + "shell.execute_reply": "2026-08-25T14:20:05.772228Z" + } + }, + "outputs": [], + "source": [ + "sensor_df = pd.concat(real_sensors, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "9acfaf6f", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:05.781391Z", + "iopub.status.busy": "2026-08-25T14:20:05.781041Z", + "iopub.status.idle": "2026-08-25T14:20:06.015467Z", + "shell.execute_reply": "2026-08-25T14:20:06.014152Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 20, - "id": "9acfaf6f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nbiasrmseurmsemaeccsir2
observation
water_level@sens11100.0008440.0989450.0989410.0760150.9749860.0005090.950559
water_level@sens2800.0072410.0972850.0970150.0777890.8507820.0005010.721882
water_level@sens389-0.0208130.1046320.1025410.0821040.9360940.0005290.871119
\n", - "
" - ], - "text/plain": [ - " n bias rmse urmse mae cc \\\n", - "observation \n", - "water_level@sens1 110 0.000844 0.098945 0.098941 0.076015 0.974986 \n", - "water_level@sens2 80 0.007241 0.097285 0.097015 0.077789 0.850782 \n", - "water_level@sens3 89 -0.020813 0.104632 0.102541 0.082104 0.936094 \n", - "\n", - " si r2 \n", - "observation \n", - "water_level@sens1 0.000509 0.950559 \n", - "water_level@sens2 0.000501 0.721882 \n", - "water_level@sens3 0.000529 0.871119 " - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nbiasrmseurmsemaeccsir2
observation
water_level@sens11100.0058920.1035770.1034090.0807410.9774310.0005310.955162
water_level@sens2790.0112470.1060830.1054850.0825450.8516500.0005450.720208
water_level@sens389-0.0238980.1026050.0997830.0864510.1610080.000509-0.056709
\n", + "
" ], - "source": [ - "multi_obs = ms.NodeObservation.from_multiple(data=sensor_df, nodes={30: \"water_level@sens1\", 54: \"water_level@sens2\", 71: \"water_level@sens3\"})\n", - "ms.match(multi_obs, network_model).skill()" + "text/plain": [ + " n bias rmse urmse mae cc \\\n", + "observation \n", + "water_level@sens1 110 0.005892 0.103577 0.103409 0.080741 0.977431 \n", + "water_level@sens2 79 0.011247 0.106083 0.105485 0.082545 0.851650 \n", + "water_level@sens3 89 -0.023898 0.102605 0.099783 0.086451 0.161008 \n", + "\n", + " si r2 \n", + "observation \n", + "water_level@sens1 0.000531 0.955162 \n", + "water_level@sens2 0.000545 0.720208 \n", + "water_level@sens3 0.000509 -0.056709 " ] - }, + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "multi_obs = ms.NodeObservation.from_multiple(data=sensor_df, nodes=dict(zip(sensor_locations, sensor_df.columns)))\n", + "ms.match(multi_obs, network_model).skill()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "d7a0acf1", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-25T14:20:06.018707Z", + "iopub.status.busy": "2026-08-25T14:20:06.018293Z", + "iopub.status.idle": "2026-08-25T14:20:06.126797Z", + "shell.execute_reply": "2026-08-25T14:20:06.124201Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 21, - "id": "d7a0acf1", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nbiasrmseurmsemaeccsir2
observation
water_level@sens11100.0008440.0989450.0989410.0760150.9749860.0005090.950559
network_sensor_2800.0072410.0972850.0970150.0777890.8507820.0005010.721882
water_level@sens389-0.0208130.1046320.1025410.0821040.9360940.0005290.871119
\n", - "
" - ], - "text/plain": [ - " n bias rmse urmse mae cc \\\n", - "observation \n", - "water_level@sens1 110 0.000844 0.098945 0.098941 0.076015 0.974986 \n", - "network_sensor_2 80 0.007241 0.097285 0.097015 0.077789 0.850782 \n", - "water_level@sens3 89 -0.020813 0.104632 0.102541 0.082104 0.936094 \n", - "\n", - " si r2 \n", - "observation \n", - "water_level@sens1 0.000509 0.950559 \n", - "network_sensor_2 0.000501 0.721882 \n", - "water_level@sens3 0.000529 0.871119 " - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nbiasrmseurmsemaeccsir2
observation
water_level@sens11100.0058920.1035770.1034090.0807410.9774310.0005310.955162
network_sensor_2790.0112470.1060830.1054850.0825450.8516500.0005450.720208
water_level@sens389-0.0238980.1026050.0997830.0864510.1610080.000509-0.056709
\n", + "
" ], - "source": [ - "multi_obs = ms.NodeObservation.from_multiple(nodes={30: sensor_1, 54: path_to_sensor2, 71: sensor_3})\n", - "ms.match(multi_obs, network_model).skill()" + "text/plain": [ + " n bias rmse urmse mae cc \\\n", + "observation \n", + "water_level@sens1 110 0.005892 0.103577 0.103409 0.080741 0.977431 \n", + "network_sensor_2 79 0.011247 0.106083 0.105485 0.082545 0.851650 \n", + "water_level@sens3 89 -0.023898 0.102605 0.099783 0.086451 0.161008 \n", + "\n", + " si r2 \n", + "observation \n", + "water_level@sens1 0.000531 0.955162 \n", + "network_sensor_2 0.000545 0.720208 \n", + "water_level@sens3 0.000509 -0.056709 " ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" } - ], - "metadata": { - "kernelspec": { - "display_name": "modelskill (3.13.13)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.13" - } + ], + "source": [ + "multi_obs = ms.NodeObservation.from_multiple(nodes=dict(zip(sensor_locations, [sensor_1, path_to_sensor2, sensor_3])))\n", + "ms.match(multi_obs, network_model).skill()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "modelskill (3.13.13)", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 5 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 } diff --git a/pyproject.toml b/pyproject.toml index 890fc7574..e33d442ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,9 @@ classifiers = [ ] [project.optional-dependencies] -networks = ["mikeio1d", "networkx"] +# networkx and xarray arrive through mikeio1d's own network extra, which +# carries the topology layer this package builds on (ADR-013). +network = ["mikeio1d[network]"] [dependency-groups] dev = ["pytest", "plotly >= 4.5", "ruff==0.6.2", "netCDF4", "dask"] @@ -62,7 +64,12 @@ test = [ notebooks = ["nbformat", "nbconvert", "jupyter", "plotly", "shapely", "seaborn"] -networks = ["mikeio1d>=1.2.1", "networkx"] +network = ["mikeio1d[network]"] + +[tool.uv.sources] +# TODO: swap for a version floor in both "network" entries above once mikeio1d +# releases the network module. ADR-013 holds modelskill 1.4.0 until it does. +mikeio1d = { git = "https://github.com/DHI/mikeio1d", branch = "main" } [project.urls] "Homepage" = "https://github.com/DHI/modelskill" diff --git a/roadmap/features/network-models.md b/roadmap/features/network-models.md index 2190befb9..246c8ad75 100644 --- a/roadmap/features/network-models.md +++ b/roadmap/features/network-models.md @@ -26,3 +26,5 @@ In active development. MIKE 1D, MIKE 11 and EPANET result files can be read toda MOUSE and Water Hammer results are not read yet: no shareable result file exists for either format, so support cannot be verified. SWMM results are not read yet: the reach connectivity lives in the companion '.inp' input file, which modelskill does not read yet. +The layer that reads those files and builds the network lives in mikeio1d, where the formats, the fixtures and a first graph conversion already were (ADR-013). ModelSkill keeps the model result, the observations and the matching, and requires `mikeio1d[network]`. The release is coordinated: this feature ships once mikeio1d has released the module it depends on. + diff --git a/src/modelskill/comparison/_comparison.py b/src/modelskill/comparison/_comparison.py index 8838184e5..4e3c6fe05 100644 --- a/src/modelskill/comparison/_comparison.py +++ b/src/modelskill/comparison/_comparison.py @@ -26,9 +26,22 @@ from .. import metrics as mtr from .. import Quantity from ..types import GeometryType -from ..obs import PointObservation, TrackObservation, NodeObservation +from ..obs import ( + PointObservation, + TrackObservation, + NodeObservation, + ReachObservation, +) from ..model import PointModelResult, TrackModelResult, VerticalModelResult -from ..timeseries._timeseries import _normalize_time_to_ns, _validate_data_var_name +from ..timeseries._coords import ( + NETWORK_LOCATION_COORDS, + _coordinate_values, + network_location, +) +from ..timeseries._timeseries import ( + _normalize_time_to_ns, + _validate_data_var_name, +) from ._comparer_plotter import ComparerPlotter from ..metrics import _parse_metric @@ -54,7 +67,7 @@ def _drop_scalar_coords(data: xr.Dataset) -> xr.Dataset: """Drop scalar coordinate variables that shouldn't appear as columns in dataframes""" - coords_to_drop = ["x", "y", "z", "node"] + coords_to_drop = ["x", "y", "z", *NETWORK_LOCATION_COORDS] return data.drop_vars(coords_to_drop, errors="ignore") @@ -72,8 +85,8 @@ def _parse_dataset(data: xr.Dataset) -> xr.Dataset: # coordinates # Only add x, y, z coordinates if they don't exist and we don't have node coordinates - has_node_coords = "node" in data.coords - if not has_node_coords: + has_network_coords = GeometryType.from_network_coords(data) is not None + if not has_network_coords: if "x" not in data.coords: data.coords["x"] = np.nan if "y" not in data.coords: @@ -112,10 +125,9 @@ def _parse_dataset(data: xr.Dataset) -> xr.Dataset: # Validate attrs if "gtype" not in data.attrs: # Determine gtype based on available coordinates - if "node" in data.coords: - data.attrs["gtype"] = str(GeometryType.NODE) - else: - data.attrs["gtype"] = str(GeometryType.POINT) + data.attrs["gtype"] = str( + GeometryType.from_network_coords(data) or GeometryType.POINT + ) # assert "gtype" in data.attrs, "data must have a gtype attribute" # assert data.attrs["gtype"] in [ # str(GeometryType.POINT), @@ -642,15 +654,27 @@ def z(self) -> Any: @property def node(self) -> Any: - """node-coordinate""" + """Name of the node this comparer sits at""" return self._coordinate_values("node") - def _coordinate_values(self, coord: str) -> None | Any: + @property + def reach(self) -> Any: + """Name of the reach this comparer sits on""" + return self._coordinate_values("reach") + + @property + def distance(self) -> Any: + """along-reach distance of a breakpoint""" + return self._coordinate_values("distance") + + @property + def _at(self) -> Any: + """Where this comparer sits, in the form NodeObservation.at takes""" + return network_location(self.data) + + def _coordinate_values(self, coord: str) -> Any: """Get coordinate values if they exist, otherwise return None""" - if coord not in self.data.coords: - return None - vals = self.data[coord].values - return np.atleast_1d(vals)[0] if vals.ndim == 0 else vals + return _coordinate_values(self.data, coord) @property def n_models(self) -> int: @@ -773,7 +797,9 @@ def rename( return Comparer(matched_data=data, raw_mod_data=raw_mod_data) - def _to_observation(self) -> PointObservation | TrackObservation | NodeObservation: + def _to_observation( + self, + ) -> PointObservation | TrackObservation | NodeObservation | ReachObservation: """Convert to Observation""" if self.gtype == "point": df = _drop_scalar_coords(self.data)[self._obs_str].to_dataframe() @@ -804,7 +830,16 @@ def _to_observation(self) -> PointObservation | TrackObservation | NodeObservati return NodeObservation( data=df, name=self.name, - at=self.node, + at=self._at, + quantity=self.quantity, + # TODO: add attrs + ) + elif self.gtype == "reach": + df = _drop_scalar_coords(self.data)[self._obs_str].to_dataframe() + return ReachObservation( + data=df, + name=self.name, + reach=self.reach, quantity=self.quantity, # TODO: add attrs ) @@ -1012,9 +1047,9 @@ def _to_long_dataframe( """Return a copy of the data as a long-format pandas DataFrame (for groupby operations)""" if self.gtype == "vertical": - data = self.data.drop_vars("node", errors="ignore") + data = self.data.drop_vars(NETWORK_LOCATION_COORDS, errors="ignore") else: - data = self.data.drop_vars(["z", "node"], errors="ignore") + data = self.data.drop_vars(["z", *NETWORK_LOCATION_COORDS], errors="ignore") # this step is necessary since we keep arbitrary derived data in the dataset, but not z/node # i.e. using a hardcoded whitelist of variables to keep is less flexible @@ -1338,8 +1373,9 @@ def to_dataframe(self) -> pd.DataFrame: + ["z"] ) return df[cols] - elif self.gtype == str(GeometryType.NODE): - # For network data, drop node coordinate like other geometries drop their coordinates + elif self.gtype in (str(GeometryType.NODE), str(GeometryType.REACH)): + # For network data, drop the location coordinates like other geometries + # drop theirs return _drop_scalar_coords(self.data).to_dataframe() else: raise NotImplementedError(f"Unknown gtype: {self.gtype}") @@ -1361,7 +1397,7 @@ def save(self, filename: Union[str, Path]) -> None: # https://docs.xarray.dev/en/stable/user-guide/io.html#groups # There is no need to save raw data for track data, since it is identical to the matched data - if self.gtype in ("point", "node"): + if self.gtype in ("point", "node", "reach"): ds = self.data.copy() # copy needed to avoid modifying self.data for key, ts_mod in self.raw_mod_data.items(): @@ -1396,7 +1432,7 @@ def load(filename: Union[str, Path]) -> "Comparer": # FIXME: consider during Phase3 return Comparer(matched_data=data) - if data.gtype in ("point", "node"): + if data.gtype in ("point", "node", "reach"): raw_mod_data: Dict[ str, PointModelResult @@ -1413,10 +1449,8 @@ def load(filename: Union[str, Path]) -> "Comparer": {"_time_raw_" + new_key: "time", var_name: new_key} ) ts: PointModelResult | NodeModelResult - if data.gtype == "node": - ts = NodeModelResult( - data=ds, node=int(ds.coords["node"].item()), name=new_key - ) + if data.gtype in ("node", "reach"): + ts = NodeModelResult(data=ds, name=new_key) else: ts = PointModelResult(data=ds, name=new_key) diff --git a/src/modelskill/model/adapters/__init__.py b/src/modelskill/model/adapters/__init__.py deleted file mode 100644 index 33ad255b1..000000000 --- a/src/modelskill/model/adapters/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Network format adapters.""" diff --git a/src/modelskill/model/adapters/_inp.py b/src/modelskill/model/adapters/_inp.py deleted file mode 100644 index 329b2c92a..000000000 --- a/src/modelskill/model/adapters/_inp.py +++ /dev/null @@ -1,109 +0,0 @@ -"""Minimal reader for EPANET and SWMM ``.inp`` input files. - -mikeio1d reads only the binary result formats, so the ``.inp`` that accompanies a -result file has to be parsed here. Both products use the same layout: bracketed -section headers, ``;``-prefixed comments (including the ``;;Name Node1 ...`` -column headers the products write), whitespace-delimited data rows, and blank -lines to ignore. - -Only the sections modelskill needs are interpreted; everything else is kept as -raw fields for a caller to use, or ignored. -""" - -from __future__ import annotations - -from pathlib import Path - - -def read_sections(path: str | Path) -> dict[str, list[list[str]]]: - """Parse an ``.inp`` file into its sections. - - Parameters - ---------- - path : str or Path - Path to an EPANET or SWMM ``.inp`` file. - - Returns - ------- - dict[str, list[list[str]]] - Section name (upper case, without brackets) mapped to its data rows, - each row split into whitespace-delimited fields. Comment-only and blank - lines are dropped, as is any trailing comment on a data row. - - Examples - -------- - >>> sections = read_sections("model.inp") # doctest: +SKIP - >>> sections["PIPES"][0] # doctest: +SKIP - ['10', '10', '11', '3209.544', '304.8', '100', '0', 'Open'] - """ - sections: dict[str, list[list[str]]] = {} - current: list[list[str]] | None = None - - with open(path, "r", encoding="utf-8", errors="replace") as f: - for line in f: - # A comment can trail a data row, so strip it before anything else. - line = line.split(";", 1)[0].strip() - if not line: - continue - - if line.startswith("["): - name = line.strip("[]").strip().upper() - current = sections.setdefault(name, []) - continue - - if current is not None: - current.append(line.split()) - - return sections - - -def read_pipe_lengths(path: str | Path) -> dict[str, float]: - """Read reach lengths from the ``[PIPES]`` section of an EPANET ``.inp``. - - Parameters - ---------- - path : str or Path - Path to an EPANET ``.inp`` file. - - Returns - ------- - dict[str, float] - Pipe ID mapped to its length. Pumps and valves are links too, but carry - no length, so they are absent from the result rather than present with a - placeholder. - - Raises - ------ - ValueError - If the file has no ``[PIPES]`` section, or a row there has too few - fields to read a length from. - - Notes - ----- - ``[PIPES]`` rows are ``ID Node1 Node2 Length Diameter Roughness ...``, so the - length is the fourth field. The units are whatever the model declares in - ``[OPTIONS]``; no conversion is applied. - """ - sections = read_sections(path) - - try: - rows = sections["PIPES"] - except KeyError: - raise ValueError( - f"'{path}' has no [PIPES] section, so it does not look like an " - "EPANET input file. Available sections: " - f"{sorted(sections)}." - ) - - _ID, _LENGTH = 0, 3 - lengths: dict[str, float] = {} - for row in rows: - if len(row) <= _LENGTH: - raise ValueError( - f"Cannot read a pipe length from [PIPES] row {' '.join(row)!r} " - f"in '{path}': expected at least {_LENGTH + 1} fields " - f"(ID, Node1, Node2, Length), got {len(row)}." - ) - lengths[row[_ID]] = float(row[_LENGTH]) - - return lengths diff --git a/src/modelskill/model/adapters/_res1d.py b/src/modelskill/model/adapters/_res1d.py deleted file mode 100644 index 567f0d498..000000000 --- a/src/modelskill/model/adapters/_res1d.py +++ /dev/null @@ -1,189 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -import pandas as pd - -if TYPE_CHECKING: - from mikeio1d.result_network import ResultNode, ResultGridPoint, ResultReach - -from modelskill.network import NetworkNode, ReachBreakPoint, NetworkReach - - -def _simplify_colnames(node: ResultNode | ResultGridPoint) -> pd.DataFrame: - # We remove suffixes and indexes so the columns contain only the quantity names - - # Some formats keep no timeseries at all on some locations - MIKE 11, for instance, - # stores everything on reach gridpoints, leaving the nodes empty. Asking mikeio1d - # for a dataframe there raises, so return an empty one instead. - if not node.quantities: - return pd.DataFrame() - - # The columns in a Res1D dataframe follow the convention "Quantity:Location:Sublocation" - # where Location refers to the node id or the reach id followed by the chainage. - RES1D_NAME_SEP = ":" - df = node.to_dataframe() - renamer_dict = {} - for quantity in node.quantities: - column_pairs = [ - (col, quantity) - for col in df.columns - if quantity in col.split(RES1D_NAME_SEP) - ] - if len(column_pairs) != 1: - raise ValueError( - f"There must be exactly one column per quantity, found {column_pairs}." - ) - old_name, new_name = column_pairs[0] - renamer_dict[old_name] = new_name - return df.rename(columns=renamer_dict).copy() - - -def _merge_extra_quantities( - base: pd.DataFrame, extra: pd.DataFrame, *, node_id: str -) -> pd.DataFrame: - """Append a companion file's quantities to a node's frame as extra columns. - - Parameters - ---------- - base : pd.DataFrame - The node's frame from the main result file. - extra : pd.DataFrame - The same node's frame from the companion file, sharing its time index. - node_id : str - Node ID, used in error messages. - - Returns - ------- - pd.DataFrame - - Raises - ------ - ValueError - If a quantity appears in both frames. Concatenating would give the node - two columns of the same name, which is the state ``_simplify_colnames`` - already refuses. - """ - if extra.empty: - return base - - overlapping = base.columns.intersection(extra.columns) - if len(overlapping) > 0: - raise ValueError( - f"Node {node_id!r} already has {sorted(overlapping)} in the main " - "result file, so the companion file's copy cannot be merged in." - ) - - return pd.concat([base, extra], axis=1) - - -class Res1DNode(NetworkNode): - def __init__( - self, - id: str, - *, - data: pd.DataFrame | None = None, - boundary: dict[str, pd.DataFrame] | None = None, - ): - self._id = id - self._data = pd.DataFrame() if data is None else data - self._boundary = {} if boundary is None else boundary - - @property - def id(self) -> str: - return self._id - - @property - def data(self) -> pd.DataFrame: - return self._data - - @property - def boundary(self) -> dict[str, pd.DataFrame]: - return self._boundary - - -class GridPoint(ReachBreakPoint): - def __init__( - self, reach_id: str, chainage: float, data: pd.DataFrame | None = None - ): - self._id = (reach_id, chainage) - self._data = pd.DataFrame() if data is None else data - - @property - def id(self) -> tuple[str, float]: - return self._id - - @property - def data(self) -> pd.DataFrame: - return self._data - - -class Res1DReach(NetworkReach): - """NetworkReach adapter for a mikeio1d ResultReach.""" - - def __init__( - self, - reach: ResultReach, - start_node: Res1DNode, - end_node: Res1DNode, - *, - populate_gridpoints: bool = True, - length: float | None = None, - ): - self._id = reach.name - - # Must be checked separately: some formats (.resx) report None for both the - # reach and the node, which the identity checks below would let through. - if reach.start_node is None or reach.end_node is None: - raise ValueError( - f"mikeio1d reported no start/end node for reach {reach.name!r}; " - "this result format's topology cannot be represented as a Network." - ) - - if start_node.id != reach.start_node: - raise ValueError("Incorrect starting node.") - if end_node.id != reach.end_node: - raise ValueError("Incorrect ending node.") - - intermediate_gridpoints = ( - reach.gridpoints[1:-1] if len(reach.gridpoints) > 2 else [] - ) - - self._start = start_node - self._end = end_node - - # A length read from a companion input file wins, since mikeio1d has none - # to offer for the formats that need one. Otherwise: mikeio1d returns 0 - # when it cannot read a reach length - link-node models such as EPANET - # report this for every reach. Report it as undefined rather than as a - # zero-length reach, which would make length-weighted graph algorithms - # treat the reach as free. The two cases cannot be told apart upstream. - self._length = length if length is not None else (reach.length or None) - self._breakpoints: list[ReachBreakPoint] = [ - GridPoint( - gridpoint.reach_name, - gridpoint.chainage, - _simplify_colnames(gridpoint) if populate_gridpoints else None, - ) - for gridpoint in intermediate_gridpoints - ] - - @property - def id(self) -> str: - return self._id - - @property - def start(self) -> Res1DNode: - return self._start - - @property - def end(self) -> Res1DNode: - return self._end - - @property - def length(self) -> float | None: - return self._length - - @property - def breakpoints(self) -> list[ReachBreakPoint]: - return self._breakpoints diff --git a/src/modelskill/model/network.py b/src/modelskill/model/network.py index 328c1cdea..5c57547ac 100644 --- a/src/modelskill/model/network.py +++ b/src/modelskill/model/network.py @@ -1,20 +1,38 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Sequence +from pathlib import Path +from typing import TYPE_CHECKING, Any, Sequence import numpy as np -import numpy.typing as npt import pandas as pd import xarray as xr -from modelskill.timeseries import TimeSeries, _parse_network_node_input +from modelskill.timeseries import ( + TimeSeries, + _parse_network_breakpoint_input, + _parse_network_node_input, +) from ._base import SelectedItems from ..obs import NodeObservation, ReachObservation +from ..timeseries._coords import network_location from ..quantity import Quantity -from ..types import PointType +from ..types import GeometryType, PointType if TYPE_CHECKING: - from modelskill.network import Network + from mikeio1d.network import Network + + +def _network_class() -> type[Network]: + # Imported here, not at module scope, so this module stays importable + # without the optional network dependencies (ADR-010). + try: + from mikeio1d.network import Network + except ImportError as err: + raise ImportError( + "NetworkModelResult needs the network topology layer from mikeio1d, " + "which the 'network' extra installs: pip install modelskill[network]" + ) from err + return Network class NodeModelResult(TimeSeries): @@ -30,8 +48,13 @@ class NodeModelResult(TimeSeries): name : str, optional The name of the model result, by default None (will be set to file name or item name) - node : int, optional - node ID (integer), by default None + node : str or tuple[str, float], optional + Where the data sits: a node name, or a break point as + ``(reach_id, distance)``. By default None, which requires data that + already carries a ``node`` or ``reach`` coordinate. + node_index : int, optional + The integer the network used for this location, recorded as provenance. + Nothing reads it back, by default None item : str | int | None, optional If multiple items/arrays are present in the input an item must be given (as either an index or a string), by default None @@ -43,62 +66,98 @@ class NodeModelResult(TimeSeries): Examples -------- >>> import modelskill as ms - >>> mr = ms.NodeModelResult(data, node=123, name="Node_123") - >>> mr2 = ms.NodeModelResult(df, item="Water Level", node=456) + >>> mr = ms.NodeModelResult(data, node="123", name="Node_123") + >>> mr2 = ms.NodeModelResult(df, item="Water Level", node=("r1", 24.5)) """ def __init__( self, data: PointType, - node: int, + node: str | tuple[str, float | None] | None = None, *, + node_index: int | None = None, name: str | None = None, item: str | int | None = None, quantity: Quantity | None = None, aux_items: Sequence[int | str] | None = None, ): if not self._is_input_validated(data): - data = _parse_network_node_input( - data, - name=name, - item=item, - quantity=quantity, - node=node, - aux_items=aux_items, - ) + if isinstance(node, tuple): + reach, distance = node + data = _parse_network_breakpoint_input( + data, + name=name, + item=item, + quantity=quantity, + aux_items=aux_items, + reach=reach, + distance=distance, + ) + elif node is not None: + data = _parse_network_node_input( + data, + name=name, + item=item, + quantity=quantity, + node=node, + aux_items=aux_items, + ) + else: + raise ValueError( + "'NodeModelResult' needs a node name or a (reach, distance) " + "pair when the data does not already carry its location" + ) if not isinstance(data, xr.Dataset): raise ValueError("'NodeModelResult' requires xarray.Dataset") - if data.coords.get("node") is None: - raise ValueError("'node' coordinate not found in data") + if GeometryType.from_network_coords(data) is None: + raise ValueError( + "'NodeModelResult' needs a node name, a (reach, distance) pair, or " + "data that already carries a 'node' or 'reach' coordinate" + ) + if node_index is not None: + data = data.assign_coords(node_index=int(node_index)) data_var = str(list(data.data_vars)[0]) data[data_var].attrs["kind"] = "model" super().__init__(data=data) @property - def node(self) -> int: - """Node ID of model result""" - node_val = self.data.coords["node"] - return int(node_val.item()) + def node(self) -> Any: + """Where this result was extracted, as its network named it.""" + return network_location(self.data) + + def _location_repr(self) -> str | None: + return f"Location: {self.node}" + + @property + def node_index(self) -> int | None: + """Graph integer this location had in the network it came from, if recorded. + + Provenance only. Nothing reads it back: the numbering belongs to one + network built by one version, so a saved result is identified by + :attr:`node` instead. + """ + if "node_index" not in self.data.coords: + return None + return int(np.atleast_1d(self.data.coords["node_index"].values)[0]) def _create_new_instance(self, data: xr.Dataset) -> NodeModelResult: - """Extract node from data and create new instance""" - node = int(data.coords["node"].item()) - return self.__class__(data, node=node) + """Create a new instance; the location already travels in the coords.""" + return self.__class__(data) class NetworkModelResult: """Model result for network data with time and node dimensions. - Construct a NetworkModelResult from a Network object containing - timeseries data for each node. Users must provide exact node IDs - (integers obtained via ``Network.find()``) when creating observations — - no spatial interpolation is performed. + Construct one from a result file, or from a :class:`mikeio1d.network.Network` + already built. Observations name the location they sit at, and no spatial + interpolation is performed. Parameters ---------- - data : Network - Network-like object with a ``to_dataset()`` method (e.g. :class:`modelskill.network.Network`). + data : Network, str or Path + Path to a ``.res1d``, ``.res11`` or ``.res`` result file, or a + :class:`mikeio1d.network.Network`. name : str, optional The name of the model result, by default None (will be set to first data variable name) @@ -113,23 +172,46 @@ class NetworkModelResult: Examples -------- >>> import modelskill as ms - >>> from modelskill.network import Network - >>> network = Network(reaches) # reaches is a list[NetworkReach] - >>> mr = ms.NetworkModelResult(network, name="MyModel") - >>> obs = ms.NodeObservation(data, node=network.find(node="node_A")) + >>> mr = ms.NetworkModelResult("model.res1d", item="WaterLevel") + >>> obs = ms.NodeObservation(data, at="node_A") >>> extracted = mr.extract(obs) + + Open the network yourself to name EPANET companion files, or to keep memory + down on a large model by reading only the locations you will score: + + >>> from mikeio1d.network import Network + >>> network = Network.open("model.res1d", nodes=["node_A", "node_B"]) + >>> mr = ms.NetworkModelResult(network, name="MyModel") + + Notes + ----- + The network is used as given, not copied, so ``mr.network`` is the caller's + object. + + See Also + -------- + mikeio1d.network.Network.open : Read a network from a result file. """ def __init__( self, - data: Network, + data: Network | str | Path, *, name: str | None = None, item: str | int | None = None, quantity: Quantity | None = None, aux_items: Sequence[int | str] | None = None, ): - self.network = data.copy() + network_class = _network_class() + if isinstance(data, (str, Path)): + self.network = network_class.open(data) + elif isinstance(data, network_class): + self.network = data + else: + raise TypeError( + "NetworkModelResult takes a mikeio1d.network.Network or a path to a " + f"result file, got {type(data).__name__}" + ) ds = self.network.to_dataset() sel_items = SelectedItems.parse( @@ -142,8 +224,16 @@ def __init__( self.sel_items = sel_items if quantity is None: - da = self.data[sel_items.values] - quantity = Quantity.from_cf_attrs(da.attrs) + # Read straight off the attributes rather than through + # Quantity.from_cf_attrs, which needs a unit as well as a name and + # reports neither without both: a result file names its quantity and + # carries no unit for it, so that would report nothing at all. A unit + # is still used if one ever travels with the data. + attrs = self.data[sel_items.values].attrs + quantity = Quantity( + name=attrs.get("long_name") or str(sel_items.values), + unit=attrs.get("units", ""), + ) self.quantity = quantity # Mark data variables as model data @@ -152,18 +242,16 @@ def __init__( def __repr__(self) -> str: return f"<{self.__class__.__name__}>: {self.name}" - _CHAINAGE_TOLERANCE = 1e-3 # Tolerance in source-network distance units (e.g., meters if chainage is in meters). + #: Coordinates mikeio1d puts on to_dataset() to say what each column is. They + #: are re-applied through NodeModelResult, which knows modelskill's names for + #: them, so they never reach a comparer under these. + _UPSTREAM_IDENTITY_COORDS = ("name", "reach", "distance") @property def time(self) -> pd.DatetimeIndex: """Return the time coordinate as a pandas.DatetimeIndex.""" return pd.DatetimeIndex(self.data.time.to_index()) - @property - def nodes(self) -> npt.NDArray[np.intp]: - """Return the node IDs as a numpy array of integers.""" - return self.data.node.values - def extract( self, observation: NodeObservation | ReachObservation, @@ -173,7 +261,7 @@ def extract( Parameters ---------- observation : NodeObservation or ReachObservation - observation with node ID or reach ID + observation naming a node, a breakpoint, or a reach Returns ------- @@ -192,134 +280,108 @@ def extract( def _extract_node(self, observation: NodeObservation) -> NodeModelResult: node_id = self._resolve_alias(observation.at) - available_nodes = set(self.data.node.values) - if node_id not in available_nodes: + if node_id not in self.data.indexes["node"]: raise ValueError( - f"Node {node_id} exists in the network topology but its timeseries was not loaded. " - f"Re-create the NetworkModelResult with the relevant nodes populated, " - f"e.g. Network.from_mike(path, nodes=[...])." + f"{observation.at!r} exists in the network topology but its " + "timeseries was not loaded. Re-create the NetworkModelResult with " + "the relevant nodes populated, e.g. " + "NetworkModelResult(Network.open(path, nodes=[...]))." ) - return NodeModelResult( - data=self.data.sel(node=node_id).drop_vars("node"), - node=node_id, - name=self.name, - item=self.sel_items.values, - quantity=self.quantity, - aux_items=self.sel_items.aux, - ) - - def _extract_reach(self, observation: ReachObservation) -> NodeModelResult: - # Extract model result from an arbitrary breakpoint belonging to the reach. + # A location that carries no data for this quantity is all-NaN here, just + # as it is on the reach path: MIKE 1D stores quantities at different grid + # points, so a breakpoint carrying Discharge may carry no WaterLevel. + item = self.sel_items.values + if not bool(self.data[item].sel(node=node_id).notnull().any()): + raise ValueError( + f"{observation.at!r} was found in the network but has no data for " + f"quantity '{item}'. Choose a location that has this quantity, or a " + "model result for a quantity this location has." + ) - # Searches the alias map for breakpoints whose reach component matches - # ``observation.reach``, then returns the first one that has data in the - # dataset. Raises if no breakpoint with data is found or if the quantity - # is not present for any breakpoint of that reach. + return self._as_node_result(node_id) + def _extract_reach(self, observation: ReachObservation) -> NodeModelResult: + # A reach observation matches any breakpoint along the reach, so long as + # they agree. Which breakpoints those are is read off the dataset's own + # coordinates; the network is consulted only to explain a failure. item = self.sel_items.values reach_id = observation.reach - try: - reach = self.network._reaches[reach_id] - except KeyError: + if reach_id not in self.network.reaches: raise ValueError(f"Reach {reach_id} not found in network.") - # This only searches intermediate breakpoints since reach-level data is not - # expected in nodes. - - available_nodes = {int(node_id) for node_id in self.data.node.values} - found_ds = None - found_int_id: int | None = None - missing_node_data = False - for breakpoint in reach.breakpoints: - if breakpoint.data is None: - continue - if item not in breakpoint.data.columns: - continue - - int_id = self.network.find( - reach=breakpoint.id[0], distance=breakpoint.distance - ) - if int_id not in available_nodes: - missing_node_data = True - continue - - ds = self.data.sel(node=int_id).drop_vars("node") - if found_ds is not None: - da1, da2 = xr.align(ds[item], found_ds[item], join="inner") - if not np.allclose(da1.values, da2.values, equal_nan=True): - raise ValueError( - "Not all data in breakpoints are equivalent. " - "Select a specific node instead of the reach." - ) - else: - found_ds = ds - found_int_id = int_id - - if found_ds is not None and found_int_id is not None: - return NodeModelResult( - data=found_ds, - node=found_int_id, - name=self.name, - item=item, - quantity=self.quantity, - aux_items=self.sel_items.aux, - ) - if missing_node_data: + on_reach = np.flatnonzero(self.data["reach"].values == reach_id) + # A location that carries no data for this quantity is all-NaN here, + # since quantities with different coverage are aligned on the way in. + with_data = self.data[item].isel(node=on_reach).notnull().any("time").values + candidates = self.data.isel(node=on_reach[np.flatnonzero(with_data)]) + + if candidates.sizes["node"] == 0: + raise ValueError(self._explain_no_reach_data(reach_id, item)) + + values = candidates[item].transpose("time", "node").values + if not np.allclose(values, values[:, :1], equal_nan=True): raise ValueError( + "Not all data in breakpoints are equivalent. " + "Select a specific node instead of the reach." + ) + + # Lowest distance first, unknown distances last, so the breakpoint chosen + # does not depend on the numbering mikeio1d happened to hand out. + distance = np.nan_to_num(candidates["distance"].values, nan=np.inf) + order = np.lexsort((candidates["node"].values, distance)) + return self._as_node_result(int(candidates["node"].values[order[0]])) + + def _explain_no_reach_data(self, reach_id: str, item: str) -> str: + # Whether the reach has no such data at all, or has it at breakpoints this + # model result did not load, is a distinction only the network can make. + has_source_data = any( + breakpoint.data is not None and item in breakpoint.data.columns + for breakpoint in self.network.reaches[reach_id].breakpoints + ) + if has_source_data: + return ( f"Reach '{reach_id}' has breakpoint data for quantity " f"'{item}', but matching breakpoint nodes are " "missing from the model dataset. Re-create the NetworkModelResult " "with the relevant reaches populated." ) - - raise ValueError( + return ( f"Reach '{reach_id}' was found in the network but none of its " - f"breakpoints have data loaded for quantity '{self.sel_items.values}'. " + f"breakpoints have data loaded for quantity '{item}'. " f"Re-create the NetworkModelResult with the relevant reaches populated." ) - def _resolve_alias(self, alias: int | str | tuple[str, float]) -> int: - # Resolve a node alias to an internal node ID. - - # Breakpoint tuple aliases are matched first by exact key lookup and then - # by reach ID and distance within ``_CHAINAGE_TOLERANCE``. If multiple - # candidates are within tolerance, the closest distance is selected; ties - # are broken by choosing the smallest node ID. Distance units are the - # same as the network chainage units. - - if isinstance(alias, int): - if alias not in self.data.node: - raise ValueError( - f"Node {alias} not found. Available: {list(self.nodes[:5])}..." - ) - return alias - else: - if alias in self.network._alias_map: - return self.network._alias_map[alias] + def _as_node_result(self, node_id: int) -> NodeModelResult: + # The location is taken from the network rather than from the observation, + # so a distance given as 24.5001 is recorded as the network's own 24.5. + where = self.network.recall(int(node_id)) + location = ( + where["node"] if "node" in where else (where["reach"], where["distance"]) + ) + data = self.data.sel(node=node_id).drop_vars( + ("node", *self._UPSTREAM_IDENTITY_COORDS), errors="ignore" + ) + return NodeModelResult( + data=data, + node=location, + node_index=int(node_id), + name=self.name, + item=self.sel_items.values, + quantity=self.quantity, + aux_items=self.sel_items.aux, + ) + def _resolve_alias(self, alias: str | tuple[str, float]) -> int: + # Delegated to Network.find rather than matched against the dataset's own + # name/reach/distance coords: find() searches the whole topology, so a hit + # that is missing from the dataset is a location whose timeseries was not + # loaded, which is a different mistake from one that does not exist. + try: if isinstance(alias, tuple): - # Handle tolerances reach_id, distance = alias - candidates: list[tuple[float, int]] = [] - for key, node_id in self.network._alias_map.items(): - if isinstance(key, tuple) and key[0] == reach_id: - diff = abs(key[1] - distance) - if diff <= self._CHAINAGE_TOLERANCE: - candidates.append((diff, node_id)) - if candidates: - return min( - candidates, key=lambda candidate: (candidate[0], candidate[1]) - )[1] - - available = list(self.network._alias_map.keys())[:5] - if isinstance(alias, tuple): - raise ValueError( - f"Breakpoint {alias} not found in network. " - f"Available aliases (first 5): {available}" - ) - raise ValueError( - f"Node alias '{alias}' not found in network. " - f"Available aliases (first 5): {available}" - ) + return int(self.network.find(reach=str(reach_id), distance=distance)) + return int(self.network.find(node=str(alias))) + except KeyError as err: + raise ValueError(f"Location {alias!r} not found. {err.args[0]}") from err diff --git a/src/modelskill/network.py b/src/modelskill/network.py deleted file mode 100644 index 4487c5809..000000000 --- a/src/modelskill/network.py +++ /dev/null @@ -1,1200 +0,0 @@ -"""Opt-in network module for network model results (e.g. MIKE 1D / res1d). - -Requires the ``networks`` dependency group (networkx, mikeio1d). -Install with:: - - uv sync --group networks - -Import this module explicitly to use network functionality:: - - from modelskill.network import Network - -""" - -from __future__ import annotations - -import sys - -from abc import ABC, abstractmethod -from pathlib import Path -from typing import Any, Sequence, overload, TYPE_CHECKING -from copy import deepcopy - -import networkx as nx -import pandas as pd -import xarray as xr - -if TYPE_CHECKING: - from mikeio1d import Res1D - from mikeio1d.result_network import ResultReach - from .model.adapters._res1d import Res1DReach - - -_MIKE_EXTENSIONS = frozenset({".res1d", ".res11"}) -_EPANET_EXTENSIONS = frozenset({".res"}) - -_NO_FIXTURE = ( - "{product} results are not supported yet: modelskill has no test fixture for " - "this format, so support cannot be verified. Please open an issue if you need it." -) -# A result file that holds timeseries but no topology of its own. The connectivity -# is in a companion file we do not parse yet. -_TOPOLOGY_IN_COMPANION_FILE = ( - "SWMM '.out' files carry no reach connectivity of their own - it lives in the " - "companion '.inp' input file, which modelskill does not read yet. Tracked in " - "https://github.com/DHI/modelskill/issues/689." -) -# A companion result file: readable, but it describes a network defined elsewhere. -_COMPANION_RESULT_FILE = ( - "'.resx' holds extra EPANET results (tank volume, pump energy) for a network " - "defined in the sibling '.res' file, so it has no topology of its own. Read the " - "'.res' file and pass this one alongside it: " - "Network.from_epanet(res, resx=...)." -) - -# extension -> why modelskill will not read it, even though mikeio1d can -_UNSUPPORTED_EXTENSIONS: dict[str, str] = { - ".out": _TOPOLOGY_IN_COMPANION_FILE, - ".resx": _COMPANION_RESULT_FILE, - ".prf": _NO_FIXTURE.format(product="MOUSE"), - ".crf": _NO_FIXTURE.format(product="MOUSE"), - ".xrf": _NO_FIXTURE.format(product="MOUSE"), - ".whr": _NO_FIXTURE.format(product="Water Hammer"), -} - -# extension -> the constructor that reads it, for "use X instead" errors -_EXTENSION_CONSTRUCTORS: dict[str, str] = { - **{extension: "from_mike" for extension in _MIKE_EXTENSIONS}, - **{extension: "from_epanet" for extension in _EPANET_EXTENSIONS}, -} - - -def _check_file_path_is_str(res: Res1D) -> None: - """Reject a Res1D opened with a path object rather than a string. - - mikeio1d resolves reach topology with ``str.endswith`` on - ``Res1D.file_path``, which raises ``AttributeError`` from deep inside the - load when that attribute is a ``Path``. Fail here instead, where the cause - can be named. - """ - file_path = getattr(res, "file_path", None) - if file_path is not None and not isinstance(file_path, str): - raise TypeError( - f"This Res1D was opened with a {type(file_path).__name__} file_path, " - "which mikeio1d cannot resolve reach topology from. Re-open it as " - "Res1D(str(path)), or pass the path to the constructor directly." - ) - - -class NetworkNode(ABC): - """Abstract base class for a node in a network. - - A node represents a discrete location in the network (e.g. a junction, - reservoir, or boundary point) that carries time-series data for one or - more physical quantities. - - Three properties must be implemented: - - * :attr:`id` - a unique string identifier for the node. - * :attr:`data` - a time-indexed :class:`pandas.DataFrame` whose columns - are quantity names. - * :attr:`boundary` - a dict of boundary-condition metadata (may be empty). - - The concrete helper :class:`BasicNode` is provided for the common case - where the data is already available as a DataFrame. - - See Also - -------- - BasicNode : Ready-to-use concrete implementation. - NetworkReach : Connects two NetworkNode instances. - Network : Container that assembles nodes and reaches into a graph. - """ - - @property - @abstractmethod - def id(self) -> str: - """Unique string identifier for this node.""" - pass - - @property - @abstractmethod - def data(self) -> pd.DataFrame: - """Time-indexed DataFrame with one column per quantity.""" - pass - - @property - @abstractmethod - def boundary(self) -> dict[str, Any]: - """Boundary-condition metadata dict (may be empty).""" - pass - - @property - def quantities(self) -> list[str]: - """List of quantity names available at this node.""" - return list(self.data.columns) - - -class ReachBreakPoint(ABC): - """Abstract base class for an intermediate break point along a network reach. - - Break points represent locations between the start and end nodes of a - reach (e.g. cross-section chainage points along a river reach) that carry - their own time-series data. - - Two properties must be implemented: - - * :attr:`id` - a ``(reach_id, distance)`` tuple that uniquely locates the - break point within the network. - * :attr:`data` - a time-indexed :class:`pandas.DataFrame` whose columns - are quantity names. - - The :attr:`distance` convenience property returns ``id[1]`` (the - along-reach distance in the units used by the parent network). - - Examples - -------- - Minimal subclass: - - >>> class MyBreakPoint(ReachBreakPoint): - ... def __init__(self, reach_id, chainage, df): - ... self._id = (reach_id, chainage) - ... self._data = df - ... @property - ... def id(self): return self._id - ... @property - ... def data(self): return self._data - - See Also - -------- - NetworkReach : Owns a list of ReachBreakPoint instances. - NetworkNode : Represents a start/end node of a reach. - Network : Assembles reaches (and their break points) into a graph. - """ - - @property - @abstractmethod - def id(self) -> tuple[str, float]: - """``(reach_id, distance)`` tuple uniquely identifying this break point.""" - pass - - @property - @abstractmethod - def data(self) -> pd.DataFrame: - """Time-indexed DataFrame with one column per quantity.""" - pass - - @property - def distance(self) -> float: - """Along-reach distance of this break point, measured from the start node.""" - return self.id[1] - - @property - def quantities(self) -> list[str]: - """List of quantity names available at this break point.""" - return list(self.data.columns) - - -class NetworkReach(ABC): - """Abstract base class for a reach in a network. - - A reach represents a directed connection between two :class:`NetworkNode` - instances (e.g. a river reach between two junctions). It may also carry - a list of :class:`ReachBreakPoint` objects for intermediate chainage - locations. - - Subclass this to integrate your own network topology. Four properties - must be implemented: - - * :attr:`id` - a unique string identifier for the reach. - * :attr:`start` - the upstream/start :class:`NetworkNode`. - * :attr:`end` - the downstream/end :class:`NetworkNode`. - * :attr:`breakpoints` - list of :class:`ReachBreakPoint` instances ordered - by increasing distance from the start node (empty list if none). - - :attr:`length` is optional and defaults to ``None``. Reach length matters - in some domains (rivers, sewer networks) and not in others (link-node water - distribution models), so override it only where a length exists. - - The concrete helper :class:`BasicReach` is provided for the common case - where all data is already available in memory. - - Examples - -------- - Minimal subclass, without a length: - - >>> class MyReach(NetworkReach): - ... def __init__(self, rid, start_node, end_node): - ... self._id = rid - ... self._start = start_node - ... self._end = end_node - ... @property - ... def id(self): return self._id - ... @property - ... def start(self): return self._start - ... @property - ... def end(self): return self._end - ... @property - ... def breakpoints(self): return [] - - Add a :attr:`length` property on top of that when the domain has one: - - >>> class MyMeasuredReach(MyReach): - ... def __init__(self, rid, start_node, end_node, length): - ... super().__init__(rid, start_node, end_node) - ... self._length = length - ... @property - ... def length(self): return self._length - - See Also - -------- - BasicReach : Ready-to-use concrete implementation. - NetworkNode : Represents the start/end of this reach. - ReachBreakPoint : Intermediate data points along this reach. - Network : Assembles a list of NetworkReach objects into a graph. - """ - - @property - @abstractmethod - def id(self) -> str: - """Unique string identifier for this reach.""" - pass - - @property - @abstractmethod - def start(self) -> NetworkNode: - """Start (upstream) node of this reach.""" - pass - - @property - @abstractmethod - def end(self) -> NetworkNode: - """End (downstream) node of this reach.""" - pass - - @property - def length(self) -> float | None: - """Total length of this reach in network units, or ``None`` if undefined.""" - return None - - @property - @abstractmethod - def breakpoints(self) -> list[ReachBreakPoint]: - """Ordered list of intermediate :class:`ReachBreakPoint` objects (may be empty).""" - pass - - @property - def n_breakpoints(self) -> int: - """Number of break points in the reach.""" - return len(self.breakpoints) - - -class BasicNode(NetworkNode): - """Concrete :class:`NetworkNode` for programmatic network construction. - - Parameters - ---------- - id : str - Unique node identifier. - data : pd.DataFrame - Time-indexed DataFrame with one column per quantity. - boundary : dict, optional - Boundary condition metadata, by default empty. - - Examples - -------- - >>> import pandas as pd - >>> time = pd.date_range("2020", periods=3, freq="h") - >>> node = BasicNode("junction_1", pd.DataFrame({"WaterLevel": [1.0, 1.1, 1.2]}, index=time)) - """ - - def __init__( - self, - id: str, - data: pd.DataFrame, - boundary: dict[str, Any] | None = None, - ) -> None: - self._id = id - self._data = data - self._boundary: dict[str, Any] = boundary or {} - - @property - def id(self) -> str: - return self._id - - @property - def data(self) -> pd.DataFrame: - return self._data - - @property - def boundary(self) -> dict[str, Any]: - return self._boundary - - -class BasicReach(NetworkReach): - """Concrete :class:`NetworkReach` for programmatic network construction. - - Parameters - ---------- - id : str - Unique reach identifier. - start : NetworkNode - Start node. - end : NetworkNode - End node. - length : float, optional - Reach length, by default None (undefined). - breakpoints : list[ReachBreakPoint], optional - Intermediate break points, by default empty. - - Examples - -------- - >>> reach = BasicReach("reach_1", node_a, node_b, length=250.0) - - Where the domain has no reach length, leave it out: - - >>> reach = BasicReach("pipe_1", node_a, node_b) - """ - - def __init__( - self, - id: str, - start: NetworkNode, - end: NetworkNode, - length: float | None = None, - breakpoints: list[ReachBreakPoint] | None = None, - ) -> None: - self._id = id - self._start = start - self._end = end - self._length = length - self._breakpoints: list[ReachBreakPoint] = breakpoints or [] - - @property - def id(self) -> str: - return self._id - - @property - def start(self) -> NetworkNode: - return self._start - - @property - def end(self) -> NetworkNode: - return self._end - - @property - def length(self) -> float | None: - return self._length - - @property - def breakpoints(self) -> list[ReachBreakPoint]: - return self._breakpoints - - -class Network: - """Network built from a set of reaches, with coordinate lookup and data access.""" - - def __init__(self, reaches: Sequence[NetworkReach]): - graph = self._generate_graph(reaches) - self._initialize_network_attributes(graph) - self._reaches = self._generate_reaches_dict(reaches) - - def _initialize_network_attributes(self, graph: nx.Graph): - self._alias_map = self._generate_alias_map(graph) - self._df = self._build_dataframe(graph) - self._graph = graph.copy() - - def __repr__(self) -> str: - time = self._df.index - time_window = "N/A - N/A" if len(time) == 0 else f"{time[0]} - {time[-1]}" - out = [ - "", - f"Reaches: {len(self._reaches)}", - f"Nodes: {self._graph.number_of_nodes()}", - f"Quantities: {self.quantities}", - f"Time: {time_window}", - ] - return "\n".join(out) - - @classmethod - def from_mike( - cls, - res: str | Path | Res1D, - *, - nodes: str | list[str] | None = None, - reaches: str | list[str] | None = None, - ) -> Network: - """Create a Network from a MIKE 1D or MIKE 11 result file. - - Parameters - ---------- - res : str, Path or Res1D - Path to a ``.res1d`` or ``.res11`` file, or an already-opened - :class:`mikeio1d.Res1D` object. - nodes : str, list of str, or None, optional - Controls which nodes have their timeseries data loaded into memory. - - * ``None`` *(default)* — data is loaded for every node. - * A single node ID or a list of node IDs — only those nodes get - data; others are topology-only. - * ``[]`` (empty list) — no node data is loaded at all. - - The full network topology is always constructed regardless of this - setting, so ``find()`` and ``recall()`` still work on all nodes. - reaches : str, list of str, or None, optional - Controls which reaches have their intermediate gridpoint data - populated. - - * ``None`` *(default)* — gridpoints are populated for every reach. - * A single reach name or a list of reach names — only those reaches - get gridpoint data; others are topology-only. - * ``[]`` (empty list) — no gridpoint data is loaded at all. - - Returns - ------- - Network - - Raises - ------ - NotImplementedError - If the file extension is not one modelskill can read. - ValueError - If the extension belongs to another constructor, such as EPANET. - - Examples - -------- - Load everything (default behaviour): - - >>> from modelskill.network import Network - >>> network = Network.from_mike("model.res1d") - - Load data only for the two nodes where observations exist, and skip - all intermediate gridpoint data to keep memory usage low: - - >>> network = Network.from_mike( - ... "model.res1d", - ... nodes=["node_a", "node_b"], - ... reaches=[], - ... ) - - Load data for selected nodes and gridpoints for one specific reach: - - >>> network = Network.from_mike( - ... "model.res1d", - ... nodes=["node_a", "node_b"], - ... reaches=["reach_1"], - ... ) - - Notes - ----- - MIKE 11 keeps its timeseries on reach gridpoints rather than on nodes, - so the nodes of a ``.res11`` network carry no data of their own. Pass - ``reaches`` rather than ``nodes`` to control what gets loaded. - - See Also - -------- - from_epanet : Read an EPANET result file. - """ - return cls._from_mikeio1d( - res, - nodes=nodes, - reaches=reaches, - allowed=_MIKE_EXTENSIONS, - caller="from_mike", - ) - - @classmethod - def from_epanet( - cls, - res: str | Path | Res1D, - *, - resx: str | Path | Res1D | None = None, - inp: str | Path | None = None, - nodes: str | list[str] | None = None, - reaches: str | list[str] | None = None, - ) -> Network: - """Create a Network from an EPANET result file and its companions. - - An EPANET run writes up to three files that modelskill can use. The - ``.res`` holds the network and its main timeseries; the optional - ``.resx`` holds extra results; and the optional ``.inp`` is the input - file, which is the only one of the three carrying reach lengths. - - Parameters - ---------- - res : str, Path or Res1D - Path to a ``.res`` file, or an already-opened - :class:`mikeio1d.Res1D` object. - resx : str, Path, Res1D or None, optional - Companion ``.resx`` file from the same run. Its extra node - quantities (tank ``Volume`` and ``Volume Percentage``) are merged - onto the matching nodes. By default None, and those quantities are - simply absent. - inp : str, Path or None, optional - EPANET ``.inp`` input file for the same model, read for its - ``[PIPES]`` lengths. By default None, and reach lengths are - undefined. - nodes : str, list of str, or None, optional - Which nodes get their timeseries loaded. See :meth:`from_mike`. - reaches : str, list of str, or None, optional - Which reaches get their gridpoint data loaded. See - :meth:`from_mike`. EPANET results have no intermediate gridpoints, - so this argument has no effect. - - Returns - ------- - Network - - Raises - ------ - NotImplementedError - If the file extension is not one modelskill can read. - ValueError - If the extension belongs to another constructor, such as MIKE, if a - companion file has the wrong extension, or if ``resx`` does not come - from the same run as ``res``. - - Examples - -------- - >>> from modelskill.network import Network - >>> network = Network.from_epanet("model.res") - - With both companions, for real edge lengths and the extra quantities: - - >>> network = Network.from_epanet( - ... "model.res", - ... resx="model.resx", - ... inp="model.inp", - ... ) - - Notes - ----- - EPANET is a link-node model, and mikeio1d reports no length and a - single synthetic gridpoint for each of its reaches. As a result: - - * without ``inp``, every edge of :attr:`graph` has ``length=None``, so a - length-weighted graph algorithm fails rather than returning a - meaningless number. Pumps and valves keep ``length=None`` even with - ``inp``, since ``[PIPES]`` is the only section carrying lengths - * reaches have no breakpoints, so - :class:`~modelskill.obs.ReachObservation` cannot be matched against - an EPANET network — use :class:`~modelskill.obs.NodeObservation` - * ``find(reach=..., distance=)`` never resolves; only - ``distance="start"`` and ``distance="end"`` work - - For the same reason, ``resx`` merges node quantities only. Its - reach-level quantities (pump energy, efficiency and costs) have no - breakpoint to live on, which is tracked in issue #680. - - Node timeseries, :meth:`to_dataframe`, :meth:`to_dataset`, - ``find(node=...)`` and :meth:`recall` are unaffected. - - See Also - -------- - from_mike : Read a MIKE 1D or MIKE 11 result file. - """ - return cls._from_mikeio1d( - res, - nodes=nodes, - reaches=reaches, - allowed=_EPANET_EXTENSIONS, - caller="from_epanet", - resx=resx, - inp=inp, - ) - - @classmethod - def _from_mikeio1d( - cls, - res: str | Path | Res1D, - *, - nodes: str | list[str] | None, - reaches: str | list[str] | None, - allowed: frozenset[str], - caller: str, - resx: str | Path | Res1D | None = None, - inp: str | Path | None = None, - ) -> Network: - """Shared implementation behind the public ``from_*`` constructors. - - Parameters - ---------- - allowed : frozenset of str - Extensions this constructor accepts. - caller : str - Name of the public method, used in error messages. - resx : str, Path, Res1D or None, optional - Companion result file whose node quantities are merged in. - inp : str, Path or None, optional - Companion input file read for reach lengths. - """ - if sys.version_info >= (3, 14): - raise NotImplementedError( - f"Current version of 'mikeio1d' requires python < 3.14 and {sys.version} is being used." - ) - - from mikeio1d import Res1D as _Res1D - - if isinstance(res, (str, Path)): - path = Path(res) - cls._validate_extension(path.suffix, allowed=allowed, caller=caller) - res = _Res1D(str(path)) - elif isinstance(res, _Res1D): - _check_file_path_is_str(res) - suffix = Path(res.file_path).suffix - cls._validate_extension(suffix, allowed=allowed, caller=caller) - else: - raise TypeError( - f"Expected a str, Path or Res1D object, got {type(res).__name__!r}" - ) - - if nodes is None: - nodes_list: list[str] = list(res.nodes.keys()) - elif isinstance(nodes, str): - nodes_list = [nodes] - else: - nodes_list = list(nodes) - - if reaches is None: - reaches_list: list[str] = list(res.reaches.keys()) - elif isinstance(reaches, str): - reaches_list = [reaches] - else: - reaches_list = list(reaches) - - extra = None if resx is None else cls._open_companion_result(res, resx) - lengths = None if inp is None else cls._read_companion_lengths(inp) - - list_of_reaches = cls._load_res1d_network( - res, nodes_list, reaches_list, extra=extra, lengths=lengths - ) - return cls(list_of_reaches) - - @staticmethod - def _read_companion_lengths(inp: str | Path) -> dict[str, float]: - """Read reach lengths from a companion ``.inp`` input file.""" - from modelskill.model.adapters._inp import read_pipe_lengths - - path = Path(inp) - if path.suffix.lower() != ".inp": - raise ValueError( - f"Expected an EPANET '.inp' input file, got '{path.suffix}'. " - "This argument reads reach lengths from the model input, not " - "from a result file." - ) - return read_pipe_lengths(path) - - @staticmethod - def _open_companion_result(res: Res1D, resx: str | Path | Res1D) -> Res1D: - """Open and validate a companion ``.resx`` result file. - - Raises - ------ - ValueError - If the extension is not ``.resx``, or if the file does not come from - the same run as ``res``. - """ - from mikeio1d import Res1D as _Res1D - - if isinstance(resx, (str, Path)): - path = Path(resx) - if path.suffix.lower() != ".resx": - raise ValueError( - f"Expected an EPANET '.resx' companion file, got '{path.suffix}'." - ) - extra = _Res1D(str(path)) - elif isinstance(resx, _Res1D): - _check_file_path_is_str(resx) - if Path(resx.file_path).suffix.lower() != ".resx": - raise ValueError( - "Expected an EPANET '.resx' companion file, got " - f"'{Path(resx.file_path).suffix}'." - ) - extra = resx - else: - raise TypeError( - f"Expected a str, Path or Res1D object, got {type(resx).__name__!r}" - ) - - # Merging two different runs would line up silently and produce a network - # that is wrong in a way no later error would reveal. - if not res.time_index.equals(extra.time_index): - raise ValueError( - "The '.resx' companion does not share a time axis with the " - "'.res' file, so the two are not from the same run. Got " - f"{len(extra.time_index)} steps ending {extra.end_time} against " - f"{len(res.time_index)} ending {res.end_time}." - ) - - unknown_nodes = set(extra.nodes) - set(res.nodes) - if unknown_nodes: - raise ValueError( - f"The '.resx' companion holds nodes {sorted(unknown_nodes)} that are " - "absent from the '.res' network, so the two files do not describe " - "the same model." - ) - - unknown_reaches = set(extra.reaches) - set(res.reaches) - if unknown_reaches: - raise ValueError( - f"The '.resx' companion holds reaches {sorted(unknown_reaches)} that are " - "absent from the '.res' network, so the two files do not describe " - "the same model." - ) - - return extra - - @staticmethod - def _validate_extension( - suffix: str, *, allowed: frozenset[str], caller: str - ) -> None: - """Check a file extension against mikeio1d and against one constructor. - - Raises - ------ - NotImplementedError - If modelskill cannot read the extension, either because mikeio1d - does not support it or because modelskill does not. - ValueError - If another constructor is the one that reads this extension. - """ - from mikeio1d import Res1D as _Res1D - - extension = suffix.lower() - - # Checked before the supported set below, since these all *are* readable - # by mikeio1d - it is modelskill that cannot use the result. - reason = _UNSUPPORTED_EXTENSIONS.get(extension) - if reason is not None: - raise NotImplementedError(f"Cannot read '{suffix}' files. {reason}") - - supported = _Res1D.get_supported_file_extensions() - if extension not in supported: - readable = sorted(supported - set(_UNSUPPORTED_EXTENSIONS)) - raise NotImplementedError( - f"Unsupported file extension '{suffix}'. " - f"Supported extensions are {readable}." - ) - - if extension not in allowed: - constructor = _EXTENSION_CONSTRUCTORS.get(extension) - if constructor is None: - raise NotImplementedError( - f"File extension '{suffix}' is supported by mikeio1d but is not mapped " - "to a Network constructor in this version of modelskill. " - "Please upgrade modelskill or open an issue." - ) - raise ValueError( - f"Network.{caller}() reads {sorted(allowed)} files, got '{suffix}'. " - f"Use Network.{constructor}() instead." - ) - - @staticmethod - def _load_res1d_network( - res: Res1D, - nodes: list[str], - reaches: list[str], - *, - extra: Res1D | None = None, - lengths: dict[str, float] | None = None, - ) -> list[Res1DReach]: - from modelskill.model.adapters._res1d import ( - Res1DReach, - Res1DNode, - _merge_extra_quantities, - _simplify_colnames, - ) - - nodes_set = set(nodes) - reaches_set = set(reaches) - lengths = lengths or {} - - # In order to work with bigger files, we might want to select a subset of nodes and avoid - # potential memory issues. For this reason, we create this intermediate step that populates - # only the data in the passed nodes - - def _init_node(reach: ResultReach, is_end: bool) -> Res1DNode: - id = reach.end_node if is_end else reach.start_node - gpt_idx = -1 if is_end else 0 - if id in nodes_set: - node = res.nodes[id] - df = _simplify_colnames(node) - # Merged here rather than up front so selective loading still - # decides what is held in memory. - if extra is not None and id in extra.nodes: - df = _merge_extra_quantities( - df, _simplify_colnames(extra.nodes[id]), node_id=id - ) - overlapping_gridpoint = reach.gridpoints[gpt_idx] - boundary = _simplify_colnames(overlapping_gridpoint) - return Res1DNode(id, data=df, boundary={reach.name: boundary}) - else: - return Res1DNode(id) - - return [ - Res1DReach( - reach, - _init_node(reach, False), - _init_node(reach, True), - populate_gridpoints=reach.name in reaches_set, - length=lengths.get(reach.name), - ) - for reach in res.reaches.values() - ] - - @staticmethod - def _generate_alias_map(g: nx.Graph) -> dict[str | tuple[str, float], int]: - return {g.nodes[id]["alias"]: id for id in g.nodes()} - - @staticmethod - def _generate_reaches_dict( - reaches: Sequence[NetworkReach], - ) -> dict[str, NetworkReach]: - return {r.id: r for r in reaches} - - @staticmethod - def _build_dataframe(g: nx.Graph) -> pd.DataFrame: - data_in_nodes = { - k: v["data"] - for k, v in g.nodes.items() - if v["data"] is not None and not v["data"].empty - } - if len(data_in_nodes) == 0: - columns = pd.MultiIndex.from_arrays([[], []], names=["node", "quantity"]) - return pd.DataFrame(index=pd.Index([], name="time"), columns=columns) - df = pd.concat(data_in_nodes, axis=1) - df.columns = df.columns.set_names(["node", "quantity"]) - df.index.name = "time" - return df.copy() - - def to_dataframe(self, sel: str | None = None) -> pd.DataFrame: - """Dataframe using node ids as column names. - - It will be multiindex unless 'sel' is passed. - - Parameters - ---------- - sel : Optional[str], optional - Quantity to select, by default None - - Returns - ------- - pd.DataFrame - Timeseries contained in graph nodes - """ - df = self._df.copy() - if sel is None: - return df - else: - df.attrs["quantity"] = sel - return df.reorder_levels(["quantity", "node"], axis=1).loc[:, sel] - - def to_dataset(self) -> xr.Dataset: - """Dataset using node ids as coords. - - Returns - ------- - xr.Dataset - Timeseries contained in graph nodes - """ - df_raw = self.to_dataframe() - if len(df_raw.columns) == 0: - return xr.Dataset() - df = df_raw.reorder_levels(["quantity", "node"], axis=1) - quantities = df.columns.get_level_values("quantity").unique() - return xr.Dataset( - {q: xr.DataArray(df[q], dims=["time", "node"]) for q in quantities} - ) - - @property - def graph(self) -> nx.Graph: - """Graph of the network.""" - return self._graph - - @property - def quantities(self) -> list[str]: - """Quantities present in data. - - Returns - ------- - List[str] - List of quantities - """ - return list(self.to_dataframe().columns.get_level_values(1).unique()) - - @staticmethod - def _generate_graph(reaches: Sequence[NetworkReach]) -> nx.Graph: - g0 = nx.Graph() - for reach in reaches: - # 1) Add start and end nodes - for node in [reach.start, reach.end]: - node_key = node.id - if node_key in g0.nodes: - g0.nodes[node_key]["boundary"].update(node.boundary) - else: - g0.add_node(node_key, data=node.data, boundary=node.boundary) - - # 2) Add edges connecting start/end nodes to their adjacent breakpoints - start_key = reach.start.id - end_key = reach.end.id - if reach.n_breakpoints == 0: - g0.add_edge(start_key, end_key, length=reach.length) - else: - bp_keys = [bp.id for bp in reach.breakpoints] - for bp, bp_key in zip(reach.breakpoints, bp_keys): - g0.add_node(bp_key, data=bp.data) - - g0.add_edge(start_key, bp_keys[0], length=reach.breakpoints[0].distance) - - # Only the final segment needs the total length. Break point - # distances are known even when the total is not, so a reach - # without a length still gets real lengths on every edge but - # this one. - tail_length = ( - None - if reach.length is None - else reach.length - reach.breakpoints[-1].distance - ) - g0.add_edge(bp_keys[-1], end_key, length=tail_length) - - # 3) Connect consecutive intermediate breakpoints - for i in range(reach.n_breakpoints - 1): - current_ = reach.breakpoints[i] - next_ = reach.breakpoints[i + 1] - length = next_.distance - current_.distance - g0.add_edge( - current_.id, - next_.id, - length=length, - ) - - return nx.convert_node_labels_to_integers(g0, label_attribute="alias") - - @overload - def find( - self, - *, - node: str, - reach: None = None, - distance: None = None, - ) -> int: - pass - - @overload - def find( - self, - *, - node: list[str], - reach: None = None, - distance: None = None, - ) -> list[int]: - pass - - @overload - def find( - self, - *, - node: None = None, - reach: str | list[str], - distance: str | float, - ) -> int: - pass - - @overload - def find( - self, - *, - node: None = None, - reach: str | list[str], - distance: list[str | float], - ) -> list[int]: - pass - - def find( - self, - node: str | list[str] | None = None, - reach: str | list[str] | None = None, - distance: str | float | list[str | float] | None = None, - ) -> int | list[int]: - """Find node or breakpoint id in the Network object based on former coordinates. - - Parameters - ---------- - node : str | List[str], optional - Node id(s) in the original network, by default None - reach : str | List[str], optional - Reach id(s) for breakpoint lookup or reach endpoint lookup, by default None - distance : str | float | List[str | float], optional - Distance(s) along reach for breakpoint lookup, or "start"/"end" - for reach endpoints, by default None - - Returns - ------- - int | List[int] - Node or breakpoint id(s) in the generic network - - Raises - ------ - ValueError - If invalid combination of parameters is provided - KeyError - If requested node/breakpoint is not found in the network - """ - by_node = node is not None - by_breakpoint = reach is not None or distance is not None - - if by_node and by_breakpoint: - raise ValueError( - "Cannot specify both 'node' and 'reach'/'distance' parameters simultaneously" - ) - - if not by_node and not by_breakpoint: - raise ValueError( - "Must specify either 'node' or both 'reach' and 'distance' parameters" - ) - - ids: list[str | tuple[str, float]] - - if by_node: - assert node is not None - if not isinstance(node, list): - node = [node] - ids = list(node) - - else: - if reach is None or distance is None: - raise ValueError( - "Both 'reach' and 'distance' parameters are required for breakpoint/endpoint lookup" - ) - - if not isinstance(reach, list): - reach = [reach] - - if not isinstance(distance, list): - distance = [distance] - - if len(reach) == 1: - reach = reach * len(distance) - - if len(reach) != len(distance): - raise ValueError( - "Incompatible lengths of 'reach' and 'distance' arguments. One 'reach' admits multiple distances, otherwise they must be the same length." - ) - - ids = [] - for reach_i, distance_i in zip(reach, distance): - if distance_i in ["start", "end"]: - if reach_i not in self._reaches: - raise KeyError(f"Reach '{reach_i}' not found in the network.") - - network_reach = self._reaches[reach_i] - if distance_i == "start": - ids.append(network_reach.start.id) - else: - ids.append(network_reach.end.id) - else: - if not isinstance(distance_i, (int, float)): - raise ValueError( - "Invalid 'distance' value for breakpoint lookup: " - f"{distance_i!r}. Expected a numeric value or 'start'/'end'." - ) - ids.append((reach_i, distance_i)) - - _CHAINAGE_TOLERANCE = 1e-3 - - def _resolve_id(id): - if id in self._alias_map: - return self._alias_map[id] - if isinstance(id, tuple): - reach_id, distance = id - for key, val in self._alias_map.items(): - if ( - isinstance(key, tuple) - and key[0] == reach_id - and abs(key[1] - distance) <= _CHAINAGE_TOLERANCE - ): - return val - return None - - resolved = [_resolve_id(id) for id in ids] - missing_ids = [ids[i] for i, v in enumerate(resolved) if v is None] - if missing_ids: - raise KeyError( - f"Node/breakpoint(s) {missing_ids} not found in the network. Available nodes are {set(self._alias_map.keys())}" - ) - if len(resolved) == 1: - return resolved[0] - return resolved - - @overload - def recall(self, id: int) -> dict[str, Any]: - pass - - @overload - def recall(self, id: list[int]) -> list[dict[str, Any]]: - pass - - def recall(self, id: int | list[int]) -> dict[str, Any] | list[dict[str, Any]]: - """Recover the original coordinates of an element given the node id(s) in the Network object. - - Parameters - ---------- - id : int | List[int] - Node id(s) in the generic network - - Returns - ------- - Dict[str, Any] | List[Dict[str, Any]] - Original coordinates. For single input returns dict, for multiple inputs returns list of dicts. - Dict contains coordinates: - - For nodes: 'node' key with node id - - For breakpoints: 'reach' and 'distance' keys with reach id and distance - - Raises - ------ - KeyError - If node id is not found in the network - ValueError - If node id string format is invalid - """ - if not isinstance(id, list): - id = [id] - - reverse_alias_map = {v: k for k, v in self._alias_map.items()} - - results: list[dict[str, Any]] = [] - for node_id in id: - if node_id not in reverse_alias_map: - raise KeyError(f"Node ID {node_id} not found in the network.") - - key = reverse_alias_map[node_id] - if isinstance(key, str): - results.append({"node": key}) - else: - results.append({"reach": key[0], "distance": key[1]}) - - if len(results) == 1: - return results[0] - else: - return results - - def copy(self) -> "Network": - """Create a deep copy of the Network. - - Returns - ------- - Network - Deep copy of the Network object - """ - return deepcopy(self) - - -def _make_basic_network(node_ids, time, data, quantity="WaterLevel"): - nodes = [ - BasicNode(nid, pd.DataFrame({quantity: data[:, i]}, index=time)) - for i, nid in enumerate(node_ids) - ] - reaches = [ - BasicReach(f"r{i}", nodes[i], nodes[i + 1], length=100.0) - for i in range(len(nodes) - 1) - ] - return Network(reaches) diff --git a/src/modelskill/obs.py b/src/modelskill/obs.py index fa2cc01ca..8fe906c02 100644 --- a/src/modelskill/obs.py +++ b/src/modelskill/obs.py @@ -1,21 +1,28 @@ """ # Observations -ModelSkill supports four types of observations: +ModelSkill supports five types of observations: * [`PointObservation`](`modelskill.PointObservation`) - a point timeseries from a dfs0/nc file or a DataFrame * [`TrackObservation`](`modelskill.TrackObservation`) - a track (moving point) timeseries from a dfs0/nc file or a DataFrame * [`VerticalObservation`](`modelskill.VerticalObservation`) - a vertical profile from a dfs0/nc file or a DataFrame -* [`NodeObservation`](`modelskill.NodeObservation`) - a network node timeseries for specific node IDs. +* [`NodeObservation`](`modelskill.NodeObservation`) - a network node timeseries for a named node or break point. +* [`ReachObservation`](`modelskill.ReachObservation`) - a network reach timeseries for a quantity uniform along the reach. An observation can be created by explicitly invoking one of the above classes or using the [`observation()`](`modelskill.observation`) function which will return the appropriate type based on the input data (if possible). """ from __future__ import annotations -from typing import Literal, Any, Union, overload +from typing import ( + Any, + Literal, + Union, + overload, +) from typing_extensions import Self import warnings +import numpy as np import pandas as pd import xarray as xr @@ -29,11 +36,16 @@ _parse_network_node_input, _parse_network_breakpoint_input, ) +from .timeseries._coords import network_location # NetCDF attributes can only be str, int, float https://unidata.github.io/netcdf4-python/#attributes-in-a-netcdf-file Serializable = Union[str, int, float] +# Where a node observation sits: the name the network gave the node, or a +# breakpoint given as (reach_id, distance) along a reach. +NodeLocation = Union[str, tuple[str, float]] + def observation( data: DataInputType, @@ -78,7 +90,7 @@ def observation( >>> import modelskill as ms >>> o_pt = ms.observation(df, item=0, x=366844, y=6154291, name="Klagshamn") >>> o_tr = ms.observation("lon_after_lat.dfs0", item="wl", x_item=1, y_item=0) - >>> o_node = ms.observation(df, item="Water Level", at=123, name="123") + >>> o_node = ms.observation(df, item="Water Level", at="123", name="123") >>> o_reach = ms.observation(df, item="Discharge", reach="reach_1", name="reach_1_Q") """ if gtype is None: @@ -477,18 +489,30 @@ def z(self): return self._coordinate_values("z") +def _at_from_coords(ds: xr.Dataset) -> str | tuple[str, float]: + """The location in the form ``NodeObservation`` takes it. + + Unlike :func:`~modelskill.timeseries._coords.network_location`, which + reports the location as recorded, this coerces to the types the ``at`` + argument is declared with. + """ + location = network_location(ds) + if isinstance(location, tuple): + return (str(location[0]), float(location[1])) + return str(location) + + class NodeObservation(Observation): """Class for observations at network nodes. Create a NodeObservation from a DataFrame or other data source. - The ``at`` parameter accepts three forms: + The ``at`` parameter accepts two forms: - * **int** — internal network ID, used directly. - * **str** — original node alias (e.g. Res1D node name), resolved to an - integer ID automatically when matched against a - :class:`~modelskill.model.network.NetworkModelResult`. - * **tuple[str, float]** — breakpoint location as ``(reach_id, distance)`` - along a reach, resolved via the alias map at match time. + * **str** — the node's name in the model (e.g. a Res1D node name). + * **tuple[str, float]** — a breakpoint, as ``(reach_id, distance)`` along a + reach. + + Both are resolved against the network when the observation is matched. .. note:: "Node" in this API follows the broad graph sense: it covers both @@ -505,12 +529,11 @@ class NodeObservation(Observation): ---------- data : str, Path, mikeio.Dataset, mikeio.DataArray, pd.DataFrame, pd.Series, xr.Dataset or xr.DataArray data source with time series for the node - at : int, str, or tuple[str, float] + at : str or tuple[str, float] Observation location. Accepted forms: - * **int** — internal network ID. - * **str** — original node alias (e.g. Res1D node name). - * **tuple[str, float]** — breakpoint as ``(reach_id, distance)``. + * **str** — the node's name in the model (e.g. a Res1D node name). + * **tuple[str, float]** — a breakpoint, as ``(reach_id, distance)``. item : (int, str), optional index or name of the wanted item/column, by default None if data contains more than one item, item must be given @@ -528,8 +551,8 @@ class NodeObservation(Observation): Examples -------- >>> import modelskill as ms - >>> o1 = ms.NodeObservation(data, at=123, name="123") - >>> o2 = ms.NodeObservation(df, item="Water Level", at=456) + >>> o1 = ms.NodeObservation(data, at="123", name="123") + >>> o2 = ms.NodeObservation(df, item="Water Level", at="456") >>> >>> # String alias resolved at match time >>> o3 = ms.NodeObservation(data, at="node_A") @@ -538,14 +561,14 @@ class NodeObservation(Observation): >>> o4 = ms.NodeObservation(data, at=("reach_1", 24.5)) >>> >>> # Multiple node observations from separate data sources - >>> obs = ms.NodeObservation.from_multiple(nodes={123: df1, 456: df2}) + >>> obs = ms.NodeObservation.from_multiple(nodes={"123": df1, "456": df2}) """ def __init__( self, data: PointType, *, - at: int | str | tuple[str, float], + at: str | tuple[str, float], item: int | str | None = None, name: str | None = None, weight: float = 1.0, @@ -553,6 +576,12 @@ def __init__( aux_items: list[int | str] | None = None, attrs: dict | None = None, ) -> None: + if isinstance(at, (int, np.integer)) and not isinstance(at, bool): + raise TypeError( + "'at' takes a node name or a (reach, distance) pair, not an integer. " + "The integers a Network hands out are an internal index; " + "network.recall() gives the name back." + ) if isinstance(at, tuple): reach, distance = str(at[0]), float(at[1]) if not self._is_input_validated(data): @@ -579,26 +608,21 @@ def __init__( super().__init__(data=data, weight=weight, attrs=attrs) @property - def at(self) -> int | str | tuple[str, float]: - """Observation location: node ID (int/str) or breakpoint ``(reach_id, distance)`` tuple.""" - if "reach" in self.data.coords: - return ( - str(self.data.coords["reach"].item()), - float(self.data.coords["distance"].item()), - ) - return self.data.coords["node"].item() # int or str + def at(self) -> str | tuple[str, float]: + """Observation location: a node name, or a ``(reach_id, distance)`` breakpoint.""" + return _at_from_coords(self.data) + + @property + def node(self) -> Any: + """Name of the node this observation sits at, or None for a break point.""" + return self._coordinate_values("node") + + def _location_repr(self) -> str | None: + return f"Location: {self.at}" def _create_new_instance(self, data: xr.Dataset) -> Self: """Reconstruct instance from a dataset slice.""" - if "reach" in data.coords: - return self.__class__( - data, - at=( - str(data.coords["reach"].item()), - float(data.coords["distance"].item()), - ), - ) - return self.__class__(data, at=data.coords["node"].item()) + return self.__class__(data, at=_at_from_coords(data)) @overload @classmethod @@ -606,7 +630,7 @@ def from_multiple( cls, *, data: PointType, - nodes: dict[int, str | int], + nodes: dict[NodeLocation, str | int], quantity: Quantity | None = None, aux_items: list[int | str] | None = None, attrs: dict | None = None, @@ -617,7 +641,7 @@ def from_multiple( def from_multiple( cls, *, - nodes: dict[int, PointType], + nodes: dict[NodeLocation, PointType], quantity: Quantity | None = None, aux_items: list[int | str] | None = None, attrs: dict | None = None, @@ -629,7 +653,7 @@ def from_multiple( cls, *, data: PointType | None = None, - nodes: dict[int, Any] | None = None, + nodes: dict[NodeLocation, Any] | None = None, quantity: Quantity | None = None, aux_items: list[int | str] | None = None, attrs: dict | None = None, @@ -641,21 +665,27 @@ def from_multiple( 1. **Separate data sources** — pass only ``nodes`` as a dict mapping each node ID to its own data source (file path, DataFrame, etc.):: - obs = NodeObservation.from_multiple(nodes={123: df1, 456: "sensor.csv"}) + obs = NodeObservation.from_multiple(nodes={"123": df1, "456": "sensor.csv"}) 2. **Shared data source** — pass a single ``data`` object together with ``nodes`` as a dict mapping each node ID to the column name or index to select from ``data``:: - obs = NodeObservation.from_multiple(data=df, nodes={123: "col_a", 456: "col_b"}) + obs = NodeObservation.from_multiple(data=df, nodes={"123": "col_a", "456": "col_b"}) Parameters ---------- data : PointType, optional - Shared data source (required when ``nodes`` values are column selectors). - nodes : dict[int, PointType | str | int] - Mapping of node_id -> data source or column selector. - quantity : Quantity | None, optional + Shared data source (required when ``nodes`` values are column + selectors). + nodes : dict[str | tuple[str, float], PointType | str | int] + Mapping of location -> data source or column selector. A location + takes either of the forms accepted by ``at``: a node name, or a + ``(reach_id, distance)`` breakpoint. + + Note that a location can appear only once, so this form cannot + express several observations at the same node. + quantity : Quantity, optional Physical quantity metadata, by default None. aux_items : list[int | str] | None, optional Auxiliary items, by default None. @@ -666,6 +696,11 @@ def from_multiple( ------- list[NodeObservation] List of NodeObservation objects. + + Raises + ------ + ValueError + If ``nodes`` is not given. """ if nodes is None: raise ValueError("'nodes' argument is required") @@ -771,10 +806,126 @@ def reach(self) -> str: """Reach ID of this observation.""" return str(self.data.coords["reach"].item()) + def _location_repr(self) -> str | None: + return f"Location: {self.reach}" + def _create_new_instance(self, data: xr.Dataset) -> Self: """Reconstruct instance from a dataset slice.""" return self.__class__(data, reach=str(data.coords["reach"].item())) + @overload + @classmethod + def from_multiple( + cls, + *, + data: PointType, + reaches: dict[str, str | int], + quantity: Quantity | None = None, + aux_items: list[int | str] | None = None, + attrs: dict | None = None, + ) -> list[ReachObservation]: + pass + + @overload + @classmethod + def from_multiple( + cls, + *, + reaches: dict[str, PointType], + quantity: Quantity | None = None, + aux_items: list[int | str] | None = None, + attrs: dict | None = None, + ) -> list[ReachObservation]: + pass + + @classmethod + def from_multiple( + cls, + *, + data: PointType | None = None, + reaches: dict[str, Any] | None = None, + quantity: Quantity | None = None, + aux_items: list[int | str] | None = None, + attrs: dict | None = None, + ) -> list[ReachObservation]: + """Create multiple ReachObservation objects. + + Two calling conventions are supported: + + 1. **Separate data sources** — pass only ``reaches`` as a dict mapping + each reach ID to its own data source (file path, DataFrame, etc.):: + + obs = ReachObservation.from_multiple(reaches={"r1": df1, "r2": "sensor.csv"}) + + 2. **Shared data source** — pass a single ``data`` object together with + ``reaches`` as a dict mapping each reach ID to the column name or + index to select from ``data``:: + + obs = ReachObservation.from_multiple(data=df, reaches={"r1": "col_a", "r2": "col_b"}) + + Parameters + ---------- + data : PointType, optional + Shared data source (required when ``reaches`` values are column + selectors). + reaches : dict[str, PointType | str | int] + Mapping of reach_id -> data source or column selector. + + Note that a reach can appear only once, so this form cannot express + several observations on the same reach. + quantity : Quantity, optional + Physical quantity metadata, by default None. + aux_items : list[int | str] | None, optional + Auxiliary items, by default None. + attrs : dict | None, optional + Additional attributes, by default None. + + Returns + ------- + list[ReachObservation] + List of ReachObservation objects. + + Raises + ------ + ValueError + If ``reaches`` is not given. + """ + if reaches is None: + raise ValueError("'reaches' argument is required") + if not isinstance(reaches, dict): + raise TypeError( + f"'reaches' must be a dict mapping reach_id -> data_source, got {type(reaches).__name__}" + ) + + reach_ids = list(reaches.keys()) + + if data is None: + data_sources: list[PointType] = list(reaches.values()) + return [ + cls( + data_i, + reach=reach_i, + item=None, + quantity=quantity, + aux_items=aux_items, + attrs=attrs, + ) + for data_i, reach_i in zip(data_sources, reach_ids) + ] + else: + reach_items: list[int | str | None] = list(reaches.values()) + return [ + cls( + data, + reach=reach_i, + item=item_i, + quantity=quantity, + aux_items=aux_items, + attrs=attrs, + ) + for reach_i, item_i in zip(reach_ids, reach_items) + ] + def unit_display_name(name: str) -> str: """Display name diff --git a/src/modelskill/timeseries/__init__.py b/src/modelskill/timeseries/__init__.py index f52f17271..9869b51b2 100644 --- a/src/modelskill/timeseries/__init__.py +++ b/src/modelskill/timeseries/__init__.py @@ -1,6 +1,6 @@ from ._timeseries import TimeSeries -from ._point import ( - _parse_xyz_point_input, +from ._point import _parse_xyz_point_input +from ._network import ( _parse_network_node_input, _parse_network_breakpoint_input, ) diff --git a/src/modelskill/timeseries/_coords.py b/src/modelskill/timeseries/_coords.py index 98304befa..14b5559d2 100644 --- a/src/modelskill/timeseries/_coords.py +++ b/src/modelskill/timeseries/_coords.py @@ -1,4 +1,9 @@ +from __future__ import annotations + +from typing import Any + import numpy as np +import xarray as xr class XYZCoords: @@ -18,7 +23,7 @@ def as_dict(self) -> dict: class NodeCoords: - def __init__(self, node: int | str | None = None): + def __init__(self, node: str | None = None): self.node = node if node is not None else np.nan @property @@ -49,3 +54,44 @@ def as_dict(self) -> dict: if self.distance is not None: d["distance"] = self.distance return d + + +def _coordinate_values(ds: xr.Dataset, coord: str) -> Any: + """A dataset's values for one coordinate, or None when it has no such coordinate. + + A scalar coordinate is unwrapped to its single value; anything else is + handed back as the array it is. + """ + if coord not in ds.coords: + return None + vals = ds[coord].values + return np.atleast_1d(vals)[0] if vals.ndim == 0 else vals + + +#: Scalar coordinates that say where a network timeseries sits, rather than what +#: it holds. They are dropped on the way to a dataframe, where they would +#: otherwise become columns. +NETWORK_LOCATION_COORDS = ("node", "node_index", "reach", "distance") + + +def network_location(ds: xr.Dataset) -> Any: + """Where a network timeseries sits, as the network that produced it named it. + + Returns a node name for a node, a ``(reach, distance)`` pair for a + breakpoint, a reach name when no distance was given, and None for data that + carries no network location. The value is returned as recorded, so a comparer + saved by an older version gives back the integer it stored. + """ + if "node" in ds.coords: + return _network_scalar(ds, "node") + if "reach" in ds.coords: + reach = _network_scalar(ds, "reach") + if "distance" not in ds.coords: + return reach + return (reach, _network_scalar(ds, "distance")) + return None + + +def _network_scalar(ds: xr.Dataset, name: str) -> Any: + value = _coordinate_values(ds, name) + return value.item() if hasattr(value, "item") else value diff --git a/src/modelskill/timeseries/_network.py b/src/modelskill/timeseries/_network.py new file mode 100644 index 000000000..535b22c53 --- /dev/null +++ b/src/modelskill/timeseries/_network.py @@ -0,0 +1,45 @@ +from __future__ import annotations +from typing import Sequence + +import xarray as xr + +from ..quantity import Quantity +from ..types import PointType +from ._coords import NodeCoords, ReachCoords +from ._point import _parse_point_input + + +def _parse_network_node_input( + data: PointType, + name: str | None, + item: str | int | None, + quantity: Quantity | None, + node: str | None, + aux_items: Sequence[int | str] | None, +) -> xr.Dataset: + if node is None: + raise ValueError("'node' argument cannot be empty.") + coords = NodeCoords(node=node) + ds = _parse_point_input(data, name, item, quantity, aux_items, coords=coords) + return ds + + +def _parse_network_breakpoint_input( + data: PointType, + name: str | None, + item: str | int | None, + quantity: Quantity | None, + aux_items: Sequence[int | str] | None, + *, + reach: str, + distance: float | None = None, +) -> xr.Dataset: + """Parse input for a breakpoint (or reach-level) observation. + + When ``distance`` is ``None`` the observation is reach-level — no + ``distance`` coordinate is stored and the result can be matched to any + breakpoint on the reach. + """ + coords = ReachCoords(reach=reach, distance=distance) + ds = _parse_point_input(data, name, item, quantity, aux_items, coords=coords) + return ds diff --git a/src/modelskill/timeseries/_point.py b/src/modelskill/timeseries/_point.py index f0742f4dc..f0eb47b2d 100644 --- a/src/modelskill/timeseries/_point.py +++ b/src/modelskill/timeseries/_point.py @@ -168,12 +168,7 @@ def _include_attributes( ) -> xr.Dataset: ds = ds.copy() - if "node" in ds.coords or ("reach" in ds.coords and "distance" in ds.coords): - ds.attrs["gtype"] = str(GeometryType.NODE) - elif "reach" in ds.coords: - ds.attrs["gtype"] = str(GeometryType.REACH) - else: - ds.attrs["gtype"] = str(GeometryType.POINT) + ds.attrs["gtype"] = str(GeometryType.from_network_coords(ds) or GeometryType.POINT) ds[name].attrs["long_name"] = quantity.name ds[name].attrs["units"] = quantity.unit @@ -279,39 +274,3 @@ def _parse_xyz_point_input( coords = XYZCoords(x, y, z) ds = _parse_point_input(data, name, item, quantity, aux_items, coords=coords) return ds - - -def _parse_network_node_input( - data: PointType, - name: str | None, - item: str | int | None, - quantity: Quantity | None, - node: int | str | None, - aux_items: Sequence[int | str] | None, -) -> xr.Dataset: - if node is None: - raise ValueError("'node' argument cannot be empty.") - coords = NodeCoords(node=node) - ds = _parse_point_input(data, name, item, quantity, aux_items, coords=coords) - return ds - - -def _parse_network_breakpoint_input( - data: PointType, - name: str | None, - item: str | int | None, - quantity: Quantity | None, - aux_items: Sequence[int | str] | None, - *, - reach: str, - distance: float | None = None, -) -> xr.Dataset: - """Parse input for a breakpoint (or reach-level) observation. - - When ``distance`` is ``None`` the observation is reach-level — no - ``distance`` coordinate is stored and the result can be matched to any - breakpoint on the reach. - """ - coords = ReachCoords(reach=reach, distance=distance) - ds = _parse_point_input(data, name, item, quantity, aux_items, coords=coords) - return ds diff --git a/src/modelskill/timeseries/_timeseries.py b/src/modelskill/timeseries/_timeseries.py index bba5d78f7..55d8ae8af 100644 --- a/src/modelskill/timeseries/_timeseries.py +++ b/src/modelskill/timeseries/_timeseries.py @@ -10,11 +10,13 @@ from ..types import GeometryType from ..quantity import Quantity +from ._coords import NETWORK_LOCATION_COORDS, _coordinate_values from ._plotter import TimeSeriesPlotter, MatplotlibTimeSeriesPlotter from .. import __version__ T = TypeVar("T", bound="TimeSeries") + DEFAULT_COLORS = [ "#b30000", "#7c1158", @@ -101,16 +103,9 @@ def _validate_dataset(ds: xr.Dataset) -> xr.Dataset: # Validate coordinates: x,y spatial, node-based, or reach-based (with or without chainage) has_spatial_coords = "x" in ds.coords and "y" in ds.coords - has_node_coord = "node" in ds.coords - has_breakpoint_coords = "reach" in ds.coords and "distance" in ds.coords - has_reach_coord = "reach" in ds.coords and "distance" not in ds.coords - - if ( - not has_spatial_coords - and not has_node_coord - and not has_breakpoint_coords - and not has_reach_coord - ): + has_network_coords = GeometryType.from_network_coords(ds) is not None + + if not has_spatial_coords and not has_network_coords: raise ValueError( "data must have either x,y coordinates, a node coordinate, " "reach+distance coordinates, or a reach coordinate" @@ -263,16 +258,8 @@ def y(self) -> Any: def y(self, value: Any) -> None: self.data["y"] = value - @property - def node(self) -> Any: - """node-coordinate""" - return self._coordinate_values("node") - - def _coordinate_values(self, coord: str) -> None | float | np.ndarray: - if coord not in self.data.coords: - return None # Node-based data doesn't have y coordinate - vals = self.data[coord].values - return np.atleast_1d(vals)[0] if vals.ndim == 0 else vals + def _coordinate_values(self, coord: str) -> Any: + return _coordinate_values(self.data, coord) @property def _is_modelresult(self) -> bool: @@ -292,16 +279,18 @@ def _values_as_series(self) -> pd.Series: def _aux_vars(self): return list(self.data.filter_by_attrs(kind="aux").data_vars) + def _location_repr(self) -> str | None: + """The location line for ``__repr__``, or None when there is nothing to say.""" + if self.gtype == str(GeometryType.POINT): + if self.x is not None and self.y is not None: + return f"Location: {self.x}, {self.y}" + return None + def __repr__(self) -> str: res = [] res.append(f"<{self.__class__.__name__}>: {self.name}") - if self.gtype == str(GeometryType.POINT): - # Show location based on available coordinates - if "node" in self.data.coords: - node_id = self.data.coords["node"].item() - res.append(f"Node: {node_id}") - elif self.x is not None and self.y is not None: - res.append(f"Location: {self.x}, {self.y}") + if (location := self._location_repr()) is not None: + res.append(location) res.append(f"Time: {self.time[0]} - {self.time[-1]}") res.append(f"Quantity: {self.quantity}") if len(self._aux_vars) > 0: @@ -366,10 +355,12 @@ def to_dataframe(self) -> pd.DataFrame: return df[cols] elif self.gtype == str(GeometryType.VERTICAL): return self.data.drop_vars(["x", "y"]).to_dataframe() - elif self.gtype == str(GeometryType.NODE): - return self.data.drop_vars(["node"]).to_dataframe() - elif self.gtype == str(GeometryType.REACH): - return self.data.drop_vars(["reach"]).to_dataframe() + elif self.gtype in (str(GeometryType.NODE), str(GeometryType.REACH)): + # A breakpoint carries reach and distance rather than node, so drop + # whichever of them this one has. + return self.data.drop_vars( + NETWORK_LOCATION_COORDS, errors="ignore" + ).to_dataframe() else: raise NotImplementedError(f"Unknown gtype: {self.gtype}") diff --git a/src/modelskill/types.py b/src/modelskill/types.py index cf9e2a390..002ddb40f 100644 --- a/src/modelskill/types.py +++ b/src/modelskill/types.py @@ -56,6 +56,44 @@ def from_string(s: str) -> "GeometryType": f"GeometryType {s} not recognized. Available options: {[m.name for m in GeometryType]}" ) from e + @staticmethod + def from_network_coords(ds: xr.Dataset) -> "GeometryType | None": + """The network location a dataset's coordinates record, if any. + + Only network coordinates are read. Data located some other way, by x and + y for instance, records no network location and gives None rather than + the geometry it does have. + + Parameters + ---------- + ds : xr.Dataset + Dataset to inspect. + + Returns + ------- + GeometryType or None + NODE for a node or a break point, REACH for a whole reach, and None + for data that carries no network location. + + Examples + -------- + >>> import xarray as xr + >>> from modelskill.types import GeometryType + >>> GeometryType.from_network_coords(xr.Dataset(coords={"node": "123"})) + + >>> GeometryType.from_network_coords(xr.Dataset(coords={"reach": "r1", "distance": 24.5})) + + >>> GeometryType.from_network_coords(xr.Dataset(coords={"reach": "r1"})) + + >>> GeometryType.from_network_coords(xr.Dataset(coords={"x": 0.0, "y": 0.0})) is None + True + """ + if "node" in ds.coords or {"reach", "distance"} <= set(ds.coords): + return GeometryType.NODE + if "reach" in ds.coords: + return GeometryType.REACH + return None + DataInputType = Union[ str, diff --git a/tests/network_helpers.py b/tests/network_helpers.py new file mode 100644 index 000000000..1c4f6a0a0 --- /dev/null +++ b/tests/network_helpers.py @@ -0,0 +1,65 @@ +"""Helpers shared by the tests that build networks by hand. + +Importing this module needs mikeio1d, which is an optional dependency (ADR-010), +so guard the import with ``pytest.importorskip("mikeio1d.network")`` first. +""" + +from __future__ import annotations + +import pandas as pd +from mikeio1d.network import Network, BasicNode, BasicReach, ReachBreakPoint + + +class BreakPoint(ReachBreakPoint): + """A break point at a known distance along a reach.""" + + def __init__(self, reach, distance, data): + self._id = (reach, distance) + self._data = data + + @property + def id(self): + return self._id + + @property + def data(self): + return self._data + + +def make_network(node_ids, time, data, quantity="WaterLevel"): + """A chain of nodes, each carrying one quantity, joined by unit reaches.""" + nodes = [ + BasicNode(node_id, pd.DataFrame({quantity: data[:, i]}, index=time)) + for i, node_id in enumerate(node_ids) + ] + reaches = [ + BasicReach(f"r{i}", nodes[i], nodes[i + 1], length=100.0) + for i in range(len(nodes) - 1) + ] + return Network(reaches) + + +def make_breakpoint_network(reach_id, distance, data): + """A one-reach network whose data sits on a break point, not on its nodes.""" + empty = pd.DataFrame() + reach = BasicReach( + reach_id, + BasicNode("start", empty), + BasicNode("end", empty), + length=100.0, + breakpoints=[BreakPoint(reach_id, distance, data)], + ) + return Network([reach]) + + +def node_series(network, quantity="WaterLevel"): + """Each node's own series for `quantity`, keyed by node id, read off the reaches. + + The three nodes of `sample_network` carry three different series, so a + comparer built from one of them cannot be satisfied by any of the others. + """ + nodes = {} + for reach in network.reaches.values(): + for node in (reach.start, reach.end): + nodes[node.id] = node.data[quantity] + return pd.DataFrame(nodes) diff --git a/tests/test_comparercollection.py b/tests/test_comparercollection.py index bdf4aa807..7a1fb9459 100644 --- a/tests/test_comparercollection.py +++ b/tests/test_comparercollection.py @@ -454,10 +454,8 @@ def test_save_and_load_preserves_raw_model_data(cc, tmp_path): @pytest.fixture def node_comparer() -> modelskill.comparison.Comparer: """A comparer built by matching a NodeObservation against a NetworkModelResult (node gtype).""" - pytest.importorskip("networkx") - from modelskill.model.network import NetworkModelResult - from modelskill.network import Network, BasicNode, BasicReach - from modelskill.obs import NodeObservation + pytest.importorskip("mikeio1d.network") + from mikeio1d.network import Network, BasicNode, BasicReach time = pd.date_range("2019-01-01", periods=6, freq="D") node_a_data = pd.DataFrame( @@ -471,9 +469,25 @@ def node_comparer() -> modelskill.comparison.Comparer: ) network = Network([reach]) - nmr = NetworkModelResult(network, name="Network_Model") - node_id = network.find(node="123") - obs = NodeObservation(node_a_data, at=node_id, name="Node_123_Obs") + nmr = ms.NetworkModelResult(network, name="Network_Model") + obs = ms.NodeObservation(node_a_data, at="123", name="Node_123_Obs") + + return ms.match(obs, nmr) + + +@pytest.fixture +def reach_comparer() -> modelskill.comparison.Comparer: + """A comparer built by matching a ReachObservation (reach gtype).""" + pytest.importorskip("mikeio1d.network") + from tests.network_helpers import make_breakpoint_network + + time = pd.date_range("2019-01-01", periods=6, freq="D") + values = pd.DataFrame({"WaterLevel": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]}, index=time) + + nmr = ms.NetworkModelResult( + make_breakpoint_network("r1", 50.0, values), name="Network_Model" + ) + obs = ms.ReachObservation(values, reach="r1", name="Reach_r1_Obs") return ms.match(obs, nmr) @@ -490,6 +504,70 @@ def test_save_and_load_round_trips_node_gtype_raw_data(node_comparer, tmp_path): assert len(cc2[0].raw_mod_data["Network_Model"]) == len( node_comparer.raw_mod_data["Network_Model"] ) + # The node was addressed by name, and the name is what comes back: reloading + # must not depend on the integer the network happened to hand out. + assert cc2[0].node == "123" + assert cc2[0].raw_mod_data["Network_Model"].node == "123" + + +def test_a_comparer_saved_by_1_4_0a3_still_loads(): + """The alpha wrote the graph integer into the node coordinate. + + Nothing on the load path derives a location from it any more, so such a file + keeps working -- it just gives the integer back. Needs no mikeio1d: it is a + netcdf file, not a network. + """ + cmp = ms.load("tests/testdata/node_comparer_1.4.0a3.nc") + + assert cmp.gtype == "node" + assert cmp.node == 0 + assert cmp.skill().to_dataframe().shape[0] == 1 + + +def test_save_and_load_round_trips_reach_gtype_raw_data(reach_comparer, tmp_path): + """Reach-gtype comparers must survive a save()/load() round trip too.""" + cc = ms.ComparerCollection([reach_comparer]) + fn = tmp_path / "test_cc_reach.msk" + cc.save(fn) + + cc2 = ms.load(fn) + + assert cc2[0].gtype == "reach" + assert cc2[0].reach == "r1" + assert len(cc2[0].raw_mod_data["Network_Model"]) == len( + reach_comparer.raw_mod_data["Network_Model"] + ) + + +def test_to_dataframe_on_a_node_comparer(node_comparer): + df = node_comparer.to_dataframe() + + assert list(df.columns) == ["Observation", "Network_Model"] + assert df.index.name == "time" + + +def test_to_dataframe_on_a_reach_comparer(reach_comparer): + """The location coordinates are dropped, as they are for every other gtype.""" + df = reach_comparer.to_dataframe() + + assert list(df.columns) == ["Observation", "Network_Model"] + assert df.index.name == "time" + + +def test_skill_on_a_node_comparer(node_comparer): + sk = node_comparer.skill() + + assert sk.to_dataframe().shape[0] == 1 + assert "Node_123_Obs" in sk.index + + +def test_plot_a_node_comparer(node_comparer): + assert node_comparer.plot.timeseries() is not None + assert node_comparer.plot.scatter() is not None + + +def test_plot_a_reach_comparer(reach_comparer): + assert reach_comparer.plot.timeseries() is not None # ======================== plotting ======================== diff --git a/tests/test_match.py b/tests/test_match.py index 3324f4788..ec0b25278 100644 --- a/tests/test_match.py +++ b/tests/test_match.py @@ -7,10 +7,6 @@ import modelskill as ms from modelskill.comparison._comparison import ItemSelection from modelskill.model.dfsu import DfsuModelResult -try: - from modelskill.network import _make_basic_network -except ImportError: - pass @pytest.fixture @@ -341,20 +337,24 @@ def test_only_1_model_depth_overlap(self, simple_vo, simple_vm): def network(): """Network fixture with 3 nodes""" pytest.importorskip("networkx") + from tests.network_helpers import make_network + time = pd.date_range("2017-10-27", periods=20, freq="h") np.random.seed(42) data = np.random.normal(1.5, 0.3, (20, 3)) - return _make_basic_network(["100", "200", "300"], time, data) + return make_network(["100", "200", "300"], time, data) @pytest.fixture def network2(): """Second network fixture with offset data for multi-model tests""" pytest.importorskip("networkx") + from tests.network_helpers import make_network + time = pd.date_range("2017-10-27", periods=20, freq="h") np.random.seed(42) data = np.random.normal(1.5, 0.3, (20, 3)) + 0.1 - return _make_basic_network(["100", "200", "300"], time, data) + return make_network(["100", "200", "300"], time, data) @pytest.fixture @@ -366,7 +366,7 @@ def network_mr(network): @pytest.fixture def node_obs1(network): """NodeObservation for node '100'""" - node_id = network.find(node="100") + node_id = "100" time = pd.date_range("2017-10-27", periods=18, freq="h") # Add some noise to make it different from model np.random.seed(123) @@ -378,7 +378,7 @@ def node_obs1(network): @pytest.fixture def node_obs2(network): """NodeObservation for node '200'""" - node_id = network.find(node="200") + node_id = "200" time = pd.date_range("2017-10-27", periods=15, freq="h") np.random.seed(456) data = np.random.normal(1.6, 0.25, len(time)) @@ -392,7 +392,7 @@ def node_obs_invalid(network): time = pd.date_range("2017-10-27", periods=10, freq="h") data = np.random.normal(1.5, 0.2, len(time)) df = pd.DataFrame({"WaterLevel": data}, index=time) - return ms.NodeObservation(df, at=999, name="Node_999_Obs") + return ms.NodeObservation(df, at="999", name="Node_999_Obs") @pytest.fixture @@ -410,7 +410,7 @@ def network_mr2(network2): @pytest.fixture def node_obs_gaps(network): """NodeObservation with time gaps""" - node_id = network.find(node="100") + node_id = "100" time = pd.date_range("2017-10-27", periods=10, freq="2h") # Different frequency data = np.random.normal(1.5, 0.2, len(time)) df = pd.DataFrame({"WaterLevel": data}, index=time) @@ -1007,6 +1007,37 @@ def test_match_node_obs_with_network_model(node_obs1, network_mr): assert cmp.mod_names == ["Network_Model"] +def test_match_reach_obs_with_network_model(): + """A reach observation matches any breakpoint along the reach.""" + pytest.importorskip("mikeio1d.network") + from tests.network_helpers import make_breakpoint_network + + time = pd.date_range("2017-10-27", periods=20, freq="h") + np.random.seed(42) + model_data = pd.DataFrame( + {"WaterLevel": np.random.normal(1.5, 0.3, len(time))}, index=time + ) + network_mr = ms.NetworkModelResult( + make_breakpoint_network("r0", 50.0, model_data), name="Network_Model" + ) + + np.random.seed(123) + obs_time = time[:18] + df = pd.DataFrame( + {"WaterLevel": np.random.normal(1.4, 0.2, len(obs_time))}, index=obs_time + ) + obs = ms.ReachObservation(df, reach="r0", name="Reach_r0") + + cmp = ms.match(obs, network_mr) + + assert cmp.n_models == 1 + assert cmp.n_points == 18 + assert cmp.name == "Reach_r0" + assert cmp.gtype == "reach" + assert cmp.reach == "r0" + assert cmp.mod_names == ["Network_Model"] + + def test_match_multiple_node_obs_with_network(node_obs1, node_obs2, network_mr): cc = ms.match([node_obs1, node_obs2], network_mr) assert cc.n_models == 1 @@ -1027,7 +1058,7 @@ def test_match_node_obs_with_multiple_network_models( def test_match_network_invalid_node_error(node_obs_invalid, network_mr): - with pytest.raises(ValueError, match="Node 999 not found"): + with pytest.raises(ValueError, match="not found"): ms.match(node_obs_invalid, network_mr) @@ -1064,7 +1095,8 @@ def test_network_match_multi_obs_multi_model_comprehensive( def test_network_match_error_non_node_observation(network_mr, point_obs_error): """Test that non-NodeObservation raises appropriate error""" with pytest.raises( - TypeError, match="NetworkModelResult supports NodeObservation and ReachObservation" + TypeError, + match="NetworkModelResult supports NodeObservation and ReachObservation", ): ms.match(point_obs_error, network_mr) diff --git a/tests/test_network.py b/tests/test_network.py index a41fc997b..ba05934be 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -2,74 +2,24 @@ # ruff: noqa: E402 import sys -from pathlib import Path import pytest -pytest.importorskip("networkx") +pytest.importorskip("mikeio1d.network") import pandas as pd import xarray as xr import numpy as np +import mikeio1d import modelskill as ms -from modelskill.model.network import ( +from mikeio1d.network import Network, BasicNode, BasicReach +from modelskill import ( NetworkModelResult, - NodeModelResult, + NodeObservation, + Quantity, + ReachObservation, ) -from modelskill.model.adapters._inp import read_pipe_lengths, read_sections -from modelskill.model.adapters._res1d import ( - Res1DNode, - Res1DReach, - _simplify_colnames, -) -from modelskill.network import ( - Network, - BasicNode, - BasicReach, - NetworkReach, - ReachBreakPoint, - _EPANET_EXTENSIONS, - _MIKE_EXTENSIONS, - _UNSUPPORTED_EXTENSIONS, -) -from modelskill.obs import NodeObservation -from modelskill.quantity import Quantity - - -def _make_network(node_ids, time, data, quantity="WaterLevel"): - nodes = [ - BasicNode(nid, pd.DataFrame({quantity: data[:, i]}, index=time)) - for i, nid in enumerate(node_ids) - ] - reaches = [ - BasicReach(f"r{i}", nodes[i], nodes[i + 1], length=100.0) - for i in range(len(nodes) - 1) - ] - return Network(reaches) - - -@pytest.fixture -def sample_network_data(): - """Sample network data as xr.Dataset""" - time = pd.date_range("2010-01-01", periods=10, freq="h") - nodes = [123, 456, 789] - - # Create sample data - np.random.seed(42) # For reproducible tests - data = np.random.randn(len(time), len(nodes)) - - ds = xr.Dataset( - { - "WaterLevel": (["time", "node"], data), - }, - coords={ - "time": time, - "node": nodes, - }, - ) - ds["WaterLevel"].attrs["units"] = "m" - ds["WaterLevel"].attrs["long_name"] = "Water Level" - return ds +from tests.network_helpers import make_breakpoint_network, make_network, node_series @pytest.fixture @@ -78,7 +28,7 @@ def sample_network(): time = pd.date_range("2010-01-01", periods=10, freq="h") np.random.seed(42) data = np.random.randn(10, 3) - return _make_network(["123", "456", "789"], time, data) + return make_network(["123", "456", "789"], time, data) @pytest.fixture @@ -102,25 +52,12 @@ def sample_network_multivars(): @pytest.fixture -def dataset_without_node(): +def breakpoint_network(): + """A one-reach network whose data sits on a break point, not on the nodes.""" time = pd.date_range("2010-01-01", periods=10, freq="h") - - # Create sample data - np.random.seed(42) # For reproducible tests - data = np.random.randn(len(time)) - - ds = xr.Dataset( - { - "WaterLevel": (["time"], data), - }, - coords={ - "time": time, - }, - ) - ds["WaterLevel"].attrs["units"] = "m" - ds["WaterLevel"].attrs["long_name"] = "Water Level" - - return ds + np.random.seed(42) + values = pd.DataFrame({"WaterLevel": np.random.randn(10)}, index=time) + return make_breakpoint_network("r1", 50.0, values) @pytest.fixture @@ -152,22 +89,42 @@ def test_init_with_network(self, sample_network): assert len(nmr.time) == 10 assert isinstance(nmr.time, pd.DatetimeIndex) - assert len(nmr.nodes) == 3 + + def test_quantity_name_survives_to_the_model_result(self, sample_network): + """The network knows its quantity by name even without a unit.""" + nmr = NetworkModelResult(sample_network) + + assert nmr.quantity.name == "WaterLevel" + assert nmr.quantity != Quantity.undefined() + + def test_quantity_carries_into_extracted_node(self, sample_network): + nmr = NetworkModelResult(sample_network) + obs_data = pd.DataFrame({"sensor": np.zeros(len(nmr.time))}, index=nmr.time) + extracted = nmr.extract(NodeObservation(obs_data, at="123")) + + assert extracted.quantity.name == "WaterLevel" + + def test_explicit_quantity_wins(self, sample_network): + given = Quantity(name="Water Level", unit="meter") + nmr = NetworkModelResult(sample_network, quantity=given) + + assert nmr.quantity == given def test_init_with_name(self, sample_network): """Test initialization with explicit name""" nmr = NetworkModelResult(sample_network, name="Test_Network") assert nmr.name == "Test_Network" - def test_init_with_item_selection(self, sample_network_multivars): + def test_init_with_item_selection(self, sample_network_multivars, sample_node_data): """Test initialization with specific item selection""" nmr = NetworkModelResult( sample_network_multivars, item="WaterLevel", name="Network_WL" ) + extracted = nmr.extract(NodeObservation(sample_node_data, at="123")) assert nmr.name == "Network_WL" - assert "WaterLevel" in nmr.data.data_vars - assert "Discharge" not in nmr.data.data_vars + assert nmr.quantity.name == "WaterLevel" + assert extracted.quantity.name == "WaterLevel" def test_init_fails_with_unsupported_type(self): """Test that passing a non-Network object raises an error""" @@ -185,21 +142,20 @@ def test_repr(self, sample_network): def test_extract_valid_node(self, sample_network, sample_node_data): """Test extraction of a valid node""" nmr = NetworkModelResult(sample_network) - node_id = sample_network.find(node="123") + node_id = "123" obs = NodeObservation(sample_node_data, at=node_id, name="Node_123") extracted = nmr.extract(obs) - assert isinstance(extracted, NodeModelResult) assert extracted.node == node_id assert len(extracted.time) == 10 def test_extract_invalid_node(self, sample_network, sample_node_data): """Test extraction of a node not present in the network""" nmr = NetworkModelResult(sample_network) - obs = NodeObservation(sample_node_data, at=999, name="Node_999") + obs = NodeObservation(sample_node_data, at="999", name="Node_999") - with pytest.raises(ValueError, match="Node 999 not found"): + with pytest.raises(ValueError, match="not found"): nmr.extract(obs) def test_extract_wrong_observation_type(self, sample_network): @@ -236,26 +192,26 @@ def test_init_with_df(self, sample_node_data): """Test initialization with pandas DataFrame""" obs = NodeObservation( - sample_node_data, at=123, name="Sensor_1", item="WaterLevel" + sample_node_data, at="123", name="Sensor_1", item="WaterLevel" ) - assert obs.at == 123 + assert obs.at == "123" assert obs.name == "Sensor_1" assert len(obs.time) == 10 assert isinstance(obs.time, pd.DatetimeIndex) def test_init_with_series(self, sample_series): """Test initialization with pandas Series""" - obs = NodeObservation(sample_series, at=456, name="Node_456") + obs = NodeObservation(sample_series, at="456", name="Node_456") - assert obs.at == 456 + assert obs.at == "456" assert obs.name == "Node_456" assert len(obs.time) == 10 def test_node_attrs(self, sample_node_data): """Test attrs property""" attrs = {"source": "test", "version": "1.0"} - obs = NodeObservation(sample_node_data, at=123, attrs=attrs, weight=2.5) + obs = NodeObservation(sample_node_data, at="123", attrs=attrs, weight=2.5) assert obs.attrs["source"] == "test" assert obs.attrs["version"] == "1.0" @@ -266,7 +222,7 @@ def test_multiple_nodes_returns_list_of_observations(self, multi_data): """Test that from_multiple returns a list of NodeObservation objects""" obs_list = NodeObservation.from_multiple( data=multi_data, - nodes={123: "station_0", 456: "station_1", 789: "station_2"}, + nodes={"123": "station_0", "456": "station_1", "789": "station_2"}, ) assert len(obs_list) == 3 @@ -275,17 +231,17 @@ def test_multiple_nodes_returns_list_of_observations(self, multi_data): def test_node_ids_are_assigned_correctly(self, multi_data): obs_list = NodeObservation.from_multiple( data=multi_data, - nodes={123: "station_0", 456: "station_1", 789: "station_2"}, + nodes={"123": "station_0", "456": "station_1", "789": "station_2"}, ) - assert obs_list[0].node == 123 - assert obs_list[1].node == 456 - assert obs_list[2].node == 789 + assert obs_list[0].node == "123" + assert obs_list[1].node == "456" + assert obs_list[2].node == "789" def test_names_derived_from_column_names(self, multi_data): obs_list = NodeObservation.from_multiple( data=multi_data, - nodes={123: "station_0", 456: "station_1", 789: "station_2"}, + nodes={"123": "station_0", "456": "station_1", "789": "station_2"}, ) assert obs_list[0].name == "station_0" @@ -301,12 +257,12 @@ def test_from_xarray_dataset(self, sample_node_data): coords={"time": sample_node_data.index}, ) obs_list = NodeObservation.from_multiple( - data=ds, nodes={123: "station_0", 456: "station_1"} + data=ds, nodes={"123": "station_0", "456": "station_1"} ) assert len(obs_list) == 2 - assert obs_list[0].node == 123 - assert obs_list[1].node == 456 + assert obs_list[0].node == "123" + assert obs_list[1].node == "456" def test_nodes_must_be_dict(self, multi_data): with pytest.raises(TypeError, match="'nodes' must be a dict"): @@ -316,7 +272,7 @@ def test_attrs_propagated_to_all_observations(self, multi_data): attrs = {"source": "sensor_array", "version": 2} obs_list = NodeObservation.from_multiple( data=multi_data, - nodes={1: "station_0", 2: "station_1", 3: "station_2"}, + nodes={"1": "station_0", "2": "station_1", "3": "station_2"}, attrs=attrs, ) @@ -326,38 +282,38 @@ def test_attrs_propagated_to_all_observations(self, multi_data): def test_init_from_csv(self): obs = NodeObservation( - "tests/testdata/network_sensor_1.csv", at=1, item="water_level@sens1" + "tests/testdata/network_sensor_1.csv", at="1", item="water_level@sens1" ) - assert obs.at == 1 + assert obs.at == "1" assert len(obs.time) == 110 assert isinstance(obs.time, pd.DatetimeIndex) def test_from_multiple_csvs_via_dict(self): obs_list = NodeObservation.from_multiple( nodes={ - 1: "tests/testdata/network_sensor_1.csv", - 2: "tests/testdata/network_sensor_2.csv", - 3: "tests/testdata/network_sensor_3.csv", + "1": "tests/testdata/network_sensor_1.csv", + "2": "tests/testdata/network_sensor_2.csv", + "3": "tests/testdata/network_sensor_3.csv", } ) assert len(obs_list) == 3 assert all(isinstance(obs, NodeObservation) for obs in obs_list) - assert obs_list[0].node == 1 - assert obs_list[1].node == 2 - assert obs_list[2].node == 3 + assert obs_list[0].node == "1" + assert obs_list[1].node == "2" + assert obs_list[2].node == "3" for obs in obs_list: assert len(obs.time) > 0 def test_nodes_dict_maps_node_to_item(self, multi_data): obs_list = NodeObservation.from_multiple( - data=multi_data, nodes={123: "station_0", 456: "station_1"} + data=multi_data, nodes={"123": "station_0", "456": "station_1"} ) assert len(obs_list) == 2 - assert obs_list[0].node == 123 - assert obs_list[1].node == 456 + assert obs_list[0].node == "123" + assert obs_list[1].node == "456" assert obs_list[0].name == "station_0" assert obs_list[1].name == "station_1" @@ -367,26 +323,77 @@ def test_nodes_none_raises(self, multi_data): def test_single_node_dict(self, sample_node_data): obs_list = NodeObservation.from_multiple( - data=sample_node_data, nodes={123: "WaterLevel"} + data=sample_node_data, nodes={"123": "WaterLevel"} ) assert len(obs_list) == 1 assert isinstance(obs_list[0], NodeObservation) - assert obs_list[0].node == 123 + assert obs_list[0].node == "123" + def test_nodes_keys_accept_aliases(self, multi_data): + obs_list = NodeObservation.from_multiple( + data=multi_data, nodes={"node_A": "station_0", "node_B": "station_1"} + ) -class TestNodeModelResult: - """Test NodeModelResult class""" + assert [obs.at for obs in obs_list] == ["node_A", "node_B"] - @pytest.mark.parametrize("fixture_name", ["sample_node_data", "sample_series"]) - def test_init_(self, request, fixture_name): - """Test initialization with pandas DataFrame""" - data = request.getfixturevalue(fixture_name) - nmr = NodeModelResult(data, node=123, name="Node_123_Model") + def test_nodes_keys_accept_breakpoints(self, multi_data): + obs_list = NodeObservation.from_multiple( + data=multi_data, + nodes={("reach_1", 24.5): "station_0", ("reach_1", 50.0): "station_1"}, + ) - assert nmr.node == 123 - assert nmr.name == "Node_123_Model" - assert len(nmr.time) == 10 + assert [obs.at for obs in obs_list] == [("reach_1", 24.5), ("reach_1", 50.0)] + + +class TestReachObservationFromMultiple: + @pytest.fixture + def multi_data(self, sample_node_data): + return pd.DataFrame( + { + "station_0": sample_node_data["WaterLevel"].values, + "station_1": sample_node_data["WaterLevel"].values + 0.1, + }, + index=sample_node_data.index, + ) + + def test_returns_list_of_reach_observations(self, multi_data): + obs_list = ReachObservation.from_multiple( + data=multi_data, reaches={"reach_1": "station_0", "reach_2": "station_1"} + ) + + assert len(obs_list) == 2 + assert all(isinstance(obs, ReachObservation) for obs in obs_list) + assert [obs.reach for obs in obs_list] == ["reach_1", "reach_2"] + assert [obs.name for obs in obs_list] == ["station_0", "station_1"] + + def test_separate_data_sources(self): + obs_list = ReachObservation.from_multiple( + reaches={ + "reach_1": "tests/testdata/network_sensor_1.csv", + "reach_2": "tests/testdata/network_sensor_2.csv", + } + ) + + assert [obs.reach for obs in obs_list] == ["reach_1", "reach_2"] + assert all(len(obs.time) > 0 for obs in obs_list) + + def test_attrs_propagated(self, multi_data): + obs_list = ReachObservation.from_multiple( + data=multi_data, + reaches={"reach_1": "station_0"}, + attrs={"source": "sensor_array"}, + ) + + assert obs_list[0].attrs["source"] == "sensor_array" + + def test_reaches_none_raises(self, multi_data): + with pytest.raises(ValueError, match="'reaches' argument is required"): + ReachObservation.from_multiple(data=multi_data, reaches=None) + + def test_reaches_must_be_dict(self, multi_data): + with pytest.raises(TypeError, match="'reaches' must be a dict"): + ReachObservation.from_multiple(data=multi_data, reaches="reach_1") class TestNetworkIntegration: @@ -395,12 +402,11 @@ class TestNetworkIntegration: def test_network_to_node_extraction(self, sample_network, sample_node_data): """Test complete workflow from network model to node extraction""" nmr = NetworkModelResult(sample_network, name="Network_Model") - node_id = sample_network.find(node="123") + node_id = "123" obs = NodeObservation(sample_node_data, at=node_id, name="Node_123_Obs") extracted = nmr.extract(obs) - assert isinstance(extracted, NodeModelResult) assert extracted.node == node_id assert extracted.name == "Network_Model" assert len(extracted.time) == len(obs.time) @@ -408,7 +414,7 @@ def test_network_to_node_extraction(self, sample_network, sample_node_data): def test_matching_workflow(self, sample_network, sample_node_data): """Test matching workflow with network data""" nmr = NetworkModelResult(sample_network, name="Network_Model") - node_id = sample_network.find(node="123") + node_id = "123" obs = NodeObservation(sample_node_data, at=node_id, name="Node_123_Obs") comparer = ms.match(obs, nmr) @@ -429,9 +435,9 @@ def test_matching_workflow_multiple_nodes(self, sample_network, sample_node_data } ) - node_0 = sample_network.find(node="123") - node_1 = sample_network.find(node="456") - node_2 = sample_network.find(node="789") + node_0 = "123" + node_1 = "456" + node_2 = "789" # Create multiple NodeObservations using .from_multiple obs_list = NodeObservation.from_multiple( @@ -450,439 +456,283 @@ def test_matching_workflow_multiple_nodes(self, sample_network, sample_node_data assert comparer.n_points > 0 -@pytest.mark.skipif( - sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" -) -def test_open_res1d(): - path_to_file = "./tests/testdata/network.res1d" - network = Network.from_mike(path_to_file) - assert network.graph.number_of_nodes() == 259 +class TestValuesReachTheComparer: + """The series a comparer holds is the one the network keeps at that location. + The observation is built from the model's own data, so an exact match is the + expected outcome and any mix-up between locations, quantities or models shows + up as a non-zero score. + """ -@pytest.mark.skipif( - sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" -) -def test_extract_reach_observation_happy_path(sample_node_data): - path_to_file = "./tests/testdata/network.res1d" - network = Network.from_mike(path_to_file) - nmr = NetworkModelResult(network, item="Discharge", name="network_model") - obs_data = sample_node_data.rename(columns={"WaterLevel": "Discharge"}) - obs = ms.ReachObservation(obs_data, reach="100l1", item="Discharge") + def test_extract_returns_the_nodes_own_series(self, sample_network): + values = node_series(sample_network) + nmr = NetworkModelResult(sample_network, name="Network_Model") + obs = NodeObservation(values, at="456", item="456") - extracted = nmr.extract(obs) + extracted = nmr.extract(obs) - assert isinstance(extracted, NodeModelResult) - assert extracted.name == "network_model" - assert extracted.node in nmr.nodes + assert extracted.to_dataframe()["Network_Model"].to_numpy() == pytest.approx( + values["456"].to_numpy() + ) + def test_a_matched_node_scores_zero_against_its_own_series(self, sample_network): + values = node_series(sample_network) + nmr = NetworkModelResult(sample_network, name="Network_Model") + obs = NodeObservation(values, at="456", item="456", name="Node_456_Obs") -@pytest.mark.skipif( - sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" -) -def test_extract_reach_observation_non_equivalent_breakpoints_raises(sample_node_data): - path_to_file = "./tests/testdata/network.res1d" - network = Network.from_mike(path_to_file) - nmr = NetworkModelResult(network, item="Discharge") - obs_data = sample_node_data.rename(columns={"WaterLevel": "Discharge"}) - obs = ms.ReachObservation(obs_data, reach="113l1", item="Discharge") + cmp = ms.match(obs, nmr) - with pytest.raises(ValueError, match="Not all data in breakpoints are equivalent"): - nmr.extract(obs) + assert cmp.n_points == len(values) + assert cmp.score()["Network_Model"] == pytest.approx(0.0) + def test_every_node_of_a_collection_keeps_its_own_series(self, sample_network): + """One observation per node, each read from that node's own column.""" + values = node_series(sample_network) + nmr = NetworkModelResult(sample_network, name="Network_Model") + obs_list = NodeObservation.from_multiple( + data=values, nodes={nid: nid for nid in values.columns} + ) -@pytest.mark.skipif( - sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" -) -def test_extract_reach_observation_with_reaches_not_populated_raises_valueerror( - sample_node_data, -): - path_to_file = "./tests/testdata/network.res1d" - network = Network.from_mike(path_to_file, reaches=[]) - nmr = NetworkModelResult(network, item="WaterLevel") - obs = ms.ReachObservation(sample_node_data, reach="100l1", item="WaterLevel") + cc = ms.match(obs_list, nmr) - with pytest.raises(ValueError, match="none of its breakpoints have data loaded"): - nmr.extract(obs) + assert len(cc) == 3 + for cmp in cc: + assert cmp.score()["Network_Model"] == pytest.approx(0.0) + def test_two_networks_keep_their_series_apart(self, sample_network): + """The second network is the first shifted by 0.1. -@pytest.mark.skipif( - sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" -) -def test_extract_reach_observation_breakpoint_node_missing_raises_valueerror( - sample_node_data, -): - path_to_file = "./tests/testdata/network.res1d" - network = Network.from_mike(path_to_file) - nmr = NetworkModelResult(network, item="Discharge") - obs_data = sample_node_data.rename(columns={"WaterLevel": "Discharge"}) - baseline_obs = ms.ReachObservation(obs_data, reach="100l1", item="Discharge") - node_id = nmr.extract(baseline_obs).node - remaining_nodes = [] - for node in nmr.data.node.values: - node_int = int(node) - if node_int != node_id: - remaining_nodes.append(node_int) - nmr.data = nmr.data.sel(node=remaining_nodes) + A crossed model column would put that shift on the wrong name. + """ + values = node_series(sample_network) + shifted = make_network( + list(values.columns), values.index, values.to_numpy() + 0.1 + ) + obs = NodeObservation(values, at="456", item="456", name="Node_456_Obs") + + cmp = ms.match( + obs, + [ + NetworkModelResult(sample_network, name="Network_1"), + NetworkModelResult(shifted, name="Network_2"), + ], + ) - obs = ms.ReachObservation(obs_data, reach="100l1", item="Discharge") + bias = cmp.score(metric="bias") + assert bias["Network_1"] == pytest.approx(0.0) + assert bias["Network_2"] == pytest.approx(0.1) - with pytest.raises(ValueError, match="matching breakpoint nodes are missing"): - nmr.extract(obs) + def test_a_matched_breakpoint_scores_zero_against_its_own_series( + self, breakpoint_network + ): + """The break point's data sits on neither of the reach's nodes.""" + values = breakpoint_network.reaches["r1"].breakpoints[0].data + nmr = NetworkModelResult(breakpoint_network, name="Network_Model") + obs = NodeObservation(values, at=("r1", 50.0), name="BP_Obs") + cmp = ms.match(obs, nmr) -@pytest.mark.skipif( - sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" -) -def test_from_mike_nodes_filter_creates_full_network(): - """When nodes is specified, the full network topology is created.""" - path_to_file = "./tests/testdata/network.res1d" - full_network = Network.from_mike(path_to_file) + assert cmp.n_points == len(values) + assert cmp.score()["Network_Model"] == pytest.approx(0.0) - selected_nodes = ["1", "108"] - partial_network = Network.from_mike(path_to_file, nodes=selected_nodes) + def test_a_matched_reach_scores_zero_against_its_breakpoints_series( + self, breakpoint_network + ): + values = breakpoint_network.reaches["r1"].breakpoints[0].data + nmr = NetworkModelResult(breakpoint_network, name="Network_Model") + obs = ReachObservation(values, reach="r1", name="Reach_Obs") - # Full topology is preserved - assert ( - partial_network.graph.number_of_nodes() == full_network.graph.number_of_nodes() - ) + cmp = ms.match(obs, nmr) + assert cmp.n_points == len(values) + assert cmp.score()["Network_Model"] == pytest.approx(0.0) -@pytest.mark.skipif( - sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" -) -def test_from_mike_nodes_filter_only_selected_have_data(): - """When nodes is specified, only selected nodes contain non-empty data.""" - path_to_file = "./tests/testdata/network.res1d" + def test_the_selected_item_brings_its_own_values(self, sample_network_multivars): + """Discharge is ten times WaterLevel here, so the selected column cannot + pass for the one left behind.""" + discharge = node_series(sample_network_multivars, "Discharge") + nmr = NetworkModelResult( + sample_network_multivars, item="Discharge", name="Network_Model" + ) + obs = NodeObservation(discharge, at="123", item="123") + + extracted = nmr.extract(obs) + + assert extracted.to_dataframe()["Network_Model"].to_numpy() == pytest.approx( + discharge["123"].to_numpy() + ) - selected_nodes = ["1", "108"] - network = Network.from_mike(path_to_file, nodes=selected_nodes, reaches=[]) - g = network.graph.copy() + def test_a_matched_item_scores_zero_against_its_own_series( + self, sample_network_multivars + ): + discharge = node_series(sample_network_multivars, "Discharge") + nmr = NetworkModelResult( + sample_network_multivars, item="Discharge", name="Network_Model" + ) + obs = NodeObservation(discharge, at="123", item="123", name="Node_123_Obs") - n_nodes = network.graph.number_of_nodes() - assert sum([g.nodes[n]["data"].empty for n in g.nodes]) == n_nodes - 2 - for n in selected_nodes: - assert not g.nodes[network.find(n)]["data"].empty + cmp = ms.match(obs, nmr) + + assert cmp.score()["Network_Model"] == pytest.approx(0.0) + + def test_an_aux_item_brings_its_own_values(self, sample_network_multivars): + """The aux item rides alongside the scored one, and holds its own series.""" + water_level = node_series(sample_network_multivars) + discharge = node_series(sample_network_multivars, "Discharge") + nmr = NetworkModelResult( + sample_network_multivars, + item="WaterLevel", + aux_items=["Discharge"], + name="Network_Model", + ) + obs = NodeObservation(water_level, at="123", item="123", name="Node_123_Obs") + + cmp = ms.match(obs, nmr) + + assert cmp.data["Discharge"].attrs["kind"] == "aux" + assert cmp.data["Discharge"].to_numpy() == pytest.approx( + discharge["123"].to_numpy() + ) + assert cmp.score()["Network_Model"] == pytest.approx(0.0) @pytest.mark.skipif( sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" ) -def test_from_mike_nodes_single_string(): - """nodes argument accepts a single string (not just a list).""" - path_to_file = "./tests/testdata/network.res1d" - full_network = Network.from_mike(path_to_file) +def test_a_model_result_built_from_a_file_carries_the_files_own_values(): + """Checked against mikeio1d's own read of the file. - network = Network.from_mike(path_to_file, nodes="108", reaches=[]) - g = network.graph.copy() + That read goes straight to the result file, not through the Network the + model result is built on, so the two agreeing pins the whole way in. + """ + path = "./tests/testdata/network.res1d" + expected = mikeio1d.open(path).nodes.read()["WaterLevel:1"] + mr = NetworkModelResult(path, item="WaterLevel", name="Network_Model") + obs = NodeObservation(expected, at="1", name="Node_1_Obs") - assert g.number_of_nodes() == full_network.graph.number_of_nodes() + extracted = mr.extract(obs) - nodes_with_data = [n for n in g.nodes if not g.nodes[n]["data"].empty] - nodes_with_data = [network.recall(n)["node"] for n in nodes_with_data] - assert nodes_with_data == ["108"] + assert extracted.to_dataframe()["Network_Model"].to_numpy() == pytest.approx( + expected.to_numpy() + ) @pytest.mark.skipif( sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" ) -def test_dataframe_from_partial_network(): - """nodes argument accepts a single string (not just a list).""" - path_to_file = "./tests/testdata/network.res1d" - selected_nodes = ["108", "101"] - network = Network.from_mike(path_to_file, nodes=selected_nodes, reaches=[]) - nodes_in_df = network.to_dataframe().droplevel(axis=1, level=1).columns +def test_a_model_result_can_be_built_from_a_result_file(): + mr = NetworkModelResult("./tests/testdata/network.res1d", item="WaterLevel") - assert set(nodes_in_df) == set([network.find(n) for n in selected_nodes]) + assert mr.quantity.name == "WaterLevel" + assert len(mr.time) > 0 @pytest.mark.skipif( sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" ) -def test_nodes_filtered_network_keeps_datetime_index(): - """Topology-only nodes must not degrade the time index to object dtype. - - A nodes-filtered network keeps the full topology, storing empty data for - the unselected nodes. Concatenating those empty (RangeIndex) frames must - not corrupt the DatetimeIndex, otherwise ms.match() later fails with - "time must be datetime". - """ +def test_extract_reach_observation_happy_path(sample_node_data): path_to_file = "./tests/testdata/network.res1d" - network = Network.from_mike(path_to_file, nodes=["108", "101"], reaches=[]) + network = Network.open(path_to_file) + nmr = NetworkModelResult(network, item="Discharge", name="network_model") + obs_data = sample_node_data.rename(columns={"WaterLevel": "Discharge"}) + obs = ms.ReachObservation(obs_data, reach="100l1", item="Discharge") - assert isinstance(network._df.index, pd.DatetimeIndex) - assert network._df.index.dtype == "datetime64[ns]" - assert network.to_dataset()["time"].dtype == np.dtype("datetime64[ns]") + extracted = nmr.extract(obs) + + assert extracted.name == "network_model" + reach, _ = extracted.node + assert reach == "100l1" @pytest.mark.skipif( sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" ) -def test_from_res1d_empty_nodes_and_reaches_keeps_topology_and_empty_outputs(): +def test_extract_reach_observation_non_equivalent_breakpoints_raises(sample_node_data): path_to_file = "./tests/testdata/network.res1d" - network = Network.from_mike(path_to_file, nodes=["108", "101"], reaches=[]) + network = Network.open(path_to_file) + nmr = NetworkModelResult(network, item="Discharge") + obs_data = sample_node_data.rename(columns={"WaterLevel": "Discharge"}) + obs = ms.ReachObservation(obs_data, reach="113l1", item="Discharge") - assert isinstance(network._df.index, pd.DatetimeIndex) - assert network._df.index.dtype == "datetime64[ns]" - assert network.to_dataset()["time"].dtype == np.dtype("datetime64[ns]") + with pytest.raises(ValueError, match="Not all data in breakpoints are equivalent"): + nmr.extract(obs) @pytest.mark.skipif( sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" ) -def test_from_mike_empty_nodes_and_reaches_keeps_topology_and_empty_outputs(): +def test_extract_reach_observation_with_reaches_not_populated_raises_valueerror( + sample_node_data, +): path_to_file = "./tests/testdata/network.res1d" - full_network = Network.from_mike(path_to_file) - network = Network.from_mike(path_to_file, nodes=[], reaches=[]) - - assert network.graph.number_of_nodes() == full_network.graph.number_of_nodes() - - df = network.to_dataframe() - assert df.empty - assert isinstance(df.columns, pd.MultiIndex) - assert df.columns.names == ["node", "quantity"] - assert df.index.name == "time" - - ds = network.to_dataset() - assert isinstance(ds, xr.Dataset) - assert len(ds.data_vars) == 0 - - -# --------------------------------------------------------------------------- -# Optional reach length -# --------------------------------------------------------------------------- - - -class _StubBreakPoint(ReachBreakPoint): - """Minimal concrete ReachBreakPoint for building reaches by hand.""" - - def __init__(self, reach_id, distance, data=None): - self._id = (reach_id, distance) - self._data = pd.DataFrame() if data is None else data - - @property - def id(self): - return self._id - - @property - def data(self): - return self._data - - -def _two_node_pair(): - time = pd.date_range("2020", periods=3, freq="h") - df = pd.DataFrame({"WaterLevel": [1.0, 1.1, 1.2]}, index=time) - return BasicNode("a", df), BasicNode("b", df.copy()) - - -class TestOptionalReachLength: - """Reach length is undefined in some domains, so it must be omittable.""" - - def test_subclass_may_omit_length(self): - class LengthlessReach(NetworkReach): - def __init__(self, id, start, end): - self._id, self._start, self._end = id, start, end - - @property - def id(self): - return self._id - - @property - def start(self): - return self._start - - @property - def end(self): - return self._end - - @property - def breakpoints(self): - return [] - - a, b = _two_node_pair() - reach = LengthlessReach("r1", a, b) - - assert reach.length is None - assert Network([reach]).graph.number_of_nodes() == 2 - - def test_basic_reach_length_defaults_to_none(self): - a, b = _two_node_pair() - - assert BasicReach("r1", a, b).length is None - - def test_edge_length_is_none_when_undefined(self): - a, b = _two_node_pair() - - network = Network([BasicReach("r1", a, b)]) - - assert [d["length"] for *_, d in network.graph.edges(data=True)] == [None] - - def test_breakpoint_distances_survive_an_undefined_length(self): - """Only the final segment needs the total, so the rest keep real lengths.""" - a, b = _two_node_pair() - breakpoints = [_StubBreakPoint("r1", d) for d in (30.0, 70.0)] - - network = Network([BasicReach("r1", a, b, breakpoints=breakpoints)]) - - lengths = sorted( - (d["length"] for *_, d in network.graph.edges(data=True)), - key=lambda v: (v is None, v), - ) - assert lengths == [30.0, 40.0, None] - - def test_length_weighted_algorithms_fail_loudly(self): - """Storing None keeps networkx honest. - - Omitting the attribute instead would let networkx default the weight to - 1, so every call below would return a plausible but meaningless number. - With None, shortest-path treats the edge as hidden and the arithmetic - consumers raise. - """ - import networkx as nx - - a, b = _two_node_pair() - g = Network([BasicReach("r1", a, b)]).graph - - with pytest.raises(nx.NetworkXNoPath): - nx.shortest_path_length(g, 0, 1, weight="length") - - with pytest.raises(TypeError): - g.size(weight="length") - - def test_known_length_is_unchanged(self): - a, b = _two_node_pair() - breakpoints = [_StubBreakPoint("r1", 40.0)] - - network = Network([BasicReach("r1", a, b, 100.0, breakpoints)]) - - assert sorted(d["length"] for *_, d in network.graph.edges(data=True)) == [ - 40.0, - 60.0, - ] - + network = Network.open(path_to_file, reaches=[]) + nmr = NetworkModelResult(network, item="WaterLevel") + obs = ms.ReachObservation(sample_node_data, reach="100l1", item="WaterLevel") -# --------------------------------------------------------------------------- -# Which extensions each constructor accepts, and why the rest are refused -# --------------------------------------------------------------------------- + with pytest.raises(ValueError, match="none of its breakpoints have data loaded"): + nmr.extract(obs) @pytest.mark.skipif( sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" ) -class TestExtensionPolicy: - @pytest.mark.parametrize("suffix", [".res1d", ".res11", ".RES1D"]) - def test_from_mike_accepts_mike_extensions(self, tmp_path, suffix): - """The file does not exist, so mikeio1d - not the guard - is what complains.""" - with pytest.raises((FileExistsError, FileNotFoundError)): - Network.from_mike(tmp_path / f"network{suffix}") - - def test_error_lists_only_readable_extensions(self): - with pytest.raises(NotImplementedError) as excinfo: - Network.from_mike("network.nc") - - message = str(excinfo.value) - for extension in _MIKE_EXTENSIONS | _EPANET_EXTENSIONS: - assert extension in message - for extension in _UNSUPPORTED_EXTENSIONS: - assert extension not in message - - def test_swmm_refusal_names_the_companion_inp(self): - """A real file, so this fails the day SWMM support lands.""" - with pytest.raises(NotImplementedError, match=r"companion '\.inp'"): - Network.from_mike("./tests/testdata/swmm.out") - - def test_resx_refusal_points_at_the_resx_argument(self): - """'.resx' is a companion, so the message must name what to do instead.""" - with pytest.raises( - NotImplementedError, match=r"from_epanet\(res, resx=\.\.\.\)" - ): - Network.from_mike("./tests/testdata/epanet.resx") - - @pytest.mark.parametrize("suffix", [".prf", ".crf", ".xrf", ".whr"]) - def test_formats_without_a_fixture_are_refused(self, tmp_path, suffix): - with pytest.raises(NotImplementedError, match="no test fixture"): - Network.from_mike(tmp_path / f"network{suffix}") - - def test_every_mikeio1d_extension_is_accounted_for(self): - """A new mikeio1d format must be read or explicitly refused, never ignored.""" - from mikeio1d import Res1D - - accounted_for = ( - _MIKE_EXTENSIONS | _EPANET_EXTENSIONS | set(_UNSUPPORTED_EXTENSIONS) - ) - - assert accounted_for == Res1D.get_supported_file_extensions() - - def test_res1d_opened_with_a_path_is_refused(self): - """mikeio1d calls str.endswith on file_path, so a Path breaks it later on.""" - from mikeio1d import Res1D - - res = Res1D(Path("./tests/testdata/network.res1d")) - - with pytest.raises(TypeError, match="file_path"): - Network.from_mike(res) - +def test_extract_breakpoint_without_data_for_the_quantity_raises_valueerror( + sample_node_data, +): + """MIKE 1D stores WaterLevel and Discharge at alternating grid points, so a + breakpoint that exists can still hold nothing for the selected quantity.""" + network = Network.open("./tests/testdata/network.res1d") + nmr = NetworkModelResult(network, item="WaterLevel") + obs = ms.NodeObservation(sample_node_data, at=("94l1", 21.285), item="WaterLevel") -# --------------------------------------------------------------------------- -# NodeObservation — alias / breakpoint node forms -# --------------------------------------------------------------------------- + with pytest.raises(ValueError, match="no data for quantity 'WaterLevel'"): + nmr.extract(obs) class TestNodeObservationAliases: - """NodeObservation accepts int, str alias, and (reach, distance) tuple.""" + """NodeObservation accepts a node name or a (reach, distance) tuple.""" - def test_integer_node_unchanged(self, sample_node_data): - obs = NodeObservation(sample_node_data, at=42) - assert obs.at == 42 - assert isinstance(obs.at, int) - - def test_integer_node_coord(self, sample_node_data): - obs = NodeObservation(sample_node_data, at=42) - assert "node" in obs.data.coords - assert int(obs.data.coords["node"].item()) == 42 + @pytest.mark.parametrize("at", [42, np.int64(42)]) + def test_an_integer_is_refused(self, sample_node_data, at): + with pytest.raises(TypeError, match="not an integer"): + NodeObservation(sample_node_data, at=at) def test_string_alias_stored(self, sample_node_data): obs = NodeObservation(sample_node_data, at="node_A", name="test") assert obs.at == "node_A" assert isinstance(obs.at, str) + assert obs.gtype == "node" - def test_string_alias_has_node_coord(self, sample_node_data): - obs = NodeObservation(sample_node_data, at="node_A") - assert "node" in obs.data.coords - assert obs.data.coords["node"].item() == "node_A" - - def test_string_alias_gtype_is_node(self, sample_node_data): + def test_a_named_node_knows_its_node(self, sample_node_data): obs = NodeObservation(sample_node_data, at="node_A") - assert obs.data.attrs["gtype"] == "node" + assert obs.node == "node_A" def test_tuple_node_stored(self, sample_node_data): obs = NodeObservation(sample_node_data, at=("reach_1", 24.5)) assert obs.at == ("reach_1", 24.5) assert isinstance(obs.at, tuple) + assert obs.gtype == "node" - def test_tuple_node_gtype_is_node(self, sample_node_data): + def test_a_breakpoint_has_no_node_name(self, sample_node_data): + """`node` names a junction; a breakpoint is placed along a reach instead.""" obs = NodeObservation(sample_node_data, at=("reach_1", 24.5)) - assert obs.data.attrs["gtype"] == "node" + assert obs.node is None - def test_tuple_node_has_reach_distance_coords(self, sample_node_data): + def test_a_breakpoint_survives_trimming(self, sample_node_data): obs = NodeObservation(sample_node_data, at=("reach_1", 24.5)) - assert "reach" in obs.data.coords - assert "distance" in obs.data.coords - assert str(obs.data.coords["reach"].item()) == "reach_1" - assert float(obs.data.coords["distance"].item()) == pytest.approx(24.5) - def test_tuple_node_has_no_node_coord(self, sample_node_data): - obs = NodeObservation(sample_node_data, at=("reach_1", 24.5)) - assert "node" not in obs.data.coords + trimmed = obs.trim(start_time=obs.time[1], end_time=obs.time[-1]) - def test_tuple_node_roundtrip_via_create_new_instance(self, sample_node_data): - obs = NodeObservation(sample_node_data, at=("reach_1", 24.5)) - obs2 = obs._create_new_instance(obs.data) - assert obs2.at == ("reach_1", 24.5) + assert trimmed.at == ("reach_1", 24.5) + assert len(trimmed) == len(obs) - 1 - def test_string_roundtrip_via_create_new_instance(self, sample_node_data): + def test_a_named_node_observation_survives_trimming(self, sample_node_data): obs = NodeObservation(sample_node_data, at="node_A") - obs2 = obs._create_new_instance(obs.data) - assert obs2.at == "node_A" + + trimmed = obs.trim(start_time=obs.time[1], end_time=obs.time[-1]) + + assert trimmed.at == "node_A" + assert len(trimmed) == len(obs) - 1 # --------------------------------------------------------------------------- @@ -891,107 +741,73 @@ def test_string_roundtrip_via_create_new_instance(self, sample_node_data): class TestNetworkModelResultAliasResolution: - """NetworkModelResult.extract() resolves str and tuple aliases via alias_map.""" + """extract() resolves a node name or a (reach, distance) pair to a location.""" - def test_network_stored(self, sample_network): + def test_the_network_is_kept_as_given(self, sample_network): nmr = NetworkModelResult(sample_network) - assert hasattr(nmr, "network") - assert "123" in nmr.network._alias_map - assert "456" in nmr.network._alias_map - assert "789" in nmr.network._alias_map + + assert nmr.network is sample_network def test_extract_with_string_alias(self, sample_network, sample_node_data): nmr = NetworkModelResult(sample_network) obs = NodeObservation(sample_node_data, at="123", name="Node_123") + extracted = nmr.extract(obs) - expected_id = sample_network.find(node="123") - assert isinstance(extracted, NodeModelResult) - assert extracted.node == expected_id + + assert extracted.node == "123" def test_extract_string_alias_wrong_key_raises( self, sample_network, sample_node_data ): nmr = NetworkModelResult(sample_network) obs = NodeObservation(sample_node_data, at="nonexistent_node") + with pytest.raises(ValueError, match="not found"): nmr.extract(obs) - def test_extract_with_tuple_breakpoint(self, sample_network, sample_node_data): - """Tuple alias is resolved via _alias_map (mapping injected for this test).""" - nmr = NetworkModelResult(sample_network) - existing_int = int(sample_network.find(node="123")) - nmr.network._alias_map[("reach_test", 10.0)] = existing_int - obs = NodeObservation(sample_node_data, at=("reach_test", 10.0)) - extracted = nmr.extract(obs) - assert extracted.node == existing_int - - def test_extract_with_tuple_breakpoint_tolerance( + def test_a_failed_lookup_names_the_near_misses( self, sample_network, sample_node_data ): nmr = NetworkModelResult(sample_network) - existing_int = int(sample_network.find(node="123")) - base_distance = 10.0 - tol = NetworkModelResult._CHAINAGE_TOLERANCE - nmr.network._alias_map[("reach_test", base_distance)] = existing_int - obs = NodeObservation( - sample_node_data, at=("reach_test", base_distance + tol / 2) - ) - extracted = nmr.extract(obs) - assert extracted.node == existing_int + obs = NodeObservation(sample_node_data, at="124") - def test_extract_with_tuple_breakpoint_outside_tolerance_raises( - self, sample_network, sample_node_data - ): - nmr = NetworkModelResult(sample_network) - existing_int = int(sample_network.find(node="123")) - base_distance = 10.0 - tol = NetworkModelResult._CHAINAGE_TOLERANCE - nmr.network._alias_map[("reach_test", base_distance)] = existing_int - obs = NodeObservation( - sample_node_data, at=("reach_test", base_distance + tol + 1e-4) - ) - with pytest.raises(ValueError, match="not found"): + with pytest.raises(ValueError, match="123"): nmr.extract(obs) - def test_extract_with_tuple_breakpoint_uses_closest_within_tolerance( - self, sample_network, sample_node_data - ): - nmr = NetworkModelResult(sample_network) - base_distance = 10.0 - tol = NetworkModelResult._CHAINAGE_TOLERANCE - node_a = int(sample_network.find(node="123")) - node_b = int(sample_network.find(node="456")) - nmr.network._alias_map[("reach_test", base_distance + 2e-4)] = node_a - nmr.network._alias_map[("reach_test", base_distance + 8e-4)] = node_b + def test_extract_with_tuple_breakpoint(self, breakpoint_network, sample_node_data): + nmr = NetworkModelResult(breakpoint_network) + obs = NodeObservation(sample_node_data, at=("r1", 50.0)) - obs = NodeObservation( - sample_node_data, at=("reach_test", base_distance + tol * 0.6) - ) extracted = nmr.extract(obs) - assert extracted.node == node_b - def test_extract_with_tuple_breakpoint_tie_uses_smallest_node_id( - self, sample_network, sample_node_data + assert extracted.node == ("r1", 50.0) + + def test_extract_with_tuple_breakpoint_tolerance( + self, breakpoint_network, sample_node_data ): - nmr = NetworkModelResult(sample_network) - base_distance = 10.0 - tol = NetworkModelResult._CHAINAGE_TOLERANCE - node_a = int(sample_network.find(node="123")) - node_b = int(sample_network.find(node="456")) - nmr.network._alias_map[("reach_test", base_distance + 4e-4)] = node_a - nmr.network._alias_map[("reach_test", base_distance + 8e-4)] = node_b + nmr = NetworkModelResult(breakpoint_network) + obs = NodeObservation(sample_node_data, at=("r1", 50.0 + 5e-4)) - obs = NodeObservation( - sample_node_data, at=("reach_test", base_distance + tol * 0.6) - ) extracted = nmr.extract(obs) - assert extracted.node == min(node_a, node_b) + + # The distance recorded is the network's own, not the one typed. + assert extracted.node == ("r1", 50.0) + + def test_extract_with_tuple_breakpoint_outside_tolerance_raises( + self, breakpoint_network, sample_node_data + ): + nmr = NetworkModelResult(breakpoint_network) + obs = NodeObservation(sample_node_data, at=("r1", 50.0 + 2e-3)) + + with pytest.raises(ValueError, match="not found"): + nmr.extract(obs) def test_extract_tuple_alias_wrong_key_raises( self, sample_network, sample_node_data ): nmr = NetworkModelResult(sample_network) obs = NodeObservation(sample_node_data, at=("nonexistent_reach", 0.0)) + with pytest.raises(ValueError, match="not found"): nmr.extract(obs) @@ -999,416 +815,114 @@ def test_match_with_string_alias(self, sample_network, sample_node_data): """Full ms.match() workflow works end-to-end with a string alias.""" nmr = NetworkModelResult(sample_network, name="Network_Model") obs = NodeObservation(sample_node_data, at="123", name="Node_123") + comparer = ms.match(obs, nmr) + assert comparer.n_points > 0 assert "Network_Model" in comparer.mod_names -# --------------------------------------------------------------------------- -# Res1D adapter — no mikeio1d required, the adapter is duck-typed -# --------------------------------------------------------------------------- - - -class _StubLocation: - """Stands in for a mikeio1d ResultNode / ResultGridPoint.""" - - def __init__(self, quantities, df=None): - self.quantities = quantities - self._df = df - - def to_dataframe(self): - if self._df is None: - raise AssertionError("to_dataframe() should not be called") - return self._df - +# ======================== location identity ======================== -class TestSimplifyColnames: - def test_location_without_quantities_gives_empty_frame(self): - """MIKE 11 keeps its data on gridpoints, leaving nodes with no quantities.""" - df = _simplify_colnames(_StubLocation(quantities=[])) - assert df.empty - assert list(df.columns) == [] +class TestLocationIdentity: + """A network timeseries is identified by the name its network gave it.""" - def test_quantity_columns_are_stripped_of_location_suffix(self): - time = pd.date_range("2020", periods=2, freq="h") - raw = pd.DataFrame({"WaterLevel:node_1": [1.0, 2.0]}, index=time) + def test_breakpoint_observation_converts_to_a_dataframe(self, sample_node_data): + obs = ms.NodeObservation(sample_node_data, at=("r1", 24.5), item="WaterLevel") - df = _simplify_colnames(_StubLocation(quantities=["WaterLevel"], df=raw)) + df = obs.to_dataframe() assert list(df.columns) == ["WaterLevel"] + assert len(df) == len(sample_node_data) + def test_reach_observation_converts_to_a_dataframe(self, sample_node_data): + obs = ms.ReachObservation(sample_node_data, reach="r1", item="WaterLevel") -class _StubReach: - """Stands in for a mikeio1d ResultReach.""" - - def __init__(self, name="r1", start_node="a", end_node="b", length=100.0): - self.name = name - self.start_node = start_node - self.end_node = end_node - self.length = length - self.gridpoints = [] - - -class TestRes1DReachConnectivity: - """Formats that expose no reach connectivity must fail with a clear message.""" - - @pytest.mark.parametrize("missing", ["start_node", "end_node"]) - def test_missing_node_raises(self, missing): - reach = _StubReach(**{missing: None}) - - with pytest.raises(ValueError, match="no start/end node for reach 'r1'"): - Res1DReach(reach, Res1DNode("a"), Res1DNode("b")) + df = obs.to_dataframe() - def test_both_nodes_missing_raises(self): - """.resx reports None for both, which the identity checks alone would allow.""" - reach = _StubReach(start_node=None, end_node=None) - - with pytest.raises(ValueError, match="no start/end node"): - Res1DReach(reach, Res1DNode(None), Res1DNode(None)) # type: ignore[arg-type] - - def test_mismatched_start_node_still_raises(self): - with pytest.raises(ValueError, match="Incorrect starting node"): - Res1DReach(_StubReach(), Res1DNode("wrong"), Res1DNode("b")) - - -class TestRes1DReachLength: - """mikeio1d returns 0 when it cannot read a length; that is not a real zero.""" - - @pytest.mark.parametrize("reported", [0, 0.0]) - def test_zero_becomes_undefined(self, reported): - reach = Res1DReach(_StubReach(length=reported), Res1DNode("a"), Res1DNode("b")) - - assert reach.length is None - - def test_real_length_passes_through(self): - reach = Res1DReach(_StubReach(length=47.5), Res1DNode("a"), Res1DNode("b")) - - assert reach.length == 47.5 - - -# --------------------------------------------------------------------------- -# from_mike / from_epanet -# --------------------------------------------------------------------------- - -requires_mikeio1d = pytest.mark.skipif( - sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14" -) - - -@requires_mikeio1d -class TestFromMike: - def test_res1d(self): - network = Network.from_mike("./tests/testdata/network.res1d") - - assert network.graph.number_of_nodes() == 259 - - def test_res11(self): - """MIKE 11 keeps its data on gridpoints, so its nodes are empty.""" - network = Network.from_mike("./tests/testdata/network_cali.res11") - - assert len(network._reaches) == 3 - assert network.graph.number_of_nodes() == 71 - assert set(network.quantities) == {"Discharge", "Water Level"} - assert [r.n_breakpoints for r in network._reaches.values()] == [23, 21, 23] - - def test_res11_reaches_have_real_lengths(self): - network = Network.from_mike("./tests/testdata/network_cali.res11") - - lengths = [d["length"] for *_, d in network.graph.edges(data=True)] - assert all(length > 0 for length in lengths) - - def test_open_res1d_object(self): - from mikeio1d import Res1D - - res = Res1D("./tests/testdata/network.res1d") - - network = Network.from_mike(res, nodes=[], reaches=[]) - - assert network.graph.number_of_nodes() == 259 - - def test_epanet_file_is_redirected(self): - with pytest.raises(ValueError, match=r"Use Network\.from_epanet\(\)"): - Network.from_mike("./tests/testdata/epanet.res") - - def test_unknown_extension(self): - with pytest.raises(NotImplementedError, match="Unsupported file extension"): - Network.from_mike("./tests/testdata/obs.dfs0") - - def test_unsupported_type(self): - with pytest.raises(TypeError, match="Expected a str, Path or Res1D object"): - Network.from_mike(42) # type: ignore[arg-type] - - -@requires_mikeio1d -class TestFromEpanet: - def test_epanet(self): - network = Network.from_epanet("./tests/testdata/epanet.res") - - assert network.graph.number_of_nodes() == 11 - assert len(network._reaches) == 13 - assert set(network.quantities) == { - "Demand", - "Head", - "Pressure", - "WaterQuality", - } - assert not network.to_dataframe().empty - - def test_link_node_reaches_have_no_length_or_breakpoints(self): - """Without inp=, mikeio1d reports neither - documented in the docstring.""" - network = Network.from_epanet("./tests/testdata/epanet.res") - - lengths = [d["length"] for *_, d in network.graph.edges(data=True)] - assert lengths and all(length is None for length in lengths) - assert all(r.n_breakpoints == 0 for r in network._reaches.values()) - - def test_reach_observation_cannot_be_matched(self, sample_node_data): - """Follows from having no breakpoints; also documented in the docstring.""" - network = Network.from_epanet("./tests/testdata/epanet.res") - nmr = NetworkModelResult(network, item="Pressure") - obs = ms.ReachObservation(sample_node_data, reach="10", item="WaterLevel") - - with pytest.raises(ValueError, match="breakpoints"): - nmr.extract(obs) - - def test_mike_file_is_redirected(self): - with pytest.raises(ValueError, match=r"Use Network\.from_mike\(\)"): - Network.from_epanet("./tests/testdata/network.res1d") - - def test_open_res1d_object_is_validated(self): - from mikeio1d import Res1D - - res = Res1D("./tests/testdata/network.res1d") - - with pytest.raises(ValueError, match=r"Use Network\.from_mike\(\)"): - Network.from_epanet(res) - - @pytest.mark.parametrize("suffix", [".res", ".RES"]) - def test_extension_is_case_insensitive(self, tmp_path, suffix): - with pytest.raises((FileExistsError, FileNotFoundError)): - Network.from_epanet(tmp_path / f"network{suffix}") - - -# --------------------------------------------------------------------------- -# EPANET companion files: .inp for reach lengths, .resx for extra quantities -# --------------------------------------------------------------------------- - -_EPANET_RES = "./tests/testdata/epanet.res" -_EPANET_RESX = "./tests/testdata/epanet.resx" -_EPANET_INP = "./tests/testdata/epanet.inp" - -# The 12 [PIPES] entries; reach "9" is the pump, which carries no length. -_PUMP_REACH = "9" - - -@requires_mikeio1d -class TestEpanetCompanionInp: - """`.inp` is the only one of the three files carrying reach lengths.""" - - def test_pipe_reaches_get_real_lengths(self): - network = Network.from_epanet(_EPANET_RES, inp=_EPANET_INP) - - lengths = {r.id: r.length for r in network._reaches.values()} - assert lengths["10"] == pytest.approx(3209.544) - assert lengths["110"] == pytest.approx(60.96) - - def test_pump_reach_stays_undefined(self): - """[PIPES] is the only section with lengths, so pumps keep None.""" - network = Network.from_epanet(_EPANET_RES, inp=_EPANET_INP) - - lengths = {r.id: r.length for r in network._reaches.values()} - assert lengths[_PUMP_REACH] is None - assert sum(v is None for v in lengths.values()) == 1 - - def test_graph_edges_carry_the_lengths(self): - network = Network.from_epanet(_EPANET_RES, inp=_EPANET_INP) - - lengths = [d["length"] for *_, d in network.graph.edges(data=True)] - assert sum(v is not None for v in lengths) == 12 - - def test_node_ids_overlapping_reach_ids_are_not_confused(self): - """Most IDs here name both a node and a reach, e.g. '9', '10', '21'.""" - network = Network.from_epanet(_EPANET_RES, inp=_EPANET_INP) - - assert set(network._reaches) & set(network._alias_map) # they do overlap - # Reach "10" is 3209.544 long; node "10" is untouched by the length map. - assert network._reaches["10"].length == pytest.approx(3209.544) - node_10 = network.find(node="10") - assert "Head" in network.to_dataframe()[node_10].columns - - def test_wrong_suffix_is_refused(self): - with pytest.raises(ValueError, match=r"Expected an EPANET '\.inp'"): - Network.from_epanet(_EPANET_RES, inp=_EPANET_RESX) - - def test_file_without_a_pipes_section_is_refused(self, tmp_path): - other = tmp_path / "not-epanet.inp" - other.write_text("[JUNCTIONS]\n;;Name\n9 1000\n") - - with pytest.raises(ValueError, match=r"no \[PIPES\] section"): - Network.from_epanet(_EPANET_RES, inp=other) - - -@requires_mikeio1d -class TestEpanetCompanionResx: - """`.resx` holds extra results for the network defined in the sibling `.res`.""" - - def test_extra_node_quantities_are_merged(self): - network = Network.from_epanet(_EPANET_RES, resx=_EPANET_RESX) - - assert set(network.quantities) == { - "Demand", - "Head", - "Pressure", - "WaterQuality", - "Volume", - "Volume Percentage", - } - - def test_only_the_nodes_present_in_the_resx_gain_them(self): - """The .resx covers the tank and the reservoir, not all eleven nodes.""" - network = Network.from_epanet(_EPANET_RES, resx=_EPANET_RESX) - df = network.to_dataframe() - - with_volume = { - node - for node in df.columns.get_level_values("node").unique() - if "Volume" in df[node].columns - } - # Node IDs are re-indexed to integers, so recall the original labels. - assert {network.recall(node)["node"] for node in with_volume} == {"2", "9"} - - def test_values_come_through(self): - network = Network.from_epanet(_EPANET_RES, resx=_EPANET_RESX) - - reservoir = network.find(node="9") - volume = network.to_dataframe()[(reservoir, "Volume Percentage")] - assert len(volume) == 25 - assert volume.notna().all() - - def test_selective_loading_still_governs_what_is_read(self): - network = Network.from_epanet(_EPANET_RES, resx=_EPANET_RESX, nodes=["2"]) - - df = network.to_dataframe() - tank = network.find(node="2") - assert set(df.columns.get_level_values("node").unique()) == {tank} - assert "Volume" in df[tank].columns - - def test_both_companions_together(self): - network = Network.from_epanet(_EPANET_RES, resx=_EPANET_RESX, inp=_EPANET_INP) - - assert "Volume" in network.quantities - assert network._reaches["10"].length == pytest.approx(3209.544) - - def test_an_open_res1d_object_is_accepted(self): - from mikeio1d import Res1D - - network = Network.from_epanet(_EPANET_RES, resx=Res1D(_EPANET_RESX)) - - assert "Volume" in network.quantities - - def test_wrong_suffix_is_refused(self): - with pytest.raises(ValueError, match=r"Expected an EPANET '\.resx'"): - Network.from_epanet(_EPANET_RES, resx=_EPANET_RES) - - def test_a_result_file_of_another_format_is_refused(self): - from mikeio1d import Res1D - - other = Res1D("./tests/testdata/network.res1d") - - with pytest.raises(ValueError, match=r"Expected an EPANET '\.resx'"): - Network.from_epanet(_EPANET_RES, resx=other) - - def test_a_companion_from_another_run_is_refused(self, monkeypatch): - """Merging two runs would line up silently and give a wrong network.""" - from mikeio1d import Res1D + assert list(df.columns) == ["WaterLevel"] - res = Res1D(_EPANET_RES) - resx = Res1D(_EPANET_RESX) - shifted = resx.time_index + pd.Timedelta("1D") + def test_a_named_node_survives_trimming(self, sample_network, sample_node_data): + nmr = NetworkModelResult(sample_network) + extracted = nmr.extract(ms.NodeObservation(sample_node_data, at="123")) - # Both objects share the Res1D class, so shift only this one instance. - original = type(resx).time_index.fget - monkeypatch.setattr( - type(resx), - "time_index", - property(lambda self: shifted if self is resx else original(self)), + trimmed = extracted.trim( + start_time=extracted.time[1], end_time=extracted.time[-1] ) - with pytest.raises(ValueError, match="does not share a time axis"): - Network.from_epanet(res, resx=resx) + assert trimmed.node == extracted.node + assert len(trimmed) == len(extracted) - 1 - def test_a_companion_naming_an_unknown_node_is_refused(self, monkeypatch): - """A node the .res has never heard of means these are different models.""" - from mikeio1d import Res1D - - res = Res1D(_EPANET_RES) - resx = Res1D(_EPANET_RESX) - strangers = dict(resx.nodes) | {"not_in_the_res": None} - - original = type(resx).nodes.fget - monkeypatch.setattr( - type(resx), - "nodes", - property(lambda self: strangers if self is resx else original(self)), - ) + def test_a_matched_breakpoint_records_its_chainage( + self, breakpoint_network, sample_node_data + ): + nmr = NetworkModelResult(breakpoint_network, name="Network_Model") + obs = ms.NodeObservation(sample_node_data, at=("r1", 50.0), name="BP") - with pytest.raises(ValueError, match="not_in_the_res"): - Network.from_epanet(res, resx=resx) + cmp = ms.match(obs, nmr) - def test_unsupported_type_is_refused(self): - with pytest.raises(TypeError, match="Expected a str, Path or Res1D object"): - Network.from_epanet(_EPANET_RES, resx=42) # type: ignore[arg-type] + assert cmp.gtype == "node" + assert cmp.node is None + assert cmp.reach == "r1" + assert cmp.distance == pytest.approx(50.0) + def test_a_matched_reach_reports_the_breakpoint_it_was_read_from( + self, breakpoint_network, sample_node_data + ): + """The observation is reach-level, so gtype stays 'reach'; distance says + which breakpoint the model data was taken from.""" + nmr = NetworkModelResult(breakpoint_network, name="Network_Model") + obs = ms.ReachObservation(sample_node_data, reach="r1", name="Reach") -class TestReadInp: - """Minimal .inp reader - see modelskill/model/adapters/_inp.py.""" + cmp = ms.match(obs, nmr) - def _write(self, tmp_path, text): - path = tmp_path / "model.inp" - path.write_text(text) - return path + assert cmp.gtype == "reach" + assert cmp.reach == "r1" + assert cmp.distance == pytest.approx(50.0) - def test_sections_are_keyed_without_brackets_and_upper_cased(self, tmp_path): - path = self._write(tmp_path, "[Pipes]\n1 a b 10\n[TANKS]\n2 5\n") - assert set(read_sections(path)) == {"PIPES", "TANKS"} +class TestObservationFactory: + """ms.observation() routes the network keywords to the right class.""" - def test_comment_and_blank_lines_are_dropped(self, tmp_path): - path = self._write( - tmp_path, - ";a leading banner\n\n[PIPES]\n" - ";;ID Node1 Node2 Length\n" - ";;-- ----- ----- ------\n" - "1 a b 10\n\n", - ) + def test_at_gives_a_node_observation(self, sample_node_data): + obs = ms.observation(sample_node_data, at="123", item="WaterLevel") - assert read_sections(path) == {"PIPES": [["1", "a", "b", "10"]]} + assert isinstance(obs, ms.NodeObservation) + assert obs.at == "123" - def test_trailing_comment_is_stripped_from_a_data_row(self, tmp_path): - path = self._write(tmp_path, "[PIPES]\n1 a b 10 ; the short one\n") + def test_a_breakpoint_tuple_gives_a_node_observation(self, sample_node_data): + obs = ms.observation(sample_node_data, at=("r1", 24.5), item="WaterLevel") - assert read_sections(path)["PIPES"] == [["1", "a", "b", "10"]] + assert isinstance(obs, ms.NodeObservation) + assert obs.at == ("r1", 24.5) - def test_rows_before_any_section_are_ignored(self, tmp_path): - path = self._write(tmp_path, "stray row\n[PIPES]\n1 a b 10\n") + def test_reach_gives_a_reach_observation(self, sample_node_data): + obs = ms.observation(sample_node_data, reach="r1", item="WaterLevel") - assert read_sections(path) == {"PIPES": [["1", "a", "b", "10"]]} + assert isinstance(obs, ms.ReachObservation) + assert obs.reach == "r1" - def test_lengths_are_read_from_the_fourth_field(self, tmp_path): - path = self._write(tmp_path, "[PIPES]\n1 a b 10.5 300 100\n") - - assert read_pipe_lengths(path) == {"1": 10.5} + @pytest.mark.parametrize( + "gtype,kwargs,expected", + [ + ("node", {"at": "123"}, ms.NodeObservation), + ("reach", {"reach": "r1"}, ms.ReachObservation), + ], + ) + def test_gtype_can_be_named_outright( + self, sample_node_data, gtype, kwargs, expected + ): + obs = ms.observation(sample_node_data, gtype=gtype, item="WaterLevel", **kwargs) - def test_a_short_row_raises_rather_than_dropping_a_length(self, tmp_path): - path = self._write(tmp_path, "[PIPES]\n1 a b\n") + assert isinstance(obs, expected) - with pytest.raises(ValueError, match="Cannot read a pipe length"): - read_pipe_lengths(path) - def test_a_repeated_section_header_accumulates(self, tmp_path): - path = self._write( - tmp_path, "[PIPES]\n1 a b 10\n[TANKS]\n2 5\n[PIPES]\n3 c d 20\n" - ) +def test_a_reach_observation_keeps_its_weight_and_attrs(sample_node_data): + obs = ReachObservation( + sample_node_data, reach="r1", weight=2.5, attrs={"source": "test"} + ) - assert read_pipe_lengths(path) == {"1": 10.0, "3": 20.0} + assert obs.weight == 2.5 + assert obs.attrs["source"] == "test" + assert obs.quantity == Quantity.undefined() diff --git a/tests/testdata/README.md b/tests/testdata/README.md index a6f4a71c6..63bb46db9 100644 --- a/tests/testdata/README.md +++ b/tests/testdata/README.md @@ -10,16 +10,20 @@ These network files come from | File | Format | Used for | |---|---|---| -| `network_cali.res11` | MIKE 11 | `Network.from_mike` coverage for `.res11` | -| `epanet.res` | EPANET | `Network.from_epanet` coverage | -| `epanet.resx` | EPANET (MIKE+) | the `resx=` companion — extra node quantities merged onto the `.res` network | -| `epanet.inp` | EPANET input | the `inp=` companion — real pipe lengths, which the `.res` does not carry | -| `swmm.out` | SWMM | asserting `.out` is refused — its reach connectivity lives in a companion `.inp` we do not read yet (#689) | +| `network_cali.res11` | MIKE 11 | nothing here any more — see below | +| `epanet.res` | EPANET | nothing here any more — see below | +| `epanet.resx` | EPANET (MIKE+) | extra node quantities, merged onto the `.res` network | +| `epanet.inp` | EPANET input | real pipe lengths, which the `.res` does not carry | +| `swmm.out` | SWMM | nothing here any more — see below | + +Reading these formats moved to mikeio1d with the rest of the topology layer +(ADR-013), and the tests that covered it moved with it. The files are kept because +mikeio1d has the same copies and modelskill may want EPANET-side coverage of its +own; nothing in this repository reads them today except `network.res1d`. `epanet.resx` and `epanet.inp` pair with `epanet.res`: same run, same IDs. The `.resx` node and reach IDs are a strict subset of the `.res` ones, and the `.inp` `[PIPES]` IDs cover every `.res` reach except the pump. -`swmm.out` is kept without its `.inp` on purpose. It pins the refusal, so the test -fails the day we add SWMM support or a future mikeio1d starts reporting reach -connectivity for it. +`swmm.out` is kept without its `.inp` on purpose: the refusal it used to pin is +mikeio1d's now, and the file is the fixture that refusal needs. diff --git a/tests/testdata/network_sensor_1.csv b/tests/testdata/network_sensor_1.csv index 904d9eb79..6f46c2869 100644 --- a/tests/testdata/network_sensor_1.csv +++ b/tests/testdata/network_sensor_1.csv @@ -1,111 +1,111 @@ ,water_level@sens1 -1994-08-07 16:35:06.721389014,193.7479319011718 -1994-08-07 16:36:11.808982110,193.9276622504125 -1994-08-07 16:36:58.463517098,193.73969537883863 -1994-08-07 16:38:50.136489724,193.5324026294447 -1994-08-07 16:39:54.184260240,193.75098664628783 -1994-08-07 16:41:02.301898383,193.9631823043365 -1994-08-07 16:41:48.047551850,193.88949067602914 -1994-08-07 16:43:03.765627271,193.73298338692013 -1994-08-07 16:43:59.271576674,193.518740505735 -1994-08-07 16:44:53.976575879,193.80052813920184 -1994-08-07 16:45:52.150380498,193.76709749688646 -1994-08-07 16:46:59.335689619,193.87266429057766 -1994-08-07 16:47:48.671800096,193.61027606890661 -1994-08-07 16:49:09.441634441,193.90646493021583 -1994-08-07 16:50:05.221428246,193.68537026321115 -1994-08-07 16:51:31.750429245,194.00527903620747 -1994-08-07 16:52:44.709396591,193.960610633433 -1994-08-07 16:54:15.295748944,193.87369664367992 -1994-08-07 16:56:09.081416788,193.74406275881358 -1994-08-07 16:57:14.043033644,193.71501017501876 -1994-08-07 16:58:18.210601321,193.83703675670696 -1994-08-07 16:59:03.257072206,194.06250124233108 -1994-08-07 17:00:06.081835904,193.97168058658363 -1994-08-07 17:01:06.426608705,193.6410669817052 -1994-08-07 17:02:22.837775497,193.7119913501634 -1994-08-07 17:03:18.768918912,193.8826429315821 -1994-08-07 17:04:17.424400499,193.76142364154504 -1994-08-07 17:05:06.371871595,193.82686832219773 -1994-08-07 17:06:17.991770538,193.7814248098547 -1994-08-07 17:07:14.600956935,193.747104244197 -1994-08-07 17:08:19.929202980,193.88962326399343 -1994-08-07 17:09:18.863933688,193.8894988894418 -1994-08-07 17:10:21.785300698,193.7678915506987 -1994-08-07 17:11:22.760047207,193.8350592978198 -1994-08-07 17:12:16.293904286,193.76937160755946 -1994-08-07 17:13:18.937531227,193.7072710276047 -1994-08-07 17:14:09.393470503,194.01678510826014 -1994-08-07 17:15:16.341863122,193.81790025709154 -1994-08-07 17:16:17.315241669,193.96796138622275 -1994-08-07 17:17:15.246401107,193.93776810871083 -1994-08-07 17:18:05.749523838,193.92373793354915 -1994-08-07 17:19:22.112742914,193.75041032904946 -1994-08-07 17:20:31.310425275,193.92249310948324 -1994-08-07 17:21:21.982712671,193.82335772625748 -1994-08-07 17:22:23.767907448,193.95466062588378 -1994-08-07 17:23:39.680152861,194.013618376674 -1994-08-07 17:24:38.147955485,194.11815372525726 -1994-08-07 17:25:38.420371252,194.50584562429492 -1994-08-07 17:26:24.408303070,194.54446646687336 -1994-08-07 17:27:31.105998416,194.46853129987517 -1994-08-07 17:28:34.880232331,194.55187457703428 -1994-08-07 17:29:37.175071072,194.86809034869842 -1994-08-07 17:30:35.271697419,194.70284194184958 -1994-08-07 17:31:31.204858260,194.98822903414495 -1994-08-07 17:32:24.847235710,195.24737706568624 -1994-08-07 17:33:36.679829931,195.2715904795984 -1994-08-07 17:34:37.932637257,195.1555004434547 -1994-08-07 17:35:25.487179907,195.11808508664626 -1994-08-07 17:36:22.047650391,195.35302938305526 -1994-08-07 17:37:22.665545301,195.058608262039 -1994-08-07 17:38:23.922713966,195.03890774364643 -1994-08-07 17:39:37.300808590,195.10925487796052 -1994-08-07 17:40:39.123378882,194.9197940042712 -1994-08-07 17:41:39.736323741,194.91541376013848 -1994-08-07 17:42:32.624612495,194.84419544155747 -1994-08-07 17:43:38.386604464,194.91238993528924 -1994-08-07 17:44:35.752954642,194.80146002502337 -1994-08-07 17:45:47.706770126,194.91559552756155 -1994-08-07 17:46:56.228029771,194.72765509600865 -1994-08-07 17:47:50.302639903,194.72477357208479 -1994-08-07 17:48:51.313688841,194.64138661647883 -1994-08-07 17:50:04.027931558,194.66788700646532 -1994-08-07 17:50:59.170111019,194.69887586125873 -1994-08-07 17:52:19.507804755,194.75091927194543 -1994-08-07 17:53:36.244289704,194.73563801241843 -1994-08-07 17:54:46.006725041,194.35800960937343 -1994-08-07 17:55:50.875697661,194.41711389439024 -1994-08-07 17:57:01.668197445,194.29313729304636 -1994-08-07 17:58:16.481604045,194.45199484204932 -1994-08-07 17:59:47.768779742,194.45872420226013 -1994-08-07 18:00:49.317493448,194.4314547834637 -1994-08-07 18:02:02.027423669,194.2515095971401 -1994-08-07 18:03:55.326990060,194.2601910363553 -1994-08-07 18:05:08.677524139,194.09049632407513 -1994-08-07 18:05:55.807125909,194.25764674606657 -1994-08-07 18:07:06.508171149,194.15893464151893 -1994-08-07 18:08:14.768585338,194.32278841101814 -1994-08-07 18:08:59.434113874,194.1892503649891 -1994-08-07 18:10:10.361033654,194.3360223971569 -1994-08-07 18:11:39.416513356,193.91053863482347 -1994-08-07 18:13:12.292137298,194.03847881603537 -1994-08-07 18:14:50.579821036,194.19255380323284 -1994-08-07 18:16:11.445107220,194.2372052362117 -1994-08-07 18:17:13.979038396,194.02910039993844 -1994-08-07 18:19:11.411173338,194.1543403568542 -1994-08-07 18:20:05.747471067,194.28718925009687 -1994-08-07 18:21:08.770390114,194.2290999628811 -1994-08-07 18:22:04.993112618,193.88244373099988 -1994-08-07 18:23:12.416131227,194.02896457246328 -1994-08-07 18:24:13.427829087,193.99948814393267 -1994-08-07 18:25:12.565706666,194.16456490763096 -1994-08-07 18:26:07.842114358,194.02641628418803 -1994-08-07 18:26:58.397587323,194.16132614507512 -1994-08-07 18:28:03.529864903,194.15134556849915 -1994-08-07 18:29:00.650668046,193.92727557471548 -1994-08-07 18:30:03.066222312,193.9766219050112 -1994-08-07 18:31:10.120818363,194.06760532977663 -1994-08-07 18:32:09.431674937,193.95571034292806 -1994-08-07 18:33:00.389496491,194.03147735060986 -1994-08-07 18:35:01.353919658,193.94705444753936 +1994-08-07 16:35:00.776781603,194.32011320654263 +1994-08-07 16:36:09.729399842,194.7470367441099 +1994-08-07 16:37:10.325784362,194.67395882505454 +1994-08-07 16:38:54.294488082,194.61153571139567 +1994-08-07 16:39:49.893755801,194.54321065864184 +1994-08-07 16:40:49.464208760,194.51251435556324 +1994-08-07 16:41:54.155002671,194.48729978930177 +1994-08-07 16:42:47.858648484,194.58252622043406 +1994-08-07 16:43:48.114422841,194.4304369580146 +1994-08-07 16:44:50.213843207,194.38249215797805 +1994-08-07 16:45:52.389905612,194.64429343992802 +1994-08-07 16:47:02.765925660,194.53358432734336 +1994-08-07 16:47:47.544625374,194.60385269292348 +1994-08-07 16:49:02.637927182,194.59824639141928 +1994-08-07 16:50:12.152163291,194.64549922015675 +1994-08-07 16:51:38.335652213,194.20982648777377 +1994-08-07 16:52:40.498338592,194.65174104529223 +1994-08-07 16:54:29.296070178,194.67321466962673 +1994-08-07 16:56:16.843462211,194.70496214061026 +1994-08-07 16:57:19.546830813,194.57169766844956 +1994-08-07 16:58:21.508555037,194.66168658625153 +1994-08-07 16:59:19.782410316,194.55758442776926 +1994-08-07 17:00:21.921517678,194.5576186499002 +1994-08-07 17:01:20.092192674,194.81469647880382 +1994-08-07 17:02:17.746355889,194.70522414915595 +1994-08-07 17:03:13.166714757,194.60789232032135 +1994-08-07 17:04:12.749365769,194.79521007424793 +1994-08-07 17:05:10.304197359,194.42783733284318 +1994-08-07 17:06:04.189757936,194.5555761260468 +1994-08-07 17:07:12.765391276,194.73618898202943 +1994-08-07 17:08:12.365563077,194.6375905289089 +1994-08-07 17:09:15.491917299,194.57025641473498 +1994-08-07 17:10:06.493562414,194.4688605015372 +1994-08-07 17:11:07.187363310,194.75550986631575 +1994-08-07 17:12:09.160016532,194.61054169889053 +1994-08-07 17:13:21.469083676,194.6253361248603 +1994-08-07 17:14:17.930689144,194.70277955607804 +1994-08-07 17:15:17.279332650,194.56556903513305 +1994-08-07 17:16:08.640601075,194.50005512303613 +1994-08-07 17:17:07.068658303,194.65868598122688 +1994-08-07 17:18:09.766449327,194.6653618297461 +1994-08-07 17:19:20.161218787,194.74595890778755 +1994-08-07 17:20:18.992883026,194.4980021093954 +1994-08-07 17:21:30.086313691,194.55154639192463 +1994-08-07 17:22:28.651457434,194.57671325756172 +1994-08-07 17:23:40.633424866,194.69867899539543 +1994-08-07 17:24:37.117548132,194.82545584348597 +1994-08-07 17:25:30.448984712,195.0279680264088 +1994-08-07 17:26:30.029453346,195.07988551475916 +1994-08-07 17:27:32.245829383,194.92487401587312 +1994-08-07 17:28:30.078420729,195.3240098122494 +1994-08-07 17:29:38.136013235,195.47706773119452 +1994-08-07 17:30:35.734525134,195.77572434729703 +1994-08-07 17:31:34.656548288,196.34019205600237 +1994-08-07 17:32:31.554119147,196.4872903805679 +1994-08-07 17:33:34.533280257,196.31028793328298 +1994-08-07 17:34:21.642437078,196.39518666193 +1994-08-07 17:35:37.901281041,196.23731771908797 +1994-08-07 17:36:31.067494778,196.2907368565569 +1994-08-07 17:37:26.536405793,196.05114435497984 +1994-08-07 17:38:26.179123415,196.23182104355894 +1994-08-07 17:39:34.480757192,195.7356264141028 +1994-08-07 17:40:32.367919827,195.76434390248752 +1994-08-07 17:41:29.068741892,195.387522485378 +1994-08-07 17:42:25.963454370,195.26662774076652 +1994-08-07 17:43:43.256506377,195.1620181140931 +1994-08-07 17:44:48.923258096,194.99956715610247 +1994-08-07 17:45:48.951022779,194.803275106843 +1994-08-07 17:46:51.832758663,194.62647855997503 +1994-08-07 17:47:53.011655455,194.840056508079 +1994-08-07 17:48:53.291279628,194.7191954018589 +1994-08-07 17:49:45.414193152,194.72130314272985 +1994-08-07 17:51:06.934395423,194.736784985074 +1994-08-07 17:52:14.283447737,194.57160881923406 +1994-08-07 17:53:31.345360278,194.83788750770336 +1994-08-07 17:54:45.878612606,194.6186418522351 +1994-08-07 17:55:54.526498381,194.60992402778382 +1994-08-07 17:57:07.804714354,194.70930496247433 +1994-08-07 17:58:29.732584061,194.631433387878 +1994-08-07 17:59:51.646966493,194.7453412546349 +1994-08-07 18:00:49.479370729,194.63355314090856 +1994-08-07 18:02:05.027988263,194.54741392208302 +1994-08-07 18:04:07.168692247,194.66260603569324 +1994-08-07 18:05:02.408720278,194.65222312074025 +1994-08-07 18:05:59.994427311,194.7324924261196 +1994-08-07 18:06:58.002591414,194.59584590330348 +1994-08-07 18:08:12.257364299,194.7322344755338 +1994-08-07 18:08:56.371471124,194.7565388217572 +1994-08-07 18:09:59.424399444,194.68480423777225 +1994-08-07 18:11:43.381217236,194.4815298273368 +1994-08-07 18:13:18.462469421,194.72667934520882 +1994-08-07 18:14:45.523662018,194.6906565875005 +1994-08-07 18:16:02.135996224,194.65676781090227 +1994-08-07 18:17:12.775638626,194.43981653379436 +1994-08-07 18:19:04.224160802,194.55663239846368 +1994-08-07 18:20:01.156801276,194.65240550437673 +1994-08-07 18:21:04.005495270,194.74085520785582 +1994-08-07 18:22:07.212758918,194.54846322157974 +1994-08-07 18:23:17.581805886,194.5943242421595 +1994-08-07 18:24:09.834797808,194.66609677586615 +1994-08-07 18:25:02.157922163,194.64754442371688 +1994-08-07 18:26:00.013570112,194.58158453962835 +1994-08-07 18:26:58.607951371,194.61501209771856 +1994-08-07 18:28:09.760211999,194.52247158113664 +1994-08-07 18:29:04.676695951,194.54233718320697 +1994-08-07 18:29:58.126126307,194.4578251058232 +1994-08-07 18:30:58.188406457,194.6101479534574 +1994-08-07 18:32:08.511690435,194.52181232461433 +1994-08-07 18:33:05.469289719,194.63804807700458 +1994-08-07 18:34:50.281906950,194.5500288327867 diff --git a/tests/testdata/network_sensor_2.csv b/tests/testdata/network_sensor_2.csv index 9eddb84df..403d0b069 100644 --- a/tests/testdata/network_sensor_2.csv +++ b/tests/testdata/network_sensor_2.csv @@ -1,81 +1,81 @@ ,water_level@sens2 -1994-08-07 17:08:19.453000537,193.69907521870385 -1994-08-07 17:09:11.667777579,193.53254848297152 -1994-08-07 17:10:17.713878006,193.37840712805215 -1994-08-07 17:11:14.377409723,193.36046774853432 -1994-08-07 17:12:19.607715440,193.35883525251685 -1994-08-07 17:13:16.506158153,193.54074175140104 -1994-08-07 17:14:22.442398906,193.5636244747378 -1994-08-07 17:15:07.096815541,193.3936963704199 -1994-08-07 17:16:10.480296727,193.48972566299682 -1994-08-07 17:17:22.450643797,193.4587060771225 -1994-08-07 17:18:21.490266204,193.35182993861991 -1994-08-07 17:19:19.872035872,193.45517089047667 -1994-08-07 17:20:18.551963043,193.39190620106453 -1994-08-07 17:21:37.487970642,193.65287311723839 -1994-08-07 17:22:38.893023517,193.51519324042974 -1994-08-07 17:23:37.808072814,193.72342214376903 -1994-08-07 17:24:30.088355655,193.42926966972004 -1994-08-07 17:25:22.809359233,193.373787100516 -1994-08-07 17:26:33.203907398,193.87313878617707 -1994-08-07 17:27:24.450142559,193.77977426912494 -1994-08-07 17:28:34.256134409,193.87776964481588 -1994-08-07 17:29:29.162052421,193.74593301162298 -1994-08-07 17:30:40.417250997,194.06335624478052 -1994-08-07 17:31:36.292748137,194.0891460493891 -1994-08-07 17:32:22.577927686,193.93598437841732 -1994-08-07 17:33:35.944430514,193.89206968675506 -1994-08-07 17:34:23.631420564,194.29720825961996 -1994-08-07 17:35:33.310491457,193.94006446417492 -1994-08-07 17:36:36.768648209,193.94301852816398 -1994-08-07 17:37:41.256034582,193.93359649072713 -1994-08-07 17:38:27.439954370,193.99934207664205 -1994-08-07 17:39:32.423879950,194.0276140940857 -1994-08-07 17:40:32.505523785,193.75309351356177 -1994-08-07 17:41:26.182311995,193.86393199710076 -1994-08-07 17:42:31.811747815,193.86698395764947 -1994-08-07 17:43:43.977586264,193.79824583031655 -1994-08-07 17:44:32.820391407,193.88413939303942 -1994-08-07 17:45:39.780028021,193.82682735759107 -1994-08-07 17:46:45.520148467,193.64527654802706 -1994-08-07 17:47:47.632936535,193.79625317554138 -1994-08-07 17:48:57.346727826,193.6655550615617 -1994-08-07 17:49:49.253930336,193.78374770218835 -1994-08-07 17:51:02.833869005,193.49014557011174 -1994-08-07 17:52:08.948334997,193.5521603282343 -1994-08-07 17:53:32.956569310,193.42249475180054 -1994-08-07 17:54:40.776321387,193.41421417275032 -1994-08-07 17:55:45.154182165,193.7623513346016 -1994-08-07 17:57:01.877564139,193.71602664387882 -1994-08-07 17:58:27.973645801,193.6626855905494 -1994-08-07 17:59:48.164323924,193.58427431473757 -1994-08-07 18:00:49.608896563,193.81199176289348 -1994-08-07 18:02:06.114975563,193.64886741921137 -1994-08-07 18:04:10.676323539,193.719005472149 -1994-08-07 18:05:07.173323943,193.96465013641256 -1994-08-07 18:06:11.346838731,193.68426045579662 -1994-08-07 18:07:15.138616621,193.88023114770002 -1994-08-07 18:08:12.352725832,193.73742809783437 -1994-08-07 18:09:09.040990372,193.95542280957721 -1994-08-07 18:10:05.444299339,193.72699587134503 -1994-08-07 18:11:43.548122207,193.64415106941962 -1994-08-07 18:13:19.975340480,193.61679887917686 -1994-08-07 18:15:00.099149664,193.7092729650918 -1994-08-07 18:15:58.266937956,193.51481360263026 -1994-08-07 18:17:11.010370099,193.88621915401467 -1994-08-07 18:19:00.194728453,193.70300139682695 -1994-08-07 18:20:01.268579900,193.74549285164244 -1994-08-07 18:20:59.085548638,193.61744713398235 -1994-08-07 18:22:04.935328179,193.73830581406855 -1994-08-07 18:23:02.479745169,193.64939163691596 -1994-08-07 18:24:03.446628434,193.70495758379232 -1994-08-07 18:25:06.549919135,193.8685145360975 -1994-08-07 18:26:03.183612415,193.76014328305922 -1994-08-07 18:27:13.078601240,193.970374402854 -1994-08-07 18:28:04.443206888,193.861958294037 -1994-08-07 18:29:11.413727234,193.7661905820629 -1994-08-07 18:30:08.277252518,193.82534783818286 -1994-08-07 18:31:15.483217962,193.74254129620306 -1994-08-07 18:32:16.040549977,193.6307058726291 -1994-08-07 18:33:10.182896344,193.70636292657173 -1994-08-07 18:34:50.194959733,193.5921011184813 +1994-08-07 17:08:16.746982777,193.46666085110937 +1994-08-07 17:09:15.911869348,193.5553573859252 +1994-08-07 17:10:12.195124338,193.68937807365793 +1994-08-07 17:11:04.448876310,193.45076123271946 +1994-08-07 17:12:21.097623039,193.35810147147876 +1994-08-07 17:13:10.410972001,193.2465448797826 +1994-08-07 17:14:18.997462489,193.3968538310765 +1994-08-07 17:15:03.516275677,193.4281083125626 +1994-08-07 17:16:19.363113442,193.41499628403477 +1994-08-07 17:17:21.535598304,193.5666798285079 +1994-08-07 17:18:06.703804784,193.39019715759977 +1994-08-07 17:19:07.113924200,193.38622798499898 +1994-08-07 17:20:33.249205987,193.44059499667398 +1994-08-07 17:21:31.188910307,193.39014297074812 +1994-08-07 17:22:25.449777484,193.5135983423928 +1994-08-07 17:23:34.351449340,193.44326026160877 +1994-08-07 17:24:36.704856539,193.64662660593314 +1994-08-07 17:25:23.749227916,193.68181603286484 +1994-08-07 17:26:25.413103928,193.65784040523326 +1994-08-07 17:27:34.119977569,193.6594899766634 +1994-08-07 17:28:38.077895472,193.56136289039708 +1994-08-07 17:29:28.892229227,193.88248108364874 +1994-08-07 17:30:37.381056452,193.879931506782 +1994-08-07 17:31:22.016878283,193.9764859878361 +1994-08-07 17:32:24.820104399,194.0092368597367 +1994-08-07 17:33:30.644397706,193.88064299765335 +1994-08-07 17:34:33.346912592,194.05445097743723 +1994-08-07 17:35:23.787289189,193.82172014137683 +1994-08-07 17:36:27.366039084,194.11063686379669 +1994-08-07 17:37:21.887545915,194.0337211037484 +1994-08-07 17:38:24.492378576,193.97610821824 +1994-08-07 17:39:30.357983784,193.8996749540457 +1994-08-07 17:40:32.873187909,193.92570259171478 +1994-08-07 17:41:34.362113670,194.00499314349867 +1994-08-07 17:42:37.953467214,193.97506638859474 +1994-08-07 17:43:42.534176765,193.8375936679057 +1994-08-07 17:44:46.286409008,193.8822436003635 +1994-08-07 17:45:38.814041258,193.92934125470285 +1994-08-07 17:46:46.299281342,193.8427036608706 +1994-08-07 17:47:54.794002989,193.67733464061652 +1994-08-07 17:48:47.411067897,193.7657885903237 +1994-08-07 17:49:54.806563276,193.79932081862353 +1994-08-07 17:51:07.203432962,193.6679871844179 +1994-08-07 17:52:24.175267637,193.66515188457322 +1994-08-07 17:53:38.221315864,193.47159887553875 +1994-08-07 17:54:47.955110981,193.3670697177164 +1994-08-07 17:55:57.151866554,193.2148360925973 +1994-08-07 17:57:08.560582293,193.62690790451714 +1994-08-07 17:58:23.735060106,193.72418492900746 +1994-08-07 17:59:55.978275973,193.6697424454863 +1994-08-07 18:00:56.860847094,193.862786559526 +1994-08-07 18:02:08.048762300,193.5319389365475 +1994-08-07 18:04:00.764336576,193.87660770279663 +1994-08-07 18:05:03.913437188,193.60076940202146 +1994-08-07 18:06:13.261131339,193.6366841968641 +1994-08-07 18:07:06.157111035,193.59798175417382 +1994-08-07 18:08:04.896493562,193.68986271298314 +1994-08-07 18:09:08.807194603,193.75154771138716 +1994-08-07 18:10:01.992525026,193.59058976854448 +1994-08-07 18:11:47.873996513,194.03607519614027 +1994-08-07 18:13:19.705641908,193.85331823073562 +1994-08-07 18:15:01.527177197,193.82125166357054 +1994-08-07 18:16:06.112479066,193.6735111347705 +1994-08-07 18:17:16.685286166,193.73108188615356 +1994-08-07 18:19:17.074371614,193.8626267277998 +1994-08-07 18:20:10.845364231,193.7936194327107 +1994-08-07 18:21:12.902532477,193.75779898411886 +1994-08-07 18:22:05.155728075,193.7031060506949 +1994-08-07 18:22:58.734020179,193.5646247175248 +1994-08-07 18:24:13.186786829,193.73911466320203 +1994-08-07 18:25:01.856294891,193.84057875255806 +1994-08-07 18:26:15.909490510,193.59172917653063 +1994-08-07 18:26:59.409353061,193.729350832721 +1994-08-07 18:28:14.140616186,193.6950562602535 +1994-08-07 18:29:12.131829961,193.56685946901322 +1994-08-07 18:30:15.997926093,193.7309558657659 +1994-08-07 18:31:00.070062248,193.77991569884506 +1994-08-07 18:31:58.657467012,193.65439446319758 +1994-08-07 18:33:12.430771829,193.7274017925486 +1994-08-07 18:35:06.217438898,193.7440013043444 diff --git a/tests/testdata/network_sensor_3.csv b/tests/testdata/network_sensor_3.csv index 540162613..b15854108 100644 --- a/tests/testdata/network_sensor_3.csv +++ b/tests/testdata/network_sensor_3.csv @@ -1,91 +1,91 @@ ,water_level@sens3 -1994-08-07 16:34:59.749185049,193.65573611633096 -1994-08-07 16:36:08.234735831,193.5492676961432 -1994-08-07 16:37:10.476205369,193.44270461528237 -1994-08-07 16:38:56.739070973,193.7316050738842 -1994-08-07 16:39:48.448422501,193.46705769407055 -1994-08-07 16:41:00.899011077,193.60328571871497 -1994-08-07 16:41:57.674627567,193.35125246300828 -1994-08-07 16:42:47.462417744,193.5185512837486 -1994-08-07 16:44:05.707731356,193.59592502393136 -1994-08-07 16:44:47.395900520,193.66394020062216 -1994-08-07 16:45:54.846537383,193.62178032405015 -1994-08-07 16:46:48.526040668,193.77009561152101 -1994-08-07 16:48:00.550698110,193.54903378032205 -1994-08-07 16:49:06.813081870,193.5248851167554 -1994-08-07 16:50:10.392793101,193.4807046599272 -1994-08-07 16:51:20.373948386,193.50658954793624 -1994-08-07 16:52:42.364153730,193.58489517430476 -1994-08-07 16:54:24.475220308,193.50643945831553 -1994-08-07 16:56:03.429894489,193.72466197230418 -1994-08-07 16:57:07.522109743,193.66315601778547 -1994-08-07 16:58:19.771112168,193.6526056046781 -1994-08-07 16:59:12.330382377,193.5774691241722 -1994-08-07 17:00:15.682992521,193.57194585146243 -1994-08-07 17:01:06.996793691,193.776140134919 -1994-08-07 17:02:03.506371148,193.68766157959166 -1994-08-07 17:03:10.614276582,193.49255884053937 -1994-08-07 17:04:12.713137359,193.62602129546661 -1994-08-07 17:05:11.105347604,193.6977653873034 -1994-08-07 17:06:08.694168494,193.76860864084824 -1994-08-07 17:07:10.279609860,193.50288362365427 -1994-08-07 17:08:21.003764660,193.55578257769696 -1994-08-07 17:09:06.412524613,193.56869342489048 -1994-08-07 17:10:15.705612895,193.40978399466348 -1994-08-07 17:11:09.451766070,193.60182994885278 -1994-08-07 17:12:08.055520793,193.51766966463958 -1994-08-07 17:13:10.657325255,193.7243146064135 -1994-08-07 17:14:21.633020060,193.51257532827768 -1994-08-07 17:15:09.075371450,193.55232084181247 -1994-08-07 17:16:17.914468302,193.62712317582472 -1994-08-07 17:17:16.975978261,193.5158279508316 -1994-08-07 17:18:08.275302169,193.52467436568807 -1994-08-07 17:19:15.119707735,193.8068739097595 -1994-08-07 17:20:17.654157988,193.58466106079132 -1994-08-07 17:21:35.874256489,193.6432198883477 -1994-08-07 17:22:26.201697028,193.7402389587467 -1994-08-07 17:23:40.614190845,193.8251455313248 -1994-08-07 17:24:35.163885201,194.0484457054399 -1994-08-07 17:25:33.831846465,194.2188581110414 -1994-08-07 17:26:29.463057842,194.14930206264734 -1994-08-07 17:27:32.301951282,194.26559908122894 -1994-08-07 17:48:51.253848509,194.47916510244187 -1994-08-07 17:49:47.468746981,194.53818636632545 -1994-08-07 17:51:17.048530468,194.42192673115431 -1994-08-07 17:52:06.196063531,194.3566111817392 -1994-08-07 17:53:33.571594531,194.49275563859712 -1994-08-07 17:54:40.295857745,194.24161289020807 -1994-08-07 17:55:51.426795930,194.32646211685966 -1994-08-07 17:57:07.010027886,194.3129625711656 -1994-08-07 17:58:14.788227728,194.21563049881922 -1994-08-07 17:59:55.817232777,193.97104689092097 -1994-08-07 18:01:00.899387468,194.01433322885484 -1994-08-07 18:02:11.092720572,194.06259026020842 -1994-08-07 18:04:08.113392108,194.0429608417371 -1994-08-07 18:05:13.679114222,193.96529261399613 -1994-08-07 18:05:59.122553354,194.15157054129583 -1994-08-07 18:06:57.704020361,194.05899018808853 -1994-08-07 18:08:00.962755607,193.87481824713652 -1994-08-07 18:09:12.803710813,193.94393360920478 -1994-08-07 18:09:55.783676414,193.90634365346295 -1994-08-07 18:11:38.994491765,194.00426585723756 -1994-08-07 18:13:23.817088485,194.21330958450045 -1994-08-07 18:15:02.660036684,193.89671511569932 -1994-08-07 18:16:07.012693812,193.78174880032458 -1994-08-07 18:17:20.710118446,193.86633562744598 -1994-08-07 18:19:15.130507240,194.0741744560302 -1994-08-07 18:20:15.800301822,194.00207588928566 -1994-08-07 18:21:05.594143504,193.98954078505082 -1994-08-07 18:22:10.672244133,193.96015892979668 -1994-08-07 18:22:59.116797345,193.8059099694073 -1994-08-07 18:24:17.782794557,193.83533534410043 -1994-08-07 18:25:04.518698881,193.9507667786435 -1994-08-07 18:26:01.010477471,193.74729023512035 -1994-08-07 18:26:58.886134140,194.11217785860217 -1994-08-07 18:28:09.564788837,193.8869974441292 -1994-08-07 18:29:08.171733686,193.8225247414004 -1994-08-07 18:30:08.862763988,193.94471797299423 -1994-08-07 18:30:58.204733811,193.73271910461622 -1994-08-07 18:32:15.465370257,193.6686396836888 -1994-08-07 18:33:11.959829548,193.89010296389915 -1994-08-07 18:35:04.487313817,193.81745709215483 +1994-08-07 16:34:53.680090784,195.93216076519226 +1994-08-07 16:36:03.016073867,195.9345555668001 +1994-08-07 16:37:03.615114632,195.87220444573137 +1994-08-07 16:39:04.169996900,196.07260811118314 +1994-08-07 16:40:05.088750158,196.01833164040877 +1994-08-07 16:40:58.934617468,195.7868431574667 +1994-08-07 16:41:46.633021730,196.07718129064628 +1994-08-07 16:42:54.313644581,195.9604742525487 +1994-08-07 16:44:01.994806709,195.82502054758228 +1994-08-07 16:45:05.716604054,195.8614853805758 +1994-08-07 16:46:05.078540769,195.94226830524835 +1994-08-07 16:47:04.659109174,196.13169890225316 +1994-08-07 16:48:04.071253636,196.0508294592809 +1994-08-07 16:48:55.856609530,195.8157297978531 +1994-08-07 16:50:20.836102217,195.78676980238802 +1994-08-07 16:51:27.259242998,196.0502612429115 +1994-08-07 16:52:46.613962431,195.90082751638676 +1994-08-07 16:54:14.361648370,195.82840913303832 +1994-08-07 16:56:09.602491818,195.86111093441735 +1994-08-07 16:57:07.509307885,196.08105725975832 +1994-08-07 16:58:04.607812159,195.91595807409047 +1994-08-07 16:59:06.162651347,196.046190892334 +1994-08-07 17:00:04.860410721,195.93309106576953 +1994-08-07 17:01:19.693130234,195.989758713676 +1994-08-07 17:02:17.013786542,196.03859678014445 +1994-08-07 17:03:21.921253632,195.9350327844052 +1994-08-07 17:04:21.306422808,196.0611642713905 +1994-08-07 17:05:19.649468214,195.99686776883638 +1994-08-07 17:06:03.336005403,195.7951648783128 +1994-08-07 17:07:08.175640300,196.03696226597071 +1994-08-07 17:08:13.223933084,196.04961642590735 +1994-08-07 17:09:20.896721614,195.86822876151624 +1994-08-07 17:10:12.692196265,195.93634924463356 +1994-08-07 17:11:21.281490027,195.95654321002246 +1994-08-07 17:12:09.750840411,195.88120744267295 +1994-08-07 17:13:19.174570528,195.69717438944858 +1994-08-07 17:14:11.448114976,196.1061718342362 +1994-08-07 17:15:07.570426731,196.09399840812893 +1994-08-07 17:16:06.885048483,195.85406340253886 +1994-08-07 17:17:22.662212163,196.0792883943752 +1994-08-07 17:18:22.246108903,196.12897187602258 +1994-08-07 17:19:12.398538344,195.96210045263325 +1994-08-07 17:20:32.008320960,196.01346569313253 +1994-08-07 17:21:31.501188032,195.97332807650434 +1994-08-07 17:22:35.058031998,196.0923133910623 +1994-08-07 17:23:24.124859305,195.93741310885218 +1994-08-07 17:24:38.659325565,196.00513593642532 +1994-08-07 17:25:35.358147024,196.06989936406853 +1994-08-07 17:26:22.438476497,195.95165645941802 +1994-08-07 17:27:37.111814779,196.1077539353862 +1994-08-07 17:48:59.845122779,196.06867177276968 +1994-08-07 17:49:59.732989933,196.0571296425243 +1994-08-07 17:51:15.496873472,195.8685146657441 +1994-08-07 17:52:14.096936412,196.14841260340083 +1994-08-07 17:53:40.763706788,195.93029445362168 +1994-08-07 17:54:39.549902410,196.01744835625516 +1994-08-07 17:55:52.701116337,195.96104178186428 +1994-08-07 17:56:59.300944272,195.80391343108298 +1994-08-07 17:58:15.648708976,196.04582044920252 +1994-08-07 17:59:55.609780366,195.73148703736967 +1994-08-07 18:00:48.491480170,196.0329238945659 +1994-08-07 18:02:05.832518720,195.94609041324372 +1994-08-07 18:04:01.981196118,196.0870217358456 +1994-08-07 18:05:06.385341376,195.82819669263213 +1994-08-07 18:06:02.100215510,195.97316503312695 +1994-08-07 18:07:09.809500401,196.04851254822992 +1994-08-07 18:08:02.507913856,195.93280039947714 +1994-08-07 18:09:09.478070425,196.07991903067744 +1994-08-07 18:10:12.897665524,195.8858685223849 +1994-08-07 18:11:42.297675514,195.85546581194953 +1994-08-07 18:13:09.578201802,196.03228099205927 +1994-08-07 18:14:58.536619975,195.9259991178699 +1994-08-07 18:16:06.565053613,195.8178981389149 +1994-08-07 18:17:14.826306388,195.88467512468196 +1994-08-07 18:19:09.806901698,195.8420830166265 +1994-08-07 18:19:58.851825129,195.88215275337 +1994-08-07 18:21:01.335159759,195.96773411751616 +1994-08-07 18:22:16.682911258,195.9911857524558 +1994-08-07 18:23:07.233670407,196.0512707039425 +1994-08-07 18:24:11.527824425,195.9524087710378 +1994-08-07 18:25:01.436698737,195.89337228514202 +1994-08-07 18:26:06.247244282,195.8784401317867 +1994-08-07 18:27:05.656973313,196.05157296880046 +1994-08-07 18:28:00.856102141,195.9754065310726 +1994-08-07 18:29:00.407347532,195.97144918429876 +1994-08-07 18:30:13.017417982,195.99000755334848 +1994-08-07 18:31:10.919329130,195.83631114492073 +1994-08-07 18:32:00.620127477,196.06952449706685 +1994-08-07 18:33:10.975642642,195.9252297985391 +1994-08-07 18:34:56.951901187,195.98766363899963 diff --git a/tests/testdata/node_comparer_1.4.0a3.nc b/tests/testdata/node_comparer_1.4.0a3.nc new file mode 100644 index 000000000..78c8a2751 Binary files /dev/null and b/tests/testdata/node_comparer_1.4.0a3.nc differ