rtc-tools-interface 0.7.0b1__tar.gz → 0.7.0b3__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.7.0b1 → rtc-tools-interface-0.7.0b3}/PKG-INFO +1 -1
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/README.md +16 -12
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/PKG-INFO +1 -1
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/SOURCES.txt +13 -9
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/_version.py +3 -3
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/base_goal.py +1 -1
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/goal_generator_mixin.py +6 -16
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/goal_performance_metrics.py +1 -1
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/helpers/statistics_mixin.py +1 -1
- rtc-tools-interface-0.7.0b3/rtctools_interface/optimization/plot_goals_mixin.py +14 -0
- rtc-tools-interface-0.7.0b3/rtctools_interface/optimization/plot_mixin.py +46 -0
- rtc-tools-interface-0.7.0b3/rtctools_interface/utils/read_goals_mixin.py +31 -0
- {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/read_plot_table.py +3 -3
- rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/plot_goals_mixin.py → rtc-tools-interface-0.7.0b3/rtctools_interface/utils/results_collection.py +72 -82
- {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/helpers → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/serialization.py +1 -1
- {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/type_definitions.py +1 -1
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/tests/optimization/test_base_optimization_problem.py +2 -2
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/tests/optimization/test_passing_goals_directly.py +2 -2
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/tests/optimization/test_plot_goals_mixin.py +5 -5
- rtc-tools-interface-0.7.0b3/tests/simulation/test_base_simulation_problem.py +27 -0
- rtc-tools-interface-0.7.0b3/tests/simulation/test_plot_mixin.py +54 -0
- rtc-tools-interface-0.7.0b3/tests/utils/__init__.py +0 -0
- {rtc-tools-interface-0.7.0b1/tests/optimization → rtc-tools-interface-0.7.0b3/tests/utils}/get_test.py +9 -6
- rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/plotting/plot_tools.py +0 -306
- rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/plotting/subplot_classes.py +0 -302
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/COPYING.LESSER +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/dependency_links.txt +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/requires.txt +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/top_level.txt +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/__init__.py +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/__init__.py +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/base_optimization_problem.py +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/goal_table_schema.py +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/helpers/__init__.py +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/read_goals.py +0 -0
- {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/plotting → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/__init__.py +0 -0
- {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/plot_table_schema.py +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/setup.cfg +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/setup.py +0 -0
- {rtc-tools-interface-0.7.0b1/rtctools_interface/utils → rtc-tools-interface-0.7.0b3/tests}/__init__.py +0 -0
- {rtc-tools-interface-0.7.0b1/tests → rtc-tools-interface-0.7.0b3/tests/optimization}/__init__.py +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/tests/optimization/test_read_goals.py +0 -0
- {rtc-tools-interface-0.7.0b1/tests/optimization → rtc-tools-interface-0.7.0b3/tests/simulation}/__init__.py +0 -0
- {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/versioneer.py +0 -0
|
@@ -110,28 +110,32 @@ The calculated metrics are:
|
|
|
110
110
|
|
|
111
111
|
|
|
112
112
|
## Automatic plotting of results
|
|
113
|
-
With the `
|
|
113
|
+
With the `PlotMixin` one can easily make plots of the results of rtc-tools. This functionality can be used both for optimization and simulation problems. For optimization problems, use:
|
|
114
114
|
```python
|
|
115
|
-
from rtctools_interface.optimization.
|
|
115
|
+
from rtctools_interface.optimization.plot_mixin import PlotMixin
|
|
116
116
|
```
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
and for simulation problems use:
|
|
118
|
+
```python
|
|
119
|
+
from rtctools_interface.simulation.plot_mixin import PlotMixin
|
|
120
|
+
```
|
|
121
|
+
Then, add the `PlotMixin` to your optimization/simulation problem class. For optimization problems, the PlotMixin can create a plot after each priority and/or a plot with the final results only.
|
|
122
|
+
By default, the `PlotMixin` will make both. This can be changed by setting the class variables `plot_results_each_priority` and `plot_final_results` to either `True` or `False` in your problem class.
|
|
119
123
|
|
|
120
|
-
Furthermore, the
|
|
124
|
+
Furthermore, the PlotMixin can either create `Plotly` plots and `matplotlib` plots. The `matplotlib` plots will be exported as `png`, the Plotly figures as `html`. By default, `Plotly` is used. To change this, pass the keyword-argument `plotting_library="matplotlib"` to the `run_optimization_problem` function.
|
|
121
125
|
|
|
122
126
|
### Comparing results from different runs
|
|
123
|
-
-
|
|
124
|
-
- The `final_results` plot will show the result from the **previous
|
|
127
|
+
- In optimization mode, the plots for a particular priority will contain line segments with the results from the previous priority result. This makes it easy to see what changed from priority to priority.
|
|
128
|
+
- The `final_results` plot will show the result from the **previous run**. This allows for comparing results from different scenario's (like input timeseries or changes to the model). Note that is not possible to change the number of goals between two comparison runs. This feature currently only works with Plotly plots, where a dropdown is available to hide the previous results.
|
|
125
129
|
### Configuration variables
|
|
126
|
-
The following class variables can be set to change the behaviour of the
|
|
130
|
+
The following class variables can be set to change the behaviour of the PlotMixin:
|
|
127
131
|
- `plot_max_rows`: an integer number for the maximum number of rows (default is 4). The number of columns will be derived from that.
|
|
128
|
-
- `plot_results_each_priority`: boolean indicating whether the plots for each priority should be generated and saved. Default is True.
|
|
132
|
+
- `plot_results_each_priority`: Only for optimization: boolean indicating whether the plots for each priority should be generated and saved. Default is True.
|
|
129
133
|
- `plot_table_file`: path to plot table csv file. Default is `input\plot_table.csv`.
|
|
130
134
|
|
|
131
135
|
### Specifying the plot table
|
|
132
|
-
There are two types of plots that can be made with the
|
|
133
|
-
1. Plots
|
|
134
|
-
2. Plots
|
|
136
|
+
There are two types of plots that can be made with the PlotMixin
|
|
137
|
+
1. Plots of arbitrary states, for example ones being optimized in a goal defined in Python.
|
|
138
|
+
2. Plots based on goals in the goal_generator table (only applicable to optimization problems).
|
|
135
139
|
|
|
136
140
|
To add a plot for a goal in the `goal_generator` table, one should add a row to the `plot_table` with an `id` equal to the id of the goal in the `goal_generator` to be plotted. The `specified_in` field should be set to `goal_generator`. Rows of the `plot_table` with `specified_in`=`goal_generator` but with an `id` that does not occcur in the `goal_table`, are ignored.
|
|
137
141
|
|
{rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/SOURCES.txt
RENAMED
|
@@ -17,21 +17,25 @@ rtctools_interface/optimization/goal_generator_mixin.py
|
|
|
17
17
|
rtctools_interface/optimization/goal_performance_metrics.py
|
|
18
18
|
rtctools_interface/optimization/goal_table_schema.py
|
|
19
19
|
rtctools_interface/optimization/plot_goals_mixin.py
|
|
20
|
-
rtctools_interface/optimization/
|
|
20
|
+
rtctools_interface/optimization/plot_mixin.py
|
|
21
21
|
rtctools_interface/optimization/read_goals.py
|
|
22
|
-
rtctools_interface/optimization/read_plot_table.py
|
|
23
|
-
rtctools_interface/optimization/type_definitions.py
|
|
24
22
|
rtctools_interface/optimization/helpers/__init__.py
|
|
25
|
-
rtctools_interface/optimization/helpers/serialization.py
|
|
26
23
|
rtctools_interface/optimization/helpers/statistics_mixin.py
|
|
27
|
-
rtctools_interface/optimization/plotting/__init__.py
|
|
28
|
-
rtctools_interface/optimization/plotting/plot_tools.py
|
|
29
|
-
rtctools_interface/optimization/plotting/subplot_classes.py
|
|
30
24
|
rtctools_interface/utils/__init__.py
|
|
25
|
+
rtctools_interface/utils/plot_table_schema.py
|
|
26
|
+
rtctools_interface/utils/read_goals_mixin.py
|
|
27
|
+
rtctools_interface/utils/read_plot_table.py
|
|
28
|
+
rtctools_interface/utils/results_collection.py
|
|
29
|
+
rtctools_interface/utils/serialization.py
|
|
30
|
+
rtctools_interface/utils/type_definitions.py
|
|
31
31
|
tests/__init__.py
|
|
32
32
|
tests/optimization/__init__.py
|
|
33
|
-
tests/optimization/get_test.py
|
|
34
33
|
tests/optimization/test_base_optimization_problem.py
|
|
35
34
|
tests/optimization/test_passing_goals_directly.py
|
|
36
35
|
tests/optimization/test_plot_goals_mixin.py
|
|
37
|
-
tests/optimization/test_read_goals.py
|
|
36
|
+
tests/optimization/test_read_goals.py
|
|
37
|
+
tests/simulation/__init__.py
|
|
38
|
+
tests/simulation/test_base_simulation_problem.py
|
|
39
|
+
tests/simulation/test_plot_mixin.py
|
|
40
|
+
tests/utils/__init__.py
|
|
41
|
+
tests/utils/get_test.py
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2023-11-
|
|
11
|
+
"date": "2023-11-28T16:07:57+0000",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.7.
|
|
14
|
+
"full-revisionid": "499d6e416027fec2a9b6dd1cc4d7249b30a41463",
|
|
15
|
+
"version": "0.7.0b3"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -8,7 +8,7 @@ from rtctools.optimization.optimization_problem import OptimizationProblem
|
|
|
8
8
|
from rtctools.optimization.timeseries import Timeseries
|
|
9
9
|
|
|
10
10
|
from rtctools_interface.optimization.goal_table_schema import GOAL_TYPES, TARGET_DATA_TYPES
|
|
11
|
-
from rtctools_interface.
|
|
11
|
+
from rtctools_interface.utils.type_definitions import GoalConfig
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
logger = logging.getLogger("rtctools")
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import Dict, Union
|
|
4
4
|
import logging
|
|
5
|
-
import os
|
|
6
5
|
import pandas as pd
|
|
7
6
|
|
|
8
7
|
from rtctools_interface.optimization.base_goal import BaseGoal
|
|
9
8
|
from rtctools_interface.optimization.goal_performance_metrics import get_performance_metrics
|
|
10
9
|
from rtctools_interface.optimization.helpers.statistics_mixin import StatisticsMixin
|
|
11
|
-
from rtctools_interface.
|
|
10
|
+
from rtctools_interface.utils.read_goals_mixin import ReadGoalsMixin
|
|
12
11
|
|
|
13
12
|
logger = logging.getLogger("rtctools")
|
|
14
13
|
|
|
@@ -21,7 +20,7 @@ def write_performance_metrics(performance_metrics: Dict[str, pd.DataFrame], outp
|
|
|
21
20
|
performance_metric_table.to_csv(output_path / f"{goal_id}.csv")
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
class GoalGeneratorMixin(StatisticsMixin):
|
|
23
|
+
class GoalGeneratorMixin(ReadGoalsMixin, StatisticsMixin):
|
|
25
24
|
# TODO: remove pylint disable below once we have more public functions.
|
|
26
25
|
# pylint: disable=too-few-public-methods
|
|
27
26
|
"""Add path goals as specified in the goal_table.
|
|
@@ -34,19 +33,10 @@ class GoalGeneratorMixin(StatisticsMixin):
|
|
|
34
33
|
|
|
35
34
|
def __init__(self, **kwargs):
|
|
36
35
|
super().__init__(**kwargs)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
self.
|
|
41
|
-
|
|
42
|
-
self._goal_generator_path_goals = read_goals(
|
|
43
|
-
self.goal_table_file, path_goal=True, read_from=self.read_from, goals_to_generate=self.goals_to_generate
|
|
44
|
-
)
|
|
45
|
-
self._goal_generator_non_path_goals = read_goals(
|
|
46
|
-
self.goal_table_file, path_goal=False, read_from=self.read_from, goals_to_generate=self.goals_to_generate
|
|
47
|
-
)
|
|
48
|
-
self._all_goal_generator_goals = self._goal_generator_path_goals + self._goal_generator_non_path_goals
|
|
49
|
-
|
|
36
|
+
if not hasattr(self, "_all_goal_generator_goals"):
|
|
37
|
+
goals_to_generate = kwargs.get("goals_to_generate", [])
|
|
38
|
+
read_from = kwargs.get("read_goals_from", "csv_table")
|
|
39
|
+
self.load_goals(read_from, goals_to_generate)
|
|
50
40
|
if self.calculate_performance_metrics:
|
|
51
41
|
# A dataframe for each goal defined by the goal generator
|
|
52
42
|
self._performance_metrics = {}
|
|
@@ -12,7 +12,7 @@ from rtctools_interface.optimization.goal_table_schema import (
|
|
|
12
12
|
RangeGoalModel,
|
|
13
13
|
RangeRateOfChangeGoalModel,
|
|
14
14
|
)
|
|
15
|
-
from rtctools_interface.
|
|
15
|
+
from rtctools_interface.utils.type_definitions import TargetDict
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
logger = logging.getLogger("rtctools")
|
|
@@ -5,7 +5,7 @@ from typing import Dict, List, Tuple
|
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
from rtctools_interface.optimization.base_goal import BaseGoal
|
|
8
|
-
from rtctools_interface.
|
|
8
|
+
from rtctools_interface.utils.type_definitions import TargetDict
|
|
9
9
|
|
|
10
10
|
logger = logging.getLogger("rtctools")
|
|
11
11
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Deprecated, use PlotMixin."""
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
from rtctools_interface.optimization.plot_mixin import PlotMixin
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PlotGoalsMixin(PlotMixin):
|
|
8
|
+
"""
|
|
9
|
+
Deprecated class, use PlotMixin instead.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, *args, **kwargs):
|
|
13
|
+
warnings.warn("PlotGoalsMixin is deprecated, use PlotMixin instead", FutureWarning, stacklevel=1)
|
|
14
|
+
super().__init__(*args, **kwargs)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Mixin to store all required data for plotting. Can also call the plot function."""
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from rtctools_interface.optimization.helpers.statistics_mixin import StatisticsMixin
|
|
5
|
+
from rtctools_interface.plotting.plot_tools import create_plot_each_priority, create_plot_final_results
|
|
6
|
+
from rtctools_interface.optimization.base_goal import BaseGoal
|
|
7
|
+
from rtctools_interface.utils.results_collection import PlottingBaseMixin
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger("rtctools")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PlotMixin(PlottingBaseMixin, StatisticsMixin):
|
|
13
|
+
"""
|
|
14
|
+
Class for plotting results.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
optimization_problem = True
|
|
18
|
+
|
|
19
|
+
def priority_completed(self, priority: int) -> None:
|
|
20
|
+
"""Store priority-dependent results required for plotting."""
|
|
21
|
+
timeseries_data = self.collect_timeseries_data(list(set(self.custom_variables + self.state_variables)))
|
|
22
|
+
to_store = {"timeseries_data": timeseries_data, "priority": priority}
|
|
23
|
+
self.intermediate_results.append(to_store)
|
|
24
|
+
super().priority_completed(priority)
|
|
25
|
+
|
|
26
|
+
def post(self):
|
|
27
|
+
"""Tasks after optimizing. Creates a plot for for each priority."""
|
|
28
|
+
super().post()
|
|
29
|
+
|
|
30
|
+
if self.solver_stats["success"]:
|
|
31
|
+
base_goals = [
|
|
32
|
+
goal.get_goal_config() for goal in self.goals() + self.path_goals() if isinstance(goal, BaseGoal)
|
|
33
|
+
]
|
|
34
|
+
current_run = self.create_plot_data_and_config(base_goals)
|
|
35
|
+
# Cache results, such that in a next run they can be used for comparison
|
|
36
|
+
self._store_current_results(self._cache_folder, current_run)
|
|
37
|
+
|
|
38
|
+
# Create the plots
|
|
39
|
+
plot_data = {}
|
|
40
|
+
if self.plot_results_each_priority:
|
|
41
|
+
plot_data = plot_data | create_plot_each_priority(current_run, plotting_library=self.plotting_library)
|
|
42
|
+
|
|
43
|
+
if self.plot_final_results:
|
|
44
|
+
plot_data = plot_data | create_plot_final_results(
|
|
45
|
+
current_run, self._previous_run, plotting_library=self.plotting_library
|
|
46
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Mixin to read the goal table and store as class variables."""
|
|
2
|
+
import os
|
|
3
|
+
from typing import Literal, Optional
|
|
4
|
+
|
|
5
|
+
from rtctools_interface.optimization.read_goals import read_goals
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ReadGoalsMixin:
|
|
9
|
+
"""Read the goal table either from the default or specified path."""
|
|
10
|
+
|
|
11
|
+
def load_goals(
|
|
12
|
+
self, read_from: Literal["csv_table", "passed_list"] = "csv_table", goals_to_generate: Optional[list] = None
|
|
13
|
+
):
|
|
14
|
+
"""Read goal table and store as instance variable."""
|
|
15
|
+
goals_to_generate = goals_to_generate if goals_to_generate else []
|
|
16
|
+
if not hasattr(self, "goal_table_file"):
|
|
17
|
+
self.goal_table_file = os.path.join(self._input_folder, "goal_table.csv")
|
|
18
|
+
|
|
19
|
+
if read_from == "csv_table" and os.path.isfile(self.goal_table_file) or read_from == "passed_list":
|
|
20
|
+
self._goal_generator_path_goals = read_goals(
|
|
21
|
+
self.goal_table_file, path_goal=True, read_from=read_from, goals_to_generate=goals_to_generate
|
|
22
|
+
)
|
|
23
|
+
self._goal_generator_non_path_goals = read_goals(
|
|
24
|
+
self.goal_table_file,
|
|
25
|
+
path_goal=False,
|
|
26
|
+
read_from=read_from,
|
|
27
|
+
goals_to_generate=goals_to_generate,
|
|
28
|
+
)
|
|
29
|
+
self._all_goal_generator_goals = self._goal_generator_path_goals + self._goal_generator_non_path_goals
|
|
30
|
+
else:
|
|
31
|
+
self._all_goal_generator_goals = []
|
|
@@ -4,7 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
from typing import List, Union
|
|
5
5
|
import pandas as pd
|
|
6
6
|
|
|
7
|
-
from rtctools_interface.
|
|
7
|
+
from rtctools_interface.utils.plot_table_schema import PlotTableRow
|
|
8
8
|
|
|
9
9
|
logger = logging.getLogger("rtctools")
|
|
10
10
|
|
|
@@ -23,7 +23,7 @@ def read_plot_config_from_csv(plot_table_file: Union[Path, str]) -> List[PlotTab
|
|
|
23
23
|
return parsed_rows
|
|
24
24
|
message = (
|
|
25
25
|
f"No plot table was found at the default location ({plot_table_file.resolve()})."
|
|
26
|
-
+ " Please create one before using the
|
|
26
|
+
+ " Please create one before using the PlotMixin."
|
|
27
27
|
+ f" It should have the following columns: '{list(PlotTableRow.model_fields.keys())}'"
|
|
28
28
|
)
|
|
29
29
|
raise FileNotFoundError(message)
|
|
@@ -45,4 +45,4 @@ def get_plot_config(plot_table_file=None, plot_config_list=None, read_from="csv_
|
|
|
45
45
|
return read_plot_config_from_csv(plot_table_file)
|
|
46
46
|
if read_from == "passed_list":
|
|
47
47
|
return read_plot_config_from_list(plot_config_list)
|
|
48
|
-
raise ValueError("
|
|
48
|
+
raise ValueError("PlotMixin should either read from 'csv_table' or 'passed_list'")
|
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
"""Mixin to store all required data for plotting.
|
|
1
|
+
"""Mixin to store all required data for plotting."""
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import copy
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
import time
|
|
7
|
-
from typing import Optional
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from rtctools_interface.
|
|
11
|
-
from rtctools_interface.
|
|
12
|
-
|
|
13
|
-
from rtctools_interface.
|
|
14
|
-
from rtctools_interface.
|
|
7
|
+
from typing import Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from rtctools_interface.utils.plot_table_schema import PlotTableRow
|
|
11
|
+
from rtctools_interface.utils.read_goals_mixin import ReadGoalsMixin
|
|
12
|
+
|
|
13
|
+
from rtctools_interface.utils.serialization import deserialize, serialize
|
|
14
|
+
from rtctools_interface.utils.read_plot_table import get_plot_config
|
|
15
|
+
from rtctools_interface.utils.type_definitions import (
|
|
15
16
|
PlotDataAndConfig,
|
|
16
17
|
PlotOptions,
|
|
17
18
|
PrioIndependentData,
|
|
18
19
|
)
|
|
19
20
|
|
|
20
|
-
logger = logging.getLogger("rtctools")
|
|
21
|
-
|
|
22
21
|
MAX_NUM_CACHED_FILES = 5
|
|
23
22
|
CONFIG_VERSION: float = 1.0
|
|
24
23
|
|
|
24
|
+
logger = logging.getLogger("rtctools")
|
|
25
|
+
|
|
25
26
|
|
|
26
27
|
def get_most_recent_cache(cache_folder):
|
|
27
28
|
"""Get the most recent pickle file, based on its name."""
|
|
@@ -73,10 +74,31 @@ def read_cache_file_from_folder(cache_folder: Path) -> Optional[PlotDataAndConfi
|
|
|
73
74
|
return loaded_data
|
|
74
75
|
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
def get_plot_variables(plot_config: list[PlotTableRow]) -> List[str]:
|
|
78
|
+
"""Get list of variable-names that are in the plot table."""
|
|
79
|
+
variables_style_1 = [var for subplot_config in plot_config for var in subplot_config.variables_style_1]
|
|
80
|
+
variables_style_2 = [var for subplot_config in plot_config for var in subplot_config.variables_style_2]
|
|
81
|
+
variables_with_previous_result = [
|
|
82
|
+
var for subplot_config in plot_config for var in subplot_config.variables_with_previous_result
|
|
83
|
+
]
|
|
84
|
+
return variables_style_1 + variables_style_2 + variables_with_previous_result
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def filter_plot_config(plot_config: list[PlotTableRow], all_goal_generator_goals) -> list[PlotTableRow]:
|
|
88
|
+
""" "Remove PlotTableRows corresponding to non-existing goals in the goal generator."""
|
|
89
|
+
goal_generator_goal_ids = [goal.goal_id for goal in all_goal_generator_goals]
|
|
90
|
+
new_plot_config = [
|
|
91
|
+
plot_table_row
|
|
92
|
+
for plot_table_row in plot_config
|
|
93
|
+
if plot_table_row.id in goal_generator_goal_ids or plot_table_row.specified_in == "python"
|
|
94
|
+
]
|
|
95
|
+
return new_plot_config
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class PlottingBaseMixin(ReadGoalsMixin):
|
|
99
|
+
"""Base class for creating plots.
|
|
100
|
+
|
|
101
|
+
Reads the plot table, if available the goal table, and contains functions to store all required data for plots."""
|
|
80
102
|
|
|
81
103
|
plot_max_rows = 4
|
|
82
104
|
plot_results_each_priority = True
|
|
@@ -94,29 +116,21 @@ class PlotGoalsMixin(StatisticsMixin):
|
|
|
94
116
|
self.plotting_library = kwargs.get("plotting_library", "plotly")
|
|
95
117
|
self.plot_config = get_plot_config(plot_table_file, plot_config_list, read_from)
|
|
96
118
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
self.custom_variables = variables_style_1 + variables_style_2 + variables_with_previous_result
|
|
119
|
+
self.custom_variables = get_plot_variables(self.plot_config)
|
|
120
|
+
|
|
121
|
+
if not hasattr(self, "_all_goal_generator_goals") and self.optimization_problem:
|
|
122
|
+
goals_to_generate = kwargs.get("goals_to_generate", [])
|
|
123
|
+
read_from = kwargs.get("read_goals_from", "csv_table")
|
|
124
|
+
self.load_goals(read_from, goals_to_generate)
|
|
104
125
|
|
|
105
|
-
if
|
|
126
|
+
if self.optimization_problem:
|
|
106
127
|
all_goal_generator_goals = self._all_goal_generator_goals
|
|
107
128
|
self.state_variables = list({base_goal.state for base_goal in all_goal_generator_goals})
|
|
108
129
|
else:
|
|
109
130
|
self.state_variables = []
|
|
110
131
|
all_goal_generator_goals = []
|
|
111
132
|
|
|
112
|
-
|
|
113
|
-
# but that goal is not specified in the goal table.
|
|
114
|
-
goal_generator_goal_ids = [goal.goal_id for goal in all_goal_generator_goals]
|
|
115
|
-
self.plot_config = [
|
|
116
|
-
plot_table_row
|
|
117
|
-
for plot_table_row in self.plot_config
|
|
118
|
-
if plot_table_row.id in goal_generator_goal_ids or plot_table_row.specified_in == "python"
|
|
119
|
-
]
|
|
133
|
+
self.plot_config = filter_plot_config(self.plot_config, all_goal_generator_goals)
|
|
120
134
|
|
|
121
135
|
self._cache_folder = Path(self._output_folder) / "cached_results"
|
|
122
136
|
if "previous_run_plot_config" in kwargs:
|
|
@@ -129,64 +143,40 @@ class PlotGoalsMixin(StatisticsMixin):
|
|
|
129
143
|
super().pre()
|
|
130
144
|
self.intermediate_results = []
|
|
131
145
|
|
|
132
|
-
def
|
|
133
|
-
"""
|
|
146
|
+
def collect_timeseries_data(self, all_variables_to_store: List[str]) -> Dict[str, np.ndarray]:
|
|
147
|
+
"""Collect the timeseries data for a list of variables."""
|
|
134
148
|
extracted_results = copy.deepcopy(self.extract_results())
|
|
135
|
-
|
|
136
|
-
timeseries_to_store = {}
|
|
149
|
+
timeseries_data = {}
|
|
137
150
|
for timeseries_name in all_variables_to_store:
|
|
138
151
|
try:
|
|
139
|
-
|
|
152
|
+
timeseries_data[timeseries_name] = extracted_results[timeseries_name]
|
|
140
153
|
except KeyError:
|
|
141
154
|
try:
|
|
142
|
-
|
|
155
|
+
timeseries_data[timeseries_name] = self.get_timeseries(timeseries_name)
|
|
143
156
|
except KeyError as exc:
|
|
144
157
|
raise KeyError("Cannot find timeseries for %s" % timeseries_name) from exc
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
"save_plot_to": self.save_plot_to,
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
current_run: PlotDataAndConfig = {
|
|
171
|
-
"intermediate_results": self.intermediate_results,
|
|
172
|
-
"plot_options": plot_options,
|
|
173
|
-
"prio_independent_data": prio_independent_data,
|
|
174
|
-
"config_version": CONFIG_VERSION,
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
self.plot_data = {}
|
|
178
|
-
if self.plot_results_each_priority:
|
|
179
|
-
self.plot_data = self.plot_data | create_plot_each_priority(
|
|
180
|
-
current_run, plotting_library=self.plotting_library
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
if self.plot_final_results:
|
|
184
|
-
self.plot_data = self.plot_data | create_plot_final_results(
|
|
185
|
-
current_run, self._previous_run, plotting_library=self.plotting_library
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
# Cache results, such that in a next run they can be used for comparison
|
|
189
|
-
self._store_current_results(self._cache_folder, current_run)
|
|
158
|
+
return timeseries_data
|
|
159
|
+
|
|
160
|
+
def create_plot_data_and_config(self, base_goals: list) -> PlotDataAndConfig:
|
|
161
|
+
"""Create the PlotDataAndConfig dict."""
|
|
162
|
+
prio_independent_data: PrioIndependentData = {
|
|
163
|
+
"io_datetimes": self.io.datetimes,
|
|
164
|
+
"times": self.times(),
|
|
165
|
+
"base_goals": base_goals,
|
|
166
|
+
}
|
|
167
|
+
plot_options: PlotOptions = {
|
|
168
|
+
"plot_config": self.plot_config,
|
|
169
|
+
"plot_max_rows": self.plot_max_rows,
|
|
170
|
+
"output_folder": self._output_folder,
|
|
171
|
+
"save_plot_to": self.save_plot_to,
|
|
172
|
+
}
|
|
173
|
+
plot_data_and_config: PlotDataAndConfig = {
|
|
174
|
+
"intermediate_results": self.intermediate_results,
|
|
175
|
+
"plot_options": plot_options,
|
|
176
|
+
"prio_independent_data": prio_independent_data,
|
|
177
|
+
"config_version": CONFIG_VERSION,
|
|
178
|
+
}
|
|
179
|
+
return plot_data_and_config
|
|
190
180
|
|
|
191
181
|
def _store_current_results(self, cache_folder, results_to_store):
|
|
192
182
|
write_cache_file(cache_folder, results_to_store)
|
|
@@ -4,7 +4,7 @@ import pathlib
|
|
|
4
4
|
from typing import Optional, Tuple, TypedDict, List, Dict, Literal
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
|
-
from rtctools_interface.
|
|
7
|
+
from rtctools_interface.utils.plot_table_schema import PlotTableRow
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class TargetDict(TypedDict):
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
import unittest
|
|
3
3
|
|
|
4
4
|
from rtctools_interface.optimization.base_optimization_problem import BaseOptimizationProblem
|
|
5
|
+
from tests.utils.get_test import get_test_data
|
|
5
6
|
|
|
6
|
-
from .get_test import get_test_data
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class TestBaseOptimizationProblem(unittest.TestCase):
|
|
10
10
|
"""Test for the base optimization problem class."""
|
|
11
11
|
def run_test(self, test):
|
|
12
12
|
"""Solve an optimization problem."""
|
|
13
|
-
test_data = get_test_data(test)
|
|
13
|
+
test_data = get_test_data(test, optimization=True)
|
|
14
14
|
problem = BaseOptimizationProblem(
|
|
15
15
|
goal_table_file=test_data["goals_file"],
|
|
16
16
|
model_folder=test_data["model_folder"],
|
|
@@ -4,7 +4,7 @@ import unittest
|
|
|
4
4
|
from rtctools_interface.optimization.base_optimization_problem import BaseOptimizationProblem
|
|
5
5
|
from rtctools_interface.optimization.read_goals import read_goals_from_csv
|
|
6
6
|
|
|
7
|
-
from .get_test import get_test_data
|
|
7
|
+
from tests.utils.get_test import get_test_data
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class TestPassingGoalsDirectly(unittest.TestCase):
|
|
@@ -12,7 +12,7 @@ class TestPassingGoalsDirectly(unittest.TestCase):
|
|
|
12
12
|
|
|
13
13
|
def run_test(self, test):
|
|
14
14
|
"""Solve an optimization problem."""
|
|
15
|
-
test_data = get_test_data(test)
|
|
15
|
+
test_data = get_test_data(test, optimization=True)
|
|
16
16
|
|
|
17
17
|
goals_to_generate = read_goals_from_csv(test_data["goals_file"])
|
|
18
18
|
problem = BaseOptimizationProblem(
|
|
@@ -4,12 +4,12 @@ import unittest
|
|
|
4
4
|
from rtctools_interface.optimization.base_optimization_problem import (
|
|
5
5
|
BaseOptimizationProblem,
|
|
6
6
|
)
|
|
7
|
-
from rtctools_interface.optimization.
|
|
7
|
+
from rtctools_interface.optimization.plot_mixin import PlotMixin
|
|
8
8
|
|
|
9
|
-
from .get_test import get_test_data
|
|
9
|
+
from tests.utils.get_test import get_test_data
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class BaseOptimizationProblemPlotting(
|
|
12
|
+
class BaseOptimizationProblemPlotting(PlotMixin, BaseOptimizationProblem):
|
|
13
13
|
# Ignore too many ancestors, since the use of mixin classes is how rtc-tools is set up.
|
|
14
14
|
# pylint: disable=too-many-ancestors
|
|
15
15
|
"""Optimization problem with plotting functionalities."""
|
|
@@ -24,12 +24,12 @@ class BaseOptimizationProblemPlotting(PlotGoalsMixin, BaseOptimizationProblem):
|
|
|
24
24
|
super().__init__(goal_table_file=goal_table_file, **kwargs)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class
|
|
27
|
+
class TestPlotMixin(unittest.TestCase):
|
|
28
28
|
"""Test for goal-plotting functionalities."""
|
|
29
29
|
|
|
30
30
|
def run_test(self, test, plotting_library):
|
|
31
31
|
"""Solve an optimization problem."""
|
|
32
|
-
test_data = get_test_data(test)
|
|
32
|
+
test_data = get_test_data(test, optimization=True)
|
|
33
33
|
problem = BaseOptimizationProblemPlotting(
|
|
34
34
|
goal_table_file=test_data["goals_file"],
|
|
35
35
|
plot_table_file=test_data["plot_table_file"],
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Tests for the base simulation problem class."""
|
|
2
|
+
import unittest
|
|
3
|
+
|
|
4
|
+
from rtctools_interface.simulation.base_simulation_problem import BaseSimulationProblem
|
|
5
|
+
|
|
6
|
+
from tests.utils.get_test import get_test_data
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestBasSimulationProblem(unittest.TestCase):
|
|
10
|
+
"""Test for the base simulation problem class."""
|
|
11
|
+
|
|
12
|
+
def run_test(self, test):
|
|
13
|
+
"""Solve an simulation problem."""
|
|
14
|
+
test_data = get_test_data(test, optimization=False)
|
|
15
|
+
problem = BaseSimulationProblem(
|
|
16
|
+
model_folder=test_data["model_folder"],
|
|
17
|
+
model_name=test_data["model_name"],
|
|
18
|
+
input_folder=test_data["model_input_folder"],
|
|
19
|
+
output_folder=test_data["output_folder"],
|
|
20
|
+
)
|
|
21
|
+
problem.simulate()
|
|
22
|
+
|
|
23
|
+
# TODO: use pytest instead to parametrise tests.
|
|
24
|
+
def test_base_simulation_problem(self):
|
|
25
|
+
"""Solve several simulation problems."""
|
|
26
|
+
for test in ["basic"]:
|
|
27
|
+
self.run_test(test)
|