epyt-flow 0.7.3__py3-none-any.whl → 0.8.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.
@@ -61,6 +61,18 @@ class ScenarioSimulator():
61
61
  ----------
62
62
  epanet_api : `epyt.epanet`
63
63
  API to EPANET and EPANET-MSX.
64
+ _model_uncertainty : :class:`~epyt_flow.uncertainty.model_uncertainty.ModelUncertainty`, protected
65
+ Model uncertainty.
66
+ _sensor_noise : :class:`~epyt_flow.uncertainty.sensor_noise.SensorNoise`, protected
67
+ Sensor noise.
68
+ _sensor_config : :class:`~epyt_flow.simulation.sensor_config.SensorConfig`, protected
69
+ Sensor configuration.
70
+ _controls : list[:class:`~epyt_flow.simulation.scada.advanced_control.AdvancedControlModule`], protected
71
+ List of custom control modules.
72
+ _system_events : list[:class:`~epyt_flow.simulation.events.system_event.SystemEvent`], protected
73
+ Lsit of system events such as leakages.
74
+ _sensor_reading_events : list[:class:`~epyt_flow.simulation.events.sensor_reading_event.SensorReadingEvent`], protected
75
+ List of sensor reading events such as sensor override attacks.
64
76
  """
65
77
 
66
78
  def __init__(self, f_inp_in: str = None, f_msx_in: str = None,
@@ -69,6 +81,8 @@ class ScenarioSimulator():
69
81
  raise ValueError("'f_inp_in' must be set if 'f_msx_in' is set.")
70
82
  if f_inp_in is None and scenario_config is None:
71
83
  raise ValueError("Either 'f_inp_in' or 'scenario_config' must be set.")
84
+ if scenario_config is not None and f_inp_in is not None:
85
+ raise ValueError("'f_inp_in' or 'scenario_config' can not be used at the same time")
72
86
  if f_inp_in is not None:
73
87
  if not isinstance(f_inp_in, str):
74
88
  raise TypeError("'f_inp_in' must be an instance of 'str' but not of " +
@@ -88,12 +102,12 @@ class ScenarioSimulator():
88
102
 
89
103
  self.__f_inp_in = f_inp_in if scenario_config is None else scenario_config.f_inp_in
90
104
  self.__f_msx_in = f_msx_in if scenario_config is None else scenario_config.f_msx_in
91
- self.__model_uncertainty = ModelUncertainty()
92
- self.__sensor_noise = None
93
- self.__sensor_config = None
94
- self.__controls = []
95
- self.__system_events = []
96
- self.__sensor_reading_events = []
105
+ self._model_uncertainty = ModelUncertainty()
106
+ self._sensor_noise = None
107
+ self._sensor_config = None
108
+ self._controls = []
109
+ self._system_events = []
110
+ self._sensor_reading_events = []
97
111
  self.__running_simulation = False
98
112
 
99
113
  custom_epanet_lib = None
@@ -140,14 +154,11 @@ class ScenarioSimulator():
140
154
  if self.__f_msx_in is not None:
141
155
  if not __file_exists(self.__f_msx_in):
142
156
  my_f_msx_in = self.__f_msx_in
143
- self.__my_f_msx_in = None
144
157
  else:
145
158
  my_f_msx_in = os.path.join(tmp_folder_path, pathlib.Path(self.__f_msx_in).name)
146
159
  shutil.copyfile(self.__f_msx_in, my_f_msx_in)
147
- self.__my_f_msx_in = my_f_msx_in
148
160
  else:
149
161
  my_f_msx_in = None
150
- self.__my_f_msx_in = None
151
162
 
152
163
  self.epanet_api = epanet(my_f_inp_in, ph=self.__f_msx_in is None,
153
164
  customlib=custom_epanet_lib, loadfile=True,
@@ -157,14 +168,14 @@ class ScenarioSimulator():
157
168
  if self.__f_msx_in is not None:
158
169
  self.epanet_api.loadMSXFile(my_f_msx_in, customMSXlib=custom_epanetmsx_lib)
159
170
 
160
- self.__sensor_config = self.__get_empty_sensor_config()
171
+ self._sensor_config = self._get_empty_sensor_config()
161
172
  if scenario_config is not None:
162
173
  if scenario_config.general_params is not None:
163
174
  self.set_general_parameters(**scenario_config.general_params)
164
175
 
165
- self.__model_uncertainty = scenario_config.model_uncertainty
166
- self.__sensor_noise = scenario_config.sensor_noise
167
- self.__sensor_config = scenario_config.sensor_config
176
+ self._model_uncertainty = scenario_config.model_uncertainty
177
+ self._sensor_noise = scenario_config.sensor_noise
178
+ self._sensor_config = scenario_config.sensor_config
168
179
 
169
180
  for control in scenario_config.controls:
170
181
  self.add_control(control)
@@ -173,10 +184,10 @@ class ScenarioSimulator():
173
184
  for event in scenario_config.sensor_reading_events:
174
185
  self.add_sensor_reading_event(event)
175
186
 
176
- def __get_empty_sensor_config(self, node_id_to_idx: dict = None, link_id_to_idx: dict = None,
177
- valve_id_to_idx: dict = None, pump_id_to_idx: dict = None,
178
- tank_id_to_idx: dict = None, bulkspecies_id_to_idx: dict = None,
179
- surfacespecies_id_to_idx: dict = None) -> SensorConfig:
187
+ def _get_empty_sensor_config(self, node_id_to_idx: dict = None, link_id_to_idx: dict = None,
188
+ valve_id_to_idx: dict = None, pump_id_to_idx: dict = None,
189
+ tank_id_to_idx: dict = None, bulkspecies_id_to_idx: dict = None,
190
+ surfacespecies_id_to_idx: dict = None) -> SensorConfig:
180
191
  flow_unit = self.epanet_api.api.ENgetflowunits()
181
192
  quality_unit = qualityunit_to_id(self.epanet_api.getQualityInfo().QualityChemUnits)
182
193
  bulk_species = []
@@ -228,7 +239,7 @@ class ScenarioSimulator():
228
239
  `str`
229
240
  Path to the .inp file.
230
241
  """
231
- self.__adapt_to_network_changes()
242
+ self._adapt_to_network_changes()
232
243
 
233
244
  return self.__f_inp_in
234
245
 
@@ -242,7 +253,7 @@ class ScenarioSimulator():
242
253
  `str`
243
254
  Path to the .msx file.
244
255
  """
245
- self.__adapt_to_network_changes()
256
+ self._adapt_to_network_changes()
246
257
 
247
258
  return self.__f_msx_in
248
259
 
@@ -256,13 +267,13 @@ class ScenarioSimulator():
256
267
  :class:`~epyt_flow.uncertainty.model_uncertainty.ModelUncertainty`
257
268
  Model uncertainty.
258
269
  """
259
- self.__adapt_to_network_changes()
270
+ self._adapt_to_network_changes()
260
271
 
261
- return deepcopy(self.__model_uncertainty)
272
+ return deepcopy(self._model_uncertainty)
262
273
 
263
274
  @model_uncertainty.setter
264
275
  def model_uncertainty(self, model_uncertainty: ModelUncertainty) -> None:
265
- self.__adapt_to_network_changes()
276
+ self._adapt_to_network_changes()
266
277
 
267
278
  self.set_model_uncertainty(model_uncertainty)
268
279
 
@@ -276,13 +287,13 @@ class ScenarioSimulator():
276
287
  :class:`~epyt_flow.uncertainty.sensor_noise.SensorNoise`
277
288
  Sensor noise.
278
289
  """
279
- self.__adapt_to_network_changes()
290
+ self._adapt_to_network_changes()
280
291
 
281
- return deepcopy(self.__sensor_noise)
292
+ return deepcopy(self._sensor_noise)
282
293
 
283
294
  @sensor_noise.setter
284
295
  def sensor_noise(self, sensor_noise: SensorNoise) -> None:
285
- self.__adapt_to_network_changes()
296
+ self._adapt_to_network_changes()
286
297
 
287
298
  self.set_sensor_noise(sensor_noise)
288
299
 
@@ -296,9 +307,9 @@ class ScenarioSimulator():
296
307
  :class:`~epyt_flow.simulation.sensor_config.SensorConfig`
297
308
  Sensor configuration.
298
309
  """
