From 4b8467a347972277f31704910a238795e9460306 Mon Sep 17 00:00:00 2001 From: David Perl Date: Fri, 2 Jun 2023 15:53:05 +0100 Subject: [PATCH 01/27] update current energy with units --- src/dodal/devices/detector.py | 2 +- src/dodal/devices/eiger.py | 6 +++--- tests/devices/system_tests/test_eiger_system.py | 2 +- tests/devices/unit_tests/test_detector.py | 4 ++-- tests/devices/unit_tests/test_eiger.py | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dodal/devices/detector.py b/src/dodal/devices/detector.py index b1c8546ea2..b6c10b355a 100644 --- a/src/dodal/devices/detector.py +++ b/src/dodal/devices/detector.py @@ -27,7 +27,7 @@ class DetectorParams(BaseModel): """Holds parameters for the detector. Provides access to a list of Dectris detector sizes and a converter for distance to beam centre.""" - current_energy: float + current_energy_ev: float exposure_time: float directory: str prefix: str diff --git a/src/dodal/devices/eiger.py b/src/dodal/devices/eiger.py index 2b953d5584..b73a2e91be 100644 --- a/src/dodal/devices/eiger.py +++ b/src/dodal/devices/eiger.py @@ -73,7 +73,7 @@ def stage(self): raise Exception(f"Odin not initialised: {error_message}") if self.detector_params.use_roi_mode: self.enable_roi_mode() - status = self.set_detector_threshold(self.detector_params.current_energy) + status = self.set_detector_threshold(self.detector_params.current_energy_ev) status &= self.set_cam_pvs() status &= self.set_odin_pvs() status &= self.set_mx_settings_pvs() @@ -178,9 +178,9 @@ def set_detector_threshold(self, energy: float, tolerance: float = 0.1) -> Statu Returns: status object that is Done when the threshold has been set correctly """ - current_energy = self.cam.photon_energy.get() + current_energy_ev = self.cam.photon_energy.get() - if abs(current_energy - energy) > tolerance: + if abs(current_energy_ev - energy) > tolerance: return self.cam.photon_energy.set(energy) else: status = Status(self) diff --git a/tests/devices/system_tests/test_eiger_system.py b/tests/devices/system_tests/test_eiger_system.py index c2a841ed4e..02986d03e9 100644 --- a/tests/devices/system_tests/test_eiger_system.py +++ b/tests/devices/system_tests/test_eiger_system.py @@ -6,7 +6,7 @@ @pytest.fixture() def eiger(): detector_params: DetectorParams = DetectorParams( - current_energy=100, + current_energy_ev=100, exposure_time=0.1, directory="/tmp", prefix="file_name", diff --git a/tests/devices/unit_tests/test_detector.py b/tests/devices/unit_tests/test_detector.py index 9cd1f2caf8..74d3d91a56 100644 --- a/tests/devices/unit_tests/test_detector.py +++ b/tests/devices/unit_tests/test_detector.py @@ -5,7 +5,7 @@ def create_detector_params_with_directory(directory): return DetectorParams( - current_energy=100, + current_energy_ev=100, exposure_time=1.0, directory=directory, prefix="test", @@ -36,7 +36,7 @@ def test_if_trailing_slash_provided_then_not_appended(): ) def test_correct_det_dist_to_beam_converter_path_passed_in(mocked_parse_table): params = DetectorParams( - current_energy=100, + current_energy_ev=100, exposure_time=1.0, directory="directory", prefix="test", diff --git a/tests/devices/unit_tests/test_eiger.py b/tests/devices/unit_tests/test_eiger.py index 34dfd6bc98..23b19b0b84 100644 --- a/tests/devices/unit_tests/test_eiger.py +++ b/tests/devices/unit_tests/test_eiger.py @@ -28,7 +28,7 @@ def create_new_params() -> DetectorParams: return DetectorParams( - current_energy=TEST_CURRENT_ENERGY, + current_energy_ev=TEST_CURRENT_ENERGY, exposure_time=TEST_EXPOSURE_TIME, directory=TEST_DIR, prefix=TEST_PREFIX, @@ -54,7 +54,7 @@ def fake_eiger(): @pytest.mark.parametrize( - "current_energy, request_energy, is_energy_change", + "current_energy_ev, request_energy, is_energy_change", [ (100.0, 100.0, False), (100.0, 200.0, True), @@ -65,12 +65,12 @@ def fake_eiger(): ) def test_detector_threshold( fake_eiger: EigerDetector, - current_energy: float, + current_energy_ev: float, request_energy: float, is_energy_change: bool, ): status_obj = MagicMock() - when(fake_eiger.cam.photon_energy).get().thenReturn(current_energy) + when(fake_eiger.cam.photon_energy).get().thenReturn(current_energy_ev) when(fake_eiger.cam.photon_energy).set(ANY).thenReturn(status_obj) returned_status = fake_eiger.set_detector_threshold(request_energy) From 564ba56cfa99b83226822b1b31081b7eeef00ddd Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Mon, 12 Jun 2023 11:58:06 +0100 Subject: [PATCH 02/27] Add as device --- src/dodal/devices/attenuator/attenuator.py | 136 +++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/dodal/devices/attenuator/attenuator.py diff --git a/src/dodal/devices/attenuator/attenuator.py b/src/dodal/devices/attenuator/attenuator.py new file mode 100644 index 0000000000..62297bccb1 --- /dev/null +++ b/src/dodal/devices/attenuator/attenuator.py @@ -0,0 +1,136 @@ +from typing import Optional + +from ophyd import Arming, Component, Device, EpicsSignal, Signal +from ophyd.status import SubscriptionStatus + +from dodal.devices.detector import DetectorParams +from dodal.devices.status import await_value +from dodal.log import LOGGER + + +class Attenuator(Device): + class TransmissionSignal(Signal): + def set(self, value, *, timeout=None, settle_time=None, **kwargs): + return self.parent.set_transmission() + + do_set_transmission: TransmissionSignal = Component(TransmissionSignal) + + # Could make a separate class for these, but that's potentially pointless as this is the only PV for it + calulated_filter_state_0: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B0") + calulated_filter_state_1: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B1") + calulated_filter_state_2: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B2") + calulated_filter_state_3: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B3") + calulated_filter_state_4: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B4") + calulated_filter_state_5: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B5") + calulated_filter_state_6: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B6") + calulated_filter_state_7: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B7") + calulated_filter_state_8: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B8") + calulated_filter_state_9: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B9") + calulated_filter_state_10: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BA") + calulated_filter_state_11: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BB") + calulated_filter_state_12: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BC") + calulated_filter_state_13: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BD") + calulated_filter_state_14: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BE") + calulated_filter_state_15: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BF") + + # Could also make another class for this - but again it's the only PV used + actual_filter_state_1: EpicsSignal = Component(EpicsSignal, ":FILTER1:INLIM") + actual_filter_state_2: EpicsSignal = Component(EpicsSignal, ":FILTER2:INLIM") + actual_filter_state_3: EpicsSignal = Component(EpicsSignal, ":FILTER3:INLIM") + actual_filter_state_4: EpicsSignal = Component(EpicsSignal, ":FILTER4:INLIM") + actual_filter_state_5: EpicsSignal = Component(EpicsSignal, ":FILTER5:INLIM") + actual_filter_state_6: EpicsSignal = Component(EpicsSignal, ":FILTER6:INLIM") + actual_filter_state_7: EpicsSignal = Component(EpicsSignal, ":FILTER7:INLIM") + actual_filter_state_8: EpicsSignal = Component(EpicsSignal, ":FILTER8:INLIM") + actual_filter_state_9: EpicsSignal = Component(EpicsSignal, ":FILTER9:INLIM") + actual_filter_state_10: EpicsSignal = Component(EpicsSignal, ":FILTER10:INLIM") + actual_filter_state_11: EpicsSignal = Component(EpicsSignal, ":FILTER11:INLIM") + actual_filter_state_12: EpicsSignal = Component(EpicsSignal, ":FILTER12:INLIM") + actual_filter_state_13: EpicsSignal = Component(EpicsSignal, ":FILTER13:INLIM") + actual_filter_state_14: EpicsSignal = Component(EpicsSignal, ":FILTER14:INLIM") + actual_filter_state_15: EpicsSignal = Component(EpicsSignal, ":FILTER15:INLIM") + actual_filter_state_16: EpicsSignal = Component(EpicsSignal, ":FILTER16:INLIM") + + desired_transmission: EpicsSignal = Component(EpicsSignal, ":T2A:SETVAL1") + use_current_energy: EpicsSignal = Component( + EpicsSignal, ":E2WL:USECURRENTENERGY.PROC" + ) + change: EpicsSignal = Component(EpicsSignal, ":FANOUT") + actual_transmission: EpicsSignal = Component(EpicsSignal, ":MATCH") + + detector_params: Optional[DetectorParams] = None + + def get_calculated_filter_state_list(self) -> list[EpicsSignal]: + return [ + self.calulated_filter_state_0, + self.calulated_filter_state_1, + self.calulated_filter_state_2, + self.calulated_filter_state_3, + self.calulated_filter_state_4, + self.calulated_filter_state_5, + self.calulated_filter_state_6, + self.calulated_filter_state_7, + self.calulated_filter_state_8, + self.calulated_filter_state_9, + self.calulated_filter_state_10, + self.calulated_filter_state_11, + self.calulated_filter_state_12, + self.calulated_filter_state_13, + self.calulated_filter_state_14, + self.calulated_filter_state_15, + ] + + def get_actual_filter_state_list(self) -> list[EpicsSignal]: + return [ + self.actual_filter_state_1, + self.actual_filter_state_2, + self.actual_filter_state_3, + self.actual_filter_state_4, + self.actual_filter_state_5, + self.actual_filter_state_6, + self.actual_filter_state_7, + self.actual_filter_state_8, + self.actual_filter_state_9, + self.actual_filter_state_10, + self.actual_filter_state_11, + self.actual_filter_state_12, + self.actual_filter_state_13, + self.actual_filter_state_14, + self.actual_filter_state_15, + self.actual_filter_state_16, + ] + + def set_transmission(self, transmission) -> SubscriptionStatus: + """Get desired states and calculated states, return a status which is complete once they are equal""" + # put this in try block? + + LOGGER.info("Using current energy") + self.pv_use_current_energy.put(1) + LOGGER.info(f"Setting desired transmission to {transmission}") + self.pv_desired_transmission.put(transmission) + LOGGER.info("Sending change filter command") + self.pv_change.put(1) + + # Get desired filter positions (16phase) + + desired_states = [] + + # Get the boolean desired state of each of the 16 filters + # TODO: put in a try catch block since the get might timeout + for calculated_state in self.get_calculated_filter_state_list(): + value = int(calculated_state.get(timeout=10)) + desired_states.append(value == 1) + + actual_states = [] + + # Get the boolean actual state of each of the 16 filters + for actual_state in self.get_actual_filter_state_list(): + value = actual_state.get(timeout=10) + actual_states.append(value == "in") + + return await_value(actual_states, desired_states, timeout=30) + + # If all the actual states are equal to the desired state, we can move on + + # and check if atteunator is ready + # Get actual positions (get filter positions() from 16 phase) From d64de38e5d6f392e8a6b377dbad7a895b2e241bd Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Mon, 12 Jun 2023 12:03:11 +0100 Subject: [PATCH 03/27] Added filter pv's --- src/dodal/devices/attenuator/filter.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/dodal/devices/attenuator/filter.py diff --git a/src/dodal/devices/attenuator/filter.py b/src/dodal/devices/attenuator/filter.py new file mode 100644 index 0000000000..8002bdaaad --- /dev/null +++ b/src/dodal/devices/attenuator/filter.py @@ -0,0 +1,22 @@ +from ophyd import Component, Device, EpicsSignal, EpicsSignalRO + +from dodal.devices.attenuator.attenuator import Attenuator + + +class AtteunatorFilter(Device): + pv_calculated_state_0: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B0") + pv_calculated_state_1: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B1") + pv_calculated_state_2: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B2") + pv_calculated_state_3: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B3") + pv_calculated_state_4: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B4") + pv_calculated_state_5: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B5") + pv_calculated_state_6: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B6") + pv_calculated_state_7: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B7") + pv_calculated_state_8: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B8") + pv_calculated_state_9: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B9") + pv_calculated_state_10: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BA") + pv_calculated_state_11: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BB") + pv_calculated_state_12: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BC") + pv_calculated_state_13: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BD") + pv_calculated_state_14: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BE") + pv_calculated_state_15: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BF") From 2b35cc9b9a9132cae87025c2a2df544eb326642c Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Mon, 12 Jun 2023 13:21:38 +0100 Subject: [PATCH 04/27] Fix set_transmission --- src/dodal/devices/attenuator/attenuator.py | 122 ++++++++++----------- src/dodal/devices/attenuator/filter.py | 19 +--- 2 files changed, 58 insertions(+), 83 deletions(-) diff --git a/src/dodal/devices/attenuator/attenuator.py b/src/dodal/devices/attenuator/attenuator.py index 62297bccb1..b79a351e6d 100644 --- a/src/dodal/devices/attenuator/attenuator.py +++ b/src/dodal/devices/attenuator/attenuator.py @@ -3,6 +3,7 @@ from ophyd import Arming, Component, Device, EpicsSignal, Signal from ophyd.status import SubscriptionStatus +from dodal.devices.attenuator.filter import AtteunatorFilter from dodal.devices.detector import DetectorParams from dodal.devices.status import await_value from dodal.log import LOGGER @@ -15,41 +16,39 @@ def set(self, value, *, timeout=None, settle_time=None, **kwargs): do_set_transmission: TransmissionSignal = Component(TransmissionSignal) - # Could make a separate class for these, but that's potentially pointless as this is the only PV for it - calulated_filter_state_0: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B0") - calulated_filter_state_1: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B1") - calulated_filter_state_2: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B2") - calulated_filter_state_3: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B3") - calulated_filter_state_4: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B4") - calulated_filter_state_5: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B5") - calulated_filter_state_6: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B6") - calulated_filter_state_7: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B7") - calulated_filter_state_8: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B8") - calulated_filter_state_9: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B9") - calulated_filter_state_10: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BA") - calulated_filter_state_11: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BB") - calulated_filter_state_12: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BC") - calulated_filter_state_13: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BD") - calulated_filter_state_14: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BE") - calulated_filter_state_15: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BF") - - # Could also make another class for this - but again it's the only PV used - actual_filter_state_1: EpicsSignal = Component(EpicsSignal, ":FILTER1:INLIM") - actual_filter_state_2: EpicsSignal = Component(EpicsSignal, ":FILTER2:INLIM") - actual_filter_state_3: EpicsSignal = Component(EpicsSignal, ":FILTER3:INLIM") - actual_filter_state_4: EpicsSignal = Component(EpicsSignal, ":FILTER4:INLIM") - actual_filter_state_5: EpicsSignal = Component(EpicsSignal, ":FILTER5:INLIM") - actual_filter_state_6: EpicsSignal = Component(EpicsSignal, ":FILTER6:INLIM") - actual_filter_state_7: EpicsSignal = Component(EpicsSignal, ":FILTER7:INLIM") - actual_filter_state_8: EpicsSignal = Component(EpicsSignal, ":FILTER8:INLIM") - actual_filter_state_9: EpicsSignal = Component(EpicsSignal, ":FILTER9:INLIM") - actual_filter_state_10: EpicsSignal = Component(EpicsSignal, ":FILTER10:INLIM") - actual_filter_state_11: EpicsSignal = Component(EpicsSignal, ":FILTER11:INLIM") - actual_filter_state_12: EpicsSignal = Component(EpicsSignal, ":FILTER12:INLIM") - actual_filter_state_13: EpicsSignal = Component(EpicsSignal, ":FILTER13:INLIM") - actual_filter_state_14: EpicsSignal = Component(EpicsSignal, ":FILTER14:INLIM") - actual_filter_state_15: EpicsSignal = Component(EpicsSignal, ":FILTER15:INLIM") - actual_filter_state_16: EpicsSignal = Component(EpicsSignal, ":FILTER16:INLIM") + calulated_filter_state_1: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B0") + calulated_filter_state_2: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B1") + calulated_filter_state_3: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B2") + calulated_filter_state_4: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B3") + calulated_filter_state_5: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B4") + calulated_filter_state_6: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B5") + calulated_filter_state_7: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B6") + calulated_filter_state_8: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B7") + calulated_filter_state_9: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B8") + calulated_filter_state_10: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B9") + calulated_filter_state_11: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BA") + calulated_filter_state_12: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BB") + calulated_filter_state_13: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BC") + calulated_filter_state_14: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BD") + calulated_filter_state_15: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BE") + calulated_filter_state_16: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BF") + + filter_1: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER1") + filter_2: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER2") + filter_3: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER3") + filter_4: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER4") + filter_5: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER5") + filter_6: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER6") + filter_7: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER7") + filter_8: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER8") + filter_9: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER9") + filter_10: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER10") + filter_11: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER11") + filter_12: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER12") + filter_13: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER13") + filter_14: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER14") + filter_15: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER15") + filter_16: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER16") desired_transmission: EpicsSignal = Component(EpicsSignal, ":T2A:SETVAL1") use_current_energy: EpicsSignal = Component( @@ -62,7 +61,6 @@ def set(self, value, *, timeout=None, settle_time=None, **kwargs): def get_calculated_filter_state_list(self) -> list[EpicsSignal]: return [ - self.calulated_filter_state_0, self.calulated_filter_state_1, self.calulated_filter_state_2, self.calulated_filter_state_3, @@ -78,45 +76,41 @@ def get_calculated_filter_state_list(self) -> list[EpicsSignal]: self.calulated_filter_state_13, self.calulated_filter_state_14, self.calulated_filter_state_15, + self.calulated_filter_state_16, ] def get_actual_filter_state_list(self) -> list[EpicsSignal]: return [ - self.actual_filter_state_1, - self.actual_filter_state_2, - self.actual_filter_state_3, - self.actual_filter_state_4, - self.actual_filter_state_5, - self.actual_filter_state_6, - self.actual_filter_state_7, - self.actual_filter_state_8, - self.actual_filter_state_9, - self.actual_filter_state_10, - self.actual_filter_state_11, - self.actual_filter_state_12, - self.actual_filter_state_13, - self.actual_filter_state_14, - self.actual_filter_state_15, - self.actual_filter_state_16, + self.filter_1.actual_filter_state, + self.filter_2.actual_filter_state, + self.filter_3.actual_filter_state, + self.filter_4.actual_filter_state, + self.filter_5.actual_filter_state, + self.filter_6.actual_filter_state, + self.filter_7.actual_filter_state, + self.filter_8.actual_filter_state, + self.filter_9.actual_filter_state, + self.filter_10.actual_filter_state, + self.filter_11.actual_filter_state, + self.filter_12.actual_filter_state, + self.filter_13.actual_filter_state, + self.filter_14.actual_filter_state, + self.filter_15.actual_filter_state, + self.filter_16.actual_filter_state, ] def set_transmission(self, transmission) -> SubscriptionStatus: """Get desired states and calculated states, return a status which is complete once they are equal""" - # put this in try block? LOGGER.info("Using current energy") - self.pv_use_current_energy.put(1) + self.use_current_energy.put(1) LOGGER.info(f"Setting desired transmission to {transmission}") - self.pv_desired_transmission.put(transmission) + self.desired_transmission.put(transmission) LOGGER.info("Sending change filter command") - self.pv_change.put(1) + self.change.put(1) # Get desired filter positions (16phase) - desired_states = [] - - # Get the boolean desired state of each of the 16 filters - # TODO: put in a try catch block since the get might timeout for calculated_state in self.get_calculated_filter_state_list(): value = int(calculated_state.get(timeout=10)) desired_states.append(value == 1) @@ -126,11 +120,7 @@ def set_transmission(self, transmission) -> SubscriptionStatus: # Get the boolean actual state of each of the 16 filters for actual_state in self.get_actual_filter_state_list(): value = actual_state.get(timeout=10) - actual_states.append(value == "in") + actual_states.append(value == "In") + # Transmission is set when all actual and desired states are equal return await_value(actual_states, desired_states, timeout=30) - - # If all the actual states are equal to the desired state, we can move on - - # and check if atteunator is ready - # Get actual positions (get filter positions() from 16 phase) diff --git a/src/dodal/devices/attenuator/filter.py b/src/dodal/devices/attenuator/filter.py index 8002bdaaad..c4f2cd31be 100644 --- a/src/dodal/devices/attenuator/filter.py +++ b/src/dodal/devices/attenuator/filter.py @@ -1,22 +1,7 @@ -from ophyd import Component, Device, EpicsSignal, EpicsSignalRO +from ophyd import Component, Device, EpicsSignal from dodal.devices.attenuator.attenuator import Attenuator class AtteunatorFilter(Device): - pv_calculated_state_0: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B0") - pv_calculated_state_1: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B1") - pv_calculated_state_2: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B2") - pv_calculated_state_3: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B3") - pv_calculated_state_4: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B4") - pv_calculated_state_5: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B5") - pv_calculated_state_6: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B6") - pv_calculated_state_7: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B7") - pv_calculated_state_8: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B8") - pv_calculated_state_9: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B9") - pv_calculated_state_10: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BA") - pv_calculated_state_11: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BB") - pv_calculated_state_12: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BC") - pv_calculated_state_13: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BD") - pv_calculated_state_14: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BE") - pv_calculated_state_15: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BF") + actual_filter_state: EpicsSignal = Component(EpicsSignal, ":INLIM") From 6e9077b7166348930f6e898e8c690f4b623bb3f9 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Mon, 12 Jun 2023 16:34:38 +0100 Subject: [PATCH 05/27] Fixed transmission and added unit tests --- src/dodal/devices/attenuator/attenuator.py | 86 ++++++++++++--------- src/dodal/devices/attenuator/filter.py | 6 +- tests/devices/unit_tests/test_attenuator.py | 34 ++++++++ 3 files changed, 84 insertions(+), 42 deletions(-) create mode 100644 tests/devices/unit_tests/test_attenuator.py diff --git a/src/dodal/devices/attenuator/attenuator.py b/src/dodal/devices/attenuator/attenuator.py index b79a351e6d..e255bd1b07 100644 --- a/src/dodal/devices/attenuator/attenuator.py +++ b/src/dodal/devices/attenuator/attenuator.py @@ -1,7 +1,7 @@ from typing import Optional -from ophyd import Arming, Component, Device, EpicsSignal, Signal -from ophyd.status import SubscriptionStatus +from ophyd import Component, Device, EpicsSignal, EpicsSignalRO, Signal +from ophyd.status import Status, SubscriptionStatus from dodal.devices.attenuator.filter import AtteunatorFilter from dodal.devices.detector import DetectorParams @@ -16,22 +16,36 @@ def set(self, value, *, timeout=None, settle_time=None, **kwargs): do_set_transmission: TransmissionSignal = Component(TransmissionSignal) - calulated_filter_state_1: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B0") - calulated_filter_state_2: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B1") - calulated_filter_state_3: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B2") - calulated_filter_state_4: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B3") - calulated_filter_state_5: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B4") - calulated_filter_state_6: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B5") - calulated_filter_state_7: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B6") - calulated_filter_state_8: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B7") - calulated_filter_state_9: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B8") - calulated_filter_state_10: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.B9") - calulated_filter_state_11: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BA") - calulated_filter_state_12: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BB") - calulated_filter_state_13: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BC") - calulated_filter_state_14: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BD") - calulated_filter_state_15: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BE") - calulated_filter_state_16: EpicsSignal = Component(EpicsSignal, ":DEC_TO_BIN.BF") + calulated_filter_state_1: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B0") + calulated_filter_state_2: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B1") + calulated_filter_state_3: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B2") + calulated_filter_state_4: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B3") + calulated_filter_state_5: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B4") + calulated_filter_state_6: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B5") + calulated_filter_state_7: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B6") + calulated_filter_state_8: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B7") + calulated_filter_state_9: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B8") + calulated_filter_state_10: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.B9" + ) + calulated_filter_state_11: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BA" + ) + calulated_filter_state_12: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BB" + ) + calulated_filter_state_13: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BC" + ) + calulated_filter_state_14: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BD" + ) + calulated_filter_state_15: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BE" + ) + calulated_filter_state_16: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BF" + ) filter_1: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER1") filter_2: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER2") @@ -52,7 +66,7 @@ def set(self, value, *, timeout=None, settle_time=None, **kwargs): desired_transmission: EpicsSignal = Component(EpicsSignal, ":T2A:SETVAL1") use_current_energy: EpicsSignal = Component( - EpicsSignal, ":E2WL:USECURRENTENERGY.PROC" + EpicsSignal, ":E2WL:USECURRENTENERY.PROC" ) change: EpicsSignal = Component(EpicsSignal, ":FANOUT") actual_transmission: EpicsSignal = Component(EpicsSignal, ":MATCH") @@ -103,24 +117,20 @@ def set_transmission(self, transmission) -> SubscriptionStatus: """Get desired states and calculated states, return a status which is complete once they are equal""" LOGGER.info("Using current energy") - self.use_current_energy.put(1) + self.use_current_energy.set(1).wait() LOGGER.info(f"Setting desired transmission to {transmission}") - self.desired_transmission.put(transmission) + self.desired_transmission.set(transmission).wait() LOGGER.info("Sending change filter command") - self.change.put(1) - - # Get desired filter positions (16phase) - desired_states = [] - for calculated_state in self.get_calculated_filter_state_list(): - value = int(calculated_state.get(timeout=10)) - desired_states.append(value == 1) - - actual_states = [] - - # Get the boolean actual state of each of the 16 filters - for actual_state in self.get_actual_filter_state_list(): - value = actual_state.get(timeout=10) - actual_states.append(value == "In") - - # Transmission is set when all actual and desired states are equal - return await_value(actual_states, desired_states, timeout=30) + self.change.set(1).wait() + + # At some point we need to check how and when the calculated states are set, since if this is ran beforehand + # ,the function won't work + status = Status(done=True, success=True) + actual_states = self.get_actual_filter_state_list() + calculated_states = self.get_calculated_filter_state_list() + for i in range(16): + status &= await_value( + actual_states[i], calculated_states[i].get(), timeout=10 + ) + + return status diff --git a/src/dodal/devices/attenuator/filter.py b/src/dodal/devices/attenuator/filter.py index c4f2cd31be..a794ccc715 100644 --- a/src/dodal/devices/attenuator/filter.py +++ b/src/dodal/devices/attenuator/filter.py @@ -1,7 +1,5 @@ -from ophyd import Component, Device, EpicsSignal - -from dodal.devices.attenuator.attenuator import Attenuator +from ophyd import Component, Device, EpicsSignalRO class AtteunatorFilter(Device): - actual_filter_state: EpicsSignal = Component(EpicsSignal, ":INLIM") + actual_filter_state: EpicsSignalRO = Component(EpicsSignalRO, ":INLIM") diff --git a/tests/devices/unit_tests/test_attenuator.py b/tests/devices/unit_tests/test_attenuator.py new file mode 100644 index 0000000000..7ccb758bfc --- /dev/null +++ b/tests/devices/unit_tests/test_attenuator.py @@ -0,0 +1,34 @@ +from unittest.mock import MagicMock + +import pytest +from ophyd.sim import make_fake_device +from ophyd.status import Status + +from dodal.devices.attenuator.attenuator import Attenuator + +CALCULATED_VALUE = 10 + + +@pytest.fixture +def fake_attenuator(): + FakeAttenuator: Attenuator = make_fake_device(Attenuator) + fake_attenuator: Attenuator = FakeAttenuator(name="aperture") + + def mock_apply_values(val: int): + actual_states = fake_attenuator.get_actual_filter_state_list() + calculated_states = fake_attenuator.get_calculated_filter_state_list() + for i in range(16): + calculated_states[i].sim_put( + CALCULATED_VALUE + ) # Ignore the actual calculation as this is EPICS layer + actual_states[i].sim_put(calculated_states[i].get()) + return Status(done=True, success=True) + + fake_attenuator.change.set = MagicMock(side_effect=mock_apply_values) + + return fake_attenuator + + +def test_set_transmission_success(fake_attenuator: Attenuator): + fake_attenuator.calulated_filter_state_10.sim_put(1) + fake_attenuator.set_transmission(1.0).wait(10) From 91fc7cffeee1165e7066e846b68813092af9ffc0 Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 14 Jun 2023 12:46:42 +0100 Subject: [PATCH 06/27] fix current energy ev --- src/dodal/devices/eiger.py | 2 +- tests/devices/unit_tests/test_eiger.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dodal/devices/eiger.py b/src/dodal/devices/eiger.py index 8fdb044693..1ac4b03eae 100644 --- a/src/dodal/devices/eiger.py +++ b/src/dodal/devices/eiger.py @@ -281,7 +281,7 @@ def do_arming_chain(self) -> Status: functions_to_do_arm.extend( [ lambda: self.set_detector_threshold( - energy=detector_params.current_energy + energy=detector_params.current_energy_ev ), self.set_cam_pvs, self.set_odin_number_of_frame_chunks, diff --git a/tests/devices/unit_tests/test_eiger.py b/tests/devices/unit_tests/test_eiger.py index ff30e196f3..e4986ba05a 100644 --- a/tests/devices/unit_tests/test_eiger.py +++ b/tests/devices/unit_tests/test_eiger.py @@ -274,7 +274,7 @@ def test_unsuccessful_true_roi_mode_change_results_in_callback_error( unwrapped_funcs = [ lambda: fake_eiger.change_roi_mode(enable=True), lambda: fake_eiger.set_detector_threshold( - energy=fake_eiger.detector_params.current_energy + energy=fake_eiger.detector_params.current_energy_ev ), ] with pytest.raises(Exception): @@ -294,7 +294,7 @@ def test_unsuccessful_false_roi_mode_change_results_in_callback_error( unwrapped_funcs = [ lambda: fake_eiger.change_roi_mode(enable=False), lambda: fake_eiger.set_detector_threshold( - energy=fake_eiger.detector_params.current_energy + energy=fake_eiger.detector_params.current_energy_ev ), ] with pytest.raises(Exception): @@ -451,7 +451,7 @@ def get_bad_status(): unwrapped_funcs = [ ( lambda: fake_eiger.set_detector_threshold( - energy=fake_eiger.detector_params.current_energy + energy=fake_eiger.detector_params.current_energy_ev ) ), (fake_eiger.set_cam_pvs), From e23ed29ecfa7a88fbfd6b455757c0b1effd7b341 Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 14 Jun 2023 13:41:57 +0100 Subject: [PATCH 07/27] add assert --- src/dodal/devices/eiger.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dodal/devices/eiger.py b/src/dodal/devices/eiger.py index 1ac4b03eae..417ce4492a 100644 --- a/src/dodal/devices/eiger.py +++ b/src/dodal/devices/eiger.py @@ -158,6 +158,7 @@ def set_odin_number_of_frame_chunks(self) -> Status: return status def set_odin_pvs(self) -> Status: + assert self.detector_params is not None file_prefix = self.detector_params.full_filename status = self.odin.file_writer.file_path.set( self.detector_params.directory, timeout=self.GENERAL_STATUS_TIMEOUT From 63481c7e9bbca003f6536ca780b8f5a0ada0be8a Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Wed, 14 Jun 2023 14:24:35 +0100 Subject: [PATCH 08/27] fix naming --- tests/devices/unit_tests/test_attenuator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/devices/unit_tests/test_attenuator.py b/tests/devices/unit_tests/test_attenuator.py index 7ccb758bfc..abe1df9daa 100644 --- a/tests/devices/unit_tests/test_attenuator.py +++ b/tests/devices/unit_tests/test_attenuator.py @@ -12,7 +12,7 @@ @pytest.fixture def fake_attenuator(): FakeAttenuator: Attenuator = make_fake_device(Attenuator) - fake_attenuator: Attenuator = FakeAttenuator(name="aperture") + fake_attenuator: Attenuator = FakeAttenuator(name="attenuator") def mock_apply_values(val: int): actual_states = fake_attenuator.get_actual_filter_state_list() From 51e3843d2a3fef1de43fd0fdcc168613b7766f0b Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Wed, 14 Jun 2023 14:52:58 +0100 Subject: [PATCH 09/27] Add xspress3mini arming and unit tests --- src/dodal/devices/status.py | 5 +- .../devices/xspress3_mini/xspress3_mini.py | 88 +++++++++++++++++-- .../xspress3_mini/xspress3_mini_channel.py | 2 +- tests/devices/test_xspress3mini.py | 23 +++++ 4 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 tests/devices/test_xspress3mini.py diff --git a/src/dodal/devices/status.py b/src/dodal/devices/status.py index cc153e1999..a4a45175fe 100644 --- a/src/dodal/devices/status.py +++ b/src/dodal/devices/status.py @@ -9,6 +9,9 @@ def await_value( subscribable: Any, expected_value: T, timeout: Union[None, int] = None ) -> SubscriptionStatus: def value_is(value, **_): - return value == expected_value + if type(expected_value) == list: + return value in expected_value + else: + return value == expected_value return SubscriptionStatus(subscribable, value_is, timeout=timeout) diff --git a/src/dodal/devices/xspress3_mini/xspress3_mini.py b/src/dodal/devices/xspress3_mini/xspress3_mini.py index 9d74184f9a..370e26e8cd 100644 --- a/src/dodal/devices/xspress3_mini/xspress3_mini.py +++ b/src/dodal/devices/xspress3_mini/xspress3_mini.py @@ -1,23 +1,97 @@ -from ophyd import Component, Device, EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV +from enum import Enum +from ophyd import ( + Component, + Device, + EpicsSignal, + EpicsSignalRO, + EpicsSignalWithRBV, + Signal, +) +from ophyd.status import Status + +from dodal.devices.status import await_value from dodal.devices.xspress3_mini.xspress3_mini_channel import Xspress3MiniChannel +from dodal.log import LOGGER + + +class TriggerMode(Enum): + SOFTWARE = "Software" + HARDWARE = "Hardware" + BURST = "Burst" + TTL_Veto_Only = "TTL_Veto_Only" + IDC = "IDC" + SOTWARE_START_STOP = "Software_Start/Stop" + TTL_BOTH = "TTL_Both" + LVDS_VETO_ONLY = "LVDS_Veto_Only" + LVDS_both = "LVDS_Both" + + +class UpdateRBV(Enum): + DISABLED = "Disabled" + ENABLED = "Enabled" + + +class EraseState(Enum): + DONE = "Done" + ERASE = "Erase" + + +class AcquireState(Enum): + DONE = "Done" + ACQUIRE = "Acquire" + + +class DetectorState(Enum): + ACQUIRE = "Acquire" + CORRECT = "Correct" + READOUT = "Readout" + ABORTING = "Aborting" + + IDLE = "Idle" + SAVING = "Saving" + ERROR = "Error" + INTILTIALIZING = "Initializing" + DISCONNECTED = "Disconnected" + ABORTED = "Aborted" class Xspress3Mini(Device): + class ArmingSignal(Signal): + def set(self, value, *, timeout=None, settle_time=None, **kwargs): + return self.parent.arm() + + do_arm: ArmingSignal = Component(ArmingSignal) + # Assume only one channel for now channel_1 = Component(Xspress3MiniChannel, "C1_") erase: EpicsSignal = Component(EpicsSignal, "ERASE") get_max_num_channels = Component(EpicsSignalRO, "MAX_NUM_CHANNELS_RBV") - acquire: EpicsSignal = Component(EpicsSignal, "Acquire") - get_roi_calc_mini: EpicsSignal = Component(EpicsSignal, "MCA1:Enable_RBV") - - NUMBER_ROIS_DEFAULT = 6 - trigger_mode_mini: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "TriggerMode") - roi_start_x: EpicsSignal = Component(EpicsSignal, "ROISUM1:MinX") roi_size_x: EpicsSignal = Component(EpicsSignal, "ROISUM1:SizeX") acquire_time: EpicsSignal = Component(EpicsSignal, "AcquireTime") + detector_state: EpicsSignalRO = Component(EpicsSignalRO, ":DetectorState_RBV") + NUMBER_ROIS_DEFAULT = 6 + + detector_busy_states = [ + DetectorState.ACQUIRE.value, + DetectorState.CORRECT.value, + DetectorState.ABORTING.value, + ] + + def do_start(self) -> Status: + self.erase.put(EraseState.ERASE.value) + status = self.channel_1.sca5_update_arrays_mini.set(AcquireState.DONE.value) + status &= self.acquire.set(AcquireState.ACQUIRE.value) + return status + + def arm(self) -> Status: + LOGGER.info("Arming Xspress3Mini detector...") + self.trigger_mode_mini.put(TriggerMode.BURST.value) + arm_status = self.do_start() + arm_status &= await_value(self.detector_state, self.detector_busy_states) + return arm_status diff --git a/src/dodal/devices/xspress3_mini/xspress3_mini_channel.py b/src/dodal/devices/xspress3_mini/xspress3_mini_channel.py index 8544de7f61..f08047d349 100644 --- a/src/dodal/devices/xspress3_mini/xspress3_mini_channel.py +++ b/src/dodal/devices/xspress3_mini/xspress3_mini_channel.py @@ -2,7 +2,7 @@ class Xspress3MiniChannel(Device): - sca5_update_arrays_mini = Component(EpicsSignalRO, "SCAS:TS:TSAcquire") + sca5_update_arrays_mini = Component(EpicsSignal, "SCAS:TS:TSAcquire") roi_high_limit = Component(EpicsSignal, "SCA5_HLM") roi_llm = Component(EpicsSignal, "SCA5_LLM") diff --git a/tests/devices/test_xspress3mini.py b/tests/devices/test_xspress3mini.py new file mode 100644 index 0000000000..4e1a996787 --- /dev/null +++ b/tests/devices/test_xspress3mini.py @@ -0,0 +1,23 @@ +from unittest.mock import MagicMock + +import pytest +from ophyd.sim import make_fake_device + +from dodal.devices.xspress3_mini.xspress3_mini import DetectorState, Xspress3Mini +from dodal.log import LOGGER + + +@pytest.fixture +def fake_xspress3mini(): + FakeXspress3Mini: Xspress3Mini = make_fake_device(Xspress3Mini) + fake_xspress3mini: Xspress3Mini = FakeXspress3Mini(name="xspress3mini") + return fake_xspress3mini + + +def test_arm_success_on_busy_state(fake_xspress3mini): + LOGGER.info = MagicMock() + fake_xspress3mini.detector_state.sim_put(DetectorState.IDLE.value) + status = fake_xspress3mini.arm() + assert status.done is False + fake_xspress3mini.detector_state.sim_put(DetectorState.ACQUIRE.value) + status.wait(timeout=1) From fd4c5e745e41af4ce847588b08f57318342f0c08 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Wed, 14 Jun 2023 15:30:08 +0100 Subject: [PATCH 10/27] move unit test to correct location --- tests/devices/{ => unit_tests}/test_xspress3mini.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/devices/{ => unit_tests}/test_xspress3mini.py (100%) diff --git a/tests/devices/test_xspress3mini.py b/tests/devices/unit_tests/test_xspress3mini.py similarity index 100% rename from tests/devices/test_xspress3mini.py rename to tests/devices/unit_tests/test_xspress3mini.py From d077d8b5fccc7af596f16f7c6a26478d7c960c4d Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Fri, 16 Jun 2023 09:55:34 +0100 Subject: [PATCH 11/27] Move filter class into attenuator, minor test change --- src/dodal/devices/attenuator.py | 140 ++++++++++++++++++++ tests/devices/unit_tests/test_attenuator.py | 7 +- 2 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 src/dodal/devices/attenuator.py diff --git a/src/dodal/devices/attenuator.py b/src/dodal/devices/attenuator.py new file mode 100644 index 0000000000..54aeb846eb --- /dev/null +++ b/src/dodal/devices/attenuator.py @@ -0,0 +1,140 @@ +from typing import Optional + +from ophyd import Component, Device, EpicsSignal, EpicsSignalRO, Signal +from ophyd.status import Status, SubscriptionStatus + +from dodal.devices.detector import DetectorParams +from dodal.devices.status import await_value +from dodal.log import LOGGER + + +class AtteunatorFilter(Device): + actual_filter_state: EpicsSignalRO = Component(EpicsSignalRO, ":INLIM") + + +class Attenuator(Device): + class TransmissionSignal(Signal): + def set(self, value, *, timeout=None, settle_time=None, **kwargs): + return self.parent.set_transmission() + + # Set in the range 0-1 + transmission: TransmissionSignal = Component(TransmissionSignal) + + calulated_filter_state_1: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B0") + calulated_filter_state_2: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B1") + calulated_filter_state_3: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B2") + calulated_filter_state_4: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B3") + calulated_filter_state_5: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B4") + calulated_filter_state_6: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B5") + calulated_filter_state_7: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B6") + calulated_filter_state_8: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B7") + calulated_filter_state_9: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B8") + calulated_filter_state_10: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.B9" + ) + calulated_filter_state_11: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BA" + ) + calulated_filter_state_12: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BB" + ) + calulated_filter_state_13: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BC" + ) + calulated_filter_state_14: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BD" + ) + calulated_filter_state_15: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BE" + ) + calulated_filter_state_16: EpicsSignalRO = Component( + EpicsSignalRO, ":DEC_TO_BIN.BF" + ) + + filter_1: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER1") + filter_2: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER2") + filter_3: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER3") + filter_4: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER4") + filter_5: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER5") + filter_6: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER6") + filter_7: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER7") + filter_8: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER8") + filter_9: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER9") + filter_10: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER10") + filter_11: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER11") + filter_12: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER12") + filter_13: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER13") + filter_14: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER14") + filter_15: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER15") + filter_16: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER16") + + desired_transmission: EpicsSignal = Component(EpicsSignal, ":T2A:SETVAL1") + use_current_energy: EpicsSignal = Component( + EpicsSignal, ":E2WL:USECURRENTENERY.PROC" + ) + change: EpicsSignal = Component(EpicsSignal, ":FANOUT") + actual_transmission: EpicsSignal = Component(EpicsSignal, ":MATCH") + + detector_params: Optional[DetectorParams] = None + + def get_calculated_filter_state_list(self) -> list[EpicsSignal]: + return [ + self.calulated_filter_state_1, + self.calulated_filter_state_2, + self.calulated_filter_state_3, + self.calulated_filter_state_4, + self.calulated_filter_state_5, + self.calulated_filter_state_6, + self.calulated_filter_state_7, + self.calulated_filter_state_8, + self.calulated_filter_state_9, + self.calulated_filter_state_10, + self.calulated_filter_state_11, + self.calulated_filter_state_12, + self.calulated_filter_state_13, + self.calulated_filter_state_14, + self.calulated_filter_state_15, + self.calulated_filter_state_16, + ] + + def get_actual_filter_state_list(self) -> list[EpicsSignal]: + return [ + self.filter_1.actual_filter_state, + self.filter_2.actual_filter_state, + self.filter_3.actual_filter_state, + self.filter_4.actual_filter_state, + self.filter_5.actual_filter_state, + self.filter_6.actual_filter_state, + self.filter_7.actual_filter_state, + self.filter_8.actual_filter_state, + self.filter_9.actual_filter_state, + self.filter_10.actual_filter_state, + self.filter_11.actual_filter_state, + self.filter_12.actual_filter_state, + self.filter_13.actual_filter_state, + self.filter_14.actual_filter_state, + self.filter_15.actual_filter_state, + self.filter_16.actual_filter_state, + ] + + def set_transmission(self, transmission) -> SubscriptionStatus: + """Get desired states and calculated states, return a status which is complete once they are equal""" + + LOGGER.info("Using current energy") + self.use_current_energy.set(1).wait() + LOGGER.info(f"Setting desired transmission to {transmission}") + self.desired_transmission.set(transmission).wait() + LOGGER.info("Sending change filter command") + self.change.set(1).wait() + + # At some point we need to check how and when the calculated states are set, since if this is ran beforehand + # ,the function won't work + status = Status(done=True, success=True) + actual_states = self.get_actual_filter_state_list() + calculated_states = self.get_calculated_filter_state_list() + for i in range(16): + status &= await_value( + actual_states[i], calculated_states[i].get(), timeout=10 + ) + + return status diff --git a/tests/devices/unit_tests/test_attenuator.py b/tests/devices/unit_tests/test_attenuator.py index abe1df9daa..b822fe935a 100644 --- a/tests/devices/unit_tests/test_attenuator.py +++ b/tests/devices/unit_tests/test_attenuator.py @@ -1,12 +1,13 @@ from unittest.mock import MagicMock +import numpy as np import pytest from ophyd.sim import make_fake_device from ophyd.status import Status -from dodal.devices.attenuator.attenuator import Attenuator +from dodal.devices.attenuator import Attenuator -CALCULATED_VALUE = 10 +CALCULATED_VALUE = np.random.randint(0, 10, size=16) @pytest.fixture @@ -19,7 +20,7 @@ def mock_apply_values(val: int): calculated_states = fake_attenuator.get_calculated_filter_state_list() for i in range(16): calculated_states[i].sim_put( - CALCULATED_VALUE + CALCULATED_VALUE[i] ) # Ignore the actual calculation as this is EPICS layer actual_states[i].sim_put(calculated_states[i].get()) return Status(done=True, success=True) From b6d95e8d0182c1976fe568f5e4b07a679f846b6e Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Fri, 16 Jun 2023 09:56:33 +0100 Subject: [PATCH 12/27] remove old files --- src/dodal/devices/attenuator/attenuator.py | 136 --------------------- src/dodal/devices/attenuator/filter.py | 5 - 2 files changed, 141 deletions(-) delete mode 100644 src/dodal/devices/attenuator/attenuator.py delete mode 100644 src/dodal/devices/attenuator/filter.py diff --git a/src/dodal/devices/attenuator/attenuator.py b/src/dodal/devices/attenuator/attenuator.py deleted file mode 100644 index e255bd1b07..0000000000 --- a/src/dodal/devices/attenuator/attenuator.py +++ /dev/null @@ -1,136 +0,0 @@ -from typing import Optional - -from ophyd import Component, Device, EpicsSignal, EpicsSignalRO, Signal -from ophyd.status import Status, SubscriptionStatus - -from dodal.devices.attenuator.filter import AtteunatorFilter -from dodal.devices.detector import DetectorParams -from dodal.devices.status import await_value -from dodal.log import LOGGER - - -class Attenuator(Device): - class TransmissionSignal(Signal): - def set(self, value, *, timeout=None, settle_time=None, **kwargs): - return self.parent.set_transmission() - - do_set_transmission: TransmissionSignal = Component(TransmissionSignal) - - calulated_filter_state_1: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B0") - calulated_filter_state_2: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B1") - calulated_filter_state_3: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B2") - calulated_filter_state_4: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B3") - calulated_filter_state_5: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B4") - calulated_filter_state_6: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B5") - calulated_filter_state_7: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B6") - calulated_filter_state_8: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B7") - calulated_filter_state_9: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B8") - calulated_filter_state_10: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.B9" - ) - calulated_filter_state_11: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BA" - ) - calulated_filter_state_12: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BB" - ) - calulated_filter_state_13: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BC" - ) - calulated_filter_state_14: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BD" - ) - calulated_filter_state_15: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BE" - ) - calulated_filter_state_16: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BF" - ) - - filter_1: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER1") - filter_2: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER2") - filter_3: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER3") - filter_4: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER4") - filter_5: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER5") - filter_6: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER6") - filter_7: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER7") - filter_8: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER8") - filter_9: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER9") - filter_10: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER10") - filter_11: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER11") - filter_12: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER12") - filter_13: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER13") - filter_14: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER14") - filter_15: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER15") - filter_16: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER16") - - desired_transmission: EpicsSignal = Component(EpicsSignal, ":T2A:SETVAL1") - use_current_energy: EpicsSignal = Component( - EpicsSignal, ":E2WL:USECURRENTENERY.PROC" - ) - change: EpicsSignal = Component(EpicsSignal, ":FANOUT") - actual_transmission: EpicsSignal = Component(EpicsSignal, ":MATCH") - - detector_params: Optional[DetectorParams] = None - - def get_calculated_filter_state_list(self) -> list[EpicsSignal]: - return [ - self.calulated_filter_state_1, - self.calulated_filter_state_2, - self.calulated_filter_state_3, - self.calulated_filter_state_4, - self.calulated_filter_state_5, - self.calulated_filter_state_6, - self.calulated_filter_state_7, - self.calulated_filter_state_8, - self.calulated_filter_state_9, - self.calulated_filter_state_10, - self.calulated_filter_state_11, - self.calulated_filter_state_12, - self.calulated_filter_state_13, - self.calulated_filter_state_14, - self.calulated_filter_state_15, - self.calulated_filter_state_16, - ] - - def get_actual_filter_state_list(self) -> list[EpicsSignal]: - return [ - self.filter_1.actual_filter_state, - self.filter_2.actual_filter_state, - self.filter_3.actual_filter_state, - self.filter_4.actual_filter_state, - self.filter_5.actual_filter_state, - self.filter_6.actual_filter_state, - self.filter_7.actual_filter_state, - self.filter_8.actual_filter_state, - self.filter_9.actual_filter_state, - self.filter_10.actual_filter_state, - self.filter_11.actual_filter_state, - self.filter_12.actual_filter_state, - self.filter_13.actual_filter_state, - self.filter_14.actual_filter_state, - self.filter_15.actual_filter_state, - self.filter_16.actual_filter_state, - ] - - def set_transmission(self, transmission) -> SubscriptionStatus: - """Get desired states and calculated states, return a status which is complete once they are equal""" - - LOGGER.info("Using current energy") - self.use_current_energy.set(1).wait() - LOGGER.info(f"Setting desired transmission to {transmission}") - self.desired_transmission.set(transmission).wait() - LOGGER.info("Sending change filter command") - self.change.set(1).wait() - - # At some point we need to check how and when the calculated states are set, since if this is ran beforehand - # ,the function won't work - status = Status(done=True, success=True) - actual_states = self.get_actual_filter_state_list() - calculated_states = self.get_calculated_filter_state_list() - for i in range(16): - status &= await_value( - actual_states[i], calculated_states[i].get(), timeout=10 - ) - - return status diff --git a/src/dodal/devices/attenuator/filter.py b/src/dodal/devices/attenuator/filter.py deleted file mode 100644 index a794ccc715..0000000000 --- a/src/dodal/devices/attenuator/filter.py +++ /dev/null @@ -1,5 +0,0 @@ -from ophyd import Component, Device, EpicsSignalRO - - -class AtteunatorFilter(Device): - actual_filter_state: EpicsSignalRO = Component(EpicsSignalRO, ":INLIM") From 7a1dca3d251d7ff28509a687f89c1f4f16215de2 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Fri, 16 Jun 2023 11:01:07 +0100 Subject: [PATCH 13/27] minor changes from review --- src/dodal/devices/attenuator.py | 2 -- tests/devices/unit_tests/test_attenuator.py | 12 ++++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/dodal/devices/attenuator.py b/src/dodal/devices/attenuator.py index 54aeb846eb..9620104532 100644 --- a/src/dodal/devices/attenuator.py +++ b/src/dodal/devices/attenuator.py @@ -127,8 +127,6 @@ def set_transmission(self, transmission) -> SubscriptionStatus: LOGGER.info("Sending change filter command") self.change.set(1).wait() - # At some point we need to check how and when the calculated states are set, since if this is ran beforehand - # ,the function won't work status = Status(done=True, success=True) actual_states = self.get_actual_filter_state_list() calculated_states = self.get_calculated_filter_state_list() diff --git a/tests/devices/unit_tests/test_attenuator.py b/tests/devices/unit_tests/test_attenuator.py index b822fe935a..5578a07102 100644 --- a/tests/devices/unit_tests/test_attenuator.py +++ b/tests/devices/unit_tests/test_attenuator.py @@ -1,13 +1,14 @@ from unittest.mock import MagicMock -import numpy as np import pytest +from bluesky import RunEngine +from bluesky import plan_stubs as bps from ophyd.sim import make_fake_device from ophyd.status import Status from dodal.devices.attenuator import Attenuator -CALCULATED_VALUE = np.random.randint(0, 10, size=16) +CALCULATED_VALUE = range(0, 17) @pytest.fixture @@ -31,5 +32,8 @@ def mock_apply_values(val: int): def test_set_transmission_success(fake_attenuator: Attenuator): - fake_attenuator.calulated_filter_state_10.sim_put(1) - fake_attenuator.set_transmission(1.0).wait(10) + fake_attenuator.set_transmission(1.0).wait(1) + + +def test_set_transmission_in_run_engine(fake_attenuator: Attenuator, RE: RunEngine): + yield from bps.abs_set(fake_attenuator.transmission, 1, wait=True) From 1655536e734282577836d87d57aaf35897a51710 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Fri, 16 Jun 2023 13:07:04 +0100 Subject: [PATCH 14/27] set_transmission is now just regular set override for attenuator --- src/dodal/devices/attenuator.py | 43 +++++++++------------ tests/devices/unit_tests/test_attenuator.py | 4 +- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/dodal/devices/attenuator.py b/src/dodal/devices/attenuator.py index 9620104532..c05cf0ea41 100644 --- a/src/dodal/devices/attenuator.py +++ b/src/dodal/devices/attenuator.py @@ -13,12 +13,25 @@ class AtteunatorFilter(Device): class Attenuator(Device): - class TransmissionSignal(Signal): - def set(self, value, *, timeout=None, settle_time=None, **kwargs): - return self.parent.set_transmission() + # Sets transmission - range 0-1 + def set(self, transmission) -> SubscriptionStatus: + """Get desired states and calculated states, return a status which is complete once they are equal""" - # Set in the range 0-1 - transmission: TransmissionSignal = Component(TransmissionSignal) + LOGGER.info("Using current energy") + self.use_current_energy.set(1).wait() + LOGGER.info(f"Setting desired transmission to {transmission}") + self.desired_transmission.set(transmission).wait() + LOGGER.info("Sending change filter command") + self.change.set(1).wait() + + status = Status(done=True, success=True) + actual_states = self.get_actual_filter_state_list() + calculated_states = self.get_calculated_filter_state_list() + for i in range(16): + status &= await_value( + actual_states[i], calculated_states[i].get(), timeout=10 + ) + return status calulated_filter_state_1: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B0") calulated_filter_state_2: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B1") @@ -116,23 +129,3 @@ def get_actual_filter_state_list(self) -> list[EpicsSignal]: self.filter_15.actual_filter_state, self.filter_16.actual_filter_state, ] - - def set_transmission(self, transmission) -> SubscriptionStatus: - """Get desired states and calculated states, return a status which is complete once they are equal""" - - LOGGER.info("Using current energy") - self.use_current_energy.set(1).wait() - LOGGER.info(f"Setting desired transmission to {transmission}") - self.desired_transmission.set(transmission).wait() - LOGGER.info("Sending change filter command") - self.change.set(1).wait() - - status = Status(done=True, success=True) - actual_states = self.get_actual_filter_state_list() - calculated_states = self.get_calculated_filter_state_list() - for i in range(16): - status &= await_value( - actual_states[i], calculated_states[i].get(), timeout=10 - ) - - return status diff --git a/tests/devices/unit_tests/test_attenuator.py b/tests/devices/unit_tests/test_attenuator.py index 5578a07102..8b91568d74 100644 --- a/tests/devices/unit_tests/test_attenuator.py +++ b/tests/devices/unit_tests/test_attenuator.py @@ -32,8 +32,8 @@ def mock_apply_values(val: int): def test_set_transmission_success(fake_attenuator: Attenuator): - fake_attenuator.set_transmission(1.0).wait(1) + fake_attenuator.set(1.0).wait(1) def test_set_transmission_in_run_engine(fake_attenuator: Attenuator, RE: RunEngine): - yield from bps.abs_set(fake_attenuator.transmission, 1, wait=True) + yield from bps.abs_set(fake_attenuator, 1, wait=True) From afb20c677086d7a8202e31760e13502188231e4d Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Fri, 16 Jun 2023 13:12:21 +0100 Subject: [PATCH 15/27] linting --- src/dodal/devices/attenuator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dodal/devices/attenuator.py b/src/dodal/devices/attenuator.py index c05cf0ea41..a8b6c79c1c 100644 --- a/src/dodal/devices/attenuator.py +++ b/src/dodal/devices/attenuator.py @@ -1,6 +1,6 @@ from typing import Optional -from ophyd import Component, Device, EpicsSignal, EpicsSignalRO, Signal +from ophyd import Component, Device, EpicsSignal, EpicsSignalRO from ophyd.status import Status, SubscriptionStatus from dodal.devices.detector import DetectorParams From 3cbca999c7d2f47eb766051e9e95a7e87ca9de91 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Fri, 16 Jun 2023 10:21:57 +0100 Subject: [PATCH 16/27] Moved await_value for a list to separate function --- src/dodal/devices/status.py | 15 ++++++++++++++- src/dodal/devices/xspress3_mini/xspress3_mini.py | 6 ++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/dodal/devices/status.py b/src/dodal/devices/status.py index a4a45175fe..bb13d0ccb2 100644 --- a/src/dodal/devices/status.py +++ b/src/dodal/devices/status.py @@ -1,4 +1,4 @@ -from typing import Any, TypeVar, Union +from typing import Any, Collection, TypeVar, Union from ophyd.status import SubscriptionStatus @@ -15,3 +15,16 @@ def value_is(value, **_): return value == expected_value return SubscriptionStatus(subscribable, value_is, timeout=timeout) + + +# Returns a status which is completed when the subscriptable contains a value within the expected_value list +def await_value_in_list( + subscribable: Any, expected_value: Collection[Any], timeout: Union[None, int] = None +) -> SubscriptionStatus: + def value_is(value, **_): + if type(expected_value) == list: + return value in expected_value + else: + raise TypeError(f"{expected_value} is not a Collection type") + + return SubscriptionStatus(subscribable, value_is, timeout=timeout) diff --git a/src/dodal/devices/xspress3_mini/xspress3_mini.py b/src/dodal/devices/xspress3_mini/xspress3_mini.py index 370e26e8cd..5d87967073 100644 --- a/src/dodal/devices/xspress3_mini/xspress3_mini.py +++ b/src/dodal/devices/xspress3_mini/xspress3_mini.py @@ -10,7 +10,7 @@ ) from ophyd.status import Status -from dodal.devices.status import await_value +from dodal.devices.status import await_value_in_list from dodal.devices.xspress3_mini.xspress3_mini_channel import Xspress3MiniChannel from dodal.log import LOGGER @@ -93,5 +93,7 @@ def arm(self) -> Status: LOGGER.info("Arming Xspress3Mini detector...") self.trigger_mode_mini.put(TriggerMode.BURST.value) arm_status = self.do_start() - arm_status &= await_value(self.detector_state, self.detector_busy_states) + arm_status &= await_value_in_list( + self.detector_state, self.detector_busy_states + ) return arm_status From ec48716fff6361eb7d6b6db7bef885b7da39b12a Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Fri, 16 Jun 2023 15:02:35 +0100 Subject: [PATCH 17/27] Add stage, change variable names --- src/dodal/devices/xspress3_mini/xspress3_mini.py | 14 ++++++++------ .../devices/xspress3_mini/xspress3_mini_channel.py | 2 +- tests/devices/unit_tests/test_xspress3mini.py | 12 ++++++++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/dodal/devices/xspress3_mini/xspress3_mini.py b/src/dodal/devices/xspress3_mini/xspress3_mini.py index 5d87967073..6ae008a695 100644 --- a/src/dodal/devices/xspress3_mini/xspress3_mini.py +++ b/src/dodal/devices/xspress3_mini/xspress3_mini.py @@ -76,6 +76,7 @@ def set(self, value, *, timeout=None, settle_time=None, **kwargs): acquire_time: EpicsSignal = Component(EpicsSignal, "AcquireTime") detector_state: EpicsSignalRO = Component(EpicsSignalRO, ":DetectorState_RBV") NUMBER_ROIS_DEFAULT = 6 + acquire_status: Status = None detector_busy_states = [ DetectorState.ACQUIRE.value, @@ -83,17 +84,18 @@ def set(self, value, *, timeout=None, settle_time=None, **kwargs): DetectorState.ABORTING.value, ] + def stage(self): + self.arm().wait() + def do_start(self) -> Status: self.erase.put(EraseState.ERASE.value) - status = self.channel_1.sca5_update_arrays_mini.set(AcquireState.DONE.value) - status &= self.acquire.set(AcquireState.ACQUIRE.value) + status = self.channel_1.update_arrays.set(AcquireState.DONE.value) + self.acquire_status = self.acquire.set(AcquireState.ACQUIRE.value) return status def arm(self) -> Status: LOGGER.info("Arming Xspress3Mini detector...") self.trigger_mode_mini.put(TriggerMode.BURST.value) - arm_status = self.do_start() - arm_status &= await_value_in_list( - self.detector_state, self.detector_busy_states - ) + self.do_start().wait() + arm_status = await_value_in_list(self.detector_state, self.detector_busy_states) return arm_status diff --git a/src/dodal/devices/xspress3_mini/xspress3_mini_channel.py b/src/dodal/devices/xspress3_mini/xspress3_mini_channel.py index f08047d349..c199c6c626 100644 --- a/src/dodal/devices/xspress3_mini/xspress3_mini_channel.py +++ b/src/dodal/devices/xspress3_mini/xspress3_mini_channel.py @@ -2,7 +2,7 @@ class Xspress3MiniChannel(Device): - sca5_update_arrays_mini = Component(EpicsSignal, "SCAS:TS:TSAcquire") + update_arrays = Component(EpicsSignal, "SCAS:TS:TSAcquire") roi_high_limit = Component(EpicsSignal, "SCA5_HLM") roi_llm = Component(EpicsSignal, "SCA5_LLM") diff --git a/tests/devices/unit_tests/test_xspress3mini.py b/tests/devices/unit_tests/test_xspress3mini.py index 4e1a996787..788c0f4fa9 100644 --- a/tests/devices/unit_tests/test_xspress3mini.py +++ b/tests/devices/unit_tests/test_xspress3mini.py @@ -1,10 +1,9 @@ -from unittest.mock import MagicMock - import pytest +from bluesky import RunEngine +from bluesky import plan_stubs as bps from ophyd.sim import make_fake_device from dodal.devices.xspress3_mini.xspress3_mini import DetectorState, Xspress3Mini -from dodal.log import LOGGER @pytest.fixture @@ -15,9 +14,14 @@ def fake_xspress3mini(): def test_arm_success_on_busy_state(fake_xspress3mini): - LOGGER.info = MagicMock() fake_xspress3mini.detector_state.sim_put(DetectorState.IDLE.value) status = fake_xspress3mini.arm() assert status.done is False fake_xspress3mini.detector_state.sim_put(DetectorState.ACQUIRE.value) status.wait(timeout=1) + + +def test_arm_sucess_on_busy_state_in_run_engine(fake_xspress3mini): + fake_xspress3mini.detector_state.sim_put(DetectorState.ACQUIRE.value) + RE = RunEngine() + RE(bps.stage(fake_xspress3mini)) From 695e090a7915099b7243a7de3b5442d496c76db3 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Fri, 16 Jun 2023 16:31:25 +0100 Subject: [PATCH 18/27] Fix typo --- tests/devices/unit_tests/test_xspress3mini.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/devices/unit_tests/test_xspress3mini.py b/tests/devices/unit_tests/test_xspress3mini.py index 788c0f4fa9..0f2e976e16 100644 --- a/tests/devices/unit_tests/test_xspress3mini.py +++ b/tests/devices/unit_tests/test_xspress3mini.py @@ -21,7 +21,7 @@ def test_arm_success_on_busy_state(fake_xspress3mini): status.wait(timeout=1) -def test_arm_sucess_on_busy_state_in_run_engine(fake_xspress3mini): +def test_arm_success_in_run_engine(fake_xspress3mini): fake_xspress3mini.detector_state.sim_put(DetectorState.ACQUIRE.value) RE = RunEngine() RE(bps.stage(fake_xspress3mini)) From b85108205bebb6e00e86e85240c1c51b6009efd6 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Mon, 19 Jun 2023 10:41:48 +0100 Subject: [PATCH 19/27] Add timeout to waits --- src/dodal/devices/xspress3_mini/xspress3_mini.py | 4 ++-- tests/devices/unit_tests/test_xspress3mini.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/dodal/devices/xspress3_mini/xspress3_mini.py b/src/dodal/devices/xspress3_mini/xspress3_mini.py index 6ae008a695..dbf83d4884 100644 --- a/src/dodal/devices/xspress3_mini/xspress3_mini.py +++ b/src/dodal/devices/xspress3_mini/xspress3_mini.py @@ -85,7 +85,7 @@ def set(self, value, *, timeout=None, settle_time=None, **kwargs): ] def stage(self): - self.arm().wait() + self.arm().wait(timeout=10) def do_start(self) -> Status: self.erase.put(EraseState.ERASE.value) @@ -96,6 +96,6 @@ def do_start(self) -> Status: def arm(self) -> Status: LOGGER.info("Arming Xspress3Mini detector...") self.trigger_mode_mini.put(TriggerMode.BURST.value) - self.do_start().wait() + self.do_start().wait(timeout=10) arm_status = await_value_in_list(self.detector_state, self.detector_busy_states) return arm_status diff --git a/tests/devices/unit_tests/test_xspress3mini.py b/tests/devices/unit_tests/test_xspress3mini.py index 0f2e976e16..48e9b728b9 100644 --- a/tests/devices/unit_tests/test_xspress3mini.py +++ b/tests/devices/unit_tests/test_xspress3mini.py @@ -21,7 +21,8 @@ def test_arm_success_on_busy_state(fake_xspress3mini): status.wait(timeout=1) -def test_arm_success_in_run_engine(fake_xspress3mini): +def test_stage_in_busy_state(fake_xspress3mini): fake_xspress3mini.detector_state.sim_put(DetectorState.ACQUIRE.value) RE = RunEngine() RE(bps.stage(fake_xspress3mini)) + fake_xspress3mini.acquire_status.wait(timeout=5) From ab2b90175e1e13296a4bc361ffd345c973bcd086 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Mon, 19 Jun 2023 10:44:48 +0100 Subject: [PATCH 20/27] consistent tests --- tests/devices/unit_tests/test_xspress3mini.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/devices/unit_tests/test_xspress3mini.py b/tests/devices/unit_tests/test_xspress3mini.py index 48e9b728b9..98a301594a 100644 --- a/tests/devices/unit_tests/test_xspress3mini.py +++ b/tests/devices/unit_tests/test_xspress3mini.py @@ -19,10 +19,11 @@ def test_arm_success_on_busy_state(fake_xspress3mini): assert status.done is False fake_xspress3mini.detector_state.sim_put(DetectorState.ACQUIRE.value) status.wait(timeout=1) + fake_xspress3mini.acquire_status.wait(timeout=1) def test_stage_in_busy_state(fake_xspress3mini): fake_xspress3mini.detector_state.sim_put(DetectorState.ACQUIRE.value) RE = RunEngine() RE(bps.stage(fake_xspress3mini)) - fake_xspress3mini.acquire_status.wait(timeout=5) + fake_xspress3mini.acquire_status.wait(timeout=1) From d83c7fe8bcf1a18071087e2412f68de5183e4192 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Tue, 20 Jun 2023 14:11:12 +0100 Subject: [PATCH 21/27] Added unit test --- .../devices/xspress3_mini/xspress3_mini.py | 1 + tests/devices/unit_tests/test_xspress3mini.py | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/dodal/devices/xspress3_mini/xspress3_mini.py b/src/dodal/devices/xspress3_mini/xspress3_mini.py index dbf83d4884..ff10972417 100644 --- a/src/dodal/devices/xspress3_mini/xspress3_mini.py +++ b/src/dodal/devices/xspress3_mini/xspress3_mini.py @@ -98,4 +98,5 @@ def arm(self) -> Status: self.trigger_mode_mini.put(TriggerMode.BURST.value) self.do_start().wait(timeout=10) arm_status = await_value_in_list(self.detector_state, self.detector_busy_states) + arm_status &= self.acquire_status return arm_status diff --git a/tests/devices/unit_tests/test_xspress3mini.py b/tests/devices/unit_tests/test_xspress3mini.py index 98a301594a..d2d817430f 100644 --- a/tests/devices/unit_tests/test_xspress3mini.py +++ b/tests/devices/unit_tests/test_xspress3mini.py @@ -1,11 +1,27 @@ +from unittest.mock import MagicMock + import pytest from bluesky import RunEngine from bluesky import plan_stubs as bps from ophyd.sim import make_fake_device +from ophyd.status import Status +from ophyd.utils.errors import WaitTimeoutError from dodal.devices.xspress3_mini.xspress3_mini import DetectorState, Xspress3Mini +def get_good_status() -> Status: + status = Status() + status.set_finished() + return status + + +def get_bad_status() -> Status: + status = Status() + status.set_exception(Exception) + return status + + @pytest.fixture def fake_xspress3mini(): FakeXspress3Mini: Xspress3Mini = make_fake_device(Xspress3Mini) @@ -27,3 +43,13 @@ def test_stage_in_busy_state(fake_xspress3mini): RE = RunEngine() RE(bps.stage(fake_xspress3mini)) fake_xspress3mini.acquire_status.wait(timeout=1) + + +def test_stage_fails_in_failed_acquire_state(fake_xspress3mini): + bad_status = Status() + bad_status.set_exception(Exception) + RE = RunEngine() + fake_xspress3mini.do_start = MagicMock(return_value=get_good_status()) + fake_xspress3mini.acquire_status = get_bad_status() + with pytest.raises(Exception): + RE(bps.stage(fake_xspress3mini)) From 722d407a4c943a8890027d74e3c13bb311cda524 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Tue, 20 Jun 2023 14:14:34 +0100 Subject: [PATCH 22/27] linting --- tests/devices/unit_tests/test_xspress3mini.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/devices/unit_tests/test_xspress3mini.py b/tests/devices/unit_tests/test_xspress3mini.py index d2d817430f..833efdec8a 100644 --- a/tests/devices/unit_tests/test_xspress3mini.py +++ b/tests/devices/unit_tests/test_xspress3mini.py @@ -5,7 +5,6 @@ from bluesky import plan_stubs as bps from ophyd.sim import make_fake_device from ophyd.status import Status -from ophyd.utils.errors import WaitTimeoutError from dodal.devices.xspress3_mini.xspress3_mini import DetectorState, Xspress3Mini From 933f43aa62a7291cef860e003fa2be1679d921b7 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Wed, 21 Jun 2023 16:48:14 +0100 Subject: [PATCH 23/27] Change and add tests for await_value_in_list --- src/dodal/devices/status.py | 17 ++++++--------- tests/devices/unit_tests/test_status.py | 29 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 tests/devices/unit_tests/test_status.py diff --git a/src/dodal/devices/status.py b/src/dodal/devices/status.py index bb13d0ccb2..4690a026b4 100644 --- a/src/dodal/devices/status.py +++ b/src/dodal/devices/status.py @@ -9,22 +9,19 @@ def await_value( subscribable: Any, expected_value: T, timeout: Union[None, int] = None ) -> SubscriptionStatus: def value_is(value, **_): - if type(expected_value) == list: - return value in expected_value - else: - return value == expected_value + return value == expected_value return SubscriptionStatus(subscribable, value_is, timeout=timeout) # Returns a status which is completed when the subscriptable contains a value within the expected_value list def await_value_in_list( - subscribable: Any, expected_value: Collection[Any], timeout: Union[None, int] = None + subscribable: Any, expected_value: list, timeout: Union[None, int] = None ) -> SubscriptionStatus: def value_is(value, **_): - if type(expected_value) == list: - return value in expected_value - else: - raise TypeError(f"{expected_value} is not a Collection type") + return value in expected_value - return SubscriptionStatus(subscribable, value_is, timeout=timeout) + if type(expected_value) != list: + raise TypeError(f"expected value {expected_value} is not a list") + else: + return SubscriptionStatus(subscribable, value_is, timeout=timeout) diff --git a/tests/devices/unit_tests/test_status.py b/tests/devices/unit_tests/test_status.py new file mode 100644 index 0000000000..a591292eca --- /dev/null +++ b/tests/devices/unit_tests/test_status.py @@ -0,0 +1,29 @@ +import pytest +from ophyd import Component, Device, EpicsSignalRO +from ophyd.sim import make_fake_device + +from dodal.devices.status import await_value_in_list + + +class FakeDevice(Device): + pv: EpicsSignalRO = Component(EpicsSignalRO, "test") + + +@pytest.fixture +def fake_device(): + MyFakeDevice = make_fake_device(FakeDevice) + fake_device = MyFakeDevice(name="test") + return fake_device + + +@pytest.mark.parametrize("awaited_value", [(1), (5.3), (False)]) +def test_await_value_in_list_with_no_list_parameter_fails(awaited_value, fake_device): + with pytest.raises(TypeError): + await_value_in_list(fake_device.pv, awaited_value) + + +def test_await_value_in_list_success(fake_device): + status = await_value_in_list(fake_device.pv, [1, 2, 3, 4, 5]) + assert status.done is False + fake_device.pv.sim_put(5) + status.wait(timeout=1) From b819be2a0aea37682fe89668bf4c637c75eab661 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Wed, 21 Jun 2023 16:52:04 +0100 Subject: [PATCH 24/27] linting --- src/dodal/devices/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dodal/devices/status.py b/src/dodal/devices/status.py index 4690a026b4..2d5f8d5b94 100644 --- a/src/dodal/devices/status.py +++ b/src/dodal/devices/status.py @@ -1,4 +1,4 @@ -from typing import Any, Collection, TypeVar, Union +from typing import Any, TypeVar, Union from ophyd.status import SubscriptionStatus From a0498c288de026babcfabba64aa6c4fd0f61774b Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Wed, 21 Jun 2023 16:59:49 +0100 Subject: [PATCH 25/27] extra test runs in RunEngine --- tests/devices/unit_tests/test_attenuator.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/devices/unit_tests/test_attenuator.py b/tests/devices/unit_tests/test_attenuator.py index 8b91568d74..35f966c066 100644 --- a/tests/devices/unit_tests/test_attenuator.py +++ b/tests/devices/unit_tests/test_attenuator.py @@ -35,5 +35,6 @@ def test_set_transmission_success(fake_attenuator: Attenuator): fake_attenuator.set(1.0).wait(1) -def test_set_transmission_in_run_engine(fake_attenuator: Attenuator, RE: RunEngine): - yield from bps.abs_set(fake_attenuator, 1, wait=True) +def test_set_transmission_in_run_engine(fake_attenuator: Attenuator): + RE = RunEngine() + RE(bps.abs_set(fake_attenuator, 1, wait=True)) From 270662f8e458aee301384c5647b0ac92b2af2e36 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Thu, 22 Jun 2023 16:15:33 +0100 Subject: [PATCH 26/27] fix attenuator PVs --- src/dodal/devices/attenuator.py | 86 ++++++++++++++------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/src/dodal/devices/attenuator.py b/src/dodal/devices/attenuator.py index a8b6c79c1c..75a6b32154 100644 --- a/src/dodal/devices/attenuator.py +++ b/src/dodal/devices/attenuator.py @@ -33,60 +33,46 @@ def set(self, transmission) -> SubscriptionStatus: ) return status - calulated_filter_state_1: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B0") - calulated_filter_state_2: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B1") - calulated_filter_state_3: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B2") - calulated_filter_state_4: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B3") - calulated_filter_state_5: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B4") - calulated_filter_state_6: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B5") - calulated_filter_state_7: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B6") - calulated_filter_state_8: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B7") - calulated_filter_state_9: EpicsSignalRO = Component(EpicsSignalRO, ":DEC_TO_BIN.B8") - calulated_filter_state_10: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.B9" - ) - calulated_filter_state_11: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BA" - ) - calulated_filter_state_12: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BB" - ) - calulated_filter_state_13: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BC" - ) - calulated_filter_state_14: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BD" - ) - calulated_filter_state_15: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BE" - ) - calulated_filter_state_16: EpicsSignalRO = Component( - EpicsSignalRO, ":DEC_TO_BIN.BF" - ) + calulated_filter_state_1: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B0") + calulated_filter_state_2: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B1") + calulated_filter_state_3: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B2") + calulated_filter_state_4: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B3") + calulated_filter_state_5: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B4") + calulated_filter_state_6: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B5") + calulated_filter_state_7: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B6") + calulated_filter_state_8: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B7") + calulated_filter_state_9: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B8") + calulated_filter_state_10: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.B9") + calulated_filter_state_11: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.BA") + calulated_filter_state_12: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.BB") + calulated_filter_state_13: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.BC") + calulated_filter_state_14: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.BD") + calulated_filter_state_15: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.BE") + calulated_filter_state_16: EpicsSignalRO = Component(EpicsSignalRO, "DEC_TO_BIN.BF") - filter_1: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER1") - filter_2: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER2") - filter_3: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER3") - filter_4: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER4") - filter_5: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER5") - filter_6: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER6") - filter_7: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER7") - filter_8: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER8") - filter_9: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER9") - filter_10: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER10") - filter_11: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER11") - filter_12: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER12") - filter_13: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER13") - filter_14: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER14") - filter_15: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER15") - filter_16: AtteunatorFilter = Component(AtteunatorFilter, ":FILTER16") + filter_1: AtteunatorFilter = Component(AtteunatorFilter, "FILTER1") + filter_2: AtteunatorFilter = Component(AtteunatorFilter, "FILTER2") + filter_3: AtteunatorFilter = Component(AtteunatorFilter, "FILTER3") + filter_4: AtteunatorFilter = Component(AtteunatorFilter, "FILTER4") + filter_5: AtteunatorFilter = Component(AtteunatorFilter, "FILTER5") + filter_6: AtteunatorFilter = Component(AtteunatorFilter, "FILTER6") + filter_7: AtteunatorFilter = Component(AtteunatorFilter, "FILTER7") + filter_8: AtteunatorFilter = Component(AtteunatorFilter, "FILTER8") + filter_9: AtteunatorFilter = Component(AtteunatorFilter, "FILTER9") + filter_10: AtteunatorFilter = Component(AtteunatorFilter, "FILTER10") + filter_11: AtteunatorFilter = Component(AtteunatorFilter, "FILTER11") + filter_12: AtteunatorFilter = Component(AtteunatorFilter, "FILTER12") + filter_13: AtteunatorFilter = Component(AtteunatorFilter, "FILTER13") + filter_14: AtteunatorFilter = Component(AtteunatorFilter, "FILTER14") + filter_15: AtteunatorFilter = Component(AtteunatorFilter, "FILTER15") + filter_16: AtteunatorFilter = Component(AtteunatorFilter, "FILTER16") - desired_transmission: EpicsSignal = Component(EpicsSignal, ":T2A:SETVAL1") + desired_transmission: EpicsSignal = Component(EpicsSignal, "T2A:SETVAL1") use_current_energy: EpicsSignal = Component( - EpicsSignal, ":E2WL:USECURRENTENERY.PROC" + EpicsSignal, "E2WL:USECURRENTENERY.PROC" ) - change: EpicsSignal = Component(EpicsSignal, ":FANOUT") - actual_transmission: EpicsSignal = Component(EpicsSignal, ":MATCH") + change: EpicsSignal = Component(EpicsSignal, "FANOUT") + actual_transmission: EpicsSignal = Component(EpicsSignal, "MATCH") detector_params: Optional[DetectorParams] = None From 7cadcd91d9ac567e2c99e8c75a2e5a11feb8b670 Mon Sep 17 00:00:00 2001 From: Oliver Silvester Date: Tue, 27 Jun 2023 10:39:40 +0100 Subject: [PATCH 27/27] remove awaiting for acquire_status --- src/dodal/devices/xspress3_mini/xspress3_mini.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dodal/devices/xspress3_mini/xspress3_mini.py b/src/dodal/devices/xspress3_mini/xspress3_mini.py index ff10972417..dbf83d4884 100644 --- a/src/dodal/devices/xspress3_mini/xspress3_mini.py +++ b/src/dodal/devices/xspress3_mini/xspress3_mini.py @@ -98,5 +98,4 @@ def arm(self) -> Status: self.trigger_mode_mini.put(TriggerMode.BURST.value) self.do_start().wait(timeout=10) arm_status = await_value_in_list(self.detector_state, self.detector_busy_states) - arm_status &= self.acquire_status return arm_status