epyt-flow 0.14.2__py3-none-any.whl → 0.15.0b1__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.
Files changed (102) hide show
  1. epyt_flow/VERSION +1 -1
  2. epyt_flow/__init__.py +0 -37
  3. epyt_flow/data/benchmarks/battledim.py +2 -2
  4. epyt_flow/data/benchmarks/leakdb.py +12 -9
  5. epyt_flow/gym/scenario_control_env.py +32 -33
  6. epyt_flow/simulation/events/actuator_events.py +24 -18
  7. epyt_flow/simulation/events/leakages.py +59 -57
  8. epyt_flow/simulation/events/quality_events.py +21 -30
  9. epyt_flow/simulation/events/system_event.py +3 -3
  10. epyt_flow/simulation/scada/complex_control.py +14 -12
  11. epyt_flow/simulation/scada/custom_control.py +22 -21
  12. epyt_flow/simulation/scada/scada_data.py +107 -104
  13. epyt_flow/simulation/scada/simple_control.py +38 -31
  14. epyt_flow/simulation/scenario_simulator.py +367 -395
  15. epyt_flow/simulation/sensor_config.py +31 -32
  16. epyt_flow/topology.py +11 -10
  17. epyt_flow/uncertainty/model_uncertainty.py +146 -122
  18. epyt_flow/utils.py +0 -66
  19. epyt_flow/visualization/visualization_utils.py +2 -4
  20. {epyt_flow-0.14.2.dist-info → epyt_flow-0.15.0b1.dist-info}/METADATA +12 -18
  21. epyt_flow-0.15.0b1.dist-info/RECORD +65 -0
  22. epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +0 -28
  23. epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +0 -21
  24. epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +0 -18
  25. epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +0 -134
  26. epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +0 -5578
  27. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +0 -865
  28. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +0 -131
  29. epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +0 -73
  30. epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +0 -193
  31. epyt_flow/EPANET/EPANET/SRC_engines/genmmd.c +0 -1000
  32. epyt_flow/EPANET/EPANET/SRC_engines/hash.c +0 -177
  33. epyt_flow/EPANET/EPANET/SRC_engines/hash.h +0 -28
  34. epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +0 -1151
  35. epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +0 -1117
  36. epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +0 -720
  37. epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +0 -476
  38. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +0 -431
  39. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +0 -1786
  40. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +0 -468
  41. epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +0 -810
  42. epyt_flow/EPANET/EPANET/SRC_engines/input1.c +0 -707
  43. epyt_flow/EPANET/EPANET/SRC_engines/input2.c +0 -864
  44. epyt_flow/EPANET/EPANET/SRC_engines/input3.c +0 -2170
  45. epyt_flow/EPANET/EPANET/SRC_engines/main.c +0 -93
  46. epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +0 -142
  47. epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +0 -24
  48. epyt_flow/EPANET/EPANET/SRC_engines/output.c +0 -852
  49. epyt_flow/EPANET/EPANET/SRC_engines/project.c +0 -1359
  50. epyt_flow/EPANET/EPANET/SRC_engines/quality.c +0 -685
  51. epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +0 -743
  52. epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +0 -694
  53. epyt_flow/EPANET/EPANET/SRC_engines/report.c +0 -1489
  54. epyt_flow/EPANET/EPANET/SRC_engines/rules.c +0 -1362
  55. epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +0 -871
  56. epyt_flow/EPANET/EPANET/SRC_engines/text.h +0 -497
  57. epyt_flow/EPANET/EPANET/SRC_engines/types.h +0 -874
  58. epyt_flow/EPANET/EPANET-MSX/MSX_Updates.txt +0 -53
  59. epyt_flow/EPANET/EPANET-MSX/Src/dispersion.h +0 -27
  60. epyt_flow/EPANET/EPANET-MSX/Src/hash.c +0 -107
  61. epyt_flow/EPANET/EPANET-MSX/Src/hash.h +0 -28
  62. epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx.h +0 -102
  63. epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx_export.h +0 -42
  64. epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.c +0 -937
  65. epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.h +0 -39
  66. epyt_flow/EPANET/EPANET-MSX/Src/mempool.c +0 -204
  67. epyt_flow/EPANET/EPANET-MSX/Src/mempool.h +0 -24
  68. epyt_flow/EPANET/EPANET-MSX/Src/msxchem.c +0 -1285
  69. epyt_flow/EPANET/EPANET-MSX/Src/msxcompiler.c +0 -368
  70. epyt_flow/EPANET/EPANET-MSX/Src/msxdict.h +0 -42
  71. epyt_flow/EPANET/EPANET-MSX/Src/msxdispersion.c +0 -586
  72. epyt_flow/EPANET/EPANET-MSX/Src/msxerr.c +0 -116
  73. epyt_flow/EPANET/EPANET-MSX/Src/msxfile.c +0 -260
  74. epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.c +0 -175
  75. epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.h +0 -35
  76. epyt_flow/EPANET/EPANET-MSX/Src/msxinp.c +0 -1504
  77. epyt_flow/EPANET/EPANET-MSX/Src/msxout.c +0 -401
  78. epyt_flow/EPANET/EPANET-MSX/Src/msxproj.c +0 -791
  79. epyt_flow/EPANET/EPANET-MSX/Src/msxqual.c +0 -2010
  80. epyt_flow/EPANET/EPANET-MSX/Src/msxrpt.c +0 -400
  81. epyt_flow/EPANET/EPANET-MSX/Src/msxtank.c +0 -422
  82. epyt_flow/EPANET/EPANET-MSX/Src/msxtoolkit.c +0 -1164
  83. epyt_flow/EPANET/EPANET-MSX/Src/msxtypes.h +0 -551
  84. epyt_flow/EPANET/EPANET-MSX/Src/msxutils.c +0 -524
  85. epyt_flow/EPANET/EPANET-MSX/Src/msxutils.h +0 -56
  86. epyt_flow/EPANET/EPANET-MSX/Src/newton.c +0 -158
  87. epyt_flow/EPANET/EPANET-MSX/Src/newton.h +0 -34
  88. epyt_flow/EPANET/EPANET-MSX/Src/rk5.c +0 -287
  89. epyt_flow/EPANET/EPANET-MSX/Src/rk5.h +0 -39
  90. epyt_flow/EPANET/EPANET-MSX/Src/ros2.c +0 -293
  91. epyt_flow/EPANET/EPANET-MSX/Src/ros2.h +0 -35
  92. epyt_flow/EPANET/EPANET-MSX/Src/smatrix.c +0 -816
  93. epyt_flow/EPANET/EPANET-MSX/Src/smatrix.h +0 -29
  94. epyt_flow/EPANET/EPANET-MSX/readme.txt +0 -14
  95. epyt_flow/EPANET/compile_linux.sh +0 -4
  96. epyt_flow/EPANET/compile_macos.sh +0 -4
  97. epyt_flow/simulation/backend/__init__.py +0 -1
  98. epyt_flow/simulation/backend/my_epyt.py +0 -1101
  99. epyt_flow-0.14.2.dist-info/RECORD +0 -142
  100. {epyt_flow-0.14.2.dist-info → epyt_flow-0.15.0b1.dist-info}/WHEEL +0 -0
  101. {epyt_flow-0.14.2.dist-info → epyt_flow-0.15.0b1.dist-info}/licenses/LICENSE +0 -0
  102. {epyt_flow-0.14.2.dist-info → epyt_flow-0.15.0b1.dist-info}/top_level.txt +0 -0
@@ -17,7 +17,7 @@ import math
17
17
  import uuid
18
18
  import numpy as np
19
19
  from tqdm import tqdm
20
- from epyt.epanet import ToolkitConstants
20
+ from epanet_plus import EPyT, EpanetConstants
21
21
 
22
22
  from .scenario_config import ScenarioConfig
23
23
  from .sensor_config import SensorConfig, areaunit_to_id, massunit_to_id, qualityunit_to_id, \
@@ -31,7 +31,7 @@ from ..uncertainty import ModelUncertainty, SensorNoise
31
31
  from .events import SystemEvent, Leakage, ActuatorEvent, SensorFault, SensorReadingAttack, \
32
32
  SensorReadingEvent
33
33
  from .scada import ScadaData, CustomControlModule, SimpleControlModule, ComplexControlModule, \
34
- RuleCondition, RuleAction, ActuatorConstants, EN_R_ACTION_SETTING
34
+ RuleCondition, RuleAction, ActuatorConstants, EN_R_ACTION_SETTING, RULESTATUS
35
35
  from ..topology import NetworkTopology, UNITS_SIMETRIC, UNITS_USCUSTOM
36
36
  from ..utils import get_temp_folder
37
37
 
@@ -136,23 +136,6 @@ class ScenarioSimulator():
136
136
  self.__running_simulation = False
137
137
  self.__uncertainties_applied = False
138
138
 
139
- # Check availability of custom EPANET libraries
140
- custom_epanet_lib = None
141
- custom_epanetmsx_lib = None
142
- if sys.platform.startswith("linux") or sys.platform.startswith("darwin") :
143
- path_to_custom_libs = os.path.join(pathlib.Path(__file__).parent.resolve(),
144
- "..", "customlibs")
145
-
146
- libepanet_name = "libepanet2_2.so" if sys.platform.startswith("linux") \
147
- else "libepanet2_2.dylib"
148
- libepanetmsx_name = "libepanetmsx2_2_0.so" if sys.platform.startswith("linux") \
149
- else "libepanetmsx2_2_0.dylib"
150
-
151
- if os.path.isfile(os.path.join(path_to_custom_libs, libepanet_name)):
152
- custom_epanet_lib = os.path.join(path_to_custom_libs, libepanet_name)
153
- if os.path.isfile(os.path.join(path_to_custom_libs, libepanetmsx_name)):
154
- custom_epanetmsx_lib = os.path.join(path_to_custom_libs, libepanetmsx_name)
155
-
156
139
  # Workaround for EPyT bug concerning parallel simulations (see EPyT issue #54):
157
140
  # 1. Create random tmp folder (make sure it is unique!)
158
141
  # 2. Copy .inp and .msx file there
@@ -183,14 +166,11 @@ class ScenarioSimulator():
183
166
  else:
184
167
  my_f_msx_in = None
185
168
 
186
- from .backend import EPyT # Workaround: Sphinx autodoc "importlib.import_module TypeError: __mro_entries__"
187
- self.epanet_api = EPyT(my_f_inp_in, ph=self.__f_msx_in is None,
188
- customlib=custom_epanet_lib, loadfile=True,
189
- display_msg=epanet_verbose,
190
- display_warnings=False)
169
+ from epanet_plus import EPyT # Workaround: Sphinx autodoc "importlib.import_module TypeError: __mro_entries__"
170
+ self.epanet_api = EPyT(my_f_inp_in, use_project=self.__f_msx_in is None)
191
171
 
192
172
  if self.__f_msx_in is not None:
193
- self.epanet_api.loadMSXFile(my_f_msx_in, customMSXlib=custom_epanetmsx_lib)
173
+ self.epanet_api.load_msx_file(my_f_msx_in)
194
174
 
195
175
  # Do not raise exceptions in the case of EPANET warnings and errors
196
176
  self.epanet_api.set_error_handling(raise_exception_on_error=raise_exception_on_error,
@@ -225,8 +205,8 @@ class ScenarioSimulator():
225
205
  valve_id_to_idx: dict = None, pump_id_to_idx: dict = None,
226
206
  tank_id_to_idx: dict = None, bulkspecies_id_to_idx: dict = None,
227
207
  surfacespecies_id_to_idx: dict = None) -> SensorConfig:
228
- flow_unit = self.epanet_api.api.ENgetflowunits()
229
- quality_unit = qualityunit_to_id(self.epanet_api.getQualityInfo().QualityChemUnits)
208
+ flow_unit = self.epanet_api.getflowunits()
209
+ quality_unit = qualityunit_to_id(self.epanet_api.get_quality_info()["chemUnits"])
230
210
  bulk_species = []
231
211
  surface_species = []
232
212
  bulk_species_mass_unit = []
@@ -234,23 +214,22 @@ class ScenarioSimulator():
234
214
  surface_species_area_unit = None
235
215
 
236
216
  if self.__f_msx_in is not None:
237
- surface_species_area_unit = areaunit_to_id(self.epanet_api.getMSXAreaUnits())
217
+ surface_species_area_unit = areaunit_to_id("FT2")#self.epanet_api.get_msx_options()["areaUnits"])
238
218
 
