epyt-flow 0.14.2__tar.gz → 0.15.0__tar.gz

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 (157) hide show
  1. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/MANIFEST.in +1 -2
  2. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/PKG-INFO +14 -19
  3. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/README.md +11 -17
  4. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/REQUIREMENTS.txt +1 -1
  5. epyt_flow-0.15.0/epyt_flow/VERSION +1 -0
  6. epyt_flow-0.15.0/epyt_flow/__init__.py +5 -0
  7. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/battledim.py +2 -2
  8. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/leakdb.py +12 -9
  9. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/gym/scenario_control_env.py +32 -33
  10. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/actuator_events.py +24 -18
  11. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/leakages.py +59 -57
  12. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/quality_events.py +21 -30
  13. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/system_event.py +3 -3
  14. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/scada/complex_control.py +14 -12
  15. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/scada/custom_control.py +22 -21
  16. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/scada/scada_data.py +107 -104
  17. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/scada/simple_control.py +38 -31
  18. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/scenario_simulator.py +368 -395
  19. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/sensor_config.py +31 -32
  20. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/topology.py +11 -10
  21. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/uncertainty/model_uncertainty.py +146 -122
  22. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow.egg-info/PKG-INFO +14 -19
  23. epyt_flow-0.15.0/epyt_flow.egg-info/SOURCES.txt +75 -0
  24. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow.egg-info/requires.txt +1 -1
  25. epyt_flow-0.15.0/net2-cl2.inp +399 -0
  26. epyt_flow-0.15.0/net2-cl2.msx +49 -0
  27. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/pyproject.toml +2 -1
  28. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +0 -28
  29. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +0 -21
  30. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +0 -18
  31. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +0 -134
  32. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +0 -5578
  33. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +0 -865
  34. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +0 -131
  35. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +0 -73
  36. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +0 -193
  37. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/genmmd.c +0 -1000
  38. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/hash.c +0 -177
  39. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/hash.h +0 -28
  40. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +0 -1151
  41. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +0 -1117
  42. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +0 -720
  43. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +0 -476
  44. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +0 -431
  45. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +0 -1786
  46. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +0 -468
  47. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +0 -810
  48. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/input1.c +0 -707
  49. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/input2.c +0 -864
  50. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/input3.c +0 -2170
  51. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/main.c +0 -93
  52. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +0 -142
  53. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +0 -24
  54. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/output.c +0 -852
  55. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/project.c +0 -1359
  56. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/quality.c +0 -685
  57. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +0 -743
  58. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +0 -694
  59. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/report.c +0 -1489
  60. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/rules.c +0 -1362
  61. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +0 -871
  62. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/text.h +0 -497
  63. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET/SRC_engines/types.h +0 -874
  64. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/MSX_Updates.txt +0 -53
  65. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/dispersion.h +0 -27
  66. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/hash.c +0 -107
  67. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/hash.h +0 -28
  68. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx.h +0 -102
  69. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx_export.h +0 -42
  70. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.c +0 -937
  71. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.h +0 -39
  72. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/mempool.c +0 -204
  73. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/mempool.h +0 -24
  74. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxchem.c +0 -1285
  75. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxcompiler.c +0 -368
  76. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxdict.h +0 -42
  77. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxdispersion.c +0 -586
  78. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxerr.c +0 -116
  79. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxfile.c +0 -260
  80. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.c +0 -175
  81. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.h +0 -35
  82. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxinp.c +0 -1504
  83. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxout.c +0 -401
  84. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxproj.c +0 -791
  85. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxqual.c +0 -2010
  86. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxrpt.c +0 -400
  87. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxtank.c +0 -422
  88. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxtoolkit.c +0 -1164
  89. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxtypes.h +0 -551
  90. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxutils.c +0 -524
  91. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/msxutils.h +0 -56
  92. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/newton.c +0 -158
  93. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/newton.h +0 -34
  94. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/rk5.c +0 -287
  95. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/rk5.h +0 -39
  96. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/ros2.c +0 -293
  97. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/ros2.h +0 -35
  98. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/smatrix.c +0 -816
  99. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/Src/smatrix.h +0 -29
  100. epyt_flow-0.14.2/epyt_flow/EPANET/EPANET-MSX/readme.txt +0 -14
  101. epyt_flow-0.14.2/epyt_flow/EPANET/compile_linux.sh +0 -4
  102. epyt_flow-0.14.2/epyt_flow/EPANET/compile_macos.sh +0 -4
  103. epyt_flow-0.14.2/epyt_flow/VERSION +0 -1
  104. epyt_flow-0.14.2/epyt_flow/__init__.py +0 -42
  105. epyt_flow-0.14.2/epyt_flow/simulation/backend/__init__.py +0 -1
  106. epyt_flow-0.14.2/epyt_flow/simulation/backend/my_epyt.py +0 -1101
  107. epyt_flow-0.14.2/epyt_flow.egg-info/SOURCES.txt +0 -150
  108. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/CITATION.cff +0 -0
  109. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/CODE_OF_CONDUCT.md +0 -0
  110. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/LICENSE +0 -0
  111. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/__init__.py +0 -0
  112. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/__init__.py +0 -0
  113. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/batadal.py +0 -0
  114. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/batadal_data.py +0 -0
  115. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/battledim_data.py +0 -0
  116. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/gecco_water_quality.py +0 -0
  117. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/leakdb_data.py +0 -0
  118. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/benchmarks/water_usage.py +0 -0
  119. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/data/networks.py +0 -0
  120. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/gym/__init__.py +0 -0
  121. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/__init__.py +0 -0
  122. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/base_handler.py +0 -0
  123. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/res_manager.py +0 -0
  124. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scada_data/__init__.py +0 -0
  125. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scada_data/data_handlers.py +0 -0
  126. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scada_data/export_handlers.py +0 -0
  127. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scada_data/handlers.py +0 -0
  128. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scenario/__init__.py +0 -0
  129. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scenario/control_handlers.py +0 -0
  130. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scenario/event_handlers.py +0 -0
  131. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scenario/handlers.py +0 -0
  132. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scenario/simulation_handlers.py +0 -0
  133. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/scenario/uncertainty_handlers.py +0 -0
  134. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/rest_api/server.py +0 -0
  135. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/serialization.py +0 -0
  136. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/__init__.py +0 -0
  137. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/__init__.py +0 -0
  138. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/event.py +0 -0
  139. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/sensor_faults.py +0 -0
  140. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/sensor_reading_attack.py +0 -0
  141. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/events/sensor_reading_event.py +0 -0
  142. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/parallel_simulation.py +0 -0
  143. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/scada/__init__.py +0 -0
  144. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/scada/scada_data_export.py +0 -0
  145. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/simulation/scenario_config.py +0 -0
  146. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/uncertainty/__init__.py +0 -0
  147. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/uncertainty/sensor_noise.py +0 -0
  148. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/uncertainty/uncertainties.py +0 -0
  149. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/uncertainty/utils.py +0 -0
  150. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/utils.py +0 -0
  151. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/visualization/__init__.py +0 -0
  152. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/visualization/scenario_visualizer.py +0 -0
  153. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow/visualization/visualization_utils.py +0 -0
  154. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow.egg-info/dependency_links.txt +0 -0
  155. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/epyt_flow.egg-info/top_level.txt +0 -0
  156. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/setup.cfg +0 -0
  157. {epyt_flow-0.14.2 → epyt_flow-0.15.0}/setup.py +0 -0
