From b0b655aea0355eb2441eaf1093534561f028e7a3 Mon Sep 17 00:00:00 2001 From: David Perl Date: Mon, 6 Jul 2026 10:45:15 +0200 Subject: [PATCH] feat: live changes 26-07-06 --- src/aare/daq/config_model.py | 20 ++++++++ src/aare/daq/daq.py | 8 ++++ src/aare/daq/operations/raster/service.py | 39 ++++++++++----- src/aare/gui/panels/local_contact_panel.py | 56 ++++++++++++++++++++++ src/aare/gui/threads/daq_worker.py | 6 ++- 5 files changed, 116 insertions(+), 13 deletions(-) diff --git a/src/aare/daq/config_model.py b/src/aare/daq/config_model.py index 0a9af8af..c8ec14a0 100644 --- a/src/aare/daq/config_model.py +++ b/src/aare/daq/config_model.py @@ -6,4 +6,24 @@ class LocalContactConfigModel(BaseModel): ge=0.0, le=120.0, description="Delay after mount and before loop centering, in seconds.", + ) + line_scan_loop_face_y_padding_fraction_each_side: float = Field( + default=0.5, + ge=0.0, + le=5.0, + description=( + "Second auto-center line-scan Y padding fraction per side when " + "the ML prediction is loop_face. 0.5 means add 50% of the detected " + "cell count above and below, making the scan 200% of the detected height." + ), + ) + line_scan_loop_all_y_padding_fraction_each_side: float = Field( + default=0.5, + ge=0.0, + le=5.0, + description=( + "Second auto-center line-scan Y padding fraction per side when " + "the ML prediction is loop_all. 0.5 means add 50% of the detected " + "cell count above and below." + ), ) \ No newline at end of file diff --git a/src/aare/daq/daq.py b/src/aare/daq/daq.py index c90df0c8..3fa09514 100644 --- a/src/aare/daq/daq.py +++ b/src/aare/daq/daq.py @@ -2758,7 +2758,15 @@ class AareDAQ: logger.info( f"Sleeping {mount_to_center_sleep_s:.2f}s between mount and loop centering" ) + sleep_started_at = time.monotonic() time.sleep(mount_to_center_sleep_s) + logger.info( + "Finished mount-to-center sleep", + extra={ + "requested_sleep_s": mount_to_center_sleep_s, + "actual_sleep_s": time.monotonic() - sleep_started_at, + }, + ) centered = False try: diff --git a/src/aare/daq/operations/raster/service.py b/src/aare/daq/operations/raster/service.py index 25fed126..bc915783 100644 --- a/src/aare/daq/operations/raster/service.py +++ b/src/aare/daq/operations/raster/service.py @@ -18,7 +18,7 @@ from aare.common.logger_events import ( sample_log_context, ) from aare.common.beamline import cfg_get -from aare.common.models import BeamlineStateEnum +from aare.common.models import BeamlineStateEnum, MLBoxType from aare.common.raster_grid import CompletedRasterGrid, CompletedRasterGridElem, RasterGridRequest, grid_to_image_id from aare.common.simulate_raster import generate_no_beam_scan_result from aare.daq.mlbox import MLBoxPredictionResult @@ -224,14 +224,14 @@ class RasterService: self.ctx.deps.devs.samcam_auto(AutoEnum.ONCE) def auto_center_line_scan_top_left( - self, - *, - omega_deg: float, - file_prefix: str | None, - grid_size_mm: Coordinate, - default_n_y: int = 50, - y_retarget_threshold_mm: float | None = None, - y_padding_fraction_each_side: float = 0.15, + self, + *, + omega_deg: float, + file_prefix: str | None, + grid_size_mm: Coordinate, + default_n_y: int = 50, + y_retarget_threshold_mm: float | None = None, + y_padding_fraction_each_side: float | None = None, ) -> tuple[SmargonCoordinate, int]: geom = self.ctx.sample_geometry beam_x_pxl = geom.beam_location_pxl.x @@ -254,6 +254,23 @@ class RasterService: target_point = prediction_result.target_point prediction_box = prediction_result.box + if y_padding_fraction_each_side is None: + local_contact_config = self.ctx.deps.cfg.local_contact_config + prediction_type = getattr(prediction_box, "type", None) + + if prediction_type == MLBoxType.LOOP_FACE: + y_padding_fraction_each_side = ( + local_contact_config.line_scan_loop_face_y_padding_fraction_each_side + ) + elif prediction_type == MLBoxType.LOOP_ALL: + y_padding_fraction_each_side = ( + local_contact_config.line_scan_loop_all_y_padding_fraction_each_side + ) + else: + y_padding_fraction_each_side = float( + cfg_get("daq.auto_raster.line_scan_y_padding_fraction", 0.15) + ) + if target_point is not None: target_y_pxl = target_point[1] y_delta_mm = abs(target_y_pxl - beam_y_pxl) * geom.pixel_in_mm @@ -325,6 +342,7 @@ class RasterService: "box_height_pxl": box_height_pxl, "pixel_in_mm": geom.pixel_in_mm, "grid_size_y_mm": grid_size_mm.y, + "prediction_type": str(getattr(prediction_box, "type", None)), "padding_fraction_each_side": y_padding_fraction_each_side, "padded_height_mm": padded_height_mm, "computed_n_y": n_y, @@ -802,9 +820,6 @@ class RasterService: geom.beam_size_mm.y * 2.0, grid.grid_size_mm.y * 4.0, ), - y_padding_fraction_each_side=float( - cfg_get("daq.auto_raster.line_scan_y_padding_fraction", 0.15) - ), ) self.logger.info( diff --git a/src/aare/gui/panels/local_contact_panel.py b/src/aare/gui/panels/local_contact_panel.py index f285d081..51921011 100644 --- a/src/aare/gui/panels/local_contact_panel.py +++ b/src/aare/gui/panels/local_contact_panel.py @@ -64,6 +64,8 @@ class LocalContactPanel(QFrame): self._bec_devices_dialog: TextListDialog | None = None self._local_contact_config_payload: dict = {} self._mount_to_center_sleep_s = QDoubleSpinBox(self) + self._line_scan_loop_face_y_padding_fraction_each_side = QDoubleSpinBox(self) + self._line_scan_loop_all_y_padding_fraction_each_side = QDoubleSpinBox(self) self.setFrameShape(QFrame.Shape.StyledPanel) self.setFrameShadow(QFrame.Shadow.Raised) @@ -149,6 +151,7 @@ class LocalContactPanel(QFrame): self._daq.load_local_contact_simulation_state() self._daq.load_local_contact_device_state() self._daq.load_local_contact_links() + self._daq.load_local_contact_config() def set_active_tab(self, tab_name: str) -> None: for index in range(self._tabs.count()): @@ -520,6 +523,31 @@ class LocalContactPanel(QFrame): form_layout.addWidget(label, 0, 0) form_layout.addWidget(self._mount_to_center_sleep_s, 0, 1) + loop_face_padding_label = QLabel("Line scan loop_face Y padding / side", form_box) + self._line_scan_loop_face_y_padding_fraction_each_side = QDoubleSpinBox(form_box) + self._line_scan_loop_face_y_padding_fraction_each_side.setRange(0.0, 5.0) + self._line_scan_loop_face_y_padding_fraction_each_side.setDecimals(2) + self._line_scan_loop_face_y_padding_fraction_each_side.setSingleStep(0.05) + self._line_scan_loop_face_y_padding_fraction_each_side.setToolTip( + "Second auto-center line-scan Y padding per side for loop_face. " + "0.50 means 50% above and 50% below, giving 200% total detected height." + ) + + loop_all_padding_label = QLabel("Line scan loop_all Y padding / side", form_box) + self._line_scan_loop_all_y_padding_fraction_each_side = QDoubleSpinBox(form_box) + self._line_scan_loop_all_y_padding_fraction_each_side.setRange(0.0, 5.0) + self._line_scan_loop_all_y_padding_fraction_each_side.setDecimals(2) + self._line_scan_loop_all_y_padding_fraction_each_side.setSingleStep(0.05) + self._line_scan_loop_all_y_padding_fraction_each_side.setToolTip( + "Second auto-center line-scan Y padding per side for loop_all. " + "0.50 means 50% above and 50% below." + ) + + form_layout.addWidget(loop_face_padding_label, 1, 0) + form_layout.addWidget(self._line_scan_loop_face_y_padding_fraction_each_side, 1, 1) + form_layout.addWidget(loop_all_padding_label, 2, 0) + form_layout.addWidget(self._line_scan_loop_all_y_padding_fraction_each_side, 2, 1) + button_row = QWidget(tab) button_layout = QHBoxLayout(button_row) button_layout.setContentsMargins(0, 0, 0, 0) @@ -709,10 +737,38 @@ class LocalContactPanel(QFrame): ) self._mount_to_center_sleep_s.blockSignals(False) + self._line_scan_loop_face_y_padding_fraction_each_side.blockSignals(True) + self._line_scan_loop_face_y_padding_fraction_each_side.setValue( + float( + self._local_contact_config_payload.get( + "line_scan_loop_face_y_padding_fraction_each_side", + 0.5, + ) + ) + ) + self._line_scan_loop_face_y_padding_fraction_each_side.blockSignals(False) + + self._line_scan_loop_all_y_padding_fraction_each_side.blockSignals(True) + self._line_scan_loop_all_y_padding_fraction_each_side.setValue( + float( + self._local_contact_config_payload.get( + "line_scan_loop_all_y_padding_fraction_each_side", + 0.5, + ) + ) + ) + self._line_scan_loop_all_y_padding_fraction_each_side.blockSignals(False) + @Slot() def _save_local_contact_config(self) -> None: payload = { "mount_to_center_sleep_s": float(self._mount_to_center_sleep_s.value()), + "line_scan_loop_face_y_padding_fraction_each_side": float( + self._line_scan_loop_face_y_padding_fraction_each_side.value() + ), + "line_scan_loop_all_y_padding_fraction_each_side": float( + self._line_scan_loop_all_y_padding_fraction_each_side.value() + ), } self._daq.set_local_contact_config(payload) diff --git a/src/aare/gui/threads/daq_worker.py b/src/aare/gui/threads/daq_worker.py index 970fff19..eb59c86a 100644 --- a/src/aare/gui/threads/daq_worker.py +++ b/src/aare/gui/threads/daq_worker.py @@ -1548,7 +1548,11 @@ class DAQWorker(QObject): @Slot() def load_local_contact_config(self): if self.__base_url is None: - self.local_contact_config_loaded.emit({"mount_to_center_sleep_s": 0.0}) + self.local_contact_config_loaded.emit({ + "mount_to_center_sleep_s": 0.0, + "line_scan_loop_face_y_padding_fraction_each_side": 0.5, + "line_scan_loop_all_y_padding_fraction_each_side": 0.5, + }) return request = QNetworkRequest(QUrl(f"{self.__base_url}/local_contact/config"))