epyt-flow 0.8.1__py3-none-any.whl → 0.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. epyt_flow/VERSION +1 -1
  2. epyt_flow/__init__.py +1 -0
  3. epyt_flow/data/benchmarks/batadal.py +1 -1
  4. epyt_flow/data/benchmarks/battledim.py +4 -3
  5. epyt_flow/data/benchmarks/gecco_water_quality.py +4 -4
  6. epyt_flow/data/benchmarks/leakdb.py +7 -7
  7. epyt_flow/data/benchmarks/water_usage.py +2 -2
  8. epyt_flow/data/networks.py +1 -1
  9. epyt_flow/gym/control_gyms.py +2 -2
  10. epyt_flow/gym/scenario_control_env.py +1 -1
  11. epyt_flow/metrics.py +28 -28
  12. epyt_flow/models/sensor_interpolation_detector.py +3 -3
  13. epyt_flow/rest_api/base_handler.py +4 -4
  14. epyt_flow/rest_api/scada_data/data_handlers.py +11 -11
  15. epyt_flow/rest_api/scada_data/export_handlers.py +2 -2
  16. epyt_flow/rest_api/scada_data/handlers.py +9 -9
  17. epyt_flow/rest_api/scenario/event_handlers.py +6 -6
  18. epyt_flow/rest_api/scenario/handlers.py +15 -15
  19. epyt_flow/rest_api/scenario/simulation_handlers.py +7 -7
  20. epyt_flow/rest_api/scenario/uncertainty_handlers.py +6 -6
  21. epyt_flow/serialization.py +4 -2
  22. epyt_flow/simulation/events/actuator_events.py +1 -1
  23. epyt_flow/simulation/events/leakages.py +1 -1
  24. epyt_flow/simulation/events/quality_events.py +16 -5
  25. epyt_flow/simulation/events/sensor_reading_attack.py +1 -1
  26. epyt_flow/simulation/events/sensor_reading_event.py +3 -3
  27. epyt_flow/simulation/events/system_event.py +1 -1
  28. epyt_flow/simulation/parallel_simulation.py +1 -1
  29. epyt_flow/simulation/scada/advanced_control.py +2 -2
  30. epyt_flow/simulation/scada/scada_data.py +117 -131
  31. epyt_flow/simulation/scada/scada_data_export.py +1 -1
  32. epyt_flow/simulation/scenario_config.py +1 -1
  33. epyt_flow/simulation/scenario_simulator.py +120 -26
  34. epyt_flow/simulation/scenario_visualizer.py +9 -9
  35. epyt_flow/simulation/sensor_config.py +22 -28
  36. epyt_flow/topology.py +2 -2
  37. epyt_flow/uncertainty/model_uncertainty.py +624 -147
  38. epyt_flow/uncertainty/sensor_noise.py +94 -19
  39. epyt_flow/uncertainty/uncertainties.py +4 -4
  40. epyt_flow/uncertainty/utils.py +7 -7
  41. epyt_flow/utils.py +9 -8
  42. {epyt_flow-0.8.1.dist-info → epyt_flow-0.9.0.dist-info}/METADATA +1 -1
  43. {epyt_flow-0.8.1.dist-info → epyt_flow-0.9.0.dist-info}/RECORD +46 -46
  44. {epyt_flow-0.8.1.dist-info → epyt_flow-0.9.0.dist-info}/LICENSE +0 -0
  45. {epyt_flow-0.8.1.dist-info → epyt_flow-0.9.0.dist-info}/WHEEL +0 -0
  46. {epyt_flow-0.8.1.dist-info → epyt_flow-0.9.0.dist-info}/top_level.txt +0 -0
@@ -4,6 +4,7 @@ Module provides a class for implementing model uncertainty.
4
4
  from copy import deepcopy
5
5
  import warnings
6
6
  import epyt
7
+ from epyt.epanet import ToolkitConstants
7
8
  import numpy as np
8
9
 
9
10
  from ..serialization import serializable, JsonSerializable, MODEL_UNCERTAINTY_ID
@@ -18,36 +19,99 @@ class ModelUncertainty(JsonSerializable):
18
19
 
19
20
  Parameters
20
21
  ----------
21
- pipe_length_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
22
- Uncertainty of pipe lengths. None, in the case of no uncertainty.
22
+ global_pipe_length_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
23
+ Global uncertainty of pipe lengths. None, in the case of no uncertainty.
23
24
 
24
25
  The default is None.
25
- pipe_roughness_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
26
- Uncertainty of pipe roughness coefficients. None, in the case of no uncertainty.
26
+ global_pipe_roughness_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
27
+ Global uncertainty of pipe roughness coefficients. None, in the case of no uncertainty.
27
28
 
28
29
  The default is None.
29
- pipe_diameter_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
30
- Uncertainty of pipe diameters. None, in the case of no uncertainty.
30
+ global_pipe_diameter_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
31
+ Global uncertainty of pipe diameters. None, in the case of no uncertainty.
31
32
 
32
33
  The default is None.
33
- base_demand_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
34
- Uncertainty of base demands. None, in the case of no uncertainty.
34
+ global_base_demand_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
35
+ Global uncertainty of base demands. None, in the case of no uncertainty.
35
36
 
36
37
  The default is None.
37
- demand_pattern_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
38
- Uncertainty of demand patterns. None, in the case of no uncertainty.
38
+ global_demand_pattern_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
39
+ Global uncertainty of demand patterns. None, in the case of no uncertainty.
39
40
 
40
41
  The default is None.
41
- elevation_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
42
- Uncertainty of elevations. None, in the case of no uncertainty.
42
+ global_elevation_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
43
+ Global uncertainty of elevations. None, in the case of no uncertainty.
43
44
 
44
45
  The default is None.
45
- constants_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
46
- Uncertainty of MSX constants. None, in the case of no uncertainty.
46
+ global_constants_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
47
+ Global uncertainty of MSX constants. None, in the case of no uncertainty.
47
48
 
48
49
  The default is None.