@@ -1,5 +1,4 @@
1
1
  include epyt_flow/VERSION
2
- recursive-include epyt_flow/EPANET *
3
2
  exclude .*
4
3
  exclude DEVELOPERS.md
5
4
  exclude REQUIREMENTS-DEV.txt
@@ -10,4 +9,4 @@ recursive-exclude examples/ *
10
9
  recursive-exclude paper/ *
11
10
  recursive-exclude docs/ *
12
11
  recursive-exclude tests/ *
13
- recursive-exclude .github/ *
12
+ recursive-exclude .github/ *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: epyt-flow
3
- Version: 0.14.2
3
+ Version: 0.15.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-Expression: MIT
@@ -17,10 +17,11 @@ Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
20
21
  Requires-Python: >=3.9
21
22
  Description-Content-Type: text/markdown
22
23
  License-File: LICENSE
23
- Requires-Dist: epyt>=1.2.2
24
+ Requires-Dist: epanet-plus>=0.1.2
24
25
  Requires-Dist: requests>=2.31.0
25
26
  Requires-Dist: scipy>=1.11.4
26
27
  Requires-Dist: u-msgpack-python>=2.8.0
@@ -49,11 +50,13 @@ Dynamic: license-file
49
50
 
50
51
  <img src="https://github.com/WaterFutures/EPyT-Flow/blob/main/docs/_static/net1_plot.png?raw=true" align="right" height="230px"/>
51
52
 