299
- self.__adapt_to_network_changes()
310
+ self._adapt_to_network_changes()
300
311
 
301
- return deepcopy(self.__sensor_config)
312
+ return deepcopy(self._sensor_config)
302
313
 
303
314
  @sensor_config.setter
304
315
  def sensor_config(self, sensor_config: SensorConfig) -> None:
@@ -309,7 +320,7 @@ class ScenarioSimulator():
309
320
 
310
321
  sensor_config.validate(self.epanet_api)
311
322
 
312
- self.__sensor_config = sensor_config
323
+ self._sensor_config = sensor_config
313
324
 
314
325
  @property
315
326
  def controls(self) -> list[AdvancedControlModule]:
@@ -321,9 +332,9 @@ class ScenarioSimulator():
321
332
  list[:class:`~epyt_flow.simulation.scada.advanced_control.AdvancedControlModule`]
322
333
  All control modules.
323
334
  """
324
- self.__adapt_to_network_changes()
335
+ self._adapt_to_network_changes()
325
336
 
326
- return deepcopy(self.__controls)
337
+ return deepcopy(self._controls)
327
338
 
328
339
  @property
329
340
  def leakages(self) -> list[Leakage]:
@@ -335,9 +346,9 @@ class ScenarioSimulator():
335
346
  list[:class:`~epyt_flow.simulation.events.leakages.Leakage`]
336
347
  All leakages.
337
348
  """
338
- self.__adapt_to_network_changes()
349
+ self._adapt_to_network_changes()
339
350
 
340
- return deepcopy(list(filter(lambda e: isinstance(e, Leakage), self.__system_events)))
351
+ return deepcopy(list(filter(lambda e: isinstance(e, Leakage), self._system_events)))
341
352
 
342
353
  @property
343
354
  def actuator_events(self) -> list[ActuatorEvent]:
@@ -349,9 +360,9 @@ class ScenarioSimulator():
349
360
  list[:class:`~epyt_flow.simulation.events.actuator_event.ActuatorEvent`]
350
361
  All actuator events.
351
362
  """
352
- self.__adapt_to_network_changes()
363
+ self._adapt_to_network_changes()
353
364
 
354
- return deepcopy(list(filter(lambda e: isinstance(e, ActuatorEvent), self.__system_events)))
365
+ return deepcopy(list(filter(lambda e: isinstance(e, ActuatorEvent), self._system_events)))
355
366
 
356
367
  @property
357
368
  def system_events(self) -> list[SystemEvent]:
@@ -363,9 +374,9 @@ class ScenarioSimulator():
363
374
  list[:class:`~epyt_flow.simulation.events.system_event.SystemEvent`]
364
375
  All system events.
365
376
  """
366
- self.__adapt_to_network_changes()
377
+ self._adapt_to_network_changes()
367
378
 
368
- return deepcopy(self.__system_events)
379
+ return deepcopy(self._system_events)
369
380
 
370
381
  @property
371
382
  def sensor_faults(self) -> list[SensorFault]:
@@ -377,10 +388,10 @@ class ScenarioSimulator():
377
388
  list[:class:`~epyt_flow.simulation.events.sensor_faults.SensorFault`]
378
389
  All sensor faults.
379
390
  """
380
- self.__adapt_to_network_changes()
391
+ self._adapt_to_network_changes()
381
392
 
382
393
  return deepcopy(list(filter(lambda e: isinstance(e, SensorFault),
383
- self.__sensor_reading_events)))
394
+ self._sensor_reading_events)))
384
395
 
385
396
  @property
386
397
  def sensor_reading_attacks(self) -> list[SensorReadingAttack]:
@@ -392,10 +403,10 @@ class ScenarioSimulator():
392
403
  list[:class:`~epyt_flow.simulation.events.sensor_reading_attacks.SensorReadingAttack`]
393
404
  All sensor reading attacks.
394
405
  """
395
- self.__adapt_to_network_changes()
406
+ self._adapt_to_network_changes()
396
407
 
397
408
  return deepcopy(list(filter(lambda e: isinstance(e, SensorReadingAttack)),
398
- self.__sensor_reading_events))
409
+ self._sensor_reading_events))
399
410
 
400
411
  @property
401
412
  def sensor_reading_events(self) -> list[SensorReadingEvent]:
@@ -407,11 +418,11 @@ class ScenarioSimulator():
407
418
  list[:class:`~epyt_flow.simulation.events.sensor_reading_event.SensorReadingEvent`]
408
419
  All sensor reading events.
409
420
  """
410
- self.__adapt_to_network_changes()
421
+ self._adapt_to_network_changes()
411
422
 
412
- return deepcopy(self.__sensor_reading_events)
423
+ return deepcopy(self._sensor_reading_events)
413
424
 
414
- def __adapt_to_network_changes(self):
425
+ def _adapt_to_network_changes(self):
415
426
  nodes = self.epanet_api.getNodeNameID()
416
427
  links = self.epanet_api.getLinkNameID()
417
428
 
@@ -424,26 +435,26 @@ class ScenarioSimulator():
424
435
  surfacespecies_id_to_idx = None
425
436
 
426
437
  # Adapt sensor configuration to potential cahnges in the network's topology
427
- new_sensor_config = self.__get_empty_sensor_config(node_id_to_idx, link_id_to_idx,
428
- valve_id_to_idx, pump_id_to_idx,
429
- tank_id_to_idx, bulkspecies_id_to_idx,
430
- surfacespecies_id_to_idx)
431
- new_sensor_config.pressure_sensors = self.__sensor_config.pressure_sensors
432
- new_sensor_config.flow_sensors = self.__sensor_config.flow_sensors
433
- new_sensor_config.demand_sensors = self.__sensor_config.demand_sensors
434
- new_sensor_config.quality_node_sensors = self.__sensor_config.quality_node_sensors
435
- new_sensor_config.quality_link_sensors = self.__sensor_config.quality_link_sensors
436
- new_sensor_config.pump_state_sensors = self.__sensor_config.pump_state_sensors
437
- new_sensor_config.pump_efficiency_sensors = self.__sensor_config.pump_efficiency_sensors
438
- new_sensor_config.pump_energyconsumption_sensors = self.__sensor_config.\
438
+ new_sensor_config = self._get_empty_sensor_config(node_id_to_idx, link_id_to_idx,
439
+ valve_id_to_idx, pump_id_to_idx,
440
+ tank_id_to_idx, bulkspecies_id_to_idx,
441
+ surfacespecies_id_to_idx)
442
+ new_sensor_config.pressure_sensors = self._sensor_config.pressure_sensors
443
+ new_sensor_config.flow_sensors = self._sensor_config.flow_sensors
444
+ new_sensor_config.demand_sensors = self._sensor_config.demand_sensors
445
+ new_sensor_config.quality_node_sensors = self._sensor_config.quality_node_sensors
446
+ new_sensor_config.quality_link_sensors = self._sensor_config.quality_link_sensors
447
+ new_sensor_config.pump_state_sensors = self._sensor_config.pump_state_sensors
448
+ new_sensor_config.pump_efficiency_sensors = self._sensor_config.pump_efficiency_sensors
449
+ new_sensor_config.pump_energyconsumption_sensors = self._sensor_config.\
439
450
  pump_energyconsumption_sensors
440
- new_sensor_config.valve_state_sensors = self.__sensor_config.valve_state_sensors
441
- new_sensor_config.tank_volume_sensors = self.__sensor_config.tank_volume_sensors
442
- new_sensor_config.bulk_species_node_sensors = self.__sensor_config.bulk_species_node_sensors
443
- new_sensor_config.bulk_species_link_sensors = self.__sensor_config.bulk_species_link_sensors
444
- new_sensor_config.surface_species_sensors = self.__sensor_config.surface_species_sensors
451
+ new_sensor_config.valve_state_sensors = self._sensor_config.valve_state_sensors
452
+ new_sensor_config.tank_volume_sensors = self._sensor_config.tank_volume_sensors
453
+ new_sensor_config.bulk_species_node_sensors = self._sensor_config.bulk_species_node_sensors
454
+ new_sensor_config.bulk_species_link_sensors = self._sensor_config.bulk_species_link_sensors
455
+ new_sensor_config.surface_species_sensors = self._sensor_config.surface_species_sensors
445
456
 
446
- self.__sensor_config = new_sensor_config
457
+ self._sensor_config = new_sensor_config
447
458
 
448
459
  def close(self):
449
460
  """
