epyt-flow 0.7.0__py3-none-any.whl → 0.7.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- epyt_flow/VERSION +1 -1
- epyt_flow/data/benchmarks/leakdb.py +1 -0
- epyt_flow/simulation/scada/scada_data.py +714 -15
- epyt_flow/simulation/scada/scada_data_export.py +5 -1
- epyt_flow/simulation/scenario_simulator.py +212 -92
- epyt_flow/simulation/sensor_config.py +48 -1
- epyt_flow/uncertainty/model_uncertainty.py +11 -5
- {epyt_flow-0.7.0.dist-info → epyt_flow-0.7.1.dist-info}/METADATA +2 -2
- {epyt_flow-0.7.0.dist-info → epyt_flow-0.7.1.dist-info}/RECORD +12 -12
- {epyt_flow-0.7.0.dist-info → epyt_flow-0.7.1.dist-info}/LICENSE +0 -0
- {epyt_flow-0.7.0.dist-info → epyt_flow-0.7.1.dist-info}/WHEEL +0 -0
- {epyt_flow-0.7.0.dist-info → epyt_flow-0.7.1.dist-info}/top_level.txt +0 -0
|
@@ -142,7 +142,11 @@ class ScadaDataExport():
|
|
|
142
142
|
unit_desc = massunit_to_str(sensor_config.
|
|
143
143
|
bulk_species_mass_unit[surface_species_idx])
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
if sensor_type not in ["bulk_species_node", "bulk_species_link", "surface_species"]:
|
|
146
|
+
col_desc[col_id] = [sensor_type, item_id, unit_desc]
|
|
147
|
+
else:
|
|
148
|
+
for location_id, c_id in col_id.items():
|
|
149
|
+
col_desc[c_id] = [sensor_type, f"{item_id} @ {location_id}", unit_desc]
|
|
146
150
|
|
|
147
151
|
return np.array(col_desc, dtype=object)
|
|
148
152
|
|
|
@@ -1644,64 +1644,73 @@ class ScenarioSimulator():
|
|
|
1644
1644
|
|
|
1645
1645
|
if reporting_time_start == 0:
|
|
1646
1646
|
if return_as_dict is True:
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1647
|
+
data = {"bulk_species_node_concentration_raw": bulk_species_node_concentrations,
|
|
1648
|
+
"bulk_species_link_concentration_raw": bulk_species_link_concentrations,
|
|
1649
|
+
"surface_species_concentration_raw": surface_species_concentrations,
|
|
1650
|
+
"sensor_readings_time": np.array([0])}
|
|
1651
1651
|
else:
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1652
|
+
data = ScadaData(sensor_config=self.__sensor_config,
|
|
1653
|
+
bulk_species_node_concentration_raw=bulk_species_node_concentrations,
|
|
1654
|
+
bulk_species_link_concentration_raw=bulk_species_link_concentrations,
|
|
1655
|
+
surface_species_concentration_raw=surface_species_concentrations,
|
|
1656
|
+
sensor_readings_time=np.array([0]),
|
|
1657
|
+
sensor_reading_events=self.__sensor_reading_events,
|
|
1658
|
+
sensor_noise=self.__sensor_noise,
|
|
1659
|
+
frozen_sensor_config=frozen_sensor_config)
|
|
1660
|
+
|
|
1661
|
+
if support_abort is True: # Can the simulation be aborted? If so, handle it.
|
|
1662
|
+
abort = yield
|
|
1663
|
+
if abort is True:
|
|
1664
|
+
return None
|
|
1665
|
+
|
|
1666
|
+
yield data
|
|
1660
1667
|
|
|
1661
1668
|
# Run step-by-step simulation
|
|
1662
1669
|
tleft = 1
|
|
1663
1670
|
total_time = 0
|
|
1664
1671
|
while tleft > 0:
|
|
1665
|
-
if support_abort is True: # Can the simulation be aborted? If so, handle it.
|
|
1666
|
-
abort = yield
|
|
1667
|
-
if abort is not False:
|
|
1668
|
-
break
|
|
1669
|
-
|
|
1670
1672
|
# Compute current time step
|
|
1671
1673
|
total_time, tleft = self.epanet_api.stepMSXQualityAnalysisTimeLeft()
|
|
1672
1674
|
|
|
1673
|
-
if verbose is True:
|
|
1674
|
-
try:
|
|
1675
|
-
next(progress_bar)
|
|
1676
|
-
except StopIteration:
|
|
1677
|
-
pass
|
|
1678
|
-
|
|
1679
1675
|
# Fetch data at regular time intervals
|
|
1680
1676
|
if total_time % hyd_time_step == 0:
|
|
1677
|
+
if verbose is True:
|
|
1678
|
+
try:
|
|
1679
|
+
next(progress_bar)
|
|
1680
|
+
except StopIteration:
|
|
1681
|
+
pass
|
|
1682
|
+
|
|
1681
1683
|
bulk_species_node_concentrations, bulk_species_link_concentrations, \
|
|
1682
1684
|
surface_species_concentrations = __get_concentrations()
|
|
1683
1685
|
|
|
1684
1686
|
# Report results in a regular time interval only!
|
|
1685
1687
|
if total_time % reporting_time_step == 0 and total_time >= reporting_time_start:
|
|
1686
1688
|
if return_as_dict is True:
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1689
|
+
data = {"bulk_species_node_concentration_raw":
|
|
1690
|
+
bulk_species_node_concentrations,
|
|
1691
|
+
"bulk_species_link_concentration_raw":
|
|
1692
|
+
bulk_species_link_concentrations,
|
|
1693
|
+
"surface_species_concentration_raw": surface_species_concentrations,
|
|
1694
|
+
"sensor_readings_time": np.array([total_time])}
|
|
1693
1695
|
else:
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1696
|
+
data = ScadaData(sensor_config=self.__sensor_config,
|
|
1697
|
+
bulk_species_node_concentration_raw=
|
|
1698
|
+
bulk_species_node_concentrations,
|
|
1699
|
+
bulk_species_link_concentration_raw=
|
|
1700
|
+
bulk_species_link_concentrations,
|
|
1701
|
+
surface_species_concentration_raw=
|
|
1702
|
+
surface_species_concentrations,
|
|
1703
|
+
sensor_readings_time=np.array([total_time]),
|
|
1704
|
+
sensor_reading_events=self.__sensor_reading_events,
|
|
1705
|
+
sensor_noise=self.__sensor_noise,
|
|
1706
|
+
frozen_sensor_config=frozen_sensor_config)
|
|
1707
|
+
|
|
1708
|
+
if support_abort is True: # Can the simulation be aborted? If so, handle it.
|
|
1709
|
+
abort = yield
|
|
1710
|
+
if abort is not False:
|
|
1711
|
+
break
|
|
1712
|
+
|
|
1713
|
+
yield data
|
|
1705
1714
|
|
|
1706
1715
|
self.__running_simulation = False
|
|
1707
1716
|
|
|
@@ -1816,11 +1825,6 @@ class ScenarioSimulator():
|
|
|
1816
1825
|
tstep = 1
|
|
1817
1826
|
first_itr = True
|
|
1818
1827
|
while tstep > 0:
|
|
1819
|
-
if support_abort is True: # Can the simulation be aborted? If so, handle it.
|
|
1820
|
-
abort = yield
|
|
1821
|
-
if abort is not False:
|
|
1822
|
-
break
|
|
1823
|
-
|
|
1824
1828
|
if first_itr is True: # Fix current time in the first iteration
|
|
1825
1829
|
tstep = 0
|
|
1826
1830
|
first_itr = False
|
|
@@ -1843,27 +1847,36 @@ class ScenarioSimulator():
|
|
|
1843
1847
|
# Yield results in a regular time interval only!
|
|
1844
1848
|
if total_time % reporting_time_step == 0 and total_time >= reporting_time_start:
|
|
1845
1849
|
if return_as_dict is True:
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1850
|
+
data = {"node_quality_data_raw": quality_node_data,
|
|
1851
|
+
"link_quality_data_raw": quality_link_data,
|
|
1852
|
+
"sensor_readings_time": np.array([total_time])}
|
|
1849
1853
|
else:
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1854
|
+
data = ScadaData(sensor_config=self.__sensor_config,
|
|
1855
|
+
node_quality_data_raw=quality_node_data,
|
|
1856
|
+
link_quality_data_raw=quality_link_data,
|
|
1857
|
+
sensor_readings_time=np.array([total_time]),
|
|
1858
|
+
sensor_reading_events=self.__sensor_reading_events,
|
|
1859
|
+
sensor_noise=self.__sensor_noise,
|
|
1860
|
+
frozen_sensor_config=frozen_sensor_config)
|
|
1861
|
+
|
|
1862
|
+
if support_abort is True: # Can the simulation be aborted? If so, handle it.
|
|
1863
|
+
abort = yield
|
|
1864
|
+
if abort is True:
|
|
1865
|
+
break
|
|
1866
|
+
|
|
1867
|
+
yield data
|
|
1857
1868
|
|
|
1858
1869
|
# Next
|
|
1859
1870
|
tstep = self.epanet_api.nextQualityAnalysisStep()
|
|
1860
1871
|
|
|
1861
1872
|
self.epanet_api.closeHydraulicAnalysis()
|
|
1862
1873
|
|
|
1863
|
-
def
|
|
1864
|
-
|
|
1874
|
+
def run_hydraulic_simulation(self, hyd_export: str = None, verbose: bool = False,
|
|
1875
|
+
frozen_sensor_config: bool = False) -> ScadaData:
|
|
1865
1876
|
"""
|
|
1866
|
-
Runs the simulation of this scenario.
|
|
1877
|
+
Runs the hydraulic simulation of this scenario (incl. basic quality if set).
|
|
1878
|
+
|
|
1879
|
+
Note that this function does not call EPANET-MSX even if an .msx file was provided.
|
|
1867
1880
|
|
|
1868
1881
|
Parameters
|
|
1869
1882
|
----------
|
|
@@ -1896,12 +1909,8 @@ class ScenarioSimulator():
|
|
|
1896
1909
|
|
|
1897
1910
|
result = None
|
|
1898
1911
|
|
|
1899
|
-
hyd_export_old = hyd_export
|
|
1900
|
-
if self.__f_msx_in is not None:
|
|
1901
|
-
hyd_export = os.path.join(get_temp_folder(), f"epytflow_MSX_{uuid.uuid4()}.hyd")
|
|
1902
|
-
|
|
1903
1912
|
# Run hydraulic simulation step-by-step
|
|
1904
|
-
gen = self.
|
|
1913
|
+
gen = self.run_hydraulic_simulation_as_generator
|
|
1905
1914
|
for scada_data in gen(hyd_export=hyd_export,
|
|
1906
1915
|
verbose=verbose,
|
|
1907
1916
|
return_as_dict=True,
|
|
@@ -1923,32 +1932,18 @@ class ScenarioSimulator():
|
|
|
1923
1932
|
sensor_noise=self.__sensor_noise,
|
|
1924
1933
|
frozen_sensor_config=frozen_sensor_config)
|
|
1925
1934
|
|
|
1926
|
-
# If necessary, run advanced quality simulation utilizing the computed hydraulics
|
|
1927
|
-
if self.f_msx_in is not None:
|
|
1928
|
-
gen = self.run_advanced_quality_simulation
|
|
1929
|
-
result_msx = gen(hyd_file_in=hyd_export,
|
|
1930
|
-
verbose=verbose,
|
|
1931
|
-
frozen_sensor_config=frozen_sensor_config)
|
|
1932
|
-
result.join(result_msx)
|
|
1933
|
-
|
|
1934
|
-
if hyd_export_old is not None:
|
|
1935
|
-
shutil.copyfile(hyd_export, hyd_export_old)
|
|
1936
|
-
|
|
1937
|
-
try:
|
|
1938
|
-
# temp solution
|
|
1939
|
-
os.remove(hyd_export)
|
|
1940
|
-
except:
|
|
1941
|
-
warnings.warn(f"Failed to remove temporary file '{hyd_export}'")
|
|
1942
|
-
|
|
1943
1935
|
return result
|
|
1944
1936
|
|
|
1945
|
-
def
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1937
|
+
def run_hydraulic_simulation_as_generator(self, hyd_export: str = None, verbose: bool = False,
|
|
1938
|
+
support_abort: bool = False,
|
|
1939
|
+
return_as_dict: bool = False,
|
|
1940
|
+
frozen_sensor_config: bool = False,
|
|
1941
|
+
) -> Generator[Union[ScadaData, dict], bool, None]:
|
|
1950
1942
|
"""
|
|
1951
|
-
Runs the simulation of this scenario
|
|
1943
|
+
Runs the hydraulic simulation of this scenario (incl. basic quality if set) and
|
|
1944
|
+
provides the results as a generator.
|
|
1945
|
+
|
|
1946
|
+
Note that this function does not run EPANET-MSX, even if an .msx file was provided.
|
|
1952
1947
|
|
|
1953
1948
|
Parameters
|
|
1954
1949
|
----------
|
|
@@ -2021,11 +2016,11 @@ class ScenarioSimulator():
|
|
|
2021
2016
|
first_itr = False
|
|
2022
2017
|
|
|
2023
2018
|
if verbose is True:
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2019
|
+
if (total_time + tstep) % requested_time_step == 0:
|
|
2020
|
+
try:
|
|
2021
|
+
next(progress_bar)
|
|
2022
|
+
except StopIteration:
|
|
2023
|
+
pass
|
|
2029
2024
|
|
|
2030
2025
|
# Apply system events in a regular time interval only!
|
|
2031
2026
|
if (total_time + tstep) % requested_time_step == 0:
|
|
@@ -2088,7 +2083,7 @@ class ScenarioSimulator():
|
|
|
2088
2083
|
|
|
2089
2084
|
if support_abort is True: # Can the simulation be aborted? If so, handle it.
|
|
2090
2085
|
abort = yield
|
|
2091
|
-
if abort is
|
|
2086
|
+
if abort is True:
|
|
2092
2087
|
break
|
|
2093
2088
|
|
|
2094
2089
|
yield data
|
|
@@ -2112,6 +2107,69 @@ class ScenarioSimulator():
|
|
|
2112
2107
|
self.__running_simulation = False
|
|
2113
2108
|
raise ex
|
|
2114
2109
|
|
|
2110
|
+
def run_simulation(self, hyd_export: str = None, verbose: bool = False,
|
|
2111
|
+
frozen_sensor_config: bool = False) -> ScadaData:
|
|
2112
|
+
"""
|
|
2113
|
+
Runs the simulation of this scenario.
|
|
2114
|
+
|
|
2115
|
+
Parameters
|
|
2116
|
+
----------
|
|
2117
|
+
hyd_export : `str`, optional
|
|
2118
|
+
Path to an EPANET .hyd file for storing the simulated hydraulics -- these hydraulics
|
|
2119
|
+
can be used later for an advanced quality analysis using EPANET-MSX.
|
|
2120
|
+
|
|
2121
|
+
If None, the simulated hydraulics will NOT be exported to an EPANET .hyd file.
|
|
2122
|
+
|
|
2123
|
+
The default is None.
|
|
2124
|
+
verbose : `bool`, optional
|
|
2125
|
+
If True, method will be verbose (e.g. showing a progress bar).
|
|
2126
|
+
|
|
2127
|
+
The default is False.
|
|
2128
|
+
frozen_sensor_config : `bool`, optional
|
|
2129
|
+
If True, the sensor config can not be changed and only the required sensor nodes/links
|
|
2130
|
+
will be stored -- this usually leads to a significant reduction in memory consumption.
|
|
2131
|
+
|
|
2132
|
+
The default is False.
|
|
2133
|
+
|
|
2134
|
+
Returns
|
|
2135
|
+
-------
|
|
2136
|
+
:class:`~epyt_flow.simulation.scada.scada_data.ScadaData`
|
|
2137
|
+
Simulation results as SCADA data (i.e. sensor readings).
|
|
2138
|
+
"""
|
|
2139
|
+
if self.__running_simulation is True:
|
|
2140
|
+
raise RuntimeError("A simulation is already running.")
|
|
2141
|
+
|
|
2142
|
+
self.__adapt_to_network_changes()
|
|
2143
|
+
|
|
2144
|
+
result = None
|
|
2145
|
+
|
|
2146
|
+
hyd_export_old = hyd_export
|
|
2147
|
+
if self.__f_msx_in is not None:
|
|
2148
|
+
hyd_export = os.path.join(get_temp_folder(), f"epytflow_MSX_{uuid.uuid4()}.hyd")
|
|
2149
|
+
|
|
2150
|
+
# Run hydraulic simulation step-by-step
|
|
2151
|
+
result = self.run_hydraulic_simulation(hyd_export=hyd_export, verbose=verbose,
|
|
2152
|
+
frozen_sensor_config=frozen_sensor_config)
|
|
2153
|
+
|
|
2154
|
+
# If necessary, run advanced quality simulation utilizing the computed hydraulics
|
|
2155
|
+
if self.f_msx_in is not None:
|
|
2156
|
+
gen = self.run_advanced_quality_simulation
|
|
2157
|
+
result_msx = gen(hyd_file_in=hyd_export,
|
|
2158
|
+
verbose=verbose,
|
|
2159
|
+
frozen_sensor_config=frozen_sensor_config)
|
|
2160
|
+
result.join(result_msx)
|
|
2161
|
+
|
|
2162
|
+
if hyd_export_old is not None:
|
|
2163
|
+
shutil.copyfile(hyd_export, hyd_export_old)
|
|
2164
|
+
|
|
2165
|
+
try:
|
|
2166
|
+
# temp solution
|
|
2167
|
+
os.remove(hyd_export)
|
|
2168
|
+
except:
|
|
2169
|
+
warnings.warn(f"Failed to remove temporary file '{hyd_export}'")
|
|
2170
|
+
|
|
2171
|
+
return result
|
|
2172
|
+
|
|
2115
2173
|
def set_model_uncertainty(self, model_uncertainty: ModelUncertainty) -> None:
|
|
2116
2174
|
"""
|
|
2117
2175
|
Specifies the model uncertainties.
|
|
@@ -2480,3 +2538,65 @@ class ScenarioSimulator():
|
|
|
2480
2538
|
self.__warn_if_quality_set()
|
|
2481
2539
|
self.set_general_parameters(quality_model={"type": "TRACE",
|
|
2482
2540
|
"trace_node_id": trace_node_id})
|
|
2541
|
+
|
|
2542
|
+
def add_species_injection_source(self, species_id: str, node_id: str, pattern: np.ndarray,
|
|
2543
|
+
source_type: int, pattern_id: str = None,
|
|
2544
|
+
source_strength: int = 1.) -> None:
|
|
2545
|
+
"""
|
|
2546
|
+
Adds a new external (bulk or surface) species injection source at a particular node.
|
|
2547
|
+
|
|
2548
|
+
Parameters
|
|
2549
|
+
----------
|
|
2550
|
+
species_id : `str`
|
|
2551
|
+
ID of the (bulk or surface) species.
|
|
2552
|
+
node_id : `str`
|
|
2553
|
+
ID of the node at which this external (bulk or surface) species injection source
|
|
2554
|
+
is placed.
|
|
2555
|
+
pattern : `numpy.ndarray`
|
|
2556
|
+
1d source pattern.
|
|
2557
|
+
source_type : `int`,
|
|
2558
|
+
Type of the external (bulk or surface) species injection source -- must be one of
|
|
2559
|
+
the following EPANET toolkit constants:
|
|
2560
|
+
|
|
2561
|
+
- EN_CONCEN = 0
|
|
2562
|
+
- EN_MASS = 1
|
|
2563
|
+
- EN_SETPOINT = 2
|
|
2564
|
+
- EN_FLOWPACED = 3
|
|
2565
|
+
|
|
2566
|
+
Description:
|
|
2567
|
+
|
|
2568
|
+
- E_CONCEN Sets the concentration of external inflow entering a node
|
|
2569
|
+
- EN_MASS Injects a given mass/minute into a node
|
|
2570
|
+
- EN_SETPOINT Sets the concentration leaving a node to a given value
|
|
2571
|
+
- EN_FLOWPACED Adds a given value to the concentration leaving a node
|
|
2572
|
+
pattern_id : `str`, optional
|
|
2573
|
+
ID of the source pattern.
|
|
2574
|
+
|
|
2575
|
+
If None, a pattern_id will be generated automatically -- be aware that this
|
|
2576
|
+
could conflict with existing pattern IDs (in this case, an exception is raised).
|
|
2577
|
+
|
|
2578
|
+
The default is None.
|
|
2579
|
+
source_strength : `int`, optional
|
|
2580
|
+
Injection source strength -- i.e. injection = source_strength * pattern.
|
|
2581
|
+
|
|
2582
|
+
The default is 1.
|
|
2583
|
+
"""
|
|
2584
|
+
source_type_ = "None"
|
|
2585
|
+
if source_type == ToolkitConstants.EN_CONCEN:
|
|
2586
|
+
source_type_ = "CONCEN"
|
|
2587
|
+
elif source_type == ToolkitConstants.EN_MASS:
|
|
2588
|
+
source_type_ = "MASS"
|
|
2589
|
+
elif source_type == ToolkitConstants.EN_SETPOINT:
|
|
2590
|
+
source_type_ = "SETPOINT"
|
|
2591
|
+
elif source_type == ToolkitConstants.EN_FLOWPACED:
|
|
2592
|
+
source_type_ = "FLOWPACED"
|
|
2593
|
+
|
|
2594
|
+
if pattern_id is None:
|
|
2595
|
+
pattern_id = f"{species_id}_{node_id}"
|
|
2596
|
+
if pattern_id in self.epanet_api.getMSXPatternsNameID():
|
|
2597
|
+
raise ValueError("Invalid 'pattern_id' -- " +
|
|
2598
|
+
f"there already exists a pattern with ID '{pattern_id}'")
|
|
2599
|
+
|
|
2600
|
+
self.epanet_api.addMSXPattern(pattern_id, pattern)
|
|
2601
|
+
self.epanet_api.setMSXSources(node_id, species_id, source_type_, source_strength,
|
|
2602
|
+
pattern_id)
|
|
@@ -112,7 +112,7 @@ def massunit_to_str(unit_id: int) -> str:
|
|
|
112
112
|
Parameters
|
|
113
113
|
----------
|
|
114
114
|
unit_id : `int`
|
|
115
|
-
ID of the
|
|
115
|
+
ID of the mass unit.
|
|
116
116
|
|
|
117
117
|
Must be one of the following constant:
|
|
118
118
|
|
|
@@ -1916,6 +1916,53 @@ class SensorConfig(JsonSerializable):
|
|
|
1916
1916
|
f"{list(map(massunit_to_str, self.__surface_species_mass_unit))} " +\
|
|
1917
1917
|
f"surface_species_area_unit: {areaunit_to_str(self.__surface_species_area_unit)}"
|
|
1918
1918
|
|
|
1919
|
+
def get_bulk_species_mass_unit_id(self, bulk_species_id: str) -> int:
|
|
1920
|
+
"""
|
|
1921
|
+
Returns the mass unit of a given bulk species.
|
|
1922
|
+
|
|
1923
|
+
Parameters
|
|
1924
|
+
----------
|
|
1925
|
+
bulk_species_id : `str`
|
|
1926
|
+
ID of the bulk species.
|
|
1927
|
+
|
|
1928
|
+
Returns
|
|
1929
|
+
-------
|
|
1930
|
+
`int`
|
|
1931
|
+
ID of the mass unit.
|
|
1932
|
+
|
|
1933
|
+
Will be one of the following constant:
|
|
1934
|
+
|
|
1935
|
+
- MASS_UNIT_MG = 4
|
|
1936
|
+
- MASS_UNIT_UG = 5
|
|
1937
|
+
- MASS_UNIT_MOL = 6
|
|
1938
|
+
- MASS_UNIT_MMOL = 7
|
|
1939
|
+
"""
|
|
1940
|
+
return self.__bulk_species_mass_unit[self.map_bulkspecies_id_to_idx(bulk_species_id)]
|
|
1941
|
+
|
|
1942
|
+
def get_surface_species_mass_unit_id(self, surface_species_id: str) -> int:
|
|
1943
|
+
"""
|
|
1944
|
+
Returns the mass unit of a given surface species.
|
|
1945
|
+
|
|
1946
|
+
Parameters
|
|
1947
|
+
----------
|
|
1948
|
+
surface_species_id : `str`
|
|
1949
|
+
ID of the surface species.
|
|
1950
|
+
|
|
1951
|
+
Returns
|
|
1952
|
+
-------
|
|
1953
|
+
`int`
|
|
1954
|
+
ID of the mass unit.
|
|
1955
|
+
|
|
1956
|
+
Will be one of the following constant:
|
|
1957
|
+
|
|
1958
|
+
- MASS_UNIT_MG = 4
|
|
1959
|
+
- MASS_UNIT_UG = 5
|
|
1960
|
+
- MASS_UNIT_MOL = 6
|
|
1961
|
+
- MASS_UNIT_MMOL = 7
|
|
1962
|
+
"""
|
|
1963
|
+
return self.__surface_species_mass_unit[self.map_surfacespecies_id_to_idx(
|
|
1964
|
+
surface_species_id)]
|
|
1965
|
+
|
|
1919
1966
|
def compute_readings(self, pressures: np.ndarray, flows: np.ndarray, demands: np.ndarray,
|
|
1920
1967
|
nodes_quality: np.ndarray, links_quality: np.ndarray,
|
|
1921
1968
|
pumps_state: np.ndarray, pumps_efficiency: np.ndarray,
|
|
@@ -293,17 +293,23 @@ class ModelUncertainty(JsonSerializable):
|
|
|
293
293
|
epanet_api.setNodeElevations(elevations)
|
|
294
294
|
|
|
295
295
|
if self.__constants is not None:
|
|
296
|
-
constants = epanet_api.getMSXConstantsValue()
|
|
296
|
+
constants = np.array(epanet_api.getMSXConstantsValue())
|
|
297
297
|
constants = self.__constants.apply_batch(constants)
|
|
298
298
|
epanet_api.setMSXConstantsValue(constants)
|
|
299
299
|
|
|
300
300
|
if self.__parameters is not None:
|
|
301
301
|
parameters_pipes = epanet_api.getMSXParametersPipesValue()
|
|
302
302
|
for i, pipe_idx in enumerate(epanet_api.getLinkPipeIndex()):
|
|
303
|
-
|
|
304
|
-
|
|
303
|
+
if len(parameters_pipes[i]) == 0:
|
|
304
|
+
continue
|
|
305
|
+
|
|
306
|
+
parameters_pipes_val = self.__parameters.apply_batch(np.array(parameters_pipes[i]))
|
|
307
|
+
epanet_api.setMSXParametersPipesValue(pipe_idx, parameters_pipes_val)
|
|
305
308
|
|
|
306
309
|
parameters_tanks = epanet_api.getMSXParametersTanksValue()
|
|
307
310
|
for i, tank_idx in enumerate(epanet_api.getNodeTankIndex()):
|
|
308
|
-
parameters_tanks[i]
|
|
309
|
-
|
|
311
|
+
if parameters_tanks[i] is None or len(parameters_tanks[i]) == 0:
|
|
312
|
+
continue
|
|
313
|
+
|
|
314
|
+
parameters_tanks_val = self.__parameters.apply_batch(np.array(parameters_tanks[i]))
|
|
315
|
+
epanet_api.setMSXParametersTanksValue(tank_idx, parameters_tanks_val)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: epyt-flow
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.1
|
|
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
|
|
7
7
|
Project-URL: Homepage, https://github.com/WaterFutures/EPyT-Flow
|
|
8
|
-
Project-URL: Documentation, https://epyt-flow.readthedocs.io/en/
|
|
8
|
+
Project-URL: Documentation, https://epyt-flow.readthedocs.io/en/stable/
|
|
9
9
|
Project-URL: Repository, https://github.com/WaterFutures/EPyT-Flow.git
|
|
10
10
|
Project-URL: Issues, https://github.com/WaterFutures/EPyT-Flow/issues
|
|
11
11
|
Keywords: epanet,water,networks,hydraulics,quality,simulations
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
epyt_flow/VERSION,sha256=
|
|
1
|
+
epyt_flow/VERSION,sha256=kCMRx7s4-hZY_0A972FY7nN4_p1uLihPocOHNcMb0ws,6
|
|
2
2
|
epyt_flow/__init__.py,sha256=KNDiPWiHdB9a5ZF1ipjA1uoq61TwU2ThjaStpvSLBtY,1742
|
|
3
3
|
epyt_flow/metrics.py,sha256=W-dolnrmWfoanyvg-knoe2QMUtFwV1xODp4D4EwsQ00,14261
|
|
4
4
|
epyt_flow/serialization.py,sha256=ltWcLiTw62s0KG2DSgkQBkn6CCkxy9soDGq_ENohkrI,13998
|
|
@@ -87,7 +87,7 @@ epyt_flow/data/benchmarks/batadal_data.py,sha256=oIzcysGivMPAgrfzrk5l8i-j6Ii96DP
|
|
|
87
87
|
epyt_flow/data/benchmarks/battledim.py,sha256=yLwiQB0x7yq197XSM77tjHm7E7ucTbrybFaNxZx2TtM,20448
|
|
88
88
|
epyt_flow/data/benchmarks/battledim_data.py,sha256=0vHm-2eAiLv6U-n5dqUUWS1o_szFRy9mVJ3eqDRp4PE,3373
|
|
89
89
|
epyt_flow/data/benchmarks/gecco_water_quality.py,sha256=1buZRJiNf4jsqWYg4Ud90GhqaiLVo4yij3RAZJkzsqE,10985
|
|
90
|
-
epyt_flow/data/benchmarks/leakdb.py,sha256=
|
|
90
|
+
epyt_flow/data/benchmarks/leakdb.py,sha256=bhqdJkFMBNdgvQyYWYIpFHFA5ly9Tt51z6nGkyo56-g,25117
|
|
91
91
|
epyt_flow/data/benchmarks/leakdb_data.py,sha256=FNssgMkC1wqWVlaOrrihr4Od9trEZY7KeK5KuBeRMvM,507058
|
|
92
92
|
epyt_flow/data/benchmarks/water_usage.py,sha256=FLqjff3pha33oEU9ZM3UGPXn9eJJumsJH8Gdj7YFX3A,4778
|
|
93
93
|
epyt_flow/gym/__init__.py,sha256=KNTDtPTEtHwZ4ehHfj9qGw81Z9acFqPIgMzYUzH5_uM,115
|
|
@@ -112,9 +112,9 @@ epyt_flow/rest_api/scenario/uncertainty_handlers.py,sha256=uuu6AP11ZZUp2P3Dnukjg
|
|
|
112
112
|
epyt_flow/simulation/__init__.py,sha256=VGGJqJRUoXZjKJ0-m6KPp3JQqD_1TFW0pofLgkwZJ8M,164
|
|
113
113
|
epyt_flow/simulation/parallel_simulation.py,sha256=VmC7xemjxRB_N0fx1AAQ7ux82tnyTi7jk7jfFpeg7gM,6523
|
|
114
114
|
epyt_flow/simulation/scenario_config.py,sha256=NyadeCihpR4bpsWVPj7J-1DU2w1CEN0pAo2yh0t8Xkg,26751
|
|
115
|
-
epyt_flow/simulation/scenario_simulator.py,sha256=
|
|
115
|
+
epyt_flow/simulation/scenario_simulator.py,sha256=RnPvgEvEZO2rxXPu3jpBGTCjl7LQ6pnSjjPrRhvsMgY,110315
|
|
116
116
|
epyt_flow/simulation/scenario_visualizer.py,sha256=fpj67zl69q-byg7Oxocqhmu1S3P7B3ROCkSYzWyM--0,2187
|
|
117
|
-
epyt_flow/simulation/sensor_config.py,sha256=
|
|
117
|
+
epyt_flow/simulation/sensor_config.py,sha256=1YduJTNpEhbndIxRXGGx9_nNxH45RIA9bSNJQFXRatA,92255
|
|
118
118
|
epyt_flow/simulation/events/__init__.py,sha256=tIdqzs7_Cus4X2kbZG4Jl2zs-zsk_4rnajFOCvL0zlI,185
|
|
119
119
|
epyt_flow/simulation/events/actuator_events.py,sha256=2_MPYbYO9As6fMkm5Oy9pjSB9kCvFuKpGu8ykYDAydg,7903
|
|
120
120
|
epyt_flow/simulation/events/event.py,sha256=kARPV20XCAl6zxnJwI9U7ICtZUPACO_rgAmtHm1mGCs,2603
|
|
@@ -125,15 +125,15 @@ epyt_flow/simulation/events/sensor_reading_event.py,sha256=rQ-CmdpSUyZzDFYwNUGH2
|
|
|
125
125
|
epyt_flow/simulation/events/system_event.py,sha256=0KI2iaAaOyC9Y-FIfFVazeKT_4ORQRp26gWyMBUu_3c,2396
|
|
126
126
|
epyt_flow/simulation/scada/__init__.py,sha256=ZFAxJVqwEVsgiyFilFetnb13gPhZg1JEOPWYvKIJT4c,90
|
|
127
127
|
epyt_flow/simulation/scada/advanced_control.py,sha256=5h7dmSMcNlTE7TMZa8gQVnOCGMf7uZy60r9aOfKDxMc,4487
|
|
128
|
-
epyt_flow/simulation/scada/scada_data.py,sha256=
|
|
129
|
-
epyt_flow/simulation/scada/scada_data_export.py,sha256=
|
|
128
|
+
epyt_flow/simulation/scada/scada_data.py,sha256=hwXoZafhd8vrB3Rug_bldNmMfiAeZhGK-ZNKDrHhJxg,139708
|
|
129
|
+
epyt_flow/simulation/scada/scada_data_export.py,sha256=ohAn6vB9UEHesLBFg1lUZ6OgsYkJjYI4q3iTb-tL0fU,11501
|
|
130
130
|
epyt_flow/uncertainty/__init__.py,sha256=ZRjuJL9rDpWVSdPwObPxFpEmMTcgAl3VmPOsS6cIyGg,89
|
|
131
|
-
epyt_flow/uncertainty/model_uncertainty.py,sha256
|
|
131
|
+
epyt_flow/uncertainty/model_uncertainty.py,sha256=SD2sYGqj7K0Ys0Lvak4HsbP18A0SmwsK5Mnys_pZilg,14191
|
|
132
132
|
epyt_flow/uncertainty/sensor_noise.py,sha256=zJVULxnxVPSSqc6UW0iwZ9O-HGf9dn4CwScPqf4yCY0,2324
|
|
133
133
|
epyt_flow/uncertainty/uncertainties.py,sha256=jzaAwv5--HGc-H4-SwB0s-pAnzhhFuc06IXck7rC5l8,17902
|
|
134
134
|
epyt_flow/uncertainty/utils.py,sha256=gq66c9-QMOxOqI6wgWLyFxjVV0fbG0_8Yzd6mQjNYNo,5315
|
|
135
|
-
epyt_flow-0.7.
|
|
136
|
-
epyt_flow-0.7.
|
|
137
|
-
epyt_flow-0.7.
|
|
138
|
-
epyt_flow-0.7.
|
|
139
|
-
epyt_flow-0.7.
|
|
135
|
+
epyt_flow-0.7.1.dist-info/LICENSE,sha256=-4hYIY2BLmCkdOv2_PehEwlnMKTCes8_oyIUXjKtkug,1076
|
|
136
|
+
epyt_flow-0.7.1.dist-info/METADATA,sha256=t8szo6HkAXOXM1sWpoOUvx1zqkzZoWjm8dhgC_6CTms,9420
|
|
137
|
+
epyt_flow-0.7.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
138
|
+
epyt_flow-0.7.1.dist-info/top_level.txt,sha256=Wh_kd7TRL8ownCw3Y3dxx-9C0iTSk6wNauv_NX9JcrY,10
|
|
139
|
+
epyt_flow-0.7.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|