fix: add remaining function, propose mechanism to avoid calling stage twice

This commit is contained in:
appel_c 2023-11-13 13:33:28 +01:00
parent 575b4e6260
commit 3e1a2b86c3

View File

@ -3,10 +3,12 @@ import os
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from ophyd import Device from ophyd import Device
from ophyd.device import Staged
from ophyd_devices.utils import bec_utils from ophyd_devices.utils import bec_utils
from bec_lib.bec_service import SERVICE_CONFIG from bec_lib.bec_service import SERVICE_CONFIG
from bec_lib.file_utils import FileWriterMixin from bec_lib.file_utils import FileWriterMixin
from bec_lib.messages import BECMessage, MessageEndpoints
from ophyd_devices.epics.devices.bec_scaninfo_mixin import BecScaninfoMixin from ophyd_devices.epics.devices.bec_scaninfo_mixin import BecScaninfoMixin
@ -81,6 +83,7 @@ class SLSDetectorBase(ABC, Device):
) )
self.sim_mode = sim_mode self.sim_mode = sim_mode
self._stopped = False self._stopped = False
self._staged = Staged.no
self.name = name self.name = name
self.service_cfg = None self.service_cfg = None
self.std_client = None self.std_client = None
@ -134,7 +137,6 @@ class SLSDetectorBase(ABC, Device):
""" """
self._init_det() self._init_det()
self._init_det_fw() self._init_det_fw()
pass
@abstractmethod @abstractmethod
def _init_det(self) -> None: def _init_det(self) -> None:
@ -217,7 +219,6 @@ class SLSDetectorBase(ABC, Device):
- _on_trigger : call trigger action - _on_trigger : call trigger action
""" """
self._on_trigger() self._on_trigger()
pass
@abstractmethod @abstractmethod
def _on_trigger(self) -> None: def _on_trigger(self) -> None:
@ -236,3 +237,108 @@ class SLSDetectorBase(ABC, Device):
- _stop_det_fw : stop detector filewriter - _stop_det_fw : stop detector filewriter
""" """
pass pass
# TODO maybe not required to overwrite, but simply used by the user.
# If yes, then self.scaninfo.scanID & self.scaninfo.name & self.filepath
# should become input arguments
@abstractmethod
def _publish_file_location(self, done: bool = False, successful: bool = None) -> None:
"""Publish the file location/event to bec
Two events are published:
- file_event : event for the filewriter
- public_file : event for any secondary service (e.g. radial integ code)
Args:
done (bool): True if scan is finished
successful (bool): True if scan was successful
"""
pipe = self._producer.pipeline()
if successful is None:
msg = BECMessage.FileMessage(file_path=self.filepath, done=done)
else:
msg = BECMessage.FileMessage(file_path=self.filepath, done=done, successful=successful)
self._producer.set_and_publish(
MessageEndpoints.public_file(self.scaninfo.scanID, self.name), msg.dumps(), pipe=pipe
)
self._producer.set_and_publish(
MessageEndpoints.file_event(self.name), msg.dumps(), pipe=pipe
)
pipe.execute()
@abstractmethod
def stage(self) -> List(object):
"""
Stage device in preparation for a scan
Internal Calls:
- _prep_det_fw : prepare detector filewriter for measurement
- _prep_det : prepare detector for measurement
- _publish_file_location : publish file location to bec
Returns:
List(object): list of objects that were staged
"""
# Method idempotent, should rais ;obj;'RedudantStaging' if staged twice
if self._staged == Staged.yes:
return super().stage()
else:
# Reset flag for detector stopped
self._stopped = False
# Load metadata of the scan
self.scaninfo.load_scan_metadata()
# Prepare detector and file writer
self._prep_det_fw()
self._prep_det()
state = False
self._publish_file_location(done=state)
return super().stage()
@abstractmethod
def unstage(self):
"""
Unstage device in preparation for a scan
Returns directly if self._stopped,
otherwise checks with self._finished
if data acquisition on device finished (an was successful)
Internal Calls:
- _finished : check if device finished acquisition (succesfully)
- _publish_file_location : publish file location to bec
"""
# Check if scan was stopped
old_scanID = self.scaninfo.scanID
self.scaninfo.load_scan_metadata()
if self.scaninfo.scanID != old_scanID:
self._stopped = True
if self._stopped == True:
return super().unstage()
# check if device finished acquisition
self._finished()
state = True
# Publish file location to bec
self._publish_file_location(done=state, successful=state)
self._stopped = False
return super().unstage()
def _finished(self):
"""
Check if acquisition on device finished (succesfully)
This function is called from unstage, and will check if
detector and filewriter of the detector return from acquisition.
If desired, it can also raise in case data acquisition was incomplete
Small examples:
(1) check detector & detector filewriter status
if both finished --> good, if either is not finished --> raise
(2) (Optional) check if number of images received
is equivalent to the number of images requested
Raises (optional):
TimeoutError: if data acquisition was incomplete
"""
pass