dls-dodal 1.60.0__py3-none-any.whl → 1.62.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.
Files changed (45) hide show
  1. {dls_dodal-1.60.0.dist-info → dls_dodal-1.62.0.dist-info}/METADATA +1 -1
  2. {dls_dodal-1.60.0.dist-info → dls_dodal-1.62.0.dist-info}/RECORD +45 -30
  3. dodal/_version.py +2 -2
  4. dodal/beamlines/i04.py +1 -1
  5. dodal/beamlines/i19_2.py +10 -0
  6. dodal/devices/apple2_undulator.py +85 -52
  7. dodal/devices/areadetector/__init__.py +0 -0
  8. dodal/devices/areadetector/plugins/__init__.py +0 -0
  9. dodal/devices/attenuator/__init__.py +0 -0
  10. dodal/devices/controllers.py +8 -6
  11. dodal/devices/electron_analyser/abstract/__init__.py +2 -2
  12. dodal/devices/electron_analyser/abstract/base_detector.py +13 -26
  13. dodal/devices/electron_analyser/abstract/base_driver_io.py +5 -4
  14. dodal/devices/electron_analyser/abstract/base_region.py +28 -13
  15. dodal/devices/electron_analyser/detector.py +19 -31
  16. dodal/devices/electron_analyser/specs/driver_io.py +0 -1
  17. dodal/devices/electron_analyser/vgscienta/driver_io.py +0 -1
  18. dodal/devices/fast_grid_scan.py +111 -32
  19. dodal/devices/fast_shutter.py +57 -0
  20. dodal/devices/i02_1/fast_grid_scan.py +1 -1
  21. dodal/devices/i04/murko_results.py +24 -12
  22. dodal/devices/i10/i10_apple2.py +15 -15
  23. dodal/devices/i10/rasor/__init__.py +0 -0
  24. dodal/devices/i11/__init__.py +0 -0
  25. dodal/devices/i15/__init__.py +0 -0
  26. dodal/devices/i15/dcm.py +10 -9
  27. dodal/devices/i15/focussing_mirror.py +4 -20
  28. dodal/devices/i15/jack.py +2 -10
  29. dodal/devices/i15/laue.py +1 -5
  30. dodal/devices/i15/multilayer_mirror.py +1 -5
  31. dodal/devices/i15/rail.py +1 -5
  32. dodal/devices/i18/__init__.py +0 -0
  33. dodal/devices/i19/mapt_configuration.py +38 -0
  34. dodal/devices/i19/pin_col_stages.py +170 -0
  35. dodal/devices/i22/__init__.py +0 -0
  36. dodal/devices/i24/commissioning_jungfrau.py +9 -1
  37. dodal/devices/mx_phase1/__init__.py +0 -0
  38. dodal/devices/oav/snapshots/__init__.py +0 -0
  39. dodal/devices/xspress3/__init__.py +0 -0
  40. dodal/parameters/__init__.py +0 -0
  41. dodal/plans/configure_arm_trigger_and_disarm_detector.py +27 -5
  42. {dls_dodal-1.60.0.dist-info → dls_dodal-1.62.0.dist-info}/WHEEL +0 -0
  43. {dls_dodal-1.60.0.dist-info → dls_dodal-1.62.0.dist-info}/entry_points.txt +0 -0
  44. {dls_dodal-1.60.0.dist-info → dls_dodal-1.62.0.dist-info}/licenses/LICENSE +0 -0
  45. {dls_dodal-1.60.0.dist-info → dls_dodal-1.62.0.dist-info}/top_level.txt +0 -0
File without changes
File without changes
File without changes
dodal/devices/i15/dcm.py CHANGED
@@ -28,19 +28,17 @@ Xtal_1 = TypeVar("Xtal_1", bound=StationaryCrystal)
28
28
  Xtal_2 = TypeVar("Xtal_2", bound=StationaryCrystal)
29
29
 
30
30
 
