epyt-flow 0.5.0__py3-none-any.whl → 0.6.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.
@@ -11,17 +11,19 @@ from epyt.epanet import ToolkitConstants
11
11
  from ..serialization import SENSOR_CONFIG_ID, JsonSerializable, serializable
12
12
 
13
13
 
14
- SENSOR_TYPE_NODE_PRESSURE = 1
15
- SENSOR_TYPE_NODE_QUALITY = 2
16
- SENSOR_TYPE_NODE_DEMAND = 3
17
- SENSOR_TYPE_LINK_FLOW = 4
18
- SENSOR_TYPE_LINK_QUALITY = 5
19
- SENSOR_TYPE_VALVE_STATE = 6
20
- SENSOR_TYPE_PUMP_STATE = 7
21
- SENSOR_TYPE_TANK_VOLUME = 8
22
- SENSOR_TYPE_NODE_BULK_SPECIES = 9
23
- SENSOR_TYPE_LINK_BULK_SPECIES = 10
24
- SENSOR_TYPE_SURFACE_SPECIES = 11
14
+ SENSOR_TYPE_NODE_PRESSURE = 1
15
+ SENSOR_TYPE_NODE_QUALITY = 2
16
+ SENSOR_TYPE_NODE_DEMAND = 3
17
+ SENSOR_TYPE_LINK_FLOW = 4
18
+ SENSOR_TYPE_LINK_QUALITY = 5
19
+ SENSOR_TYPE_VALVE_STATE = 6
20
+ SENSOR_TYPE_PUMP_STATE = 7
21
+ SENSOR_TYPE_TANK_VOLUME = 8
22
+ SENSOR_TYPE_NODE_BULK_SPECIES = 9
23
+ SENSOR_TYPE_LINK_BULK_SPECIES = 10
24
+ SENSOR_TYPE_SURFACE_SPECIES = 11
25
+ SENSOR_TYPE_PUMP_EFFICIENCY = 12
26
+ SENSOR_TYPE_PUMP_ENERGYCONSUMPTION = 13
25
27
 
26
28
  AREA_UNIT_FT2 = 1
27
29
  AREA_UNIT_M2 = 2
@@ -462,6 +464,8 @@ class SensorConfig(JsonSerializable):
462
464
  quality_link_sensors: list[str] = [],
463
465
  valve_state_sensors: list[str] = [],
464
466
  pump_state_sensors: list[str] = [],
467
+ pump_efficiency_sensors: list[str] = [],
468
+ pump_energyconsumption_sensors: list[str] = [],
465
469
  tank_volume_sensors: list[str] = [],
466
470
  bulk_species_node_sensors: dict = {},
467
471
  bulk_species_link_sensors: dict = {},
@@ -572,6 +576,20 @@ class SensorConfig(JsonSerializable):
572
576
  raise ValueError("Each item in 'pump_state_sensors' must be in 'pumps' -- cannot " +
573
577
  "place a sensor at a non-existing pump.")
574
578
 
579
+ if not isinstance(pump_efficiency_sensors, list):
580
+ raise TypeError("'pump_efficiency_sensors' must be an instance of 'list[str]' " +
581
+ f"but not of '{type(pump_efficiency_sensors)}'")
582
+ if any(link not in pumps for link in pump_efficiency_sensors):
583
+ raise ValueError("Each item in 'pump_efficiency_sensors' must be in 'pumps' -- cannot " +
584
+ "place a sensor at a non-existing pump.")
585
+
586
+ if not isinstance(pump_energyconsumption_sensors, list):
587
+ raise TypeError("'pump_energyconsumption_sensors' must be an instance of 'list[str]' " +
588
+ f"but not of '{type(pump_energyconsumption_sensors)}'")
589
+ if any(link not in pumps for link in pump_energyconsumption_sensors):
590
+ raise ValueError("Each item in 'pump_energyconsumption_sensors' must be in 'pumps' -- cannot " +
591
+ "place a sensor at a non-existing pump.")
592
+
575
593
  if not isinstance(tank_volume_sensors, list):
576
594
  raise TypeError("'tank_volume_sensors' must be an instance of 'list[str]' " +
577
595
  f"but not of '{type(tank_volume_sensors)}'")
@@ -714,6 +732,8 @@ class SensorConfig(JsonSerializable):
714
732
  self.__quality_link_sensors = quality_link_sensors
715
733
  self.__valve_state_sensors = valve_state_sensors
716
734
  self.__pump_state_sensors = pump_state_sensors
735
+ self.__pump_energyconsumption_sensors = pump_energyconsumption_sensors
736
+ self.__pump_efficiency_sensors = pump_efficiency_sensors
717
737
  self.__tank_volume_sensors = tank_volume_sensors
718
738
  self.__bulk_species_node_sensors = bulk_species_node_sensors
719
739
  self.__bulk_species_link_sensors = bulk_species_link_sensors
@@ -771,6 +791,51 @@ class SensorConfig(JsonSerializable):
771
791
  bulkspecies_id_to_idx=sensor_config.bulkspecies_id_to_idx,
772
792
  surfacespecies_id_to_idx=sensor_config.surfacespecies_id_to_idx)
