DAQ: changed routing so that there is a mid layer between automation and manual alls of private functions such as mount, loop_center, rotation and raster. Needs some checking and testing.

This commit is contained in:
appleb_m committed 2026-04-02 14:41:14 +02:00
1 parent 2f0f9623a7
commit 2044313864
1 file changed
+190 -73
+190 -73
View File
@@ -83,6 +83,116 @@ class AareDAQ:
except Exception as e:
logger.warning(f"Failed to emit face detection progress: {e}")
def _handle_operation_error(self, operation_name: str, sample: SampleShortInfo | None, error: Exception,
error_type: str = "generic") -> None:
"""
Centralized error handling for all operations.
Args:
operation_name: Name of the operation that failed (e.g., "mount", "alc", "raster")
sample: The sample being processed
error: The exception that occurred
error_type: Type of error - "mount", "alc", "axc", or "generic"
"""
if sample is None:
logger.error(f"Error in {operation_name}: {error}")
return
try:
if error_type == "mount":
self.__aare.sample_failed(sample, failed_comment=f"Mount failed: {error}")
elif error_type == "alc":
self.__aare.alc_failed(sample, alc_comment=f"Loop centering failed: {error}")
elif error_type == "axc":
self.__aare.axc_failed(sample)
else:
self.__aare.sample_failed(sample, failed_comment=f"Error in {operation_name}: {error}")
except Exception as db_error:
logger.error(f"Failed to report {operation_name} error to database: {db_error}")
def _execute_mount_and_prepare(self, sample: SampleShortInfo) -> bool:
"""
Execute mounting and take screenshot.
Returns:
True if successful, False otherwise
"""
try:
self.__mount(sample)
if sample.db_id is not None:
self.__aare.sample_mounted(sample)
self.save_screenshot_db(sample.db_id, f"{sample.db_id}_mounted")
return True
except Exception as e:
logger.error(f"Mount failed: {e}")
self._handle_operation_error("mount", sample, e, error_type="mount")
return False
def _execute_loop_centering(self, sample_id: int | None) -> bool:
"""
Execute loop centering sequence.
Returns:
True if successful, False otherwise
"""
try:
if not self.__loop_center_sequence(sample_id):
self._handle_operation_error("loop_centering", self.sample, LoopCenteringFailed(), error_type="alc")
return False
return True
except Exception as e:
logger.error(f"Loop centering failed: {e}")
self._handle_operation_error("loop_centering", self.sample, e, error_type="alc")
return False
def _execute_raster_sequence(self, grid_request: RasterGridRequest,
auto_center: bool = False) -> CompletedRasterGrid | None:
"""
Execute raster scan with optional auto-centering.
Args:
grid_request: Raster grid parameters
auto_center: If True, use auto-centering; if False, use direct raster
Returns:
CompletedRasterGrid result or None if failed
"""
try:
if auto_center:
result = self.__auto_center(grid_request)
else:
raster_result = self.__raster(grid_request)
result = CompletedRasterGrid(r=[raster_result])
return result
except Exception as e:
logger.error(f"Raster sequence failed: {e}")
self._handle_operation_error("raster", self.sample, e, error_type="axc")
return None
def _execute_rotation_sequence(self, rotation_request: RotationScanRequest) -> CompletedRotationScan | None:
"""
Execute rotation scan.
Args:
rotation_request: Rotation scan parameters
Returns:
CompletedRotationScan result or None if failed
"""
try:
result = self.__rotation(rotation_request)
self.__set_state(BeamlineStateEnum.SampleAlignment)
if self.sample is not None and self.sample.db_id is not None:
self.save_screenshot_db(self.sample.db_id, "scan_preview")
self.__aare.sample_collected(self.sample)
self.__aare.ingest_scan(sample=self.sample, result=result.result,
geom=self.sample_geometry, beam_mark_pxl=self.__cfg.get_beam_mark(self.zoom))
return result
except Exception as e:
logger.error(f"Rotation sequence failed: {e}")
self._handle_operation_error("rotation", self.sample, e, error_type="generic")
return None
def _append_smargon_trace(self, *, sample_id: int | None, event: str) -> None:
try:
path = self._smargon_trace_path
@@ -865,24 +975,15 @@ class AareDAQ:
"""
self.__cfg.try_set_busy(timeout=ceil(360))
try:
if auto:
result = self.__auto_center(r)
else:
raster_result = self.__raster(r)
result = CompletedRasterGrid(r=[raster_result])
self.__set_state(BeamlineStateEnum.SampleAlignment)
result = self._execute_raster_sequence(r, auto_center=auto)
if result is None:
raise Exception("Raster scan failed")
self.__cfg.state_busy = False
#return CompletedRasterGrid(r=[])
return result
except Exception as e:
try:
self.__aare.axc_failed(self.sample)
except Exception as axc_e:
logger.error(f"Exception while reporting AXC failure: {axc_e}")
if not self.busy:
self.__cfg.try_set_busy(timeout=ceil(360))
if self.status.state != BeamlineStateEnum.SampleAlignment:
self.__set_state(BeamlineStateEnum.SampleAlignment)
self.__set_state(BeamlineStateEnum.SampleAlignment)
self.__cfg.state_busy = False
raise e
@@ -973,8 +1074,10 @@ class AareDAQ:
self.__cfg.try_set_busy(timeout=ceil(total_time + 360))
try:
result = self.__rotation(request)
self.__set_state(BeamlineStateEnum.SampleAlignment)
result = self._execute_rotation_sequence(request)
if result is None:
raise Exception("Rotation scan failed")
self.__cfg.state_busy = False
return result
except Exception as e:
@@ -1516,18 +1619,19 @@ class AareDAQ:
self.__cfg.try_set_busy(timeout=360)
if sample_id is None:
sample_id = self.__cfg.current_sample.db_id
if not self.__loop_center_sequence(sample_id):
if not self._execute_loop_centering(sample_id):
raise LoopCenteringFailed
self.__cfg.state_busy = False
except Exception:
except Exception as e:
self.__cfg.zoom_mode = ZoomModeEnum.User
#self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom)
self.__cfg.state_busy = False
raise
self.__cfg.zoom_mode = ZoomModeEnum.User
#self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom)
finally:
self.__cfg.zoom_mode = ZoomModeEnum.User
end = time.perf_counter()
return end - start
@@ -1676,6 +1780,17 @@ class AareDAQ:
return default_params, "defaults"
def _end_operation(self, start) -> float:
"""
End an operation and return elapsed time.
Returns:
(elapsed_seconds, end_time_perf_counter)
"""
self.__cfg.state_busy = False
end = time.perf_counter()
return end - start
def measure(self, sample: SampleShortInfo) -> float:
"""
Main measurement sequence for a given sample.
@@ -1700,79 +1815,81 @@ class AareDAQ:
logger.info(f"setting busy at {time.perf_counter() - start}")
self.__cfg.try_set_busy(timeout=360)
logger.info(f"set busy at {time.perf_counter() - start}")
geom = self.sample_geometry
start_mount=time.perf_counter()
logger.info(f"starting mount {sample.db_id} at {time.ctime()}")
self.__mount(sample)
logger.info(f"mounting done at {time.perf_counter() - start_mount}, total time: {time.perf_counter() - start}")
#self.__devs.smargon_pos
#self.__devs.aerotech_pos =
alc_time = time.perf_counter() - start
logger.info(f"starting alc at {alc_time}")
if not self.__loop_center_sequence(sample.db_id):
self.__aare.alc_failed(sample)
print("alc failed")
self.__cfg.state_busy = False
end = time.perf_counter()
return end - start
if not self._execute_mount_and_prepare(sample):
logger.error("Failed to mount sample")
return self._end_operation(start)
logger.info(f"mounting done at {time.perf_counter() - start}")
# Step 2: Loop centering
if not self._execute_loop_centering(sample.db_id):
logger.error("Loop Centering did not succeed")
return self._end_operation(start)
logger.info(f"alc done at {time.perf_counter() - start}")
# Step 3: Face detection
result = self.__face_detection_sequence(steps=7, step_size=30)
self._emit_face_detection_progress(result)
logger.info(f"face_detection done at {time.perf_counter() - start}")
#self.zoom = 500
hex_string = secrets.token_hex(3) # 3 bytes = 6 hex characters
print(hex_string.upper())
hex_string = secrets.token_hex(3)
raster_params = self.get_auto_raster_params()
if self.__auto_center(RasterGridRequest(
geom = self.sample_geometry
raster_grid = RasterGridRequest(
exp_time_s=raster_params.exp_time_s,
file_prefix=sample_prefix + f"_{hex_string}",
smargon_top_left= SmargonCoordinate(),
smargon_top_left=SmargonCoordinate(),
n_x=1,
n_y=1,
dtz=raster_params.dtz,
grid_size_mm=Coordinate(x=geom.beam_size_mm.x * 0.5, y=geom.beam_size_mm.y * 0.5),
omega_deg=self.omega,
transmission = raster_params.transmission,
)):
logger.info(f"raster scans done at {time.perf_counter() - start}")
params, source = self.get_collection_params(prefer_smart=False)
logger.info(f"Using {source} for data collection: {params}")
transmission=raster_params.transmission,
)
raster_result = self._execute_raster_sequence(raster_grid, auto_center=True)
if raster_result is None:
logger.error("Raster result was None")
return self._end_operation(start)
logger.info(f"raster scans done at {time.perf_counter() - start}")
# Step 5: Data collection (rotation)
params, source = self.get_collection_params(prefer_smart=False)
logger.info(f"Using {source} for data collection: {params}")
self.__devs.dtz = params.dtz
start_omega = self.omega
rotation_request = RotationScanRequest(
start_omega_deg=start_omega,
dtz=params.dtz,
file_prefix="data/" + sample_prefix + f"_{hex_string}",
exp_time_s=params.exp_time_s,
incr_omega_deg=params.incr_omega_deg,
steps=params.steps,
transmission=params.transmission,
)
rotation_result = self._execute_rotation_sequence(rotation_request)
if rotation_result is None:
logger.error("Rotation result was None")
return self._end_operation(start)
logger.info(f"rotation done at {time.perf_counter() - start}")
self.__devs.dtz = params.dtz
start_omega = self.omega
self.__rotation( RotationScanRequest(start_omega_deg=start_omega,
dtz=params.dtz,
file_prefix="data/" + sample_prefix + f"_{hex_string}",
exp_time_s=params.exp_time_s,
incr_omega_deg=params.incr_omega_deg,
steps=params.steps,
transmission=params.transmission,
))
logger.info(f"rotation done at {time.perf_counter() - start}")
self.__cfg.state_busy = False
end = time.perf_counter()
return end - start
else:
logger.error("auto center failed")
self.__aare.axc_failed(sample)
except Exception as e:
logger.error(f"Error in measure: {e}")
if isinstance(e, AXCFailed):
logger.debug(f"error is instance AXCFailed")
self.__aare.axc_failed(sample)
else:
self.__aare.sample_failed(sample, f"Error in automation: {e}")
self.__cfg.state_busy = False
end = time.perf_counter()
raise e
self.__cfg.state_busy = False
end = time.perf_counter()
return end - start
self._handle_operation_error("measure", sample, e, error_type="generic")
finally:
return self._end_operation(start)
def __set_state(self, target: BeamlineStateEnum):
"""__set_state assumes that beamline is already in busy state