Skip to content

Commit ae850c3

Browse files
authored
Fixes #1787 Add I19 filter wheel selections (#1954)
* Fixes #1787 Add I19 filter wheel selections * Add filter wheel with all six indexed positions * Changes requested in code review
1 parent 4d732f7 commit ae850c3

File tree

3 files changed

+134
-16
lines changed

3 files changed

+134
-16
lines changed

src/dodal/beamlines/i19_optics.py

Lines changed: 105 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
from ophyd_async.epics.motor import Motor
2+
13
from dodal.common.beamlines.beamline_utils import (
24
set_beamline as set_utils_beamline,
35
)
46
from dodal.device_manager import DeviceManager
7+
from dodal.devices.attenuator.filter import FilterWheel
8+
from dodal.devices.attenuator.filter_selections import I19FilterOneSelections
59
from dodal.devices.beamlines.i19.access_controlled.hutch_access import (
610
ACCESS_DEVICE_NAME,
711
HutchAccessControl,
@@ -20,32 +24,119 @@
2024

2125

2226
@devices.factory()
23-
def shutter() -> InterlockedHutchShutter:
24-
"""Real experiment shutter device for I19."""
25-
return InterlockedHutchShutter(
26-
PREFIX.beamline_prefix, HutchInterlock(PREFIX.beamline_prefix)
27-
)
27+
def access_control() -> HutchAccessControl:
28+
"""Device factory for access control device.
2829
30+
I19 features two experimental hutches, EH-1 and EH-2,
31+
longitudinally positioned downstream from the common optics hutch:
32+
Only one active EH can control the optics.
33+
This device checks which EH is the active hutch.
2934
30-
@devices.factory()
31-
def access_control() -> HutchAccessControl:
32-
"""Device to check which hutch is the active hutch on i19."""
35+
Uses:
36+
I19 beamline prefix extended with an infix specific to the access control.
37+
Name of the access device in i19-blueapi.
38+
"""
3339
return HutchAccessControl(
3440
f"{PREFIX.beamline_prefix}-OP-STAT-01:", ACCESS_DEVICE_NAME
3541
)
3642

3743

3844
@devices.factory()
39-
def vfm() -> FocusingMirrorWithPiezo:
40-
"""Get the i19 vfm device, instantiate it if it hasn't already been.
41-
If this is called when already instantiated, it will return the existing object.
45+
def attenuator_x_motor() -> Motor:
46+
"""Device factory for the I19 attenuator x-axis motor.
47+
48+
The x-axis linear motor drives an absorber wedge horizontally orthogonal to the x-ray beam.
49+
50+
Uses:
51+
Prefix for the I19 beamline extended with an infix specific to the attenuator x-axis motor.
52+
Name of the attenuator system x-axis motor device.
53+
54+
Returns:
55+
Device for the x-axis attenuation system motor.
4256
"""
43-
return FocusingMirrorWithPiezo(f"{PREFIX.beamline_prefix}-OP-VFM-01:")
57+
return Motor(f"{PREFIX.beamline_prefix}-OP-ATTN-04:X", "attenuator_x")
58+
59+
60+
@devices.factory()
61+
def attenuator_y_motor() -> Motor:
62+
"""Device factory for the I19 attenuator y-axis motor.
63+
64+
The y-axis linear motor drives an absorber wedge vertically orthogonal to the x-ray beam.
65+
66+
Uses:
67+
Prefix for the I19 beamline extended with an infix specific to the attenuator y-axis motor.
68+
Name of the attenuator system y-axis motor device.
69+
70+
Returns:
71+
Device for the y-axis attenuation system motor.
72+
"""
73+
return Motor(f"{PREFIX.beamline_prefix}-OP-ATTN-05:Y", "attenuator_y")
74+
75+
76+
@devices.factory()
77+
def filter_wheel() -> FilterWheel:
78+
"""Device factory for the I19 EH-1 filter wheel indexing motor.
79+
80+
Filter wheel motor rotates indexed wheel to bring specific attenuating filter into/out of x-ray beam.
81+
82+
Uses:
83+
Beamline prefix for I19 extended with infix specific to the filter motor.
84+
A further infix specific to filter wheel usage.
85+
Name of the first filter wheel.
86+
87+
Returns:
88+
First indexed filter wheel slot selecting rotation device.
89+
"""
90+
return FilterWheel(
91+
prefix=f"{PREFIX.beamline_prefix}-MO-FILT-01:",
92+
filter_infix="FILTER",
93+
filter_selections=I19FilterOneSelections,
94+
name="filter_w_1",
95+
)
4496

4597

4698
@devices.factory()
4799
def hfm() -> FocusingMirrorWithPiezo:
48-
"""Get the i19 hfm device, instantiate it if it hasn't already been.
49-
If this is called when already instantiated, it will return the existing object.
100+
"""Device factory for the I19 Horizontal Focus Mirror (HFM) Piezo Device.
101+
102+
Lazy instantiation: Instantiates a device object if none have been,
103+
else it will return the pre-existing instance.
104+
105+
Uses:
106+
I19 beamline prefix extended with an infix specific to the HFM.
107+
108+
Returns:
109+
Focusing mirror piezo device for the HFM.
50110
"""
51111
return FocusingMirrorWithPiezo(f"{PREFIX.beamline_prefix}-OP-HFM-01:")
112+
113+
114+
def shutter() -> InterlockedHutchShutter:
115+
"""Device factory for the I19 optics hutch shutter device.
116+
117+
Uses:
118+
I19 beamline prefix extended with an infix specific to the optics hutch shutter.
119+
HutchInterlock device (itself using I19 beamline prefix)
120+
121+
Returns:
122+
I19 optics hutch shutter device.
123+
"""
124+
return InterlockedHutchShutter(
125+
PREFIX.beamline_prefix, HutchInterlock(PREFIX.beamline_prefix)
126+
)
127+
128+
129+
@devices.factory()
130+
def vfm() -> FocusingMirrorWithPiezo:
131+
"""Device factory for the I19 Vertical Focus Mirror (VFM) Piezo Device.
132+
133+
Lazy instantiation: Instantiates a device object if none have been,
134+
else it will return the pre-existing instance.
135+
136+
Uses:
137+
I19 beamline prefix with VFM infix.
138+
139+
Returns:
140+
Focusing mirror piezo device for the VFM.
141+
"""
142+
return FocusingMirrorWithPiezo(f"{PREFIX.beamline_prefix}-OP-VFM-01:")

src/dodal/devices/attenuator/filter.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from ophyd_async.core import StandardReadable, SubsetEnum
1+
from ophyd_async.core import StandardReadable, StrictEnum, SubsetEnum
22
from ophyd_async.epics.core import epics_signal_rw
33

44

@@ -12,3 +12,21 @@ def __init__(
1212
int, f"{prefix}DMOV"
1313
) # 1 for yes, 0 for no
1414
super().__init__(name=name)
15+
16+
17+
class FilterWheel(StandardReadable):
18+
def __init__(
19+
self,
20+
prefix: str,
21+
filter_infix: str,
22+
filter_selections: type[StrictEnum | SubsetEnum],
23+
name: str = "",
24+
):
25+
filter_prefix: str = f"{prefix}{filter_infix}"
26+
with self.add_children_as_readables():
27+
self.user_setpoint = epics_signal_rw(
28+
datatype=filter_selections,
29+
read_pv=filter_prefix,
30+
write_pv=filter_prefix,
31+
)
32+
super().__init__(name=name)

src/dodal/devices/attenuator/filter_selections.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from ophyd_async.core import SubsetEnum
1+
from ophyd_async.core import StrictEnum, SubsetEnum
22

33

44
class P99FilterSelections(SubsetEnum):
@@ -72,6 +72,15 @@ class I02_1FilterFourSelections(SubsetEnum): # noqa: N801
7272
TI500 = "Ti500"
7373

7474

75+
class I19FilterOneSelections(StrictEnum):
76+
AIR1 = "1 - "
77+
AL = "2 - Al"
78+
AIR3 = "3 - "
79+
AU = "4 - Au"
80+
AIR5 = "5 - "
81+
FE = "6 - Fe"
82+
83+
7584
class I24FilterOneSelections(SubsetEnum):
7685
EMPTY = "Empty"
7786
AL12_5 = "Al12.5"

0 commit comments

Comments
 (0)