773
793
 
794
+ def is_empty(self) -> bool:
795
+ """
796
+ Checks if the sensor configuration is empty -- i.e. no sensors are placed.
797
+
798
+ Returns
799
+ -------
800
+ `bool`
801
+ True if no sensors are placed, False otherwise.
802
+ """
803
+ if self.__pressure_sensors == [] and self.__flow_sensors == [] \
804
+ and self.__demand_sensors == [] and self.__quality_node_sensors == [] \
805
+ and self.__quality_link_sensors == [] and self.__valve_state_sensors == [] \
806
+ and self.__pump_state_sensors == [] \
807
+ and self.__pump_energyconsumption_sensors == [] \
808
+ and self.__pump_efficiency_sensors == [] and self.__tank_volume_sensors == [] \
809
+ and self.__bulk_species_node_sensors == [] \
810
+ and self.__bulk_species_link_sensors == [] \
811
+ and self.__surface_species_sensors == []:
812
+ return True
813
+ else:
814
+ return False
815
+
816
+ def place_sensors_everywhere(self) -> None:
817
+ """
818
+ Places sensors everywhere -- i.e. every possible quantity is monitored
819
+ at every position in the network.
820
+ """
821
+ self.__pressure_sensors = self.__nodes[:]
822
+ self.__demand_sensors = self.__nodes[:]
823
+ self.__flow_sensors = self.__links[:]
824
+ self.__quality_node_sensors = self.__nodes[:]
825
+ self.__quality_link_sensors = self.__links[:]
826
+ self.__pump_state_sensors = self.__pumps[:]
827
+ self.__pump_energyconsumption_sensors = self.__pumps[:]
828
+ self.__pump_efficiency_sensors = self.__pumps[:]
829
+ self.__tank_volume_sensors = self.__tanks[:]
830
+ self.__bulk_species_node_sensors = {species_id: self.__nodes[:]
831
+ for species_id in self.__bulk_species}
832
+ self.__bulk_species_link_sensors = {species_id: self.__links[:]
833
+ for species_id in self.__bulk_species}
834
+ self.__surface_species_sensors = {species_id: self.__links[:]
835
+ for species_id in self.__surface_species}
836
+
837
+ self.__compute_indices()
838
+
774
839
  @property
775
840
  def node_id_to_idx(self) -> dict:
776
841
  """
@@ -1032,6 +1097,12 @@ class SensorConfig(JsonSerializable):
1032
1097
  for v in self.__valve_state_sensors], dtype=np.int32)
1033
1098
  self.__pump_state_idx = np.array([self.map_pump_id_to_idx(p)
1034
1099
  for p in self.__pump_state_sensors], dtype=np.int32)
1100
+ self.__pump_efficiency_idx = np.array([self.map_pump_id_to_idx(p)
1101
+ for p in self.__pump_efficiency_sensors],
1102
+ dtype=np.int32)
1103
+ self.__pump_energyconsumption_idx = np.array([self.map_pump_id_to_idx(p)
1104
+ for p in self.__pump_energyconsumption_sensors],
1105
+ dtype=np.int32)
1035
1106
  self.__tank_volume_idx = np.array([self.map_tank_id_to_idx(t)
1036
1107
  for t in self.__tank_volume_sensors], dtype=np.int32)
1037
1108
  self.__bulk_species_node_idx = np.array([(self.map_bulkspecies_id_to_idx(s),
@@ -1057,6 +1128,8 @@ class SensorConfig(JsonSerializable):
1057
1128
  n_link_quality_sensors = len(self.__quality_link_sensors)
1058
1129
  n_valve_state_sensors = len(self.__valve_state_sensors)
1059
1130
  n_pump_state_sensors = len(self.__pump_state_sensors)
1131
+ n_pump_efficiency_sensors = len(self.__pump_efficiency_sensors)
1132
+ n_pump_energyconsumption_sensors = len(self.__pump_energyconsumption_sensors)
1060
1133
  n_tank_volume_sensors = len(self.__tank_volume_sensors)
1061
1134
  n_bulk_species_node_sensors = len(list(itertools.chain(
1062
1135
  *self.__bulk_species_node_sensors.values())))
@@ -1070,7 +1143,9 @@ class SensorConfig(JsonSerializable):
1070
1143
  link_quality_idx_shift = node_quality_idx_shift + n_node_quality_sensors
1071
1144
  valve_state_idx_shift = link_quality_idx_shift + n_link_quality_sensors
1072
1145
  pump_state_idx_shift = valve_state_idx_shift + n_valve_state_sensors
1073
- tank_volume_idx_shift = pump_state_idx_shift + n_pump_state_sensors
1146
+ pump_efficiency_idx_shift = pump_state_idx_shift + n_pump_state_sensors
1147
+ pump_energyconsumption_idx_shift = pump_efficiency_idx_shift + n_pump_efficiency_sensors
1148
+ tank_volume_idx_shift = pump_energyconsumption_idx_shift + n_pump_energyconsumption_sensors
1074
1149
  bulk_species_node_idx_shift = tank_volume_idx_shift + n_tank_volume_sensors
1075
1150
  bulk_species_link_idx_shift = bulk_species_node_idx_shift + n_bulk_species_node_sensors
1076
1151
  surface_species_idx_shift = bulk_species_link_idx_shift + n_bulk_species_link_sensors
@@ -1103,6 +1178,11 @@ class SensorConfig(JsonSerializable):
1103
1178
  valve_state_idx_shift),
1104
1179
  "pump_state": __build_sensors_id_to_idx(self.__pump_state_sensors,
1105
1180
  pump_state_idx_shift),
1181
+ "pump_efficiency": __build_sensors_id_to_idx(self.__pump_efficiency_sensors,
1182
+ pump_efficiency_idx_shift),
1183
+ "pump_energyconsumption":
1184
+ __build_sensors_id_to_idx(self.__pump_energyconsumption_sensors,
1185
+ pump_energyconsumption_idx_shift),
1106
1186
  "tank_volume": __build_sensors_id_to_idx(self.__tank_volume_sensors,
1107
1187
  tank_volume_idx_shift),
1108
1188
  "bulk_species_node":
@@ -1526,6 +1606,58 @@ class SensorConfig(JsonSerializable):
1526
1606
 
1527
1607
  self.__compute_indices()
1528
1608
 
1609
+ @property
1610
+ def pump_energyconsumption_sensors(self) -> list[str]:
1611
+ """
1612
+ Gets all pump energy consumption sensors
1613
+ (i.e. IDs of pumps at which the energy consumption is monitored).
1614
+
1615
+ Returns
1616
+ -------
1617
+ `list[str]`
1618
+ All pump IDs with an energy consumption sensor.
1619
+ """
1620
+ return self.__pump_energyconsumption_sensors.copy()
1621
+
1622
+ @pump_energyconsumption_sensors.setter
1623
+ def pump_energyconsumption_sensors(self, pump_energyconsumption_sensors: list[str]) -> None:
1624
+ if not isinstance(pump_energyconsumption_sensors, list):
1625
+ raise TypeError("'pump_energyconsumption_sensors' must be an instance of 'list[str]' " +
1626
+ f"but not of '{type(pump_energyconsumption_sensors)}'")
1627
+ if any(link not in self.__pumps for link in pump_energyconsumption_sensors):
1628
+ raise ValueError("Each item in 'pump_energyconsumption_sensors' must be in 'pumps' " +
1629
+ "-- cannot place a sensor at a non-existing pump.")
1630
+
1631
+ self.__pump_energyconsumption_sensors = pump_energyconsumption_sensors
1632
+
1633
+ self.__compute_indices()
1634
+
1635
+ @property
1636
+ def pump_efficiency_sensors(self) -> list[str]:
1637
+ """
1638
+ Gets all pump efficiency sensors
1639
+ (i.e. IDs of pumps at which the efficiency is monitored).
1640
+
1641
+ Returns
1642
+ -------
1643
+ `list[str]`
1644
+ All pump IDs with an efficiency sensor.
1645
+ """
1646
+ return self.__pump_efficiency_sensors.copy()
1647
+
1648
+ @pump_efficiency_sensors.setter
1649
+ def pump_efficiency_sensors(self, pump_efficiency_sensors: list[str]) -> None:
1650
+ if not isinstance(pump_efficiency_sensors, list):
1651
+ raise TypeError("'pump_efficiency_sensors' must be an instance of 'list[str]' " +
1652
+ f"but not of '{type(pump_efficiency_sensors)}'")
1653
+ if any(link not in self.__pumps for link in pump_efficiency_sensors):
1654
+ raise ValueError("Each item in 'pump_efficiency_sensors' must be in 'pumps' " +
1655
+ "-- cannot place a sensor at a non-existing pump.")
1656
+
1657
+ self.__pump_efficiency_sensors = pump_efficiency_sensors
1658
+
1659
+ self.__compute_indices()
1660
+
1529
1661
  @property
1530
1662
  def tank_volume_sensors(self) -> list[str]:
1531
1663
  """
@@ -1670,6 +1802,10 @@ class SensorConfig(JsonSerializable):
1670
1802
  r["valve_state"] = self.__valve_state_sensors
1671
1803
  if self.__pump_state_sensors != []:
1672
1804
  r["pump_state"] = self.__pump_state_sensors
1805
+ if self.__pump_efficiency_sensors != []:
1806
+ r["pump_efficiency"] = self.__pump_efficiency_sensors
1807
+ if self.__pump_energyconsumption_sensors != []:
1808
+ r["pump_energyconsumption"] = self.__pump_energyconsumption_sensors
1673
1809
  if self.__quality_node_sensors != []:
1674
1810
  r["node_quality"] = self.__quality_node_sensors
1675
1811
  if self.__quality_link_sensors != []:
@@ -1695,6 +1831,8 @@ class SensorConfig(JsonSerializable):
1695
1831
  "quality_link_sensors": self.__quality_link_sensors,
1696
1832
  "valve_state_sensors": self.__valve_state_sensors,
1697
1833
  "pump_state_sensors": self.__pump_state_sensors,
