pymodaq 4.1.5__py3-none-any.whl → 4.2.1__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 (80) hide show
  1. pymodaq/__init__.py +23 -4
  2. pymodaq/control_modules/daq_move.py +32 -73
  3. pymodaq/control_modules/daq_viewer.py +73 -98
  4. pymodaq/control_modules/daq_viewer_ui.py +2 -1
  5. pymodaq/control_modules/move_utility_classes.py +17 -7
  6. pymodaq/control_modules/utils.py +153 -5
  7. pymodaq/control_modules/viewer_utility_classes.py +31 -20
  8. pymodaq/dashboard.py +23 -5
  9. pymodaq/examples/tcp_client.py +97 -0
  10. pymodaq/extensions/__init__.py +4 -0
  11. pymodaq/extensions/bayesian/__init__.py +2 -0
  12. pymodaq/extensions/bayesian/bayesian_optimisation.py +673 -0
  13. pymodaq/extensions/bayesian/utils.py +403 -0
  14. pymodaq/extensions/daq_scan.py +4 -4
  15. pymodaq/extensions/daq_scan_ui.py +2 -1
  16. pymodaq/extensions/pid/pid_controller.py +12 -7
  17. pymodaq/extensions/pid/utils.py +9 -26
  18. pymodaq/extensions/utils.py +3 -0
  19. pymodaq/post_treatment/load_and_plot.py +42 -19
  20. pymodaq/resources/VERSION +1 -1
  21. pymodaq/resources/config_template.toml +9 -24
  22. pymodaq/resources/setup_plugin.py +1 -1
  23. pymodaq/utils/config.py +103 -5
  24. pymodaq/utils/daq_utils.py +35 -134
  25. pymodaq/utils/data.py +614 -95
  26. pymodaq/utils/enums.py +17 -1
  27. pymodaq/utils/factory.py +2 -2
  28. pymodaq/utils/gui_utils/custom_app.py +5 -2
  29. pymodaq/utils/gui_utils/dock.py +33 -4
  30. pymodaq/utils/gui_utils/utils.py +14 -1
  31. pymodaq/utils/h5modules/backends.py +9 -1
  32. pymodaq/utils/h5modules/data_saving.py +254 -57
  33. pymodaq/utils/h5modules/saving.py +1 -0
  34. pymodaq/utils/leco/__init__.py +25 -0
  35. pymodaq/utils/leco/daq_move_LECODirector.py +172 -0
  36. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +170 -0
  37. pymodaq/utils/leco/desktop.ini +2 -0
  38. pymodaq/utils/leco/director_utils.py +58 -0
  39. pymodaq/utils/leco/leco_director.py +88 -0
  40. pymodaq/utils/leco/pymodaq_listener.py +279 -0
  41. pymodaq/utils/leco/utils.py +41 -0
  42. pymodaq/utils/managers/action_manager.py +20 -6
  43. pymodaq/utils/managers/parameter_manager.py +6 -4
  44. pymodaq/utils/managers/roi_manager.py +63 -54
  45. pymodaq/utils/math_utils.py +1 -1
  46. pymodaq/utils/plotting/data_viewers/__init__.py +3 -1
  47. pymodaq/utils/plotting/data_viewers/base.py +286 -0
  48. pymodaq/utils/plotting/data_viewers/viewer.py +29 -202
  49. pymodaq/utils/plotting/data_viewers/viewer0D.py +94 -47
  50. pymodaq/utils/plotting/data_viewers/viewer1D.py +341 -174
  51. pymodaq/utils/plotting/data_viewers/viewer1Dbasic.py +1 -1
  52. pymodaq/utils/plotting/data_viewers/viewer2D.py +271 -181
  53. pymodaq/utils/plotting/data_viewers/viewerND.py +26 -22
  54. pymodaq/utils/plotting/items/crosshair.py +3 -3
  55. pymodaq/utils/plotting/items/image.py +2 -1
  56. pymodaq/utils/plotting/plotter/plotter.py +94 -0
  57. pymodaq/utils/plotting/plotter/plotters/__init__.py +0 -0
  58. pymodaq/utils/plotting/plotter/plotters/matplotlib_plotters.py +134 -0
  59. pymodaq/utils/plotting/plotter/plotters/qt_plotters.py +78 -0
  60. pymodaq/utils/plotting/utils/axes_viewer.py +1 -1
  61. pymodaq/utils/plotting/utils/filter.py +194 -147
  62. pymodaq/utils/plotting/utils/lineout.py +13 -11
  63. pymodaq/utils/plotting/utils/plot_utils.py +89 -12
  64. pymodaq/utils/scanner/__init__.py +0 -3
  65. pymodaq/utils/scanner/scan_config.py +1 -9
  66. pymodaq/utils/scanner/scan_factory.py +10 -36
  67. pymodaq/utils/scanner/scanner.py +3 -2
  68. pymodaq/utils/scanner/scanners/_1d_scanners.py +7 -5
  69. pymodaq/utils/scanner/scanners/_2d_scanners.py +36 -49
  70. pymodaq/utils/scanner/scanners/sequential.py +10 -4
  71. pymodaq/utils/scanner/scanners/tabular.py +10 -5
  72. pymodaq/utils/slicing.py +1 -1
  73. pymodaq/utils/tcp_ip/serializer.py +38 -5
  74. pymodaq/utils/tcp_ip/tcp_server_client.py +25 -17
  75. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/METADATA +4 -2
  76. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/RECORD +79 -63
  77. pymodaq/resources/config_scan_template.toml +0 -42
  78. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/WHEEL +0 -0
  79. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/entry_points.txt +0 -0
  80. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,673 @@
