refactor: eiger, refactoring done of unstage, stop and closing det and filewriter

This commit is contained in:
Christian Appel 2023-10-24 14:44:37 +02:00
parent 7346f5d76a
commit d9606a4707

View File

@ -179,7 +179,7 @@ class Eiger9mCsaxs(DetectorBase):
Depends on hardware configuration and delay generators. Depends on hardware configuration and delay generators.
At this point it is set up for gating mode (09/2023). At this point it is set up for gating mode (09/2023).
""" """
self.stop_acquisition() self._stop_detector()
self._set_trigger(TriggerSource.GATING) self._set_trigger(TriggerSource.GATING)
# TODO function for abstract class? # TODO function for abstract class?
@ -272,7 +272,7 @@ class Eiger9mCsaxs(DetectorBase):
while not os.path.exists(os.path.dirname(self.filepath)): while not os.path.exists(os.path.dirname(self.filepath)):
time.sleep(0.1) time.sleep(0.1)
self._close_file_writer() self._stop_file_writer()
logger.info(f" std_daq output filepath {self.filepath}") logger.info(f" std_daq output filepath {self.filepath}")
# TODO Discuss with Leo if this is needed, or how to start the async writing best # TODO Discuss with Leo if this is needed, or how to start the async writing best
try: try:
@ -294,7 +294,7 @@ class Eiger9mCsaxs(DetectorBase):
time.sleep(0.005) time.sleep(0.005)
# TODO function for abstract class? # TODO function for abstract class?
def _close_file_writer(self) -> None: def _stop_file_writer(self) -> None:
"""Close file writer""" """Close file writer"""
self.std_client.stop_writer() self.std_client.stop_writer()
# TODO can I wait for a status message here maybe? To ensure writer returned # TODO can I wait for a status message here maybe? To ensure writer returned
@ -349,6 +349,7 @@ class Eiger9mCsaxs(DetectorBase):
) )
pipe.execute() pipe.execute()
# TODO function for abstract class?
def _arm_acquisition(self) -> None: def _arm_acquisition(self) -> None:
"""Arm detector for acquisition""" """Arm detector for acquisition"""
self.cam.acquire.put(1) self.cam.acquire.put(1)
@ -369,71 +370,80 @@ class Eiger9mCsaxs(DetectorBase):
self._on_trigger() self._on_trigger()
return super().trigger() return super().trigger()
# TODO function for abstract class?
def _on_trigger(self): def _on_trigger(self):
"""Specify action that should be taken upon trigger signal.""" """Specify action that should be taken upon trigger signal."""
pass pass
# TODO function for abstract class?
# TODO threadlocked was attached, in principle unstage needs to be fast and should possibly called multiple times # TODO threadlocked was attached, in principle unstage needs to be fast and should possibly called multiple times
@threadlocked @threadlocked
def unstage(self) -> List[object]: def unstage(self) -> List[object]:
"""Unstage the device, this means detector and file writer. """Unstage the device, detector and file writer.
This method must be idempotent, multiple calls (without a new This method must be idempotent, multiple calls (without a new
call to 'stage') have no effect. call to 'stage') have no effect.
""" """
logger.info("Waiting for Eiger9M to finish") # TODO solution for multiple calls of the function to avoid calling the finished loop.
# Loop to avoid calling the finished loop multiple times
old_scanID = self.scaninfo.scanID old_scanID = self.scaninfo.scanID
self.scaninfo.load_scan_metadata() self.scaninfo.load_scan_metadata()
logger.info(f"Old scanID: {old_scanID}, ")
if self.scaninfo.scanID != old_scanID: if self.scaninfo.scanID != old_scanID:
self._stopped = True self._stopped = True
if self._stopped == True: if self._stopped == True:
return super().unstage() return super().unstage()
self._eiger9M_finished() self._finished()
# Message to BEC
state = True state = True
self._publish_file_location(done=state, successful=state) self._publish_file_location(done=state, successful=state)
self._stopped = False self._stopped = False
logger.info("Eiger9M finished")
return super().unstage() return super().unstage()
# TODO function for abstract class?
# TODO necessary, how can we make this cleaner.
@threadlocked @threadlocked
def _eiger9M_finished(self): def _finished(self):
"""Function with 10s timeout""" """Check if acquisition is finished.
This function is called from unstage and stop
and will check detector and file backend status.
Timeouts after given time
"""
sleep_time = 0.1
timeout = 5
timer = 0 timer = 0
# Check status with timeout, break out if _stopped=True
while True: while True:
det_ctrl = self.cam.acquire.read()[self.cam.acquire.name]["value"] det_ctrl = self.cam.acquire.read()[self.cam.acquire.name]["value"]
# det_ctrl = 0
std_ctrl = self.std_client.get_status()["acquisition"]["state"] std_ctrl = self.std_client.get_status()["acquisition"]["state"]
status = self.std_client.get_status() status = self.std_client.get_status()
received_frames = status["acquisition"]["stats"]["n_write_completed"] received_frames = status["acquisition"]["stats"]["n_write_completed"]
total_frames = int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger) total_frames = int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger)
# TODO if no writing was performed before
if det_ctrl == 0 and std_ctrl == "FINISHED" and total_frames == received_frames: if det_ctrl == 0 and std_ctrl == "FINISHED" and total_frames == received_frames:
break break
if self._stopped == True: if self._stopped == True:
self.stop_acquisition() self._stop_detector()
self._close_file_writer() self._stop_file_writer()
break break
time.sleep(0.1) time.sleep(sleep_time)
timer += 0.1 timer += sleep_time
if timer > 5: if timer > timeout:
self._stopped == True self._stopped == True
self._close_file_writer() self._stop_detector()
self.stop_acquisition() self._stop_file_writer()
raise EigerTimeoutError( raise EigerTimeoutError(
f"Reached timeout with detector state {det_ctrl}, std_daq state {std_ctrl} and received frames of {received_frames} for the file writer" f"Reached timeout with detector state {det_ctrl}, std_daq state {std_ctrl} and received frames of {received_frames} for the file writer"
) )
self._close_file_writer() self._stop_detector()
self._stop_file_writer()
def stop_acquisition(self) -> None: def _stop_detector(self) -> None:
"""Stop the detector and wait for the proper status message""" """Stop the detector and wait for the proper status message"""
logger.info("Waiting for Eiger9m to be armed")
elapsed_time = 0 elapsed_time = 0
sleep_time = 0.01 sleep_time = 0.01
timeout = 5
# Stop acquisition
self.cam.acquire.put(0) self.cam.acquire.put(0)
retry = False retry = False
# Check status
while True: while True:
det_ctrl = self.cam.detector_state.read()[self.cam.detector_state.name]["value"] det_ctrl = self.cam.detector_state.read()[self.cam.detector_state.name]["value"]
if det_ctrl == int(DetectorState.IDLE): if det_ctrl == int(DetectorState.IDLE):
@ -442,16 +452,17 @@ class Eiger9mCsaxs(DetectorBase):
break break
time.sleep(sleep_time) time.sleep(sleep_time)
elapsed_time += sleep_time elapsed_time += sleep_time
if elapsed_time > 2 and not retry: if elapsed_time > timeout // 2 and not retry:
retry = True retry = True
# Retry to stop acquisition
self.cam.acquire.put(0) self.cam.acquire.put(0)
if elapsed_time > 5: if elapsed_time > timeout:
raise EigerTimeoutError("Failed to stop the acquisition. IOC did not update.") raise EigerTimeoutError("Failed to stop the acquisition. IOC did not update.")
def stop(self, *, success=False) -> None: def stop(self, *, success=False) -> None:
"""Stop the scan, with camera and file writer""" """Stop the scan, with camera and file writer"""
self.stop_acquisition() self._stop_detector()
self._close_file_writer() self._stop_file_writer()
super().stop(success=success) super().stop(success=success)
self._stopped = True self._stopped = True