pymodaq 5.0.18__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.

Files changed (92) hide show
  1. pymodaq/__init__.py +23 -11
  2. pymodaq/control_modules/__init__.py +1 -0
  3. pymodaq/control_modules/daq_move.py +451 -246
  4. pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
  5. pymodaq/control_modules/daq_move_ui/factory.py +48 -0
  6. pymodaq/control_modules/{daq_move_ui.py → daq_move_ui/ui_base.py} +168 -210
  7. pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
  8. pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
  9. pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
  10. pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
  11. pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
  12. pymodaq/control_modules/daq_viewer.py +113 -101
  13. pymodaq/control_modules/daq_viewer_ui.py +41 -31
  14. pymodaq/control_modules/mocks.py +2 -2
  15. pymodaq/control_modules/move_utility_classes.py +113 -41
  16. pymodaq/control_modules/thread_commands.py +137 -0
  17. pymodaq/control_modules/ui_utils.py +72 -0
  18. pymodaq/control_modules/utils.py +107 -63
  19. pymodaq/control_modules/viewer_utility_classes.py +13 -17
  20. pymodaq/dashboard.py +1294 -625
  21. pymodaq/examples/qt_less_standalone_module.py +48 -11
  22. pymodaq/extensions/__init__.py +8 -3
  23. pymodaq/extensions/adaptive/__init__.py +2 -0
  24. pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
  25. pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
  26. pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
  27. pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
  28. pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
  29. pymodaq/extensions/adaptive/utils.py +123 -0
  30. pymodaq/extensions/bayesian/__init__.py +1 -1
  31. pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
  32. pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
  33. pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
  34. pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
  35. pymodaq/extensions/bayesian/utils.py +71 -297
  36. pymodaq/extensions/daq_logger/daq_logger.py +7 -12
  37. pymodaq/extensions/daq_logger/h5logging.py +1 -1
  38. pymodaq/extensions/daq_scan.py +30 -55
  39. pymodaq/extensions/data_mixer/__init__.py +0 -0
  40. pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
  41. pymodaq/extensions/data_mixer/data_mixer.py +262 -0
  42. pymodaq/extensions/data_mixer/model.py +108 -0
  43. pymodaq/extensions/data_mixer/models/__init__.py +0 -0
  44. pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
  45. pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
  46. pymodaq/extensions/data_mixer/parser.py +53 -0
  47. pymodaq/extensions/data_mixer/utils.py +23 -0
  48. pymodaq/extensions/h5browser.py +3 -34
  49. pymodaq/extensions/optimizers_base/__init__.py +0 -0
  50. pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
  51. pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
  52. pymodaq/extensions/optimizers_base/utils.py +427 -0
  53. pymodaq/extensions/pid/actuator_controller.py +3 -2
  54. pymodaq/extensions/pid/daq_move_PID.py +107 -30
  55. pymodaq/extensions/pid/pid_controller.py +613 -287
  56. pymodaq/extensions/pid/utils.py +8 -5
  57. pymodaq/extensions/utils.py +17 -2
  58. pymodaq/resources/config_template.toml +57 -0
  59. pymodaq/resources/preset_default.xml +1 -1
  60. pymodaq/utils/config.py +10 -4
  61. pymodaq/utils/daq_utils.py +14 -0
  62. pymodaq/utils/data.py +1 -0
  63. pymodaq/utils/gui_utils/loader_utils.py +25 -15
  64. pymodaq/utils/h5modules/module_saving.py +134 -22
  65. pymodaq/utils/leco/daq_move_LECODirector.py +123 -84
  66. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +84 -97
  67. pymodaq/utils/leco/director_utils.py +32 -16
  68. pymodaq/utils/leco/leco_director.py +104 -27
  69. pymodaq/utils/leco/pymodaq_listener.py +186 -97
  70. pymodaq/utils/leco/rpc_method_definitions.py +43 -0
  71. pymodaq/utils/leco/utils.py +25 -25
  72. pymodaq/utils/managers/batchscan_manager.py +12 -11
  73. pymodaq/utils/managers/modules_manager.py +74 -33
  74. pymodaq/utils/managers/overshoot_manager.py +11 -10
  75. pymodaq/utils/managers/preset_manager.py +100 -64
  76. pymodaq/utils/managers/preset_manager_utils.py +163 -107
  77. pymodaq/utils/managers/remote_manager.py +21 -16
  78. pymodaq/utils/scanner/scan_factory.py +12 -3
  79. pymodaq/utils/scanner/scan_selector.py +1 -3
  80. pymodaq/utils/scanner/scanner.py +35 -6
  81. pymodaq/utils/scanner/scanners/_1d_scanners.py +15 -46
  82. pymodaq/utils/scanner/scanners/_2d_scanners.py +21 -68
  83. pymodaq/utils/scanner/scanners/sequential.py +50 -31
  84. pymodaq/utils/scanner/scanners/tabular.py +45 -28
  85. {pymodaq-5.0.18.dist-info → pymodaq-5.1.0.dist-info}/METADATA +7 -6
  86. pymodaq-5.1.0.dist-info/RECORD +154 -0
  87. {pymodaq-5.0.18.dist-info → pymodaq-5.1.0.dist-info}/entry_points.txt +0 -2
  88. pymodaq/extensions/bayesian/bayesian_optimisation.py +0 -690
  89. pymodaq/utils/leco/desktop.ini +0 -2
  90. pymodaq-5.0.18.dist-info/RECORD +0 -121
  91. {pymodaq-5.0.18.dist-info → pymodaq-5.1.0.dist-info}/WHEEL +0 -0
  92. {pymodaq-5.0.18.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
+