1
+ from typing import List, Union, Optional
2
+ import tempfile
3
+ from pathlib import Path
4
+
5
+ from qtpy import QtWidgets, QtCore
6
+ import time
7
+ import numpy as np
8
+
9
+
10
+ from pymodaq.utils.data import DataToExport, DataToActuators, DataCalculated, DataActuator
11
+ from pymodaq.utils.plotting.data_viewers.viewer0D import Viewer0D
12
+ from pymodaq.utils.plotting.data_viewers.viewer import ViewerDispatcher, ViewersEnum
13
+ from pymodaq.extensions.bayesian.utils import (get_bayesian_models, BayesianModelGeneric,
14
+ BayesianAlgorithm, UtilityKind,
15
+ UtilityParameters, StopType, StoppingParameters)
16
+ from pymodaq.utils.gui_utils import QLED
17
+ from pymodaq.utils.managers.modules_manager import ModulesManager
18
+ from pymodaq.utils import gui_utils as gutils
19
+ from pymodaq.utils import daq_utils as utils
20
+ from pymodaq.utils.parameter import utils as putils
21
+ from pymodaq.utils.h5modules.saving import H5Saver
22
+ from pymodaq.utils.h5modules.data_saving import DataEnlargeableSaver
23
+ from pymodaq.post_treatment.load_and_plot import LoaderPlotter
24
+ from pymodaq.extensions.bayesian.utils import BayesianConfig
25
+ from pymodaq.utils import config as configmod
26
+ from pymodaq.utils.logger import set_logger, get_module_name
27
+
28
+
29
+ EXTENSION_NAME = 'BayesianOptimisation'
30
+ CLASS_NAME = 'BayesianOptimisation'
31
+
32
+ logger = set_logger(get_module_name(__file__))
33
+
34
+
35
+ class BayesianOptimisation(gutils.CustomApp):
36
+ """ PyMoDAQ extension of the DashBoard to perform the optimization of a target signal
37
+ taken form the detectors as a function of one or more parameters controlled by the actuators.
38
+ """
39
+
40
+ command_runner = QtCore.Signal(utils.ThreadCommand)
41
+ models = get_bayesian_models()
42
+ explored_viewer_name = 'algo/ProbedData'
43
+ optimisation_done_signal = QtCore.Signal(DataToExport)
44
+
45
+ params = [
46
+ {'title': 'Main Settings:', 'name': 'main_settings', 'expanded': True, 'type': 'group',
47
+ 'children': [
48
+ {'title': 'Utility Function:', 'name': 'utility', 'expanded': False, 'type': 'group',
49
+ 'children': [
50
+ {'title': 'Kind', 'name': 'kind', 'type': 'list',
51
+ 'limits': UtilityKind.to_dict_value()},
52
+ {'title': 'Kappa:', 'name': 'kappa', 'type': 'slide', 'value': 2.576,
53
+ 'min': 0.001, 'max': 100, 'subtype': 'log',
54
+ 'tip': 'Parameter to indicate how closed are the next parameters sampled.'
55
+ 'Higher value = favors spaces that are least explored.'
56
+ 'Lower value = favors spaces where the regression function is the '
57
+ 'highest.'},
58
+ {'title': 'Kappa actual:', 'name': 'kappa_actual', 'type': 'float', 'value': 2.576,
59
+ 'tip': 'Current value of the kappa parameter', 'readonly': True},
60
+ {'title': 'xi:', 'name': 'xi', 'type': 'slide', 'value': 0,
61
+ 'tip': 'Governs the exploration/exploitation tradeoff.'
62
+ 'Lower prefers exploitation, higher prefers exploration.'},
63
+ {'title': 'Kappa decay:', 'name': 'kappa_decay', 'type': 'float', 'value': 0.9,
64
+ 'tip': 'kappa is multiplied by this factor every iteration.'},
65
+ {'title': 'Kappa decay delay:', 'name': 'kappa_decay_delay', 'type': 'int',
66
+ 'value': 20, 'tip': 'Number of iterations that must have passed before applying '
67
+ 'the decay to kappa.'},
68
+ ]},
69
+ {'title': 'Stopping Criteria:', 'name': 'stopping', 'expanded': False, 'type': 'group',
70
+ 'children': [
71
+ {'title': 'Niteration', 'name': 'niter', 'type': 'int', 'value': 100, 'min': -1},
72
+ {'title': 'Type:', 'name': 'stop_type', 'type': 'list',
73
+ 'limits': StopType.names()},
74
+ {'title': 'Tolerance', 'name': 'tolerance', 'type': 'slide', 'value': 1e-2,
75
+ 'min': 1e-8, 'max': 1, 'subtype': 'log',},
76
+ {'title': 'Npoints', 'name': 'npoints', 'type': 'int', 'value': 5, 'min': 1},
77
+ ]},
78
+ {'title': 'Ini. State', 'name': 'ini_random', 'type': 'int', 'value': 5},
79
+ {'title': 'bounds', 'name': 'bounds', 'type': 'group', 'children': []},
80
+ ]},
81
+
82
+ {'title': 'Models', 'name': 'models', 'type': 'group', 'expanded': True, 'visible': True,
83
+ 'children': [
84
+ {'title': 'Models class:', 'name': 'model_class', 'type': 'list',
85
+ 'limits': [d['name'] for d in models]},
86
+ {'title': 'Ini Model', 'name': 'ini_model', 'type': 'action', },
87
+ {'title': 'Ini Algo', 'name': 'ini_runner', 'type': 'action', 'enabled': False},
88
+ {'title': 'Model params:', 'name': 'model_params', 'type': 'group', 'children': []},
89
+ ]},
90
+ {'title': 'Move settings:', 'name': 'move_settings', 'expanded': True, 'type': 'group',
91
+ 'visible': False, 'children': [
92
+ {'title': 'Units:', 'name': 'units', 'type': 'str', 'value': ''}]},
93
+
94
+ ]
95
+
96
+ def __init__(self, dockarea, dashboard):
97
+ super().__init__(dockarea, dashboard)
98
+
99
+ self.algorithm: Optional[BayesianAlgorithm] = None
100
+ self.viewer_fitness: Optional[Viewer0D] = None
101
+ self.viewer_observable: Optional[ViewerDispatcher] = None
102
+ self.model_class: Optional[BayesianModelGeneric] = None
103
+ self._save_main_settings = True
104
+ self._modules_manager = ModulesManager(self.dashboard.detector_modules,
105
+ self.dashboard.actuators_modules)
106
+ self.modules_manager.actuators_changed[list].connect(self.update_actuators)
107
+ self.modules_manager.settings.child('data_dimensions').setOpts(expanded=False)
108
+ self.modules_manager.settings.child('actuators_positions').setOpts(expanded=False)
109
+ self.setup_ui()
110
+
111
+ self.bayesian_config = BayesianConfig()
112
+ self.mainsettings_saver_loader = configmod.ConfigSaverLoader(
113
+ self.settings.child('main_settings'), self.bayesian_config)
114
+
115
+ self.h5temp: H5Saver = None
116
+ self.temp_path: tempfile.TemporaryDirectory = None
117
+
118
+ self.enlargeable_saver: DataEnlargeableSaver = None
119
+ self.live_plotter = LoaderPlotter(self.dockarea)
120
+
121
+ self.enl_index = 0
122
+
123
+ self.settings.child('models', 'ini_model').sigActivated.connect(
124
+ self.get_action('ini_model').trigger)
125
+
126
+ self.settings.child('models', 'ini_runner').sigActivated.connect(
127
+ self.get_action('ini_runner').trigger)
128
+
129
+ @property
130
+ def modules_manager(self) -> ModulesManager:
131
+ return self._modules_manager
132
+
133
+ def setup_docks(self):
134
+ """
135
+ to be subclassed to setup the docks layout
136
+ for instance:
137
+
138
+ self.docks['ADock'] = gutils.Dock('ADock name)
139
+ self.dockarea.addDock(self.docks['ADock"])
140
+ self.docks['AnotherDock'] = gutils.Dock('AnotherDock name)
141
+ self.dockarea.addDock(self.docks['AnotherDock"], 'bottom', self.docks['ADock"])
142
+
143
+ See Also
144
+ ########
145
+ pyqtgraph.dockarea.Dock
146
+ """
147
+ self.docks['settings'] = gutils.Dock('Settings')
148
+ self.dockarea.addDock(self.docks['settings'])
149
+ splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
150
+ self.docks['settings'].addWidget(splitter)
151
+ splitter.addWidget(self.settings_tree)
152
+ splitter.addWidget(self.modules_manager.settings_tree)
153
+ self.modules_manager.show_only_control_modules(False)
154
+ splitter.setSizes((int(self.dockarea.height() / 2),
155
+ int(self.dockarea.height() / 2)))
156
+
157
+ widget_observable = QtWidgets.QWidget()
158
+ widget_observable.setLayout(QtWidgets.QHBoxLayout())
159
+ observable_dockarea = gutils.DockArea()
160
+ widget_observable.layout().addWidget(observable_dockarea)
161
+ self.viewer_observable = ViewerDispatcher(observable_dockarea, direction='bottom')
162
+ self.docks['observable'] = gutils.Dock('Observable')
163
+ self.dockarea.addDock(self.docks['observable'], 'right', self.docks['settings'])
164
+ self.docks['observable'].addWidget(widget_observable)
165
+
166
+ if len(self.models) != 0:
167
+ self.get_set_model_params(self.models[0]['name'])
168
+
169
+ def get_set_model_params(self, model_name):
170
+ self.settings.child('models', 'model_params').clearChildren()
171
+ if len(self.models) > 0:
172
+ model_class = utils.find_dict_in_list_from_key_val(self.models, 'name', model_name)['class']
173
+ params = getattr(model_class, 'params')
174
+ self.settings.child('models', 'model_params').addChildren(params)
175
+
176
+ def setup_menu(self):
177
+ '''
178
+ to be subclassed
179
+ create menu for actions contained into the self.actions_manager, for instance:
180
+
181
+ For instance:
182
+
183
+ file_menu = self.menubar.addMenu('File')
184
+ self.actions_manager.affect_to('load', file_menu)
185
+ self.actions_manager.affect_to('save', file_menu)
186
+
187
+ file_menu.addSeparator()
188
+ self.actions_manager.affect_to('quit', file_menu)
189
+ '''
190
+ pass
191
+
192
+ def value_changed(self, param):
193
+ ''' to be subclassed for actions to perform when one of the param's value in self.settings is changed
194
+
195
+ For instance:
196
+ if param.name() == 'do_something':
197
+ if param.value():
198
+ print('Do something')
199
+ self.settings.child('main_settings', 'something_done').setValue(False)
200
+
201
+ Parameters
202
+ ----------
203
+ param: (Parameter) the parameter whose value just changed
204
+ '''
205
+ if param.name() == 'model_class':
206
+ self.get_set_model_params(param.value())
207
+ elif param.name() in putils.iter_children(self.settings.child('models', 'model_params'), []):
208
+ if self.model_class is not None:
209
+ self.model_class.update_settings(param)
210
+ elif param.name() in putils.iter_children(
211
+ self.settings.child('main_settings', 'utility'), []):
212
+ if param.name() != 'kappa_actual':
213
+ self.update_utility_function()
214
+ elif param.name() in putils.iter_children(
215
+ self.settings.child('main_settings', 'bounds'), []):
216
+ self.update_bounds()
217
+ elif param.name() in putils.iter_children(
218
+ self.settings.child('main_settings', 'stopping'), []):
219
+ self.update_stopping_criteria()
220
+ if self._save_main_settings and param.name() in putils.iter_children(
221
+ self.settings.child('main_settings'), []):
222
+ self.mainsettings_saver_loader.save_config()
223
+
224
+ def update_utility_function(self):
225
+ utility_settings = self.settings.child('main_settings', 'utility')
226
+ uparams = UtilityParameters(utility_settings['kind'], utility_settings['kappa'],
227
+ utility_settings['xi'], utility_settings['kappa_decay'],
228
+ utility_settings['kappa_decay_delay'])
229
+ self.command_runner.emit(utils.ThreadCommand('utility', uparams))
230
+
231
+ def get_stopping_parameters(self) -> StoppingParameters:
232
+ stopping_settings = self.settings.child('main_settings', 'stopping')
233
+ stopping_params = StoppingParameters(stopping_settings['niter'],
234
+ stopping_settings['stop_type'],
235
+ stopping_settings['tolerance'],
236
+ stopping_settings['npoints'])
237
+ return stopping_params
238
+
239
+ def update_stopping_criteria(self):
240
+ self.command_runner.emit(utils.ThreadCommand('stopping', self.get_stopping_parameters()))
241
+
242
+ def update_bounds(self):
243
+ bounds = {}
244
+ for child in self.settings.child('main_settings', 'bounds').children():
245
+ bounds[child.name()] = (child['min'], child['max'])
246
+
247
+ self.command_runner.emit(utils.ThreadCommand('bounds', bounds))
248
+
249
+ def setup_actions(self):
250
+ logger.debug('setting actions')
251
+ self.add_action('quit', 'Quit', 'close2', "Quit program")
252
+ self.add_action('ini_model', 'Init Model', 'ini')
253
+ self.add_widget('model_led', QLED, toolbar=self.toolbar)
254
+ self.add_action('ini_runner', 'Init the Optimisation Algorithm', 'ini', checkable=True,
255
+ enabled=False)
256
+ self.add_widget('runner_led', QLED, toolbar=self.toolbar)
257
+ self.add_action('run', 'Run Optimisation', 'run2', checkable=True, enabled=False)
258
+ self.add_action('gotobest', 'Got to best individual', 'move_contour', enabled=False,
259
+ tip='Go to the best individual guessed by the algorithm')
260
+ logger.debug('actions set')
261
+
262
+ def connect_things(self):
263
+ logger.debug('connecting things')
264
+ self.connect_action('quit', self.quit, )
265
+ self.connect_action('ini_model', self.ini_model)
266
+ self.connect_action('ini_runner', self.ini_optimisation_runner)
267
+ self.connect_action('run', self.run_optimisation)
268
+ self.connect_action('gotobest', self.go_to_best)
269
+
270
+ def go_to_best(self):
271
+ best_individual = self.algorithm.best_individual
272
+ actuators = self.modules_manager.selected_actuators_name
273
+ dte_act = DataToActuators('best', data=[
274
+ DataActuator(actuators[ind], data=float(best_individual[ind])) for ind in range(len(best_individual))
275
+ ],
276
+ mode='abs')
277
+ self.modules_manager.connect_actuators(True)
278
+ self.modules_manager.move_actuators(dte_act, polling=True)
279
+ self.modules_manager.connect_actuators(False)
280
+
281
+ self.modules_manager.grab_datas()
282
+
283
+ def quit(self):
284
+ self.dockarea.parent().close()
285
+ self.clean_h5_temp()
286
+
287
+ def set_model(self):
288
+ model_name = self.settings.child('models', 'model_class').value()
289
+ self.model_class = utils.find_dict_in_list_from_key_val(
290
+ self.models, 'name', model_name)['class'](self)
291
+ self.model_class.ini_model_base()
292
+
293
+ def ini_temp_file(self):
294
+ self.clean_h5_temp()
295
+
296
+ self.h5temp = H5Saver()
297
+ self.temp_path = tempfile.TemporaryDirectory(prefix='pymo')
298
+ addhoc_file_path = Path(self.temp_path.name).joinpath('bayesian_temp_data.h5')
299
+ self.h5temp.init_file(custom_naming=True, addhoc_file_path=addhoc_file_path)
300
+ act_names = [child.name() for child in self.settings.child( 'main_settings',
301
+ 'bounds').children()]
302
+ act_units = [self.modules_manager.get_mod_from_name(act_name, 'act').units for act_name
303
+ in act_names]
304
+ self.enlargeable_saver = DataEnlargeableSaver(
305
+ self.h5temp,
306
+ enl_axis_names=act_names,
307
+ enl_axis_units=act_units)
308
+
309
+ def ini_live_plot(self):
310
+ self.live_plotter.h5saver = self.h5temp
311
+ act_names = [child.name() for child in self.settings.child('main_settings',
312
+ 'bounds').children()]
313
+ act_units = [self.modules_manager.get_mod_from_name(act_name, 'act').units for act_name
314
+ in act_names]
315
+ if len(act_names) == 1:
316
+ viewer_enum = 'Viewer1D'
317
+ elif len(act_names) == 2:
318
+ viewer_enum = 'Viewer2D'
319
+ else:
320
+ viewer_enum = 'ViewerND'
321
+ viewers = self.live_plotter.prepare_viewers([viewer_enum],
322
+ viewers_name=[self.explored_viewer_name])
323
+ for viewer in viewers:
324
+ if viewer.has_action('crosshair'):
325
+ viewer.get_action('crosshair').trigger()
326
+ if hasattr(viewer.view, 'collapse_lineout_widgets'):
327
+ viewer.view.collapse_lineout_widgets()
328
+ if viewer.has_action('sort'):
329
+ if not viewer.is_action_checked('sort'):
330
+ viewer.get_action('sort').trigger()
331
+ if viewer.has_action('scatter'):
332
+ if not viewer.is_action_checked('scatter'):
333
+ viewer.get_action('scatter').trigger()
334
+
335
+ QtWidgets.QApplication.processEvents()
336
+ win_width = self.dockarea.width()
337
+ self.docks['settings'].container().setSizes((int(win_width / 5),
338
+ int(2 * win_width / 5),
339
+ int(2 * win_width / 5), 10, 10))
340
+
341
+ def update_actuators(self, actuators: List[str]):
342
+ if self.is_action_checked('ini_runner'):
343
+ self.get_action('ini_runner').trigger()
344
+ QtWidgets.QApplication.processEvents()
345
+
346
+ self._save_main_settings = False
347
+
348
+ for child in self.settings.child('main_settings', 'bounds').children():
349
+ self.settings.child('main_settings', 'bounds').removeChild(child)
350
+ params = []
351
+ for actuator in actuators:
352
+ params.append({'title': actuator, 'name': actuator, 'type': 'group', 'children': [
353
+ {'title': 'min', 'name': 'min', 'type': 'float', 'value': -5},
354
+ {'title': 'max', 'name': 'max', 'type': 'float', 'value': 5},
355
+ ]})
356
+ self.settings.child('main_settings', 'bounds').addChildren(params)
357
+ self.mainsettings_saver_loader.base_path = [self.model_class.__class__.__name__] + \
358
+ self.modules_manager.selected_actuators_name
359
+ self.mainsettings_saver_loader.load_config()
360
+ self._save_main_settings = True
361
+
362
+ def format_bounds(self):
363
+ bound_dict = {}
364
+ for bound in self.settings.child('main_settings', 'bounds').children():
365
+ bound_dict.update({bound.name(): (bound['min'], bound['max'])})
366
+ return bound_dict
367
+
368
+ def set_algorithm(self):
369
+ self.algorithm = BayesianAlgorithm(
370
+ ini_random=self.settings['main_settings', 'ini_random'],
371
+ bounds=self.format_bounds(),)
372
+
373
+ def ini_model(self):
374
+ try:
375
+ if self.model_class is None:
376
+ self.set_model()
377
+
378
+ self.modules_manager.selected_actuators_name = self.model_class.actuators_name
379
+ self.modules_manager.selected_detectors_name = self.model_class.detectors_name
380
+
381
+ self.enable_controls_opti(True)
382
+ self.get_action('model_led').set_as_true()
383
+ self.set_action_enabled('ini_model', False)
384
+
385
+ self.viewer_observable.update_viewers(['Viewer0D', 'Viewer0D'],
386
+ ['Fitness', 'Individual'])
387
+ self.settings.child('models', 'ini_model').setValue(True)
388
+ self.settings.child('models', 'ini_runner').setOpts(enabled=True)
389
+ self.set_action_enabled('ini_runner', True)
390
+
391
+ self.mainsettings_saver_loader.base_path = [self.model_class.__class__.__name__] + \
392
+ self.modules_manager.selected_actuators_name
393
+ self.mainsettings_saver_loader.load_config()
394
+
395
+ try: # this is correct for Default Model and probably for all models...
396
+ self.model_class.settings.child('optimizing_signal', 'data_probe').activate()
397
+ except Exception:
398
+ pass
399
+
400
+ except Exception as e:
401
+ logger.exception(str(e))
402
+
403
+ def ini_optimisation_runner(self):
404
+ if self.is_action_checked('ini_runner'):
405
+ self.set_algorithm()
406
+
407
+ self.settings.child('models', 'ini_runner').setValue(True)
408
+ self.enl_index = 0
409
+
410
+ self.ini_temp_file()
411
+ self.ini_live_plot()
412
+
413
+ self.runner_thread = QtCore.QThread()
414
+ runner = OptimisationRunner(self.model_class, self.modules_manager, self.algorithm,
415
+ self.get_stopping_parameters())
416
+ self.runner_thread.runner = runner
417
+ runner.algo_output_signal.connect(self.process_output)
418
+ runner.algo_finished.connect(self.optimisation_done)
419
+ self.command_runner.connect(runner.queue_command)
420
+
421
+ runner.moveToThread(self.runner_thread)
422
+
423
+ self.runner_thread.start()
424
+ self.get_action('runner_led').set_as_true()
425
+ self.set_action_enabled('run', True)
426
+ self.model_class.runner_initialized()
427
+ self.update_utility_function()
428
+ else:
429
+ if self.is_action_checked('run'):
430
+ self.get_action('run').trigger()
431
+ QtWidgets.QApplication.processEvents()
432
+ self.runner_thread.terminate()
433
+ self.get_action('runner_led').set_as_false()
434
+
435
+ def clean_h5_temp(self):
436
+ if self.temp_path is not None:
437
+ try:
438
+ self.h5temp.close()
439
+ self.temp_path.cleanup()
440
+ except Exception as e:
441
+ logger.exception(str(e))
442
+
443
+ def optimisation_done(self, dte: DataToExport):
444
+ self.go_to_best()
445
+ self.optimisation_done_signal.emit(dte)
446
+
447
+ def process_output(self, dte: DataToExport):
448
+
449
+ self.enl_index += 1
450
+ dwa_kappa = dte.remove(dte.get_data_from_name('kappa'))
451
+ self.settings.child('main_settings', 'utility', 'kappa_actual').setValue(
452
+ float(dwa_kappa[0][0])
453
+ )
454
+
455
+ dwa_data = dte.remove(dte.get_data_from_name('ProbedData'))
456
+ dwa_actuators: DataActuator = dte.remove(dte.get_data_from_name('Actuators'))
457
+ self.viewer_observable.show_data(dte)
458
+
459
+ # dwa_observations = self.algorithm.get_dwa_obervations(
460
+ # self.modules_manager.selected_actuators_name)
461
+ self.model_class.update_plots()
462
+
463
+ best_individual = dte.get_data_from_name('Individual')
464
+ best_indiv_as_list = [float(best_individual[ind][0]) for ind in range(len(best_individual))]
465
+
466
+
467
+ self.enlargeable_saver.add_data('/RawData', dwa_data,
468
+ axis_values=dwa_actuators.values())
469
+ if len(best_indiv_as_list) == 1 or (
470
+ len(best_indiv_as_list) == 2 and self.enl_index >= 3):
471
+ self.update_data_plot(target_at=dwa_actuators.values(),
472
+ crosshair_at=best_indiv_as_list)
473
+
474
+ def update_data_plot(self, target_at=None, crosshair_at=None):
475
+ self.live_plotter.load_plot_data(remove_navigation=False,
476
+ crosshair_at=crosshair_at,
477
+ target_at=target_at)
478
+
479
+ def enable_controls_opti(self, enable: bool):
480
+ pass
481
+
482
+ def run_optimisation(self):
483
+ if self.is_action_checked('run'):
484
+ self.get_action('run').set_icon('pause')
485
+ self.command_runner.emit(utils.ThreadCommand('start', {}))
486
+ QtWidgets.QApplication.processEvents()
487
+ QtWidgets.QApplication.processEvents()
488
+ self.command_runner.emit(utils.ThreadCommand('run', {}))
489
+ else:
490
+ self.get_action('run').set_icon('run2')
491
+ self.command_runner.emit(utils.ThreadCommand('stop', {}))
492
+ self.set_action_enabled('gotobest', True)
493
+
494
+ QtWidgets.QApplication.processEvents()
495
+
496
+
497
+ class OptimisationRunner(QtCore.QObject):
498
+ algo_output_signal = QtCore.Signal(DataToExport)
499
+ algo_finished = QtCore.Signal(DataToExport)
500
+
501
+ def __init__(self, model_class: BayesianModelGeneric, modules_manager: ModulesManager,
502
+ algorithm: BayesianAlgorithm, stopping_params: StoppingParameters):
503
+ super().__init__()
504
+
505
+ self.det_done_datas: DataToExport = None
506
+ self.input_from_dets: float = None
507
+ self.outputs: List[np.ndarray] = []
508
+ self.dte_actuators: DataToExport = None
509
+ self.stopping_params: StoppingParameters = stopping_params
510
+
511
+ self.model_class: BayesianModelGeneric = model_class
512
+ self.modules_manager: ModulesManager = modules_manager
513
+
514
+ self.running = True
515
+
516
+ self.optimisation_algorithm: BayesianAlgorithm = algorithm
517
+
518
+ self._ind_iter: int = 0
519
+
520
+ @QtCore.Slot(utils.ThreadCommand)
521
+ def queue_command(self, command: utils.ThreadCommand):
522
+ """
523
+ """
524
+ if command.command == "run":
525
+ self.run_opti(**command.attribute)
526
+
527
+ elif command.command == "stop":
528
+ self.running = False
529
+
530
+ elif command.command == 'utility':
531
+ utility_params: UtilityParameters = command.attribute
532
+ self.optimisation_algorithm.set_utility_function(
533
+ utility_params.kind,
534
+ kappa=utility_params.kappa,
535
+ xi=utility_params.xi,
536
+ kappa_decay=utility_params.kappa_decay,
537
+ kappa_decay_delay=utility_params.kappa_decay_delay)
538
+
539
+ elif command.command == 'stopping':
540
+ self.stopping_params: StoppingParameters = command.attribute
541
+
542
+ elif command.command == 'bounds':
543
+ self.optimisation_algorithm.set_bounds(command.attribute)
544
+
545
+ def run_opti(self, sync_detectors=True, sync_acts=True):
546
+ """Start the optimisation loop
547
+
548
+ Parameters
549
+ ----------
550
+ sync_detectors: (bool) if True will make sure all selected detectors (if any) all got their data before calling
551
+ the model
552
+ sync_acts: (bool) if True will make sure all selected actuators (if any) all reached their target position
553
+ before calling the model
554
+ """
555
+ self.running = True
556
+ converged = False
557
+ try:
558
+ if sync_detectors:
559
+ self.modules_manager.connect_detectors()
560
+ if sync_acts:
561
+ self.modules_manager.connect_actuators()
562
+
563
+ self.current_time = time.perf_counter()
564
+ logger.info('Optimisation loop starting')
565
+ while self.running:
566
+ self._ind_iter += 1
567
+
568
+ next_target = self.optimisation_algorithm.ask()
569
+
570
+ self.outputs = next_target
571
+ self.output_to_actuators: DataToActuators =\
572
+ self.model_class.convert_output(
573
+ self.outputs,
574
+ best_individual=self.optimisation_algorithm.best_individual
575
+ )
576
+
577
+ self.modules_manager.move_actuators(self.output_to_actuators,
578
+ self.output_to_actuators.mode,
579
+ polling=sync_acts)
580
+
581
+ # Do the evaluation (measurements)
582
+ self.det_done_datas = self.modules_manager.grab_datas()
583
+ self.input_from_dets = self.model_class.convert_input(self.det_done_datas)
584
+
585
+ # Run the algo internal mechanic
586
+ self.optimisation_algorithm.tell(float(self.input_from_dets))
587
+
588
+ dte = DataToExport('algo',
589
+ data=[self.individual_as_data(
590
+ np.array([self.optimisation_algorithm.best_fitness]),
591
+ 'Fitness'),
592
+ self.individual_as_data(
593
+ self.optimisation_algorithm.best_individual,
594
+ 'Individual'),
595
+ DataCalculated('ProbedData',
596
+ data=[np.array([self.input_from_dets])],
597
+ ),
598
+ self.output_to_actuators.merge_as_dwa('Data0D',
599
+ 'Actuators'),
600
+ DataCalculated(
601
+ 'kappa',
602
+ data=[
603
+ np.array([self.optimisation_algorithm.kappa])])
604
+ ])
605
+ self.algo_output_signal.emit(dte)
606
+
607
+ self.optimisation_algorithm.update_utility_function()
608
+
609
+ if self.optimisation_algorithm.stopping(self._ind_iter, self.stopping_params):
610
+ converged = True
611
+ break
612
+
613
+ self.current_time = time.perf_counter()
614
+ QtWidgets.QApplication.processEvents()
615
+
616
+ logger.info('Optimisation loop exiting')
617
+ self.modules_manager.connect_actuators(False)
618
+ self.modules_manager.connect_detectors(False)
619
+
620
+ if converged:
621
+ self.algo_finished.emit(dte)
622
+
623
+ except Exception as e:
624
+ logger.exception(str(e))
625
+
626
+ @staticmethod
627
+ def individual_as_data(individual: np.ndarray, name: str = 'Individual') -> DataCalculated:
628
+ return DataCalculated(name, data=[np.atleast_1d(np.squeeze(coordinate)) for coordinate in
629
+ np.atleast_1d(np.squeeze(individual))])
630
+
631
+
632
+ def main(init_qt=True):
633
+ import sys
634
+ from pathlib import Path
635
+ from pymodaq.utils.daq_utils import get_set_preset_path
636
+
637
+ if init_qt: # used for the test suite
638
+ app = QtWidgets.QApplication(sys.argv)
639
+
640
+ import qdarkstyle
641
+ app.setStyleSheet(qdarkstyle.load_stylesheet())
642
+
643
+ from pymodaq.dashboard import DashBoard
644
+
645
+ win = QtWidgets.QMainWindow()
646
+ area = gutils.dock.DockArea()
647
+ win.setCentralWidget(area)
648
+ win.resize(1000, 500)
649
+ win.setWindowTitle('PyMoDAQ Dashboard')
650
+
651
+ dashboard = DashBoard(area)
652
+ daq_scan = None
653
+ file = Path(get_set_preset_path()).joinpath(f"{'beam_steering_mock'}.xml")
654
+
655
+ if file.exists():
656
+ dashboard.set_preset_mode(file)
657
+ daq_scan = dashboard.load_bayesian()
658
+ else:
659
+ msgBox = QtWidgets.QMessageBox()
660
+ msgBox.setText(f"The default file specified in the configuration file does not exists!\n"
661
+ f"{file}\n"
662
+ f"Impossible to load the DAQScan Module")
663
+ msgBox.setStandardButtons(msgBox.Ok)
664
+ ret = msgBox.exec()
665
+
666
+ if init_qt:
667
+ sys.exit(app.exec_())
668
+ return dashboard, daq_scan, win
669
+
670
+
671
+ if __name__ == '__main__':
672
+ main()
673
+