|
1
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
|
|
3
|
|
|
""" |
|
4
|
|
|
This file contains the GUI for magnet control. |
|
5
|
|
|
|
|
6
|
|
|
QuDi is free software: you can redistribute it and/or modify |
|
7
|
|
|
it under the terms of the GNU General Public License as published by |
|
8
|
|
|
the Free Software Foundation, either version 3 of the License, or |
|
9
|
|
|
(at your option) any later version. |
|
10
|
|
|
|
|
11
|
|
|
QuDi is distributed in the hope that it will be useful, |
|
12
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14
|
|
|
GNU General Public License for more details. |
|
15
|
|
|
|
|
16
|
|
|
You should have received a copy of the GNU General Public License |
|
17
|
|
|
along with QuDi. If not, see <http://www.gnu.org/licenses/>. |
|
18
|
|
|
|
|
19
|
|
|
Copyright (c) the Qudi Developers. See the COPYRIGHT.txt file at the |
|
20
|
|
|
top-level directory of this distribution and at <https://github.com/Ulm-IQO/qudi/> |
|
21
|
|
|
""" |
|
22
|
|
|
|
|
23
|
|
|
import os |
|
24
|
|
|
import numpy as np |
|
25
|
|
|
import pyqtgraph as pg |
|
26
|
|
|
from qtpy import QtCore |
|
27
|
|
|
from qtpy import QtWidgets |
|
28
|
|
|
from qtpy import uic |
|
29
|
|
|
import datetime |
|
30
|
|
|
|
|
31
|
|
|
from gui.guibase import GUIBase |
|
32
|
|
|
from gui.guiutils import ColorBar |
|
33
|
|
|
from gui.colordefs import ColorScaleInferno |
|
34
|
|
|
from core.util.units import get_unit_prefix_dict |
|
35
|
|
|
from tools.scientific_spinbox import ScienSpinBox |
|
36
|
|
|
from tools.scientific_spinbox import ScienDSpinBox |
|
37
|
|
|
import pyqtgraph.exporters |
|
38
|
|
|
|
|
39
|
|
|
|
|
40
|
|
|
class MagnetMainWindow(QtWidgets.QMainWindow): |
|
41
|
|
|
""" Create the Main Window based on the *.ui file. """ |
|
42
|
|
|
|
|
43
|
|
|
def __init__(self): |
|
44
|
|
|
# Get the path to the *.ui file |
|
45
|
|
|
this_dir = os.path.dirname(__file__) |
|
46
|
|
|
ui_file = os.path.join(this_dir, 'ui_magnet_gui.ui') |
|
47
|
|
|
|
|
48
|
|
|
# Load it |
|
49
|
|
|
super(MagnetMainWindow, self).__init__() |
|
50
|
|
|
uic.loadUi(ui_file, self) |
|
51
|
|
|
self.show() |
|
52
|
|
|
|
|
53
|
|
|
class MagnetSettingsWindow(QtWidgets.QDialog): |
|
54
|
|
|
def __init__(self): |
|
55
|
|
|
# Get the path to the *.ui file |
|
56
|
|
|
this_dir = os.path.dirname(__file__) |
|
57
|
|
|
ui_file = os.path.join(this_dir, 'ui_magnet_settings.ui') |
|
58
|
|
|
|
|
59
|
|
|
# Load it |
|
60
|
|
|
super(MagnetSettingsWindow, self).__init__() |
|
61
|
|
|
|
|
62
|
|
|
uic.loadUi(ui_file, self) |
|
63
|
|
|
|
|
64
|
|
|
|
|
65
|
|
|
class MagnetGui(GUIBase): |
|
66
|
|
|
""" Main GUI for the magnet. """ |
|
67
|
|
|
|
|
68
|
|
|
_modclass = 'MagnetGui' |
|
69
|
|
|
_modtype = 'gui' |
|
70
|
|
|
|
|
71
|
|
|
## declare connectors |
|
72
|
|
|
_in = {'magnetlogic1': 'MagnetLogic', |
|
73
|
|
|
'savelogic': 'SaveLogic'} |
|
74
|
|
|
|
|
75
|
|
|
def __init__(self, config, **kwargs): |
|
76
|
|
|
super().__init__(config=config, **kwargs) |
|
77
|
|
|
|
|
78
|
|
|
self.log.info('The following configuration was found.') |
|
79
|
|
|
|
|
80
|
|
|
# checking for the right configuration |
|
81
|
|
|
for key in config.keys(): |
|
82
|
|
|
self.log.info('{0}: {1}'.format(key,config[key])) |
|
83
|
|
|
|
|
84
|
|
|
self._continue_2d_fluorescence_alignment = False |
|
85
|
|
|
|
|
86
|
|
|
|
|
87
|
|
|
def on_activate(self, e=None): |
|
88
|
|
|
""" Definition and initialisation of the GUI. |
|
89
|
|
|
|
|
90
|
|
|
@param object e: Fysom.event object from Fysom class. |
|
91
|
|
|
An object created by the state machine module Fysom, |
|
92
|
|
|
which is connected to a specific event (have a look in |
|
93
|
|
|
the Base Class). This object contains the passed event, |
|
94
|
|
|
the state before the event happened and the destination |
|
95
|
|
|
of the state which should be reached after the event |
|
96
|
|
|
had happened. |
|
97
|
|
|
""" |
|
98
|
|
|
self._magnet_logic = self.connector['in']['magnetlogic1']['object'] |
|
99
|
|
|
self._save_logic = self.connector['in']['savelogic']['object'] |
|
100
|
|
|
|
|
101
|
|
|
self._mw = MagnetMainWindow() |
|
102
|
|
|
|
|
103
|
|
|
config = self.getConfiguration() |
|
104
|
|
|
|
|
105
|
|
|
# create all the needed control elements. They will manage the |
|
106
|
|
|
# connection with each other themselves. Note some buttons are also |
|
107
|
|
|
# connected within these functions because they have to be placed at |
|
108
|
|
|
# first in the GUI Layout, otherwise the signals will not react. |
|
109
|
|
|
self._create_axis_pos_disp() |
|
110
|
|
|
self._create_move_rel_control() |
|
111
|
|
|
self._create_move_abs_control() |
|
112
|
|
|
|
|
113
|
|
|
self._create_meas_type_RadioButtons() |
|
114
|
|
|
|
|
115
|
|
|
# Configuring the dock widgets |
|
116
|
|
|
# Use the class 'MagnetMainWindow' to create the GUI window |
|
117
|
|
|
|
|
118
|
|
|
axis_list = list(self._magnet_logic.get_hardware_constraints()) |
|
119
|
|
|
self._mw.align_2d_axes0_name_ComboBox.clear() |
|
120
|
|
|
self._mw.align_2d_axes0_name_ComboBox.addItems(axis_list) |
|
121
|
|
|
|
|
122
|
|
|
self._mw.align_2d_axes1_name_ComboBox.clear() |
|
123
|
|
|
self._mw.align_2d_axes1_name_ComboBox.addItems(axis_list) |
|
124
|
|
|
|
|
125
|
|
|
# Setup dock widgets |
|
126
|
|
|
self._mw.centralwidget.hide() |
|
127
|
|
|
self._mw.setDockNestingEnabled(True) |
|
128
|
|
|
# self._mw.tabifyDockWidget(self._mw.curr_pos_DockWidget, self._mw.move_rel_DockWidget) |
|
129
|
|
|
# self._mw.tabifyDockWidget(self._mw.curr_pos_DockWidget, self._mw.move_abs_DockWidget) |
|
130
|
|
|
# self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(1), self._mw.curr_pos_DockWidget) |
|
131
|
|
|
# self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(2), self._mw.move_rel_DockWidget) |
|
132
|
|
|
# self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(3), self._mw.move_abs_DockWidget) |
|
133
|
|
|
self.set_default_view_main_window() |
|
134
|
|
|
|
|
135
|
|
|
# After a movement command, the device should not block the program, at |
|
136
|
|
|
# least on the hardware level. That meant that the dll (or whatever |
|
137
|
|
|
# protocol is used to access the hardware) can receive a command during |
|
138
|
|
|
# an ongoing action. That is of course controller specific, but in |
|
139
|
|
|
# general should it should be possible (unless the controller was |
|
140
|
|
|
# written by someone who has no clue what he is doing). Eventually with |
|
141
|
|
|
# that you have the possibility of stopping an ongoing movement! |
|
142
|
|
|
self._interactive_mode = True |
|
143
|
|
|
self._activate_magnet_settings(e) |
|
144
|
|
|
|
|
145
|
|
|
# connect the actions of the toolbar: |
|
146
|
|
|
self._mw.magnet_settings_Action.triggered.connect(self.open_magnet_settings) |
|
147
|
|
|
self._mw.default_view_Action.triggered.connect(self.set_default_view_main_window) |
|
148
|
|
|
|
|
149
|
|
|
self.update_pos() |
|
150
|
|
|
self._magnet_logic.sigPosChanged.connect(self.update_pos) |
|
151
|
|
|
|
|
152
|
|
|
# Connect alignment GUI elements: |
|
153
|
|
|
|
|
154
|
|
|
self._magnet_logic.sigMeasurementFinished.connect(self._change_display_to_stop_2d_alignment) |
|
155
|
|
|
|
|
156
|
|
|
|
|
157
|
|
|
|
|
158
|
|
|
self._mw.align_2d_axes0_name_ComboBox.currentIndexChanged.connect(self._update_limits_axis0) |
|
159
|
|
|
self._mw.align_2d_axes1_name_ComboBox.currentIndexChanged.connect(self._update_limits_axis1) |
|
160
|
|
|
self._mw.align_2d_axis0_set_vel_CheckBox.stateChanged.connect(self._set_vel_display_axis0) |
|
161
|
|
|
self._mw.align_2d_axis1_set_vel_CheckBox.stateChanged.connect(self._set_vel_display_axis1) |
|
162
|
|
|
|
|
163
|
|
|
|
|
164
|
|
|
self._mw.alignment_2d_cb_min_centiles_DSpinBox.valueChanged.connect(self._update_2d_graph_data) |
|
165
|
|
|
self._mw.alignment_2d_cb_max_centiles_DSpinBox.valueChanged.connect(self._update_2d_graph_data) |
|
166
|
|
|
self._mw.alignment_2d_cb_low_centiles_DSpinBox.valueChanged.connect(self._update_2d_graph_data) |
|
167
|
|
|
self._mw.alignment_2d_cb_high_centiles_DSpinBox.valueChanged.connect(self._update_2d_graph_data) |
|
168
|
|
|
|
|
169
|
|
|
self._update_limits_axis0() |
|
170
|
|
|
self._update_limits_axis1() |
|
171
|
|
|
self._set_vel_display_axis0() |
|
172
|
|
|
self._set_vel_display_axis1() |
|
173
|
|
|
|
|
174
|
|
|
self._2d_alignment_ImageItem = pg.ImageItem(self._magnet_logic.get_2d_data_matrix()) |
|
175
|
|
|
axis0, axis1 = self._magnet_logic.get_2d_axis_arrays() |
|
176
|
|
|
self._2d_alignment_ImageItem.setRect(QtCore.QRectF(axis0[0], |
|
177
|
|
|
axis1[0], |
|
178
|
|
|
axis0[-1]-axis0[0], |
|
179
|
|
|
axis1[-1]-axis1[0],)) |
|
180
|
|
|
|
|
181
|
|
|
self._mw.alignment_2d_GraphicsView.addItem(self._2d_alignment_ImageItem) |
|
182
|
|
|
|
|
183
|
|
|
# Get the colorscales at set LUT |
|
184
|
|
|
my_colors = ColorScaleInferno() |
|
185
|
|
|
|
|
186
|
|
|
self._2d_alignment_ImageItem.setLookupTable(my_colors.lut) |
|
187
|
|
|
|
|
188
|
|
|
|
|
189
|
|
|
|
|
190
|
|
|
# Configuration of Colorbar: |
|
191
|
|
|
self._2d_alignment_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000) |
|
192
|
|
|
|
|
193
|
|
|
self._mw.alignment_2d_cb_GraphicsView.addItem(self._2d_alignment_cb) |
|
194
|
|
|
self._mw.alignment_2d_cb_GraphicsView.hideAxis('bottom') |
|
195
|
|
|
self._mw.alignment_2d_cb_GraphicsView.hideAxis('left') |
|
196
|
|
|
|
|
197
|
|
|
self._mw.alignment_2d_cb_GraphicsView.addItem(self._2d_alignment_cb) |
|
198
|
|
|
|
|
199
|
|
|
if 'alignment_2d_cb_GraphicsView_text' in self._statusVariables: |
|
200
|
|
|
textlabel = self._statusVariables['alignment_2d_cb_GraphicsView_text'] |
|
201
|
|
|
|
|
202
|
|
|
else: |
|
203
|
|
|
textlabel = 'Fluorescence' |
|
204
|
|
|
|
|
205
|
|
|
if 'alignment_2d_cb_GraphicsView_units' in self._statusVariables: |
|
206
|
|
|
units = self._statusVariables['alignment_2d_cb_GraphicsView_units'] |
|
207
|
|
|
else: |
|
208
|
|
|
units = 'counts/s' |
|
209
|
|
|
|
|
210
|
|
|
self._mw.alignment_2d_cb_GraphicsView.setLabel('right', textlabel, units=units) |
|
211
|
|
|
|
|
212
|
|
|
#FIXME: save that in the logic |
|
213
|
|
|
if 'align_2d_axes0_range_DSpinBox' in self._statusVariables: |
|
214
|
|
|
self._mw.align_2d_axes0_range_DSpinBox.setValue(self._statusVariables['align_2d_axes0_range_DSpinBox']) |
|
215
|
|
|
if 'align_2d_axes0_step_DSpinBox' in self._statusVariables: |
|
216
|
|
|
self._mw.align_2d_axes0_step_DSpinBox.setValue(self._statusVariables['align_2d_axes0_step_DSpinBox']) |
|
217
|
|
|
if 'align_2d_axes0_vel_DSpinBox' in self._statusVariables: |
|
218
|
|
|
self._mw.align_2d_axes0_vel_DSpinBox.setValue(self._statusVariables['align_2d_axes0_vel_DSpinBox']) |
|
219
|
|
|
if 'align_2d_axes1_range_DSpinBox' in self._statusVariables: |
|
220
|
|
|
self._mw.align_2d_axes1_range_DSpinBox.setValue(self._statusVariables['align_2d_axes1_range_DSpinBox']) |
|
221
|
|
|
if 'align_2d_axes1_step_DSpinBox' in self._statusVariables: |
|
222
|
|
|
self._mw.align_2d_axes1_step_DSpinBox.setValue(self._statusVariables['align_2d_axes1_step_DSpinBox']) |
|
223
|
|
|
if 'align_2d_axes1_vel_DSpinBox' in self._statusVariables: |
|
224
|
|
|
self._mw.align_2d_axes1_vel_DSpinBox.setValue(self._statusVariables['align_2d_axes1_vel_DSpinBox']) |
|
225
|
|
|
|
|
226
|
|
|
#FIXME: that should be actually set in the logic |
|
227
|
|
|
if 'measurement_type' in self._statusVariables: |
|
228
|
|
|
self.measurement_type = self._statusVariables['measurement_type'] |
|
229
|
|
|
else: |
|
230
|
|
|
self.measurement_type = 'fluorescence' |
|
231
|
|
|
|
|
232
|
|
|
self._magnet_logic.sig2DAxisChanged.connect(self._update_2d_graph_axis) |
|
233
|
|
|
self._magnet_logic.sig2DMatrixChanged.connect(self._update_2d_graph_data) |
|
234
|
|
|
|
|
235
|
|
|
# Connect the buttons and inputs for the odmr colorbar |
|
236
|
|
|
self._mw.alignment_2d_manual_RadioButton.clicked.connect(self._update_2d_graph_data) |
|
237
|
|
|
self._mw.alignment_2d_centiles_RadioButton.clicked.connect(self._update_2d_graph_data) |
|
238
|
|
|
|
|
239
|
|
|
self._update_2d_graph_data() |
|
240
|
|
|
self._update_2d_graph_cb() |
|
241
|
|
|
|
|
242
|
|
|
|
|
243
|
|
|
# Add save file tag input box |
|
244
|
|
|
self._mw.alignment_2d_nametag_LineEdit = QtWidgets.QLineEdit(self._mw) |
|
245
|
|
|
self._mw.alignment_2d_nametag_LineEdit.setMaximumWidth(200) |
|
246
|
|
|
self._mw.alignment_2d_nametag_LineEdit.setToolTip('Enter a nametag which will be\n' |
|
247
|
|
|
'added to the filename.') |
|
248
|
|
|
|
|
249
|
|
|
self._mw.save_ToolBar.addWidget(self._mw.alignment_2d_nametag_LineEdit) |
|
250
|
|
|
self._mw.save_Action.triggered.connect(self.save_2d_plots_and_data) |
|
251
|
|
|
|
|
252
|
|
|
self._mw.run_stop_2d_alignment_Action.triggered.connect(self.run_stop_2d_alignment) |
|
253
|
|
|
self._mw.continue_2d_alignment_Action.triggered.connect(self.continue_stop_2d_alignment) |
|
254
|
|
|
|
|
255
|
|
|
# connect the signals: |
|
256
|
|
|
# -------------------- |
|
257
|
|
|
|
|
258
|
|
|
# for fluorescence alignment: |
|
259
|
|
|
self._mw.align_2d_fluorescence_optimize_CheckBox.stateChanged.connect(self.optimize_pos_changed) |
|
260
|
|
|
|
|
261
|
|
|
|
|
262
|
|
|
# for odmr alignment: |
|
263
|
|
|
self._mw.meas_type_fluorescence_RadioButton.toggled.connect(self.set_measurement_type) |
|
264
|
|
|
self._mw.meas_type_odmr_RadioButton.toggled.connect(self.set_measurement_type) |
|
265
|
|
|
self._mw.meas_type_nuclear_spin_RadioButton.toggled.connect(self.set_measurement_type) |
|
266
|
|
|
self.set_measurement_type() |
|
267
|
|
|
|
|
268
|
|
|
# for odmr alignment: |
|
269
|
|
|
self._mw.align_2d_odmr_low_fit_func_ComboBox.clear() |
|
270
|
|
|
self._mw.align_2d_odmr_low_fit_func_ComboBox.addItems(self._magnet_logic.odmr_2d_low_fitfunction_list) |
|
271
|
|
|
self._mw.align_2d_odmr_low_fit_func_ComboBox.setCurrentIndex(1) |
|
272
|
|
|
self._mw.align_2d_odmr_low_center_freq_DSpinBox.setValue(self._magnet_logic.odmr_2d_low_center_freq) |
|
273
|
|
|
self._mw.align_2d_odmr_low_range_freq_DSpinBox.setValue(self._magnet_logic.odmr_2d_low_range_freq) |
|
274
|
|
|
self._mw.align_2d_odmr_low_step_freq_DSpinBox.setValue(self._magnet_logic.odmr_2d_low_step_freq) |
|
275
|
|
|
self._mw.align_2d_odmr_low_power_DSpinBox.setValue(self._magnet_logic.odmr_2d_low_power) |
|
276
|
|
|
self._mw.align_2d_odmr_low_runtime_DSpinBox.setValue(self._magnet_logic.odmr_2d_low_runtime) |
|
277
|
|
|
|
|
278
|
|
|
self._mw.align_2d_odmr_high_fit_func_ComboBox.clear() |
|
279
|
|
|
self._mw.align_2d_odmr_high_fit_func_ComboBox.addItems(self._magnet_logic.odmr_2d_high_fitfunction_list) |
|
280
|
|
|
self._mw.align_2d_odmr_high_fit_func_ComboBox.setCurrentIndex(1) |
|
281
|
|
|
self._mw.align_2d_odmr_high_center_freq_DSpinBox.setValue(self._magnet_logic.odmr_2d_high_center_freq) |
|
282
|
|
|
self._mw.align_2d_odmr_high_range_freq_DSpinBox.setValue(self._magnet_logic.odmr_2d_high_range_freq) |
|
283
|
|
|
self._mw.align_2d_odmr_high_step_freq_DSpinBox.setValue(self._magnet_logic.odmr_2d_high_step_freq) |
|
284
|
|
|
self._mw.align_2d_odmr_high_power_DSpinBox.setValue(self._magnet_logic.odmr_2d_high_power) |
|
285
|
|
|
self._mw.align_2d_odmr_high_runtime_DSpinBox.setValue(self._magnet_logic.odmr_2d_high_runtime) |
|
286
|
|
|
|
|
287
|
|
|
self._mw.align_2d_odmr_save_after_measure_CheckBox.setChecked(self._magnet_logic.odmr_2d_save_after_measure) |
|
288
|
|
|
|
|
289
|
|
|
self._mw.odmr_2d_single_trans_CheckBox.stateChanged.connect(self._odmr_single_trans_alignment_changed) |
|
290
|
|
|
|
|
291
|
|
|
# peak shift for odmr: |
|
292
|
|
|
self._mw.align_2d_axes0_shift_DSpinBox.setValue(self._magnet_logic.odmr_2d_peak_axis0_move_ratio/1e12) |
|
293
|
|
|
self._mw.align_2d_axes1_shift_DSpinBox.setValue(self._magnet_logic.odmr_2d_peak_axis1_move_ratio/1e12) |
|
294
|
|
|
|
|
295
|
|
|
|
|
296
|
|
|
|
|
297
|
|
|
# for single shot alignment of a nuclear spin: |
|
298
|
|
|
self._mw.align_2d_nuclear_rabi_periode_DSpinBox.setValue(self._magnet_logic.nuclear_2d_rabi_periode) |
|
299
|
|
|
self._mw.align_2d_nuclear_mw_freq_DSpinBox.setValue(self._magnet_logic.nuclear_2d_mw_freq) |
|
300
|
|
|
self._mw.align_2d_nuclear_mw_channel_SpinBox.setValue(self._magnet_logic.nuclear_2d_mw_channel) |
|
301
|
|
|
self._mw.align_2d_nuclear_mw_power_DSpinBox.setValue(self._magnet_logic.nuclear_2d_mw_power) |
|
302
|
|
|
self._mw.align_2d_nuclear_laser_time_DSpinBox.setValue(self._magnet_logic.nuclear_2d_laser_time) |
|
303
|
|
|
self._mw.align_2d_nuclear_laser_channel_SpinBox.setValue(self._magnet_logic.nuclear_2d_laser_channel) |
|
304
|
|
|
self._mw.align_2d_nuclear_detect_channel_SpinBox.setValue(self._magnet_logic.nuclear_2d_detect_channel) |
|
305
|
|
|
self._mw.align_2d_nuclear_idle_time_DSpinBox.setValue(self._magnet_logic.nuclear_2d_idle_time) |
|
306
|
|
|
self._mw.align_2d_nuclear_reps_within_ssr_SpinBox.setValue(self._magnet_logic.nuclear_2d_reps_within_ssr) |
|
307
|
|
|
self._mw.align_2d_nuclear_num_of_ssr_SpinBox.setValue(self._magnet_logic.nuclear_2d_num_ssr) |
|
308
|
|
|
|
|
309
|
|
|
def _activate_magnet_settings(self, e): |
|
310
|
|
|
""" Activate magnet settings. |
|
311
|
|
|
|
|
312
|
|
|
@param object e: Fysom.event object from Fysom class. A more detailed |
|
313
|
|
|
explanation can be found in the method initUI. |
|
314
|
|
|
""" |
|
315
|
|
|
self._ms = MagnetSettingsWindow() |
|
316
|
|
|
# default config is normal_mode |
|
317
|
|
|
self._ms.normal_mode_checkBox.setChecked(True) |
|
318
|
|
|
self._ms.z_mode_checkBox.setChecked(False) |
|
319
|
|
|
# make sure the buttons are exclusively checked |
|
320
|
|
|
self._ms.normal_mode_checkBox.stateChanged.connect(self.trig_wrapper_normal_mode) |
|
321
|
|
|
self._ms.z_mode_checkBox.stateChanged.connect(self.trig_wrapper_z_mode) |
|
322
|
|
|
|
|
323
|
|
|
#self._ms.z_mode_checkBox.stateChanged.connect(self._ms.normal_mode_checkBox.toggle) |
|
324
|
|
|
self._ms.accepted.connect(self.update_magnet_settings) |
|
325
|
|
|
self._ms.rejected.connect(self.keep_former_magnet_settings) |
|
326
|
|
|
self._ms.ButtonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_magnet_settings) |
|
327
|
|
|
|
|
328
|
|
|
self.keep_former_magnet_settings() |
|
329
|
|
|
|
|
330
|
|
|
def trig_wrapper_normal_mode(self): |
|
331
|
|
|
if not self._ms.normal_mode_checkBox.isChecked() and not self._ms.z_mode_checkBox.isChecked(): |
|
332
|
|
|
self._ms.z_mode_checkBox.toggle() |
|
333
|
|
|
elif self._ms.normal_mode_checkBox.isChecked() and self._ms.z_mode_checkBox.isChecked(): |
|
334
|
|
|
self._ms.z_mode_checkBox.toggle() |
|
335
|
|
|
|
|
336
|
|
|
def trig_wrapper_z_mode(self): |
|
337
|
|
|
if not self._ms.normal_mode_checkBox.isChecked() and not self._ms.z_mode_checkBox.isChecked(): |
|
338
|
|
|
self._ms.normal_mode_checkBox.toggle() |
|
339
|
|
|
elif self._ms.normal_mode_checkBox.isChecked() and self._ms.z_mode_checkBox.isChecked(): |
|
340
|
|
|
self._ms.normal_mode_checkBox.toggle() |
|
341
|
|
|
|
|
342
|
|
|
|
|
343
|
|
|
def on_deactivate(self, e=None): |
|
344
|
|
|
""" Deactivate the module properly. |
|
345
|
|
|
|
|
346
|
|
|
@param object e: Fysom.event object from Fysom class. A more detailed |
|
347
|
|
|
explanation can be found in the method initUI. |
|
348
|
|
|
""" |
|
349
|
|
|
self._statusVariables['measurement_type'] = self.measurement_type |
|
350
|
|
|
self._statusVariables['alignment_2d_cb_GraphicsView_text'] = self._mw.alignment_2d_cb_GraphicsView.plotItem.axes['right']['item'].labelText |
|
351
|
|
|
self._statusVariables['alignment_2d_cb_GraphicsView_units'] = self._mw.alignment_2d_cb_GraphicsView.plotItem.axes['right']['item'].labelUnits |
|
352
|
|
|
|
|
353
|
|
|
#FIXME: save that in the logic |
|
354
|
|
|
self._statusVariables['align_2d_axes0_range_DSpinBox'] = self._mw.align_2d_axes0_range_DSpinBox.value() |
|
355
|
|
|
self._statusVariables['align_2d_axes0_step_DSpinBox'] = self._mw.align_2d_axes0_step_DSpinBox.value() |
|
356
|
|
|
self._statusVariables['align_2d_axes0_vel_DSpinBox'] = self._mw.align_2d_axes0_vel_DSpinBox.value() |
|
357
|
|
|
self._statusVariables['align_2d_axes1_range_DSpinBox'] = self._mw.align_2d_axes1_range_DSpinBox.value() |
|
358
|
|
|
self._statusVariables['align_2d_axes1_step_DSpinBox'] = self._mw.align_2d_axes1_step_DSpinBox.value() |
|
359
|
|
|
self._statusVariables['align_2d_axes1_vel_DSpinBox'] = self._mw.align_2d_axes1_vel_DSpinBox.value() |
|
360
|
|
|
|
|
361
|
|
|
self._mw.close() |
|
362
|
|
|
|
|
363
|
|
|
def show(self): |
|
364
|
|
|
"""Make window visible and put it above all other windows. """ |
|
365
|
|
|
QtWidgets.QMainWindow.show(self._mw) |
|
366
|
|
|
self._mw.activateWindow() |
|
367
|
|
|
self._mw.raise_() |
|
368
|
|
|
|
|
369
|
|
|
|
|
370
|
|
|
def set_default_view_main_window(self): |
|
371
|
|
|
""" Establish the default dock Widget configuration. """ |
|
372
|
|
|
|
|
373
|
|
|
# connect all widgets to the main Window |
|
374
|
|
|
self._mw.curr_pos_DockWidget.setFloating(False) |
|
375
|
|
|
self._mw.move_rel_DockWidget.setFloating(False) |
|
376
|
|
|
self._mw.move_abs_DockWidget.setFloating(False) |
|
377
|
|
|
self._mw.alignment_DockWidget.setFloating(False) |
|
378
|
|
|
|
|
379
|
|
|
# QtCore.Qt.LeftDockWidgetArea 0x1 |
|
380
|
|
|
# QtCore.Qt.RightDockWidgetArea 0x2 |
|
381
|
|
|
# QtCore.Qt.TopDockWidgetArea 0x4 |
|
382
|
|
|
# QtCore.Qt.BottomDockWidgetArea 0x8 |
|
383
|
|
|
# QtCore.Qt.AllDockWidgetAreas DockWidgetArea_Mask |
|
384
|
|
|
# QtCore.Qt.NoDockWidgetArea 0 |
|
385
|
|
|
|
|
386
|
|
|
# align the widget |
|
387
|
|
|
self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(1), |
|
388
|
|
|
self._mw.curr_pos_DockWidget) |
|
389
|
|
|
self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(1), |
|
390
|
|
|
self._mw.move_rel_DockWidget) |
|
391
|
|
|
self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(1), |
|
392
|
|
|
self._mw.move_abs_DockWidget) |
|
393
|
|
|
|
|
394
|
|
|
self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(2), |
|
395
|
|
|
self._mw.alignment_DockWidget) |
|
396
|
|
|
|
|
397
|
|
|
def open_magnet_settings(self): |
|
398
|
|
|
""" This method opens the settings menu. """ |
|
399
|
|
|
self._ms.exec_() |
|
400
|
|
|
|
|
401
|
|
|
def update_magnet_settings(self): |
|
402
|
|
|
""" Apply the set configuration in the Settings Window. """ |
|
403
|
|
|
|
|
404
|
|
|
if self._ms.interactive_mode_CheckBox.isChecked(): |
|
405
|
|
|
self._interactive_mode = True |
|
406
|
|
|
else: |
|
407
|
|
|
self._interactive_mode = False |
|
408
|
|
|
|
|
409
|
|
|
if self._ms.interactive_mode_CheckBox.isChecked(): |
|
410
|
|
|
self._interactive_mode = True |
|
411
|
|
|
else: |
|
412
|
|
|
self._interactive_mode = False |
|
413
|
|
|
if self._ms.z_mode_checkBox.isChecked(): |
|
414
|
|
|
self._z_mode = True |
|
415
|
|
|
self._magnet_logic._magnet_device.mode = 'z_mode' |
|
416
|
|
|
else: |
|
417
|
|
|
self._z_mode = False |
|
418
|
|
|
self._magnet_logic._magnet_device.mode = 'normal_mode' |
|
419
|
|
|
|
|
420
|
|
|
if self._ms.normal_mode_checkBox.isChecked(): |
|
421
|
|
|
self._normal_mode = True |
|
422
|
|
|
self._magnet_logic._magnet_device.mode = 'normal_mode' |
|
423
|
|
|
else: |
|
424
|
|
|
self._normal_mode = False |
|
425
|
|
|
self._magnet_logic._magnet_device.mode = 'z_mode' |
|
426
|
|
|
|
|
427
|
|
|
def keep_former_magnet_settings(self): |
|
428
|
|
|
|
|
429
|
|
|
self._ms.interactive_mode_CheckBox.setChecked(self._interactive_mode) |
|
430
|
|
|
|
|
431
|
|
|
def _create_meas_type_RadioButtons(self): |
|
432
|
|
|
""" Create the measurement Buttons for the desired measurements: |
|
433
|
|
|
|
|
434
|
|
|
@return: |
|
435
|
|
|
""" |
|
436
|
|
|
|
|
437
|
|
|
self._mw.alignment_2d_ButtonGroup = QtWidgets.QButtonGroup(self._mw) |
|
438
|
|
|
|
|
439
|
|
|
self._mw.meas_type_fluorescence_RadioButton = QtWidgets.QRadioButton(parent=self._mw) |
|
440
|
|
|
self._mw.alignment_2d_ButtonGroup.addButton(self._mw.meas_type_fluorescence_RadioButton) |
|
441
|
|
|
self._mw.alignment_2d_ToolBar.addWidget(self._mw.meas_type_fluorescence_RadioButton) |
|
442
|
|
|
self._mw.meas_type_fluorescence_RadioButton.setText('Fluorescence') |
|
443
|
|
|
|
|
444
|
|
|
self._mw.meas_type_odmr_RadioButton = QtWidgets.QRadioButton(parent=self._mw) |
|
445
|
|
|
self._mw.alignment_2d_ButtonGroup.addButton(self._mw.meas_type_odmr_RadioButton) |
|
446
|
|
|
self._mw.alignment_2d_ToolBar.addWidget(self._mw.meas_type_odmr_RadioButton) |
|
447
|
|
|
self._mw.meas_type_odmr_RadioButton.setText('ODMR') |
|
448
|
|
|
|
|
449
|
|
|
self._mw.meas_type_nuclear_spin_RadioButton = QtWidgets.QRadioButton(parent=self._mw) |
|
450
|
|
|
self._mw.alignment_2d_ButtonGroup.addButton(self._mw.meas_type_nuclear_spin_RadioButton) |
|
451
|
|
|
self._mw.alignment_2d_ToolBar.addWidget(self._mw.meas_type_nuclear_spin_RadioButton) |
|
452
|
|
|
self._mw.meas_type_nuclear_spin_RadioButton.setText('Nuclear Spin') |
|
453
|
|
|
|
|
454
|
|
|
self._mw.meas_type_fluorescence_RadioButton.setChecked(True) |
|
455
|
|
|
|
|
456
|
|
|
|
|
457
|
|
|
def _create_axis_pos_disp(self): |
|
458
|
|
|
""" Create the axis position display. |
|
459
|
|
|
|
|
460
|
|
|
The generic variable name for a created QLable is: |
|
461
|
|
|
curr_pos_axis{0}_Label |
|
462
|
|
|
The generic variable name for a created ScienDSpinBox is: |
|
463
|
|
|
curr_pos_axis{0}_ScienDSpinBox |
|
464
|
|
|
where in {0} the name of the axis will be inserted. |
|
465
|
|
|
|
|
466
|
|
|
DO NOT CALL THESE VARIABLES DIRECTLY! USE THE DEDICATED METHOD INSTEAD! |
|
467
|
|
|
Use the method get_ref_curr_pos_ScienDSpinBox with the appropriated |
|
468
|
|
|
label, otherwise you will break the generality. |
|
469
|
|
|
""" |
|
470
|
|
|
|
|
471
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
472
|
|
|
|
|
473
|
|
|
# set the parameters in the curr_pos_DockWidget: |
|
474
|
|
|
for index, axis_label in enumerate(constraints): |
|
475
|
|
|
|
|
476
|
|
|
# Set the QLabel according to the grid |
|
477
|
|
|
# this is the name prototype for the label of current position display |
|
478
|
|
|
label_var_name = 'curr_pos_axis{0}_Label'.format(axis_label) |
|
479
|
|
|
setattr(self._mw, label_var_name, QtWidgets.QLabel(self._mw.curr_pos_DockWidgetContents)) |
|
480
|
|
|
label_var = getattr(self._mw, label_var_name) |
|
481
|
|
|
label_var.setObjectName(label_var_name) |
|
482
|
|
|
label_var.setText('{0}'.format(axis_label)) |
|
483
|
|
|
self._mw.curr_pos_GridLayout.addWidget(label_var, index, 0, 1, 1) |
|
484
|
|
|
|
|
485
|
|
|
# Set the ScienDSpinBox according to the grid |
|
486
|
|
|
# this is the name prototype for the current position display |
|
487
|
|
|
dspinbox_ref_name = 'curr_pos_axis{0}_ScienDSpinBox'.format(axis_label) |
|
488
|
|
|
|
|
489
|
|
|
setattr(self._mw, dspinbox_ref_name, ScienDSpinBox(parent=self._mw.curr_pos_DockWidgetContents)) |
|
490
|
|
|
dspinbox_ref = getattr(self._mw, dspinbox_ref_name) |
|
491
|
|
|
dspinbox_ref.setObjectName(dspinbox_ref_name) |
|
492
|
|
|
dspinbox_ref.setReadOnly(True) |
|
493
|
|
|
dspinbox_ref.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) |
|
494
|
|
|
dspinbox_ref.setMaximum(np.inf) |
|
495
|
|
|
dspinbox_ref.setMinimum(-np.inf) |
|
496
|
|
|
|
|
497
|
|
|
# in the ScienDSpinBox the decimals are actually the number of |
|
498
|
|
|
# significant digits, therefore set them here by default: |
|
499
|
|
|
dspinbox_ref.setDecimals(5) |
|
500
|
|
|
dspinbox_ref.setOpts(minStep=constraints[axis_label]['pos_step']) |
|
501
|
|
|
dspinbox_ref.setSingleStep(0.001) |
|
502
|
|
|
dspinbox_ref.setSuffix(constraints[axis_label]['unit']) |
|
503
|
|
|
|
|
504
|
|
|
self._mw.curr_pos_GridLayout.addWidget(dspinbox_ref, index, 1, 1, 1) |
|
505
|
|
|
|
|
506
|
|
|
extension = len(constraints) |
|
507
|
|
|
self._mw.curr_pos_GridLayout.addWidget(self._mw.curr_pos_get_pos_PushButton, 0, 2, extension, 1) |
|
508
|
|
|
self._mw.curr_pos_GridLayout.addWidget(self._mw.curr_pos_stop_PushButton, 0, 3, extension, 1) |
|
509
|
|
|
self._mw.curr_pos_get_pos_PushButton.clicked.connect(self.update_pos) |
|
510
|
|
|
self._mw.curr_pos_stop_PushButton.clicked.connect(self.stop_movement) |
|
511
|
|
|
|
|
512
|
|
|
def _create_move_rel_control(self): |
|
513
|
|
|
""" Create all the gui elements to control a relative movement. |
|
514
|
|
|
|
|
515
|
|
|
The generic variable name for a created QLable is: |
|
516
|
|
|
move_rel_axis_{0}_Label |
|
517
|
|
|
The generic variable name for a created ScienDSpinBox is: |
|
518
|
|
|
move_rel_axis_{0}_ScienDSpinBox |
|
519
|
|
|
The generic variable name for a created QPushButton in negative dir is: |
|
520
|
|
|
move_rel_axis_{0}_m_PushButton |
|
521
|
|
|
The generic variable name for a created QPushButton in positive dir is: |
|
522
|
|
|
move_rel_axis_{0}_p_PushButton |
|
523
|
|
|
|
|
524
|
|
|
DO NOT CALL THESE VARIABLES DIRECTLY! USE THE DEDICATED METHOD INSTEAD! |
|
525
|
|
|
Use the method get_ref_move_rel_ScienDSpinBox with the appropriated |
|
526
|
|
|
label, otherwise you will break the generality. |
|
527
|
|
|
""" |
|
528
|
|
|
|
|
529
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
530
|
|
|
|
|
531
|
|
|
# set the axis_labels in the curr_pos_DockWidget: |
|
532
|
|
|
for index, axis_label in enumerate(constraints): |
|
533
|
|
|
|
|
534
|
|
|
label_var_name = 'move_rel_axis_{0}_Label'.format(axis_label) |
|
535
|
|
|
setattr(self._mw, label_var_name, QtWidgets.QLabel(self._mw.move_rel_DockWidgetContents)) |
|
536
|
|
|
label_var = getattr(self._mw, label_var_name) # get the reference |
|
537
|
|
|
label_var.setObjectName(label_var_name) # set axis_label for the label |
|
538
|
|
|
label_var.setText('{0}'.format(axis_label)) |
|
539
|
|
|
# add the label to the grid: |
|
540
|
|
|
self._mw.move_rel_GridLayout.addWidget(label_var, index, 0, 1, 1) |
|
541
|
|
|
|
|
542
|
|
|
# Set the ScienDSpinBox according to the grid |
|
543
|
|
|
# this is the name prototype for the relative movement display |
|
544
|
|
|
dspinbox_ref_name = 'move_rel_axis_{0}_ScienDSpinBox'.format(axis_label) |
|
545
|
|
|
setattr(self._mw, dspinbox_ref_name, ScienDSpinBox(parent=self._mw.move_rel_DockWidgetContents)) |
|
546
|
|
|
dspinbox_ref = getattr(self._mw, dspinbox_ref_name) |
|
547
|
|
|
dspinbox_ref.setObjectName(dspinbox_ref_name) |
|
548
|
|
|
# dspinbox_ref.setButtonSymbols(QtGui.QAbstractSpinBox.NoButtons) |
|
549
|
|
|
|
|
550
|
|
|
dspinbox_ref.setMaximum(constraints[axis_label]['pos_max']) |
|
551
|
|
|
dspinbox_ref.setMinimum(constraints[axis_label]['pos_min']) |
|
552
|
|
|
|
|
553
|
|
|
# in the ScienDSpinBox the decimals are actually the number of |
|
554
|
|
|
# significant digits, therefore set them here by default: |
|
555
|
|
|
dspinbox_ref.setDecimals(5) |
|
556
|
|
|
dspinbox_ref.setOpts(minStep=constraints[axis_label]['pos_step']) |
|
557
|
|
|
dspinbox_ref.setSingleStep(0.001) |
|
558
|
|
|
dspinbox_ref.setSuffix(constraints[axis_label]['unit']) |
|
559
|
|
|
|
|
560
|
|
|
self._mw.move_rel_GridLayout.addWidget(dspinbox_ref, index, 1, 1, 1) |
|
561
|
|
|
|
|
562
|
|
|
|
|
563
|
|
|
# this is the name prototype for the relative movement minus button |
|
564
|
|
|
func_name = 'move_rel_axis_{0}_m'.format(axis_label) |
|
565
|
|
|
# create a method and assign it as attribute: |
|
566
|
|
|
setattr(self, func_name, self._function_builder_move_rel(func_name,axis_label,-1) ) |
|
567
|
|
|
move_rel_m_ref = getattr(self, func_name) # get the reference |
|
568
|
|
|
|
|
569
|
|
|
# the change of the PushButton is connected to the previous method. |
|
570
|
|
|
button_var_name = 'move_rel_axis_{0}_m_PushButton'.format(axis_label) |
|
571
|
|
|
setattr(self._mw, button_var_name, QtWidgets.QPushButton(self._mw.move_rel_DockWidgetContents)) |
|
572
|
|
|
button_var = getattr(self._mw, button_var_name) |
|
573
|
|
|
button_var.setObjectName(button_var_name) |
|
574
|
|
|
button_var.setText('-') |
|
575
|
|
|
button_var.clicked.connect(move_rel_m_ref, type=QtCore.Qt.QueuedConnection) |
|
576
|
|
|
self._mw.move_rel_GridLayout.addWidget(button_var, index, 2, 1, 1) |
|
577
|
|
|
|
|
578
|
|
|
# this is the name prototype for the relative movement plus button |
|
579
|
|
|
func_name = 'move_rel_axis_{0}_p'.format(axis_label) |
|
580
|
|
|
setattr(self, func_name, self._function_builder_move_rel(func_name,axis_label,1) ) |
|
581
|
|
|
move_rel_p_ref = getattr(self, func_name) |
|
582
|
|
|
|
|
583
|
|
|
# the change of the PushButton is connected to the previous method. |
|
584
|
|
|
button_var_name = 'move_rel_axis_{0}_p_PushButton'.format(axis_label) |
|
585
|
|
|
setattr(self._mw, button_var_name, QtWidgets.QPushButton(self._mw.move_rel_DockWidgetContents)) |
|
586
|
|
|
button_var = getattr(self._mw, button_var_name) |
|
587
|
|
|
button_var.setObjectName(button_var_name) |
|
588
|
|
|
button_var.setText('+') |
|
589
|
|
|
button_var.clicked.connect(move_rel_p_ref, type=QtCore.Qt.QueuedConnection) |
|
590
|
|
|
self._mw.move_rel_GridLayout.addWidget(button_var, index, 3, 1, 1) |
|
591
|
|
|
|
|
592
|
|
|
def _create_move_abs_control(self): |
|
593
|
|
|
""" Create all the GUI elements to control a relative movement. |
|
594
|
|
|
|
|
595
|
|
|
The generic variable name for a created QLable is: |
|
596
|
|
|
move_abs_axis_{0}_Label |
|
597
|
|
|
The generic variable name for a created QLable is: |
|
598
|
|
|
move_abs_axis_{0}_Slider |
|
599
|
|
|
The generic variable name for a created ScienDSpinBox is: |
|
600
|
|
|
move_abs_axis_{0}_ScienDSpinBox |
|
601
|
|
|
The generic variable name for a created QPushButton for move is: |
|
602
|
|
|
move_abs_PushButton |
|
603
|
|
|
|
|
604
|
|
|
These methods should not be called: |
|
605
|
|
|
The generic variable name for a update method for the ScienDSpinBox: |
|
606
|
|
|
_update_move_abs_{0}_dspinbox |
|
607
|
|
|
The generic variable name for a update method for the QSlider: |
|
608
|
|
|
_update_move_abs_{0}_slider |
|
609
|
|
|
|
|
610
|
|
|
DO NOT CALL THESE VARIABLES DIRECTLY! USE THE DEDICATED METHOD INSTEAD! |
|
611
|
|
|
Use the method get_ref_move_abs_ScienDSpinBox with the appropriated |
|
612
|
|
|
label, otherwise you will break the generality. |
|
613
|
|
|
""" |
|
614
|
|
|
|
|
615
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
616
|
|
|
|
|
617
|
|
|
for index, axis_label in enumerate(constraints): |
|
618
|
|
|
|
|
619
|
|
|
label_var_name = 'move_abs_axis_{0}_Label'.format(axis_label) |
|
620
|
|
|
setattr(self._mw, label_var_name, QtWidgets.QLabel(self._mw.move_abs_DockWidgetContents)) |
|
621
|
|
|
label_var = getattr(self._mw, label_var_name) # get the reference |
|
622
|
|
|
# set axis_label for the label: |
|
623
|
|
|
label_var.setObjectName(label_var_name) |
|
624
|
|
|
label_var.setText(axis_label) |
|
625
|
|
|
|
|
626
|
|
|
# make the steps of the splider as a multiple of 10 |
|
627
|
|
|
# smallest_step_slider = 10**int(np.log10(constraints[axis_label]['pos_step']) -1) |
|
628
|
|
|
smallest_step_slider = constraints[axis_label]['pos_step'] |
|
629
|
|
|
|
|
630
|
|
|
# add the label to the grid: |
|
631
|
|
|
self._mw.move_abs_GridLayout.addWidget(label_var, index, 0, 1, 1) |
|
632
|
|
|
|
|
633
|
|
|
# Set the ScienDSpinBox according to the grid |
|
634
|
|
|
# this is the name prototype for the relative movement display |
|
635
|
|
|
slider_obj_name = 'move_abs_axis_{0}_Slider'.format(axis_label) |
|
636
|
|
|
setattr(self._mw, slider_obj_name, QtWidgets.QSlider(self._mw.move_abs_DockWidgetContents)) |
|
637
|
|
|
slider_obj = getattr(self._mw, slider_obj_name) |
|
638
|
|
|
slider_obj.setObjectName(slider_obj_name) |
|
639
|
|
|
slider_obj.setOrientation(QtCore.Qt.Horizontal) |
|
640
|
|
|
# dspinbox_ref.setButtonSymbols(QtGui.QAbstractSpinBox.NoButtons) |
|
641
|
|
|
|
|
642
|
|
|
max_val = abs(constraints[axis_label]['pos_max'] - constraints[axis_label]['pos_min']) |
|
643
|
|
|
|
|
644
|
|
|
# set the step size of the slider to a fixed resolution, that |
|
645
|
|
|
# prevents really ugly rounding error behaviours in display. |
|
646
|
|
|
# Set precision to nanometer scale, which is actually never reached. |
|
647
|
|
|
max_steps = int(max_val/smallest_step_slider) |
|
648
|
|
|
|
|
649
|
|
|
|
|
650
|
|
|
slider_obj.setMaximum(max_steps) |
|
651
|
|
|
slider_obj.setMinimum(0) |
|
652
|
|
|
#TODO: set the decimals also from the constraints! |
|
653
|
|
|
# slider_obj.setDecimals(3) |
|
654
|
|
|
slider_obj.setSingleStep(1) |
|
655
|
|
|
# slider_obj.setEnabled(False) |
|
656
|
|
|
|
|
657
|
|
|
self._mw.move_abs_GridLayout.addWidget(slider_obj, index, 1, 1, 1) |
|
658
|
|
|
|
|
659
|
|
|
# Set the ScienDSpinBox according to the grid |
|
660
|
|
|
# this is the name prototype for the relative movement display |
|
661
|
|
|
dspinbox_ref_name = 'move_abs_axis_{0}_ScienDSpinBox'.format(axis_label) |
|
662
|
|
|
setattr(self._mw, dspinbox_ref_name, ScienDSpinBox(parent=self._mw.move_abs_DockWidgetContents)) |
|
663
|
|
|
dspinbox_ref = getattr(self._mw, dspinbox_ref_name) |
|
664
|
|
|
dspinbox_ref.setObjectName(dspinbox_ref_name) |
|
665
|
|
|
# dspinbox_ref.setButtonSymbols(QtGui.QAbstractSpinBox.NoButtons) |
|
666
|
|
|
|
|
667
|
|
|
dspinbox_ref.setMaximum(constraints[axis_label]['pos_max']) |
|
668
|
|
|
dspinbox_ref.setMinimum(constraints[axis_label]['pos_min']) |
|
669
|
|
|
|
|
670
|
|
|
# in the ScienDSpinBox the decimals are actually the number of |
|
671
|
|
|
# significant digits, therefore set them here by default: |
|
672
|
|
|
dspinbox_ref.setDecimals(5) |
|
673
|
|
|
dspinbox_ref.setOpts(minStep=constraints[axis_label]['pos_step']) |
|
674
|
|
|
dspinbox_ref.setSingleStep(0.001) |
|
675
|
|
|
dspinbox_ref.setSuffix(constraints[axis_label]['unit']) |
|
676
|
|
|
|
|
677
|
|
|
# set the horizontal size to 100 pixel: |
|
678
|
|
|
dspinbox_ref.setMaximumSize(QtCore.QSize(80, 16777215)) |
|
679
|
|
|
|
|
680
|
|
|
self._mw.move_abs_GridLayout.addWidget(dspinbox_ref, index, 2, 1, 1) |
|
681
|
|
|
|
|
682
|
|
|
# build a function to change the dspinbox value and connect a |
|
683
|
|
|
# slidermove event to it: |
|
684
|
|
|
func_name = '_update_move_abs_{0}_dspinbox'.format(axis_label) |
|
685
|
|
|
setattr(self, func_name, self._function_builder_update_viewbox(func_name, axis_label, dspinbox_ref)) |
|
686
|
|
|
update_func_dspinbox_ref = getattr(self, func_name) |
|
687
|
|
|
slider_obj.valueChanged.connect(update_func_dspinbox_ref) |
|
688
|
|
|
|
|
689
|
|
|
# build a function to change the slider value and connect a |
|
690
|
|
|
# spinbox value change event to it: |
|
691
|
|
|
func_name = '_update_move_abs_{0}_slider'.format(axis_label) |
|
692
|
|
|
setattr(self, func_name, self._function_builder_update_slider(func_name, axis_label, slider_obj)) |
|
693
|
|
|
update_func_slider_ref = getattr(self, func_name) |
|
694
|
|
|
# dspinbox_ref.valueChanged.connect(update_func_slider_ref) |
|
695
|
|
|
|
|
696
|
|
|
# the editingFinished idea has to be implemented properly at first: |
|
697
|
|
|
dspinbox_ref.editingFinished.connect(update_func_slider_ref) |
|
698
|
|
|
|
|
699
|
|
|
extension = len(constraints) |
|
700
|
|
|
self._mw.move_abs_GridLayout.addWidget(self._mw.move_abs_PushButton, 0, 3, extension, 1) |
|
701
|
|
|
self._mw.move_abs_PushButton.clicked.connect(self.move_abs) |
|
702
|
|
|
|
|
703
|
|
|
def _function_builder_move_rel(self, func_name, axis_label, direction): |
|
704
|
|
|
""" Create a function/method, which gots executed for pressing move_rel. |
|
705
|
|
|
|
|
706
|
|
|
@param str func_name: name how the function should be called. |
|
707
|
|
|
@param str axis_label: label of the axis you want to create a control |
|
708
|
|
|
function for. |
|
709
|
|
|
@param int direction: either 1 or -1 depending on the relative movement. |
|
710
|
|
|
@return: function with name func_name |
|
711
|
|
|
|
|
712
|
|
|
A routine to construct a method on the fly and attach it as attribute |
|
713
|
|
|
to the object, so that it can be used or so that other signals can be |
|
714
|
|
|
connected to it. That means the return value is already fixed for a |
|
715
|
|
|
function name. |
|
716
|
|
|
""" |
|
717
|
|
|
|
|
718
|
|
|
def func_dummy_name(): |
|
719
|
|
|
self.move_rel(axis_label, direction) |
|
720
|
|
|
|
|
721
|
|
|
func_dummy_name.__name__ = func_name |
|
722
|
|
|
return func_dummy_name |
|
723
|
|
|
|
|
724
|
|
|
# create the signals for the push buttons and connect them to the move |
|
725
|
|
|
# rel method in the Logic |
|
726
|
|
|
|
|
727
|
|
|
def _function_builder_update_viewbox(self, func_name, axis_label, |
|
728
|
|
|
ref_dspinbox): |
|
729
|
|
|
""" Create a function/method, which gots executed for pressing move_rel. |
|
730
|
|
|
|
|
731
|
|
|
@param str func_name: name how the function should be called. |
|
732
|
|
|
@param str axis_label: label of the axis you want to create a control |
|
733
|
|
|
function for. |
|
734
|
|
|
@param object ref_dspinbox: a reference to the dspinbox object, which |
|
735
|
|
|
will actually apply the changed within the |
|
736
|
|
|
created method. |
|
737
|
|
|
|
|
738
|
|
|
@return: function with name func_name |
|
739
|
|
|
|
|
740
|
|
|
A routine to construct a method on the fly and attach it as attribute |
|
741
|
|
|
to the object, so that it can be used or so that other signals can be |
|
742
|
|
|
connected to it. The connection of a signal to this method must appear |
|
743
|
|
|
outside of the present function. |
|
744
|
|
|
""" |
|
745
|
|
|
|
|
746
|
|
|
def func_dummy_name(slider_val): |
|
747
|
|
|
""" |
|
748
|
|
|
@param int slider_val: The current value of the slider, will be an |
|
749
|
|
|
integer value between |
|
750
|
|
|
[0,(pos_max - pos_min)/pos_step] |
|
751
|
|
|
of the corresponding axis label. |
|
752
|
|
|
Now convert this value back to a viewbox |
|
753
|
|
|
value like: |
|
754
|
|
|
pos_min + slider_step*pos_step |
|
755
|
|
|
""" |
|
756
|
|
|
|
|
757
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
758
|
|
|
# set the resolution of the slider to nanometer precision, that is |
|
759
|
|
|
# better for the display behaviour. In the end, that will just make |
|
760
|
|
|
# everything smoother but not actually affect the displayed number: |
|
761
|
|
|
|
|
762
|
|
|
# max_step_slider = 10**int(np.log10(constraints[axis_label]['pos_step']) -1) |
|
763
|
|
|
max_step_slider = constraints[axis_label]['pos_step'] |
|
764
|
|
|
|
|
765
|
|
|
actual_pos = (constraints[axis_label]['pos_min'] + slider_val * max_step_slider) |
|
766
|
|
|
ref_dspinbox.setValue(actual_pos) |
|
767
|
|
|
|
|
768
|
|
|
func_dummy_name.__name__ = func_name |
|
769
|
|
|
return func_dummy_name |
|
770
|
|
|
|
|
771
|
|
|
def _function_builder_update_slider(self, func_name, axis_label, ref_slider): |
|
772
|
|
|
""" Create a function/method, which gots executed for pressing move_rel. |
|
773
|
|
|
|
|
774
|
|
|
Create a function/method, which gots executed for pressing move_rel. |
|
775
|
|
|
|
|
776
|
|
|
@param str func_name: name how the function should be called. |
|
777
|
|
|
@param str axis_label: label of the axis you want to create a control |
|
778
|
|
|
function for. |
|
779
|
|
|
@param object ref_slider: a reference to the slider object, which |
|
780
|
|
|
will actually apply the changed within the |
|
781
|
|
|
created method. |
|
782
|
|
|
|
|
783
|
|
|
@return: function with name func_name |
|
784
|
|
|
|
|
785
|
|
|
A routine to construct a method on the fly and attach it as attribute |
|
786
|
|
|
to the object, so that it can be used or so that other signals can be |
|
787
|
|
|
connected to it. The connection of a signal to this method must appear |
|
788
|
|
|
outside of the present function. |
|
789
|
|
|
""" |
|
790
|
|
|
|
|
791
|
|
|
def func_dummy_name(): |
|
792
|
|
|
""" |
|
793
|
|
|
@param int slider_step: The current value of the slider, will be an |
|
794
|
|
|
integer value between |
|
795
|
|
|
[0,(pos_max - pos_min)/pos_step] |
|
796
|
|
|
of the corresponding axis label. |
|
797
|
|
|
Now convert this value back to a viewbox |
|
798
|
|
|
value like: |
|
799
|
|
|
pos_min + slider_step*pos_step |
|
800
|
|
|
""" |
|
801
|
|
|
|
|
802
|
|
|
dspinbox_obj = self.get_ref_move_abs_ScienDSpinBox(axis_label) |
|
803
|
|
|
viewbox_val = dspinbox_obj.value() |
|
804
|
|
|
|
|
805
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
806
|
|
|
# set the resolution of the slider to nanometer precision, that is |
|
807
|
|
|
# better for the display behaviour. In the end, that will just make |
|
808
|
|
|
# everything smoother but not actually affect the displayed number: |
|
809
|
|
|
|
|
810
|
|
|
# max_step_slider = 10**int(np.log10(constraints[axis_label]['pos_step']) -1) |
|
811
|
|
|
max_step_slider = constraints[axis_label]['pos_step'] |
|
812
|
|
|
|
|
813
|
|
|
slider_val = abs(viewbox_val - constraints[axis_label]['pos_min'])/max_step_slider |
|
814
|
|
|
ref_slider.setValue(slider_val) |
|
815
|
|
|
|
|
816
|
|
|
func_dummy_name.__name__ = func_name |
|
817
|
|
|
return func_dummy_name |
|
818
|
|
|
|
|
819
|
|
|
# create the signals for the push buttons and connect them to the move |
|
820
|
|
|
# rel method in the Logic |
|
821
|
|
|
|
|
822
|
|
|
def move_rel(self, axis_label, direction): |
|
823
|
|
|
""" Move relative by the axis with given label an direction. |
|
824
|
|
|
|
|
825
|
|
|
@param str axis_label: tells which axis should move. |
|
826
|
|
|
@param int direction: either 1 or -1 depending on the relative movement. |
|
827
|
|
|
|
|
828
|
|
|
That method get called from methods, which are created on the fly at |
|
829
|
|
|
runtime during the activation of that module (basically from the |
|
830
|
|
|
methods with the generic name move_rel_axis_{0}_p or |
|
831
|
|
|
move_rel_axis_{0}_m with the appropriate label). |
|
832
|
|
|
""" |
|
833
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
834
|
|
|
dspinbox = self.get_ref_move_rel_ScienDSpinBox(axis_label) |
|
835
|
|
|
|
|
836
|
|
|
movement = dspinbox.value() * direction |
|
837
|
|
|
|
|
838
|
|
|
self._magnet_logic.move_rel({axis_label: movement}) |
|
839
|
|
|
# if self._interactive_mode: |
|
840
|
|
|
# self.update_pos() |
|
841
|
|
|
|
|
842
|
|
|
def move_abs(self, param_dict=None): |
|
843
|
|
|
""" Perform an absolute movement. |
|
844
|
|
|
|
|
845
|
|
|
@param param_dict: with {<axis_label>:<position>}, can of course |
|
846
|
|
|
contain many entries of the same kind. |
|
847
|
|
|
|
|
848
|
|
|
Basically all the axis can be controlled at the same time. |
|
849
|
|
|
""" |
|
850
|
|
|
|
|
851
|
|
|
if (param_dict is not None) and (type(param_dict) is not bool): |
|
852
|
|
|
self._magnet_logic.move_abs(param_dict) |
|
853
|
|
|
else: |
|
854
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
855
|
|
|
|
|
856
|
|
|
# create the move_abs dict |
|
857
|
|
|
move_abs = {} |
|
858
|
|
|
for label in constraints: |
|
859
|
|
|
move_abs[label] = self.get_ref_move_abs_ScienDSpinBox(label).value() |
|
860
|
|
|
|
|
861
|
|
|
self._magnet_logic.move_abs(move_abs) |
|
862
|
|
|
|
|
863
|
|
|
# if self._interactive_mode: |
|
864
|
|
|
# self.update_pos() |
|
865
|
|
|
|
|
866
|
|
|
|
|
867
|
|
|
def get_ref_curr_pos_ScienDSpinBox(self, label): |
|
868
|
|
|
""" Get the reference to the double spin box for the passed label. """ |
|
869
|
|
|
|
|
870
|
|
|
dspinbox_name = 'curr_pos_axis{0}_ScienDSpinBox'.format(label) |
|
871
|
|
|
dspinbox_ref = getattr(self._mw, dspinbox_name) |
|
872
|
|
|
return dspinbox_ref |
|
873
|
|
|
|
|
874
|
|
|
def get_ref_move_rel_ScienDSpinBox(self, label): |
|
875
|
|
|
""" Get the reference to the double spin box for the passed label. """ |
|
876
|
|
|
|
|
877
|
|
|
dspinbox_name = 'move_rel_axis_{0}_ScienDSpinBox'.format(label) |
|
878
|
|
|
dspinbox_ref = getattr(self._mw, dspinbox_name) |
|
879
|
|
|
return dspinbox_ref |
|
880
|
|
|
|
|
881
|
|
|
def get_ref_move_abs_ScienDSpinBox(self, label): |
|
882
|
|
|
""" Get the reference to the double spin box for the passed label. """ |
|
883
|
|
|
|
|
884
|
|
|
dspinbox_name = 'move_abs_axis_{0}_ScienDSpinBox'.format(label) |
|
885
|
|
|
dspinbox_ref = getattr(self._mw, dspinbox_name) |
|
886
|
|
|
return dspinbox_ref |
|
887
|
|
|
|
|
888
|
|
|
def get_ref_move_abs_Slider(self, label): |
|
889
|
|
|
""" Get the reference to the slider for the passed label. """ |
|
890
|
|
|
|
|
891
|
|
|
slider_name = 'move_abs_axis_{0}_Slider'.format(label) |
|
892
|
|
|
slider_ref = getattr(self._mw, slider_name) |
|
893
|
|
|
return slider_ref |
|
894
|
|
|
|
|
895
|
|
|
def optimize_pos_changed(self): |
|
896
|
|
|
""" Set whether postition should be optimized at each point. """ |
|
897
|
|
|
|
|
898
|
|
|
state = self._mw.align_2d_fluorescence_optimize_CheckBox.isChecked() |
|
899
|
|
|
self._magnet_logic.set_optimize_pos(state) |
|
900
|
|
|
|
|
901
|
|
|
def stop_movement(self): |
|
902
|
|
|
""" Invokes an immediate stop of the hardware. |
|
903
|
|
|
|
|
904
|
|
|
MAKE SURE THAT THE HARDWARE CAN BE CALLED DURING AN ACTION! |
|
905
|
|
|
If the parameter _interactive_mode is set to False no stop can be done |
|
906
|
|
|
since the device would anyway not respond to a method call. |
|
907
|
|
|
""" |
|
908
|
|
|
|
|
909
|
|
|
if self._interactive_mode: |
|
910
|
|
|
self._magnet_logic.stop_movement() |
|
911
|
|
|
else: |
|
912
|
|
|
self.log.warning('Movement cannot be stopped during a movement ' |
|
913
|
|
|
'anyway! Set the interactive mode to True in the Magnet ' |
|
914
|
|
|
'Settings! Otherwise this method is useless.') |
|
915
|
|
|
|
|
916
|
|
|
def update_pos(self, param_list=None): |
|
917
|
|
|
""" Update the current position. |
|
918
|
|
|
|
|
919
|
|
|
@param list param_list: optional, if specific positions needed to be |
|
920
|
|
|
updated. |
|
921
|
|
|
|
|
922
|
|
|
If no value is passed, the current position is retrieved from the |
|
923
|
|
|
logic and the display is changed. |
|
924
|
|
|
""" |
|
925
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
926
|
|
|
curr_pos = self._magnet_logic.get_pos() |
|
927
|
|
|
|
|
928
|
|
|
if (param_list is not None) and (type(param_list) is not bool): |
|
929
|
|
|
param_list = list(param_list) |
|
930
|
|
|
# param_list =list(param_list) # convert for safety to a list |
|
931
|
|
|
curr_pos = self._magnet_logic.get_pos(param_list) |
|
932
|
|
|
|
|
933
|
|
|
for axis_label in curr_pos: |
|
934
|
|
|
# update the values of the current position viewboxes: |
|
935
|
|
|
dspinbox_pos_ref = self.get_ref_curr_pos_ScienDSpinBox(axis_label) |
|
936
|
|
|
|
|
937
|
|
|
dspinbox_pos_ref.setValue(curr_pos[axis_label]) |
|
938
|
|
|
|
|
939
|
|
|
# update the values also of the absolute movement display: |
|
940
|
|
|
dspinbox_move_abs_ref = self.get_ref_move_abs_ScienDSpinBox(axis_label) |
|
941
|
|
|
dspinbox_move_abs_ref.setValue(curr_pos[axis_label]) |
|
942
|
|
|
|
|
943
|
|
|
|
|
944
|
|
|
def run_stop_2d_alignment(self, is_checked): |
|
945
|
|
|
""" Manage what happens if 2d magnet scan is started/stopped |
|
946
|
|
|
|
|
947
|
|
|
@param bool is_checked: state if the current scan, True = started, |
|
948
|
|
|
False = stopped |
|
949
|
|
|
""" |
|
950
|
|
|
|
|
951
|
|
|
if is_checked: |
|
952
|
|
|
self.start_2d_alignment_clicked() |
|
953
|
|
|
|
|
954
|
|
|
else: |
|
955
|
|
|
self.abort_2d_alignment_clicked() |
|
956
|
|
|
|
|
957
|
|
|
def _change_display_to_stop_2d_alignment(self): |
|
958
|
|
|
""" Changes every display component back to the stopped state. """ |
|
959
|
|
|
|
|
960
|
|
|
self._mw.run_stop_2d_alignment_Action.blockSignals(True) |
|
961
|
|
|
self._mw.run_stop_2d_alignment_Action.setChecked(False) |
|
962
|
|
|
|
|
963
|
|
|
self._mw.continue_2d_alignment_Action.blockSignals(True) |
|
964
|
|
|
self._mw.continue_2d_alignment_Action.setChecked(False) |
|
965
|
|
|
|
|
966
|
|
|
self._mw.run_stop_2d_alignment_Action.blockSignals(False) |
|
967
|
|
|
self._mw.continue_2d_alignment_Action.blockSignals(False) |
|
968
|
|
|
|
|
969
|
|
|
def start_2d_alignment_clicked(self): |
|
970
|
|
|
""" Start the 2d alignment. """ |
|
971
|
|
|
|
|
972
|
|
|
if self.measurement_type == '2d_fluorescence': |
|
973
|
|
|
self._magnet_logic.curr_alignment_method = self.measurement_type |
|
974
|
|
|
|
|
975
|
|
|
self._magnet_logic.fluorescence_integration_time = self._mw.align_2d_fluorescence_integrationtime_DSpinBox.value() |
|
976
|
|
|
|
|
977
|
|
|
self._mw.alignment_2d_cb_GraphicsView.setLabel('right', 'Fluorescence', units='c/s') |
|
978
|
|
|
|
|
979
|
|
|
elif self.measurement_type == '2d_odmr': |
|
980
|
|
|
self._magnet_logic.curr_alignment_method = self.measurement_type |
|
981
|
|
|
|
|
982
|
|
|
self._magnet_logic.odmr_2d_low_center_freq = self._mw.align_2d_odmr_low_center_freq_DSpinBox.value() |
|
983
|
|
|
self._magnet_logic.odmr_2d_low_range_freq = self._mw.align_2d_odmr_low_range_freq_DSpinBox.value() |
|
984
|
|
|
self._magnet_logic.odmr_2d_low_step_freq = self._mw.align_2d_odmr_low_step_freq_DSpinBox.value() |
|
985
|
|
|
self._magnet_logic.odmr_2d_low_power = self._mw.align_2d_odmr_low_power_DSpinBox.value() |
|
986
|
|
|
self._magnet_logic.odmr_2d_low_runtime = self._mw.align_2d_odmr_low_runtime_DSpinBox.value() |
|
987
|
|
|
self._magnet_logic.odmr_2d_low_fitfunction = self._mw.align_2d_odmr_low_fit_func_ComboBox.currentText() |
|
988
|
|
|
|
|
989
|
|
|
self._magnet_logic.odmr_2d_high_center_freq = self._mw.align_2d_odmr_high_center_freq_DSpinBox.value() |
|
990
|
|
|
self._magnet_logic.odmr_2d_high_range_freq = self._mw.align_2d_odmr_high_range_freq_DSpinBox.value() |
|
991
|
|
|
self._magnet_logic.odmr_2d_high_step_freq = self._mw.align_2d_odmr_high_step_freq_DSpinBox.value() |
|
992
|
|
|
self._magnet_logic.odmr_2d_high_power = self._mw.align_2d_odmr_high_power_DSpinBox.value() |
|
993
|
|
|
self._magnet_logic.odmr_2d_high_runtime = self._mw.align_2d_odmr_high_runtime_DSpinBox.value() |
|
994
|
|
|
self._magnet_logic.odmr_2d_high_fitfunction = self._mw.align_2d_odmr_high_fit_func_ComboBox.currentText() |
|
995
|
|
|
|
|
996
|
|
|
self._magnet_logic.odmr_2d_peak_axis0_move_ratio = self._mw.align_2d_axes0_shift_DSpinBox.value()*1e12 |
|
997
|
|
|
self._magnet_logic.odmr_2d_peak_axis1_move_ratio = self._mw.align_2d_axes1_shift_DSpinBox.value()*1e12 |
|
998
|
|
|
|
|
999
|
|
|
self._magnet_logic.odmr_2d_single_trans = self._mw.odmr_2d_single_trans_CheckBox.isChecked() |
|
1000
|
|
|
|
|
1001
|
|
|
if self._mw.odmr_2d_single_trans_CheckBox.isChecked(): |
|
1002
|
|
|
self._mw.alignment_2d_cb_GraphicsView.setLabel('right', 'ODMR transition contrast', units='%') |
|
1003
|
|
|
else: |
|
1004
|
|
|
self._mw.alignment_2d_cb_GraphicsView.setLabel('right', 'Half ODMR splitting', units='Hz') |
|
1005
|
|
|
|
|
1006
|
|
|
elif self.measurement_type == '2d_nuclear': |
|
1007
|
|
|
self._magnet_logic.curr_alignment_method = self.measurement_type |
|
1008
|
|
|
|
|
1009
|
|
|
# ODMR stuff: |
|
1010
|
|
|
self._magnet_logic.odmr_2d_low_center_freq = self._mw.align_2d_odmr_low_center_freq_DSpinBox.value()*1e6 |
|
1011
|
|
|
self._magnet_logic.odmr_2d_low_step_freq = self._mw.align_2d_odmr_low_step_freq_DSpinBox.value()*1e6 |
|
1012
|
|
|
self._magnet_logic.odmr_2d_low_range_freq = self._mw.align_2d_odmr_low_range_freq_DSpinBox.value()*1e6 |
|
1013
|
|
|
self._magnet_logic.odmr_2d_low_power = self._mw.align_2d_odmr_low_power_DSpinBox.value() |
|
1014
|
|
|
self._magnet_logic.odmr_2d_low_runtime = self._mw.align_2d_odmr_low_runtime_DSpinBox.value() |
|
1015
|
|
|
self._magnet_logic.odmr_2d_low_fitfunction = self._mw.align_2d_odmr_low_fit_func_ComboBox.currentText() |
|
1016
|
|
|
|
|
1017
|
|
|
self._magnet_logic.odmr_2d_peak_axis0_move_ratio = self._mw.align_2d_axes0_shift_DSpinBox.value()*1e12 |
|
1018
|
|
|
self._magnet_logic.odmr_2d_peak_axis1_move_ratio = self._mw.align_2d_axes1_shift_DSpinBox.value()*1e12 |
|
1019
|
|
|
|
|
1020
|
|
|
self._magnet_logic.odmr_2d_single_trans = self._mw.odmr_2d_single_trans_CheckBox.isChecked() |
|
1021
|
|
|
|
|
1022
|
|
|
# nuclear ops: |
|
1023
|
|
|
self._magnet_logic.nuclear_2d_rabi_periode = self._mw.align_2d_nuclear_rabi_periode_DSpinBox.value()*1e-9 |
|
1024
|
|
|
self._magnet_logic.nuclear_2d_mw_freq = self._mw.align_2d_nuclear_mw_freq_DSpinBox.value()*1e6 |
|
1025
|
|
|
self._magnet_logic.nuclear_2d_mw_channel = self._mw.align_2d_nuclear_mw_channel_SpinBox.value() |
|
1026
|
|
|
self._magnet_logic.nuclear_2d_mw_power = self._mw.align_2d_nuclear_mw_power_DSpinBox.value() |
|
1027
|
|
|
self._magnet_logic.nuclear_2d_laser_time = self._mw.align_2d_nuclear_laser_time_DSpinBox.value() |
|
1028
|
|
|
self._magnet_logic.nuclear_2d_laser_channel = self._mw.align_2d_nuclear_laser_channel_SpinBox.value() |
|
1029
|
|
|
self._magnet_logic.nuclear_2d_detect_channel = self._mw.align_2d_nuclear_detect_channel_SpinBox.value() |
|
1030
|
|
|
self._magnet_logic.nuclear_2d_idle_time = self._mw.align_2d_nuclear_idle_time_DSpinBox.value() |
|
1031
|
|
|
self._magnet_logic.nuclear_2d_reps_within_ssr = self._mw.align_2d_nuclear_reps_within_ssr_SpinBox.value() |
|
1032
|
|
|
self._magnet_logic.nuclear_2d_num_ssr = self._mw.align_2d_nuclear_num_of_ssr_SpinBox.value() |
|
1033
|
|
|
|
|
1034
|
|
|
self._mw.alignment_2d_cb_GraphicsView.setLabel('right', 'Single shot readout fidelity', units='%') |
|
1035
|
|
|
|
|
1036
|
|
|
|
|
1037
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
1038
|
|
|
|
|
1039
|
|
|
axis0_name = self._mw.align_2d_axes0_name_ComboBox.currentText() |
|
1040
|
|
|
axis0_range = self._mw.align_2d_axes0_range_DSpinBox.value() |
|
1041
|
|
|
axis0_step = self._mw.align_2d_axes0_step_DSpinBox.value() |
|
1042
|
|
|
|
|
1043
|
|
|
axis1_name = self._mw.align_2d_axes1_name_ComboBox.currentText() |
|
1044
|
|
|
axis1_range = self._mw.align_2d_axes1_range_DSpinBox.value() |
|
1045
|
|
|
axis1_step = self._mw.align_2d_axes1_step_DSpinBox.value() |
|
1046
|
|
|
|
|
1047
|
|
|
if axis0_name == axis1_name: |
|
1048
|
|
|
self.log.error('Fluorescence Alignment cannot be started since the ' |
|
1049
|
|
|
'same axis with name "{0}" was chosen for axis0 and ' |
|
1050
|
|
|
'axis1!\n' |
|
1051
|
|
|
'Alignment will not be started. Change the ' |
|
1052
|
|
|
'settings!'.format(axis0_name)) |
|
1053
|
|
|
return |
|
1054
|
|
|
|
|
1055
|
|
|
if self._mw.align_2d_axis0_set_vel_CheckBox.isChecked(): |
|
1056
|
|
|
axis0_vel = self._mw.align_2d_axes0_vel_DSpinBox.value() |
|
1057
|
|
|
else: |
|
1058
|
|
|
axis0_vel = None |
|
1059
|
|
View Code Duplication |
|
|
|
|
|
|
|
1060
|
|
|
if self._mw.align_2d_axis1_set_vel_CheckBox.isChecked(): |
|
1061
|
|
|
axis1_vel = self._mw.align_2d_axes1_vel_DSpinBox.value() |
|
1062
|
|
|
else: |
|
1063
|
|
|
axis1_vel = None |
|
1064
|
|
|
|
|
1065
|
|
|
self._magnet_logic.start_2d_alignment(axis0_name=axis0_name, axis0_range=axis0_range, |
|
1066
|
|
|
axis0_step=axis0_step, axis1_name=axis1_name, |
|
1067
|
|
|
axis1_range=axis1_range,axis1_step=axis1_step, |
|
1068
|
|
|
axis0_vel=axis0_vel, axis1_vel=axis1_vel, |
|
1069
|
|
|
continue_meas=self._continue_2d_fluorescence_alignment) |
|
1070
|
|
|
|
|
1071
|
|
|
self._continue_2d_fluorescence_alignment = False |
|
1072
|
|
|
|
|
1073
|
|
|
def continue_stop_2d_alignment(self, is_checked): |
|
1074
|
|
|
""" Manage what happens if 2d magnet scan is continued/stopped |
|
1075
|
|
|
|
|
1076
|
|
|
@param bool is_checked: state if the current scan, True = continue, |
|
1077
|
|
|
False = stopped |
|
1078
|
|
|
""" |
|
1079
|
|
|
|
|
1080
|
|
|
if is_checked: |
|
1081
|
|
|
self.continue_2d_alignment_clicked() |
|
1082
|
|
|
else: |
|
1083
|
|
|
self.abort_2d_alignment_clicked() |
|
1084
|
|
|
|
|
1085
|
|
|
|
|
1086
|
|
|
def continue_2d_alignment_clicked(self): |
|
1087
|
|
|
|
|
1088
|
|
View Code Duplication |
self._continue_2d_fluorescence_alignment = True |
|
|
|
|
|
|
1089
|
|
|
self.start_2d_alignment_clicked() |
|
1090
|
|
|
|
|
1091
|
|
|
|
|
1092
|
|
|
def abort_2d_alignment_clicked(self): |
|
1093
|
|
|
""" Stops the current Fluorescence alignment. """ |
|
1094
|
|
|
|
|
1095
|
|
|
self._change_display_to_stop_2d_alignment() |
|
1096
|
|
|
self._magnet_logic.stop_alignment() |
|
1097
|
|
|
|
|
1098
|
|
|
def _update_limits_axis0(self): |
|
1099
|
|
|
""" Whenever a new axis name was chosen in axis0 config, the limits of the |
|
1100
|
|
|
viewboxes will be adjusted. |
|
1101
|
|
|
""" |
|
1102
|
|
|
|
|
1103
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
1104
|
|
|
axis0_name = self._mw.align_2d_axes0_name_ComboBox.currentText() |
|
1105
|
|
|
|
|
1106
|
|
|
# set the range constraints: |
|
1107
|
|
|
self._mw.align_2d_axes0_range_DSpinBox.setMinimum(0) |
|
1108
|
|
|
self._mw.align_2d_axes0_range_DSpinBox.setMaximum(constraints[axis0_name]['pos_max']) |
|
1109
|
|
|
self._mw.align_2d_axes0_range_DSpinBox.setSingleStep(constraints[axis0_name]['pos_step']) |
|
1110
|
|
|
# self._mw.align_2d_axes0_range_DSpinBox.setDecimals(5) |
|
1111
|
|
|
self._mw.align_2d_axes0_range_DSpinBox.setSuffix(constraints[axis0_name]['unit']) |
|
1112
|
|
|
|
|
1113
|
|
|
# set the step constraints: |
|
1114
|
|
|
self._mw.align_2d_axes0_step_DSpinBox.setMinimum(0) |
|
1115
|
|
|
self._mw.align_2d_axes0_step_DSpinBox.setMaximum(constraints[axis0_name]['pos_max']) |
|
1116
|
|
|
self._mw.align_2d_axes0_step_DSpinBox.setSingleStep(constraints[axis0_name]['pos_step']) |
|
1117
|
|
|
# self._mw.align_2d_axes0_step_DSpinBox.setDecimals(5) |
|
1118
|
|
|
self._mw.align_2d_axes0_step_DSpinBox.setSuffix(constraints[axis0_name]['unit']) |
|
1119
|
|
|
|
|
1120
|
|
|
# set the velocity constraints: |
|
1121
|
|
|
self._mw.align_2d_axes0_vel_DSpinBox.setMinimum(constraints[axis0_name]['vel_min']) |
|
1122
|
|
|
self._mw.align_2d_axes0_vel_DSpinBox.setMaximum(constraints[axis0_name]['vel_max']) |
|
1123
|
|
|
self._mw.align_2d_axes0_vel_DSpinBox.setSingleStep(constraints[axis0_name]['vel_step']) |
|
1124
|
|
|
# self._mw.align_2d_axes0_vel_DSpinBox.setDecimals(5) |
|
1125
|
|
|
self._mw.align_2d_axes0_vel_DSpinBox.setSuffix(constraints[axis0_name]['unit']+'/s') |
|
1126
|
|
|
|
|
1127
|
|
|
def _update_limits_axis1(self): |
|
1128
|
|
|
""" Whenever a new axis name was chosen in axis0 config, the limits of the |
|
1129
|
|
|
viewboxes will be adjusted. |
|
1130
|
|
|
""" |
|
1131
|
|
|
|
|
1132
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
1133
|
|
|
axis1_name = self._mw.align_2d_axes1_name_ComboBox.currentText() |
|
1134
|
|
|
|
|
1135
|
|
|
self._mw.align_2d_axes1_range_DSpinBox.setMinimum(0) |
|
1136
|
|
|
self._mw.align_2d_axes1_range_DSpinBox.setMaximum(constraints[axis1_name]['pos_max']) |
|
1137
|
|
|
self._mw.align_2d_axes1_range_DSpinBox.setSingleStep(constraints[axis1_name]['pos_step']) |
|
1138
|
|
|
# self._mw.align_2d_axes1_range_DSpinBox.setDecimals(5) |
|
1139
|
|
|
self._mw.align_2d_axes1_range_DSpinBox.setSuffix(constraints[axis1_name]['unit']) |
|
1140
|
|
|
|
|
1141
|
|
|
self._mw.align_2d_axes1_step_DSpinBox.setMinimum(0) |
|
1142
|
|
|
self._mw.align_2d_axes1_step_DSpinBox.setMaximum(constraints[axis1_name]['pos_max']) |
|
1143
|
|
|
self._mw.align_2d_axes1_step_DSpinBox.setSingleStep(constraints[axis1_name]['pos_step']) |
|
1144
|
|
|
# self._mw.align_2d_axes1_step_DSpinBox.setDecimals(5) |
|
1145
|
|
|
self._mw.align_2d_axes1_step_DSpinBox.setSuffix(constraints[axis1_name]['unit']) |
|
1146
|
|
|
|
|
1147
|
|
|
self._mw.align_2d_axes1_vel_DSpinBox.setMinimum(constraints[axis1_name]['vel_min']) |
|
1148
|
|
|
self._mw.align_2d_axes1_vel_DSpinBox.setMaximum(constraints[axis1_name]['vel_max']) |
|
1149
|
|
|
self._mw.align_2d_axes1_vel_DSpinBox.setSingleStep(constraints[axis1_name]['vel_step']) |
|
1150
|
|
|
# self._mw.align_2d_axes1_vel_DSpinBox.setDecimals(5) |
|
1151
|
|
|
self._mw.align_2d_axes1_vel_DSpinBox.setSuffix(constraints[axis1_name]['unit']+'/s') |
|
1152
|
|
|
|
|
1153
|
|
|
def _set_vel_display_axis0(self): |
|
1154
|
|
|
""" Set the visibility of the velocity display for axis 0. """ |
|
1155
|
|
|
|
|
1156
|
|
|
if self._mw.align_2d_axis0_set_vel_CheckBox.isChecked(): |
|
1157
|
|
|
self._mw.align_2d_axes0_vel_DSpinBox.setVisible(True) |
|
1158
|
|
|
else: |
|
1159
|
|
View Code Duplication |
self._mw.align_2d_axes0_vel_DSpinBox.setVisible(False) |
|
|
|
|
|
|
1160
|
|
|
|
|
1161
|
|
|
def _set_vel_display_axis1(self): |
|
1162
|
|
|
""" Set the visibility of the velocity display for axis 1. """ |
|
1163
|
|
|
|
|
1164
|
|
|
if self._mw.align_2d_axis1_set_vel_CheckBox.isChecked(): |
|
1165
|
|
|
self._mw.align_2d_axes1_vel_DSpinBox.setVisible(True) |
|
1166
|
|
|
else: |
|
1167
|
|
|
self._mw.align_2d_axes1_vel_DSpinBox.setVisible(False) |
|
1168
|
|
|
|
|
1169
|
|
|
def _update_2d_graph_axis(self): |
|
1170
|
|
|
|
|
1171
|
|
|
constraints = self._magnet_logic.get_hardware_constraints() |
|
1172
|
|
|
|
|
1173
|
|
|
axis0_name = self._mw.align_2d_axes0_name_ComboBox.currentText() |
|
1174
|
|
|
axis0_unit = constraints[axis0_name]['unit'] |
|
1175
|
|
|
axis1_name = self._mw.align_2d_axes1_name_ComboBox.currentText() |
|
1176
|
|
|
axis1_unit = constraints[axis1_name]['unit'] |
|
1177
|
|
|
|
|
1178
|
|
|
axis0_array, axis1_array = self._magnet_logic.get_2d_axis_arrays() |
|
1179
|
|
|
|
|
1180
|
|
|
self._2d_alignment_ImageItem.setRect(QtCore.QRectF(axis0_array[0], |
|
1181
|
|
|
axis1_array[0], |
|
1182
|
|
|
axis0_array[-1]-axis0_array[0], |
|
1183
|
|
|
axis1_array[-1]-axis1_array[0],)) |
|
1184
|
|
|
|
|
1185
|
|
|
self._mw.alignment_2d_GraphicsView.setLabel('bottom', 'Absolute Position, Axis0: ' + axis0_name, units=axis0_unit) |
|
1186
|
|
|
self._mw.alignment_2d_GraphicsView.setLabel('left', 'Absolute Position, Axis1: '+ axis1_name, units=axis1_unit) |
|
1187
|
|
|
|
|
1188
|
|
View Code Duplication |
def _update_2d_graph_cb(self): |
|
|
|
|
|
|
1189
|
|
|
""" Update the colorbar to a new scaling. |
|
1190
|
|
|
|
|
1191
|
|
|
That function alters the color scaling of the colorbar next to the main |
|
1192
|
|
|
picture. |
|
1193
|
|
|
""" |
|
1194
|
|
|
|
|
1195
|
|
|
# If "Centiles" is checked, adjust colour scaling automatically to |
|
1196
|
|
|
# centiles. Otherwise, take user-defined values. |
|
1197
|
|
|
|
|
1198
|
|
|
if self._mw.alignment_2d_centiles_RadioButton.isChecked(): |
|
1199
|
|
|
|
|
1200
|
|
|
low_centile = self._mw.alignment_2d_cb_low_centiles_DSpinBox.value() |
|
1201
|
|
|
high_centile = self._mw.alignment_2d_cb_high_centiles_DSpinBox.value() |
|
1202
|
|
|
|
|
1203
|
|
|
if np.isclose(low_centile, 0.0): |
|
1204
|
|
|
low_centile = 0.0 |
|
1205
|
|
|
|
|
1206
|
|
|
# mask the array such that the arrays will be |
|
1207
|
|
|
masked_image = np.ma.masked_equal(self._2d_alignment_ImageItem.image, 0.0) |
|
1208
|
|
|
|
|
1209
|
|
|
if len(masked_image.compressed()) == 0: |
|
1210
|
|
|
cb_min = np.percentile(self._2d_alignment_ImageItem.image, low_centile) |
|
1211
|
|
|
cb_max = np.percentile(self._2d_alignment_ImageItem.image, high_centile) |
|
1212
|
|
|
else: |
|
1213
|
|
|
cb_min = np.percentile(masked_image.compressed(), low_centile) |
|
1214
|
|
|
cb_max = np.percentile(masked_image.compressed(), high_centile) |
|
1215
|
|
|
|
|
1216
|
|
|
else: |
|
1217
|
|
|
cb_min = self._mw.alignment_2d_cb_min_centiles_DSpinBox.value() |
|
1218
|
|
|
cb_max = self._mw.alignment_2d_cb_max_centiles_DSpinBox.value() |
|
1219
|
|
|
|
|
1220
|
|
|
self._2d_alignment_cb.refresh_colorbar(cb_min, cb_max) |
|
1221
|
|
|
self._mw.alignment_2d_cb_GraphicsView.update() |
|
1222
|
|
View Code Duplication |
|
|
|
|
|
|
|
1223
|
|
|
def _update_2d_graph_data(self): |
|
1224
|
|
|
""" Refresh the 2D-matrix image. """ |
|
1225
|
|
|
matrix_data = self._magnet_logic.get_2d_data_matrix() |
|
1226
|
|
|
|
|
1227
|
|
|
if self._mw.alignment_2d_centiles_RadioButton.isChecked(): |
|
1228
|
|
|
|
|
1229
|
|
|
low_centile = self._mw.alignment_2d_cb_low_centiles_DSpinBox.value() |
|
1230
|
|
|
high_centile = self._mw.alignment_2d_cb_high_centiles_DSpinBox.value() |
|
1231
|
|
|
|
|
1232
|
|
|
if np.isclose(low_centile, 0.0): |
|
1233
|
|
|
low_centile = 0.0 |
|
1234
|
|
|
|
|
1235
|
|
|
# mask the array in order to mark the values which are zeros with |
|
1236
|
|
|
# True, the rest with False: |
|
1237
|
|
|
masked_image = np.ma.masked_equal(matrix_data, 0.0) |
|
1238
|
|
|
|
|
1239
|
|
|
# compress the 2D masked array to a 1D array where the zero values |
|
1240
|
|
|
# are excluded: |
|
1241
|
|
|
if len(masked_image.compressed()) == 0: |
|
1242
|
|
|
cb_min = np.percentile(self._2d_alignment_ImageItem.image, low_centile) |
|
1243
|
|
|
cb_max = np.percentile(self._2d_alignment_ImageItem.image, high_centile) |
|
1244
|
|
|
else: |
|
1245
|
|
|
cb_min = np.percentile(masked_image.compressed(), low_centile) |
|
1246
|
|
|
cb_max = np.percentile(masked_image.compressed(), high_centile) |
|
1247
|
|
|
else: |
|
1248
|
|
|
cb_min = self._mw.alignment_2d_cb_min_centiles_DSpinBox.value() |
|
1249
|
|
|
cb_max = self._mw.alignment_2d_cb_max_centiles_DSpinBox.value() |
|
1250
|
|
|
|
|
1251
|
|
|
|
|
1252
|
|
|
self._2d_alignment_ImageItem.setImage(image=matrix_data, |
|
1253
|
|
|
levels=(cb_min, cb_max)) |
|
1254
|
|
|
self._update_2d_graph_axis() |
|
1255
|
|
|
|
|
1256
|
|
|
self._update_2d_graph_cb() |
|
1257
|
|
|
|
|
1258
|
|
|
# get data from logic |
|
1259
|
|
|
|
|
1260
|
|
|
|
|
1261
|
|
|
def save_2d_plots_and_data(self): |
|
1262
|
|
|
""" Save the sum plot, the scan marix plot and the scan data """ |
|
1263
|
|
|
timestamp = datetime.datetime.now() |
|
1264
|
|
|
filetag = self._mw.alignment_2d_nametag_LineEdit.text() |
|
1265
|
|
|
filepath = self._save_logic.get_path_for_module(module_name='Magnet') |
|
1266
|
|
|
|
|
1267
|
|
|
if len(filetag) > 0: |
|
1268
|
|
|
filename = os.path.join(filepath, '{0}_{1}_Magnet'.format(timestamp.strftime('%Y%m%d-%H%M-%S'), filetag)) |
|
1269
|
|
|
else: |
|
1270
|
|
|
filename = os.path.join(filepath, '{0}_Magnet'.format(timestamp.strftime('%Y%m%d-%H%M-%S'),)) |
|
1271
|
|
|
|
|
1272
|
|
|
exporter_graph = pyqtgraph.exporters.SVGExporter(self._mw.alignment_2d_GraphicsView.plotItem.scene()) |
|
1273
|
|
|
#exporter_graph = pg.exporters.ImageExporter(self._mw.odmr_PlotWidget.plotItem) |
|
1274
|
|
|
exporter_graph.export(filename + '.svg') |
|
1275
|
|
|
|
|
1276
|
|
|
# self._save_logic. |
|
1277
|
|
|
self._magnet_logic.save_2d_data(filetag, timestamp) |
|
1278
|
|
|
|
|
1279
|
|
|
def set_measurement_type(self): |
|
1280
|
|
|
""" According to the selected Radiobox a measurement type will be chosen.""" |
|
1281
|
|
|
|
|
1282
|
|
|
#FIXME: the measurement type should actually be set and saved in the logic |
|
1283
|
|
|
|
|
1284
|
|
|
if self._mw.meas_type_fluorescence_RadioButton.isChecked(): |
|
1285
|
|
|
self.measurement_type = '2d_fluorescence' |
|
1286
|
|
|
elif self._mw.meas_type_odmr_RadioButton.isChecked(): |
|
1287
|
|
|
self.measurement_type = '2d_odmr' |
|
1288
|
|
|
elif self._mw.meas_type_nuclear_spin_RadioButton.isChecked(): |
|
1289
|
|
|
self.measurement_type = '2d_nuclear' |
|
1290
|
|
|
else: |
|
1291
|
|
|
self.log.error('No measurement type specified in Magnet GUI!') |
|
1292
|
|
|
def _odmr_single_trans_alignment_changed(self): |
|
1293
|
|
|
""" Adjust the GUI display if only one ODMR transition is used. """ |
|
1294
|
|
|
|
|
1295
|
|
|
if self._mw.odmr_2d_single_trans_CheckBox.isChecked(): |
|
1296
|
|
|
self._mw.odmr_2d_high_trans_GroupBox.setVisible(False) |
|
1297
|
|
|
else: |
|
1298
|
|
|
self._mw.odmr_2d_high_trans_GroupBox.setVisible(True) |
|
1299
|
|
|
|