From 81e481777fb33920021b458a58e6f8fa42d43f20 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 17 Jun 2025 12:20:22 +0200 Subject: [PATCH] GUI: More beamtime improvements --- daq/src/aaredaq/daq.py | 5 ++++ daq/src/aaredaq/server.py | 4 +++ daq/src/mxlibs3/jfjoch.py | 3 +++ gui/src/aaregui/main.py | 2 +- gui/src/aaregui/main_window.py | 19 +------------- .../panels/data_collection_settings.py | 15 +++++++---- gui/src/aaregui/panels/status_panel.py | 8 ++++-- .../aaregui/scan_logic/raster_grid_manager.py | 2 +- gui/src/aaregui/threads/daq_worker.py | 4 +++ gui/src/aaregui/widgets/status_bar.py | 25 ++++++++++++++++++- gui/src/aaregui/widgets/value_label.py | 22 ++++++++++++++++ 11 files changed, 81 insertions(+), 28 deletions(-) create mode 100644 gui/src/aaregui/widgets/value_label.py diff --git a/daq/src/aaredaq/daq.py b/daq/src/aaredaq/daq.py index 34a40784..515ebaa2 100644 --- a/daq/src/aaredaq/daq.py +++ b/daq/src/aaredaq/daq.py @@ -262,6 +262,7 @@ class AareDAQ: ) self.__devs.aerotech.wait_scan_done(max_time) self.__devs.aerotech.reset() + self.__devs.abr_pos = self.__cfg.abr_meas_pos self.__devs.smargon.target = save_smargon_position result = self.__jfjoch.wait_till_done(5) return CompletedRasterGrid(request=copy.deepcopy(r), result=result) @@ -776,3 +777,7 @@ class AareDAQ: diffraction=self.diffraction_geometry ) + def cancel(self): + if self.__cfg.state == BeamlineStateEnum.DataCollection: + self.__devs.aerotech.stop() + self.__jfjoch.cancel() diff --git a/daq/src/aaredaq/server.py b/daq/src/aaredaq/server.py index 81c413cd..dc925263 100644 --- a/daq/src/aaredaq/server.py +++ b/daq/src/aaredaq/server.py @@ -254,6 +254,10 @@ async def auto(s: SampleShortInfo, token: str = Depends(oauth2_scheme)): runtime = daq.measure(s) return f"{runtime:0.3f}" +@app.post("/scan/cancel") +async def cancel(token: str = Depends(oauth2_scheme)): + auth.check_jwt_rw(cfg, auth.parse_token(token)) + daq.cancel() # ALC routines @app.post("/alc/background") diff --git a/daq/src/mxlibs3/jfjoch.py b/daq/src/mxlibs3/jfjoch.py index 85b02b63..ca78e517 100644 --- a/daq/src/mxlibs3/jfjoch.py +++ b/daq/src/mxlibs3/jfjoch.py @@ -25,6 +25,9 @@ class JFJochWrapper: def initialize(self): self.__api.initialize_post() + def cancel(self): + self.__api.cancel_post() + def is_idle(self) -> bool: status = self.__api.status_get() return status.state == 'Idle' diff --git a/gui/src/aaregui/main.py b/gui/src/aaregui/main.py index b54fbef1..e7a201ca 100644 --- a/gui/src/aaregui/main.py +++ b/gui/src/aaregui/main.py @@ -77,5 +77,5 @@ if __name__ == "__main__": win.show() sys.exit(app.exec()) else: - print("Cancelled") + print("Cannot connect to AareDAQ server. Exiting.") sys.exit() diff --git a/gui/src/aaregui/main_window.py b/gui/src/aaregui/main_window.py index 1992ffbc..d510d453 100644 --- a/gui/src/aaregui/main_window.py +++ b/gui/src/aaregui/main_window.py @@ -19,7 +19,6 @@ from aaredaqlib.sample_geometry import SampleGeometryModel from aaregui.panels.beamline_controls import BeamlineControls from aaregui.panels.data_collection_settings import DataCollectionSettings from aaregui.panels.sample_queue_panel import SampleQueuePanel -from aaregui.panels.status_panel import StatusPanel from aaregui.panels.tell_sample_panel import TellSamplePanel from aaregui.scan_logic.raster_grid_manager import RasterGridManager from aaregui.threads.camera_thread import SampleCameraThread @@ -101,7 +100,6 @@ class MainWindow(QMainWindow): self.tell_samples = TellSamplePanel(samples=SampleShortInfoList(s = [])) self.job_list_panel = SampleQueuePanel() - self.status_panel = StatusPanel() self.tell_samples_dock = QDockWidget("Sample List", self) self.tell_samples_dock.setWidget(self.tell_samples) @@ -113,11 +111,6 @@ class MainWindow(QMainWindow): self.job_list_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea) self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.job_list_dock) - self.status_panel_dock = QDockWidget("Beamline status", self) - self.status_panel_dock.setWidget(self.status_panel) - self.status_panel_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea) - self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.status_panel_dock) - self.setCentralWidget(top_widget) self.setWindowTitle("AareGUI") @@ -133,7 +126,6 @@ class MainWindow(QMainWindow): self.daq.update.connect(self.data_collection.update_daq_status) self.daq.update.connect(self.beamline.illumination_panel.update_daq_status) self.daq.update.connect(self.raster.update_daq_status) - self.daq.update.connect(self.status_panel.update_daq_status) self.daq.update.connect(self.camera_image.update_daq_status) self.daq.update.connect(self.tell_samples.update_daq_status) self.daq.update.connect(self.beamline.abr_tweak.update_daq_status) @@ -201,6 +193,7 @@ class MainWindow(QMainWindow): self.data_collection.raster.dtz_updated.connect(self.raster.update_dtz) self.data_collection.raster.grid_metric_updated.connect(self.raster.metric) self.data_collection.raster.raster_alpha_changed.connect(self.camera_image.raster_alpha) + self.data_collection.cancel.connect(self.daq.cancel) self.raster.grid_scan.connect(self.daq.raster_scan) self.data_collection.screening.rotation_scan.connect(self.daq.standard_scan) @@ -243,16 +236,6 @@ class MainWindow(QMainWindow): show_job_list_action.triggered.connect(lambda: self.job_list_dock.setVisible(show_job_list_action.isChecked())) view_menu.addAction(show_job_list_action) - show_beamline_status_action = QAction("Show beamline status", self) - show_beamline_status_action.setCheckable(True) - show_beamline_status_action.setChecked(True) - show_beamline_status_action.triggered.connect(self.status_panel_dock.setVisible) - # When dock visibility changes, update the action's checked state - show_beamline_status_action.triggered.connect(lambda: self.status_panel_dock.setVisible(show_beamline_status_action.isChecked())) - self.status_panel_dock.visibilityChanged.connect(show_beamline_status_action.setChecked) - - view_menu.addAction(show_beamline_status_action) - # Help menu help_menu = menu_bar.addMenu("Help") about_action = QAction("About", self) # Action for 'About' diff --git a/gui/src/aaregui/panels/data_collection_settings.py b/gui/src/aaregui/panels/data_collection_settings.py index b919f938..ec1b3dd5 100644 --- a/gui/src/aaregui/panels/data_collection_settings.py +++ b/gui/src/aaregui/panels/data_collection_settings.py @@ -21,9 +21,9 @@ from aaregui.widgets.title_label import TitleLabel class DataCollectionSettings(QFrame): - standard_data_collection = Signal(RotationScanRequest) - set_width = 400 + cancel = Signal() + set_width = 400 def __init__(self, s: SampleGeometryModel, raster_mgr: RasterGridManager, @@ -51,15 +51,20 @@ class DataCollectionSettings(QFrame): v_layout.addStretch() - self.abort_button = QPushButton("Abort measurement", parent=self) - self.abort_button.setStyleSheet("color: rgb(164, 0, 0);") - v_layout.addWidget(self.abort_button) + abort_button = QPushButton("Abort measurement", parent=self) + abort_button.setStyleSheet("color: rgb(164, 0, 0);") + abort_button.clicked.connect(self.cancel_button_clicked) + v_layout.addWidget(abort_button) raster_mgr.update_filename(self.file_path_panel.filename) self.screening.update_filename(self.file_path_panel.filename) self.file_path_panel.path_updated.connect(raster_mgr.update_filename) self.file_path_panel.path_updated.connect(self.screening.update_filename) + @Slot() + def cancel_button_clicked(self): + self.cancel.emit() + @Slot(DAQStatusModel) def update_daq_status(self, s: DAQStatusModel): self.raster.update_daq_status(s) diff --git a/gui/src/aaregui/panels/status_panel.py b/gui/src/aaregui/panels/status_panel.py index a00c4358..f37c3906 100644 --- a/gui/src/aaregui/panels/status_panel.py +++ b/gui/src/aaregui/panels/status_panel.py @@ -62,9 +62,13 @@ class StatusPanel(QFrame): self.beam_size.setText( f"{s.geom.beam_size_mm.x * 1000.0} x {s.geom.beam_size_mm.y * 1000.0}" ) - self.ring_current.setText(f"{s.bl.ring_current_mA:.1f}") - self.flux.setText(f"{(s.bl.flux_ph_s / 1e9):.2f}") + if s.bl.ring_current_mA < 390.0: + self.ring_current.setText(f"{s.bl.ring_current_mA:.1f}") + else: + self.ring_current.setText(f"{s.bl.ring_current_mA:.1f}") + + self.flux.setText(f"{(s.bl.flux_ph_s / 1e9):.2f}") if s.diffraction.wavelength_angstrom is None: self.wavelength.setText("N/A") else: diff --git a/gui/src/aaregui/scan_logic/raster_grid_manager.py b/gui/src/aaregui/scan_logic/raster_grid_manager.py index 428b39a3..bed0541b 100644 --- a/gui/src/aaregui/scan_logic/raster_grid_manager.py +++ b/gui/src/aaregui/scan_logic/raster_grid_manager.py @@ -86,7 +86,7 @@ class RasterGridManager(QObject): smargon = self.__geom.smargon, grid_size_mm=Coordinate(x=0.01, y=0.01), omega_deg=self.__geom.omega_deg, - exp_time_s=1.0, + exp_time_s=0.01, transmission=1.0, dtz=120.0 ) diff --git a/gui/src/aaregui/threads/daq_worker.py b/gui/src/aaregui/threads/daq_worker.py index 5761f6e8..ac14dfb4 100644 --- a/gui/src/aaregui/threads/daq_worker.py +++ b/gui/src/aaregui/threads/daq_worker.py @@ -302,3 +302,7 @@ class DAQWorker(QObject): @Slot(SampleShortInfo) def mount(self, s: SampleShortInfo): self.generic_post(f"tell/mount?dbid={s.db_id}") + + @Slot() + def cancel(self): + self.generic_post("scan/cancel") \ No newline at end of file diff --git a/gui/src/aaregui/widgets/status_bar.py b/gui/src/aaregui/widgets/status_bar.py index cbfd9dee..065c5679 100644 --- a/gui/src/aaregui/widgets/status_bar.py +++ b/gui/src/aaregui/widgets/status_bar.py @@ -4,6 +4,7 @@ from PySide6.QtWidgets import QStatusBar, QDialog, QMenu, QLabel from aaredaqlib.models import TokenData, BeamlineStateEnum, DAQStatusModel, SessionsStateEnum from aaregui.widgets.clickable_label import ClickableLabel from aaregui.widgets.pgroup_dialog import PGroupDialog +from aaregui.widgets.value_label import ValueLabel class StatusBar(QStatusBar): @@ -20,6 +21,10 @@ class StatusBar(QStatusBar): super().__init__(parent) self.__decoded_token = token + self.ring_current = ValueLabel("Ring current", "mA", self) + self.wvl = ValueLabel("Wavelength", "Å", self) + self.cryo_label = ValueLabel("Cryo", "K", self) + self.pgroup_label = ClickableLabel(self) self.pgroup_label.clicked.connect(self.show_pgroup_menu) @@ -34,6 +39,9 @@ class StatusBar(QStatusBar): self.shutter_label = ClickableLabel(parent=self) self.shutter_label.clicked.connect(self.show_shutter_menu) + self.addPermanentWidget(self.ring_current) + self.addPermanentWidget(self.wvl) + self.addPermanentWidget(self.cryo_label) self.addPermanentWidget(self.shutter_label) self.addPermanentWidget(self.pgroup_label) self.addPermanentWidget(self.pgroup_label) @@ -41,9 +49,24 @@ class StatusBar(QStatusBar): self.addPermanentWidget(self.busy_label) self.addPermanentWidget(self.session_label) - @Slot(DAQStatusModel) def update_daq_status(self, status: DAQStatusModel): + if status.bl.ring_current_mA < 5.0: + self.ring_current.set_value(f"{status.bl.ring_current_mA:.2f}", "red") + elif status.bl.ring_current_mA < 390.0: + self.ring_current.set_value(f"{status.bl.ring_current_mA:.2f}", "orange") + else: + self.ring_current.set_value(f"{status.bl.ring_current_mA:.2f}") + + self.wvl.set_value(f"{status.diffraction.wavelength_angstrom:.2f}") + + if status.bl.cryojet_K < 110.0: + self.cryo_label.set_value(f"{status.bl.cryojet_K:.1f}", "blue") + elif status.bl.cryojet_K < 250.0: + self.cryo_label.set_value(f"{status.bl.cryojet_K:.1f}", "orange") + else: + self.cryo_label.set_value(f"{status.bl.cryojet_K:.1f}", "red") + if status.bl.shutter_open: self.shutter_label.setText(f"""Shutter: Open ⬤ """) else: diff --git a/gui/src/aaregui/widgets/value_label.py b/gui/src/aaregui/widgets/value_label.py new file mode 100644 index 00000000..f9632961 --- /dev/null +++ b/gui/src/aaregui/widgets/value_label.py @@ -0,0 +1,22 @@ +from PySide6.QtCore import Signal, Qt +from PySide6.QtWidgets import QLabel + + +class ValueLabel(QLabel): + clicked = Signal() + def __init__(self, text: str, unit: str = "", parent=None): + super().__init__(parent) + self.__descr = text + self.__unit = unit + + def set_value(self, s: str, color: str | None = None): + if color is not None: + self.setText(f"""{self.__descr}: {s} {self.__unit} """) + else: + self.setText(f"{self.__descr}: {s} {self.__unit}") + + def mousePressEvent(self, event): + if event.button() == Qt.MouseButton.LeftButton: + self.clicked.emit() + else: + super().mousePressEvent(event) \ No newline at end of file