dls-dodal 1.47.0__py3-none-any.whl → 1.48.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.47.0.dist-info → dls_dodal-1.48.0.dist-info}/METADATA +2 -2
- {dls_dodal-1.47.0.dist-info → dls_dodal-1.48.0.dist-info}/RECORD +40 -40
- {dls_dodal-1.47.0.dist-info → dls_dodal-1.48.0.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamlines/aithre.py +6 -0
- dodal/beamlines/b01_1.py +1 -1
- dodal/beamlines/i03.py +21 -6
- dodal/beamlines/i04.py +17 -10
- dodal/beamlines/i18.py +1 -1
- dodal/beamlines/i19_1.py +9 -6
- dodal/beamlines/i24.py +5 -5
- dodal/common/beamlines/beamline_parameters.py +2 -28
- dodal/devices/aithre_lasershaping/goniometer.py +36 -2
- dodal/devices/aithre_lasershaping/laser_robot.py +27 -0
- dodal/devices/electron_analyser/__init__.py +10 -0
- dodal/devices/electron_analyser/abstract/__init__.py +0 -6
- dodal/devices/electron_analyser/abstract/base_detector.py +69 -56
- dodal/devices/electron_analyser/abstract/base_driver_io.py +114 -5
- dodal/devices/electron_analyser/abstract/base_region.py +1 -0
- dodal/devices/electron_analyser/specs/__init__.py +1 -2
- dodal/devices/electron_analyser/specs/detector.py +5 -21
- dodal/devices/electron_analyser/specs/driver_io.py +27 -2
- dodal/devices/electron_analyser/vgscienta/__init__.py +1 -2
- dodal/devices/electron_analyser/vgscienta/detector.py +8 -22
- dodal/devices/electron_analyser/vgscienta/driver_io.py +31 -3
- dodal/devices/electron_analyser/vgscienta/region.py +0 -1
- dodal/devices/fast_grid_scan.py +1 -1
- dodal/devices/i04/murko_results.py +93 -96
- dodal/devices/i18/diode.py +37 -4
- dodal/devices/mx_phase1/beamstop.py +23 -6
- dodal/devices/oav/oav_detector.py +61 -23
- dodal/devices/oav/oav_parameters.py +46 -16
- dodal/devices/oav/oav_to_redis_forwarder.py +2 -2
- dodal/devices/robot.py +20 -1
- dodal/devices/smargon.py +43 -4
- dodal/devices/zebra/zebra.py +8 -0
- dodal/plans/configure_arm_trigger_and_disarm_detector.py +167 -0
- dodal/plan_stubs/electron_analyser/__init__.py +0 -3
- dodal/plan_stubs/electron_analyser/configure_driver.py +0 -92
- {dls_dodal-1.47.0.dist-info → dls_dodal-1.48.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.47.0.dist-info → dls_dodal-1.48.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.47.0.dist-info → dls_dodal-1.48.0.dist-info}/top_level.txt +0 -0
dodal/devices/smargon.py
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
from collections.abc import Collection, Generator
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from enum import Enum
|
|
4
5
|
from math import isclose
|
|
5
|
-
from typing import cast
|
|
6
|
+
from typing import TypedDict, cast
|
|
6
7
|
|
|
7
8
|
from bluesky import plan_stubs as bps
|
|
9
|
+
from bluesky.protocols import Movable
|
|
8
10
|
from bluesky.utils import Msg
|
|
9
|
-
from ophyd_async.core import
|
|
10
|
-
|
|
11
|
+
from ophyd_async.core import (
|
|
12
|
+
AsyncStatus,
|
|
13
|
+
Device,
|
|
14
|
+
StandardReadable,
|
|
15
|
+
StrictEnum,
|
|
16
|
+
wait_for_value,
|
|
17
|
+
)
|
|
18
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
11
19
|
from ophyd_async.epics.motor import Motor
|
|
20
|
+
from typing_extensions import NotRequired
|
|
12
21
|
|
|
13
22
|
from dodal.devices.util.epics_util import SetWhenEnabled
|
|
14
23
|
|
|
@@ -91,7 +100,23 @@ class XYZLimits:
|
|
|
91
100
|
)
|
|
92
101
|
|
|
93
102
|
|
|
94
|
-
class
|
|
103
|
+
class DeferMoves(StrictEnum):
|
|
104
|
+
ON = "Defer On"
|
|
105
|
+
OFF = "Defer Off"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class CombinedMove(TypedDict):
|
|
109
|
+
"""A move on multiple axes at once using a deferred move"""
|
|
110
|
+
|
|
111
|
+
x: NotRequired[float | None]
|
|
112
|
+
y: NotRequired[float | None]
|
|
113
|
+
z: NotRequired[float | None]
|
|
114
|
+
omega: NotRequired[float | None]
|
|
115
|
+
phi: NotRequired[float | None]
|
|
116
|
+
chi: NotRequired[float | None]
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class Smargon(StandardReadable, Movable):
|
|
95
120
|
"""
|
|
96
121
|
Real motors added to allow stops following pin load (e.g. real_x1.stop() )
|
|
97
122
|
X1 and X2 real motors provide compound chi motion as well as the compound X travel,
|
|
@@ -116,6 +141,8 @@ class Smargon(StandardReadable):
|
|
|
116
141
|
self.stub_offsets = StubOffsets(prefix=prefix)
|
|
117
142
|
self.disabled = epics_signal_r(int, prefix + "DISABLED")
|
|
118
143
|
|
|
144
|
+
self.defer_move = epics_signal_rw(DeferMoves, prefix + "CS1:DeferMoves")
|
|
145
|
+
|
|
119
146
|
super().__init__(name)
|
|
120
147
|
|
|
121
148
|
def get_xyz_limits(self) -> Generator[Msg, None, XYZLimits]:
|
|
@@ -135,3 +162,15 @@ class Smargon(StandardReadable):
|
|
|
135
162
|
max_value = yield from bps.rd(pv.high_limit_travel)
|
|
136
163
|
limits[name] = AxisLimit(min_value, max_value)
|
|
137
164
|
return XYZLimits(**limits)
|
|
165
|
+
|
|
166
|
+
@AsyncStatus.wrap
|
|
167
|
+
async def set(self, value: CombinedMove):
|
|
168
|
+
await self.defer_move.set(DeferMoves.ON)
|
|
169
|
+
try:
|
|
170
|
+
tasks = []
|
|
171
|
+
for k, v in value.items():
|
|
172
|
+
if v is not None:
|
|
173
|
+
tasks.append(getattr(self, k).set(v))
|
|
174
|
+
await asyncio.gather(*tasks)
|
|
175
|
+
finally:
|
|
176
|
+
await self.defer_move.set(DeferMoves.OFF)
|
dodal/devices/zebra/zebra.py
CHANGED
|
@@ -68,6 +68,14 @@ class RotationDirection(StrictEnum):
|
|
|
68
68
|
def multiplier(self):
|
|
69
69
|
return 1 if self == RotationDirection.POSITIVE else -1
|
|
70
70
|
|
|
71
|
+
@property
|
|
72
|
+
def opposite(self) -> RotationDirection:
|
|
73
|
+
return (
|
|
74
|
+
RotationDirection.POSITIVE
|
|
75
|
+
if self == RotationDirection.NEGATIVE
|
|
76
|
+
else RotationDirection.NEGATIVE
|
|
77
|
+
)
|
|
78
|
+
|
|
71
79
|
|
|
72
80
|
class ArmDemand(Enum):
|
|
73
81
|
ARM = 1
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
import bluesky.plan_stubs as bps
|
|
4
|
+
from bluesky import preprocessors as bpp
|
|
5
|
+
from bluesky.run_engine import RunEngine
|
|
6
|
+
from ophyd_async.core import DetectorTrigger
|
|
7
|
+
from ophyd_async.fastcs.eiger import EigerDetector, EigerTriggerInfo
|
|
8
|
+
|
|
9
|
+
from dodal.beamlines.i03 import fastcs_eiger
|
|
10
|
+
from dodal.devices.detector import DetectorParams
|
|
11
|
+
from dodal.log import LOGGER, do_default_logging_setup
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@bpp.run_decorator()
|
|
15
|
+
def configure_arm_trigger_and_disarm_detector(
|
|
16
|
+
eiger: EigerDetector,
|
|
17
|
+
detector_params: DetectorParams,
|
|
18
|
+
trigger_info: EigerTriggerInfo,
|
|
19
|
+
):
|
|
20
|
+
assert detector_params.expected_energy_ev
|
|
21
|
+
start = time.time()
|
|
22
|
+
yield from bps.unstage(eiger, wait=True)
|
|
23
|
+
LOGGER.info(f"Stopping Eiger-Odin: {time.time() - start}s")
|
|
24
|
+
start = time.time()
|
|
25
|
+
yield from set_cam_pvs(eiger, detector_params, wait=True)
|
|
26
|
+
LOGGER.info(f"Setting CAM PVs: {time.time() - start}s")
|
|
27
|
+
start = time.time()
|
|
28
|
+
yield from change_roi_mode(eiger, detector_params, wait=True)
|
|
29
|
+
LOGGER.info(f"Changing ROI Mode: {time.time() - start}s")
|
|
30
|
+
start = time.time()
|
|
31
|
+
yield from bps.abs_set(eiger.odin.num_frames_chunks, 1)
|
|
32
|
+
LOGGER.info(f"Setting # of Frame Chunks: {time.time() - start}s")
|
|
33
|
+
start = time.time()
|
|
34
|
+
yield from set_mx_settings_pvs(eiger, detector_params, wait=True)
|
|
35
|
+
LOGGER.info(f"Setting MX PVs: {time.time() - start}s")
|
|
36
|
+
start = time.time()
|
|
37
|
+
yield from bps.prepare(eiger, trigger_info, wait=True)
|
|
38
|
+
LOGGER.info(f"Preparing Eiger: {time.time() - start}s")
|
|
39
|
+
start = time.time()
|
|
40
|
+
yield from bps.kickoff(eiger, wait=True)
|
|
41
|
+
LOGGER.info(f"Kickoff Eiger: {time.time() - start}s")
|
|
42
|
+
start = time.time()
|
|
43
|
+
yield from bps.trigger(eiger.drv.detector.trigger) # type: ignore
|
|
44
|
+
LOGGER.info(f"Triggering Eiger: {time.time() - start}s")
|
|
45
|
+
start = time.time()
|
|
46
|
+
yield from bps.complete(eiger, wait=True)
|
|
47
|
+
LOGGER.info(f"Completing Capture: {time.time() - start}s")
|
|
48
|
+
start = time.time()
|
|
49
|
+
yield from bps.unstage(eiger, wait=True)
|
|
50
|
+
LOGGER.info(f"Disarming Eiger: {time.time() - start}s")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def set_cam_pvs(
|
|
54
|
+
eiger: EigerDetector,
|
|
55
|
+
detector_params: DetectorParams,
|
|
56
|
+
wait: bool,
|
|
57
|
+
group="cam_pvs",
|
|
58
|
+
):
|
|
59
|
+
yield from bps.abs_set(
|
|
60
|
+
eiger.drv.detector.count_time, detector_params.exposure_time_s, group=group
|
|
61
|
+
)
|
|
62
|
+
yield from bps.abs_set(
|
|
63
|
+
eiger.drv.detector.frame_time, detector_params.exposure_time_s, group=group
|
|
64
|
+
)
|
|
65
|
+
yield from bps.abs_set(eiger.drv.detector.nexpi, 1, group=group)
|
|
66
|
+
|
|
67
|
+
if wait:
|
|
68
|
+
yield from bps.wait(group)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def change_roi_mode(
|
|
72
|
+
eiger: EigerDetector,
|
|
73
|
+
detector_params: DetectorParams,
|
|
74
|
+
wait: bool,
|
|
75
|
+
group="roi_mode",
|
|
76
|
+
):
|
|
77
|
+
detector_dimensions = (
|
|
78
|
+
detector_params.detector_size_constants.roi_size_pixels
|
|
79
|
+
if detector_params.use_roi_mode
|
|
80
|
+
else detector_params.detector_size_constants.det_size_pixels
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
yield from bps.abs_set(
|
|
84
|
+
eiger.drv.detector.roi_mode,
|
|
85
|
+
1 if detector_params.use_roi_mode else 0,
|
|
86
|
+
group=group,
|
|
87
|
+
)
|
|
88
|
+
yield from bps.abs_set(
|
|
89
|
+
eiger.odin.image_height,
|
|
90
|
+
detector_dimensions.height,
|
|
91
|
+
group=group,
|
|
92
|
+
)
|
|
93
|
+
yield from bps.abs_set(
|
|
94
|
+
eiger.odin.image_width,
|
|
95
|
+
detector_dimensions.width,
|
|
96
|
+
group=group,
|
|
97
|
+
)
|
|
98
|
+
yield from bps.abs_set(
|
|
99
|
+
eiger.odin.num_row_chunks,
|
|
100
|
+
detector_dimensions.height,
|
|
101
|
+
group=group,
|
|
102
|
+
)
|
|
103
|
+
yield from bps.abs_set(
|
|
104
|
+
eiger.odin.num_col_chunks,
|
|
105
|
+
detector_dimensions.width,
|
|
106
|
+
group=group,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if wait:
|
|
110
|
+
yield from bps.wait(group)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def set_mx_settings_pvs(
|
|
114
|
+
eiger: EigerDetector,
|
|
115
|
+
detector_params: DetectorParams,
|
|
116
|
+
wait: bool,
|
|
117
|
+
group="mx_settings",
|
|
118
|
+
):
|
|
119
|
+
beam_x_pixels, beam_y_pixels = detector_params.get_beam_position_pixels(
|
|
120
|
+
detector_params.detector_distance
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
yield from bps.abs_set(eiger.drv.detector.beam_center_x, beam_x_pixels, group)
|
|
124
|
+
yield from bps.abs_set(eiger.drv.detector.beam_center_y, beam_y_pixels, group)
|
|
125
|
+
yield from bps.abs_set(
|
|
126
|
+
eiger.drv.detector.detector_distance, detector_params.detector_distance, group
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
yield from bps.abs_set(
|
|
130
|
+
eiger.drv.detector.omega_start, detector_params.omega_start, group
|
|
131
|
+
)
|
|
132
|
+
yield from bps.abs_set(
|
|
133
|
+
eiger.drv.detector.omega_increment, detector_params.omega_increment, group
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if wait:
|
|
137
|
+
yield from bps.wait(group)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
RE = RunEngine()
|
|
142
|
+
do_default_logging_setup()
|
|
143
|
+
eiger = fastcs_eiger(connect_immediately=True)
|
|
144
|
+
RE(
|
|
145
|
+
configure_arm_trigger_and_disarm_detector(
|
|
146
|
+
eiger=eiger,
|
|
147
|
+
detector_params=DetectorParams(
|
|
148
|
+
expected_energy_ev=12800,
|
|
149
|
+
exposure_time_s=0.01,
|
|
150
|
+
directory="/dls/i03/data/2025/cm40607-2/test_new_eiger/",
|
|
151
|
+
prefix="",
|
|
152
|
+
detector_distance=255,
|
|
153
|
+
omega_start=0,
|
|
154
|
+
omega_increment=0.1,
|
|
155
|
+
num_images_per_trigger=1,
|
|
156
|
+
num_triggers=1,
|
|
157
|
+
use_roi_mode=False,
|
|
158
|
+
det_dist_to_beam_converter_path="/dls_sw/i03/software/daq_configuration/lookup/DetDistToBeamXYConverter.txt",
|
|
159
|
+
),
|
|
160
|
+
trigger_info=EigerTriggerInfo(
|
|
161
|
+
number_of_events=1,
|
|
162
|
+
energy_ev=12800,
|
|
163
|
+
trigger=DetectorTrigger.INTERNAL,
|
|
164
|
+
deadtime=0.0001,
|
|
165
|
+
),
|
|
166
|
+
)
|
|
167
|
+
)
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
from bluesky import plan_stubs as bps
|
|
2
|
-
from bluesky.utils import MsgGenerator, plan
|
|
3
|
-
from ophyd_async.epics.adcore import ADImageMode
|
|
4
|
-
|
|
5
|
-
from dodal.common.types import MsgGenerator
|
|
6
|
-
from dodal.devices.electron_analyser.abstract import (
|
|
7
|
-
AbstractAnalyserDriverIO,
|
|
8
|
-
AbstractBaseRegion,
|
|
9
|
-
)
|
|
10
|
-
from dodal.devices.electron_analyser.specs import SpecsAnalyserDriverIO, SpecsRegion
|
|
11
|
-
from dodal.devices.electron_analyser.util import to_kinetic_energy
|
|
12
|
-
from dodal.devices.electron_analyser.vgscienta import (
|
|
13
|
-
VGScientaAnalyserDriverIO,
|
|
14
|
-
VGScientaRegion,
|
|
15
|
-
)
|
|
16
|
-
from dodal.log import LOGGER
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@plan
|
|
20
|
-
def configure_analyser(
|
|
21
|
-
analyser: AbstractAnalyserDriverIO,
|
|
22
|
-
region: AbstractBaseRegion,
|
|
23
|
-
excitation_energy: float,
|
|
24
|
-
) -> MsgGenerator:
|
|
25
|
-
LOGGER.info(f'Configuring analyser with region "{region.name}"')
|
|
26
|
-
|
|
27
|
-
low_energy = to_kinetic_energy(
|
|
28
|
-
region.low_energy, region.energy_mode, excitation_energy
|
|
29
|
-
)
|
|
30
|
-
high_energy = to_kinetic_energy(
|
|
31
|
-
region.high_energy, region.energy_mode, excitation_energy
|
|
32
|
-
)
|
|
33
|
-
pass_energy_type = analyser.pass_energy_type
|
|
34
|
-
pass_energy = pass_energy_type(region.pass_energy)
|
|
35
|
-
|
|
36
|
-
# Set detector settings, wait for them all to have completed
|
|
37
|
-
# fmt: off
|
|
38
|
-
yield from bps.mv(
|
|
39
|
-
analyser.region_name, region.name,
|
|
40
|
-
analyser.energy_mode, region.energy_mode,
|
|
41
|
-
analyser.excitation_energy, excitation_energy,
|
|
42
|
-
analyser.low_energy, low_energy,
|
|
43
|
-
analyser.high_energy, high_energy,
|
|
44
|
-
analyser.slices, region.slices,
|
|
45
|
-
analyser.lens_mode, region.lens_mode,
|
|
46
|
-
analyser.pass_energy, pass_energy,
|
|
47
|
-
analyser.iterations, region.iterations,
|
|
48
|
-
analyser.acquisition_mode, region.acquisition_mode,
|
|
49
|
-
)
|
|
50
|
-
# fmt: on
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@plan
|
|
54
|
-
def configure_specs(
|
|
55
|
-
analyser: SpecsAnalyserDriverIO, region: SpecsRegion, excitation_energy: float
|
|
56
|
-
) -> MsgGenerator:
|
|
57
|
-
yield from configure_analyser(analyser, region, excitation_energy)
|
|
58
|
-
# fmt: off
|
|
59
|
-
yield from bps.mv(
|
|
60
|
-
analyser.snapshot_values, region.values,
|
|
61
|
-
analyser.psu_mode, region.psu_mode,
|
|
62
|
-
)
|
|
63
|
-
# fmt: on
|
|
64
|
-
if region.acquisition_mode == "Fixed Transmission":
|
|
65
|
-
yield from bps.mv(analyser.centre_energy, region.centre_energy)
|
|
66
|
-
|
|
67
|
-
if region.acquisition_mode == "Fixed Energy":
|
|
68
|
-
yield from bps.mv(analyser.energy_step, region.energy_step)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@plan
|
|
72
|
-
def configure_vgscienta(
|
|
73
|
-
analyser: VGScientaAnalyserDriverIO, region: VGScientaRegion, excitation_energy
|
|
74
|
-
) -> MsgGenerator:
|
|
75
|
-
yield from configure_analyser(analyser, region, excitation_energy)
|
|
76
|
-
centre_energy = to_kinetic_energy(
|
|
77
|
-
region.fix_energy, region.energy_mode, excitation_energy
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
# fmt: off
|
|
81
|
-
yield from bps.mv(
|
|
82
|
-
analyser.centre_energy, centre_energy,
|
|
83
|
-
analyser.energy_step, region.energy_step,
|
|
84
|
-
analyser.first_x_channel, region.first_x_channel,
|
|
85
|
-
analyser.first_y_channel, region.first_y_channel,
|
|
86
|
-
analyser.x_channel_size, region.x_channel_size(),
|
|
87
|
-
analyser.y_channel_size, region.y_channel_size(),
|
|
88
|
-
analyser.detector_mode, region.detector_mode,
|
|
89
|
-
analyser.excitation_energy_source, region.excitation_energy_source,
|
|
90
|
-
analyser.image_mode, ADImageMode.SINGLE,
|
|
91
|
-
)
|
|
92
|
-
# fmt: on
|
|
File without changes
|
|
File without changes
|
|
File without changes
|