mx-bluesky 1.5.0__py3-none-any.whl → 1.5.2__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 (56) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/i04/__init__.py +4 -1
  3. mx_bluesky/beamlines/i04/callbacks/murko_callback.py +56 -1
  4. mx_bluesky/beamlines/i04/experiment_plans/__init__.py +0 -0
  5. mx_bluesky/beamlines/i04/experiment_plans/i04_grid_detect_then_xray_centre_plan.py +259 -0
  6. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +8 -8
  7. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +8 -6
  8. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +4 -4
  9. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +2 -2
  10. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +5 -5
  11. mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +3 -3
  12. mx_bluesky/common/device_setup_plans/robot_load_unload.py +123 -0
  13. mx_bluesky/common/experiment_plans/change_aperture_then_move_plan.py +5 -1
  14. mx_bluesky/common/experiment_plans/common_flyscan_xray_centre_plan.py +27 -3
  15. mx_bluesky/common/experiment_plans/common_grid_detect_then_xray_centre_plan.py +1 -0
  16. mx_bluesky/common/experiment_plans/inner_plans/do_fgs.py +3 -1
  17. mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +26 -24
  18. mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +11 -7
  19. mx_bluesky/common/external_interaction/nexus/write_nexus.py +2 -2
  20. mx_bluesky/common/parameters/__init__.py +0 -0
  21. mx_bluesky/common/parameters/components.py +7 -2
  22. mx_bluesky/common/parameters/constants.py +5 -3
  23. mx_bluesky/common/parameters/device_composites.py +1 -1
  24. mx_bluesky/common/parameters/gridscan.py +1 -0
  25. mx_bluesky/common/xrc_result.py +25 -2
  26. mx_bluesky/hyperion/__main__.py +1 -1
  27. mx_bluesky/hyperion/baton_handler.py +36 -4
  28. mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +4 -93
  29. mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +19 -31
  30. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +26 -8
  31. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +21 -75
  32. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +2 -2
  33. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +14 -9
  34. mx_bluesky/hyperion/external_interaction/agamemnon.py +4 -4
  35. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -1
  36. mx_bluesky/hyperion/external_interaction/callbacks/{robot_load → robot_actions}/ispyb_callback.py +28 -19
  37. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +1 -1
  38. mx_bluesky/hyperion/external_interaction/callbacks/snapshot_callback.py +3 -0
  39. mx_bluesky/hyperion/external_interaction/config_server.py +0 -11
  40. mx_bluesky/hyperion/parameters/constants.py +2 -7
  41. mx_bluesky/hyperion/parameters/gridscan.py +2 -6
  42. mx_bluesky/hyperion/parameters/load_centre_collect.py +15 -0
  43. mx_bluesky/hyperion/parameters/rotation.py +7 -3
  44. mx_bluesky/hyperion/utils/context.py +19 -5
  45. mx_bluesky/phase1_zebra/__init__.py +1 -0
  46. mx_bluesky/phase1_zebra/device_setup_plans/__init__.py +0 -0
  47. mx_bluesky/phase1_zebra/device_setup_plans/setup_zebra.py +112 -0
  48. {mx_bluesky-1.5.0.dist-info → mx_bluesky-1.5.2.dist-info}/METADATA +5 -4
  49. {mx_bluesky-1.5.0.dist-info → mx_bluesky-1.5.2.dist-info}/RECORD +55 -49
  50. mx_bluesky/hyperion/utils/validation.py +0 -196
  51. /mx_bluesky/common/experiment_plans/{read_hardware.py → inner_plans/read_hardware.py} +0 -0
  52. /mx_bluesky/common/experiment_plans/{write_sample_status.py → inner_plans/write_sample_status.py} +0 -0
  53. {mx_bluesky-1.5.0.dist-info → mx_bluesky-1.5.2.dist-info}/WHEEL +0 -0
  54. {mx_bluesky-1.5.0.dist-info → mx_bluesky-1.5.2.dist-info}/entry_points.txt +0 -0
  55. {mx_bluesky-1.5.0.dist-info → mx_bluesky-1.5.2.dist-info}/licenses/LICENSE +0 -0
  56. {mx_bluesky-1.5.0.dist-info → mx_bluesky-1.5.2.dist-info}/top_level.txt +0 -0
