diff --git a/common/src/aaredaqlib/models.py b/common/src/aaredaqlib/models.py index 687e7ea3..6ec3874f 100644 --- a/common/src/aaredaqlib/models.py +++ b/common/src/aaredaqlib/models.py @@ -154,6 +154,7 @@ class BeamlineStatus(BaseModel): flux_ph_s: float sample_camera: SampleCameraSettings transmission: Annotated[float, Field(ge=0.0, le=1.0)] | None + zoom: float class SessionStatus(BaseModel): session: SessionsStateEnum = SessionsStateEnum.Vacant diff --git a/daq/src/aaredaq/config.py b/daq/src/aaredaq/config.py index 93dbb70b..18dfe3b2 100644 --- a/daq/src/aaredaq/config.py +++ b/daq/src/aaredaq/config.py @@ -168,6 +168,25 @@ class BeamlineConfig: self.__client.set(f"{self.__bl}:beam_center_x", data[0]) self.__client.set(f"{self.__bl}:beam_center_y", data[1]) + @property + def beam_size_mm(self) -> Coordinate: + tmp_x = self.__client.get(f"{self.__bl}:beam_size_x") + tmp_y = self.__client.get(f"{self.__bl}:beam_size_y") + if tmp_x: + val_x = float(tmp_x) + else: + val_x = 0.04 + if tmp_y: + val_y = float(tmp_y) + else: + val_y = 0.04 + return Coordinate(x=val_x, y=val_y) + + @beam_size_mm.setter + def beam_size_mm(self, data: Coordinate): + self.__client.set(f"{self.__bl}:beam_size_x", data.x) + self.__client.set(f"{self.__bl}:beam_size_y", data.y) + def __get_settings(self) -> BeamlineSettingsModel: tmp = self.__client.get(f"{self.__bl}:settings") if tmp is None: @@ -354,3 +373,4 @@ class BeamlineConfig: x_pxl = np.polyval(model.coeff_x, zoom) y_pxl = np.polyval(model.coeff_y, zoom) return float(x_pxl), float(y_pxl) + diff --git a/daq/src/aaredaq/daq.py b/daq/src/aaredaq/daq.py index f62b3a8a..5f4c6a62 100644 --- a/daq/src/aaredaq/daq.py +++ b/daq/src/aaredaq/daq.py @@ -272,7 +272,7 @@ class AareDAQ: 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) + result = self.__jfjoch.wait_till_done(60) return CompletedRasterGrid(request=copy.deepcopy(r), result=result) def measure_raster(self, r: RasterGridRequest) -> CompletedRasterGrid: @@ -431,7 +431,7 @@ class AareDAQ: pixel_in_mm=self.__cfg.pixel_to_mm(zoom), omega_deg=self.__devs.aerotech.omega, smargon=self.__devs.smargon.readback, - beam_size_mm=Coordinate(x=0.040, y=0.040), + beam_size_mm=self.__cfg.beam_size_mm, aerotech=Coordinate( x=self.__devs.gmx.value - abr_pos.x, y=self.__devs.gmy.value - abr_pos.y, @@ -448,6 +448,14 @@ class AareDAQ: def beam_center(self, val: Tuple[float, float]): self.__cfg.beam_center = val + @property + def beam_size_mm(self) -> Coordinate: + return self.__cfg.beam_size_mm + + @beam_size_mm.setter + def beam_size_mm(self, val: Coordinate): + self.__cfg.beam_size_mm = val + def get_beam_mark(self): return self.__cfg.get_beam_mark(self.__devs.zoom) @@ -778,7 +786,8 @@ class AareDAQ: flux_ph_s=3.0e12, sample_camera=self.__devs.samcam_settings, name=self.__bl, - transmission=self.__devs.transmission.get() + transmission=self.__devs.transmission.get(), + zoom=self.__devs.zoom ) @property diff --git a/daq/src/aaredaq/server.py b/daq/src/aaredaq/server.py index 7ebe80fb..3d98e30e 100644 --- a/daq/src/aaredaq/server.py +++ b/daq/src/aaredaq/server.py @@ -104,7 +104,7 @@ async def goto_abr_meas_pos(token: str = Depends(oauth2_scheme)): return "OK" @app.post("/beam_mark/add") -async def mark_beam_center(x: float, y: float, token: str = Depends(oauth2_scheme)): +async def mark_beam(x: float, y: float, token: str = Depends(oauth2_scheme)): auth.check_jwt_staff(auth.parse_token(token)) daq.mark_beam(x, y) return "OK" @@ -122,6 +122,12 @@ async def beam_center(x: float, y: float, token: str = Depends(oauth2_scheme)): daq.beam_center = (x, y) return "OK" +@app.post("/beamline/beam_size_mm") +async def beam_size_mm(x: float, y: float, token: str = Depends(oauth2_scheme)): + auth.check_jwt_staff(auth.parse_token(token)) + daq.beam_size_mm = Coordinate(x=x, y=y) + return "OK" + @app.put("/beamline/samcam") async def samcam_settings(s: SampleCameraSettings, token: str = Depends(oauth2_scheme)): auth.check_jwt_rw(cfg, auth.parse_token(token)) diff --git a/daq/src/aaredaq/workflows.py b/daq/src/aaredaq/workflows.py index 8b21ec54..50b06158 100644 --- a/daq/src/aaredaq/workflows.py +++ b/daq/src/aaredaq/workflows.py @@ -50,6 +50,7 @@ def wait_for_se_devices(devs: BeamlineDevices, cfg: BeamlineConfig): def common_2rse(devs: BeamlineDevices, cfg: BeamlineConfig): + devs.collimator_up = False devs.smargon.move_home(wait=True) devs.aerotech.move(ABR_OMEGA_MOUNT, wait=True, direct=True) devs.abr_pos = ABR_POS_MOUNT @@ -97,6 +98,7 @@ def sa2se(devs: BeamlineDevices, cfg: BeamlineConfig): if devs.cryo.position < _cryopark: devs.cryo.move(_cryopark) + devs.collimator_up = False devs.reflector_up = False devs.beamstop_stage_up = False devs.smargon.move_home(wait=True) diff --git a/gui/src/aaregui/main_window.py b/gui/src/aaregui/main_window.py index 0e0a637e..700613d0 100644 --- a/gui/src/aaregui/main_window.py +++ b/gui/src/aaregui/main_window.py @@ -125,6 +125,8 @@ class MainWindow(QMainWindow): self.daq.spreadsheet.connect(self.tell_samples.new_sample_list) self.daq.update.connect(self.beamline.omega_panel.update_daq_status) self.daq.update.connect(self.beamline.smargon_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.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) @@ -133,6 +135,8 @@ class MainWindow(QMainWindow): self.daq.update.connect(self.beamline.abr_tweak.update_daq_status) self.daq.update.connect(self.status_bar.update_daq_status) self.daq.update.connect(self.beamline.samcam.update_daq_status) + self.daq.update.connect(self.beamline.zoom_panel.update_daq_status) + self.daq.update.connect(self.beamline.beam_mark.update_daq_status) self.daq.raster_scan_completed.connect(self.raster.grid_scan_completed) @@ -152,8 +156,9 @@ class MainWindow(QMainWindow): self.beamline.abr_tweak.abr_goto_meas.connect(self.daq.abr_goto_meas) self.beamline.beam_mark.beam_mark_clear.connect(self.daq.beam_mark_clear) - self.camera_image.update_beam_center.connect(self.daq.beam_mark_add) + self.camera_image.update_beam_mark.connect(self.daq.beam_mark_add) self.beamline.beam_center.beam_center.connect(self.daq.beam_center) + self.beamline.beam_size.beam_size.connect(self.daq.beam_size_mm) if zmq_addr is not None: self.camera_thread = SampleCameraThread(zmq_url=zmq_addr) diff --git a/gui/src/aaregui/panels/beam_center_panel.py b/gui/src/aaregui/panels/beam_center_panel.py index 43cab0e5..3fd7c385 100644 --- a/gui/src/aaregui/panels/beam_center_panel.py +++ b/gui/src/aaregui/panels/beam_center_panel.py @@ -14,7 +14,7 @@ class BeamCenterWidget(QWidget): grid_layout = QGridLayout(self) - grid_layout.addWidget(TitleLabel("Beam center", self), 0, 0, 1, 5) + grid_layout.addWidget(TitleLabel("Beam center (detector)", self), 0, 0, 1, 5) self.x = NumberLineEdit(-4000, 4000, 0, parent=self) self.x.newValue.connect(self.beam_center_edited) @@ -30,8 +30,8 @@ class BeamCenterWidget(QWidget): @Slot(DAQStatusModel) def update_daq_status(self, s: DAQStatusModel): - self.x.update_value(s.diffraction.beam_center_x) - self.y.update_value(s.diffraction.beam_center_y) + self.x.update_value(s.diffraction.beam_center_pxl[0]) + self.y.update_value(s.diffraction.beam_center_pxl[1]) @Slot(float) def beam_center_edited(self, _: float): diff --git a/gui/src/aaregui/panels/beam_mark_panel.py b/gui/src/aaregui/panels/beam_mark_panel.py index ef8b47bb..aeb4ef46 100644 --- a/gui/src/aaregui/panels/beam_mark_panel.py +++ b/gui/src/aaregui/panels/beam_mark_panel.py @@ -1,6 +1,7 @@ from PySide6.QtCore import Signal, Slot -from PySide6.QtWidgets import QWidget, QGridLayout, QPushButton +from PySide6.QtWidgets import QWidget, QGridLayout, QPushButton, QLabel +from aaredaqlib.models import DAQStatusModel from aaregui.widgets.title_label import TitleLabel @@ -12,12 +13,26 @@ class BeamMarkWidget(QWidget): grid_layout = QGridLayout(self) - grid_layout.addWidget(TitleLabel("Beam mark (image)", self), 0, 0) + grid_layout.addWidget(TitleLabel("Beam mark (image)", self), 0, 0,1,5) + + self.x = QLabel("0") + self.y = QLabel("0") + + grid_layout.addWidget(QLabel("x:"), 1, 0) + grid_layout.addWidget(self.x, 1, 1) + grid_layout.addWidget(QLabel("y:"), 1, 2) + grid_layout.addWidget(self.y, 1, 3) + grid_layout.addWidget(QLabel("pxl"), 1, 4) clear_button = QPushButton("Clear marks") - grid_layout.addWidget(clear_button, 1, 0) + grid_layout.addWidget(clear_button, 2, 0,1,5) clear_button.pressed.connect(self.clear_button_pressed) @Slot() def clear_button_pressed(self): self.beam_mark_clear.emit() + + @Slot(DAQStatusModel) + def update_daq_status(self, s: DAQStatusModel): + self.x.setText(f"{s.geom.beam_location_pxl.x:.0f}") + self.y.setText(f"{s.geom.beam_location_pxl.y:.0f}") diff --git a/gui/src/aaregui/panels/beam_size_panel.py b/gui/src/aaregui/panels/beam_size_panel.py new file mode 100644 index 00000000..785399c7 --- /dev/null +++ b/gui/src/aaregui/panels/beam_size_panel.py @@ -0,0 +1,38 @@ +from PySide6.QtCore import Signal, Slot +from PySide6.QtWidgets import QWidget, QGridLayout, QLabel + +from aaredaqlib.models import DAQStatusModel +from aaregui.widgets.number_line_edit import NumberLineEdit +from aaregui.widgets.title_label import TitleLabel + + +class BeamSizeWidget(QWidget): + beam_size = Signal(float, float) + + def __init__(self, parent=None): + super().__init__(parent) + + grid_layout = QGridLayout(self) + + grid_layout.addWidget(TitleLabel("Beam size", self), 0, 0, 1, 5) + + self.x = NumberLineEdit(1, 40.0, 10, parent=self) + self.x.newValue.connect(self.beam_size_edited) + + self.y = NumberLineEdit(1, 40.0, 10, parent=self) + self.y.newValue.connect(self.beam_size_edited) + + grid_layout.addWidget(QLabel("x:"), 1, 0) + grid_layout.addWidget(self.x, 1, 1) + grid_layout.addWidget(QLabel("y:"), 1, 2) + grid_layout.addWidget(self.y, 1, 3) + grid_layout.addWidget(QLabel("μm"), 1, 4) + + @Slot(DAQStatusModel) + def update_daq_status(self, s: DAQStatusModel): + self.x.update_value(s.geom.beam_size_mm.x * 1000.0) + self.y.update_value(s.geom.beam_size_mm.y * 1000.0) + + @Slot(float) + def beam_size_edited(self, _: float): + self.beam_size.emit(self.x.value / 1000.0, self.y.value / 1000.0) diff --git a/gui/src/aaregui/panels/beamline_controls.py b/gui/src/aaregui/panels/beamline_controls.py index 85a4a3d3..eaba7adc 100644 --- a/gui/src/aaregui/panels/beamline_controls.py +++ b/gui/src/aaregui/panels/beamline_controls.py @@ -3,6 +3,7 @@ from PySide6.QtWidgets import QFrame, QVBoxLayout from aaregui.panels.abr_tweak_panel import AbrTweakWidget from aaregui.panels.beam_center_panel import BeamCenterWidget from aaregui.panels.beam_mark_panel import BeamMarkWidget +from aaregui.panels.beam_size_panel import BeamSizeWidget from aaregui.panels.beamline_state_panel import BeamlineStatePanel from aaregui.panels.illumination_panel import IlluminationPanel from aaregui.panels.loop_centering_panel import LoopCenteringPanel @@ -43,11 +44,13 @@ class BeamlineControls(QFrame): self.abr_tweak = AbrTweakWidget(self) self.beam_mark = BeamMarkWidget(self) self.beam_center = BeamCenterWidget(self) + self.beam_size = BeamSizeWidget(self) if staff: self.v_layout.addWidget(self.abr_tweak) self.v_layout.addWidget(self.beam_mark) self.v_layout.addWidget(self.beam_center) + self.v_layout.addWidget(self.beam_size) self.v_layout.addStretch() self.setLayout(self.v_layout) diff --git a/gui/src/aaregui/panels/file_path_panel.py b/gui/src/aaregui/panels/file_path_panel.py index ff53b828..ebf9e287 100644 --- a/gui/src/aaregui/panels/file_path_panel.py +++ b/gui/src/aaregui/panels/file_path_panel.py @@ -87,7 +87,7 @@ class FilePathPanel(QWidget): self.__filename = self.__filename.replace('{date}', self.__formatted_date) self.__filename = self.__filename.replace('{sample}', self.__sample_name) self.__filename = self.__filename.replace('{puck}', self.__puck_name) - self.__filename = self.__filename.replace('{pos}', f"{self.__puck_pos}") + self.__filename = self.__filename.replace('{pos}', f"{self.__puck_pos:02d}") self.__filename = self.__filename.replace('{sample_id}', f"{self.__sample_id}") self.file_name_label.setText(self.__filename + "_master.h5") @@ -126,15 +126,12 @@ class FilePathPanel(QWidget): self.__sample_name = "sample" self.__dewar_pos = "None" self.__puck_name = "Manual" - self.__puck_pos = 0 + self.__puck_pos = 99 else: self.__sample_name = status.sample.sample_name self.__dewar_pos = status.sample.loc_str() self.__puck_name = status.sample.puck_name - if status.sample.location is not None: - self.__puck_pos = status.sample.location.pos - else: - self.__puck_pos = 0 + self.__puck_pos = status.sample.pin self.update_filename() sample_id_old = self.__sample_id diff --git a/gui/src/aaregui/panels/zoom_panel.py b/gui/src/aaregui/panels/zoom_panel.py index eb602a5f..b99c3ef0 100644 --- a/gui/src/aaregui/panels/zoom_panel.py +++ b/gui/src/aaregui/panels/zoom_panel.py @@ -15,7 +15,7 @@ class ZoomPanel(QWidget): self.__zoom = 1.0 grid_layout = QGridLayout(self) - zoom_settings = [ + self.__zoom_settings = [ {"name": "1x", "value": 1}, {"name": "2.0x", "value": 280}, {"name": "3.5x", "value": 500}, @@ -25,11 +25,14 @@ class ZoomPanel(QWidget): ] grid_layout.addWidget(TitleLabel("Zoom", self), 0, 0, 1, 2) i = 2 - for z in zoom_settings: + + self.__buttons = [] + for z in self.__zoom_settings: button = ButtonWithPayload(z["name"], {"zoom": z["value"]}) grid_layout.addWidget(button, int(i / 2), int(i % 2)) i += 1 button.pressed.connect(self.set_zoom) + self.__buttons.append(button) @Slot(dict) def set_zoom(self, payload: dict): @@ -38,5 +41,11 @@ class ZoomPanel(QWidget): @Slot(DAQStatusModel) def update_daq_status(self, status: DAQStatusModel): - self.__zoom = status.geom.zoom_factor + self.__zoom = status.bl.zoom + for z in self.__zoom_settings: + + if z["value"] == self.__zoom: + self.__buttons[self.__zoom_settings.index(z)].setStyleSheet("font-weight: bold;") + else: + self.__buttons[self.__zoom_settings.index(z)].setStyleSheet("") diff --git a/gui/src/aaregui/threads/daq_worker.py b/gui/src/aaregui/threads/daq_worker.py index ac14dfb4..c7e2f803 100644 --- a/gui/src/aaregui/threads/daq_worker.py +++ b/gui/src/aaregui/threads/daq_worker.py @@ -295,6 +295,10 @@ class DAQWorker(QObject): def beam_center(self, x: float, y: float): self.generic_post(f"beamline/beam_center?x={x}&y={y}") + @Slot(float, float) + def beam_size_mm(self, x: float, y: float): + self.generic_post(f"beamline/beam_size_mm?x={x}&y={y}") + @Slot() def unmount(self): self.generic_post("tell/unmount") diff --git a/gui/src/aaregui/widgets/camera_image.py b/gui/src/aaregui/widgets/camera_image.py index e56d177c..4578696f 100644 --- a/gui/src/aaregui/widgets/camera_image.py +++ b/gui/src/aaregui/widgets/camera_image.py @@ -47,7 +47,7 @@ class SampleCameraImageLabel(QGraphicsView): set_omega = Signal(float) set_helical_start = Signal(SmargonCoordinate) set_helical_end = Signal(SmargonCoordinate) - update_beam_center = Signal(float, float) + update_beam_mark = Signal(float, float) autofocus = Signal(AutofocusSettings) samcam_updated = Signal(SampleCameraSettings) @@ -119,7 +119,7 @@ class SampleCameraImageLabel(QGraphicsView): match self.__state: case SampleCameraImageState.BEAM_MARKING: if event.button() == Qt.MouseButton.LeftButton: - self.update_beam_center.emit(self.start_point.x(), self.start_point.y()) + self.update_beam_mark.emit(self.start_point.x(), self.start_point.y()) case SampleCameraImageState.IDLE: self.click_timer.start(self.right_click_hold_threshold) if event.button() == Qt.MouseButton.RightButton: @@ -234,7 +234,7 @@ class SampleCameraImageLabel(QGraphicsView): z_steps=25)) elif action == beam_mark_action: c = self.mapToScene(event.pos()) - self.update_beam_center.emit(c.x(), c.y()) + self.update_beam_mark.emit(c.x(), c.y()) self.update() def __screenshot_with_dialog(self, overlay: bool):