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
|
@@ -20,7 +20,8 @@ class CSVMixin(IOMixin):
|
|
|
20
20
|
During preprocessing, files named ``timeseries_import.csv``, ``initial_state.csv``,
|
|
21
21
|
and ``parameters.csv`` are read from the ``input`` subfolder.
|
|
22
22
|
|
|
23
|
-
During postprocessing, a file named ``timeseries_export.csv`` is written to the ``output``
|
|
23
|
+
During postprocessing, a file named ``timeseries_export.csv`` is written to the ``output``
|
|
24
|
+
subfolder.
|
|
24
25
|
|
|
25
26
|
In ensemble mode, a file named ``ensemble.csv`` is read from the ``input`` folder. This file
|
|
26
27
|
contains two columns. The first column gives the name of the ensemble member, and the second
|
|
@@ -44,16 +45,16 @@ class CSVMixin(IOMixin):
|
|
|
44
45
|
"""
|
|
45
46
|
|
|
46
47
|
#: Initial state file basename
|
|
47
|
-
csv_initial_state_basename =
|
|
48
|
+
csv_initial_state_basename = "initial_state"
|
|
48
49
|
|
|
49
50
|
#: Parameters file basename
|
|
50
|
-
csv_parameters_basename =
|
|
51
|
+
csv_parameters_basename = "parameters"
|
|
51
52
|
|
|
52
53
|
#: Ensemble file basename
|
|
53
|
-
csv_ensemble_basename =
|
|
54
|
+
csv_ensemble_basename = "ensemble"
|
|
54
55
|
|
|
55
56
|
#: Column delimiter used in CSV files
|
|
56
|
-
csv_delimiter =
|
|
57
|
+
csv_delimiter = ","
|
|
57
58
|
|
|
58
59
|
#: Whether or not the timeseries data is equidistant
|
|
59
60
|
csv_equidistant = True
|
|
@@ -80,20 +81,27 @@ class CSVMixin(IOMixin):
|
|
|
80
81
|
"""
|
|
81
82
|
if initial_state.shape:
|
|
82
83
|
raise Exception(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
os.path.join(self._input_folder, self.csv_initial_state_basename +
|
|
84
|
+
"CSVMixin: Initial state file {} contains more than one row of data. "
|
|
85
|
+
"Please remove the data row(s) that do not describe the initial state.".format(
|
|
86
|
+
os.path.join(self._input_folder, self.csv_initial_state_basename + ".csv")
|
|
87
|
+
)
|
|
88
|
+
)
|
|
86
89
|
|
|
87
90
|
# Read CSV files
|
|
88
91
|
self.__initial_state = []
|
|
89
92
|
if self.csv_ensemble_mode:
|
|
90
93
|
self.__ensemble = np.genfromtxt(
|
|
91
|
-
os.path.join(self._input_folder, self.csv_ensemble_basename +
|
|
92
|
-
delimiter=",",
|
|
94
|
+
os.path.join(self._input_folder, self.csv_ensemble_basename + ".csv"),
|
|
95
|
+
delimiter=",",
|
|
96
|
+
deletechars="",
|
|
97
|
+
dtype=None,
|
|
98
|
+
names=True,
|
|
99
|
+
encoding=None,
|
|
100
|
+
)
|
|
93
101
|
|
|
94
102
|
logger.debug("CSVMixin: Read ensemble description")
|
|
95
103
|
|
|
96
|
-
for ensemble_member_index, ensemble_member_name in enumerate(self.__ensemble[
|
|
104
|
+
for ensemble_member_index, ensemble_member_name in enumerate(self.__ensemble["name"]):
|
|
97
105
|
_timeseries = csv.load(
|
|
98
106
|
os.path.join(
|
|
99
107
|
self._input_folder,
|
|
@@ -112,37 +120,47 @@ class CSVMixin(IOMixin):
|
|
|
112
120
|
key,
|
|
113
121
|
self.__timeseries_times,
|
|
114
122
|
np.asarray(_timeseries[key], dtype=np.float64),
|
|
115
|
-
ensemble_member_index
|
|
123
|
+
ensemble_member_index,
|
|
116
124
|
)
|
|
117
125
|
logger.debug("CSVMixin: Read timeseries")
|
|
118
126
|
|
|
119
|
-
for ensemble_member_index, ensemble_member_name in enumerate(self.__ensemble[
|
|
127
|
+
for ensemble_member_index, ensemble_member_name in enumerate(self.__ensemble["name"]):
|
|
120
128
|
try:
|
|
121
|
-
_parameters = csv.load(
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
_parameters = csv.load(
|
|
130
|
+
os.path.join(
|
|
131
|
+
self._input_folder,
|
|
132
|
+
ensemble_member_name,
|
|
133
|
+
self.csv_parameters_basename + ".csv",
|
|
134
|
+
),
|
|
135
|
+
delimiter=self.csv_delimiter,
|
|
136
|
+
)
|
|
124
137
|
for key in _parameters.dtype.names:
|
|
125
138
|
self.io.set_parameter(key, float(_parameters[key]), ensemble_member_index)
|
|
126
139
|
except IOError:
|
|
127
140
|
pass
|
|
128
141
|
logger.debug("CSVMixin: Read parameters.")
|
|
129
142
|
|
|
130
|
-
for ensemble_member_name in self.__ensemble[
|
|
143
|
+
for ensemble_member_name in self.__ensemble["name"]:
|
|
131
144
|
try:
|
|
132
|
-
_initial_state = csv.load(
|
|
133
|
-
|
|
134
|
-
|
|
145
|
+
_initial_state = csv.load(
|
|
146
|
+
os.path.join(
|
|
147
|
+
self._input_folder,
|
|
148
|
+
ensemble_member_name,
|
|
149
|
+
self.csv_initial_state_basename + ".csv",
|
|
150
|
+
),
|
|
151
|
+
delimiter=self.csv_delimiter,
|
|
152
|
+
)
|
|
135
153
|
check_initial_state_array(_initial_state)
|
|
136
|
-
_initial_state = {
|
|
154
|
+
_initial_state = {
|
|
155
|
+
key: float(_initial_state[key]) for key in _initial_state.dtype.names
|
|
156
|
+
}
|
|
137
157
|
except IOError:
|
|
138
158
|
_initial_state = {}
|
|
139
159
|
self.__initial_state.append(AliasDict(self.alias_relation, _initial_state))
|
|
140
160
|
logger.debug("CSVMixin: Read initial state.")
|
|
141
161
|
else:
|
|
142
162
|
_timeseries = csv.load(
|
|
143
|
-
os.path.join(
|
|
144
|
-
self._input_folder, self.timeseries_import_basename + ".csv"
|
|
145
|
-
),
|
|
163
|
+
os.path.join(self._input_folder, self.timeseries_import_basename + ".csv"),
|
|
146
164
|
delimiter=self.csv_delimiter,
|
|
147
165
|
with_time=True,
|
|
148
166
|
)
|
|
@@ -151,12 +169,16 @@ class CSVMixin(IOMixin):
|
|
|
151
169
|
self.io.reference_datetime = self.__timeseries_times[0]
|
|
152
170
|
|
|
153
171
|
for key in _timeseries.dtype.names[1:]:
|
|
154
|
-
self.io.set_timeseries(
|
|
172
|
+
self.io.set_timeseries(
|
|
173
|
+
key, self.__timeseries_times, np.asarray(_timeseries[key], dtype=np.float64)
|
|
174
|
+
)
|
|
155
175
|
logger.debug("CSVMixin: Read timeseries.")
|
|
156
176
|
|
|
157
177
|
try:
|
|
158
|
-
_parameters = csv.load(
|
|
159
|
-
self._input_folder, self.csv_parameters_basename +
|
|
178
|
+
_parameters = csv.load(
|
|
179
|
+
os.path.join(self._input_folder, self.csv_parameters_basename + ".csv"),
|
|
180
|
+
delimiter=self.csv_delimiter,
|
|
181
|
+
)
|
|
160
182
|
logger.debug("CSVMixin: Read parameters.")
|
|
161
183
|
for key in _parameters.dtype.names:
|
|
162
184
|
self.io.set_parameter(key, float(_parameters[key]))
|
|
@@ -164,11 +186,15 @@ class CSVMixin(IOMixin):
|
|
|
164
186
|
pass
|
|
165
187
|
|
|
166
188
|
try:
|
|
167
|
-
_initial_state = csv.load(
|
|
168
|
-
self._input_folder, self.csv_initial_state_basename +
|
|
189
|
+
_initial_state = csv.load(
|
|
190
|
+
os.path.join(self._input_folder, self.csv_initial_state_basename + ".csv"),
|
|
191
|
+
delimiter=self.csv_delimiter,
|
|
192
|
+
)
|
|
169
193
|
logger.debug("CSVMixin: Read initial state.")
|
|
170
194
|
check_initial_state_array(_initial_state)
|
|
171
|
-
_initial_state = {
|
|
195
|
+
_initial_state = {
|
|
196
|
+
key: float(_initial_state[key]) for key in _initial_state.dtype.names
|
|
197
|
+
}
|
|
172
198
|
except IOError:
|
|
173
199
|
_initial_state = {}
|
|
174
200
|
self.__initial_state.append(AliasDict(self.alias_relation, _initial_state))
|
|
@@ -178,8 +204,7 @@ class CSVMixin(IOMixin):
|
|
|
178
204
|
times = self.__timeseries_times
|
|
179
205
|
for i in range(len(times) - 1):
|
|
180
206
|
if times[i] >= times[i + 1]:
|
|
181
|
-
raise Exception(
|
|
182
|
-
'CSVMixin: Time stamps must be strictly increasing.')
|
|
207
|
+
raise Exception("CSVMixin: Time stamps must be strictly increasing.")
|
|
183
208
|
|
|
184
209
|
if self.csv_equidistant:
|
|
185
210
|
# Check if the timeseries are truly equidistant
|
|
@@ -189,13 +214,14 @@ class CSVMixin(IOMixin):
|
|
|
189
214
|
for i in range(len(times) - 1):
|
|
190
215
|
if times[i + 1] - times[i] != dt:
|
|
191
216
|
raise Exception(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
217
|
+
"CSVMixin: Expecting equidistant timeseries, the time step towards "
|
|
218
|
+
"{} is not the same as the time step(s) before. "
|
|
219
|
+
"Set csv_equidistant = False if this is intended.".format(times[i + 1])
|
|
220
|
+
)
|
|
195
221
|
|
|
196
222
|
def ensemble_member_probability(self, ensemble_member):
|
|
197
223
|
if self.csv_ensemble_mode:
|
|
198
|
-
return self.__ensemble[
|
|
224
|
+
return self.__ensemble["probability"][ensemble_member]
|
|
199
225
|
else:
|
|
200
226
|
return 1.0
|
|
201
227
|
|
|
@@ -207,11 +233,12 @@ class CSVMixin(IOMixin):
|
|
|
207
233
|
initial_time = np.array([self.initial_time])
|
|
208
234
|
|
|
209
235
|
# Load parameters from parameter config
|
|
210
|
-
for variable in self.dae_variables[
|
|
236
|
+
for variable in self.dae_variables["free_variables"]:
|
|
211
237
|
variable = variable.name()
|
|
212
238
|
try:
|
|
213
|
-
history[variable] = Timeseries(
|
|
214
|
-
|
|
239
|
+
history[variable] = Timeseries(
|
|
240
|
+
initial_time, self.__initial_state[ensemble_member][variable]
|
|
241
|
+
)
|
|
215
242
|
except (KeyError, ValueError):
|
|
216
243
|
pass
|
|
217
244
|
else:
|
|
@@ -228,30 +255,33 @@ class CSVMixin(IOMixin):
|
|
|
228
255
|
|
|
229
256
|
def write_output(ensemble_member, folder):
|
|
230
257
|
results = self.extract_results(ensemble_member)
|
|
231
|
-
names = [
|
|
232
|
-
formats = [
|
|
233
|
-
dtype = {
|
|
258
|
+
names = ["time"] + sorted({sym.name() for sym in self.output_variables})
|
|
259
|
+
formats = ["O"] + (len(names) - 1) * ["f8"]
|
|
260
|
+
dtype = {"names": names, "formats": formats}
|
|
234
261
|
data = np.zeros(len(times), dtype=dtype)
|
|
235
|
-
data[
|
|
262
|
+
data["time"] = [self.io.reference_datetime + timedelta(seconds=s) for s in times]
|
|
236
263
|
for output_variable in self.output_variables:
|
|
237
264
|
output_variable = output_variable.name()
|
|
238
265
|
try:
|
|
239
266
|
values = results[output_variable]
|
|
240
267
|
if len(values) != len(times):
|
|
241
268
|
values = self.interpolate(
|
|
242
|
-
times,
|
|
269
|
+
times,
|
|
270
|
+
self.times(output_variable),
|
|
271
|
+
values,
|
|
272
|
+
self.interpolation_method(output_variable),
|
|
273
|
+
)
|
|
243
274
|
except KeyError:
|
|
244
275
|
try:
|
|
245
|
-
ts = self.get_timeseries(
|
|
246
|
-
output_variable, ensemble_member)
|
|
276
|
+
ts = self.get_timeseries(output_variable, ensemble_member)
|
|
247
277
|
if len(ts.times) != len(times):
|
|
248
|
-
values = self.interpolate(
|
|
249
|
-
times, ts.times, ts.values)
|
|
278
|
+
values = self.interpolate(times, ts.times, ts.values)
|
|
250
279
|
else:
|
|
251
280
|
values = ts.values
|
|
252
281
|
except KeyError:
|
|
253
282
|
logger.error(
|
|
254
|
-
"Output requested for non-existent variable {}".format(output_variable)
|
|
283
|
+
"Output requested for non-existent variable {}".format(output_variable)
|
|
284
|
+
)
|
|
255
285
|
continue
|
|
256
286
|
data[output_variable] = values
|
|
257
287
|
|
|
@@ -259,8 +289,9 @@ class CSVMixin(IOMixin):
|
|
|
259
289
|
csv.save(fname, data, delimiter=self.csv_delimiter, with_time=True)
|
|
260
290
|
|
|
261
291
|
if self.csv_ensemble_mode:
|
|
262
|
-
for ensemble_member, ensemble_member_name in enumerate(self.__ensemble[
|
|
263
|
-
write_output(
|
|
264
|
-
self._output_folder, ensemble_member_name)
|
|
292
|
+
for ensemble_member, ensemble_member_name in enumerate(self.__ensemble["name"]):
|
|
293
|
+
write_output(
|
|
294
|
+
ensemble_member, os.path.join(self._output_folder, ensemble_member_name)
|
|
295
|
+
)
|
|
265
296
|
else:
|
|
266
297
|
write_output(0, self._output_folder)
|