dls-dodal 1.36.2__py3-none-any.whl → 1.37.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/METADATA +4 -4
- {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/RECORD +54 -38
- {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamlines/i02_1.py +37 -0
- dodal/beamlines/i03.py +20 -3
- dodal/beamlines/i04.py +3 -3
- dodal/beamlines/i10.py +179 -7
- dodal/beamlines/i22.py +15 -0
- dodal/beamlines/i24.py +2 -2
- dodal/beamlines/p99.py +6 -2
- dodal/common/crystal_metadata.py +3 -3
- dodal/common/udc_directory_provider.py +3 -1
- dodal/devices/aperturescatterguard.py +3 -0
- dodal/devices/apple2_undulator.py +9 -9
- dodal/devices/{attenuator.py → attenuator/attenuator.py} +29 -1
- dodal/devices/attenuator/filter.py +11 -0
- dodal/devices/attenuator/filter_selections.py +72 -0
- dodal/devices/bimorph_mirror.py +151 -0
- dodal/devices/current_amplifiers/__init__.py +34 -0
- dodal/devices/current_amplifiers/current_amplifier.py +103 -0
- dodal/devices/current_amplifiers/current_amplifier_detector.py +109 -0
- dodal/devices/current_amplifiers/femto.py +143 -0
- dodal/devices/current_amplifiers/sr570.py +214 -0
- dodal/devices/current_amplifiers/struck_scaler_counter.py +79 -0
- dodal/devices/detector/det_dim_constants.py +15 -0
- dodal/devices/eiger_odin.py +3 -3
- dodal/devices/fast_grid_scan.py +8 -3
- dodal/devices/i03/beamstop.py +85 -0
- dodal/devices/i04/transfocator.py +67 -53
- dodal/devices/i10/i10_setting_data.py +3 -3
- dodal/devices/i10/mirrors.py +24 -0
- dodal/devices/i10/rasor/rasor_current_amp.py +72 -0
- dodal/devices/i10/rasor/rasor_motors.py +62 -0
- dodal/devices/i10/rasor/rasor_scaler_cards.py +12 -0
- dodal/devices/i10/slits.py +37 -0
- dodal/devices/i24/dual_backlight.py +1 -0
- dodal/devices/i24/focus_mirrors.py +12 -12
- dodal/devices/linkam3.py +2 -2
- dodal/devices/p99/sample_stage.py +2 -28
- dodal/devices/robot.py +2 -2
- dodal/devices/slits.py +29 -7
- dodal/devices/tetramm.py +16 -16
- dodal/devices/undulator_dcm.py +9 -11
- dodal/devices/util/test_utils.py +2 -2
- dodal/devices/xspress3/xspress3.py +3 -3
- dodal/devices/zebra.py +19 -14
- dodal/devices/zocalo/zocalo_interaction.py +2 -1
- dodal/devices/zocalo/zocalo_results.py +22 -2
- dodal/log.py +2 -2
- dodal/plans/wrapped.py +3 -3
- {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import math
|
|
2
|
-
from time import sleep, time
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
from ophyd_async.core import (
|
|
5
|
+
AsyncStatus,
|
|
6
|
+
StandardReadable,
|
|
7
|
+
observe_value,
|
|
8
|
+
wait_for_value,
|
|
9
|
+
)
|
|
10
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
7
11
|
|
|
8
12
|
from dodal.log import LOGGER
|
|
9
13
|
|
|
10
14
|
|
|
11
|
-
class Transfocator(
|
|
15
|
+
class Transfocator(StandardReadable):
|
|
12
16
|
"""The transfocator is a device that puts a number of lenses in the beam to change
|
|
13
17
|
its shape.
|
|
14
18
|
|
|
@@ -18,34 +22,50 @@ class Transfocator(Device):
|
|
|
18
22
|
my_transfocator.set(vert_beamsize_microns)
|
|
19
23
|
"""
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
def __init__(self, prefix: str, name: str = ""):
|
|
26
|
+
with self.add_children_as_readables():
|
|
27
|
+
self.beamsize_set_microns = epics_signal_rw(float, prefix + "VERT_REQ")
|
|
28
|
+
self.predicted_vertical_num_lenses = epics_signal_rw(
|
|
29
|
+
float, prefix + "LENS_PRED"
|
|
30
|
+
)
|
|
31
|
+
self.number_filters_sp = epics_signal_rw(int, prefix + "NUM_FILTERS")
|
|
32
|
+
self.start = epics_signal_rw(int, prefix + "START.PROC")
|
|
33
|
+
self.start_rbv = epics_signal_r(int, prefix + "START_RBV")
|
|
34
|
+
self.vertical_lens_rbv = epics_signal_r(float, prefix + "VER")
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
_POLLING_WAIT = 0.01
|
|
36
|
+
self.TIMEOUT = 120
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
# For some reason couldn't get monitors working on START_RBV
|
|
36
|
-
# (See https://github.com/DiamondLightSource/dodal/issues/152)
|
|
37
|
-
start_time = time()
|
|
38
|
-
while time() < start_time + self.TIMEOUT:
|
|
39
|
-
RBV_value = self.start_rbv.get()
|
|
40
|
-
if RBV_value == for_value:
|
|
41
|
-
return
|
|
42
|
-
sleep(self._POLLING_WAIT)
|
|
38
|
+
super().__init__(name=name)
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
raise TimeoutError()
|
|
40
|
+
async def _observe_beamsize_microns(self):
|
|
41
|
+
is_set_filters_done = False
|
|
47
42
|
|
|
48
|
-
|
|
43
|
+
async def set_based_on_prediction(value: float):
|
|
44
|
+
if not math.isclose(
|
|
45
|
+
self.latest_pred_vertical_num_lenses, value, abs_tol=1e-8
|
|
46
|
+
):
|
|
47
|
+
# We can only put an integer number of lenses in the beam but the
|
|
48
|
+
# calculation in the IOC returns the theoretical float number of lenses
|
|
49
|
+
nonlocal is_set_filters_done
|
|
50
|
+
value = round(value)
|
|
51
|
+
LOGGER.info(f"Transfocator setting {value} filters")
|
|
52
|
+
await self.number_filters_sp.set(value)
|
|
53
|
+
await self.start.set(1)
|
|
54
|
+
LOGGER.info("Waiting for start_rbv to change to 1")
|
|
55
|
+
await wait_for_value(self.start_rbv, 1, self.TIMEOUT)
|
|
56
|
+
LOGGER.info("Waiting for start_rbv to change to 0")
|
|
57
|
+
await wait_for_value(self.start_rbv, 0, self.TIMEOUT)
|
|
58
|
+
self.latest_pred_vertical_num_lenses = value
|
|
59
|
+
is_set_filters_done = True
|
|
60
|
+
|
|
61
|
+
# The value hasn't changed so assume the device is already set up correctly
|
|
62
|
+
async for value in observe_value(self.predicted_vertical_num_lenses):
|
|
63
|
+
await set_based_on_prediction(value)
|
|
64
|
+
if is_set_filters_done:
|
|
65
|
+
break
|
|
66
|
+
|
|
67
|
+
@AsyncStatus.wrap
|
|
68
|
+
async def set(self, value: float):
|
|
49
69
|
"""To set the beamsize on the transfocator we must:
|
|
50
70
|
1. Set the beamsize in the calculator part of the transfocator
|
|
51
71
|
2. Get the predicted number of lenses needed from this calculator
|
|
@@ -53,30 +73,24 @@ class Transfocator(Device):
|
|
|
53
73
|
4. Start the device moving
|
|
54
74
|
5. Wait for the start_rbv goes high and low again
|
|
55
75
|
"""
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
self.latest_pred_vertical_num_lenses = (
|
|
77
|
+
await self.predicted_vertical_num_lenses.get_value()
|
|
78
|
+
)
|
|
58
79
|
|
|
59
|
-
|
|
60
|
-
if not math.isclose(old_value, value, abs_tol=1e-8):
|
|
61
|
-
self.predicted_vertical_num_lenses.unsubscribe(subscriber)
|
|
80
|
+
LOGGER.info(f"Transfocator setting {value} beamsize")
|
|
62
81
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
self.
|
|
68
|
-
self.start.set(1).wait()
|
|
69
|
-
self.polling_wait_on_start_rbv(1)
|
|
70
|
-
self.polling_wait_on_start_rbv(0)
|
|
71
|
-
# The value hasn't changed so assume the device is already set up correctly
|
|
72
|
-
status.set_finished()
|
|
73
|
-
|
|
74
|
-
LOGGER.info(f"Transfocator setting {beamsize_microns} beamsize")
|
|
75
|
-
if self.beamsize_set_microns.get() != beamsize_microns:
|
|
76
|
-
subscriber = self.predicted_vertical_num_lenses.subscribe(
|
|
77
|
-
set_based_on_predicition, run=False
|
|
82
|
+
if await self.beamsize_set_microns.get_value() != value:
|
|
83
|
+
# Logic in the IOC calculates predicted_vertical_num_lenses when beam_set_microns changes
|
|
84
|
+
await asyncio.gather(
|
|
85
|
+
self.beamsize_set_microns.set(value),
|
|
86
|
+
self._observe_beamsize_microns(),
|
|
78
87
|
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
88
|
+
|
|
89
|
+
number_filters_rbv, vertical_lens_size_rbv = await asyncio.gather(
|
|
90
|
+
self.number_filters_sp.get_value(),
|
|
91
|
+
self.vertical_lens_rbv.get_value(),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
LOGGER.info(
|
|
95
|
+
f"Transfocator set complete. Number of filters is: {number_filters_rbv} and Vertical beam size is: {vertical_lens_size_rbv}"
|
|
96
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
3
|
+
from ophyd_async.epics.motor import Motor
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PiezoMirror(StandardReadable):
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
prefix: str,
|
|
10
|
+
name: str = "",
|
|
11
|
+
):
|
|
12
|
+
with self.add_children_as_readables():
|
|
13
|
+
self.x = Motor(prefix + "X")
|
|
14
|
+
self.y = Motor(prefix + "Y")
|
|
15
|
+
self.z = Motor(prefix + "Z")
|
|
16
|
+
self.yaw = Motor(prefix + "YAW")
|
|
17
|
+
self.pitch = Motor(prefix + "PITCH")
|
|
18
|
+
self.roll = Motor(prefix + "ROLL")
|
|
19
|
+
self.fine_pitch = epics_signal_rw(
|
|
20
|
+
float,
|
|
21
|
+
read_pv=prefix + "FPITCH:RBV:AI",
|
|
22
|
+
write_pv=prefix + "FPITCH:DMD:AO",
|
|
23
|
+
)
|
|
24
|
+
super().__init__(name=name)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from ophyd_async.core import Device
|
|
2
|
+
|
|
3
|
+
from dodal.devices.current_amplifiers import (
|
|
4
|
+
SR570,
|
|
5
|
+
Femto3xxGainTable,
|
|
6
|
+
Femto3xxGainToCurrentTable,
|
|
7
|
+
Femto3xxRaiseTime,
|
|
8
|
+
FemtoDDPCA,
|
|
9
|
+
SR570FineGainTable,
|
|
10
|
+
SR570FullGainTable,
|
|
11
|
+
SR570GainTable,
|
|
12
|
+
SR570GainToCurrentTable,
|
|
13
|
+
SR570RaiseTimeTable,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RasorFemto(Device):
|
|
18
|
+
def __init__(self, prefix: str, suffix: str = "GAIN", name: str = "") -> None:
|
|
19
|
+
self.ca1 = FemtoDDPCA(
|
|
20
|
+
prefix + "-01:",
|
|
21
|
+
suffix=suffix,
|
|
22
|
+
gain_table=Femto3xxGainTable,
|
|
23
|
+
gain_to_current_table=Femto3xxGainToCurrentTable,
|
|
24
|
+
raise_timetable=Femto3xxRaiseTime,
|
|
25
|
+
)
|
|
26
|
+
self.ca2 = FemtoDDPCA(
|
|
27
|
+
prefix + "-02:",
|
|
28
|
+
suffix=suffix,
|
|
29
|
+
gain_table=Femto3xxGainTable,
|
|
30
|
+
gain_to_current_table=Femto3xxGainToCurrentTable,
|
|
31
|
+
raise_timetable=Femto3xxRaiseTime,
|
|
32
|
+
)
|
|
33
|
+
self.ca3 = FemtoDDPCA(
|
|
34
|
+
prefix + "-03:",
|
|
35
|
+
suffix=suffix,
|
|
36
|
+
gain_table=Femto3xxGainTable,
|
|
37
|
+
gain_to_current_table=Femto3xxGainToCurrentTable,
|
|
38
|
+
raise_timetable=Femto3xxRaiseTime,
|
|
39
|
+
)
|
|
40
|
+
super().__init__(name)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class RasorSR570(Device):
|
|
44
|
+
def __init__(self, prefix: str, suffix: str = "SENS:SEL", name: str = "") -> None:
|
|
45
|
+
self.ca1 = SR570(
|
|
46
|
+
prefix + "-04:",
|
|
47
|
+
suffix=suffix,
|
|
48
|
+
fine_gain_table=SR570FineGainTable,
|
|
49
|
+
coarse_gain_table=SR570GainTable,
|
|
50
|
+
combined_table=SR570FullGainTable,
|
|
51
|
+
gain_to_current_table=SR570GainToCurrentTable,
|
|
52
|
+
raise_timetable=SR570RaiseTimeTable,
|
|
53
|
+
)
|
|
54
|
+
self.ca2 = SR570(
|
|
55
|
+
prefix + "-05:",
|
|
56
|
+
suffix=suffix,
|
|
57
|
+
fine_gain_table=SR570FineGainTable,
|
|
58
|
+
coarse_gain_table=SR570GainTable,
|
|
59
|
+
combined_table=SR570FullGainTable,
|
|
60
|
+
gain_to_current_table=SR570GainToCurrentTable,
|
|
61
|
+
raise_timetable=SR570RaiseTimeTable,
|
|
62
|
+
)
|
|
63
|
+
self.ca3 = SR570(
|
|
64
|
+
prefix + "-06:",
|
|
65
|
+
suffix=suffix,
|
|
66
|
+
fine_gain_table=SR570FineGainTable,
|
|
67
|
+
coarse_gain_table=SR570GainTable,
|
|
68
|
+
combined_table=SR570FullGainTable,
|
|
69
|
+
gain_to_current_table=SR570GainToCurrentTable,
|
|
70
|
+
raise_timetable=SR570RaiseTimeTable,
|
|
71
|
+
)
|
|
72
|
+
super().__init__(name)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.motor import Motor
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class PinHole(StandardReadable):
|
|
6
|
+
"Two motors stage for rasor pinhole"
|
|
7
|
+
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
prefix: str,
|
|
11
|
+
name: str = "",
|
|
12
|
+
):
|
|
13
|
+
with self.add_children_as_readables():
|
|
14
|
+
self.x = Motor(prefix + "X")
|
|
15
|
+
self.y = Motor(prefix + "Y")
|
|
16
|
+
super().__init__(name=name)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Diffractometer(StandardReadable):
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
prefix: str,
|
|
23
|
+
name: str = "",
|
|
24
|
+
):
|
|
25
|
+
with self.add_children_as_readables():
|
|
26
|
+
self.tth = Motor(prefix + "TWOTHETA")
|
|
27
|
+
self.th = Motor(prefix + "THETA")
|
|
28
|
+
self.chi = Motor(prefix + "CHI")
|
|
29
|
+
self.chamber_x = Motor(prefix + "X")
|
|
30
|
+
self.alpha = Motor(prefix + "ALPHA")
|
|
31
|
+
super().__init__(name=name)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DetSlits(StandardReadable):
|
|
35
|
+
"Detector slits"
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
prefix: str,
|
|
40
|
+
name: str = "",
|
|
41
|
+
):
|
|
42
|
+
with self.add_children_as_readables():
|
|
43
|
+
self.upstream = Motor(prefix + "1:TRANS")
|
|
44
|
+
self.downstream = Motor(prefix + "2:TRANS")
|
|
45
|
+
super().__init__(name=name)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PaStage(StandardReadable):
|
|
49
|
+
"Rasor detector stage"
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
prefix: str,
|
|
54
|
+
name: str = "",
|
|
55
|
+
):
|
|
56
|
+
with self.add_children_as_readables():
|
|
57
|
+
self.ttp = Motor(prefix + "TWOTHETA")
|
|
58
|
+
self.thp = Motor(prefix + "THETA")
|
|
59
|
+
self.py = Motor(prefix + "Y")
|
|
60
|
+
self.pz = Motor(prefix + "Z")
|
|
61
|
+
self.eta = Motor(prefix + "ETA")
|
|
62
|
+
super().__init__(name=name)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from ophyd_async.core import Device
|
|
2
|
+
|
|
3
|
+
from dodal.devices.current_amplifiers import StruckScaler
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RasorScalerCard1(Device):
|
|
7
|
+
def __init__(self, prefix, name: str = "") -> None:
|
|
8
|
+
self.mon = StruckScaler(prefix=prefix, suffix=".16")
|
|
9
|
+
self.det = StruckScaler(prefix=prefix, suffix=".17")
|
|
10
|
+
self.fluo = StruckScaler(prefix=prefix, suffix=".18")
|
|
11
|
+
self.drain = StruckScaler(prefix=prefix, suffix=".19")
|
|
12
|
+
super().__init__(name)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from ophyd_async.epics.motor import Motor
|
|
2
|
+
|
|
3
|
+
from dodal.devices.slits import Slits
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class I10Slits(Slits):
|
|
7
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
8
|
+
with self.add_children_as_readables():
|
|
9
|
+
self.x_ring_blade = Motor(prefix + "XRING")
|
|
10
|
+
self.x_hall_blade = Motor(prefix + "XHALL")
|
|
11
|
+
self.y_top_blade = Motor(prefix + "YPLUS")
|
|
12
|
+
self.y_bot_blade = Motor(prefix + "YMINUS")
|
|
13
|
+
super().__init__(
|
|
14
|
+
prefix=prefix,
|
|
15
|
+
x_gap="XSIZE",
|
|
16
|
+
x_centre="XCENTRE",
|
|
17
|
+
y_gap="YSIZE",
|
|
18
|
+
y_centre="YCENTRE",
|
|
19
|
+
name=name,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class I10PrimarySlits(Slits):
|
|
24
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
25
|
+
with self.add_children_as_readables():
|
|
26
|
+
self.x_aptr_1 = Motor(prefix + "APTR1:X")
|
|
27
|
+
self.x_aptr_2 = Motor(prefix + "APTR2:X")
|
|
28
|
+
self.y_aptr_1 = Motor(prefix + "APTR1:Y")
|
|
29
|
+
self.y_aptr_1 = Motor(prefix + "APTR2:Y")
|
|
30
|
+
super().__init__(
|
|
31
|
+
prefix=prefix,
|
|
32
|
+
x_gap="XSIZE",
|
|
33
|
+
x_centre="XCENTRE",
|
|
34
|
+
y_gap="YSIZE",
|
|
35
|
+
y_centre="YCENTRE",
|
|
36
|
+
name=name,
|
|
37
|
+
)
|
|
@@ -5,21 +5,21 @@ from dodal.common.signal_utils import create_hardware_backed_soft_signal
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class HFocusMode(StrictEnum):
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
FOCUS_10 = "HMFMfocus10"
|
|
9
|
+
FOCUS_20D = "HMFMfocus20d"
|
|
10
|
+
FOCUS_30D = "HMFMfocus30d"
|
|
11
|
+
FOCUS_50D = "HMFMfocus50d"
|
|
12
|
+
FOCUS_1050D = "HMFMfocus1030d"
|
|
13
|
+
FOCUS_3010D = "HMFMfocus3010d"
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class VFocusMode(StrictEnum):
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
FOCUS_10 = "VMFMfocus10"
|
|
18
|
+
FOCUS_20D = "VMFMfocus20d"
|
|
19
|
+
FOCUS_30D = "VMFMfocus30d"
|
|
20
|
+
FOCUS_50D = "VMFMfocus50d"
|
|
21
|
+
FOCUS_1030D = "VMFMfocus1030d"
|
|
22
|
+
FOCUS_3010D = "VMFMfocus3010d"
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
BEAM_SIZES = {
|
dodal/devices/linkam3.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from ophyd_async.core import StandardReadable
|
|
2
|
-
from ophyd_async.epics.core import
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_rw_rbv
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class SampleAngleStage(StandardReadable):
|
|
@@ -9,29 +9,3 @@ class SampleAngleStage(StandardReadable):
|
|
|
9
9
|
self.roll = epics_signal_rw_rbv(float, prefix + "WRITEROLL", ":RBV")
|
|
10
10
|
self.pitch = epics_signal_rw_rbv(float, prefix + "WRITEPITCH", ":RBV")
|
|
11
11
|
super().__init__(name=name)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class p99StageSelections(SubsetEnum):
|
|
15
|
-
Empty = "Empty"
|
|
16
|
-
Mn5um = "Mn 5um"
|
|
17
|
-
Fe = "Fe (empty)"
|
|
18
|
-
Co5um = "Co 5um"
|
|
19
|
-
Ni5um = "Ni 5um"
|
|
20
|
-
Cu5um = "Cu 5um"
|
|
21
|
-
Zn5um = "Zn 5um"
|
|
22
|
-
Zr = "Zr (empty)"
|
|
23
|
-
Mo = "Mo (empty)"
|
|
24
|
-
Rh = "Rh (empty)"
|
|
25
|
-
Pd = "Pd (empty)"
|
|
26
|
-
Ag = "Ag (empty)"
|
|
27
|
-
Cd25um = "Cd 25um"
|
|
28
|
-
W = "W (empty)"
|
|
29
|
-
Pt = "Pt (empty)"
|
|
30
|
-
User = "User"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class FilterMotor(StandardReadable):
|
|
34
|
-
def __init__(self, prefix: str, name: str = ""):
|
|
35
|
-
with self.add_children_as_readables():
|
|
36
|
-
self.user_setpoint = epics_signal_rw(p99StageSelections, prefix)
|
|
37
|
-
super().__init__(name=name)
|
dodal/devices/robot.py
CHANGED
|
@@ -70,8 +70,8 @@ class BartRobot(StandardReadable, Movable):
|
|
|
70
70
|
self.program_running = epics_signal_r(bool, prefix + "PROGRAM_RUNNING")
|
|
71
71
|
self.program_name = epics_signal_r(str, prefix + "PROGRAM_NAME")
|
|
72
72
|
self.error_str = epics_signal_r(str, prefix + "PRG_ERR_MSG")
|
|
73
|
-
|
|
74
|
-
self.
|
|
73
|
+
self.error_code = epics_signal_r(int, prefix + "PRG_ERR_CODE")
|
|
74
|
+
self.reset = epics_signal_x(prefix + "RESET.PROC")
|
|
75
75
|
super().__init__(name=name)
|
|
76
76
|
|
|
77
77
|
async def pin_mounted_or_no_pin_found(self):
|
dodal/devices/slits.py
CHANGED
|
@@ -2,16 +2,38 @@ from ophyd_async.core import StandardReadable
|
|
|
2
2
|
from ophyd_async.epics.motor import Motor
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class MinimalSlits(StandardReadable):
|
|
6
|
+
"""Gap only X Y slits."""
|
|
7
|
+
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
prefix: str,
|
|
11
|
+
x_gap: str = "X:SIZE",
|
|
12
|
+
y_gap: str = "Y:SIZE",
|
|
13
|
+
name: str = "",
|
|
14
|
+
) -> None:
|
|
15
|
+
with self.add_children_as_readables():
|
|
16
|
+
self.x_gap = Motor(prefix + x_gap)
|
|
17
|
+
self.y_gap = Motor(prefix + y_gap)
|
|
18
|
+
super().__init__(name=name)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Slits(MinimalSlits):
|
|
6
22
|
"""
|
|
7
23
|
Representation of a 4-blade set of slits. Allows control/readout of the gap
|
|
8
24
|
between each pair of blades.
|
|
9
25
|
"""
|
|
10
26
|
|
|
11
|
-
def __init__(
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
prefix: str,
|
|
30
|
+
x_gap: str = "X:SIZE",
|
|
31
|
+
y_gap: str = "Y:SIZE",
|
|
32
|
+
x_centre: str = "X:CENTRE",
|
|
33
|
+
y_centre: str = "Y:CENTRE",
|
|
34
|
+
name: str = "",
|
|
35
|
+
) -> None:
|
|
12
36
|
with self.add_children_as_readables():
|
|
13
|
-
self.
|
|
14
|
-
self.
|
|
15
|
-
|
|
16
|
-
self.y_centre = Motor(prefix + "Y:CENTRE")
|
|
17
|
-
super().__init__(name)
|
|
37
|
+
self.x_centre = Motor(prefix + x_centre)
|
|
38
|
+
self.y_centre = Motor(prefix + y_centre)
|
|
39
|
+
super().__init__(prefix=prefix, x_gap=x_gap, y_gap=y_gap, name=name)
|
dodal/devices/tetramm.py
CHANGED
|
@@ -22,31 +22,31 @@ from ophyd_async.epics.core import (
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class TetrammRange(StrictEnum):
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
UA = "+- 120 uA"
|
|
26
|
+
NA = "+- 120 nA"
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class TetrammTrigger(StrictEnum):
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
FREE_RUN = "Free run"
|
|
31
|
+
EXT_TRIGGER = "Ext. trig."
|
|
32
|
+
EXT_BULB = "Ext. bulb"
|
|
33
|
+
EXT_GATE = "Ext. gate"
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
class TetrammChannels(StrictEnum):
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
ONE = "1"
|
|
38
|
+
TWO = "2"
|
|
39
|
+
FOUR = "4"
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
class TetrammResolution(StrictEnum):
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
SIXTEEN_BITS = "16 bits"
|
|
44
|
+
TWENTY_FOUR_BITS = "24 bits"
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
class TetrammGeometry(StrictEnum):
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
DIAMOND = "Diamond"
|
|
49
|
+
SQUARE = "Square"
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
class TetrammDriver(Device):
|
|
@@ -118,7 +118,7 @@ class TetrammController(DetectorController):
|
|
|
118
118
|
assert trigger_info.livetime is not None
|
|
119
119
|
|
|
120
120
|
# trigger mode must be set first and on its own!
|
|
121
|
-
await self._drv.trigger_mode.set(TetrammTrigger.
|
|
121
|
+
await self._drv.trigger_mode.set(TetrammTrigger.EXT_TRIGGER)
|
|
122
122
|
|
|
123
123
|
await asyncio.gather(
|
|
124
124
|
self._drv.averaging_time.set(trigger_info.livetime),
|
|
@@ -134,8 +134,8 @@ class TetrammController(DetectorController):
|
|
|
134
134
|
|
|
135
135
|
def _validate_trigger(self, trigger: DetectorTrigger) -> None:
|
|
136
136
|
supported_trigger_types = {
|
|
137
|
-
DetectorTrigger.
|
|
138
|
-
DetectorTrigger.
|
|
137
|
+
DetectorTrigger.EDGE_TRIGGER,
|
|
138
|
+
DetectorTrigger.CONSTANT_GATE,
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
if trigger not in supported_trigger_types:
|
dodal/devices/undulator_dcm.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
|
|
3
3
|
from bluesky.protocols import Movable
|
|
4
|
-
from ophyd_async.core import AsyncStatus, StandardReadable
|
|
4
|
+
from ophyd_async.core import AsyncStatus, Reference, StandardReadable
|
|
5
5
|
|
|
6
6
|
from dodal.common.beamlines.beamline_parameters import get_beamline_parameters
|
|
7
7
|
|
|
@@ -33,12 +33,8 @@ class UndulatorDCM(StandardReadable, Movable):
|
|
|
33
33
|
prefix: str = "",
|
|
34
34
|
name: str = "",
|
|
35
35
|
):
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# Attributes are set after super call so they are not renamed to
|
|
39
|
-
# <name>-undulator, etc.
|
|
40
|
-
self.undulator = undulator
|
|
41
|
-
self.dcm = dcm
|
|
36
|
+
self.undulator_ref = Reference(undulator)
|
|
37
|
+
self.dcm_ref = Reference(dcm)
|
|
42
38
|
|
|
43
39
|
# These attributes are just used by hyperion for lookup purposes
|
|
44
40
|
self.pitch_energy_table_path = (
|
|
@@ -53,13 +49,15 @@ class UndulatorDCM(StandardReadable, Movable):
|
|
|
53
49
|
daq_configuration_path + "/domain/beamlineParameters"
|
|
54
50
|
)["DCM_Perp_Offset_FIXED"]
|
|
55
51
|
|
|
52
|
+
super().__init__(name)
|
|
53
|
+
|
|
56
54
|
@AsyncStatus.wrap
|
|
57
55
|
async def set(self, value: float):
|
|
58
|
-
await self.
|
|
56
|
+
await self.undulator_ref().raise_if_not_enabled()
|
|
59
57
|
await asyncio.gather(
|
|
60
|
-
self.
|
|
61
|
-
self.
|
|
58
|
+
self.dcm_ref().energy_in_kev.set(value, timeout=ENERGY_TIMEOUT_S),
|
|
59
|
+
self.undulator_ref().set(value),
|
|
62
60
|
)
|
|
63
61
|
# DCM Perp pitch
|
|
64
62
|
LOGGER.info(f"Adjusting DCM offset to {self.dcm_fixed_offset_mm} mm")
|
|
65
|
-
await self.
|
|
63
|
+
await self.dcm_ref().offset_in_mm.set(self.dcm_fixed_offset_mm)
|
dodal/devices/util/test_utils.py
CHANGED
|
@@ -26,12 +26,12 @@ class TriggerMode(StrictEnum):
|
|
|
26
26
|
SOFTWARE = "Software"
|
|
27
27
|
HARDWARE = "Hardware"
|
|
28
28
|
BURST = "Burst"
|
|
29
|
-
|
|
29
|
+
TTL_VETO_ONLY = "TTL Veto Only"
|
|
30
30
|
IDC = "IDC"
|
|
31
31
|
SOTWARE_START_STOP = "Software Start/Stop"
|
|
32
32
|
TTL_BOTH = "TTL Both"
|
|
33
33
|
LVDS_VETO_ONLY = "LVDS Veto Only"
|
|
34
|
-
|
|
34
|
+
LVDS_BOTH = "LVDS Both"
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class UpdateRBV(StrictEnum):
|
|
@@ -49,7 +49,7 @@ class DetectorState(StrictEnum):
|
|
|
49
49
|
ACQUIRE = "Acquire"
|
|
50
50
|
READOUT = "Readout"
|
|
51
51
|
CORRECT = "Correct"
|
|
52
|
-
|
|
52
|
+
SAVING = "Saving"
|
|
53
53
|
ABORTING = "Aborting"
|
|
54
54
|
ERROR = "Error"
|
|
55
55
|
WAITING = "Waiting"
|