From 53e941f4e46ae13ee7165b03fa506761797463dd Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 25 Nov 2025 14:46:39 +0100 Subject: [PATCH] DAQ/GUI: update to version 0.2.62 - changed how raster scan works so always relative to top left corner of grid. This is then corrected in the appropriate places and has been updated in the visualiser --- common/pyproject.toml | 2 +- common/src/aaredaqlib/find_xtal.py | 58 ++++++------ common/src/aaredaqlib/models.py | 42 ++++++++- common/src/aaredaqlib/raster_grid.py | 9 +- common/src/aaredaqlib/sample_geometry.py | 5 ++ daq/pyproject.toml | 4 +- daq/src/aaredaq/aaredb.py | 54 ++++++----- daq/src/aaredaq/daq.py | 89 ++++++++++--------- gui/pyproject.toml | 4 +- gui/src/aaregui/panels/sample_queue_panel.py | 33 +++++-- .../aaregui/scan_logic/raster_grid_manager.py | 46 +++++----- gui/src/aaregui/widgets/raster_grid_table.py | 4 +- 12 files changed, 203 insertions(+), 147 deletions(-) diff --git a/common/pyproject.toml b/common/pyproject.toml index 3eccbb24..cb0f8ed4 100644 --- a/common/pyproject.toml +++ b/common/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "aaredaqlib" -version = "0.2.61" +version = "0.2.62" description = "Libraries shared between AareDAQ and AareGUI" readme = "README.md" requires-python = ">=3.11" diff --git a/common/src/aaredaqlib/find_xtal.py b/common/src/aaredaqlib/find_xtal.py index 31a6f685..3034d3e1 100644 --- a/common/src/aaredaqlib/find_xtal.py +++ b/common/src/aaredaqlib/find_xtal.py @@ -3,15 +3,16 @@ from typing import List, Optional, Callable import numpy as np from scipy import ndimage -from aaredaqlib.models import CrystalSize +from aaredaqlib.coordinate import Coordinate +from aaredaqlib.models import CrystalSize, CenterOfMassModel from aaredaqlib.raster_grid import RasterGridRequest from aaredaqlib.logger_config import setup_logger logger = setup_logger('aareDAQ') -def identify_crystal_raster(result, r: RasterGridRequest): +def identify_crystal_raster(result, r: RasterGridRequest) -> CenterOfMassModel | None: images = result.images - # if images and any(getattr(img, "spots", 0) for img in images): + if images and any(getattr(img, "spots", 0) for img in images): # # indexed_images = [img for img in images if img.index and img.spots_low_res > 4 and img.bkg > 4.5] # @@ -35,18 +36,21 @@ def identify_crystal_raster(result, r: RasterGridRequest): # logger.debug(f"Maximum spots_indexed value: {max_image.spots_indexed}") # logger.debug(f"Maximum spots_low_res value: {max_image.spots_low_res}") # else: - logger.debug(f"Find image by maximum number of low resolution spots") - max_image = max(images, key=lambda img: img.spots_low_res) - logger.debug(f"Image with maximum spots_low_res: {max_image}") - logger.debug(f"Maximum spots_low_res value: {max_image.spots_low_res}") - logger.debug(f"Maximum image found at grid coordiantes {max_image.nx}, {max_image.ny}") - logger.debug(f"Maximum image found at umL {max_image.nx * r.grid_size_mm.x}, {max_image.ny * r.grid_size_mm.y}") + logger.debug(f"Find image by maximum number of low resolution spots") + max_image = max(images, key=lambda img: img.spots_low_res) + logger.debug(f"Image with maximum spots_low_res: {max_image}") + logger.debug(f"Maximum spots_low_res value: {max_image.spots_low_res}") + logger.debug(f"Maximum image found at grid coordiantes {max_image.nx}, {max_image.ny}") + logger.debug(f"Maximum image found at umL {max_image.nx * r.grid_size_mm.x}, {max_image.ny * r.grid_size_mm.y}") + com = CenterOfMassModel(n_x=max_image.n_x, n_y=max_image.n_y) + com_mm = com.get_com_mm(r) + grid_mm_x = com_mm.x + grid_mm_y = com_mm.y - grid_mm_x = (max_image.nx+0.5) * r.grid_size_mm.x - grid_mm_y = (max_image.ny+0.5) * r.grid_size_mm.y - - logger.debug(f"Grid coordinates in mm: ({grid_mm_x}, {grid_mm_y})") - return grid_mm_x, grid_mm_y + logger.debug(f"Grid coordinates in mm: x={grid_mm_x}, y={grid_mm_y}") + return com + else: + return None def rebuild_array_from_scan_results(scan_results: List, value_field: str, @@ -254,7 +258,7 @@ def get_best_res(result_list: List): return best_res.res def com_nan_check(com): - if np.isnan(com[0]) or np.isnan(com[1]): + if np.isnan(com.n_x) or np.isnan(com.n_y): return False else: return True @@ -276,23 +280,15 @@ def get_com_image_number(com, images): logger.info(f"com found for image: {image.number}") return -def get_grid_mm_from_com(com, r:RasterGridRequest): - if not com_nan_check(com): - grid_mm_x = None - grid_mm_y = None - else: - grid_mm_x = com[0] * r.grid_size_mm.x - grid_mm_y = com[1] * r.grid_size_mm.y - if r.n_x == 1: - grid_mm_x += (0.5 * r.grid_size_mm.x) - else: - grid_mm_y += (0.5 * r.grid_size_mm.y) - return grid_mm_x, grid_mm_y -def raster_centre_of_mass(result_array, r:RasterGridRequest): +def raster_centre_of_mass(result_array, r:RasterGridRequest) -> CenterOfMassModel | None: + # grid_mm_x and grid_mm_y are relative to the top left corner of raster grid com = ndimage.center_of_mass(result_array) - logger.info(f"Center of mass: {com}") - grid_mm_x, grid_mm_y = get_grid_mm_from_com(com, r) - return grid_mm_x, grid_mm_y, com + if com or not com_nan_check(com): + logger.info(f"Center of mass: {com}") + return CenterOfMassModel(n_x=com[0], n_y=com[1]) + else: + logger.warning("No valid center of mass found") + return None diff --git a/common/src/aaredaqlib/models.py b/common/src/aaredaqlib/models.py index 3ecd862f..f77e9162 100644 --- a/common/src/aaredaqlib/models.py +++ b/common/src/aaredaqlib/models.py @@ -3,11 +3,14 @@ import re from enum import Enum from typing import Annotated, Literal, Tuple, List, Optional -from pydantic import BaseModel, Field, field_validator +import numpy as np +from pydantic import BaseModel, Field, field_validator, AfterValidator -from aaredaqlib.coordinate import Coordinate +from aaredaqlib.coordinate import Coordinate, positive_coords from aaredaqlib.diffraction_geometry import DiffractionGeometry +from aaredaqlib.raster_grid import RasterGridRequest from aaredaqlib.sample_geometry import SampleGeometryModel +from jfjoch_client.models.scan_result import ScanResult from aaredaqlib.beamline import MXBeamline @@ -776,4 +779,37 @@ class SimpleScanParameters(BaseModel): beam_size_y_um: float | None = None dose_rate_MGy_s: float | None = None d_vis: float | None = None - d_tar: float | None = None \ No newline at end of file + d_tar: float | None = None + +class RasterPayloadModel(BaseModel): + request: RasterGridRequest + result: ScanResult + sample_id: int + attach_image: bool = True + center_pxl: Coordinate | None + start_pxl: Coordinate + cell_size_pxl: Annotated[Coordinate, AfterValidator(positive_coords)] + +class CenterOfMassModel(BaseModel): + n_x: float + n_y: float + + @classmethod + def model_validate_maybe(cls, n_x: float, n_y: float) -> "CenterOfMassModel | None": + # Return None if either coordinate is NaN + if np.isnan(n_x) or np.isnan(n_y): + return None + return cls(n_x=float(n_x), n_y=float(n_y)) + + def get_com_mm(self, r:RasterGridRequest) -> Coordinate: + #defines COM in mm at beam position, relative to the top left corner of grid + return Coordinate(x=(self.n_x+0.5)*r.grid_size_mm.x, y=(self.n_y+0.5)*r.grid_size_mm.y) + + def get_com_pxl(self, r:RasterGridRequest, geom:SampleGeometryModel) -> Coordinate: + #defines COM in pixels at beam position, relative to the top left corner of grid + com_mm = self.get_com_mm(r) + return Coordinate(x=com_mm.x/geom.pixel_in_mm, y=com_mm.y/geom.pixel_in_mm) + + def com_nan_check(self): + # True if both values are finite (not NaN) + return not (np.isnan(self.n_x) or np.isnan(self.n_y)) \ No newline at end of file diff --git a/common/src/aaredaqlib/raster_grid.py b/common/src/aaredaqlib/raster_grid.py index 993fa1e5..7fc93c41 100644 --- a/common/src/aaredaqlib/raster_grid.py +++ b/common/src/aaredaqlib/raster_grid.py @@ -20,8 +20,9 @@ class RasterGridRequest(BaseModel): # Size of grid elements grid_size_mm: Annotated[Coordinate, AfterValidator(positive_coords)] - # Coordinates of top left corner in Smargon (SH...) coordinates - smargon: SmargonCoordinate + # Coordinates of top left corner in Smargon (SH...) coordinates. + # If None, measure from the current position. + smargon_top_left: SmargonCoordinate | None # omega angle omega_deg: float = 0.0 @@ -35,7 +36,9 @@ class RasterGridRequest(BaseModel): return self.grid_size_mm / geom.pixel_in_mm def start_pxl(self, geom: SampleGeometryModel) -> Coordinate: - return geom.smargon_to_beamline(self.smargon.sh_mm) + if self.smargon_top_left is None: + return geom.smargon_to_beamline(geom.smargon.sh_mm) + return geom.smargon_to_beamline(self.smargon_top_left.sh_mm) class CompletedRasterGridElem(BaseModel): request: RasterGridRequest diff --git a/common/src/aaredaqlib/sample_geometry.py b/common/src/aaredaqlib/sample_geometry.py index e733c6e2..2e27d56b 100644 --- a/common/src/aaredaqlib/sample_geometry.py +++ b/common/src/aaredaqlib/sample_geometry.py @@ -44,6 +44,11 @@ class SampleGeometryModel(BaseModel): beam_pxl = (beam_mm - self.aerotech) / self.pixel_in_mm return beam_pxl + self.beam_location_pxl + def translate_smargon(self, coord: Coordinate) -> SmargonCoordinate: + return SmargonCoordinate(sh_mm=self.smargon.sh_mm + self.smargon_nudge(coord), + phi_deg=self.smargon.phi_deg, + chi_deg=self.smargon.chi_deg) + def smargon_nudge(self, coord: Coordinate) -> Coordinate: phi = np.radians(np.around(self.smargon.phi_deg, decimals=1)) chi = np.radians(np.around(self.smargon.chi_deg, decimals=1)) diff --git a/daq/pyproject.toml b/daq/pyproject.toml index dbdc7386..5c95a186 100644 --- a/daq/pyproject.toml +++ b/daq/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "aaredaq" -version = "0.2.61" +version = "0.2.62" description = "AareDAQ data acquisition server" readme = "README.md" requires-python = ">=3.11" @@ -18,7 +18,7 @@ dependencies = [ "python_multipart==0.0.20", "websocket-client==1.8.0", "sseclient-py==1.8.0", - "aaredaqlib==0.2.4", + "aaredaqlib==0.2.62", ] [lint] diff --git a/daq/src/aaredaq/aaredb.py b/daq/src/aaredaq/aaredb.py index b0a18e78..77ac67b7 100644 --- a/daq/src/aaredaq/aaredb.py +++ b/daq/src/aaredaq/aaredb.py @@ -21,6 +21,7 @@ from aareDBclient import ( BeamlineParametersInput, ExperimentParametersCreate) +from aaredaqlib.coordinate import Coordinate from aaredaqlib.diffraction_geometry import DiffractionGeometry from aaredaqlib.logger_config import setup_logger from aaredaqlib.models import ( @@ -28,7 +29,7 @@ from aaredaqlib.models import ( PuckLoadedInfo, DewarAddress, SampleShortInfoList, - DAQStatusModel, SessionStatus, + DAQStatusModel, SessionStatus, RasterPayloadModel, CenterOfMassModel, ) from aaredaqlib.beamline import MXBeamline @@ -339,28 +340,13 @@ class AareWrapper: except Exception as e: print(e) - def _create_default_geometry(self): - """Create default geometry configuration for raster grid ingestion.""" - return { - 'beam_location_pxl': {'x': 512, 'y': 384, 'z': 0}, - 'pixel_in_mm': 0.01, - 'aerotech': {'x': 0, 'y': 0, 'z': 0}, - 'aerotech_meas': {'x': 0, 'y': 0, 'z': 0}, - 'smargon': { - 'sh_mm': {'x': 0, 'y': 0, 'z': 0}, - 'phi_deg': 0, - 'chi_deg': 0 - }, - 'omega_deg': 0, - 'beam_size_mm': {'x': 0.02, 'y': 0.02, 'z': 0}, - } + def ingest_gridscan(self, sample: Optional[SampleShortInfo], raster_result: ScanResult, + raster_request: RasterGridRequest, geom: SampleGeometryModel, com: Optional[CenterOfMassModel]): - def ingest_gridscan(self, s: Optional[SampleShortInfo], raster_result: ScanResult, r: RasterGridRequest): - - if s is None: + if sample is None: return - payload = self.format_gridscan_payload(s, raster_result, r) + payload = self.format_gridscan_payload(sample, raster_result, raster_request, geom, com).model_dump() if payload is None: return @@ -378,19 +364,29 @@ class AareWrapper: print(f"Response status code: {response.status_code}") - def format_gridscan_payload(self, s: Optional[SampleShortInfo], raster_result:ScanResult, r:RasterGridRequest): + def format_gridscan_payload(self, sample: Optional[SampleShortInfo], raster_result:ScanResult, + raster_request:RasterGridRequest, geom:SampleGeometryModel, + com: Optional[CenterOfMassModel]) -> RasterPayloadModel|None: try: - geometry = self._create_default_geometry() + if com: + center_pxl = com.get_com_pxl(raster_request, geom) + else: + center_pxl = None - payload = { - "request": r.model_dump(), # RasterGridRequest as dict - "result": raster_result.model_dump(), # ScanResult as dict - "geometry": geometry, # SampleGeometryModel as dict - "sample_id": s.db_id, - "attach_image": True, - } + cell_size_pxl = Coordinate(x=raster_request.grid_size_mm.x/geom.pixel_in_mm, + y=raster_request.grid_size_mm.y/geom.pixel_in_mm) + + payload = RasterPayloadModel( + request = raster_request, + result = raster_result, + sample_id = sample.db_id, + attach_image = True, + start_pxl = raster_request.start_pxl(geom), + center_pxl = center_pxl, + cell_size_pxl = cell_size_pxl + ) return payload diff --git a/daq/src/aaredaq/daq.py b/daq/src/aaredaq/daq.py index 6b2a5e87..136d0f2f 100644 --- a/daq/src/aaredaq/daq.py +++ b/daq/src/aaredaq/daq.py @@ -468,7 +468,7 @@ class AareDAQ: if r is not None: geom = self.sample_geometry - grid.smargon = r.smargon + grid.smargon_top_left = r.smargon_top_left grid.grid_size_mm = r.grid_size_mm grid.n_x = r.n_x grid.n_y = r.n_y @@ -488,9 +488,11 @@ class AareDAQ: grid.n_y = 50 grid.file_prefix = f"{old_prefix}_{grid.omega_deg}deg" grid.grid_size_mm = Coordinate(x=geom.beam_size_mm.x, y=geom.beam_size_mm.y * 0.25) - offset = Coordinate(x=0, y=-grid.n_y * grid.grid_size_mm.y / 2.0) + offset = Coordinate(x=-grid.grid_size_mm.x/2.0, y=-(grid.n_y + 0.5) * grid.grid_size_mm.y / 2.0) geom = self.sample_geometry - grid.smargon.sh_mm = geom.smargon.sh_mm + geom.smargon_nudge(offset) + logger.debug(f"set offset y scan {offset}") + # self.__devs.smargon.target = geom.translate_smargon(offset) + grid.smargon_top_left = geom.translate_smargon(offset) res2 = self.__raster(grid) self.__devs.reflector_up = True time.sleep(0.1) @@ -502,7 +504,7 @@ class AareDAQ: return None - def __raster(self, r: RasterGridRequest, corner_coord: bool) -> CompletedRasterGridElem: + def __raster(self, r: RasterGridRequest) -> CompletedRasterGridElem: max_time = r.exp_time_s * r.n_y * r.n_x + 60 if r.dtz is not None: @@ -511,12 +513,12 @@ class AareDAQ: self.__set_state(BeamlineStateEnum.DataCollection) save_smargon_position = self.__devs.smargon.readback + if r.smargon_top_left is not None: + delta_mm = self.sample_geometry.smargon_nudge(Coordinate(x=r.grid_size_mm.x / 2, y=r.grid_size_mm.y / 2)) - delta_mm = self.sample_geometry.smargon_nudge(Coordinate(x=r.grid_size_mm.x / 2, y=r.grid_size_mm.y / 2)) - - self.__devs.smargon.target = SmargonCoordinate(sh_mm=r.smargon.sh_mm + delta_mm, - phi_deg=r.smargon.phi_deg, - chi_deg=r.smargon.chi_deg) + self.__devs.smargon.target = SmargonCoordinate(sh_mm=r.smargon_top_left.sh_mm + delta_mm, + phi_deg=r.smargon_top_left.phi_deg, + chi_deg=r.smargon_top_left.chi_deg) if r.transmission is not None: self.__devs.transmission.set(r.transmission, wait=False) self.__devs.aerotech.move(r.omega_deg, wait=True, speed=360.0) @@ -543,59 +545,58 @@ class AareDAQ: self.__devs.abr_pos = self.__cfg.abr_meas_pos result = self.__jfjoch.wait_till_done(60) - if self.sample is not None and self.sample.db_id is not None and result is not None: - try: - self.__aare.ingest_gridscan(self.sample, result, r) - except Exception as e: - logger.error(f"Exception ingesting grid scan: {e}") - images = result.images - output_data = { - 'timestamp': time.ctime(), - 'scan_results': [image.model_dump() for image in images], - 'total_results': len([image for image in images]) - } - if self.sample is not None and self.sample.db_id is not None: - if r.n_x == 1: - filename=f'/sls/MX/applications/raster_results/{self.sample.db_id}_scan_results_vertical.json' - else: - filename=f'/sls/MX/applications/raster_results/{self.sample.db_id}_scan_results_horizontal.json' - with open(filename, 'w') as f: - json.dump(output_data, f, indent=2) result_array = create_quality_filtered_array(images, 'spots_low_res', min_spots=None, min_efficiency=1.0, min_background=None, min_low_res_spots=None) self.__cfg.crystal_size = get_xtal_size(self.__cfg.crystal_size, result_array, r) - grid_mm_x, grid_mm_y, com = raster_centre_of_mass(result_array, r) - - if grid_mm_x is None or grid_mm_y is None or com is None: + com = raster_centre_of_mass(result_array, r) + if com is None: logger.debug(f"using old method as COM is disabled") - grid_mm_x, grid_mm_y = identify_crystal_raster(result, r) + com = identify_crystal_raster(result, r) + if com: + com_mm = com.get_com_mm(r) + grid_mm_x = com_mm.x + grid_mm_y = com_mm.y + else: + grid_mm_x = None + grid_mm_y = None if grid_mm_x or grid_mm_y: - if r.n_x == 1: - new_delta_mm = self.sample_geometry.smargon_nudge(Coordinate(x=grid_mm_x, y=grid_mm_y)) + new_delta_mm = self.sample_geometry.smargon_nudge(Coordinate(x=grid_mm_x, y=grid_mm_y)) - else: + if r.n_x != 1: result_list = get_result_list_from_com(images, com) self.__cfg.last_best_b_factor = get_best_b_factor(result_list) self.__cfg.last_best_res = get_best_res(result_list) logger.debug(f"b_factor: {self.__cfg.last_best_b_factor}, best_res: {self.__cfg.last_best_res}") - new_delta_mm = self.sample_geometry.smargon_nudge(Coordinate(x=grid_mm_x, y=grid_mm_y)) else: new_delta_mm = None if new_delta_mm is not None: - logger.debug(f'{time.ctime()}, moving SMARGON to target new delta mm {r.smargon.sh_mm + new_delta_mm} mm') - self.__devs.smargon.target = SmargonCoordinate(sh_mm=r.smargon.sh_mm + new_delta_mm, - phi_deg=r.smargon.phi_deg, - chi_deg=r.smargon.chi_deg) + if r.smargon_top_left: + new_target = r.smargon_top_left + else: + new_target = save_smargon_position + + logger.debug(f'moving SMARGON to target new delta mm {new_target.sh_mm + new_delta_mm} mm') + self.__devs.smargon.target = SmargonCoordinate(sh_mm=new_target.sh_mm + new_delta_mm, + phi_deg=new_target.phi_deg, + chi_deg=new_target.chi_deg) else: logger.error("Auto finding optimal image failed due to no images found. Using previous position.") self.__devs.smargon.target = save_smargon_position + if self.sample is not None and self.sample.db_id is not None and result is not None: + try: + self.__aare.ingest_gridscan(sample = self.sample, raster_result =result, + raster_request = r, geom = self.sample_geometry, + com = com) + except Exception as e: + logger.error(f"Exception ingesting grid scan: {e}") + return CompletedRasterGridElem(request=copy.deepcopy(r), result=result) def measure_raster(self, r: RasterGridRequest, auto: bool) -> CompletedRasterGrid: @@ -604,7 +605,7 @@ class AareDAQ: if auto: result = self.__auto_center(r) else: - raster_result = self.__raster(r, True) + raster_result = self.__raster(r) result = CompletedRasterGrid(r=[raster_result]) self.__devs.reflector_up = True time.sleep(0.1) @@ -878,7 +879,7 @@ class AareDAQ: return RasterGridRequest( exp_time_s=0.02, transmission=1.0, - smargon= SmargonCoordinate(chi_deg = geom.smargon.chi_deg, + smargon_top_left = SmargonCoordinate(chi_deg = geom.smargon.chi_deg, phi_deg= geom.smargon.phi_deg, sh_mm=start_coord), n_x=n_x, @@ -1354,7 +1355,7 @@ class AareDAQ: if self.__auto_center(RasterGridRequest( exp_time_s=raster_params.exp_time_s, file_prefix=sample_prefix + f"_{hex_string}", - smargon= SmargonCoordinate(), + smargon_top_left= SmargonCoordinate(), n_x=1, n_y=1, dtz=raster_params.dtz, @@ -1383,14 +1384,14 @@ class AareDAQ: )) logger.info(f"rotation done at {time.perf_counter() - start}") else: - print("auto center failed") + logger.error("auto center failed") self.__aare.axc_failed(sample) self.zoom = 1 self.__cfg.zoom_mode = ZoomModeEnum.User self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom) self.__cfg.state_busy = False except Exception as e: - print(f"Error in measure: {e}") + logger.error(f"Error in measure: {e}") self.__aare.sample_failed(sample) self.__cfg.state_busy = False end = time.perf_counter() diff --git a/gui/pyproject.toml b/gui/pyproject.toml index ba482fa4..9fe4f224 100644 --- a/gui/pyproject.toml +++ b/gui/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "aaregui" -version = "0.2.4" +version = "0.2.62" description = "Beamline control GUI" readme = "README.md" requires-python = ">=3.11" @@ -9,7 +9,7 @@ dependencies = [ "pyzmq==26.4.0", "opencv-python-headless==4.11.0.86", "PySide6==6.9.0", - "aaredaqlib==0.2.4" + "aaredaqlib==0.2.62" ] [lint] diff --git a/gui/src/aaregui/panels/sample_queue_panel.py b/gui/src/aaregui/panels/sample_queue_panel.py index da124499..30c590ee 100644 --- a/gui/src/aaregui/panels/sample_queue_panel.py +++ b/gui/src/aaregui/panels/sample_queue_panel.py @@ -1,6 +1,6 @@ from PySide6.QtCore import Signal, Slot, Qt from PySide6.QtWidgets import QFrame, QVBoxLayout, QHBoxLayout, QPushButton, QHeaderView, QSizePolicy, \ - QTableView + QTableView, QMessageBox from PySide6.QtGui import QKeySequence, QShortcut from aaredaqlib.models import SampleShortInfoList, SampleShortInfo @@ -92,8 +92,29 @@ class SampleQueuePanel(QFrame): sample = self.table_model.samples[row] self.table_model.remove_sample(sample.db_id) + def __ring_current_low_check(self) -> bool: + if self.ring_current is not None and self.ring_current < 100: + logger.debug(f"Ring current too low {self.ring_current}") + self.table_model.set_running(False) + self.set_to_pause = True + self.__pause = True + self.play_button.setText("▶ Run") + reply = QMessageBox.question(self, "Ring current too low", f"Ring current is too low: {self.ring_current} mA. Do you wish to continue?", + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No) + if reply == QMessageBox.StandardButton.Yes: + return True + else: + return False + logger.debug(f"Ring current: {self.ring_current}") + return True + def run(self): - if self.__pause: + if not self.__ring_current_low_check(): + logger.debug("low ring current, skipping") + return + + elif self.__pause: if len(self.table_model.samples) > 0: self.table_model.set_running(True) self.__set_to_pause = False @@ -120,11 +141,9 @@ class SampleQueuePanel(QFrame): if self._current_db_id is not None and db_id != self._current_db_id: return - if self.ring_current is not None and self.ring_current < 100: - self.table_model.set_running(False) - self.__pause = True - self.play_button.setText("▶ Run") - + if not self.__ring_current_low_check(): + self.unmount.emit() + return if success: self.table_model.remove_sample(db_id) diff --git a/gui/src/aaregui/scan_logic/raster_grid_manager.py b/gui/src/aaregui/scan_logic/raster_grid_manager.py index d0cf7aeb..85392b4b 100644 --- a/gui/src/aaregui/scan_logic/raster_grid_manager.py +++ b/gui/src/aaregui/scan_logic/raster_grid_manager.py @@ -104,7 +104,7 @@ class RasterGridManager(QObject): self.__active_grid : RasterGridRequest = RasterGridRequest( n_x= 0, n_y= 0, - smargon = self.__geom.smargon, + smargon_top_left = self.__geom.smargon, grid_size_mm=Coordinate(x= 0.8 * self.__beam_size_mm.x, y= 0.8 * self.__beam_size_mm.y), omega_deg=self.__geom.omega_deg, @@ -122,8 +122,8 @@ class RasterGridManager(QObject): if ( grid.visible and abs(normalize_angle(grid.omega_deg - self.__geom.omega_deg)) < 0.2 - and abs(grid.smargon.phi_deg - self.__geom.smargon.phi_deg) < 0.2 - and abs(grid.smargon.chi_deg - self.__geom.smargon.chi_deg) < 0.2 + and abs(grid.smargon_top_left.phi_deg - self.__geom.smargon.phi_deg) < 0.2 + and abs(grid.smargon_top_left.chi_deg - self.__geom.smargon.chi_deg) < 0.2 and grid.n_x > 0 and grid.n_y > 0 ): @@ -132,7 +132,7 @@ class RasterGridManager(QObject): @Slot(RasterGridRequest) def update_active_grid_request(self, grid: RasterGridRequest): - self.__active_grid.smargon = grid.smargon + self.__active_grid.smargon_top_left = grid.smargon_top_left self.__active_grid.omega_deg = grid.omega_deg self.__active_grid.grid_size_mm = grid.grid_size_mm self.__active_grid.n_x = grid.n_x @@ -176,7 +176,7 @@ class RasterGridManager(QObject): else: self.__start_point = start - self.__active_grid.smargon = SmargonCoordinate( + self.__active_grid.smargon_top_left = SmargonCoordinate( sh_mm=self.__geom.beamline_to_smargon(c), phi_deg=self.__geom.smargon.phi_deg, chi_deg=self.__geom.smargon.chi_deg, @@ -196,8 +196,8 @@ class RasterGridManager(QObject): delta_mm = self.__geom.smargon_nudge(delta_pxl * self.__geom.pixel_in_mm) - self.__active_grid.smargon = SmargonCoordinate( - sh_mm=self.__active_grid.smargon.sh_mm + delta_mm, + self.__active_grid.smargon_top_left = SmargonCoordinate( + sh_mm=self.__active_grid.smargon_top_left.sh_mm + delta_mm, phi_deg=self.__geom.smargon.phi_deg, chi_deg=self.__geom.smargon.chi_deg, ) @@ -213,7 +213,7 @@ class RasterGridManager(QObject): def get_grid_coord(self, grid: RasterGridRequest, point: QPointF) -> Tuple[int, int]: point_bl = self.__geom.picture_to_sample(Coordinate(x=point.x(), y=point.y())) - delta = point_bl - self.__geom.smargon_to_beamline(grid.smargon.sh_mm) + delta = point_bl - self.__geom.smargon_to_beamline(grid.smargon_top_left.sh_mm) elem_x = grid.grid_size_mm.x elem_y = grid.grid_size_mm.y @@ -247,7 +247,7 @@ class RasterGridManager(QObject): return False point_bl = self.__geom.picture_to_sample(Coordinate(x=point.x(), y=point.y())) - delta = point_bl - self.__geom.smargon_to_beamline(self.__active_grid.smargon.sh_mm) + delta = point_bl - self.__geom.smargon_to_beamline(self.__active_grid.smargon_top_left.sh_mm) return (0 <= delta.x < self.__active_grid.n_x * self.__active_grid.grid_size_mm.x) and ( 0 <= delta.y < self.__active_grid.n_y * self.__active_grid.grid_size_mm.y ) @@ -319,10 +319,10 @@ class RasterGridManager(QObject): n_x=ag.n_x, n_y=ag.n_y, grid_size_mm=Coordinate(x=ag.grid_size_mm.x, y=ag.grid_size_mm.y), - smargon=SmargonCoordinate( - sh_mm=Coordinate(x=ag.smargon.sh_mm.x, y=ag.smargon.sh_mm.y, z=ag.smargon.sh_mm.z), - phi_deg=ag.smargon.phi_deg, - chi_deg=ag.smargon.chi_deg, + smargon_top_left=SmargonCoordinate( + sh_mm=Coordinate(x=ag.smargon_top_left.sh_mm.x, y=ag.smargon_top_left.sh_mm.y, z=ag.smargon_top_left.sh_mm.z), + phi_deg=ag.smargon_top_left.phi_deg, + chi_deg=ag.smargon_top_left.chi_deg, ), omega_deg=ag.omega_deg, visible=ag.visible, @@ -341,10 +341,10 @@ class RasterGridManager(QObject): n_x=ag.n_x, n_y=ag.n_y, grid_size_mm=Coordinate(x=ag.grid_size_mm.x, y=ag.grid_size_mm.y), - smargon=SmargonCoordinate( - sh_mm=Coordinate(x=ag.smargon.sh_mm.x, y=ag.smargon.sh_mm.y, z=ag.smargon.sh_mm.z), - phi_deg=ag.smargon.phi_deg, - chi_deg=ag.smargon.chi_deg, + smargon_top_left=SmargonCoordinate( + sh_mm=Coordinate(x=ag.smargon_top_left.sh_mm.x, y=ag.smargon_top_left.sh_mm.y, z=ag.smargon_top_left.sh_mm.z), + phi_deg=ag.smargon_top_left.phi_deg, + chi_deg=ag.smargon_top_left.chi_deg, ), omega_deg=ag.omega_deg, visible=ag.visible, @@ -474,8 +474,8 @@ class RasterGridManager(QObject): if 0 <= row < len(self.__completed_grids): self.omega.emit(self.__completed_grids[row].request.omega_deg) self.smargon.emit(SmargonCoordinate( - phi_deg=self.__completed_grids[row].request.smargon.phi_deg, - chi_deg=self.__completed_grids[row].request.smargon.chi_deg, + phi_deg=self.__completed_grids[row].request.smargon_top_left.phi_deg, + chi_deg=self.__completed_grids[row].request.smargon_top_left.chi_deg, )) @Slot(int) @@ -485,10 +485,10 @@ class RasterGridManager(QObject): self.__active_grid.n_x = src.n_x self.__active_grid.n_y = src.n_y self.__active_grid.grid_size_mm = Coordinate(x=src.grid_size_mm.x, y=src.grid_size_mm.y) - self.__active_grid.smargon = SmargonCoordinate( - sh_mm=Coordinate(x=src.smargon.sh_mm.x, y=src.smargon.sh_mm.y, z=src.smargon.sh_mm.z), - phi_deg=src.smargon.phi_deg, - chi_deg=src.smargon.chi_deg, + self.__active_grid.smargon_top_left = SmargonCoordinate( + sh_mm=Coordinate(x=src.smargon_top_left.sh_mm.x, y=src.smargon_top_left.sh_mm.y, z=src.smargon_top_left.sh_mm.z), + phi_deg=src.smargon_top_left.phi_deg, + chi_deg=src.smargon_top_left.chi_deg, ) self.__active_grid.omega_deg = src.omega_deg diff --git a/gui/src/aaregui/widgets/raster_grid_table.py b/gui/src/aaregui/widgets/raster_grid_table.py index dd24e0d4..3f12ce66 100644 --- a/gui/src/aaregui/widgets/raster_grid_table.py +++ b/gui/src/aaregui/widgets/raster_grid_table.py @@ -45,8 +45,8 @@ class RasterGridTable(QTableWidget): # Add data cells self.setItem(row_position, 0, QTableWidgetItem(f"{req.omega_deg:.1f}")) - self.setItem(row_position, 1, QTableWidgetItem(f"{req.smargon.chi_deg:.1f}")) - self.setItem(row_position, 2, QTableWidgetItem(f"{req.smargon.phi_deg:.1f}")) + self.setItem(row_position, 1, QTableWidgetItem(f"{req.smargon_top_left.chi_deg:.1f}")) + self.setItem(row_position, 2, QTableWidgetItem(f"{req.smargon_top_left.phi_deg:.1f}")) self.setItem(row_position, 3, QTableWidgetItem(f"{req.n_x} x {req.n_y}")) # Add action buttons