rtc-tools 2.5.2rc4__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.

Files changed (47) hide show
  1. {rtc_tools-2.5.2rc4.dist-info → rtc_tools-2.6.0.dist-info}/METADATA +7 -7
  2. rtc_tools-2.6.0.dist-info/RECORD +50 -0
  3. {rtc_tools-2.5.2rc4.dist-info → rtc_tools-2.6.0.dist-info}/WHEEL +1 -1
  4. rtctools/__init__.py +2 -1
  5. rtctools/_internal/alias_tools.py +12 -10
  6. rtctools/_internal/caching.py +5 -3
  7. rtctools/_internal/casadi_helpers.py +11 -32
  8. rtctools/_internal/debug_check_helpers.py +1 -1
  9. rtctools/_version.py +3 -3
  10. rtctools/data/__init__.py +2 -2
  11. rtctools/data/csv.py +54 -33
  12. rtctools/data/interpolation/bspline.py +3 -3
  13. rtctools/data/interpolation/bspline1d.py +42 -29
  14. rtctools/data/interpolation/bspline2d.py +10 -4
  15. rtctools/data/netcdf.py +137 -93
  16. rtctools/data/pi.py +304 -210
  17. rtctools/data/rtc.py +64 -53
  18. rtctools/data/storage.py +91 -51
  19. rtctools/optimization/collocated_integrated_optimization_problem.py +1244 -696
  20. rtctools/optimization/control_tree_mixin.py +68 -66
  21. rtctools/optimization/csv_lookup_table_mixin.py +107 -74
  22. rtctools/optimization/csv_mixin.py +83 -52
  23. rtctools/optimization/goal_programming_mixin.py +237 -146
  24. rtctools/optimization/goal_programming_mixin_base.py +204 -111
  25. rtctools/optimization/homotopy_mixin.py +36 -27
  26. rtctools/optimization/initial_state_estimation_mixin.py +8 -8
  27. rtctools/optimization/io_mixin.py +48 -43
  28. rtctools/optimization/linearization_mixin.py +3 -1
  29. rtctools/optimization/linearized_order_goal_programming_mixin.py +57 -28
  30. rtctools/optimization/min_abs_goal_programming_mixin.py +72 -29
  31. rtctools/optimization/modelica_mixin.py +135 -81
  32. rtctools/optimization/netcdf_mixin.py +32 -18
  33. rtctools/optimization/optimization_problem.py +181 -127
  34. rtctools/optimization/pi_mixin.py +68 -36
  35. rtctools/optimization/planning_mixin.py +19 -0
  36. rtctools/optimization/single_pass_goal_programming_mixin.py +159 -112
  37. rtctools/optimization/timeseries.py +4 -6
  38. rtctools/rtctoolsapp.py +18 -18
  39. rtctools/simulation/csv_mixin.py +37 -30
  40. rtctools/simulation/io_mixin.py +9 -5
  41. rtctools/simulation/pi_mixin.py +62 -32
  42. rtctools/simulation/simulation_problem.py +471 -180
  43. rtctools/util.py +84 -56
  44. rtc_tools-2.5.2rc4.dist-info/RECORD +0 -49
  45. {rtc_tools-2.5.2rc4.dist-info → rtc_tools-2.6.0.dist-info}/COPYING.LESSER +0 -0
  46. {rtc_tools-2.5.2rc4.dist-info → rtc_tools-2.6.0.dist-info}/entry_points.txt +0 -0
  47. {rtc_tools-2.5.2rc4.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``, ``rtcParameterConfig.xml``,
18
- and ``rtcParameterConfig_Numerical.xml`` are read from the ``input`` subfolder. ``rtcDataConfig.xml`` maps
19
- tuples of FEWS identifiers, including location and parameter ID, to RTC-Tools time series identifiers.
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`` subfolder.
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 = ['rtcParameterConfig']
40
- pi_parameter_config_numerical_basename = 'rtcParameterConfig_Numerical'
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(pi.ParameterConfig(
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(pi_parameter_config_basename, self._input_folder))
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, self._input_folder, self.timeseries_import_basename,
79
- binary=self.pi_binary_timeseries, pi_validate_times=self.pi_validate_timeseries)
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("PIMixin: {}.xml not found in {}.".format(
82
- self.timeseries_import_basename, self._input_folder))
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, self._output_folder, self.timeseries_export_basename,
86
- binary=self.pi_binary_timeseries, pi_validate_times=False, make_new_file=True)
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
- 'PIMixin: Expecting equidistant timeseries, the time step '
106
- 'towards {} is not the same as the time step(s) before. Set '
107
- 'unit to nonequidistant if this is intended.'.format(
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(parameter_id, location_id, model_id)
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(parameter, value, ensemble_member,
128
- check_duplicates=self.pi_check_for_duplicate_parameters)
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) for s in times]
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 = (self.ensemble_size > 1)
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
- 'PIMixin: Output requested for non-existent alias {}. '
197
- 'Will not be in output file.'.format(alias))
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
- 'PIMixin: variable {} has no mapping defined in rtcDataConfig '
206
- 'so cannot be added to the output file.'.format(alias))
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, values,
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)