epyt-flow 0.9.0__tar.gz → 0.11.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.
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/LICENSE +1 -1
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/PKG-INFO +18 -6
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/README.md +14 -3
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/REQUIREMENTS.txt +1 -1
- epyt_flow-0.11.0/epyt_flow/VERSION +1 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/networks.py +27 -14
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/gym/control_gyms.py +8 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/gym/scenario_control_env.py +17 -4
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/metrics.py +5 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/models/event_detector.py +5 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/models/sensor_interpolation_detector.py +5 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/serialization.py +5 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/__init__.py +0 -1
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/actuator_events.py +7 -1
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/sensor_reading_attack.py +16 -3
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/sensor_reading_event.py +18 -3
- epyt_flow-0.11.0/epyt_flow/simulation/scada/__init__.py +5 -0
- epyt_flow-0.11.0/epyt_flow/simulation/scada/advanced_control.py +138 -0
- epyt_flow-0.11.0/epyt_flow/simulation/scada/complex_control.py +625 -0
- epyt_flow-0.9.0/epyt_flow/simulation/scada/advanced_control.py → epyt_flow-0.11.0/epyt_flow/simulation/scada/custom_control.py +3 -3
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/scada/scada_data.py +547 -8
- epyt_flow-0.11.0/epyt_flow/simulation/scada/simple_control.py +317 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/scenario_config.py +87 -26
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/scenario_simulator.py +865 -51
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/sensor_config.py +34 -2
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/topology.py +16 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/uncertainty/model_uncertainty.py +80 -62
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/uncertainty/sensor_noise.py +15 -4
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/uncertainty/uncertainties.py +71 -18
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/uncertainty/utils.py +40 -13
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/utils.py +15 -1
- epyt_flow-0.11.0/epyt_flow/visualization/__init__.py +2 -0
- {epyt_flow-0.9.0/epyt_flow/simulation → epyt_flow-0.11.0/epyt_flow/visualization}/scenario_visualizer.py +429 -586
- epyt_flow-0.11.0/epyt_flow/visualization/visualization_utils.py +611 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow.egg-info/PKG-INFO +18 -6
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow.egg-info/SOURCES.txt +7 -2
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow.egg-info/requires.txt +1 -1
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow.egg-info/top_level.txt +1 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/pyproject.toml +2 -1
- epyt_flow-0.9.0/epyt_flow/VERSION +0 -1
- epyt_flow-0.9.0/epyt_flow/simulation/scada/__init__.py +0 -3
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/CITATION.cff +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/CODE_OF_CONDUCT.md +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/MANIFEST.in +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/genmmd.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/hash.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/hash.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/input1.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/input2.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/input3.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/main.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/output.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/project.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/quality.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/report.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/rules.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/text.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET/SRC_engines/types.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/MSX_Updates.txt +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/dispersion.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/hash.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/hash.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx_export.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/mempool.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/mempool.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxchem.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxcompiler.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxdict.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxdispersion.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxerr.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxfile.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxinp.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxout.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxproj.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxqual.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxrpt.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxtank.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxtoolkit.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxtypes.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxutils.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxutils.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/newton.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/newton.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/rk5.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/rk5.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/ros2.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/ros2.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/smatrix.c +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/Src/smatrix.h +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/EPANET-MSX/readme.txt +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/compile_linux.sh +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/EPANET/compile_macos.sh +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/batadal.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/batadal_data.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/battledim.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/battledim_data.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/gecco_water_quality.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/leakdb.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/leakdb_data.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/data/benchmarks/water_usage.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/gym/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/models/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/base_handler.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/res_manager.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scada_data/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scada_data/data_handlers.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scada_data/export_handlers.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scada_data/handlers.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scenario/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scenario/event_handlers.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scenario/handlers.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scenario/simulation_handlers.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/scenario/uncertainty_handlers.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/rest_api/server.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/event.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/leakages.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/quality_events.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/sensor_faults.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/events/system_event.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/parallel_simulation.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/simulation/scada/scada_data_export.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow/uncertainty/__init__.py +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/epyt_flow.egg-info/dependency_links.txt +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/setup.cfg +0 -0
- {epyt_flow-0.9.0 → epyt_flow-0.11.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: epyt-flow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: EPyT-Flow -- EPANET Python Toolkit - Flow
|
|
5
5
|
Author-email: André Artelt <aartelt@techfak.uni-bielefeld.de>, "Marios S. Kyriakou" <kiriakou.marios@ucy.ac.cy>, "Stelios G. Vrachimis" <vrachimis.stelios@ucy.ac.cy>
|
|
6
6
|
License: MIT License
|
|
@@ -17,10 +17,11 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
21
|
Requires-Python: >=3.9
|
|
21
22
|
Description-Content-Type: text/markdown
|
|
22
23
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: epyt>=1.2.
|
|
24
|
+
Requires-Dist: epyt>=1.2.1
|
|
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
|
|
@@ -66,8 +67,8 @@ Unique features of EPyT-Flow that make it superior to other (Python) toolboxes a
|
|
|
66
67
|
- High- and low-level interface
|
|
67
68
|
- Object-orientated design that is easy to extend and customize
|
|
68
69
|
- Sensor configurations
|
|
69
|
-
- Wide variety of pre-defined events (e.g. leakages, sensor faults, actuator events, cyber-attacks, etc.)
|
|
70
|
-
- Wide variety of pre-defined types of uncertainties (e.g. model uncertainties)
|
|
70
|
+
- Wide variety of pre-defined events (e.g. leakages, sensor faults, actuator events, contamination, cyber-attacks, etc.)
|
|
71
|
+
- Wide variety of pre-defined types of global & local uncertainties (e.g. model uncertainties)
|
|
71
72
|
- Step-wise simulation and environment for training and evaluating control strategies
|
|
72
73
|
- Serialization module for easy exchange of data and (scenario) configurations
|
|
73
74
|
- REST API to make EPyT-Flow accessible in other applications
|
|
@@ -76,7 +77,7 @@ Unique features of EPyT-Flow that make it superior to other (Python) toolboxes a
|
|
|
76
77
|
|
|
77
78
|
## Installation
|
|
78
79
|
|
|
79
|
-
EPyT-Flow supports Python 3.9 - 3.
|
|
80
|
+
EPyT-Flow supports Python 3.9 - 3.13
|
|
80
81
|
|
|
81
82
|
Note that [EPANET and EPANET-MSX sources](epyt_flow/EPANET/) are compiled and overwrite the binaries
|
|
82
83
|
shipped by EPyT **IF** EPyT-Flow is installed on a Unix system and the *gcc* compiler is available.
|
|
@@ -183,6 +184,17 @@ Besides that, you can read in-depth about the different functionalities of EPyT-
|
|
|
183
184
|
we recommend reading the chapters in the order in which they are presented;
|
|
184
185
|
you might decide to skip some of the last chapters if their content is not relevant to you.
|
|
185
186
|
|
|
187
|
+
## More Networks and Benchmarks
|
|
188
|
+
|
|
189
|
+
More Water Distribution Networks (WDNs) and benchmarks are available on the
|
|
190
|
+
[WaterBenchmarkHub](https://waterfutures.github.io/WaterBenchmarkHub) platform.
|
|
191
|
+
|
|
192
|
+
## More on Control
|
|
193
|
+
|
|
194
|
+
We recommend checking out [EPyT-Control](https://github.com/WaterFutures/EPyT-Control)
|
|
195
|
+
if you are intersted in (data-driven) control and relates tasks such as state estimation
|
|
196
|
+
and event diagnosis in Water Distribution Networks.
|
|
197
|
+
|
|
186
198
|
## License
|
|
187
199
|
|
|
188
200
|
MIT license -- see [LICENSE](LICENSE)
|
|
@@ -29,8 +29,8 @@ Unique features of EPyT-Flow that make it superior to other (Python) toolboxes a
|
|
|
29
29
|
- High- and low-level interface
|
|
30
30
|
- Object-orientated design that is easy to extend and customize
|
|
31
31
|
- Sensor configurations
|
|
32
|
-
- Wide variety of pre-defined events (e.g. leakages, sensor faults, actuator events, cyber-attacks, etc.)
|
|
33
|
-
- Wide variety of pre-defined types of uncertainties (e.g. model uncertainties)
|
|
32
|
+
- Wide variety of pre-defined events (e.g. leakages, sensor faults, actuator events, contamination, cyber-attacks, etc.)
|
|
33
|
+
- Wide variety of pre-defined types of global & local uncertainties (e.g. model uncertainties)
|
|
34
34
|
- Step-wise simulation and environment for training and evaluating control strategies
|
|
35
35
|
- Serialization module for easy exchange of data and (scenario) configurations
|
|
36
36
|
- REST API to make EPyT-Flow accessible in other applications
|
|
@@ -39,7 +39,7 @@ Unique features of EPyT-Flow that make it superior to other (Python) toolboxes a
|
|
|
39
39
|
|
|
40
40
|
## Installation
|
|
41
41
|
|
|
42
|
-
EPyT-Flow supports Python 3.9 - 3.
|
|
42
|
+
EPyT-Flow supports Python 3.9 - 3.13
|
|
43
43
|
|
|
44
44
|
Note that [EPANET and EPANET-MSX sources](epyt_flow/EPANET/) are compiled and overwrite the binaries
|
|
45
45
|
shipped by EPyT **IF** EPyT-Flow is installed on a Unix system and the *gcc* compiler is available.
|
|
@@ -146,6 +146,17 @@ Besides that, you can read in-depth about the different functionalities of EPyT-
|
|
|
146
146
|
we recommend reading the chapters in the order in which they are presented;
|
|
147
147
|
you might decide to skip some of the last chapters if their content is not relevant to you.
|
|
148
148
|
|
|
149
|
+
## More Networks and Benchmarks
|
|
150
|
+
|
|
151
|
+
More Water Distribution Networks (WDNs) and benchmarks are available on the
|
|
152
|
+
[WaterBenchmarkHub](https://waterfutures.github.io/WaterBenchmarkHub) platform.
|
|
153
|
+
|
|
154
|
+
## More on Control
|
|
155
|
+
|
|
156
|
+
We recommend checking out [EPyT-Control](https://github.com/WaterFutures/EPyT-Control)
|
|
157
|
+
if you are intersted in (data-driven) control and relates tasks such as state estimation
|
|
158
|
+
and event diagnosis in Water Distribution Networks.
|
|
159
|
+
|
|
149
160
|
## License
|
|
150
161
|
|
|
151
162
|
MIT license -- see [LICENSE](LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.11.0
|
|
@@ -154,8 +154,9 @@ def load_net1(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
154
154
|
"""
|
|
155
155
|
f_in = os.path.join(download_dir, "Net1.inp")
|
|
156
156
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/Net1.inp"
|
|
157
|
+
backup_urls = ["https://raw.githubusercontent.com/OpenWaterAnalytics/EPyT/refs/heads/dev/epyt/networks/asce-tf-wdst/Net1.inp"]
|
|
157
158
|
|
|
158
|
-
download_if_necessary(f_in, url, verbose)
|
|
159
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
159
160
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
160
161
|
|
|
161
162
|
|
|
@@ -201,8 +202,9 @@ def load_net2(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
201
202
|
"""
|
|
202
203
|
f_in = os.path.join(download_dir, "Net2.inp")
|
|
203
204
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/Net2.inp"
|
|
205
|
+
backup_urls = ["https://raw.githubusercontent.com/OpenWaterAnalytics/EPyT/refs/heads/dev/epyt/networks/asce-tf-wdst/Net2.inp"]
|
|
204
206
|
|
|
205
|
-
download_if_necessary(f_in, url, verbose)
|
|
207
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
206
208
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
207
209
|
|
|
208
210
|
|
|
@@ -248,8 +250,9 @@ def load_net3(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
248
250
|
"""
|
|
249
251
|
f_in = os.path.join(download_dir, "Net3.inp")
|
|
250
252
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/Net3.inp"
|
|
253
|
+
backup_urls = ["https://raw.githubusercontent.com/OpenWaterAnalytics/EPyT/refs/heads/dev/epyt/networks/asce-tf-wdst/Net3.inp"]
|
|
251
254
|
|
|
252
|
-
download_if_necessary(f_in, url, verbose)
|
|
255
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
253
256
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
254
257
|
|
|
255
258
|
|
|
@@ -342,8 +345,9 @@ def load_richmond(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
342
345
|
"""
|
|
343
346
|
f_in = os.path.join(download_dir, "Richmond_standard.inp")
|
|
344
347
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/Richmond_standard.inp"
|
|
348
|
+
backup_urls = ["https://raw.githubusercontent.com/KIOS-Research/EPANET-Benchmarks/refs/heads/master/collect-epanet-inp/Richmond_standard.inp"]
|
|
345
349
|
|
|
346
|
-
download_if_necessary(f_in, url, verbose)
|
|
350
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
347
351
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
348
352
|
|
|
349
353
|
|
|
@@ -389,8 +393,9 @@ def load_micropolis(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
389
393
|
"""
|
|
390
394
|
f_in = os.path.join(download_dir, "MICROPOLIS_v1.inp")
|
|
391
395
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/MICROPOLIS_v1.inp"
|
|
396
|
+
backup_urls = ["https://raw.githubusercontent.com/KIOS-Research/EPANET-Benchmarks/refs/heads/master/collect-epanet-inp/MICROPOLIS_v1.inp"]
|
|
392
397
|
|
|
393
|
-
download_if_necessary(f_in, url, verbose)
|
|
398
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
394
399
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
395
400
|
|
|
396
401
|
|
|
@@ -436,8 +441,9 @@ def load_balerma(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
436
441
|
"""
|
|
437
442
|
f_in = os.path.join(download_dir, "Balerma.inp")
|
|
438
443
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/Balerma.inp"
|
|
444
|
+
backup_urls = ["https://raw.githubusercontent.com/KIOS-Research/EPANET-Benchmarks/refs/heads/master/collect-epanet-inp/Balerma.inp"]
|
|
439
445
|
|
|
440
|
-
download_if_necessary(f_in, url, verbose)
|
|
446
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
441
447
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
442
448
|
|
|
443
449
|
|
|
@@ -483,8 +489,9 @@ def load_rural(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
483
489
|
"""
|
|
484
490
|
f_in = os.path.join(download_dir, "RuralNetwork.inp")
|
|
485
491
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/RuralNetwork.inp"
|
|
492
|
+
backup_urls = ["https://raw.githubusercontent.com/KIOS-Research/EPANET-Benchmarks/refs/heads/master/collect-epanet-inp/RuralNetwork.inp"]
|
|
486
493
|
|
|
487
|
-
download_if_necessary(f_in, url, verbose)
|
|
494
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
488
495
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
489
496
|
|
|
490
497
|
|
|
@@ -530,8 +537,9 @@ def load_bwsn1(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
530
537
|
"""
|
|
531
538
|
f_in = os.path.join(download_dir, "BWSN_Network_1.inp")
|
|
532
539
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/BWSN_Network_1.inp"
|
|
540
|
+
backup_urls = ["https://raw.githubusercontent.com/KIOS-Research/EPANET-Benchmarks/refs/heads/master/collect-epanet-inp/BWSN_Network_1.inp"]
|
|
533
541
|
|
|
534
|
-
download_if_necessary(f_in, url, verbose)
|
|
542
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
535
543
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
536
544
|
|
|
537
545
|
|
|
@@ -577,8 +585,9 @@ def load_bwsn2(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
577
585
|
"""
|
|
578
586
|
f_in = os.path.join(download_dir, "BWSN_Network_2.inp")
|
|
579
587
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/BWSN_Network_2.inp"
|
|
588
|
+
backup_urls = ["https://raw.githubusercontent.com/KIOS-Research/EPANET-Benchmarks/refs/heads/master/collect-epanet-inp/BWSN_Network_2.inp"]
|
|
580
589
|
|
|
581
|
-
download_if_necessary(f_in, url, verbose)
|
|
590
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
582
591
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
583
592
|
|
|
584
593
|
|
|
@@ -624,8 +633,9 @@ def load_anytown(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
624
633
|
"""
|
|
625
634
|
f_in = os.path.join(download_dir, "Anytown.inp")
|
|
626
635
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/Anytown.inp"
|
|
636
|
+
backup_urls = ["https://raw.githubusercontent.com/OpenWaterAnalytics/EPyT/refs/heads/dev/epyt/networks/asce-tf-wdst/Anytown.inp"]
|
|
627
637
|
|
|
628
|
-
download_if_necessary(f_in, url, verbose)
|
|
638
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
629
639
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
630
640
|
|
|
631
641
|
|
|
@@ -670,9 +680,10 @@ def load_dtown(download_dir: str = get_temp_folder(), verbose: bool = True,
|
|
|
670
680
|
:class:`~epyt_flow.simulation.scenario_simulator.ScenarioSimulator`.
|
|
671
681
|
"""
|
|
672
682
|
f_in = os.path.join(download_dir, "d-town.inp")
|
|
673
|
-
url = "https://
|
|
683
|
+
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/d-town.inp"
|
|
684
|
+
backup_urls = ["https://raw.githubusercontent.com/KIOS-Research/EPANET-Benchmarks/refs/heads/master/collect-epanet-inp/d-town.inp"]
|
|
674
685
|
|
|
675
|
-
download_if_necessary(f_in, url, verbose)
|
|
686
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
676
687
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
677
688
|
|
|
678
689
|
|
|
@@ -774,8 +785,9 @@ def load_kentucky(wdn_id: int = 1, download_dir: str = get_temp_folder(),
|
|
|
774
785
|
|
|
775
786
|
f_in = os.path.join(download_dir, f"ky{wdn_id}.inp")
|
|
776
787
|
url = f"https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/ky{wdn_id}.inp"
|
|
788
|
+
backup_urls = [f"https://raw.githubusercontent.com/OpenWaterAnalytics/EPyT/refs/heads/dev/epyt/networks/asce-tf-wdst/ky{wdn_id}.inp"]
|
|
777
789
|
|
|
778
|
-
download_if_necessary(f_in, url, verbose)
|
|
790
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
779
791
|
return load_inp(f_in, flow_units_id=flow_units_id)
|
|
780
792
|
|
|
781
793
|
|
|
@@ -826,8 +838,9 @@ def load_hanoi(download_dir: str = get_temp_folder(),
|
|
|
826
838
|
"""
|
|
827
839
|
f_in = os.path.join(download_dir, "Hanoi.inp")
|
|
828
840
|
url = "https://filedn.com/lumBFq2P9S74PNoLPWtzxG4/EPyT-Flow/Networks/Hanoi.inp"
|
|
841
|
+
backup_urls = ["https://raw.githubusercontent.com/OpenWaterAnalytics/EPyT/refs/heads/dev/epyt/networks/asce-tf-wdst/Hanoi.inp"]
|
|
829
842
|
|
|
830
|
-
download_if_necessary(f_in, url, verbose)
|
|
843
|
+
download_if_necessary(f_in, url, verbose, backup_urls)
|
|
831
844
|
config = load_inp(f_in, flow_units_id=flow_units_id)
|
|
832
845
|
|
|
833
846
|
if include_default_sensor_placement is True:
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Module provides functions for registering and creating control environments.
|
|
3
3
|
"""
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
4
6
|
from .scenario_control_env import ScenarioControlEnv
|
|
5
7
|
|
|
6
8
|
|
|
@@ -18,6 +20,9 @@ def register(env_name: str, env: ScenarioControlEnv) -> None:
|
|
|
18
20
|
env : :class:`~epyt_flow.gym.scenario_control_env.ScenarioControlEnv`
|
|
19
21
|
Environment.
|
|
20
22
|
"""
|
|
23
|
+
warnings.warn("'register()' is deprecated and will be removed in future releases -- " +
|
|
24
|
+
"please consider switching to the EPyT-Control package")
|
|
25
|
+
|
|
21
26
|
if env_name in environments:
|
|
22
27
|
raise ValueError(f"Environment '{env_name}' already exists.")
|
|
23
28
|
if not issubclass(env, ScenarioControlEnv):
|
|
@@ -41,6 +46,9 @@ def make(env_name: str, **kwds) -> ScenarioControlEnv:
|
|
|
41
46
|
:class:`~epyt_flow.gym.scenario_control_env.ScenarioControlEnv`
|
|
42
47
|
Environment.
|
|
43
48
|
"""
|
|
49
|
+
warnings.warn("'make()' is deprecated and will be removed in future releases -- " +
|
|
50
|
+
"please consider switching to the EPyT-Control package")
|
|
51
|
+
|
|
44
52
|
if env_name not in environments:
|
|
45
53
|
raise ValueError(f"Unknown environment '{env_name}'.")
|
|
46
54
|
|
|
@@ -107,6 +107,14 @@ class ScenarioControlEnv(ABC):
|
|
|
107
107
|
Current SCADA data (i.e. sensor readings).
|
|
108
108
|
"""
|
|
109
109
|
if self._scenario_sim is not None:
|
|
110
|
+
# Abort current simulation if any is runing
|
|
111
|
+
try:
|
|
112
|
+
next(self._sim_generator)
|
|
113
|
+
self._sim_generator.send(True)
|
|
114
|
+
except StopIteration:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
# Close scenario
|
|
110
118
|
self._scenario_sim.close()
|
|
111
119
|
|
|
112
120
|
self._scenario_sim = ScenarioSimulator(
|
|
@@ -169,9 +177,14 @@ class ScenarioControlEnv(ABC):
|
|
|
169
177
|
raise RuntimeError("Can not execute actions affecting the hydraulics "+
|
|
170
178
|
"when running EPANET-MSX")
|
|
171
179
|
|
|
172
|
-
pump_idx = self._scenario_sim.epanet_api.getLinkPumpNameID().index(pump_id)
|
|
173
|
-
pump_link_idx = self._scenario_sim.epanet_api.getLinkPumpIndex(pump_idx
|
|
174
|
-
|
|
180
|
+
pump_idx = self._scenario_sim.epanet_api.getLinkPumpNameID().index(pump_id) + 1
|
|
181
|
+
pump_link_idx = self._scenario_sim.epanet_api.getLinkPumpIndex(pump_idx)
|
|
182
|
+
|
|
183
|
+
pattern_idx = self._scenario_sim.epanet_api.getLinkPumpPatternIndex(pump_idx)
|
|
184
|
+
if pattern_idx != 0:
|
|
185
|
+
warnings.warn(f"Can not set pump state of pump {pump_id} because a pump pattern exists")
|
|
186
|
+
else:
|
|
187
|
+
self._scenario_sim.epanet_api.setLinkStatus(pump_link_idx, status)
|
|
175
188
|
|
|
176
189
|
def set_pump_speed(self, pump_id: str, speed: float) -> None:
|
|
177
190
|
"""
|
|
@@ -194,7 +207,7 @@ class ScenarioControlEnv(ABC):
|
|
|
194
207
|
if pattern_idx == 0:
|
|
195
208
|
warnings.warn(f"No pattern for pump '{pump_id}' found -- a new pattern is created")
|
|
196
209
|
pattern_idx = self._scenario_sim.epanet_api.addPattern(f"pump_speed_{pump_id}")
|
|
197
|
-
self._scenario_sim.epanet_api.setLinkPumpPatternIndex(pump_idx, pattern_idx)
|
|
210
|
+
self._scenario_sim.epanet_api.setLinkPumpPatternIndex(pump_idx + 1, pattern_idx)
|
|
198
211
|
|
|
199
212
|
self._scenario_sim.epanet_api.setPattern(pattern_idx, np.array([speed]))
|
|
200
213
|
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module provides different metrics for evaluation.
|
|
3
3
|
"""
|
|
4
|
+
import warnings
|
|
4
5
|
import numpy as np
|
|
5
6
|
from sklearn.metrics import roc_auc_score as skelarn_roc_auc_score, f1_score as skelarn_f1_scpre, \
|
|
6
7
|
mean_absolute_error, root_mean_squared_error, r2_score as sklearn_r2_score
|
|
7
8
|
|
|
8
9
|
|
|
10
|
+
warnings.warn("'epyt_flow.metrics' is deprecated in favor of EPyT-Control " +
|
|
11
|
+
"and will be removed in future releases.")
|
|
12
|
+
|
|
13
|
+
|
|
9
14
|
def r2_score(y_pred: np.ndarray, y: np.ndarray) -> float:
|
|
10
15
|
"""
|
|
11
16
|
Computes the R^2 score (also called the coefficient of determination).
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Module provides a base class for event detectors.
|
|
3
3
|
"""
|
|
4
|
+
import warnings
|
|
4
5
|
from abc import abstractmethod, ABC
|
|
5
6
|
|
|
6
7
|
from ..simulation.scada import ScadaData
|
|
7
8
|
|
|
8
9
|
|
|
10
|
+
warnings.warn("'epyt_flow.models' is deprecated in favor of EPyT-Control " +
|
|
11
|
+
"and will be removed in future releases.")
|
|
12
|
+
|
|
13
|
+
|
|
9
14
|
class EventDetector(ABC):
|
|
10
15
|
"""
|
|
11
16
|
Base class for event detectors.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Module provides a simple residual-based event detector that performs sensor interpolation.
|
|
3
3
|
"""
|
|
4
|
+
import warnings
|
|
4
5
|
from typing import Any, Union
|
|
5
6
|
from copy import deepcopy
|
|
6
7
|
import numpy as np
|
|
@@ -10,6 +11,10 @@ from .event_detector import EventDetector
|
|
|
10
11
|
from ..simulation.scada import ScadaData
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
warnings.warn("'epyt_flow.models' is deprecated in favor of EPyT-Control " +
|
|
15
|
+
"and will be removed in future releases.")
|
|
16
|
+
|
|
17
|
+
|
|
13
18
|
class SensorInterpolationDetector(EventDetector):
|
|
14
19
|
"""
|
|
15
20
|
Class implementing a residual-based event detector based on sensor interpolation.
|
|
@@ -48,6 +48,11 @@ PUMP_STATE_EVENT_ID = 28
|
|
|
48
48
|
PUMP_SPEED_EVENT_ID = 29
|
|
49
49
|
VALVE_STATE_EVENT_ID = 30
|
|
50
50
|
SPECIESINJECTION_EVENT_ID = 31
|
|
51
|
+
SIMPLE_CONTROL_ID = 32
|
|
52
|
+
COMPLEX_CONTROL_ID = 33
|
|
53
|
+
COMPLEX_CONTROL_CONDITION_ID = 34
|
|
54
|
+
COMPLEX_CONTROL_ACTION_ID = 35
|
|
55
|
+
COLOR_SCHEMES_ID = 36
|
|
51
56
|
|
|
52
57
|
|
|
53
58
|
def my_packb(data: Any) -> bytes:
|
|
@@ -134,7 +134,13 @@ class PumpStateEvent(PumpEvent, JsonSerializable):
|
|
|
134
134
|
def apply(self, cur_time: int) -> None:
|
|
135
135
|
pump_idx = self._epanet_api.getLinkPumpNameID().index(self.pump_id) + 1
|
|
136
136
|
pump_link_idx = self._epanet_api.getLinkPumpIndex(pump_idx)
|
|
137
|
-
|
|
137
|
+
|
|
138
|
+
pattern_idx = self._epanet_api.getLinkPumpPatternIndex(pump_idx)
|
|
139
|
+
if pattern_idx != 0:
|
|
140
|
+
warnings.warn(f"Can not set pump state of pump {self.pump_id} " +
|
|
141
|
+
"because a pump pattern exists")
|
|
142
|
+
else:
|
|
143
|
+
self._epanet_api.setLinkStatus(pump_link_idx, self.__pump_state)
|
|
138
144
|
|
|
139
145
|
|
|
140
146
|
@serializable(PUMP_SPEED_EVENT_ID, ".epytflow_pump_speed_event")
|
|
@@ -46,7 +46,7 @@ class SensorOverrideAttack(SensorReadingAttack, JsonSerializable):
|
|
|
46
46
|
@property
|
|
47
47
|
def new_sensor_values(self) -> np.ndarray:
|
|
48
48
|
"""
|
|
49
|
-
|
|
49
|
+
Returns the new sensor reading values -- i.e. these values replace the
|
|
50
50
|
true sensor reading values.
|
|
51
51
|
|
|
52
52
|
Returns
|
|
@@ -64,7 +64,7 @@ class SensorOverrideAttack(SensorReadingAttack, JsonSerializable):
|
|
|
64
64
|
raise TypeError("Can not compare 'SensorOverrideAttack' instance " +
|
|
65
65
|
f"with '{type(other)}' instance")
|
|
66
66
|
|
|
67
|
-
return super().__eq__(other) and self.__new_sensor_values == other.new_sensor_values
|
|
67
|
+
return super().__eq__(other) and np.all(self.__new_sensor_values == other.new_sensor_values)
|
|
68
68
|
|
|
69
69
|
def __str__(self) -> str:
|
|
70
70
|
return f"{type(self).__name__} {super().__str__()} " +\
|
|
@@ -151,6 +151,19 @@ class SensorReplayAttack(SensorReadingAttack, JsonSerializable):
|
|
|
151
151
|
"""
|
|
152
152
|
return self.__sensor_data_time_window_end
|
|
153
153
|
|
|
154
|
+
@property
|
|
155
|
+
def new_sensor_values(self) -> np.ndarray:
|
|
156
|
+
"""
|
|
157
|
+
Returns the new sensor reading values -- i.e. these values replace the
|
|
158
|
+
true sensor reading values.
|
|
159
|
+
|
|
160
|
+
Returns
|
|
161
|
+
-------
|
|
162
|
+
`np.ndarray`
|
|
163
|
+
New sensor readings.
|
|
164
|
+
"""
|
|
165
|
+
return deepcopy(self.__new_sensor_values)
|
|
166
|
+
|
|
154
167
|
def get_attributes(self) -> dict:
|
|
155
168
|
my_attributes = {"new_sensor_values": self.__new_sensor_values,
|
|
156
169
|
"replay_data_time_window_start": self.__sensor_data_time_window_start,
|
|
@@ -163,7 +176,7 @@ class SensorReplayAttack(SensorReadingAttack, JsonSerializable):
|
|
|
163
176
|
raise TypeError("Can not compare 'SensorReplayAttack' instance " +
|
|
164
177
|
f"with '{type(other)}' instance")
|
|
165
178
|
|
|
166
|
-
return super().__eq__(other) and self.__new_sensor_values == other.new_sensor_values
|
|
179
|
+
return super().__eq__(other) and np.all(self.__new_sensor_values == other.new_sensor_values)
|
|
167
180
|
|
|
168
181
|
def __str__(self) -> str:
|
|
169
182
|
return f"{type(self).__name__} {super().__str__()} " +\
|
|
@@ -95,13 +95,28 @@ class SensorReadingEvent(Event):
|
|
|
95
95
|
if self.__sensor_id not in sensor_config.tank_volume_sensors:
|
|
96
96
|
__show_warning()
|
|
97
97
|
elif self.__sensor_type == SENSOR_TYPE_NODE_BULK_SPECIES:
|
|
98
|
-
|
|
98
|
+
sensor_present = False
|
|
99
|
+
for _, sensors_id in sensor_config.bulk_species_node_sensors.items():
|
|
100
|
+
if self.__sensor_id in sensors_id:
|
|
101
|
+
sensor_present = True
|
|
102
|
+
break
|
|
103
|
+
if sensor_present is False:
|
|
99
104
|
__show_warning()
|
|
100
105
|
elif self.__sensor_type == SENSOR_TYPE_LINK_BULK_SPECIES:
|
|
101
|
-
|
|
106
|
+
sensor_present = False
|
|
107
|
+
for _, sensors_id in sensor_config.bulk_species_link_sensors.items():
|
|
108
|
+
if self.__sensor_id in sensors_id:
|
|
109
|
+
sensor_present = True
|
|
110
|
+
break
|
|
111
|
+
if sensor_present is False:
|
|
102
112
|
__show_warning()
|
|
103
113
|
elif self.__sensor_type == SENSOR_TYPE_SURFACE_SPECIES:
|
|
104
|
-
|
|
114
|
+
sensor_present = False
|
|
115
|
+
for _, sensors_id in sensor_config.surface_species_sensors.items():
|
|
116
|
+
if self.__sensor_id in sensors_id:
|
|
117
|
+
sensor_present = True
|
|
118
|
+
break
|
|
119
|
+
if sensor_present is False:
|
|
105
120
|
__show_warning()
|
|
106
121
|
|
|
107
122
|
@property
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deprecated -- use epyt_flow.simulation.scada.custom_control instead
|
|
3
|
+
"""
|
|
4
|
+
import warnings
|
|
5
|
+
from abc import abstractmethod, ABC
|
|
6
|
+
import numpy as np
|
|
7
|
+
import epyt
|
|
8
|
+
|
|
9
|
+
from . import ScadaData
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
warnings.warn("'epyt_flow.simulation.scada.advanced_control' is deprecated and will be removed " +
|
|
13
|
+
"in future releases -- use 'epyt_flow.simulation.scada.custom_control' instead")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AdvancedControlModule(ABC):
|
|
17
|
+
"""
|
|
18
|
+
Base class for a control module.
|
|
19
|
+
|
|
20
|
+
Attributes
|
|
21
|
+
----------
|
|
22
|
+
epanet_api : `epyt.epanet <https://epanet-python-toolkit-epyt.readthedocs.io/en/latest/api.html#epyt.epanet.epanet>`_
|
|
23
|
+
API to EPANET and EPANET-MSX. Is set in :func:`init`.
|
|
24
|
+
"""
|
|
25
|
+
def __init__(self, **kwds):
|
|
26
|
+
self._epanet_api = None
|
|
27
|
+
|
|
28
|
+
super().__init__(**kwds)
|
|
29
|
+
|
|
30
|
+
def init(self, epanet_api: epyt.epanet) -> None:
|
|
31
|
+
"""
|
|
32
|
+
Initializes the control module.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
epanet_api : `epyt.epanet <https://epanet-python-toolkit-epyt.readthedocs.io/en/latest/api.html#epyt.epanet.epanet>`_
|
|
37
|
+
API to EPANET for implementing the control module.
|
|
38
|
+
"""
|
|
39
|
+
if not isinstance(epanet_api, epyt.epanet):
|
|
40
|
+
raise TypeError("'epanet_api' must be an instance of 'epyt.epanet' but not of " +
|
|
41
|
+
f"'{type(epanet_api)}'")
|
|
42
|
+
|
|
43
|
+
self._epanet_api = epanet_api
|
|
44
|
+
|
|
45
|
+
def set_pump_status(self, pump_id: str, status: int) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Sets the status of a pump.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
pump_id : `str`
|
|
52
|
+
ID of the pump for which the status is set.
|
|
53
|
+
status : `int`
|
|
54
|
+
New status of the pump -- either active (i.e. open) or inactive (i.e. closed).
|
|
55
|
+
|
|
56
|
+
Must be one of the following constants defined in
|
|
57
|
+
:class:`~epyt_flow.simulation.events.actuator_events.ActuatorConstants`:
|
|
58
|
+
|
|
59
|
+
- EN_CLOSED = 0
|
|
60
|
+
- EN_OPEN = 1
|
|
61
|
+
"""
|
|
62
|
+
pump_idx = self._epanet_api.getLinkPumpNameID().index(pump_id)
|
|
63
|
+
pump_link_idx = self._epanet_api.getLinkPumpIndex(pump_idx + 1)
|
|
64
|
+
self._epanet_api.setLinkStatus(pump_link_idx, status)
|
|
65
|
+
|
|
66
|
+
def set_pump_speed(self, pump_id: str, speed: float) -> None:
|
|
67
|
+
"""
|
|
68
|
+
Sets the speed of a pump.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
pump_id : `str`
|
|
73
|
+
ID of the pump for which the pump speed is set.
|
|
74
|
+
speed : `float`
|
|
75
|
+
New pump speed.
|
|
76
|
+
"""
|
|
77
|
+
pump_idx = self._epanet_api.getLinkPumpNameID().index(pump_id)
|
|
78
|
+
pattern_idx = self._epanet_api.getLinkPumpPatternIndex(pump_idx + 1)
|
|
79
|
+
|
|
80
|
+
if pattern_idx == 0:
|
|
81
|
+
warnings.warn(f"No pattern for pump '{pump_id}' found -- a new pattern is created")
|
|
82
|
+
pattern_idx = self._epanet_api.addPattern(f"pump_speed_{pump_id}")
|
|
83
|
+
self._epanet_api.setLinkPumpPatternIndex(pattern_idx)
|
|
84
|
+
|
|
85
|
+
self._epanet_api.setPattern(pattern_idx, np.array([speed]))
|
|
86
|
+
|
|
87
|
+
def set_valve_status(self, valve_id: str, status: int) -> None:
|
|
88
|
+
"""
|
|
89
|
+
Sets the status of a valve.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
valve_id : `str`
|
|
94
|
+
ID of the valve for which the status is set.
|
|
95
|
+
status : `int`
|
|
96
|
+
New status of the valve -- either open or closed.
|
|
97
|
+
|
|
98
|
+
Must be one of the following constants defined in
|
|
99
|
+
:class:`~epyt_flow.simulation.events.actuator_events.ActuatorConstants`:
|
|
100
|
+
|
|
101
|
+
- EN_CLOSED = 0
|
|
102
|
+
- EN_OPEN = 1
|
|
103
|
+
"""
|
|
104
|
+
valve_idx = self._epanet_api.getLinkValveNameID().index(valve_id)
|
|
105
|
+
valve_link_idx = self._epanet_api.getLinkValveIndex()[valve_idx]
|
|
106
|
+
self._epanet_api.setLinkStatus(valve_link_idx, status)
|
|
107
|
+
|
|
108
|
+
def set_node_quality_source_value(self, node_id: str, pattern_id: str,
|
|
109
|
+
qual_value: float) -> None:
|
|
110
|
+
"""
|
|
111
|
+
Sets the quality source at a particular node to a specific value -- e.g.
|
|
112
|
+
setting the chlorine concentration injection to a specified value.
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
node_id : `str`
|
|
117
|
+
ID of the node.
|
|
118
|
+
pattern_id : `str`
|
|
119
|
+
ID of the quality pattern at the specific node.
|
|
120
|
+
qual_value : `float`
|
|
121
|
+
New quality source value.
|
|
122
|
+
"""
|
|
123
|
+
node_idx = self._epanet_api.getNodeIndex(node_id)
|
|
124
|
+
pattern_idx = self._epanet_api.getPatternIndex(pattern_id)
|
|
125
|
+
self._epanet_api.setNodeSourceQuality(node_idx, 1)
|
|
126
|
+
self._epanet_api.setPattern(pattern_idx, np.array([qual_value]))
|
|
127
|
+
|
|
128
|
+
@abstractmethod
|
|
129
|
+
def step(self, scada_data: ScadaData) -> None:
|
|
130
|
+
"""
|
|
131
|
+
Implements the control algorithm -- i.e. mapping of sensor reading to actions.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
scada_data : :class:`~epyt_flow.simulation.scada.scada_data.ScadaData`
|
|
136
|
+
Sensor readings.
|
|
137
|
+
"""
|
|
138
|
+
raise NotImplementedError()
|