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.
Files changed (44) hide show
  1. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/PKG-INFO +1 -1
  2. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/README.md +16 -12
  3. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/PKG-INFO +1 -1
  4. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/SOURCES.txt +13 -9
  5. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/_version.py +3 -3
  6. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/base_goal.py +1 -1
  7. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/goal_generator_mixin.py +6 -16
  8. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/goal_performance_metrics.py +1 -1
  9. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/helpers/statistics_mixin.py +1 -1
  10. rtc-tools-interface-0.7.0b3/rtctools_interface/optimization/plot_goals_mixin.py +14 -0
  11. rtc-tools-interface-0.7.0b3/rtctools_interface/optimization/plot_mixin.py +46 -0
  12. rtc-tools-interface-0.7.0b3/rtctools_interface/utils/read_goals_mixin.py +31 -0
  13. {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/read_plot_table.py +3 -3
  14. 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
  15. {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/helpers → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/serialization.py +1 -1
  16. {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/type_definitions.py +1 -1
  17. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/tests/optimization/test_base_optimization_problem.py +2 -2
  18. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/tests/optimization/test_passing_goals_directly.py +2 -2
  19. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/tests/optimization/test_plot_goals_mixin.py +5 -5
  20. rtc-tools-interface-0.7.0b3/tests/simulation/test_base_simulation_problem.py +27 -0
  21. rtc-tools-interface-0.7.0b3/tests/simulation/test_plot_mixin.py +54 -0
  22. rtc-tools-interface-0.7.0b3/tests/utils/__init__.py +0 -0
  23. {rtc-tools-interface-0.7.0b1/tests/optimization → rtc-tools-interface-0.7.0b3/tests/utils}/get_test.py +9 -6
  24. rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/plotting/plot_tools.py +0 -306
  25. rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/plotting/subplot_classes.py +0 -302
  26. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/COPYING.LESSER +0 -0
  27. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/dependency_links.txt +0 -0
  28. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/requires.txt +0 -0
  29. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtc_tools_interface.egg-info/top_level.txt +0 -0
  30. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/__init__.py +0 -0
  31. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/__init__.py +0 -0
  32. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/base_optimization_problem.py +0 -0
  33. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/goal_table_schema.py +0 -0
  34. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/helpers/__init__.py +0 -0
  35. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/rtctools_interface/optimization/read_goals.py +0 -0
  36. {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization/plotting → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/__init__.py +0 -0
  37. {rtc-tools-interface-0.7.0b1/rtctools_interface/optimization → rtc-tools-interface-0.7.0b3/rtctools_interface/utils}/plot_table_schema.py +0 -0
  38. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/setup.cfg +0 -0
  39. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/setup.py +0 -0
  40. {rtc-tools-interface-0.7.0b1/rtctools_interface/utils → rtc-tools-interface-0.7.0b3/tests}/__init__.py +0 -0
  41. {rtc-tools-interface-0.7.0b1/tests → rtc-tools-interface-0.7.0b3/tests/optimization}/__init__.py +0 -0
  42. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/tests/optimization/test_read_goals.py +0 -0
  43. {rtc-tools-interface-0.7.0b1/tests/optimization → rtc-tools-interface-0.7.0b3/tests/simulation}/__init__.py +0 -0
  44. {rtc-tools-interface-0.7.0b1 → rtc-tools-interface-0.7.0b3}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rtc-tools-interface
3
- Version: 0.7.0b1
3
+ Version: 0.7.0b3
4
4
  Summary: Toolbox for user interfaces for RTC-Tools
5
5
  Home-page: UNKNOWN
6
6
  Author: Deltares
@@ -110,28 +110,32 @@ The calculated metrics are:
110
110
 
111
111
 
112
112
  ## Automatic plotting of results
113
- With the `PlotGoalsMixin` one can easily make plots of the results of rtc-tools. To utilize this functionality, import the mixin as follows:
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.plot_goals_mixin import PlotGoalsMixin
115
+ from rtctools_interface.optimization.plot_mixin import PlotMixin
116
116
  ```
117
- Then, add the `PlotGoalsMixin` to your optimization problem class. The PlotGoalsMixin can create a plot after each priority and/or a plot with the final results only.
118
- By default, the `PlotGoalsMixin` 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.
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 PlotGoalsMixin 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.
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
- - 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.
124
- - The `final_results` plot will show the result from the **previous optimization run**. This allows for comparing results from different scenario's (like input timeseries or differently parametrized goals). 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.
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 PlotGoalsMixin:
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 PlotGoalsMixin
133
- 1. Plots based on goals in the goal_generator table
134
- 2. Plots of arbitrary states, for example ones being optimized in a goal defined in Python.
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rtc-tools-interface
3
- Version: 0.7.0b1
3
+ Version: 0.7.0b3
4
4
  Summary: Toolbox for user interfaces for RTC-Tools
5
5
  Home-page: UNKNOWN
6
6
  Author: Deltares
@@ -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/plot_table_schema.py
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-21T10:57:38+0000",
11
+ "date": "2023-11-28T16:07:57+0000",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "b8f48b0eb7ffe88f3bf8c0fd75781d0f9661f6e1",
15
- "version": "0.7.0b1"
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.optimization.type_definitions import GoalConfig
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.optimization.read_goals import read_goals
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
- self.goals_to_generate = kwargs.get("goals_to_generate", [])
38
- self.read_from = kwargs.get("read_goals_from", "csv_table")
39
- if not hasattr(self, "goal_table_file"):
40
- self.goal_table_file = os.path.join(self._input_folder, "goal_table.csv")
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.optimization.type_definitions import TargetDict
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.optimization.type_definitions import TargetDict
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.optimization.plot_table_schema import PlotTableRow
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 PlotGoalsMixin."
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("PlotGoalsMixin should either read from 'csv_table' or 'passed_list'")
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. Can also call the plot function."""
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
- from rtctools_interface.optimization.helpers.serialization import deserialize, serialize
10
- from rtctools_interface.optimization.helpers.statistics_mixin import StatisticsMixin
11
- from rtctools_interface.optimization.plotting.plot_tools import create_plot_each_priority, create_plot_final_results
12
- from rtctools_interface.optimization.read_plot_table import get_plot_config
13
- from rtctools_interface.optimization.base_goal import BaseGoal
14
- from rtctools_interface.optimization.type_definitions import (
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
- class PlotGoalsMixin(StatisticsMixin):
77
- """
78
- Class for plotting results.
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
- # Store list of variable-names that may not be present in the results.
98
- variables_style_1 = [var for subplot_config in self.plot_config for var in subplot_config.variables_style_1]
99
- variables_style_2 = [var for subplot_config in self.plot_config for var in subplot_config.variables_style_2]
100
- variables_with_previous_result = [
101
- var for subplot_config in self.plot_config for var in subplot_config.variables_with_previous_result
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 hasattr(self, "_all_goal_generator_goals"):
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
- # Remove PlotTableRows corresponding to a goal in the goal in the goal generator,
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 priority_completed(self, priority: int) -> None:
133
- """Store priority-dependent results required for plotting."""
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
- all_variables_to_store = set(self.custom_variables + self.state_variables)
136
- timeseries_to_store = {}
149
+ timeseries_data = {}
137
150
  for timeseries_name in all_variables_to_store:
138
151
  try:
139
- timeseries_to_store[timeseries_name] = extracted_results[timeseries_name]
152
+ timeseries_data[timeseries_name] = extracted_results[timeseries_name]
140
153
  except KeyError:
141
154
  try:
142
- timeseries_to_store[timeseries_name] = self.get_timeseries(timeseries_name)
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
- to_store = {"timeseries_data": timeseries_to_store, "priority": priority}
147
- self.intermediate_results.append(to_store)
148
- super().priority_completed(priority)
149
-
150
- def post(self):
151
- """Tasks after optimizing. Creates a plot for for each priority."""
152
- super().post()
153
-
154
- if self.solver_stats["success"]:
155
- prio_independent_data: PrioIndependentData = {
156
- "io_datetimes": self.io.datetimes,
157
- "times": self.times(),
158
- "base_goals": [
159
- goal.get_goal_config() for goal in self.goals() + self.path_goals() if isinstance(goal, BaseGoal)
160
- ],
161
- }
162
-
163
- plot_options: PlotOptions = {
164
- "plot_config": self.plot_config,
165
- "plot_max_rows": self.plot_max_rows,
166
- "output_folder": self._output_folder,
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)
@@ -6,7 +6,7 @@ from typing import Any
6
6
 
7
7
  import numpy as np
8
8
  import pandas as pd
9
- from rtctools_interface.optimization.plot_table_schema import PlotTableRow
9
+ from rtctools_interface.utils.plot_table_schema import PlotTableRow
10
10
 
11
11
 
12
12
  def custom_encoder(obj):
@@ -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.optimization.plot_table_schema import PlotTableRow
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.plot_goals_mixin import PlotGoalsMixin
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(PlotGoalsMixin, BaseOptimizationProblem):
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 TestPlotGoalsMixin(unittest.TestCase):
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)