epyt-flow 0.11.0__py3-none-any.whl → 0.13.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/EPANET/EPANET-MSX/Src/msxtoolkit.c +1 -1
- epyt_flow/VERSION +1 -1
- epyt_flow/data/benchmarks/gecco_water_quality.py +2 -2
- epyt_flow/data/benchmarks/leakdb.py +40 -5
- epyt_flow/data/benchmarks/water_usage.py +4 -3
- epyt_flow/gym/__init__.py +0 -3
- epyt_flow/gym/scenario_control_env.py +5 -12
- epyt_flow/rest_api/scenario/control_handlers.py +118 -0
- epyt_flow/rest_api/scenario/event_handlers.py +114 -1
- epyt_flow/rest_api/scenario/handlers.py +33 -0
- epyt_flow/rest_api/server.py +14 -2
- epyt_flow/simulation/backend/__init__.py +1 -0
- epyt_flow/simulation/backend/my_epyt.py +1056 -0
- epyt_flow/simulation/events/quality_events.py +3 -1
- epyt_flow/simulation/scada/scada_data.py +201 -12
- epyt_flow/simulation/scenario_simulator.py +179 -87
- epyt_flow/topology.py +8 -7
- epyt_flow/uncertainty/sensor_noise.py +2 -9
- epyt_flow/utils.py +30 -0
- epyt_flow/visualization/scenario_visualizer.py +159 -69
- epyt_flow/visualization/visualization_utils.py +144 -17
- {epyt_flow-0.11.0.dist-info → epyt_flow-0.13.0.dist-info}/METADATA +4 -4
- {epyt_flow-0.11.0.dist-info → epyt_flow-0.13.0.dist-info}/RECORD +26 -29
- {epyt_flow-0.11.0.dist-info → epyt_flow-0.13.0.dist-info}/WHEEL +1 -1
- epyt_flow/gym/control_gyms.py +0 -55
- epyt_flow/metrics.py +0 -471
- epyt_flow/models/__init__.py +0 -2
- epyt_flow/models/event_detector.py +0 -36
- epyt_flow/models/sensor_interpolation_detector.py +0 -123
- epyt_flow/simulation/scada/advanced_control.py +0 -138
- {epyt_flow-0.11.0.dist-info → epyt_flow-0.13.0.dist-info/licenses}/LICENSE +0 -0
- {epyt_flow-0.11.0.dist-info → epyt_flow-0.13.0.dist-info}/top_level.txt +0 -0
epyt_flow/utils.py
CHANGED
|
@@ -67,6 +67,36 @@ def volume_to_level(tank_volume: float, tank_diameter: float) -> float:
|
|
|
67
67
|
return (4. / (math.pow(tank_diameter, 2) * math.pi)) * tank_volume
|
|
68
68
|
|
|
69
69
|
|
|
70
|
+
def level_to_volume(tank_level: float, tank_diameter: float) -> float:
|
|
71
|
+
"""
|
|
72
|
+
Computes the volume of water in a tank given the water level in the tank.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
tank_level : `float`
|
|
77
|
+
Water level in the tank.
|
|
78
|
+
tank_diameter : `float`
|
|
79
|
+
Diameter of the tank.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
`float`
|
|
84
|
+
Water volume in tank.
|
|
85
|
+
"""
|
|
86
|
+
if not isinstance(tank_level, float):
|
|
87
|
+
raise TypeError("'tank_level' must be an instace of 'float' " +
|
|
88
|
+
f"but not of '{type(tank_level)}'")
|
|
89
|
+
if tank_level < 0:
|
|
90
|
+
raise ValueError("'tank_level' can not be negative")
|
|
91
|
+
if not isinstance(tank_diameter, float):
|
|
92
|
+
raise TypeError("'tank_diameter' must be an instace of 'float' " +
|
|
93
|
+
f"but not of '{type(tank_diameter)}'")
|
|
94
|
+
if tank_diameter <= 0:
|
|
95
|
+
raise ValueError("'tank_diameter' must be greater than zero")
|
|
96
|
+
|
|
97
|
+
return tank_level * math.pow(0.5 * tank_diameter, 2) * math.pi
|
|
98
|
+
|
|
99
|
+
|
|
70
100
|
def plot_timeseries_data(data: np.ndarray, labels: list[str] = None, x_axis_label: str = None,
|
|
71
101
|
y_axis_label: str = None, y_ticks: tuple[list[float], list[str]] = None,
|
|
72
102
|
show: bool = True, save_to_file: str = None,
|
|
@@ -4,7 +4,6 @@ Module provides a class for visualizing scenarios.
|
|
|
4
4
|
from typing import Optional, Union, List, Tuple
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
|
-
from deprecated import deprecated
|
|
8
7
|
|
|
9
8
|
import matplotlib.pyplot as plt
|
|
10
9
|
from matplotlib.animation import FuncAnimation
|
|
@@ -14,7 +13,8 @@ from svgpath2mpl import parse_path
|
|
|
14
13
|
|
|
15
14
|
from ..simulation.scenario_simulator import ScenarioSimulator
|
|
16
15
|
from ..simulation.scada.scada_data import ScadaData
|
|
17
|
-
from ..visualization import JunctionObject, EdgeObject, ColorScheme,
|
|
16
|
+
from ..visualization import JunctionObject, EdgeObject, ColorScheme, \
|
|
17
|
+
epyt_flow_colors
|
|
18
18
|
|
|
19
19
|
PUMP_PATH = ('M 202.5 93 A 41.5 42 0 0 0 161 135 A 41.5 42 0 0 0 202.5 177 A '
|
|
20
20
|
'41.5 42 0 0 0 244 135 A 41.5 42 0 0 0 241.94922 122 L 278 122 '
|
|
@@ -220,8 +220,10 @@ class ScenarioVisualizer:
|
|
|
220
220
|
|
|
221
221
|
self.colorbars = {}
|
|
222
222
|
self.labels = {}
|
|
223
|
+
self.masks = {}
|
|
223
224
|
|
|
224
|
-
def _get_midpoints(self, elements: List[str]) -> dict[
|
|
225
|
+
def _get_midpoints(self, elements: List[str]) -> dict[
|
|
226
|
+
str, tuple[float, float]]:
|
|
225
227
|
"""
|
|
226
228
|
Computes and returns the midpoints for drawing either valves or pumps
|
|
227
229
|
in a water distribution network.
|
|
@@ -298,6 +300,34 @@ class ScenarioVisualizer:
|
|
|
298
300
|
ax=self.ax, label='Pumps',
|
|
299
301
|
**self.pump_parameters.get_frame(frame_number))
|
|
300
302
|
|
|
303
|
+
for key, mask in self.masks.items():
|
|
304
|
+
if key == 'nodes':
|
|
305
|
+
nxp.draw_networkx_nodes(self.topology, ax=self.ax,
|
|
306
|
+
**self.junction_parameters.get_frame_mask(
|
|
307
|
+
mask,
|
|
308
|
+
self.color_scheme.node_color))
|
|
309
|
+
if key == 'pumps':
|
|
310
|
+
nxp.draw_networkx_nodes(
|
|
311
|
+
self.topology,
|
|
312
|
+
ax=self.ax,
|
|
313
|
+
**self.pump_parameters.get_frame_mask(mask,
|
|
314
|
+
self.color_scheme.pump_color))
|
|
315
|
+
if key == 'links':
|
|
316
|
+
nxp.draw_networkx_edges(self.topology, ax=self.ax,
|
|
317
|
+
**self.pipe_parameters.get_frame_mask(
|
|
318
|
+
frame_number,
|
|
319
|
+
self.color_scheme.pipe_color))
|
|
320
|
+
if key == 'tanks':
|
|
321
|
+
nxp.draw_networkx_nodes(self.topology, ax=self.ax,
|
|
322
|
+
**self.tank_parameters.get_frame_mask(
|
|
323
|
+
mask,
|
|
324
|
+
self.color_scheme.tank_color))
|
|
325
|
+
if key == 'valves':
|
|
326
|
+
nxp.draw_networkx_nodes(
|
|
327
|
+
self.topology, ax=self.ax,
|
|
328
|
+
**self.valve_parameters.get_frame_mask(mask,
|
|
329
|
+
self.color_scheme.valve_color))
|
|
330
|
+
|
|
301
331
|
self._draw_labels()
|
|
302
332
|
self.ax.legend(fontsize=6)
|
|
303
333
|
|
|
@@ -361,7 +391,7 @@ class ScenarioVisualizer:
|
|
|
361
391
|
+ sensor_config.quality_link_sensors)
|
|
362
392
|
return highlighted_nodes, highlighted_links
|
|
363
393
|
|
|
364
|
-
def add_labels(self, components: list or tuple = ()
|
|
394
|
+
def add_labels(self, components: str or list or tuple = (),
|
|
365
395
|
font_size: int = 8):
|
|
366
396
|
"""
|
|
367
397
|
Adds labels to hydraulic components according to the specified
|
|
@@ -509,7 +539,7 @@ class ScenarioVisualizer:
|
|
|
509
539
|
|
|
510
540
|
if export_to_file is not None:
|
|
511
541
|
plt.savefig(export_to_file, transparent=True, bbox_inches='tight',
|
|
512
|
-
dpi=
|
|
542
|
+
dpi=900)
|
|
513
543
|
if not suppress_plot:
|
|
514
544
|
plt.show()
|
|
515
545
|
else:
|
|
@@ -520,10 +550,12 @@ class ScenarioVisualizer:
|
|
|
520
550
|
self, data: Optional[Union[ScadaData, np.ndarray]] = None,
|
|
521
551
|
parameter: str = 'pressure', statistic: str = 'mean',
|
|
522
552
|
pit: Optional[Union[int, Tuple[int, int]]] = None,
|
|
553
|
+
species: str = None,
|
|
523
554
|
colormap: str = 'viridis',
|
|
524
555
|
intervals: Optional[Union[int, List[Union[int, float]]]] = None,
|
|
525
556
|
conversion: Optional[dict] = None,
|
|
526
|
-
show_colorbar: bool = False
|
|
557
|
+
show_colorbar: bool = False,
|
|
558
|
+
use_sensor_data: bool = False) -> None:
|
|
527
559
|
"""
|
|
528
560
|
Colors the nodes (junctions) in the water distribution network based on
|
|
529
561
|
the SCADA data and the specified parameters.
|
|
@@ -551,6 +583,9 @@ class ScenarioVisualizer:
|
|
|
551
583
|
representing the start and end time steps. A tuple is necessary to
|
|
552
584
|
process the data for the :meth:`~ScenarioVisualizer.show_animation`
|
|
553
585
|
method. Default is `None`.
|
|
586
|
+
species: `str`, optional
|
|
587
|
+
Key of species. Only necessary for parameter
|
|
588
|
+
'bulk_species_concentration'.
|
|
554
589
|
colormap : `str`, optional
|
|
555
590
|
The colormap to use for visualizing node values. Default is
|
|
556
591
|
'viridis'.
|
|
@@ -564,6 +599,11 @@ class ScenarioVisualizer:
|
|
|
564
599
|
show_colorbar : `bool`, optional
|
|
565
600
|
If `True`, a colorbar will be displayed on the plot to indicate the
|
|
566
601
|
range of node values. Default is `False`.
|
|
602
|
+
use_sensor_data : `bool`, optional
|
|
603
|
+
If `True`, instead of using raw simulation data, the data recorded
|
|
604
|
+
by the corresponding sensors in the system is used for the
|
|
605
|
+
visualization. Note: Not all components may have a sensor attached
|
|
606
|
+
and sensors may be subject to sensor faults or noise.
|
|
567
607
|
|
|
568
608
|
Raises
|
|
569
609
|
------
|
|
@@ -583,15 +623,45 @@ class ScenarioVisualizer:
|
|
|
583
623
|
if conversion:
|
|
584
624
|
self.scada_data = self.scada_data.convert_units(**conversion)
|
|
585
625
|
|
|
626
|
+
# TODO: is there any way to make this look better (e.g. do a mapping somewhere??)
|
|
586
627
|
if parameter == 'pressure':
|
|
587
|
-
|
|
628
|
+
if use_sensor_data:
|
|
629
|
+
values, self.masks[
|
|
630
|
+
'nodes'] = self.scada_data.get_data_pressures_as_node_features()
|
|
631
|
+
else:
|
|
632
|
+
values = self.scada_data.pressure_data_raw
|
|
588
633
|
elif parameter == 'demand':
|
|
589
|
-
|
|
634
|
+
if use_sensor_data:
|
|
635
|
+
values, self.masks[
|
|
636
|
+
'nodes'] = self.scada_data.get_data_demands_as_node_features()
|
|
637
|
+
else:
|
|
638
|
+
values = self.scada_data.demand_data_raw
|
|
590
639
|
elif parameter == 'node_quality':
|
|
591
|
-
|
|
640
|
+
if use_sensor_data:
|
|
641
|
+
values, self.masks[
|
|
642
|
+
'nodes'] = self.scada_data.get_data_nodes_quality_as_node_features()
|
|
643
|
+
else:
|
|
644
|
+
values = self.scada_data.node_quality_data_raw
|
|
592
645
|
elif parameter == 'custom_data':
|
|
593
646
|
# Custom should have the dimensions (timesteps, nodes)
|
|
594
647
|
values = self.scada_data
|
|
648
|
+
elif parameter == 'bulk_species_concentration':
|
|
649
|
+
if not species:
|
|
650
|
+
raise ValueError('Species must be set when using bulk_species_'
|
|
651
|
+
'concentration.')
|
|
652
|
+
if use_sensor_data:
|
|
653
|
+
values, self.masks[
|
|
654
|
+
'nodes'] = self.scada_data.get_data_bulk_species_concentrations_as_node_features()
|
|
655
|
+
self.masks['nodes'] = self.masks['nodes'][:,
|
|
656
|
+
self.scada_data.sensor_config.bulk_species.index(
|
|
657
|
+
species)]
|
|
658
|
+
values = values[:, :,
|
|
659
|
+
self.scada_data.sensor_config.bulk_species.index(
|
|
660
|
+
species)]
|
|
661
|
+
else:
|
|
662
|
+
values = self.scada_data.bulk_species_node_concentration_raw[:,
|
|
663
|
+
self.scada_data.sensor_config.bulk_species.index(
|
|
664
|
+
species), :]
|
|
595
665
|
else:
|
|
596
666
|
raise ValueError(
|
|
597
667
|
'Parameter must be pressure, demand, node_quality or custom_'
|
|
@@ -621,17 +691,19 @@ class ScenarioVisualizer:
|
|
|
621
691
|
self.colorbars['junctions'] = {'mappable': plt.cm.ScalarMappable(
|
|
622
692
|
norm=mpl.colors.Normalize(
|
|
623
693
|
vmin=self.junction_parameters.vmin,
|
|
624
|
-
vmax=self.junction_parameters.
|
|
694
|
+
vmax=self.junction_parameters.vmax), cmap=colormap),
|
|
625
695
|
'label': label}
|
|
626
696
|
|
|
627
697
|
def color_links(
|
|
628
698
|
self, data: Optional[Union[ScadaData, np.ndarray]] = None,
|
|
629
699
|
parameter: str = 'flow_rate', statistic: str = 'mean',
|
|
630
700
|
pit: Optional[Union[int, Tuple[int, int]]] = None,
|
|
701
|
+
species: str = None,
|
|
631
702
|
colormap: str = 'coolwarm',
|
|
632
703
|
intervals: Optional[Union[int, List[Union[int, float]]]] = None,
|
|
633
704
|
conversion: Optional[dict] = None,
|
|
634
|
-
show_colorbar: bool = False
|
|
705
|
+
show_colorbar: bool = False,
|
|
706
|
+
use_sensor_data: bool = False) -> None:
|
|
635
707
|
"""
|
|
636
708
|
Colors the links (pipes) in the water distribution network based on the
|
|
637
709
|
SCADA data and the specified parameters.
|
|
@@ -659,6 +731,9 @@ class ScenarioVisualizer:
|
|
|
659
731
|
representing the start and end time steps. A tuple is necessary to
|
|
660
732
|
process the data for the :func:`~ScenarioVisualizer.show_animation`
|
|
661
733
|
method. Default is `None`.
|
|
734
|
+
species: `str`, optional
|
|
735
|
+
Key of species. Only necessary for parameter
|
|
736
|
+
'bulk_species_concentration'.
|
|
662
737
|
colormap : `str`, optional
|
|
663
738
|
The colormap to use for visualizing link values. Default is
|
|
664
739
|
'coolwarm'.
|
|
@@ -672,6 +747,11 @@ class ScenarioVisualizer:
|
|
|
672
747
|
show_colorbar : `bool`, optional
|
|
673
748
|
If `True`, a colorbar will be displayed on the plot to indicate the
|
|
674
749
|
range of values. Default is `False`.
|
|
750
|
+
use_sensor_data : `bool`, optional
|
|
751
|
+
If `True`, instead of using raw simulation data, the data recorded
|
|
752
|
+
by the corresponding sensors in the system is used for the
|
|
753
|
+
visualization. Note: Not all components may have a sensor attached
|
|
754
|
+
and sensors may be subject to sensor faults or noise.
|
|
675
755
|
|
|
676
756
|
Raises
|
|
677
757
|
------
|
|
@@ -707,11 +787,16 @@ class ScenarioVisualizer:
|
|
|
707
787
|
break
|
|
708
788
|
self.pipe_parameters.add_frame(self.topology, 'edge_color',
|
|
709
789
|
self.scada_data, parameter,
|
|
710
|
-
statistic, frame,
|
|
790
|
+
statistic, frame, species,
|
|
791
|
+
intervals, use_sensor_data)
|
|
711
792
|
else:
|
|
712
793
|
self.pipe_parameters.add_frame(self.topology, 'edge_color',
|
|
713
794
|
self.scada_data, parameter,
|
|
714
|
-
statistic, pit, intervals
|
|
795
|
+
statistic, pit, species, intervals,
|
|
796
|
+
use_sensor_data)
|
|
797
|
+
|
|
798
|
+
if hasattr(self.pipe_parameters, 'mask'):
|
|
799
|
+
self.masks['links'] = self.pipe_parameters.mask
|
|
715
800
|
|
|
716
801
|
if show_colorbar:
|
|
717
802
|
if statistic == 'time_step':
|
|
@@ -731,7 +816,8 @@ class ScenarioVisualizer:
|
|
|
731
816
|
parameter: str = 'efficiency', statistic: str = 'mean',
|
|
732
817
|
pit: Optional[Union[int, Tuple[int]]] = None,
|
|
733
818
|
intervals: Optional[Union[int, List[Union[int, float]]]] = None,
|
|
734
|
-
colormap: str = 'viridis', show_colorbar: bool = False
|
|
819
|
+
colormap: str = 'viridis', show_colorbar: bool = False,
|
|
820
|
+
use_sensor_data: bool = False) -> None:
|
|
735
821
|
"""
|
|
736
822
|
Colors the pumps in the water distribution network based on SCADA data
|
|
737
823
|
and the specified parameters.
|
|
@@ -769,6 +855,11 @@ class ScenarioVisualizer:
|
|
|
769
855
|
show_colorbar : `bool`, optional
|
|
770
856
|
If `True`, a colorbar will be displayed on the plot to indicate the
|
|
771
857
|
range of pump values. Default is `False`.
|
|
858
|
+
use_sensor_data : `bool`, optional
|
|
859
|
+
If `True`, instead of using raw simulation data, the data recorded
|
|
860
|
+
by the corresponding sensors in the system is used for the
|
|
861
|
+
visualization. Note: Not all components may have a sensor attached
|
|
862
|
+
and sensors may be subject to sensor faults or noise.
|
|
772
863
|
|
|
773
864
|
Raises
|
|
774
865
|
------
|
|
@@ -787,11 +878,23 @@ class ScenarioVisualizer:
|
|
|
787
878
|
self.scada_data = self.__scenario.run_simulation()
|
|
788
879
|
|
|
789
880
|
if parameter == 'efficiency':
|
|
790
|
-
|
|
881
|
+
if use_sensor_data:
|
|
882
|
+
values, self.masks[
|
|
883
|
+
'pumps'] = self.scada_data.get_data_pumps_efficiency_as_node_features()
|
|
884
|
+
else:
|
|
885
|
+
values = self.scada_data.pumps_efficiency_data_raw
|
|
791
886
|
elif parameter == 'energy_consumption':
|
|
792
|
-
|
|
887
|
+
if use_sensor_data:
|
|
888
|
+
values, self.masks[
|
|
889
|
+
'pumps'] = self.scada_data.get_data_pumps_energyconsumption_as_node_features()
|
|
890
|
+
else:
|
|
891
|
+
values = self.scada_data.pumps_energyconsumption_data_raw
|
|
793
892
|
elif parameter == 'state':
|
|
794
|
-
|
|
893
|
+
if use_sensor_data:
|
|
894
|
+
values, self.masks[
|
|
895
|
+
'pumps'] = self.scada_data.get_data_pumps_state_as_node_features()
|
|
896
|
+
else:
|
|
897
|
+
values = self.scada_data.pumps_state_data_raw
|
|
795
898
|
elif parameter == 'custom_data':
|
|
796
899
|
values = self.scada_data
|
|
797
900
|
else:
|
|
@@ -828,7 +931,8 @@ class ScenarioVisualizer:
|
|
|
828
931
|
statistic: str = 'mean',
|
|
829
932
|
pit: Optional[Union[int, Tuple[int, int]]] = None,
|
|
830
933
|
intervals: Optional[Union[int, List[Union[int, float]]]] = None,
|
|
831
|
-
colormap: str = 'viridis', show_colorbar: bool = False
|
|
934
|
+
colormap: str = 'viridis', show_colorbar: bool = False,
|
|
935
|
+
use_sensor_data: bool = False) -> None:
|
|
832
936
|
"""
|
|
833
937
|
Colors the tanks in the water distribution network based on the SCADA
|
|
834
938
|
tank volume data and the specified statistic.
|
|
@@ -863,6 +967,11 @@ class ScenarioVisualizer:
|
|
|
863
967
|
show_colorbar : `bool`, optional
|
|
864
968
|
If `True`, a colorbar will be displayed on the plot to indicate the
|
|
865
969
|
range of tank volume values. Default is `False`.
|
|
970
|
+
use_sensor_data : `bool`, optional
|
|
971
|
+
If `True`, instead of using raw simulation data, the data recorded
|
|
972
|
+
by the corresponding sensors in the system is used for the
|
|
973
|
+
visualization. Note: Not all components may have a sensor attached
|
|
974
|
+
and sensors may be subject to sensor faults or noise.
|
|
866
975
|
|
|
867
976
|
Raises
|
|
868
977
|
------
|
|
@@ -878,7 +987,11 @@ class ScenarioVisualizer:
|
|
|
878
987
|
self.scada_data = self.__scenario.run_simulation()
|
|
879
988
|
|
|
880
989
|
if isinstance(self.scada_data, ScadaData):
|
|
881
|
-
|
|
990
|
+
if use_sensor_data:
|
|
991
|
+
values, self.masks[
|
|
992
|
+
'tanks'] = self.scada_data.get_data_tanks_water_volume_as_node_features()
|
|
993
|
+
else:
|
|
994
|
+
values = self.scada_data.tanks_volume_data_raw
|
|
882
995
|
parameter = 'tank volume'
|
|
883
996
|
else:
|
|
884
997
|
values = self.scada_data
|
|
@@ -912,7 +1025,8 @@ class ScenarioVisualizer:
|
|
|
912
1025
|
statistic: str = 'mean',
|
|
913
1026
|
pit: Optional[Union[int, Tuple[int, int]]] = None,
|
|
914
1027
|
intervals: Optional[Union[int, List[Union[int, float]]]] = None,
|
|
915
|
-
colormap: str = 'viridis', show_colorbar: bool = False
|
|
1028
|
+
colormap: str = 'viridis', show_colorbar: bool = False,
|
|
1029
|
+
use_sensor_data: bool = False) -> None:
|
|
916
1030
|
"""
|
|
917
1031
|
Colors the valves in the water distribution network based on SCADA
|
|
918
1032
|
valve state data and the specified statistic.
|
|
@@ -947,6 +1061,11 @@ class ScenarioVisualizer:
|
|
|
947
1061
|
show_colorbar : `bool`, optional
|
|
948
1062
|
If `True`, a colorbar will be displayed on the plot to indicate the
|
|
949
1063
|
range of valve state values. Default is `False`.
|
|
1064
|
+
use_sensor_data : `bool`, optional
|
|
1065
|
+
If `True`, instead of using raw simulation data, the data recorded
|
|
1066
|
+
by the corresponding sensors in the system is used for the
|
|
1067
|
+
visualization. Note: Not all components may have a sensor attached
|
|
1068
|
+
and sensors may be subject to sensor faults or noise.
|
|
950
1069
|
|
|
951
1070
|
Raises
|
|
952
1071
|
------
|
|
@@ -963,7 +1082,11 @@ class ScenarioVisualizer:
|
|
|
963
1082
|
self.scada_data = self.__scenario.run_simulation()
|
|
964
1083
|
|
|
965
1084
|
if isinstance(self.scada_data, ScadaData):
|
|
966
|
-
|
|
1085
|
+
if use_sensor_data:
|
|
1086
|
+
values, self.masks[
|
|
1087
|
+
'valves'] = self.scada_data.get_data_valves_state_as_node_features()
|
|
1088
|
+
else:
|
|
1089
|
+
values = self.scada_data.valves_state_data_raw
|
|
967
1090
|
parameter = 'valve state'
|
|
968
1091
|
else:
|
|
969
1092
|
values = self.scada_data
|
|
@@ -998,8 +1121,10 @@ class ScenarioVisualizer:
|
|
|
998
1121
|
parameter: str = 'flow_rate', statistic: str = 'mean',
|
|
999
1122
|
line_widths: Tuple[int, int] = (1, 2),
|
|
1000
1123
|
pit: Optional[Union[int, Tuple[int, int]]] = None,
|
|
1124
|
+
species: str = None,
|
|
1001
1125
|
intervals: Optional[Union[int, List[Union[int, float]]]] = None,
|
|
1002
|
-
conversion: Optional[dict] = None
|
|
1126
|
+
conversion: Optional[dict] = None,
|
|
1127
|
+
use_sensor_data: bool = False) -> None:
|
|
1003
1128
|
"""
|
|
1004
1129
|
Resizes the width of the links (pipes) in the water distribution
|
|
1005
1130
|
network based on SCADA data and the specified parameters.
|
|
@@ -1029,6 +1154,9 @@ class ScenarioVisualizer:
|
|
|
1029
1154
|
representing the start and end time steps. A tuple is necessary to
|
|
1030
1155
|
process the data for the :meth:`~ScenarioVisualizer.show_animation`
|
|
1031
1156
|
method. Default is `None`.
|
|
1157
|
+
species: `str`, optional
|
|
1158
|
+
Key of species. Only necessary for parameter
|
|
1159
|
+
'bulk_species_concentration'.
|
|
1032
1160
|
intervals : `int` or `list[int]` or `list[float]`, optional
|
|
1033
1161
|
If provided, the data will be grouped into intervals. It can be an
|
|
1034
1162
|
integer specifying the number of groups or a list of boundary
|
|
@@ -1036,6 +1164,11 @@ class ScenarioVisualizer:
|
|
|
1036
1164
|
conversion : `dict`, optional
|
|
1037
1165
|
A dictionary of conversion parameters to convert SCADA data units.
|
|
1038
1166
|
Default is `None`.
|
|
1167
|
+
use_sensor_data : `bool`, optional
|
|
1168
|
+
If `True`, instead of using raw simulation data, the data recorded
|
|
1169
|
+
by the corresponding sensors in the system is used for the
|
|
1170
|
+
visualization. Note: Not all components may have a sensor attached
|
|
1171
|
+
and sensors may be subject to sensor faults or noise.
|
|
1039
1172
|
"""
|
|
1040
1173
|
sim_length = None
|
|
1041
1174
|
|
|
@@ -1062,11 +1195,13 @@ class ScenarioVisualizer:
|
|
|
1062
1195
|
break
|
|
1063
1196
|
self.pipe_parameters.add_frame(self.topology, 'edge_width',
|
|
1064
1197
|
self.scada_data, parameter,
|
|
1065
|
-
statistic, frame,
|
|
1198
|
+
statistic, frame, species,
|
|
1199
|
+
intervals, use_sensor_data)
|
|
1066
1200
|
else:
|
|
1067
1201
|
self.pipe_parameters.add_frame(self.topology, 'edge_width',
|
|
1068
1202
|
self.scada_data, parameter,
|
|
1069
|
-
statistic, pit, intervals
|
|
1203
|
+
statistic, pit, species, intervals,
|
|
1204
|
+
use_sensor_data)
|
|
1070
1205
|
self.pipe_parameters.rescale_widths(line_widths)
|
|
1071
1206
|
|
|
1072
1207
|
def hide_nodes(self) -> None:
|
|
@@ -1103,48 +1238,3 @@ class ScenarioVisualizer:
|
|
|
1103
1238
|
self.junction_parameters.add_attributes(
|
|
1104
1239
|
{'linewidths': 1, 'edgecolors': node_edges})
|
|
1105
1240
|
self.pipe_parameters.add_attributes({'style': pipe_style})
|
|
1106
|
-
|
|
1107
|
-
@deprecated(reason="This function will be removed in feature versions, "
|
|
1108
|
-
"please use show_plot() instead.")
|
|
1109
|
-
def plot_topology(self, show_sensor_config: bool = False,
|
|
1110
|
-
export_to_file: str = None) -> None:
|
|
1111
|
-
"""
|
|
1112
|
-
Plots the topology of the water distribution network in the given
|
|
1113
|
-
scenario.
|
|
1114
|
-
|
|
1115
|
-
Parameters
|
|
1116
|
-
----------
|
|
1117
|
-
show_sensor_config : `bool`, optional
|
|
1118
|
-
Indicates whether the sensor configuration should be shown as well.
|
|
1119
|
-
|
|
1120
|
-
The default is False.
|
|
1121
|
-
export_to_file : `str`, optional
|
|
1122
|
-
Path to the file where the visualization will be stored.
|
|
1123
|
-
If None, visualization will be just shown but NOT be stored
|
|
1124
|
-
anywhere.
|
|
1125
|
-
|
|
1126
|
-
The default is None.
|
|
1127
|
-
"""
|
|
1128
|
-
_ = plt.figure()
|
|
1129
|
-
|
|
1130
|
-
highlighted_links = None
|
|
1131
|
-
highlighted_nodes = None
|
|
1132
|
-
if show_sensor_config is True:
|
|
1133
|
-
highlighted_nodes = []
|
|
1134
|
-
highlighted_links = []
|
|
1135
|
-
|
|
1136
|
-
sensor_config = self.__scenario.sensor_config
|
|
1137
|
-
highlighted_nodes += (sensor_config.pressure_sensors
|
|
1138
|
-
+ sensor_config.demand_sensors
|
|
1139
|
-
+ sensor_config.quality_node_sensors)
|
|
1140
|
-
highlighted_links += (sensor_config.flow_sensors
|
|
1141
|
-
+ sensor_config.quality_link_sensors)
|
|
1142
|
-
|
|
1143
|
-
self.__scenario.epanet_api.plot(highlightlink=highlighted_links,
|
|
1144
|
-
highlightnode=highlighted_nodes,
|
|
1145
|
-
figure=False)
|
|
1146
|
-
|
|
1147
|
-
if export_to_file is not None:
|
|
1148
|
-
plt.savefig(export_to_file, transparent=True, bbox_inches='tight')
|
|
1149
|
-
else:
|
|
1150
|
-
plt.show()
|