49
- parameters_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
50
- Uncertainty of MSX parameters. None, in the case of no uncertainty.
50
+ global_parameters_uncertainty : :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`, optional
51
+ Global uncertainty of MSX parameters. None, in the case of no uncertaint.
52
+
53
+ The default is None.
54
+ local_pipe_length_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
55
+ Local uncertainty of pipe lengths -- i.e. a dictionary of pipe IDs and uncertainties.
56
+
57
+ None, in the case of no uncertainty.
58
+
59
+ The default is None.
60
+ local_pipe_roughness_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
61
+ Local uncertainty of pipe roughness coefficients -- i.e. a dictionary of pipe IDs and uncertainties.
62
+
63
+ None, in the case of no uncertainty.
64
+
65
+ The default is None.
66
+ local_pipe_diameter_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
67
+ Local uncertainty of pipe diameters -- i.e. a dictionary of pipe IDs and uncertainties.
68
+
69
+ None, in the case of no uncertainty.
70
+
71
+ The default is None.
72
+ local_base_demand_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
73
+ Local uncertainty of base demands -- i.e. a dictionary of node IDs and uncertainties.
74
+
75
+ None, in the case of no uncertainty.
76
+
77
+ The default is None.
78
+ local_demand_pattern_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
79
+ Local uncertainty of demand patterns --
80
+ i.e. a dictionary of demand pattern IDs and uncertainties.
81
+
82
+ None, in the case of no uncertainty.
83
+
84
+ The default is None.
85
+ local_elevation_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
86
+ Local uncertainty of elevations -- i.e. a dictionary of node IDs and uncertainties.
87
+
88
+ None, in the case of no uncertainty.
89
+
90
+ The default is None.
91
+ local_constants_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
92
+ Local uncertainty of MSX constants -- i.e. a dictionary of constant IDs and uncertainties.
93
+
94
+ None, in the case of no uncertainty.
95
+
96
+ The default is None.
97
+ local_parameters_uncertainty : dict[tuple[str, int, str] :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
98
+ Local uncertainty of MSX parameters -- i.e. a dictionary of
99
+ (parameter ID, item type, item ID) and uncertainties.
100
+
101
+ None, in the case of no uncertainty.
102
+
103
+ The default is None.
104
+ local_patterns_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
105
+ Local uncertainty of EPANET patterns -- i.e. a dictionary of pattern IDs and uncertainties.
106
+
107
+ None, in the case of no uncertainty.
108
+
109
+ The default is None.
110
+ local_msx_patterns_uncertainty : dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`], optional
111
+ Local uncertainty of EPANET-MSX patterns -- i.e. a dictionary of MSX pattern IDs
112
+ and uncertainties.
113
+
114
+ None, in the case of no uncertainty.
51
115
 
52
116
  The default is None.