239
- for species_id, species_type, mass_unit in zip(self.epanet_api.getMSXSpeciesNameID(),
240
- self.epanet_api.getMSXSpeciesType(),
241
- self.epanet_api.getMSXSpeciesUnits()):
242
- if species_type == "BULK":
219
+ for species_id, species_info in zip(self.epanet_api.get_all_msx_species_id(),
220
+ self.epanet_api.get_all_msx_species_info()):
221
+ if species_info["type"] == EpanetConstants.MSX_BULK:
243
222
  bulk_species.append(species_id)
244
- bulk_species_mass_unit.append(massunit_to_id(mass_unit))
245
- elif species_type == "WALL":
223
+ bulk_species_mass_unit.append(massunit_to_id(species_info["units"]))
224
+ elif species_info["type"] == EpanetConstants.MSX_WALL:
246
225
  surface_species.append(species_id)
247
- surface_species_mass_unit.append(massunit_to_id(mass_unit))
226
+ surface_species_mass_unit.append(massunit_to_id(species_info["units"]))
248
227
 
249
- return SensorConfig(nodes=self.epanet_api.getNodeNameID(),
250
- links=self.epanet_api.getLinkNameID(),
251
- valves=self.epanet_api.getLinkValveNameID(),
252
- pumps=self.epanet_api.getLinkPumpNameID(),
253
- tanks=self.epanet_api.getNodeTankNameID(),
228
+ return SensorConfig(nodes=self.epanet_api.get_all_nodes_id(),
229
+ links=self.epanet_api.get_all_links_id(),
230
+ valves=self.epanet_api.get_all_valves_id(),
231
+ pumps=self.epanet_api.get_all_pumps_id(),
232
+ tanks=self.epanet_api.get_all_tanks_id(),
254
233
  bulk_species=bulk_species,
255
234
  surface_species=surface_species,
256
235
  flow_unit=flow_unit,
@@ -490,31 +469,18 @@ class ScenarioSimulator():
490
469
  def _parse_simple_control_rules(self) -> list[SimpleControlModule]:
491
470
  controls = []
492
471
 
493
- for idx in self.epanet_api.getControls():
494
- control = self.epanet_api.getControls(idx)
472
+ for idx in range(self.epanet_api.get_num_controls()):
473
+ cond_type, link_idx, link_status, node_idx, level = \
474
+ self.epanet_api.getcontrol(idx + 1)
495
475
 
496
- if control.Setting == "OPEN":
497
- link_status = ActuatorConstants.EN_OPEN
498
- else:
499
- link_status = ActuatorConstants.EN_CLOSED
500
-
501
- if control.Type == "LOWLEVEL":
502
- cond_type = ToolkitConstants.EN_LOWLEVEL
503
- elif control.Type == "HIGHLEVEL":
504
- cond_type = ToolkitConstants.EN_HILEVEL
505
- elif control.Type == "TIMER":
506
- cond_type = ToolkitConstants.EN_TIMER
507
- elif control.Type == "TIMEOFDAY":
508
- cond_type = ToolkitConstants.EN_TIMEOFDAY
509
-
510
- if control.NodeID is not None:
511
- cond_var_value = control.NodeID
512
- cond_comp_value = control.Value
476
+ if node_idx != 0:
477
+ cond_var_value = self.epanet_api.get_node_id(node_idx)
478
+ cond_comp_value = level
513
479
  else:
514
- if cond_type == ToolkitConstants.EN_TIMER:
515
- cond_var_value = int(control.Value / 3600)
516
- elif cond_type == ToolkitConstants.EN_TIMEOFDAY:
517
- sec = control.Value
480
+ if cond_type == EpanetConstants.EN_TIMER:
481
+ cond_var_value = int(level / 3600)
482
+ elif cond_type == EpanetConstants.EN_TIMEOFDAY:
483
+ sec = level
518
484
  if sec <= 43200:
519
485
  cond_var_value = \
520
486
  f"{':'.join(str(timedelta(seconds=sec)).split(':')[:2])} AM"
@@ -524,7 +490,7 @@ class ScenarioSimulator():
524
490
  f"{':'.join(str(timedelta(seconds=sec)).split(':')[:2])} PM"
525
491
  cond_comp_value = None
526
492
 
527
- controls.append(SimpleControlModule(link_id=control.LinkID,
493
+ controls.append(SimpleControlModule(link_id=self.epanet_api.get_link_id(link_idx),
528
494
  link_status=link_status,
529
495
  cond_type=cond_type,
530
496
  cond_var_value=cond_var_value,
@@ -535,35 +501,30 @@ class ScenarioSimulator():
535
501
  def _parse_complex_control_rules(self) -> list[ComplexControlModule]:
536
502
  controls = []
537
503
 
538
- rules = self.epanet_api.getRules()
539
- for rule_idx, rule in rules.items():
540
- rule_info = self.epanet_api.getRuleInfo(rule_idx)
541
-
542
- rule_id = rule["Rule_ID"]
543
- rule_priority, *_ = rule_info.Priority
544
-
545
- # Parse conditions
546
- n_rule_premises, *_ = rule_info.Premises
504
+ all_rules_id = self.epanet_api.get_all_rules_id()
505
+ for rule_idx, rule_id in enumerate(all_rules_id, start=1):
506
+ n_rule_premises, n_rule_then_actions, n_rule_else_actions, rule_priority = \
507
+ self.epanet_api.getrule(rule_idx)
547
508
 
548
509
  condition_1 = None
549
510
  additional_conditions = []
550
511
  for j in range(1, n_rule_premises + 1):
551
512
  [logop, object_type_id, obj_idx, variable_type_id, relop, status, value_premise] = \
552
- self.epanet_api.api.ENgetpremise(rule_idx, j)
513
+ self.epanet_api.getpremise(rule_idx, j)
553
514
 
554
515
  object_id = None
555
- if object_type_id == ToolkitConstants.EN_R_NODE:
556
- object_id = self.epanet_api.getNodeNameID(obj_idx)
557
- elif object_type_id == ToolkitConstants.EN_R_LINK:
558
- object_id = self.epanet_api.getLinkNameID(obj_idx)
559
- elif object_type_id == ToolkitConstants.EN_R_SYSTEM:
516
+ if object_type_id == EpanetConstants.EN_R_NODE:
517
+ object_id = self.epanet_api.get_node_id(obj_idx)
518
+ elif object_type_id == EpanetConstants.EN_R_LINK:
519
+ object_id = self.epanet_api.get_link_id(obj_idx)
520
+ elif object_type_id == EpanetConstants.EN_R_SYSTEM:
560
521
  object_id = ""
561
522
 
562
- if variable_type_id >= ToolkitConstants.EN_R_TIME:
523
+ if variable_type_id >= EpanetConstants.EN_R_TIME:
563
524
  value_premise = datetime.fromtimestamp(value_premise)\
564
525
  .strftime("%I:%M %p")
565
526
  if status != 0:
566
- value_premise = self.epanet_api.RULESTATUS[status - 1]
527
+ value_premise = RULESTATUS[status - 1]
567
528
 
568
529
  condition = RuleCondition(object_type_id, object_id, variable_type_id,
569
530
  relop, value_premise)
@@ -573,14 +534,13 @@ class ScenarioSimulator():
573
534
  additional_conditions.append((logop, condition))
574
535
 
575
536
  # Parse actions
576
- n_rule_then_actions, *_ = rule_info.ThenActions
577
537
  actions = []
578
538
  for j in range(1, n_rule_then_actions + 1):
579
539
  [link_idx, link_status, link_setting] = \
580
- self.epanet_api.api.ENgetthenaction(rule_idx, j)
540
+ self.epanet_api.getthenaction(rule_idx, j)
581
541
 
582
- link_type_id = self.epanet_api.getLinkTypeIndex(link_idx)
583
- link_id = self.epanet_api.getLinkNameID(link_idx)
542
+ link_type_id = self.epanet_api.getlinktype(link_idx)
543
+ link_id = self.epanet_api.get_link_id(link_idx)
584
544
  if link_status >= 0:
585
545
  action_type_id = link_status
586
546
  action_value = link_status
@@ -590,14 +550,13 @@ class ScenarioSimulator():
590
550
 
591
551
  actions.append(RuleAction(link_type_id, link_id, action_type_id, action_value))
592
552
 
593
- n_rule_else_actions, *_ = rule_info.ElseActions
594
553
  else_actions = []
595
554
  for j in range(1, n_rule_else_actions + 1):
596
555
  [link_idx, link_status, link_setting] = \
597
- self.epanet_api.api.ENgetelseaction(rule_idx, j)
556
+ self.epanet_api.getelseaction(rule_idx, j)
598
557
 
599
- link_type_id = self.epanet_api.getLinkType(link_idx)
600
- link_id = self.epanet_api.getLinkNameID(link_idx)
558
+ link_type_id = self.epanet_api.getlinktype(link_idx)
559
+ link_id = self.epanet_api.get_link_id(link_idx)
601
560
  if link_status <= 3:
602
561
  action_type_id = link_status
603
562
  action_value = link_status
@@ -614,11 +573,11 @@ class ScenarioSimulator():
614
573
  return controls
615
574
 
616
575
  def _adapt_to_network_changes(self):
617
- nodes = self.epanet_api.getNodeNameID()
618
- links = self.epanet_api.getLinkNameID()
576
+ nodes = self.epanet_api.get_all_nodes_id()
577
+ links = self.epanet_api.get_all_links_id()
619
578
 
620
- node_id_to_idx = {node_id: self.epanet_api.getNodeIndex(node_id) - 1 for node_id in nodes}
621
- link_id_to_idx = {link_id: self.epanet_api.getLinkIndex(link_id) - 1 for link_id in links}
579
+ node_id_to_idx = {node_id: self.epanet_api.get_node_idx(node_id) - 1 for node_id in nodes}
580
+ link_id_to_idx = {link_id: self.epanet_api.get_link_idx(link_id) - 1 for link_id in links}
622
581
  valve_id_to_idx = None # {valve_id: self.epanet_api.getLinkValveIndex(valve_id) for valve_id in valves}
623
582
  pump_id_to_idx = None # {pump_id: self.epanet_api.getLinkPumpIndex(pump_id) - 1 for pump_id in pumps}
624
583
  tank_id_to_idx = None # {tank_id: self.epanet_api.getNodeTankIndex(tank_id) - 1 for tank_id in tanks}
@@ -653,10 +612,7 @@ class ScenarioSimulator():
653
612
 
654
613
  Call this function after the simulation is done -- do not call this function before!
655
614
  """
656
- if self.__f_msx_in is not None:
657
- self.epanet_api.unloadMSX()
658
-
659
- self.epanet_api.unload()
615
+ self.epanet_api.close()
660
616
 
661
617
  if self.__my_f_inp_in is not None:
662
618
  shutil.rmtree(pathlib.Path(self.__my_f_inp_in).parent)
@@ -737,7 +693,7 @@ class ScenarioSimulator():
737
693
  event.cleanup()
738
694
 
739
695
  if inp_file_path is not None:
740
- self.epanet_api.saveInputFile(inp_file_path)
696
+ self.epanet_api.saveinpfile(inp_file_path)
741
697
  self.__f_inp_in = inp_file_path
742
698
 
743
699
  if export_sensor_config is True:
@@ -792,7 +748,7 @@ class ScenarioSimulator():
792
748
  __override_report_section(inp_file_path, report_desc)
793
749
 
794
750
  if self.__f_msx_in is not None and msx_file_path is not None:
795
- self.epanet_api.saveMSXFile(msx_file_path)
751
+ self.epanet_api.MSXsavemsxfile(msx_file_path)
796
752
  self.__f_msx_in = msx_file_path
797
753
 
798
754
  if export_sensor_config is True:
@@ -845,7 +801,7 @@ class ScenarioSimulator():
845
801
  """
846
802
  Gets the flow units.
847
803
 
848
- Will be one of the following EPANET toolkit constants:
804
+ Will be one of the following EPANET constants:
849
805
 
850
806
  - EN_CFS = 0 (cu foot/sec)
851
807
  - EN_GPM = 1 (gal/min)
@@ -863,7 +819,7 @@ class ScenarioSimulator():
863
819
  `int`
864
820
  Flow units.
865
821
  """
866
- return self.epanet_api.api.ENgetflowunits()
822
+ return self.epanet_api.getflowunits()
867
823
 
868
824
  def get_units_category(self) -> int:
869
825
  """
@@ -879,9 +835,9 @@ class ScenarioSimulator():
879
835
  `int`
880
836
  Units category.
881
837
  """
882
- if self.get_flow_units() in [ToolkitConstants.EN_CFS, ToolkitConstants.EN_GPM,
883
- ToolkitConstants.EN_MGD, ToolkitConstants.EN_IMGD,
884
- ToolkitConstants.EN_AFD]:
838
+ if self.get_flow_units() in [EpanetConstants.EN_CFS, EpanetConstants.EN_GPM,
839
+ EpanetConstants.EN_MGD, EpanetConstants.EN_IMGD,
840
+ EpanetConstants.EN_AFD]:
885
841
  return UNITS_USCUSTOM
886
842
  else:
887
843
  return UNITS_SIMETRIC
@@ -895,7 +851,7 @@ class ScenarioSimulator():
895
851
  `int`
896
852
  Hydraulic time step in seconds.
897
853
  """
898
- return self.epanet_api.getTimeHydraulicStep()
854
+ return self.epanet_api.get_hydraulic_time_step()
899
855
 
900
856
  def get_quality_time_step(self) -> int:
901
857
  """
@@ -906,7 +862,7 @@ class ScenarioSimulator():
906
862
  `int`
907
863
  Quality time step in seconds.
908
864
  """
909
- return self.epanet_api.getTimeQualityStep()
865
+ return self.epanet_api.get_quality_time_step()
910
866
 
911
867
  def get_simulation_duration(self) -> int:
912
868
  """
@@ -917,7 +873,7 @@ class ScenarioSimulator():
917
873
  `int`
918
874
  Simulation duration in seconds.
919
875
  """
920
- return self.epanet_api.getTimeSimulationDuration()
876
+ return self.epanet_api.get_simulation_duration()
921
877
 
922
878
  def get_demand_model(self) -> dict:
923
879
  """
@@ -928,12 +884,12 @@ class ScenarioSimulator():
928
884
  `dict`
929
885
  Demand model.
930
886
  """
931
- demand_info = self.epanet_api.getDemandModel()
887
+ demand_info = self.epanet_api.get_demand_model()
932
888
 
933
- return {"type": "PDA" if demand_info.DemandModelCode == 1 else "DDA",
934
- "pressure_min": demand_info.DemandModelPmin,
935
- "pressure_required": demand_info.DemandModelPreq,
936
- "pressure_exponent": demand_info.DemandModelPexp}
889
+ return {"type": demand_info["type"],
890
+ "pressure_min": demand_info["pmin"],
891
+ "pressure_required": demand_info["preq"],
892
+ "pressure_exponent": demand_info["pexp"]}
937
893
 
938
894
  def get_quality_model(self) -> dict:
939
895
  """
@@ -947,13 +903,13 @@ class ScenarioSimulator():
947
903
  `dict`
948
904
  Quality model.
949
905
  """
950
- qual_info = self.epanet_api.getQualityInfo()
906
+ qual_info = self.epanet_api.get_quality_info()
951
907
 
952
- return {"code": qual_info.QualityCode,
953
- "type": qual_info.QualityType,
954
- "chemical_name": qual_info.QualityChemName,
955
- "units": qualityunit_to_id(qual_info.QualityChemUnits),
956
- "trace_node_id": qual_info.TraceNode}
908
+ return {"code": self.epanet_api.getqualtype(),
909
+ "type": qual_info["qualType"],
910
+ "chemical_name": qual_info["chemName"],
911
+ "units": qualityunit_to_id(qual_info["chemUnits"]),
912
+ "trace_node_id": qual_info["traceNode"]}
957
913
 
958
914
  def get_reporting_time_step(self) -> int:
959
915
  """
@@ -966,7 +922,7 @@ class ScenarioSimulator():
966
922
  `int`
967
923
  Reporting time steps in seconds.
968
924
  """
969
- return self.epanet_api.getTimeReportingStep()
925
+ return self.epanet_api.get_reporting_time_step()
970
926
 
971
927
  def get_scenario_config(self) -> ScenarioConfig:
972
928
  """
@@ -1011,14 +967,15 @@ class ScenarioSimulator():
1011
967
  """
1012
968
  self._adapt_to_network_changes()
1013
969
 
1014
- n_time_steps = int(self.epanet_api.getTimeSimulationDuration() /
1015
- self.epanet_api.getTimeReportingStep())
1016
- n_quantities = self.epanet_api.getNodeCount() * 3 + self.epanet_api.getNodeTankCount() + \
1017
- self.epanet_api.getLinkValveCount() + self.epanet_api.getLinkPumpCount() + \
1018
- self.epanet_api.getLinkCount() * 2
970
+ n_time_steps = int(self.epanet_api.get_simulation_duration() /
971
+ self.epanet_api.get_reporting_time_step())
972
+ n_quantities = self.epanet_api.get_num_nodes() * 3 + self.epanet_api.get_num_tanks() + \
973
+ self.epanet_api.get_num_valves() + self.epanet_api.get_num_pumps() + \
974
+ self.epanet_api.get_num_links() * 2
1019
975
 
1020
976
  if self.__f_msx_in is not None:
1021
- n_quantities += self.epanet_api.getLinkCount() * 2 + self.epanet_api.getNodeCount()
977
+ n_quantities += self.epanet_api.get_num_links() * 2 * self.epanet_api.get_num_msx_species() + \
978
+ self.epanet_api.get_num_nodes() * self.epanet_api.get_num_msx_species()
1022
979
 
1023
980
  n_bytes_per_quantity = 64
1024
981
 
@@ -1036,28 +993,39 @@ class ScenarioSimulator():
1036
993
  self._adapt_to_network_changes()
1037
994
 
1038
995
  # Collect information about the topology of the water distribution network
1039
- nodes_id = self.epanet_api.getNodeNameID()
1040
- nodes_elevation = self.epanet_api.getNodeElevations()
1041
- nodes_type = [self.epanet_api.TYPENODE[i] for i in self.epanet_api.getNodeTypeIndex()]
1042
- nodes_coord = [self.epanet_api.api.ENgetcoord(node_idx)
1043
- for node_idx in self.epanet_api.getNodeIndex()]
1044
- nodes_comments = self.epanet_api.getNodeComment()
1045
- node_tank_names = self.epanet_api.getNodeTankNameID()
1046
-
1047
- links_id = self.epanet_api.getLinkNameID()
1048
- links_type = self.epanet_api.getLinkType()
1049
- links_data = self.epanet_api.getNodesConnectingLinksID()
1050
- links_diameter = self.epanet_api.getLinkDiameter()
1051
- links_length = self.epanet_api.getLinkLength()
1052
- links_roughness_coeff = self.epanet_api.getLinkRoughnessCoeff()
1053
- links_bulk_coeff = self.epanet_api.getLinkBulkReactionCoeff()
1054
- links_wall_coeff = self.epanet_api.getLinkWallReactionCoeff()
1055
- links_loss_coeff = self.epanet_api.getLinkMinorLossCoeff()
1056
-
1057
- pumps_id = self.epanet_api.getLinkPumpNameID()
1058
- pumps_type = self.epanet_api.getLinkPumpType()
1059
-
1060
- valves_id = self.epanet_api.getLinkValveNameID()
996
+ nodes_id = self.epanet_api.get_all_nodes_id()
997
+ nodes_elevation = [self.epanet_api.get_node_elevation(node_idx)
998
+ for node_idx in self.epanet_api.get_all_nodes_idx()]
999
+ nodes_type = [self.epanet_api.get_node_type(node_idx)
1000
+ for node_idx in self.epanet_api.get_all_nodes_idx()]
1001
+ nodes_coord = [self.epanet_api.getcoord(node_idx)
1002
+ for node_idx in self.epanet_api.get_all_nodes_idx()]
1003
+ nodes_comments = [self.epanet_api.get_node_comment(node_idx)
1004
+ for node_idx in self.epanet_api.get_all_nodes_idx()]
1005
+ node_tank_names = self.epanet_api.get_all_tanks_id()
1006
+
1007
+ links_id = self.epanet_api.get_all_links_id()
1008
+ links_type = [self.epanet_api.get_link_type(link_idx)
1009
+ for link_idx in self.epanet_api.get_all_links_idx()]
1010
+ links_data = self.epanet_api.get_all_links_connecting_nodes_id()
1011
+ links_diameter = [self.epanet_api.get_link_diameter(link_idx)
1012
+ for link_idx in self.epanet_api.get_all_links_idx()]
1013
+ links_length = [self.epanet_api.get_link_length(link_idx)
1014
+ for link_idx in self.epanet_api.get_all_links_idx()]
1015
+ links_roughness_coeff = [self.epanet_api.get_link_roughness(link_idx)
1016
+ for link_idx in self.epanet_api.get_all_links_idx()]
1017
+ links_bulk_coeff = [self.epanet_api.get_link_bulk_raction_coeff(link_idx)
1018
+ for link_idx in self.epanet_api.get_all_links_idx()]
1019
+ links_wall_coeff = [self.epanet_api.get_link_wall_raction_coeff(link_idx)
1020
+ for link_idx in self.epanet_api.get_all_links_idx()]
1021
+ links_loss_coeff = [self.epanet_api.get_link_minorloss(link_idx)
1022
+ for link_idx in self.epanet_api.get_all_links_idx()]
1023
+
1024
+ pumps_id = self.epanet_api.get_all_pumps_id()
1025
+ pumps_type = [self.epanet_api.get_pump_type(pump_idx)
1026
+ for pump_idx in self.epanet_api.get_all_pumps_idx()]
1027
+
1028
+ valves_id = self.epanet_api.get_all_valves_id()
1061
1029
 
1062
1030
  # Build graph describing the topology
1063
1031
  nodes = []
@@ -1068,14 +1036,14 @@ class ScenarioSimulator():
1068
1036
  "coord": node_coord,
1069
1037
  "comment": node_comment,
1070
1038
  "type": node_type}
1071
- if node_type == "TANK":
1072
- node_tank_idx = node_tank_names.index(node_id) + 1
1073
- node_info["diameter"] = float(self.epanet_api.getNodeTankDiameter(node_tank_idx))
1074
- node_info["volume"] = float(self.epanet_api.getNodeTankVolume(node_tank_idx))
1075
- node_info["max_level"] = float(self.epanet_api.getNodeTankMaximumWaterLevel(node_tank_idx))
1076
- node_info["min_level"] = float(self.epanet_api.getNodeTankMinimumWaterLevel(node_tank_idx))
1077
- node_info["mixing_fraction"] = float(self.epanet_api.getNodeTankMixingFraction(node_tank_idx))
1078
- #node_info["mixing_model"] = int(self.epanet_api.getNodeTankMixingModelCode(node_tank_idx)[0])
1039
+ if node_type == EpanetConstants.EN_TANK:
1040
+ node_tank_idx = self.epanet_api.get_node_idx(node_id)
1041
+ node_info["diameter"] = float(self.epanet_api.get_tank_diameter(node_tank_idx))
1042
+ node_info["volume"] = float(self.epanet_api.get_tank_volume(node_tank_idx))
1043
+ node_info["max_level"] = float(self.epanet_api.get_tank_max_level(node_tank_idx))
1044
+ node_info["min_level"] = float(self.epanet_api.get_tank_min_level(node_tank_idx))
1045
+ node_info["mixing_fraction"] = float(self.epanet_api.get_tank_mix_fraction(node_tank_idx))
1046
+ node_info["mixing_model"] = int(self.epanet_api.get_tank_mix_model(node_tank_idx))
1079
1047
 
1080
1048
  nodes.append((node_id, node_info))
1081
1049
 
@@ -1132,23 +1100,21 @@ class ScenarioSimulator():
1132
1100
  self._adapt_to_network_changes()
1133
1101
 
1134
1102
  # Get all demand patterns
1135
- demand_patterns_idx = self.epanet_api.getNodeDemandPatternIndex()
1136
- demand_patterns_id = np.unique([idx for _, idx in demand_patterns_idx.items()])
1103
+ demand_patterns_idx = [self.epanet_api.get_node_demand_patterns_idx(node_idx)
1104
+ for node_idx in self.epanet_api.get_all_nodes_idx()]
1105
+ demand_patterns_idx = list(set(itertools.chain.from_iterable(demand_patterns_idx)))
1137
1106
 
1138
1107
  # Process each pattern separately
1139
- for pattern_id in demand_patterns_id:
1140
- if pattern_id == 0:
1141
- continue
1142
-
1143
- pattern_length = self.epanet_api.getPatternLengths(pattern_id)
1108
+ for pattern_idx in demand_patterns_idx:
1109
+ pattern_length = self.epanet_api.getpatternlen(pattern_idx)
1144
1110
  pattern = []
1145
1111
  for t in range(pattern_length): # Get pattern
1146
- pattern.append(self.epanet_api.getPatternValue(pattern_id, t + 1))
1112
+ pattern.append(self.epanet_api.getpatternvalue(pattern_idx, t + 1))
1147
1113
 
1148
1114
  random.shuffle(pattern) # Shuffle pattern
1149
1115
 
1150
1116
  for t in range(pattern_length): # Set shuffled/randomized pattern
1151
- self.epanet_api.setPatternValue(pattern_id, t + 1, pattern[t])
1117
+ self.epanet_api.setpatternvalue(pattern_idx, t + 1, pattern[t])
1152
1118
 
1153
1119
  def get_pattern(self, pattern_id: str) -> np.ndarray:
1154
1120
  """
@@ -1168,13 +1134,11 @@ class ScenarioSimulator():
1168
1134
  raise TypeError("'pattern_id' must be an instance of 'str' " +
1169
1135
  f"but not of '{type(pattern_id)}'")
1170
1136
 
1171
- pattern_idx = self.epanet_api.getPatternIndex(pattern_id)
1137
+ pattern_idx = self.epanet_api.getpatternindex(pattern_id)
1172
1138
  if pattern_idx == 0:
1173
1139
  raise ValueError(f"Unknown pattern '{pattern_id}'")
1174
1140
 
1175
- pattern_length = self.epanet_api.getPatternLengths(pattern_idx)
1176
- return np.array([self.epanet_api.getPatternValue(pattern_idx, t+1)
1177
- for t in range(pattern_length)])
1141
+ return np.array(self.epanet_api.get_pattern(pattern_idx))
1178
1142
 
1179
1143
  def add_pattern(self, pattern_id: str, pattern: np.ndarray) -> None:
1180
1144
  """
@@ -1199,7 +1163,7 @@ class ScenarioSimulator():
1199
1163
  raise ValueError(f"Inconsistent pattern shape '{pattern.shape}' " +
1200
1164
  "detected. Expected a one dimensional array!")
1201
1165
 
1202
- pattern_idx = self.epanet_api.addPattern(pattern_id, pattern)
1166
+ pattern_idx = self.epanet_api.add_pattern(pattern_id, pattern.tolist())
1203
1167
  if pattern_idx == 0:
1204
1168
  raise RuntimeError("Failed to add pattern! " +
1205
1169
  "Maybe pattern name contains invalid characters or is too long?")
@@ -1223,21 +1187,21 @@ class ScenarioSimulator():
1223
1187
  if node_id not in self._sensor_config.nodes:
1224
1188
  raise ValueError(f"Unknown node '{node_id}'")
1225
1189
 
1226
- node_idx = self.epanet_api.getNodeIndex(node_id)
1227
- n_demand_categories = self.epanet_api.getNodeDemandCategoriesNumber(node_idx)
1190
+ node_idx = self.epanet_api.get_node_idx(node_id)
1191
+ n_demand_categories = self.epanet_api.getnumdemands(node_idx)
1228
1192
 
1229
1193
  if n_demand_categories == 0:
1230
1194
  return None
1231
1195
  else:
1232
1196
  base_demand = 0
1233
- for demand_category in range(n_demand_categories):
1234
- base_demand += self.epanet_api.getNodeBaseDemands(node_idx)[demand_category + 1]
1197
+ for demand_idx in range(n_demand_categories):
1198
+ base_demand += self.epanet_api.getbasedemand(node_idx)[demand_idx + 1]
1235
1199
 
1236
1200
  return base_demand
1237
1201
 
1238
1202
  def get_node_demand_pattern(self, node_id: str) -> np.ndarray:
1239
1203
  """
1240
- Returns the values of the demand pattern of a given node --
1204
+ Returns the values of the primary demand pattern of a given node --
1241
1205
  i.e. multiplier factors that are applied to the base demand.
1242
1206
 
1243
1207
  Parameters
@@ -1256,10 +1220,14 @@ class ScenarioSimulator():
1256
1220
  if node_id not in self._sensor_config.nodes:
1257
1221
  raise ValueError(f"Unknown node '{node_id}'")
1258
1222
 
1259
- node_idx = self.epanet_api.getNodeIndex(node_id)
1260
- demand_category = self.epanet_api.getNodeDemandCategoriesNumber()[node_idx]
1261
- demand_pattern_id = self.epanet_api.getNodeDemandPatternNameID()[demand_category][node_idx - 1]
1262
- return self.get_pattern(demand_pattern_id)
1223
+ node_idx = self.epanet_api.get_node_idx(node_id)
1224
+
1225
+ if self.epanet_api.getnodetype(node_idx) != EpanetConstants.EN_RESERVOIR:
1226
+ demand_pattern_idx = self.epanet_api.getdemandpattern(node_idx)
1227
+ else:
1228
+ demand_pattern_idx = self.epanet_api.getnodevalue(node_idx, EpanetConstants.EN_PATTERN)
1229
+
1230
+ return self.get_pattern(self.epanet_api.getpatternid(demand_pattern_idx))
1263
1231
 
1264
1232
  def set_node_demand_pattern(self, node_id: str, base_demand: float, demand_pattern_id: str,
1265
1233
  demand_pattern: np.ndarray = None) -> None:
@@ -1298,20 +1266,20 @@ class ScenarioSimulator():
1298
1266
  raise ValueError(f"Inconsistent demand pattern shape '{demand_pattern.shape}' " +
1299
1267
  "detected. Expected a one dimensional array!")
1300
1268
 
1301
- node_idx = self.epanet_api.getNodeIndex(node_id)
1269
+ node_idx = self.epanet_api.get_node_idx(node_id)
1302
1270
 
1303
- if demand_pattern_id not in self.epanet_api.getPatternNameID():
1271
+ if demand_pattern_id not in self.epanet_api.get_all_patterns_id():
1304
1272
  if demand_pattern is None:
1305
1273
  raise ValueError("'demand_pattern' can not be None if " +
1306
1274
  "'demand_pattern_id' does not already exist.")
1307
- self.epanet_api.addPattern(demand_pattern_id, demand_pattern)
1275
+ self.epanet_api.add_pattern(demand_pattern_id, demand_pattern.tolist())
1308
1276
  else:
1309
1277
  if demand_pattern is not None:
1310
- pattern_idx = self.epanet_api.getPatternIndex(demand_pattern_id)
1311
- self.epanet_api.setPattern(pattern_idx, demand_pattern)
1278
+ pattern_idx = self.epanet_api.get_node_pattern_idx(demand_pattern_id)
1279
+ self.epanet_api.set_pattern(pattern_idx, demand_pattern.tolist())
1312
1280
 
1313
- self.epanet_api.setNodeJunctionData(node_idx, self.epanet_api.getNodeElevations(node_idx),
1314
- base_demand, demand_pattern_id)
1281
+ self.epanet_api.setjuncdata(node_idx, self.epanet_api.get_node_elevation(node_idx),
1282
+ base_demand, demand_pattern_id)
1315
1283
 
1316
1284
  def add_custom_control(self, control: CustomControlModule) -> None:
1317
1285
  """
@@ -1349,13 +1317,20 @@ class ScenarioSimulator():
1349
1317
 
1350
1318
  if not any(c == control for c in self._simple_controls):
1351
1319
  self._simple_controls.append(control)
1352
- self.epanet_api.addControls(str(control))
1320
+
1321
+ link_idx = self.epanet_api.get_link_idx(control.link_id)
1322
+ cond_var_value = control.cond_var_value
1323
+ if control.cond_type == EpanetConstants.EN_LOWLEVEL or \
1324
+ control.cond_type == EpanetConstants.EN_HILEVEL:
1325
+ cond_var_value = self.epanet_api.get_node_idx(cond_var_value)
1326
+ self.epanet_api.addcontrol(control.cond_type, link_idx, control.link_status,
1327
+ cond_var_value, control.cond_comp_value)
1353
1328
 
1354
1329
  def remove_all_simple_controls(self) -> None:
1355
1330
  """
1356
1331
  Removes all simple EPANET controls from the scenario.
1357
1332
  """
1358
- self.epanet_api.deleteControls()
1333
+ self.epanet_api.remove_all_controls()
1359
1334
  self._simple_controls = []
1360
1335
 
1361
1336
  def remove_simple_control(self, control: SimpleControlModule) -> None:
@@ -1382,7 +1357,7 @@ class ScenarioSimulator():
1382
1357
  if control_idx is None:
1383
1358
  raise ValueError("Invalid/Unknown control module.")
1384
1359
 
1385
- self.epanet_api.deleteControls(control_idx)
1360
+ self.epanet_api.deletecontrol(control_idx)
1386
1361
  self._simple_controls.remove(control)
1387
1362
 
1388
1363
  def add_complex_control(self, control: ComplexControlModule) -> None:
@@ -1403,13 +1378,13 @@ class ScenarioSimulator():
1403
1378
 
1404
1379
  if not any(c == control for c in self._complex_controls):
1405
1380
  self._complex_controls.append(control)
1406
- self.epanet_api.addRules(str(control))
1381
+ self.epanet_api.addrule(str(control))
1407
1382
 
1408
1383
  def remove_all_complex_controls(self) -> None:
1409
1384
  """
1410
1385
  Removes all complex EPANET controls from the scenario.
1411
1386
  """
1412
- self.epanet_api.deleteRules()
1387
+ self.epanet_api.remove_all_rules()
1413
1388
  self._complex_controls = []
1414
1389
 
1415
1390
  def remove_complex_control(self, control: ComplexControlModule) -> None:
@@ -1428,12 +1403,13 @@ class ScenarioSimulator():
1428
1403
  "'epyt_flow.simulation.scada.ComplexControlModule' not of " +
1429
1404
  f"'{type(control)}'")
1430
1405
 
1431
- if control.rule_id not in self.epanet_api.getRuleID():
1406
+ all_rules_id = self.epanet_api.get_all_rules_id()
1407
+ if control.rule_id not in all_rules_id:
1432
1408
  raise ValueError("Invalid/Unknown control module. " +
1433
1409
  f"Can not find rule ID '{control.rule_id}'")
1434
1410
 
1435
- rule_idx = self.epanet_api.getRuleID().index(control.rule_id) + 1
1436
- self.epanet_api.deleteRules(rule_idx)
1411
+ rule_idx = all_rules_id.index(control.rule_id) + 1
1412
+ self.epanet_api.deleterule(rule_idx)
1437
1413
  self._complex_controls.remove(control)
1438
1414
 
1439
1415
  def add_leakage(self, leakage_event: Leakage) -> None:
@@ -1643,7 +1619,7 @@ class ScenarioSimulator():
1643
1619
  The default is False.
1644
1620
  """
1645
1621
  if junctions_only is True:
1646
- self.set_pressure_sensors(self.epanet_api.getNodeJunctionNameID())
1622
+ self.set_pressure_sensors(self.epanet_api.get_all_junctions_id())
1647
1623
  else:
1648
1624
  self.set_pressure_sensors(self._sensor_config.nodes)
1649
1625
 
@@ -2112,42 +2088,43 @@ class ScenarioSimulator():
2112
2088
  self._prepare_simulation(reapply_uncertainties)
2113
2089
 
2114
2090
  # Load pre-computed hydraulics
2115
- self.epanet_api.useMSXHydraulicFile(hyd_file_in)
2091
+ self.epanet_api.MSXusehydfile(hyd_file_in)
2116
2092
 
2117
2093
  # Initialize simulation
2118
- n_nodes = self.epanet_api.getNodeCount()
2119
- n_links = self.epanet_api.getLinkCount()
2094
+ n_nodes = self.epanet_api.get_num_nodes()
2095
+ n_links = self.epanet_api.get_num_links()
2120
2096
 
2121
- reporting_time_start = self.epanet_api.getTimeReportingStart()
2122
- reporting_time_step = self.epanet_api.getTimeReportingStep()
2123
- hyd_time_step = self.epanet_api.getTimeHydraulicStep()
2097
+ reporting_time_start = self.epanet_api.get_reporting_start_time()
2098
+ reporting_time_step = self.epanet_api.get_reporting_time_step()
2099
+ hyd_time_step = self.epanet_api.get_hydraulic_time_step()
2124
2100
 
2125
2101
  network_topo = self.get_topology()
2126
2102
 
2127
2103
  if use_quality_time_step_as_reporting_time_step is True:
2128
- quality_time_step = self.epanet_api.getMSXTimeStep()
2104
+ quality_time_step = self.epanet_api.get_msx_time_step()
2129
2105
  reporting_time_step = quality_time_step
2130
2106
  hyd_time_step = quality_time_step
2131
2107
 
2132
- self.epanet_api.initializeMSXQualityAnalysis(ToolkitConstants.EN_NOSAVE)
2108
+ self.epanet_api.MSXinit(EpanetConstants.EN_NOSAVE)
2133
2109
 
2134
2110
  self.__running_simulation = True
2135
2111
 
2136
- bulk_species_idx = self.epanet_api.getMSXSpeciesIndex(self._sensor_config.bulk_species)
2137
- surface_species_idx = self.epanet_api.getMSXSpeciesIndex(
2138
- self._sensor_config.surface_species)
2112
+ bulk_species_idx = [self.epanet_api.get_msx_species_idx(species_id)
2113
+ for species_id in self._sensor_config.bulk_species]
2114
+ surface_species_idx = [self.epanet_api.get_msx_species_idx(species_id)
2115
+ for species_id in self._sensor_config.surface_species]
2139
2116
 
2140
2117
  if verbose is True:
2141
2118
  print("Running EPANET-MSX ...")
2142
- n_iterations = math.ceil(self.epanet_api.getTimeSimulationDuration() /
2119
+ n_iterations = math.ceil(self.epanet_api.get_simulation_duration() /
2143
2120
  hyd_time_step)
2144
2121
  progress_bar = iter(tqdm(range(n_iterations + 1), ascii=True, desc="Time steps"))
2145
2122
 
2146
2123
  def __get_concentrations(init_qual=False):
2147
2124
  if init_qual is True:
2148
- msx_get_cur_value = self.epanet_api.msx.MSXgetinitqual
2125
+ msx_get_cur_value = self.epanet_api.MSXgetinitqual
2149
2126
  else:
2150
- msx_get_cur_value = self.epanet_api.getMSXSpeciesConcentration
2127
+ msx_get_cur_value = self.epanet_api.get_msx_species_concentration
2151
2128
 
2152
2129
  # Bulk species
2153
2130
  bulk_species_node_concentrations = []
@@ -2155,13 +2132,13 @@ class ScenarioSimulator():
2155
2132
  for species_idx in bulk_species_idx:
2156
2133
  cur_species_concentrations = []
2157
2134
  for node_idx in range(1, n_nodes + 1):
2158
- concen = msx_get_cur_value(0, node_idx, species_idx)
2135
+ concen = msx_get_cur_value(EpanetConstants.MSX_NODE, node_idx, species_idx)
2159
2136
  cur_species_concentrations.append(concen)
2160
2137
  bulk_species_node_concentrations.append(cur_species_concentrations)
2161
2138
 
2162
2139
  cur_species_concentrations = []
2163
2140
  for link_idx in range(1, n_links + 1):
2164
- concen = msx_get_cur_value(1, link_idx, species_idx)
2141
+ concen = msx_get_cur_value(EpanetConstants.MSX_LINK, link_idx, species_idx)
2165
2142
  cur_species_concentrations.append(concen)
2166
2143
  bulk_species_link_concentrations.append(cur_species_concentrations)
2167
2144
 
@@ -2183,7 +2160,7 @@ class ScenarioSimulator():
2183
2160
  cur_species_concentrations = []
2184
2161
 
2185
2162
  for link_idx in range(1, n_links + 1):
2186
- concen = msx_get_cur_value(1, link_idx, species_idx)
2163
+ concen = msx_get_cur_value(EpanetConstants.MSX_LINK, link_idx, species_idx)
2187
2164
  cur_species_concentrations.append(concen)
2188
2165
 
2189
2166
  surface_species_concentrations.append(cur_species_concentrations)
@@ -2208,7 +2185,7 @@ class ScenarioSimulator():
2208
2185
  pass
2209
2186
 
2210
2187
  if reporting_time_start == 0:
2211
- msx_error_code = self.epanet_api.msx.get_last_error_code()
2188
+ msx_error_code = self.epanet_api.get_last_error_code()
2212
2189
 
2213
2190
  if return_as_dict is True:
2214
2191
  data = {"bulk_species_node_concentration_raw": bulk_species_node_concentrations,
@@ -2241,8 +2218,8 @@ class ScenarioSimulator():
2241
2218
  last_msx_error_code = 0
2242
2219
  while tleft > 0:
2243
2220
  # Compute current time step
2244
- total_time, tleft = self.epanet_api.stepMSXQualityAnalysisTimeLeft()
2245
- msx_error_code = self.epanet_api.msx.get_last_error_code()
2221
+ total_time, tleft = self.epanet_api.MSXstep()
2222
+ msx_error_code = self.epanet_api.get_last_error_code()
2246
2223
  if last_msx_error_code == 0:
2247
2224
  last_msx_error_code = msx_error_code
2248
2225
 
@@ -2404,26 +2381,26 @@ class ScenarioSimulator():
2404
2381
  if self.__running_simulation is True:
2405
2382
  raise RuntimeError("A simulation is already running.")
2406
2383
 
2407
- requested_total_time = self.epanet_api.getTimeSimulationDuration()
2408
- requested_time_step = self.epanet_api.getTimeHydraulicStep()
2409
- reporting_time_start = self.epanet_api.getTimeReportingStart()
2410
- reporting_time_step = self.epanet_api.getTimeReportingStep()
2384
+ requested_total_time = self.epanet_api.get_simulation_duration()
2385
+ requested_time_step = self.epanet_api.get_hydraulic_time_step()
2386
+ reporting_time_start = self.epanet_api.get_reporting_start_time()
2387
+ reporting_time_step = self.epanet_api.get_reporting_time_step()
2411
2388
 
2412
2389
  if use_quality_time_step_as_reporting_time_step is True:
2413
- quality_time_step = self.epanet_api.getTimeQualityStep()
2390
+ quality_time_step = self.epanet_api.get_quality_time_step()
2414
2391
  requested_time_step = quality_time_step
2415
2392
  reporting_time_step = quality_time_step
2416
2393
 
2417
2394
  network_topo = self.get_topology()
2418
2395
 
2419
- self.epanet_api.useHydraulicFile(hyd_file_in)
2396
+ self.epanet_api.usehydfile(hyd_file_in)
2420
2397
 
2421
- self.epanet_api.openQualityAnalysis()
2422
- self.epanet_api.initializeQualityAnalysis(ToolkitConstants.EN_NOSAVE)
2398
+ self.epanet_api.openQ()
2399
+ self.epanet_api.initQ(EpanetConstants.EN_NOSAVE)
2423
2400
 
2424
2401
  if verbose is True:
2425
2402
  print("Running basic quality analysis using EPANET ...")
2426
- n_iterations = math.ceil(self.epanet_api.getTimeSimulationDuration() /
2403
+ n_iterations = math.ceil(self.epanet_api.get_simulation_duration() /
2427
2404
  requested_time_step)
2428
2405
  progress_bar = iter(tqdm(range(n_iterations + 1), ascii=True, desc="Time steps"))
2429
2406
 
@@ -2445,15 +2422,15 @@ class ScenarioSimulator():
2445
2422
  pass
2446
2423
 
2447
2424
  # Compute current time step
2448
- t = self.epanet_api.api.ENrunQ()
2425
+ t = self.epanet_api.runQ()
2449
2426
  total_time = t
2450
2427
 
2451
2428
  # Fetch data
2452
2429
  error_code = self.epanet_api.get_last_error_code()
2453
2430
  if last_error_code == 0:
2454
2431
  last_error_code = error_code
2455
- quality_node_data = self.epanet_api.getNodeActualQuality().reshape(1, -1)
2456
- quality_link_data = self.epanet_api.getLinkActualQuality().reshape(1, -1)
2432
+ quality_node_data = np.array(self.epanet_api.getnodevalues(EpanetConstants.EN_QUALITY)).reshape(1, -1)
2433
+ quality_link_data = np.array(self.epanet_api.getlinkvalues(EpanetConstants.EN_QUALITY)).reshape(1, -1)
2457
2434
 
2458
2435
  # Yield results in a regular time interval only!
2459
2436
  if total_time % reporting_time_step == 0 and total_time >= reporting_time_start:
@@ -2481,12 +2458,12 @@ class ScenarioSimulator():
2481
2458
  yield (data, total_time >= requested_total_time)
2482
2459
 
2483
2460
  # Next
2484
- tstep = self.epanet_api.api.ENstepQ()
2461
+ tstep = self.epanet_api.stepQ()
2485
2462
  error_code = self.epanet_api.get_last_error_code()
2486
2463
  if last_error_code == 0:
2487
2464
  last_error_code = error_code
2488
2465
 
2489
- self.epanet_api.closeQualityAnalysis()
2466
+ self.epanet_api.closeQ()
2490
2467
 
2491
2468
  def run_hydraulic_simulation(self, hyd_export: str = None, verbose: bool = False,
2492
2469
  frozen_sensor_config: bool = False,
@@ -2541,13 +2518,18 @@ class ScenarioSimulator():
2541
2518
  if result is None:
2542
2519
  result = {}
2543
2520
  for data_type, data in scada_data.items():
2544
- result[data_type] = [data]
2521
+ if data is None:
2522
+ result[data_type] = None
2523
+ else:
2524
+ result[data_type] = [data]
2545
2525
  else:
2546
2526
  for data_type, data in scada_data.items():
2547
- result[data_type].append(data)
2527
+ if result[data_type] is not None:
2528
+ result[data_type].append(data)
2548
2529
 
2549
2530
  for data_type in result:
2550
- result[data_type] = np.concatenate(result[data_type], axis=0)
2531
+ if result[data_type] is not None:
2532
+ result[data_type] = np.concatenate(result[data_type], axis=0)
2551
2533
 
2552
2534
  result = ScadaData(**result,
2553
2535
  network_topo=self.get_topology(),
@@ -2619,21 +2601,21 @@ class ScenarioSimulator():
2619
2601
 
2620
2602
  self.__running_simulation = True
2621
2603
 
2622
- self.epanet_api.api.ENopenH()
2623
- self.epanet_api.api.ENopenQ()
2624
- self.epanet_api.initializeHydraulicAnalysis(ToolkitConstants.EN_SAVE)
2625
- self.epanet_api.initializeQualityAnalysis(ToolkitConstants.EN_SAVE)
2604
+ self.epanet_api.openH()
2605
+ self.epanet_api.openQ()
2606
+ self.epanet_api.initH(EpanetConstants.EN_SAVE)
2607
+ self.epanet_api.initQ(EpanetConstants.EN_SAVE)
2626
2608
 
2627
- requested_total_time = self.epanet_api.getTimeSimulationDuration()
2628
- requested_time_step = self.epanet_api.getTimeHydraulicStep()
2629
- reporting_time_start = self.epanet_api.getTimeReportingStart()
2630
- reporting_time_step = self.epanet_api.getTimeReportingStep()
2609
+ requested_total_time = self.epanet_api.get_simulation_duration()
2610
+ requested_time_step = self.epanet_api.get_hydraulic_time_step()
2611
+ reporting_time_start = self.epanet_api.get_reporting_start_time()
2612
+ reporting_time_step = self.epanet_api.get_reporting_time_step()
2631
2613
 
2632
2614
  network_topo = self.get_topology()
2633
2615
 
2634
2616
  if verbose is True:
2635
2617
  print("Running EPANET ...")
2636
- n_iterations = math.ceil(self.epanet_api.getTimeSimulationDuration() /
2618
+ n_iterations = math.ceil(self.epanet_api.get_simulation_duration() /
2637
2619
  requested_time_step)
2638
2620
  progress_bar = iter(tqdm(range(n_iterations + 1), ascii=True, desc="Time steps"))
2639
2621
 
@@ -2661,9 +2643,9 @@ class ScenarioSimulator():
2661
2643
  event.step(total_time + tstep)
2662
2644
 
2663
2645
  # Compute current time step
2664
- t = self.epanet_api.api.ENrunH()
2646
+ t = self.epanet_api.runH()
2665
2647
  error_code = self.epanet_api.get_last_error_code()
2666
- self.epanet_api.api.ENrunQ()
2648
+ self.epanet_api.runQ()
2667
2649
  if error_code == 0:
2668
2650
  error_code = self.epanet_api.get_last_error_code()
2669
2651
  total_time = t
@@ -2671,20 +2653,32 @@ class ScenarioSimulator():
2671
2653
  last_error_code = error_code
2672
2654
 
2673
2655
  # Fetch data
2674
- pressure_data = self.epanet_api.getNodePressure().reshape(1, -1)
2675
- flow_data = self.epanet_api.getLinkFlows().reshape(1, -1)
2676
- demand_data = self.epanet_api.getNodeActualDemand().reshape(1, -1)
2677
- quality_node_data = self.epanet_api.getNodeActualQuality().reshape(1, -1)
2678
- quality_link_data = self.epanet_api.getLinkActualQuality().reshape(1, -1)
2679
- pumps_state_data = self.epanet_api.getLinkPumpState().reshape(1, -1)
2680
- tanks_volume_data = self.epanet_api.getNodeTankVolume().reshape(1, -1)
2681
-
2682
- pump_idx = self.epanet_api.getLinkPumpIndex()
2683
- pumps_energy_usage_data = self.epanet_api.getLinkEnergy(pump_idx).reshape(1, -1)
2684
- pumps_efficiency_data = self.epanet_api.getLinkPumpEfficiency().reshape(1, -1)
2685
-
2686
- link_valve_idx = self.epanet_api.getLinkValveIndex()
2687
- valves_state_data = self.epanet_api.getLinkStatus(link_valve_idx).reshape(1, -1)
2656
+ pressure_data = np.array(self.epanet_api.getnodevalues(EpanetConstants.EN_PRESSURE)).reshape(1, -1)
2657
+ flow_data = np.array(self.epanet_api.getlinkvalues(EpanetConstants.EN_FLOW)).reshape(1, -1)
2658
+ demand_data = np.array(self.epanet_api.getnodevalues(EpanetConstants.EN_DEMAND)).reshape(1, -1)
2659
+ quality_node_data = np.array(self.epanet_api.getnodevalues(EpanetConstants.EN_QUALITY)).reshape(1, -1)
2660
+ quality_link_data = np.array(self.epanet_api.getlinkvalues(EpanetConstants.EN_QUALITY)).reshape(1, -1)
2661
+
2662
+ tanks_volume_data = None
2663
+ if len(self.epanet_api.get_all_tanks_idx()) > 0:
2664
+ tanks_volume_data = np.array([self.epanet_api.get_tank_volume(tank_idx)
2665
+ for tank_idx in self.epanet_api.get_all_tanks_idx()]).reshape(1, -1)
2666
+
2667
+ pumps_state_data = None
2668
+ pumps_energy_usage_data = None
2669
+ pumps_efficiency_data = None
2670
+ if len(self.epanet_api.get_all_pumps_idx()) > 0:
2671
+ pumps_state_data = np.array([self.epanet_api.getlinkvalue(link_idx, EpanetConstants.EN_PUMP_STATE)
2672
+ for link_idx in self.epanet_api.get_all_pumps_idx()]).reshape(1, -1)
2673
+ pumps_energy_usage_data = np.array([self.epanet_api.get_pump_energy_usage(pump_idx)
2674
+ for pump_idx in self.epanet_api.get_all_pumps_idx()]).reshape(1, -1)
2675
+ pumps_efficiency_data = np.array([self.epanet_api.get_pump_efficiency(pump_idx)
2676
+ for pump_idx in self.epanet_api.get_all_pumps_idx()]).reshape(1, -1)
2677
+
2678
+ valves_state_data = None
2679
+ if len(self.epanet_api.get_all_valves_idx()) > 0:
2680
+ valves_state_data = np.array([self.epanet_api.getlinkvalue(link_valve_idx, EpanetConstants.EN_STATUS)
2681
+ for link_valve_idx in self.epanet_api.get_all_valves_idx()]).reshape(1, -1)
2688
2682
 
2689
2683
  scada_data = ScadaData(network_topo=network_topo,
2690
2684
  sensor_config=self._sensor_config,
@@ -2736,23 +2730,23 @@ class ScenarioSimulator():
2736
2730
  control.step(scada_data)
2737
2731
 
2738
2732
  # Next
2739
- tstep = self.epanet_api.api.ENnextH()
2733
+ tstep = self.epanet_api.nextH()
2740
2734
  error_code = self.epanet_api.get_last_error_code()
2741
2735
  if last_error_code == 0:
2742
2736
  last_error_code = error_code
2743
2737
 
2744
- self.epanet_api.api.ENnextQ()
2738
+ self.epanet_api.nextQ()
2745
2739
  error_code = self.epanet_api.get_last_error_code()
2746
2740
  if last_error_code == 0:
2747
2741
  last_error_code = error_code
2748
2742
 
2749
- self.epanet_api.api.ENcloseQ()
2750
- self.epanet_api.api.ENcloseH()
2743
+ self.epanet_api.closeQ()
2744
+ self.epanet_api.closeH()
2751
2745
 
2752
2746
  self.__running_simulation = False
2753
2747
 
2754
2748
  if hyd_export is not None:
2755
- self.epanet_api.saveHydraulicFile(hyd_export)
2749
+ self.epanet_api.savehydfile(hyd_export)
2756
2750
  except Exception as ex:
2757
2751
  self.__running_simulation = False
2758
2752
  raise ex
@@ -2929,7 +2923,7 @@ class ScenarioSimulator():
2929
2923
  Specifies the flow units -- i.e. all flows will be reported in these units.
2930
2924
  If None, the units from the .inp file will be used.
2931
2925
 
2932
- Must be one of the following EPANET toolkit constants:
2926
+ Must be one of the following EPANET constants:
2933
2927
 
2934
2928
  - EN_CFS = 0 (cubic foot/sec)
2935
2929
  - EN_GPM = 1 (gal/min)
@@ -2956,39 +2950,39 @@ class ScenarioSimulator():
2956
2950
  self._adapt_to_network_changes()
2957
2951
 
2958
2952
  if flow_units_id is not None:
2959
- if flow_units_id == ToolkitConstants.EN_CFS:
2960
- self.epanet_api.setFlowUnitsCFS()
2961
- elif flow_units_id == ToolkitConstants.EN_GPM:
2962
- self.epanet_api.setFlowUnitsGPM()
2963
- elif flow_units_id == ToolkitConstants.EN_MGD:
2964
- self.epanet_api.setFlowUnitsMGD()
2965
- elif flow_units_id == ToolkitConstants.EN_IMGD:
2966
- self.epanet_api.setFlowUnitsIMGD()
2967
- elif flow_units_id == ToolkitConstants.EN_AFD:
2968
- self.epanet_api.setFlowUnitsAFD()
2969
- elif flow_units_id == ToolkitConstants.EN_LPS:
2970
- self.epanet_api.setFlowUnitsLPS()
2971
- elif flow_units_id == ToolkitConstants.EN_LPM:
2972
- self.epanet_api.setFlowUnitsLPM()
2973
- elif flow_units_id == ToolkitConstants.EN_MLD:
2974
- self.epanet_api.setFlowUnitsMLD()
2975
- elif flow_units_id == ToolkitConstants.EN_CMH:
2976
- self.epanet_api.setFlowUnitsCMH()
2977
- elif flow_units_id == ToolkitConstants.EN_CMD:
2978
- self.epanet_api.setFlowUnitsCMD()
2953
+ if flow_units_id == EpanetConstants.EN_CFS:
2954
+ self.epanet_api.setflowunits(flow_units_id)
2955
+ elif flow_units_id == EpanetConstants.EN_GPM:
2956
+ self.epanet_api.setflowunits(flow_units_id)
2957
+ elif flow_units_id == EpanetConstants.EN_MGD:
2958
+ self.epanet_api.setflowunits(flow_units_id)
2959
+ elif flow_units_id == EpanetConstants.EN_IMGD:
2960
+ self.epanet_api.setflowunits(flow_units_id)
2961
+ elif flow_units_id == EpanetConstants.EN_AFD:
2962
+ self.epanet_api.setflowunits(flow_units_id)
2963
+ elif flow_units_id == EpanetConstants.EN_LPS:
2964
+ self.epanet_api.setflowunits(flow_units_id)
2965
+ elif flow_units_id == EpanetConstants.EN_LPM:
2966
+ self.epanet_api.setflowunits(flow_units_id)
2967
+ elif flow_units_id == EpanetConstants.EN_MLD:
2968
+ self.epanet_api.setflowunits(flow_units_id)
2969
+ elif flow_units_id == EpanetConstants.EN_CMH:
2970
+ self.epanet_api.setflowunits(flow_units_id)
2971
+ elif flow_units_id == EpanetConstants.EN_CMD:
2972
+ self.epanet_api.setflowunits(flow_units_id)
2979
2973
  else:
2980
2974
  raise ValueError(f"Unknown flow units '{flow_units_id}'")
2981
2975
 
2982
2976
  if demand_model is not None:
2983
- self.epanet_api.setDemandModel(demand_model["type"], demand_model["pressure_min"],
2984
- demand_model["pressure_required"],
2985
- demand_model["pressure_exponent"])
2977
+ self.epanet_api.set_demand_model(demand_model["type"], demand_model["pressure_min"],
2978
+ demand_model["pressure_required"],
2979
+ demand_model["pressure_exponent"])
2986
2980
 
2987
2981
  if simulation_duration is not None:
2988
2982
  if not isinstance(simulation_duration, int) or simulation_duration <= 0:
2989
2983
  raise ValueError("'simulation_duration' must be a positive integer specifying " +
2990
2984
  "the number of seconds to simulate")
2991
- self.epanet_api.setTimeSimulationDuration(simulation_duration)
2985
+ self.epanet_api.set_simulation_duration(simulation_duration)
2992
2986
 
2993
2987
  if hydraulic_time_step is not None:
2994
2988
  if not isinstance(hydraulic_time_step, int) or hydraulic_time_step <= 0:
@@ -2997,52 +2991,47 @@ class ScenarioSimulator():
2997
2991
  if len(self._system_events) != 0:
2998
2992
  raise RuntimeError("Hydraulic time step cannot be changed after system events " +
2999
2993
  "such as leakages have been added to the scenario")
3000
- self.epanet_api.setTimeHydraulicStep(hydraulic_time_step)
2994
+ self.epanet_api.set_hydraulic_time_step(hydraulic_time_step)
3001
2995
  if reporting_time_step is None:
3002
2996
  warnings.warn("No report time steps specified -- using 'hydraulic_time_step'")
3003
- self.epanet_api.setTimeReportingStep(hydraulic_time_step)
2997
+ self.epanet_api.set_reporting_time_step(hydraulic_time_step)
3004
2998
 
3005
2999
  if reporting_time_step is not None:
3006
- hydraulic_time_step = self.epanet_api.getTimeHydraulicStep()
3000
+ hydraulic_time_step = self.epanet_api.get_hydraulic_time_step()
3007
3001
  if not isinstance(reporting_time_step, int) or \
3008
3002
  reporting_time_step % hydraulic_time_step != 0:
3009
3003
  raise ValueError("'reporting_time_step' must be a positive integer " +
3010
3004
  "and a multiple of 'hydraulic_time_step'")
3011
- self.epanet_api.setTimeReportingStep(reporting_time_step)
3005
+ self.epanet_api.set_reporting_time_step(reporting_time_step)
3012
3006
 
3013
3007
  if reporting_time_start is not None:
3014
3008
  if not isinstance(reporting_time_start, int) or reporting_time_start <= 0:
3015
3009
  raise ValueError("'reporting_time_start' must be a positive integer specifying " +
3016
3010
  "the time at which reporting starts")
3017
- self.epanet_api.setTimeReportingStart(reporting_time_start)
3011
+ self.epanet_api.set_reporting_start_time(reporting_time_start)
3018
3012
 
3019
3013
  if quality_time_step is not None:
3020
3014
  if not isinstance(quality_time_step, int) or quality_time_step <= 0 or \
3021
- quality_time_step > self.epanet_api.getTimeHydraulicStep():
3015
+ quality_time_step > self.epanet_api.get_hydraulic_time_step():
3022
3016
  raise ValueError("'quality_time_step' must be a positive integer that is not " +
3023
3017
  "greater than the hydraulic time step")
3024
- self.epanet_api.setTimeQualityStep(quality_time_step)
3018
+ self.epanet_api.set_quality_time_step(quality_time_step)
3025
3019
 
3026
3020
  if advanced_quality_time_step is not None:
3027
3021
  if not isinstance(advanced_quality_time_step, int) or \
3028
3022
  advanced_quality_time_step <= 0 or \
3029
- advanced_quality_time_step > self.epanet_api.getTimeHydraulicStep():
3023
+ advanced_quality_time_step > self.epanet_api.get_hydraulic_time_step():
3030
3024
  raise ValueError("'advanced_quality_time_step' must be a positive integer " +
3031
3025
  "that is not greater than the hydraulic time step")
3032
- self.epanet_api.setMSXTimeStep(advanced_quality_time_step)
3026
+ self.epanet_api.set_msx_time_step(advanced_quality_time_step)
3033
3027
 
3034
3028
  if quality_model is not None:
3035
- if quality_model["type"] == "NONE":
3036
- self.epanet_api.setQualityType("none")
3037
- elif quality_model["type"] == "AGE":
3038
- self.epanet_api.setQualityType("age")
3039
- elif quality_model["type"] == "CHEM":
3040
- self.epanet_api.setQualityType("chem", quality_model["chemical_name"],
3041
- qualityunit_to_str(quality_model["units"]))
3042
- elif quality_model["type"] == "TRACE":
3043
- self.epanet_api.setQualityType("trace", quality_model["trace_node_id"])
3044
- else:
3045
- raise ValueError(f"Unknown quality type: {quality_model['type']}")
3029
+ chem_name = quality_model["chem_name"] if "chem_name" in quality_model else ""
3030
+ chem_units = quality_model["chem_units"] if "chem_units" in quality_model else ""
3031
+ trace_node_id = quality_model["trace_node_id"] \
3032
+ if "trace_node_id" in quality_model else ""
3033
+ self.epanet_api.set_quality_type(quality_model["type"], chem_name, chem_units,
3034
+ trace_node_id)
3046
3035
 
3047
3036
  def get_events_active_time_points(self) -> list[int]:
3048
3037
  """
@@ -3056,7 +3045,7 @@ class ScenarioSimulator():
3056
3045
  """
3057
3046
  events_times = []
3058
3047
 
3059
- hyd_time_step = self.epanet_api.getTimeHydraulicStep()
3048
+ hyd_time_step = self.epanet_api.get_hydraulic_time_step()
3060
3049
 
3061
3050
  def __process_event(event) -> None:
3062
3051
  cur_time = event.start_time
@@ -3107,18 +3096,18 @@ class ScenarioSimulator():
3107
3096
  else:
3108
3097
  pattern_id = f"energy_price_{pump_id}"
3109
3098
 
3110
- pattern_idx = self.epanet_api.getPatternIndex(pattern_id)
3099
+ pattern_idx = self.epanet_api.getpatternindex(pattern_id)
3111
3100
  if pattern_idx != 0:
3112
3101
  warnings.warn(f"Overwriting existing pattern '{pattern_id}'")
3113
3102
 
3114
- pump_idx = self.epanet_api.getLinkIndex(pump_id)
3115
- pattern_idx = self.epanet_api.getLinkPumpEPat(pump_idx)
3103
+ pump_idx = self.epanet_api.get_link_idx(pump_id)
3104
+ pattern_idx = self.epanet_api.getlinkvalue(pump_idx, EpanetConstants.EN_PUMP_EPAT)
3116
3105
  if pattern_idx != 0:
3117
3106
  warnings.warn(f"Overwriting existing energy price pattern of pump '{pump_id}'")
3118
3107
 
3119
- self.add_pattern(pattern_id, pattern)
3120
- pattern_idx = self.epanet_api.getPatternIndex(pattern_id)
3121
- self.epanet_api.setLinkPumpEPat(pattern_idx)
3108
+ self.add_pattern(pattern_id, pattern.tolist())
3109
+ pattern_idx = self.epanet_api.getpatternindex(pattern_id)
3110
+ self.epanet_api.setlinkvalue(pump_idx, EpanetConstants.PUMP_EPAT, pattern_idx)
3122
3111
 
3123
3112
  def get_pump_energy_price_pattern(self, pump_id: str) -> np.ndarray:
3124
3113
  """
@@ -3139,14 +3128,12 @@ class ScenarioSimulator():
3139
3128
  if pump_id not in self._sensor_config.pumps:
3140
3129
  raise ValueError(f"Unknown pump '{pump_id}'")
3141
3130
 
3142
- pump_idx = self.epanet_api.getLinkIndex(pump_id)
3143
- pattern_idx = self.epanet_api.getLinkPumpEPat(pump_idx)
3131
+ pump_idx = self.epanet_api.get_link_idx(pump_id)
3132
+ pattern_idx = self.epanet_api.getlinkvalue(pump_idx, EpanetConstants.EN_PUMP_EPAT)
3144
3133
  if pattern_idx == 0:
3145
3134
  return None
3146
3135
  else:
3147
- pattern_length = self.epanet_api.getPatternLengths(pattern_idx)
3148
- return np.array([self.epanet_api.getPatternValue(pattern_idx, t+1)
3149
- for t in range(pattern_length)])
3136
+ return np.array(self.epanet_api.get_pattern(pattern_idx))
3150
3137
 
3151
3138
  def get_pump_energy_price(self, pump_id: str) -> float:
3152
3139
  """
@@ -3167,8 +3154,8 @@ class ScenarioSimulator():
3167
3154
  if pump_id not in self._sensor_config.pumps:
3168
3155
  raise ValueError(f"Unknown pump '{pump_id}'")
3169
3156
 
3170
- pump_idx = self.epanet_api.getLinkIndex(pump_id)
3171
- return self.epanet_api.getLinkPumpECost(pump_idx)
3157
+ pump_idx = self.epanet_api.get_link_idx(pump_id)
3158
+ return self.epanet_api.get_pump_avg_energy_price(pump_idx)
3172
3159
 
3173
3160
  def set_pump_energy_price(self, pump_id, price: float) -> None:
3174
3161
  """
@@ -3190,11 +3177,8 @@ class ScenarioSimulator():
3190
3177
  if price <= 0:
3191
3178
  raise ValueError("'price' must be positive")
3192
3179
 
3193
- pump_idx = self._sensor_config.pumps.index(pump_id) + 1
3194
- pumps_energy_price = self.epanet_api.getLinkPumpECost()
3195
- pumps_energy_price[pump_idx - 1] = price
3196
-
3197
- self.epanet_api.setLinkPumpECost(pumps_energy_price)
3180
+ pump_idx = self.epanet_api.get_link_idx(pump_id)
3181
+ self.epanet_api.setlinkvalue(pump_idx, EpanetConstants.EN_PUMP_ECOST, price)
3198
3182
 
3199
3183
  def set_initial_link_status(self, link_id: str, status: int) -> None:
3200
3184
  """
@@ -3219,8 +3203,8 @@ class ScenarioSimulator():
3219
3203
  if status not in [ActuatorConstants.EN_CLOSED, ActuatorConstants.EN_OPEN]:
3220
3204
  raise ValueError(f"Invalid link status '{status}'")
3221
3205
 
3222
- link_idx = self.epanet_api.getLinkIndex(link_id)
3223
- self.epanet_api.setLinkInitialStatus(link_idx, status)
3206
+ link_idx = self.epanet_api.get_link_idx(link_id)
3207
+ self.epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_INITSTATUS, status)
3224
3208
 
3225
3209
  def set_initial_pump_speed(self, pump_id: str, speed: float) -> None:
3226
3210
  """
@@ -3242,8 +3226,8 @@ class ScenarioSimulator():
3242
3226
  if speed < 0:
3243
3227
  raise ValueError("'speed' can not be negative")
3244
3228
 
3245
- pump_idx = self.epanet_api.getLinkIndex(pump_id)
3246
- self.epanet_api.setLinkInitialSetting(pump_idx, speed)
3229
+ pump_idx = self.epanet_api.get_link_idx(pump_id)
3230
+ self.epanet_api.setlinkvalue(pump_idx, EpanetConstants.EN_INITSETTING, speed)
3247
3231
 
3248
3232
  def set_initial_tank_level(self, tank_id, level: int) -> None:
3249
3233
  """
@@ -3265,14 +3249,14 @@ class ScenarioSimulator():
3265
3249
  if level < 0:
3266
3250
  raise ValueError("'level' can not be negative")
3267
3251
 
3268
- tank_idx = self.epanet_api.getNodeIndex(tank_id)
3269
- self.epanet_api.setNodeTankInitialLevel(tank_idx, level)
3252
+ tank_idx = self.epanet_api.get_node_idx(tank_id)
3253
+ self.epanet_api.setnodevalue(tank_idx, EpanetConstants.EN_TANKLEVEL, level)
3270
3254
 
3271
3255
  def __warn_if_quality_set(self):
3272
- qual_info = self.epanet_api.getQualityInfo()
3273
- if qual_info.QualityCode != ToolkitConstants.EN_NONE:
3256
+ qual_code = self.epanet_api.getqualinfo()[0]
3257
+ if qual_code != EpanetConstants.EN_NONE:
3274
3258
  warnings.warn("You are overriding current quality settings " +
3275
- f"'{qual_info.QualityType}'")
3259
+ f"'{qual_code}'")
3276
3260
 
3277
3261
  def enable_waterage_analysis(self) -> None:
3278
3262
  """
@@ -3285,7 +3269,7 @@ class ScenarioSimulator():
3285
3269
  self._adapt_to_network_changes()
3286
3270
 
3287
3271
  self.__warn_if_quality_set()
3288
- self.set_general_parameters(quality_model={"type": "AGE"})
3272
+ self.set_general_parameters(quality_model={"type": EpanetConstants.EN_AGE})
3289
3273
 
3290
3274
  def enable_chemical_analysis(self, chemical_name: str = "Chlorine",
3291
3275
  chemical_units: int = MASS_UNIT_MG) -> None:
@@ -3316,8 +3300,9 @@ class ScenarioSimulator():
3316
3300
  self._adapt_to_network_changes()
3317
3301
 
3318
3302
  self.__warn_if_quality_set()
3319
- self.set_general_parameters(quality_model={"type": "CHEM", "chemical_name": chemical_name,
3320
- "units": chemical_units})
3303
+ self.set_general_parameters(quality_model={"type": EpanetConstants.EN_CHEM,
3304
+ "chem_name": chemical_name,
3305
+ "chem_units": qualityunit_to_str(chemical_units)})
3321
3306
 
3322
3307
  def add_quality_source(self, node_id: str, source_type: int, pattern: np.ndarray = None,
3323
3308
  pattern_id: str = None, source_strength: int = 1.) -> None:
@@ -3330,7 +3315,7 @@ class ScenarioSimulator():
3330
3315
  ID of the node at which this external water quality source is placed.
3331
3316
  source_type : `int`,
3332
3317
  Types of the external water quality source -- must be of the following
3333
- EPANET toolkit constants:
3318
+ EPANET constants:
3334
3319
 
3335
3320
  - EN_CONCEN = 0
3336
3321
  - EN_MASS = 1
@@ -3366,7 +3351,7 @@ class ScenarioSimulator():
3366
3351
 
3367
3352
  self._adapt_to_network_changes()
3368
3353
 
3369
- if self.epanet_api.getQualityInfo().QualityCode != ToolkitConstants.EN_CHEM:
3354
+ if self.epanet_api.getqualinfo()[0] != EpanetConstants.EN_CHEM:
3370
3355
  raise RuntimeError("Chemical analysis is not enabled -- " +
3371
3356
  "call 'enable_chemical_analysis()' before calling this function.")
3372
3357
  if node_id not in self._sensor_config.nodes:
@@ -3382,19 +3367,20 @@ class ScenarioSimulator():
3382
3367
  if pattern_id is None:
3383
3368
  pattern_id = f"qual_src_pat_{node_id}"
3384
3369
 
3385
- node_idx = self.epanet_api.getNodeIndex(node_id)
3370
+ node_idx = self.epanet_api.get_node_idx(node_id)
3386
3371
 
3387
3372
  if pattern is None:
3388
- pattern_idx = self.epanet_api.getPatternIndex(pattern_id)
3373
+ pattern_idx = self.epanet_api.getpatternindex(pattern_id)
3389
3374
  else:
3390
- pattern_idx = self.epanet_api.addPattern(pattern_id, pattern)
3375
+ self.epanet_api.add_pattern(pattern_id, pattern.tolist())
3376
+ pattern_idx = self.epanet_api.getpatternindex(pattern_id)
3391
3377
  if pattern_idx == 0:
3392
3378
  raise RuntimeError("Failed to add/get pattern! " +
3393
3379
  "Maybe pattern name contains invalid characters or is too long?")
3394
3380
 
3395
- self.epanet_api.api.ENsetnodevalue(node_idx, ToolkitConstants.EN_SOURCETYPE, source_type)
3396
- self.epanet_api.setNodeSourceQuality(node_idx, source_strength)
3397
- self.epanet_api.setNodeSourcePatternIndex(node_idx, pattern_idx)
3381
+ self.epanet_api.setnodevalue(node_idx, EpanetConstants.EN_SOURCETYPE, source_type)
3382
+ self.epanet_api.setnodevalue(node_idx, EpanetConstants.EN_SOURCEQUAL, source_strength)
3383
+ self.epanet_api.setnodevalue(node_idx, EpanetConstants.EN_SOURCEPAT, pattern_idx)
3398
3384
 
3399
3385
  def set_initial_node_quality(self, node_id: str, initial_quality: float) -> None:
3400
3386
  """
@@ -3486,12 +3472,8 @@ class ScenarioSimulator():
3486
3472
  if node_init_qual < 0:
3487
3473
  raise ValueError(f"{node_id}: Initial node quality can not be negative")
3488
3474
 
3489
- init_qual = self.epanet_api.getNodeInitialQuality()
3490
- for node_id, node_init_qual in initial_quality:
3491
- node_idx = self.epanet_api.getNodeIndex(node_id) - 1
3492
- init_qual[node_idx] = node_init_qual
3493
-
3494
- self.epanet_api.setNodeInitialQuality(init_qual)
3475
+ for node_idx in self.epanet_api.get_all_nodes_idx():
3476
+ self.epanet_api.set_node_init_quality(node_idx, node_init_qual)
3495
3477
 
3496
3478
  if order_wall is not None:
3497
3479
  if not isinstance(order_wall, int):
@@ -3500,7 +3482,7 @@ class ScenarioSimulator():
3500
3482
  if order_wall not in [0, 1]:
3501
3483
  raise ValueError(f"Invalid value '{order_wall}' for order_wall")
3502
3484
 
3503
- self.epanet_api.setOptionsPipeWallReactionOrder(order_wall)
3485
+ self.epanet_api.setoption(EpanetConstants.EN_WALLORDER, order_wall)
3504
3486
 
3505
3487
  if order_bulk is not None:
3506
3488
  if not isinstance(order_bulk, int):
@@ -3509,7 +3491,7 @@ class ScenarioSimulator():
3509
3491
  if order_bulk not in [0, 1]:
3510
3492
  raise ValueError(f"Invalid value '{order_bulk}' for order_bulk")
3511
3493
 
3512
- self.epanet_api.setOptionsPipeBulkReactionOrder(order_bulk)
3494
+ self.epanet_api.setoption(EpanetConstants.EN_BULKORDER, order_bulk)
3513
3495
 
3514
3496
  if order_tank is not None:
3515
3497
  if not isinstance(order_tank, int):
@@ -3518,29 +3500,25 @@ class ScenarioSimulator():
3518
3500
  if order_tank not in [0, 1]:
3519
3501
  raise ValueError(f"Invalid value '{order_tank}' for order_wall")
3520
3502
 
3521
- self.epanet_api.setOptionsTankBulkReactionOrder(order_tank)
3503
+ self.epanet_api.setoption(EpanetConstants.EN_TANKORDER, order_tank)
3522
3504
 
3523
3505
  if global_wall_reaction_coefficient is not None:
3524
3506
  if not isinstance(global_wall_reaction_coefficient, float):
3525
3507
  raise TypeError("'global_wall_reaction_coefficient' must be an instance of " +
3526
3508
  f"'float' but not of '{type(global_wall_reaction_coefficient)}'")
3527
3509
 
3528
- wall_reaction_coeff = self.epanet_api.getLinkWallReactionCoeff()
3529
- for i in range(len(wall_reaction_coeff)):
3530
- wall_reaction_coeff[i] = global_wall_reaction_coefficient
3531
-
3532
- self.epanet_api.setLinkWallReactionCoeff(wall_reaction_coeff)
3510
+ for link_idx in self.epanet_api.get_all_links_idx():
3511
+ self.epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_KWALL,
3512
+ global_wall_reaction_coefficient)
3533
3513
 
3534
3514
  if global_bulk_reaction_coefficient is not None:
3535
3515
  if not isinstance(global_bulk_reaction_coefficient, float):
3536
3516
  raise TypeError("'global_bulk_reaction_coefficient' must be an instance of " +
3537
3517
  f"'float' but not of '{type(global_bulk_reaction_coefficient)}'")
3538
3518
 
3539
- bulk_reaction_coeff = self.epanet_api.getLinkBulkReactionCoeff()
3540
- for i in range(len(bulk_reaction_coeff)):
3541
- bulk_reaction_coeff[i] = global_bulk_reaction_coefficient
3542
-
3543
- self.epanet_api.setLinkBulkReactionCoeff(bulk_reaction_coeff)
3519
+ for link_idx in self.epanet_api.get_all_links_idx():
3520
+ self.epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_KBULK,
3521
+ global_bulk_reaction_coefficient)
3544
3522
 
3545
3523
  if local_wall_reaction_coefficient is not None:
3546
3524
  if not isinstance(local_wall_reaction_coefficient, dict):
@@ -3556,8 +3534,8 @@ class ScenarioSimulator():
3556
3534
  raise ValueError(f"Invalid link ID '{link_id}'")
3557
3535
 
3558
3536
  for link_id, link_reaction_coeff in local_wall_reaction_coefficient:
3559
- link_idx = self.epanet_api.getLinkIndex(link_id)
3560
- self.epanet_api.setLinkWallReactionCoeff(link_idx, link_reaction_coeff)
3537
+ link_idx = self.epanet_api.get_link_idx(link_id)
3538
+ self.epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_KWALL, link_reaction_coeff)
3561
3539
 
3562
3540
  if local_bulk_reaction_coefficient is not None:
3563
3541
  if not isinstance(local_bulk_reaction_coefficient, dict):
@@ -3573,8 +3551,8 @@ class ScenarioSimulator():
3573
3551
  raise ValueError(f"Invalid link ID '{link_id}'")
3574
3552
 
3575
3553
  for link_id, link_reaction_coeff in local_bulk_reaction_coefficient:
3576
- link_idx = self.epanet_api.getLinkIndex(link_id)
3577
- self.epanet_api.setLinkBulkReactionCoeff(link_idx, link_reaction_coeff)
3554
+ link_idx = self.epanet_api.get_link_idx(link_id)
3555
+ self.epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_KBULK, link_reaction_coeff)
3578
3556
 
3579
3557
  if local_tank_reaction_coefficient is not None:
3580
3558
  if not isinstance(local_tank_reaction_coefficient, dict):
@@ -3590,8 +3568,9 @@ class ScenarioSimulator():
3590
3568
  raise ValueError(f"Invalid tank ID '{tank_id}'")
3591
3569
 
3592
3570
  for tank_id, tank_reaction_coeff in local_tank_reaction_coefficient:
3593
- tank_idx = self.epanet_api.getNodeTankIndex(tank_id)
3594
- self.epanet_api.setNodeTankBulkReactionCoeff(tank_idx, tank_reaction_coeff)
3571
+ tank_idx = self.epanet_api.get_node_idx(tank_id)
3572
+ self.epanet_api.setnodevalue(tank_idx, EpanetConstants.EN_TANK_KBULK,
3573
+ tank_reaction_coeff)
3595
3574
 
3596
3575
  if limiting_potential is not None:
3597
3576
  if not isinstance(limiting_potential, float):
@@ -3600,7 +3579,7 @@ class ScenarioSimulator():
3600
3579
  if limiting_potential < 0:
3601
3580
  raise ValueError("'limiting_potential' can not be negative")
3602
3581
 
3603
- self.epanet_api.setOptionsLimitingConcentration(limiting_potential)
3582
+ self.epanet_api.setoption(EpanetConstants.EN_CONCENLIMIT, limiting_potential)
3604
3583
 
3605
3584
  def enable_sourcetracing_analysis(self, trace_node_id: str) -> None:
3606
3585
  """
@@ -3621,7 +3600,7 @@ class ScenarioSimulator():
3621
3600
  raise ValueError(f"Invalid node ID '{trace_node_id}'")
3622
3601
 
3623
3602
  self.__warn_if_quality_set()
3624
- self.set_general_parameters(quality_model={"type": "TRACE",
3603
+ self.set_general_parameters(quality_model={"type": EpanetConstants.EN_TRACE,
3625
3604
  "trace_node_id": trace_node_id})
3626
3605
 
3627
3606
  def add_species_injection_source(self, species_id: str, node_id: str, pattern: np.ndarray,
@@ -3645,7 +3624,7 @@ class ScenarioSimulator():
3645
3624
  Note that the pattern time step is equivalent to the EPANET pattern time step.
3646
3625
  source_type : `int`,
3647
3626
  Type of the external (bulk or surface) species injection source -- must be one of
3648
- the following EPANET toolkit constants:
3627
+ the following EPANET constants:
3649
3628
 
3650
3629
  - EN_CONCEN = 0
3651
3630
  - EN_MASS = 1
@@ -3670,25 +3649,18 @@ class ScenarioSimulator():
3670
3649
 
3671
3650
  The default is 1.
3672
3651
  """
3673
- source_type_ = "None"
3674
- if source_type == ToolkitConstants.EN_CONCEN:
3675
- source_type_ = "CONCEN"
3676
- elif source_type == ToolkitConstants.EN_MASS:
3677
- source_type_ = "MASS"
3678
- elif source_type == ToolkitConstants.EN_SETPOINT:
3679
- source_type_ = "SETPOINT"
3680
- elif source_type == ToolkitConstants.EN_FLOWPACED:
3681
- source_type_ = "FLOWPACED"
3682
-
3683
3652
  if pattern_id is None:
3684
3653
  pattern_id = f"{species_id}_{node_id}"
3685
- if pattern_id in self.epanet_api.getMSXPatternsNameID():
3654
+ if pattern_id in self.epanet_api.get_all_msx_pattern_id():
3686
3655
  raise ValueError("Invalid 'pattern_id' -- " +
3687
3656
  f"there already exists a pattern with ID '{pattern_id}'")
3688
3657
 
3689
- self.epanet_api.addMSXPattern(pattern_id, pattern)
3690
- self.epanet_api.setMSXSources(node_id, species_id, source_type_, source_strength,
3691
- pattern_id)
3658
+ self.epanet_api.MSXaddpattern(pattern_id)
3659
+ pattern_idx = self.epanet_api.MSXgetindex(EpanetConstants.MSX_PATTERN, pattern_id)
3660
+ self.epanet_api.MSXsetpattern(pattern_idx, pattern.tolist(), len(pattern))
3661
+ self.epanet_api.MSXsetsource(self.epanet_api.get_node_idx(node_id),
3662
+ self.epanet_api.get_msx_species_idx(species_id),
3663
+ source_type, source_strength, pattern_idx)
3692
3664
 
3693
3665
  def set_bulk_species_node_initial_concentrations(self,
3694
3666
  inital_conc: dict[str, list[tuple[str, float]]]
@@ -3723,12 +3695,12 @@ class ScenarioSimulator():
3723
3695
  raise ValueError("Initial node concentration can not be negative")
3724
3696
 
3725
3697
  for species_id, node_initial_conc in inital_conc.items():
3726
- species_idx, = self.epanet_api.getMSXSpeciesIndex([species_id])
3698
+ species_idx = self.epanet_api.get_msx_species_idx(species_id)
3727
3699
 
3728
3700
  for node_id, initial_conc in node_initial_conc:
3729
- node_idx = self.epanet_api.getNodeIndex(node_id)
3730
- self.epanet_api.msx.MSXsetinitqual(ToolkitConstants.MSX_NODE, node_idx, species_idx,
3731
- initial_conc)
3701
+ node_idx = self.epanet_api.get_node_idx(node_id)
3702
+ self.epanet_api.MSXsetinitqual(EpanetConstants.MSX_NODE, node_idx, species_idx,
3703
+ initial_conc)
3732
3704
 
3733
3705
  def set_species_link_initial_concentrations(self,
3734
3706
  inital_conc: dict[str, list[tuple[str, float]]]
@@ -3762,9 +3734,9 @@ class ScenarioSimulator():
3762
3734
  raise ValueError("Initial link concentration can not be negative")
3763
3735
 
3764
3736
  for species_id, link_initial_conc in inital_conc.items():
3765
- species_idx, = self.epanet_api.getMSXSpeciesIndex([species_id])
3737
+ species_idx = self.epanet_api.get_msx_species_idx(species_id)
3766
3738
 
3767
3739
  for link_id, initial_conc in link_initial_conc:
3768
- link_idx = self.epanet_api.getLinkIndex(link_id)
3769
- self.epanet_api.msx.MSXsetinitqual(ToolkitConstants.MSX_LINK, link_idx, species_idx,
3770
- initial_conc)
3740
+ link_idx = self.epanet_api.get_link_idx(link_id)
3741
+ self.epanet_api.MSXsetinitqual(EpanetConstants.MSX_LINK, link_idx, species_idx,
3742
+ initial_conc)