@@ -542,27 +553,27 @@ class ScenarioSimulator():
542
553
  links = []
543
554
 
544
555
  # Parse sensor config
545
- pressure_sensors = self.__sensor_config.pressure_sensors
556
+ pressure_sensors = self._sensor_config.pressure_sensors
546
557
  if len(pressure_sensors) != 0:
547
558
  report_desc += "Pressure YES\n"
548
559
  nodes += pressure_sensors
549
560
 
550
- flow_sensors = self.__sensor_config.flow_sensors
561
+ flow_sensors = self._sensor_config.flow_sensors
551
562
  if len(flow_sensors) != 0:
552
563
  report_desc += "Flow YES\n"
553
564
  links += flow_sensors
554
565
 
555
- demand_sensors = self.__sensor_config.demand_sensors
566
+ demand_sensors = self._sensor_config.demand_sensors
556
567
  if len(demand_sensors) != 0:
557
568
  report_desc += "Demand YES\n"
558
569
  nodes += demand_sensors
559
570
 
560
- node_quality_sensors = self.__sensor_config.quality_node_sensors
571
+ node_quality_sensors = self._sensor_config.quality_node_sensors
561
572
  if len(node_quality_sensors) != 0:
562
573
  report_desc += "Quality YES\n"
563
574
  nodes += node_quality_sensors
564
575
 
565
- link_quality_sensors = self.__sensor_config.quality_link_sensors
576
+ link_quality_sensors = self._sensor_config.quality_link_sensors
566
577
  if len(link_quality_sensors) != 0:
567
578
  if len(node_quality_sensors) == 0:
568
579
  report_desc += "Quality YES\n"
@@ -573,12 +584,12 @@ class ScenarioSimulator():
573
584
  links = list(set(links))
574
585
 
575
586
  if len(nodes) != 0:
576
- if set(nodes) == set(self.__sensor_config.nodes):
587
+ if set(nodes) == set(self._sensor_config.nodes):
577
588
  nodes = ["ALL"]
578
589
  report_desc += f"NODES {' '.join(nodes)}\n"
579
590
 
580
591
  if len(links) != 0:
581
- if set(links) == set(self.__sensor_config.links):
592
+ if set(links) == set(self._sensor_config.links):
582
593
  links = ["ALL"]
583
594
  report_desc += f"LINKS {' '.join(links)}\n"
584
595
 
@@ -595,17 +606,17 @@ class ScenarioSimulator():
595
606
  links = []
596
607
 
597
608
  # Parse sensor config
598
- bulk_species_node_sensors = self.__sensor_config.bulk_species_node_sensors
609
+ bulk_species_node_sensors = self._sensor_config.bulk_species_node_sensors
599
610
  for bulk_species_id in bulk_species_node_sensors.keys():
600
611
  species.append(bulk_species_id)
601
612
  nodes += bulk_species_node_sensors[bulk_species_id]
602
613
 
603
- bulk_species_link_sensors = self.__sensor_config.bulk_species_link_sensors
614
+ bulk_species_link_sensors = self._sensor_config.bulk_species_link_sensors
604
615
  for bulk_species_id in bulk_species_link_sensors.keys():
605
616
  species.append(bulk_species_id)
606
617
  links += bulk_species_link_sensors[bulk_species_id]
607
618
 
608
- surface_species_link_sensors = self.__sensor_config.surface_species_sensors
619
+ surface_species_link_sensors = self._sensor_config.surface_species_sensors
609
620
  for surface_species_id in surface_species_link_sensors.keys():
610
621
  species.append(surface_species_id)
611
622
  links += surface_species_link_sensors[surface_species_id]
@@ -616,12 +627,12 @@ class ScenarioSimulator():
616
627
 
617
628
  # Create REPORT section
618
629
  if len(nodes) != 0:
619
- if set(nodes) == set(self.__sensor_config.nodes):
630
+ if set(nodes) == set(self._sensor_config.nodes):
620
631
  nodes = ["ALL"]
621
632
  report_desc += f"NODES {' '.join(nodes)}\n"
622
633
 
623
634
  if len(links) != 0:
624
- if set(links) == set(self.__sensor_config.links):
635
+ if set(links) == set(self._sensor_config.links):
625
636
  links = ["ALL"]
626
637
  report_desc += f"LINKS {' '.join(links)}\n"
627
638
 
@@ -767,7 +778,7 @@ class ScenarioSimulator():
767
778
  :class:`~epyt_flow.simulation.scenario_config.ScenarioConfig`
768
779
  Complete scenario specification.
769
780
  """
770
- self.__adapt_to_network_changes()
781
+ self._adapt_to_network_changes()
771
782
 
772
783
  general_params = {"hydraulic_time_step": self.get_hydraulic_time_step(),
773
784
  "quality_time_step": self.get_quality_time_step(),
@@ -795,7 +806,7 @@ class ScenarioSimulator():
795
806
  `float`
796
807
  Estimated memory consumption in MB.
797
808
  """
798
- self.__adapt_to_network_changes()
809
+ self._adapt_to_network_changes()
799
810
 
800
811
  n_time_steps = int(self.epanet_api.getTimeSimulationDuration() /
801
812
  self.epanet_api.getTimeReportingStep())
@@ -819,7 +830,7 @@ class ScenarioSimulator():
819
830
  :class:`~epyt_flow.topology.NetworkTopology`
820
831
  Topology of this WDN as a graph.
821
832
  """
822
- self.__adapt_to_network_changes()
833
+ self._adapt_to_network_changes()
823
834
 
824
835
  # Collect information about the topology of the water distribution network
825
836
  nodes_id = self.epanet_api.getNodeNameID()
@@ -883,6 +894,22 @@ class ScenarioSimulator():
883
894
  return NetworkTopology(f_inp=self.f_inp_in, nodes=nodes, links=links, pumps=pumps,
884
895
  valves=valves, units=self.get_units_category())
885
896
 
897
+ def plot_topology(self, export_to_file: str = None) -> None:
898
+ """
899
+ Plots the topology of the water distribution network.
900
+
901
+ Parameters
902
+ ----------
903
+ export_to_file : `str`, optional
904
+ Path to the file where the visualization will be stored.
905
+ If None, visualization will be just shown but NOT be stored
906
+ anywhere.
907
+
908
+ The default is None.
909
+ """
910
+ from .scenario_visualizer import ScenarioVisualizer
911
+ ScenarioVisualizer(self).show_plot(export_to_file)
912
+
886
913
  def randomize_demands(self) -> None:
887
914
  """
888
915
  Randomizes all demand patterns.
@@ -890,7 +917,7 @@ class ScenarioSimulator():
890
917
  if self.__running_simulation is True:
891
918
  raise RuntimeError("Can not change general parameters when simulation is running.")
892
919
 
893
- self.__adapt_to_network_changes()
920
+ self._adapt_to_network_changes()
894
921
 
895
922
  # Get all demand patterns
896
923
  demand_patterns_idx = self.epanet_api.getNodeDemandPatternIndex()
@@ -927,9 +954,9 @@ class ScenarioSimulator():
927
954
  demand_pattern : `numpy.ndarray`