31
- class DualCrystalMonoSimple(StandardReadable, Generic[Xtal_1, Xtal_2]):
31
+ class BaseDCMforI15(StandardReadable, Generic[Xtal_1, Xtal_2]):
32
32
  """
33
- Device for simple double crystal monochromators (DCM), which only allow energy of the beam to be selected.
33
+ Device for double crystal monochromators (DCM), which only allow energy of the beam to be selected.
34
34
 
35
35
  Features common across all DCM's should include virtual motors to set energy/wavelength and contain two crystals,
36
36
  each of which can be movable. Some DCM's contain crystals with roll motors, and some contain crystals with roll and pitch motors.
37
- This base device accounts for all combinations of this.
37
+ This device only accounts for combinations of energy plus two crystals.
38
38
 
39
- This device is more able to act as a parent for beamline-specific DCM's, in which any other missing signals can be added,
40
- as it doesn't assume WAVELENGTH, BRAGG and OFFSET are available for all DCM deivces, as BaseDCM does.
41
-
42
- Bluesky plans using DCM's should be typed to specify which types of crystals are required. For example, a plan
43
- which only requires one crystal which can roll should be typed 'def my_plan(dcm: BaseDCM[RollCrystal, StationaryCrystal])`
39
+ This device is designed to be a drop in replacement for BaseDCM for i15, which doesn't require WAVELENGTH, BRAGG and OFFSET to
40
+ be available. Once the i15 DCM supports all of the PVs required by BaseDCM, the i15 DCM device can switch to inheriting from
41
+ BaseDCM and this class can be removed.
44
42
  """
45
43
 