52
- EPyT-Flow is a Python package building on top of [EPyT](https://github.com/OpenWaterAnalytics/EPyT)
53
+ EPyT-Flow is a Python package building on top of [EPANET-PLUS](https://github.com/WaterFutures/EPANET-PLUS) --
54
+ an extension and interface of [EPANET](https://github.com/OpenWaterAnalytics/EPANET)
55
+ and [EPANET-MSX](https://github.com/OpenWaterAnalytics/epanet-msx) --
53
56
  for providing easy access to water distribution network simulations.
54
57
  It aims to provide a high-level interface for the easy generation of hydraulic and water quality scenario data.
55
- However, it also provides access to low-level functions by [EPANET](https://github.com/USEPA/EPANET2.2)
56
- and [EPANET-MSX](https://github.com/USEPA/EPANETMSX/).
58
+ However, it also provides access to all functions of EPANET
59
+ and EPANET-MSX.
57
60
 
58
61
  EPyT-Flow provides easy access to popular benchmark data sets for event detection and localization.
59
62
  Furthermore, it also provides an environment for developing and testing control algorithms.
@@ -77,21 +80,13 @@ Unique features of EPyT-Flow that make it superior to other (Python) toolboxes a
77
80
 
78
81
  ## Installation
79
82
 
80
- EPyT-Flow supports Python 3.9 - 3.13
83
+ EPyT-Flow supports Python 3.9 - 3.14
81
84
 
82
- Note that [EPANET and EPANET-MSX sources](epyt_flow/EPANET/) are compiled and overwrite the binaries
83
- shipped by EPyT **IF** EPyT-Flow is installed on a Unix system and the *gcc* compiler is available.
84
- By this, we not only aim to achieve a better performance of the simulations but also avoid any
85
- compatibility issues of pre-compiled binaries.
86
-
87
- #### Prerequisites for macOS users
88
- The "true" *gcc* compiler (version 15) is needed which is not the
89
- *clang* compiler that is shipped with Xcode and is linked to gcc!
90
-
91
- The correct version of the "true" *gcc* can be installed via [brew](https://brew.sh/):
92
- ```
93
- brew install gcc@15
94
- ```
85
+ Note that EPyT-Flow builds upon [EPANET-PLUS](https://github.com/WaterFutures/EPANET-PLUS) which
86
+ constitutes a C extension and Python package.
87
+ In the rare case that the pre-build package of EPANET-PLUS does not work on your system,
88
+ you have to build and install it manually -- please follow the instructions provided
89
+ [here](https://epanet-plus.readthedocs.io/en/stable/installation.html).
95
90
 
96
91
  ### PyPI
97
92
 
@@ -11,11 +11,13 @@
11
11
 
12
12
  <img src="https://github.com/WaterFutures/EPyT-Flow/blob/main/docs/_static/net1_plot.png?raw=true" align="right" height="230px"/>
13
13
 
14
- EPyT-Flow is a Python package building on top of [EPyT](https://github.com/OpenWaterAnalytics/EPyT)
14
+ EPyT-Flow is a Python package building on top of [EPANET-PLUS](https://github.com/WaterFutures/EPANET-PLUS) --
15
+ an extension and interface of [EPANET](https://github.com/OpenWaterAnalytics/EPANET)
16
+ and [EPANET-MSX](https://github.com/OpenWaterAnalytics/epanet-msx) --
15
17
  for providing easy access to water distribution network simulations.
16
18
  It aims to provide a high-level interface for the easy generation of hydraulic and water quality scenario data.
17
- However, it also provides access to low-level functions by [EPANET](https://github.com/USEPA/EPANET2.2)
18
- and [EPANET-MSX](https://github.com/USEPA/EPANETMSX/).
19
+ However, it also provides access to all functions of EPANET
20
+ and EPANET-MSX.
19
21
 
20
22
  EPyT-Flow provides easy access to popular benchmark data sets for event detection and localization.
21
23
  Furthermore, it also provides an environment for developing and testing control algorithms.
@@ -39,21 +41,13 @@ Unique features of EPyT-Flow that make it superior to other (Python) toolboxes a
39
41
 
40
42
  ## Installation
41
43
 
42
- EPyT-Flow supports Python 3.9 - 3.13
44
+ EPyT-Flow supports Python 3.9 - 3.14
43
45
 
44
- Note that [EPANET and EPANET-MSX sources](epyt_flow/EPANET/) are compiled and overwrite the binaries
45
- shipped by EPyT **IF** EPyT-Flow is installed on a Unix system and the *gcc* compiler is available.
46
- By this, we not only aim to achieve a better performance of the simulations but also avoid any
47
- compatibility issues of pre-compiled binaries.
48
-
49
- #### Prerequisites for macOS users
50
- The "true" *gcc* compiler (version 15) is needed which is not the
51
- *clang* compiler that is shipped with Xcode and is linked to gcc!
52
-
53
- The correct version of the "true" *gcc* can be installed via [brew](https://brew.sh/):
54
- ```
55
- brew install gcc@15
56
- ```
46
+ Note that EPyT-Flow builds upon [EPANET-PLUS](https://github.com/WaterFutures/EPANET-PLUS) which
47
+ constitutes a C extension and Python package.
48
+ In the rare case that the pre-build package of EPANET-PLUS does not work on your system,
49
+ you have to build and install it manually -- please follow the instructions provided
50
+ [here](https://epanet-plus.readthedocs.io/en/stable/installation.html).
57
51
 
58
52
  ### PyPI
59
53
 
@@ -1,4 +1,4 @@
1
- epyt>=1.2.2
1
+ epanet-plus>=0.1.2
2
2
  requests>=2.31.0
3
3
  scipy>=1.11.4
4
4
  u-msgpack-python>=2.8.0
@@ -0,0 +1 @@
1
+ 0.15.0
@@ -0,0 +1,5 @@
1
+ import os
2
+
3
+ with open(os.path.join(os.path.dirname(__file__), 'VERSION'), encoding="utf-8") as f:
4
+ VERSION = f.read().strip()
5
+ __version__ = VERSION
@@ -32,7 +32,7 @@ from .battledim_data import START_TIME_TEST, START_TIME_TRAIN, LEAKS_CONFIG_TEST
32
32
  LEAKS_CONFIG_TRAIN
33
33
  from ..networks import load_ltown
34
34
  from ...simulation.events import AbruptLeakage, IncipientLeakage, Leakage
35
- from ...simulation import ScenarioConfig
35
+ from ...simulation import ScenarioConfig, EpanetConstants
36
36
  from ...topology import NetworkTopology
37
37
  from ...simulation.scada import ScadaData
38
38
  from ...utils import get_temp_folder, to_seconds, create_path_if_not_exist, download_if_necessary
@@ -463,7 +463,7 @@ def load_scenario(return_test_scenario: bool, download_dir: str = None,
463
463
  general_params = {"simulation_duration": to_seconds(days=365), # One year
464
464
  "hydraulic_time_step": to_seconds(minutes=5), # 5min time steps
465
465
  "reporting_time_step": to_seconds(minutes=5),
466
- "demand_model": {"type": "PDA", "pressure_min": 0,
466
+ "demand_model": {"type": EpanetConstants.EN_PDA, "pressure_min": 0,
467
467
  "pressure_required": 0.1,
468
468
  "pressure_exponent": 0.5}
469
469
  } | ltown_config.general_params
@@ -28,7 +28,7 @@ from ..networks import load_net1, load_hanoi
28
28
  from .leakdb_data import NET1_LEAKAGES, HANOI_LEAKAGES
29
29
  from ...utils import get_temp_folder, to_seconds, unpack_zip_archive, create_path_if_not_exist, \
30
30
  download_if_necessary
31
- from ...simulation import ScenarioSimulator, ToolkitConstants
31
+ from ...simulation import ScenarioSimulator, EpanetConstants
32
32
  from ...simulation.events import AbruptLeakage, IncipientLeakage
33
33
  from ...simulation import ScenarioConfig
34
34
  from ...simulation.scada import ScadaData
@@ -275,6 +275,8 @@ def load_data(scenarios_id: list[int], use_net1: bool, download_dir: str = None,
275
275
  create_path_if_not_exist(scenario_data_folder_in)
276
276
  unpack_zip_archive(scenario_data_file_in, scenario_data_folder_in)
277
277
 
278
+ scenario_data_folder_in = os.path.join(scenario_data_folder_in, f"Scenario-{s_id}")
279
+
278
280
  # Load and parse data
279
281
  pressure_files = list(filter(lambda d: d.endswith(".csv"),
280
282
  os.listdir(os.path.join(scenario_data_folder_in,
@@ -464,8 +466,8 @@ def load_scenarios(scenarios_id: list[int], use_net1: bool = True,
464
466
  general_params = {"simulation_duration": to_seconds(days=365), # One year
465
467
  "hydraulic_time_step": hydraulic_time_step,
466
468
  "reporting_time_step": hydraulic_time_step,
467
- "flow_units_id": ToolkitConstants.EN_CMH,
468
- "demand_model": {"type": "PDA", "pressure_min": 0,
469
+ "flow_units_id": EpanetConstants.EN_CMH,
470
+ "demand_model": {"type": EpanetConstants.EN_PDA, "pressure_min": 0,
469
471
  "pressure_required": 0.1,
470
472
  "pressure_exponent": 0.5}
471
473
  } | network_config.general_params
@@ -544,18 +546,19 @@ def load_scenarios(scenarios_id: list[int], use_net1: bool = True,
544
546
  if not os.path.exists(f_inp_in):
545
547
  with ScenarioSimulator(f_inp_in=network_config.f_inp_in) as wdn:
546
548
  wdn.set_general_parameters(**general_params)
547
- wdn.epanet_api.setTimePatternStep(hydraulic_time_step)
549
+ wdn.epanet_api.set_hydraulic_time_step(hydraulic_time_step)
548
550
 
549
- wdn.epanet_api.deletePatternsAll()
551
+ for idx in range(1, wdn.epanet_api.getcount(EpanetConstants.EN_PATCOUNT) + 1):
552
+ wdn.epanet_api.deletepattern(idx)
550
553
 
551
- reservoir_nodes_id = wdn.epanet_api.getNodeReservoirNameID()
554
+ reservoir_nodes_id = wdn.epanet_api.get_all_reservoirs_id()
552
555
  for node_id in network_config.sensor_config.nodes:
553
556
  if node_id in network_config.sensor_config.tanks or\
554
557
  node_id in reservoir_nodes_id:
555
558
  continue
556
559
 
557
- node_idx = wdn.epanet_api.getNodeIndex(node_id)
558
- base_demand = wdn.epanet_api.getNodeBaseDemands(node_idx)[1][0]
560
+ node_idx = wdn.epanet_api.get_node_idx(node_id)
561
+ base_demand = wdn.epanet_api.get_node_base_demand(node_idx)
559
562
 
560
563
  my_demand_pattern = np.array(gen_dem(download_dir))
561
564
 
@@ -563,7 +566,7 @@ def load_scenarios(scenarios_id: list[int], use_net1: bool = True,
563
566
  demand_pattern_id=f"demand_{node_id}",
564
567
  demand_pattern=my_demand_pattern)
565
568
 
566
- wdn.epanet_api.saveInputFile(f_inp_in)
569
+ wdn.epanet_api.saveinpfile(f_inp_in)
567
570
 
568
571
  # Create uncertainties
569
572
  class MyUniformUncertainty(UniformUncertainty):
@@ -6,9 +6,9 @@ import uuid
6
6
  from abc import abstractmethod, ABC
7
7
  from typing import Union
8
8
  import warnings
9
- import numpy as np
9
+ from epanet_plus import EpanetConstants
10
10
 
11
- from ..simulation import ScenarioSimulator, ScenarioConfig, ScadaData, ToolkitConstants
11
+ from ..simulation import ScenarioSimulator, ScenarioConfig, ScadaData
12
12
  from ..utils import get_temp_folder
13
13
 
14
14
 
@@ -193,14 +193,14 @@ class ScenarioControlEnv(ABC):
193
193
  raise RuntimeError("Can not execute actions affecting the hydraulics "+
194
194
  "when running EPANET-MSX")
195
195
 
196
- pump_idx = self._scenario_sim.epanet_api.getLinkPumpNameID().index(pump_id) + 1
197
- pump_link_idx = self._scenario_sim.epanet_api.getLinkPumpIndex(pump_idx)
198
-
199
- pattern_idx = self._scenario_sim.epanet_api.getLinkPumpPatternIndex(pump_idx)
196
+ pump_link_idx = self._scenario_sim.epanet_api.get_link_idx(pump_id)
197
+ pattern_idx = self._scenario_sim.epanet_api.getlinkvalue(pump_link_idx,
198
+ EpanetConstants.EN_LINKPATTERN)
200
199
  if pattern_idx != 0:
201
200
  warnings.warn(f"Can not set pump state of pump {pump_id} because a pump pattern exists")
202
201
  else:
203
- self._scenario_sim.epanet_api.setLinkStatus(pump_link_idx, status)
202
+ self._scenario_sim.epanet_api.setlinkvalue(pump_link_idx, EpanetConstants.EN_STATUS,
203
+ status)
204
204
 
205
205
  def set_pump_speed(self, pump_id: str, speed: float) -> None:
206
206
  """
@@ -217,15 +217,19 @@ class ScenarioControlEnv(ABC):
217
217
  raise RuntimeError("Can not execute actions affecting the hydraulics "+
218
218
  "when running EPANET-MSX")
219
219
 
220
- pump_idx = self._scenario_sim.epanet_api.getLinkPumpNameID().index(pump_id)
221
- pattern_idx = self._scenario_sim.epanet_api.getLinkPumpPatternIndex(pump_idx + 1)
220
+ pump_idx = self._scenario_sim.epanet_api.get_link_idx(pump_id)
221
+ pattern_idx = int(self._scenario_sim.epanet_api.getlinkvalue(pump_idx,
222
+ EpanetConstants.EN_LINKPATTERN))
222
223
 
223
224
  if pattern_idx == 0:
224
225
  warnings.warn(f"No pattern for pump '{pump_id}' found -- a new pattern is created")
225
- pattern_idx = self._scenario_sim.epanet_api.addPattern(f"pump_speed_{pump_id}")
226
- self._scenario_sim.epanet_api.setLinkPumpPatternIndex(pump_idx + 1, pattern_idx)
226
+ pattern_id = f"pump_speed_{pump_id}"
227
+ self._scenario_sim.epanet_api.add_pattern(pattern_id, [speed])
228
+ pattern_idx = self._scenario_sim.epanet_api.getpatternindex(pattern_id)
229
+ self._scenario_sim.epanet_api.setlinkvalue(pump_idx, EpanetConstants.EN_LINKPATTERN,
230
+ pattern_idx)
227
231
 
228
- self._scenario_sim.epanet_api.setPattern(pattern_idx, np.array([speed]))
232
+ self._scenario_sim.epanet_api.setpattern(pattern_idx, [speed], 1)
229
233
 
230
234
  def set_valve_status(self, valve_id: str, status: int) -> None:
231
235
  """
@@ -248,9 +252,9 @@ class ScenarioControlEnv(ABC):
248
252
  raise RuntimeError("Can not execute actions affecting the hydraulics "+
249
253
  "when running EPANET-MSX")
250
254
 
251
- valve_idx = self._scenario_sim.epanet_api.getLinkValveNameID().index(valve_id)
252
- valve_link_idx = self._scenario_sim.epanet_api.getLinkValveIndex()[valve_idx]
253
- self._scenario_sim.epanet_api.setLinkStatus(valve_link_idx, status)
255
+ valve_link_idx = self._scenario_sim.epanet_api.get_link_idx(valve_id)
256
+ self._scenario_sim.epanet_api.setlinkvalue(valve_link_idx, EpanetConstants.EN_STATUS,
257
+ status)
254
258
 
255
259
  def set_node_quality_source_value(self, node_id: str, pattern_id: str,
256
260
  qual_value: float) -> None:
@@ -271,10 +275,10 @@ class ScenarioControlEnv(ABC):
271
275
  raise RuntimeError("Can not execute actions affecting the hydraulics "+
272
276
  "when running EPANET-MSX")
273
277
 
274
- node_idx = self._scenario_sim.epanet_api.getNodeIndex(node_id)
275
- pattern_idx = self._scenario_sim.epanet_api.getPatternIndex(pattern_id)
276
- self._scenario_sim.epanet_api.setNodeSourceQuality(node_idx, 1)
277
- self._scenario_sim.epanet_api.setPattern(pattern_idx, np.array([qual_value]))
278
+ node_idx = self._scenario_sim.epanet_api.get_node_idx(node_id)
279
+ pattern_idx = self._scenario_sim.epanet_api.getpatternindex(pattern_id)
280
+ self._scenario_sim.epanet_api.setnodevalue(node_idx, EpanetConstants.EN_SOURCEQUAL, 1)
281
+ self._scenario_sim.epanet_api.set_pattern(pattern_idx, [qual_value])
278
282
 
279
283
  def set_node_species_source_value(self, species_id: str, node_id: str, source_type: int,
280
284
  pattern_id: str, source_strength: float) -> None:
@@ -290,7 +294,7 @@ class ScenarioControlEnv(ABC):
290
294
  ID of the node.
291
295
  source_type : `int`
292
296
  Type of the external species injection source -- must be one of
293
- the following EPANET toolkit constants:
297
+ the following EPANET constants:
294
298
 
295
299
  - EN_CONCEN = 0
296
300
  - EN_MASS = 1
@@ -312,19 +316,14 @@ class ScenarioControlEnv(ABC):
312
316
  if self._scenario_sim.f_msx_in is None:
313
317
  raise RuntimeError("You are not running EPANET-MSX")
314
318
 
315
- source_type_ = "None"
316
- if source_type == ToolkitConstants.EN_CONCEN:
317
- source_type_ = "CONCEN"
318
- elif source_type == ToolkitConstants.EN_MASS:
319
- source_type_ = "MASS"
320
- elif source_type == ToolkitConstants.EN_SETPOINT:
321
- source_type_ = "SETPOINT"
322
- elif source_type == ToolkitConstants.EN_FLOWPACED:
323
- source_type_ = "FLOWPACED"
324
-
325
- self._scenario_sim.epanet_api.setMSXPattern(pattern_id, [1])
326
- self._scenario_sim.epanet_api.setMSXSources(node_id, species_id, source_type_,
327
- source_strength, pattern_id)
319
+ pattern_idx = self._scenario_sim.epanet_api.MSXgetindex(EpanetConstants.MSX_PATTERN,
320
+ pattern_id)
321
+ self._scenario_sim.epanet_api.MSXsetpattern(pattern_idx, [1], 1)
322
+
323
+ node_idx = self._scenario_sim.epanet_api.get_node_idx(node_id)
324
+ species_idx = self._scenario_sim.epanet_api.get_msx_species_idx(species_id)
325
+ self._scenario_sim.epanet_api.MSXsetsource(node_idx, species_idx, source_type,
326
+ source_strength, pattern_idx)
328
327
 
329
328
  @abstractmethod
330
329
  def step(self, *actions) -> Union[tuple[ScadaData, float, bool], tuple[ScadaData, float]]:
@@ -2,8 +2,7 @@
2
2
  Module provides implementations of different types of actuator events.
3
3
  """
4
4
  import warnings
5
- from epyt.epanet import epanet
6
- import numpy as np
5
+ from epanet_plus import EPyT, EpanetConstants
7
6
 
8
7
  from .system_event import SystemEvent
9
8
  from ...serialization import serializable, JsonSerializable, PUMP_STATE_EVENT_ID, \
@@ -20,9 +19,15 @@ class ActuatorConstants:
20
19
  Valve or pump is closed.
21
20
  EN_OPEN
22
21
  Valve or pump is open -- i.e. active.
22
+ EN_SET_CLOSED
23
+ Link set closed indicator
24
+ EN_SET_OPEN
25
+ Link set open indicator
23
26
  """
24
27
  EN_CLOSED = 0
25
28
  EN_OPEN = 1
29
+ EN_SET_CLOSED = -1e10
30
+ EN_SET_OPEN = 1e10
26
31
 
27
32
 
28
33
  class ActuatorEvent(SystemEvent):
@@ -59,8 +64,8 @@ class PumpEvent(ActuatorEvent):
59
64
 
60
65
  super().__init__(**kwds)
61
66
 
62
- def init(self, epanet_api: epanet) -> None:
63
- if self.__pump_id not in epanet_api.getLinkPumpNameID():
67
+ def init(self, epanet_api: EPyT) -> None:
68
+ if self.__pump_id not in epanet_api.get_all_pumps_id():
64
69
  raise ValueError(f"Invalid pump ID '{self.__pump_id}'")
65
70
 
66
71
  super().init(epanet_api)
@@ -132,15 +137,15 @@ class PumpStateEvent(PumpEvent, JsonSerializable):
132
137
  return self.__pump_state
133
138
 
134
139
  def apply(self, cur_time: int) -> None:
135
- pump_idx = self._epanet_api.getLinkPumpNameID().index(self.pump_id) + 1
136
- pump_link_idx = self._epanet_api.getLinkPumpIndex(pump_idx)
140
+ pump_link_idx = self._epanet_api.getlinkindex(self.pump_id)
137
141
 
138
- pattern_idx = self._epanet_api.getLinkPumpPatternIndex(pump_idx)
142
+ pattern_idx = self._epanet_api.getlinkvalue(pump_link_idx, EpanetConstants.EN_LINKPATTERN)
139
143
  if pattern_idx != 0:
140
144
  warnings.warn(f"Can not set pump state of pump {self.pump_id} " +
141
145
  "because a pump pattern exists")
142
146
  else:
143
- self._epanet_api.setLinkStatus(pump_link_idx, self.__pump_state)
147
+ self._epanet_api.setlinkvalue(pump_link_idx, EpanetConstants.EN_STATUS,
148
+ self.__pump_state)
144
149
 
145
150
 
146
151
  @serializable(PUMP_SPEED_EVENT_ID, ".epytflow_pump_speed_event")
@@ -180,15 +185,17 @@ class PumpSpeedEvent(PumpEvent, JsonSerializable):
180
185
  return self.__pump_speed
181
186
 
182
187
  def apply(self, cur_time: int) -> None:
183
- pump_idx = self._epanet_api.getLinkPumpNameID().index(self.pump_id) + 1
184
- pattern_idx = self._epanet_api.getLinkPumpPatternIndex(pump_idx)
188
+ pump_idx = self._epanet_api.get_link_idx(self.pump_id)
189
+ pattern_idx = self._epanet_api.getlinkvalue(pump_idx, EpanetConstants.EN_LINKPATTERN)
185
190
 
186
191
  if pattern_idx == 0:
187
192
  warnings.warn(f"No pattern for pump '{self.pump_id}' found -- a new pattern is created")
188
- pattern_idx = self._epanet_api.addPattern(f"pump_speed_{self.pump_id}")
189
- self._epanet_api.setLinkPumpPatternIndex(pump_idx, pattern_idx)
193
+ pattern_id = f"pump_speed_{self.pump_id}"
194
+ self._epanet_api.add_pattern(pattern_id, [self.__pump_speed])
195
+ pattern_idx = self._epanet_api.getpatternindex(pattern_id)
196
+ self._epanet_api.setlinkvalue(pump_idx, EpanetConstants.EN_LINKPATTERN, pattern_idx)
190
197
 
191
- self._epanet_api.setPattern(pattern_idx, np.array([self.__pump_speed]))
198
+ self._epanet_api.setpattern(pattern_idx, [self.__pump_speed], 1)
192
199
 
193
200
 
194
201
  @serializable(VALVE_STATE_EVENT_ID, ".epytflow_valve_state_event")
@@ -222,8 +229,8 @@ class ValveStateEvent(ActuatorEvent, JsonSerializable):
222
229
 
223
230
  super().__init__(**kwds)
224
231
 
225
- def init(self, epanet_api: epanet) -> None:
226
- if self.__valve_id not in epanet_api.getLinkValveNameID():
232
+ def init(self, epanet_api: EPyT) -> None:
233
+ if self.__valve_id not in epanet_api.get_all_valves_id():
227
234
  raise ValueError(f"Invalid valve ID '{self.__valve_id}'")
228
235
 
229
236
  super().init(epanet_api)
@@ -260,6 +267,5 @@ class ValveStateEvent(ActuatorEvent, JsonSerializable):
260
267
  return self.__valve_state
261
268
 
262
269
  def apply(self, cur_time: int) -> None:
263
- valve_idx = self._epanet_api.getLinkValveNameID().index(self.__valve_id) + 1
264
- valve_link_idx = self._epanet_api.getLinkValveIndex(valve_idx)
265
- self._epanet_api.setLinkStatus(valve_link_idx, self.__valve_state)
270
+ valve_link_idx = self._epanet_api.get_link_idx(self.__valve_id)
271
+ self._epanet_api.setlinkvalue(valve_link_idx, EpanetConstants.EN_STATUS, self.__valve_state)
@@ -4,8 +4,7 @@ Module provides classes for implementing leakages.
4
4
  from copy import deepcopy
5
5
  import math
6
6
  import numpy as np
7
- import epyt
8
- from epyt.epanet import ToolkitConstants
7
+ from epanet_plus import EPyT, EpanetConstants
9
8
 
10
9
  from .system_event import SystemEvent
11
10
  from ...serialization import serializable, JsonSerializable, \
@@ -231,10 +230,10 @@ class Leakage(SystemEvent, JsonSerializable):
231
230
  `float`
232
231
  Leak emitter coefficient.
233
232
  """
234
- flow_unit = self._epanet_api.api.ENgetflowunits()
235
- if flow_unit == ToolkitConstants.EN_CMH:
233
+ flow_unit = self._epanet_api.getflowunits()
234
+ if flow_unit == EpanetConstants.EN_CMH:
236
235
  g = 127137600 # m/h^2
237
- elif flow_unit == ToolkitConstants.EN_CFS:
236
+ elif flow_unit == EpanetConstants.EN_CFS:
238
237
  g = 32.17405 # feet/s^2
239
238
  else:
240
239
  raise ValueError("Leakages are only implemented for the following flow units:\n" +
@@ -248,30 +247,30 @@ class Leakage(SystemEvent, JsonSerializable):
248
247
  def _get_new_node_id(self) -> str:
249
248
  return f"leak_node_{self.__link_id}"
250
249
 
251
- def init(self, epanet_api: epyt.epanet) -> None:
250
+ def init(self, epanet_api: EPyT) -> None:
252
251
  super().init(epanet_api)
253
252
 
254
253
  # Split pipe if leak is placed at a link/pipe
255
254
  if self.__link_id is not None:
256
- if self.__link_id not in self._epanet_api.getLinkNameID():
255
+ if self.__link_id not in self._epanet_api.get_all_links_id():
257
256
  raise ValueError(f"Unknown link/pipe '{self.__link_id}'")
258
257
 
259
258
  new_link_id = self._get_new_link_id()
260
259
  new_node_id = self._get_new_node_id()
261
260
 
262
- all_nodes_id = self._epanet_api.getNodeNameID()
261
+ all_nodes_id = self._epanet_api.get_all_nodes_id()
263
262
  if new_node_id in all_nodes_id:
264
263
  raise ValueError(f"There is already a leak at pipe {self.link_id}")
265
264
 
266
- self._epanet_api.splitPipe(self.link_id, new_link_id, new_node_id)
267
- self.__leaky_node_idx = self._epanet_api.getNodeIndex(new_node_id)
265
+ self._epanet_api.split_pipe(self.link_id, new_link_id, new_node_id)
266
+ self.__leaky_node_idx = self._epanet_api.get_node_idx(new_node_id)
268
267
  else:
269
- if self.__node_id not in self._epanet_api.getNodeNameID():
268
+ if self.__node_id not in self._epanet_api.get_all_nodes_id():
270
269
  raise ValueError(f"Unknown node '{self.__node_id}'")
271
270
 
272
- self.__leaky_node_idx = self._epanet_api.getNodeIndex(self.__node_id)
271
+ self.__leaky_node_idx = self._epanet_api.get_node_idx(self.__node_id)
273
272
 
274
- self._epanet_api.setNodeEmitterCoeff(self.__leaky_node_idx, 0.)
273
+ self._epanet_api.setnodevalue(self.__leaky_node_idx, EpanetConstants.EN_EMITTER, 0.)
275
274
 
276
275
  # Compute leak emitter coefficient
277
276
  self.__leak_emitter_coef = self.compute_leak_emitter_coefficient(
@@ -279,51 +278,54 @@ class Leakage(SystemEvent, JsonSerializable):
279
278
 
280
279
  def cleanup(self) -> None:
281
280
  if self.__link_id is not None:
282
- pipe_idx = self._epanet_api.getLinkIndex(self.__link_id)
283
- link_prop = self._epanet_api.getLinksInfo()
284
- link_diameter = link_prop.LinkDiameter[pipe_idx - 1]
285
- link_length = link_prop.LinkLength[pipe_idx - 1] * 2.
286
- link_roughness_coeff = link_prop.LinkRoughnessCoeff[pipe_idx - 1]
287
- link_minor_loss_coeff = link_prop.LinkMinorLossCoeff[pipe_idx - 1]
288
- link_initial_status = link_prop.LinkInitialStatus[pipe_idx - 1]
289
- link_initial_setting = link_prop.LinkInitialSetting[pipe_idx - 1]
290
- link_bulk_reaction_coeff = link_prop.LinkBulkReactionCoeff[pipe_idx - 1]
291
- link_wall_reaction_coeff = link_prop.LinkWallReactionCoeff[pipe_idx - 1]
292
-
293
- node_a_idx = int(self._epanet_api.getLinkNodesIndex(pipe_idx)[0])
294
- node_b_idx = int(self._epanet_api.getLinkNodesIndex(self._get_new_link_id())[1])
295
-
296
- self._epanet_api.deleteLink(self._get_new_link_id())
297
- self._epanet_api.deleteLink(self.__link_id)
298
- self._epanet_api.deleteNode(self._get_new_node_id())
299
-
300
- self._epanet_api.addLinkPipe(self.__link_id,
301
- self._epanet_api.getNodeNameID(node_a_idx),
302
- self._epanet_api.getNodeNameID(node_b_idx))
303
- link_idx = self._epanet_api.getLinkIndex(self.__link_id)
304
- self._epanet_api.setLinkNodesIndex(link_idx,
305
- node_a_idx, node_b_idx)
306
- self._epanet_api.setLinkPipeData(link_idx, link_length, link_diameter,
307
- link_roughness_coeff,
308
- link_minor_loss_coeff)
309
- if link_minor_loss_coeff != 0:
310
- self._epanet_api.setLinklinkMinorLossCoeff(link_idx, link_minor_loss_coeff)
311
- self._epanet_api.setLinkInitialStatus(link_idx, link_initial_status)
312
- self._epanet_api.setLinkInitialSetting(link_idx, link_initial_setting)
313
- self._epanet_api.setLinkBulkReactionCoeff(link_idx, link_bulk_reaction_coeff)
314
- self._epanet_api.setLinkWallReactionCoeff(link_idx, link_wall_reaction_coeff)
315
- self._epanet_api.setLinkTypePipe(link_idx)
281
+ pipe_idx = self._epanet_api.get_link_idx(self.__link_id)
282
+ link_diameter = self._epanet_api.get_link_diameter(pipe_idx)
283
+ link_length = self._epanet_api.get_link_length(pipe_idx)
284
+ link_roughness_coeff = self._epanet_api.get_link_roughness(pipe_idx)
285
+ link_minor_loss_coeff = self._epanet_api.get_link_minorloss(pipe_idx)
286
+ link_initial_status = self._epanet_api.get_link_init_status(pipe_idx)
287
+ link_initial_setting = self._epanet_api.get_link_init_setting(pipe_idx)
288
+ link_bulk_reaction_coeff = self._epanet_api.get_link_bulk_raction_coeff(pipe_idx)
289
+ link_wall_reaction_coeff = self._epanet_api.get_link_wall_raction_coeff(pipe_idx)
290
+
291
+ node_a_idx = int(self._epanet_api.getlinknodes(pipe_idx)[0])
292
+ node_b_idx = int(self._epanet_api.getlinknodes(self._epanet_api.get_link_idx(self._get_new_link_id()))[1])
293
+
294
+ self._epanet_api.deletelink(self._epanet_api.get_link_idx(self._get_new_link_id()),
295
+ EpanetConstants.EN_UNCONDITIONAL)
296
+ self._epanet_api.deletelink(self._epanet_api.get_link_idx(self.__link_id),
297
+ EpanetConstants.EN_UNCONDITIONAL)
298
+ self._epanet_api.deletenode(self._epanet_api.get_node_idx(self._get_new_node_id()),
299
+ EpanetConstants.EN_UNCONDITIONAL)
300
+
301
+ self._epanet_api.addlink(self.__link_id, EpanetConstants.EN_PIPE,
302
+ self._epanet_api.get_node_id(node_a_idx),
303
+ self._epanet_api.get_node_id(node_b_idx))
304
+ link_idx = self._epanet_api.get_link_idx(self.__link_id)
305
+ self._epanet_api.setlinknodes(link_idx, node_a_idx, node_b_idx)
306
+ self._epanet_api.setlinktype(link_idx, EpanetConstants.EN_PIPE,
307
+ EpanetConstants.EN_UNCONDITIONAL)
308
+ self._epanet_api.setpipedata(link_idx, link_length, link_diameter, link_roughness_coeff,
309
+ link_minor_loss_coeff)
310
+ self._epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_INITSTATUS,
311
+ link_initial_status)
312
+ self._epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_INITSETTING,
313
+ link_initial_setting)
314
+ self._epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_KBULK,
315
+ link_bulk_reaction_coeff)
316
+ self._epanet_api.setlinkvalue(link_idx, EpanetConstants.EN_KWALL,
317
+ link_wall_reaction_coeff)
316
318
 
317
319
  def reset(self) -> None:
318
320
  self.__time_pattern_idx = 0
319
321
 
320
322
  def exit(self, cur_time) -> None:
321
- self._epanet_api.setNodeEmitterCoeff(self.__leaky_node_idx, 0.)
323
+ self._epanet_api.setnodevalue(self.__leaky_node_idx, EpanetConstants.EN_EMITTER, 0.)
322
324
 
323
325
  def apply(self, cur_time: int) -> None:
324
- self._epanet_api.setNodeEmitterCoeff(self.__leaky_node_idx,
325
- self.__leak_emitter_coef *
326
- self.__profile[self.__time_pattern_idx])
326
+ self._epanet_api.setnodevalue(self.__leaky_node_idx, EpanetConstants.EN_EMITTER,
327
+ self.__leak_emitter_coef *
328
+ self.__profile[self.__time_pattern_idx])
327
329
  self.__time_pattern_idx += 1
328
330
 
329
331
 
@@ -357,12 +359,12 @@ class AbruptLeakage(Leakage):
357
359
  else:
358
360
  super().__init__(link_id=link_id, diameter=diameter, area=area, **kwds)
359
361
 
360
- def init(self, epanet_api: epyt.epanet) -> None:
362
+ def init(self, epanet_api: EPyT) -> None:
361
363
  super().init(epanet_api)
362
364
 
363
365
  # Set pattern
364
- total_sim_duration = self._epanet_api.getTimeSimulationDuration()
365
- time_step = self._epanet_api.getTimeHydraulicStep()
366
+ total_sim_duration = self._epanet_api.get_simulation_duration()
367
+ time_step = self._epanet_api.get_hydraulic_time_step()
366
368
 
367
369
  if self.end_time is not None:
368
370
  n_leaky_time_points = math.ceil((self.end_time - self.start_time) / time_step)
@@ -436,12 +438,12 @@ class IncipientLeakage(Leakage):
436
438
  def __str__(self) -> str:
437
439
  return f"{super().__str__()} peak_time: {self.peak_time}"
438
440
 
439
- def init(self, epanet_api: epyt.epanet) -> None:
441
+ def init(self, epanet_api: EPyT) -> None:
440
442
  super().init(epanet_api)
441
443
 
442
444
  # Set pattern
443
- total_sim_duration = self._epanet_api.getTimeSimulationDuration()
444
- time_step = self._epanet_api.getTimeHydraulicStep()
445
+ total_sim_duration = self._epanet_api.get_simulation_duration()
446
+ time_step = self._epanet_api.get_hydraulic_time_step()
445
447
 
446
448
  if self.end_time is not None:
447
449
  n_leaky_time_points = math.ceil((self.end_time - self.start_time) / time_step)