928
955
  Demand pattern over time. Final demand over time = base_demand * demand_pattern
929
956
  """
930
- self.__adapt_to_network_changes()
957
+ self._adapt_to_network_changes()
931
958
 
932
- if node_id not in self.__sensor_config.nodes:
959
+ if node_id not in self._sensor_config.nodes:
933
960
  raise ValueError(f"Unknown node '{node_id}'")
934
961
  if not isinstance(base_demand, float):
935
962
  raise TypeError("'base_demand' must be an instance of 'float' " +
@@ -958,14 +985,14 @@ class ScenarioSimulator():
958
985
  control : :class:`~epyt_flow.simulation.scada.advanced_control.AdvancedControlModule`
959
986
  Control module.
960
987
  """
961
- self.__adapt_to_network_changes()
988
+ self._adapt_to_network_changes()
962
989
 
963
990
  if not isinstance(control, AdvancedControlModule):
964
991
  raise TypeError("'control' must be an instance of " +
965
992
  "'epyt_flow.simulation.scada.AdvancedControlModule' not of " +
966
993
  f"'{type(control)}'")
967
994
 
968
- self.__controls.append(control)
995
+ self._controls.append(control)
969
996
 
970
997
  def add_leakage(self, leakage_event: Leakage) -> None:
971
998
  """
@@ -976,7 +1003,7 @@ class ScenarioSimulator():
976
1003
  event : :class:`~epyt_flow.simulation.events.leakages.Leakage`
977
1004
  Leakage.
978
1005
  """
979
- self.__adapt_to_network_changes()
1006
+ self._adapt_to_network_changes()
980
1007
 
981
1008
  if not isinstance(leakage_event, Leakage):
