diff --git a/src/aare/daq/daq.py b/src/aare/daq/daq.py index 2ce4b920..590b7480 100644 --- a/src/aare/daq/daq.py +++ b/src/aare/daq/daq.py @@ -1379,6 +1379,27 @@ class AareDAQ: ) return None + def _validate_rotation_params(self, request: RotationScanRequest): + total_time = request.exp_time_s * request.steps + logger.debug("Validating rotation parameters with AareScan") + if request.screening: + if request.wedge_omega_deg is None: + raise ValueError("Must supply a wedge angle for screening requests") + self._devs.aerotech.screening_scan_validation( + rotation_deg=request.incr_omega_deg, + wedge_deg=request.wedge_omega_deg, + time_sec=total_time, + steps=request.steps, + run_async=True, + ) + else: + self._devs.aerotech.rotation_scan( + rotation_deg=request.steps * request.incr_omega_deg, + time_sec=total_time, + start_pos_deg=request.start_omega_deg, + run_async=True, + ) + def _execute_rotation_sequence( self, rotation_request: RotationScanRequest ) -> CompletedRotationScan | None: @@ -1396,6 +1417,7 @@ class AareDAQ: logger.warning(f"Exposure shorter than default of {min_exp_time} s! Adjusting.") rotation_request.exp_time_s = min_exp_time try: + self._validate_rotation_params(rotation_request) return self._create_rotation_service().run(rotation_request) except JFJochCommunicationError as e: logger.error(f"Rotation sequence failed due to JFJoch Communication error: {e}") @@ -1992,74 +2014,6 @@ class AareDAQ: self._set_state(BeamlineStateEnum.SampleAlignment) raise - def _rotation(self, request: RotationScanRequest) -> CompletedRotationScan: - omega_start = self.omega - status = self.status - - if request.exp_time_s < 0.004: - logger.warning("Exposure time too short for PXII rotation scan") - request.exp_time_s = 0.004 - total_time = request.exp_time_s * request.steps - if self.sample is not None and self.sample.db_id is not None: - self._aare.create_rotation_run(self.sample, request, status) - - if not self._cfg.simulated_detector: - try: - self._jfjoch.wait_till_running(timeout=60.0) - except Exception as e: - self._raise_if_critical_jfjoch_detector_error(e, command="wait_till_running") - raise - try: - if request.screening: - self._devs.aerotech.screening_scan( - rotation_deg=request.steps * request.incr_omega_deg, - wedge_deg=request.wedge_omega_deg, - time_sec=total_time, - steps=request.steps, - run_async=True, - ) - else: - self._devs.aerotech.rotation_scan( - rotation_deg=request.steps * request.incr_omega_deg, - time_sec=total_time, - start_pos_deg=request.start_omega_deg, - run_async=True, - ) - - # Is this for helical scans...? do we do smargon scans? - if request.start is not None and request.end is not None: - smargon_time_step = request.exp_time_s / float(request.steps) - pos_step = (request.end.sh_mm - request.start.sh_mm) * ( - 1.0 / float(request.steps) - ) - - for i in range(request.steps): - self._devs.smargon.target = SmargonCoordinate( - sh_mm=request.start.sh_mm + pos_step * i - ) - time.sleep(smargon_time_step) - - self._devs.aerotech.wait_till_done(timeout=int(round(total_time + 60, 0))) - self._devs.aerotech_omega = omega_start - - if self._cfg.simulated_detector: - logger.warning("Detector in simulation mode, returning fake zero rotation result.") - return self._build_fake_rotation_result(request) - else: - try: - scan_result = self._jfjoch.wait_till_done(60) - except Exception as e: - self._raise_if_critical_jfjoch_detector_error(e, command="wait_till_done") - raise - return CompletedRotationScan(request=copy.deepcopy(request), result=scan_result) - - except JFJochCommunicationError as e: - logger.error(f"Exception during rotation scan related to JFJoch: {e}") - raise - except Exception as e: - logger.error(f"Exception during rotation scan: {e}") - raise - def measure_rotation(self, request: RotationScanRequest) -> CompletedRotationScan: """ Execute a rotation scan. diff --git a/src/aare/devices/aerotech.py b/src/aare/devices/aerotech.py index 3eac3bec..10d1d402 100644 --- a/src/aare/devices/aerotech.py +++ b/src/aare/devices/aerotech.py @@ -190,10 +190,7 @@ class AerotechController: start_pos_deg=start_pos_deg, run_async=run_async, ) - logger.debug(f"Payload sent to AareScan for rotation: {payload}") - if self._simulated: - return payload - + logger.debug(f"Payload sent to AareScan for rotation execution: {payload}") try: return self._api.rotation_scan_post(payload) except Exception as e: @@ -204,6 +201,26 @@ class AerotechController: operation="POST", ) from e + def validate_rotation_scan( + self, rotation_deg: float, time_sec: float, start_pos_deg: float, run_async: bool = False + ): + payload = RotationRequest( + rotation_deg=rotation_deg, + time_sec=time_sec, + start_pos_deg=start_pos_deg, + run_async=run_async, + ) + logger.debug(f"Payload sent to AareScan for validating rotation: {payload}") + try: + return self._api.validate_rotation_scan_post(payload) + except Exception as e: + raise AerotechCommunicationError( + f"Aerotech rotation scan failed validation: {e}", + endpoint="rotation_scan_post", + base_url=self._base, + operation="POST", + ) from e + def grid_scan( self, grid_elem_count_y: int, @@ -221,14 +238,44 @@ class AerotechController: time_sec=time_sec, run_async=run_async, ) - logger.debug(f"Payload sent to AareScan for grid_scan: {payload}") + logger.debug(f"Payload sent to AareScan for grid_scan execution: {payload}") if self._simulated: return payload try: return self._api.grid_scan_post(payload) except Exception as e: raise AerotechCommunicationError( - "Aerotech grid scan failed", + f"Aerotech grid scan failed: {e}", + endpoint="grid_scan_post", + base_url=self._base, + operation="POST", + ) from e + + def validate_grid_scan( + self, + grid_elem_count_y: int, + grid_elem_size_y_um: float, + time_sec: float, + grid_elem_size_x_um: float | None = None, + grid_elem_count_x: int | None = None, + run_async: bool | None = False, + ): + payload = GridRequest( + grid_elem_count_x=grid_elem_count_x, + grid_elem_count_y=grid_elem_count_y, + grid_elem_size_x_um=grid_elem_size_x_um, + grid_elem_size_y_um=grid_elem_size_y_um, + time_sec=time_sec, + run_async=run_async, + ) + logger.debug(f"Payload sent to AareScan for grid_scan validation: {payload}") + if self._simulated: + return payload + try: + return self._api.validate_grid_scan_post(payload) + except Exception as e: + raise AerotechCommunicationError( + f"Aerotech grid scan validation failed: {e}", endpoint="grid_scan_post", base_url=self._base, operation="POST", @@ -252,7 +299,7 @@ class AerotechController: if self._simulated: return payload try: - logger.info("sending screening scan request to aerotech") + logger.info(f"sending screening scan request to aerotech with payload {payload}") return self._api.screening_post(payload) except Exception as e: raise AerotechCommunicationError( @@ -262,6 +309,34 @@ class AerotechController: operation="POST", ) from e + def screening_scan_validation( + self, + rotation_deg: float, + wedge_deg: float, + time_sec: float, + steps: int, + run_async: bool = False, + ): + payload = ScreenRequest( + rotation_deg=rotation_deg, + wedge_deg=wedge_deg, + time_sec=time_sec, + steps=steps, + run_async=run_async, + ) + try: + logger.info( + f"sending screening scan request to aarescan for validation with payload {payload}" + ) + return self._api.screening_post(payload) + except Exception as e: + raise AerotechCommunicationError( + f"Aerotech screening validation failed: {e}", + endpoint="screening_post", + base_url=self._base, + operation="POST", + ) from e + if __name__ == "__main__": beamline = mx_beamline()