rtc-tools 2.7.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. rtc_tools-2.7.3.dist-info/METADATA +53 -0
  2. rtc_tools-2.7.3.dist-info/RECORD +50 -0
  3. rtc_tools-2.7.3.dist-info/WHEEL +5 -0
  4. rtc_tools-2.7.3.dist-info/entry_points.txt +3 -0
  5. rtc_tools-2.7.3.dist-info/licenses/COPYING.LESSER +165 -0
  6. rtc_tools-2.7.3.dist-info/top_level.txt +1 -0
  7. rtctools/__init__.py +5 -0
  8. rtctools/_internal/__init__.py +0 -0
  9. rtctools/_internal/alias_tools.py +188 -0
  10. rtctools/_internal/caching.py +25 -0
  11. rtctools/_internal/casadi_helpers.py +99 -0
  12. rtctools/_internal/debug_check_helpers.py +41 -0
  13. rtctools/_version.py +21 -0
  14. rtctools/data/__init__.py +4 -0
  15. rtctools/data/csv.py +150 -0
  16. rtctools/data/interpolation/__init__.py +3 -0
  17. rtctools/data/interpolation/bspline.py +31 -0
  18. rtctools/data/interpolation/bspline1d.py +169 -0
  19. rtctools/data/interpolation/bspline2d.py +54 -0
  20. rtctools/data/netcdf.py +467 -0
  21. rtctools/data/pi.py +1236 -0
  22. rtctools/data/rtc.py +228 -0
  23. rtctools/data/storage.py +343 -0
  24. rtctools/optimization/__init__.py +0 -0
  25. rtctools/optimization/collocated_integrated_optimization_problem.py +3208 -0
  26. rtctools/optimization/control_tree_mixin.py +221 -0
  27. rtctools/optimization/csv_lookup_table_mixin.py +462 -0
  28. rtctools/optimization/csv_mixin.py +300 -0
  29. rtctools/optimization/goal_programming_mixin.py +769 -0
  30. rtctools/optimization/goal_programming_mixin_base.py +1094 -0
  31. rtctools/optimization/homotopy_mixin.py +165 -0
  32. rtctools/optimization/initial_state_estimation_mixin.py +89 -0
  33. rtctools/optimization/io_mixin.py +320 -0
  34. rtctools/optimization/linearization_mixin.py +33 -0
  35. rtctools/optimization/linearized_order_goal_programming_mixin.py +235 -0
  36. rtctools/optimization/min_abs_goal_programming_mixin.py +385 -0
  37. rtctools/optimization/modelica_mixin.py +482 -0
  38. rtctools/optimization/netcdf_mixin.py +177 -0
  39. rtctools/optimization/optimization_problem.py +1302 -0
  40. rtctools/optimization/pi_mixin.py +292 -0
  41. rtctools/optimization/planning_mixin.py +19 -0
  42. rtctools/optimization/single_pass_goal_programming_mixin.py +676 -0
  43. rtctools/optimization/timeseries.py +56 -0
  44. rtctools/rtctoolsapp.py +131 -0
  45. rtctools/simulation/__init__.py +0 -0
  46. rtctools/simulation/csv_mixin.py +171 -0
  47. rtctools/simulation/io_mixin.py +195 -0
  48. rtctools/simulation/pi_mixin.py +255 -0
  49. rtctools/simulation/simulation_problem.py +1293 -0
  50. rtctools/util.py +241 -0