1834
+ "pump_efficiency_sensors": self.__pump_efficiency_sensors,
1835
+ "pump_energyconsumption_sensors": self.__pump_energyconsumption_sensors,
1698
1836
  "tank_volume_sensors": self.__tank_volume_sensors,
1699
1837
  "bulk_species_node_sensors": self.__bulk_species_node_sensors,
1700
1838
  "bulk_species_link_sensors": self.__bulk_species_link_sensors,
@@ -1730,6 +1868,8 @@ class SensorConfig(JsonSerializable):
1730
1868
  and self.__quality_link_sensors == other.quality_link_sensors \
1731
1869
  and self.__valve_state_sensors == other.valve_state_sensors \
1732
1870
  and self.__pump_state_sensors == other.pump_state_sensors \
1871
+ and self.__pump_efficiency_sensors == other.pump_efficiency_sensors \
1872
+ and self.__pump_energyconsumption_sensors == other.pump_energyconsumption_sensors \
1733
1873
  and self.__tank_volume_sensors == other.tank_volume_sensors \
1734
1874
  and self.__bulk_species_node_sensors == other.bulk_species_node_sensors \
1735
1875
  and self.__bulk_species_link_sensors == other.bulk_species_link_sensors \
@@ -1762,6 +1902,8 @@ class SensorConfig(JsonSerializable):
1762
1902
  f"quality_link_sensors: {self.__quality_link_sensors} " +\
1763
1903
  f"valve_state_sensors: {self.__valve_state_sensors} " +\
1764
1904
  f"pump_state_sensors: {self.__pump_state_sensors} " +\
1905
+ f"pump_efficiency_sensors: {self.__pump_efficiency_sensors} " +\
1906
+ f"pump_energyconsumption_sensors: {self.__pump_energyconsumption_sensors} " +\
1765
1907
  f"tank_volume_sensors: {self.__tank_volume_sensors} " +\
1766
1908
  f"bulk_species_node_sensors: {self.__bulk_species_node_sensors} " +\
1767
1909
  f"bulk_species_link_sensors: {self.__bulk_species_link_sensors} " +\
@@ -1776,7 +1918,8 @@ class SensorConfig(JsonSerializable):
1776
1918
 
1777
1919
  def compute_readings(self, pressures: np.ndarray, flows: np.ndarray, demands: np.ndarray,
1778
1920
  nodes_quality: np.ndarray, links_quality: np.ndarray,
1779
- pumps_state: np.ndarray, valves_state: np.ndarray,
1921
+ pumps_state: np.ndarray, pumps_efficiency: np.ndarray,
1922
+ pumps_energyconsumption: np.ndarray, valves_state: np.ndarray,
1780
1923
  tanks_volume: np.ndarray, bulk_species_node_concentrations: np.ndarray,
1781
1924
  bulk_species_link_concentrations: np.ndarray,
1782
1925
  surface_species_concentrations: np.ndarray) -> np.ndarray:
@@ -1798,6 +1941,10 @@ class SensorConfig(JsonSerializable):
1798
1941
  Quality values at all links/pipes.
1799
1942
  pumps_state : `numpy.ndarray`
1800
1943
  States of all pumps.
1944
+ pumps_efficiency : `numpy.ndarray`
1945
+ Efficiency of all pumps.
1946
+ pumps_energyconsumption : `numpy.ndarray`
1947
+ Energy consumption of all pumps.
1801
1948
  valves_state : `numpy.ndarray`
1802
1949
  States of all valves.
1803
1950
  tanks_volume : `numpy.ndarray`
@@ -1874,6 +2021,20 @@ class SensorConfig(JsonSerializable):
1874
2021
  raise ValueError("Pump states readings requested " +
1875
2022
  "but no pump state data is given")
1876
2023
 
2024
+ if pumps_efficiency is not None:
2025
+ data.append(pumps_efficiency[:, self.__pump_efficiency_idx])
2026
+ else:
2027
+ if len(self.__pump_efficiency_sensors) != 0:
2028
+ raise ValueError("Pump efficiency readings requested " +
2029
+ "but no pump efficiency data is given")
2030
+
2031
+ if pumps_energyconsumption is not None:
2032
+ data.append(pumps_energyconsumption[:, self.__pump_energyconsumption_idx])
2033
+ else:
2034
+ if len(self.__pump_energyconsumption_sensors) != 0:
2035
+ raise ValueError("Pump energy consumption readings requested " +
2036
+ "but no pump energy consumption data is given")
2037
+
1877
2038
  if tanks_volume is not None:
1878
2039
  data.append(tanks_volume[:, self.__tank_volume_idx])
1879
2040
  else:
@@ -1913,7 +2074,9 @@ class SensorConfig(JsonSerializable):
1913
2074
  def get_index_of_reading(self, pressure_sensor: str = None, flow_sensor: str = None,
1914
2075
  demand_sensor: str = None, node_quality_sensor: str = None,
1915
2076
  link_quality_sensor: str = None, valve_state_sensor: str = None,
1916
- pump_state_sensor: str = None, tank_volume_sensor: str = None,
2077
+ pump_state_sensor: str = None, pump_efficiency_sensor: str = None,
2078
+ pump_energyconsumption_sensor: str = None,
2079
+ tank_volume_sensor: str = None,
1917
2080
  bulk_species_node_sensor: tuple[str, str] = None,
1918
2081
  bulk_species_link_sensor: tuple[str, str] = None,
1919
2082
  surface_species_sensor: tuple[str, str] = None) -> int:
