pymodaq 5.0.17__py3-none-any.whl → 5.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pymodaq might be problematic. Click here for more details.
- pymodaq/__init__.py +23 -11
- pymodaq/control_modules/__init__.py +1 -0
- pymodaq/control_modules/daq_move.py +458 -246
- pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/factory.py +48 -0
- pymodaq/control_modules/{daq_move_ui.py → daq_move_ui/ui_base.py} +168 -210
- pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
- pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
- pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
- pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
- pymodaq/control_modules/daq_viewer.py +113 -101
- pymodaq/control_modules/daq_viewer_ui.py +41 -31
- pymodaq/control_modules/mocks.py +2 -2
- pymodaq/control_modules/move_utility_classes.py +113 -41
- pymodaq/control_modules/thread_commands.py +137 -0
- pymodaq/control_modules/ui_utils.py +72 -0
- pymodaq/control_modules/utils.py +107 -63
- pymodaq/control_modules/viewer_utility_classes.py +13 -17
- pymodaq/dashboard.py +1294 -625
- pymodaq/examples/qt_less_standalone_module.py +48 -11
- pymodaq/extensions/__init__.py +8 -3
- pymodaq/extensions/adaptive/__init__.py +2 -0
- pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
- pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
- pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
- pymodaq/extensions/adaptive/utils.py +123 -0
- pymodaq/extensions/bayesian/__init__.py +1 -1
- pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
- pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
- pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
- pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
- pymodaq/extensions/bayesian/utils.py +71 -297
- pymodaq/extensions/daq_logger/daq_logger.py +7 -12
- pymodaq/extensions/daq_logger/h5logging.py +1 -1
- pymodaq/extensions/daq_scan.py +30 -55
- pymodaq/extensions/data_mixer/__init__.py +0 -0
- pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
- pymodaq/extensions/data_mixer/data_mixer.py +262 -0
- pymodaq/extensions/data_mixer/model.py +108 -0
- pymodaq/extensions/data_mixer/models/__init__.py +0 -0
- pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
- pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
- pymodaq/extensions/data_mixer/parser.py +53 -0
- pymodaq/extensions/data_mixer/utils.py +23 -0
- pymodaq/extensions/h5browser.py +3 -34
- pymodaq/extensions/optimizers_base/__init__.py +0 -0
- pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
- pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
- pymodaq/extensions/optimizers_base/utils.py +427 -0
- pymodaq/extensions/pid/actuator_controller.py +3 -2
- pymodaq/extensions/pid/daq_move_PID.py +107 -30
- pymodaq/extensions/pid/pid_controller.py +613 -287
- pymodaq/extensions/pid/utils.py +8 -5
- pymodaq/extensions/utils.py +17 -2
- pymodaq/resources/config_template.toml +57 -0
- pymodaq/resources/preset_default.xml +1 -1
- pymodaq/utils/config.py +13 -4
- pymodaq/utils/daq_utils.py +14 -0
- pymodaq/utils/data.py +1 -0
- pymodaq/utils/gui_utils/loader_utils.py +25 -15
- pymodaq/utils/h5modules/module_saving.py +134 -22
- pymodaq/utils/leco/daq_move_LECODirector.py +123 -84
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +84 -97
- pymodaq/utils/leco/director_utils.py +32 -16
- pymodaq/utils/leco/leco_director.py +104 -27
- pymodaq/utils/leco/pymodaq_listener.py +186 -97
- pymodaq/utils/leco/rpc_method_definitions.py +43 -0
- pymodaq/utils/leco/utils.py +25 -25
- pymodaq/utils/managers/batchscan_manager.py +12 -11
- pymodaq/utils/managers/modules_manager.py +74 -33
- pymodaq/utils/managers/overshoot_manager.py +11 -10
- pymodaq/utils/managers/preset_manager.py +100 -64
- pymodaq/utils/managers/preset_manager_utils.py +163 -107
- pymodaq/utils/managers/remote_manager.py +21 -16
- pymodaq/utils/scanner/scan_factory.py +18 -4
- pymodaq/utils/scanner/scan_selector.py +1 -3
- pymodaq/utils/scanner/scanner.py +35 -6
- pymodaq/utils/scanner/scanners/_1d_scanners.py +15 -46
- pymodaq/utils/scanner/scanners/_2d_scanners.py +21 -68
- pymodaq/utils/scanner/scanners/sequential.py +50 -31
- pymodaq/utils/scanner/scanners/tabular.py +45 -28
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/METADATA +7 -6
- pymodaq-5.1.0.dist-info/RECORD +154 -0
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/entry_points.txt +0 -2
- pymodaq/extensions/bayesian/bayesian_optimisation.py +0 -685
- pymodaq/utils/leco/desktop.ini +0 -2
- pymodaq-5.0.17.dist-info/RECORD +0 -121
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/WHEEL +0 -0
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,1016 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
import tempfile
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from qtpy import QtWidgets, QtCore
|
|
8
|
+
import time
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from collections import OrderedDict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
from pymodaq.utils.managers.modules_manager import ModulesManager
|
|
15
|
+
from pymodaq_gui.messenger import messagebox
|
|
16
|
+
from pymodaq_utils import utils
|
|
17
|
+
|
|
18
|
+
from pymodaq_utils.enums import BaseEnum, StrEnum
|
|
19
|
+
from pymodaq_utils.logger import set_logger, get_module_name
|
|
20
|
+
try:
|
|
21
|
+
from pymodaq_gui.config_saver_loader import ConfigSaverLoader
|
|
22
|
+
except ModuleNotFoundError:
|
|
23
|
+
from pymodaq_gui.config import ConfigSaverLoader #backcompatibility
|
|
24
|
+
|
|
25
|
+
from pymodaq_utils.config import Config as ConfigUtils
|
|
26
|
+
|
|
27
|
+
from pymodaq_data.h5modules.data_saving import DataEnlargeableSaver
|
|
28
|
+
|
|
29
|
+
from pymodaq_gui.plotting.data_viewers.viewer0D import Viewer0D
|
|
30
|
+
from pymodaq_gui.plotting.data_viewers.viewer import ViewerDispatcher
|
|
31
|
+
from pymodaq_gui.utils import QLED
|
|
32
|
+
from pymodaq_gui.utils.widgets.spinbox import QSpinBox_ro
|
|
33
|
+
from pymodaq_gui import utils as gutils
|
|
34
|
+
from pymodaq_gui.parameter import utils as putils
|
|
35
|
+
from pymodaq_gui.h5modules.saving import H5Saver
|
|
36
|
+
|
|
37
|
+
from pymodaq.utils.data import DataToExport, DataToActuators, DataCalculated, DataActuator
|
|
38
|
+
from pymodaq.post_treatment.load_and_plot import LoaderPlotter
|
|
39
|
+
from pymodaq.extensions.utils import CustomExt
|
|
40
|
+
|
|
41
|
+
from pymodaq.utils.h5modules import module_saving
|
|
42
|
+
from pymodaq.utils import config as config_mod
|
|
43
|
+
|
|
44
|
+
from pymodaq.extensions.optimizers_base.utils import (
|
|
45
|
+
get_optimizer_models, OptimizerModelGeneric,
|
|
46
|
+
GenericAlgorithm, StopType, StoppingParameters,
|
|
47
|
+
OptimizerConfig, individual_as_dta, individual_as_dte)
|
|
48
|
+
from pymodaq.extensions.optimizers_base.thread_commands import OptimizerToRunner, OptimizerThreadStatus
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
logger = set_logger(get_module_name(__file__))
|
|
52
|
+
config = config_mod.Config()
|
|
53
|
+
config_utils = ConfigUtils()
|
|
54
|
+
|
|
55
|
+
PREDICTION_PARAMS = [] # to be subclassed in real optimizer implementations
|
|
56
|
+
MODELS = get_optimizer_models()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class OptimizerAction(StrEnum):
|
|
60
|
+
QUIT = 'quit'
|
|
61
|
+
INI_MODEL = 'ini_model'
|
|
62
|
+
MODELS = 'models'
|
|
63
|
+
SAVE = 'save'
|
|
64
|
+
INI_RUNNER = 'ini_runner'
|
|
65
|
+
RUN = 'run'
|
|
66
|
+
RESTART = 'restart'
|
|
67
|
+
STOP = 'stop'
|
|
68
|
+
GO_TO_BEST = 'gotobest'
|
|
69
|
+
GO_TO = 'goto'
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class DataNames(StrEnum):
|
|
73
|
+
Fitness = 'fitness'
|
|
74
|
+
Individual = 'individual'
|
|
75
|
+
ProbedData = 'probed_data'
|
|
76
|
+
Actuators = 'actuators'
|
|
77
|
+
Tradeoff = 'tradeoff'
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def optimizer_params(prediction_params: list[dict]):
|
|
81
|
+
return [
|
|
82
|
+
{'title': 'Main Settings:', 'name': 'main_settings', 'expanded': True, 'type': 'group',
|
|
83
|
+
'children': [
|
|
84
|
+
{'title': 'Prediction Function:', 'name': 'prediction', 'expanded': False, 'type': 'group',
|
|
85
|
+
'children': prediction_params
|
|
86
|
+
|
|
87
|
+
},
|
|
88
|
+
{'title': 'Stopping Criteria:', 'name': 'stopping', 'expanded': False, 'type': 'group',
|
|
89
|
+
'children': [
|
|
90
|
+
{'title': 'Niteration', 'name': 'niter', 'type': 'int',
|
|
91
|
+
'value': config('optimizer', 'n_iter'), 'min': 5},
|
|
92
|
+
{'title': 'Type:', 'name': 'stop_type', 'type': 'list',
|
|
93
|
+
'limits': StopType.values(), 'value': str(StopType.ITER),
|
|
94
|
+
'tip': StopType.ITER.tip()},
|
|
95
|
+
{'title': 'Tolerance', 'name': 'tolerance', 'type': 'slide', 'value': 1e-2,
|
|
96
|
+
'min': 1e-8, 'max': 1, 'subtype': 'log', },
|
|
97
|
+
{'title': 'Npoints', 'name': 'npoints', 'type': 'int', 'value': 5, 'min': 1},
|
|
98
|
+
]},
|
|
99
|
+
{'title': 'Ini. Random Points', 'name': 'ini_random', 'type': 'int', 'value': 5},
|
|
100
|
+
{'title': 'bounds', 'name': 'bounds', 'type': 'group', 'children': []},
|
|
101
|
+
]},
|
|
102
|
+
|
|
103
|
+
{'title': 'Models', 'name': 'models', 'type': 'group', 'expanded': True, 'visible': True,
|
|
104
|
+
'children': [
|
|
105
|
+
{'title': 'Models class:', 'name': 'model_class', 'type': 'list',
|
|
106
|
+
'limits': [d['name'] for d in MODELS]},
|
|
107
|
+
{'title': 'Ini Model', 'name': 'ini_model', 'type': 'action', },
|
|
108
|
+
{'title': 'Ini Algo', 'name': 'ini_runner', 'type': 'action', 'enabled': False},
|
|
109
|
+
{'title': 'Model params:', 'name': 'model_params', 'type': 'group', 'children': []},
|
|
110
|
+
]},
|
|
111
|
+
{'title': 'Move settings:', 'name': 'move_settings', 'expanded': True, 'type': 'group',
|
|
112
|
+
'visible': False, 'children': [
|
|
113
|
+
{'title': 'Units:', 'name': 'units', 'type': 'str', 'value': ''}]},
|
|
114
|
+
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class DataToActuatorsOpti(DataToActuators):
|
|
119
|
+
""" Specific class including the step in the optimization loop for further use"""
|
|
120
|
+
ind_iter: int
|
|
121
|
+
def __init__(self, *args, ind_iter=0, **kwargs):
|
|
122
|
+
super().__init__(*args, ind_iter=ind_iter, **kwargs)
|
|
123
|
+
|
|
124
|
+
def __repr__(self):
|
|
125
|
+
return f'{super().__repr__()} iter:{self.ind_iter}'
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class OptimizationRunner(QtCore.QObject):
|
|
130
|
+
algo_live_plot_signal = QtCore.Signal(DataToExport)
|
|
131
|
+
algo_finished = QtCore.Signal(DataToExport)
|
|
132
|
+
saver_signal = QtCore.Signal(DataToActuatorsOpti)
|
|
133
|
+
|
|
134
|
+
runner_command = QtCore.Signal(utils.ThreadCommand)
|
|
135
|
+
|
|
136
|
+
def __init__(self, model_class: OptimizerModelGeneric, modules_manager: ModulesManager,
|
|
137
|
+
algorithm: GenericAlgorithm, stopping_params: StoppingParameters):
|
|
138
|
+
super().__init__()
|
|
139
|
+
|
|
140
|
+
self.det_done_datas: DataToExport = None
|
|
141
|
+
self.input_from_dets: float = None
|
|
142
|
+
self.outputs: List[np.ndarray] = []
|
|
143
|
+
self.output_to_actuators: DataToActuators = None
|
|
144
|
+
self.dte_actuators: DataToExport = None
|
|
145
|
+
self.stopping_params: StoppingParameters = stopping_params
|
|
146
|
+
|
|
147
|
+
self.model_class: OptimizerModelGeneric = model_class
|
|
148
|
+
self.modules_manager: ModulesManager = modules_manager
|
|
149
|
+
|
|
150
|
+
self.running = True
|
|
151
|
+
self.converged = False
|
|
152
|
+
self._ind_iter = -1
|
|
153
|
+
|
|
154
|
+
self.optimization_algorithm: GenericAlgorithm = algorithm
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def queue_command(self, command: utils.ThreadCommand):
|
|
158
|
+
"""
|
|
159
|
+
"""
|
|
160
|
+
if command.command == OptimizerToRunner.RUN:
|
|
161
|
+
if command.attribute is None:
|
|
162
|
+
command.attribute = {}
|
|
163
|
+
self.run_opti(**command.attribute)
|
|
164
|
+
|
|
165
|
+
elif command.command == OptimizerToRunner.PAUSE:
|
|
166
|
+
self.running = False
|
|
167
|
+
|
|
168
|
+
elif command.command == OptimizerToRunner.STOP:
|
|
169
|
+
self.converged = True
|
|
170
|
+
|
|
171
|
+
elif command.command == OptimizerToRunner.STOPPING:
|
|
172
|
+
self.stopping_params: StoppingParameters = command.attribute
|
|
173
|
+
|
|
174
|
+
elif command.command == OptimizerToRunner.BOUNDS:
|
|
175
|
+
self.optimization_algorithm.bounds = command.attribute
|
|
176
|
+
|
|
177
|
+
elif command.command == OptimizerToRunner.RESTART:
|
|
178
|
+
self.optimization_algorithm = command.attribute
|
|
179
|
+
self._ind_iter = -1
|
|
180
|
+
|
|
181
|
+
def run_opti(self, sync_detectors=True, sync_acts=True):
|
|
182
|
+
"""Start the optimization loop
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
sync_detectors: (bool) if True will make sure all selected detectors (if any) all got their data before calling
|
|
187
|
+
the model
|
|
188
|
+
sync_acts: (bool) if True will make sure all selected actuators (if any) all reached their target position
|
|
189
|
+
before calling the model
|
|
190
|
+
"""
|
|
191
|
+
self.running = True
|
|
192
|
+
self.converged = False
|
|
193
|
+
try:
|
|
194
|
+
if sync_detectors:
|
|
195
|
+
self.modules_manager.connect_detectors()
|
|
196
|
+
if sync_acts:
|
|
197
|
+
self.modules_manager.connect_actuators()
|
|
198
|
+
|
|
199
|
+
self.current_time = time.perf_counter()
|
|
200
|
+
logger.info('Optimisation loop starting')
|
|
201
|
+
while self.running:
|
|
202
|
+
self._ind_iter += 1
|
|
203
|
+
|
|
204
|
+
next_target: dict[str, float] = self.optimization_algorithm.ask()
|
|
205
|
+
|
|
206
|
+
self.outputs = next_target
|
|
207
|
+
self.output_to_actuators: DataToActuators = \
|
|
208
|
+
self.model_class.convert_output(
|
|
209
|
+
self.outputs,
|
|
210
|
+
best_individual=self.optimization_algorithm.best_individual
|
|
211
|
+
)
|
|
212
|
+
for dwa in self.output_to_actuators:
|
|
213
|
+
dwa.origin = DataNames.Actuators
|
|
214
|
+
|
|
215
|
+
self.modules_manager.move_actuators(self.output_to_actuators,
|
|
216
|
+
self.output_to_actuators.mode,
|
|
217
|
+
polling=sync_acts)
|
|
218
|
+
|
|
219
|
+
# Do the evaluation (measurements)
|
|
220
|
+
self.det_done_datas = self.modules_manager.grab_data()
|
|
221
|
+
self.input_from_dets = self.model_class.convert_input(self.det_done_datas)
|
|
222
|
+
|
|
223
|
+
#log data
|
|
224
|
+
self.runner_command.emit(
|
|
225
|
+
utils.ThreadCommand(OptimizerThreadStatus.ADD_DATA,))
|
|
226
|
+
|
|
227
|
+
# Run the algo internal mechanic
|
|
228
|
+
self.optimization_algorithm.tell(self.input_from_dets)
|
|
229
|
+
|
|
230
|
+
dte_algo = individual_as_dte(self.optimization_algorithm.best_individual,
|
|
231
|
+
self.modules_manager.actuators,
|
|
232
|
+
DataNames.Individual)
|
|
233
|
+
dte_algo.append([DataCalculated(DataNames.Fitness,
|
|
234
|
+
data=[np.atleast_1d(self.optimization_algorithm.best_fitness)]),
|
|
235
|
+
])
|
|
236
|
+
dte_algo.append(self.output_to_actuators)
|
|
237
|
+
dte_algo.append(DataCalculated(DataNames.ProbedData,
|
|
238
|
+
data=[np.array([self.input_from_dets])],
|
|
239
|
+
origin='algo'))
|
|
240
|
+
self.algo_live_plot_signal.emit(dte_algo)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
self.saver_signal.emit(DataToActuatorsOpti(DataNames.Actuators,
|
|
244
|
+
data = self.output_to_actuators.deepcopy().data,
|
|
245
|
+
mode=self.output_to_actuators.mode,
|
|
246
|
+
ind_iter=self._ind_iter))
|
|
247
|
+
|
|
248
|
+
self.optimization_algorithm.update_prediction_function()
|
|
249
|
+
self.runner_command.emit(
|
|
250
|
+
utils.ThreadCommand(OptimizerThreadStatus.TRADE_OFF, attribute=self.optimization_algorithm.tradeoff))
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
self.converged = (self.converged or
|
|
254
|
+
self.optimization_algorithm.stopping(self._ind_iter, self.stopping_params))
|
|
255
|
+
if self.converged:
|
|
256
|
+
break
|
|
257
|
+
|
|
258
|
+
self.current_time = time.perf_counter()
|
|
259
|
+
QtWidgets.QApplication.processEvents()
|
|
260
|
+
QtWidgets.QApplication.processEvents()
|
|
261
|
+
logger.info('Optimisation loop exiting')
|
|
262
|
+
self.modules_manager.connect_actuators(False)
|
|
263
|
+
self.modules_manager.connect_detectors(False)
|
|
264
|
+
|
|
265
|
+
if self.converged:
|
|
266
|
+
self.algo_finished.emit(dte_algo)
|
|
267
|
+
|
|
268
|
+
except Exception as e:
|
|
269
|
+
logger.exception(str(e))
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class GenericOptimization(CustomExt):
|
|
273
|
+
""" PyMoDAQ extension of the DashBoard to perform the optimization of a target signal
|
|
274
|
+
taken form the detectors as a function of one or more parameters controlled by the actuators.
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
command_runner = QtCore.Signal(utils.ThreadCommand)
|
|
278
|
+
explored_viewer_name = f'algo/{DataNames.ProbedData}'
|
|
279
|
+
optimization_done_signal = QtCore.Signal(DataToExport)
|
|
280
|
+
|
|
281
|
+
runner = OptimizationRunner # replace in real implementation if customization is needed
|
|
282
|
+
DISPLAY_BEST = True
|
|
283
|
+
|
|
284
|
+
params = optimizer_params(PREDICTION_PARAMS)
|
|
285
|
+
|
|
286
|
+
config_saver = OptimizerConfig #to be redefined in real implementation if needed
|
|
287
|
+
|
|
288
|
+
def __init__(self, dockarea, dashboard):
|
|
289
|
+
super().__init__(dockarea, dashboard)
|
|
290
|
+
|
|
291
|
+
self._ini_runner = False
|
|
292
|
+
|
|
293
|
+
self.algorithm: Optional[GenericAlgorithm] = None
|
|
294
|
+
self.viewer_observable: Optional[ViewerDispatcher] = None
|
|
295
|
+
self.model_class: Optional[OptimizerModelGeneric] = None
|
|
296
|
+
self._save_main_settings = True
|
|
297
|
+
|
|
298
|
+
self.modules_manager.actuators_changed[list].connect(self.update_actuators)
|
|
299
|
+
self.modules_manager.settings.child('data_dimensions').setOpts(expanded=False)
|
|
300
|
+
self.modules_manager.settings.child('actuators_positions').setOpts(expanded=False)
|
|
301
|
+
|
|
302
|
+
self._h5saver: H5Saver = None
|
|
303
|
+
self.h5saver.settings.child('do_save').hide()
|
|
304
|
+
self.h5saver.settings.child('custom_name').hide()
|
|
305
|
+
self.h5saver.new_file_sig.connect(self.create_new_file)
|
|
306
|
+
|
|
307
|
+
self.setup_ui()
|
|
308
|
+
|
|
309
|
+
self.optimizer_config = self.config_saver()
|
|
310
|
+
|
|
311
|
+
self.mainsettings_saver_loader = ConfigSaverLoader(
|
|
312
|
+
self.settings.child('main_settings'), self.optimizer_config)
|
|
313
|
+
|
|
314
|
+
self._base_name: str = None
|
|
315
|
+
|
|
316
|
+
self.h5temp: H5Saver = None
|
|
317
|
+
self.temp_path: tempfile.TemporaryDirectory = None
|
|
318
|
+
self.enlargeable_saver: DataEnlargeableSaver = None
|
|
319
|
+
self.live_plotter = LoaderPlotter(self.dockarea)
|
|
320
|
+
|
|
321
|
+
self._module_and_data_saver: module_saving.OptimizerSaver = None
|
|
322
|
+
|
|
323
|
+
self._ind_iter: int = 0
|
|
324
|
+
self.enl_index = 0
|
|
325
|
+
|
|
326
|
+
self.settings.child('models', 'ini_model').sigActivated.connect(
|
|
327
|
+
self.get_action(OptimizerAction.INI_MODEL).trigger)
|
|
328
|
+
|
|
329
|
+
self.settings.child('models', 'ini_runner').sigActivated.connect(
|
|
330
|
+
self.get_action(OptimizerAction.INI_RUNNER).trigger)
|
|
331
|
+
|
|
332
|
+
self.ini_custom_attributes()
|
|
333
|
+
|
|
334
|
+
if len(MODELS) == 1:
|
|
335
|
+
self.get_action(OptimizerAction.INI_MODEL).trigger()
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
@property
|
|
339
|
+
def title(self):
|
|
340
|
+
return f'{self.__class__.__name__}'
|
|
341
|
+
|
|
342
|
+
def ini_custom_attributes(self):
|
|
343
|
+
""" Here you can reimplement specific attributes"""
|
|
344
|
+
self._base_name: str = 'Optimizer' # base name used for naming the hdf5 file
|
|
345
|
+
|
|
346
|
+
@property
|
|
347
|
+
def h5saver(self):
|
|
348
|
+
if self._h5saver is None:
|
|
349
|
+
self._h5saver = H5Saver(save_type='optimizer', backend=config_utils('general', 'hdf5_backend'))
|
|
350
|
+
self._h5saver.settings.child('base_name').setValue('Optimizer')
|
|
351
|
+
if self._h5saver.h5_file is None:
|
|
352
|
+
self._h5saver.init_file(update_h5=True)
|
|
353
|
+
if not self._h5saver.isopen():
|
|
354
|
+
self._h5saver.init_file(addhoc_file_path=self._h5saver.settings['current_h5_file'])
|
|
355
|
+
return self._h5saver
|
|
356
|
+
|
|
357
|
+
@h5saver.setter
|
|
358
|
+
def h5saver(self, h5saver_temp: H5Saver):
|
|
359
|
+
self._h5saver = h5saver_temp
|
|
360
|
+
|
|
361
|
+
@property
|
|
362
|
+
def module_and_data_saver(self):
|
|
363
|
+
if not self._module_and_data_saver.h5saver.isopen():
|
|
364
|
+
self._module_and_data_saver.h5saver = self.h5saver
|
|
365
|
+
return self._module_and_data_saver
|
|
366
|
+
|
|
367
|
+
@module_and_data_saver.setter
|
|
368
|
+
def module_and_data_saver(self, mod: module_saving.OptimizerSaver):
|
|
369
|
+
self._module_and_data_saver = mod
|
|
370
|
+
self._module_and_data_saver.h5saver = self.h5saver
|
|
371
|
+
|
|
372
|
+
def create_new_file(self, new_file):
|
|
373
|
+
if new_file:
|
|
374
|
+
self.close_file()
|
|
375
|
+
self.module_and_data_saver.h5saver = self.h5saver # force all control modules to update their h5saver
|
|
376
|
+
|
|
377
|
+
def close_file(self):
|
|
378
|
+
self.h5saver.close_file()
|
|
379
|
+
|
|
380
|
+
def add_data(self, dta: DataToActuatorsOpti):
|
|
381
|
+
if self.is_action_checked(OptimizerAction.SAVE):
|
|
382
|
+
self.module_and_data_saver.add_data(axis_values=[dwa[0] for dwa in dta],
|
|
383
|
+
init_step=dta.ind_iter == 0)
|
|
384
|
+
|
|
385
|
+
@abc.abstractmethod
|
|
386
|
+
def validate_config(self) -> bool:
|
|
387
|
+
pass
|
|
388
|
+
|
|
389
|
+
@property
|
|
390
|
+
def config_path(self) -> Path:
|
|
391
|
+
return self.optimizer_config.config_path
|
|
392
|
+
|
|
393
|
+
def setup_docks(self):
|
|
394
|
+
"""
|
|
395
|
+
to be subclassed to setup the docks layout
|
|
396
|
+
for instance:
|
|
397
|
+
|
|
398
|
+
self.docks['ADock'] = gutils.Dock('ADock name)
|
|
399
|
+
self.dockarea.addDock(self.docks['ADock"])
|
|
400
|
+
self.docks['AnotherDock'] = gutils.Dock('AnotherDock name)
|
|
401
|
+
self.dockarea.addDock(self.docks['AnotherDock"], 'bottom', self.docks['ADock"])
|
|
402
|
+
|
|
403
|
+
See Also
|
|
404
|
+
########
|
|
405
|
+
pyqtgraph.dockarea.Dock
|
|
406
|
+
"""
|
|
407
|
+
self.docks['saving'] = gutils.Dock('Saving')
|
|
408
|
+
self.docks['saving'].addWidget(self.h5saver.settings_tree)
|
|
409
|
+
self.dockarea.addDock(self.docks['saving'])
|
|
410
|
+
|
|
411
|
+
self.docks['settings'] = gutils.Dock('Settings')
|
|
412
|
+
self.dockarea.addDock(self.docks['settings'], 'below', self.docks['saving'])
|
|
413
|
+
splitter = QtWidgets.QSplitter(QtCore.Qt.Orientation.Vertical)
|
|
414
|
+
self.docks['settings'].addWidget(splitter)
|
|
415
|
+
splitter.addWidget(self.modules_manager.settings_tree)
|
|
416
|
+
splitter.addWidget(self.settings_tree)
|
|
417
|
+
self.modules_manager.show_only_control_modules(True)
|
|
418
|
+
self.modules_manager.settings_tree.setEnabled(False)
|
|
419
|
+
|
|
420
|
+
splitter.setSizes((int(self.dockarea.height() / 2),
|
|
421
|
+
int(self.dockarea.height() / 2)))
|
|
422
|
+
if self.DISPLAY_BEST:
|
|
423
|
+
widget_observable = QtWidgets.QWidget()
|
|
424
|
+
widget_observable.setLayout(QtWidgets.QHBoxLayout())
|
|
425
|
+
observable_dockarea = gutils.DockArea()
|
|
426
|
+
widget_observable.layout().addWidget(observable_dockarea)
|
|
427
|
+
self.viewer_observable = ViewerDispatcher(observable_dockarea, direction='bottom')
|
|
428
|
+
self.docks['observable'] = gutils.Dock('Observable')
|
|
429
|
+
self.dockarea.addDock(self.docks['observable'], 'right', self.docks['settings'])
|
|
430
|
+
self.docks['observable'].addWidget(widget_observable)
|
|
431
|
+
|
|
432
|
+
if len(MODELS) != 0:
|
|
433
|
+
self.get_set_model_params(MODELS[0]['name'])
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
self._statusbar = QtWidgets.QStatusBar()
|
|
437
|
+
self.mainwindow.setStatusBar(self._statusbar)
|
|
438
|
+
self.populate_status_bar()
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def populate_status_bar(self):
|
|
442
|
+
self._status_message_label = QtWidgets.QLabel('Initializing')
|
|
443
|
+
self._optimizing_step = QSpinBox_ro()
|
|
444
|
+
self._optimizing_step.setToolTip('Current Optimizing step')
|
|
445
|
+
|
|
446
|
+
self._optimizing_done_LED = QLED()
|
|
447
|
+
self._optimizing_done_LED.set_as_false()
|
|
448
|
+
self._optimizing_done_LED.clickable = False
|
|
449
|
+
self._optimizing_done_LED.setToolTip('Scan done state')
|
|
450
|
+
self._statusbar.addPermanentWidget(self._status_message_label)
|
|
451
|
+
|
|
452
|
+
self._statusbar.addPermanentWidget(self._optimizing_step)
|
|
453
|
+
self._statusbar.addPermanentWidget(self._optimizing_done_LED)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def get_set_model_params(self, model_name):
|
|
457
|
+
self.settings.child('models', 'model_params').clearChildren()
|
|
458
|
+
if len(MODELS) > 0:
|
|
459
|
+
model_class = utils.find_dict_in_list_from_key_val(MODELS, 'name', model_name)['class']
|
|
460
|
+
params = getattr(model_class, 'params')
|
|
461
|
+
self.settings.child('models', 'model_params').addChildren(params)
|
|
462
|
+
|
|
463
|
+
def setup_menu(self, menubar: QtWidgets.QMenuBar = None):
|
|
464
|
+
'''
|
|
465
|
+
to be subclassed
|
|
466
|
+
create menu for actions contained into the self.actions_manager, for instance:
|
|
467
|
+
|
|
468
|
+
For instance:
|
|
469
|
+
|
|
470
|
+
file_menu = self.menubar.addMenu('File')
|
|
471
|
+
self.actions_manager.affect_to('load', file_menu)
|
|
472
|
+
self.actions_manager.affect_to('save', file_menu)
|
|
473
|
+
|
|
474
|
+
file_menu.addSeparator()
|
|
475
|
+
self.actions_manager.affect_to('quit', file_menu)
|
|
476
|
+
'''
|
|
477
|
+
pass
|
|
478
|
+
|
|
479
|
+
def value_changed(self, param):
|
|
480
|
+
''' to be subclassed for actions to perform when one of the param's value in self.settings is changed
|
|
481
|
+
|
|
482
|
+
For instance:
|
|
483
|
+
if param.name() == 'do_something':
|
|
484
|
+
if param.value():
|
|
485
|
+
print('Do something')
|
|
486
|
+
self.settings.child('main_settings', 'something_done').setValue(False)
|
|
487
|
+
|
|
488
|
+
Parameters
|
|
489
|
+
----------
|
|
490
|
+
param: (Parameter) the parameter whose value just changed
|
|
491
|
+
'''
|
|
492
|
+
if param.name() == 'model_class':
|
|
493
|
+
self.get_set_model_params(param.value())
|
|
494
|
+
self.get_action(OptimizerAction.MODELS).setCurrentText(param.value())
|
|
495
|
+
elif param.name() in putils.iter_children(self.settings.child('models', 'model_params'), []):
|
|
496
|
+
if self.model_class is not None:
|
|
497
|
+
self.model_class.update_settings(param)
|
|
498
|
+
elif param.name() in putils.iter_children(
|
|
499
|
+
self.settings.child('main_settings', 'bounds'), []):
|
|
500
|
+
self.update_bounds()
|
|
501
|
+
elif param.name() in putils.iter_children(
|
|
502
|
+
self.settings.child('main_settings', 'stopping'), []):
|
|
503
|
+
self.update_stopping_criteria()
|
|
504
|
+
if param.name() == 'stop_type' and param.value() is not None:
|
|
505
|
+
self.settings.child('main_settings', 'stopping', 'stop_type').setOpts(
|
|
506
|
+
tip=StopType(param.value()).tip())
|
|
507
|
+
elif param.name() in putils.iter_children(
|
|
508
|
+
self.settings.child('main_settings', 'prediction'), []):
|
|
509
|
+
if param.name() != 'tradeoff_actual':
|
|
510
|
+
self.update_prediction_function()
|
|
511
|
+
|
|
512
|
+
if self._save_main_settings and self.model_class is not None and param.name() in putils.iter_children(
|
|
513
|
+
self.settings.child('main_settings'), []):
|
|
514
|
+
self.mainsettings_saver_loader.save_config()
|
|
515
|
+
|
|
516
|
+
def update_prediction_function(self):
|
|
517
|
+
""" Get the selected prediction function options and pass them to the Runner
|
|
518
|
+
|
|
519
|
+
Should be reimplemented in real Optimizer implementation
|
|
520
|
+
Something like:
|
|
521
|
+
|
|
522
|
+
utility_settings = self.settings.child('main_settings', 'prediction')
|
|
523
|
+
kind = utility_settings.child('kind').value()
|
|
524
|
+
uparams = {child.name() : child.value() for child in utility_settings.child('options').children()}
|
|
525
|
+
uparams['kind'] = kind
|
|
526
|
+
self.command_runner.emit(
|
|
527
|
+
utils.ThreadCommand(OptimizerToRunner.PREDICTION, uparams))
|
|
528
|
+
"""
|
|
529
|
+
pass
|
|
530
|
+
|
|
531
|
+
def get_stopping_parameters(self) -> StoppingParameters:
|
|
532
|
+
stopping_settings = self.settings.child('main_settings', 'stopping')
|
|
533
|
+
stopping_params = StoppingParameters(stopping_settings['niter'],
|
|
534
|
+
stopping_settings['stop_type'],
|
|
535
|
+
stopping_settings['tolerance'],
|
|
536
|
+
stopping_settings['npoints'])
|
|
537
|
+
return stopping_params
|
|
538
|
+
|
|
539
|
+
def update_stopping_criteria(self):
|
|
540
|
+
self.command_runner.emit(
|
|
541
|
+
utils.ThreadCommand(OptimizerToRunner.STOPPING, self.get_stopping_parameters()))
|
|
542
|
+
|
|
543
|
+
def update_bounds(self):
|
|
544
|
+
bounds = {}
|
|
545
|
+
for child in self.settings.child('main_settings', 'bounds').children():
|
|
546
|
+
bounds[child.name()] = (child['min'], child['max'])
|
|
547
|
+
|
|
548
|
+
self.command_runner.emit(utils.ThreadCommand(OptimizerToRunner.BOUNDS, bounds))
|
|
549
|
+
|
|
550
|
+
def setup_actions(self):
|
|
551
|
+
logger.debug('setting actions')
|
|
552
|
+
self.add_action(OptimizerAction.QUIT, 'Quit', 'close2', "Quit program")
|
|
553
|
+
combo_model = QtWidgets.QComboBox()
|
|
554
|
+
combo_model.addItems([model['name'] for model in MODELS])
|
|
555
|
+
self.add_widget(OptimizerAction.MODELS, combo_model, tip='List of available models')
|
|
556
|
+
self.add_action(OptimizerAction.INI_MODEL, 'Init Model', 'ini')
|
|
557
|
+
self.add_widget('model_led', QLED, toolbar=self.toolbar)
|
|
558
|
+
self.add_action(OptimizerAction.SAVE, 'Save?', 'SaveAs', tip='If checked, data will be saved',
|
|
559
|
+
checkable=True)
|
|
560
|
+
self.add_action(OptimizerAction.INI_RUNNER, 'Init the Optimisation Algorithm', 'ini', checkable=True,
|
|
561
|
+
enabled=False)
|
|
562
|
+
self.add_widget('runner_led', QLED, toolbar=self.toolbar)
|
|
563
|
+
self.add_action(OptimizerAction.RUN, 'Run Optimisation', 'run2', checkable=True, enabled=False)
|
|
564
|
+
self.add_action(OptimizerAction.RESTART, 'Restart algo', 'Refresh2', checkable=False, enabled=False)
|
|
565
|
+
self.add_action(OptimizerAction.STOP, 'Stop algo', 'stop', checkable=False, enabled=False,
|
|
566
|
+
tip='Stop algo and go to best individual')
|
|
567
|
+
|
|
568
|
+
self.add_action(OptimizerAction.GO_TO_BEST, 'Go to best', 'Rendezvous', enabled=False,
|
|
569
|
+
tip='Go to the position optimizing the signal')
|
|
570
|
+
self.add_action(OptimizerAction.GO_TO, 'Go to ', 'move_contour', enabled=False, checkable=True,
|
|
571
|
+
tip='Go to the double clicked position in the plot')
|
|
572
|
+
logger.debug('actions set')
|
|
573
|
+
|
|
574
|
+
def connect_things(self):
|
|
575
|
+
logger.debug('connecting things')
|
|
576
|
+
self.connect_action(OptimizerAction.QUIT, self.quit)
|
|
577
|
+
self.connect_action('models', self.update_model_settings_from_action,
|
|
578
|
+
signal_name='currentTextChanged')
|
|
579
|
+
|
|
580
|
+
self.connect_action(OptimizerAction.SAVE, self.do_save)
|
|
581
|
+
self.connect_action(OptimizerAction.INI_MODEL, self.ini_model)
|
|
582
|
+
self.connect_action(OptimizerAction.INI_RUNNER, self.ini_optimization_runner)
|
|
583
|
+
self.connect_action(OptimizerAction.RUN, self.run_optimization)
|
|
584
|
+
self.connect_action(OptimizerAction.RESTART, self.restart_algo)
|
|
585
|
+
self.connect_action(OptimizerAction.STOP, self.stop_algo)
|
|
586
|
+
self.connect_action(OptimizerAction.GO_TO_BEST, self.go_to_best)
|
|
587
|
+
self.connect_action(OptimizerAction.GO_TO, self.allow_go_to)
|
|
588
|
+
self.h5saver.new_file_sig.connect(self.create_new_file)
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def update_model_settings_from_action(self, model: str):
|
|
592
|
+
self.settings.child('models', 'model_class').setValue(model)
|
|
593
|
+
|
|
594
|
+
def go_to_best(self):
|
|
595
|
+
best_individual = self.algorithm.best_individual
|
|
596
|
+
if best_individual is not None:
|
|
597
|
+
actuators = self.modules_manager.actuators
|
|
598
|
+
dte_act = DataToActuators('best',
|
|
599
|
+
data=[
|
|
600
|
+
DataActuator(actuators[ind].title,
|
|
601
|
+
data=float(best_individual[actuators[ind].title]),
|
|
602
|
+
units=actuators[ind].units)
|
|
603
|
+
for ind in range(len(best_individual))
|
|
604
|
+
],
|
|
605
|
+
mode='abs')
|
|
606
|
+
self.modules_manager.connect_actuators(True)
|
|
607
|
+
self.modules_manager.move_actuators(dte_act, polling=True)
|
|
608
|
+
self.modules_manager.connect_actuators(False)
|
|
609
|
+
|
|
610
|
+
def allow_go_to(self, enable=True):
|
|
611
|
+
if len(self.live_plotter.viewers) > 0:
|
|
612
|
+
if enable:
|
|
613
|
+
self.live_plotter.viewers[0].sig_double_clicked.connect(self.go_to)
|
|
614
|
+
else:
|
|
615
|
+
self.live_plotter.viewers[0].sig_double_clicked.disconnect(self.go_to)
|
|
616
|
+
|
|
617
|
+
def go_to(self, *positions):
|
|
618
|
+
actuators = self.modules_manager.actuators
|
|
619
|
+
dte_act = DataToActuators('best',
|
|
620
|
+
data=[
|
|
621
|
+
DataActuator(actuators[ind].title,
|
|
622
|
+
data=float(positions[ind]),
|
|
623
|
+
units=actuators[ind].units)
|
|
624
|
+
for ind in range(len(positions))
|
|
625
|
+
],
|
|
626
|
+
mode='abs')
|
|
627
|
+
self.modules_manager.connect_actuators(True)
|
|
628
|
+
self.modules_manager.move_actuators(dte_act, polling=True)
|
|
629
|
+
self.modules_manager.connect_actuators(False)
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
def quit(self):
|
|
633
|
+
self.dockarea.parent().close()
|
|
634
|
+
self.clean_h5_temp()
|
|
635
|
+
|
|
636
|
+
def set_model(self):
|
|
637
|
+
model_name = self.settings.child('models', 'model_class').value()
|
|
638
|
+
self.model_class = utils.find_dict_in_list_from_key_val(
|
|
639
|
+
MODELS, 'name', model_name)['class'](self)
|
|
640
|
+
self.model_class.ini_model_base()
|
|
641
|
+
|
|
642
|
+
def ini_temp_file(self):
|
|
643
|
+
self.clean_h5_temp()
|
|
644
|
+
|
|
645
|
+
self.h5temp = H5Saver()
|
|
646
|
+
self.temp_path = tempfile.TemporaryDirectory(prefix='pymo')
|
|
647
|
+
addhoc_file_path = Path(self.temp_path.name).joinpath('bayesian_temp_data.h5')
|
|
648
|
+
self.h5temp.init_file(custom_naming=True, addhoc_file_path=addhoc_file_path)
|
|
649
|
+
act_names = [child.name() for child in self.settings.child( 'main_settings',
|
|
650
|
+
'bounds').children()]
|
|
651
|
+
act_units = [self.modules_manager.get_mod_from_name(act_name, 'act').units for act_name
|
|
652
|
+
in act_names]
|
|
653
|
+
self.enlargeable_saver = DataEnlargeableSaver(
|
|
654
|
+
self.h5temp,
|
|
655
|
+
enl_axis_names=act_names,
|
|
656
|
+
enl_axis_units=act_units)
|
|
657
|
+
|
|
658
|
+
def ini_live_plot(self):
|
|
659
|
+
self.live_plotter.h5saver = self.h5temp
|
|
660
|
+
act_names = [child.name() for child in self.settings.child('main_settings',
|
|
661
|
+
'bounds').children()]
|
|
662
|
+
act_units = [self.modules_manager.get_mod_from_name(act_name, 'act').units for act_name
|
|
663
|
+
in act_names]
|
|
664
|
+
if len(act_names) == 1:
|
|
665
|
+
viewer_enum = 'Viewer1D'
|
|
666
|
+
elif len(act_names) == 2:
|
|
667
|
+
viewer_enum = 'Viewer2D'
|
|
668
|
+
else:
|
|
669
|
+
viewer_enum = 'ViewerND'
|
|
670
|
+
viewers = self.live_plotter.prepare_viewers([viewer_enum],
|
|
671
|
+
viewers_name=[self.explored_viewer_name])
|
|
672
|
+
for viewer in viewers:
|
|
673
|
+
if viewer.has_action('crosshair'):
|
|
674
|
+
viewer.get_action('crosshair').trigger()
|
|
675
|
+
if hasattr(viewer.view, 'collapse_lineout_widgets'):
|
|
676
|
+
viewer.view.collapse_lineout_widgets()
|
|
677
|
+
if viewer.has_action('sort'):
|
|
678
|
+
if not viewer.is_action_checked('sort'):
|
|
679
|
+
viewer.get_action('sort').trigger()
|
|
680
|
+
if viewer.has_action('scatter'):
|
|
681
|
+
if not viewer.is_action_checked('scatter'):
|
|
682
|
+
viewer.get_action('scatter').trigger()
|
|
683
|
+
if viewer.has_action('autolevels'):
|
|
684
|
+
if viewer.is_action_checked('autolevels'):
|
|
685
|
+
viewer.get_action('autolevels').trigger()
|
|
686
|
+
viewer.get_action('autolevels').trigger()
|
|
687
|
+
if viewer.has_action('aspect_ratio'):
|
|
688
|
+
if viewer.is_action_checked('aspect_ratio'):
|
|
689
|
+
viewer.get_action('aspect_ratio').trigger()
|
|
690
|
+
|
|
691
|
+
QtWidgets.QApplication.processEvents()
|
|
692
|
+
win_width = self.dockarea.width()
|
|
693
|
+
self.docks['settings'].container().parent().setSizes((int(win_width / 5),
|
|
694
|
+
int(2 * win_width / 5),
|
|
695
|
+
int(2 * win_width / 5), 10, 10))
|
|
696
|
+
|
|
697
|
+
def update_actuators(self, actuators: List[str]):
|
|
698
|
+
if self.is_action_checked(OptimizerAction.INI_RUNNER):
|
|
699
|
+
self.get_action(OptimizerAction.INI_RUNNER).trigger()
|
|
700
|
+
QtWidgets.QApplication.processEvents()
|
|
701
|
+
|
|
702
|
+
self._save_main_settings = False
|
|
703
|
+
|
|
704
|
+
for child in self.settings.child('main_settings', 'bounds').children():
|
|
705
|
+
self.settings.child('main_settings', 'bounds').removeChild(child)
|
|
706
|
+
params = []
|
|
707
|
+
for actuator in actuators:
|
|
708
|
+
params.append({'title': actuator, 'name': actuator, 'type': 'group', 'children': [
|
|
709
|
+
{'title': 'min', 'name': 'min', 'type': 'float',
|
|
710
|
+
'value': config('optimizer', 'bounds', 'actuator_min')},
|
|
711
|
+
{'title': 'max', 'name': 'max', 'type': 'float',
|
|
712
|
+
'value': config('optimizer', 'bounds','actuator_max')},
|
|
713
|
+
]})
|
|
714
|
+
self.settings.child('main_settings', 'bounds').addChildren(params)
|
|
715
|
+
|
|
716
|
+
try:
|
|
717
|
+
self.mainsettings_saver_loader.base_path = [self.model_class.__class__.__name__] + \
|
|
718
|
+
self.modules_manager.selected_actuators_name
|
|
719
|
+
self.mainsettings_saver_loader.load_config()
|
|
720
|
+
self._save_main_settings = True
|
|
721
|
+
except Exception as e:
|
|
722
|
+
logger.exception(f'Could not load the configuration')
|
|
723
|
+
|
|
724
|
+
self.update_after_actuators_changed(self.modules_manager.selected_actuators_name)
|
|
725
|
+
|
|
726
|
+
@abc.abstractmethod
|
|
727
|
+
def update_after_actuators_changed(self, actuators: list[str]):
|
|
728
|
+
""" Actions to do after the actuators have been updated
|
|
729
|
+
|
|
730
|
+
To be implemented
|
|
731
|
+
"""
|
|
732
|
+
...
|
|
733
|
+
|
|
734
|
+
def format_bounds(self):
|
|
735
|
+
bound_dict = OrderedDict([])
|
|
736
|
+
for bound in self.settings.child('main_settings', 'bounds').children():
|
|
737
|
+
bound_dict.update({bound.name(): (bound['min'], bound['max'])})
|
|
738
|
+
return bound_dict
|
|
739
|
+
|
|
740
|
+
@abc.abstractmethod
|
|
741
|
+
def set_algorithm(self):
|
|
742
|
+
self.algorithm = ...
|
|
743
|
+
|
|
744
|
+
def ini_model(self):
|
|
745
|
+
try:
|
|
746
|
+
if self.model_class is None:
|
|
747
|
+
self.set_model()
|
|
748
|
+
|
|
749
|
+
self.modules_manager.selected_actuators_name = self.model_class.actuators_name
|
|
750
|
+
self.modules_manager.selected_detectors_name = self.model_class.detectors_name
|
|
751
|
+
|
|
752
|
+
self.enable_controls_opti(True)
|
|
753
|
+
self.get_action('model_led').set_as_true()
|
|
754
|
+
self.set_action_enabled(OptimizerAction.INI_MODEL, False)
|
|
755
|
+
self.set_action_enabled(OptimizerAction.MODELS, False)
|
|
756
|
+
|
|
757
|
+
if self.DISPLAY_BEST:
|
|
758
|
+
self.viewer_observable.update_viewers(['Viewer0D'] + ['Viewer0D' for _ in self.modules_manager.selected_actuators_name],
|
|
759
|
+
['Fitness'] + [act for act in self.modules_manager.selected_actuators_name])
|
|
760
|
+
self.settings.child('models', 'ini_model').setValue(True)
|
|
761
|
+
self.settings.child('models', 'ini_runner').setOpts(enabled=True)
|
|
762
|
+
self.set_action_enabled(OptimizerAction.INI_RUNNER, True)
|
|
763
|
+
|
|
764
|
+
self.mainsettings_saver_loader.base_path = [self.model_class.__class__.__name__] + \
|
|
765
|
+
self.modules_manager.selected_actuators_name
|
|
766
|
+
self.mainsettings_saver_loader.load_config()
|
|
767
|
+
|
|
768
|
+
self.modules_manager.settings_tree.setEnabled(True)
|
|
769
|
+
self.settings.child('models', 'ini_model').hide()
|
|
770
|
+
|
|
771
|
+
#Warning the activate method here is blocking???
|
|
772
|
+
# try: # this is correct for Default Model and probably for all models...
|
|
773
|
+
# self.model_class.settings.child('optimizing_signal', 'data_probe').activate()
|
|
774
|
+
# except Exception:
|
|
775
|
+
# pass
|
|
776
|
+
|
|
777
|
+
except Exception as e:
|
|
778
|
+
logger.exception(str(e))
|
|
779
|
+
|
|
780
|
+
def do_save(self):
|
|
781
|
+
""" Properly prepare the extension for saving """
|
|
782
|
+
if self.is_action_checked(OptimizerAction.SAVE):
|
|
783
|
+
if self.is_action_checked(OptimizerAction.INI_RUNNER):
|
|
784
|
+
if self.is_action_checked(OptimizerAction.RUN):
|
|
785
|
+
self.get_action(OptimizerAction.RUN).trigger()
|
|
786
|
+
QtWidgets.QApplication.processEvents()
|
|
787
|
+
self.get_action(OptimizerAction.INI_RUNNER).trigger() # for the model/algo de-initialization to correctly resave data
|
|
788
|
+
# afterwards
|
|
789
|
+
QtWidgets.QApplication.processEvents()
|
|
790
|
+
self.get_action(OptimizerAction.INI_RUNNER).trigger()
|
|
791
|
+
|
|
792
|
+
def ini_saver(self):
|
|
793
|
+
if self.is_action_checked(OptimizerAction.SAVE):
|
|
794
|
+
self.module_and_data_saver = module_saving.OptimizerSaver(
|
|
795
|
+
self, enl_axis_names=self.modules_manager.selected_actuators_name,
|
|
796
|
+
enl_axis_units=[act.units for act in self.modules_manager.actuators])
|
|
797
|
+
self.create_new_file(True)
|
|
798
|
+
self.module_and_data_saver.h5saver = self.h5saver
|
|
799
|
+
self.check_create_save_node()
|
|
800
|
+
else:
|
|
801
|
+
self.module_and_data_saver.forget_h5()
|
|
802
|
+
self.module_and_data_saver.h5saver.close_file()
|
|
803
|
+
|
|
804
|
+
def recursive_enable(self, param: putils.Parameter, enable=True):
|
|
805
|
+
param.setOpts(enabled=enable)
|
|
806
|
+
for child in param.children():
|
|
807
|
+
self.recursive_enable(child, enable)
|
|
808
|
+
|
|
809
|
+
def enable_settings_run(self, enable=True):
|
|
810
|
+
self.modules_manager.settings_tree.setEnabled(enable)
|
|
811
|
+
self.recursive_enable(self.settings.child('models'), enable)
|
|
812
|
+
self.recursive_enable(self.settings.child('main_settings', 'bounds'), enable)
|
|
813
|
+
self.recursive_enable(self.settings.child('main_settings', 'ini_random'), enable)
|
|
814
|
+
|
|
815
|
+
def stop_algo(self):
|
|
816
|
+
self.command_runner.emit(utils.ThreadCommand(OptimizerToRunner.STOP))
|
|
817
|
+
|
|
818
|
+
def restart_algo(self):
|
|
819
|
+
|
|
820
|
+
if self.is_action_checked(OptimizerAction.RUN):
|
|
821
|
+
self.get_action(OptimizerAction.RUN).trigger()
|
|
822
|
+
QtWidgets.QApplication.processEvents()
|
|
823
|
+
|
|
824
|
+
self.set_algorithm()
|
|
825
|
+
self.model_class.runner_initialized()
|
|
826
|
+
self.command_runner.emit(utils.ThreadCommand(OptimizerToRunner.RESTART, self.algorithm))
|
|
827
|
+
self.update_prediction_function()
|
|
828
|
+
if self.viewer_observable is not None:
|
|
829
|
+
for viewer in self.viewer_observable.viewers:
|
|
830
|
+
if isinstance(viewer, Viewer0D):
|
|
831
|
+
viewer.view.data_displayer.clear_data()
|
|
832
|
+
|
|
833
|
+
self.enl_index = 0
|
|
834
|
+
self._optimizing_done_LED.set_as_false()
|
|
835
|
+
self.ini_temp_file()
|
|
836
|
+
self.ini_live_plot()
|
|
837
|
+
|
|
838
|
+
if self.is_action_checked(OptimizerAction.SAVE):
|
|
839
|
+
self.check_create_save_node()
|
|
840
|
+
|
|
841
|
+
self.get_action(OptimizerAction.RUN).trigger()
|
|
842
|
+
|
|
843
|
+
def check_create_save_node(self):
|
|
844
|
+
node_is_empty = (
|
|
845
|
+
len(self.module_and_data_saver.get_set_node().children()) == 0 or
|
|
846
|
+
len(self.module_and_data_saver.get_set_node().get_child('Detector000').children()) == 0)
|
|
847
|
+
node = self.module_and_data_saver.get_set_node(new= not node_is_empty)
|
|
848
|
+
self.h5saver.settings.child('current_scan_name').setValue(node.name)
|
|
849
|
+
|
|
850
|
+
def ini_optimization_runner(self):
|
|
851
|
+
self._status_message_label.setText('Initializing Algorithm and thread')
|
|
852
|
+
if self.is_action_checked(OptimizerAction.INI_RUNNER):
|
|
853
|
+
self._optimizing_done_LED.set_as_false()
|
|
854
|
+
if not self.model_class.has_fitness_observable():
|
|
855
|
+
messagebox(title='Warning', text='No 0D observable has been chosen as a fitness value for the algorithm')
|
|
856
|
+
self.set_action_checked(OptimizerAction.INI_RUNNER, False)
|
|
857
|
+
return
|
|
858
|
+
|
|
859
|
+
self.enable_settings_run(False)
|
|
860
|
+
if not self._ini_runner:
|
|
861
|
+
self._ini_runner = True
|
|
862
|
+
self.set_algorithm()
|
|
863
|
+
|
|
864
|
+
if self.is_action_checked(OptimizerAction.SAVE):
|
|
865
|
+
self.ini_saver()
|
|
866
|
+
self.check_create_save_node()
|
|
867
|
+
|
|
868
|
+
self.settings.child('models', 'ini_runner').setValue(True)
|
|
869
|
+
self.enl_index = 0
|
|
870
|
+
|
|
871
|
+
self.ini_temp_file()
|
|
872
|
+
self.ini_live_plot()
|
|
873
|
+
|
|
874
|
+
self.runner_thread = QtCore.QThread()
|
|
875
|
+
runner = self.runner(self.model_class, self.modules_manager, self.algorithm,
|
|
876
|
+
self.get_stopping_parameters())
|
|
877
|
+
self.runner_thread.runner = runner
|
|
878
|
+
runner.algo_live_plot_signal.connect(self.do_live_plot)
|
|
879
|
+
runner.algo_finished.connect(self.optimization_done)
|
|
880
|
+
runner.runner_command.connect(self.thread_status)
|
|
881
|
+
runner.saver_signal.connect(self.add_data)
|
|
882
|
+
self.command_runner.connect(runner.queue_command)
|
|
883
|
+
|
|
884
|
+
runner.moveToThread(self.runner_thread)
|
|
885
|
+
self.runner_thread.start()
|
|
886
|
+
self.get_action('runner_led').set_as_true()
|
|
887
|
+
self.set_action_enabled(OptimizerAction.RUN, True)
|
|
888
|
+
self.set_action_enabled(OptimizerAction.RESTART, True)
|
|
889
|
+
self.set_action_enabled(OptimizerAction.STOP, True)
|
|
890
|
+
self.model_class.runner_initialized()
|
|
891
|
+
self.update_prediction_function()
|
|
892
|
+
else:
|
|
893
|
+
self.set_action_enabled(OptimizerAction.INI_RUNNER, False)
|
|
894
|
+
self.enable_settings_run(True)
|
|
895
|
+
if self.is_action_checked(OptimizerAction.RUN):
|
|
896
|
+
self.get_action(OptimizerAction.RUN).trigger()
|
|
897
|
+
QtWidgets.QApplication.processEvents()
|
|
898
|
+
|
|
899
|
+
self._status_message_label.setText('Quitting Runner Thread')
|
|
900
|
+
try:
|
|
901
|
+
self.command_runner.disconnect()
|
|
902
|
+
except TypeError:
|
|
903
|
+
pass
|
|
904
|
+
if self.runner_thread is not None:
|
|
905
|
+
self.runner_thread.quit()
|
|
906
|
+
self.runner_thread.wait(5000)
|
|
907
|
+
if not self.runner_thread.isFinished():
|
|
908
|
+
self.runner_thread.terminate()
|
|
909
|
+
self.runner_thread.wait()
|
|
910
|
+
self.splash.setVisible(False)
|
|
911
|
+
self.get_action('runner_led').set_as_false()
|
|
912
|
+
self._ini_runner = False
|
|
913
|
+
self.set_action_enabled(OptimizerAction.RUN, False)
|
|
914
|
+
self.set_action_enabled(OptimizerAction.RESTART, False)
|
|
915
|
+
self.set_action_enabled(OptimizerAction.STOP, False)
|
|
916
|
+
self.set_action_enabled(OptimizerAction.INI_RUNNER, True) # reactivate the action only when the thread is finished
|
|
917
|
+
|
|
918
|
+
def clean_h5_temp(self):
|
|
919
|
+
if self.temp_path is not None:
|
|
920
|
+
try:
|
|
921
|
+
self.h5temp.close()
|
|
922
|
+
self.temp_path.cleanup()
|
|
923
|
+
except Exception as e:
|
|
924
|
+
logger.exception(str(e))
|
|
925
|
+
|
|
926
|
+
def optimization_done(self, dte: DataToExport):
|
|
927
|
+
self.go_to_best()
|
|
928
|
+
self.get_action(OptimizerAction.RUN).trigger()
|
|
929
|
+
self.optimization_done_signal.emit(dte)
|
|
930
|
+
self._optimizing_done_LED.set_as_true()
|
|
931
|
+
self._status_message_label.setText('Optimization Done')
|
|
932
|
+
|
|
933
|
+
def do_live_plot(self, dte_algo: DataToExport):
|
|
934
|
+
self.enl_index += 1
|
|
935
|
+
self._optimizing_step.setValue(self.enl_index)
|
|
936
|
+
self.model_class.update_plots()
|
|
937
|
+
|
|
938
|
+
dwa_data = dte_algo.pop(dte_algo.index_from_name_origin(DataNames.ProbedData, 'algo'))
|
|
939
|
+
|
|
940
|
+
actuators_values = [
|
|
941
|
+
dte_algo.get_data_from_name_origin(
|
|
942
|
+
act,
|
|
943
|
+
DataNames.Actuators)
|
|
944
|
+
.value() for act in self.modules_manager.selected_actuators_name]
|
|
945
|
+
|
|
946
|
+
best_individual = [
|
|
947
|
+
dte_algo.get_data_from_name_origin(
|
|
948
|
+
act,
|
|
949
|
+
DataNames.Individual)
|
|
950
|
+
.value() for act in self.modules_manager.selected_actuators_name]
|
|
951
|
+
|
|
952
|
+
fitness = dte_algo.get_data_from_name('fitness')
|
|
953
|
+
|
|
954
|
+
dte_live = DataToExport('Live', data=[
|
|
955
|
+
DataCalculated('Fitness',
|
|
956
|
+
data=[np.atleast_1d(dwa_data.value()), np.atleast_1d(fitness.value())],
|
|
957
|
+
labels=['Fitness', 'Fitness_best']
|
|
958
|
+
),])
|
|
959
|
+
for ind, act in enumerate(self.modules_manager.actuators):
|
|
960
|
+
dte_live.append([
|
|
961
|
+
DataCalculated(act.title,
|
|
962
|
+
data=[np.atleast_1d(actuators_values[ind]),
|
|
963
|
+
np.atleast_1d(best_individual[ind])],
|
|
964
|
+
labels=[act.title, f'{act.title}_best'],
|
|
965
|
+
units=act.units
|
|
966
|
+
),
|
|
967
|
+
])
|
|
968
|
+
|
|
969
|
+
if self.DISPLAY_BEST:
|
|
970
|
+
self.viewer_observable.show_data(dte_live)
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
self.enlargeable_saver.add_data('/RawData', dwa_data,
|
|
974
|
+
axis_values=actuators_values)
|
|
975
|
+
if len(best_individual) == 1 or (
|
|
976
|
+
len(best_individual) == 2 and self.enl_index >= 3):
|
|
977
|
+
self.update_data_plot(target_at=actuators_values,
|
|
978
|
+
crosshair_at=best_individual)
|
|
979
|
+
|
|
980
|
+
def update_data_plot(self, target_at=None, crosshair_at=None):
|
|
981
|
+
self.live_plotter.load_plot_data(remove_navigation=False,
|
|
982
|
+
crosshair_at=crosshair_at,
|
|
983
|
+
target_at=target_at)
|
|
984
|
+
|
|
985
|
+
def enable_controls_opti(self, enable: bool):
|
|
986
|
+
pass
|
|
987
|
+
|
|
988
|
+
def run_optimization(self):
|
|
989
|
+
if self.is_action_checked(OptimizerAction.RUN):
|
|
990
|
+
self._status_message_label.setText('Running Optimization')
|
|
991
|
+
self.set_action_enabled(OptimizerAction.SAVE, False)
|
|
992
|
+
self.get_action(OptimizerAction.RUN).set_icon('pause')
|
|
993
|
+
self.set_action_enabled(OptimizerAction.GO_TO_BEST, False)
|
|
994
|
+
self.set_action_checked(OptimizerAction.GO_TO, False)
|
|
995
|
+
self.set_action_enabled(OptimizerAction.GO_TO, False)
|
|
996
|
+
self.set_action_enabled(OptimizerAction.INI_RUNNER, False)
|
|
997
|
+
self.command_runner.emit(utils.ThreadCommand(OptimizerToRunner.START))
|
|
998
|
+
QtWidgets.QApplication.processEvents()
|
|
999
|
+
QtWidgets.QApplication.processEvents()
|
|
1000
|
+
self.command_runner.emit(utils.ThreadCommand(OptimizerToRunner.RUN))
|
|
1001
|
+
else:
|
|
1002
|
+
self._status_message_label.setText('Pausing Optimization')
|
|
1003
|
+
self.get_action(OptimizerAction.RUN).set_icon('run2')
|
|
1004
|
+
self.set_action_enabled(OptimizerAction.SAVE, True)
|
|
1005
|
+
self.command_runner.emit(utils.ThreadCommand(OptimizerToRunner.PAUSE))
|
|
1006
|
+
self.set_action_enabled(OptimizerAction.GO_TO_BEST, True)
|
|
1007
|
+
self.set_action_enabled(OptimizerAction.GO_TO, True)
|
|
1008
|
+
self.set_action_enabled(OptimizerAction.INI_RUNNER, True)
|
|
1009
|
+
QtWidgets.QApplication.processEvents()
|
|
1010
|
+
|
|
1011
|
+
def thread_status(self, status: utils.ThreadCommand):
|
|
1012
|
+
"""To reimplement if needed"""
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
|