46
44
  def __init__(
@@ -64,9 +62,12 @@ class DualCrystalMonoSimple(StandardReadable, Generic[Xtal_1, Xtal_2]):
64
62
  self.xtal_2 = xtal_2(prefix)
65
63
 
66
64
 
67
- class DCM(DualCrystalMonoSimple[ThetaRollYZCrystal, ThetaYCrystal]):
65
+ class DCM(BaseDCMforI15[ThetaRollYZCrystal, ThetaYCrystal]):
68
66
  """
69
67
  A double crystal monocromator device, used to select the beam energy.
68
+
69
+ Once the i15 DCM supports all of the PVs required by BaseDCM, this class can be
70
+ changed to inherit from BaseDCM and BaseDCMforI15 can be removed.
70
71
  """
71
72
 
72
73
  def __init__(self, prefix: str, name: str = "") -> None:
@@ -5,11 +5,7 @@ from ophyd_async.epics.motor import Motor
5
5
  class FocusingMirrorBase(StandardReadable):
6
6
  """Focusing Mirror with curve, ellip & pitch"""
7
7
 
8
- def __init__(
9
- self,
10
- prefix: str,
11
- name: str = "",
12
- ):
8
+ def __init__(self, prefix: str, name: str = ""):
13
9
  with self.add_children_as_readables():
14
10
  self.curve = Motor(prefix + "CURVE")
15
11
  self.ellipticity = Motor(prefix + "ELLIP")
@@ -21,11 +17,7 @@ class FocusingMirrorBase(StandardReadable):
21
17
  class FocusingMirrorHorizontal(FocusingMirrorBase):
22
18
  """Focusing Mirror with curve, ellip, pitch & X"""
23
19
 
24
- def __init__(
25
- self,
26
- prefix: str,
27
- name: str = "",
28
- ):
20
+ def __init__(self, prefix: str, name: str = ""):
29
21
  with self.add_children_as_readables():
30
22
  self.x = Motor(prefix + "X")
31
23
 
@@ -35,11 +27,7 @@ class FocusingMirrorHorizontal(FocusingMirrorBase):
35
27
  class FocusingMirrorVertical(FocusingMirrorBase):
36
28
  """Focusing Mirror with curve, ellip, pitch & Y"""
37
29
 
38
- def __init__(
39
- self,
40
- prefix: str,
41
- name: str = "",
42
- ):
30
+ def __init__(self, prefix: str, name: str = ""):
43
31
  with self.add_children_as_readables():
44
32
  self.y = Motor(prefix + "Y")
45
33
 
@@ -49,11 +37,7 @@ class FocusingMirrorVertical(FocusingMirrorBase):
49
37
  class FocusingMirror(FocusingMirrorBase):
50
38
  """Focusing Mirror with curve, ellip, pitch, yaw, X & Y"""
51
39
 
52
- def __init__(
53
- self,
54
- prefix: str,
55
- name: str = "",
56
- ):
40
+ def __init__(self, prefix: str, name: str = ""):
57
41
  with self.add_children_as_readables():
58
42
  self.yaw = Motor(prefix + "YAW")
59
43
  self.x = Motor(prefix + "X")
dodal/devices/i15/jack.py CHANGED
@@ -5,11 +5,7 @@ from ophyd_async.epics.motor import Motor
5
5
  class JackX(StandardReadable):
6
6
  """Focusing Mirror"""
7
7
 
8
- def __init__(
9
- self,
10
- prefix: str,
11
- name: str = "",
12
- ):
8
+ def __init__(self, prefix: str, name: str = ""):
13
9
  with self.add_children_as_readables():
14
10
  self.rotation = Motor(prefix + "Ry")
15
11
  self.transx = Motor(prefix + "X")
@@ -23,11 +19,7 @@ class JackX(StandardReadable):
23
19
  class JackY(StandardReadable):
24
20
  """Focusing Mirror"""
25
21
 
26
- def __init__(
27
- self,
28
- prefix: str,
29
- name: str = "",
30
- ):
22
+ def __init__(self, prefix: str, name: str = ""):
31
23
  with self.add_children_as_readables():
32
24
  self.j1 = Motor(prefix + "J1")
33
25
  self.j2 = Motor(prefix + "J2")
dodal/devices/i15/laue.py CHANGED
@@ -3,11 +3,7 @@ from ophyd_async.epics.motor import Motor
3
3
 
4
4
 
5
5
  class LaueMonochrometer(StandardReadable):
6
- def __init__(
7
- self,
8
- prefix: str,
9
- name: str = "",
10
- ):
6
+ def __init__(self, prefix: str, name: str = ""):
11
7
  with self.add_children_as_readables():
12
8
  self.bend = Motor(prefix + "BENDER")
13
9
  self.bragg = Motor(prefix + "PITCH")
@@ -5,11 +5,7 @@ from ophyd_async.epics.motor import Motor
5
5
  class MultiLayerMirror(StandardReadable):
6
6
  """Multilayer Mirror"""
7
7
 
8
- def __init__(
9
- self,
10
- prefix: str,
11
- name: str = "",
12
- ):
8
+ def __init__(self, prefix: str, name: str = ""):
13
9
  with self.add_children_as_readables():
14
10
  self.ds_x = Motor(prefix + "X2")
15
11
  self.ds_y = Motor(prefix + "J3")
dodal/devices/i15/rail.py CHANGED
@@ -3,11 +3,7 @@ from ophyd_async.epics.motor import Motor
3
3
 
4
4
 
5
5
  class Rail(StandardReadable):
6
- def __init__(
7
- self,
8
- prefix: str,
9
- name: str = "",
10
- ):
6
+ def __init__(self, prefix: str, name: str = ""):
11
7
  with self.add_children_as_readables():
12
8
  self.pitch = Motor(prefix + "PITCH")
13
9
  self.y = Motor(prefix + "Y")
File without changes
@@ -0,0 +1,38 @@
1
+ from ophyd_async.core import DeviceVector, SignalR, StandardReadable, SubsetEnum
2
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_x
3
+
4
+
5
+ class MAPTConfigurationTable(StandardReadable):
6
+ """Readable device that can be used to build the read-only MAPT (Mini Apertures)
7
+ configuration table in controls for aperture motors in the available positions.
8
+ For each aperture it sets up a readable signal with the position of all the motors
9
+ in the MAPT configuration.
10
+ This device can be used to build the table for both eh1 and eh2 on I19, in
11
+ combination with the MAPTConfigurationControl device.
12
+ """
13
+
14
+ def __init__(
15
+ self, prefix: str, motor_name: str, aperture_list: list[int], name: str = ""
16
+ ) -> None:
17
+ with self.add_children_as_readables():
18
+ self.in_positions: DeviceVector[SignalR[float]] = DeviceVector(
19
+ {
20
+ pos: epics_signal_r(float, f"{prefix}:{pos}UM:{motor_name}")
21
+ for pos in aperture_list
22
+ }
23
+ )
24
+ super().__init__(name)
25
+
26
+
27
+ class MAPTConfigurationControl(StandardReadable):
28
+ """A device to control the MAPT (Mini Aperture) configuration. It provides a signal
29
+ to set the configuration PV to the requested value and a triggerable signal that
30
+ will move all the motors to the correct position."""
31
+
32
+ def __init__(
33
+ self, prefix: str, aperture_request: type[SubsetEnum], name: str = ""
34
+ ) -> None:
35
+ with self.add_children_as_readables():
36
+ self.select_config = epics_signal_rw(aperture_request, f"{prefix}")
37
+ self.apply_selection = epics_signal_x(f"{prefix}:APPLY.PROC")
38
+ super().__init__(name)
@@ -0,0 +1,170 @@
1
+ import asyncio
2
+ from enum import StrEnum
3
+
4
+ from bluesky.protocols import Movable
5
+ from ophyd_async.core import AsyncStatus, StandardReadable, SubsetEnum
6
+ from ophyd_async.epics.core import epics_signal_r
7
+ from pydantic import BaseModel
8
+
9
+ from dodal.devices.i19.mapt_configuration import (
10
+ MAPTConfigurationControl,
11
+ MAPTConfigurationTable,
12
+ )
13
+ from dodal.devices.motors import XYStage
14
+ from dodal.log import LOGGER
15
+
16
+ _PIN = "-MO-PIN-01:"
17
+ _COL = "-MO-COL-01:"
18
+ _CONFIG = "-OP-PCOL-01:"
19
+
20
+
21
+ class PinColRequest(StrEnum):
22
+ """Aperture request positions."""
23
+
24
+ PCOL20 = "20um"
25
+ PCOL40 = "40um"
26
+ PCOL100 = "100um"
27
+ PCOL3000 = "3000um"
28
+ OUT = "OUT"
29
+
30
+
31
+ # NOTE. Using subset enum because from the OUT positions should only be used by
32
+ # the beamline scientists from the synoptic. Another option will be needed in the
33
+ # device for OUT position.
34
+ class _PinColPosition(SubsetEnum):
35
+ """Aperture request IN positions."""
36
+
37
+ PCOL20 = "20um"
38
+ PCOL40 = "40um"
39
+ PCOL100 = "100um"
40
+ PCOL3000 = "3000um"
41
+
42
+
43
+ class AperturePosition(BaseModel):
44
+ """Describe the positions of the pinhole and collimator stage motors for
45
+ one of the available apertures.
46
+
47
+ Attributes:
48
+ pinhole_x: The position of the x motor on the pinhole stage
49
+ pinhole_y: The position of the y motor on the pinhole stage
50
+ collimator_x: The position of the x motor on the collimator stage
51
+ collimator_y: The position of the y motor on the collimator stage
52
+ """
53
+
54
+ pinhole_x: float
55
+ pinhole_y: float
56
+ collimator_x: float
57
+ collimator_y: float
58
+
59
+
60
+ class PinColConfiguration(StandardReadable):
61
+ """Full MAPT configuration table, including out positions and selection for the
62
+ Pinhole and Collimator control."""
63
+
64
+ def __init__(self, prefix: str, apertures: list[int], name: str = "") -> None:
65
+ with self.add_children_as_readables():
66
+ self.configuration = MAPTConfigurationControl(prefix, _PinColPosition)
67
+ self.pin_x = MAPTConfigurationTable(prefix, "PINX", apertures)
68
+ self.pin_y = MAPTConfigurationTable(prefix, "PINY", apertures)
69
+ self.col_x = MAPTConfigurationTable(prefix, "COLX", apertures)
70
+ self.col_y = MAPTConfigurationTable(prefix, "COLY", apertures)
71
+ self.pin_x_out = epics_signal_r(float, f"{prefix}:OUT:PINX")
72
+ self.col_x_out = epics_signal_r(float, f"{prefix}:OUT:COLX")
73
+ super().__init__(name)
74
+
75
+
76
+ class PinholeCollimatorControl(StandardReadable, Movable[str]):
77
+ """Device to control the Pinhole and Collimator stages moves on I19-2, using the
78
+ MAPT configuration table to look up the positions."""
79
+
80
+ def __init__(
81
+ self,
82
+ prefix: str,
83
+ name: str = "",
84
+ pin_infix: str = _PIN,
85
+ col_infix: str = _COL,
86
+ config_infix: str = _CONFIG,
87
+ ):
88
+ self._aperture_sizes = [self._get_aperture_size(i) for i in _PinColPosition]
89
+ with self.add_children_as_readables():
90
+ self._pinhole = XYStage(f"{prefix}{pin_infix}")
91
+ self._collimator = XYStage(f"{prefix}{col_infix}")
92
+ self.mapt = PinColConfiguration(
93
+ f"{prefix}{config_infix}CONFIG", apertures=self._aperture_sizes
94
+ )
95
+ super().__init__(name=name)
96
+
97
+ def _get_aperture_size(self, ap_request: str) -> int:
98
+ return int(ap_request.strip("um"))
99
+
100
+ async def _get_motor_positions_for_requested_aperture(
101
+ self, ap_request: _PinColPosition
102
+ ) -> AperturePosition:
103
+ val = self._get_aperture_size(ap_request.value)
104
+
105
+ pinx = await self.mapt.pin_x.in_positions[val].get_value()
106
+ piny = await self.mapt.pin_y.in_positions[val].get_value()
107
+ colx = await self.mapt.col_x.in_positions[val].get_value()
108
+ coly = await self.mapt.col_y.in_positions[val].get_value()
109
+
110
+ return AperturePosition(
111
+ pinhole_x=pinx, pinhole_y=piny, collimator_x=colx, collimator_y=coly
112
+ )
113
+
114
+ async def _safe_move_out(self):
115
+ """Move the pinhole and collimator stages safely to the out position, which
116
+ involves only the x motors of the stages.
117
+ In order to avoid a collision, we have to make sure that the collimator stage is
118
+ always moved out first and the pinhole stage second.
119
+ """
120
+ LOGGER.info("Moving pinhole and collimator stages to out position")
121
+ colx_out = await self.mapt.col_x_out.get_value()
122
+ pin_x_out = await self.mapt.pin_x_out.get_value()
123
+ # First move Collimator x motor
124
+ LOGGER.debug(f"Move collimator stage x motor to {colx_out}")
125
+ await self._collimator.x.set(colx_out)
126
+ # Then move Pinhole x motor
127
+ LOGGER.debug(f"Move pinhole stage x motor to {pin_x_out}")
128
+ await self._pinhole.x.set(pin_x_out)
129
+
130
+ async def _safe_move_in(self, value: _PinColPosition):
131
+ """Move the pinhole and collimator stages safely to the in position.
132
+ In order to avoid a collision, we have to make sure that the pinhole stage is
133
+ always moved in before the collimator stage."""
134
+ LOGGER.info(
135
+ f"Moving pinhole and collimator stages to in position: {value.value}"
136
+ )
137
+ await self.mapt.configuration.select_config.set(value, wait=True)
138
+ # NOTE. The apply PV will not be used here unless fixed in controls first.
139
+ # This is to avoid collisions. A safe move in will move first the pinhole stage
140
+ # and then the collimator stage, but apply will try to move all the motors
141
+ # at the same time.
142
+ aperture_positions = await self._get_motor_positions_for_requested_aperture(
143
+ value
144
+ )
145
+ LOGGER.debug(f"Moving motors to {aperture_positions}")
146
+
147
+ # First move Pinhole motors,
148
+ LOGGER.debug("Moving pinhole stage in")
149
+ await asyncio.gather(
150
+ self._pinhole.x.set(aperture_positions.pinhole_x),
151
+ self._pinhole.y.set(aperture_positions.pinhole_y),
152
+ )
153
+ # Then move Collimator motors
154
+ LOGGER.debug("Moving collimator stage in")
155
+ await asyncio.gather(
156
+ self._collimator.x.set(aperture_positions.collimator_x),
157
+ self._collimator.y.set(aperture_positions.collimator_y),
158
+ )
159
+
160
+ @AsyncStatus.wrap
161
+ async def set(self, value: PinColRequest):
162
+ """Moves the motor stages to the position for the requested aperture while
163
+ avoiding possible collisions.
164
+ The request coming from a plan should always be one of accepted request values:
165
+ ('20um', '40um', '100um', '3000um', 'OUT').
166
+ """
167
+ if value is PinColRequest.OUT:
168
+ await self._safe_move_out()
169
+ else:
170
+ await self._safe_move_in(_PinColPosition(value))
File without changes
@@ -5,11 +5,13 @@ from pathlib import Path
5
5
  from bluesky.protocols import StreamAsset
6
6
  from event_model import DataKey # type: ignore
7
7
  from ophyd_async.core import (
8
+ AsyncStatus,
8
9
  AutoIncrementingPathProvider,
9
10
  DetectorWriter,
10
11
  StandardDetector,
11
12
  StandardReadable,
12
13
  StaticPathProvider,
14
+ TriggerInfo,
13
15
  observe_value,
14
16
  wait_for_value,
15
17
  )
@@ -40,6 +42,7 @@ class JunfrauCommissioningWriter(DetectorWriter, StandardReadable):
40
42
  self.file_name = epics_signal_rw_rbv(str, f"{prefix}FileName")
41
43
  self.file_path = epics_signal_rw_rbv(str, f"{prefix}FilePath")
42
44
  self.writer_ready = epics_signal_r(int, f"{prefix}Ready_RBV")
45
+ self.expected_frames = epics_signal_rw(int, f"{prefix}NumCapture")
43
46
  super().__init__(name)
44
47
 
45
48
  async def open(self, name: str, exposures_per_event: int = 1) -> dict[str, DataKey]:
@@ -80,7 +83,7 @@ class JunfrauCommissioningWriter(DetectorWriter, StandardReadable):
80
83
  async def observe_indices_written(
81
84
  self, timeout: float
82
85
  ) -> AsyncGenerator[int, None]:
83
- timeout = timeout * 2 # This filewriter is slow
86
+ timeout = timeout * 4 # This filewriter is very slow
84
87
  async for num_captured in observe_value(self.frame_counter, timeout):
85
88
  yield num_captured // (self._exposures_per_event)
86
89
 
@@ -112,3 +115,8 @@ class CommissioningJungfrau(
112
115
  writer = JunfrauCommissioningWriter(writer_prefix, path_provider)
113
116
  controller = JungfrauController(self.drv)
114
117
  super().__init__(controller, writer, name=name)
118
+
119
+ @AsyncStatus.wrap
120
+ async def prepare(self, value: TriggerInfo) -> None:
121
+ await super().prepare(value)
122
+ await self._writer.expected_frames.set(value.total_number_of_exposures)
File without changes
File without changes
File without changes
File without changes
@@ -1,12 +1,18 @@
1
1
  import time
2
+ from pathlib import PurePath
2
3
 
3
4
  import bluesky.plan_stubs as bps
4
5
  from bluesky import preprocessors as bpp
5
6
  from bluesky.run_engine import RunEngine
6
- from ophyd_async.core import DetectorTrigger, TriggerInfo
7
+ from ophyd_async.core import (
8
+ DetectorTrigger,
9
+ StaticFilenameProvider,
10
+ StaticPathProvider,
11
+ TriggerInfo,
12
+ )
7
13
  from ophyd_async.fastcs.eiger import EigerDetector
8
14
 
9
- from dodal.beamlines.i03 import fastcs_eiger
15
+ from dodal.beamlines.i03 import fastcs_eiger, set_path_provider
10
16
  from dodal.devices.detector import DetectorParams
11
17
  from dodal.log import LOGGER, do_default_logging_setup
12
18
 
@@ -28,9 +34,17 @@ def configure_arm_trigger_and_disarm_detector(
28
34
  yield from change_roi_mode(eiger, detector_params, wait=True)
29
35
  LOGGER.info(f"Changing ROI Mode: {time.time() - start}s")
30
36
  start = time.time()
31
- yield from bps.abs_set(eiger.odin.num_frames_chunks, 1)
37
+ yield from bps.abs_set(eiger.odin.num_frames_chunks, 1, wait=True)
32
38
  LOGGER.info(f"Setting # of Frame Chunks: {time.time() - start}s")
33
39
  start = time.time()
40
+ yield from bps.abs_set(
41
+ eiger.drv.detector.photon_energy, detector_params.expected_energy_ev, wait=True
42
+ )
43
+ LOGGER.info(f"Setting Photon Energy: {time.time() - start}s")
44
+ start = time.time()
45
+ yield from bps.abs_set(eiger.drv.detector.ntrigger, 1, wait=True)
46
+ LOGGER.info(f"Setting Number of Triggers: {time.time() - start}s")
47
+ start = time.time()
34
48
  yield from set_mx_settings_pvs(eiger, detector_params, wait=True)
35
49
  LOGGER.info(f"Setting MX PVs: {time.time() - start}s")
36
50
  start = time.time()
@@ -40,7 +54,7 @@ def configure_arm_trigger_and_disarm_detector(
40
54
  yield from bps.kickoff(eiger, wait=True)
41
55
  LOGGER.info(f"Kickoff Eiger: {time.time() - start}s")
42
56
  start = time.time()
43
- yield from bps.trigger(eiger.drv.detector.trigger) # type: ignore
57
+ yield from bps.trigger(eiger.drv.detector.trigger, wait=True)
44
58
  LOGGER.info(f"Triggering Eiger: {time.time() - start}s")
45
59
  start = time.time()
46
60
  yield from bps.complete(eiger, wait=True)
@@ -82,7 +96,7 @@ def change_roi_mode(
82
96
 
83
97
  yield from bps.abs_set(
84
98
  eiger.drv.detector.roi_mode,
85
- 1 if detector_params.use_roi_mode else 0,
99
+ "4M" if detector_params.use_roi_mode else "disabled",
86
100
  group=group,
87
101
  )
88
102
  yield from bps.abs_set(
@@ -143,6 +157,14 @@ def set_mx_settings_pvs(
143
157
  if __name__ == "__main__":
144
158
  RE = RunEngine()
145
159
  do_default_logging_setup()
160
+
161
+ path_provider = StaticPathProvider(
162
+ StaticFilenameProvider("eiger_test_file12.h5"),
163
+ PurePath("/dls/i03/data/2025/cm40607-2/test_new_eiger/"),
164
+ )
165
+
166
+ set_path_provider(path_provider)
167
+
146
168
  eiger = fastcs_eiger(connect_immediately=True)
147
169
  RE(
148
170
  configure_arm_trigger_and_disarm_detector(