11from __future__ import annotations
22
3+ from pathlib import Path
34from typing import TYPE_CHECKING , Sequence
45
56import numpy as np
@@ -90,15 +91,17 @@ def _create_new_instance(self, data: xr.Dataset) -> NodeModelResult:
9091class NetworkModelResult :
9192 """Model result for network data with time and node dimensions.
9293
93- Construct a NetworkModelResult from a Network object containing
94- timeseries data for each node. Users must provide exact node IDs
95- (integers obtained via ``Network.find()``) when creating observations —
96- no spatial interpolation is performed.
94+ Construct a NetworkModelResult from a result file or from an already-loaded
95+ Network containing timeseries data for each node. Users must provide exact
96+ node IDs (integers obtained via ``Network.find()``) when creating
97+ observations — no spatial interpolation is performed.
9798
9899 Parameters
99100 ----------
100- data : Network
101- Network-like object with a ``to_dataset()`` method (e.g. :class:`modelskill.network.Network`).
101+ data : Network, str or Path
102+ Path to a ``.res1d``, ``.res11`` or ``.res`` result file, or a
103+ network-like object with a ``to_dataset()`` method (e.g.
104+ :class:`modelskill.network.Network`).
102105 name : str, optional
103106 The name of the model result,
104107 by default None (will be set to first data variable name)
@@ -113,23 +116,54 @@ class NetworkModelResult:
113116 Examples
114117 --------
115118 >>> import modelskill as ms
119+ >>> mr = ms.NetworkModelResult("model.res1d", item="WaterLevel")
120+
121+ From a network built by hand, or loaded with arguments of its own:
122+
116123 >>> from modelskill.network import Network
117124 >>> network = Network(reaches) # reaches is a list[NetworkReach]
118125 >>> mr = ms.NetworkModelResult(network, name="MyModel")
119- >>> obs = ms.NodeObservation(data, node =network.find(node="node_A"))
126+ >>> obs = ms.NodeObservation(data, at =network.find(node="node_A"))
120127 >>> extracted = mr.extract(obs)
128+
129+ Notes
130+ -----
131+ A path is read by the constructor its extension belongs to: ``.res1d`` and
132+ ``.res11`` by :meth:`Network.from_mike
133+ <modelskill.network.Network.from_mike>`, ``.res`` by
134+ :meth:`Network.from_epanet <modelskill.network.Network.from_epanet>`. An
135+ EPANET file also picks up the ``.resx`` and ``.inp`` companions that share
136+ its folder and stem, since the ``.inp`` is the only one of the three
137+ carrying reach lengths.
138+
139+ Load the network yourself when you need to name the companions, or to keep
140+ memory down on a large file by reading only the nodes, reaches or
141+ quantities you will score.
142+
143+ See Also
144+ --------
145+ modelskill.network.Network.from_mike : Read a MIKE 1D or MIKE 11 result file.
146+ modelskill.network.Network.from_epanet : Read an EPANET result file.
121147 """
122148
123149 def __init__ (
124150 self ,
125- data : Network ,
151+ data : Network | str | Path ,
126152 * ,
127153 name : str | None = None ,
128154 item : str | int | None = None ,
129155 quantity : Quantity | None = None ,
130156 aux_items : Sequence [int | str ] | None = None ,
131157 ):
132- self .network = data .copy ()
158+ if isinstance (data , (str , Path )):
159+ # Imported here, not at module scope, to keep this module importable
160+ # without the optional network dependencies (ADR-010).
161+ from modelskill .network import _network_from_path
162+
163+ # Freshly built, so nothing else holds a reference to copy away from.
164+ self .network = _network_from_path (data )
165+ else :
166+ self .network = data .copy ()
133167
134168 ds = self .network .to_dataset ()
135169 sel_items = SelectedItems .parse (
0 commit comments