rtc-tools 2.7.0a1__py3-none-any.whl → 2.7.0a3__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.
Potentially problematic release.
This version of rtc-tools might be problematic. Click here for more details.
- {rtc_tools-2.7.0a1.dist-info → rtc_tools-2.7.0a3.dist-info}/METADATA +2 -2
- {rtc_tools-2.7.0a1.dist-info → rtc_tools-2.7.0a3.dist-info}/RECORD +9 -9
- rtctools/_version.py +3 -3
- rtctools/data/pi.py +44 -10
- rtctools/simulation/simulation_problem.py +25 -6
- {rtc_tools-2.7.0a1.dist-info → rtc_tools-2.7.0a3.dist-info}/COPYING.LESSER +0 -0
- {rtc_tools-2.7.0a1.dist-info → rtc_tools-2.7.0a3.dist-info}/WHEEL +0 -0
- {rtc_tools-2.7.0a1.dist-info → rtc_tools-2.7.0a3.dist-info}/entry_points.txt +0 -0
- {rtc_tools-2.7.0a1.dist-info → rtc_tools-2.7.0a3.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rtc-tools
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.0a3
|
|
4
4
|
Summary: Toolbox for control and optimization of water systems.
|
|
5
5
|
Home-page: https://oss.deltares.nl/web/rtc-tools/home
|
|
6
6
|
Author: Deltares
|
|
@@ -30,7 +30,7 @@ Requires-Dist: casadi ==3.6.*,>=3.6.3
|
|
|
30
30
|
Requires-Dist: numpy <1.26,>=1.16.0
|
|
31
31
|
Requires-Dist: scipy <1.11,>=1.0.0
|
|
32
32
|
Requires-Dist: pymoca ==0.9.*,>=0.9.1
|
|
33
|
-
Requires-Dist: rtc-tools-channel-flow >=1.
|
|
33
|
+
Requires-Dist: rtc-tools-channel-flow >=1.2.0
|
|
34
34
|
Requires-Dist: defusedxml >=0.7.0
|
|
35
35
|
Provides-Extra: all
|
|
36
36
|
Requires-Dist: netCDF4 ; extra == 'all'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
rtctools/__init__.py,sha256=91hvS2-ryd2Pvw0COpsUzTwJwSnTZ035REiej-1hNI4,107
|
|
2
|
-
rtctools/_version.py,sha256=
|
|
2
|
+
rtctools/_version.py,sha256=NDNDfYdfbfnXYIbOXMs5aKbrACG7Okc9i2sbnNx2dZU,499
|
|
3
3
|
rtctools/rtctoolsapp.py,sha256=UnkuiJhv0crEEVs8H6PYvMuc2y_q6V_xLuyKEgXj9GM,4200
|
|
4
4
|
rtctools/util.py,sha256=PaeKfDUA174ODZbY5fZjCTf-F-TdhW7yEuP189Ro190,9075
|
|
5
5
|
rtctools/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -10,7 +10,7 @@ rtctools/_internal/debug_check_helpers.py,sha256=UgQTEPw4PyR7MbYLewSSWQqTwQj7xr5
|
|
|
10
10
|
rtctools/data/__init__.py,sha256=EllgSmCdrlvQZSd1VilvjPaeYJGhY9ErPiQtedmuFoA,157
|
|
11
11
|
rtctools/data/csv.py,sha256=iYOEED3AaNxt4ews_aAkHfl9Tq9a-9vjxvYwjVR_lQE,5231
|
|
12
12
|
rtctools/data/netcdf.py,sha256=xpk4Ggl7gItNG6lO7p3OJPR-elK8_CiCtxUI7cX0gwk,19109
|
|
13
|
-
rtctools/data/pi.py,sha256=
|
|
13
|
+
rtctools/data/pi.py,sha256=VZNLtaYTdyXFVbM6rLM8BKMnyRs-H3NwKz955Mp-KTc,46988
|
|
14
14
|
rtctools/data/rtc.py,sha256=1yGJZGq2Z36MYLiLuZaHnxupL4mgw-Wuu54PAG05kcM,9077
|
|
15
15
|
rtctools/data/storage.py,sha256=67J4BRTl0AMEzlKNZ8Xdpy_4cGtwx8Lo_tL2n0G4S9w,13206
|
|
16
16
|
rtctools/data/interpolation/__init__.py,sha256=GBubCIT5mFoSTV-lOk7cpwvZekNMEe5bvqSQJ9HE34M,73
|
|
@@ -41,10 +41,10 @@ rtctools/simulation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
41
41
|
rtctools/simulation/csv_mixin.py,sha256=rGDUFPsqGHmF0_dWdXeWzWzMpkPmwCNweTBVrwSh31g,6704
|
|
42
42
|
rtctools/simulation/io_mixin.py,sha256=SJasNGI--OQ9Y-Z61oeeaGCxSrNddYz4AOVfJYbmf74,6209
|
|
43
43
|
rtctools/simulation/pi_mixin.py,sha256=vcizArZsOn7tGlSFCsUmkjmRFA1A1kMNqUllLlkVc9Y,9831
|
|
44
|
-
rtctools/simulation/simulation_problem.py,sha256=
|
|
45
|
-
rtc_tools-2.7.
|
|
46
|
-
rtc_tools-2.7.
|
|
47
|
-
rtc_tools-2.7.
|
|
48
|
-
rtc_tools-2.7.
|
|
49
|
-
rtc_tools-2.7.
|
|
50
|
-
rtc_tools-2.7.
|
|
44
|
+
rtctools/simulation/simulation_problem.py,sha256=8k3MjznzvFIut04NAiu7UAhfndAvNTkQFsO9vbmNd-0,49567
|
|
45
|
+
rtc_tools-2.7.0a3.dist-info/COPYING.LESSER,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
46
|
+
rtc_tools-2.7.0a3.dist-info/METADATA,sha256=o9lVOLg5xdv9pe2GRSjdPr0_6ubcI7SvqPc6jOU9gRc,1494
|
|
47
|
+
rtc_tools-2.7.0a3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
48
|
+
rtc_tools-2.7.0a3.dist-info/entry_points.txt,sha256=-x622IB_l1duw2M6t6syfQ4yzOiQTp0IZxKGcYRgWgk,151
|
|
49
|
+
rtc_tools-2.7.0a3.dist-info/top_level.txt,sha256=pnBrb58PFPd1kp1dqa-JHU7R55h3alDNJIJnF3Jf9Dw,9
|
|
50
|
+
rtc_tools-2.7.0a3.dist-info/RECORD,,
|
rtctools/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2024-
|
|
11
|
+
"date": "2024-07-23T15:26:53+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.7.
|
|
14
|
+
"full-revisionid": "4657ff3b5634df60af117b022fca4e968b88feb7",
|
|
15
|
+
"version": "2.7.0a3"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
rtctools/data/pi.py
CHANGED
|
@@ -369,8 +369,6 @@ class Timeseries:
|
|
|
369
369
|
self.__folder = folder
|
|
370
370
|
self.__basename = basename
|
|
371
371
|
|
|
372
|
-
self.__path_xml = os.path.join(self.__folder, basename + ".xml")
|
|
373
|
-
|
|
374
372
|
self.__internal_dtype = np.float64
|
|
375
373
|
self.__pi_dtype = np.float32
|
|
376
374
|
|
|
@@ -378,7 +376,7 @@ class Timeseries:
|
|
|
378
376
|
if self.make_new_file:
|
|
379
377
|
self.__reset_xml_tree()
|
|
380
378
|
else:
|
|
381
|
-
self.__tree = DefusedElementTree.parse(self.
|
|
379
|
+
self.__tree = DefusedElementTree.parse(self.path)
|
|
382
380
|
self.__xml_root = self.__tree.getroot()
|
|
383
381
|
|
|
384
382
|
self.__values = [{}]
|
|
@@ -801,13 +799,20 @@ class Timeseries:
|
|
|
801
799
|
# Add series to xml
|
|
802
800
|
self.__xml_root.append(series)
|
|
803
801
|
|
|
804
|
-
def write(self):
|
|
802
|
+
def write(self, output_folder=None, output_filename=None) -> None:
|
|
805
803
|
"""
|
|
806
804
|
Writes the time series data to disk.
|
|
805
|
+
|
|
806
|
+
:param output_folder: The folder in which the output file is located.
|
|
807
|
+
If None, the original folder is used.
|
|
808
|
+
:param output_filename: The name of the output file without extension.
|
|
809
|
+
If None, the original filename is used.
|
|
807
810
|
"""
|
|
811
|
+
xml_path = self.output_path(output_folder, output_filename)
|
|
812
|
+
binary_path = self.output_binary_path(output_folder, output_filename)
|
|
808
813
|
|
|
809
814
|
if self.__binary:
|
|
810
|
-
f = io.open(
|
|
815
|
+
f = io.open(binary_path, "wb")
|
|
811
816
|
|
|
812
817
|
if self.make_new_file:
|
|
813
818
|
# Force reinitialization in case write() is called more than once
|
|
@@ -911,7 +916,7 @@ class Timeseries:
|
|
|
911
916
|
f.close()
|
|
912
917
|
|
|
913
918
|
self.format_xml_data()
|
|
914
|
-
self.__tree.write(
|
|
919
|
+
self.__tree.write(xml_path)
|
|
915
920
|
|
|
916
921
|
def format_xml_data(self):
|
|
917
922
|
"""
|
|
@@ -1170,16 +1175,45 @@ class Timeseries:
|
|
|
1170
1175
|
self.__end_datetime = end_datetime
|
|
1171
1176
|
|
|
1172
1177
|
@property
|
|
1173
|
-
def path(self):
|
|
1174
|
-
|
|
1178
|
+
def path(self) -> str:
|
|
1179
|
+
"""
|
|
1180
|
+
The path to the original xml file.
|
|
1181
|
+
"""
|
|
1182
|
+
return os.path.join(self.__folder, self.__basename + ".xml")
|
|
1175
1183
|
|
|
1176
1184
|
@property
|
|
1177
|
-
def binary_path(self):
|
|
1185
|
+
def binary_path(self) -> str:
|
|
1178
1186
|
"""
|
|
1179
|
-
The path
|
|
1187
|
+
The path to the original binary data .bin file.
|
|
1180
1188
|
"""
|
|
1181
1189
|
return os.path.join(self.__folder, self.__basename + ".bin")
|
|
1182
1190
|
|
|
1191
|
+
def _output_path_without_extension(self, output_folder=None, output_filename=None) -> str:
|
|
1192
|
+
"""
|
|
1193
|
+
Get the output path without file extension.
|
|
1194
|
+
"""
|
|
1195
|
+
if output_folder is None:
|
|
1196
|
+
output_folder = self.__folder
|
|
1197
|
+
if output_filename is None:
|
|
1198
|
+
output_filename = self.__basename
|
|
1199
|
+
return os.path.join(output_folder, output_filename)
|
|
1200
|
+
|
|
1201
|
+
def output_path(self, output_folder=None, output_filename=None) -> str:
|
|
1202
|
+
"""
|
|
1203
|
+
Get the path to the output xml file.
|
|
1204
|
+
|
|
1205
|
+
The optional arguments are the same as in :py:method:`write`.
|
|
1206
|
+
"""
|
|
1207
|
+
return self._output_path_without_extension(output_folder, output_filename) + ".xml"
|
|
1208
|
+
|
|
1209
|
+
def output_binary_path(self, output_folder=None, output_filename=None) -> str:
|
|
1210
|
+
"""
|
|
1211
|
+
Get the path to the output binary file.
|
|
1212
|
+
|
|
1213
|
+
The optional arguments are the same as in :py:method:`write`.
|
|
1214
|
+
"""
|
|
1215
|
+
return self._output_path_without_extension(output_folder, output_filename) + ".bin"
|
|
1216
|
+
|
|
1183
1217
|
def items(self, ensemble_member=0):
|
|
1184
1218
|
"""
|
|
1185
1219
|
Returns an iterator over all timeseries IDs and value arrays for the given
|
|
@@ -419,7 +419,6 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
419
419
|
start_values = {}
|
|
420
420
|
|
|
421
421
|
# Attempt to cast var.start to python type
|
|
422
|
-
start_value_is_symbolic = False
|
|
423
422
|
mx_start = ca.MX(var.start)
|
|
424
423
|
if mx_start.is_constant():
|
|
425
424
|
# cast var.start to python type
|
|
@@ -427,7 +426,6 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
427
426
|
if start_value_pymoca is not None and start_value_pymoca != 0:
|
|
428
427
|
start_values["modelica"] = start_value_pymoca
|
|
429
428
|
else:
|
|
430
|
-
start_value_is_symbolic = True
|
|
431
429
|
start_values["modelica"] = mx_start
|
|
432
430
|
|
|
433
431
|
if not var.fixed:
|
|
@@ -479,8 +477,8 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
479
477
|
input_source = "modelica"
|
|
480
478
|
source_description = "modelica file or default value"
|
|
481
479
|
start_val = start_values.get(input_source, None)
|
|
482
|
-
|
|
483
|
-
numeric_start_val = start_val if
|
|
480
|
+
start_is_numeric = start_val is not None and not isinstance(start_val, ca.MX)
|
|
481
|
+
numeric_start_val = start_val if start_is_numeric else 0.0
|
|
484
482
|
if len(start_values) > 1:
|
|
485
483
|
logger.warning(
|
|
486
484
|
"Initialize: Multiple initial values for {} are provided: {}.".format(
|
|
@@ -500,10 +498,12 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
500
498
|
|
|
501
499
|
# Add a residual for the difference between the state and its starting expression
|
|
502
500
|
start_expr = start_val
|
|
501
|
+
min_is_symbolic = isinstance(var.min, ca.MX)
|
|
502
|
+
max_is_symbolic = isinstance(var.max, ca.MX)
|
|
503
503
|
if var.fixed:
|
|
504
504
|
# Set bounds to be equal to each other, such that IPOPT can
|
|
505
505
|
# turn the decision variable into a parameter.
|
|
506
|
-
if var.min != -np.inf or var.max != np.inf:
|
|
506
|
+
if min_is_symbolic or max_is_symbolic or var.min != -np.inf or var.max != np.inf:
|
|
507
507
|
logger.info(
|
|
508
508
|
"Initialize: bounds of {} will be overwritten".format(var_name)
|
|
509
509
|
+ " by the start value given by {}.".format(source_description)
|
|
@@ -515,7 +515,7 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
515
515
|
minimized_residuals.append((var.symbol - start_expr) / var_nominal)
|
|
516
516
|
|
|
517
517
|
# Check that the start_value is in between the variable bounds.
|
|
518
|
-
if
|
|
518
|
+
if start_is_numeric and not min_is_symbolic and not max_is_symbolic:
|
|
519
519
|
if not (var.min <= start_val and start_val <= var.max):
|
|
520
520
|
logger.warning(
|
|
521
521
|
"Initialize: start value {} = {}".format(var_name, start_val)
|
|
@@ -838,6 +838,8 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
838
838
|
self.set_var("time", self.get_current_time() + dt)
|
|
839
839
|
|
|
840
840
|
# take a step
|
|
841
|
+
if np.isnan(self.__state_vector).any():
|
|
842
|
+
logger.error("Found a nan in the state vector (before making the step)")
|
|
841
843
|
guess = self.__state_vector[: self.__n_states]
|
|
842
844
|
if len(self.__mx["parameters"]) > 0:
|
|
843
845
|
next_state = self.__do_step(
|
|
@@ -845,6 +847,23 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
845
847
|
)
|
|
846
848
|
else:
|
|
847
849
|
next_state = self.__do_step(guess, dt, self.__state_vector)
|
|
850
|
+
|
|
851
|
+
try:
|
|
852
|
+
if np.isnan(next_state).any():
|
|
853
|
+
index_to_name = {index[0]: name for name, index in self.__indices.items()}
|
|
854
|
+
named_next_state = {
|
|
855
|
+
index_to_name[i]: float(next_state[i]) for i in range(0, next_state.shape[0])
|
|
856
|
+
}
|
|
857
|
+
variables_with_nan = [
|
|
858
|
+
name for name, value in named_next_state.items() if np.isnan(value)
|
|
859
|
+
]
|
|
860
|
+
if variables_with_nan:
|
|
861
|
+
logger.error(
|
|
862
|
+
f"Found nan(s) in the next_state vector for:\n\t {variables_with_nan}"
|
|
863
|
+
)
|
|
864
|
+
except (KeyError, IndexError, TypeError):
|
|
865
|
+
logger.warning("Something went wrong while checking for nans in the next_state vector")
|
|
866
|
+
|
|
848
867
|
# Check convergence of rootfinder
|
|
849
868
|
rootfinder_stats = self.__do_step.stats()
|
|
850
869
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|