dls-dodal 1.55.1__py3-none-any.whl → 1.56.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.55.1.dist-info → dls_dodal-1.56.0.dist-info}/METADATA +2 -2
- {dls_dodal-1.55.1.dist-info → dls_dodal-1.56.0.dist-info}/RECORD +97 -83
- dodal/_version.py +16 -3
- dodal/beamlines/b01_1.py +6 -1
- dodal/beamlines/b07.py +2 -1
- dodal/beamlines/b07_1.py +2 -1
- dodal/beamlines/b21.py +4 -24
- dodal/beamlines/i03.py +53 -53
- dodal/beamlines/i04.py +16 -38
- dodal/beamlines/i09.py +3 -2
- dodal/beamlines/i09_1.py +2 -1
- dodal/beamlines/i11.py +143 -0
- dodal/beamlines/i19_1.py +1 -0
- dodal/beamlines/i19_2.py +7 -0
- dodal/beamlines/i22.py +2 -2
- dodal/beamlines/i23.py +3 -3
- dodal/beamlines/i24.py +6 -14
- dodal/beamlines/p38.py +1 -0
- dodal/beamlines/p60.py +3 -2
- dodal/cli.py +11 -1
- dodal/common/__init__.py +4 -0
- dodal/common/beamlines/beamline_parameters.py +1 -1
- dodal/common/beamlines/beamline_utils.py +5 -1
- dodal/common/enums.py +19 -0
- dodal/common/watcher_utils.py +83 -0
- dodal/devices/aithre_lasershaping/laser_robot.py +4 -9
- dodal/devices/aperturescatterguard.py +52 -12
- dodal/devices/apple2_undulator.py +0 -1
- dodal/devices/b16/detector.py +1 -10
- dodal/devices/backlight.py +8 -20
- dodal/devices/bimorph_mirror.py +4 -7
- dodal/devices/collimation_table.py +36 -0
- dodal/devices/controllers.py +21 -0
- dodal/devices/cryostream.py +97 -7
- dodal/devices/current_amplifiers/femto.py +1 -1
- dodal/devices/detector/detector_motion.py +1 -7
- dodal/devices/eiger.py +22 -8
- dodal/devices/eiger_odin.py +2 -0
- dodal/devices/electron_analyser/__init__.py +2 -1
- dodal/devices/electron_analyser/abstract/__init__.py +0 -1
- dodal/devices/electron_analyser/abstract/base_detector.py +3 -25
- dodal/devices/electron_analyser/abstract/base_driver_io.py +18 -9
- dodal/devices/electron_analyser/abstract/base_region.py +34 -3
- dodal/devices/electron_analyser/detector.py +24 -0
- dodal/devices/electron_analyser/enums.py +5 -0
- dodal/devices/electron_analyser/specs/detector.py +2 -1
- dodal/devices/electron_analyser/specs/driver_io.py +21 -26
- dodal/devices/electron_analyser/specs/region.py +1 -1
- dodal/devices/electron_analyser/util.py +20 -0
- dodal/devices/electron_analyser/vgscienta/__init__.py +3 -3
- dodal/devices/electron_analyser/vgscienta/detector.py +2 -1
- dodal/devices/electron_analyser/vgscienta/driver_io.py +24 -32
- dodal/devices/electron_analyser/vgscienta/enums.py +0 -8
- dodal/devices/electron_analyser/vgscienta/region.py +2 -31
- dodal/devices/eurotherm.py +126 -0
- dodal/devices/fluorescence_detector_motion.py +3 -10
- dodal/devices/focusing_mirror.py +1 -1
- dodal/devices/i03/undulator_dcm.py +0 -1
- dodal/devices/i09/enums.py +8 -8
- dodal/devices/i10/diagnostics.py +4 -4
- dodal/devices/i10/i10_apple2.py +3 -6
- dodal/devices/i11/cyberstar_blower.py +34 -0
- dodal/devices/i11/diff_stages.py +55 -0
- dodal/devices/i11/mythen.py +165 -0
- dodal/devices/i11/nx100robot.py +153 -0
- dodal/devices/i11/spinner.py +30 -0
- dodal/devices/i13_1/merlin_controller.py +4 -4
- dodal/devices/i19/diffractometer.py +34 -0
- dodal/devices/i19/shutter.py +11 -1
- dodal/devices/i22/dcm.py +1 -1
- dodal/devices/i22/fswitch.py +3 -12
- dodal/devices/i24/aperture.py +3 -3
- dodal/devices/i24/dcm.py +11 -15
- dodal/devices/i24/dual_backlight.py +11 -12
- dodal/devices/i24/pmac.py +8 -7
- dodal/devices/mx_phase1/beamstop.py +10 -11
- dodal/devices/oav/pin_image_recognition/__init__.py +0 -3
- dodal/devices/p60/enums.py +8 -8
- dodal/devices/p60/lab_xray_source.py +3 -2
- dodal/devices/pressure_jump_cell.py +77 -123
- dodal/devices/scintillator.py +76 -4
- dodal/devices/smargon.py +2 -2
- dodal/devices/synchrotron.py +1 -2
- dodal/devices/thawer.py +6 -11
- dodal/devices/undulator.py +3 -8
- dodal/devices/util/epics_util.py +1 -1
- dodal/devices/watsonmarlow323_pump.py +7 -7
- dodal/devices/xbpm_feedback.py +4 -6
- dodal/devices/xspress3/xspress3.py +0 -5
- dodal/devices/zocalo/zocalo_results.py +1 -3
- dodal/testing/__init__.py +0 -0
- dodal/testing/electron_analyser/__init__.py +6 -0
- dodal/testing/electron_analyser/device_factory.py +59 -0
- dodal/devices/CTAB.py +0 -41
- {dls_dodal-1.55.1.dist-info → dls_dodal-1.56.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.55.1.dist-info → dls_dodal-1.56.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.55.1.dist-info → dls_dodal-1.56.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.55.1.dist-info → dls_dodal-1.56.0.dist-info}/top_level.txt +0 -0
|
@@ -48,9 +48,6 @@ class PinTipDetection(StandardReadable):
|
|
|
48
48
|
INVALID_POSITION = np.array([np.iinfo(np.int32).min, np.iinfo(np.int32).min])
|
|
49
49
|
|
|
50
50
|
def __init__(self, prefix: str, name: str = ""):
|
|
51
|
-
self._prefix: str = prefix
|
|
52
|
-
self._name = name
|
|
53
|
-
|
|
54
51
|
self.triggered_tip, self._tip_setter = soft_signal_r_and_setter(
|
|
55
52
|
Tip, name="triggered_tip"
|
|
56
53
|
)
|
dodal/devices/p60/enums.py
CHANGED
|
@@ -16,11 +16,11 @@ class PsuMode(StrictEnum):
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class PassEnergy(StrictEnum):
|
|
19
|
-
E1 = 1
|
|
20
|
-
E2 = 2
|
|
21
|
-
E5 = 5
|
|
22
|
-
E10 = 10
|
|
23
|
-
E20 = 20
|
|
24
|
-
E50 = 50
|
|
25
|
-
E100 = 100
|
|
26
|
-
E200 = 200
|
|
19
|
+
E1 = "1"
|
|
20
|
+
E2 = "2"
|
|
21
|
+
E5 = "5"
|
|
22
|
+
E10 = "10"
|
|
23
|
+
E20 = "20"
|
|
24
|
+
E50 = "50"
|
|
25
|
+
E100 = "100"
|
|
26
|
+
E200 = "200"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from
|
|
2
|
+
from enum import IntEnum
|
|
3
|
+
from typing import Generic, TypeVar
|
|
3
4
|
|
|
4
|
-
from bluesky.protocols import
|
|
5
|
+
from bluesky.protocols import Movable
|
|
5
6
|
from ophyd_async.core import (
|
|
6
7
|
AsyncStatus,
|
|
7
8
|
DeviceVector,
|
|
@@ -26,23 +27,23 @@ class StopState(StrictEnum):
|
|
|
26
27
|
STOP = "STOP"
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
class
|
|
30
|
+
class ValveControlRequest(StrictEnum):
|
|
30
31
|
OPEN = "Open"
|
|
31
32
|
CLOSE = "Close"
|
|
32
33
|
RESET = "Reset"
|
|
33
|
-
ARM = "Arm"
|
|
34
|
-
DISARM = "Disarm"
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
class
|
|
38
|
-
OPEN =
|
|
39
|
-
CLOSE =
|
|
40
|
-
RESET =
|
|
36
|
+
class FastValveControlRequest(StrictEnum):
|
|
37
|
+
OPEN = ValveControlRequest.OPEN.value
|
|
38
|
+
CLOSE = ValveControlRequest.CLOSE.value
|
|
39
|
+
RESET = ValveControlRequest.RESET.value
|
|
40
|
+
ARM = "Arm"
|
|
41
|
+
DISARM = "Disarm"
|
|
41
42
|
|
|
42
43
|
|
|
43
|
-
class ValveOpenSeqRequest(
|
|
44
|
-
INACTIVE =
|
|
45
|
-
OPEN_SEQ =
|
|
44
|
+
class ValveOpenSeqRequest(IntEnum):
|
|
45
|
+
INACTIVE = 0
|
|
46
|
+
OPEN_SEQ = 1
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
class PumpMotorDirectionState(StrictEnum):
|
|
@@ -60,138 +61,89 @@ class ValveState(StrictEnum):
|
|
|
60
61
|
|
|
61
62
|
|
|
62
63
|
class FastValveState(StrictEnum):
|
|
63
|
-
FAULT =
|
|
64
|
-
OPEN =
|
|
64
|
+
FAULT = ValveState.FAULT.value
|
|
65
|
+
OPEN = ValveState.OPEN.value
|
|
65
66
|
OPEN_ARMED = "Open Armed"
|
|
66
|
-
CLOSED =
|
|
67
|
+
CLOSED = ValveState.CLOSED.value
|
|
67
68
|
CLOSED_ARMED = "Closed Armed"
|
|
68
69
|
NONE = "Unused"
|
|
69
70
|
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
TValveControlRequest = TypeVar(
|
|
73
|
+
"TValveControlRequest", bound=ValveControlRequest | FastValveControlRequest
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ValveControl(
|
|
78
|
+
StandardReadable, Movable[TValveControlRequest], Generic[TValveControlRequest]
|
|
79
|
+
):
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
prefix: str,
|
|
83
|
+
valve_control_type: type[TValveControlRequest],
|
|
84
|
+
name: str = "",
|
|
85
|
+
):
|
|
86
|
+
with self.add_children_as_readables():
|
|
87
|
+
self.control = epics_signal_rw(valve_control_type, prefix + ":CON")
|
|
88
|
+
self.open = epics_signal_rw(int, prefix + ":OPENSEQ")
|
|
89
|
+
super().__init__(name)
|
|
90
|
+
|
|
91
|
+
@AsyncStatus.wrap
|
|
92
|
+
async def set(self, value: TValveControlRequest):
|
|
93
|
+
if value.value == "Open":
|
|
94
|
+
await self.open.set(ValveOpenSeqRequest.OPEN_SEQ)
|
|
95
|
+
await asyncio.sleep(OPENSEQ_PULSE_LENGTH)
|
|
96
|
+
await self.open.set(ValveOpenSeqRequest.INACTIVE)
|
|
97
|
+
else:
|
|
98
|
+
await self.control.set(value)
|
|
77
99
|
|
|
78
100
|
|
|
79
|
-
class AllValvesControl(StandardReadable
|
|
101
|
+
class AllValvesControl(StandardReadable):
|
|
80
102
|
"""
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
slow_valves: tuple[int, ...] = (1, 3)
|
|
103
|
+
The default IOC for this device only controls
|
|
104
|
+
specific valves. Other valves are under manual
|
|
105
|
+
control.
|
|
85
106
|
"""
|
|
86
107
|
|
|
87
108
|
def __init__(
|
|
88
109
|
self,
|
|
89
110
|
prefix: str,
|
|
90
111
|
name: str = "",
|
|
91
|
-
|
|
92
|
-
|
|
112
|
+
fast_valves_numbers: tuple[int, ...] = (5, 6),
|
|
113
|
+
slow_valves_numbers: tuple[int, ...] = (1, 3),
|
|
93
114
|
) -> None:
|
|
94
|
-
self.fast_valves = fast_valves
|
|
95
|
-
self.slow_valves = slow_valves
|
|
96
115
|
with self.add_children_as_readables():
|
|
97
116
|
self.valve_states: DeviceVector[SignalR[ValveState]] = DeviceVector(
|
|
98
117
|
{
|
|
99
118
|
i: epics_signal_r(ValveState, f"{prefix}V{i}:STA")
|
|
100
|
-
for i in
|
|
119
|
+
for i in slow_valves_numbers
|
|
101
120
|
}
|
|
102
121
|
)
|
|
103
122
|
self.fast_valve_states: DeviceVector[SignalR[FastValveState]] = (
|
|
104
123
|
DeviceVector(
|
|
105
124
|
{
|
|
106
125
|
i: epics_signal_r(FastValveState, f"{prefix}V{i}:STA")
|
|
107
|
-
for i in
|
|
126
|
+
for i in fast_valves_numbers
|
|
108
127
|
}
|
|
109
128
|
)
|
|
110
129
|
)
|
|
111
130
|
|
|
112
|
-
self.fast_valve_control
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
self.valve_control: DeviceVector[ValveControl] = DeviceVector(
|
|
117
|
-
{i: ValveControl(f"{prefix}V{i}") for i in self.slow_valves}
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
super().__init__(name)
|
|
121
|
-
|
|
122
|
-
async def set_valve(
|
|
123
|
-
self,
|
|
124
|
-
valve: int,
|
|
125
|
-
value: ValveControlRequest | FastValveControlRequest,
|
|
126
|
-
):
|
|
127
|
-
if valve in self.slow_valves and (isinstance(value, ValveControlRequest)):
|
|
128
|
-
if value == ValveControlRequest.OPEN:
|
|
129
|
-
await self.valve_control[valve].set(ValveOpenSeqRequest.OPEN_SEQ)
|
|
130
|
-
await asyncio.sleep(OPENSEQ_PULSE_LENGTH)
|
|
131
|
-
await self.valve_control[valve].set(ValveOpenSeqRequest.INACTIVE)
|
|
132
|
-
else:
|
|
133
|
-
await self.valve_control[valve].set(value)
|
|
134
|
-
|
|
135
|
-
elif valve in self.fast_valves and (isinstance(value, FastValveControlRequest)):
|
|
136
|
-
if value == FastValveControlRequest.OPEN:
|
|
137
|
-
await self.fast_valve_control[valve].set(ValveOpenSeqRequest.OPEN_SEQ)
|
|
138
|
-
await asyncio.sleep(OPENSEQ_PULSE_LENGTH)
|
|
139
|
-
await self.fast_valve_control[valve].set(ValveOpenSeqRequest.INACTIVE)
|
|
140
|
-
else:
|
|
141
|
-
await self.fast_valve_control[valve].set(value)
|
|
142
|
-
|
|
143
|
-
@AsyncStatus.wrap
|
|
144
|
-
async def set(self, value: AllValvesControlState):
|
|
145
|
-
await asyncio.gather(
|
|
146
|
-
*(
|
|
147
|
-
self.set_valve(int(i[-1]), value)
|
|
148
|
-
for i, value in value.__dict__.items()
|
|
149
|
-
if value is not None
|
|
150
|
-
)
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
class ValveControl(
|
|
155
|
-
StandardReadable, Movable[ValveControlRequest | ValveOpenSeqRequest]
|
|
156
|
-
):
|
|
157
|
-
def __init__(self, prefix: str, name: str = "") -> None:
|
|
158
|
-
with self.add_children_as_readables():
|
|
159
|
-
self.close = epics_signal_rw(ValveControlRequest, prefix + ":CON")
|
|
160
|
-
self.open = epics_signal_rw(int, prefix + ":OPENSEQ")
|
|
161
|
-
|
|
162
|
-
super().__init__(name)
|
|
163
|
-
|
|
164
|
-
def set(self, value: ValveControlRequest | ValveOpenSeqRequest) -> AsyncStatus:
|
|
165
|
-
set_status = None
|
|
166
|
-
|
|
167
|
-
if isinstance(value, ValveControlRequest):
|
|
168
|
-
set_status = self.close.set(value)
|
|
169
|
-
elif isinstance(value, ValveOpenSeqRequest):
|
|
170
|
-
set_status = self.open.set(value.value)
|
|
131
|
+
self.fast_valve_control = {
|
|
132
|
+
i: ValveControl(f"{prefix}V{i}", FastValveControlRequest)
|
|
133
|
+
for i in fast_valves_numbers
|
|
134
|
+
}
|
|
171
135
|
|
|
172
|
-
|
|
136
|
+
self.slow_valve_control = {
|
|
137
|
+
i: ValveControl(f"{prefix}V{i}", ValveControlRequest)
|
|
138
|
+
for i in slow_valves_numbers
|
|
139
|
+
}
|
|
173
140
|
|
|
141
|
+
all_valves = self.fast_valve_control | self.slow_valve_control
|
|
174
142
|
|
|
175
|
-
|
|
176
|
-
StandardReadable, Movable[FastValveControlRequest | ValveOpenSeqRequest]
|
|
177
|
-
):
|
|
178
|
-
def __init__(self, prefix: str, name: str = "") -> None:
|
|
179
|
-
with self.add_children_as_readables():
|
|
180
|
-
self.close = epics_signal_rw(FastValveControlRequest, prefix + ":CON")
|
|
181
|
-
self.open = epics_signal_rw(int, prefix + ":OPENSEQ")
|
|
143
|
+
self.valve_control: DeviceVector[ValveControl] = DeviceVector(all_valves)
|
|
182
144
|
|
|
183
145
|
super().__init__(name)
|
|
184
146
|
|
|
185
|
-
def set(self, value: FastValveControlRequest | ValveOpenSeqRequest) -> AsyncStatus:
|
|
186
|
-
set_status = None
|
|
187
|
-
|
|
188
|
-
if isinstance(value, FastValveControlRequest):
|
|
189
|
-
set_status = self.close.set(value)
|
|
190
|
-
elif isinstance(value, ValveOpenSeqRequest):
|
|
191
|
-
set_status = self.open.set(value.value)
|
|
192
|
-
|
|
193
|
-
return set_status
|
|
194
|
-
|
|
195
147
|
|
|
196
148
|
class Pump(StandardReadable):
|
|
197
149
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
@@ -249,25 +201,27 @@ class PressureTransducer(StandardReadable):
|
|
|
249
201
|
super().__init__(name)
|
|
250
202
|
|
|
251
203
|
|
|
252
|
-
class PressureJumpCellController(
|
|
204
|
+
class PressureJumpCellController(StandardReadable):
|
|
205
|
+
"""
|
|
206
|
+
Top-level control for a fixed pressure or pressure jumps.
|
|
207
|
+
"""
|
|
208
|
+
|
|
253
209
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
254
|
-
self.
|
|
210
|
+
with self.add_children_as_readables():
|
|
211
|
+
self.stop = epics_signal_rw(StopState, f"{prefix}STOP")
|
|
255
212
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
213
|
+
self.target_pressure = epics_signal_rw(float, f"{prefix}TARGET")
|
|
214
|
+
self.timeout = epics_signal_rw(float, f"{prefix}TIMER.HIGH")
|
|
215
|
+
self.go = epics_signal_rw(bool, f"{prefix}GO")
|
|
259
216
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
self.jump_ready = epics_signal_rw(bool, f"{prefix}SETJUMP")
|
|
217
|
+
self.from_pressure = epics_signal_rw(float, f"{prefix}JUMPF")
|
|
218
|
+
self.to_pressure = epics_signal_rw(float, f"{prefix}JUMPT")
|
|
219
|
+
self.jump_ready = epics_signal_rw(bool, f"{prefix}SETJUMP")
|
|
264
220
|
|
|
265
|
-
|
|
266
|
-
super().__init__()
|
|
221
|
+
self.result = epics_signal_r(str, f"{prefix}RESULT")
|
|
267
222
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return self._name
|
|
223
|
+
self._name = name
|
|
224
|
+
super().__init__(name)
|
|
271
225
|
|
|
272
226
|
|
|
273
227
|
class PressureJumpCell(StandardReadable):
|
dodal/devices/scintillator.py
CHANGED
|
@@ -1,10 +1,82 @@
|
|
|
1
|
-
from
|
|
1
|
+
from math import isclose
|
|
2
|
+
|
|
3
|
+
from ophyd_async.core import Reference, StandardReadable, StrictEnum, derived_signal_rw
|
|
2
4
|
from ophyd_async.epics.motor import Motor
|
|
3
5
|
|
|
6
|
+
from dodal.common.beamlines.beamline_parameters import GDABeamlineParameters
|
|
7
|
+
from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class InOut(StrictEnum):
|
|
11
|
+
"""Currently Hyperion only needs to move the scintillator out for data collection."""
|
|
12
|
+
|
|
13
|
+
OUT = "Out"
|
|
14
|
+
UNKNOWN = "Unknown"
|
|
15
|
+
|
|
4
16
|
|
|
5
17
|
class Scintillator(StandardReadable):
|
|
6
|
-
|
|
18
|
+
"""Moves a scintillator into and out of the beam.
|
|
19
|
+
|
|
20
|
+
The scintillator will light up when hit with xrays, this allows scientists to use it
|
|
21
|
+
in conjunction with the optical OAV camera to commission the beamline.
|
|
22
|
+
|
|
23
|
+
When moved out of the beam it is parked under the table. This parking has a potential
|
|
24
|
+
to collide with the aperture/scatterguard if that is not correctly parked already.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
prefix: str,
|
|
30
|
+
aperture_scatterguard: Reference[ApertureScatterguard],
|
|
31
|
+
beamline_parameters: GDABeamlineParameters,
|
|
32
|
+
name: str = "",
|
|
33
|
+
):
|
|
7
34
|
with self.add_children_as_readables():
|
|
8
|
-
self.
|
|
9
|
-
self.
|
|
35
|
+
self.y_mm = Motor(f"{prefix}Y")
|
|
36
|
+
self.z_mm = Motor(f"{prefix}Z")
|
|
37
|
+
self.selected_pos = derived_signal_rw(
|
|
38
|
+
self._get_selected_position,
|
|
39
|
+
self._set_selected_position,
|
|
40
|
+
y=self.y_mm,
|
|
41
|
+
z=self.z_mm,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
self._aperture_scatterguard = aperture_scatterguard
|
|
45
|
+
self._scintillator_out_yz_mm = [
|
|
46
|
+
float(beamline_parameters[f"scin_{axis}_SCIN_OUT"]) for axis in ("y", "z")
|
|
47
|
+
]
|
|
48
|
+
self._yz_tolerance_mm = [
|
|
49
|
+
float(beamline_parameters[f"scin_{axis}_tolerance"]) for axis in ("y", "z")
|
|
50
|
+
]
|
|
51
|
+
|
|
10
52
|
super().__init__(name)
|
|
53
|
+
|
|
54
|
+
def _get_selected_position(self, y: float, z: float) -> InOut:
|
|
55
|
+
current_pos = [y, z]
|
|
56
|
+
if all(
|
|
57
|
+
isclose(axis_pos, axis_in_beam, abs_tol=axis_tolerance)
|
|
58
|
+
for axis_pos, axis_in_beam, axis_tolerance in zip(
|
|
59
|
+
current_pos,
|
|
60
|
+
self._scintillator_out_yz_mm,
|
|
61
|
+
self._yz_tolerance_mm,
|
|
62
|
+
strict=False,
|
|
63
|
+
)
|
|
64
|
+
):
|
|
65
|
+
return InOut.OUT
|
|
66
|
+
else:
|
|
67
|
+
return InOut.UNKNOWN
|
|
68
|
+
|
|
69
|
+
async def _set_selected_position(self, position: InOut) -> None:
|
|
70
|
+
match position:
|
|
71
|
+
case InOut.OUT:
|
|
72
|
+
if (
|
|
73
|
+
self._aperture_scatterguard().selected_aperture.get_value()
|
|
74
|
+
!= ApertureValue.PARKED
|
|
75
|
+
):
|
|
76
|
+
raise ValueError(
|
|
77
|
+
"Cannot move scintillator out if aperture/scatterguard is not parked"
|
|
78
|
+
)
|
|
79
|
+
await self.y_mm.set(self._scintillator_out_yz_mm[0])
|
|
80
|
+
await self.z_mm.set(self._scintillator_out_yz_mm[1])
|
|
81
|
+
case _:
|
|
82
|
+
raise ValueError(f"Cannot set scintillator to position {position}")
|
dodal/devices/smargon.py
CHANGED
|
@@ -42,7 +42,7 @@ class StubOffsets(Device):
|
|
|
42
42
|
set them so that the current position is zero or to pre-defined positions.
|
|
43
43
|
"""
|
|
44
44
|
|
|
45
|
-
def __init__(self,
|
|
45
|
+
def __init__(self, prefix: str, name: str = ""):
|
|
46
46
|
self.center_at_current_position = SetWhenEnabled(prefix=prefix + "CENTER_CS")
|
|
47
47
|
self.to_robot_load = SetWhenEnabled(prefix=prefix + "SET_STUBS_TO_RL")
|
|
48
48
|
super().__init__(name)
|
|
@@ -123,7 +123,7 @@ class Smargon(XYZStage, Movable):
|
|
|
123
123
|
Robot loading can nudge these and lead to errors.
|
|
124
124
|
"""
|
|
125
125
|
|
|
126
|
-
def __init__(self, prefix: str
|
|
126
|
+
def __init__(self, prefix: str, name: str = ""):
|
|
127
127
|
with self.add_children_as_readables():
|
|
128
128
|
self.chi = Motor(prefix + "CHI")
|
|
129
129
|
self.phi = Motor(prefix + "PHI")
|
dodal/devices/synchrotron.py
CHANGED
dodal/devices/thawer.py
CHANGED
|
@@ -4,10 +4,10 @@ from bluesky.protocols import Movable, Stoppable
|
|
|
4
4
|
from ophyd_async.core import (
|
|
5
5
|
AsyncStatus,
|
|
6
6
|
Device,
|
|
7
|
+
OnOff,
|
|
7
8
|
Reference,
|
|
8
9
|
SignalRW,
|
|
9
10
|
StandardReadable,
|
|
10
|
-
StrictEnum,
|
|
11
11
|
)
|
|
12
12
|
from ophyd_async.epics.core import epics_signal_rw
|
|
13
13
|
|
|
@@ -16,27 +16,22 @@ class ThawingException(Exception):
|
|
|
16
16
|
pass
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class ThawerStates(StrictEnum):
|
|
20
|
-
OFF = "Off"
|
|
21
|
-
ON = "On"
|
|
22
|
-
|
|
23
|
-
|
|
24
19
|
class ThawingTimer(Device, Stoppable, Movable[float]):
|
|
25
|
-
def __init__(self, control_signal: SignalRW[
|
|
20
|
+
def __init__(self, control_signal: SignalRW[OnOff]) -> None:
|
|
26
21
|
self._control_signal_ref = Reference(control_signal)
|
|
27
22
|
self._thawing_task: Task | None = None
|
|
28
23
|
super().__init__("thaw_for_time_s")
|
|
29
24
|
|
|
30
25
|
@AsyncStatus.wrap
|
|
31
26
|
async def set(self, value: float):
|
|
32
|
-
await self._control_signal_ref().set(
|
|
27
|
+
await self._control_signal_ref().set(OnOff.ON)
|
|
33
28
|
if self._thawing_task and not self._thawing_task.done():
|
|
34
29
|
raise ThawingException("Thawing task already in progress")
|
|
35
30
|
self._thawing_task = create_task(sleep(value))
|
|
36
31
|
try:
|
|
37
32
|
await self._thawing_task
|
|
38
33
|
finally:
|
|
39
|
-
await self._control_signal_ref().set(
|
|
34
|
+
await self._control_signal_ref().set(OnOff.OFF)
|
|
40
35
|
|
|
41
36
|
@AsyncStatus.wrap
|
|
42
37
|
async def stop(self, *args, **kwargs):
|
|
@@ -46,11 +41,11 @@ class ThawingTimer(Device, Stoppable, Movable[float]):
|
|
|
46
41
|
|
|
47
42
|
class Thawer(StandardReadable, Stoppable):
|
|
48
43
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
49
|
-
self.control = epics_signal_rw(
|
|
44
|
+
self.control = epics_signal_rw(OnOff, prefix + ":CTRL")
|
|
50
45
|
self.thaw_for_time_s = ThawingTimer(self.control)
|
|
51
46
|
super().__init__(name)
|
|
52
47
|
|
|
53
48
|
@AsyncStatus.wrap
|
|
54
49
|
async def stop(self, *args, **kwargs):
|
|
55
50
|
await self.thaw_for_time_s.stop()
|
|
56
|
-
await self.control.set(
|
|
51
|
+
await self.control.set(OnOff.OFF)
|
dodal/devices/undulator.py
CHANGED
|
@@ -7,12 +7,12 @@ from ophyd_async.core import (
|
|
|
7
7
|
AsyncStatus,
|
|
8
8
|
StandardReadable,
|
|
9
9
|
StandardReadableFormat,
|
|
10
|
-
StrictEnum,
|
|
11
10
|
soft_signal_r_and_setter,
|
|
12
11
|
)
|
|
13
12
|
from ophyd_async.epics.core import epics_signal_r
|
|
14
13
|
from ophyd_async.epics.motor import Motor
|
|
15
14
|
|
|
15
|
+
from dodal.common.enums import EnabledDisabledUpper
|
|
16
16
|
from dodal.log import LOGGER
|
|
17
17
|
|
|
18
18
|
from .util.lookup_tables import energy_distance_table
|
|
@@ -33,11 +33,6 @@ UNDULATOR_DISCREPANCY_THRESHOLD_MM = 2e-3
|
|
|
33
33
|
STATUS_TIMEOUT_S: float = 10.0
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class UndulatorGapAccess(StrictEnum):
|
|
37
|
-
ENABLED = "ENABLED"
|
|
38
|
-
DISABLED = "DISABLED"
|
|
39
|
-
|
|
40
|
-
|
|
41
36
|
def _get_gap_for_energy(
|
|
42
37
|
dcm_energy_ev: float, energy_to_distance_table: ndarray
|
|
43
38
|
) -> float:
|
|
@@ -73,7 +68,7 @@ class Undulator(StandardReadable, Movable[float]):
|
|
|
73
68
|
with self.add_children_as_readables():
|
|
74
69
|
self.gap_motor = Motor(prefix + "BLGAPMTR")
|
|
75
70
|
self.current_gap = epics_signal_r(float, prefix + "CURRGAPD")
|
|
76
|
-
self.gap_access = epics_signal_r(
|
|
71
|
+
self.gap_access = epics_signal_r(EnabledDisabledUpper, prefix + "IDBLENA")
|
|
77
72
|
|
|
78
73
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
79
74
|
self.gap_discrepancy_tolerance_mm, _ = soft_signal_r_and_setter(
|
|
@@ -110,7 +105,7 @@ class Undulator(StandardReadable, Movable[float]):
|
|
|
110
105
|
|
|
111
106
|
async def raise_if_not_enabled(self):
|
|
112
107
|
access_level = await self.gap_access.get_value()
|
|
113
|
-
if access_level is
|
|
108
|
+
if access_level is EnabledDisabledUpper.DISABLED and not TEST_MODE:
|
|
114
109
|
raise AccessError("Undulator gap access is disabled. Contact Control Room")
|
|
115
110
|
|
|
116
111
|
async def _set_undulator_gap(self, energy_kev: float) -> None:
|
dodal/devices/util/epics_util.py
CHANGED
|
@@ -117,7 +117,7 @@ def call_func(func: Callable[[], StatusBase]) -> StatusBase:
|
|
|
117
117
|
class SetWhenEnabled(OphydAsyncDevice, Movable[int]):
|
|
118
118
|
"""A device that sets the proc field of a PV when it becomes enabled."""
|
|
119
119
|
|
|
120
|
-
def __init__(self,
|
|
120
|
+
def __init__(self, prefix: str, name: str = ""):
|
|
121
121
|
self.proc = epics_signal_rw(int, prefix + ".PROC")
|
|
122
122
|
self.disp = epics_signal_r(int, prefix + ".DISP")
|
|
123
123
|
super().__init__(name)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
from ophyd_async.core import
|
|
1
|
+
from ophyd_async.core import (
|
|
2
|
+
EnabledDisabled,
|
|
3
|
+
StandardReadable,
|
|
4
|
+
StandardReadableFormat,
|
|
5
|
+
StrictEnum,
|
|
6
|
+
)
|
|
2
7
|
from ophyd_async.epics.core import epics_signal_rw
|
|
3
8
|
|
|
4
9
|
|
|
5
|
-
class WatsonMarlow323PumpEnable(StrictEnum):
|
|
6
|
-
DISABLED = "Disabled"
|
|
7
|
-
ENABLED = "Enabled"
|
|
8
|
-
|
|
9
|
-
|
|
10
10
|
class WatsonMarlow323PumpDirection(StrictEnum):
|
|
11
11
|
CLOCKWISE = "CW"
|
|
12
12
|
COUNTER_CLOCKWISE = "CCW"
|
|
@@ -38,7 +38,7 @@ class WatsonMarlow323Pump(StandardReadable):
|
|
|
38
38
|
|
|
39
39
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
40
40
|
self.enabled = epics_signal_rw(
|
|
41
|
-
|
|
41
|
+
EnabledDisabled,
|
|
42
42
|
prefix + "DISABLE",
|
|
43
43
|
)
|
|
44
44
|
|
dodal/devices/xbpm_feedback.py
CHANGED
|
@@ -14,12 +14,10 @@ class XBPMFeedback(Device, Triggerable):
|
|
|
14
14
|
"""The XBPM feedback device is an IOC that moves the DCM, HFM and VFM to automatically
|
|
15
15
|
hold the beam into place, as measured by the XBPM sensor."""
|
|
16
16
|
|
|
17
|
-
def __init__(self, prefix: str
|
|
18
|
-
self.pos_ok = epics_signal_r(float, prefix + "
|
|
19
|
-
self.pos_stable = epics_signal_r(float, prefix + "
|
|
20
|
-
self.pause_feedback = epics_signal_rw(Pause, prefix + "
|
|
21
|
-
self.x = epics_signal_r(float, prefix + "-EA-XBPM-02:PosX:MeanValue_RBV")
|
|
22
|
-
self.y = epics_signal_r(float, prefix + "-EA-XBPM-02:PosY:MeanValue_RBV")
|
|
17
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
18
|
+
self.pos_ok = epics_signal_r(float, prefix + "XBPM2POSITION_OK")
|
|
19
|
+
self.pos_stable = epics_signal_r(float, prefix + "XBPM2_STABLE")
|
|
20
|
+
self.pause_feedback = epics_signal_rw(Pause, prefix + "FB_PAUSE")
|
|
23
21
|
super().__init__(name=name)
|
|
24
22
|
|
|
25
23
|
@AsyncStatus.wrap
|
|
@@ -125,19 +125,17 @@ class ZocaloResults(StandardReadable, Triggerable):
|
|
|
125
125
|
|
|
126
126
|
def __init__(
|
|
127
127
|
self,
|
|
128
|
-
name: str = "
|
|
128
|
+
name: str = "",
|
|
129
129
|
zocalo_environment: str = ZOCALO_ENV,
|
|
130
130
|
channel: str = "xrc.i03",
|
|
131
131
|
sort_key: str = DEFAULT_SORT_KEY.value,
|
|
132
132
|
timeout_s: float = DEFAULT_TIMEOUT,
|
|
133
|
-
prefix: str = "",
|
|
134
133
|
results_source: ZocaloSource = ZocaloSource.CPU,
|
|
135
134
|
) -> None:
|
|
136
135
|
self.zocalo_environment = zocalo_environment
|
|
137
136
|
self.sort_key = SortKeys[sort_key]
|
|
138
137
|
self.channel = channel
|
|
139
138
|
self.timeout_s = timeout_s
|
|
140
|
-
self._prefix = prefix
|
|
141
139
|
self._raw_results_received: Queue = Queue()
|
|
142
140
|
self.transport: CommonTransport | None = None
|
|
143
141
|
self.results_source = results_source
|
|
File without changes
|