rtctools/util.py ADDED
@@ -0,0 +1,241 @@
1
+ import cProfile
2
+ import logging
3
+ import os
4
+ import pstats
5
+ import re
6
+ import sys
7
+
8
+ import casadi
9
+
10
+ from . import __version__
11
+ from ._internal.alias_tools import OrderedSet
12
+ from .data import pi
13
+ from .optimization.csv_mixin import CSVMixin as OptimizationCSVMixin
14
+ from .optimization.io_mixin import IOMixin as OptimizationIOMixin
15
+ from .optimization.pi_mixin import PIMixin as OptimizationPIMixin
16
+ from .simulation.csv_mixin import CSVMixin as SimulationCSVMixin
17
+ from .simulation.io_mixin import IOMixin as SimulationIOMixin
18
+ from .simulation.pi_mixin import PIMixin as SimulationPIMixin
19
+
20
+
21
+ def _resolve_folder(kwargs, base_folder, subfolder_kw, default):
22
+ subfolder = kwargs.pop(subfolder_kw, default)
23
+ if os.path.isabs(subfolder):
24
+ return subfolder
25
+ else:
26
+ return os.path.join(base_folder, subfolder)
27
+
28
+
29
+ def run_optimization_problem(
30
+ optimization_problem_class, base_folder="..", log_level=logging.INFO, profile=False, **kwargs
31
+ ):
32
+ """
33
+ Sets up and solves an optimization problem.
34
+
35
+ This function makes the following assumptions:
36
+
37
+ 1. That the ``base_folder`` contains subfolders ``input``, ``output``, and ``model``,
38
+ containing input data, output data, and the model, respectively.
39
+ 2. When using :class:`.CSVLookupTableMixin`, that the base folder contains
40
+ a subfolder ``lookup_tables``.
41
+ 3. When using :class:`.ModelicaMixin`, that the base folder contains
42
+ a subfolder ``model``.
43
+ 4. When using :class:`.ModelicaMixin`, that the toplevel Modelica model name
44
+ equals the class name.
45
+
46
+ :param optimization_problem_class: Optimization problem class to solve.
47
+ :param base_folder: Base folder.
48
+ :param log_level: The log level to use.
49
+ :param profile: Whether or not to enable profiling.
50
+
51
+ :returns: :class:`.OptimizationProblem` instance.
52
+ """
53
+
54
+ # Do some checks on the problem class
55
+ if issubclass(optimization_problem_class, SimulationCSVMixin):
56
+ raise ValueError(
57
+ "Optimization problem class cannot be derived from simulation.csv_mixin.CSVMixin."
58
+ )
59
+ if issubclass(optimization_problem_class, SimulationIOMixin):
60
+ raise ValueError(
61
+ "Optimization problem class cannot be derived from simulation.csv_mixin.IOMixin."
62
+ )
63
+ if issubclass(optimization_problem_class, SimulationPIMixin):
64
+ raise ValueError(
65
+ "Optimization problem class cannot be derived from simulation.csv_mixin.PIMixin."
66
+ )
67
+
68
+ # Set input/output folders
69
+ if not os.path.isabs(base_folder):
70
+ # Resolve base folder relative to script folder
71
+ base_folder = os.path.join(sys.path[0], base_folder)
72
+
73
+ model_folder = _resolve_folder(kwargs, base_folder, "model_folder", "model")
74
+ input_folder = _resolve_folder(kwargs, base_folder, "input_folder", "input")
75
+ output_folder = _resolve_folder(kwargs, base_folder, "output_folder", "output")
76
+
77
+ # Set up logging
78
+ logger = logging.getLogger("rtctools")
79
+
80
+ # Add stream handler if it does not already exist.
81
+ if not logger.hasHandlers() and not any(
82
+ (isinstance(h, logging.StreamHandler) for h in logger.handlers)
83
+ ):
84
+ handler = logging.StreamHandler()
85
+ formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
86
+ handler.setFormatter(formatter)
87
+ logger.addHandler(handler)
88
+
89
+ # Add pi.DiagHandler, if using PIMixin. Only add it if it does not already exist.
90
+ if issubclass(optimization_problem_class, OptimizationPIMixin) and not any(
91
+ (isinstance(h, pi.DiagHandler) for h in logger.handlers)
92
+ ):
93
+ handler = pi.DiagHandler(output_folder)
94
+ logger.addHandler(handler)
95
+
96
+ # Set log level
97
+ logger.setLevel(log_level)
98
+
99
+ # Log version info
100
+ logger.info("Using RTC-Tools {}.".format(__version__))
101
+ logger.debug("Using CasADi {}.".format(casadi.__version__))
102
+
103
+ # Check for some common mistakes in inheritance order
104
+ suggested_order = OrderedSet(
105
+ [
106
+ "HomotopyMixin",
107
+ "MinAbsGoalProgrammingMixin",
108
+ "LinearizedOrderGoalProgrammingMixin",
109
+ "SinglePassGoalProgrammingMixin",
110
+ "GoalProgrammingMixin",
111
+ "PIMixin",
112
+ "CSVMixin",
113
+ "IOMixin",
114
+ "ModelicaMixin",
115
+ "PlanningMixin",
116
+ "ControlTreeMixin",
117
+ "CollocatedIntegratedOptimizationProblem",
118
+ "OptimizationProblem",
119
+ ]
120
+ )
121
+ base_names = OrderedSet([b.__name__ for b in optimization_problem_class.__bases__])
122
+ if suggested_order & base_names != base_names & suggested_order:
123
+ msg = "Please inherit from base classes in the following order: {}".format(
124
+ list(base_names & suggested_order)
125
+ )
126
+ logger.error(msg)
127
+ raise Exception(msg)
128
+
129
+ # Run
130
+ try:
131
+ prob = optimization_problem_class(
132
+ model_folder=model_folder,
133
+ input_folder=input_folder,
134
+ output_folder=output_folder,
135
+ **kwargs,
136
+ )
137
+ if profile:
138
+ filename = os.path.join(base_folder, "profile.prof")
139
+
140
+ cProfile.runctx("prob.optimize()", globals(), locals(), filename)
141
+
142
+ s = pstats.Stats(filename)
143
+ s.strip_dirs().sort_stats("time").print_stats()
144
+ else:
145
+ prob.optimize()
146
+ return prob
147
+ except Exception as e:
148
+ logger.error(str(e))
149
+ if isinstance(e, TypeError):
150
+ exc_info = sys.exc_info()
151
+ value = exc_info[1]
152
+ try:
153
+ failed_class = re.search(
154
+ "Can't instantiate (.*) with abstract methods", str(value)
155
+ ).group(1)
156
+ abstract_method = re.search(" with abstract methods (.*)", str(value)).group(1)
157
+ logger.error(
158
+ "The {} is missing a mixin. Please add a mixin that instantiates "
159
+ "abstract method {}, so that the optimizer can run.".format(
160
+ failed_class, abstract_method
161
+ )
162
+ )
163
+ except Exception:
164
+ pass
165
+ for handler in logger.handlers:
166
+ handler.flush()
167
+ raise
168
+
169
+
170
+ def run_simulation_problem(
171
+ simulation_problem_class, base_folder="..", log_level=logging.INFO, **kwargs
172
+ ):
173
+ """
174
+ Sets up and runs a simulation problem.
175
+
176
+ :param simulation_problem_class: Simulation problem class to solve.
177
+ :param base_folder: Folder within which subfolders "input", "output", and "model"
178
+ exist, containing input and output data, and the model, respectively.
179
+ :param log_level: The log level to use.
180
+
181
+ :returns: :class:`SimulationProblem` instance.
182
+ """
183
+
184
+ # Do some checks on the problem class
185
+ if issubclass(simulation_problem_class, OptimizationCSVMixin):
186
+ raise ValueError(
187
+ "Simulation problem class cannot be derived from optimization.csv_mixin.CSVMixin."
188
+ )
189
+ if issubclass(simulation_problem_class, OptimizationIOMixin):
190
+ raise ValueError(
191
+ "Simulation problem class cannot be derived from optimization.csv_mixin.IOMixin."
192
+ )
193
+ if issubclass(simulation_problem_class, OptimizationPIMixin):
194
+ raise ValueError(
195
+ "Simulation problem class cannot be derived from optimization.csv_mixin.PIMixin."
196
+ )
197
+
198
+ # Set input/output folders
199
+ if base_folder is None:
200
+ # Check command line arguments
201
+ if len(sys.argv) != 2:
202
+ raise Exception("Usage: {} BASE_FOLDER".format(sys.argv[0]))
203
+
204
+ base_folder = sys.argv[1]
205
+ else:
206
+ if not os.path.isabs(base_folder):
207
+ # Resolve base folder relative to script folder
208
+ base_folder = os.path.join(sys.path[0], base_folder)
209
+
210
+ model_folder = _resolve_folder(kwargs, base_folder, "model_folder", "model")
211
+ input_folder = _resolve_folder(kwargs, base_folder, "input_folder", "input")
212
+ output_folder = _resolve_folder(kwargs, base_folder, "output_folder", "output")
213
+
214
+ # Set up logging
215
+ logger = logging.getLogger("rtctools")
216
+ if not logger.hasHandlers() and not any(
217
+ (isinstance(h, logging.StreamHandler) for h in logger.handlers)
218
+ ):
219
+ handler = logging.StreamHandler()
220
+ formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
221
+ handler.setFormatter(formatter)
222
+ logger.addHandler(handler)
223
+
224
+ # Add pi.DiagHandler, if using PIMixin. Only add it if it does not already exist.
225
+ if issubclass(simulation_problem_class, SimulationPIMixin) and not any(
226
+ (isinstance(h, pi.DiagHandler) for h in logger.handlers)
227
+ ):
228
+ handler = pi.DiagHandler(output_folder)
229
+ logger.addHandler(handler)
230
+
231
+ logger.setLevel(log_level)
232
+
233
+ logger.info("Using RTC-Tools {}".format(__version__))
234
+ logger.debug("Using CasADi {}.".format(casadi.__version__))
235
+
236
+ # Run
237
+ prob = simulation_problem_class(
238
+ model_folder=model_folder, input_folder=input_folder, output_folder=output_folder, **kwargs
239
+ )
240
+ prob.simulate()
241
+ return prob