GUI: updated smart_rotation_panel functionality and included more widgets in the GUI
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import math
|
||||
|
||||
from PySide6.QtCore import Slot, Qt, Signal
|
||||
from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QFrame, QPushButton, QSpacerItem, QSizePolicy
|
||||
|
||||
@@ -14,6 +16,12 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
|
||||
super().__init__(parent)
|
||||
|
||||
self.xtal_size_dose_rate_MGy_s = None
|
||||
self.xtal_x = None
|
||||
self.xtal_y = None
|
||||
self.xtal_z = None
|
||||
self.target_dose_MGy = None
|
||||
self.dose_rate_MGy_s = None
|
||||
self._filename = ""
|
||||
self.dtz = 120
|
||||
self.n_images = None
|
||||
@@ -21,6 +29,9 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self.image_time_s = None
|
||||
self.image_angle = 0.2
|
||||
self.__d = None
|
||||
self._temperature = 100
|
||||
self.__omega = 0
|
||||
self._wilson_b = 0
|
||||
|
||||
self._layout = QGridLayout(self)
|
||||
|
||||
@@ -73,55 +84,201 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
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(QLabel("Wilson B Factor", parent=self), 11, 0)
|
||||
self.wilson_b_label = QLabel(f"--", parent=self)
|
||||
self.wilson_b_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.wilson_b_label, 11, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("Å^2", parent=self), 11, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Crystal Size x from Grid Scan", parent=self), 12, 0)
|
||||
self.xtal_x_label = QLabel(f"--", parent=self)
|
||||
self.xtal_x_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.xtal_x_label, 12, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("um", parent=self), 12, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Crystal Size y from Grid Scan", parent=self), 13, 0)
|
||||
self.xtal_y_label = QLabel(f"--", parent=self)
|
||||
self.xtal_y_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.xtal_y_label, 13, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("um", parent=self), 13, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Crystal Size z from Grid Scan", parent=self), 14, 0)
|
||||
self.xtal_z_label = QLabel(f"--", parent=self)
|
||||
self.xtal_z_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.xtal_z_label, 14, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("um", parent=self), 14, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Calculated Dose from crystal size", parent=self), 15, 0)
|
||||
self.xtal_size_dose_label = QLabel(f"--", parent=self)
|
||||
self.xtal_size_dose_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.xtal_size_dose_label, 15, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("MGy", parent=self), 15, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("X-ray Wavelength", parent=self), 16, 0)
|
||||
self.wavelength_label = QLabel("--", parent=self)
|
||||
self.wavelength_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.wavelength_label, 16, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("Å", parent=self), 16, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Flux", parent=self), 17, 0)
|
||||
self.flux_label = QLabel(f"--", parent=self)
|
||||
self.flux_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.flux_label, 17, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("ph s^-1", parent=self), 17, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Beam Size", parent=self), 18, 0)
|
||||
self.beam_size_label = QLabel(f"--", parent=self)
|
||||
self.beam_size_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.beam_size_label, 18, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("um ^ 2", parent=self), 18, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Calculated Dose", parent=self), 19, 0)
|
||||
self.calculated_dose_label = QLabel(f"--", parent=self)
|
||||
self.calculated_dose_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.calculated_dose_label, 19, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("MGy", parent=self), 19, 4)
|
||||
|
||||
# add vertical stretch between detector distance and the run button
|
||||
self._layout.addItem(QSpacerItem(0, 0, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding), 7, 0, 1, 6)
|
||||
self._layout.addItem(QSpacerItem(0, 0, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding), 20, 0, 1, 6)
|
||||
|
||||
# Run rotation button
|
||||
self.run_rotation_button = QPushButton("Run rotation", parent=self)
|
||||
self.run_rotation_button.setStyleSheet("color: rgb(78, 154, 6);")
|
||||
self._layout.addWidget(self.run_rotation_button, 8, 0, 1, 6)
|
||||
self.run_rotation_button.clicked.connect(self.run_measurement)
|
||||
self._layout.addWidget(self.run_rotation_button, 21, 0, 1, 6)
|
||||
|
||||
@Slot(DAQStatusModel)
|
||||
def update_daq_status(self, s: DAQStatusModel):
|
||||
self.__d = s
|
||||
best = getattr(s, "last_best_res", None)
|
||||
if best is not None:
|
||||
best_res = s.last_best_res
|
||||
|
||||
if best_res is not None:
|
||||
# clamp to control limits and update field; this will also trigger recalculation
|
||||
lo, hi = 0.8, 10.0
|
||||
v = max(lo, min(hi, float(best)))
|
||||
v = max(lo, min(hi, float(best_res)))
|
||||
self.visible_res_enter.update_value(v)
|
||||
self.set_visible_resolution(v)
|
||||
|
||||
best_b_factor = s.last_best_b_factor
|
||||
|
||||
if best_b_factor is not None:
|
||||
self.wilson_b_label.setText(f"{best_b_factor:.2f}")
|
||||
|
||||
xtal_size = s.crystal_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
|
||||
self.xtal_y = xtal_size.y
|
||||
self.xtal_z = xtal_size.z
|
||||
self.xtal_x_label.setText(f"{self.xtal_x:.2f}")
|
||||
self.xtal_y_label.setText(f"{self.xtal_y:.2f}")
|
||||
self.xtal_z_label.setText(f"{self.xtal_z:.2f}")
|
||||
|
||||
#self.omega.new_value(s.geom.omega_deg)
|
||||
self.beam_size_label.setText(
|
||||
f"<b>{s.geom.beam_size_mm.x * 1000.0}</b> x <b>{s.geom.beam_size_mm.y * 1000.0}</b>"
|
||||
)
|
||||
self.flux_label.setText(f"<b>{(s.bl.flux_ph_s / 1e9):.2f}</b>")
|
||||
if s.diffraction.wavelength_angstrom is None:
|
||||
self.wavelength_label.setText("<b>N/A</b>")
|
||||
else:
|
||||
self.wavelength_label.setText(f"<b>{s.diffraction.wavelength_angstrom:.3f}</b>")
|
||||
self.update_calculated_labels()
|
||||
|
||||
@Slot(float)
|
||||
def set_visible_resolution(self, v: float):
|
||||
self.update_calculated_labels()
|
||||
|
||||
@Slot(float)
|
||||
def set_temperature(self, v: float):
|
||||
self.update_calculated_labels()
|
||||
|
||||
@Slot(str)
|
||||
def update_filename(self, filename: str):
|
||||
self._filename = filename
|
||||
|
||||
@Slot()
|
||||
def update_omega_start(self):
|
||||
self.start_angle.update_value(self.__omega)
|
||||
|
||||
def update_calculated_labels(self):
|
||||
if self.__d is None:
|
||||
return
|
||||
flux = 2.5e11
|
||||
|
||||
flux = 2.5e11 #TODO link flux
|
||||
#TODO add start angle
|
||||
#TODO link beam energy
|
||||
#TODO read resolution estiamtion from jfjoch
|
||||
total_angle = self.angular_range_enter.value
|
||||
d_vis = self.visible_res_enter.value
|
||||
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)
|
||||
dose_rate_MGy_s = (flux / (self.__d.geom.beam_size_mm.x * 1000 * self.__d.geom.beam_size_mm.y * 1000 * Kdose)) / 1e6
|
||||
target_dose_MGy = 10 * d_tar / 2.0
|
||||
total_time_s = target_dose_MGy / dose_rate_MGy_s
|
||||
|
||||
beam_size_um_y = self.__d.geom.beam_size_mm.y * 1000
|
||||
beam_size_um_x = self.__d.geom.beam_size_mm.x * 1000
|
||||
self.dose_rate_MGy_s = (flux / (beam_size_um_x * beam_size_um_y * Kdose)) / 1e6
|
||||
if self.xtal_y is None or self.xtal_z is None or beam_size_um_x is None or beam_size_um_y is None:
|
||||
self.xtal_size_dose_rate_MGy_s = self.dose_rate_MGy_s
|
||||
|
||||
elif self.xtal_y > beam_size_um_y or self.xtal_z > beam_size_um_y :
|
||||
multiplier_1 = max(self.xtal_y, beam_size_um_y)
|
||||
multiplier_2 = max( self.xtal_z,beam_size_um_y)
|
||||
new_beam_um_y = math.sqrt(multiplier_1*multiplier_2)
|
||||
self.xtal_size_dose_rate_MGy_s = (flux / (beam_size_um_x * new_beam_um_y * Kdose)) / 1e6
|
||||
|
||||
else:
|
||||
self.xtal_size_dose_rate_MGy_s = self.dose_rate_MGy_s
|
||||
|
||||
if self.temp_enter.value > 250:
|
||||
self.target_dose_MGy = 0.1 * d_tar / 2.0 #TODO add user input
|
||||
else:
|
||||
self.target_dose_MGy = 10 * d_tar / 2.0
|
||||
|
||||
self.target_dose_label.setText(f"{self.target_dose_MGy:.2f}")
|
||||
self.calculated_dose_rate_label.setText(f"{self.dose_rate_MGy_s:.2f}")
|
||||
self.xtal_size_dose_label.setText(f"{self.xtal_size_dose_rate_MGy_s:.2f}")
|
||||
|
||||
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
|
||||
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
|
||||
image_time_s = 0.01
|
||||
self.image_time_s = 0.01
|
||||
else:
|
||||
self.transmission = 1.0
|
||||
|
||||
@@ -134,6 +291,7 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self.dtz_label.setText(f"""<span style="color: red ; ">-</span>""")
|
||||
elif self.dtz < self.__d.bl.dtz_min:
|
||||
self.dtz_label.setText(f"""<span style="color: red ; ">{self.dtz:.2f}</span>""")
|
||||
self.dtz = self.__d.bl.dtz_min
|
||||
else:
|
||||
self.dtz_label.setText(f"{self.dtz:.2f}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user