DAQ: organising operation handlers, state changes
This commit is contained in:
+64
-28
@@ -97,6 +97,9 @@ class AareDAQ:
|
||||
f"ML bundle metadata for {context}: target_point={target_point}, focus={focus}"
|
||||
)
|
||||
|
||||
#--------------------------------------------
|
||||
# Operation Handlers
|
||||
#--------------------------------------------
|
||||
#TODO make sure this is implemented currectly
|
||||
def _handle_operation_error(
|
||||
self,
|
||||
@@ -107,7 +110,7 @@ class AareDAQ:
|
||||
additional_comment: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Centralized error handling for all operations.
|
||||
Centralized databse maessage error handling for all operations.
|
||||
|
||||
Args:
|
||||
operation: Name of the operation that failed (e.g., "mount", "alc", "raster")
|
||||
@@ -131,29 +134,40 @@ class AareDAQ:
|
||||
logger.error(f"Failed to report {operation.value} error to database: {db_error}")
|
||||
|
||||
#todo make sure these functions are correctly implemented!
|
||||
#Operation handlers should handle database communication and beamline state changes,
|
||||
#where possible/between operations. For example in raster, we may use XtalSnapshot to take a screenshot, then
|
||||
#return to Datacollection.
|
||||
#Busy stats are handled by the public function call i.e. sample() or by automation i.e. measure()
|
||||
def _execute_mount_and_prepare(self, sample: SampleShortInfo) -> bool:
|
||||
"""
|
||||
Execute mounting and take screenshot.
|
||||
Operation handler for executing mounting and take screenshot.
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
if sample.db_id is not None:
|
||||
self.__set_state(BeamlineStateEnum.RobotSampleExchange)
|
||||
if sample is not None and sample.db_id is not None:
|
||||
self.__aare.send_sample_event(sample, SampleEventType.MOUNTING)
|
||||
self.__mount(sample)
|
||||
if sample.db_id is not None:
|
||||
if sample is not None and sample.db_id is not None:
|
||||
self.__aare.send_sample_event(sample, SampleEventType.MOUNTED)
|
||||
self.save_screenshot_db(sample.db_id, f"{sample.db_id}_mounted")
|
||||
self.__set_state(BeamlineStateEnum.SampleAlignment)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Mount failed: {e}")
|
||||
self._handle_operation_error(
|
||||
operation=DAQOperation.MOUNT,
|
||||
sample=sample,
|
||||
error=e,
|
||||
event_type=SampleEventType.MOUNTFAILED
|
||||
)
|
||||
try:
|
||||
self.__set_state(BeamlineStateEnum.SampleAlignment)
|
||||
except Exception:
|
||||
logger.exception("Failed to set state to SampleAlignment")
|
||||
finally:
|
||||
self._handle_operation_error(
|
||||
operation=DAQOperation.MOUNT,
|
||||
sample=sample,
|
||||
error=e,
|
||||
event_type=SampleEventType.MOUNTFAILED
|
||||
)
|
||||
return False
|
||||
|
||||
def _execute_loop_centering(self, sample: SampleShortInfo) -> bool:
|
||||
@@ -169,6 +183,9 @@ class AareDAQ:
|
||||
logger.error("Loop centering failed: no sample provided")
|
||||
return False
|
||||
|
||||
self.__set_state(BeamlineStateEnum.SampleAlignment)
|
||||
self.__devs.lamp_light = 2.5
|
||||
|
||||
try:
|
||||
self.__aare.send_sample_event(sample, SampleEventType.CENTERING)
|
||||
result = self.__loop_center_sequence(sample.db_id)
|
||||
@@ -213,12 +230,23 @@ class AareDAQ:
|
||||
CompletedRasterGrid result or None if failed
|
||||
"""
|
||||
try:
|
||||
self.__setup_datacollection(request=grid_request)
|
||||
if auto_center:
|
||||
result = self.__auto_center(grid_request)
|
||||
else:
|
||||
raster_result = self.__raster(grid_request)
|
||||
result = CompletedRasterGrid(r=[raster_result])
|
||||
return result
|
||||
except JFJochCommunicationError as e:
|
||||
logger.error(f"Raster sequence failed due to JFJoch Communication error: {e}")
|
||||
self._handle_operation_error(
|
||||
operation=DAQOperation.RASTER,
|
||||
sample=self.sample,
|
||||
error=e,
|
||||
event_type=SampleEventType.RASTERINGFAILED,
|
||||
additional_comment=f"JFJoch communication error: {e}"
|
||||
)
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Raster sequence failed: {e}")
|
||||
self._handle_operation_error(
|
||||
@@ -240,6 +268,7 @@ class AareDAQ:
|
||||
CompletedRotationScan result or None if failed
|
||||
"""
|
||||
try:
|
||||
self.__setup_datacollection(request=rotation_request)
|
||||
if self.sample is not None and self.sample.db_id is not None:
|
||||
self.__aare.send_sample_event(self.sample, SampleEventType.COLLECTING)
|
||||
result = self.__rotation(rotation_request)
|
||||
@@ -555,7 +584,7 @@ class AareDAQ:
|
||||
def save_abr_meas_pos(self):
|
||||
self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment)
|
||||
try:
|
||||
self.__cfg.abr_meas_pos = self.__devs.aerotech_pos
|
||||
self.__cfg.abr_meas_pos = AerotechCoordinate(at_mm=self.__devs.aerotech_pos.at_mm, omega_deg=0.0)
|
||||
self.__cfg.state_busy = False
|
||||
except Exception:
|
||||
self.__cfg.state_busy = False
|
||||
@@ -590,6 +619,7 @@ class AareDAQ:
|
||||
def park_and_dry(self):
|
||||
self.__cfg.try_set_busy(timeout=360)
|
||||
try:
|
||||
self.__devs.tell.check_enable_motion()
|
||||
self.__devs.tell.wait_not_busy()
|
||||
self.__devs.tell.set_in_mount_position(True)
|
||||
self.__devs.tell.unmount(wait=True, timeout=60.0)
|
||||
@@ -632,19 +662,23 @@ class AareDAQ:
|
||||
self.__devs.aerotech_pos = ABR_POS_MOUNT
|
||||
#collimator should be down!!!
|
||||
self.__magnet_position_sensor_check(timeout=360.0)
|
||||
self.__devs.tell.check_enable_motion()
|
||||
self.__devs.tell.wait_not_busy()
|
||||
self.__devs.tell.set_in_mount_position(True)
|
||||
if target is None:
|
||||
logger.debug(f"Unmounting sample: {self.__cfg.current_sample} (address: {self.__cfg.current_sample.tell_address()})")
|
||||
try:
|
||||
self.__devs.tell.unmount(wait=True, timeout=60.0)
|
||||
self.__aare.send_sample_event(self.__cfg.current_sample, SampleEventType.UNMOUNTED)
|
||||
self.__cfg.current_sample = None
|
||||
if self.__cfg.current_sample is not None and self.__cfg.current_sample.db_id is not None:
|
||||
self.__aare.send_sample_event(self.__cfg.current_sample, SampleEventType.UNMOUNTED)
|
||||
self.__cfg.current_sample = target
|
||||
except Exception as e:
|
||||
raise UnmountingFailed(f"Failed to unmount: {e}")
|
||||
else:
|
||||
try:
|
||||
#TODO: how to differentiate between mounting and unmounting fails
|
||||
# during a typucal mount call as this is handled by Tell?
|
||||
logger.debug(f"Mounting sample: {target} (address: {target.tell_address()})")
|
||||
value = self.__devs.tell.mount(address=target.tell_address(), force=True, auto_unmount=True, read_dm=False,
|
||||
wait=True, timeout=360.0)
|
||||
self.__mount_failure_handler(value)
|
||||
@@ -662,6 +696,7 @@ class AareDAQ:
|
||||
self.__cfg.try_set_busy(timeout=360)
|
||||
try:
|
||||
self.__set_state(BeamlineStateEnum.RobotSampleExchange)
|
||||
self.__devs.tell.check_enable_motion()
|
||||
self.__devs.tell.wait_not_busy()
|
||||
self.__devs.tell.set_in_mount_position(True)
|
||||
self.__devs.tell.unmount(wait=True, timeout=360.0)
|
||||
@@ -676,19 +711,22 @@ class AareDAQ:
|
||||
def sample(self, target: SampleShortInfo | None):
|
||||
self.__cfg.try_set_busy(timeout=360)
|
||||
try:
|
||||
workflows.common_2rse(devs=self.__devs, cfg=self.__cfg)
|
||||
logger.debug(target)
|
||||
|
||||
logger.debug(f"Mount target {target}")
|
||||
if target is None:
|
||||
logger.debug("Unmounting sample")
|
||||
type = "Unmount"
|
||||
else:
|
||||
logger.debug(f"Mounting sample: {target}")
|
||||
type = "Mount"
|
||||
if not self._execute_mount_and_prepare(target):
|
||||
raise MountingFailed("Failed to mount sample")
|
||||
raise MountingFailed(f"Failed to {type} sample {target or self.__cfg.current_sample}")
|
||||
logger.info(f"Sample mounted: {target}")
|
||||
self.__cfg.state_busy = False
|
||||
except Exception as e:
|
||||
workflows.rse2sa(devs=self.__devs, cfg=self.__cfg)
|
||||
self.__cfg.state_busy = False
|
||||
logger.debug(f"Failed to mount sample: {e}")
|
||||
raise
|
||||
workflows.rse2sa(devs=self.__devs, cfg=self.__cfg)
|
||||
self.__cfg.state_busy = False
|
||||
|
||||
|
||||
@property
|
||||
def camera_image(self) -> np.ndarray | None:
|
||||
@@ -786,6 +824,12 @@ class AareDAQ:
|
||||
|
||||
def __setup_datacollection(self, request: RasterGridRequest | RotationScanRequest, screening: bool = False):
|
||||
|
||||
if request.omega_deg is not None:
|
||||
self.__devs.aerotech_omega = request.omega_deg
|
||||
|
||||
else:
|
||||
omega = self.omega
|
||||
|
||||
if request.dtz is not None:
|
||||
logger.info(f'requesting dtz to move to {request.dtz}')
|
||||
self.__cfg.dtz = request.dtz
|
||||
@@ -859,9 +903,6 @@ class AareDAQ:
|
||||
)
|
||||
|
||||
def __raster(self, request: RasterGridRequest) -> CompletedRasterGridElem:
|
||||
self.__devs.aerotech_omega = request.omega_deg
|
||||
self.__setup_datacollection(request=request)
|
||||
|
||||
status = self.status
|
||||
logger.info(f"raster status {status}")
|
||||
logger.info(f'raster grid request: {request}')
|
||||
@@ -1029,8 +1070,6 @@ class AareDAQ:
|
||||
self.__devs.aerotech.wait_till_done(timeout=int(round(total_time + 60,0)))
|
||||
self.__devs.aerotech_omega = omega_start
|
||||
|
||||
# self.__aare.sample_collected(self.sample)
|
||||
|
||||
if self.__cfg.simulated_detector:
|
||||
logger.warning("Detector in simulation mode, returning fake zero rotation result.")
|
||||
result = self._build_fake_rotation_result(request)
|
||||
@@ -1547,9 +1586,6 @@ class AareDAQ:
|
||||
trace_all_alc_moves: bool = False
|
||||
) -> LoopCenteringResult:
|
||||
|
||||
self.__set_state(BeamlineStateEnum.SampleAlignment)
|
||||
self.__devs.lamp_light = 2.5
|
||||
|
||||
found_classes_count: dict[int, int] = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0}
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user