epyt-flow 0.9.0__py3-none-any.whl → 0.10.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 CHANGED
@@ -1 +1 @@
1
- 0.9.0
1
+ 0.10.0
@@ -107,6 +107,14 @@ class ScenarioControlEnv(ABC):
107
107
  Current SCADA data (i.e. sensor readings).
108
108
  """
109
109
  if self._scenario_sim is not None:
110
+ # Abort current simulation if any is runing
111
+ try:
112
+ next(self._sim_generator)
113
+ self._sim_generator.send(True)
114
+ except StopIteration:
115
+ pass
116
+
117
+ # Close scenario
110
118
  self._scenario_sim.close()
111
119
 
112
120
  self._scenario_sim = ScenarioSimulator(
@@ -194,7 +202,7 @@ class ScenarioControlEnv(ABC):
194
202
  if pattern_idx == 0:
195
203
  warnings.warn(f"No pattern for pump '{pump_id}' found -- a new pattern is created")
196
204
  pattern_idx = self._scenario_sim.epanet_api.addPattern(f"pump_speed_{pump_id}")
197
- self._scenario_sim.epanet_api.setLinkPumpPatternIndex(pump_idx, pattern_idx)
205
+ self._scenario_sim.epanet_api.setLinkPumpPatternIndex(pump_idx + 1, pattern_idx)
198
206
 
199
207
  self._scenario_sim.epanet_api.setPattern(pattern_idx, np.array([speed]))
200
208
 
@@ -48,6 +48,10 @@ PUMP_STATE_EVENT_ID = 28
48
48
  PUMP_SPEED_EVENT_ID = 29
49
49
  VALVE_STATE_EVENT_ID = 30
50
50
  SPECIESINJECTION_EVENT_ID = 31
51
+ SIMPLE_CONTROL_ID = 32
52
+ COMPLEX_CONTROL_ID = 33
53
+ COMPLEX_CONTROL_CONDITION_ID = 34
54
+ COMPLEX_CONTROL_ACTION_ID = 35
51
55
 
52
56
 
53
57
  def my_packb(data: Any) -> bytes:
@@ -46,7 +46,7 @@ class SensorOverrideAttack(SensorReadingAttack, JsonSerializable):
46
46
  @property
47
47
  def new_sensor_values(self) -> np.ndarray:
48
48
  """
49
- Get the new sensor reading values -- i.e. these values replace the
49
+ Returns the new sensor reading values -- i.e. these values replace the
50
50
  true sensor reading values.
51
51
 
52
52
  Returns
@@ -64,7 +64,7 @@ class SensorOverrideAttack(SensorReadingAttack, JsonSerializable):
64
64
  raise TypeError("Can not compare 'SensorOverrideAttack' instance " +
65
65
  f"with '{type(other)}' instance")
66
66
 
67
- return super().__eq__(other) and self.__new_sensor_values == other.new_sensor_values
67
+ return super().__eq__(other) and np.all(self.__new_sensor_values == other.new_sensor_values)
68
68
 
69
69
  def __str__(self) -> str:
70
70
  return f"{type(self).__name__} {super().__str__()} " +\
@@ -151,6 +151,19 @@ class SensorReplayAttack(SensorReadingAttack, JsonSerializable):
151
151
  """
152
152
  return self.__sensor_data_time_window_end
153
153
 
154
+ @property
155
+ def new_sensor_values(self) -> np.ndarray:
156
+ """
157
+ Returns the new sensor reading values -- i.e. these values replace the
158
+ true sensor reading values.
159
+
160
+ Returns
161
+ -------
162
+ `np.ndarray`
163
+ New sensor readings.
164
+ """
165
+ return deepcopy(self.__new_sensor_values)
166
+
154
167
  def get_attributes(self) -> dict:
155
168
  my_attributes = {"new_sensor_values": self.__new_sensor_values,
156
169
  "replay_data_time_window_start": self.__sensor_data_time_window_start,
@@ -163,7 +176,7 @@ class SensorReplayAttack(SensorReadingAttack, JsonSerializable):
163
176
  raise TypeError("Can not compare 'SensorReplayAttack' instance " +
164
177
  f"with '{type(other)}' instance")
165
178
 
166
- return super().__eq__(other) and self.__new_sensor_values == other.new_sensor_values
179
+ return super().__eq__(other) and np.all(self.__new_sensor_values == other.new_sensor_values)
167
180
 
168
181
  def __str__(self) -> str:
169
182
  return f"{type(self).__name__} {super().__str__()} " +\
@@ -95,13 +95,28 @@ class SensorReadingEvent(Event):
95
95
  if self.__sensor_id not in sensor_config.tank_volume_sensors:
96
96
  __show_warning()
97
97
  elif self.__sensor_type == SENSOR_TYPE_NODE_BULK_SPECIES:
98
- if self.__sensor_id not in sensor_config.bulk_species_node_sensors:
98
+ sensor_present = False
99
+ for _, sensors_id in sensor_config.bulk_species_node_sensors.items():
100
+ if self.__sensor_id in sensors_id:
101
+ sensor_present = True
102
+ break
103
+ if sensor_present is False:
99
104
  __show_warning()
100
105
  elif self.__sensor_type == SENSOR_TYPE_LINK_BULK_SPECIES:
101
- if self.__sensor_id not in sensor_config.bulk_species_link_sensors:
106
+ sensor_present = False
107
+ for _, sensors_id in sensor_config.bulk_species_link_sensors.items():
108
+ if self.__sensor_id in sensors_id:
109
+ sensor_present = True
110
+ break
111
+ if sensor_present is False:
102
112
  __show_warning()
103
113
  elif self.__sensor_type == SENSOR_TYPE_SURFACE_SPECIES:
104
- if self.__sensor_id not in sensor_config.surface_species_sensors:
114
+ sensor_present = False
115
+ for _, sensors_id in sensor_config.surface_species_sensors.items():
116
+ if self.__sensor_id in sensors_id:
117
+ sensor_present = True
118
+ break
119
+ if sensor_present is False:
105
120
  __show_warning()
106
121
 
107
122
  @property
@@ -1,3 +1,5 @@
1
1
  from .scada_data import *
2
2
  from .scada_data_export import *
3
- from .advanced_control import *
3
+ from .custom_control import *
4
+ from .simple_control import *
5
+ from .complex_control import *
@@ -1,14 +1,18 @@
1
1
  """
2
- Module provides a base class for control modules.
2
+ Deprecated -- use epyt_flow.simulation.scada.custom_control instead
3
3
  """
4
- from abc import abstractmethod, ABC
5
4
  import warnings
5
+ from abc import abstractmethod, ABC
6
6
  import numpy as np
7
7
  import epyt
8
8
 
9
9
  from . import ScadaData
10
10
 
11
11
 
12
+ warnings.warn("'epyt_flow.simulation.scada.advanced_control' is deprecated and will be removed " +
13
+ "in future releases -- use 'epyt_flow.simulation.scada.custom_control' instead")
14
+
15
+
12
16
  class AdvancedControlModule(ABC):
13
17
  """
14
18
  Base class for a control module.