@@ -1943,6 +2106,10 @@ class SensorConfig(JsonSerializable):
1943
2106
  ID of the state sensor (at a valve).
1944
2107
  pump_state_sensor : `str`
1945
2108
  ID of the state sensor (at a pump).
2109
+ pump_efficiency_sensor : `str`
2110
+ ID of the efficiency sensor (at a pump).
2111
+ pump_energyconsumption_sensor : `str`
2112
+ ID of the energy consumption sensor (at a pump).
1946
2113
  tank_volume_sensor : `str`
1947
2114
  ID of the water volume sensor (at a tank)
1948
2115
  bulk_species_node_sensor : `tuple[str, str]`
@@ -1966,6 +2133,10 @@ class SensorConfig(JsonSerializable):
1966
2133
  return self.__sensors_id_to_idx["valve_state"][valve_state_sensor]
1967
2134
  elif pump_state_sensor is not None:
1968
2135
  return self.__sensors_id_to_idx["pump_state"][pump_state_sensor]
2136
+ elif pump_efficiency_sensor is not None:
2137
+ return self.__sensors_id_to_idx["pump_efficiency"][pump_efficiency_sensor]
2138
+ elif pump_energyconsumption_sensor is not None:
2139
+ return self.__sensors_id_to_idx["pump_energyconsumption"][pump_energyconsumption_sensor]
1969
2140
  elif tank_volume_sensor is not None:
1970
2141
  return self.__sensors_id_to_idx["tank_volume"][tank_volume_sensor]
1971
2142
  elif surface_species_sensor is not None:
epyt_flow/topology.py CHANGED
@@ -188,6 +188,17 @@ class NetworkTopology(nx.Graph, JsonSerializable):
188
188
  """
189
189
  return [node_id for node_id, _ in self.__nodes]
190
190
 
191
+ def get_number_of_nodes(self) -> int:
192
+ """
193
+ Returns the number of nodes.
194
+
195
+ Returns
196
+ -------
197
+ `int`
198
+ Number of nodes.
199
+ """
200
+ return len(self.get_all_nodes())
201
+
191
202
  def get_all_links(self) -> list[tuple[str, tuple[str, str]]]:
192
203
  """
193
204
  Gets a list of all links/pipes (incl. their end points).
@@ -199,6 +210,17 @@ class NetworkTopology(nx.Graph, JsonSerializable):
199
210
  """
200
211
  return [(link_id, end_points) for link_id, end_points, _ in self.__links]
201
212
 
213
+ def get_number_of_links(self) -> int:
214
+ """
215
+ Returns the number of links.
216
+
217
+ Returns
218
+ -------
219
+ `int`
220
+ Number of links.
221
+ """
222
+ return len(self.get_all_links())
223
+
202
224
  def get_all_junctions(self) -> list[str]:
203
225
  """
204
226
  Gets all junctions -- i.e. nodes that are not tanks or reservoirs.
@@ -216,6 +238,17 @@ class NetworkTopology(nx.Graph, JsonSerializable):
216
238
 
217
239
  return r
218
240
 
241
+ def get_number_of_junctions(self) -> int:
242
+ """
243
+ Returns the number of junctions.
244
+
245
+ Returns
246
+ -------
247
+ `int`
248
+ Number of junctions.
249
+ """
250
+ return len(self.get_all_junctions())
251
+
219
252
  def get_all_tanks(self) -> list[str]:
220
253
  """
221
254
  Gets all tanks -- i.e. nodes that are not junctions or reservoirs.
@@ -233,6 +266,17 @@ class NetworkTopology(nx.Graph, JsonSerializable):
233
266
 
234
267
  return r
235
268
 
269
+ def get_number_of_tanks(self) -> int:
270
+ """
271
+ Returns the number of tanks.
272
+
273
+ Returns
274
+ -------
275
+ `int`
276
+ Number of tanks.
277
+ """
278
+ return len(self.get_all_tanks())
279
+
236
280
  def get_all_reservoirs(self) -> list[str]:
237
281
  """
238
282
  Gets all reservoirs -- i.e. nodes that are not junctions or tanks.
@@ -250,6 +294,17 @@ class NetworkTopology(nx.Graph, JsonSerializable):
250
294
 
251
295
  return r
252
296
 
297
+ def get_number_of_reservoirs(self) -> int:
298
+ """
299
+ Returns the number of reservoirs.
300
+
301
+ Returns
302
+ -------
303
+ `int`
304
+ Number of reservoirs.
305
+ """
306
+ return len(self.get_all_reservoirs())
307
+
253
308
  def get_all_pipes(self) -> list[tuple[str, tuple[str, str]]]:
254
309
  """
255
310
  Gets all pipes -- i.e. links that not valves or pumps.
@@ -269,6 +324,17 @@ class NetworkTopology(nx.Graph, JsonSerializable):
269
324
 
270
325
  return r
271
326
 
327
+ def get_number_of_pipes(self) -> int:
328
+ """
329
+ Returns the number of pipes.
330
+
331
+ Returns
332
+ -------
333
+ `int`
334
+ Number of pipes.
335
+ """
336
+ return len(self.get_all_pipes())
337
+
272
338
  def get_all_pumps(self) -> list[str]:
273
339
  """
274
340
  Gets the IDs of all pumps.
@@ -278,7 +344,18 @@ class NetworkTopology(nx.Graph, JsonSerializable):
278
344
  `list[str]`
279
345
  Pump IDs.
280
346
  """
281
- return self.__pumps.keys()
347
+ return list(self.__pumps.keys())
348
+
349
+ def get_number_of_pumps(self) -> int:
350
+ """
351
+ Returns the number of pumps.
352
+
353
+ Returns
354
+ -------
355
+ `int`
356
+ Number of pumps.
357
+ """
358
+ return len(self.get_all_pumps())
282
359
 
283
360
  def get_all_valves(self) -> list[str]:
284
361
  """
@@ -289,7 +366,18 @@ class NetworkTopology(nx.Graph, JsonSerializable):
289
366
  `list[str]`
290
367
  Valve IDs.
