From 05a1e3d8beda46fbcdf3ecd7a6bf3f6b6653abb9 Mon Sep 17 00:00:00 2001 From: appel_c Date: Mon, 2 Mar 2026 08:23:02 +0100 Subject: [PATCH] refactor: cleanup docs and logs for most relevant devices --- .../epics/delay_generator_csaxs/ddg_1.py | 8 +++-- .../devices/epics/mcs_card/mcs_card_csaxs.py | 7 ++-- csaxs_bec/devices/jungfraujoch/eiger.py | 1 - csaxs_bec/devices/panda_box/panda_box.py | 36 +++++++++---------- csaxs_bec/devices/panda_box/panda_box_omny.py | 25 +++++-------- csaxs_bec/scans/jungfrau_joch_scan.py | 2 +- 6 files changed, 32 insertions(+), 47 deletions(-) diff --git a/csaxs_bec/devices/epics/delay_generator_csaxs/ddg_1.py b/csaxs_bec/devices/epics/delay_generator_csaxs/ddg_1.py index 79e1bcd..5f9181b 100644 --- a/csaxs_bec/devices/epics/delay_generator_csaxs/ddg_1.py +++ b/csaxs_bec/devices/epics/delay_generator_csaxs/ddg_1.py @@ -309,7 +309,11 @@ class DDG1(PSIDeviceBase, DelayGeneratorCSAXS): # Shutter opens without delay at t0, closes after exp_time * burst_count + 2ms (self._shutter_to_open_delay) self.set_delay_pairs(channel="cd", delay=0, width=shutter_width) - self.set_delay_pairs(channel="gh", delay=self._shutter_to_open_delay, width=(shutter_width-self._shutter_to_open_delay)) + self.set_delay_pairs( + channel="gh", + delay=self._shutter_to_open_delay, + width=(shutter_width - self._shutter_to_open_delay), + ) # Trigger extra pulse for MCS OR gate # f = e + 1us @@ -520,7 +524,6 @@ class DDG1(PSIDeviceBase, DelayGeneratorCSAXS): - Return the status object to BEC which will automatically resolve once the status register has the END_OF_BURST bit set. The callback of the status object will also stop the polling loop. """ - overall_start = time.time() self._stop_polling() # NOTE If the trigger source is not SINGLE_SHOT, the DDG is triggered by an external source @@ -559,7 +562,6 @@ class DDG1(PSIDeviceBase, DelayGeneratorCSAXS): # Send trigger self.trigger_shot.put(1, use_complete=True) self.cancel_on_stop(status) - logger.info(f"Configured ddg in {time.time()-overall_start}") return status def on_stop(self) -> None: diff --git a/csaxs_bec/devices/epics/mcs_card/mcs_card_csaxs.py b/csaxs_bec/devices/epics/mcs_card/mcs_card_csaxs.py index ea2c73c..31220c1 100644 --- a/csaxs_bec/devices/epics/mcs_card/mcs_card_csaxs.py +++ b/csaxs_bec/devices/epics/mcs_card/mcs_card_csaxs.py @@ -261,7 +261,6 @@ class MCSCardCSAXS(PSIDeviceBase, MCSCard): **kwargs: Additional keyword arguments from the subscription, including 'obj' (the EpicsSignalRO instance). """ with self._rlock: - logger.info(f"Received update on mcs card {self.name}") if self._omit_mca_callbacks.is_set(): return # Suppress callbacks when erasing all channels self._mca_counter_index += 1 @@ -293,9 +292,6 @@ class MCSCardCSAXS(PSIDeviceBase, MCSCard): ) # Once we have received all channels, push data to BEC and reset for next accumulation - logger.info( - f"Received update for {attr_name}, index {self._mca_counter_index}/{self.NUM_MCA_CHANNELS}" - ) if len(self._current_data) == self.NUM_MCA_CHANNELS: logger.debug( f"Current data index {self._current_data_index} complete, pushing to BEC." @@ -398,11 +394,12 @@ class MCSCardCSAXS(PSIDeviceBase, MCSCard): # NOTE Make sure that the signal that omits mca callbacks is cleared self._omit_mca_callbacks.clear() - logger.info(f"MCS Card {self.name} on_stage completed in {time.time() - start_time:.3f}s.") # For a fly scan we need to start the mcs card ourselves if self.scan_info.msg.scan_type == "fly": self.erase_start.put(1) + logger.info(f"MCS Card {self.name} on_stage completed in {time.time() - start_time:.3f}s.") + def on_prescan(self) -> None | StatusBase: """ This method is called after on_stage and before the scan starts. For the MCS card, we need to make sure diff --git a/csaxs_bec/devices/jungfraujoch/eiger.py b/csaxs_bec/devices/jungfraujoch/eiger.py index 9d8c71b..cfff422 100644 --- a/csaxs_bec/devices/jungfraujoch/eiger.py +++ b/csaxs_bec/devices/jungfraujoch/eiger.py @@ -132,7 +132,6 @@ class Eiger(PSIDeviceBase): if data is None: logger.error(f"Received image message on device {self.name} without data.") return - logger.info(f"Received preview image on device {self.name}") self.preview_image.put(data) # pylint: disable=missing-function-docstring diff --git a/csaxs_bec/devices/panda_box/panda_box.py b/csaxs_bec/devices/panda_box/panda_box.py index 516d3b0..bd3e44d 100644 --- a/csaxs_bec/devices/panda_box/panda_box.py +++ b/csaxs_bec/devices/panda_box/panda_box.py @@ -3,14 +3,18 @@ import time from bec_lib.logger import bec_logger -from ophyd_devices import AsyncMultiSignal, StatusBase +from ophyd_devices import StatusBase from ophyd_devices.devices.panda_box.panda_box import PandaBox, PandaState -from pandablocks.responses import FrameData logger = bec_logger.logger class PandaBoxCSAXS(PandaBox): + """ + PandaBox integration for cSAXS. This class implements cSAXS specific logic for the PandaBox integration. + + TODO: This logic is not yet mapped to any existing hardware. Adapt Docstring once the hardware is defined and integrated. + """ def on_init(self): super().on_init() @@ -18,6 +22,7 @@ class PandaBoxCSAXS(PandaBox): self._timeout_on_completed = 10 def on_stage(self): + start_time = time.time() super().on_stage() # TODO, adjust as seen fit. # Adjust the acquisition group based on scan parameters if needed @@ -29,6 +34,8 @@ class PandaBoxCSAXS(PandaBox): else: self._acquisition_group = "burst" + logger.info(f"PandaBox {self.name} on_stage completed in {time.time() - start_time:.3f}s.") + def on_complete(self): """On complete is called after the scan is complete. We need to wait for the capture to complete before we can disarm the PandaBox.""" @@ -41,12 +48,13 @@ class PandaBoxCSAXS(PandaBox): * self.scan_info.msg.scan_parameters.get("frames_per_trigger", 1) ) while captured < expected_points: - logger.info( - f"Run with captured {captured} and expected points : {expected_points}." - ) ret = self.send_raw("*PCAP.CAPTURED?") captured = int(ret[0].split("=")[-1]) time.sleep(0.01) + if (time.monotonic() - start_time) > self._timeout_on_completed / 2: + logger.info( + f"Waiting for capture on device {self.name} to complete: captured {captured}/{expected_points} points." + ) if (time.monotonic() - start_time) > self._timeout_on_completed: raise TimeoutError( f"Pandabox {self.name} did not complete after {self._timeout_on_completed} with points captured {captured}/{expected_points}" @@ -54,21 +62,9 @@ class PandaBoxCSAXS(PandaBox): finally: self._disarm() - _check_capture_complete() - - # NOTE: This utility class allows to submit a blocking function to a thread and return a status object - # that can be awaited for. This allows for asynchronous waiting for the capture to complete without blocking - # the main duty cycle of the device server. The device server knows how to handle the status object (future) - # and will wait for it to complete. - # status = self.task_handler.submit_task(_check_capture_complete, run=True) - - # status_panda_state = StatusBase(obj=self) - # self.add_status_callback( - # status, success=[PandaState.END, PandaState.DISARMED], failure=[PandaState.READY] - # ) - # ret_status = status & status_panda_state - # self.cancel_on_stop(ret_status) - # return ret_status + status_captured = self.task_handler.submit_task(_check_capture_complete, run=True) + self.cancel_on_stop(status_captured) + return status_captured if __name__ == "__main__": diff --git a/csaxs_bec/devices/panda_box/panda_box_omny.py b/csaxs_bec/devices/panda_box/panda_box_omny.py index e41f2d8..fdf543f 100644 --- a/csaxs_bec/devices/panda_box/panda_box_omny.py +++ b/csaxs_bec/devices/panda_box/panda_box_omny.py @@ -10,6 +10,7 @@ logger = bec_logger.logger class PandaBoxOMNY(PandaBox): + """PandaBox integration for OMNY. This class implements OMNY specific logic for the PandaBox integration.""" def on_init(self): super().on_init() @@ -17,6 +18,7 @@ class PandaBoxOMNY(PandaBox): self._timeout_on_completed = 10 def on_stage(self): + start_time = time.time() super().on_stage() # TODO, adjust as seen fit. # Adjust the acquisition group based on scan parameters if needed @@ -28,6 +30,8 @@ class PandaBoxOMNY(PandaBox): else: self._acquisition_group = "burst" + logger.info(f"PandaBox {self.name} on_stage completed in {time.time() - start_time:.3f}s.") + def on_complete(self): """On complete is called after the scan is complete. We need to wait for the capture to complete before we can disarm the PandaBox.""" @@ -40,12 +44,13 @@ class PandaBoxOMNY(PandaBox): * self.scan_info.msg.scan_parameters.get("frames_per_trigger", 1) ) while captured < expected_points: - logger.info( - f"Run with captured {captured} and expected points : {expected_points}." - ) ret = self.send_raw("*PCAP.CAPTURED?") captured = int(ret[0].split("=")[-1]) time.sleep(0.01) + if (time.monotonic() - start_time) > self._timeout_on_completed / 2: + logger.info( + f"Waiting for capture on device {self.name} to complete: captured {captured}/{expected_points} points." + ) if (time.monotonic() - start_time) > self._timeout_on_completed: raise TimeoutError( f"Pandabox {self.name} did not complete after {self._timeout_on_completed} with points captured {captured}/{expected_points}" @@ -57,20 +62,6 @@ class PandaBoxOMNY(PandaBox): self.cancel_on_stop(status_captured) return status_captured - # NOTE: This utility class allows to submit a blocking function to a thread and return a status object - # that can be awaited for. This allows for asynchronous waiting for the capture to complete without blocking - # the main duty cycle of the device server. The device server knows how to handle the status object (future) - # and will wait for it to complete. - # status = self.task_handler.submit_task(_check_capture_complete, run=True) - - # status_panda_state = StatusBase(obj=self) - # self.add_status_callback( - # status, success=[PandaState.END, PandaState.DISARMED], failure=[PandaState.READY] - # ) - # ret_status = status & status_panda_state - # self.cancel_on_stop(ret_status) - # return ret_status - if __name__ == "__main__": import time diff --git a/csaxs_bec/scans/jungfrau_joch_scan.py b/csaxs_bec/scans/jungfrau_joch_scan.py index 5713da1..7a58268 100644 --- a/csaxs_bec/scans/jungfrau_joch_scan.py +++ b/csaxs_bec/scans/jungfrau_joch_scan.py @@ -1,4 +1,4 @@ -""" Module with JungfrauJochTestScan class. """ +"""Module with JungfrauJochTestScan class.""" from bec_lib import bec_logger from bec_server.scan_server.scans import AsyncFlyScanBase, ScanAbortion