From ba01cf7b2da25d40611f0a059493ac22f66a36c7 Mon Sep 17 00:00:00 2001 From: appel_c Date: Mon, 6 Nov 2023 17:44:25 +0100 Subject: [PATCH] refactor: add min_readouttime, add complemented test cases; closes #11 #10 --- ophyd_devices/epics/devices/eiger9m_csaxs.py | 19 ++++++++++++---- ophyd_devices/epics/devices/pilatus_csaxs.py | 16 +++++++++++-- tests/test_eiger9m_csaxs.py | 19 ++++++++++++++++ tests/test_pilatus_csaxs.py | 24 +++++++++++++++++++- 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/ophyd_devices/epics/devices/eiger9m_csaxs.py b/ophyd_devices/epics/devices/eiger9m_csaxs.py index 38ca436..ae03f64 100644 --- a/ophyd_devices/epics/devices/eiger9m_csaxs.py +++ b/ophyd_devices/epics/devices/eiger9m_csaxs.py @@ -23,6 +23,8 @@ from ophyd_devices.utils import bec_utils logger = bec_logger.logger +EIGER9M_MIN_READOUT = 3e-3 + class EigerError(Exception): """Base class for exceptions in this module.""" @@ -144,6 +146,7 @@ class Eiger9McSAXS(DetectorBase): self.std_client = None self.scaninfo = None self.filewriter = None + self.readout_time_min = EIGER9M_MIN_READOUT self.std_rest_server_url = ( kwargs["file_writer_url"] if "file_writer_url" in kwargs else "http://xbl-daq-29:5000" ) @@ -182,12 +185,19 @@ class Eiger9McSAXS(DetectorBase): self._init_detector() self._init_filewriter() - # TODO function for abstract class? def _default_parameter(self) -> None: - """Set default parameters for Eiger 9M - readout (float) : readout time in seconds + """Set default parameters for Pilatus300k detector + readout (float): readout time in seconds """ - self.reduce_readout = 1e-3 + self._update_readout_time() + + def _update_readout_time(self) -> None: + readout_time = ( + self.scaninfo.readout_time + if hasattr(self.scaninfo, "readout_time") + else self.readout_time_min + ) + self.readout_time = max(readout_time, self.readout_time_min) # TODO function for abstract class? def _init_detector(self) -> None: @@ -354,6 +364,7 @@ class Eiger9McSAXS(DetectorBase): """Set acquisition parameters for the detector""" self.cam.num_images.put(int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger)) self.cam.num_frames.put(1) + self._update_readout_time() # TODO function for abstract class? + call it for each scan?? def _set_trigger(self, trigger_source: TriggerSource) -> None: diff --git a/ophyd_devices/epics/devices/pilatus_csaxs.py b/ophyd_devices/epics/devices/pilatus_csaxs.py index c26780a..2aa2634 100644 --- a/ophyd_devices/epics/devices/pilatus_csaxs.py +++ b/ophyd_devices/epics/devices/pilatus_csaxs.py @@ -22,6 +22,8 @@ from ophyd_devices.epics.devices.bec_scaninfo_mixin import BecScaninfoMixin logger = bec_logger.logger +PILATUS_MIN_READOUT = 3e-3 + class PilatusError(Exception): """Base class for exceptions in this module.""" @@ -135,6 +137,7 @@ class PilatuscSAXS(DetectorBase): self.std_client = None self.scaninfo = None self.filewriter = None + self.readout_time_min = PILATUS_MIN_READOUT # TODO move url from data backend up here? self.wait_for_connection(all_signals=True) if not sim_mode: @@ -174,7 +177,15 @@ class PilatuscSAXS(DetectorBase): """Set default parameters for Pilatus300k detector readout (float): readout time in seconds """ - self.reduce_readout = 1e-3 + self._update_readout_time() + + def _update_readout_time(self) -> None: + readout_time = ( + self.scaninfo.readout_time + if hasattr(self.scaninfo, "readout_time") + else self.readout_time_min + ) + self.readout_time = max(readout_time, self.readout_time_min) def _init_detector(self) -> None: """Initialize the detector""" @@ -190,6 +201,7 @@ class PilatuscSAXS(DetectorBase): # TODO slow reaction, seemed to have timeout. self._set_det_threshold() self._set_acquisition_params() + self._set_trigger(TriggerSource.EXT_ENABLE) def _set_det_threshold(self) -> None: # threshold_energy PV exists on Eiger 9M? @@ -208,7 +220,7 @@ class PilatuscSAXS(DetectorBase): # self.cam.acquire_period.set(self.exp_time + self.readout) self.cam.num_images.set(int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger)) self.cam.num_frames.set(1) - self._set_trigger(TriggerSource.EXT_ENABLE) # EXT_TRIGGER) + self._update_readout_time() def _set_trigger(self, trigger_source: int) -> None: """Set trigger source for the detector, either directly to value or TriggerSource.* with diff --git a/tests/test_eiger9m_csaxs.py b/tests/test_eiger9m_csaxs.py index f4a2f49..8efab00 100644 --- a/tests/test_eiger9m_csaxs.py +++ b/tests/test_eiger9m_csaxs.py @@ -206,6 +206,25 @@ def test_init( assert mock_init_fw.call_count == 2 +@pytest.mark.parametrize( + "readout_time, expected_value", + [ + (1e-3, 3e-3), + (3e-3, 3e-3), + (5e-3, 5e-3), + (None, 3e-3), + ], +) +def test_update_readout_time(mock_det, readout_time, expected_value): + if readout_time is None: + mock_det._update_readout_time() + assert mock_det.readout_time == expected_value + else: + mock_det.scaninfo.readout_time = readout_time + mock_det._update_readout_time() + assert mock_det.readout_time == expected_value + + @pytest.mark.parametrize( "eacc, exp_url, daq_status, daq_cfg, expected_exception", [ diff --git a/tests/test_pilatus_csaxs.py b/tests/test_pilatus_csaxs.py index 2d70bfe..f20c5fa 100644 --- a/tests/test_pilatus_csaxs.py +++ b/tests/test_pilatus_csaxs.py @@ -246,7 +246,9 @@ def test_stage( # TODO consider putting energy as variable in scaninfo mock_det.device_manager.add_device("mokev", value=12.4) mock_det._stopped = stopped - with mock.patch.object(mock_det, "_prep_file_writer") as mock_prep_fw: + with mock.patch.object(mock_det, "_prep_file_writer") as mock_prep_fw, mock.patch.object( + mock_det, "_update_readout_time" + ) as mock_update_readout_time: mock_det.filepath = scaninfo["filepath"] if expected_exception: with pytest.raises(Exception): @@ -254,6 +256,7 @@ def test_stage( else: mock_det.stage() mock_prep_fw.assert_called_once() + mock_update_readout_time.assert_called() # Check _prep_det assert mock_det.cam.num_images.get() == int( scaninfo["num_points"] * scaninfo["frames_per_trigger"] @@ -268,6 +271,25 @@ def test_pre_scan(mock_det): assert mock_det.cam.acquire.get() == 1 +@pytest.mark.parametrize( + "readout_time, expected_value", + [ + (1e-3, 3e-3), + (3e-3, 3e-3), + (5e-3, 5e-3), + (None, 3e-3), + ], +) +def test_update_readout_time(mock_det, readout_time, expected_value): + if readout_time is None: + mock_det._update_readout_time() + assert mock_det.readout_time == expected_value + else: + mock_det.scaninfo.readout_time = readout_time + mock_det._update_readout_time() + assert mock_det.readout_time == expected_value + + @pytest.mark.parametrize( "scaninfo", [