53
117
  """
@@ -59,188 +123,504 @@ class ModelUncertainty(JsonSerializable):
59
123
  elevation_uncertainty: Uncertainty = None,
60
124
  constants_uncertainty: Uncertainty = None,
61
125
  parameters_uncertainty: Uncertainty = None,
62
- demand_base_uncertainty: Uncertainty = None, **kwds):
63
- if demand_base_uncertainty is not None:
64
- warnings.warn("Loading a file that was created with an outdated version of EPyT-Flow" +
65
- " -- support of such old files will be removed in the next release!",
66
- DeprecationWarning)
67
-
126
+ global_pipe_length_uncertainty: Uncertainty = None,
127
+ global_pipe_roughness_uncertainty: Uncertainty = None,
128
+ global_pipe_diameter_uncertainty: Uncertainty = None,
129
+ global_base_demand_uncertainty: Uncertainty = None,
130
+ global_demand_pattern_uncertainty: Uncertainty = None,
131
+ global_elevation_uncertainty: Uncertainty = None,
132
+ global_constants_uncertainty: Uncertainty = None,
133
+ global_parameters_uncertainty: Uncertainty = None,
134
+ local_pipe_length_uncertainty: dict[str, Uncertainty] = None,
135
+ local_pipe_roughness_uncertainty: dict[str, Uncertainty] = None,
136
+ local_pipe_diameter_uncertainty: dict[str, Uncertainty] = None,
137
+ local_base_demand_uncertainty: dict[str, Uncertainty] = None,
138
+ local_demand_pattern_uncertainty: dict[str, Uncertainty] = None,
139
+ local_elevation_uncertainty: dict[str, Uncertainty] = None,
140
+ local_constants_uncertainty: dict[str, Uncertainty] = None,
141
+ local_parameters_uncertainty: dict[str, int, Uncertainty] = None,
142
+ local_patterns_uncertainty: dict[str, Uncertainty] = None,
143
+ local_msx_patterns_uncertainty: dict[str, Uncertainty] = None,
144
+ **kwds):
68
145
  if pipe_length_uncertainty is not None:
69
- if not isinstance(pipe_length_uncertainty, Uncertainty):
70
- raise TypeError("'pipe_length_uncertainty' must be an instance of " +
71
- "'epyt_flow.uncertainty.Uncertainty' but not of " +
72
- f"'{type(pipe_length_uncertainty)}'")
146
+ global_pipe_diameter_uncertainty = pipe_length_uncertainty
147
+ warnings.warn("'pipe_length_uncertainty' is deprecated and " +
148
+ "will be removed in future releases")
73
149
  if pipe_roughness_uncertainty is not None:
74
- if not isinstance(pipe_roughness_uncertainty, Uncertainty):
75
- raise TypeError("'pipe_roughness_uncertainty' must be an instance of " +
76
- "'epyt_flow.uncertainty.Uncertainty' but not of " +
77
- f"'{type(pipe_roughness_uncertainty)}'")
150
+ global_pipe_roughness_uncertainty = pipe_roughness_uncertainty
151
+ warnings.warn("'pipe_roughness_uncertainty' is deprecated and " +
152
+ "will be removed in future releases")
78
153
  if pipe_diameter_uncertainty is not None:
79
- if not isinstance(pipe_diameter_uncertainty, Uncertainty):
80
- raise TypeError("'pipe_diameter_uncertainty' must be an instance of " +
81
- "'epyt_flow.uncertainty.Uncertainty' but not of " +
82
- f"'{type(pipe_diameter_uncertainty)}'")
154
+ global_pipe_diameter_uncertainty = pipe_diameter_uncertainty
155
+ warnings.warn("'pipe_diameter_uncertainty' is deprecated and " +
156
+ "will be removed in future releases")
83
157
  if base_demand_uncertainty is not None:
84
- if not isinstance(base_demand_uncertainty, Uncertainty):
85
- raise TypeError("'base_demand_uncertainty' must be an instance of " +
86
- "'epyt_flow.uncertainty.Uncertainty' but not of " +
87
- f"'{type(base_demand_uncertainty)}'")
158
+ global_base_demand_uncertainty = base_demand_uncertainty
159
+ warnings.warn("'base_demand_uncertainty' is deprecated and " +
160
+ "will be removed in future releases")
88
161
  if demand_pattern_uncertainty is not None:
89
- if not isinstance(demand_pattern_uncertainty, Uncertainty):
90
- raise TypeError("'demand_pattern_uncertainty' must be an instance of " +
91
- "'epyt_flow.uncertainty.Uncertainty' but not of " +
92
- f"'{type(demand_pattern_uncertainty)}'")
162
+ global_demand_pattern_uncertainty = demand_pattern_uncertainty
163
+ warnings.warn("'demand_pattern_uncertainty' is deprecated and " +
164
+ "will be removed in future releases")
93
165
  if elevation_uncertainty is not None:
94
- if not isinstance(elevation_uncertainty, Uncertainty):
95
- raise TypeError("'elevation_uncertainty' must be an instance of " +
96
- "'epyt_flow.uncertainty.Uncertainty' but not of " +
97
- f"'{type(elevation_uncertainty)}'")
166
+ global_elevation_uncertainty = elevation_uncertainty
167
+ warnings.warn("'elevation_uncertainty' is deprecated and " +
168
+ "will be removed in future releases")
98
169
  if constants_uncertainty is not None:
99
- if not isinstance(constants_uncertainty, Uncertainty):
100
- raise TypeError("'constants_uncertainty' must be an instance of " +
101
- "'epyt_flow.uncertainty.Uncertainty' but not of " +
102
- f"'{type(constants_uncertainty)}'")
170
+ global_constants_uncertainty = constants_uncertainty
171
+ warnings.warn("'constants_uncertainty' is deprecated and " +
172
+ "will be removed in future releases")
103
173
  if parameters_uncertainty is not None:
104
- if not isinstance(parameters_uncertainty, Uncertainty):
105
- raise TypeError("'parameters_uncertainty' must be an instance of " +
106
- "'epyt_flow.uncertainty.Uncertainty' but not of " +
107
- f"'{type(parameters_uncertainty)}'")
174
+ global_parameters_uncertainty = parameters_uncertainty
175
+ warnings.warn("'parameters_uncertainty' is deprecated and " +
176
+ "will be removed in future releases")
108
177
 
109
- self.__pipe_length = pipe_length_uncertainty
110
- self.__pipe_roughness = pipe_roughness_uncertainty
111
- self.__pipe_diameter = pipe_diameter_uncertainty
112
- self.__base_demand = base_demand_uncertainty
113
- self.__demand_pattern = demand_pattern_uncertainty
114
- self.__elevation = elevation_uncertainty
115
- self.__constants = constants_uncertainty
116
- self.__parameters = parameters_uncertainty
178
+ if global_pipe_length_uncertainty is not None:
179
+ if not isinstance(global_pipe_length_uncertainty, Uncertainty):
180
+ raise TypeError("'global_pipe_length_uncertainty' must be an instance of " +
181
+ "'epyt_flow.uncertainty.Uncertainty' but not of " +
182
+ f"'{type(global_pipe_length_uncertainty)}'")
183
+ if global_pipe_roughness_uncertainty is not None:
184
+ if not isinstance(global_pipe_roughness_uncertainty, Uncertainty):
185
+ raise TypeError("'global_pipe_roughness_uncertainty' must be an instance of " +
186
+ "'epyt_flow.uncertainty.Uncertainty' but not of " +
187
+ f"'{type(global_pipe_roughness_uncertainty)}'")
188
+ if global_pipe_diameter_uncertainty is not None:
189
+ if not isinstance(global_pipe_diameter_uncertainty, Uncertainty):
190
+ raise TypeError("'global_pipe_diameter_uncertainty' must be an instance of " +
191
+ "'epyt_flow.uncertainty.Uncertainty' but not of " +
192
+ f"'{type(global_pipe_diameter_uncertainty)}'")
193
+ if global_base_demand_uncertainty is not None:
194
+ if not isinstance(global_base_demand_uncertainty, Uncertainty):
195
+ raise TypeError("'global_base_demand_uncertainty' must be an instance of " +
196
+ "'epyt_flow.uncertainty.Uncertainty' but not of " +
197
+ f"'{type(global_base_demand_uncertainty)}'")
198
+ if global_demand_pattern_uncertainty is not None:
199
+ if not isinstance(global_demand_pattern_uncertainty, Uncertainty):
200
+ raise TypeError("'global_demand_pattern_uncertainty' must be an instance of " +
201
+ "'epyt_flow.uncertainty.Uncertainty' but not of " +
202
+ f"'{type(global_demand_pattern_uncertainty)}'")
203
+ if global_elevation_uncertainty is not None:
204
+ if not isinstance(global_elevation_uncertainty, Uncertainty):
205
+ raise TypeError("'global_elevation_uncertainty' must be an instance of " +
206
+ "'epyt_flow.uncertainty.Uncertainty' but not of " +
207
+ f"'{type(global_elevation_uncertainty)}'")
208
+ if global_constants_uncertainty is not None:
209
+ if not isinstance(global_constants_uncertainty, Uncertainty):
210
+ raise TypeError("'global_constants_uncertainty' must be an instance of " +
211
+ "'epyt_flow.uncertainty.Uncertainty' but not of " +
212
+ f"'{type(global_constants_uncertainty)}'")
213
+ if global_parameters_uncertainty is not None:
214
+ if not isinstance(global_parameters_uncertainty, Uncertainty):
215
+ raise TypeError("'global_parameters_uncertainty' must be an instance of " +
216
+ "'epyt_flow.uncertainty.Uncertainty' but not of " +
217
+ f"'{type(global_parameters_uncertainty)}'")
218
+
219
+ if local_pipe_length_uncertainty is not None:
220
+ if not isinstance(local_pipe_length_uncertainty, dict):
221
+ raise TypeError("'local_pipe_length_uncertainty' must be an instance of " +
222
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
223
+ f"'{type(local_pipe_length_uncertainty)}'")
224
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
225
+ for key, val in local_pipe_length_uncertainty.items()):
226
+ raise TypeError("'local_pipe_length_uncertainty': " +
227
+ "All keys must be instances of 'str' and all values must be " +
228
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
229
+ if local_pipe_roughness_uncertainty is not None:
230
+ if not isinstance(local_pipe_roughness_uncertainty, dict):
231
+ raise TypeError("'local_pipe_roughness_uncertainty' must be an instance of " +
232
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
233
+ f"'{type(local_pipe_roughness_uncertainty)}'")
234
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
235
+ for key, val in local_pipe_roughness_uncertainty.items()):
236
+ raise TypeError("'local_pipe_roughness_uncertainty': " +
237
+ "All keys must be instances of 'str' and all values must be " +
238
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
239
+ if local_pipe_diameter_uncertainty is not None:
240
+ if not isinstance(local_pipe_diameter_uncertainty, dict):
241
+ raise TypeError("'local_pipe_diameter_uncertainty' must be an instance of " +
242
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
243
+ f"'{type(local_pipe_diameter_uncertainty)}'")
244
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
245
+ for key, val in local_pipe_diameter_uncertainty.items()):
246
+ raise TypeError("'local_pipe_diameter_uncertainty': " +
247
+ "All keys must be instances of 'str' and all values must be " +
248
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
249
+ if local_base_demand_uncertainty is not None:
250
+ if not isinstance(local_base_demand_uncertainty, dict):
251
+ raise TypeError("'local_base_demand_uncertainty' must be an instance of " +
252
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
253
+ f"'{type(local_base_demand_uncertainty)}'")
254
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
255
+ for key, val in local_base_demand_uncertainty.items()):
256
+ raise TypeError("'local_base_demand_uncertainty': " +
257
+ "All keys must be instances of 'str' and all values must be " +
258
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
259
+ if local_demand_pattern_uncertainty is not None:
260
+ if not isinstance(local_demand_pattern_uncertainty, dict):
261
+ raise TypeError("'local_demand_pattern_uncertainty' must be an instance of " +
262
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
263
+ f"'{type(local_demand_pattern_uncertainty)}'")
264
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
265
+ for key, val in local_demand_pattern_uncertainty.items()):
266
+ raise TypeError("'local_demand_pattern_uncertainty': " +
267
+ "All keys must be instances of 'str' and all values must be " +
268
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
269
+ if local_elevation_uncertainty is not None:
270
+ if not isinstance(local_elevation_uncertainty, dict):
271
+ raise TypeError("'local_elevation_uncertainty' must be an instance of " +
272
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
273
+ f"'{type(local_elevation_uncertainty)}'")
274
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
275
+ for key, val in local_elevation_uncertainty.items()):
276
+ raise TypeError("'local_elevation_uncertainty': " +
277
+ "All keys must be instances of 'str' and all values must be " +
278
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
279
+ if local_constants_uncertainty is not None:
280
+ if not isinstance(local_constants_uncertainty, dict):
281
+ raise TypeError("'local_constants_uncertainty' must be an instance of " +
282
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
283
+ f"'{type(local_constants_uncertainty)}'")
284
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
285
+ for key, val in local_constants_uncertainty.items()):
286
+ raise TypeError("'local_constants_uncertainty': " +
287
+ "All keys must be instances of 'str' and all values must be " +
288
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
289
+ if local_parameters_uncertainty is not None:
290
+ if not isinstance(local_parameters_uncertainty, dict):
291
+ raise TypeError("'local_parameters_uncertainty' must be an instance of " +
292
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
293
+ f"'{type(local_parameters_uncertainty)}'")
294
+ if any(not isinstance(key, tuple) or not isinstance(key[0], str) or
295
+ not isinstance(key[1], int) or not isinstance(key[2], str) or
296
+ not isinstance(local_parameters_uncertainty[key], Uncertainty)
297
+ for key in local_parameters_uncertainty.keys()):
298
+ raise TypeError("'local_parameters_uncertainty': " +
299
+ "All keys must be instances of 'tuple[str, int, str]' and all " +
300
+ "values must be instances of 'epyt_flow.uncertainty.Uncertainty'")
301
+ if local_patterns_uncertainty is not None:
302
+ if not isinstance(local_patterns_uncertainty, dict):
303
+ raise TypeError("'local_patterns_uncertainty' must be an instance of " +
304
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
305
+ f"'{type(local_patterns_uncertainty)}'")
306
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
307
+ for key, val in local_patterns_uncertainty.items()):
308
+ raise TypeError("'local_patterns_uncertainty': " +
309
+ "All keys must be instances of 'str' and all values must be " +
310
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
311
+ if local_msx_patterns_uncertainty is not None:
312
+ if not isinstance(local_msx_patterns_uncertainty, dict):
313
+ raise TypeError("'local_msx_patterns_uncertainty' must be an instance of " +
314
+ "'dict[str, epyt_flow.uncertainty.Uncertainty]' but not of " +
315
+ f"'{type(local_msx_patterns_uncertainty)}'")
316
+ if any(not isinstance(key, str) or not isinstance(val, Uncertainty)
317
+ for key, val in local_msx_patterns_uncertainty.items()):
318
+ raise TypeError("'local_msx_patterns_uncertainty': " +
319
+ "All keys must be instances of 'str' and all values must be " +
320
+ "instances of 'epyt_flow.uncertainty.Uncertainty'")
321
+
322
+ self.__global_pipe_length = global_pipe_length_uncertainty
323
+ self.__global_pipe_roughness = global_pipe_roughness_uncertainty
324
+ self.__global_pipe_diameter = global_pipe_diameter_uncertainty
325
+ self.__global_base_demand = global_base_demand_uncertainty
326
+ self.__global_demand_pattern = global_demand_pattern_uncertainty
327
+ self.__global_elevation = global_elevation_uncertainty
328
+ self.__global_constants = global_constants_uncertainty
329
+ self.__global_parameters = global_parameters_uncertainty
330
+ self.__local_pipe_length = local_pipe_length_uncertainty
331
+ self.__local_pipe_roughness = local_pipe_roughness_uncertainty
332
+ self.__local_pipe_diameter = local_pipe_diameter_uncertainty
333
+ self.__local_base_demand = local_base_demand_uncertainty
334
+ self.__local_demand_pattern = local_demand_pattern_uncertainty
335
+ self.__local_elevation = local_elevation_uncertainty
336
+ self.__local_constants = local_constants_uncertainty
337
+ self.__local_parameters = local_parameters_uncertainty
338
+ self.__local_patterns = local_patterns_uncertainty
339
+ self.__local_msx_patterns = local_msx_patterns_uncertainty
117
340
 
118
341
  super().__init__(**kwds)
119
342
 
120
343
  @property
121
- def pipe_length(self) -> Uncertainty:
344
+ def global_pipe_length(self) -> Uncertainty:
122
345
  """
