From be0d9382d6dbb1daac6c33ea25faf67f5de7103b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 10 Oct 2025 17:14:47 +0200 Subject: [PATCH] GUI: updated features to smart_rotation_panel.py --- .../aaregui/panels/smart_rotation_panel.py | 191 ++++++++++-------- 1 file changed, 111 insertions(+), 80 deletions(-) diff --git a/gui/src/aaregui/panels/smart_rotation_panel.py b/gui/src/aaregui/panels/smart_rotation_panel.py index 5c765d87..9dae8fc6 100644 --- a/gui/src/aaregui/panels/smart_rotation_panel.py +++ b/gui/src/aaregui/panels/smart_rotation_panel.py @@ -3,19 +3,22 @@ import math from PySide6.QtCore import Slot, Qt, Signal from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QFrame, QPushButton, QSpacerItem, QSizePolicy -from aaredaqlib.models import DAQStatusModel +from aaredaqlib.models import DAQStatusModel, SimpleScanParameters from aaredaqlib.rotation_scan import RotationScanRequest +from aaregui.panels.rotation_data_collection import add_data_to_path from aaregui.widgets.number_line_edit import NumberLineEdit class SimpleRotationSettingsPanel(QWidget): rotation_scan = Signal(RotationScanRequest) viewer_track_online = Signal() + parameters_changed = Signal(SimpleScanParameters) def __init__(self, parent=None): super().__init__(parent) + self.n_images = 1 self.xtal_size_dose_rate_MGy_s = None self.xtal_x = None self.xtal_y = None @@ -24,14 +27,12 @@ class SimpleRotationSettingsPanel(QWidget): self.dose_rate_MGy_s = None self._filename = "" self.dtz = 120 - self.n_images = None - self.transmission = 1.0 - self.image_time_s = None - self.image_angle = 0.2 + self.image_time_s = 0.1 self.__d = None self._temperature = 100 self.__omega = 0 - self._wilson_b = 0 + self._wilson_b = None + self.parameters = SimpleScanParameters() self._layout = QGridLayout(self) @@ -44,73 +45,75 @@ class SimpleRotationSettingsPanel(QWidget): self._layout.addWidget(QLabel("Å", parent=self), 0, 4) self.visible_res_enter.newValue.connect(self.set_visible_resolution) - # Angular range (entry) - self._layout.addWidget(QLabel("Total angle", parent=self), 1, 0) - self.angular_range_enter = NumberLineEdit( - 5.0, 1000.0, decimals=3, default=210.0, parent=self - ) - self._layout.addWidget(self.angular_range_enter, 1, 1, 1, 3) + self._layout.addWidget(QLabel("Start angle", parent=self), 1, 0) + self.start_angle_enter = NumberLineEdit(-720, 720.0, 0.0, decimals=3, parent=self) + self._layout.addWidget(self.start_angle_enter, 1, 1, 1, 3) self._layout.addWidget(QLabel("°", parent=self), 1, 4) - self.visible_res_enter.newValue.connect(self.set_visible_resolution) - - # Calculated labels - self._layout.addWidget(QLabel("Target resolution", parent=self), 2, 0) - self.target_res_label = QLabel("--", parent=self) - self.target_res_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) - self._layout.addWidget(self.target_res_label, 2, 1, 1, 3) - self._layout.addWidget(QLabel("Å", parent=self), 2, 4) - - self._layout.addWidget(QLabel("Image angle", parent=self), 3, 0) - self.image_angle_label = QLabel("--", parent=self) - self.image_angle_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) - self._layout.addWidget(self.image_angle_label, 3, 1, 1, 3) - self._layout.addWidget(QLabel("°", parent=self), 3, 4) - - self._layout.addWidget(QLabel("Image time", parent=self), 4, 0) - self.image_time_label = QLabel("--", parent=self) - self.image_time_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) - self._layout.addWidget(self.image_time_label, 4, 1, 1, 3) - self._layout.addWidget(QLabel("s", parent=self), 4, 4) - - self._layout.addWidget(QLabel("Transmission", parent=self), 5, 0) - self.transmission_label = QLabel("--", parent=self) - self.transmission_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) - self._layout.addWidget(self.transmission_label, 5, 1, 1, 3) - self._layout.addWidget(QLabel("%", parent=self), 5, 4) - - self._layout.addWidget(QLabel("Detector distance", parent=self), 6, 0) - self.dtz_label = QLabel(f"--", parent=self) - self.dtz_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) - self._layout.addWidget(self.dtz_label, 6, 1, 1, 3) - self._layout.addWidget(QLabel("mm", parent=self), 6, 4) - - self._layout.addWidget(QLabel("Target Dose", parent=self), 7, 0) - self.target_dose_label = QLabel(f"--", parent=self) - self.target_dose_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) - self._layout.addWidget(self.target_dose_label, 7, 1, 1, 3) - self._layout.addWidget(QLabel("MGy", parent=self), 7, 4) - - self._layout.addWidget(QLabel("Calculated Dose Rate", parent=self), 8, 0) - self.calculated_dose_rate_label = QLabel(f"--", parent=self) - self.calculated_dose_rate_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) - self._layout.addWidget(self.calculated_dose_rate_label, 8, 1, 1, 3) - self._layout.addWidget(QLabel("MGy S^-1", parent=self), 8, 4) - - self._layout.addWidget(QLabel("Temperature", parent=self), 9, 0) - self.temp_enter = NumberLineEdit(80, 330, decimals=2, default=100.0, parent=self) - self._layout.addWidget(self.temp_enter, 9, 1, 1, 3) - self._layout.addWidget(QLabel("K", parent=self), 9, 4) - self.temp_enter.newValue.connect(self.set_temperature) - - self._layout.addWidget(QLabel("Start angle", parent=self), 10, 0) - self.start_angle = NumberLineEdit(-720, 720.0, 0.0, decimals=3, parent=self) - self._layout.addWidget(self.start_angle, 10, 1, 1, 3) - self._layout.addWidget(QLabel("°", parent=self), 10, 4) self.omega_button = QPushButton("Ω") self.omega_button.setFixedWidth(20) self.omega_button.clicked.connect(self.update_omega_start) - self._layout.addWidget(self.omega_button, 10, 5) + self._layout.addWidget(self.omega_button, 1, 5) + + # Angular range (entry) + self._layout.addWidget(QLabel("Total angle", parent=self), 2, 0) + self.angular_range_enter = NumberLineEdit( + 5.0, 1000.0, decimals=3, default=360.0, parent=self + ) + self._layout.addWidget(self.angular_range_enter, 2, 1, 1, 3) + self._layout.addWidget(QLabel("°", parent=self), 2, 4) + self.visible_res_enter.newValue.connect(self.set_total_angle) + + self._layout.addWidget(QLabel("Image angle", parent=self), 3, 0) + self.image_angle_enter = NumberLineEdit( + 0.001, 1.000, decimals=3, default=0.2, parent=self + ) + self._layout.addWidget(self.image_angle_enter, 3, 1, 1, 3) + self._layout.addWidget(QLabel("°", parent=self), 3, 4) + self.image_angle_enter.newValue.connect(self.set_image_angle) + + self._layout.addWidget(QLabel("Temperature", parent=self), 4, 0) + self.temp_enter = NumberLineEdit(80, 330, decimals=2, default=100.0, parent=self) + self._layout.addWidget(self.temp_enter, 4, 1, 1, 3) + self._layout.addWidget(QLabel("K", parent=self), 4, 4) + self.temp_enter.newValue.connect(self.set_temperature) + + # Calculated labels + self._layout.addWidget(QLabel("Target resolution", parent=self), 5, 0) + self.target_res_label = QLabel("--", parent=self) + self.target_res_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) + self._layout.addWidget(self.target_res_label, 5, 1, 1, 3) + self._layout.addWidget(QLabel("Å", parent=self), 5, 4) + + self._layout.addWidget(QLabel("Image time", parent=self), 6, 0) + self.image_time_label = QLabel("--", parent=self) + self.image_time_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) + self._layout.addWidget(self.image_time_label, 6, 1, 1, 3) + self._layout.addWidget(QLabel("s", parent=self), 6, 4) + + self._layout.addWidget(QLabel("Transmission", parent=self), 7, 0) + self.transmission_label = QLabel("--", parent=self) + self.transmission_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) + self._layout.addWidget(self.transmission_label, 7, 1, 1, 3) + self._layout.addWidget(QLabel("%", parent=self), 7, 4) + + self._layout.addWidget(QLabel("Detector distance", parent=self), 8, 0) + self.dtz_label = QLabel(f"--", parent=self) + self.dtz_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) + self._layout.addWidget(self.dtz_label, 8, 1, 1, 3) + self._layout.addWidget(QLabel("mm", parent=self), 8, 4) + + self._layout.addWidget(QLabel("Target Dose", parent=self), 9, 0) + self.target_dose_label = QLabel(f"--", parent=self) + self.target_dose_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) + self._layout.addWidget(self.target_dose_label, 9, 1, 1, 3) + self._layout.addWidget(QLabel("MGy", parent=self), 9, 4) + + self._layout.addWidget(QLabel("Calculated Dose Rate", parent=self), 10, 0) + self.calculated_dose_rate_label = QLabel(f"--", parent=self) + self.calculated_dose_rate_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) + self._layout.addWidget(self.calculated_dose_rate_label, 10, 1, 1, 3) + self._layout.addWidget(QLabel("MGy S^-1", parent=self), 10, 4) self._layout.addWidget(QLabel("Wilson B Factor", parent=self), 11, 0) self.wilson_b_label = QLabel(f"--", parent=self) @@ -178,7 +181,12 @@ class SimpleRotationSettingsPanel(QWidget): @Slot(DAQStatusModel) def update_daq_status(self, s: DAQStatusModel): self.__d = s + #TODO only update best_res after raster finished otherwise ask to update. or have toggle to overwrite with user value + #TODO only take best res from flat face scan + #TODO identify flat face!!!! best_res = s.last_best_res + print("best_res: ", best_res) + self.__omega = s.geom.omega_deg if best_res is not None: # clamp to control limits and update field; this will also trigger recalculation @@ -187,12 +195,14 @@ class SimpleRotationSettingsPanel(QWidget): self.visible_res_enter.update_value(v) self.set_visible_resolution(v) - best_b_factor = s.last_best_b_factor + self._wilson_b = s.last_best_b_factor + print("b_factor: ", self._wilson_b) - if best_b_factor is not None: - self.wilson_b_label.setText(f"{best_b_factor:.2f}") + if self._wilson_b is not None: + self.wilson_b_label.setText(f"{self._wilson_b:.2f}") xtal_size = s.crystal_size + print("crystal_size: ", xtal_size) if xtal_size is not None: # clamp to control limits and update field; this will also trigger recalculation self.xtal_x = xtal_size.x @@ -211,12 +221,21 @@ class SimpleRotationSettingsPanel(QWidget): self.wavelength_label.setText("N/A") else: self.wavelength_label.setText(f"{s.diffraction.wavelength_angstrom:.3f}") + self.update_calculated_labels() @Slot(float) def set_visible_resolution(self, v: float): self.update_calculated_labels() + @Slot(float) + def set_total_angle(self, v: float): + self.update_calculated_labels() + + @Slot(float) + def set_image_angle(self, v: float): + self.update_calculated_labels() + @Slot(float) def set_temperature(self, v: float): self.update_calculated_labels() @@ -227,7 +246,7 @@ class SimpleRotationSettingsPanel(QWidget): @Slot() def update_omega_start(self): - self.start_angle.update_value(self.__omega) + self.start_angle_enter.update_value(self.__omega) def update_calculated_labels(self): if self.__d is None: @@ -238,9 +257,12 @@ class SimpleRotationSettingsPanel(QWidget): #TODO read resolution estiamtion from jfjoch total_angle = self.angular_range_enter.value d_vis = self.visible_res_enter.value + image_angle = self.image_angle_enter.value + if d_vis == 0.0: + d_vis = 1.3 d_tar = 1/(1/d_vis + 0.1) + self.target_res_label.setText(f"{d_tar:.2f}") - #self.wilson_b_label.setText("--") Kdose = 2000 / (self.__d.diffraction.wavelength_angstrom**2) @@ -271,10 +293,9 @@ class SimpleRotationSettingsPanel(QWidget): total_time_s = self.target_dose_MGy / self.dose_rate_MGy_s self.calculated_dose_label.setText(f"{self.xtal_size_dose_rate_MGy_s*total_time_s:.2f}") - - self.image_angle = 0.2 - self.image_angle_label.setText(f"{self.image_angle:.3f}") - self.n_images = total_angle / self.image_angle + if image_angle == 0.0: + image_angle = 0.001 + self.n_images = round(total_angle / image_angle) self.image_time_s = total_time_s / self.n_images if self.image_time_s < 0.01: self.transmission = self.image_time_s / 0.01 @@ -295,13 +316,23 @@ class SimpleRotationSettingsPanel(QWidget): else: self.dtz_label.setText(f"{self.dtz:.2f}") + self.parameters = SimpleScanParameters( + dtz=int(round(self.dtz)), + exp_time_s=self.image_time_s, + start_omega_deg=self.start_angle_enter.value, + incr_omega_deg=image_angle, + steps=self.n_images, + transmission=self.transmission + ) + self.parameters_changed.emit(self.parameters) + @Slot() def run_measurement(self): r = RotationScanRequest( - file_prefix=self._filename, - start_omega_deg=0,#,self.start_angle.value, + file_prefix=str(add_data_to_path(self._filename)), + start_omega_deg=self.start_angle_enter.value, steps=self.n_images, - incr_omega_deg=self.image_angle, + incr_omega_deg=self.image_angle_enter.value, dtz=self.dtz, transmission=self.transmission, screening=False,