dls-dodal 1.58.0__py3-none-any.whl → 1.60.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.58.0.dist-info → dls_dodal-1.60.0.dist-info}/METADATA +3 -3
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.60.0.dist-info}/RECORD +71 -47
- dodal/_version.py +2 -2
- dodal/beamlines/__init__.py +1 -0
- dodal/beamlines/b07.py +10 -5
- dodal/beamlines/b07_1.py +10 -5
- dodal/beamlines/b21.py +22 -0
- dodal/beamlines/i02_1.py +80 -0
- dodal/beamlines/i03.py +5 -3
- dodal/beamlines/i04.py +5 -3
- dodal/beamlines/i09.py +10 -9
- dodal/beamlines/i09_1.py +10 -5
- dodal/beamlines/i10-1.py +25 -0
- dodal/beamlines/i10.py +17 -1
- dodal/beamlines/i11.py +0 -17
- dodal/beamlines/i15.py +242 -0
- dodal/beamlines/i15_1.py +156 -0
- dodal/beamlines/i19_1.py +3 -1
- dodal/beamlines/i19_2.py +12 -1
- dodal/beamlines/i21.py +27 -0
- dodal/beamlines/i22.py +12 -2
- dodal/beamlines/i24.py +32 -3
- dodal/beamlines/k07.py +31 -0
- dodal/beamlines/p60.py +10 -9
- dodal/common/watcher_utils.py +1 -1
- dodal/devices/apple2_undulator.py +18 -142
- dodal/devices/attenuator/attenuator.py +48 -2
- dodal/devices/attenuator/filter.py +3 -0
- dodal/devices/attenuator/filter_selections.py +26 -0
- dodal/devices/eiger.py +2 -1
- dodal/devices/electron_analyser/__init__.py +4 -0
- dodal/devices/electron_analyser/abstract/base_driver_io.py +30 -18
- dodal/devices/electron_analyser/energy_sources.py +101 -0
- dodal/devices/electron_analyser/specs/detector.py +6 -6
- dodal/devices/electron_analyser/specs/driver_io.py +7 -15
- dodal/devices/electron_analyser/vgscienta/detector.py +6 -6
- dodal/devices/electron_analyser/vgscienta/driver_io.py +7 -14
- dodal/devices/fast_grid_scan.py +130 -64
- dodal/devices/focusing_mirror.py +30 -0
- dodal/devices/i02_1/__init__.py +0 -0
- dodal/devices/i02_1/fast_grid_scan.py +61 -0
- dodal/devices/i02_1/sample_motors.py +19 -0
- dodal/devices/i04/murko_results.py +69 -23
- dodal/devices/i10/i10_apple2.py +282 -140
- dodal/devices/i15/dcm.py +77 -0
- dodal/devices/i15/focussing_mirror.py +71 -0
- dodal/devices/i15/jack.py +39 -0
- dodal/devices/i15/laue.py +18 -0
- dodal/devices/i15/motors.py +27 -0
- dodal/devices/i15/multilayer_mirror.py +25 -0
- dodal/devices/i15/rail.py +17 -0
- dodal/devices/i21/__init__.py +3 -0
- dodal/devices/i21/enums.py +8 -0
- dodal/devices/i22/nxsas.py +2 -0
- dodal/devices/i24/commissioning_jungfrau.py +114 -0
- dodal/devices/motors.py +52 -1
- dodal/devices/slits.py +18 -0
- dodal/devices/smargon.py +0 -56
- dodal/devices/temperture_controller/__init__.py +3 -0
- dodal/devices/temperture_controller/lakeshore/__init__.py +0 -0
- dodal/devices/temperture_controller/lakeshore/lakeshore.py +204 -0
- dodal/devices/temperture_controller/lakeshore/lakeshore_io.py +112 -0
- dodal/devices/tetramm.py +38 -16
- dodal/devices/v2f.py +39 -0
- dodal/devices/zebra/zebra.py +1 -0
- dodal/devices/zebra/zebra_constants_mapping.py +1 -1
- dodal/parameters/experiment_parameter_base.py +1 -5
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.60.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.60.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.60.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.60.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from ophyd_async.core import Device, DeviceVector, SignalDatatypeT
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LakeshoreControlChannel(Device):
|
|
6
|
+
"""
|
|
7
|
+
Single control channel for a Lakeshore temperature controller.
|
|
8
|
+
|
|
9
|
+
Provides access to setpoint, ramp rate, ramp enable, heater output, heater output range,
|
|
10
|
+
PID parameters (P, I, D), and manual output for the channel.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
prefix: str,
|
|
16
|
+
suffix: str,
|
|
17
|
+
heater_type: type[SignalDatatypeT],
|
|
18
|
+
name: str = "",
|
|
19
|
+
):
|
|
20
|
+
"""Initialize the LakeshoreControlChannel device.
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
prefix: str
|
|
24
|
+
The EPICS prefix for the Lakeshore device.
|
|
25
|
+
suffix: str
|
|
26
|
+
Suffix for the channel, used to differentiate multiple channels.
|
|
27
|
+
heater_type: SignalDatatypeT
|
|
28
|
+
Type of the heater output range.
|
|
29
|
+
name: str
|
|
30
|
+
Optional name for the device.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def channel_rw(channel_type, pv_name):
|
|
34
|
+
return epics_signal_rw(
|
|
35
|
+
channel_type,
|
|
36
|
+
f"{prefix}{pv_name}{suffix}",
|
|
37
|
+
f"{prefix}{pv_name}_S{suffix}",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
self.user_setpoint = channel_rw(channel_type=float, pv_name="SETP")
|
|
41
|
+
self.ramp_rate = channel_rw(channel_type=float, pv_name="RAMP")
|
|
42
|
+
self.ramp_enable = channel_rw(channel_type=int, pv_name="RAMPST")
|
|
43
|
+
self.heater_output_range = channel_rw(channel_type=heater_type, pv_name="RANGE")
|
|
44
|
+
self.p = channel_rw(channel_type=float, pv_name="P")
|
|
45
|
+
self.i = channel_rw(channel_type=float, pv_name="I")
|
|
46
|
+
self.d = channel_rw(channel_type=float, pv_name="D")
|
|
47
|
+
self.manual_output = channel_rw(channel_type=float, pv_name="MOUT")
|
|
48
|
+
self.heater_output = epics_signal_r(float, f"{prefix}{'HTR'}{suffix}")
|
|
49
|
+
|
|
50
|
+
super().__init__(name=name)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class LakeshoreBaseIO(Device):
|
|
54
|
+
"""Base class for Lakeshore temperature controller IO.
|
|
55
|
+
|
|
56
|
+
Provides access to control channels and readback channels for setpoint, ramp rate, heater output,
|
|
57
|
+
and PID parameters. Supports both single and multiple control channel configurations.
|
|
58
|
+
Note:
|
|
59
|
+
Almost all models have a controller for each readback channel but some models
|
|
60
|
+
only has a single controller for multiple readback channels.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
prefix: str,
|
|
66
|
+
num_readback_channel: int,
|
|
67
|
+
heater_setting: type[SignalDatatypeT],
|
|
68
|
+
name: str = "",
|
|
69
|
+
single_control_channel: bool = False,
|
|
70
|
+
):
|
|
71
|
+
"""Initialize the LakeshoreBaseIO device.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
-----------
|
|
75
|
+
prefix: str
|
|
76
|
+
The EPICS prefix for the Lakeshore device.
|
|
77
|
+
num_readback_channel: int
|
|
78
|
+
Number of readback channels to create.
|
|
79
|
+
heater_setting: SignalDatatypeT
|
|
80
|
+
Type of the heater setting.
|
|
81
|
+
name: str
|
|
82
|
+
Optional name for the device.
|
|
83
|
+
single_control_channel: bool
|
|
84
|
+
If True, use a single control channel for all readback.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
suffixes = (
|
|
88
|
+
[""]
|
|
89
|
+
if single_control_channel
|
|
90
|
+
else map(str, range(1, num_readback_channel + 1))
|
|
91
|
+
)
|
|
92
|
+
self.control_channels = DeviceVector(
|
|
93
|
+
{
|
|
94
|
+
i: LakeshoreControlChannel(
|
|
95
|
+
prefix=prefix, suffix=suffix, heater_type=heater_setting
|
|
96
|
+
)
|
|
97
|
+
for i, suffix in enumerate(suffixes, start=1)
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
self.readback = DeviceVector(
|
|
102
|
+
{
|
|
103
|
+
i: epics_signal_r(
|
|
104
|
+
float,
|
|
105
|
+
read_pv=f"{prefix}KRDG{i - 1}",
|
|
106
|
+
)
|
|
107
|
+
for i in range(1, num_readback_channel + 1)
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
super().__init__(
|
|
111
|
+
name=name,
|
|
112
|
+
)
|
dodal/devices/tetramm.py
CHANGED
|
@@ -16,6 +16,7 @@ from ophyd_async.core import (
|
|
|
16
16
|
TriggerInfo,
|
|
17
17
|
set_and_wait_for_value,
|
|
18
18
|
soft_signal_r_and_setter,
|
|
19
|
+
wait_for_value,
|
|
19
20
|
)
|
|
20
21
|
from ophyd_async.epics.adcore import (
|
|
21
22
|
ADHDFWriter,
|
|
@@ -23,7 +24,7 @@ from ophyd_async.epics.adcore import (
|
|
|
23
24
|
NDFileHDFIO,
|
|
24
25
|
NDPluginBaseIO,
|
|
25
26
|
)
|
|
26
|
-
from ophyd_async.epics.core import PvSuffix,
|
|
27
|
+
from ophyd_async.epics.core import PvSuffix, epics_signal_r
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
class TetrammRange(StrictEnum):
|
|
@@ -77,6 +78,7 @@ class TetrammController(DetectorController):
|
|
|
77
78
|
_supported_trigger_types = {
|
|
78
79
|
DetectorTrigger.EDGE_TRIGGER: TetrammTrigger.EXT_TRIGGER,
|
|
79
80
|
DetectorTrigger.CONSTANT_GATE: TetrammTrigger.EXT_TRIGGER,
|
|
81
|
+
DetectorTrigger.VARIABLE_GATE: TetrammTrigger.EXT_TRIGGER,
|
|
80
82
|
}
|
|
81
83
|
""""On the TetrAMM ASCII mode requires a minimum value of ValuesPerRead of 500,
|
|
82
84
|
[...] binary mode the minimum value of ValuesPerRead is 5."
|
|
@@ -86,11 +88,9 @@ class TetrammController(DetectorController):
|
|
|
86
88
|
"""The TetrAMM always digitizes at 100 kHz"""
|
|
87
89
|
_base_sample_rate: int = 100_000
|
|
88
90
|
|
|
89
|
-
def __init__(
|
|
90
|
-
self,
|
|
91
|
-
driver: TetrammDriver,
|
|
92
|
-
) -> None:
|
|
91
|
+
def __init__(self, driver: TetrammDriver, file_io: NDFileHDFIO) -> None:
|
|
93
92
|
self.driver = driver
|
|
93
|
+
self._file_io = file_io
|
|
94
94
|
self._arm_status: AsyncStatus | None = None
|
|
95
95
|
|
|
96
96
|
def get_deadtime(self, exposure: float | None) -> float:
|
|
@@ -107,13 +107,19 @@ class TetrammController(DetectorController):
|
|
|
107
107
|
if trigger_info.livetime is None:
|
|
108
108
|
raise ValueError(f"{self.__class__.__name__} requires that livetime is set")
|
|
109
109
|
|
|
110
|
+
current_trig_status = await self.driver.trigger_mode.get_value()
|
|
111
|
+
|
|
112
|
+
if current_trig_status == TetrammTrigger.FREE_RUN: # if freerun turn off first
|
|
113
|
+
await self.disarm()
|
|
114
|
+
|
|
110
115
|
# trigger mode must be set first and on its own!
|
|
111
116
|
await self.driver.trigger_mode.set(
|
|
112
117
|
self._supported_trigger_types[trigger_info.trigger]
|
|
113
118
|
)
|
|
119
|
+
|
|
114
120
|
await asyncio.gather(
|
|
115
|
-
self.driver.averaging_time.set(trigger_info.livetime),
|
|
116
121
|
self.set_exposure(trigger_info.livetime),
|
|
122
|
+
self._file_io.num_capture.set(trigger_info.total_number_of_exposures),
|
|
117
123
|
)
|
|
118
124
|
|
|
119
125
|
# raise an error if asked to trigger faster than the max.
|
|
@@ -133,14 +139,18 @@ class TetrammController(DetectorController):
|
|
|
133
139
|
self._arm_status = await self.start_acquiring_driver_and_ensure_status()
|
|
134
140
|
|
|
135
141
|
async def wait_for_idle(self):
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
self.
|
|
142
|
+
# tetramm never goes idle really, actually it is always acquiring
|
|
143
|
+
# so need to wait for the capture to finish instead
|
|
144
|
+
await wait_for_value(self._file_io.acquire, False, timeout=None)
|
|
145
|
+
|
|
146
|
+
async def unstage(self):
|
|
147
|
+
await self.disarm()
|
|
148
|
+
await self._file_io.acquire.set(False)
|
|
139
149
|
|
|
140
150
|
async def disarm(self):
|
|
141
151
|
# We can't use caput callback as we already used it in arm() and we can't have
|
|
142
152
|
# 2 or they will deadlock
|
|
143
|
-
await
|
|
153
|
+
await set_and_wait_for_value(self.driver.acquire, False, timeout=1)
|
|
144
154
|
|
|
145
155
|
async def set_exposure(self, exposure: float) -> None:
|
|
146
156
|
"""Set the exposure time and acquire period.
|
|
@@ -164,7 +174,9 @@ class TetrammController(DetectorController):
|
|
|
164
174
|
"Tetramm exposure time must be at least "
|
|
165
175
|
f"{minimum_samples * sample_time}s, asked to set it to {exposure}s"
|
|
166
176
|
)
|
|
167
|
-
await self.driver.averaging_time.set(
|
|
177
|
+
await self.driver.averaging_time.set(
|
|
178
|
+
samples_per_reading * sample_time
|
|
179
|
+
) # correct
|
|
168
180
|
|
|
169
181
|
async def start_acquiring_driver_and_ensure_status(self) -> AsyncStatus:
|
|
170
182
|
"""Start acquiring driver, raising ValueError if the detector is in a bad state.
|
|
@@ -202,10 +214,7 @@ class TetrammDatasetDescriber(DatasetDescriber):
|
|
|
202
214
|
async def shape(self) -> tuple[int, int]:
|
|
203
215
|
return (
|
|
204
216
|
int(await self._driver.num_channels.get_value()),
|
|
205
|
-
int(
|
|
206
|
-
await self._driver.averaging_time.get_value()
|
|
207
|
-
/ await self._driver.sample_time.get_value(),
|
|
208
|
-
),
|
|
217
|
+
int(await self._driver.to_average.get_value()),
|
|
209
218
|
)
|
|
210
219
|
|
|
211
220
|
|
|
@@ -223,7 +232,20 @@ class TetrammDetector(StandardDetector):
|
|
|
223
232
|
):
|
|
224
233
|
self.driver = TetrammDriver(prefix + drv_suffix)
|
|
225
234
|
self.file_io = NDFileHDFIO(prefix + fileio_suffix)
|
|
226
|
-
controller = TetrammController(self.driver)
|
|
235
|
+
controller = TetrammController(self.driver, self.file_io)
|
|
236
|
+
|
|
237
|
+
self.current1 = epics_signal_r(float, prefix + "Cur1:MeanValue_RBV")
|
|
238
|
+
self.current2 = epics_signal_r(float, prefix + "Cur2:MeanValue_RBV")
|
|
239
|
+
self.current3 = epics_signal_r(float, prefix + "Cur3:MeanValue_RBV")
|
|
240
|
+
self.current4 = epics_signal_r(float, prefix + "Cur4:MeanValue_RBV")
|
|
241
|
+
|
|
242
|
+
self.sum_x = epics_signal_r(float, prefix + "SumX:MeanValue_RBV")
|
|
243
|
+
self.sum_y = epics_signal_r(float, prefix + "SumY:MeanValue_RBV")
|
|
244
|
+
self.sum_all = epics_signal_r(float, prefix + "SumAll:MeanValue_RBV")
|
|
245
|
+
self.diff_x = epics_signal_r(float, prefix + "DiffX:MeanValue_RBV")
|
|
246
|
+
self.diff_y = epics_signal_r(float, prefix + "DiffY:MeanValue_RBV")
|
|
247
|
+
self.pos_x = epics_signal_r(float, prefix + "PosX:MeanValue_RBV")
|
|
248
|
+
self.pos_y = epics_signal_r(float, prefix + "PosY:MeanValue_RBV")
|
|
227
249
|
|
|
228
250
|
writer = ADHDFWriter(
|
|
229
251
|
fileio=self.file_io,
|
dodal/devices/v2f.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from ophyd_async.core import StandardReadable, StandardReadableFormat, StrictEnum
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class V2FGain(StrictEnum):
|
|
6
|
+
LOW_NOISE3 = "10^3 low noise"
|
|
7
|
+
LOW_NOISE4 = "10^4 low noise"
|
|
8
|
+
LOW_NOISE5 = "10^5 low noise"
|
|
9
|
+
LOW_NOISE6 = "10^6 low noise"
|
|
10
|
+
LOW_NOISE7 = "10^7 low noise"
|
|
11
|
+
LOW_NOISE8 = "10^8 low noise"
|
|
12
|
+
LOW_NOISE9 = "10^9 low noise"
|
|
13
|
+
HIGH_SPEED5 = "10^5 high speed"
|
|
14
|
+
HIGH_SPEED6 = "10^6 high speed"
|
|
15
|
+
HIGH_SPEED7 = "10^7 high speed"
|
|
16
|
+
HIGH_SPEED8 = "10^8 high speed"
|
|
17
|
+
HIGH_SPEED9 = "10^9 high speed"
|
|
18
|
+
HIGH_SPEED10 = "10^10 high spd"
|
|
19
|
+
HIGH_SPEED11 = "10^11 high spd"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class QDV2F(StandardReadable):
|
|
23
|
+
"""
|
|
24
|
+
A Quantum Detectors V2F low noise voltage to frequency converter.
|
|
25
|
+
Two channel V2F - 50mHz
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
prefix: str,
|
|
31
|
+
name: str = "",
|
|
32
|
+
I_suffix="I",
|
|
33
|
+
) -> None:
|
|
34
|
+
with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
|
|
35
|
+
self.intensity = epics_signal_r(float, f"{prefix}{I_suffix}")
|
|
36
|
+
with self.add_children_as_readables():
|
|
37
|
+
self.gain = epics_signal_rw(V2FGain, f"{prefix}GAIN")
|
|
38
|
+
|
|
39
|
+
super().__init__(name)
|
dodal/devices/zebra/zebra.py
CHANGED
|
@@ -77,7 +77,7 @@ class ZebraMapping(ZebraMappingValidations):
|
|
|
77
77
|
Zebra's hardware configuration and wiring.
|
|
78
78
|
"""
|
|
79
79
|
|
|
80
|
-
# Zebra ophyd signal for
|
|
80
|
+
# Zebra ophyd signal for output can be accessed
|
|
81
81
|
# with, eg, zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR]
|
|
82
82
|
outputs: ZebraTTLOutputs = ZebraTTLOutputs()
|
|
83
83
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from abc import ABC
|
|
1
|
+
from abc import ABC
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
|
|
@@ -9,7 +9,3 @@ class AbstractExperimentParameterBase(BaseModel, ABC):
|
|
|
9
9
|
|
|
10
10
|
class AbstractExperimentWithBeamParams(AbstractExperimentParameterBase):
|
|
11
11
|
transmission_fraction: float
|
|
12
|
-
|
|
13
|
-
@abstractmethod
|
|
14
|
-
def get_num_images(self) -> int:
|
|
15
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|