123
- Gets the pipe length uncertainty.
346
+ Returns the global pipe length uncertainty.
124
347
 
125
348
  Returns
126
349
  -------
127
350
  :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`
128
- Pipe length uncertainty.
351
+ Global pipe length uncertainty.
129
352
  """
130
- return deepcopy(self.__pipe_length)
353
+ return deepcopy(self.__global_pipe_length)
131
354
 
132
355
  @property
133
- def pipe_roughness(self) -> Uncertainty:
356
+ def global_pipe_roughness(self) -> Uncertainty:
134
357
  """
135
- Gets the pipe roughness uncertainty.
358
+ Returns the global pipe roughness uncertainty.
136
359
 
137
360
  Returns
138
361
  -------
139
362
  :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`
140
- Pipe roughness uncertainty.
363
+ Global pipe roughness uncertainty.
141
364
  """
142
- return deepcopy(self.__pipe_roughness)
365
+ return deepcopy(self.__global_pipe_roughness)
143
366
 
144
367
  @property
145
- def pipe_diameter(self) -> Uncertainty:
368
+ def global_pipe_diameter(self) -> Uncertainty:
146
369
  """
147
- Gets the pipe diameter uncertainty.
370
+ Returns the global pipe diameter uncertainty.
148
371
 
149
372
  Returns