291
368
  """
292
- return self.__valves.keys()
369
+ return list(self.__valves.keys())
370
+
371
+ def get_number_of_valves(self) -> int:
372
+ """
373
+ Returns the number of valves.
374
+
375
+ Returns
376
+ -------
377
+ `int`
378
+ Number of valves.
379
+ """
380
+ return len(self.get_all_valves())
293
381
 
294
382
  def get_node_info(self, node_id: str) -> dict:
295
383
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: epyt-flow
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: EPyT-Flow -- EPANET Python Toolkit - Flow
5
5
  Author-email: André Artelt <aartelt@techfak.uni-bielefeld.de>, "Marios S. Kyriakou" <kiriakou.marios@ucy.ac.cy>, "Stelios G. Vrachimis" <vrachimis.stelios@ucy.ac.cy>
6
6
  License: MIT License
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.12
20
20
  Requires-Python: >=3.9
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: epyt >=1.1.6
23
+ Requires-Dist: epyt >=1.1.9
24
24
  Requires-Dist: requests >=2.31.0
25
25
  Requires-Dist: scipy >=1.11.4
26
26
  Requires-Dist: u-msgpack-python >=2.8.0
@@ -1,8 +1,8 @@
1
- epyt_flow/VERSION,sha256=oK1QZAE5pST4ZZEVcUW_HUZ06pwGW_6iFVjw97BEMMg,6
1
+ epyt_flow/VERSION,sha256=l6XW5UCmEg0Jw53bZn4Ojiusf8wv_vgTuC4I_WA2W84,6
2
2
  epyt_flow/__init__.py,sha256=KNDiPWiHdB9a5ZF1ipjA1uoq61TwU2ThjaStpvSLBtY,1742
3
3
  epyt_flow/metrics.py,sha256=kvt42pzZrUR9PSlCyK4uq5kj6UlYHkt7OcCjLnI1RQE,12883
4
- epyt_flow/serialization.py,sha256=nBcwc3aMUbHF0zW8Nvpc49kKeLPh75blc3gzjKDR1ok,12893
5
- epyt_flow/topology.py,sha256=yKIspoX4uoo9rAeVR5eWJ6D91QNozHzvzjiry9bFkNI,23424
4
+ epyt_flow/serialization.py,sha256=YhqDFZ7FLLcYOPnhOQdS0K8uyqM6bIXOkKDzGJQ-d3o,13075
5
+ epyt_flow/topology.py,sha256=pWG3Cq48Kq-mql-Lg3HUwvj5BGN0SrySa_OfDYNcGxg,25244
6
6
  epyt_flow/utils.py,sha256=AB2MuknQ_16UE-URQe1WShIS7dmSyFwZYVHxMVT539k,12379
7
7
  epyt_flow/EPANET/compile_linux.sh,sha256=wcrDyiB8NkivmaC-X9FI2WxhY3IJqDLiyIbVTv2XEPY,489
8
8
  epyt_flow/EPANET/compile_macos.sh,sha256=1K33-bPdgr01EIf87YUvmOFHXyOkBWI6mKXQ8x1Hzmo,504
@@ -80,19 +80,19 @@ epyt_flow/EPANET/EPANET-MSX/Src/smatrix.h,sha256=heHTNgQNNDTs_Jx0YBts7_B7dPg8VUF
80
80
  epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx.h,sha256=L9y0VKHk5Fg1JZxID9uBzcvLZWOb1xuQP-MkmHH_LD4,3429
81
81
  epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx_export.h,sha256=h5UMaf6pH_0asRJOmhWUGAZhyA180ui2Cz8_y5h1FKw,1054
82
82
  epyt_flow/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
- epyt_flow/data/networks.py,sha256=Ct-3tNEJPq6EooGWHr_Hz4vkkNYjv-QgiSwNKOTZ-oM,38526
83
+ epyt_flow/data/networks.py,sha256=ieL_rIQ21Wqm4_Ois2IyI54Qkv0R2FbbQfqA4MtsmQA,38393
84
84
  epyt_flow/data/benchmarks/__init__.py,sha256=nJ6hqPaPNp8YMizniev3fwOWpzvvNUBMoRF16wACUkE,754
85
85
  epyt_flow/data/benchmarks/batadal.py,sha256=sa_OZwO5XIbJONgGMwgok-KCGyHq07WpIQagVq-a-gw,11175
86
86
  epyt_flow/data/benchmarks/batadal_data.py,sha256=oIzcysGivMPAgrfzrk5l8i-j6Ii96DPcFa6sL4TSaw8,880
87
- epyt_flow/data/benchmarks/battledim.py,sha256=K0j9tbfxuXJmqBQY_e5XBJZGDYavaOZ7efkCT96Fb8A,20167
87
+ epyt_flow/data/benchmarks/battledim.py,sha256=yLwiQB0x7yq197XSM77tjHm7E7ucTbrybFaNxZx2TtM,20448
88
88
  epyt_flow/data/benchmarks/battledim_data.py,sha256=0vHm-2eAiLv6U-n5dqUUWS1o_szFRy9mVJ3eqDRp4PE,3373
89
89
  epyt_flow/data/benchmarks/gecco_water_quality.py,sha256=1buZRJiNf4jsqWYg4Ud90GhqaiLVo4yij3RAZJkzsqE,10985
90
- epyt_flow/data/benchmarks/leakdb.py,sha256=Z_ah6FXAyN4M7dn4jH0qYFmKTtViNHd6Jn2L9I6nMYg,24952
90
+ epyt_flow/data/benchmarks/leakdb.py,sha256=iNgGVTQT7Sl8xXC1iCyTZTJ0OHXW_n5uqsM7NBTIBHU,25046
91
91
  epyt_flow/data/benchmarks/leakdb_data.py,sha256=FNssgMkC1wqWVlaOrrihr4Od9trEZY7KeK5KuBeRMvM,507058
92
92
  epyt_flow/data/benchmarks/water_usage.py,sha256=FLqjff3pha33oEU9ZM3UGPXn9eJJumsJH8Gdj7YFX3A,4778
93
93
  epyt_flow/gym/__init__.py,sha256=KNTDtPTEtHwZ4ehHfj9qGw81Z9acFqPIgMzYUzH5_uM,115
94
94
  epyt_flow/gym/control_gyms.py,sha256=xbq1gjUC2i-TR_0jXBxXFM24lo_ykHLqMEEpmXPaGq0,1281
95
- epyt_flow/gym/scenario_control_env.py,sha256=YAej2YJzZD5bnQSkPNZRcHWdQzLLieGktKBHmdGBb9s,2950
95
+ epyt_flow/gym/scenario_control_env.py,sha256=vOadWpjpdcdwcypu0vy0DBkJZODsXnT1tArGQsmsgoM,6789
96
96
  epyt_flow/models/__init__.py,sha256=be5s08y1Tg66SuNYKGz5GnNMHThnQJo8SWJdT9493Kc,75
97
97
  epyt_flow/models/event_detector.py,sha256=idR7byBgloo07XEJEyMIwi49VW4wxJErLQtI-tJXWPs,789
98
98
  epyt_flow/models/sensor_interpolation_detector.py,sha256=5MBK9WlliGPonrNApf0j9lp-NjwF0iTwPDXx4yv7Fa0,3624
@@ -111,10 +111,10 @@ epyt_flow/rest_api/scenario/simulation_handlers.py,sha256=oY1Ch6ZQgYT_5WeE1I7tvG
111
111
  epyt_flow/rest_api/scenario/uncertainty_handlers.py,sha256=uuu6AP11ZZUp2P3Dnukjg5ZTjyYKljlubg1xLN1GnXY,4048
112
112
  epyt_flow/simulation/__init__.py,sha256=VGGJqJRUoXZjKJ0-m6KPp3JQqD_1TFW0pofLgkwZJ8M,164
113
113
  epyt_flow/simulation/parallel_simulation.py,sha256=VmC7xemjxRB_N0fx1AAQ7ux82tnyTi7jk7jfFpeg7gM,6523
114
- epyt_flow/simulation/scenario_config.py,sha256=_Zs0EPyfet0mTLpAt-oMN3k7jCW3x7_VbOQHpHVntrA,26597
115
- epyt_flow/simulation/scenario_simulator.py,sha256=1amMxO-PVHBU_AN6K9Ga6xzFmpaX2ZZnhwkirtj6IgY,93036
114
+ epyt_flow/simulation/scenario_config.py,sha256=NyadeCihpR4bpsWVPj7J-1DU2w1CEN0pAo2yh0t8Xkg,26751
115
+ epyt_flow/simulation/scenario_simulator.py,sha256=_DINJgPVBdKds6hq0w4zJuCIoQVBnkqBwU04KIi5egY,101950
116
116
  epyt_flow/simulation/scenario_visualizer.py,sha256=fpj67zl69q-byg7Oxocqhmu1S3P7B3ROCkSYzWyM--0,2187
117
- epyt_flow/simulation/sensor_config.py,sha256=MGeerEnLhyFLE6XA2p-X9Swd4k0o0T7QboeGuTUFq7I,81584
117
+ epyt_flow/simulation/sensor_config.py,sha256=HSNT8BAfWo0G4k5PXI8BhWDl8YzpS8CYJqlv0pmbPZc,90921
118
118
  epyt_flow/simulation/events/__init__.py,sha256=tIdqzs7_Cus4X2kbZG4Jl2zs-zsk_4rnajFOCvL0zlI,185
119
119
  epyt_flow/simulation/events/actuator_events.py,sha256=2_MPYbYO9As6fMkm5Oy9pjSB9kCvFuKpGu8ykYDAydg,7903
120
120
  epyt_flow/simulation/events/event.py,sha256=kARPV20XCAl6zxnJwI9U7ICtZUPACO_rgAmtHm1mGCs,2603
@@ -124,16 +124,16 @@ epyt_flow/simulation/events/sensor_reading_attack.py,sha256=bo5VavArN0wD5AHbIXJC
124
124
  epyt_flow/simulation/events/sensor_reading_event.py,sha256=rQ-CmdpSUyZzDFYwNUGH2jGoj0oyU-aAb-7E8Oshhqw,6785
125
125
  epyt_flow/simulation/events/system_event.py,sha256=0KI2iaAaOyC9Y-FIfFVazeKT_4ORQRp26gWyMBUu_3c,2396
126
126
  epyt_flow/simulation/scada/__init__.py,sha256=ZFAxJVqwEVsgiyFilFetnb13gPhZg1JEOPWYvKIJT4c,90
127
- epyt_flow/simulation/scada/advanced_control.py,sha256=Enox02ggt36HdFLX7ZNxgxuqsTEeu9AACHrzU8CXGrg,4489
128
- epyt_flow/simulation/scada/scada_data.py,sha256=WaFSppBHvJOwSyLYNs9Pu2GngSzWsfkpqPfBQoeiEcU,105101
127
+ epyt_flow/simulation/scada/advanced_control.py,sha256=5h7dmSMcNlTE7TMZa8gQVnOCGMf7uZy60r9aOfKDxMc,4487
128
+ epyt_flow/simulation/scada/scada_data.py,sha256=YBgVfs2L85XQxHRcC4-X-yTudB2E8p2oYCxqazPrI9k,110586
129
129
  epyt_flow/simulation/scada/scada_data_export.py,sha256=0BwDgV-5qZx17wIyWQ8Nl2TPgho3mBI49027RDq8sDA,11217
130
130
  epyt_flow/uncertainty/__init__.py,sha256=ZRjuJL9rDpWVSdPwObPxFpEmMTcgAl3VmPOsS6cIyGg,89
131
131
  epyt_flow/uncertainty/model_uncertainty.py,sha256=-2QT2AffZerKZyZ_w_mmeqYpfBALyPDvV61sCrvcK1o,13966
132
132
  epyt_flow/uncertainty/sensor_noise.py,sha256=zJVULxnxVPSSqc6UW0iwZ9O-HGf9dn4CwScPqf4yCY0,2324
133
133
  epyt_flow/uncertainty/uncertainties.py,sha256=X-o7GZUC0HELtzpoXIAJaAeYOw35N05TuRoSmStcCpI,17669
134
134
  epyt_flow/uncertainty/utils.py,sha256=gq66c9-QMOxOqI6wgWLyFxjVV0fbG0_8Yzd6mQjNYNo,5315
135
- epyt_flow-0.5.0.dist-info/LICENSE,sha256=-4hYIY2BLmCkdOv2_PehEwlnMKTCes8_oyIUXjKtkug,1076
136
- epyt_flow-0.5.0.dist-info/METADATA,sha256=a7kEbUctgxuMBJ06GNrwJnAlr_arMtcxHg-TZzSiD8M,7087
137
- epyt_flow-0.5.0.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
138
- epyt_flow-0.5.0.dist-info/top_level.txt,sha256=Wh_kd7TRL8ownCw3Y3dxx-9C0iTSk6wNauv_NX9JcrY,10
139
- epyt_flow-0.5.0.dist-info/RECORD,,
135
+ epyt_flow-0.6.0.dist-info/LICENSE,sha256=-4hYIY2BLmCkdOv2_PehEwlnMKTCes8_oyIUXjKtkug,1076
136
+ epyt_flow-0.6.0.dist-info/METADATA,sha256=8dlCwOkZghE4xDbbWWQ2dOjMBRGo8m48cZuzhmJ0_ds,7087
137
+ epyt_flow-0.6.0.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
138
+ epyt_flow-0.6.0.dist-info/top_level.txt,sha256=Wh_kd7TRL8ownCw3Y3dxx-9C0iTSk6wNauv_NX9JcrY,10
139
+ epyt_flow-0.6.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (70.1.1)
2
+ Generator: setuptools (71.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5