mx_bluesky/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.5.0'
21
- __version_tuple__ = version_tuple = (1, 5, 0)
20
+ __version__ = version = '1.5.2'
21
+ __version_tuple__ = version_tuple = (1, 5, 2)
@@ -1,3 +1,6 @@
1
+ from mx_bluesky.beamlines.i04.experiment_plans import (
2
+ i04_grid_detect_then_xray_centre_plan,
3
+ )
1
4
  from mx_bluesky.beamlines.i04.thawing_plan import thaw, thaw_and_stream_to_redis
2
5
 
3
- __all__ = ["thaw", "thaw_and_stream_to_redis"]
6
+ __all__ = ["thaw", "thaw_and_stream_to_redis", "i04_grid_detect_then_xray_centre_plan"]
@@ -1,6 +1,7 @@
1
1
  import copy
2
2
  import json
3
3
  from datetime import timedelta
4
+ from typing import TypedDict
4
5
 
5
6
  from bluesky.callbacks import CallbackBase
6
7
  from dodal.log import LOGGER
@@ -8,7 +9,43 @@ from event_model.documents import Event, RunStart, RunStop
8
9
  from redis import StrictRedis
9
10
 
10
11
 
12
+ class OmegaReading(TypedDict):
13
+ value: float
14
+ timestamp: float
15
+
16
+
17
+ def extrapolate_omega(
18
+ latest_omega: OmegaReading, previous_omega: OmegaReading, image_timestamp: float
19
+ ) -> float:
20
+ """Extrapolate an image omega from previous omegas.
21
+
22
+ There are a number of assumptions in this calculation:
23
+ * The speed of the smargon is fixed
24
+ * The timestamps from the two different devices are synchronised and match the data
25
+ exactly
26
+
27
+ These are accepted to be reasonable based on larger errors likely coming from murko
28
+ itself and that the results ultimately will be averaged out.
29
+ """
30
+ omega_per_sec = (latest_omega["value"] - previous_omega["value"]) / (
31
+ latest_omega["timestamp"] - previous_omega["timestamp"]
32
+ )
33
+ time_elapsed = image_timestamp - latest_omega["timestamp"]
34
+ return latest_omega["value"] + time_elapsed * omega_per_sec
35
+
36
+
11
37
  class MurkoCallback(CallbackBase):
38
+ """A callback that triggers murko processing of images.
39
+
40
+ It combines metadata readings from e.g the goniometer rotation with the uuid's given
41
+ to us by an `OAVToRedisForwarder` (which describe the location of images in redis).
42
+ And writes these as a package to redis. A separate service then forwards this to murko.
43
+
44
+ The metadata and image data arrive independently, it is expected that the image data
45
+ is arriving at a faster rate than gonio metadata and so the value of omega for when
46
+ the image arrives is extrapolated based on previous omega readings.
47
+ """
48
+
12
49
  DATA_EXPIRY_DAYS = 7
13
50
 
14
51
  def __init__(self, redis_host: str, redis_password: str, redis_db: int = 0):
@@ -16,6 +53,7 @@ class MurkoCallback(CallbackBase):
16
53
  host=redis_host, password=redis_password, db=redis_db
17
54
  )
18
55
  self.last_uuid = None
56
+ self.previous_omegas: list[OmegaReading] = []
19
57
 
20
58
  def start(self, doc: RunStart) -> RunStart | None:
21
59
  self.sample_id = doc.get("sample_id")
@@ -28,14 +66,31 @@ class MurkoCallback(CallbackBase):
28
66
  "sample_id": self.sample_id,
29
67
  }
30
68
  self.last_uuid = None
69
+ self.previous_omegas = []
31
70
  LOGGER.info(f"Starting to stream metadata to murko under {self.sample_id}")
32
71
  return doc
33
72
 
34
73
  def event(self, doc: Event) -> Event:
35
74
  if latest_omega := doc["data"].get("smargon-omega"):
36
- if self.last_uuid is not None:
75
+ if len(self.previous_omegas) <= 2 and self.last_uuid:
76
+ # For the first few images there's not enough data to extrapolate so we
77
+ # match them one to one
37
78
  self.call_murko(self.last_uuid, latest_omega)
79
+ self.previous_omegas.append(
80
+ OmegaReading(
81
+ value=latest_omega,
82
+ timestamp=doc["timestamps"]["smargon-omega"],
83
+ )
84
+ )
38
85
  elif (uuid := doc["data"].get("oav_to_redis_forwarder-uuid")) is not None:
86
+ if len(self.previous_omegas) >= 2:
87
+ omega = extrapolate_omega(
88
+ self.previous_omegas[-1],
89
+ self.previous_omegas[-2],
90
+ doc["timestamps"]["oav_to_redis_forwarder-uuid"],
91
+ )
92
+ LOGGER.info(f"Using extrapolated omega of {omega}")
93
+ self.call_murko(uuid, omega)
39
94
  self.last_uuid = uuid
40
95
  return doc
41
96
 
File without changes
@@ -0,0 +1,259 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+
5
+ import bluesky.plan_stubs as bps
6
+ import bluesky.preprocessors as bpp
7
+ from blueapi.core import BlueskyContext
8
+ from bluesky.utils import MsgGenerator
9
+ from dodal.common import inject
10
+ from dodal.devices.aperturescatterguard import ApertureScatterguard
11
+ from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
12
+ from dodal.devices.backlight import Backlight
13
+ from dodal.devices.common_dcm import BaseDCM
14
+ from dodal.devices.detector.detector_motion import DetectorMotion
15
+ from dodal.devices.eiger import EigerDetector
16
+ from dodal.devices.fast_grid_scan import (
17
+ ZebraFastGridScan,
18
+ set_fast_grid_scan_params,
19
+ )
20
+ from dodal.devices.flux import Flux
21
+ from dodal.devices.mx_phase1.beamstop import Beamstop
22
+ from dodal.devices.oav.oav_detector import OAV
23
+ from dodal.devices.oav.pin_image_recognition import PinTipDetection
24
+ from dodal.devices.robot import BartRobot
25
+ from dodal.devices.s4_slit_gaps import S4SlitGaps
26
+ from dodal.devices.smargon import Smargon
27
+ from dodal.devices.synchrotron import Synchrotron
28
+ from dodal.devices.undulator import Undulator
29
+ from dodal.devices.xbpm_feedback import XBPMFeedback
30
+ from dodal.devices.zebra.zebra import Zebra
31
+ from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
32
+ from dodal.devices.zocalo import ZocaloResults
33
+ from dodal.plans.preprocessors.verify_undulator_gap import (
34
+ verify_undulator_gap_before_run_decorator,
35
+ )
36
+
37
+ from mx_bluesky.common.experiment_plans.common_flyscan_xray_centre_plan import (
38
+ BeamlineSpecificFGSFeatures,
39
+ construct_beamline_specific_FGS_features,
40
+ )
41
+ from mx_bluesky.common.experiment_plans.common_grid_detect_then_xray_centre_plan import (
42
+ grid_detect_then_xray_centre,
43
+ )
44
+ from mx_bluesky.common.experiment_plans.oav_snapshot_plan import (
45
+ setup_beamline_for_OAV,
46
+ )
47
+ from mx_bluesky.common.external_interaction.callbacks.common.zocalo_callback import (
48
+ ZocaloCallback,
49
+ )
50
+ from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import (
51
+ GridscanISPyBCallback,
52
+ )
53
+ from mx_bluesky.common.external_interaction.callbacks.xray_centre.nexus_callback import (
54
+ GridscanNexusFileCallback,
55
+ )
56
+ from mx_bluesky.common.parameters.constants import (
57
+ EnvironmentConstants,
58
+ OavConstants,
59
+ PlanGroupCheckpointConstants,
60
+ PlanNameConstants,
61
+ )
62
+ from mx_bluesky.common.parameters.device_composites import (
63
+ GridDetectThenXRayCentreComposite,
64
+ )
65
+ from mx_bluesky.common.parameters.gridscan import GridCommon, SpecifiedThreeDGridScan
66
+ from mx_bluesky.common.preprocessors.preprocessors import (
67
+ transmission_and_xbpm_feedback_for_collection_decorator,
68
+ )
69
+ from mx_bluesky.common.utils.context import device_composite_from_context
70
+ from mx_bluesky.phase1_zebra.device_setup_plans.setup_zebra import (
71
+ setup_zebra_for_gridscan,
72
+ tidy_up_zebra_after_gridscan,
73
+ )
74
+
75
+
76
+ def create_devices(
77
+ context: BlueskyContext,
78
+ ) -> GridDetectThenXRayCentreComposite:
79
+ return device_composite_from_context(context, GridDetectThenXRayCentreComposite)
80
+
81
+
82
+ # See https://github.com/DiamondLightSource/blueapi/issues/506 for using device composites
83
+ def i04_grid_detect_then_xray_centre(
84
+ parameters: GridCommon,
85
+ aperture_scatterguard: ApertureScatterguard = inject("aperture_scatterguard"),
86
+ attenuator: BinaryFilterAttenuator = inject("attenuator"),
87
+ backlight: Backlight = inject("backlight"),
88
+ beamstop: Beamstop = inject("beamstop"),
89
+ dcm: BaseDCM = inject("dcm"),
90
+ zebra_fast_grid_scan: ZebraFastGridScan = inject("zebra_fast_grid_scan"),
91
+ flux: Flux = inject("flux"),
92
+ oav: OAV = inject("oav"),
93
+ pin_tip_detection: PinTipDetection = inject("pin_tip_detection"),
94
+ s4_slit_gaps: S4SlitGaps = inject("s4_slit_gaps"),
95
+ undulator: Undulator = inject("undulator"),
96
+ xbpm_feedback: XBPMFeedback = inject("xbpm_feedback"),
97
+ zebra: Zebra = inject("zebra"),
98
+ robot: BartRobot = inject("robot"),
99
+ sample_shutter: ZebraShutter = inject("sample_shutter"),
100
+ eiger: EigerDetector = inject("eiger"),
101
+ synchrotron: Synchrotron = inject("synchrotron"),
102
+ zocalo: ZocaloResults = inject("zocalo"),
103
+ smargon: Smargon = inject("smargon"),
104
+ detector_motion: DetectorMotion = inject("detector_motion"),
105
+ oav_config: str = OavConstants.OAV_CONFIG_JSON,
106
+ udc: bool = False,
107
+ ) -> MsgGenerator:
108
+ """
109
+ A composite plan which:
110
+ - Uses the OAV to draw a virtual grid over the sample and to take snapshots of the sample
111
+ - Scans through the grid to identify the crystal centre
112
+ - Changes the aperture to match the beam size to the crystal size
113
+ - Moves the sample to the crystal centre of mass
114
+
115
+
116
+ i04's implementation of this plan is very similar to Hyperion. However, since i04
117
+ isn't running in a continious Bluesky UDC loop, we take additional steps in beamline
118
+ tidy-up.
119
+ """
120
+
121
+ composite = GridDetectThenXRayCentreComposite(
122
+ eiger,
123
+ synchrotron,
124
+ zocalo,
125
+ smargon,
126
+ aperture_scatterguard,
127
+ attenuator,
128
+ backlight,
129
+ beamstop,
130
+ dcm,
131
+ detector_motion,
132
+ zebra_fast_grid_scan,
133
+ flux,
134
+ oav,
135
+ pin_tip_detection,
136
+ s4_slit_gaps,
137
+ undulator,
138
+ xbpm_feedback,
139
+ zebra,
140
+ robot,
141
+ sample_shutter,
142
+ )
143
+
144
+ def tidy_beamline_if_not_udc():
145
+ if not udc:
146
+ yield from get_ready_for_oav_and_close_shutter(
147
+ composite.smargon,
148
+ composite.backlight,
149
+ composite.aperture_scatterguard,
150
+ composite.detector_motion,
151
+ )
152
+
153
+ @bpp.finalize_decorator(tidy_beamline_if_not_udc)
154
+ def _inner_grid_detect_then_xrc():
155
+ # These callbacks let us talk to ISPyB and Nexgen. They aren't included in the common plan because
156
+ # Hyperion handles its callbacks differently to BlueAPI-managed plans, see
157
+ # https://github.com/DiamondLightSource/mx-bluesky/issues/1117
158
+ callbacks = create_gridscan_callbacks()
159
+
160
+ @bpp.subs_decorator(callbacks)
161
+ @verify_undulator_gap_before_run_decorator(composite)
162
+ @transmission_and_xbpm_feedback_for_collection_decorator(
163
+ composite, parameters.transmission_frac, PlanNameConstants.GRIDSCAN_OUTER
164
+ )
165
+ def grid_detect_then_xray_centre_with_callbacks():
166
+ yield from grid_detect_then_xray_centre(
167
+ composite=composite,
168
+ parameters=parameters,
169
+ xrc_params_type=SpecifiedThreeDGridScan,
170
+ construct_beamline_specific=construct_i04_specific_features,
171
+ oav_config=oav_config,
172
+ )
173
+
174
+ yield from grid_detect_then_xray_centre_with_callbacks()
175
+
176
+ yield from _inner_grid_detect_then_xrc()
177
+
178
+
179
+ def get_ready_for_oav_and_close_shutter(
180
+ smargon: Smargon,
181
+ backlight: Backlight,
182
+ aperture_scatterguard: ApertureScatterguard,
183
+ detector_motion: DetectorMotion,
184
+ ):
185
+ yield from bps.wait(PlanGroupCheckpointConstants.GRID_READY_FOR_DC)
186
+ group = "get_ready_for_oav_and_close_shutter"
187
+ yield from setup_beamline_for_OAV(
188
+ smargon, backlight, aperture_scatterguard, group=group
189
+ )
190
+ yield from bps.abs_set(
191
+ detector_motion.shutter,
192
+ 0,
193
+ group=group,
194
+ )
195
+ yield from bps.wait(group)
196
+
197
+
198
+ def create_gridscan_callbacks() -> tuple[
199
+ GridscanNexusFileCallback, GridscanISPyBCallback
200
+ ]:
201
+ return (
202
+ GridscanNexusFileCallback(param_type=SpecifiedThreeDGridScan),
203
+ GridscanISPyBCallback(
204
+ param_type=GridCommon,
205
+ emit=ZocaloCallback(
206
+ PlanNameConstants.DO_FGS, EnvironmentConstants.ZOCALO_ENV
207
+ ),
208
+ ),
209
+ )
210
+
211
+
212
+ def construct_i04_specific_features(
213
+ xrc_composite: GridDetectThenXRayCentreComposite,
214
+ xrc_parameters: SpecifiedThreeDGridScan,
215
+ ) -> BeamlineSpecificFGSFeatures:
216
+ """
217
+ Get all the information needed to do the i04 XRC flyscan.
218
+ """
219
+ signals_to_read_pre_flyscan = [
220
+ xrc_composite.undulator.current_gap,
221
+ xrc_composite.synchrotron.synchrotron_mode,
222
+ xrc_composite.s4_slit_gaps.xgap,
223
+ xrc_composite.s4_slit_gaps.ygap,
224
+ xrc_composite.smargon.x,
225
+ xrc_composite.smargon.y,
226
+ xrc_composite.smargon.z,
227
+ xrc_composite.dcm.energy_in_kev,
228
+ ]
229
+
230
+ signals_to_read_during_collection = [
231
+ xrc_composite.aperture_scatterguard,
232
+ xrc_composite.attenuator.actual_transmission,
233
+ xrc_composite.flux.flux_reading,
234
+ xrc_composite.dcm.energy_in_kev,
235
+ xrc_composite.eiger.bit_depth,
236
+ ]
237
+
238
+ tidy_plan = partial(
239
+ tidy_up_zebra_after_gridscan,
240
+ xrc_composite.zebra,
241
+ xrc_composite.sample_shutter,
242
+ group="flyscan_zebra_tidy",
243
+ wait=True,
244
+ )
245
+ set_flyscan_params_plan = partial(
246
+ set_fast_grid_scan_params,
247
+ xrc_composite.zebra_fast_grid_scan,
248
+ xrc_parameters.FGS_params,
249
+ )
250
+ fgs_motors = xrc_composite.zebra_fast_grid_scan
251
+ return construct_beamline_specific_FGS_features(
252
+ setup_zebra_for_gridscan,
253
+ tidy_plan,
254
+ set_flyscan_params_plan,
255
+ fgs_motors,
256
+ signals_to_read_pre_flyscan,
257
+ signals_to_read_during_collection,
258
+ get_xrc_results_from_zocalo=True,
259
+ )
@@ -23,8 +23,8 @@ from dodal.devices.i24.beamstop import Beamstop
23
23
  from dodal.devices.i24.dcm import DCM