150
373
  -------
151
374
  :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`
152
- Pipe diameter uncertainty.
375
+ Global pipe diameter uncertainty.
153
376
  """
154
- return deepcopy(self.__pipe_diameter)
377
+ return deepcopy(self.__global_pipe_diameter)
155
378
 
156
379
  @property
157
- def base_demand(self) -> Uncertainty:
380
+ def global_base_demand(self) -> Uncertainty:
158
381
  """
159
- Gets the base demand uncertainty.
382
+ Returns the global base demand uncertainty.
160
383
 
161
384
  Returns
162
385
  -------
163
386
  :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`
164
- Demand base uncertainty.
387
+ Global base demand uncertainty.
165
388
  """
166
- return deepcopy(self.__base_demand)
389
+ return deepcopy(self.__global_base_demand)
167
390
 
168
391
  @property
169
- def demand_pattern(self) -> Uncertainty:
392
+ def global_demand_pattern(self) -> Uncertainty:
170
393
  """
171
- Gets the demand pattern uncertainty.
394
+ Returns the global demand pattern uncertainty.
172
395
 
173
396
  Returns
174
397
  -------
175
398
  :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`
176
- Demand pattern uncertainty.
399
+ Global demand pattern uncertainty.
177
400
  """
178
- return deepcopy(self.__demand_pattern)
401
+ return deepcopy(self.__global_demand_pattern)
179
402
 
180
403
  @property
181
- def elevation(self) -> Uncertainty:
404
+ def global_elevation(self) -> Uncertainty:
182
405
  """
183
- Gets the node elevation uncertainty.
406
+ Returns the global node elevation uncertainty.
184
407
 
185
408
  Returns
186
409
  -------
187
410
  :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`
188
- Node elevation uncertainty.
411
+ Global node elevation uncertainty.
189
412
  """
190
- return deepcopy(self.__elevation)
413
+ return deepcopy(self.__global_elevation)
191
414
 
192
415
  @property
193
- def constants(self) -> Uncertainty:
416
+ def global_constants(self) -> Uncertainty:
194
417
  """
195
- Gets the MSX constant uncertainty.
418
+ Returns the global MSX constant uncertainty.
196
419
 
197
420
  Returns
198
421
  -------
199
422
  :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`
200
- MSX constant uncertainty.
423
+ Global MSX constant uncertainty.
201
424
  """
202
- return deepcopy(self.__constants)
425
+ return deepcopy(self.__global_constants)
203
426
 
204
427
  @property
205
- def parameters(self) -> Uncertainty:
428
+ def global_parameters(self) -> Uncertainty:
206
429
  """
207
- Gets the MSX parameter uncertainty.
430
+ Returns the global MSX parameter uncertainty.
208
431
 
209
432
  Returns
210
433
  -------
211
434
  :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`
