diff --git a/src/dodal/beamlines/__init__.py b/src/dodal/beamlines/__init__.py index e8a1a03be9..77a398c838 100644 --- a/src/dodal/beamlines/__init__.py +++ b/src/dodal/beamlines/__init__.py @@ -10,8 +10,11 @@ # dictionary, which maps ${BEAMLINE} to dodal.beamlines. _BEAMLINE_NAME_OVERRIDES = { "i05-1": "i05_1", + "i06-1": "i06_1", + "i06-2": "i06_2", "b07-1": "b07_1", "i09-1": "i09_1", + "i09-2": "i09_2", "i13-1": "i13_1", "i15-1": "i15_1", "i10-1": "i10_1", diff --git a/src/dodal/beamlines/i06.py b/src/dodal/beamlines/i06.py new file mode 100644 index 0000000000..76fe477a64 --- /dev/null +++ b/src/dodal/beamlines/i06.py @@ -0,0 +1,20 @@ +from dodal.beamlines.i06_shared import devices as i06_shared_devices +from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline +from dodal.device_manager import DeviceManager +from dodal.devices.motors import XYPhiStage +from dodal.log import set_beamline as set_log_beamline +from dodal.utils import BeamlinePrefix, get_beamline_name + +BL = get_beamline_name("i06") +PREFIX = BeamlinePrefix(BL) +set_log_beamline(BL) +set_utils_beamline(BL) + +devices = DeviceManager() +devices.include(i06_shared_devices) + + +@devices.factory +def ps() -> XYPhiStage: + """PEEM manipulating sample stage.""" + return XYPhiStage(f"{PREFIX.beamline_prefix}-MO-PEEM-01:", phi_infix="PHI:OS") diff --git a/src/dodal/beamlines/i06_1.py b/src/dodal/beamlines/i06_1.py index fc11e83986..b98a1d6a9e 100644 --- a/src/dodal/beamlines/i06_1.py +++ b/src/dodal/beamlines/i06_1.py @@ -1,9 +1,9 @@ from dodal.beamlines.i06_shared import devices as i06_shared_devices from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.device_manager import DeviceManager -from dodal.devices.temperture_controller import ( - Lakeshore336, -) +from dodal.devices.beamlines.i06_1 import DiffractionDichroism +from dodal.devices.motors import XYThetaStage +from dodal.devices.temperture_controller import Lakeshore336 from dodal.log import set_beamline as set_log_beamline from dodal.utils import BeamlinePrefix, get_beamline_name @@ -24,3 +24,13 @@ def diff_cooling_temperature_controller() -> Lakeshore336: @devices.factory() def diff_heating_temperature_controller() -> Lakeshore336: return Lakeshore336(prefix=f"{PREFIX.beamline_prefix}-EA-TCTRL-03:") + + +@devices.factory() +def xabs() -> XYThetaStage: + return XYThetaStage(f"{PREFIX.beamline_prefix}-EA-XABS-01:") + + +@devices.factory() +def dd() -> DiffractionDichroism: + return DiffractionDichroism(f"{PREFIX.beamline_prefix}-EA-DDIFF-01:") diff --git a/src/dodal/beamlines/i06_2.py b/src/dodal/beamlines/i06_2.py new file mode 100644 index 0000000000..54b5d4e810 --- /dev/null +++ b/src/dodal/beamlines/i06_2.py @@ -0,0 +1,18 @@ +from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline +from dodal.device_manager import DeviceManager +from dodal.devices.beamlines.i06_2 import PEEMManipulator +from dodal.log import set_beamline as set_log_beamline +from dodal.utils import BeamlinePrefix, get_beamline_name + +BL = get_beamline_name("i06_2") +PREFIX = BeamlinePrefix(BL, suffix="K") +set_log_beamline(BL) +set_utils_beamline(BL) + + +devices = DeviceManager() + + +@devices.factory +def peem() -> PEEMManipulator: + return PEEMManipulator(f"{PREFIX.beamline_prefix}-MO-PEEM-01:") diff --git a/src/dodal/devices/beamlines/i06_1/__init__.py b/src/dodal/devices/beamlines/i06_1/__init__.py new file mode 100644 index 0000000000..f9bccf1328 --- /dev/null +++ b/src/dodal/devices/beamlines/i06_1/__init__.py @@ -0,0 +1,4 @@ +from .led_light import LEDLight +from .motors import DiffractionDichroism + +__all__ = ["LEDLight", "DiffractionDichroism"] diff --git a/src/dodal/devices/beamlines/i06_1/led_light.py b/src/dodal/devices/beamlines/i06_1/led_light.py new file mode 100644 index 0000000000..58ad56542c --- /dev/null +++ b/src/dodal/devices/beamlines/i06_1/led_light.py @@ -0,0 +1,15 @@ +from ophyd_async.core import StandardReadable +from ophyd_async.epics.core import epics_signal_rw + +from dodal.common.enums import OnOffUpper + + +class LEDLight(StandardReadable): + """LED with brightness intensity and switch on/off control.""" + + def __init__(self, prefix: str, name: str = ""): + with self.add_children_as_readables(): + self.intensity = epics_signal_rw(float, prefix + "PWMDEMAND") + self.switch = epics_signal_rw(OnOffUpper, prefix + "TOGGLE") + + super().__init__(name) diff --git a/src/dodal/devices/beamlines/i06_1/motors.py b/src/dodal/devices/beamlines/i06_1/motors.py new file mode 100644 index 0000000000..aaa23d5173 --- /dev/null +++ b/src/dodal/devices/beamlines/i06_1/motors.py @@ -0,0 +1,29 @@ +from ophyd_async.epics.motor import Motor + +from dodal.devices.beamlines.i06_1.led_light import LEDLight +from dodal.devices.motors import XYZThetaStage + + +class DiffractionDichroism(XYZThetaStage): + def __init__(self, prefix: str, name: str = ""): + with self.add_children_as_readables(): + # Additional Motors + self.chi = Motor(prefix + "CHI") + self.phi = Motor(prefix + "PHI") + self.twotheta = Motor(prefix + "DET:2THETA") + self.dy = Motor(prefix + "DET:Y") + # Camera lights + self.cl1 = LEDLight(prefix + "LED1:") + self.cl2 = LEDLight(prefix + "LED2:") + self.cl3 = LEDLight(prefix + "LED3:") + self.cl4 = LEDLight(prefix + "LED4:") + self.cl5 = LEDLight(prefix + "LED5:") + + super().__init__( + prefix=prefix, + name=name, + x_infix="SMPL:X", + y_infix="SMPL:Y", + z_infix="SMPL:Z", + theta_infix="THETA", + ) diff --git a/src/dodal/devices/beamlines/i06_2/__init__.py b/src/dodal/devices/beamlines/i06_2/__init__.py new file mode 100644 index 0000000000..3508a9954b --- /dev/null +++ b/src/dodal/devices/beamlines/i06_2/__init__.py @@ -0,0 +1,3 @@ +from .motors import PEEMManipulator + +__all__ = ["PEEMManipulator"] diff --git a/src/dodal/devices/beamlines/i06_2/motors.py b/src/dodal/devices/beamlines/i06_2/motors.py new file mode 100644 index 0000000000..e6fe360a61 --- /dev/null +++ b/src/dodal/devices/beamlines/i06_2/motors.py @@ -0,0 +1,22 @@ +from ophyd_async.epics.motor import Motor + +from dodal.devices.motors import _PHI, _X, _Y, XYPhiStage + + +class PEEMManipulator(XYPhiStage): + """Four-axis stage with a standard xy stage and one axis of rotation: phi. This + also has an additional energy slit (es) translational motor. + """ + + def __init__( + self, + prefix: str, + x_infix: str = _X, + y_infix: str = _Y, + phi_infix: str = _PHI, + es_infix: str = "ES:TRANS", + name: str = "", + ) -> None: + with self.add_children_as_readables(): + self.es = Motor(prefix + es_infix) + super().__init__(prefix, x_infix, y_infix, phi_infix, name) diff --git a/src/dodal/devices/motors.py b/src/dodal/devices/motors.py index e94710b146..684b6822a6 100644 --- a/src/dodal/devices/motors.py +++ b/src/dodal/devices/motors.py @@ -19,6 +19,7 @@ _Y = "Y" _Z = "Z" +_THETA = "THETA" _OMEGA = "OMEGA" _PHI = "PHI" _POLAR = "POLAR" @@ -111,7 +112,7 @@ def __init__( x_infix: str = _X, y_infix: str = _Y, z_infix: str = _Z, - theta_infix: str = "THETA", + theta_infix: str = _THETA, ) -> None: with self.add_children_as_readables(): self.theta = Motor(prefix + theta_infix) @@ -231,6 +232,22 @@ def __init__( super().__init__(prefix, name, x_infix, y_infix) +class XYThetaStage(XYStage): + """Three-axis stage with a standard xy stage and one axis of rotation: theta.""" + + def __init__( + self, + prefix: str, + x_infix: str = _X, + y_infix: str = _Y, + theta_infix: str = _THETA, + name: str = "", + ) -> None: + with self.add_children_as_readables(): + self.theta = Motor(prefix + theta_infix) + super().__init__(prefix, name, x_infix, y_infix) + + class XYPitchStage(XYStage): """Three-axis stage with a standard xy stage and one axis of rotation: pitch.""" diff --git a/tests/devices/beamlines/i06_1/__init__.py b/tests/devices/beamlines/i06_1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/devices/beamlines/i06_1/test_led_light.py b/tests/devices/beamlines/i06_1/test_led_light.py new file mode 100644 index 0000000000..00f3a5e735 --- /dev/null +++ b/tests/devices/beamlines/i06_1/test_led_light.py @@ -0,0 +1,23 @@ +import pytest +from ophyd_async.core import init_devices +from ophyd_async.testing import assert_reading, partial_reading + +from dodal.common.enums import OnOffUpper +from dodal.devices.beamlines.i06_1 import LEDLight + + +@pytest.fixture +def led_light() -> LEDLight: + with init_devices(mock=True): + led_light = LEDLight("TEST:") + return led_light + + +async def test_led_light_read(led_light: LEDLight) -> None: + await assert_reading( + led_light, + { + "led_light-intensity": partial_reading(0), + "led_light-switch": partial_reading(OnOffUpper.ON), + }, + ) diff --git a/tests/devices/beamlines/i06_1/test_motors.py b/tests/devices/beamlines/i06_1/test_motors.py new file mode 100644 index 0000000000..addf590d73 --- /dev/null +++ b/tests/devices/beamlines/i06_1/test_motors.py @@ -0,0 +1,39 @@ +import pytest +from ophyd_async.core import init_devices +from ophyd_async.testing import assert_reading, partial_reading + +from dodal.common.enums import OnOffUpper +from dodal.devices.beamlines.i06_1 import DiffractionDichroism + + +@pytest.fixture +def dd() -> DiffractionDichroism: + with init_devices(mock=True): + dd = DiffractionDichroism("TEST:") + return dd + + +async def test_dd_read(dd: DiffractionDichroism) -> None: + await assert_reading( + dd, + { + "dd-x": partial_reading(0), + "dd-y": partial_reading(0), + "dd-z": partial_reading(0), + "dd-theta": partial_reading(0), + "dd-chi": partial_reading(0), + "dd-phi": partial_reading(0), + "dd-twotheta": partial_reading(0), + "dd-dy": partial_reading(0), + "dd-cl1-intensity": partial_reading(0), + "dd-cl1-switch": partial_reading(OnOffUpper.ON), + "dd-cl2-intensity": partial_reading(0), + "dd-cl2-switch": partial_reading(OnOffUpper.ON), + "dd-cl3-intensity": partial_reading(0), + "dd-cl3-switch": partial_reading(OnOffUpper.ON), + "dd-cl4-intensity": partial_reading(0), + "dd-cl4-switch": partial_reading(OnOffUpper.ON), + "dd-cl5-intensity": partial_reading(0), + "dd-cl5-switch": partial_reading(OnOffUpper.ON), + }, + ) diff --git a/tests/devices/beamlines/i06_2/__init__.py b/tests/devices/beamlines/i06_2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/devices/beamlines/i06_2/test_motors.py b/tests/devices/beamlines/i06_2/test_motors.py new file mode 100644 index 0000000000..404bc5ffee --- /dev/null +++ b/tests/devices/beamlines/i06_2/test_motors.py @@ -0,0 +1,24 @@ +import pytest +from ophyd_async.core import init_devices +from ophyd_async.testing import assert_reading, partial_reading + +from dodal.devices.beamlines.i06_2 import PEEMManipulator + + +@pytest.fixture +def peem() -> PEEMManipulator: + with init_devices(mock=True): + peem = PEEMManipulator("TEST:") + return peem + + +async def test_peem_read(peem: PEEMManipulator) -> None: + await assert_reading( + peem, + { + "peem-x": partial_reading(0), + "peem-y": partial_reading(0), + "peem-phi": partial_reading(0), + "peem-es": partial_reading(0), + }, + )