pymodaq 5.1.6__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.
- pymodaq/__init__.py +98 -0
- pymodaq/control_modules/__init__.py +1 -0
- pymodaq/control_modules/daq_move.py +1238 -0
- 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/ui_base.py +359 -0
- 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 +1517 -0
- pymodaq/control_modules/daq_viewer_ui.py +407 -0
- pymodaq/control_modules/mocks.py +57 -0
- pymodaq/control_modules/move_utility_classes.py +1141 -0
- pymodaq/control_modules/thread_commands.py +137 -0
- pymodaq/control_modules/ui_utils.py +72 -0
- pymodaq/control_modules/utils.py +591 -0
- pymodaq/control_modules/viewer_utility_classes.py +670 -0
- pymodaq/daq_utils/__init__.py +0 -0
- pymodaq/daq_utils/daq_utils.py +6 -0
- pymodaq/dashboard.py +2396 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.aliases +3 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.lvlps +3 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.lvproj +32 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Server_1Dgaussian.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Server_2Dgaussian.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_cmd.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_float.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_int.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_data.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_int.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_scalar.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_string.vi +0 -0
- pymodaq/examples/Labview_TCP_Client/client_state.ctl +0 -0
- pymodaq/examples/Labview_TCP_Client/cmd_types.ctl +0 -0
- pymodaq/examples/__init__.py +0 -0
- pymodaq/examples/function_plotter.py +160 -0
- pymodaq/examples/nonlinearscanner.py +126 -0
- pymodaq/examples/qt_less_standalone_module.py +165 -0
- pymodaq/examples/tcp_client.py +97 -0
- pymodaq/extensions/__init__.py +25 -0
- 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 +2 -0
- 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 +180 -0
- pymodaq/extensions/console.py +73 -0
- pymodaq/extensions/daq_logger/__init__.py +1 -0
- pymodaq/extensions/daq_logger/abstract.py +52 -0
- pymodaq/extensions/daq_logger/daq_logger.py +519 -0
- pymodaq/extensions/daq_logger/db/__init__.py +0 -0
- pymodaq/extensions/daq_logger/db/db_logger.py +300 -0
- pymodaq/extensions/daq_logger/db/db_logger_models.py +100 -0
- pymodaq/extensions/daq_logger/h5logging.py +84 -0
- pymodaq/extensions/daq_scan.py +1218 -0
- pymodaq/extensions/daq_scan_ui.py +241 -0
- 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 +9 -0
- 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/__init__.py +16 -0
- pymodaq/extensions/pid/actuator_controller.py +14 -0
- pymodaq/extensions/pid/daq_move_PID.py +154 -0
- pymodaq/extensions/pid/pid_controller.py +1016 -0
- pymodaq/extensions/pid/utils.py +189 -0
- pymodaq/extensions/utils.py +111 -0
- pymodaq/icon.ico +0 -0
- pymodaq/post_treatment/__init__.py +6 -0
- pymodaq/post_treatment/load_and_plot.py +352 -0
- pymodaq/resources/__init__.py +0 -0
- pymodaq/resources/config_template.toml +57 -0
- pymodaq/resources/preset_default.xml +1 -0
- pymodaq/resources/setup_plugin.py +73 -0
- pymodaq/splash.png +0 -0
- pymodaq/utils/__init__.py +0 -0
- pymodaq/utils/array_manipulation.py +6 -0
- pymodaq/utils/calibration_camera.py +180 -0
- pymodaq/utils/chrono_timer.py +203 -0
- pymodaq/utils/config.py +53 -0
- pymodaq/utils/conftests.py +5 -0
- pymodaq/utils/daq_utils.py +158 -0
- pymodaq/utils/data.py +128 -0
- pymodaq/utils/enums.py +6 -0
- pymodaq/utils/exceptions.py +38 -0
- pymodaq/utils/gui_utils/__init__.py +10 -0
- pymodaq/utils/gui_utils/loader_utils.py +75 -0
- pymodaq/utils/gui_utils/utils.py +18 -0
- pymodaq/utils/gui_utils/widgets/lcd.py +8 -0
- pymodaq/utils/h5modules/__init__.py +2 -0
- pymodaq/utils/h5modules/module_saving.py +526 -0
- pymodaq/utils/leco/__init__.py +25 -0
- pymodaq/utils/leco/daq_move_LECODirector.py +217 -0
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +163 -0
- pymodaq/utils/leco/director_utils.py +74 -0
- pymodaq/utils/leco/leco_director.py +166 -0
- pymodaq/utils/leco/pymodaq_listener.py +364 -0
- pymodaq/utils/leco/rpc_method_definitions.py +43 -0
- pymodaq/utils/leco/utils.py +74 -0
- pymodaq/utils/logger.py +6 -0
- pymodaq/utils/managers/__init__.py +0 -0
- pymodaq/utils/managers/batchscan_manager.py +346 -0
- pymodaq/utils/managers/modules_manager.py +589 -0
- pymodaq/utils/managers/overshoot_manager.py +242 -0
- pymodaq/utils/managers/preset_manager.py +229 -0
- pymodaq/utils/managers/preset_manager_utils.py +262 -0
- pymodaq/utils/managers/remote_manager.py +484 -0
- pymodaq/utils/math_utils.py +6 -0
- pymodaq/utils/messenger.py +6 -0
- pymodaq/utils/parameter/__init__.py +10 -0
- pymodaq/utils/parameter/utils.py +6 -0
- pymodaq/utils/scanner/__init__.py +5 -0
- pymodaq/utils/scanner/scan_config.py +16 -0
- pymodaq/utils/scanner/scan_factory.py +259 -0
- pymodaq/utils/scanner/scan_selector.py +477 -0
- pymodaq/utils/scanner/scanner.py +324 -0
- pymodaq/utils/scanner/scanners/_1d_scanners.py +174 -0
- pymodaq/utils/scanner/scanners/_2d_scanners.py +299 -0
- pymodaq/utils/scanner/scanners/__init__.py +1 -0
- pymodaq/utils/scanner/scanners/sequential.py +224 -0
- pymodaq/utils/scanner/scanners/tabular.py +319 -0
- pymodaq/utils/scanner/utils.py +110 -0
- pymodaq/utils/svg/__init__.py +6 -0
- pymodaq/utils/svg/svg_renderer.py +20 -0
- pymodaq/utils/svg/svg_view.py +35 -0
- pymodaq/utils/svg/svg_viewer2D.py +50 -0
- pymodaq/utils/tcp_ip/__init__.py +6 -0
- pymodaq/utils/tcp_ip/mysocket.py +12 -0
- pymodaq/utils/tcp_ip/serializer.py +13 -0
- pymodaq/utils/tcp_ip/tcp_server_client.py +772 -0
- pymodaq-5.1.6.dist-info/METADATA +238 -0
- pymodaq-5.1.6.dist-info/RECORD +154 -0
- pymodaq-5.1.6.dist-info/WHEEL +4 -0
- pymodaq-5.1.6.dist-info/entry_points.txt +7 -0
- pymodaq-5.1.6.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from bayes_opt.acquisition import UpperConfidenceBound, ExpectedImprovement, ProbabilityOfImprovement
|
|
2
|
+
from pymodaq.extensions.bayesian.acquisition import GenericAcquisitionFunctionFactory, GenericAcquisitionFunctionBase
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@GenericAcquisitionFunctionFactory.register()
|
|
6
|
+
class GenericUpperConfidenceBound(GenericAcquisitionFunctionBase):
|
|
7
|
+
usual_name = "Upper Confidence Bound"
|
|
8
|
+
short_name = "ucb"
|
|
9
|
+
params = [
|
|
10
|
+
{'title': 'Kappa:', 'name': 'kappa', 'type': 'slide', 'value': 2.576,
|
|
11
|
+
'min': 0.001, 'max': 100, 'subtype': 'log',
|
|
12
|
+
'tip': 'Parameter to indicate how closed are the next parameters sampled.'
|
|
13
|
+
'Higher value = favors spaces that are least explored.'
|
|
14
|
+
'Lower value = favors spaces where the regression function is the '
|
|
15
|
+
'highest.'},
|
|
16
|
+
{'title': 'Kappa actual:', 'name': 'tradeoff_actual', 'type': 'float', 'value': 2.576,
|
|
17
|
+
'tip': 'Current value of the kappa parameter', 'readonly': True},
|
|
18
|
+
{'title': 'Exploration decay:', 'name': 'exploration_decay', 'type': 'float', 'value': 0.9,
|
|
19
|
+
'tip': 'kappa is multiplied by this factor every iteration.'},
|
|
20
|
+
{'title': 'Exploration decay delay:', 'name': 'exploration_decay_delay', 'type': 'int', 'value': 20,
|
|
21
|
+
'tip': 'Number of iterations that must have passed before applying the decay to kappa.'}
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def __init__(self, **kwargs):
|
|
26
|
+
super().__init__()
|
|
27
|
+
self._function = UpperConfidenceBound(
|
|
28
|
+
kappa=kwargs.get('kappa', 2.576),
|
|
29
|
+
exploration_decay=kwargs.get('exploration_decay', None),
|
|
30
|
+
exploration_decay_delay=kwargs.get('exploration_decay_delay', None),
|
|
31
|
+
random_state=kwargs.get('random_state', None),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def tradeoff(self):
|
|
36
|
+
return self._function.kappa
|
|
37
|
+
|
|
38
|
+
@tradeoff.setter
|
|
39
|
+
def tradeoff(self, tradeoff):
|
|
40
|
+
self._function.kappa = tradeoff
|
|
41
|
+
|
|
42
|
+
@GenericAcquisitionFunctionFactory.register()
|
|
43
|
+
class GenericProbabilityOfImprovement(GenericAcquisitionFunctionBase):
|
|
44
|
+
usual_name = "Probability of Improvement"
|
|
45
|
+
short_name = "poi"
|
|
46
|
+
params = [
|
|
47
|
+
{'title': 'Xi:', 'name': 'xi', 'type': 'slide', 'value': 0,
|
|
48
|
+
'tip': 'Governs the exploration/exploitation tradeoff.'
|
|
49
|
+
'Lower prefers exploitation, higher prefers exploration.'},
|
|
50
|
+
{'title': 'Xi actual:', 'name': 'tradeoff_actual', 'type': 'float', 'value': 2.576,
|
|
51
|
+
'tip': 'Current value of the xi parameter', 'readonly': True},
|
|
52
|
+
{'title': 'Exploration decay:', 'name': 'exploration_decay', 'type': 'float', 'value': 0.9,
|
|
53
|
+
'tip': 'Xi is multiplied by this factor every iteration.'},
|
|
54
|
+
{'title': 'Exploration decay delay:', 'name': 'exploration_decay_delay', 'type': 'int', 'value': 20,
|
|
55
|
+
'tip': 'Number of iterations that must have passed before applying the decay to xi.'}
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
def __init__(self, **kwargs):
|
|
59
|
+
super().__init__()
|
|
60
|
+
self._function = ProbabilityOfImprovement(
|
|
61
|
+
xi=kwargs.get('xi'),
|
|
62
|
+
exploration_decay=kwargs.get('exploration_decay', None),
|
|
63
|
+
exploration_decay_delay=kwargs.get('exploration_decay_delay', None),
|
|
64
|
+
random_state=kwargs.get('random_state', None),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def tradeoff(self):
|
|
69
|
+
return self._function.xi
|
|
70
|
+
|
|
71
|
+
@tradeoff.setter
|
|
72
|
+
def tradeoff(self, tradeoff):
|
|
73
|
+
self._function.xi = tradeoff
|
|
74
|
+
|
|
75
|
+
@GenericAcquisitionFunctionFactory.register()
|
|
76
|
+
class GenericExpectedImprovement(GenericAcquisitionFunctionBase):
|
|
77
|
+
usual_name = "Expected Improvement"
|
|
78
|
+
short_name = "ei"
|
|
79
|
+
params = [
|
|
80
|
+
{'title': 'Xi:', 'name': 'xi', 'type': 'slide', 'value': 0,
|
|
81
|
+
'tip': 'Governs the exploration/exploitation tradeoff.'
|
|
82
|
+
'Lower prefers exploitation, higher prefers exploration.'},
|
|
83
|
+
{'title': 'Xi actual:', 'name': 'tradeoff_actual', 'type': 'float', 'value': 2.576,
|
|
84
|
+
'tip': 'Current value of the xi parameter', 'readonly': True},
|
|
85
|
+
{'title': 'Exploration decay:', 'name': 'exploration_decay', 'type': 'float', 'value': 0.9,
|
|
86
|
+
'tip': 'Xi is multiplied by this factor every iteration.'},
|
|
87
|
+
{'title': 'Exploration decay delay:', 'name': 'exploration_decay_delay', 'type': 'int', 'value': 20,
|
|
88
|
+
'tip': 'Number of iterations that must have passed before applying the decay to xi.'}
|
|
89
|
+
]
|
|
90
|
+
def __init__(self, **kwargs):
|
|
91
|
+
super().__init__()
|
|
92
|
+
self._function = ExpectedImprovement(
|
|
93
|
+
xi=kwargs.get('xi'),
|
|
94
|
+
exploration_decay=kwargs.get('exploration_decay', None),
|
|
95
|
+
exploration_decay_delay=kwargs.get('exploration_decay_delay', None),
|
|
96
|
+
random_state=kwargs.get('random_state', None),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def tradeoff(self):
|
|
101
|
+
return self._function.xi
|
|
102
|
+
|
|
103
|
+
@tradeoff.setter
|
|
104
|
+
def tradeoff(self, tradeoff):
|
|
105
|
+
self._function.xi = tradeoff
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from pymodaq_utils import config as config_mod, utils
|
|
4
|
+
from pymodaq_utils.logger import set_logger, get_module_name
|
|
5
|
+
from pymodaq_utils.utils import ThreadCommand
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
from pymodaq.extensions.bayesian.utils import BayesianAlgorithm, BayesianConfig
|
|
9
|
+
|
|
10
|
+
from pymodaq.extensions.bayesian.acquisition import GenericAcquisitionFunctionFactory
|
|
11
|
+
|
|
12
|
+
from pymodaq.extensions.optimizers_base.optimizer import (
|
|
13
|
+
GenericOptimization, OptimizationRunner, optimizer_params, OptimizerAction)
|
|
14
|
+
from pymodaq.extensions.optimizers_base.utils import OptimizerModelDefault, find_key_in_nested_dict
|
|
15
|
+
from pymodaq.extensions.optimizers_base.thread_commands import OptimizerToRunner, OptimizerThreadStatus
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logger = set_logger(get_module_name(__file__))
|
|
19
|
+
config = config_mod.Config()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
EXTENSION_NAME = 'BayesianOptimization'
|
|
23
|
+
CLASS_NAME = 'BayesianOptimization'
|
|
24
|
+
|
|
25
|
+
PREDICTION_NAMES = GenericAcquisitionFunctionFactory.usual_names()
|
|
26
|
+
PREDICTION_SHORT_NAMES = GenericAcquisitionFunctionFactory.short_names()
|
|
27
|
+
PREDICTION_PARAMS = ([{'title': 'Kind', 'name': 'kind', 'type': 'list',
|
|
28
|
+
'value': PREDICTION_NAMES[0],
|
|
29
|
+
'limits': {name: short_name for name, short_name in zip(PREDICTION_NAMES, PREDICTION_SHORT_NAMES)}}
|
|
30
|
+
] +
|
|
31
|
+
[{'title': 'Options', 'name': 'options', 'type': 'group',
|
|
32
|
+
'children': GenericAcquisitionFunctionFactory.get(PREDICTION_SHORT_NAMES[0]).params}]
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class BayesianOptimizationRunner(OptimizationRunner):
|
|
37
|
+
|
|
38
|
+
def __init__(self, *args, **kwargs):
|
|
39
|
+
super().__init__(*args, **kwargs)
|
|
40
|
+
|
|
41
|
+
def queue_command(self, command: ThreadCommand):
|
|
42
|
+
"""
|
|
43
|
+
"""
|
|
44
|
+
if command.command == OptimizerToRunner.PREDICTION:
|
|
45
|
+
kind = command.attribute.pop('kind')
|
|
46
|
+
self.optimization_algorithm.set_acquisition_function(
|
|
47
|
+
kind,
|
|
48
|
+
**command.attribute)
|
|
49
|
+
else:
|
|
50
|
+
super().queue_command(command)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class BayesianOptimization(GenericOptimization):
|
|
54
|
+
""" PyMoDAQ extension of the DashBoard to perform the optimization of a target signal
|
|
55
|
+
taken form the detectors as a function of one or more parameters controlled by the actuators.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
runner = BayesianOptimizationRunner
|
|
59
|
+
params = optimizer_params(PREDICTION_PARAMS)
|
|
60
|
+
config_saver = BayesianConfig
|
|
61
|
+
|
|
62
|
+
def ini_custom_attributes(self):
|
|
63
|
+
""" Here you can reimplement specific attributes"""
|
|
64
|
+
self._base_name: str = 'Bayesian'
|
|
65
|
+
|
|
66
|
+
def update_after_actuators_changed(self, actuators: list[str]):
|
|
67
|
+
""" Actions to do after the actuators have been updated
|
|
68
|
+
"""
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
def update_prediction_function(self):
|
|
72
|
+
""" Get the selected prediction function options and pass them to the Runner
|
|
73
|
+
|
|
74
|
+
Should be reimplemented in real Optimizer implementation
|
|
75
|
+
"""
|
|
76
|
+
utility_settings = self.settings.child('main_settings', 'prediction')
|
|
77
|
+
|
|
78
|
+
kind = utility_settings.child('kind').value()
|
|
79
|
+
uparams = {child.name() : child.value() for child in utility_settings.child('options').children()}
|
|
80
|
+
uparams['kind'] = kind
|
|
81
|
+
self.command_runner.emit(
|
|
82
|
+
utils.ThreadCommand(OptimizerToRunner.PREDICTION, uparams))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def validate_config(self) -> bool:
|
|
86
|
+
utility = find_key_in_nested_dict(self.optimizer_config.to_dict(), 'prediction')
|
|
87
|
+
if utility:
|
|
88
|
+
try:
|
|
89
|
+
kind = utility.pop('kind', None)
|
|
90
|
+
if kind is not None:
|
|
91
|
+
GenericAcquisitionFunctionFactory.create(kind, **utility)
|
|
92
|
+
except ValueError:
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
return True
|
|
96
|
+
|
|
97
|
+
def value_changed(self, param):
|
|
98
|
+
""" to be subclassed for actions to perform when one of the param's value in self.settings is changed
|
|
99
|
+
|
|
100
|
+
For instance:
|
|
101
|
+
if param.name() == 'do_something':
|
|
102
|
+
if param.value():
|
|
103
|
+
print('Do something')
|
|
104
|
+
self.settings.child('main_settings', 'something_done').setValue(False)
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
param: (Parameter) the parameter whose value just changed
|
|
109
|
+
"""
|
|
110
|
+
super().value_changed(param)
|
|
111
|
+
if param.name() == 'kind':
|
|
112
|
+
param.parent().child('options').clearChildren()
|
|
113
|
+
param.parent().child('options').addChildren(
|
|
114
|
+
GenericAcquisitionFunctionFactory.get(param.value()).params)
|
|
115
|
+
|
|
116
|
+
def set_algorithm(self):
|
|
117
|
+
self.algorithm = BayesianAlgorithm(
|
|
118
|
+
ini_random=self.settings['main_settings', 'ini_random'],
|
|
119
|
+
bounds=self.format_bounds(),
|
|
120
|
+
actuators=self.modules_manager.selected_actuators_name)
|
|
121
|
+
|
|
122
|
+
def thread_status(self, status: utils.ThreadCommand):
|
|
123
|
+
super().thread_status(status)
|
|
124
|
+
if status.command == OptimizerThreadStatus.TRADE_OFF:
|
|
125
|
+
self.settings.child('main_settings', 'prediction', 'options', 'tradeoff_actual').setValue(status.attribute)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def main():
|
|
129
|
+
from pymodaq_gui.utils.utils import mkQApp
|
|
130
|
+
from pymodaq.utils.gui_utils.loader_utils import load_dashboard_with_preset
|
|
131
|
+
|
|
132
|
+
app = mkQApp('Bayesian Optimiser')
|
|
133
|
+
#preset_file_name = config('presets', f'beam_steering')
|
|
134
|
+
|
|
135
|
+
dashboard, extension, win = load_dashboard_with_preset('beam_steering', 'Bayesian')
|
|
136
|
+
|
|
137
|
+
app.exec()
|
|
138
|
+
|
|
139
|
+
return dashboard, extension, win
|
|
140
|
+
|
|
141
|
+
if __name__ == '__main__':
|
|
142
|
+
main()
|
|
143
|
+
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created the 31/08/2023
|
|
4
|
+
|
|
5
|
+
@author: Sebastien Weber
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import List, TYPE_CHECKING, Union, Dict, Tuple, Iterable
|
|
9
|
+
|
|
10
|
+
import bayes_opt.exception
|
|
11
|
+
import numpy as np
|
|
12
|
+
from collections import namedtuple
|
|
13
|
+
|
|
14
|
+
from bayes_opt import BayesianOptimization
|
|
15
|
+
from bayes_opt.exception import TargetSpaceEmptyError
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from pymodaq_utils.logger import set_logger, get_module_name
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
from pymodaq_data.data import (DataToExport, DataCalculated,
|
|
22
|
+
DataRaw, Axis)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from pymodaq.extensions.bayesian.acquisition import GenericAcquisitionFunctionFactory
|
|
26
|
+
|
|
27
|
+
from pymodaq.extensions.optimizers_base.utils import (
|
|
28
|
+
GenericAlgorithm, OptimizerModelDefault, StopType, StoppingParameters,
|
|
29
|
+
OptimizerConfig, PredictionError)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
logger = set_logger(get_module_name(__file__))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BayesianConfig(OptimizerConfig):
|
|
36
|
+
config_name = f"bayesian_settings"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class BayesianAlgorithm(GenericAlgorithm):
|
|
41
|
+
|
|
42
|
+
def __init__(self, ini_random: int, bounds: dict[str, tuple[float, float]], actuators: list[str], **kwargs):
|
|
43
|
+
super().__init__(ini_random, bounds, actuators)
|
|
44
|
+
self._algo = BayesianOptimization(f=None,
|
|
45
|
+
pbounds=bounds,
|
|
46
|
+
**kwargs
|
|
47
|
+
)
|
|
48
|
+
self.sorting_index: list = None
|
|
49
|
+
|
|
50
|
+
def set_prediction_function(self, kind: str = '', **kwargs):
|
|
51
|
+
self._prediction = GenericAcquisitionFunctionFactory.create(kind, **kwargs)
|
|
52
|
+
|
|
53
|
+
def update_prediction_function(self):
|
|
54
|
+
""" Update the parameters of the acquisition function (kappa decay for instance)"""
|
|
55
|
+
self._prediction.decay_exploration()
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def tradeoff(self):
|
|
59
|
+
return self._prediction.tradeoff
|
|
60
|
+
|
|
61
|
+
def get_random_point(self) -> dict[str, float]:
|
|
62
|
+
""" Get a random point coordinates in the defined bounds"""
|
|
63
|
+
point = dict()
|
|
64
|
+
for key, vals in self.bounds.items():
|
|
65
|
+
point[key] = (np.max(vals) - np.min(vals)) * np.random.random_sample() + np.min(vals)
|
|
66
|
+
return point
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def bounds(self) -> dict[str, float]:
|
|
70
|
+
""" Return bounds as a dict.
|
|
71
|
+
"""
|
|
72
|
+
return self._algo.space.array_to_params(self._algo.space.bounds)
|
|
73
|
+
|
|
74
|
+
@bounds.setter
|
|
75
|
+
def bounds(self, bounds: Dict[str, Tuple[float, float]]):
|
|
76
|
+
if isinstance(bounds, dict):
|
|
77
|
+
self._algo.set_bounds(bounds)
|
|
78
|
+
else:
|
|
79
|
+
raise TypeError('Bounds should be defined as a dictionary')
|
|
80
|
+
|
|
81
|
+
def prediction_ask(self) -> dict[str, float]:
|
|
82
|
+
""" Ask the prediction function or algo to provide the next point to probe
|
|
83
|
+
|
|
84
|
+
Warning the space algo object is sorting by name the bounds...
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
return self._algo.space.array_to_params(self._prediction.suggest(self._algo._gp, self._algo.space))
|
|
88
|
+
except TargetSpaceEmptyError as e:
|
|
89
|
+
raise PredictionError(str(e))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def tell(self, function_value: float):
|
|
93
|
+
self._algo.register(params=self._next_point, target=function_value)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def best_fitness(self) -> float:
|
|
97
|
+
if self._algo.max is None:
|
|
98
|
+
return 0.001
|
|
99
|
+
else:
|
|
100
|
+
return self._algo.max['target']
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def best_individual(self) -> Union[dict[str, float], None]:
|
|
104
|
+
if self._algo.max is None:
|
|
105
|
+
return None
|
|
106
|
+
else:
|
|
107
|
+
max_param = self._algo.max.get('params', None)
|
|
108
|
+
if max_param is None:
|
|
109
|
+
return None
|
|
110
|
+
return max_param
|
|
111
|
+
|
|
112
|
+
def stopping(self, ind_iter: int, stopping_parameters: StoppingParameters):
|
|
113
|
+
if stopping_parameters.stop_type != StopType.NONE:
|
|
114
|
+
if ind_iter >= stopping_parameters.niter: # For instance StopType.ITER
|
|
115
|
+
return True
|
|
116
|
+
if ind_iter > stopping_parameters.npoints:
|
|
117
|
+
if stopping_parameters.stop_type == StopType.PREDICT:
|
|
118
|
+
coordinates = np.atleast_1d([
|
|
119
|
+
[coordinates[act] for coordinates in self._suggested_coordinates[-stopping_parameters.npoints:]]
|
|
120
|
+
for act in self.actuators])
|
|
121
|
+
return np.all(np.abs((np.std(coordinates, axis=1) / np.mean(coordinates, axis=1)))
|
|
122
|
+
< stopping_parameters.tolerance)
|
|
123
|
+
elif stopping_parameters.stop_type == StopType.BEST:
|
|
124
|
+
coordinates = np.atleast_1d(
|
|
125
|
+
[[best['params'][act] for best in
|
|
126
|
+
sorted(self._algo.res, key=lambda x: x['target'])[-stopping_parameters.npoints:]]
|
|
127
|
+
for act in self.actuators])
|
|
128
|
+
return np.all(np.abs((np.std(coordinates, axis=1) / np.mean(coordinates, axis=1)))
|
|
129
|
+
< stopping_parameters.tolerance)
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
def _posterior(self, x_obs, y_obs, grid):
|
|
133
|
+
|
|
134
|
+
if len(x_obs.shape) == 1:
|
|
135
|
+
x_obs = x_obs.reshape(-1, 1)
|
|
136
|
+
y_obs = y_obs.reshape(-1, 1)
|
|
137
|
+
grid = grid.reshape(-1, 1)
|
|
138
|
+
|
|
139
|
+
self._algo._gp.fit(x_obs, y_obs)
|
|
140
|
+
|
|
141
|
+
mu, sigma = self._algo._gp.predict(grid, return_std=True)
|
|
142
|
+
return mu, sigma
|
|
143
|
+
|
|
144
|
+
def get_dwa_obervations(self, actuators_name):
|
|
145
|
+
try:
|
|
146
|
+
axes = [Axis(act, data=np.array([res['params'][act] for res in self._algo.res])) for
|
|
147
|
+
act in actuators_name]
|
|
148
|
+
data_arrays = [np.array([res['target'] for res in self._algo.res])]
|
|
149
|
+
|
|
150
|
+
return DataRaw('Observations', data=data_arrays, labels=actuators_name,
|
|
151
|
+
axes=axes)
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
pass
|
|
155
|
+
|
|
156
|
+
def get_1D_dwa_gp(self, x: np.ndarray, actuator_name: str):
|
|
157
|
+
""" Get Measurements and predictions as DataWithAxes
|
|
158
|
+
|
|
159
|
+
Parameters
|
|
160
|
+
----------
|
|
161
|
+
x: np.ndarray
|
|
162
|
+
linear grid to get the Bayesian Optimisation On
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
dwa_obervation = self.get_dwa_obervations([actuator_name])
|
|
166
|
+
|
|
167
|
+
mu, sigma = self._posterior(dwa_obervation.axes[0].get_data(),
|
|
168
|
+
dwa_obervation.data[0], x)
|
|
169
|
+
|
|
170
|
+
dwa_measured = DataCalculated('Measurements', data=[dwa_obervation.data[0]],
|
|
171
|
+
axes=[Axis('measured_axis',
|
|
172
|
+
data=dwa_obervation.axes[0].get_data())],
|
|
173
|
+
labels=['Sampled'])
|
|
174
|
+
dwa_prediction = DataCalculated('Prediction', data=[mu],
|
|
175
|
+
axes=[Axis('tested_pos', data=x)],
|
|
176
|
+
errors=[1.96 * sigma])
|
|
177
|
+
return dwa_measured, dwa_prediction
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created the 25/10/2022
|
|
4
|
+
|
|
5
|
+
@author: Sebastien Weber
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
|
9
|
+
from qtconsole.inprocess import QtInProcessKernelManager
|
|
10
|
+
|
|
11
|
+
from pymodaq_utils import config as configmod
|
|
12
|
+
from pymodaq_utils.utils import get_version
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
config = configmod.Config()
|
|
16
|
+
|
|
17
|
+
BANNER = f'PyMoDAQ v{get_version("pymodaq")}\n' \
|
|
18
|
+
'Main objects available for interaction:\n'\
|
|
19
|
+
'* dashboard: Main Dashboard Object\n'\
|
|
20
|
+
'* mods: ModuleManager of the dashboard\'s Control Modules\n'\
|
|
21
|
+
'* np: numpy module\n\n'\
|
|
22
|
+
'For inline plotting use: %matplotlib\n\n'
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class QtConsole(RichJupyterWidget):
|
|
26
|
+
"""Live IPython console widget.
|
|
27
|
+
.. image:: img/IPythonWidget.png
|
|
28
|
+
:param custom_banner: Custom welcome message to be printed at the top of
|
|
29
|
+
the console.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, parent=None, custom_banner=None, *args, **kwargs):
|
|
33
|
+
if parent is not None:
|
|
34
|
+
kwargs["parent"] = parent
|
|
35
|
+
super().__init__(*args, **kwargs)
|
|
36
|
+
if custom_banner is not None:
|
|
37
|
+
self.banner = custom_banner
|
|
38
|
+
self.kernel_manager = kernel_manager = QtInProcessKernelManager()
|
|
39
|
+
kernel_manager.start_kernel()
|
|
40
|
+
|
|
41
|
+
self.kernel_client = kernel_client = self._kernel_manager.client()
|
|
42
|
+
kernel_client.start_channels()
|
|
43
|
+
|
|
44
|
+
def stop():
|
|
45
|
+
kernel_client.stop_channels()
|
|
46
|
+
kernel_manager.shutdown_kernel()
|
|
47
|
+
self.exit_requested.connect(stop)
|
|
48
|
+
|
|
49
|
+
def push_variables(self, variable_dict):
|
|
50
|
+
""" Given a dictionary containing name / value pairs, push those
|
|
51
|
+
variables to the IPython console widget.
|
|
52
|
+
:param variable_dict: Dictionary of variables to be pushed to the
|
|
53
|
+
console's interactive namespace (```{variable_name: object, …}```)
|
|
54
|
+
"""
|
|
55
|
+
self.kernel_manager.kernel.shell.push(variable_dict)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def main():
|
|
59
|
+
from pymodaq_gui.utils.utils import mkQApp
|
|
60
|
+
|
|
61
|
+
app = mkQApp('Console')
|
|
62
|
+
|
|
63
|
+
prog = QtConsole(style_sheet=config('style', 'syntax_highlighting'),
|
|
64
|
+
syntax_style=config('style', 'syntax_highlighting'),
|
|
65
|
+
custom_banner=BANNER,
|
|
66
|
+
)
|
|
67
|
+
prog.show()
|
|
68
|
+
app.exec()
|
|
69
|
+
return prog
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if __name__ == '__main__':
|
|
73
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .daq_logger import main
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AbstractLogger(ABC):
|
|
5
|
+
"""
|
|
6
|
+
Minimal set of methods a class should implement to be considered as a logger in PyMoDAQ and used by the DAQ_Logger
|
|
7
|
+
extension
|
|
8
|
+
|
|
9
|
+
See Also
|
|
10
|
+
--------
|
|
11
|
+
pymodaq.utils.h5modules.H5Logger or pymodaq.utils.db.db_logger.DbLoggerGUI
|
|
12
|
+
"""
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def close(self):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def settings_tree(self):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def settings(self):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def init_logger(self, settings):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def get_handler(self):
|
|
33
|
+
"""
|
|
34
|
+
returns a log handler to save the output of the error log into the particular implementation of the Logger object
|
|
35
|
+
"""
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def add_detector(self, module_name, settings):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def add_actuator(self, module_name, settings):
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def add_data(self, data):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
@abstractmethod
|
|
51
|
+
def stop_logger(self):
|
|
52
|
+
pass
|