212
- MSX parameter uncertainty.
435
+ Global MSX parameter uncertainty.
436
+ """
437
+ return deepcopy(self.__global_parameters)
438
+
439
+ @property
440
+ def local_pipe_length(self) -> dict[str, Uncertainty]:
441
+ """
442
+ Returns the local pipe length uncertainty.
443
+
444
+ Returns
445
+ -------
446
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
447
+ Local pipe length uncertainty.
448
+ """
449
+ return deepcopy(self.__local_pipe_length)
450
+
451
+ @property
452
+ def local_pipe_roughness(self) -> dict[str, Uncertainty]:
453
+ """
454
+ Returns the local pipe roughness uncertainty.
455
+
456
+ Returns
457
+ -------
458
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
459
+ Local pipe roughness uncertainty.
460
+ """
461
+ return deepcopy(self.__local_pipe_roughness)
462
+
463
+ @property
464
+ def local_pipe_diameter(self) -> dict[str, Uncertainty]:
465
+ """
466
+ Returns the local pipe diameter uncertainty.
467
+
468
+ Returns
469
+ -------
470
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
471
+ Local pipe diameter uncertainty.
472
+ """
473
+ return deepcopy(self.__local_pipe_diameter)
474
+
475
+ @property
476
+ def local_base_demand(self) -> dict[str, Uncertainty]:
477
+ """
478
+ Returns the local base demand uncertainty.
479
+
480
+ Returns
481
+ -------
482
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
483
+ Local base demand uncertainty.
484
+ """
485
+ return deepcopy(self.__local_base_demand)
486
+
487
+ @property
488
+ def local_demand_pattern(self) -> dict[str, Uncertainty]:
489
+ """
490
+ Returns the local demand pattern uncertainty.
491
+
492
+ Returns
493
+ -------
494
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
495
+ Local demand pattern uncertainty.
496
+ """
497
+ return deepcopy(self.__local_demand_pattern)
498
+
499
+ @property
500
+ def local_elevation(self) -> dict[str, Uncertainty]:
501
+ """
502
+ Returns the local node elevation uncertainty.
503
+
504
+ Returns
505
+ -------
506
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
507
+ Local node elevation uncertainty.
213
508
  """
214
- return deepcopy(self.__parameters)
509
+ return deepcopy(self.__local_elevation)
510
+
511
+ @property
512
+ def local_constants(self) -> dict[str, Uncertainty]:
513
+ """
514
+ Returns the local MSX constant uncertainty.
515
+
516
+ Returns
517
+ -------
518
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
519
+ Local MSX constant uncertainty.
520
+ """
521
+ return deepcopy(self.__local_constants)
522
+
523
+ @property
524
+ def local_parameters(self) -> dict[tuple[str, int, str], Uncertainty]:
525
+ """
526
+ Returns the local MSX parameter uncertainty.
527
+
528
+ Returns
529
+ -------
530
+ dict[tuple[str, int, str], :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
531
+ Local MSX parameter uncertainty.
532
+ """
533
+ return deepcopy(self.__local_parameters)
534
+
535
+ @property
536
+ def local_patterns(self) -> dict[str, Uncertainty]:
537
+ """
538
+ Returns the local EPANET patterns uncertainty.
539
+
540
+ Returns
541
+ -------
542
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
543
+ Local EPANET patterns uncertainty.
544
+ """
545
+ return deepcopy(self.__local_patterns)
546
+
547
+ @property
548
+ def local_msx_patterns(self) -> dict[str, Uncertainty]:
549
+ """
550
+ Returns the local EPANET-MSX patterns uncertainty.
551
+
552
+ Returns
553
+ -------
554
+ dict[str, :class:`~epyt_flow.uncertainty.uncertainties.Uncertainty`]
555
+ Local EPANET-MSX patterns uncertainty.
556
+ """
557
+ return deepcopy(self.__local_msx_patterns)
215
558
 
216
559
  def get_attributes(self) -> dict:
217
- return super().get_attributes() | {"pipe_length_uncertainty": self.__pipe_length,
218
- "pipe_roughness_uncertainty": self.__pipe_roughness,
219
- "pipe_diameter_uncertainty": self.__pipe_diameter,
220
- "base_demand_uncertainty": self.__base_demand,
221
- "demand_pattern_uncertainty": self.__demand_pattern,
222
- "elevation_uncertainty": self.__elevation,
223
- "constants_uncertainty": self.__constants,
224
- "parameters_uncertainty": self.__parameters}
560
+ attribs = {"global_pipe_length_uncertainty": self.__global_pipe_length,
561
+ "global_pipe_roughness_uncertainty": self.__global_pipe_roughness,
562
+ "global_pipe_diameter_uncertainty": self.__global_pipe_diameter,
563
+ "global_base_demand_uncertainty": self.__global_base_demand,
564
+ "global_demand_pattern_uncertainty": self.__global_demand_pattern,
565
+ "global_elevation_uncertainty": self.__global_elevation,
566
+ "global_constants_uncertainty": self.__global_constants,
567
+ "global_parameters_uncertainty": self.__global_parameters,
568
+ "local_pipe_length_uncertainty": self.__local_pipe_length,
569
+ "local_pipe_roughness_uncertainty": self.__local_pipe_roughness,
570
+ "local_pipe_diameter_uncertainty": self.__local_pipe_diameter,
571
+ "local_base_demand_uncertainty": self.__local_base_demand,
572
+ "local_demand_pattern_uncertainty": self.__local_demand_pattern,
573
+ "local_elevation_uncertainty": self.__local_elevation,
574
+ "local_constants_uncertainty": self.__local_constants,
575
+ "local_parameters_uncertainty": self.__local_parameters,
576
+ "local_patterns_uncertainty": self.__local_patterns,
577
+ "local_msx_patterns_uncertainty": self.__local_msx_patterns}
578
+
579
+ return super().get_attributes() | attribs
225
580
 
226
581
  def __eq__(self, other) -> bool:
227
582
  if not isinstance(other, ModelUncertainty):
228
583
  raise TypeError("Can not compare 'ModelUncertainty' instance " +
229
584
  f"with '{type(other)}' instance")
230
585
 
231
- return self.__pipe_length == other.pipe_length \
232
- and self.__pipe_roughness == other.pipe_roughness \
233
- and self.__pipe_diameter == other.pipe_diameter \
234
- and self.__base_demand == other.base_demand \
235
- and self.__demand_pattern == other.demand_pattern \
236
- and self.__elevation == other.elevation \
237
- and self.__parameters == other.parameters and self.__constants == other.constants
586
+ return self.__global_pipe_length == other.global_pipe_length \
587
+ and self.__global_pipe_roughness == other.global_pipe_roughness \
588
+ and self.__global_pipe_diameter == other.global_pipe_diameter \
589
+ and self.__global_base_demand == other.global_base_demand \
590
+ and self.__global_demand_pattern == other.global_demand_pattern \
591
+ and self.__global_elevation == other.global_elevation \
592
+ and self.__global_parameters == other.global_parameters \
593
+ and self.__global_constants == other.global_constants \
594
+ and self.__local_pipe_length == other.local_pipe_length \
595
+ and self.__local_pipe_roughness == other.local_pipe_roughness \
596
+ and self.__local_pipe_diameter == other.local_pipe_diameter \
597
+ and self.__local_base_demand == other.local_base_demand \
598
+ and self.__local_demand_pattern == other.local_demand_pattern \
599
+ and self.__local_elevation == other.local_elevation \
600
+ and self.__local_parameters == other.local_parameters \
601
+ and self.__local_constants == other.local_constants \
602
+ and self.__local_patterns == other.local_patterns \
603
+ and self.__local_msx_patterns == other.local_msx_patterns
238
604
 
239
605
  def __str__(self) -> str:
240
- return f"pipe_length: {self.__pipe_length} pipe_roughness: {self.__pipe_roughness} " + \
241
- f"pipe_diameter: {self.__pipe_diameter} demand_base: {self.__base_demand} " + \
242
- f"demand_pattern: {self.__demand_pattern} elevation: {self.__elevation} " + \
243
- f"constants: {self.__constants} parameters: {self.__parameters}"
606
+ return f"global_pipe_length: {self.__global_pipe_length} " +\
607
+ f"global_pipe_roughness: {self.__global_pipe_roughness} " + \
608
+ f"global_pipe_diameter: {self.__global_pipe_diameter} " + \
609
+ f"global_demand_base: {self.__global_base_demand} " + \
610
+ f"global_demand_pattern: {self.__global_demand_pattern} " + \
611
+ f"global_elevation: {self.__global_elevation} " + \
612
+ f"global_constants: {self.__global_constants} " + \
613
+ f"global_parameters: {self.__global_parameters}" + \
614
+ f"local_pipe_length: {self.__local_pipe_length} " +\
615
+ f"local_pipe_roughness: {self.__local_pipe_roughness} " + \
616
+ f"local_pipe_diameter: {self.__local_pipe_diameter} " + \
617
+ f"local_demand_base: {self.__local_base_demand} " + \
618
+ f"local_demand_pattern: {self.__local_demand_pattern} " + \
619
+ f"local_elevation: {self.__local_elevation} " + \
620
+ f"local_constants: {self.__local_constants} " + \
621
+ f"local_parameters: {self.__local_parameters} " + \
622
+ f"local_patterns: {self.__local_patterns} " + \
623
+ f"local_msx_patterns: {self.__local_msx_patterns}"
244
624
 
245
625
  def apply(self, epanet_api: epyt.epanet) -> None:
246
626
  """
@@ -248,34 +628,64 @@ class ModelUncertainty(JsonSerializable):
248
628
 
249
629
  Parameters
250
630
  ----------
251
- epanet_api : `epyt.epanet`
631
+ epanet_api : `epyt.epanet <https://epanet-python-toolkit-epyt.readthedocs.io/en/stable/api.html#epyt.epanet.epanet>`_
252
632
  Interface to EPANET and EPANET-MSX.
253
633
  """
254
- if self.__pipe_length is not None:
634
+ if self.__global_pipe_length is not None:
255
635
  link_length = epanet_api.getLinkLength()
256
- link_length = self.__pipe_length.apply_batch(link_length)
636
+ link_length = self.__global_pipe_length.apply_batch(link_length)
257
637
  epanet_api.setLinkLength(link_length)
258
638
 
259
- if self.__pipe_diameter is not None:
639
+ if self.__local_pipe_length is not None:
640
+ for pipe_id, uncertainty in self.__local_pipe_length.items():
641
+ link_idx = epanet_api.getLinkIndex(pipe_id)
642
+ link_length = epanet_api.getLinkLength(link_idx)
643
+ link_length = uncertainty.apply(link_length)
644
+ epanet_api.setLinkLength(link_idx, link_length)
645
+
646
+ if self.__global_pipe_diameter is not None:
260
647
  link_diameters = epanet_api.getLinkDiameter()
261
- link_diameters = self.__pipe_diameter.apply_batch(link_diameters)
648
+ link_diameters = self.__global_pipe_diameter.apply_batch(link_diameters)
262
649
  epanet_api.setLinkDiameter(link_diameters)
263
650
 
264
- if self.__pipe_roughness is not None:
651
+ if self.__local_pipe_diameter is not None:
652
+ for pipe_id, uncertainty in self.__local_pipe_diameter.items():
653
+ link_idx = epanet_api.getLinkIndex(pipe_id)
654
+ link_diameter = epanet_api.getLinkDiameter(link_idx)
655
+ link_diameter = uncertainty.apply(link_diameter)
656
+ epanet_api.setLinkDiameter(link_idx, link_diameter)
657
+
658
+ if self.__global_pipe_roughness is not None:
265
659
  coeffs = epanet_api.getLinkRoughnessCoeff()
266
- coeffs = self.__pipe_roughness.apply_batch(coeffs)
660
+ coeffs = self.__global_pipe_roughness.apply_batch(coeffs)
267
661
  epanet_api.setLinkRoughnessCoeff(coeffs)
268
662
 
269
- if self.__base_demand is not None:
663
+ if self.__local_pipe_roughness is not None:
664
+ for pipe_id, uncertainty in self.__local_pipe_roughness.items():
665
+ link_idx = epanet_api.getLinkIndex(pipe_id)
666
+ link_roughness_coeff = epanet_api.getLinkRoughnessCoeff(link_idx)
667
+ link_roughness_coeff = uncertainty.apply(link_roughness_coeff)
668
+ epanet_api.setLinkRoughnessCoeff(link_idx, link_roughness_coeff)
669
+
670
+ if self.__global_base_demand is not None:
270
671
  all_nodes_idx = epanet_api.getNodeIndex()
271
672
  for node_idx in all_nodes_idx:
272
673
  n_demand_categories = epanet_api.getNodeDemandCategoriesNumber(node_idx)
273
674
  for demand_category in range(n_demand_categories):
274
675
  base_demand = epanet_api.getNodeBaseDemands(node_idx)[demand_category + 1]
275
- base_demand = self.__base_demand.apply(base_demand)
676
+ base_demand = self.__global_base_demand.apply(base_demand)
677
+ epanet_api.setNodeBaseDemands(node_idx, demand_category + 1, base_demand)
678
+
679
+ if self.__local_base_demand is not None:
680
+ for node_id, uncertainty in self.__local_base_demand.items():
681
+ node_idx = epanet_api.getNodeIndex(node_id)
682
+ n_demand_categories = epanet_api.getNodeDemandCategoriesNumber(node_idx)
683
+ for demand_category in range(n_demand_categories):
684
+ base_demand = epanet_api.getNodeBaseDemands(node_idx)[demand_category + 1]
685
+ base_demand = uncertainty.apply(base_demand)
276
686
  epanet_api.setNodeBaseDemands(node_idx, demand_category + 1, base_demand)
277
687
 
278
- if self.__demand_pattern is not None:
688
+ if self.__global_demand_pattern is not None:
279
689
  demand_patterns_idx = epanet_api.getNodeDemandPatternIndex()
280
690
  demand_patterns_id = np.unique([demand_patterns_idx[k]
281
691
  for k in demand_patterns_idx.keys()])
@@ -285,31 +695,98 @@ class ModelUncertainty(JsonSerializable):
285
695
  pattern_length = epanet_api.getPatternLengths(pattern_id)
286
696
  for t in range(pattern_length):
287
697
  v = epanet_api.getPatternValue(pattern_id, t+1)
288
- epanet_api.setPatternValue(pattern_id, t+1, self.__demand_pattern.apply(v))
289
-
290
- if self.__elevation is not None:
291
- elevations = epanet_api.getNodeElevations()
292
- elevations = self.__elevation.apply_batch(elevations)
293
- epanet_api.setNodeElevations(elevations)
698
+ v_ = self.__global_demand_pattern.apply(v)
699
+ epanet_api.setPatternValue(pattern_id, t+1, v_)
294
700
 
295
- if self.__constants is not None:
296
- constants = np.array(epanet_api.getMSXConstantsValue())
297
- constants = self.__constants.apply_batch(constants)
298
- epanet_api.setMSXConstantsValue(constants)
299
-
300
- if self.__parameters is not None:
301
- parameters_pipes = epanet_api.getMSXParametersPipesValue()
302
- for i, pipe_idx in enumerate(epanet_api.getLinkPipeIndex()):
303
- if len(parameters_pipes[i]) == 0:
304
- continue
701
+ if self.__local_demand_pattern is not None:
702
+ patterns_id = epanet_api.getPatternNameID()
703
+ paterns_idx = epanet_api.getPatternIndex()
305
704
 
306
- parameters_pipes_val = self.__parameters.apply_batch(np.array(parameters_pipes[i]))
307
- epanet_api.setMSXParametersPipesValue(pipe_idx, parameters_pipes_val)
705
+ for pattern_id, uncertainty in self.__local_demand_pattern.items():
706
+ pattern_idx = paterns_idx[patterns_id.index(pattern_id)]
707
+ pattern_length, = epanet_api.getPatternLengths(pattern_id)
708
+ for t in range(pattern_length):
709
+ v = epanet_api.getPatternValue(pattern_idx, t+1)
710
+ v_ = uncertainty.apply(v)
711
+ epanet_api.setPatternValue(pattern_idx, t+1, v_)
308
712
 
309
- parameters_tanks = epanet_api.getMSXParametersTanksValue()
310
- for i, tank_idx in enumerate(epanet_api.getNodeTankIndex()):
311
- if parameters_tanks[i] is None or len(parameters_tanks[i]) == 0:
312
- continue
713
+ if self.__global_elevation is not None:
714
+ elevations = epanet_api.getNodeElevations()
715
+ elevations = self.__global_elevation.apply_batch(elevations)
716
+ epanet_api.setNodeElevations(elevations)
313
717
 
314
- parameters_tanks_val = self.__parameters.apply_batch(np.array(parameters_tanks[i]))
315
- epanet_api.setMSXParametersTanksValue(tank_idx, parameters_tanks_val)
718
+ if self.__local_elevation is not None:
719
+ for node_id, uncertainty in self.__local_elevation.items():
720
+ node_idx = epanet_api.getNodeIndex(node_id)
721
+ elevation = epanet_api.getNodeElevations(node_idx)
722
+ elevation = uncertainty.apply(elevation)
723
+ epanet_api.setNodeElevations(node_idx, elevation)
724
+
725
+ if self.__local_patterns is not None:
726
+ for pattern_id, uncertainty in self.__local_patterns.items():
727
+ pattern_idx = epanet_api.getPatternIndex(pattern_id)
728
+ pattern_length = epanet_api.getPatternLengths(pattern_idx)
729
+ pattern = np.array([epanet_api.getPatternValue(pattern_idx, t+1)
730
+ for t in range(pattern_length)])
731
+ pattern = uncertainty.apply_batch(pattern)
732
+ epanet_api.setPattern(pattern_idx, pattern)
733
+
734
+ if epanet_api.MSXFile is not None:
735
+ if self.__global_constants is not None:
736
+ constants = np.array(epanet_api.getMSXConstantsValue())
737
+ constants = self.__global_constants.apply_batch(constants)
738
+ epanet_api.setMSXConstantsValue(constants)
739
+
740
+ if self.__local_constants:
741
+ for constant_id, uncertainty in self.__local_constants.items():
742
+ idx = epanet_api.MSXgetindex(ToolkitConstants.MSX_CONSTANT, constant_id)
743
+ constant = epanet_api.msx.MSXgetconstant(idx)
744
+ constant = uncertainty.apply(constant)
745
+ epanet_api.msx.MSXsetconstant(idx, constant)
746
+
747
+ if self.__global_parameters is not None:
748
+ parameters_pipes = epanet_api.getMSXParametersPipesValue()
749
+ for i, pipe_idx in enumerate(epanet_api.getLinkPipeIndex()):
750
+ if len(parameters_pipes[i]) == 0:
751
+ continue
752
+
753
+ parameters_pipes_val = self.__global_parameters.apply_batch(
754
+ np.array(parameters_pipes[i]))
755
+ epanet_api.setMSXParametersPipesValue(pipe_idx, parameters_pipes_val)
756
+
757
+ parameters_tanks = epanet_api.getMSXParametersTanksValue()
758
+ for i, tank_idx in enumerate(epanet_api.getNodeTankIndex()):
759
+ if parameters_tanks[i] is None or len(parameters_tanks[i]) == 0:
760
+ continue
761
+
762
+ parameters_tanks_val = self.__global_parameters.apply_batch(
763
+ np.array(parameters_tanks[i]))
764
+ epanet_api.setMSXParametersTanksValue(tank_idx, parameters_tanks_val)
765
+
766
+ if self.__local_parameters is not None:
767
+ for (param_id, item_type, item_id), uncertainty in self.__local_parameters.items():
768
+ idx, = epanet_api.getMSXParametersIndex([param_id])
769
+
770
+ if item_type == ToolkitConstants.MSX_NODE:
771
+ item_idx = epanet_api.getNodeIndex(item_id)
772
+ elif item_type == ToolkitConstants.MSX_LINK:
773
+ item_idx = epanet_api.getLinkIndex(item_id)
774
+ else:
775
+ raise ValueError(f"Unknown item type '{item_type}' must be either " +
776
+ "ToolkitConstants.MSX_NODE or ToolkitConstants.MSX_LINK")
777
+
778
+ parameter = epanet_api.msx.MSXgetparameter(item_type, item_idx, idx)
779
+ parameter = uncertainty.apply(parameter)
780
+ epanet_api.msx.MSXsetparameter(item_type, item_idx, idx, parameter)
781
+
782
+ if self.__local_msx_patterns is not None:
783
+ for pattern_id, uncertainty in self.__local_msx_patterns.items():
784
+ pattern_idx, = epanet_api.getMSXPatternsIndex([pattern_id])
785
+ pattern = epanet_api.getMSXConstantsValue([pattern_idx])
786
+ pattern = uncertainty.apply_batch(pattern)
787
+ epanet_api.setMSXPattern(pattern_idx, pattern)
788
+ else:
789
+ if self.__local_msx_patterns is not None or self.__local_parameters is not None or \
790
+ self.__local_constants is not None or self.__global_constants is not None or \
791
+ self.__global_parameters is not None:
792
+ warnings.warn("Ignoring EPANET-MSX uncertainties because not .msx file was loaded")