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
|
@@ -64,7 +64,7 @@ class SpeciesInjectionEvent(SystemEvent, JsonSerializable):
|
|
|
64
64
|
|
|
65
65
|
self.__species_id = species_id
|
|
66
66
|
self.__node_id = node_id
|
|
67
|
-
self.
|
|
67
|
+
self._profile = profile
|
|
68
68
|
self.__source_type = source_type
|
|
69
69
|
|
|
70
70
|
super().__init__(**kwds)
|
|
@@ -103,7 +103,7 @@ class SpeciesInjectionEvent(SystemEvent, JsonSerializable):
|
|
|
103
103
|
`numpy.ndarray`
|
|
104
104
|
Pattern of the injection.
|
|
105
105
|
"""
|
|
106
|
-
return deepcopy(self.
|
|
106
|
+
return deepcopy(self._profile)
|
|
107
107
|
|
|
108
108
|
@property
|
|
109
109
|
def source_type(self) -> int:
|
|
@@ -125,17 +125,17 @@ class SpeciesInjectionEvent(SystemEvent, JsonSerializable):
|
|
|
125
125
|
|
|
126
126
|
def get_attributes(self) -> dict:
|
|
127
127
|
return super().get_attributes() | {"species_id": self.__species_id,
|
|
128
|
-
"node_id": self.__node_id, "profile": self.
|
|
128
|
+
"node_id": self.__node_id, "profile": self._profile,
|
|
129
129
|
"source_type": self.__source_type}
|
|
130
130
|
|
|
131
131
|
def __eq__(self, other) -> bool:
|
|
132
132
|
return super().__eq__(other) and self.__species_id == other.species_id and \
|
|
133
|
-
self.__node_id == other.node_id and np.all(self.
|
|
133
|
+
self.__node_id == other.node_id and np.all(self._profile == other.profile) and \
|
|
134
134
|
self.__source_type == other.source_type
|
|
135
135
|
|
|
136
136
|
def __str__(self) -> str:
|
|
137
137
|
return f"{super().__str__()} species_id: {self.__species_id} " +\
|
|
138
|
-
f"node_id: {self.__node_id} profile: {self.
|
|
138
|
+
f"node_id: {self.__node_id} profile: {self._profile} source_type: {self.__source_type}"
|
|
139
139
|
|
|
140
140
|
def _get_pattern_id(self) -> str:
|
|
141
141
|
return f"{self.__species_id}_{self.__node_id}"
|
|
@@ -160,7 +160,7 @@ class SpeciesInjectionEvent(SystemEvent, JsonSerializable):
|
|
|
160
160
|
injection_time_start_idx = int(self.start_time / time_step)
|
|
161
161
|
|
|
162
162
|
injection_pattern = None
|
|
163
|
-
if len(self.
|
|
163
|
+
if len(self._profile) == injection_pattern_length:
|
|
164
164
|
injection_pattern = self.profile
|
|
165
165
|
else:
|
|
166
166
|
injection_pattern = np.tile(self.profile,
|
|
@@ -93,7 +93,7 @@ class SensorFaultConstant(SensorFault, JsonSerializable):
|
|
|
93
93
|
raise TypeError("'constant_shift' must be an instance of 'float' but no of " +
|
|
94
94
|
f"'{type(constant_shift)}'")
|
|
95
95
|
|
|
96
|
-
self.
|
|
96
|
+
self._constant_shift = constant_shift
|
|
97
97
|
|
|
98
98
|
super().__init__(**kwds)
|
|
99
99
|
|
|
@@ -107,20 +107,20 @@ class SensorFaultConstant(SensorFault, JsonSerializable):
|
|
|
107
107
|
`float`
|
|
108
108
|
Constant that is added to the sensor reading.
|
|
109
109
|
"""
|
|
110
|
-
return self.
|
|
110
|
+
return self._constant_shift
|
|
111
111
|
|
|
112
112
|
def get_attributes(self) -> dict:
|
|
113
|
-
return super().get_attributes() | {"constant_shift": self.
|
|
113
|
+
return super().get_attributes() | {"constant_shift": self._constant_shift}
|
|
114
114
|
|
|
115
115
|
def __eq__(self, other) -> bool:
|
|
116
|
-
return super().__eq__(other) and self.
|
|
116
|
+
return super().__eq__(other) and self._constant_shift == other.constant_shift
|
|
117
117
|
|
|
118
118
|
def __str__(self) -> str:
|
|
119
|
-
return f"{type(self).__name__} {super().__str__()} constant: {self.
|
|
119
|
+
return f"{type(self).__name__} {super().__str__()} constant: {self._constant_shift}"
|
|
120
120
|
|
|
121
121
|
def apply_sensor_fault(self, cur_multiplier: float, sensor_reading: float,
|
|
122
122
|
cur_time: int) -> float:
|
|
123
|
-
return sensor_reading + cur_multiplier * self.
|
|
123
|
+
return sensor_reading + cur_multiplier * self._constant_shift
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
@serializable(SENSOR_FAULT_DRIFT_ID, ".epytflow_sensorfault_drift")
|
|
@@ -134,7 +134,7 @@ class SensorFaultDrift(SensorFault, JsonSerializable):
|
|
|
134
134
|
Coefficient of the drift.
|
|
135
135
|
"""
|
|
136
136
|
def __init__(self, coef: float, **kwds):
|
|
137
|
-
self.
|
|
137
|
+
self._coef = coef
|
|
138
138
|
|
|
139
139
|
super().__init__(**kwds)
|
|
140
140
|
|
|
@@ -148,20 +148,20 @@ class SensorFaultDrift(SensorFault, JsonSerializable):
|
|
|
148
148
|
`float`
|
|
149
149
|
Coefficient of the drift.
|
|
150
150
|
"""
|
|
151
|
-
return self.
|
|
151
|
+
return self._coef
|
|
152
152
|
|
|
153
153
|
def get_attributes(self) -> dict:
|
|
154
|
-
return super().get_attributes() | {"coef": self.
|
|
154
|
+
return super().get_attributes() | {"coef": self._coef}
|
|
155
155
|
|
|
156
156
|
def __eq__(self, other) -> bool:
|
|
157
|
-
return super().__eq__(other) and self.
|
|
157
|
+
return super().__eq__(other) and self._coef == other.coef
|
|
158
158
|
|
|
159
159
|
def __str__(self) -> str:
|
|
160
|
-
return f"{type(self).__name__} {super().__str__()} coef: {self.
|
|
160
|
+
return f"{type(self).__name__} {super().__str__()} coef: {self._coef}"
|
|
161
161
|
|
|
162
162
|
def apply_sensor_fault(self, cur_multiplier: float, sensor_reading: float,
|
|
163
163
|
cur_time: int) -> float:
|
|
164
|
-
return sensor_reading + cur_multiplier * (self.
|
|
164
|
+
return sensor_reading + cur_multiplier * (self._coef * (cur_time - self.start_time))
|
|
165
165
|
|
|
166
166
|
|
|
167
167
|
@serializable(SENSOR_FAULT_GAUSSIAN_ID, ".epytflow_sensorfault_gaussian")
|
|
@@ -179,7 +179,7 @@ class SensorFaultGaussian(SensorFault, JsonSerializable):
|
|
|
179
179
|
if not isinstance(std, float) or not std > 0:
|
|
180
180
|
raise ValueError("'std' must be an instance of 'float' and be greater than 0")
|
|
181
181
|
|
|
182
|
-
self.
|
|
182
|
+
self._std = std
|
|
183
183
|
|
|
184
184
|
super().__init__(**kwds)
|
|
185
185
|
|
|
@@ -193,20 +193,20 @@ class SensorFaultGaussian(SensorFault, JsonSerializable):
|
|
|
193
193
|
`float`
|
|
194
194
|
Standard deviation of the Gaussian noise.
|
|
195
195
|
"""
|
|
196
|
-
return self.
|
|
196
|
+
return self._std
|
|
197
197
|
|
|
198
198
|
def get_attributes(self) -> dict:
|
|
199
|
-
return super().get_attributes() | {"std": self.
|
|
199
|
+
return super().get_attributes() | {"std": self._std}
|
|
200
200
|
|
|
201
201
|
def __eq__(self, other) -> bool:
|
|
202
|
-
return super().__eq__(other) and self.
|
|
202
|
+
return super().__eq__(other) and self._std == other.std
|
|
203
203
|
|
|
204
204
|
def __str__(self) -> str:
|
|
205
|
-
return f"{type(self).__name__} {super().__str__()} std: {self.
|
|
205
|
+
return f"{type(self).__name__} {super().__str__()} std: {self._std}"
|
|
206
206
|
|
|
207
207
|
def apply_sensor_fault(self, cur_multiplier: float, sensor_reading: float,
|
|
208
208
|
cur_time: int) -> float:
|
|
209
|
-
return sensor_reading + cur_multiplier * np.random.normal(loc=0, scale=self.
|
|
209
|
+
return sensor_reading + cur_multiplier * np.random.normal(loc=0, scale=self._std)
|
|
210
210
|
|
|
211
211
|
|
|
212
212
|
@serializable(SENSOR_FAULT_PERCENTAGE_ID, ".epytflow_sensorfault_percentage",)
|
|
@@ -223,7 +223,7 @@ class SensorFaultPercentage(SensorFault, JsonSerializable):
|
|
|
223
223
|
if not isinstance(coef, float) or not coef > 0:
|
|
224
224
|
raise ValueError("'coef' must be an instance of 'float' and be greater than zero.")
|
|
225
225
|
|
|
226
|
-
self.
|
|
226
|
+
self._coef = coef
|
|
227
227
|
|
|
228
228
|
super().__init__(**kwds)
|
|
229
229
|
|
|
@@ -237,20 +237,20 @@ class SensorFaultPercentage(SensorFault, JsonSerializable):
|
|
|
237
237
|
`float`
|
|
238
238
|
Coefficient (percentage) of the shift.
|
|
239
239
|
"""
|
|
240
|
-
return self.
|
|
240
|
+
return self._coef
|
|
241
241
|
|
|
242
242
|
def get_attributes(self) -> dict:
|
|
243
|
-
return super().get_attributes() | {"coef": self.
|
|
243
|
+
return super().get_attributes() | {"coef": self._coef}
|
|
244
244
|
|
|
245
245
|
def __eq__(self, other) -> bool:
|
|
246
|
-
return super().__eq__(other) and self.
|
|
246
|
+
return super().__eq__(other) and self._coef == other.coef
|
|
247
247
|
|
|
248
248
|
def __str__(self) -> str:
|
|
249
|
-
return f"{type(self).__name__} {super().__str__()} coef: {self.
|
|
249
|
+
return f"{type(self).__name__} {super().__str__()} coef: {self._coef}"
|
|
250
250
|
|
|
251
251
|
def apply_sensor_fault(self, cur_multiplier: float, sensor_reading: float,
|
|
252
252
|
cur_time: int) -> float:
|
|
253
|
-
return sensor_reading + cur_multiplier * self.
|
|
253
|
+
return sensor_reading + cur_multiplier * self._coef * sensor_reading
|
|
254
254
|
|
|
255
255
|
|
|
256
256
|
@serializable(SENSOR_FAULT_STUCKATZERO_ID, ".epytflow_sensorfault_zero")
|
|
@@ -13,7 +13,7 @@ class SystemEvent(Event):
|
|
|
13
13
|
"""
|
|
14
14
|
def __init__(self, **kwds):
|
|
15
15
|
self._epanet_api = None
|
|
16
|
-
self.
|
|
16
|
+
self._exit_called = False
|
|
17
17
|
|
|
18
18
|
super().__init__(**kwds)
|
|
19
19
|
|
|
@@ -52,9 +52,9 @@ class SystemEvent(Event):
|
|
|
52
52
|
if self.start_time <= cur_time < self.end_time:
|
|
53
53
|
self.apply(cur_time)
|
|
54
54
|
elif cur_time > self.end_time:
|
|
55
|
-
if self.
|
|
55
|
+
if self._exit_called is False:
|
|
56
56
|
self.exit(cur_time)
|
|
57
|
-
self.
|
|
57
|
+
self._exit_called = True
|
|
58
58
|
|
|
59
59
|
def reset(self) -> None:
|
|
60
60
|
"""
|
|
@@ -167,9 +167,7 @@ class ScadaData(Serializable):
|
|
|
167
167
|
raise TypeError("'sensor_readings_time' must be an instance of 'numpy.ndarray' " +
|
|
168
168
|
f"but not of '{type(sensor_readings_time)}'")
|
|
169
169
|
if warnings_code is None:
|
|
170
|
-
|
|
171
|
-
" -- support of such old files will be removed in the next release!",
|
|
172
|
-
DeprecationWarning)
|
|
170
|
+
warnings_code = [0] * len(sensor_readings_time)
|
|
173
171
|
else:
|
|
174
172
|
if not isinstance(warnings_code, np.ndarray):
|
|
175
173
|
raise TypeError("'warnings_code' must be an instance of 'numpy.ndarray' " +
|
|
@@ -376,6 +374,8 @@ class ScadaData(Serializable):
|
|
|
376
374
|
self.__sensor_readings = None
|
|
377
375
|
self.__frozen_sensor_config = frozen_sensor_config
|
|
378
376
|
self.__sensor_readings_time = sensor_readings_time
|
|
377
|
+
self.__sensor_readings_time_to_idx = {time: idx for idx, time in
|
|
378
|
+
enumerate(self.__sensor_readings_time)}
|
|
379
379
|
|
|
380
380
|
if self.__frozen_sensor_config is False:
|
|
381
381
|
self.__pressure_data_raw = pressure_data_raw
|
|
@@ -1713,7 +1713,7 @@ class ScadaData(Serializable):
|
|
|
1713
1713
|
self.__sensor_reading_events = sensor_reading_events
|
|
1714
1714
|
self.__init()
|
|
1715
1715
|
|
|
1716
|
-
def extract_time_window(self, start_time: int, end_time: int):
|
|
1716
|
+
def extract_time_window(self, start_time: int, end_time: int = None):
|
|
1717
1717
|
"""
|
|
1718
1718
|
Extracts a time window of SCADA data from this SCADA data instance --
|
|
1719
1719
|
i.e. creating a new SCADA data instance containing data from the requested
|
|
@@ -1748,8 +1748,8 @@ class ScadaData(Serializable):
|
|
|
1748
1748
|
else:
|
|
1749
1749
|
end_time = self.__sensor_readings_time[-1]
|
|
1750
1750
|
|
|
1751
|
-
start_idx = self.
|
|
1752
|
-
end_idx = self.
|
|
1751
|
+
start_idx = self.__sensor_readings_time_to_idx[start_time]
|
|
1752
|
+
end_idx = self.__sensor_readings_time_to_idx[end_time] + 1
|
|
1753
1753
|
|
|
1754
1754
|
pressure_data_raw = None
|
|
1755
1755
|
if self.__pressure_data_raw is not None:
|
|
@@ -2375,11 +2375,10 @@ class ScadaData(Serializable):
|
|
|
2375
2375
|
mask = np.zeros(len(self.__sensor_config.nodes))
|
|
2376
2376
|
node_features = np.array([[default_missing_value] * len(self.__sensor_config.nodes)
|
|
2377
2377
|
for _ in range(len(self.__sensor_readings_time))])
|
|
2378
|
-
nodes_id = self.__network_topo.get_all_nodes()
|
|
2379
2378
|
|
|
2380
2379
|
pressure_readings = self.get_data_pressures()
|
|
2381
2380
|
for pressures_idx, node_id in enumerate(self.__sensor_config.pressure_sensors):
|
|
2382
|
-
idx =
|
|
2381
|
+
idx = self.__sensor_config.map_node_id_to_idx(node_id)
|
|
2383
2382
|
node_features[:, idx] = pressure_readings[:, pressures_idx]
|
|
2384
2383
|
mask[idx] = 1
|
|
2385
2384
|
|
|
@@ -2617,11 +2616,10 @@ class ScadaData(Serializable):
|
|
|
2617
2616
|
mask = np.zeros(len(self.__sensor_config.nodes))
|
|
2618
2617
|
node_features = np.array([[default_missing_value] * len(self.__sensor_config.nodes)
|
|
2619
2618
|
for _ in range(len(self.__sensor_readings_time))])
|
|
2620
|
-
nodes_id = self.__network_topo.get_all_nodes()
|
|
2621
2619
|
|
|
2622
2620
|
demand_readings = self.get_data_demands()
|
|
2623
2621
|
for demands_idx, node_id in enumerate(self.__sensor_config.demand_sensors):
|
|
2624
|
-
idx =
|
|
2622
|
+
idx = self.__sensor_config.map_node_id_to_idx(node_id)
|
|
2625
2623
|
node_features[:, idx] = demand_readings[:, demands_idx]
|
|
2626
2624
|
mask[idx] = 1
|
|
2627
2625
|
|
|
@@ -2737,11 +2735,10 @@ class ScadaData(Serializable):
|
|
|
2737
2735
|
mask = np.zeros(len(self.__sensor_config.nodes))
|
|
2738
2736
|
node_features = np.array([[default_missing_value] * len(self.__sensor_config.nodes)
|
|
2739
2737
|
for _ in range(len(self.__sensor_readings_time))])
|
|
2740
|
-
nodes_id = self.__network_topo.get_all_nodes()
|
|
2741
2738
|
|
|
2742
2739
|
node_quality_readings = self.get_data_nodes_quality()
|
|
2743
2740
|
for quality_idx, node_id in enumerate(self.__sensor_config.quality_node_sensors):
|
|
2744
|
-
idx =
|
|
2741
|
+
idx = self.__sensor_config.map_node_id_to_idx(node_id)
|
|
2745
2742
|
node_features[:, idx] = node_quality_readings[:, quality_idx]
|
|
2746
2743
|
mask[idx] = 1
|
|
2747
2744
|
|
|
@@ -3752,7 +3749,6 @@ class ScadaData(Serializable):
|
|
|
3752
3749
|
masks = []
|
|
3753
3750
|
results = []
|
|
3754
3751
|
|
|
3755
|
-
all_nodes_id = self.__network_topo.get_all_nodes()
|
|
3756
3752
|
bulk_species_sensor_locations = self.__sensor_config.bulk_species_node_sensors
|
|
3757
3753
|
|
|
3758
3754
|
for species_id, nodes_id in bulk_species_sensor_locations.items():
|
|
@@ -3762,7 +3758,7 @@ class ScadaData(Serializable):
|
|
|
3762
3758
|
|
|
3763
3759
|
sensor_readings = self.get_data_bulk_species_node_concentration({species_id: nodes_id})
|
|
3764
3760
|
for sensor_readings_idx, node_id in enumerate(nodes_id):
|
|
3765
|
-
idx =
|
|
3761
|
+
idx = self.__sensor_config.map_node_id_to_idx(node_id)
|
|
3766
3762
|
node_features[:, idx] = sensor_readings[:, sensor_readings_idx]
|
|
3767
3763
|
mask[idx] = 1
|
|
3768
3764
|
|