epyt-flow 0.7.3__py3-none-any.whl → 0.8.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.
- epyt_flow/VERSION +1 -1
- epyt_flow/gym/scenario_control_env.py +129 -10
- epyt_flow/serialization.py +10 -3
- epyt_flow/simulation/events/__init__.py +1 -0
- epyt_flow/simulation/events/leakages.py +55 -12
- epyt_flow/simulation/events/quality_events.py +194 -0
- epyt_flow/simulation/events/system_event.py +5 -0
- epyt_flow/simulation/scada/scada_data.py +512 -64
- epyt_flow/simulation/scada/scada_data_export.py +7 -5
- epyt_flow/simulation/scenario_config.py +13 -2
- epyt_flow/simulation/scenario_simulator.py +275 -187
- epyt_flow/simulation/scenario_visualizer.py +1259 -13
- {epyt_flow-0.7.3.dist-info → epyt_flow-0.8.0.dist-info}/METADATA +31 -30
- {epyt_flow-0.7.3.dist-info → epyt_flow-0.8.0.dist-info}/RECORD +17 -16
- {epyt_flow-0.7.3.dist-info → epyt_flow-0.8.0.dist-info}/WHEEL +1 -1
- {epyt_flow-0.7.3.dist-info → epyt_flow-0.8.0.dist-info}/LICENSE +0 -0
- {epyt_flow-0.7.3.dist-info → epyt_flow-0.8.0.dist-info}/top_level.txt +0 -0
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
Module provides a class for storing and processing SCADA data.
|
|
3
3
|
"""
|
|
4
4
|
import warnings
|
|
5
|
-
from typing import Callable, Any
|
|
5
|
+
from typing import Callable, Any, Union
|
|
6
6
|
from copy import deepcopy
|
|
7
7
|
import numpy as np
|
|
8
|
+
from scipy.sparse import bsr_array
|
|
8
9
|
import matplotlib
|
|
10
|
+
import pandas as pd
|
|
9
11
|
from epyt.epanet import ToolkitConstants
|
|
10
12
|
|
|
11
13
|
from ..sensor_config import SensorConfig, is_flowunit_simetric, massunit_to_str, flowunit_to_str,\
|
|
@@ -127,13 +129,19 @@ class ScadaData(Serializable):
|
|
|
127
129
|
The default is False.
|
|
128
130
|
"""
|
|
129
131
|
def __init__(self, sensor_config: SensorConfig, sensor_readings_time: np.ndarray,
|
|
130
|
-
pressure_data_raw: np.ndarray
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
pressure_data_raw: Union[np.ndarray, bsr_array] = None,
|
|
133
|
+
flow_data_raw: Union[np.ndarray, bsr_array] = None,
|
|
134
|
+
demand_data_raw: Union[np.ndarray, bsr_array] = None,
|
|
135
|
+
node_quality_data_raw: Union[np.ndarray, bsr_array] = None,
|
|
136
|
+
link_quality_data_raw: Union[np.ndarray, bsr_array] = None,
|
|
137
|
+
pumps_state_data_raw: Union[np.ndarray, bsr_array] = None,
|
|
138
|
+
valves_state_data_raw: Union[np.ndarray, bsr_array] = None,
|
|
139
|
+
tanks_volume_data_raw: Union[np.ndarray, bsr_array] = None,
|
|
140
|
+
surface_species_concentration_raw: Union[np.ndarray, dict[int, bsr_array]] = None,
|
|
141
|
+
bulk_species_node_concentration_raw: Union[np.ndarray,
|
|
142
|
+
dict[int, bsr_array]] = None,
|
|
143
|
+
bulk_species_link_concentration_raw: Union[np.ndarray,
|
|
144
|
+
dict[int, bsr_array]] = None,
|
|
137
145
|
pump_energy_usage_data = None,
|
|
138
146
|
pump_efficiency_data = None,
|
|
139
147
|
pumps_energy_usage_data_raw: np.ndarray = None,
|
|
@@ -151,64 +159,116 @@ class ScadaData(Serializable):
|
|
|
151
159
|
raise TypeError("'sensor_readings_time' must be an instance of 'numpy.ndarray' " +
|
|
152
160
|
f"but not of '{type(sensor_readings_time)}'")
|
|
153
161
|
if pressure_data_raw is not None:
|
|
154
|
-
if not isinstance(pressure_data_raw, np.ndarray)
|
|
162
|
+
if not isinstance(pressure_data_raw, np.ndarray) and \
|
|
163
|
+
not isinstance(pressure_data_raw, bsr_array):
|
|
155
164
|
raise TypeError("'pressure_data_raw' must be an instance of 'numpy.ndarray'" +
|
|
156
165
|
f" but not of '{type(pressure_data_raw)}'")
|
|
166
|
+
if isinstance(pressure_data_raw, bsr_array) and not frozen_sensor_config:
|
|
167
|
+
raise ValueError("'pressure_data_raw' can only be an instance of " +
|
|
168
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
157
169
|
if flow_data_raw is not None:
|
|
158
|
-
if not isinstance(flow_data_raw, np.ndarray)
|
|
170
|
+
if not isinstance(flow_data_raw, np.ndarray) and \
|
|
171
|
+
not isinstance(flow_data_raw, bsr_array):
|
|
159
172
|
raise TypeError("'flow_data_raw' must be an instance of 'numpy.ndarray' " +
|
|
160
173
|
f"but not of '{type(flow_data_raw)}'")
|
|
174
|
+
if isinstance(flow_data_raw, bsr_array) and not frozen_sensor_config:
|
|
175
|
+
raise ValueError("'flow_data_raw' can only be an instance of " +
|
|
176
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
161
177
|
if demand_data_raw is not None:
|
|
162
|
-
if not isinstance(demand_data_raw, np.ndarray)
|
|
178
|
+
if not isinstance(demand_data_raw, np.ndarray) and \
|
|
179
|
+
not isinstance(demand_data_raw, bsr_array):
|
|
163
180
|
raise TypeError("'demand_data_raw' must be an instance of 'numpy.ndarray' " +
|
|
164
181
|
f"but not of '{type(demand_data_raw)}'")
|
|
182
|
+
if isinstance(demand_data_raw, bsr_array) and not frozen_sensor_config:
|
|
183
|
+
raise ValueError("'demand_data_raw' can only be an instance of " +
|
|
184
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
165
185
|
if node_quality_data_raw is not None:
|
|
166
|
-
if not isinstance(node_quality_data_raw, np.ndarray)
|
|
186
|
+
if not isinstance(node_quality_data_raw, np.ndarray) and \
|
|
187
|
+
not isinstance(node_quality_data_raw, bsr_array):
|
|
167
188
|
raise TypeError("'node_quality_data_raw' must be an instance of 'numpy.ndarray'" +
|
|
168
189
|
f" but not of '{type(node_quality_data_raw)}'")
|
|
190
|
+
if isinstance(node_quality_data_raw, bsr_array) and not frozen_sensor_config:
|
|
191
|
+
raise ValueError("'node_quality_data_raw' can only be an instance of " +
|
|
192
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
169
193
|
if link_quality_data_raw is not None:
|
|
170
|
-
if not isinstance(link_quality_data_raw, np.ndarray)
|
|
194
|
+
if not isinstance(link_quality_data_raw, np.ndarray) and \
|
|
195
|
+
not isinstance(link_quality_data_raw, bsr_array):
|
|
171
196
|
raise TypeError("'link_quality_data_raw' must be an instance of 'numpy.ndarray'" +
|
|
172
197
|
f" but not of '{type(link_quality_data_raw)}'")
|
|
198
|
+
if isinstance(link_quality_data_raw, bsr_array) and not frozen_sensor_config:
|
|
199
|
+
raise ValueError("'link_quality_data_raw' can only be an instance of " +
|
|
200
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
173
201
|
if pumps_state_data_raw is not None:
|
|
174
|
-
if not isinstance(pumps_state_data_raw, np.ndarray)
|
|
202
|
+
if not isinstance(pumps_state_data_raw, np.ndarray) and \
|
|
203
|
+
not isinstance(pumps_state_data_raw, bsr_array):
|
|
175
204
|
raise TypeError("'pumps_state_data_raw' must be an instance of 'numpy.ndarray' " +
|
|
176
205
|
f"but no of '{type(pumps_state_data_raw)}'")
|
|
206
|
+
if isinstance(pumps_state_data_raw, bsr_array) and not frozen_sensor_config:
|
|
207
|
+
raise ValueError("'pumps_state_data_raw' can only be an instance of " +
|
|
208
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
177
209
|
if valves_state_data_raw is not None:
|
|
178
|
-
if not isinstance(valves_state_data_raw, np.ndarray)
|
|
210
|
+
if not isinstance(valves_state_data_raw, np.ndarray) and \
|
|
211
|
+
not isinstance(valves_state_data_raw, bsr_array):
|
|
179
212
|
raise TypeError("'valves_state_data_raw' must be an instance of 'numpy.ndarray' " +
|
|
180
213
|
f"but no of '{type(valves_state_data_raw)}'")
|
|
214
|
+
if isinstance(valves_state_data_raw, bsr_array) and not frozen_sensor_config:
|
|
215
|
+
raise ValueError("'valves_state_data_raw' can only be an instance of " +
|
|
216
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
181
217
|
if tanks_volume_data_raw is not None:
|
|
182
|
-
if not isinstance(tanks_volume_data_raw, np.ndarray)
|
|
218
|
+
if not isinstance(tanks_volume_data_raw, np.ndarray) and \
|
|
219
|
+
not isinstance(tanks_volume_data_raw, bsr_array):
|
|
183
220
|
raise TypeError("'tanks_volume_data_raw' must be an instance of 'numpy.ndarray'" +
|
|
184
221
|
f" but not of '{type(tanks_volume_data_raw)}'")
|
|
222
|
+
if isinstance(tanks_volume_data_raw, bsr_array) and not frozen_sensor_config:
|
|
223
|
+
raise ValueError("'tanks_volume_data_raw' can only be an instance of " +
|
|
224
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
185
225
|
if sensor_faults is None or not isinstance(sensor_faults, list):
|
|
186
226
|
raise TypeError("'sensor_faults' must be a list of " +
|
|
187
227
|
"'epyt_flow.simulation.events.SensorFault' instances but " +
|
|
188
228
|
f"'{type(sensor_faults)}'")
|
|
189
229
|
if surface_species_concentration_raw is not None:
|
|
190
|
-
if not isinstance(surface_species_concentration_raw, np.ndarray)
|
|
230
|
+
if not isinstance(surface_species_concentration_raw, np.ndarray) and \
|
|
231
|
+
not isinstance(surface_species_concentration_raw, dict):
|
|
191
232
|
raise TypeError("'surface_species_concentration_raw' must be an instance of " +
|
|
192
233
|
"'numpy.ndarray' but not of " +
|
|
193
234
|
f"'{type(surface_species_concentration_raw)}'")
|
|
235
|
+
if isinstance(surface_species_concentration_raw, dict) and not frozen_sensor_config:
|
|
236
|
+
raise TypeError("'surface_species_concentration_raw' can only be an instance of " +
|
|
237
|
+
"'dict' if 'frozen_sensor_config=True'")
|
|
194
238
|
if bulk_species_node_concentration_raw is not None:
|
|
195
|
-
if not isinstance(bulk_species_node_concentration_raw, np.ndarray)
|
|
239
|
+
if not isinstance(bulk_species_node_concentration_raw, np.ndarray) and \
|
|
240
|
+
not isinstance(bulk_species_node_concentration_raw, dict):
|
|
196
241
|
raise TypeError("'bulk_species_node_concentration_raw' must be an instance of " +
|
|
197
242
|
"'numpy.ndarray' but not of " +
|
|
198
243
|
f"'{type(bulk_species_node_concentration_raw)}'")
|
|
244
|
+
if isinstance(bulk_species_node_concentration_raw, dict) and not frozen_sensor_config:
|
|
245
|
+
raise TypeError("'bulk_species_node_concentration_raw' can only be an instance of " +
|
|
246
|
+
"'dict' if 'frozen_sensor_config=True'")
|
|
199
247
|
if bulk_species_link_concentration_raw is not None:
|
|
200
|
-
if not isinstance(bulk_species_link_concentration_raw, np.ndarray)
|
|
248
|
+
if not isinstance(bulk_species_link_concentration_raw, np.ndarray) and \
|
|
249
|
+
not isinstance(bulk_species_link_concentration_raw, dict):
|
|
201
250
|
raise TypeError("'bulk_species_link_concentration_raw' must be an instance of " +
|
|
202
251
|
"'numpy.ndarray' but not of " +
|
|
203
252
|
f"'{type(bulk_species_link_concentration_raw)}'")
|
|
253
|
+
if isinstance(bulk_species_link_concentration_raw, dict) and not frozen_sensor_config:
|
|
254
|
+
raise TypeError("'bulk_species_link_concentration_raw' can only be an instance of " +
|
|
255
|
+
"'dict' if 'frozen_sensor_config=True'")
|
|
204
256
|
if pumps_energy_usage_data_raw is not None:
|
|
205
|
-
if not isinstance(pumps_energy_usage_data_raw, np.ndarray)
|
|
257
|
+
if not isinstance(pumps_energy_usage_data_raw, np.ndarray) and \
|
|
258
|
+
not isinstance(pumps_energy_usage_data_raw, bsr_array):
|
|
206
259
|
raise TypeError("'pumps_energy_usage_data_raw' must be an instance of 'numpy.ndarray' " +
|
|
207
260
|
f"but not of '{type(pumps_energy_usage_data_raw)}'")
|
|
261
|
+
if isinstance(pumps_energy_usage_data_raw, bsr_array) and not frozen_sensor_config:
|
|
262
|
+
raise ValueError("'pumps_energy_usage_data_raw' can only be an instance of " +
|
|
263
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
208
264
|
if pumps_efficiency_data_raw is not None:
|
|
209
|
-
if not isinstance(pumps_efficiency_data_raw, np.ndarray)
|
|
265
|
+
if not isinstance(pumps_efficiency_data_raw, np.ndarray) and \
|
|
266
|
+
not isinstance(pumps_efficiency_data_raw, bsr_array):
|
|
210
267
|
raise TypeError("'pumps_efficiency_data_raw' must be an instance of 'numpy.ndarray' " +
|
|
211
268
|
f"but not of '{type(pumps_efficiency_data_raw)}'")
|
|
269
|
+
if isinstance(pumps_efficiency_data_raw, bsr_array) and not frozen_sensor_config:
|
|
270
|
+
raise ValueError("'pumps_efficiency_data_raw' can only be an instance of " +
|
|
271
|
+
"'scipy.sparse.bsr_array' if 'frozen_sensor_config=True'")
|
|
212
272
|
if len(sensor_faults) != 0:
|
|
213
273
|
if any(not isinstance(f, SensorFault) for f in sensor_faults):
|
|
214
274
|
raise TypeError("'sensor_faults' must be a list of " +
|
|
@@ -274,14 +334,17 @@ class ScadaData(Serializable):
|
|
|
274
334
|
if not tanks_volume_data_raw.shape[0] == n_time_steps:
|
|
275
335
|
__raise_shape_mismatch("tanks_volume_data_raw")
|
|
276
336
|
if bulk_species_node_concentration_raw is not None:
|
|
277
|
-
if bulk_species_node_concentration_raw.
|
|
278
|
-
|
|
337
|
+
if isinstance(bulk_species_node_concentration_raw, np.ndarray):
|
|
338
|
+
if bulk_species_node_concentration_raw.shape[0] != n_time_steps:
|
|
339
|
+
__raise_shape_mismatch("bulk_species_node_concentration_raw")
|
|
279
340
|
if bulk_species_link_concentration_raw is not None:
|
|
280
|
-
if bulk_species_link_concentration_raw.
|
|
281
|
-
|
|
341
|
+
if isinstance(bulk_species_link_concentration_raw, np.ndarray):
|
|
342
|
+
if bulk_species_link_concentration_raw.shape[0] != n_time_steps:
|
|
343
|
+
__raise_shape_mismatch("bulk_species_link_concentration_raw")
|
|
282
344
|
if surface_species_concentration_raw is not None:
|
|
283
|
-
if surface_species_concentration_raw.
|
|
284
|
-
|
|
345
|
+
if isinstance(surface_species_concentration_raw, np.ndarray):
|
|
346
|
+
if surface_species_concentration_raw.shape[0] != n_time_steps:
|
|
347
|
+
__raise_shape_mismatch("surface_species_concentration_raw")
|
|
285
348
|
if pumps_energy_usage_data_raw is not None:
|
|
286
349
|
if pumps_energy_usage_data_raw.shape[0] != n_time_steps:
|
|
287
350
|
__raise_shape_mismatch("pumps_energy_usage_data_raw")
|
|
@@ -331,35 +394,64 @@ class ScadaData(Serializable):
|
|
|
331
394
|
else:
|
|
332
395
|
return data[:, idx]
|
|
333
396
|
|
|
397
|
+
if isinstance(pressure_data_raw, bsr_array):
|
|
398
|
+
pressure_data_raw = pressure_data_raw.todense()
|
|
334
399
|
self.__pressure_data_raw = __reduce_data(data=pressure_data_raw,
|
|
335
400
|
item_to_idx=node_to_idx,
|
|
336
401
|
sensors=sensor_config.pressure_sensors)
|
|
402
|
+
|
|
403
|
+
if isinstance(flow_data_raw, bsr_array):
|
|
404
|
+
flow_data_raw = flow_data_raw.todense()
|
|
337
405
|
self.__flow_data_raw = __reduce_data(data=flow_data_raw,
|
|
338
406
|
item_to_idx=link_to_idx,
|
|
339
407
|
sensors=sensor_config.flow_sensors)
|
|
408
|
+
|
|
409
|
+
if isinstance(demand_data_raw, bsr_array):
|
|
410
|
+
demand_data_raw = demand_data_raw.todense()
|
|
340
411
|
self.__demand_data_raw = __reduce_data(data=demand_data_raw,
|
|
341
412
|
item_to_idx=node_to_idx,
|
|
342
413
|
sensors=sensor_config.demand_sensors)
|
|
414
|
+
|
|
415
|
+
if isinstance(node_quality_data_raw, bsr_array):
|
|
416
|
+
node_quality_data_raw = node_quality_data_raw.todense()
|
|
343
417
|
self.__node_quality_data_raw = __reduce_data(data=node_quality_data_raw,
|
|
344
418
|
item_to_idx=node_to_idx,
|
|
345
419
|
sensors=sensor_config.quality_node_sensors)
|
|
420
|
+
|
|
421
|
+
if isinstance(link_quality_data_raw, bsr_array):
|
|
422
|
+
link_quality_data_raw = link_quality_data_raw.todense()
|
|
346
423
|
self.__link_quality_data_raw = __reduce_data(data=link_quality_data_raw,
|
|
347
424
|
item_to_idx=link_to_idx,
|
|
348
425
|
sensors=sensor_config.quality_link_sensors)
|
|
426
|
+
|
|
427
|
+
if isinstance(pumps_state_data_raw, bsr_array):
|
|
428
|
+
pumps_state_data_raw = pumps_state_data_raw.todense()
|
|
349
429
|
self.__pumps_state_data_raw = __reduce_data(data=pumps_state_data_raw,
|
|
350
430
|
item_to_idx=pump_to_idx,
|
|
351
431
|
sensors=sensor_config.pump_state_sensors)
|
|
432
|
+
|
|
433
|
+
if isinstance(pumps_energy_usage_data_raw, bsr_array):
|
|
434
|
+
pumps_energy_usage_data_raw = pumps_energy_usage_data_raw.todense()
|
|
352
435
|
self.__pumps_energy_usage_data_raw = \
|
|
353
436
|
__reduce_data(data=pumps_energy_usage_data_raw,
|
|
354
437
|
item_to_idx=pump_to_idx,
|
|
355
438
|
sensors=sensor_config.pump_energyconsumption_sensors)
|
|
439
|
+
|
|
440
|
+
if isinstance(pumps_efficiency_data_raw, bsr_array):
|
|
441
|
+
pumps_efficiency_data_raw = pumps_efficiency_data_raw.todense()
|
|
356
442
|
self.__pumps_efficiency_data_raw = \
|
|
357
443
|
__reduce_data(data=pumps_efficiency_data_raw,
|
|
358
444
|
item_to_idx=pump_to_idx,
|
|
359
445
|
sensors=sensor_config.pump_efficiency_sensors)
|
|
446
|
+
|
|
447
|
+
if isinstance(valves_state_data_raw, bsr_array):
|
|
448
|
+
valves_state_data_raw = valves_state_data_raw.todense()
|
|
360
449
|
self.__valves_state_data_raw = __reduce_data(data=valves_state_data_raw,
|
|
361
450
|
item_to_idx=valve_to_idx,
|
|
362
451
|
sensors=sensor_config.valve_state_sensors)
|
|
452
|
+
|
|
453
|
+
if isinstance(tanks_volume_data_raw, bsr_array):
|
|
454
|
+
tanks_volume_data_raw = tanks_volume_data_raw.todense()
|
|
363
455
|
self.__tanks_volume_data_raw = __reduce_data(data=tanks_volume_data_raw,
|
|
364
456
|
item_to_idx=tank_to_idx,
|
|
365
457
|
sensors=sensor_config.tank_volume_sensors)
|
|
@@ -376,29 +468,56 @@ class ScadaData(Serializable):
|
|
|
376
468
|
|
|
377
469
|
return np.concatenate(r, axis=1)
|
|
378
470
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
471
|
+
def __reduce_msx_dict_data(data: dict, species_senors: dict[str, list[str]],
|
|
472
|
+
map_sensor_id_to_idx: Callable[str, int]) -> np.ndarray:
|
|
473
|
+
r = []
|
|
474
|
+
|
|
475
|
+
for species_id in data:
|
|
476
|
+
data_ = data[species_id].todense()
|
|
477
|
+
for sensor_id in species_senors[species_id]:
|
|
478
|
+
data_idx = map_sensor_id_to_idx(sensor_id)
|
|
479
|
+
r.append(data_[:, data_idx].reshape(-1, 1))
|
|
480
|
+
|
|
481
|
+
return np.concatenate(r, axis=1)
|
|
482
|
+
|
|
483
|
+
if isinstance(bulk_species_node_concentration_raw, dict):
|
|
484
|
+
self.__bulk_species_node_concentration_raw = __reduce_msx_dict_data(
|
|
485
|
+
bulk_species_node_concentration_raw, sensor_config.bulk_species_node_sensors,
|
|
486
|
+
sensor_config.map_node_id_to_idx)
|
|
487
|
+
else:
|
|
488
|
+
node_bulk_species_idx = [(sensor_config.map_bulkspecies_id_to_idx(s),
|
|
489
|
+
[sensor_config.map_node_id_to_idx(node_id)
|
|
490
|
+
for node_id in sensor_config.bulk_species_node_sensors[s]])
|
|
491
|
+
for s in sensor_config.bulk_species_node_sensors.keys()]
|
|
492
|
+
self.__bulk_species_node_concentration_raw = \
|
|
493
|
+
__reduce_msx_data(data=bulk_species_node_concentration_raw,
|
|
494
|
+
sensors=node_bulk_species_idx)
|
|
495
|
+
|
|
496
|
+
if isinstance(bulk_species_link_concentration_raw, dict):
|
|
497
|
+
self.__bulk_species_link_concentration_raw = __reduce_msx_dict_data(
|
|
498
|
+
bulk_species_link_concentration_raw, sensor_config.bulk_species_link_sensors,
|
|
499
|
+
sensor_config.map_link_id_to_idx)
|
|
500
|
+
else:
|
|
501
|
+
bulk_species_link_idx = [(sensor_config.map_bulkspecies_id_to_idx(s),
|
|
502
|
+
[sensor_config.map_link_id_to_idx(link_id)
|
|
503
|
+
for link_id in sensor_config.bulk_species_link_sensors[s]])
|
|
504
|
+
for s in sensor_config.bulk_species_link_sensors.keys()]
|
|
505
|
+
self.__bulk_species_link_concentration_raw = \
|
|
506
|
+
__reduce_msx_data(data=bulk_species_link_concentration_raw,
|
|
507
|
+
sensors=bulk_species_link_idx)
|
|
508
|
+
|
|
509
|
+
if isinstance(surface_species_concentration_raw, dict):
|
|
510
|
+
self.__surface_species_concentration_raw = __reduce_msx_dict_data(
|
|
511
|
+
surface_species_concentration_raw, sensor_config.surface_species_sensors,
|
|
512
|
+
sensor_config.map_link_id_to_idx)
|
|
513
|
+
else:
|
|
514
|
+
surface_species_idx = [(sensor_config.map_surfacespecies_id_to_idx(s),
|
|
515
|
+
[sensor_config.map_link_id_to_idx(link_id)
|
|
516
|
+
for link_id in sensor_config.surface_species_sensors[s]])
|
|
517
|
+
for s in sensor_config.surface_species_sensors.keys()]
|
|
518
|
+
self.__surface_species_concentration_raw = \
|
|
519
|
+
__reduce_msx_data(data=surface_species_concentration_raw,
|
|
520
|
+
sensors=surface_species_idx)
|
|
402
521
|
|
|
403
522
|
self.__init()
|
|
404
523
|
|
|
@@ -755,15 +874,17 @@ class ScadaData(Serializable):
|
|
|
755
874
|
return 5.450992969
|
|
756
875
|
|
|
757
876
|
# Convert units
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
877
|
+
attributes = self.get_attributes()
|
|
878
|
+
|
|
879
|
+
pressure_data = attributes["pressure_data_raw"]
|
|
880
|
+
flow_data = attributes["flow_data_raw"]
|
|
881
|
+
demand_data = attributes["demand_data_raw"]
|
|
882
|
+
quality_node_data = attributes["node_quality_data_raw"]
|
|
883
|
+
quality_link_data = attributes["link_quality_data_raw"]
|
|
884
|
+
tanks_volume_data = attributes["tanks_volume_data_raw"]
|
|
885
|
+
surface_species_concentrations = attributes["surface_species_concentration_raw"]
|
|
886
|
+
bulk_species_node_concentrations = attributes["bulk_species_node_concentration_raw"]
|
|
887
|
+
bulk_species_link_concentrations = attributes["bulk_species_link_concentration_raw"]
|
|
767
888
|
|
|
768
889
|
if flow_unit is not None:
|
|
769
890
|
old_flow_unit = self.__sensor_config.flow_unit
|
|
@@ -808,23 +929,23 @@ class ScadaData(Serializable):
|
|
|
808
929
|
if bulk_species_mass_unit is not None:
|
|
809
930
|
# Convert bulk species concentrations
|
|
810
931
|
if self.__frozen_sensor_config is True:
|
|
811
|
-
for i, species_id
|
|
932
|
+
for i, species_id in enumerate(self.__sensor_config.bulk_species_node_sensors):
|
|
812
933
|
species_idx = self.__sensor_config.bulk_species.index(species_id)
|
|
813
934
|
new_mass_unit = bulk_species_mass_unit[species_idx]
|
|
814
935
|
old_mass_unit = self.__sensor_config.bulk_species_mass_unit[species_idx]
|
|
815
936
|
|
|
816
937
|
if new_mass_unit != old_mass_unit:
|
|
817
938
|
convert_factor = __get_mass_convert_factor(new_mass_unit, old_mass_unit)
|
|
818
|
-
bulk_species_node_concentrations[
|
|
939
|
+
bulk_species_node_concentrations[species_id] *= convert_factor
|
|
819
940
|
|
|
820
|
-
for i, species_id,
|
|
941
|
+
for i, species_id, in enumerate(self.__sensor_config.bulk_species_link_sensors):
|
|
821
942
|
species_idx = self.__sensor_config.bulk_species.index(species_id)
|
|
822
943
|
new_mass_unit = bulk_species_mass_unit[species_idx]
|
|
823
944
|
old_mass_unit = self.__sensor_config.bulk_species_mass_unit[species_idx]
|
|
824
945
|
|
|
825
946
|
if new_mass_unit != old_mass_unit:
|
|
826
947
|
convert_factor = __get_mass_convert_factor(new_mass_unit, old_mass_unit)
|
|
827
|
-
bulk_species_link_concentrations[
|
|
948
|
+
bulk_species_link_concentrations[species_id] *= convert_factor
|
|
828
949
|
else:
|
|
829
950
|
for i in range(bulk_species_node_concentrations.shape[1]):
|
|
830
951
|
if bulk_species_mass_unit[i] != self.__sensor_config.bulk_species_mass_unit[i]:
|
|
@@ -845,7 +966,7 @@ class ScadaData(Serializable):
|
|
|
845
966
|
|
|
846
967
|
if new_mass_unit != old_mass_unit:
|
|
847
968
|
convert_factor = __get_mass_convert_factor(new_mass_unit, old_mass_unit)
|
|
848
|
-
surface_species_concentrations[
|
|
969
|
+
surface_species_concentrations[species_id] *= convert_factor
|
|
849
970
|
else:
|
|
850
971
|
for i in range(surface_species_concentrations.shape[1]):
|
|
851
972
|
old_mass_unit = self.__sensor_config.surface_species_mass_unit[i]
|
|
@@ -1272,6 +1393,131 @@ class ScadaData(Serializable):
|
|
|
1272
1393
|
"pumps_energy_usage_data_raw": self.__pumps_energy_usage_data_raw,
|
|
1273
1394
|
"pumps_efficiency_data_raw": self.__pumps_efficiency_data_raw}
|
|
1274
1395
|
|
|
1396
|
+
if self.__frozen_sensor_config is True:
|
|
1397
|
+
def __create_sparse_array(sensors: list[str], map_sensor_to_idx: Callable[str, int],
|
|
1398
|
+
n_all_items: int,
|
|
1399
|
+
get_data: Callable[list[str], np.ndarray]) -> bsr_array:
|
|
1400
|
+
row = []
|
|
1401
|
+
col = []
|
|
1402
|
+
data = []
|
|
1403
|
+
|
|
1404
|
+
for sensor_id in sensors:
|
|
1405
|
+
idx = map_sensor_to_idx(sensor_id)
|
|
1406
|
+
data_ = get_data([sensor_id])
|
|
1407
|
+
|
|
1408
|
+
data += data_.flatten().tolist()
|
|
1409
|
+
row += list(range(len(self.__sensor_readings_time)))
|
|
1410
|
+
col += [idx] * len(self.__sensor_readings_time)
|
|
1411
|
+
|
|
1412
|
+
return bsr_array((data, (row, col)),
|
|
1413
|
+
shape=(len(self.__sensor_readings_time), n_all_items))
|
|
1414
|
+
|
|
1415
|
+
def __msx_create_sparse_array(sensors: list[str], map_sensor_to_idx: Callable[str, int],
|
|
1416
|
+
species_id: str, n_all_items: int,
|
|
1417
|
+
get_data: Callable[dict[str, list[str]], np.ndarray]
|
|
1418
|
+
) -> bsr_array:
|
|
1419
|
+
row = []
|
|
1420
|
+
col = []
|
|
1421
|
+
data = []
|
|
1422
|
+
|
|
1423
|
+
for sensor_id in sensors:
|
|
1424
|
+
item_idx = map_sensor_to_idx(sensor_id)
|
|
1425
|
+
|
|
1426
|
+
row += list(range(len(self.__sensor_readings_time)))
|
|
1427
|
+
col += [item_idx] * len(self.__sensor_readings_time)
|
|
1428
|
+
data += get_data({species_id: [sensor_id]}).flatten().tolist()
|
|
1429
|
+
|
|
1430
|
+
return bsr_array((data, (row, col)),
|
|
1431
|
+
shape=(len(self.__sensor_readings_time), n_all_items))
|
|
1432
|
+
|
|
1433
|
+
if self.__pressure_data_raw is not None:
|
|
1434
|
+
attr["pressure_data_raw"] = __create_sparse_array(
|
|
1435
|
+
self.__sensor_config.pressure_sensors,
|
|
1436
|
+
self.__sensor_config.map_node_id_to_idx,
|
|
1437
|
+
len(self.__sensor_config.nodes),
|
|
1438
|
+
self.get_data_pressures)
|
|
1439
|
+
if self.__flow_data_raw is not None:
|
|
1440
|
+
attr["flow_data_raw"] = __create_sparse_array(
|
|
1441
|
+
self.__sensor_config.flow_sensors,
|
|
1442
|
+
self.__sensor_config.map_link_id_to_idx,
|
|
1443
|
+
len(self.__sensor_config.links),
|
|
1444
|
+
self.get_data_flows)
|
|
1445
|
+
if self.__demand_data_raw is not None:
|
|
1446
|
+
attr["demand_data_raw"] = __create_sparse_array(
|
|
1447
|
+
self.__sensor_config.demand_sensors,
|
|
1448
|
+
self.__sensor_config.map_node_id_to_idx,
|
|
1449
|
+
len(self.__sensor_config.nodes),
|
|
1450
|
+
self.get_data_demands)
|
|
1451
|
+
if self.__node_quality_data_raw is not None:
|
|
1452
|
+
attr["node_quality_data_raw"] = __create_sparse_array(
|
|
1453
|
+
self.__sensor_config.quality_node_sensors,
|
|
1454
|
+
self.__sensor_config.map_node_id_to_idx,
|
|
1455
|
+
len(self.__sensor_config.nodes),
|
|
1456
|
+
self.get_data_nodes_quality)
|
|
1457
|
+
if self.__link_quality_data_raw is not None:
|
|
1458
|
+
attr["link_quality_data_raw"] = __create_sparse_array(
|
|
1459
|
+
self.__sensor_config.quality_link_sensors,
|
|
1460
|
+
self.__sensor_config.map_link_id_to_idx,
|
|
1461
|
+
len(self.__sensor_config.links),
|
|
1462
|
+
self.get_data_links_quality)
|
|
1463
|
+
if self.__pumps_state_data_raw is not None:
|
|
1464
|
+
attr["pumps_state_data_raw"] = __create_sparse_array(
|
|
1465
|
+
self.__sensor_config.pump_state_sensors,
|
|
1466
|
+
self.__sensor_config.map_pump_id_to_idx,
|
|
1467
|
+
len(self.__sensor_config.pumps),
|
|
1468
|
+
self.get_data_pumps_state)
|
|
1469
|
+
if self.__valves_state_data_raw is not None:
|
|
1470
|
+
attr["valves_state_data_raw"] = __create_sparse_array(
|
|
1471
|
+
self.__sensor_config.valve_state_sensors,
|
|
1472
|
+
self.__sensor_config.map_valve_id_to_idx,
|
|
1473
|
+
len(self.__sensor_config.valves),
|
|
1474
|
+
self.get_data_valves_state)
|
|
1475
|
+
if self.__tanks_volume_data_raw is not None:
|
|
1476
|
+
attr["tanks_volume_data_raw"] = __create_sparse_array(
|
|
1477
|
+
self.__sensor_config.tank_volume_sensors,
|
|
1478
|
+
self.__sensor_config.map_tank_id_to_idx,
|
|
1479
|
+
len(self.__sensor_config.tanks),
|
|
1480
|
+
self.get_data_tanks_water_volume)
|
|
1481
|
+
if self.__pumps_energy_usage_data_raw is not None:
|
|
1482
|
+
attr["pumps_energy_usage_data_raw"] = __create_sparse_array(
|
|
1483
|
+
self.__sensor_config.pump_energyconsumption_sensors,
|
|
1484
|
+
self.__sensor_config.map_pump_id_to_idx,
|
|
1485
|
+
len(self.__sensor_config.pumps),
|
|
1486
|
+
self.get_data_pumps_energyconsumption)
|
|
1487
|
+
if self.__pumps_efficiency_data_raw is not None:
|
|
1488
|
+
attr["pumps_efficiency_data_raw"] = __create_sparse_array(
|
|
1489
|
+
self.__sensor_config.pump_efficiency_sensors,
|
|
1490
|
+
self.__sensor_config.map_pump_id_to_idx,
|
|
1491
|
+
len(self.__sensor_config.pumps),
|
|
1492
|
+
self.get_data_pumps_efficiency)
|
|
1493
|
+
if self.__surface_species_concentration_raw is not None:
|
|
1494
|
+
data = {}
|
|
1495
|
+
for s in self.__sensor_config.surface_species_sensors.keys():
|
|
1496
|
+
data[s] = __msx_create_sparse_array(self.__sensor_config.surface_species_sensors[s],
|
|
1497
|
+
self.__sensor_config.map_link_id_to_idx,
|
|
1498
|
+
s, len(self.__sensor_config.links),
|
|
1499
|
+
self.get_data_surface_species_concentration)
|
|
1500
|
+
|
|
1501
|
+
attr["surface_species_concentration_raw"] = data
|
|
1502
|
+
if self.__bulk_species_node_concentration_raw is not None:
|
|
1503
|
+
data = {}
|
|
1504
|
+
for s in self.__sensor_config.bulk_species_node_sensors.keys():
|
|
1505
|
+
data[s] = __msx_create_sparse_array(self.__sensor_config.bulk_species_node_sensors[s],
|
|
1506
|
+
self.__sensor_config.map_node_id_to_idx,
|
|
1507
|
+
s, len(self.__sensor_config.nodes),
|
|
1508
|
+
self.get_data_bulk_species_node_concentration)
|
|
1509
|
+
|
|
1510
|
+
attr["bulk_species_node_concentration_raw"] = data
|
|
1511
|
+
if self.__bulk_species_link_concentration_raw is not None:
|
|
1512
|
+
data = {}
|
|
1513
|
+
for s in self.__sensor_config.bulk_species_link_sensors.keys():
|
|
1514
|
+
data[s] = __msx_create_sparse_array(self.__sensor_config.bulk_species_link_sensors[s],
|
|
1515
|
+
self.__sensor_config.map_link_id_to_idx,
|
|
1516
|
+
s, len(self.__sensor_config.links),
|
|
1517
|
+
self.get_data_bulk_species_link_concentration)
|
|
1518
|
+
|
|
1519
|
+
attr["bulk_species_link_concentration_raw"] = data
|
|
1520
|
+
|
|
1275
1521
|
return super().get_attributes() | attr
|
|
1276
1522
|
|
|
1277
1523
|
def __eq__(self, other) -> bool:
|
|
@@ -1412,6 +1658,120 @@ class ScadaData(Serializable):
|
|
|
1412
1658
|
self.__sensor_reading_events = sensor_reading_events
|
|
1413
1659
|
self.__init()
|
|
1414
1660
|
|
|
1661
|
+
def extract_time_window(self, start_time: int, end_time: int):
|
|
1662
|
+
"""
|
|
1663
|
+
Extracts a time window of SCADA data from this SCADA data instance --
|
|
1664
|
+
i.e. creating a new SCADA data instance containing data from the requested
|
|
1665
|
+
time period only.
|
|
1666
|
+
|
|
1667
|
+
Parameters
|
|
1668
|
+
----------
|
|
1669
|
+
start_time : `int`
|
|
1670
|
+
Start time -- i.e. beginning of the time window.
|
|
1671
|
+
end_time : `int`, optional
|
|
1672
|
+
End time -- i.e. end of the time window.
|
|
1673
|
+
If None, all sensor readings from the start time onward are included
|
|
1674
|
+
|
|
1675
|
+
The default is None.
|
|
1676
|
+
|
|
1677
|
+
Returns
|
|
1678
|
+
-------
|
|
1679
|
+
:class:`~epyt_flow.simulation.scada.scada_data.ScadaData`
|
|
1680
|
+
New SCADA data instance containing data from the requested time period only.
|
|
1681
|
+
"""
|
|
1682
|
+
if not isinstance(start_time, int):
|
|
1683
|
+
raise TypeError("'start_time' must be an instance of `int` but not of " +
|
|
1684
|
+
f"'{type(start_time)}'")
|
|
1685
|
+
if start_time not in self.__sensor_readings_time:
|
|
1686
|
+
raise ValueError("No data found for 'start_time'")
|
|
1687
|
+
if end_time is not None:
|
|
1688
|
+
if not isinstance(end_time, int):
|
|
1689
|
+
raise TypeError("'end_time' must be an instance of `int` but not of " +
|
|
1690
|
+
f"'{type(end_time)}'")
|
|
1691
|
+
if end_time not in self.__sensor_readings_time:
|
|
1692
|
+
raise ValueError("No data found for 'end_time'")
|
|
1693
|
+
else:
|
|
1694
|
+
end_time = self.__sensor_readings_time[-1]
|
|
1695
|
+
|
|
1696
|
+
start_idx = self.__sensor_readings_time.tolist().index(start_time)
|
|
1697
|
+
end_idx = self.__sensor_readings_time.tolist().index(end_time) + 1
|
|
1698
|
+
|
|
1699
|
+
pressure_data_raw = None
|
|
1700
|
+
if self.__pressure_data_raw is not None:
|
|
1701
|
+
pressure_data_raw = self.__pressure_data_raw[start_idx:end_idx, :]
|
|
1702
|
+
|
|
1703
|
+
flow_data_raw = None
|
|
1704
|
+
if self.__flow_data_raw is not None:
|
|
1705
|
+
flow_data_raw = self.__flow_data_raw[start_idx:end_idx, :]
|
|
1706
|
+
|
|
1707
|
+
demand_data_raw = None
|
|
1708
|
+
if self.__demand_data_raw is not None:
|
|
1709
|
+
demand_data_raw = self.__demand_data_raw[start_idx:end_idx, :]
|
|
1710
|
+
|
|
1711
|
+
node_quality_data_raw = None
|
|
1712
|
+
if self.__node_quality_data_raw is not None:
|
|
1713
|
+
node_quality_data_raw = self.__node_quality_data_raw[start_idx:end_idx, :]
|
|
1714
|
+
|
|
1715
|
+
link_quality_data_raw = None
|
|
1716
|
+
if self.__link_quality_data_raw is not None:
|
|
1717
|
+
link_quality_data_raw = self.__link_quality_data_raw[start_idx:end_idx, :]
|
|
1718
|
+
|
|
1719
|
+
pumps_state_data_raw = None
|
|
1720
|
+
if self.__pumps_state_data_raw is not None:
|
|
1721
|
+
pumps_state_data_raw = self.__pumps_state_data_raw[start_idx:end_idx, :]
|
|
1722
|
+
|
|
1723
|
+
valves_state_data_raw = None
|
|
1724
|
+
if self.__valves_state_data_raw is not None:
|
|
1725
|
+
valves_state_data_raw = self.__valves_state_data_raw[start_idx:end_idx, :]
|
|
1726
|
+
|
|
1727
|
+
tanks_volume_data_raw = None
|
|
1728
|
+
if self.__tanks_volume_data_raw is not None:
|
|
1729
|
+
tanks_volume_data_raw = self.__tanks_volume_data_raw[start_idx:end_idx, :]
|
|
1730
|
+
|
|
1731
|
+
surface_species_concentration_raw = None
|
|
1732
|
+
if self.__surface_species_concentration_raw is not None:
|
|
1733
|
+
surface_species_concentration_raw = \
|
|
1734
|
+
self.__surface_species_concentration_raw[start_idx:end_idx, :]
|
|
1735
|
+
|
|
1736
|
+
bulk_species_node_concentration_raw = None
|
|
1737
|
+
if self.__bulk_species_node_concentration_raw is not None:
|
|
1738
|
+
bulk_species_node_concentration_raw = \
|
|
1739
|
+
self.__bulk_species_node_concentration_raw[start_idx:end_idx, :]
|
|
1740
|
+
|
|
1741
|
+
bulk_species_link_concentration_raw = None
|
|
1742
|
+
if self.__bulk_species_link_concentration_raw is not None:
|
|
1743
|
+
bulk_species_link_concentration_raw = \
|
|
1744
|
+
self.__bulk_species_link_concentration_raw[start_idx:end_idx, :]
|
|
1745
|
+
|
|
1746
|
+
pumps_energy_usage_data_raw = None
|
|
1747
|
+
if self.__pumps_energy_usage_data_raw is not None:
|
|
1748
|
+
pumps_energy_usage_data_raw = self.__pumps_energy_usage_data_raw[start_idx:end_idx, :]
|
|
1749
|
+
|
|
1750
|
+
pumps_efficiency_data_raw = None
|
|
1751
|
+
if self.__pumps_efficiency_data_raw is not None:
|
|
1752
|
+
pumps_efficiency_data_raw = self.__pumps_efficiency_data_raw[start_idx:end_idx, :]
|
|
1753
|
+
|
|
1754
|
+
return ScadaData(sensor_config=self.sensor_config,
|
|
1755
|
+
sensor_readings_time=self.sensor_readings_time[start_idx:end_idx],
|
|
1756
|
+
frozen_sensor_config=self.frozen_sensor_config,
|
|
1757
|
+
sensor_noise=self.sensor_noise,
|
|
1758
|
+
sensor_reading_events=self.sensor_reading_events,
|
|
1759
|
+
sensor_reading_attacks=self.sensor_reading_attacks,
|
|
1760
|
+
sensor_faults=self.sensor_faults,
|
|
1761
|
+
pressure_data_raw=pressure_data_raw,
|
|
1762
|
+
flow_data_raw=flow_data_raw,
|
|
1763
|
+
demand_data_raw=demand_data_raw,
|
|
1764
|
+
node_quality_data_raw=node_quality_data_raw,
|
|
1765
|
+
link_quality_data_raw=link_quality_data_raw,
|
|
1766
|
+
valves_state_data_raw=valves_state_data_raw,
|
|
1767
|
+
pumps_state_data_raw=pumps_state_data_raw,
|
|
1768
|
+
tanks_volume_data_raw=tanks_volume_data_raw,
|
|
1769
|
+
surface_species_concentration_raw=surface_species_concentration_raw,
|
|
1770
|
+
bulk_species_node_concentration_raw=bulk_species_node_concentration_raw,
|
|
1771
|
+
bulk_species_link_concentration_raw=bulk_species_link_concentration_raw,
|
|
1772
|
+
pumps_energy_usage_data_raw=pumps_energy_usage_data_raw,
|
|
1773
|
+
pumps_efficiency_data_raw=pumps_efficiency_data_raw)
|
|
1774
|
+
|
|
1415
1775
|
def join(self, other) -> None:
|
|
1416
1776
|
"""
|
|
1417
1777
|
Joins two :class:`~epyt_flow.simulation.scada.scada_data.ScadaData` instances based
|
|
@@ -2921,3 +3281,91 @@ class ScadaData(Serializable):
|
|
|
2921
3281
|
x_axis_label=self.__get_x_axis_label(),
|
|
2922
3282
|
y_axis_label=y_axis_label,
|
|
2923
3283
|
show=show, save_to_file=save_to_file, ax=ax)
|
|
3284
|
+
|
|
3285
|
+
def to_pandas_dataframe(self, export_raw_data: bool = False) -> pd.DataFrame:
|
|
3286
|
+
"""
|
|
3287
|
+
Exports this SCADA data to a Pandas dataframe.
|
|
3288
|
+
|
|
3289
|
+
Parameters
|
|
3290
|
+
----------
|
|
3291
|
+
export_raw_data : `bool`, optional
|
|
3292
|
+
If True, the raw measurements (i.e. sensor reading without any noise or faults)
|
|
3293
|
+
are exported instead of the final sensor readings.
|
|
3294
|
+
|
|
3295
|
+
The default is False.
|
|
3296
|
+
|
|
3297
|
+
Returns
|
|
3298
|
+
-------
|
|
3299
|
+
`pandas.DataFrame`
|
|
3300
|
+
Exported data.
|
|
3301
|
+
"""
|
|
3302
|
+
from .scada_data_export import ScadaDataExport
|
|
3303
|
+
|
|
3304
|
+
old_sensor_config = None
|
|
3305
|
+
if export_raw_data is True:
|
|
3306
|
+
# Backup old sensor config and set a new one with sensors everywhere
|
|
3307
|
+
old_sensor_config = self.sensor_config
|
|
3308
|
+
self.change_sensor_config(ScadaDataExport.create_global_sensor_config(self))
|
|
3309
|
+
|
|
3310
|
+
sensor_readings = self.get_data()
|
|
3311
|
+
col_desc = ScadaDataExport.create_column_desc(self)
|
|
3312
|
+
columns = [f"{sensor_type} [{unit_desc}] at {item_id}" for sensor_type, item_id, unit_desc in col_desc]
|
|
3313
|
+
|
|
3314
|
+
data = {col_desc: sensor_readings[:, c_id] for c_id, col_desc in enumerate(columns)}
|
|
3315
|
+
|
|
3316
|
+
if export_raw_data is True:
|
|
3317
|
+
# Restore old sensor config
|
|
3318
|
+
self.change_sensor_config(old_sensor_config)
|
|
3319
|
+
|
|
3320
|
+
return pd.DataFrame(data)
|
|
3321
|
+
|
|
3322
|
+
def to_numpy_file(self, f_out: str, export_raw_data: bool = False) -> None:
|
|
3323
|
+
"""
|
|
3324
|
+
Exporting this SCADA data to Numpy (.npz file).
|
|
3325
|
+
|
|
3326
|
+
Parameters
|
|
3327
|
+
----------
|
|
3328
|
+
f_out : `str`
|
|
3329
|
+
Path to the .npz file to which the SCADA data will be exported.
|
|
3330
|
+
export_raw_data : `bool`, optional
|
|
3331
|
+
If True, the raw measurements (i.e. sensor reading without any noise or faults)
|
|
3332
|
+
are exported instead of the final sensor readings.
|
|
3333
|
+
|
|
3334
|
+
The default is False.
|
|
3335
|
+
"""
|
|
3336
|
+
from .scada_data_export import ScadaDataNumpyExport
|
|
3337
|
+
ScadaDataNumpyExport(f_out, export_raw_data).export(self)
|
|
3338
|
+
|
|
3339
|
+
def to_excel_file(self, f_out: str, export_raw_data: bool = False) -> None:
|
|
3340
|
+
"""
|
|
3341
|
+
Exporting this SCADA data to MS Excel (.xlsx file).
|
|
3342
|
+
|
|
3343
|
+
Parameters
|
|
3344
|
+
----------
|
|
3345
|
+
f_out : `str`
|
|
3346
|
+
Path to the .xlsx file to which the SCADA data will be exported.
|
|
3347
|
+
export_raw_data : `bool`, optional
|
|
3348
|
+
If True, the raw measurements (i.e. sensor reading without any noise or faults)
|
|
3349
|
+
are exported instead of the final sensor readings.
|
|
3350
|
+
|
|
3351
|
+
The default is False.
|
|
3352
|
+
"""
|
|
3353
|
+
from .scada_data_export import ScadaDataXlsxExport
|
|
3354
|
+
ScadaDataXlsxExport(f_out, export_raw_data).export(self)
|
|
3355
|
+
|
|
3356
|
+
def to_matlab_file(self, f_out: str, export_raw_data: bool = False) -> None:
|
|
3357
|
+
"""
|
|
3358
|
+
Exporting this SCADA data to Matlab (.mat file).
|
|
3359
|
+
|
|
3360
|
+
Parameters
|
|
3361
|
+
----------
|
|
3362
|
+
f_out : `str`
|
|
3363
|
+
Path to the .mat file to which the SCADA data will be exported.
|
|
3364
|
+
export_raw_data : `bool`, optional
|
|
3365
|
+
If True, the raw measurements (i.e. sensor reading without any noise or faults)
|
|
3366
|
+
are exported instead of the final sensor readings.
|
|
3367
|
+
|
|
3368
|
+
The default is False.
|
|
3369
|
+
"""
|
|
3370
|
+
from .scada_data_export import ScadaDataMatlabExport
|
|
3371
|
+
ScadaDataMatlabExport(f_out, export_raw_data).export(self)
|