pymodaq 5.0.0__py3-none-any.whl → 5.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pymodaq might be problematic. Click here for more details.
- pymodaq/__init__.py +55 -89
- pymodaq/control_modules/daq_move.py +129 -55
- pymodaq/control_modules/daq_move_ui.py +42 -11
- pymodaq/control_modules/daq_viewer.py +32 -13
- pymodaq/control_modules/move_utility_classes.py +346 -79
- pymodaq/control_modules/utils.py +26 -9
- pymodaq/control_modules/viewer_utility_classes.py +51 -14
- pymodaq/daq_utils/daq_utils.py +6 -0
- pymodaq/dashboard.py +532 -263
- pymodaq/examples/qt_less_standalone_module.py +128 -0
- pymodaq/extensions/bayesian/bayesian_optimisation.py +30 -21
- pymodaq/extensions/bayesian/utils.py +6 -3
- pymodaq/extensions/daq_logger/__init__.py +1 -0
- pymodaq/extensions/daq_logger/daq_logger.py +4 -5
- pymodaq/extensions/daq_scan.py +28 -8
- pymodaq/extensions/daq_scan_ui.py +7 -9
- pymodaq/extensions/pid/__init__.py +0 -1
- pymodaq/extensions/pid/actuator_controller.py +13 -0
- pymodaq/extensions/pid/daq_move_PID.py +25 -46
- pymodaq/extensions/pid/pid_controller.py +49 -41
- pymodaq/extensions/pid/utils.py +7 -31
- pymodaq/extensions/utils.py +41 -7
- pymodaq/post_treatment/load_and_plot.py +43 -10
- pymodaq/resources/setup_plugin.py +1 -0
- pymodaq/updater.py +107 -0
- pymodaq/utils/chrono_timer.py +6 -7
- pymodaq/utils/daq_utils.py +6 -3
- pymodaq/utils/data.py +21 -17
- pymodaq/utils/enums.py +6 -0
- pymodaq/utils/gui_utils/loader_utils.py +29 -2
- pymodaq/utils/gui_utils/utils.py +9 -12
- pymodaq/utils/gui_utils/widgets/lcd.py +8 -0
- pymodaq/utils/h5modules/module_saving.py +5 -2
- pymodaq/utils/leco/daq_move_LECODirector.py +22 -16
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +15 -9
- pymodaq/utils/leco/leco_director.py +4 -3
- pymodaq/utils/leco/pymodaq_listener.py +9 -13
- pymodaq/utils/leco/utils.py +40 -7
- pymodaq/utils/managers/modules_manager.py +22 -12
- pymodaq/utils/managers/overshoot_manager.py +45 -1
- pymodaq/utils/managers/preset_manager.py +22 -46
- pymodaq/utils/managers/preset_manager_utils.py +17 -13
- pymodaq/utils/managers/remote_manager.py +1 -1
- pymodaq/utils/messenger.py +6 -0
- pymodaq/utils/parameter/__init__.py +5 -1
- pymodaq/utils/tcp_ip/mysocket.py +4 -110
- pymodaq/utils/tcp_ip/serializer.py +4 -769
- pymodaq/utils/tcp_ip/tcp_server_client.py +5 -5
- pymodaq-5.0.2.dist-info/METADATA +242 -0
- {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/RECORD +54 -55
- {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/WHEEL +1 -1
- {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/entry_points.txt +1 -0
- pymodaq/examples/custom_app.py +0 -255
- pymodaq/examples/custom_viewer.py +0 -112
- pymodaq/examples/parameter_ex.py +0 -158
- pymodaq/examples/preset_MockCamera.xml +0 -1
- pymodaq/post_treatment/daq_measurement/daq_measurement_GUI.py +0 -142
- pymodaq/post_treatment/daq_measurement/daq_measurement_GUI.ui +0 -232
- pymodaq/post_treatment/daq_measurement/daq_measurement_main.py +0 -391
- pymodaq/post_treatment/daq_measurement/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -2
- pymodaq-5.0.0.dist-info/METADATA +0 -166
- /pymodaq/{post_treatment/daq_measurement → daq_utils}/__init__.py +0 -0
- {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Example how to create an actuator or detector module, which does not require Qt, nor any GUI functionality.
|
|
3
|
+
|
|
4
|
+
You can connect to this qtless module with a PyMoDAQ LECODirector module (the detector or actuator version, both are preinstalled),
|
|
5
|
+
as if it were any pymodaq module.
|
|
6
|
+
|
|
7
|
+
This example works best with an Actuator Director Module as it has fake movements, but does not return any detector value.
|
|
8
|
+
In this example, the name is "qt_less" (defined in the final if clause), which you have to give as the "actor" argument to the Director module.
|
|
9
|
+
|
|
10
|
+
Add any code in the methods defined below, for example instrument access and execute the file.
|
|
11
|
+
For remote control, you need to start a Coordinator, as described for remote control via LECO.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
from time import sleep
|
|
16
|
+
from typing import List, Union
|
|
17
|
+
|
|
18
|
+
from pyleco.utils.listener import Listener
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class QtLessModule:
|
|
22
|
+
"""Some module doing things without Qt.
|
|
23
|
+
|
|
24
|
+
You can run an instance of this class anywhere in your LECO network.
|
|
25
|
+
Then you can control this instance with a PyMoDAQ LECODirectorModule (in mock modules) as if it were a PyMoDAQ module.
|
|
26
|
+
|
|
27
|
+
Just add any logic you wish to the methods below.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, name: str, host: str = "localhost", **kwargs) -> None:
|
|
31
|
+
super().__init__()
|
|
32
|
+
self.listener = Listener(name=name, host=host, timeout=1, **kwargs)
|
|
33
|
+
self._fake_position = 0
|
|
34
|
+
self.start_listen()
|
|
35
|
+
self._stored = []
|
|
36
|
+
|
|
37
|
+
def start_listen(self) -> None:
|
|
38
|
+
"""Start to listen on incoming commands."""
|
|
39
|
+
self.listener.start_listen()
|
|
40
|
+
self.communicator = self.listener.get_communicator()
|
|
41
|
+
self.register_rpc_methods()
|
|
42
|
+
|
|
43
|
+
def register_rpc_methods(self) -> None:
|
|
44
|
+
"""Make the following methods available via LECO."""
|
|
45
|
+
register_rpc_method = self.communicator.register_rpc_method
|
|
46
|
+
register_rpc_method(self.set_info)
|
|
47
|
+
register_rpc_method(self.send_data)
|
|
48
|
+
register_rpc_method(self.move_abs)
|
|
49
|
+
register_rpc_method(self.move_rel)
|
|
50
|
+
register_rpc_method(self.move_home)
|
|
51
|
+
register_rpc_method(self.get_actuator_value)
|
|
52
|
+
register_rpc_method(self.stop_motion)
|
|
53
|
+
register_rpc_method(self.set_remote_name)
|
|
54
|
+
|
|
55
|
+
def stop_listen(self) -> None:
|
|
56
|
+
"""Stop to listen on incoming commands."""
|
|
57
|
+
self.listener.stop_listen()
|
|
58
|
+
|
|
59
|
+
# smethods for being remote controlled
|
|
60
|
+
# these methods are executed and cannot talk to the controlling module directly.
|
|
61
|
+
# if you need to send a response (for example with a value) you have to store the information and
|
|
62
|
+
# send it after these methods have been executed.
|
|
63
|
+
def set_remote_name(self, name: str) -> None:
|
|
64
|
+
"""Define what the name of the remote for answers is."""
|
|
65
|
+
self.remote_name = name
|
|
66
|
+
|
|
67
|
+
# generic commands
|
|
68
|
+
def set_info(self, path: List[str], param_dict_str: str) -> None:
|
|
69
|
+
print("set_info", path, param_dict_str)
|
|
70
|
+
|
|
71
|
+
# detector commands
|
|
72
|
+
def send_data(self, grabber_type: str = "") -> None:
|
|
73
|
+
print("send_data")
|
|
74
|
+
|
|
75
|
+
# actuator commands
|
|
76
|
+
def move_abs(self, position: Union[float, str]) -> None:
|
|
77
|
+
print("move_abs", position)
|
|
78
|
+
self._fake_position = float(position)
|
|
79
|
+
|
|
80
|
+
def move_rel(self, position: Union[float, str]) -> None:
|
|
81
|
+
print("move_rel", position)
|
|
82
|
+
self._fake_position += float(position)
|
|
83
|
+
|
|
84
|
+
def move_home(self) -> None:
|
|
85
|
+
self._fake_position = 0
|
|
86
|
+
print("move_home")
|
|
87
|
+
|
|
88
|
+
def get_actuator_value(self) -> None:
|
|
89
|
+
"""Request that the actuator value is sent later on."""
|
|
90
|
+
# according to DAQ_Move, this supersedes "check_position"
|
|
91
|
+
print("get_actuator_value")
|
|
92
|
+
# send the actuator position after this method has finished execution.
|
|
93
|
+
# this method sends the result to the controlling control module.
|
|
94
|
+
self.send_later(
|
|
95
|
+
receiver=self.remote_name,
|
|
96
|
+
method="set_position",
|
|
97
|
+
position=self._fake_position,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def stop_motion(self,) -> None:
|
|
101
|
+
# not implemented in DAQ_Move!
|
|
102
|
+
print("stop_motion")
|
|
103
|
+
|
|
104
|
+
# end of methods for being remote controlled
|
|
105
|
+
|
|
106
|
+
def send_later(self, receiver, method, **kwargs):
|
|
107
|
+
"""Store information to send it later."""
|
|
108
|
+
self._stored.append((receiver, method, kwargs))
|
|
109
|
+
|
|
110
|
+
def send_stored(self):
|
|
111
|
+
"""Send messages stored for later sending."""
|
|
112
|
+
while self._stored:
|
|
113
|
+
receiver, method, kwargs = self._stored.pop()
|
|
114
|
+
self.communicator.ask_rpc(receiver=receiver, method=method, **kwargs)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
print("listening endlessly as 'qt_less'")
|
|
119
|
+
log = logging.getLogger()
|
|
120
|
+
log.addHandler(logging.StreamHandler())
|
|
121
|
+
# log.setLevel(logging.DEBUG)
|
|
122
|
+
m = QtLessModule("qt_less")
|
|
123
|
+
try:
|
|
124
|
+
while True:
|
|
125
|
+
sleep(0.1)
|
|
126
|
+
m.send_stored()
|
|
127
|
+
except KeyboardInterrupt:
|
|
128
|
+
m.stop_listen()
|
|
@@ -9,12 +9,16 @@ import numpy as np
|
|
|
9
9
|
from pymodaq.utils.data import DataToExport, DataToActuators, DataCalculated, DataActuator
|
|
10
10
|
from pymodaq.utils.managers.modules_manager import ModulesManager
|
|
11
11
|
from pymodaq_utils import utils
|
|
12
|
-
from pymodaq_utils import config as
|
|
12
|
+
from pymodaq_utils import config as config_mod
|
|
13
|
+
from pymodaq_utils.enums import BaseEnum
|
|
14
|
+
|
|
15
|
+
from pymodaq_gui.config import ConfigSaverLoader
|
|
13
16
|
from pymodaq_utils.logger import set_logger, get_module_name
|
|
14
17
|
|
|
15
18
|
from pymodaq_gui.plotting.data_viewers.viewer0D import Viewer0D
|
|
16
19
|
from pymodaq_gui.plotting.data_viewers.viewer import ViewerDispatcher, ViewersEnum
|
|
17
20
|
from pymodaq_gui.utils import QLED
|
|
21
|
+
from pymodaq_gui.utils.utils import mkQApp
|
|
18
22
|
from pymodaq_gui import utils as gutils
|
|
19
23
|
from pymodaq_gui.parameter import utils as putils
|
|
20
24
|
from pymodaq_gui.h5modules.saving import H5Saver
|
|
@@ -27,15 +31,24 @@ from pymodaq.extensions.bayesian.utils import (get_bayesian_models, BayesianMode
|
|
|
27
31
|
UtilityParameters, StopType, StoppingParameters)
|
|
28
32
|
from pymodaq.post_treatment.load_and_plot import LoaderPlotter
|
|
29
33
|
from pymodaq.extensions.bayesian.utils import BayesianConfig
|
|
30
|
-
|
|
34
|
+
from pymodaq.extensions.utils import CustomExt
|
|
31
35
|
|
|
32
36
|
EXTENSION_NAME = 'BayesianOptimisation'
|
|
33
37
|
CLASS_NAME = 'BayesianOptimisation'
|
|
34
38
|
|
|
35
39
|
logger = set_logger(get_module_name(__file__))
|
|
40
|
+
config = config_mod.Config()
|
|
41
|
+
|
|
36
42
|
|
|
43
|
+
class DataNames(BaseEnum):
|
|
44
|
+
Fitness = 0
|
|
45
|
+
Individual = 1
|
|
46
|
+
ProbedData = 2
|
|
47
|
+
Actuators = 3
|
|
48
|
+
Kappa = 4
|
|
37
49
|
|
|
38
|
-
|
|
50
|
+
|
|
51
|
+
class BayesianOptimisation(CustomExt):
|
|
39
52
|
""" PyMoDAQ extension of the DashBoard to perform the optimization of a target signal
|
|
40
53
|
taken form the detectors as a function of one or more parameters controlled by the actuators.
|
|
41
54
|
"""
|
|
@@ -112,7 +125,7 @@ class BayesianOptimisation(gutils.CustomApp):
|
|
|
112
125
|
self.setup_ui()
|
|
113
126
|
|
|
114
127
|
self.bayesian_config = BayesianConfig()
|
|
115
|
-
self.mainsettings_saver_loader =
|
|
128
|
+
self.mainsettings_saver_loader = ConfigSaverLoader(
|
|
116
129
|
self.settings.child('main_settings'), self.bayesian_config)
|
|
117
130
|
|
|
118
131
|
self.h5temp: H5Saver = None
|
|
@@ -176,7 +189,7 @@ class BayesianOptimisation(gutils.CustomApp):
|
|
|
176
189
|
params = getattr(model_class, 'params')
|
|
177
190
|
self.settings.child('models', 'model_params').addChildren(params)
|
|
178
191
|
|
|
179
|
-
def setup_menu(self):
|
|
192
|
+
def setup_menu(self, menubar: QtWidgets.QMenuBar = None):
|
|
180
193
|
'''
|
|
181
194
|
to be subclassed
|
|
182
195
|
create menu for actions contained into the self.actions_manager, for instance:
|
|
@@ -450,20 +463,20 @@ class BayesianOptimisation(gutils.CustomApp):
|
|
|
450
463
|
def process_output(self, dte: DataToExport):
|
|
451
464
|
|
|
452
465
|
self.enl_index += 1
|
|
453
|
-
dwa_kappa = dte.remove(dte.get_data_from_name(
|
|
466
|
+
dwa_kappa = dte.remove(dte.get_data_from_name(DataNames.Kappa.name))
|
|
454
467
|
self.settings.child('main_settings', 'utility', 'kappa_actual').setValue(
|
|
455
468
|
float(dwa_kappa[0][0])
|
|
456
469
|
)
|
|
457
470
|
|
|
458
|
-
dwa_data = dte.remove(dte.get_data_from_name(
|
|
459
|
-
dwa_actuators: DataActuator = dte.remove(dte.get_data_from_name(
|
|
471
|
+
dwa_data = dte.remove(dte.get_data_from_name(DataNames.ProbedData.name))
|
|
472
|
+
dwa_actuators: DataActuator = dte.remove(dte.get_data_from_name(DataNames.Actuators.name))
|
|
460
473
|
self.viewer_observable.show_data(dte)
|
|
461
474
|
|
|
462
475
|
# dwa_observations = self.algorithm.get_dwa_obervations(
|
|
463
476
|
# self.modules_manager.selected_actuators_name)
|
|
464
477
|
self.model_class.update_plots()
|
|
465
478
|
|
|
466
|
-
best_individual = dte.get_data_from_name(
|
|
479
|
+
best_individual = dte.get_data_from_name(DataNames.Individual.name)
|
|
467
480
|
best_indiv_as_list = [float(best_individual[ind][0]) for ind in range(len(best_individual))]
|
|
468
481
|
|
|
469
482
|
|
|
@@ -582,7 +595,7 @@ class OptimisationRunner(QtCore.QObject):
|
|
|
582
595
|
polling=sync_acts)
|
|
583
596
|
|
|
584
597
|
# Do the evaluation (measurements)
|
|
585
|
-
self.det_done_datas = self.modules_manager.
|
|
598
|
+
self.det_done_datas = self.modules_manager.grab_data()
|
|
586
599
|
self.input_from_dets = self.model_class.convert_input(self.det_done_datas)
|
|
587
600
|
|
|
588
601
|
# Run the algo internal mechanic
|
|
@@ -591,17 +604,17 @@ class OptimisationRunner(QtCore.QObject):
|
|
|
591
604
|
dte = DataToExport('algo',
|
|
592
605
|
data=[self.individual_as_data(
|
|
593
606
|
np.array([self.optimisation_algorithm.best_fitness]),
|
|
594
|
-
|
|
607
|
+
DataNames.Fitness.name),
|
|
595
608
|
self.individual_as_data(
|
|
596
609
|
self.optimisation_algorithm.best_individual,
|
|
597
|
-
|
|
598
|
-
DataCalculated(
|
|
610
|
+
DataNames.Individual.name),
|
|
611
|
+
DataCalculated(DataNames.ProbedData.name,
|
|
599
612
|
data=[np.array([self.input_from_dets])],
|
|
600
613
|
),
|
|
601
|
-
self.output_to_actuators.merge_as_dwa(
|
|
602
|
-
|
|
614
|
+
self.output_to_actuators.merge_as_dwa(
|
|
615
|
+
'Data0D', DataNames.Actuators.name),
|
|
603
616
|
DataCalculated(
|
|
604
|
-
|
|
617
|
+
DataNames.Kappa.name,
|
|
605
618
|
data=[
|
|
606
619
|
np.array([self.optimisation_algorithm.kappa])])
|
|
607
620
|
])
|
|
@@ -638,10 +651,7 @@ def main(init_qt=True):
|
|
|
638
651
|
from pymodaq.utils.daq_utils import get_set_preset_path
|
|
639
652
|
|
|
640
653
|
if init_qt: # used for the test suite
|
|
641
|
-
app =
|
|
642
|
-
|
|
643
|
-
import qdarkstyle
|
|
644
|
-
app.setStyleSheet(qdarkstyle.load_stylesheet())
|
|
654
|
+
app = mkQApp("PyMoDAQ Dashboard")
|
|
645
655
|
|
|
646
656
|
from pymodaq.dashboard import DashBoard
|
|
647
657
|
|
|
@@ -649,7 +659,6 @@ def main(init_qt=True):
|
|
|
649
659
|
area = gutils.dock.DockArea()
|
|
650
660
|
win.setCentralWidget(area)
|
|
651
661
|
win.resize(1000, 500)
|
|
652
|
-
win.setWindowTitle('PyMoDAQ Dashboard')
|
|
653
662
|
|
|
654
663
|
dashboard = DashBoard(area)
|
|
655
664
|
daq_scan = None
|
|
@@ -116,10 +116,13 @@ class BayesianAlgorithm:
|
|
|
116
116
|
|
|
117
117
|
@property
|
|
118
118
|
def best_individual(self) -> Union[np.ndarray, None]:
|
|
119
|
-
|
|
120
|
-
if max_param is None:
|
|
119
|
+
if self._algo.max is None:
|
|
121
120
|
return None
|
|
122
|
-
|
|
121
|
+
else:
|
|
122
|
+
max_param = self._algo.max.get('params', None)
|
|
123
|
+
if max_param is None:
|
|
124
|
+
return None
|
|
125
|
+
return self._algo.space.params_to_array(max_param)
|
|
123
126
|
|
|
124
127
|
def stopping(self, ind_iter: int, stopping_parameters: StoppingParameters):
|
|
125
128
|
if ind_iter >= stopping_parameters.niter:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .daq_logger import main
|
|
@@ -12,7 +12,6 @@ import datetime
|
|
|
12
12
|
from typing import TYPE_CHECKING, Union
|
|
13
13
|
|
|
14
14
|
from pymodaq_utils.logger import set_logger, get_module_name
|
|
15
|
-
from pymodaq_gui.utils.custom_app import CustomApp
|
|
16
15
|
from pymodaq_gui.utils.dock import Dock, DockArea
|
|
17
16
|
from pymodaq_utils.config import Config
|
|
18
17
|
from pymodaq_gui.parameter import ioxml
|
|
@@ -26,7 +25,7 @@ from pymodaq_gui.utils.widgets import QLED
|
|
|
26
25
|
from pymodaq.extensions.daq_logger.h5logging import H5Logger
|
|
27
26
|
from pymodaq.utils.managers.modules_manager import ModulesManager
|
|
28
27
|
from pymodaq.utils.data import DataActuator, DataToExport
|
|
29
|
-
|
|
28
|
+
from pymodaq.extensions.utils import CustomExt
|
|
30
29
|
|
|
31
30
|
if TYPE_CHECKING:
|
|
32
31
|
from pymodaq.dashboard import DashBoard
|
|
@@ -51,7 +50,7 @@ if is_sql:
|
|
|
51
50
|
LOG_TYPES.append('SQL DataBase')
|
|
52
51
|
|
|
53
52
|
|
|
54
|
-
class DAQ_Logger(
|
|
53
|
+
class DAQ_Logger(CustomExt):
|
|
55
54
|
"""
|
|
56
55
|
Main class initializing a DAQ_Logger module
|
|
57
56
|
"""
|
|
@@ -147,10 +146,10 @@ class DAQ_Logger(CustomApp):
|
|
|
147
146
|
|
|
148
147
|
self._actions['infos'].connect_to(self.dashboard.show_log)
|
|
149
148
|
|
|
150
|
-
def setup_menu(self):
|
|
149
|
+
def setup_menu(self, menubar: QtWidgets.QMenuBar = None):
|
|
151
150
|
"""
|
|
152
151
|
"""
|
|
153
|
-
file_menu =
|
|
152
|
+
file_menu = menubar.addMenu('File')
|
|
154
153
|
self.affect_to('infos', file_menu)
|
|
155
154
|
|
|
156
155
|
def value_changed(self, param):
|
pymodaq/extensions/daq_scan.py
CHANGED
|
@@ -29,18 +29,16 @@ from pymodaq_gui.parameter import ioxml
|
|
|
29
29
|
from pymodaq_gui.plotting.data_viewers import ViewersEnum
|
|
30
30
|
from pymodaq_gui.managers.parameter_manager import ParameterManager, Parameter, ParameterTree
|
|
31
31
|
from pymodaq_gui.plotting.navigator import Navigator
|
|
32
|
-
|
|
33
32
|
from pymodaq_gui.messenger import messagebox
|
|
34
33
|
from pymodaq_gui import utils as gutils
|
|
35
34
|
from pymodaq_gui.h5modules.saving import H5Saver
|
|
36
35
|
|
|
37
|
-
from pymodaq.utils.scanner.scanner import Scanner
|
|
36
|
+
from pymodaq.utils.scanner.scanner import Scanner
|
|
38
37
|
from pymodaq.utils.managers.batchscan_manager import BatchScanner
|
|
39
38
|
from pymodaq.utils.managers.modules_manager import ModulesManager
|
|
40
39
|
from pymodaq.post_treatment.load_and_plot import LoaderPlotter
|
|
41
40
|
from pymodaq.extensions.daq_scan_ui import DAQScanUI
|
|
42
41
|
from pymodaq.utils.h5modules import module_saving
|
|
43
|
-
|
|
44
42
|
from pymodaq.utils.scanner.scan_selector import ScanSelector, SelectorItem
|
|
45
43
|
from pymodaq.utils.data import DataActuator
|
|
46
44
|
|
|
@@ -88,7 +86,12 @@ class DAQScan(QObject, ParameterManager):
|
|
|
88
86
|
{'title': 'Timeout (ms)', 'name': 'timeout', 'type': 'int', 'value': 10000},
|
|
89
87
|
]},
|
|
90
88
|
{'title': 'Scan options', 'name': 'scan_options', 'type': 'group', 'children': [
|
|
91
|
-
{'title': 'Naverage:', 'name': 'scan_average', 'type': 'int',
|
|
89
|
+
{'title': 'Naverage:', 'name': 'scan_average', 'type': 'int',
|
|
90
|
+
'value': config('scan', 'Naverage'), 'min': 1},
|
|
91
|
+
{'title': 'Plot on top:', 'name': 'average_on_top', 'type': 'bool',
|
|
92
|
+
'value': config('scan', 'average_on_top'),
|
|
93
|
+
'tip': 'At the second iteration will plot the averaged scan on top (True) of the current one'
|
|
94
|
+
'or in a second panel (False)'},
|
|
92
95
|
]},
|
|
93
96
|
|
|
94
97
|
{'title': 'Plotting options', 'name': 'plot_options', 'type': 'group', 'children': [
|
|
@@ -441,7 +444,7 @@ class DAQScan(QObject, ParameterManager):
|
|
|
441
444
|
if not os.path.isdir(self.h5saver.settings['base_path']):
|
|
442
445
|
os.mkdir(self.h5saver.settings['base_path'])
|
|
443
446
|
filename = gutils.file_io.select_file(self.h5saver.settings['base_path'], save=True, ext='h5')
|
|
444
|
-
self.h5saver.h5_file.copy_file(str(filename))
|
|
447
|
+
self.h5saver.h5_file.copy_file(str(filename), overwrite=True)
|
|
445
448
|
|
|
446
449
|
def save_metadata(self, node, type_info='dataset_info'):
|
|
447
450
|
"""
|
|
@@ -635,6 +638,10 @@ class DAQScan(QObject, ParameterManager):
|
|
|
635
638
|
viewers_enum.extend([ViewersEnum('Data1D').increase_dim(self.scanner.n_axes)
|
|
636
639
|
for _ in range(len(self.settings['plot_options', 'plot_1d']['selected']))])
|
|
637
640
|
data_names.extend(self.settings['plot_options', 'plot_1d']['selected'][:])
|
|
641
|
+
if not self.settings['scan_options', 'average_on_top']:
|
|
642
|
+
|
|
643
|
+
viewers_enum = viewers_enum + viewers_enum
|
|
644
|
+
data_names = data_names + [f'{data_name}_averaged' for data_name in data_names]
|
|
638
645
|
self.live_plotter.prepare_viewers(viewers_enum, viewers_name=data_names)
|
|
639
646
|
|
|
640
647
|
def update_status(self, txt: str, wait_time=0):
|
|
@@ -674,6 +681,7 @@ class DAQScan(QObject, ParameterManager):
|
|
|
674
681
|
self.ui.set_scan_step_average(status.attribute[1] + 1)
|
|
675
682
|
|
|
676
683
|
elif status.command == "Scan_done":
|
|
684
|
+
|
|
677
685
|
self.modules_manager.reset_signals()
|
|
678
686
|
self.live_timer.stop()
|
|
679
687
|
self.ui.set_scan_done()
|
|
@@ -738,6 +746,7 @@ class DAQScan(QObject, ParameterManager):
|
|
|
738
746
|
self.live_plotter.load_plot_data(group_0D=self.settings['plot_options', 'group0D'],
|
|
739
747
|
average_axis=average_axis,
|
|
740
748
|
average_index=self.ind_average,
|
|
749
|
+
separate_average= not self.settings['scan_options', 'average_on_top'],
|
|
741
750
|
target_at=self.scanner.positions[self.ind_scan],
|
|
742
751
|
last_step=(self.ind_scan ==
|
|
743
752
|
self.scanner.positions.size - 1 and
|
|
@@ -774,6 +783,8 @@ class DAQScan(QObject, ParameterManager):
|
|
|
774
783
|
text="There are not enough or too much selected move modules for this scan")
|
|
775
784
|
return False
|
|
776
785
|
|
|
786
|
+
## TODO the stuff about adaptive scans have to be moved into a dedicated extension. M
|
|
787
|
+
## Most similat to the Bayesian one!
|
|
777
788
|
if self.scanner.scan_sub_type == 'Adaptive':
|
|
778
789
|
#todo include this in scanners objects for the adaptive scanners
|
|
779
790
|
if len(self.modules_manager.get_selected_probed_data('0D')) == 0:
|
|
@@ -862,9 +873,15 @@ class DAQScan(QObject, ParameterManager):
|
|
|
862
873
|
self.save_metadata(scan_node, 'scan_info')
|
|
863
874
|
|
|
864
875
|
self._init_live()
|
|
876
|
+
Naverage = self.settings['scan_options', 'scan_average']
|
|
877
|
+
if Naverage > 1:
|
|
878
|
+
scan_shape = [Naverage]
|
|
879
|
+
scan_shape.extend(self.scanner.get_scan_shape())
|
|
880
|
+
else:
|
|
881
|
+
scan_shape = self.scanner.get_scan_shape()
|
|
865
882
|
for det in self.modules_manager.detectors:
|
|
866
883
|
det.module_and_data_saver = (
|
|
867
|
-
module_saving.DetectorExtendedSaver(det,
|
|
884
|
+
module_saving.DetectorExtendedSaver(det, scan_shape))
|
|
868
885
|
self.module_and_data_saver.h5saver = self.h5saver # force the update as the h5saver ill also be set on each detectors
|
|
869
886
|
|
|
870
887
|
# mandatory to deal with multithreads
|
|
@@ -1044,7 +1061,7 @@ class DAQScanAcquisition(QObject):
|
|
|
1044
1061
|
|
|
1045
1062
|
def start_acquisition(self):
|
|
1046
1063
|
try:
|
|
1047
|
-
#todo hoaw to apply newlayout to adaptive mode?
|
|
1064
|
+
#todo hoaw to apply newlayout to adaptive mode? => cannot has to be a new extension
|
|
1048
1065
|
|
|
1049
1066
|
self.modules_manager.connect_actuators()
|
|
1050
1067
|
self.modules_manager.connect_detectors()
|
|
@@ -1116,6 +1133,7 @@ class DAQScanAcquisition(QObject):
|
|
|
1116
1133
|
# daq_scan wait time
|
|
1117
1134
|
QThread.msleep(self.scan_settings.child('time_flow', 'wait_time').value())
|
|
1118
1135
|
|
|
1136
|
+
self.modules_manager.timeout_signal.disconnect()
|
|
1119
1137
|
self.modules_manager.connect_actuators(False)
|
|
1120
1138
|
self.modules_manager.connect_detectors(False)
|
|
1121
1139
|
|
|
@@ -1123,6 +1141,7 @@ class DAQScanAcquisition(QObject):
|
|
|
1123
1141
|
attribute="Acquisition has finished"))
|
|
1124
1142
|
self.status_sig.emit(utils.ThreadCommand("Scan_done"))
|
|
1125
1143
|
|
|
1144
|
+
|
|
1126
1145
|
except Exception as e:
|
|
1127
1146
|
logger.exception(str(e))
|
|
1128
1147
|
|
|
@@ -1158,7 +1177,8 @@ class DAQScanAcquisition(QObject):
|
|
|
1158
1177
|
full_names: list = self.scan_settings['plot_options', 'plot_0d']['selected'][:]
|
|
1159
1178
|
full_names.extend(self.scan_settings['plot_options', 'plot_1d']['selected'][:])
|
|
1160
1179
|
data_temp = det_done_datas.get_data_from_full_names(full_names, deepcopy=False)
|
|
1161
|
-
|
|
1180
|
+
n_nav_axis_selection = 2-len(indexes) + 1 if self.Naverage > 1 else 2-len(indexes)
|
|
1181
|
+
data_temp = data_temp.get_data_with_naxes_lower_than(n_nav_axis_selection) # maximum Data2D included nav indexes
|
|
1162
1182
|
|
|
1163
1183
|
self.scan_data_tmp.emit(ScanDataTemp(self.ind_scan, indexes, data_temp))
|
|
1164
1184
|
|
|
@@ -38,9 +38,10 @@ class DAQScanUI(CustomApp, ViewerDispatcher):
|
|
|
38
38
|
def __init__(self, parent):
|
|
39
39
|
CustomApp.__init__(self, parent)
|
|
40
40
|
self.setup_docks()
|
|
41
|
-
ViewerDispatcher.__init__(self, self.dockarea, title='Scanner',
|
|
41
|
+
ViewerDispatcher.__init__(self, self.dockarea, title='Scanner',
|
|
42
|
+
next_to_dock=self.dock_command)
|
|
42
43
|
|
|
43
|
-
self.setup_menu()
|
|
44
|
+
self.setup_menu(self._menubar)
|
|
44
45
|
self.setup_actions()
|
|
45
46
|
self.connect_things()
|
|
46
47
|
|
|
@@ -83,13 +84,10 @@ class DAQScanUI(CustomApp, ViewerDispatcher):
|
|
|
83
84
|
self.connect_action('navigator', lambda: self.command_sig.emit(ThreadCommand('navigator')))
|
|
84
85
|
self.connect_action('batch', lambda: self.command_sig.emit(ThreadCommand('batch')))
|
|
85
86
|
|
|
86
|
-
def setup_menu(self):
|
|
87
|
-
self.
|
|
88
|
-
self.menubar.
|
|
89
|
-
self.
|
|
90
|
-
self.file_menu = self.menubar.addMenu('File')
|
|
91
|
-
self._extensions_menu = self.menubar.addMenu('Extensions')
|
|
92
|
-
self.action_menu = self.menubar.addMenu('Actions')
|
|
87
|
+
def setup_menu(self, menubar: QtWidgets.QMenuBar = None):
|
|
88
|
+
self.file_menu = menubar.addMenu('File')
|
|
89
|
+
self._extensions_menu = menubar.addMenu('Extensions')
|
|
90
|
+
self.action_menu = menubar.addMenu('Actions')
|
|
93
91
|
|
|
94
92
|
def setup_docks(self):
|
|
95
93
|
self.dock_command = Dock('Scan Command')
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from .pid_controller import DAQ_PID
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PIDController:
|
|
8
|
+
""" Fake controller object for the DAQ_Move_PID"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, daq_pid: 'DAQ_PID'):
|
|
11
|
+
self.curr_point = daq_pid.curr_points_signal
|
|
12
|
+
self.setpoint = daq_pid.setpoints_signal
|
|
13
|
+
self.emit_curr_points = daq_pid.emit_curr_points_sig
|
|
@@ -1,32 +1,30 @@
|
|
|
1
|
-
from easydict import EasyDict as edict
|
|
2
|
-
|
|
3
1
|
from pymodaq_utils.utils import ThreadCommand
|
|
4
2
|
|
|
5
|
-
from pymodaq.control_modules.move_utility_classes import DAQ_Move_base, comon_parameters_fun
|
|
3
|
+
from pymodaq.control_modules.move_utility_classes import (DAQ_Move_base, comon_parameters_fun,
|
|
4
|
+
DataActuatorType, DataActuator)
|
|
5
|
+
|
|
6
|
+
from pymodaq.extensions.pid.actuator_controller import PIDController
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class DAQ_Move_PID(DAQ_Move_base):
|
|
9
10
|
"""
|
|
10
11
|
"""
|
|
11
|
-
_controller_units = '
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
_controller_units = ''
|
|
13
|
+
data_actuator_type = DataActuatorType.DataActuator
|
|
14
|
+
is_multiaxes = False
|
|
15
|
+
stage_names = ['',]
|
|
14
16
|
|
|
15
17
|
params = comon_parameters_fun(is_multiaxes, stage_names, master=False)
|
|
16
18
|
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
+
def ini_attributes(self):
|
|
20
|
+
self.controller: PIDController = None
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
def update_position(self, dict_val):
|
|
22
|
+
def update_position(self, dict_val: dict):
|
|
22
23
|
self.current_value = dict_val[self.parent.title]
|
|
23
24
|
|
|
24
25
|
def get_actuator_value(self):
|
|
25
|
-
self.controller
|
|
26
|
+
self.controller.emit_curr_points.emit()
|
|
26
27
|
pos = self.current_value
|
|
27
|
-
#
|
|
28
|
-
# pos = self.get_position_with_scaling(pos)
|
|
29
|
-
# self.current_value = pos
|
|
30
28
|
return pos
|
|
31
29
|
|
|
32
30
|
def close(self):
|
|
@@ -38,51 +36,32 @@ class DAQ_Move_PID(DAQ_Move_base):
|
|
|
38
36
|
def ini_stage(self, controller=None):
|
|
39
37
|
"""
|
|
40
38
|
"""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
self.controller = None # any object that will control the stages
|
|
51
|
-
|
|
52
|
-
self.controller['curr_point'].connect(self.update_position)
|
|
53
|
-
|
|
54
|
-
info = "PID stage"
|
|
55
|
-
self.status.info = info
|
|
56
|
-
self.status.controller = self.controller
|
|
57
|
-
self.status.initialized = True
|
|
58
|
-
return self.status.info, self.status.initialized
|
|
59
|
-
|
|
60
|
-
except Exception as e:
|
|
61
|
-
self.status.info = str(e)
|
|
62
|
-
self.status.initialized = False
|
|
63
|
-
return self.status
|
|
64
|
-
|
|
65
|
-
def move_Abs(self, position):
|
|
39
|
+
self.controller = controller
|
|
40
|
+
|
|
41
|
+
self.controller.curr_point.connect(self.update_position)
|
|
42
|
+
|
|
43
|
+
info = "PID stage"
|
|
44
|
+
initialized = True
|
|
45
|
+
return info, initialized
|
|
46
|
+
|
|
47
|
+
def move_abs(self, position: DataActuator):
|
|
66
48
|
"""
|
|
67
49
|
"""
|
|
68
50
|
position = self.check_bound(position)
|
|
69
|
-
# position=self.set_position_with_scaling(position)
|
|
70
|
-
# print(position)
|
|
71
51
|
self.target_position = position
|
|
72
52
|
|
|
73
|
-
self.controller
|
|
74
|
-
self.poll_moving()
|
|
53
|
+
self.controller.setpoint.emit({self.parent.title: self.target_position})
|
|
75
54
|
|
|
76
|
-
def
|
|
55
|
+
def move_rel(self, position: DataActuator):
|
|
77
56
|
"""
|
|
78
57
|
"""
|
|
79
58
|
position = self.check_bound(self.current_value + position) - self.current_value
|
|
80
59
|
self.target_position = position + self.current_value
|
|
81
60
|
|
|
82
|
-
self.controller
|
|
61
|
+
self.controller.setpoint.emit({self.parent.title: self.target_position})
|
|
83
62
|
self.poll_moving()
|
|
84
63
|
|
|
85
|
-
def
|
|
64
|
+
def move_home(self):
|
|
86
65
|
"""
|
|
87
66
|
"""
|
|
88
67
|
self.emit_status(ThreadCommand('Update_Status', ['Move Home not implemented']))
|