GUI: added controls for mono_picth_scan and change_energy

This commit is contained in:
2026-05-12 17:05:07 +02:00
parent 36a633a291
commit ab4dd89486
7 changed files with 193 additions and 4 deletions
+14
View File
@@ -3608,6 +3608,20 @@ class AareDAQ:
finally:
self.__cfg.state_busy = False
def mono_pitch_scan(self, plot: bool = False) -> None:
self.__cfg.try_set_busy(timeout=360)
try:
self.__devs.bec_worker.mono_pitch_scan_runner(plot=plot)
finally:
self.__cfg.state_busy = False
def change_energy(self, value: float, plot: bool = False) -> None:
self.__cfg.try_set_busy(timeout=360)
try:
self.__devs.bec_worker.change_energy(value=value, plot=plot)
finally:
self.__cfg.state_busy = False
def fluorimeter_take_spectrum(self, fm: FluorescenceSpectrumParameterModel) -> FluorescenceSpectrumOutputModel:
self.__cfg.try_set_busy(timeout=360)
+37
View File
@@ -424,6 +424,43 @@ async def zoom(val: float, token: str = Depends(oauth2_scheme)):
return "OK"
@app.post("/beamline/mono_pitch_scan")
async def mono_pitch_scan(plot: bool = False, token: str = Depends(oauth2_scheme)):
"""
Run a monochromator pitch scan. Staff only.
Args:
plot: Whether to enable plotting in the BEC worker.
token: OAuth2 access token.
Returns:
"OK" on success.
"""
logger.debug(f"Running mono pitch scan (plot={plot})")
auth.check_jwt_staff(cfg, auth.parse_token(token))
daq.mono_pitch_scan(plot=plot)
return "OK"
@app.put("/beamline/change_energy")
async def change_energy(value: float, plot: bool = False, token: str = Depends(oauth2_scheme)):
"""
Change monochromator energy. Staff only.
Args:
value: Target energy.
plot: Whether to enable plotting in the BEC worker.
token: OAuth2 access token.
Returns:
"OK" on success.
"""
logger.debug(f"Changing energy to {value} (plot={plot})")
auth.check_jwt_staff(cfg, auth.parse_token(token))
daq.change_energy(value=value, plot=plot)
return "OK"
@app.put("/beamline/smargon")
async def smargon(val: SmargonCoordinate, token: str = Depends(oauth2_scheme)):
"""
+27 -1
View File
@@ -92,6 +92,8 @@ class MainWindow(QMainWindow):
self._cleanup_done = False
self._default_window_state = None
self._show_beamline_state_panel_for_users = True
self._waiting_for_baton_response: bool = False
self._baton_request_dialog: BatonRequestDialog | None = None
self._baton_pending_dialog: BatonPendingDialog | None = None
@@ -187,10 +189,16 @@ class MainWindow(QMainWindow):
self.loop_centering = LoopCenteringPanel(parent=self.left_column)
self.beamline_state_panel = BeamlineStatePanel(parent=self.left_column)
self._beamline_state_panel_enabled = bool(
self.__decoded_token.staff or self._show_beamline_state_panel_for_users
)
self.left_column_layout.addWidget(self.data_collection)
self.left_column_layout.addWidget(self.loop_centering)
self.left_column_layout.addWidget(self.beamline_state_panel)
if self._beamline_state_panel_enabled:
self.left_column_layout.addWidget(self.beamline_state_panel)
else:
self.beamline_state_panel.hide()
self.left_column_layout.addStretch()
top_widget_layout.addWidget(collection_controls_scroll)
@@ -456,6 +464,8 @@ class MainWindow(QMainWindow):
self.beamline.illumination_panel.back_light.connect(self.daq.back_light)
if self.__decoded_token.staff:
self.beamline.monochromator_panel.mono_pitch_scan.connect(self.daq.mono_pitch_scan)
self.beamline.monochromator_panel.change_energy.connect(self.daq.change_energy)
self.beamline.abr_tweak.abr_tweak.connect(self.daq.abr_tweak)
self.beamline.abr_tweak.abr_save.connect(self.daq.abr_save)
self.beamline.abr_tweak.abr_goto_meas.connect(self.daq.abr_goto_meas)
@@ -613,6 +623,7 @@ class MainWindow(QMainWindow):
self.daq.update.connect(self.camera_thread.update_daq_status)
if self.__decoded_token.staff:
self.daq.update.connect(self.beamline.monochromator_panel.update_daq_status)
self.daq.update.connect(self.beamline.beam_size.update_daq_status)
self.daq.update.connect(self.beamline.beam_center.update_daq_status)
self.daq.update.connect(self.beamline.abr_tweak.update_daq_status)
@@ -823,6 +834,15 @@ class MainWindow(QMainWindow):
view_menu = menu_bar.addMenu("View")
if self._beamline_state_panel_enabled:
self._show_beamline_state_action = QAction("Show Beamline State Panel", self)
self._show_beamline_state_action.setCheckable(True)
self._show_beamline_state_action.setChecked(self.beamline_state_panel.isVisible())
self._show_beamline_state_action.triggered.connect(
lambda checked: self.beamline_state_panel.setVisible(checked)
)
view_menu.addAction(self._show_beamline_state_action)
show_samples_action = QAction("Show Sample List", self)
show_samples_action.setCheckable(True)
show_samples_action.setChecked(True)
@@ -973,6 +993,12 @@ class MainWindow(QMainWindow):
self.job_list_dock.setVisible(True)
self.manual_sample_dock.setVisible(True)
if self._beamline_state_panel_enabled:
self.beamline_state_panel.setVisible(True)
self.beamline_state_panel.set_collapsed(False)
if hasattr(self, "_show_beamline_state_action"):
self._show_beamline_state_action.setChecked(True)
self.face_panel_dock.setVisible(False)
self.fluor_panel_dock.setVisible(False)
self.smargon_trace_dock.setVisible(False)
+3 -1
View File
@@ -5,6 +5,7 @@ from aare.gui.panels.beam_center_panel import BeamCenterWidget
from aare.gui.panels.beam_mark_panel import BeamMarkWidget
from aare.gui.panels.beam_size_panel import BeamSizeWidget
from aare.gui.panels.illumination_panel import IlluminationPanel
from aare.gui.panels.monochromator_panel import MonochromatorPanel
from aare.gui.panels.omega_panel import OmegaPanel
from aare.gui.panels.samcam_panel import SamcamPanel
from aare.gui.panels.smargon_panel import SmargonPanel
@@ -37,11 +38,13 @@ class BeamlineControls(QFrame):
self.v_layout.addWidget(self.samcam)
if staff:
self.monochromator_panel = MonochromatorPanel(self)
self.abr_tweak = AbrTweakWidget(self)
self.beam_mark = BeamMarkWidget(self)
self.beam_center = BeamCenterWidget(self)
self.beam_size = BeamSizeWidget(self)
self.v_layout.addWidget(self.monochromator_panel)
self.v_layout.addWidget(self.abr_tweak)
self.v_layout.addWidget(self.beam_mark)
self.v_layout.addWidget(self.beam_center)
@@ -49,4 +52,3 @@ class BeamlineControls(QFrame):
self.v_layout.addStretch()
self.setLayout(self.v_layout)
+62 -2
View File
@@ -56,6 +56,8 @@ class BeamlineStatePanel(QFrame):
set_width = 400
map_height = 470
title_height = 50
collapsed_height = 50
station_radius = 8
def __init__(self, parent=None):
@@ -63,7 +65,9 @@ class BeamlineStatePanel(QFrame):
self.setFrameShape(QFrame.Shape.StyledPanel)
self.setFrameShadow(QFrame.Shadow.Raised)
self.setFixedWidth(self.set_width)
self._is_collapsed = False
self.setMinimumHeight(self.map_height)
self.setMaximumHeight(self.map_height)
self._current_state: BeamlineStateEnum | None = None
self._hovered_state: BeamlineStateEnum | None = None
@@ -134,8 +138,27 @@ class BeamlineStatePanel(QFrame):
self.title.setText("<H3>Beamline state</H3>")
self.title.setStyleSheet("background-color: #4B0082; color: #ffffff;")
self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.title.setFixedHeight(50)
self.title.setGeometry(0, 0, self.set_width, 50)
self.title.setFixedHeight(self.title_height)
self.title.setGeometry(0, 0, self.set_width, self.title_height)
self.toggle_button = QPushButton("", self)
self.toggle_button.setToolTip("Minimise beamline state panel")
self.toggle_button.setFixedSize(28, 28)
self.toggle_button.move(self.set_width - 36, 11)
self.toggle_button.clicked.connect(self.toggle_collapsed)
self.toggle_button.setStyleSheet("""
QPushButton {
border: none;
border-radius: 14px;
background-color: rgba(255, 255, 255, 0.20);
color: white;
font-size: 16px;
font-weight: 700;
}
QPushButton:hover {
background-color: rgba(255, 255, 255, 0.32);
}
""")
self.current_label = QLabel("Current: —", self)
self.current_label.setStyleSheet("""
@@ -165,6 +188,7 @@ class BeamlineStatePanel(QFrame):
self._build_station_widgets()
self._position_station_widgets()
self._update_collapsed_state()
@staticmethod
def _canon_segment(a: BeamlineStateEnum, b: BeamlineStateEnum) -> tuple[BeamlineStateEnum, BeamlineStateEnum]:
@@ -267,6 +291,39 @@ class BeamlineStatePanel(QFrame):
self._apply_station_highlight()
def toggle_collapsed(self) -> None:
self._is_collapsed = not self._is_collapsed
self._update_collapsed_state()
def set_collapsed(self, collapsed: bool) -> None:
if self._is_collapsed == collapsed:
return
self._is_collapsed = collapsed
self._update_collapsed_state()
def _update_collapsed_state(self) -> None:
show_content = not self._is_collapsed
self.current_label.setVisible(show_content)
self.tell_label.setVisible(show_content)
for widget in self._station_widgets.values():
widget.setVisible(show_content)
if self._is_collapsed:
self.setMinimumHeight(self.collapsed_height)
self.setMaximumHeight(self.collapsed_height)
self.toggle_button.setText("+")
self.toggle_button.setToolTip("Restore beamline state panel")
else:
self.setMinimumHeight(self.map_height)
self.setMaximumHeight(self.map_height)
self.toggle_button.setText("")
self.toggle_button.setToolTip("Minimise beamline state panel")
self.updateGeometry()
self.update()
def _emit_for_state(self, state: BeamlineStateEnum) -> None:
self._pending_target_state = state
self._hovered_state = None
@@ -460,6 +517,9 @@ class BeamlineStatePanel(QFrame):
def paintEvent(self, event) -> None:
super().paintEvent(event)
if self._is_collapsed:
return
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
@@ -0,0 +1,42 @@
from PySide6.QtCore import Signal, Slot
from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QDoubleSpinBox, QPushButton
from aare.common.models import DAQStatusModel
from aare.gui.widgets.title_label import TitleLabel
class MonochromatorPanel(QWidget):
mono_pitch_scan = Signal()
change_energy = Signal(float)
def __init__(self, parent=None):
super().__init__(parent)
grid_layout = QGridLayout(self)
grid_layout.addWidget(TitleLabel("Monochromator", self), 0, 0, 1, 2)
self.mono_pitch_scan_button = QPushButton("Mono Pitch Scan", parent=self)
self.mono_pitch_scan_button.clicked.connect(self.mono_pitch_scan.emit)
grid_layout.addWidget(self.mono_pitch_scan_button, 1, 0, 1, 2)
grid_layout.addWidget(QLabel("Energy", parent=self), 2, 0)
self.energy_spin = QDoubleSpinBox(parent=self)
self.energy_spin.setDecimals(3)
self.energy_spin.setRange(1000.0, 30000.0)
self.energy_spin.setSingleStep(100.0)
self.energy_spin.setSuffix(" eV")
self.energy_spin.setValue(12000.0)
grid_layout.addWidget(self.energy_spin, 3, 0)
self.change_energy_button = QPushButton("Change Energy", parent=self)
self.change_energy_button.clicked.connect(self._emit_change_energy)
grid_layout.addWidget(self.change_energy_button, 3, 1)
@Slot()
def _emit_change_energy(self):
self.change_energy.emit(float(self.energy_spin.value()))
@Slot(DAQStatusModel)
def update_daq_status(self, _status: DAQStatusModel):
pass
+8
View File
@@ -661,6 +661,14 @@ class DAQWorker(QObject):
def zoom(self, f: float):
self.generic_put(f"beamline/zoom?val={f:.3f}")
@Slot()
def mono_pitch_scan(self):
self.generic_post("beamline/mono_pitch_scan")
@Slot(float)
def change_energy(self, value: float):
self.generic_put(f"beamline/change_energy?value={value:.3f}")
@Slot(int)
def front_light(self, v: int):
self.generic_put(f"beamline/front_light?val={v:d}")