rtc-tools 2.5.2rc3__py3-none-any.whl → 2.6.0__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.5.2rc3.dist-info → rtc_tools-2.6.0.dist-info}/METADATA +7 -7
- rtc_tools-2.6.0.dist-info/RECORD +50 -0
- {rtc_tools-2.5.2rc3.dist-info → rtc_tools-2.6.0.dist-info}/WHEEL +1 -1
- rtctools/__init__.py +2 -1
- rtctools/_internal/alias_tools.py +12 -10
- rtctools/_internal/caching.py +5 -3
- rtctools/_internal/casadi_helpers.py +11 -32
- rtctools/_internal/debug_check_helpers.py +1 -1
- rtctools/_version.py +3 -3
- rtctools/data/__init__.py +2 -2
- rtctools/data/csv.py +54 -33
- rtctools/data/interpolation/bspline.py +3 -3
- rtctools/data/interpolation/bspline1d.py +42 -29
- rtctools/data/interpolation/bspline2d.py +10 -4
- rtctools/data/netcdf.py +137 -93
- rtctools/data/pi.py +304 -210
- rtctools/data/rtc.py +64 -53
- rtctools/data/storage.py +91 -51
- rtctools/optimization/collocated_integrated_optimization_problem.py +1244 -696
- rtctools/optimization/control_tree_mixin.py +68 -66
- rtctools/optimization/csv_lookup_table_mixin.py +107 -74
- rtctools/optimization/csv_mixin.py +83 -52
- rtctools/optimization/goal_programming_mixin.py +239 -148
- rtctools/optimization/goal_programming_mixin_base.py +204 -111
- rtctools/optimization/homotopy_mixin.py +36 -27
- rtctools/optimization/initial_state_estimation_mixin.py +8 -8
- rtctools/optimization/io_mixin.py +48 -43
- rtctools/optimization/linearization_mixin.py +3 -1
- rtctools/optimization/linearized_order_goal_programming_mixin.py +57 -28
- rtctools/optimization/min_abs_goal_programming_mixin.py +72 -29
- rtctools/optimization/modelica_mixin.py +135 -81
- rtctools/optimization/netcdf_mixin.py +32 -18
- rtctools/optimization/optimization_problem.py +181 -127
- rtctools/optimization/pi_mixin.py +68 -36
- rtctools/optimization/planning_mixin.py +19 -0
- rtctools/optimization/single_pass_goal_programming_mixin.py +159 -112
- rtctools/optimization/timeseries.py +4 -6
- rtctools/rtctoolsapp.py +18 -18
- rtctools/simulation/csv_mixin.py +37 -30
- rtctools/simulation/io_mixin.py +9 -5
- rtctools/simulation/pi_mixin.py +62 -32
- rtctools/simulation/simulation_problem.py +471 -180
- rtctools/util.py +84 -56
- rtc_tools-2.5.2rc3.dist-info/RECORD +0 -49
- {rtc_tools-2.5.2rc3.dist-info → rtc_tools-2.6.0.dist-info}/COPYING.LESSER +0 -0
- {rtc_tools-2.5.2rc3.dist-info → rtc_tools-2.6.0.dist-info}/entry_points.txt +0 -0
- {rtc_tools-2.5.2rc3.dist-info → rtc_tools-2.6.0.dist-info}/top_level.txt +0 -0
|
@@ -14,11 +14,13 @@ class PIMixin(IOMixin):
|
|
|
14
14
|
<https://publicwiki.deltares.nl/display/FEWSDOC/The+Delft-Fews+Published+Interface>`_
|
|
15
15
|
I/O to your optimization problem.
|
|
16
16
|
|
|
17
|
-
During preprocessing, files named ``rtcDataConfig.xml``, ``timeseries_import.xml``,
|
|
18
|
-
and ``rtcParameterConfig_Numerical.xml`` are read from the
|
|
19
|
-
tuples of FEWS identifiers, including
|
|
17
|
+
During preprocessing, files named ``rtcDataConfig.xml``, ``timeseries_import.xml``,
|
|
18
|
+
``rtcParameterConfig.xml``, and ``rtcParameterConfig_Numerical.xml`` are read from the
|
|
19
|
+
``input`` subfolder. ``rtcDataConfig.xml`` maps tuples of FEWS identifiers, including
|
|
20
|
+
location and parameter ID, to RTC-Tools time series identifiers.
|
|
20
21
|
|
|
21
|
-
During postprocessing, a file named ``timeseries_export.xml`` is written to the ``output``
|
|
22
|
+
During postprocessing, a file named ``timeseries_export.xml`` is written to the ``output``
|
|
23
|
+
subfolder.
|
|
22
24
|
|
|
23
25
|
:cvar pi_binary_timeseries:
|
|
24
26
|
Whether to use PI binary timeseries format. Default is ``False``.
|
|
@@ -36,8 +38,8 @@ class PIMixin(IOMixin):
|
|
|
36
38
|
pi_binary_timeseries = False
|
|
37
39
|
|
|
38
40
|
#: Location of rtcParameterConfig files
|
|
39
|
-
pi_parameter_config_basenames = [
|
|
40
|
-
pi_parameter_config_numerical_basename =
|
|
41
|
+
pi_parameter_config_basenames = ["rtcParameterConfig"]
|
|
42
|
+
pi_parameter_config_numerical_basename = "rtcParameterConfig_Numerical"
|
|
41
43
|
|
|
42
44
|
#: Check consistency of timeseries
|
|
43
45
|
pi_validate_timeseries = True
|
|
@@ -61,29 +63,46 @@ class PIMixin(IOMixin):
|
|
|
61
63
|
self.__parameter_config = []
|
|
62
64
|
try:
|
|
63
65
|
for pi_parameter_config_basename in self.pi_parameter_config_basenames:
|
|
64
|
-
self.__parameter_config.append(
|
|
65
|
-
self._input_folder, pi_parameter_config_basename)
|
|
66
|
+
self.__parameter_config.append(
|
|
67
|
+
pi.ParameterConfig(self._input_folder, pi_parameter_config_basename)
|
|
68
|
+
)
|
|
66
69
|
except IOError:
|
|
67
70
|
raise Exception(
|
|
68
|
-
"PIMixin: {}.xml not found in {}.".format(
|
|
71
|
+
"PIMixin: {}.xml not found in {}.".format(
|
|
72
|
+
pi_parameter_config_basename, self._input_folder
|
|
73
|
+
)
|
|
74
|
+
)
|
|
69
75
|
|
|
70
76
|
try:
|
|
71
77
|
self.__parameter_config_numerical = pi.ParameterConfig(
|
|
72
|
-
self._input_folder, self.pi_parameter_config_numerical_basename
|
|
78
|
+
self._input_folder, self.pi_parameter_config_numerical_basename
|
|
79
|
+
)
|
|
73
80
|
except IOError:
|
|
74
81
|
self.__parameter_config_numerical = None
|
|
75
82
|
|
|
76
83
|
try:
|
|
77
84
|
self.__timeseries_import = pi.Timeseries(
|
|
78
|
-
self.__data_config,
|
|
79
|
-
|
|
85
|
+
self.__data_config,
|
|
86
|
+
self._input_folder,
|
|
87
|
+
self.timeseries_import_basename,
|
|
88
|
+
binary=self.pi_binary_timeseries,
|
|
89
|
+
pi_validate_times=self.pi_validate_timeseries,
|
|
90
|
+
)
|
|
80
91
|
except IOError:
|
|
81
|
-
raise Exception(
|
|
82
|
-
|
|
92
|
+
raise Exception(
|
|
93
|
+
"PIMixin: {}.xml not found in {}.".format(
|
|
94
|
+
self.timeseries_import_basename, self._input_folder
|
|
95
|
+
)
|
|
96
|
+
)
|
|
83
97
|
|
|
84
98
|
self.__timeseries_export = pi.Timeseries(
|
|
85
|
-
self.__data_config,
|
|
86
|
-
|
|
99
|
+
self.__data_config,
|
|
100
|
+
self._output_folder,
|
|
101
|
+
self.timeseries_export_basename,
|
|
102
|
+
binary=self.pi_binary_timeseries,
|
|
103
|
+
pi_validate_times=False,
|
|
104
|
+
make_new_file=True,
|
|
105
|
+
)
|
|
87
106
|
|
|
88
107
|
# Convert timeseries timestamps to seconds since t0 for internal use
|
|
89
108
|
timeseries_import_times = self.__timeseries_import.times
|
|
@@ -92,8 +111,7 @@ class PIMixin(IOMixin):
|
|
|
92
111
|
if self.pi_validate_timeseries:
|
|
93
112
|
for i in range(len(timeseries_import_times) - 1):
|
|
94
113
|
if timeseries_import_times[i] >= timeseries_import_times[i + 1]:
|
|
95
|
-
raise Exception(
|
|
96
|
-
'PIMixin: Time stamps must be strictly increasing.')
|
|
114
|
+
raise Exception("PIMixin: Time stamps must be strictly increasing.")
|
|
97
115
|
|
|
98
116
|
if self.__timeseries_import.dt:
|
|
99
117
|
# Check if the timeseries are truly equidistant
|
|
@@ -102,10 +120,12 @@ class PIMixin(IOMixin):
|
|
|
102
120
|
for i in range(len(timeseries_import_times) - 1):
|
|
103
121
|
if timeseries_import_times[i + 1] - timeseries_import_times[i] != dt:
|
|
104
122
|
raise Exception(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
timeseries_import_times[i + 1]
|
|
123
|
+
"PIMixin: Expecting equidistant timeseries, the time step "
|
|
124
|
+
"towards {} is not the same as the time step(s) before. Set "
|
|
125
|
+
"unit to nonequidistant if this is intended.".format(
|
|
126
|
+
timeseries_import_times[i + 1]
|
|
127
|
+
)
|
|
128
|
+
)
|
|
109
129
|
|
|
110
130
|
# Offer input timeseries to IOMixin
|
|
111
131
|
self.io.reference_datetime = self.__timeseries_import.forecast_datetime
|
|
@@ -120,12 +140,18 @@ class PIMixin(IOMixin):
|
|
|
120
140
|
for parameter_config in self.__parameter_config:
|
|
121
141
|
for location_id, model_id, parameter_id, value in parameter_config:
|
|
122
142
|
try:
|
|
123
|
-
parameter = self.__data_config.parameter(
|
|
143
|
+
parameter = self.__data_config.parameter(
|
|
144
|
+
parameter_id, location_id, model_id
|
|
145
|
+
)
|
|
124
146
|
except KeyError:
|
|
125
147
|
parameter = parameter_id
|
|
126
148
|
|
|
127
|
-
self.io.set_parameter(
|
|
128
|
-
|
|
149
|
+
self.io.set_parameter(
|
|
150
|
+
parameter,
|
|
151
|
+
value,
|
|
152
|
+
ensemble_member,
|
|
153
|
+
check_duplicates=self.pi_check_for_duplicate_parameters,
|
|
154
|
+
)
|
|
129
155
|
|
|
130
156
|
def solver_options(self):
|
|
131
157
|
# Call parent
|
|
@@ -157,7 +183,9 @@ class PIMixin(IOMixin):
|
|
|
157
183
|
# Write the time range for the export file.
|
|
158
184
|
self.__timeseries_export.times = [
|
|
159
185
|
self.__timeseries_import.times[self.__timeseries_import.forecast_index]
|
|
160
|
-
+ timedelta(seconds=s)
|
|
186
|
+
+ timedelta(seconds=s)
|
|
187
|
+
for s in times
|
|
188
|
+
]
|
|
161
189
|
|
|
162
190
|
# Write other time settings
|
|
163
191
|
self.__timeseries_export.forecast_datetime = self.__timeseries_import.forecast_datetime
|
|
@@ -168,7 +196,7 @@ class PIMixin(IOMixin):
|
|
|
168
196
|
if self.ensemble_size > 1:
|
|
169
197
|
self.__timeseries_export.contains_ensemble = True
|
|
170
198
|
self.__timeseries_export.ensemble_size = self.ensemble_size
|
|
171
|
-
self.__timeseries_export.contains_ensemble =
|
|
199
|
+
self.__timeseries_export.contains_ensemble = self.ensemble_size > 1
|
|
172
200
|
|
|
173
201
|
# Start looping over the ensembles for extraction of the output values.
|
|
174
202
|
for ensemble_member in range(self.ensemble_size):
|
|
@@ -182,19 +210,20 @@ class PIMixin(IOMixin):
|
|
|
182
210
|
values = results[alias]
|
|
183
211
|
if len(values) != len(times):
|
|
184
212
|
values = self.interpolate(
|
|
185
|
-
times, self.times(alias), values, self.interpolation_method(alias)
|
|
213
|
+
times, self.times(alias), values, self.interpolation_method(alias)
|
|
214
|
+
)
|
|
186
215
|
except KeyError:
|
|
187
216
|
try:
|
|
188
217
|
ts = self.get_timeseries(alias, ensemble_member)
|
|
189
218
|
if len(ts.times) != len(times):
|
|
190
|
-
values = self.interpolate(
|
|
191
|
-
times, ts.times, ts.values)
|
|
219
|
+
values = self.interpolate(times, ts.times, ts.values)
|
|
192
220
|
else:
|
|
193
221
|
values = ts.values
|
|
194
222
|
except KeyError:
|
|
195
223
|
logger.error(
|
|
196
|
-
|
|
197
|
-
|
|
224
|
+
"PIMixin: Output requested for non-existent alias {}. "
|
|
225
|
+
"Will not be in output file.".format(alias)
|
|
226
|
+
)
|
|
198
227
|
continue
|
|
199
228
|
|
|
200
229
|
# Check if ID mapping is present
|
|
@@ -202,17 +231,20 @@ class PIMixin(IOMixin):
|
|
|
202
231
|
self.__data_config.pi_variable_ids(alias)
|
|
203
232
|
except KeyError:
|
|
204
233
|
logger.debug(
|
|
205
|
-
|
|
206
|
-
|
|
234
|
+
"PIMixin: variable {} has no mapping defined in rtcDataConfig "
|
|
235
|
+
"so cannot be added to the output file.".format(alias)
|
|
236
|
+
)
|
|
207
237
|
continue
|
|
208
238
|
|
|
209
239
|
# Add series to output file.
|
|
210
240
|
# NOTE: We use the unit of the zeroth ensemble member, as
|
|
211
241
|
# we might be outputting more ensembles than we read in.
|
|
212
242
|
self.__timeseries_export.set(
|
|
213
|
-
alias,
|
|
243
|
+
alias,
|
|
244
|
+
values,
|
|
214
245
|
unit=self.__timeseries_import.get_unit(alias, ensemble_member=0),
|
|
215
|
-
ensemble_member=ensemble_member
|
|
246
|
+
ensemble_member=ensemble_member,
|
|
247
|
+
)
|
|
216
248
|
|
|
217
249
|
# Write output file to disk
|
|
218
250
|
self.__timeseries_export.write()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from rtctools.optimization.optimization_problem import OptimizationProblem
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PlanningMixin(OptimizationProblem):
|
|
5
|
+
"""
|
|
6
|
+
Uses default discretization logic for planning variables, but uses
|
|
7
|
+
dedicated per-ensemble-member decision variables for other, non-planning control
|
|
8
|
+
variables.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# Planning variables
|
|
12
|
+
planning_variables = []
|
|
13
|
+
|
|
14
|
+
def discretize_control(self, variable, ensemble_member, times, offset):
|
|
15
|
+
if variable not in self.planning_variables:
|
|
16
|
+
# Non-planning variables are never shared between ensemble members
|
|
17
|
+
return slice(offset, offset + len(times))
|
|
18
|
+
else:
|
|
19
|
+
return super().discretize_control(variable, ensemble_member, times, offset)
|