rtc-tools-interface 0.9.0a2__tar.gz → 0.10.1__tar.gz
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.
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/PKG-INFO +1 -1
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/README.md +12 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtc_tools_interface.egg-info/PKG-INFO +1 -1
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtc_tools_interface.egg-info/requires.txt +1 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/_version.py +3 -3
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/closed_loop/config.py +4 -3
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/closed_loop/optimization_ranges.py +1 -1
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/closed_loop/results_construction.py +12 -4
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/closed_loop/runner.py +35 -19
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/closed_loop/time_series_handler.py +7 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/base_goal.py +1 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/simulation/plot_mixin.py +10 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/setup.py +1 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/closed_loop/test_run_optization_problem_closed_loop.py +81 -30
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/COPYING.LESSER +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtc_tools_interface.egg-info/SOURCES.txt +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtc_tools_interface.egg-info/dependency_links.txt +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtc_tools_interface.egg-info/top_level.txt +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/closed_loop/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/base_optimization_problem.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/goal_generator_mixin.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/goal_performance_metrics.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/goal_table_schema.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/helpers/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/helpers/statistics_mixin.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/plot_goals_mixin.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/plot_mixin.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/optimization/read_goals.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/plotting/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/plotting/plot_tools.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/plotting/subplot_classes.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/simulation/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/simulation/base_simulation_problem.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/plot_table_schema.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/read_goals_mixin.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/read_plot_table.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/results_collection.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/serialization.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/type_definitions.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/setup.cfg +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/closed_loop/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/closed_loop/test_optimization_ranges.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/closed_loop/test_read_xml.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/optimization/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/optimization/test_base_optimization_problem.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/optimization/test_passing_goals_directly.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/optimization/test_plot_goals_mixin.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/optimization/test_read_goals.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/simulation/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/simulation/test_base_simulation_problem.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/simulation/test_plot_mixin.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/utils/__init__.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/utils/get_test.py +0 -0
- {rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/versioneer.py +0 -0
|
@@ -189,7 +189,19 @@ Import `ClosedLoopConfig` and `run_optimization_problem_closed_loop` with:
|
|
|
189
189
|
from rtctools_interface.closed_loop.config import ClosedLoopConfig
|
|
190
190
|
from rtctools_interface.closed_loop.runner import run_optimization_problem_closed_loop
|
|
191
191
|
```
|
|
192
|
+
#### Fixed inputs
|
|
193
|
+
Create the file `fixed_inputs.json`, in which you specify which variables in your
|
|
194
|
+
timeseries import are what we call 'fixed_inputs'. They are timeseries that the closed
|
|
195
|
+
loop runner should simply copy as they are, even if they contain only NaNs in a modelling
|
|
196
|
+
period.
|
|
192
197
|
|
|
198
|
+
The variables that are not mentioned in this list of fixed_inputs, and have only NaN's
|
|
199
|
+
in a modelling period, are considered being 'initial values'. The closed loop runner will set
|
|
200
|
+
the first timestep of each modelling period with the corresponding calculated value from the
|
|
201
|
+
previous modelling period.
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
#### Closed loop config
|
|
193
205
|
A `ClosedLoopConfig` configuration can be created from a csv file or
|
|
194
206
|
from a given forecast timestep (time between each time range)
|
|
195
207
|
and optimization period (duration of each time range).
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "
|
|
11
|
+
"date": "2025-06-04T10:02:27+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.
|
|
14
|
+
"full-revisionid": "33cba7abbd05364334aabef715ce319b398ff945",
|
|
15
|
+
"version": "0.10.1"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/closed_loop/config.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Module for configuring a closed-loop optimization problem."""
|
|
2
|
-
from pathlib import Path
|
|
3
2
|
from datetime import timedelta
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class ClosedLoopConfig():
|
|
@@ -29,8 +30,8 @@ class ClosedLoopConfig():
|
|
|
29
30
|
if file is not None:
|
|
30
31
|
file = Path(file).resolve()
|
|
31
32
|
self._file = file
|
|
32
|
-
self._forecast_timestep = None
|
|
33
|
-
self._optimization_period = None
|
|
33
|
+
self._forecast_timestep: Optional[timedelta] = None
|
|
34
|
+
self._optimization_period: Optional[timedelta] = None
|
|
34
35
|
self.round_to_dates = round_to_dates
|
|
35
36
|
|
|
36
37
|
@classmethod
|
|
@@ -49,7 +49,7 @@ def get_optimization_ranges_from_file(
|
|
|
49
49
|
min(closed_loop_dates["start_date"]).date() == model_time_range[0].date()
|
|
50
50
|
), (
|
|
51
51
|
"The start day of the first optimization run is not equal"
|
|
52
|
-
" to the start day of the
|
|
52
|
+
" to the start day of the forecast date (or first timestep)."
|
|
53
53
|
)
|
|
54
54
|
assert (
|
|
55
55
|
max(closed_loop_dates["end_date"]).date() <= model_time_range[1].date()
|
|
@@ -28,8 +28,15 @@ def combine_xml_exports(output_base_path: Path, original_input_timeseries_path:
|
|
|
28
28
|
dataconfig = rtc.DataConfig(folder=original_input_timeseries_path)
|
|
29
29
|
|
|
30
30
|
ts_import_orig = pi.Timeseries(
|
|
31
|
-
data_config=dataconfig,
|
|
31
|
+
data_config=dataconfig,
|
|
32
|
+
folder=original_input_timeseries_path,
|
|
33
|
+
basename="timeseries_import",
|
|
34
|
+
binary=False,
|
|
32
35
|
)
|
|
36
|
+
if ts_import_orig.forecast_datetime > ts_import_orig.start_datetime:
|
|
37
|
+
logger.info("Timeseries export will start at original forecast date, disregarding data before forecast date.")
|
|
38
|
+
ts_import_orig.resize(ts_import_orig.forecast_datetime, ts_import_orig.end_datetime)
|
|
39
|
+
ts_import_orig.times = ts_import_orig.times[ts_import_orig.times.index(ts_import_orig.forecast_datetime):]
|
|
33
40
|
orig_start_datetime = ts_import_orig.start_datetime
|
|
34
41
|
orig_end_datetime = ts_import_orig.end_datetime
|
|
35
42
|
|
|
@@ -76,15 +83,16 @@ def combine_xml_exports(output_base_path: Path, original_input_timeseries_path:
|
|
|
76
83
|
ts_export.write(output_folder=output_base_path.parent, output_filename="timeseries_export")
|
|
77
84
|
|
|
78
85
|
if write_csv_out:
|
|
79
|
-
data = pd.DataFrame()
|
|
80
|
-
|
|
86
|
+
data = pd.DataFrame({"date": all_times})
|
|
87
|
+
new_columns = []
|
|
81
88
|
for timeseries_id in variables:
|
|
82
89
|
try:
|
|
83
90
|
values = ts_export.get(timeseries_id)
|
|
91
|
+
new_columns.append(pd.Series(values, name=timeseries_id))
|
|
84
92
|
except KeyError:
|
|
85
93
|
logger.debug("Variable {} not found in output of model horizon: {}".format(timeseries_id, i))
|
|
86
94
|
continue
|
|
87
|
-
|
|
95
|
+
data = pd.concat([data] + new_columns, axis=1)
|
|
88
96
|
data.round(6).to_csv(output_base_path.parent / "timeseries_export.csv", index=False)
|
|
89
97
|
|
|
90
98
|
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/closed_loop/runner.py
RENAMED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import copy
|
|
1
2
|
import datetime
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
2
5
|
import os
|
|
3
|
-
import copy
|
|
4
|
-
from pathlib import Path
|
|
5
6
|
import shutil
|
|
6
7
|
import sys
|
|
8
|
+
from pathlib import Path
|
|
7
9
|
from typing import List, Optional
|
|
10
|
+
|
|
8
11
|
from rtctools.data.pi import DiagHandler
|
|
9
12
|
from rtctools.optimization.pi_mixin import PIMixin
|
|
10
13
|
from rtctools.optimization.csv_mixin import CSVMixin
|
|
@@ -13,7 +16,6 @@ from rtctools_interface.closed_loop.config import ClosedLoopConfig
|
|
|
13
16
|
import rtctools_interface.closed_loop.optimization_ranges as opt_ranges
|
|
14
17
|
from rtctools_interface.closed_loop.results_construction import combine_csv_exports, combine_xml_exports
|
|
15
18
|
from rtctools_interface.closed_loop.time_series_handler import XMLTimeSeriesFile, CSVTimeSeriesFile, TimeSeriesHandler
|
|
16
|
-
import logging
|
|
17
19
|
|
|
18
20
|
logger = logging.getLogger("rtctools")
|
|
19
21
|
|
|
@@ -61,9 +63,7 @@ def _get_optimization_ranges(
|
|
|
61
63
|
"""Return a list of optimization periods."""
|
|
62
64
|
if config.file is not None:
|
|
63
65
|
datetime_range = input_timeseries.get_datetime_range()
|
|
64
|
-
optimization_ranges = opt_ranges.get_optimization_ranges_from_file(
|
|
65
|
-
config.file, datetime_range
|
|
66
|
-
)
|
|
66
|
+
optimization_ranges = opt_ranges.get_optimization_ranges_from_file(config.file, datetime_range)
|
|
67
67
|
elif config.optimization_period is not None:
|
|
68
68
|
datetimes = input_timeseries.get_datetimes()
|
|
69
69
|
optimization_ranges = opt_ranges.get_optimization_ranges(
|
|
@@ -73,9 +73,7 @@ def _get_optimization_ranges(
|
|
|
73
73
|
optimization_period=config.optimization_period,
|
|
74
74
|
)
|
|
75
75
|
else:
|
|
76
|
-
raise ValueError(
|
|
77
|
-
"The closed-loop configuration should have either a file or optimization_period set."
|
|
78
|
-
)
|
|
76
|
+
raise ValueError("The closed-loop configuration should have either a file or optimization_period set.")
|
|
79
77
|
if config.round_to_dates:
|
|
80
78
|
optimization_ranges = opt_ranges.round_datetime_ranges_to_days(optimization_ranges)
|
|
81
79
|
return optimization_ranges
|
|
@@ -86,9 +84,10 @@ def run_optimization_problem_closed_loop(
|
|
|
86
84
|
base_folder="..",
|
|
87
85
|
log_level=logging.INFO,
|
|
88
86
|
profile=False,
|
|
89
|
-
config: ClosedLoopConfig = None,
|
|
87
|
+
config: Optional[ClosedLoopConfig] = None,
|
|
88
|
+
modelling_period_input_folder: Optional[str] = None,
|
|
90
89
|
**kwargs,
|
|
91
|
-
):
|
|
90
|
+
) -> dict:
|
|
92
91
|
"""
|
|
93
92
|
Runs an optimization problem in closed loop mode.
|
|
94
93
|
|
|
@@ -126,7 +125,19 @@ def run_optimization_problem_closed_loop(
|
|
|
126
125
|
|
|
127
126
|
variables_in_import = original_import.get_all_internal_ids()
|
|
128
127
|
|
|
129
|
-
|
|
128
|
+
fixed_input_config_file = (original_input_folder / "fixed_inputs.json").resolve()
|
|
129
|
+
if not fixed_input_config_file.exists():
|
|
130
|
+
raise FileNotFoundError(
|
|
131
|
+
f"Could not find fixed inputs configuration file: {fixed_input_config_file}"
|
|
132
|
+
"Create a file with a list of strings that represent the fixed inputs (can be an empty list)."
|
|
133
|
+
)
|
|
134
|
+
with open(fixed_input_config_file, "r") as file:
|
|
135
|
+
fixed_input_series = json.load(file)
|
|
136
|
+
if not isinstance(fixed_input_series, list) and all(isinstance(item, str) for item in fixed_input_series):
|
|
137
|
+
raise ValueError("Fixed input config file should be a list of strings (or an empty list).")
|
|
138
|
+
|
|
139
|
+
if modelling_period_input_folder is None:
|
|
140
|
+
modelling_period_input_folder = base_folder / "input_modelling_periods"
|
|
130
141
|
if modelling_period_input_folder.exists():
|
|
131
142
|
shutil.rmtree(modelling_period_input_folder)
|
|
132
143
|
modelling_period_input_folder.mkdir(exist_ok=True)
|
|
@@ -154,7 +165,7 @@ def run_optimization_problem_closed_loop(
|
|
|
154
165
|
modelling_period_input_folder_i = modelling_period_input_folder / modelling_period_name
|
|
155
166
|
write_input_folder(modelling_period_input_folder_i, original_input_folder, timeseries_import)
|
|
156
167
|
|
|
157
|
-
logger.info(f"
|
|
168
|
+
logger.info(f"Running optimization for period {i}: {(str(start_time), str(end_time))}.")
|
|
158
169
|
result = run_optimization_problem(
|
|
159
170
|
optimization_problem_class,
|
|
160
171
|
base_folder,
|
|
@@ -164,14 +175,18 @@ def run_optimization_problem_closed_loop(
|
|
|
164
175
|
output_folder=modelling_period_output_folder_i,
|
|
165
176
|
**kwargs,
|
|
166
177
|
)
|
|
167
|
-
|
|
178
|
+
period = f"period {i} {(str(start_time), str(end_time))}"
|
|
179
|
+
if result.solver_stats["success"]:
|
|
180
|
+
logger.info(f"Successful optimization for {period}.")
|
|
181
|
+
else:
|
|
182
|
+
message = f"Failed optimization for {period} with status '{result.solver_stats['return_status']}'."
|
|
183
|
+
logger.error(message)
|
|
184
|
+
raise Exception(message)
|
|
168
185
|
|
|
169
|
-
results_previous_run = {
|
|
186
|
+
results_previous_run = {
|
|
187
|
+
key: result.extract_results().get(key) for key in variables_in_import if key not in fixed_input_series
|
|
188
|
+
}
|
|
170
189
|
previous_run_datetimes = result.io.datetimes
|
|
171
|
-
if len(results_previous_run) != len(variables_in_import):
|
|
172
|
-
logger.warning("Could not find the results for all input variables.")
|
|
173
|
-
logger.warning("Missing variables: " + str(set(variables_in_import) - set(results_previous_run.keys())))
|
|
174
|
-
raise ValueError("Could not find the results for all input variables.")
|
|
175
190
|
|
|
176
191
|
logger.info("Finished all optimization runs.")
|
|
177
192
|
if issubclass(optimization_problem_class, PIMixin):
|
|
@@ -182,3 +197,4 @@ def run_optimization_problem_closed_loop(
|
|
|
182
197
|
logger.warning(
|
|
183
198
|
"Could not combine exports because the optimization problem class is not derived from PIMixin or CSVMixin."
|
|
184
199
|
)
|
|
200
|
+
return result.solver_stats
|
|
@@ -170,6 +170,11 @@ class XMLTimeSeriesFile(TimeSeriesHandler):
|
|
|
170
170
|
self.pi_timeseries = None
|
|
171
171
|
self.read(timeseries_import_basename)
|
|
172
172
|
|
|
173
|
+
if self.get_datetime_range()[0] < self.forecast_date:
|
|
174
|
+
logger.warning("Currently, the closed loop runner does support data before the forecast date.")
|
|
175
|
+
logger.warning("Removing data before forecast date.")
|
|
176
|
+
self.select_time_range(self.forecast_date, self.pi_timeseries.times[-1])
|
|
177
|
+
|
|
173
178
|
def read(self, file_name: str):
|
|
174
179
|
"""Read the timeseries data from a file."""
|
|
175
180
|
timeseries_import_basename = file_name
|
|
@@ -215,6 +220,8 @@ class XMLTimeSeriesFile(TimeSeriesHandler):
|
|
|
215
220
|
self.forecast_date = times[i_start]
|
|
216
221
|
|
|
217
222
|
def write(self, file_path: Path, file_name: str = "timeseries_import"):
|
|
223
|
+
# By setting make_new_file headers will be recreated, neceesary for writing new forecast date
|
|
224
|
+
self.pi_timeseries.make_new_file = True
|
|
218
225
|
self.pi_timeseries.write(output_folder=file_path, output_filename=file_name)
|
|
219
226
|
|
|
220
227
|
def get_datetimes(self):
|
|
@@ -39,6 +39,16 @@ class PlotMixin(PlottingBaseMixin):
|
|
|
39
39
|
"""Tasks after optimizing."""
|
|
40
40
|
super().post()
|
|
41
41
|
|
|
42
|
+
# find empty arrays in self._manual_extracted_states
|
|
43
|
+
# for these variables try to use self.get_timeseries(variable)
|
|
44
|
+
for variable in self.custom_variables:
|
|
45
|
+
if not self._manual_extracted_states[variable] or len(self._manual_extracted_states[variable]) == 0:
|
|
46
|
+
logger.debug(f"Variable {variable} has empty data collected.")
|
|
47
|
+
try:
|
|
48
|
+
self._manual_extracted_states[variable] = self.get_timeseries(variable)
|
|
49
|
+
except KeyError:
|
|
50
|
+
logger.warning(f"Variable {variable} not found in output of model.")
|
|
51
|
+
|
|
42
52
|
timeseries_data = self.collect_timeseries_data(self.custom_variables)
|
|
43
53
|
self._intermediate_results.append({"timeseries_data": timeseries_data, "priority": 0})
|
|
44
54
|
current_run = self.create_plot_data_and_config([])
|
|
@@ -20,7 +20,7 @@ R_TOL = 0.1
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def compare_xml_file(file_result: Path, file_ref: Path):
|
|
23
|
-
"""Compare two timeseries_export files elementwise."""
|
|
23
|
+
"""Compare two timeseries_export files elementwise."""
|
|
24
24
|
tree_result = ET.parse(file_result)
|
|
25
25
|
tree_ref = ET.parse(file_ref)
|
|
26
26
|
series_result = tree_result.findall("pi:series", ns)
|
|
@@ -142,39 +142,90 @@ class TestClosedLoop(TestCase):
|
|
|
142
142
|
"""
|
|
143
143
|
Check if test model runs without problems and generates same results.
|
|
144
144
|
"""
|
|
145
|
+
test_cases = [
|
|
146
|
+
{
|
|
147
|
+
"description": "without forecast date",
|
|
148
|
+
"input_folder": "input",
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"description": "with forecast date unequal to first date",
|
|
152
|
+
"input_folder": "input_with_forecast_date",
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"description": "with forecast date equal to first date",
|
|
156
|
+
"input_folder": "input_with_forecast_date_equal_first_date",
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
|
|
145
160
|
base_folder = Path(__file__).parent / "test_models" / "goal_programming_xml"
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
161
|
+
|
|
162
|
+
for case in test_cases:
|
|
163
|
+
with self.subTest(case["description"]):
|
|
164
|
+
config = ClosedLoopConfig(
|
|
165
|
+
file=base_folder / case["input_folder"] / "closed_loop_dates.csv",
|
|
166
|
+
round_to_dates=True
|
|
167
|
+
)
|
|
168
|
+
run_optimization_problem_closed_loop(
|
|
169
|
+
ExampleXml,
|
|
170
|
+
base_folder=base_folder,
|
|
171
|
+
config=config,
|
|
172
|
+
input_folder=case["input_folder"]
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
self.compare_xml_files(
|
|
176
|
+
output_folder=base_folder / "output" / "output_modelling_periods",
|
|
177
|
+
reference_folder=base_folder / "output" / "output_modelling_periods_reference",
|
|
178
|
+
n_periods=3
|
|
179
|
+
)
|
|
180
|
+
self.compare_xml_file(
|
|
181
|
+
output_file=base_folder / "output" / "timeseries_export.xml",
|
|
182
|
+
reference_file=base_folder / "output" / "timeseries_export_reference.xml"
|
|
183
|
+
)
|
|
160
184
|
|
|
161
185
|
def test_running_closed_loop_xml_fixed_periods(self):
|
|
162
186
|
"""
|
|
163
187
|
Check if test model runs for fixed optimization periods.
|
|
164
188
|
"""
|
|
189
|
+
test_cases = [
|
|
190
|
+
{
|
|
191
|
+
"description": "without forecast date",
|
|
192
|
+
"output_folder": "output_fixed_periods",
|
|
193
|
+
"input_folder": "input",
|
|
194
|
+
"optimization_period": timedelta(days=3),
|
|
195
|
+
"forecast_timestep": timedelta(days=2)
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"description": "with forecast date unequal to first date",
|
|
199
|
+
"output_folder": "output_fixed_periods",
|
|
200
|
+
"input_folder": "input_with_forecast_date",
|
|
201
|
+
"optimization_period": timedelta(days=3),
|
|
202
|
+
"forecast_timestep": timedelta(days=2)
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"description": "with forecast date equal to first date",
|
|
206
|
+
"output_folder": "output_fixed_periods",
|
|
207
|
+
"input_folder": "input_with_forecast_date_equal_first_date",
|
|
208
|
+
"optimization_period": timedelta(days=3),
|
|
209
|
+
"forecast_timestep": timedelta(days=2)
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
|
|
165
213
|
base_folder = Path(__file__).parent / "test_models" / "goal_programming_xml"
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
214
|
+
|
|
215
|
+
for case in test_cases:
|
|
216
|
+
with self.subTest(case["description"]):
|
|
217
|
+
config = ClosedLoopConfig.from_fixed_periods(
|
|
218
|
+
optimization_period=case["optimization_period"],
|
|
219
|
+
forecast_timestep=case["forecast_timestep"]
|
|
220
|
+
)
|
|
221
|
+
run_optimization_problem_closed_loop(
|
|
222
|
+
ExampleXml,
|
|
223
|
+
base_folder=base_folder,
|
|
224
|
+
config=config,
|
|
225
|
+
output_folder=case["output_folder"],
|
|
226
|
+
input_folder=case["input_folder"]
|
|
227
|
+
)
|
|
228
|
+
self.compare_xml_file(
|
|
229
|
+
output_file=base_folder / case["output_folder"] / "timeseries_export.xml",
|
|
230
|
+
reference_file=base_folder / "output" / "timeseries_export_reference.xml"
|
|
231
|
+
)
|
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtc_tools_interface.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/plotting/__init__.py
RENAMED
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/plotting/plot_tools.py
RENAMED
|
File without changes
|
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/simulation/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/rtctools_interface/utils/serialization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/closed_loop/test_read_xml.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/optimization/test_read_goals.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rtc-tools-interface-0.9.0a2 → rtc-tools-interface-0.10.1}/tests/simulation/test_plot_mixin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|