982
1009
  raise TypeError("'leakage_event' must be an instance of " +
@@ -994,7 +1021,7 @@ class ScenarioSimulator():
994
1021
  event : :class:`~epyt_flow.simulation.events.actuator_events.ActuatorEvent`
995
1022
  Actuator event.
996
1023
  """
997
- self.__adapt_to_network_changes()
1024
+ self._adapt_to_network_changes()
998
1025
 
999
1026
  if not isinstance(event, ActuatorEvent):
1000
1027
  raise TypeError("'event' must be an instance of " +
@@ -1015,7 +1042,7 @@ class ScenarioSimulator():
1015
1042
  if self.__running_simulation is True:
1016
1043
  raise RuntimeError("Can not add events when simulation is running.")
1017
1044
 
1018
- self.__adapt_to_network_changes()
1045
+ self._adapt_to_network_changes()
1019
1046
 
1020
1047
  if not isinstance(event, SystemEvent):
1021
1048
  raise TypeError("'event' must be an instance of " +
@@ -1023,7 +1050,7 @@ class ScenarioSimulator():
1023
1050
 
1024
1051
  event.init(self.epanet_api)
1025
1052
 
1026
- self.__system_events.append(event)
1053
+ self._system_events.append(event)
1027
1054
 
1028
1055
  def add_sensor_fault(self, sensor_fault_event: SensorFault) -> None:
1029
1056
  """
@@ -1037,16 +1064,16 @@ class ScenarioSimulator():
1037
1064
  if self.__running_simulation is True:
1038
1065
  raise RuntimeError("Can not add events when simulation is running.")
1039
1066
 
1040
- self.__adapt_to_network_changes()
1067
+ self._adapt_to_network_changes()
1041
1068
 
1042
- sensor_fault_event.validate(self.__sensor_config)
1069
+ sensor_fault_event.validate(self._sensor_config)
1043
1070
 
1044
1071
  if not isinstance(sensor_fault_event, SensorFault):
1045
1072
  raise TypeError("'sensor_fault_event' must be an instance of " +
1046
1073
  "'epyt_flow.simulation.events.SensorFault' not of " +
1047
1074
  f"'{type(sensor_fault_event)}'")
1048
1075
 
1049
- self.__sensor_reading_events.append(sensor_fault_event)
1076
+ self._sensor_reading_events.append(sensor_fault_event)
1050
1077
 
1051
1078
  def add_sensor_reading_attack(self, sensor_reading_attack: SensorReadingAttack) -> None:
1052
1079
  """
@@ -1060,16 +1087,16 @@ class ScenarioSimulator():
1060
1087
  if self.__running_simulation is True:
1061
1088
  raise RuntimeError("Can not add events when simulation is running.")
1062
1089
 
1063
- self.__adapt_to_network_changes()
1090
+ self._adapt_to_network_changes()
1064
1091
 
1065
- sensor_reading_attack.validate(self.__sensor_config)
1092
+ sensor_reading_attack.validate(self._sensor_config)
1066
1093
 
1067
1094
  if not isinstance(sensor_reading_attack, SensorReadingAttack):
1068
1095
  raise TypeError("'sensor_reading_attack' must be an instance of " +
1069
1096
  "'epyt_flow.simulation.events.SensorReadingAttack' not of " +
1070
1097
  f"'{type(sensor_reading_attack)}'")
1071
1098
 
1072
- self.__sensor_reading_events.append(sensor_reading_attack)
1099
+ self._sensor_reading_events.append(sensor_reading_attack)
1073
1100
 
1074
1101
  def add_sensor_reading_event(self, event: SensorReadingEvent) -> None:
1075
1102
  """
@@ -1083,16 +1110,16 @@ class ScenarioSimulator():
1083
1110
  if self.__running_simulation is True:
1084
1111
  raise RuntimeError("Can not add events when simulation is running.")
1085
1112
 
1086
- self.__adapt_to_network_changes()
1113
+ self._adapt_to_network_changes()
1087
1114
 
1088
- event.validate(self.__sensor_config)
1115
+ event.validate(self._sensor_config)
1089
1116
 
1090
1117
  if not isinstance(event, SensorReadingEvent):
1091
1118
  raise TypeError("'event' must be an instance of " +
1092
1119
  "'epyt_flow.simulation.events.SensorReadingEvent' not of " +
1093
1120
  f"'{type(event)}'")
1094
1121
 
1095
- self.__sensor_reading_events.append(event)
1122
+ self._sensor_reading_events.append(event)
1096
1123
 
1097
1124
  def set_sensors(self, sensor_type: int, sensor_locations: Union[list[str], dict]) -> None:
1098
1125
  """
@@ -1118,38 +1145,38 @@ class ScenarioSimulator():
1118
1145
  Locations (IDs) of sensors either as a list or as a dict in the case of
1119
1146
  bulk and surface species.
1120
1147
  """
1121
- self.__adapt_to_network_changes()
1148
+ self._adapt_to_network_changes()
1122
1149
 
1123
1150
  if sensor_type == SENSOR_TYPE_NODE_PRESSURE:
1124
- self.__sensor_config.pressure_sensors = sensor_locations
1151
+ self._sensor_config.pressure_sensors = sensor_locations
1125
1152
  elif sensor_type == SENSOR_TYPE_LINK_FLOW:
1126
- self.__sensor_config.flow_sensors = sensor_locations
1153
+ self._sensor_config.flow_sensors = sensor_locations
1127
1154
  elif sensor_type == SENSOR_TYPE_NODE_DEMAND:
1128
- self.__sensor_config.demand_sensors = sensor_locations
1155
+ self._sensor_config.demand_sensors = sensor_locations
1129
1156
  elif sensor_type == SENSOR_TYPE_NODE_QUALITY:
1130
- self.__sensor_config.quality_node_sensors = sensor_locations
1157
+ self._sensor_config.quality_node_sensors = sensor_locations
1131
1158
  elif sensor_type == SENSOR_TYPE_LINK_QUALITY:
1132
- self.__sensor_config.quality_link_sensors = sensor_locations
1159
+ self._sensor_config.quality_link_sensors = sensor_locations
1133
1160
  elif sensor_type == SENSOR_TYPE_VALVE_STATE:
1134
- self.__sensor_config.valve_state_sensors = sensor_locations
1161
+ self._sensor_config.valve_state_sensors = sensor_locations
1135
1162
  elif sensor_type == SENSOR_TYPE_PUMP_STATE:
1136
- self.__sensor_config.pump_state_sensors = sensor_locations
1163
+ self._sensor_config.pump_state_sensors = sensor_locations
1137
1164
  elif sensor_type == SENSOR_TYPE_PUMP_EFFICIENCY:
1138
- self.__sensor_config.pump_efficiency_sensors = sensor_locations
1165
+ self._sensor_config.pump_efficiency_sensors = sensor_locations
1139
1166
  elif sensor_type == SENSOR_TYPE_PUMP_ENERGYCONSUMPTION:
1140
- self.__sensor_config.pump_energyconsumption_sensors = sensor_locations
1167
+ self._sensor_config.pump_energyconsumption_sensors = sensor_locations
1141
1168
  elif sensor_type == SENSOR_TYPE_TANK_VOLUME:
1142
- self.__sensor_config.tank_volume_sensors = sensor_locations
1169
+ self._sensor_config.tank_volume_sensors = sensor_locations
1143
1170
  elif sensor_type == SENSOR_TYPE_NODE_BULK_SPECIES:
1144
- self.__sensor_config.bulk_species_node_sensors = sensor_locations
1171
+ self._sensor_config.bulk_species_node_sensors = sensor_locations
1145
1172
  elif sensor_type == SENSOR_TYPE_LINK_BULK_SPECIES:
1146
- self.__sensor_config.bulk_species_link_sensors = sensor_locations
1173
+ self._sensor_config.bulk_species_link_sensors = sensor_locations
1147
1174
  elif sensor_type == SENSOR_TYPE_SURFACE_SPECIES:
1148
- self.__sensor_config.surface_species_sensors = sensor_locations
1175
+ self._sensor_config.surface_species_sensors = sensor_locations
1149
1176
  else:
1150
1177
  raise ValueError(f"Unknown sensor type '{sensor_type}'")
1151
1178
 
1152
- self.__sensor_config.validate(self.epanet_api)
1179
+ self._sensor_config.validate(self.epanet_api)
1153
1180
 
1154
1181
  def set_pressure_sensors(self, sensor_locations: list[str]) -> None:
1155
1182
  """
@@ -1176,7 +1203,7 @@ class ScenarioSimulator():
1176
1203
  if junctions_only is True:
1177
1204
  self.set_pressure_sensors(self.epanet_api.getNodeJunctionNameID())
1178
1205
  else:
1179
- self.set_pressure_sensors(self.__sensor_config.nodes)
1206
+ self.set_pressure_sensors(self._sensor_config.nodes)
1180
1207
 
1181
1208
  def set_flow_sensors(self, sensor_locations: list[str]) -> None:
1182
1209
  """
@@ -1193,7 +1220,7 @@ class ScenarioSimulator():
1193
1220
  """
1194
1221
  Places a flow sensors at every link/pipe in the network.
1195
1222
  """
1196
- self.set_flow_sensors(self.__sensor_config.links)
1223
+ self.set_flow_sensors(self._sensor_config.links)
1197
1224
 
1198
1225
  def set_demand_sensors(self, sensor_locations: list[str]) -> None:
1199
1226
  """
@@ -1210,7 +1237,7 @@ class ScenarioSimulator():
1210
1237
  """
1211
1238
  Places a demand sensor at every node in the network.
1212
1239
  """
1213
- self.set_demand_sensors(self.__sensor_config.nodes)
1240
+ self.set_demand_sensors(self._sensor_config.nodes)
1214
1241
 
1215
1242
  def set_node_quality_sensors(self, sensor_locations: list[str]) -> None:
1216
1243
  """
@@ -1228,7 +1255,7 @@ class ScenarioSimulator():
1228
1255
  """
1229
1256
  Places a water quality sensor at every node in the network.
1230
1257
  """
1231
- self.set_node_quality_sensors(self.__sensor_config.nodes)
1258
+ self.set_node_quality_sensors(self._sensor_config.nodes)
1232
1259
 
1233
1260
  def set_link_quality_sensors(self, sensor_locations: list[str]) -> None:
1234
1261
  """
@@ -1246,7 +1273,7 @@ class ScenarioSimulator():
1246
1273
  """
1247
1274
  Places a water quality sensor at every link/pipe in the network.
1248
1275
  """
1249
- self.set_link_quality_sensors(self.__sensor_config.links)
1276
+ self.set_link_quality_sensors(self._sensor_config.links)
1250
1277
 
1251
1278
  def set_valve_sensors(self, sensor_locations: list[str]) -> None:
1252
1279
  """
@@ -1263,10 +1290,10 @@ class ScenarioSimulator():
1263
1290
  """
1264
1291
  Places a valve state sensor at every valve in the network.
1265
1292
  """
1266
- if len(self.__sensor_config.valves) == 0:
1293
+ if len(self._sensor_config.valves) == 0:
1267
1294
  warnings.warn("Network does not contain any valves", UserWarning)
1268
1295
 
1269
- self.set_valve_sensors(self.__sensor_config.valves)
1296
+ self.set_valve_sensors(self._sensor_config.valves)
1270
1297
 
1271
1298
  def set_pump_state_sensors(self, sensor_locations: list[str]) -> None:
1272
1299
  """
@@ -1283,10 +1310,10 @@ class ScenarioSimulator():
1283
1310
  """
1284
1311
  Places a pump state sensor at every pump in the network.
1285
1312
  """
1286
- if len(self.__sensor_config.pumps) == 0:
1313
+ if len(self._sensor_config.pumps) == 0:
1287
1314
  warnings.warn("Network does not contain any pumps", UserWarning)
1288
1315
 
1289
- self.set_pump_state_sensors(self.__sensor_config.pumps)
1316
+ self.set_pump_state_sensors(self._sensor_config.pumps)
1290
1317
 
1291
1318
  def set_pump_efficiency_sensors(self, sensor_locations: list[str]) -> None:
1292
1319
  """
@@ -1304,10 +1331,10 @@ class ScenarioSimulator():
1304
1331
  """
1305
1332
  Places a pump efficiency sensor at every pump in the network.
1306
1333
  """
1307
- if len(self.__sensor_config.pumps) == 0:
1334
+ if len(self._sensor_config.pumps) == 0:
1308
1335
  warnings.warn("Network does not contain any pumps", UserWarning)
1309
1336
 
1310
- self.set_pump_efficiency_sensors(self.__sensor_config.pumps)
1337
+ self.set_pump_efficiency_sensors(self._sensor_config.pumps)
1311
1338
 
1312
1339
  def set_pump_energyconsumption_sensors(self, sensor_locations: list[str]) -> None:
1313
1340
  """
@@ -1325,10 +1352,10 @@ class ScenarioSimulator():
1325
1352
  """
1326
1353
  Places a pump energy consumption sensor at every pump in the network.
1327
1354
  """
1328
- if len(self.__sensor_config.pumps) == 0:
1355
+ if len(self._sensor_config.pumps) == 0:
1329
1356
  warnings.warn("Network does not contain any pumps", UserWarning)
1330
1357
 
1331
- self.set_pump_energyconsumption_sensors(self.__sensor_config.pumps)
1358
+ self.set_pump_energyconsumption_sensors(self._sensor_config.pumps)
1332
1359
 
1333
1360
  def set_pump_sensors(self, sensor_locations: list[str]) -> None:
1334
1361
  """
@@ -1349,10 +1376,10 @@ class ScenarioSimulator():
1349
1376
  Palces pump sensors at every pump in the network -- i.e. retrieving the state, efficiency,
1350
1377
  and energy consumption of all pumps in the network.
1351
1378
  """
1352
- if len(self.__sensor_config.pumps) == 0:
1379
+ if len(self._sensor_config.pumps) == 0:
1353
1380
  warnings.warn("Network does not contain any pumps", UserWarning)
1354
1381
 
1355
- self.set_pump_sensors(self.__sensor_config.pumps)
1382
+ self.set_pump_sensors(self._sensor_config.pumps)
1356
1383
 
1357
1384
  def set_tank_sensors(self, sensor_locations: list[str]) -> None:
1358
1385
  """
@@ -1369,10 +1396,10 @@ class ScenarioSimulator():
1369
1396
  """
1370
1397
  Places a water tank volume sensor at every tank in the network.
1371
1398
  """
1372
- if len(self.__sensor_config.tanks) == 0:
1399
+ if len(self._sensor_config.tanks) == 0:
1373
1400
  warnings.warn("Network does not contain any tanks", UserWarning)
1374
1401
 
1375
- self.set_tank_sensors(self.__sensor_config.tanks)
1402
+ self.set_tank_sensors(self._sensor_config.tanks)
1376
1403
 
1377
1404
  def set_bulk_species_node_sensors(self, sensor_info: dict) -> None:
1378
1405
  """
@@ -1386,13 +1413,30 @@ class ScenarioSimulator():
1386
1413
  """
1387
1414
  self.set_sensors(SENSOR_TYPE_NODE_BULK_SPECIES, sensor_info)
1388
1415
 
1389
- def place_bulk_species_node_sensors_everywhere(self) -> None:
1416
+ def place_bulk_species_node_sensors_everywhere(self, bulk_species: list[str] = None) -> None:
1390
1417
  """
1391
1418
  Places bulk species concentration sensors at every node in the network for
1392
1419
  every bulk species.
1420
+
1421
+ Parameters
1422
+ ----------
1423
+ bulk_species : `list[str]`, optional
1424
+ List of bulk species IDs which we want to monitor at every node.
1425
+ If None, every bulk species will be monitored at every node.
1426
+
1427
+ The default is None.
1393
1428
  """
1394
- self.set_bulk_species_node_sensors({species_id: self.__sensor_config.nodes
1395
- for species_id in self.__sensor_config.bulk_species})
1429
+ if bulk_species is None:
1430
+ self.set_bulk_species_node_sensors({species_id: self._sensor_config.nodes
1431
+ for species_id in
1432
+ self._sensor_config.bulk_species})
1433
+ else:
1434
+ if any(species_id not in self._sensor_config.bulk_species
1435
+ for species_id in bulk_species):
1436
+ raise ValueError("Invalid bulk species ID in 'bulk_species'")
1437
+
1438
+ self.set_bulk_species_node_sensors({species_id: self._sensor_config.nodes
1439
+ for species_id in bulk_species})
1396
1440
 
1397
1441
  def set_bulk_species_link_sensors(self, sensor_info: dict) -> None:
1398
1442
  """
@@ -1406,13 +1450,30 @@ class ScenarioSimulator():
1406
1450
  """
1407
1451
  self.set_sensors(SENSOR_TYPE_LINK_BULK_SPECIES, sensor_info)
1408
1452
 
1409
- def place_bulk_species_link_sensors_everywhere(self) -> None:
1453
+ def place_bulk_species_link_sensors_everywhere(self, bulk_species: list[str] = None) -> None:
1410
1454
  """
1411
1455
  Places bulk species concentration sensors at every link/pipe in the network
1412
1456
  for every bulk species.
1457
+
1458
+ Parameters
1459
+ ----------
1460
+ bulk_species : `list[str]`, optional
1461
+ List of bulk species IDs which we want to monitor at every link/pipe.
1462
+ If None, every bulk species will be monitored at every link/pipe.
1463
+
1464
+ The default is None.
1413
1465
  """
1414
- self.set_bulk_species_link_sensors({species_id: self.__sensor_config.links
1415
- for species_id in self.__sensor_config.bulk_species})
1466
+ if bulk_species is None:
1467
+ self.set_bulk_species_link_sensors({species_id: self._sensor_config.links
1468
+ for species_id in
1469
+ self._sensor_config.bulk_species})
1470
+ else:
1471
+ if any(species_id not in self._sensor_config.bulk_species
1472
+ for species_id in bulk_species):
1473
+ raise ValueError("Invalid bulk species ID in 'bulk_species'")
1474
+
1475
+ self.set_bulk_species_link_sensors({species_id: self._sensor_config.links
1476
+ for species_id in bulk_species})
1416
1477
 
1417
1478
  def set_surface_species_sensors(self, sensor_info: dict) -> None:
1418
1479
  """
@@ -1426,33 +1487,50 @@ class ScenarioSimulator():
1426
1487
  """
1427
1488
  self.set_sensors(SENSOR_TYPE_SURFACE_SPECIES, sensor_info)
1428
1489
 
1429
- def place_surface_species_sensors_everywhere(self) -> None:
1490
+ def place_surface_species_sensors_everywhere(self, surface_species_id: list[str] = None
1491
+ ) -> None:
1430
1492
  """
1431
1493
  Places surface species concentration sensors at every link/pipe in the network
1432
1494
  for every surface species.
1495
+
1496
+ Parameters
1497
+ ----------
1498
+ surface_species_id : `list[str]`, optional
1499
+ List of surface species IDs which we want to monitor at every link/pipe.
1500
+ If None, every surface species will be monitored at every link/pipe.
1501
+
1502
+ The default is None.
1433
1503
  """
1434
- self.set_bulk_species_node_sensors({species_id: self.__sensor_config.links
1435
- for species_id in
1436
- self.__sensor_config.surface_species})
1504
+ if surface_species_id is None:
1505
+ self.set_bulk_species_node_sensors({species_id: self._sensor_config.links
1506
+ for species_id in
1507
+ self._sensor_config.surface_species})
1508
+ else:
1509
+ if any(species_id not in self._sensor_config.surface_species
1510
+ for species_id in surface_species_id):
1511
+ raise ValueError("Invalid surface species ID in 'surface_species_id'")
1512
+
1513
+ self.set_bulk_species_node_sensors({species_id: self._sensor_config.links
1514
+ for species_id in surface_species_id})
1437
1515
 
1438
1516
  def place_sensors_everywhere(self) -> None:
1439
1517
  """
1440
1518
  Places sensors everywhere -- i.e. every possible quantity is monitored
1441
1519
  at every position in the network.
1442
1520
  """
1443
- self.__sensor_config.place_sensors_everywhere()
1521
+ self._sensor_config.place_sensors_everywhere()
1444
1522
 
1445
- def __prepare_simulation(self) -> None:
1446
- self.__adapt_to_network_changes()
1523
+ def _prepare_simulation(self) -> None:
1524
+ self._adapt_to_network_changes()
1447
1525
 
1448
- if self.__model_uncertainty is not None:
1449
- self.__model_uncertainty.apply(self.epanet_api)
1526
+ if self._model_uncertainty is not None:
1527
+ self._model_uncertainty.apply(self.epanet_api)
1450
1528
 
1451
- for event in self.__system_events:
1529
+ for event in self._system_events:
1452
1530
  event.reset()
1453
1531
 
1454
- if self.__controls is not None:
1455
- for c in self.__controls:
1532
+ if self._controls is not None:
1533
+ for c in self._controls:
1456
1534
  c.init(self.epanet_api)
1457
1535
 
1458
1536
  def run_advanced_quality_simulation(self, hyd_file_in: str, verbose: bool = False,
@@ -1509,9 +1587,9 @@ class ScenarioSimulator():
1509
1587
  result[data_type] = None
1510
1588
 
1511
1589
  return ScadaData(**result,
1512
- sensor_config=self.__sensor_config,
1513
- sensor_reading_events=self.__sensor_reading_events,
1514
- sensor_noise=self.__sensor_noise,
1590
+ sensor_config=self._sensor_config,
1591
+ sensor_reading_events=self._sensor_reading_events,
1592
+ sensor_noise=self._sensor_noise,
1515
1593
  frozen_sensor_config=frozen_sensor_config)
1516
1594
 
1517
1595
  def run_advanced_quality_simulation_as_generator(self, hyd_file_in: str, verbose: bool = False,
@@ -1568,9 +1646,9 @@ class ScenarioSimulator():
1568
1646
 
1569
1647
  self.__running_simulation = True
1570
1648
 
1571
- bulk_species_idx = self.epanet_api.getMSXSpeciesIndex(self.__sensor_config.bulk_species)
1649
+ bulk_species_idx = self.epanet_api.getMSXSpeciesIndex(self._sensor_config.bulk_species)
1572
1650
  surface_species_idx = self.epanet_api.getMSXSpeciesIndex(
1573
- self.__sensor_config.surface_species)
1651
+ self._sensor_config.surface_species)
1574
1652
 
1575
1653
  if verbose is True:
1576
1654
  print("Running EPANET-MSX ...")
@@ -1649,13 +1727,13 @@ class ScenarioSimulator():
1649
1727
  "surface_species_concentration_raw": surface_species_concentrations,
1650
1728
  "sensor_readings_time": np.array([0])}
1651
1729
  else:
1652
- data = ScadaData(sensor_config=self.__sensor_config,
1730
+ data = ScadaData(sensor_config=self._sensor_config,
1653
1731
  bulk_species_node_concentration_raw=bulk_species_node_concentrations,
1654
1732
  bulk_species_link_concentration_raw=bulk_species_link_concentrations,
1655
1733
  surface_species_concentration_raw=surface_species_concentrations,
1656
1734
  sensor_readings_time=np.array([0]),
1657
- sensor_reading_events=self.__sensor_reading_events,
1658
- sensor_noise=self.__sensor_noise,
1735
+ sensor_reading_events=self._sensor_reading_events,
1736
+ sensor_noise=self._sensor_noise,
1659
1737
  frozen_sensor_config=frozen_sensor_config)
1660
1738
 
1661
1739
  if support_abort is True: # Can the simulation be aborted? If so, handle it.
@@ -1693,7 +1771,7 @@ class ScenarioSimulator():
1693
1771
  "surface_species_concentration_raw": surface_species_concentrations,
1694
1772
  "sensor_readings_time": np.array([total_time])}
1695
1773
  else:
1696
- data = ScadaData(sensor_config=self.__sensor_config,
1774
+ data = ScadaData(sensor_config=self._sensor_config,
1697
1775
  bulk_species_node_concentration_raw=
1698
1776
  bulk_species_node_concentrations,
1699
1777
  bulk_species_link_concentration_raw=
@@ -1701,8 +1779,8 @@ class ScenarioSimulator():
1701
1779
  surface_species_concentration_raw=
1702
1780
  surface_species_concentrations,
1703
1781
  sensor_readings_time=np.array([total_time]),
1704
- sensor_reading_events=self.__sensor_reading_events,
1705
- sensor_noise=self.__sensor_noise,
1782
+ sensor_reading_events=self._sensor_reading_events,
1783
+ sensor_noise=self._sensor_noise,
1706
1784
  frozen_sensor_config=frozen_sensor_config)
1707
1785
 
1708
1786
  if support_abort is True: # Can the simulation be aborted? If so, handle it.
@@ -1763,9 +1841,9 @@ class ScenarioSimulator():
1763
1841
  result[data_type] = np.concatenate(result[data_type], axis=0)
1764
1842
 
1765
1843
  return ScadaData(**result,
1766
- sensor_config=self.__sensor_config,
1767
- sensor_reading_events=self.__sensor_reading_events,
1768
- sensor_noise=self.__sensor_noise,
1844
+ sensor_config=self._sensor_config,
1845
+ sensor_reading_events=self._sensor_reading_events,
1846
+ sensor_noise=self._sensor_noise,
1769
1847
  frozen_sensor_config=frozen_sensor_config)
1770
1848
 
1771
1849
  def run_basic_quality_simulation_as_generator(self, hyd_file_in: str, verbose: bool = False,
@@ -1851,12 +1929,12 @@ class ScenarioSimulator():
1851
1929
  "link_quality_data_raw": quality_link_data,
1852
1930
  "sensor_readings_time": np.array([total_time])}
1853
1931
  else:
1854
- data = ScadaData(sensor_config=self.__sensor_config,
1932
+ data = ScadaData(sensor_config=self._sensor_config,
1855
1933
  node_quality_data_raw=quality_node_data,
1856
1934
  link_quality_data_raw=quality_link_data,
1857
1935
  sensor_readings_time=np.array([total_time]),
1858
- sensor_reading_events=self.__sensor_reading_events,
1859
- sensor_noise=self.__sensor_noise,
1936
+ sensor_reading_events=self._sensor_reading_events,
1937
+ sensor_noise=self._sensor_noise,
1860
1938
  frozen_sensor_config=frozen_sensor_config)
1861
1939
 
1862
1940
  if support_abort is True: # Can the simulation be aborted? If so, handle it.
@@ -1905,7 +1983,7 @@ class ScenarioSimulator():
1905
1983
  if self.__running_simulation is True:
1906
1984
  raise RuntimeError("A simulation is already running.")
1907
1985
 
1908
- self.__adapt_to_network_changes()
1986
+ self._adapt_to_network_changes()
1909
1987
 
1910
1988
  result = None
1911
1989
 
@@ -1927,9 +2005,9 @@ class ScenarioSimulator():
1927
2005
  result[data_type] = np.concatenate(result[data_type], axis=0)
1928
2006
 
1929
2007
  result = ScadaData(**result,
1930
- sensor_config=self.__sensor_config,
1931
- sensor_reading_events=self.__sensor_reading_events,
1932
- sensor_noise=self.__sensor_noise,
2008
+ sensor_config=self._sensor_config,
2009
+ sensor_reading_events=self._sensor_reading_events,
2010
+ sensor_noise=self._sensor_noise,
1933
2011
  frozen_sensor_config=frozen_sensor_config)
1934
2012
 
1935
2013
  return result
@@ -1984,9 +2062,9 @@ class ScenarioSimulator():
1984
2062
  if self.__running_simulation is True:
1985
2063
  raise RuntimeError("A simulation is already running.")
1986
2064
 
1987
- self.__adapt_to_network_changes()
2065
+ self._adapt_to_network_changes()
1988
2066
 
1989
- self.__prepare_simulation()
2067
+ self._prepare_simulation()
1990
2068
 
1991
2069
  self.__running_simulation = True
1992
2070
 
@@ -2024,7 +2102,7 @@ class ScenarioSimulator():
2024
2102
 
2025
2103
  # Apply system events in a regular time interval only!
2026
2104
  if (total_time + tstep) % requested_time_step == 0:
2027
- for event in self.__system_events:
2105
+ for event in self._system_events:
2028
2106
  event.step(total_time + tstep)
2029
2107
 
2030
2108
  # Compute current time step
@@ -2048,7 +2126,7 @@ class ScenarioSimulator():
2048
2126
  link_valve_idx = self.epanet_api.getLinkValveIndex()
2049
2127
  valves_state_data = self.epanet_api.getLinkStatus(link_valve_idx).reshape(1, -1)
2050
2128
 
2051
- scada_data = ScadaData(sensor_config=self.__sensor_config,
2129
+ scada_data = ScadaData(sensor_config=self._sensor_config,
2052
2130
  pressure_data_raw=pressure_data,
2053
2131
  flow_data_raw=flow_data,
2054
2132
  demand_data_raw=demand_data,
@@ -2060,8 +2138,8 @@ class ScenarioSimulator():
2060
2138
  pumps_energy_usage_data_raw=pumps_energy_usage_data,
2061
2139
  pumps_efficiency_data_raw=pumps_efficiency_data,
2062
2140
  sensor_readings_time=np.array([total_time]),
2063
- sensor_reading_events=self.__sensor_reading_events,
2064
- sensor_noise=self.__sensor_noise,
2141
+ sensor_reading_events=self._sensor_reading_events,
2142
+ sensor_noise=self._sensor_noise,
2065
2143
  frozen_sensor_config=frozen_sensor_config)
2066
2144
 
2067
2145
  # Yield results in a regular time interval only!
@@ -2089,7 +2167,7 @@ class ScenarioSimulator():
2089
2167
  yield data
2090
2168
 
2091
2169
  # Apply control modules
2092
- for control in self.__controls:
2170
+ for control in self._controls:
2093
2171
  control.step(scada_data)
2094
2172
 
2095
2173
  # Next
@@ -2107,6 +2185,16 @@ class ScenarioSimulator():
2107
2185
  self.__running_simulation = False
2108
2186
  raise ex
2109
2187
 
2188
+ def run_simulation_as_generator(self, hyd_export: str = None, verbose: bool = False,
2189
+ support_abort: bool = False,
2190
+ return_as_dict: bool = False,
2191
+ frozen_sensor_config: bool = False,
2192
+ ) -> Generator[Union[ScadaData, dict], bool, None]:
2193
+ warnings.warn("'run_simulation_as_generator' is deprecated and will be removed in " +
2194
+ "future releases -- use 'run_hydraulic_simulation_as_generator' instead")
2195
+ return self.run_hydraulic_simulation_as_generator(hyd_export, verbose, support_abort,
2196
+ return_as_dict, frozen_sensor_config)
2197
+
2110
2198
  def run_simulation(self, hyd_export: str = None, verbose: bool = False,
2111
2199
  frozen_sensor_config: bool = False) -> ScadaData:
2112
2200
  """
@@ -2139,7 +2227,7 @@ class ScenarioSimulator():
2139
2227
  if self.__running_simulation is True:
2140
2228
  raise RuntimeError("A simulation is already running.")
2141
2229
 
2142
- self.__adapt_to_network_changes()
2230
+ self._adapt_to_network_changes()
2143
2231
 
2144
2232
  result = None
2145
2233
 
@@ -2182,14 +2270,14 @@ class ScenarioSimulator():
2182
2270
  if self.__running_simulation is True:
2183
2271
  raise RuntimeError("Can not set uncertainties when simulation is running.")
2184
2272
 
2185
- self.__adapt_to_network_changes()
2273
+ self._adapt_to_network_changes()
2186
2274
 
2187
2275
  if not isinstance(model_uncertainty, ModelUncertainty):
2188
2276
  raise TypeError("'model_uncertainty' must be an instance of " +
2189
2277
  "'epyt_flow.uncertainty.ModelUncertainty' but not of " +
2190
2278
  f"'{type(model_uncertainty)}'")
2191
2279
 
2192
- self.__model_uncertainty = model_uncertainty
2280
+ self._model_uncertainty = model_uncertainty
2193
2281
 
2194
2282
  def set_sensor_noise(self, sensor_noise: SensorNoise) -> None:
2195
2283
  """
@@ -2203,14 +2291,14 @@ class ScenarioSimulator():
2203
2291
  if self.__running_simulation is True:
2204
2292
  raise RuntimeError("Can not set sensor noise when simulation is running.")
2205
2293
 
2206
- self.__adapt_to_network_changes()
2294
+ self._adapt_to_network_changes()
2207
2295
 
2208
2296
  if not isinstance(sensor_noise, SensorNoise):
2209
2297
  raise TypeError("'sensor_noise' must be an instance of " +
2210
2298
  "'epyt_flow.uncertainties.SensorNoise' but not of " +
2211
2299
  f"'{type(sensor_noise)}'")
2212
2300
 
2213
- self.__sensor_noise = sensor_noise
2301
+ self._sensor_noise = sensor_noise
2214
2302
 
2215
2303
  def set_general_parameters(self, demand_model: dict = None, simulation_duration: int = None,
2216
2304
  hydraulic_time_step: int = None, quality_time_step: int = None,
@@ -2288,7 +2376,7 @@ class ScenarioSimulator():
2288
2376
  if self.__running_simulation is True:
2289
2377
  raise RuntimeError("Can not change general parameters when simulation is running.")
2290
2378
 
2291
- self.__adapt_to_network_changes()
2379
+ self._adapt_to_network_changes()
2292
2380
 
2293
2381
  if flow_units_id is not None:
2294
2382
  if flow_units_id == ToolkitConstants.EN_CFS:
@@ -2329,7 +2417,7 @@ class ScenarioSimulator():
2329
2417
  if not isinstance(hydraulic_time_step, int) or hydraulic_time_step <= 0:
2330
2418
  raise ValueError("'hydraulic_time_step' must be a positive integer specifying " +
2331
2419
  "the time steps of the hydraulic simulation")
2332
- if len(self.__system_events) != 0:
2420
+ if len(self._system_events) != 0:
2333
2421
  raise RuntimeError("Hydraulic time step cannot be changed after system events " +
2334
2422
  "such as leakages have been added to the scenario")
2335
2423
  self.epanet_api.setTimeHydraulicStep(hydraulic_time_step)
@@ -2391,10 +2479,10 @@ class ScenarioSimulator():
2391
2479
  events_times.append(cur_time)
2392
2480
  cur_time += hyd_time_step
2393
2481
 
2394
- for event in self.__sensor_reading_events:
2482
+ for event in self._sensor_reading_events:
2395
2483
  __process_event(event)
2396
2484
 
2397
- for event in self.__system_events:
2485
+ for event in self._system_events:
2398
2486
  __process_event(event)
2399
2487
 
2400
2488
  return list(set(events_times))
@@ -2413,7 +2501,7 @@ class ScenarioSimulator():
2413
2501
  if self.__running_simulation is True:
2414
2502
  raise RuntimeError("Can not change general parameters when simulation is running.")
2415
2503
 
2416
- self.__adapt_to_network_changes()
2504
+ self._adapt_to_network_changes()
2417
2505
 
2418
2506
  self.__warn_if_quality_set()
2419
2507
  self.set_general_parameters(quality_model={"type": "AGE"})
@@ -2444,7 +2532,7 @@ class ScenarioSimulator():
2444
2532
  if self.__running_simulation is True:
2445
2533
  raise RuntimeError("Can not change general parameters when simulation is running.")
2446
2534
 
2447
- self.__adapt_to_network_changes()
2535
+ self._adapt_to_network_changes()
2448
2536
 
2449
2537
  self.__warn_if_quality_set()
2450
2538
  self.set_general_parameters(quality_model={"type": "CHEM", "chemical_name": chemical_name,
@@ -2491,12 +2579,12 @@ class ScenarioSimulator():
2491
2579
  if self.__running_simulation is True:
2492
2580
  raise RuntimeError("Can not change general parameters when simulation is running.")
2493
2581
 
2494
- self.__adapt_to_network_changes()
2582
+ self._adapt_to_network_changes()
2495
2583
 
2496
2584
  if self.epanet_api.getQualityInfo().QualityCode != ToolkitConstants.EN_CHEM:
2497
2585
  raise RuntimeError("Chemical analysis is not enabled -- " +
2498
2586
  "call 'enable_chemical_analysis()' before calling this function.")
2499
- if node_id not in self.__sensor_config.nodes:
2587
+ if node_id not in self._sensor_config.nodes:
2500
2588
  raise ValueError(f"Unknown node '{node_id}'")
2501
2589
  if not isinstance(pattern, np.ndarray):
2502
2590
  raise TypeError("'pattern' must be an instance of 'numpy.ndarray' " +
@@ -2530,9 +2618,9 @@ class ScenarioSimulator():
2530
2618
  if self.__running_simulation is True:
2531
2619
  raise RuntimeError("Can not change general parameters when simulation is running.")
2532
2620
 
2533
- self.__adapt_to_network_changes()
2621
+ self._adapt_to_network_changes()
2534
2622
 
2535
- if trace_node_id not in self.__sensor_config.nodes:
2623
+ if trace_node_id not in self._sensor_config.nodes:
2536
2624
  raise ValueError(f"Invalid node ID '{trace_node_id}'")
2537
2625
 
2538
2626
  self.__warn_if_quality_set()