24
24
  from dodal.devices.i24.dual_backlight import DualBacklight
25
25
  from dodal.devices.i24.focus_mirrors import FocusMirrorsMode
26
- from dodal.devices.i24.i24_detector_motion import DetectorMotion
27
26
  from dodal.devices.i24.pilatus_metadata import PilatusMetadata
27
+ from dodal.devices.motors import YZStage
28
28
  from dodal.devices.zebra.zebra import Zebra
29
29
 
30
30
  from mx_bluesky.beamlines.i24.serial.dcid import (
@@ -70,7 +70,7 @@ def flush_print(text):
70
70
 
71
71
  @log_on_entry
72
72
  def initialise_extruder(
73
- detector_stage: DetectorMotion = inject("detector_motion"),
73
+ detector_stage: YZStage = inject("detector_motion"),
74
74
  ) -> MsgGenerator:
75
75
  SSX_LOGGER.info("Initialise Parameters for extruder data collection on I24.")
76
76
 
@@ -98,7 +98,7 @@ def initialise_extruder(
98
98
  def laser_check(
99
99
  mode: str,
100
100
  zebra: Zebra = inject("zebra"),
101
- detector_stage: DetectorMotion = inject("detector_motion"),
101
+ detector_stage: YZStage = inject("detector_motion"),
102
102
  ) -> MsgGenerator:
103
103
  """Plan to open the shutter and check the laser beam from the viewer by pressing \
104
104
  'Laser On' and 'Laser Off' buttons on the edm.
@@ -138,7 +138,7 @@ def laser_check(
138
138
 
139
139
  @log_on_entry
140
140
  def enter_hutch(
141
- detector_stage: DetectorMotion = inject("detector_motion"),
141
+ detector_stage: YZStage = inject("detector_motion"),
142
142
  ) -> MsgGenerator:
143
143
  """Move the detector stage before entering hutch."""
144
144
  yield from bps.mv(detector_stage.z, SAFE_DET_Z)
@@ -146,12 +146,12 @@ def enter_hutch(
146
146
 
147
147
 
148
148
  @log_on_entry
149
- def read_parameters(detector_stage: DetectorMotion, attenuator: ReadOnlyAttenuator):
149
+ def read_parameters(detector_stage: YZStage, attenuator: ReadOnlyAttenuator):
150
150
  """ Read the parameters from user input and create the parameter model for an \
151
151
  extruder collection.
152
152
 
153
153
  Args:
154
- detector_stage (DetectorMotion): The detector stage device.
154
+ detector_stage (YZStage): The detector stage device.
155
155
  attenuator (ReadOnlyAttenuator): A read-only attenuator device to get the \
156
156
  transmission value.
157
157
 
@@ -208,7 +208,7 @@ def main_extruder_plan(
208
208
  aperture: Aperture,
209
209
  backlight: DualBacklight,
210
210
  beamstop: Beamstop,
211
- detector_stage: DetectorMotion,
211
+ detector_stage: YZStage,
212
212
  shutter: HutchShutter,
213
213
  dcm: DCM,
214
214
  mirrors: FocusMirrorsMode,
@@ -500,7 +500,7 @@ def run_extruder_plan(
500
500
  aperture: Aperture = inject("aperture"),
501
501
  backlight: DualBacklight = inject("backlight"),
502
502
  beamstop: Beamstop = inject("beamstop"),
503
- detector_stage: DetectorMotion = inject("detector_motion"),
503
+ detector_stage: YZStage = inject("detector_motion"),
504
504
  shutter: HutchShutter = inject("shutter"),
505
505
  dcm: DCM = inject("dcm"),
506
506
  mirrors: FocusMirrorsMode = inject("focus_mirrors"),
@@ -18,9 +18,9 @@ from dodal.devices.i24.beamstop import Beamstop
18
18
  from dodal.devices.i24.dcm import DCM
19
19
  from dodal.devices.i24.dual_backlight import DualBacklight
20
20
  from dodal.devices.i24.focus_mirrors import FocusMirrorsMode
21
- from dodal.devices.i24.i24_detector_motion import DetectorMotion
22
21
  from dodal.devices.i24.pilatus_metadata import PilatusMetadata
23
22
  from dodal.devices.i24.pmac import PMAC
23
+ from dodal.devices.motors import YZStage
24
24
  from dodal.devices.zebra.zebra import Zebra
25
25
 
26
26
  from mx_bluesky.beamlines.i24.serial.dcid import (
@@ -269,7 +269,7 @@ def start_i24(
269
269
  aperture: Aperture,
270
270
  backlight: DualBacklight,
271
271
  beamstop: Beamstop,
272
- detector_stage: DetectorMotion,
272
+ detector_stage: YZStage,
273
273
  shutter: HutchShutter,
274
274
  parameters: FixedTargetParameters,
275
275
  dcm: DCM,
@@ -490,7 +490,9 @@ def run_aborted_plan(pmac: PMAC, dcid: DCID, exception: Exception):
490
490
  either by pressing the Abort button or because of a timeout, and to reset the \
491
491
  P variable.
492
492
  """
493
- SSX_LOGGER.warning(f"Data Collection Aborted: {format_exception(exception)}")
493
+ SSX_LOGGER.warning(
494
+ f"Data Collection Aborted: {''.join(format_exception(exception))}"
495
+ )
494
496
  yield from bps.trigger(pmac.abort_program, wait=True)
495
497
 
496
498
  end_time = datetime.now()
@@ -504,7 +506,7 @@ def main_fixed_target_plan(
504
506
  aperture: Aperture,
505
507
  backlight: DualBacklight,
506
508
  beamstop: Beamstop,
507
- detector_stage: DetectorMotion,
509
+ detector_stage: YZStage,
508
510
  shutter: HutchShutter,
509
511
  dcm: DCM,
510
512
  mirrors: FocusMirrorsMode,
@@ -655,7 +657,7 @@ def run_fixed_target_plan(
655
657
  aperture: Aperture = inject("aperture"),
656
658
  backlight: DualBacklight = inject("backlight"),
657
659
  beamstop: Beamstop = inject("beamstop"),
658
- detector_stage: DetectorMotion = inject("detector_motion"),
660
+ detector_stage: YZStage = inject("detector_motion"),
659
661
  shutter: HutchShutter = inject("shutter"),
660
662
  dcm: DCM = inject("dcm"),
661
663
  mirrors: FocusMirrorsMode = inject("focus_mirrors"),
@@ -707,7 +709,7 @@ def run_plan_in_wrapper(
707
709
  aperture: Aperture,
708
710
  backlight: DualBacklight,
709
711
  beamstop: Beamstop,
710
- detector_stage: DetectorMotion,
712
+ detector_stage: YZStage,
711
713
  shutter: HutchShutter,
712
714
  dcm: DCM,
713
715
  mirrors: FocusMirrorsMode,
@@ -16,8 +16,8 @@ from dodal.common import inject
16
16
  from dodal.devices.attenuator.attenuator import ReadOnlyAttenuator
17
17
  from dodal.devices.i24.beamstop import Beamstop, BeamstopPositions
18
18
  from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
19
- from dodal.devices.i24.i24_detector_motion import DetectorMotion
20
19
  from dodal.devices.i24.pmac import PMAC, EncReset, LaserSettings
20
+ from dodal.devices.motors import YZStage
21
21
 
22
22
  from mx_bluesky.beamlines.i24.serial.fixed_target.ft_utils import (
23
23
  ChipType,
@@ -121,14 +121,14 @@ def _is_checker_pattern() -> bool:
121
121
 
122
122
  @log_on_entry
123
123
  def read_parameters(
124
- detector_stage: DetectorMotion,
124
+ detector_stage: YZStage,
125
125
  attenuator: ReadOnlyAttenuator,
126
126
  ) -> MsgGenerator:
127
127
  """ Read the parameters from user input and create the parameter model for a fixed \
128
128
  target collection.
129
129
 
130
130
  Args:
131
- detector_stage (DetectorMotion): The detector stage device.
131
+ detector_stage (YZStage): The detector stage device.
132
132
  attenuator (ReadOnlyAttenuator): A read-only attenuator device to get the \
133
133
  transmission value.
134
134
 
@@ -566,7 +566,7 @@ def moveto_preset(
566
566
  pmac: PMAC = inject("pmac"),
567
567
  beamstop: Beamstop = inject("beamstop"),
568
568
  backlight: DualBacklight = inject("backlight"),
569
- det_stage: DetectorMotion = inject("detector_motion"),
569
+ det_stage: YZStage = inject("detector_motion"),
570
570
  ) -> MsgGenerator:
571
571
  # Non Chip Specific Move
572
572
  if place == "zero":
@@ -7,7 +7,7 @@ from dodal.devices.i24.beam_center import DetectorBeamCenter
7
7
  from dodal.devices.i24.beamstop import Beamstop, BeamstopPositions
8
8
  from dodal.devices.i24.dcm import DCM
9
9
  from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
10
- from dodal.devices.i24.i24_detector_motion import DetectorMotion
10
+ from dodal.devices.motors import YZStage
11
11
  from dodal.devices.util.lookup_tables import (
12
12
  linear_interpolation_lut,
13
13
  parse_lookup_table,
@@ -69,7 +69,7 @@ def setup_beamline_for_collection_plan(
69
69
 
70
70
 
71
71
  def move_detector_stage_to_position_plan(
72
- detector_stage: DetectorMotion,
72
+ detector_stage: YZStage,
73
73
  detector_distance: float,
74
74
  ):
75
75
  SSX_LOGGER.debug("Setup beamline: moving detector stage.")
@@ -8,7 +8,7 @@ from enum import IntEnum
8
8
  import bluesky.plan_stubs as bps
9
9
  from bluesky.utils import Msg, MsgGenerator
10
10
  from dodal.common import inject
11
- from dodal.devices.i24.i24_detector_motion import DetectorMotion
11
+ from dodal.devices.motors import YZStage
12
12
 
13
13
  from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER
14
14
  from mx_bluesky.beamlines.i24.serial.parameters import SSXType
@@ -38,9 +38,9 @@ class UnknownDetectorType(Exception):
38
38
  pass
39
39
 
40
40
 
41
- def get_detector_type(detector_stage: DetectorMotion) -> Generator[Msg, None, Detector]:
41
+ def get_detector_type(detector_stage: YZStage) -> Generator[Msg, None, Detector]:
42
42
  det_y = yield from bps.rd(detector_stage.y)
43
- # DetectorMotion should also be used for this.
43
+ # YZStage should also be used for this.
44
44
  # This should be part of https://github.com/DiamondLightSource/mx_bluesky/issues/51
45
45
  if float(det_y) < Eiger.det_y_threshold:
46
46
  SSX_LOGGER.info("Eiger detector in use.")
@@ -53,7 +53,7 @@ def get_detector_type(detector_stage: DetectorMotion) -> Generator[Msg, None, De
53
53
  raise UnknownDetectorType("Detector not found.")
54
54
 
55
55
 
56
- def _move_detector_stage(detector_stage: DetectorMotion, target: float) -> MsgGenerator:
56
+ def _move_detector_stage(detector_stage: YZStage, target: float) -> MsgGenerator:
57
57
  SSX_LOGGER.info(f"Moving detector stage to target position: {target}.")
58
58
  yield from bps.mv(detector_stage.y, target)
59
59
 
@@ -82,7 +82,7 @@ def _get_requested_detector(det_type_pv: str) -> str:
82
82
 
83
83
 
84
84
  def setup_detector_stage(
85
- expt_type: SSXType, detector_stage: DetectorMotion = inject("detector_motion")
85
+ expt_type: SSXType, detector_stage: YZStage = inject("detector_motion")
86
86
  ) -> MsgGenerator:
87
87
  # Grab the correct PV depending on experiment
88
88
  # Its value is set with MUX on edm screen
@@ -13,9 +13,9 @@ from dodal.devices.i24.beamstop import Beamstop
13
13
  from dodal.devices.i24.dcm import DCM
14
14
  from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
15
15
  from dodal.devices.i24.focus_mirrors import FocusMirrorsMode
16
- from dodal.devices.i24.i24_detector_motion import DetectorMotion
17
16
  from dodal.devices.i24.pilatus_metadata import PilatusMetadata
18
17
  from dodal.devices.i24.pmac import PMAC
18
+ from dodal.devices.motors import YZStage
19
19
  from dodal.devices.oav.oav_detector import OAVBeamCentreFile
20
20
  from dodal.devices.zebra.zebra import Zebra
21
21
 
@@ -104,7 +104,7 @@ def gui_sleep(sec: int) -> MsgGenerator:
104
104
  @bpp.run_decorator()
105
105
  def gui_move_detector(
106
106
  det: Literal["eiger", "pilatus"],
107
- detector_stage: DetectorMotion = inject("detector_motion"),
107
+ detector_stage: YZStage = inject("detector_motion"),
108
108
  ) -> MsgGenerator:
109
109
  det_y_target = Eiger.det_y_target if det == "eiger" else Pilatus.det_y_target
110
110
  yield from _move_detector_stage(detector_stage, det_y_target)
@@ -134,7 +134,7 @@ def gui_run_chip_collection(
134
134
  aperture: Aperture = inject("aperture"),
135
135
  backlight: DualBacklight = inject("backlight"),
136
136
  beamstop: Beamstop = inject("beamstop"),
137
- detector_stage: DetectorMotion = inject("detector_motion"),
137
+ detector_stage: YZStage = inject("detector_motion"),
138
138
  shutter: HutchShutter = inject("shutter"),
139
139
  dcm: DCM = inject("dcm"),
140
140
  mirrors: FocusMirrorsMode = inject("focus_mirrors"),