epyt-flow 0.13.1__py3-none-any.whl → 0.14.1__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.
- epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +40 -8
- epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +3 -3
- epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +24 -7
- epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +726 -374
- epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +128 -32
- epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +7 -1
- epyt_flow/EPANET/EPANET/SRC_engines/flowbalance.c +186 -0
- epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +40 -14
- epyt_flow/EPANET/EPANET/SRC_engines/hash.c +177 -177
- epyt_flow/EPANET/EPANET/SRC_engines/hash.h +28 -28
- epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +192 -40
- epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +101 -46
- epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +85 -24
- epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +29 -63
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +70 -37
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +408 -234
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +87 -37
- epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +153 -79
- epyt_flow/EPANET/EPANET/SRC_engines/input1.c +59 -94
- epyt_flow/EPANET/EPANET/SRC_engines/input2.c +73 -202
- epyt_flow/EPANET/EPANET/SRC_engines/input3.c +446 -351
- epyt_flow/EPANET/EPANET/SRC_engines/leakage.c +527 -0
- epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +8 -4
- epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +23 -23
- epyt_flow/EPANET/EPANET/SRC_engines/output.c +5 -4
- epyt_flow/EPANET/EPANET/SRC_engines/project.c +407 -75
- epyt_flow/EPANET/EPANET/SRC_engines/quality.c +12 -2
- epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +70 -13
- epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +7 -5
- epyt_flow/EPANET/EPANET/SRC_engines/report.c +88 -20
- epyt_flow/EPANET/EPANET/SRC_engines/rules.c +144 -6
- epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +19 -19
- epyt_flow/EPANET/EPANET/SRC_engines/text.h +16 -5
- epyt_flow/EPANET/EPANET/SRC_engines/types.h +73 -19
- epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.c +59 -0
- epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.h +38 -0
- epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.c +92 -0
- epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.h +39 -0
- epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.c +212 -0
- epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.h +81 -0
- epyt_flow/EPANET/EPANET/SRC_engines/validate.c +408 -0
- epyt_flow/EPANET/compile_linux.sh +1 -1
- epyt_flow/EPANET/compile_macos.sh +2 -2
- epyt_flow/VERSION +1 -1
- epyt_flow/__init__.py +1 -1
- epyt_flow/gym/scenario_control_env.py +26 -3
- epyt_flow/simulation/backend/my_epyt.py +58 -13
- epyt_flow/simulation/events/quality_events.py +6 -6
- epyt_flow/simulation/events/sensor_faults.py +24 -24
- epyt_flow/simulation/events/system_event.py +3 -3
- epyt_flow/simulation/scada/scada_data.py +10 -14
- epyt_flow/simulation/scenario_simulator.py +100 -20
- epyt_flow/topology.py +8 -1
- epyt_flow/uncertainty/model_uncertainty.py +292 -150
- epyt_flow/uncertainty/uncertainties.py +2 -2
- {epyt_flow-0.13.1.dist-info → epyt_flow-0.14.1.dist-info}/METADATA +4 -4
- {epyt_flow-0.13.1.dist-info → epyt_flow-0.14.1.dist-info}/RECORD +60 -54
- {epyt_flow-0.13.1.dist-info → epyt_flow-0.14.1.dist-info}/WHEEL +1 -1
- epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +0 -18
- epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +0 -131
- epyt_flow/EPANET/EPANET/SRC_engines/main.c +0 -93
- {epyt_flow-0.13.1.dist-info → epyt_flow-0.14.1.dist-info}/licenses/LICENSE +0 -0
- {epyt_flow-0.13.1.dist-info → epyt_flow-0.14.1.dist-info}/top_level.txt +0 -0
|
@@ -59,6 +59,20 @@ class ScenarioSimulator():
|
|
|
59
59
|
If True, EPyT is verbose and might print messages from time to time.
|
|
60
60
|
|
|
61
61
|
The default is False.
|
|
62
|
+
raise_exception_on_error : `bool`, optional
|
|
63
|
+
If True, an exception is raised whenever an error occurs in EPANET or EPANET-MSX.
|
|
64
|
+
|
|
65
|
+
The default is False.
|
|
66
|
+
warn_on_error : `bool`, optional
|
|
67
|
+
If True, a warning is generated whenever an error occurs in EPANET or EPANET-MSX.
|
|
68
|
+
|
|
69
|
+
The default is True.
|
|
70
|
+
ignore_error_codes : `list[int]`, optional
|
|
71
|
+
List of error codes that should be ignored -- i.e., no exception or
|
|
72
|
+
warning will be generated.
|
|
73
|
+
However, error codes will still be included in the SCADA data.
|
|
74
|
+
|
|
75
|
+
The default is [].
|
|
62
76
|
|
|
63
77
|
Attributes
|
|
64
78
|
----------
|
|
@@ -83,7 +97,9 @@ class ScenarioSimulator():
|
|
|
83
97
|
"""
|
|
84
98
|
|
|
85
99
|
def __init__(self, f_inp_in: str = None, f_msx_in: str = None,
|
|
86
|
-
scenario_config: ScenarioConfig = None, epanet_verbose: bool = False
|
|
100
|
+
scenario_config: ScenarioConfig = None, epanet_verbose: bool = False,
|
|
101
|
+
raise_exception_on_error: bool = False, warn_on_error: bool = True,
|
|
102
|
+
ignore_error_codes: list[int] = []):
|
|
87
103
|
if f_msx_in is not None and f_inp_in is None:
|
|
88
104
|
raise ValueError("'f_inp_in' must be set if 'f_msx_in' is set.")
|
|
89
105
|
if f_inp_in is None and scenario_config is None:
|
|
@@ -118,6 +134,7 @@ class ScenarioSimulator():
|
|
|
118
134
|
self._system_events = []
|
|
119
135
|
self._sensor_reading_events = []
|
|
120
136
|
self.__running_simulation = False
|
|
137
|
+
self.__uncertainties_applied = False
|
|
121
138
|
|
|
122
139
|
# Check availability of custom EPANET libraries
|
|
123
140
|
custom_epanet_lib = None
|
|
@@ -176,7 +193,9 @@ class ScenarioSimulator():
|
|
|
176
193
|
self.epanet_api.loadMSXFile(my_f_msx_in, customMSXlib=custom_epanetmsx_lib)
|
|
177
194
|
|
|
178
195
|
# Do not raise exceptions in the case of EPANET warnings and errors
|
|
179
|
-
self.epanet_api.set_error_handling(
|
|
196
|
+
self.epanet_api.set_error_handling(raise_exception_on_error=raise_exception_on_error,
|
|
197
|
+
warn_on_error=warn_on_error,
|
|
198
|
+
ignore_error_codes=ignore_error_codes)
|
|
180
199
|
|
|
181
200
|
# Parse and initialize scenario
|
|
182
201
|
self._simple_controls = self._parse_simple_control_rules()
|
|
@@ -1943,11 +1962,16 @@ class ScenarioSimulator():
|
|
|
1943
1962
|
"""
|
|
1944
1963
|
self._sensor_config.place_sensors_everywhere()
|
|
1945
1964
|
|
|
1946
|
-
def _prepare_simulation(self) -> None:
|
|
1965
|
+
def _prepare_simulation(self, reapply_uncertainties: bool = False) -> None:
|
|
1947
1966
|
self._adapt_to_network_changes()
|
|
1948
1967
|
|
|
1949
1968
|
if self._model_uncertainty is not None:
|
|
1950
|
-
self.
|
|
1969
|
+
if self.__uncertainties_applied is False:
|
|
1970
|
+
self._model_uncertainty.apply(self.epanet_api)
|
|
1971
|
+
self.__uncertainties_applied = True
|
|
1972
|
+
elif self.__uncertainties_applied is True and reapply_uncertainties is True:
|
|
1973
|
+
self._model_uncertainty.undo(self.epanet_api)
|
|
1974
|
+
self._model_uncertainty.apply(self.epanet_api)
|
|
1951
1975
|
|
|
1952
1976
|
for event in self._system_events:
|
|
1953
1977
|
event.reset()
|
|
@@ -1958,7 +1982,8 @@ class ScenarioSimulator():
|
|
|
1958
1982
|
|
|
1959
1983
|
def run_advanced_quality_simulation(self, hyd_file_in: str, verbose: bool = False,
|
|
1960
1984
|
frozen_sensor_config: bool = False,
|
|
1961
|
-
use_quality_time_step_as_reporting_time_step: bool = False
|
|
1985
|
+
use_quality_time_step_as_reporting_time_step: bool = False,
|
|
1986
|
+
reapply_uncertainties: bool = False
|
|
1962
1987
|
) -> ScadaData:
|
|
1963
1988
|
"""
|
|
1964
1989
|
Runs an advanced quality analysis using EPANET-MSX.
|
|
@@ -1983,6 +2008,10 @@ class ScenarioSimulator():
|
|
|
1983
2008
|
As a consequence, the simualtion results can not be merged
|
|
1984
2009
|
with the hydraulic simulation.
|
|
1985
2010
|
|
|
2011
|
+
The default is False.
|
|
2012
|
+
reapply_uncertainties: `bool`, optional
|
|
2013
|
+
If True, the uncertainties are re-applied on the original properties.
|
|
2014
|
+
|
|
1986
2015
|
The default is False.
|
|
1987
2016
|
|
|
1988
2017
|
Returns
|
|
@@ -2004,7 +2033,8 @@ class ScenarioSimulator():
|
|
|
2004
2033
|
return_as_dict=True,
|
|
2005
2034
|
frozen_sensor_config=frozen_sensor_config,
|
|
2006
2035
|
use_quality_time_step_as_reporting_time_step=
|
|
2007
|
-
use_quality_time_step_as_reporting_time_step
|
|
2036
|
+
use_quality_time_step_as_reporting_time_step,
|
|
2037
|
+
reapply_uncertainties=reapply_uncertainties):
|
|
2008
2038
|
if result is None:
|
|
2009
2039
|
result = {}
|
|
2010
2040
|
for data_type, data in scada_data.items():
|
|
@@ -2032,6 +2062,7 @@ class ScenarioSimulator():
|
|
|
2032
2062
|
return_as_dict: bool = False,
|
|
2033
2063
|
frozen_sensor_config: bool = False,
|
|
2034
2064
|
use_quality_time_step_as_reporting_time_step: bool = False,
|
|
2065
|
+
reapply_uncertainties: bool = False
|
|
2035
2066
|
) -> Generator[Union[tuple[ScadaData, bool], tuple[dict, bool]], bool, None]:
|
|
2036
2067
|
"""
|
|
2037
2068
|
Runs an advanced quality analysis using EPANET-MSX.
|
|
@@ -2060,6 +2091,10 @@ class ScenarioSimulator():
|
|
|
2060
2091
|
As a consequence, the simualtion results can not be merged
|
|
2061
2092
|
with the hydraulic simulation.
|
|
2062
2093
|
|
|
2094
|
+
The default is False.
|
|
2095
|
+
reapply_uncertainties : `bool`, optional
|
|
2096
|
+
If True, the uncertainties are re-applied on the original properties.
|
|
2097
|
+
|
|
2063
2098
|
The default is False.
|
|
2064
2099
|
|
|
2065
2100
|
Returns
|
|
@@ -2074,6 +2109,8 @@ class ScenarioSimulator():
|
|
|
2074
2109
|
if self.__f_msx_in is None:
|
|
2075
2110
|
raise ValueError("No .msx file specified")
|
|
2076
2111
|
|
|
2112
|
+
self._prepare_simulation(reapply_uncertainties)
|
|
2113
|
+
|
|
2077
2114
|
# Load pre-computed hydraulics
|
|
2078
2115
|
self.epanet_api.useMSXHydraulicFile(hyd_file_in)
|
|
2079
2116
|
|
|
@@ -2171,12 +2208,14 @@ class ScenarioSimulator():
|
|
|
2171
2208
|
pass
|
|
2172
2209
|
|
|
2173
2210
|
if reporting_time_start == 0:
|
|
2211
|
+
msx_error_code = self.epanet_api.msx.get_last_error_code()
|
|
2212
|
+
|
|
2174
2213
|
if return_as_dict is True:
|
|
2175
2214
|
data = {"bulk_species_node_concentration_raw": bulk_species_node_concentrations,
|
|
2176
2215
|
"bulk_species_link_concentration_raw": bulk_species_link_concentrations,
|
|
2177
2216
|
"surface_species_concentration_raw": surface_species_concentrations,
|
|
2178
2217
|
"sensor_readings_time": np.array([0]),
|
|
2179
|
-
"warnings_code": np.array([
|
|
2218
|
+
"warnings_code": np.array([msx_error_code])
|
|
2180
2219
|
}
|
|
2181
2220
|
else:
|
|
2182
2221
|
data = ScadaData(network_topo=network_topo, sensor_config=self._sensor_config,
|
|
@@ -2184,7 +2223,7 @@ class ScenarioSimulator():
|
|
|
2184
2223
|
bulk_species_link_concentration_raw=bulk_species_link_concentrations,
|
|
2185
2224
|
surface_species_concentration_raw=surface_species_concentrations,
|
|
2186
2225
|
sensor_readings_time=np.array([0]),
|
|
2187
|
-
warnings_code=np.array([
|
|
2226
|
+
warnings_code=np.array([msx_error_code]),
|
|
2188
2227
|
sensor_reading_events=self._sensor_reading_events,
|
|
2189
2228
|
sensor_noise=self._sensor_noise,
|
|
2190
2229
|
frozen_sensor_config=frozen_sensor_config)
|
|
@@ -2199,9 +2238,13 @@ class ScenarioSimulator():
|
|
|
2199
2238
|
# Run step-by-step simulation
|
|
2200
2239
|
tleft = 1
|
|
2201
2240
|
total_time = 0
|
|
2241
|
+
last_msx_error_code = 0
|
|
2202
2242
|
while tleft > 0:
|
|
2203
2243
|
# Compute current time step
|
|
2204
2244
|
total_time, tleft = self.epanet_api.stepMSXQualityAnalysisTimeLeft()
|
|
2245
|
+
msx_error_code = self.epanet_api.msx.get_last_error_code()
|
|
2246
|
+
if last_msx_error_code == 0:
|
|
2247
|
+
last_msx_error_code = msx_error_code
|
|
2205
2248
|
|
|
2206
2249
|
# Fetch data at regular time intervals
|
|
2207
2250
|
if total_time % hyd_time_step == 0:
|
|
@@ -2223,7 +2266,7 @@ class ScenarioSimulator():
|
|
|
2223
2266
|
bulk_species_link_concentrations,
|
|
2224
2267
|
"surface_species_concentration_raw": surface_species_concentrations,
|
|
2225
2268
|
"sensor_readings_time": np.array([total_time]),
|
|
2226
|
-
"warnings_code": np.array([
|
|
2269
|
+
"warnings_code": np.array([last_msx_error_code]),
|
|
2227
2270
|
}
|
|
2228
2271
|
else:
|
|
2229
2272
|
data = ScadaData(network_topo=network_topo,
|
|
@@ -2235,7 +2278,7 @@ class ScenarioSimulator():
|
|
|
2235
2278
|
surface_species_concentration_raw=
|
|
2236
2279
|
surface_species_concentrations,
|
|
2237
2280
|
sensor_readings_time=np.array([total_time]),
|
|
2238
|
-
warnings_code=np.array([
|
|
2281
|
+
warnings_code=np.array([last_msx_error_code]),
|
|
2239
2282
|
sensor_reading_events=self._sensor_reading_events,
|
|
2240
2283
|
sensor_noise=self._sensor_noise,
|
|
2241
2284
|
frozen_sensor_config=frozen_sensor_config)
|
|
@@ -2388,6 +2431,7 @@ class ScenarioSimulator():
|
|
|
2388
2431
|
total_time = 0
|
|
2389
2432
|
tstep = 1
|
|
2390
2433
|
first_itr = True
|
|
2434
|
+
last_error_code = 0
|
|
2391
2435
|
while tstep > 0:
|
|
2392
2436
|
if first_itr is True: # Fix current time in the first iteration
|
|
2393
2437
|
tstep = 0
|
|
@@ -2406,6 +2450,8 @@ class ScenarioSimulator():
|
|
|
2406
2450
|
|
|
2407
2451
|
# Fetch data
|
|
2408
2452
|
error_code = self.epanet_api.get_last_error_code()
|
|
2453
|
+
if last_error_code == 0:
|
|
2454
|
+
last_error_code = error_code
|
|
2409
2455
|
quality_node_data = self.epanet_api.getNodeActualQuality().reshape(1, -1)
|
|
2410
2456
|
quality_link_data = self.epanet_api.getLinkActualQuality().reshape(1, -1)
|
|
2411
2457
|
|
|
@@ -2415,14 +2461,14 @@ class ScenarioSimulator():
|
|
|
2415
2461
|
data = {"node_quality_data_raw": quality_node_data,
|
|
2416
2462
|
"link_quality_data_raw": quality_link_data,
|
|
2417
2463
|
"sensor_readings_time": np.array([total_time]),
|
|
2418
|
-
"warnings_code": np.array([
|
|
2464
|
+
"warnings_code": np.array([last_error_code])}
|
|
2419
2465
|
else:
|
|
2420
2466
|
data = ScadaData(network_topo=network_topo,
|
|
2421
2467
|
sensor_config=self._sensor_config,
|
|
2422
2468
|
node_quality_data_raw=quality_node_data,
|
|
2423
2469
|
link_quality_data_raw=quality_link_data,
|
|
2424
2470
|
sensor_readings_time=np.array([total_time]),
|
|
2425
|
-
warnings_code=np.array([
|
|
2471
|
+
warnings_code=np.array([last_error_code]),
|
|
2426
2472
|
sensor_reading_events=self._sensor_reading_events,
|
|
2427
2473
|
sensor_noise=self._sensor_noise,
|
|
2428
2474
|
frozen_sensor_config=frozen_sensor_config)
|
|
@@ -2436,11 +2482,15 @@ class ScenarioSimulator():
|
|
|
2436
2482
|
|
|
2437
2483
|
# Next
|
|
2438
2484
|
tstep = self.epanet_api.api.ENstepQ()
|
|
2485
|
+
error_code = self.epanet_api.get_last_error_code()
|
|
2486
|
+
if last_error_code == 0:
|
|
2487
|
+
last_error_code = error_code
|
|
2439
2488
|
|
|
2440
2489
|
self.epanet_api.closeQualityAnalysis()
|
|
2441
2490
|
|
|
2442
2491
|
def run_hydraulic_simulation(self, hyd_export: str = None, verbose: bool = False,
|
|
2443
|
-
frozen_sensor_config: bool = False
|
|
2492
|
+
frozen_sensor_config: bool = False,
|
|
2493
|
+
reapply_uncertainties: bool = False) -> ScadaData:
|
|
2444
2494
|
"""
|
|
2445
2495
|
Runs the hydraulic simulation of this scenario (incl. basic quality if set).
|
|
2446
2496
|
|
|
@@ -2463,6 +2513,10 @@ class ScenarioSimulator():
|
|
|
2463
2513
|
If True, the sensor config can not be changed and only the required sensor nodes/links
|
|
2464
2514
|
will be stored -- this usually leads to a significant reduction in memory consumption.
|
|
2465
2515
|
|
|
2516
|
+
The default is False.
|
|
2517
|
+
reapply_uncertainties : `bool`, optional
|
|
2518
|
+
If True, the uncertainties are re-applied on the original properties.
|
|
2519
|
+
|
|
2466
2520
|
The default is False.
|
|
2467
2521
|
|
|
2468
2522
|
Returns
|
|
@@ -2482,7 +2536,8 @@ class ScenarioSimulator():
|
|
|
2482
2536
|
for scada_data, _ in gen(hyd_export=hyd_export,
|
|
2483
2537
|
verbose=verbose,
|
|
2484
2538
|
return_as_dict=True,
|
|
2485
|
-
frozen_sensor_config=frozen_sensor_config
|
|
2539
|
+
frozen_sensor_config=frozen_sensor_config,
|
|
2540
|
+
reapply_uncertainties=reapply_uncertainties):
|
|
2486
2541
|
if result is None:
|
|
2487
2542
|
result = {}
|
|
2488
2543
|
for data_type, data in scada_data.items():
|
|
@@ -2507,6 +2562,7 @@ class ScenarioSimulator():
|
|
|
2507
2562
|
support_abort: bool = False,
|
|
2508
2563
|
return_as_dict: bool = False,
|
|
2509
2564
|
frozen_sensor_config: bool = False,
|
|
2565
|
+
reapply_uncertainties: bool = False
|
|
2510
2566
|
) -> Generator[Union[tuple[ScadaData, bool], tuple[dict, bool]], bool, None]:
|
|
2511
2567
|
"""
|
|
2512
2568
|
Runs the hydraulic simulation of this scenario (incl. basic quality if set) and
|
|
@@ -2542,6 +2598,10 @@ class ScenarioSimulator():
|
|
|
2542
2598
|
If True, the sensor config can not be changed and only the required sensor nodes/links
|
|
2543
2599
|
will be stored -- this usually leads to a significant reduction in memory consumption.
|
|
2544
2600
|
|
|
2601
|
+
The default is False.
|
|
2602
|
+
reapply_uncertainties : `bool`, optional
|
|
2603
|
+
If True, the uncertainties are re-applied on the original properties.
|
|
2604
|
+
|
|
2545
2605
|
The default is False.
|
|
2546
2606
|
|
|
2547
2607
|
Returns
|
|
@@ -2555,7 +2615,7 @@ class ScenarioSimulator():
|
|
|
2555
2615
|
|
|
2556
2616
|
self._adapt_to_network_changes()
|
|
2557
2617
|
|
|
2558
|
-
self._prepare_simulation()
|
|
2618
|
+
self._prepare_simulation(reapply_uncertainties)
|
|
2559
2619
|
|
|
2560
2620
|
self.__running_simulation = True
|
|
2561
2621
|
|
|
@@ -2582,6 +2642,7 @@ class ScenarioSimulator():
|
|
|
2582
2642
|
total_time = 0
|
|
2583
2643
|
tstep = 1
|
|
2584
2644
|
first_itr = True
|
|
2645
|
+
last_error_code = 0
|
|
2585
2646
|
while tstep > 0:
|
|
2586
2647
|
if first_itr is True: # Fix current time in the first iteration
|
|
2587
2648
|
tstep = 0
|
|
@@ -2606,6 +2667,8 @@ class ScenarioSimulator():
|
|
|
2606
2667
|
if error_code == 0:
|
|
2607
2668
|
error_code = self.epanet_api.get_last_error_code()
|
|
2608
2669
|
total_time = t
|
|
2670
|
+
if last_error_code == 0:
|
|
2671
|
+
last_error_code = error_code
|
|
2609
2672
|
|
|
2610
2673
|
# Fetch data
|
|
2611
2674
|
pressure_data = self.epanet_api.getNodePressure().reshape(1, -1)
|
|
@@ -2636,7 +2699,7 @@ class ScenarioSimulator():
|
|
|
2636
2699
|
pumps_energy_usage_data_raw=pumps_energy_usage_data,
|
|
2637
2700
|
pumps_efficiency_data_raw=pumps_efficiency_data,
|
|
2638
2701
|
sensor_readings_time=np.array([total_time]),
|
|
2639
|
-
warnings_code=np.array([
|
|
2702
|
+
warnings_code=np.array([last_error_code]),
|
|
2640
2703
|
sensor_reading_events=self._sensor_reading_events,
|
|
2641
2704
|
sensor_noise=self._sensor_noise,
|
|
2642
2705
|
frozen_sensor_config=frozen_sensor_config)
|
|
@@ -2655,10 +2718,12 @@ class ScenarioSimulator():
|
|
|
2655
2718
|
"pumps_energy_usage_data_raw": pumps_energy_usage_data,
|
|
2656
2719
|
"pumps_efficiency_data_raw": pumps_efficiency_data,
|
|
2657
2720
|
"sensor_readings_time": np.array([total_time]),
|
|
2658
|
-
"warnings_code": np.array([
|
|
2721
|
+
"warnings_code": np.array([last_error_code])}
|
|
2659
2722
|
else:
|
|
2660
2723
|
data = scada_data
|
|
2661
2724
|
|
|
2725
|
+
last_error_code = 0
|
|
2726
|
+
|
|
2662
2727
|
if support_abort is True: # Can the simulation be aborted? If so, handle it.
|
|
2663
2728
|
abort = yield
|
|
2664
2729
|
if abort is True:
|
|
@@ -2672,7 +2737,14 @@ class ScenarioSimulator():
|
|
|
2672
2737
|
|
|
2673
2738
|
# Next
|
|
2674
2739
|
tstep = self.epanet_api.api.ENnextH()
|
|
2740
|
+
error_code = self.epanet_api.get_last_error_code()
|
|
2741
|
+
if last_error_code == 0:
|
|
2742
|
+
last_error_code = error_code
|
|
2743
|
+
|
|
2675
2744
|
self.epanet_api.api.ENnextQ()
|
|
2745
|
+
error_code = self.epanet_api.get_last_error_code()
|
|
2746
|
+
if last_error_code == 0:
|
|
2747
|
+
last_error_code = error_code
|
|
2676
2748
|
|
|
2677
2749
|
self.epanet_api.api.ENcloseQ()
|
|
2678
2750
|
self.epanet_api.api.ENcloseH()
|
|
@@ -2686,7 +2758,8 @@ class ScenarioSimulator():
|
|
|
2686
2758
|
raise ex
|
|
2687
2759
|
|
|
2688
2760
|
def run_simulation(self, hyd_export: str = None, verbose: bool = False,
|
|
2689
|
-
frozen_sensor_config: bool = False
|
|
2761
|
+
frozen_sensor_config: bool = False,
|
|
2762
|
+
reapply_uncertainties: bool = False) -> ScadaData:
|
|
2690
2763
|
"""
|
|
2691
2764
|
Runs the simulation of this scenario.
|
|
2692
2765
|
|
|
@@ -2707,6 +2780,10 @@ class ScenarioSimulator():
|
|
|
2707
2780
|
If True, the sensor config can not be changed and only the required sensor nodes/links
|
|
2708
2781
|
will be stored -- this usually leads to a significant reduction in memory consumption.
|
|
2709
2782
|
|
|
2783
|
+
The default is False.
|
|
2784
|
+
reapply_uncertainties: `bool`, optional
|
|
2785
|
+
If True, the uncertainties are re-applied on the original properties.
|
|
2786
|
+
|
|
2710
2787
|
The default is False.
|
|
2711
2788
|
|
|
2712
2789
|
Returns
|
|
@@ -2727,14 +2804,16 @@ class ScenarioSimulator():
|
|
|
2727
2804
|
|
|
2728
2805
|
# Run hydraulic simulation step-by-step
|
|
2729
2806
|
result = self.run_hydraulic_simulation(hyd_export=hyd_export, verbose=verbose,
|
|
2730
|
-
frozen_sensor_config=frozen_sensor_config
|
|
2807
|
+
frozen_sensor_config=frozen_sensor_config,
|
|
2808
|
+
reapply_uncertainties=reapply_uncertainties)
|
|
2731
2809
|
|
|
2732
2810
|
# If necessary, run advanced quality simulation utilizing the computed hydraulics
|
|
2733
2811
|
if self.f_msx_in is not None:
|
|
2734
2812
|
gen = self.run_advanced_quality_simulation
|
|
2735
2813
|
result_msx = gen(hyd_file_in=hyd_export,
|
|
2736
2814
|
verbose=verbose,
|
|
2737
|
-
frozen_sensor_config=frozen_sensor_config
|
|
2815
|
+
frozen_sensor_config=frozen_sensor_config,
|
|
2816
|
+
reapply_uncertainties=reapply_uncertainties)
|
|
2738
2817
|
result.join(result_msx)
|
|
2739
2818
|
|
|
2740
2819
|
if hyd_export_old is not None:
|
|
@@ -2768,6 +2847,7 @@ class ScenarioSimulator():
|
|
|
2768
2847
|
f"'{type(model_uncertainty)}'")
|
|
2769
2848
|
|
|
2770
2849
|
self._model_uncertainty = model_uncertainty
|
|
2850
|
+
self.__uncertainties_applied = False
|
|
2771
2851
|
|
|
2772
2852
|
def set_sensor_noise(self, sensor_noise: SensorNoise) -> None:
|
|
2773
2853
|
"""
|
epyt_flow/topology.py
CHANGED
|
@@ -500,8 +500,15 @@ class NetworkTopology(nx.Graph, JsonSerializable):
|
|
|
500
500
|
raise TypeError("Can not compare 'NetworkTopology' instance to " +
|
|
501
501
|
f"'{type(other)}' instance")
|
|
502
502
|
|
|
503
|
+
adj_matrix = self.get_adj_matrix()
|
|
504
|
+
other_adj_matrix = other.get_adj_matrix()
|
|
505
|
+
|
|
503
506
|
return super().__eq__(other) and \
|
|
504
|
-
self.
|
|
507
|
+
self.name == other.name \
|
|
508
|
+
and not np.any(adj_matrix.data != other_adj_matrix.data) \
|
|
509
|
+
and not np.any(adj_matrix.indices != other_adj_matrix.indices) \
|
|
510
|
+
and not np.any(adj_matrix.indptr != other_adj_matrix.indptr) \
|
|
511
|
+
and self.get_all_nodes() == other.get_all_nodes() \
|
|
505
512
|
and all(link_a[0] == link_b[0] and link_a[1] == link_b[1]
|
|
506
513
|
for link_a, link_b in zip(self.get_all_links(), other.get_all_links())) \
|
|
507
514
|
and self.__units == other.units \
|