mx-bluesky 1.4.8__py3-none-any.whl → 1.4.9__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 (49) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/aithre_lasershaping/__init__.py +8 -0
  3. mx_bluesky/beamlines/aithre_lasershaping/beamline_safe.py +36 -0
  4. mx_bluesky/beamlines/aithre_lasershaping/goniometer_controls.py +43 -0
  5. mx_bluesky/beamlines/i24/serial/blueapi_config.yaml +2 -1
  6. mx_bluesky/beamlines/i24/serial/dcid.py +5 -5
  7. mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DetStage.edl +2 -2
  8. mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +9 -9
  9. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +18 -3
  10. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DetStage.edl +2 -2
  11. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +14 -14
  12. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +2 -2
  13. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +23 -4
  14. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +7 -1
  15. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +0 -8
  16. mx_bluesky/common/device_setup_plans/manipulate_sample.py +5 -13
  17. mx_bluesky/common/external_interaction/nexus/nexus_utils.py +2 -2
  18. mx_bluesky/common/utils/log.py +12 -11
  19. mx_bluesky/hyperion/__main__.py +6 -11
  20. mx_bluesky/hyperion/baton_handler.py +8 -3
  21. mx_bluesky/hyperion/device_setup_plans/smargon.py +2 -7
  22. mx_bluesky/hyperion/device_setup_plans/utils.py +4 -3
  23. mx_bluesky/hyperion/experiment_plans/__init__.py +2 -2
  24. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +3 -4
  25. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +10 -0
  26. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +40 -10
  27. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +3 -0
  28. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +2 -11
  29. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +22 -25
  30. mx_bluesky/hyperion/external_interaction/agamemnon.py +68 -62
  31. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -1
  32. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -3
  33. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +6 -3
  34. mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +2 -2
  35. mx_bluesky/hyperion/external_interaction/config_server.py +4 -1
  36. mx_bluesky/hyperion/parameters/cli.py +3 -10
  37. mx_bluesky/hyperion/parameters/constants.py +1 -0
  38. mx_bluesky/hyperion/parameters/load_centre_collect.py +4 -4
  39. mx_bluesky/hyperion/parameters/rotation.py +9 -8
  40. mx_bluesky/hyperion/utils/context.py +5 -2
  41. mx_bluesky/hyperion/utils/validation.py +10 -17
  42. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/METADATA +4 -4
  43. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/RECORD +47 -48
  44. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/WHEEL +1 -1
  45. mx_bluesky/common/device_setup_plans/check_beamstop.py +0 -27
  46. mx_bluesky/common/external_interaction/test_config_server.py +0 -38
  47. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/entry_points.txt +0 -0
  48. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/licenses/LICENSE +0 -0
  49. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/top_level.txt +0 -0
@@ -158,6 +158,6 @@ def create_beam_and_attenuator_parameters(
158
158
  tuple[Beam, Attenuator]: Descriptions of the beam and attenuator for nexgen.
159
159
  """
160
160
  return (
161
- Beam(convert_eV_to_angstrom(energy_kev * 1000), flux), # pyright: ignore
162
- Attenuator(transmission_fraction), # pyright: ignore
161
+ Beam(wavelength=convert_eV_to_angstrom(energy_kev * 1000), flux=flux),
162
+ Attenuator(transmission=transmission_fraction),
163
163
  )
@@ -66,7 +66,7 @@ def do_default_logging_setup(
66
66
  """Configures dodal logger so that separate debug and info log files are created,
67
67
  info logs are sent to Graylog, info logs are streamed to sys.sterr, and logs from ophyd
68
68
  and bluesky and ophyd-async are optionally included."""
69
- logging_path, debug_logging_path = _get_logging_dirs()
69
+ logging_path, debug_logging_path = _get_logging_dirs(dev_mode)
70
70
  handlers = set_up_all_logging_handlers(
71
71
  dodal_logger,
72
72
  logging_path,
@@ -103,7 +103,7 @@ def flush_debug_handler() -> str:
103
103
  return handler.target.baseFilename
104
104
 
105
105
 
106
- def _get_logging_dirs() -> tuple[Path, Path]:
106
+ def _get_logging_dirs(dev_mode: bool) -> tuple[Path, Path]:
107
107
  """Get the paths to write the mx_bluesky log files to.
108
108
 
109
109
  Log location can be specified in the LOG_DIR environment variable, otherwise MX bluesky logs are written to 'dls_sw/ixx/logs/bluesky'.
@@ -115,17 +115,18 @@ def _get_logging_dirs() -> tuple[Path, Path]:
115
115
  tuple[Path, Path]: Paths to the standard log file and to the debug log file, for the file handlers to write to
116
116
  """
117
117
 
118
- logging_str = environ.get("LOG_DIR")
119
118
  beamline = environ.get("BEAMLINE")
120
- if logging_str:
121
- logging_path = Path(logging_str)
122
- debug_logging_path = logging_path
123
- elif beamline:
124
- logging_path = Path(f"/dls_sw/{beamline}/logs/bluesky/")
125
- debug_logging_path = Path(f"/dls/tmp/{beamline}/logs/bluesky/")
119
+
120
+ if beamline and not dev_mode:
121
+ default_logging_str = f"/dls_sw/{beamline}/logs/bluesky/"
122
+ default_debug_logging_str = f"/dls/tmp/{beamline}/logs/bluesky/"
126
123
  else:
127
- logging_path = Path("/tmp/logs/bluesky")
128
- debug_logging_path = logging_path
124
+ default_logging_str = "/tmp/logs/bluesky"
125
+ default_debug_logging_str = default_logging_str
126
+
127
+ logging_path = Path(environ.get("LOG_DIR", default_logging_str))
128
+ debug_logging_path = Path(environ.get("DEBUG_LOG_DIR", default_debug_logging_str))
129
+
129
130
  Path.mkdir(logging_path, exist_ok=True, parents=True)
130
131
  Path.mkdir(debug_logging_path, exist_ok=True, parents=True)
131
132
  return logging_path, debug_logging_path
@@ -19,9 +19,6 @@ from pydantic.dataclasses import dataclass
19
19
  from mx_bluesky.common.external_interaction.callbacks.common.log_uid_tag_callback import (
20
20
  LogUidTaggingCallback,
21
21
  )
22
- from mx_bluesky.common.external_interaction.callbacks.common.logging_callback import (
23
- VerbosePlanExecutionLoggingCallback,
24
- )
25
22
  from mx_bluesky.common.parameters.components import MxBlueskyParameters
26
23
  from mx_bluesky.common.parameters.constants import Actions, Status
27
24
  from mx_bluesky.common.utils.exceptions import WarningException
@@ -41,10 +38,9 @@ from mx_bluesky.hyperion.external_interaction.agamemnon import (
41
38
  )
42
39
  from mx_bluesky.hyperion.parameters.cli import parse_cli_args
43
40
  from mx_bluesky.hyperion.parameters.constants import CONST
41
+ from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
44
42
  from mx_bluesky.hyperion.utils.context import setup_context
45
43
 
46
- VERBOSE_EVENT_LOGGING: bool | None = None
47
-
48
44
 
49
45
  @dataclass
50
46
  class Command:
@@ -97,9 +93,6 @@ class BlueskyRunner:
97
93
  self.publisher = Publisher(f"localhost:{CONST.CALLBACK_0MQ_PROXY_PORTS[0]}")
98
94
  RE.subscribe(self.publisher)
99
95
 
100
- if VERBOSE_EVENT_LOGGING:
101
- RE.subscribe(VerbosePlanExecutionLoggingCallback())
102
-
103
96
  def start(
104
97
  self,
105
98
  experiment: Callable,
@@ -198,7 +191,8 @@ def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions)
198
191
  try:
199
192
  parameters = experiment_internal_param_type(**json.loads(request.data))
200
193
  parameters = update_params_from_agamemnon(parameters)
201
- compare_params(parameters)
194
+ if isinstance(parameters, LoadCentreCollect):
195
+ compare_params(parameters)
202
196
  if parameters.model_extra:
203
197
  raise ValueError(f"Extra fields not allowed {parameters.model_extra}")
204
198
  except Exception as e:
@@ -271,8 +265,9 @@ class FlushLogs(Resource):
271
265
  def create_app(
272
266
  test_config=None,
273
267
  RE: RunEngine = RunEngine({}),
268
+ dev_mode: bool = False,
274
269
  ) -> tuple[Flask, BlueskyRunner]:
275
- context = setup_context()
270
+ context = setup_context(dev_mode=dev_mode)
276
271
  runner = BlueskyRunner(
277
272
  RE,
278
273
  context=context,
@@ -305,7 +300,7 @@ def create_targets():
305
300
  CONST.LOG_FILE_NAME, CONST.GRAYLOG_PORT, dev_mode=args.dev_mode
306
301
  )
307
302
  LOGGER.info(f"Hyperion launched with args:{argv}")
308
- app, runner = create_app()
303
+ app, runner = create_app(dev_mode=args.dev_mode)
309
304
  return app, runner, hyperion_port, args.dev_mode
310
305
 
311
306
 
@@ -1,3 +1,5 @@
1
+ from collections.abc import Sequence
2
+
1
3
  from bluesky import plan_stubs as bps
2
4
  from bluesky import preprocessors as bpp
3
5
  from dodal.devices.baton import Baton
@@ -37,9 +39,12 @@ def main_hyperion_loop(baton: Baton, composite: LoadCentreCollectComposite):
37
39
  while requested_user == HYPERION_USER:
38
40
 
39
41
  def inner_loop():
40
- parameters: LoadCentreCollect | None = create_parameters_from_agamemnon() # type: ignore # not complete until https://github.com/DiamondLightSource/mx-bluesky/issues/773
41
- if parameters:
42
- yield from load_centre_collect_full(composite, parameters)
42
+ parameter_list: Sequence[LoadCentreCollect] = (
43
+ create_parameters_from_agamemnon()
44
+ )
45
+ if parameter_list:
46
+ for parameters in parameter_list:
47
+ yield from load_centre_collect_full(composite, parameters)
43
48
  else:
44
49
  yield from bps.mv(baton.requested_user, NO_USER)
45
50
 
@@ -1,6 +1,6 @@
1
1
  import numpy as np
2
2
  from bluesky import plan_stubs as bps
3
- from dodal.devices.smargon import Smargon
3
+ from dodal.devices.smargon import CombinedMove, Smargon
4
4
 
5
5
  from mx_bluesky.common.utils.exceptions import SampleException
6
6
 
@@ -16,10 +16,5 @@ def move_smargon_warn_on_out_of_range(
16
16
  "Pin tip centring failed - pin too long/short/bent and out of range"
17
17
  )
18
18
  yield from bps.mv(
19
- smargon.x,
20
- position[0],
21
- smargon.y,
22
- position[1],
23
- smargon.z,
24
- position[2],
19
+ smargon, CombinedMove(x=position[0], y=position[1], z=position[2])
25
20
  )
@@ -8,10 +8,9 @@ from dodal.devices.detector import (
8
8
  )
9
9
  from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
10
10
  from dodal.devices.eiger import EigerDetector
11
- from dodal.devices.i03 import Beamstop
12
11
  from dodal.devices.i03.dcm import DCM
12
+ from dodal.devices.mx_phase1.beamstop import Beamstop, BeamstopPositions
13
13
 
14
- from mx_bluesky.common.device_setup_plans.check_beamstop import check_beamstop
15
14
  from mx_bluesky.common.device_setup_plans.position_detector import (
16
15
  set_detector_z_position,
17
16
  set_shutter,
@@ -45,6 +44,9 @@ def start_preparing_data_collection_then_do_plan(
45
44
 
46
45
  def wrapped_plan():
47
46
  yield from bps.abs_set(eiger.do_arm, 1, group=group) # type: ignore # Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
47
+ yield from bps.abs_set(
48
+ beamstop.selected_pos, BeamstopPositions.DATA_COLLECTION, group=group
49
+ )
48
50
  if detector_distance_mm:
49
51
  yield from set_detector_z_position(
50
52
  detector_motion, detector_distance_mm, group
@@ -52,7 +54,6 @@ def start_preparing_data_collection_then_do_plan(
52
54
  yield from set_shutter(detector_motion, ShutterState.OPEN, group)
53
55
  yield from plan_to_run
54
56
 
55
- yield from check_beamstop(beamstop)
56
57
  yield from bpp.contingency_wrapper(
57
58
  wrapped_plan(),
58
59
  except_plan=lambda e: (yield from bps.stop(eiger)), # type: ignore # Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
@@ -13,12 +13,12 @@ from mx_bluesky.hyperion.experiment_plans.pin_centre_then_xray_centre_plan impor
13
13
  pin_tip_centre_then_xray_centre,
14
14
  )
15
15
  from mx_bluesky.hyperion.experiment_plans.rotation_scan_plan import (
16
- multi_rotation_scan,
16
+ rotation_scan,
17
17
  )
18
18
 
19
19
  __all__ = [
20
20
  "grid_detect_then_xray_centre",
21
21
  "pin_tip_centre_then_xray_centre",
22
- "multi_rotation_scan",
22
+ "rotation_scan",
23
23
  "load_centre_collect_full",
24
24
  ]
@@ -15,7 +15,7 @@ from mx_bluesky.hyperion.parameters.gridscan import (
15
15
  PinTipCentreThenXrayCentre,
16
16
  )
17
17
  from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
18
- from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan, RotationScan
18
+ from mx_bluesky.hyperion.parameters.rotation import RotationScan
19
19
 
20
20
 
21
21
  def not_implemented():
@@ -32,7 +32,6 @@ class ExperimentRegistryEntry(TypedDict):
32
32
  HyperionSpecifiedThreeDGridScan
33
33
  | GridScanWithEdgeDetect
34
34
  | RotationScan
35
- | MultiRotationScan
36
35
  | PinTipCentreThenXrayCentre
37
36
  | LoadCentreCollect
38
37
  ]
@@ -47,9 +46,9 @@ PLAN_REGISTRY: dict[str, ExperimentRegistryEntry] = {
47
46
  "setup": pin_centre_then_xray_centre_plan.create_devices,
48
47
  "param_type": PinTipCentreThenXrayCentre,
49
48
  },
50
- "multi_rotation_scan": {
49
+ "rotation_scan": {
51
50
  "setup": rotation_scan_plan.create_devices,
52
- "param_type": MultiRotationScan,
51
+ "param_type": RotationScan,
53
52
  },
54
53
  "load_centre_collect_full": {
55
54
  "setup": load_centre_collect_full_plan.create_devices,
@@ -49,6 +49,9 @@ from mx_bluesky.hyperion.device_setup_plans.utils import (
49
49
  from mx_bluesky.hyperion.experiment_plans.hyperion_flyscan_xray_centre_plan import (
50
50
  construct_hyperion_specific_features,
51
51
  )
52
+ from mx_bluesky.hyperion.experiment_plans.oav_snapshot_plan import (
53
+ setup_beamline_for_OAV,
54
+ )
52
55
  from mx_bluesky.hyperion.parameters.constants import CONST
53
56
  from mx_bluesky.hyperion.parameters.device_composites import (
54
57
  GridDetectThenXRayCentreComposite,
@@ -106,6 +109,13 @@ def detect_grid_and_do_gridscan(
106
109
  parameters.box_size_um,
107
110
  )
108
111
 
112
+ yield from setup_beamline_for_OAV(
113
+ composite.smargon,
114
+ composite.backlight,
115
+ composite.aperture_scatterguard,
116
+ wait=True,
117
+ )
118
+
109
119
  if parameters.selected_aperture:
110
120
  # Start moving the aperture/scatterguard into position without moving it in
111
121
  yield from bps.prepare(
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Generator
4
+
3
5
  import bluesky.plan_stubs as bps
4
6
  import numpy as np
5
7
  import pydantic
@@ -18,12 +20,13 @@ from mx_bluesky.hyperion.experiment_plans.robot_load_then_centre_plan import (
18
20
  robot_load_then_xray_centre,
19
21
  )
20
22
  from mx_bluesky.hyperion.experiment_plans.rotation_scan_plan import (
21
- MultiRotationScan,
23
+ RotationScan,
22
24
  RotationScanComposite,
23
- multi_rotation_scan_internal,
25
+ rotation_scan_internal,
24
26
  )
25
27
  from mx_bluesky.hyperion.parameters.constants import CONST
26
28
  from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
29
+ from mx_bluesky.hyperion.parameters.rotation import RotationScanPerSweep
27
30
 
28
31
 
29
32
  @pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
@@ -48,6 +51,8 @@ def load_centre_collect_full(
48
51
  * If X-ray centring finds a diffracting centre then move to that centre and
49
52
  * do a collection with the specified parameters.
50
53
  """
54
+ parameters.features.update_self_from_server()
55
+
51
56
  if not oav_params:
52
57
  oav_params = OAVParameters(context="xrayCentring")
53
58
  oav_config_file = oav_params.oav_config_json
@@ -99,21 +104,46 @@ def load_centre_collect_full(
99
104
 
100
105
  multi_rotation.rotation_scans.clear()
101
106
 
107
+ is_alternating = parameters.features.alternate_rotation_direction
108
+
109
+ generator = rotation_scan_generator(is_alternating)
110
+ next(generator)
102
111
  for location in locations_to_collect_um:
103
112
  for rot in rotation_template:
104
- combination = rot.model_copy()
105
- (
106
- combination.x_start_um,
107
- combination.y_start_um,
108
- combination.z_start_um,
109
- ) = location
113
+ combination = generator.send((rot, location))
110
114
  multi_rotation.rotation_scans.append(combination)
111
- multi_rotation = MultiRotationScan.model_validate(multi_rotation)
115
+ multi_rotation = RotationScan.model_validate(multi_rotation)
112
116
 
113
117
  assert (
114
118
  multi_rotation.demand_energy_ev
115
119
  == parameters.robot_load_then_centre.demand_energy_ev
116
120
  ), "Setting a different energy for gridscan and rotation is not supported"
117
- yield from multi_rotation_scan_internal(composite, multi_rotation, oav_params)
121
+ yield from rotation_scan_internal(composite, multi_rotation, oav_params)
118
122
 
119
123
  yield from plan_with_callback_subs()
124
+
125
+
126
+ def rotation_scan_generator(
127
+ is_alternating: bool,
128
+ ) -> Generator[RotationScanPerSweep, tuple[RotationScanPerSweep, np.ndarray], None]:
129
+ scan_template, location = yield # type: ignore
130
+ next_rotation_direction = scan_template.rotation_direction
131
+ while True:
132
+ scan = scan_template.model_copy()
133
+ (
134
+ scan.x_start_um,
135
+ scan.y_start_um,
136
+ scan.z_start_um,
137
+ ) = location
138
+ if is_alternating:
139
+ if next_rotation_direction != scan.rotation_direction:
140
+ # If originally specified direction of the current scan is different
141
+ # from that required, swap the start and ends.
142
+ start = scan.omega_start_deg
143
+ rotation_sign = scan.rotation_direction.multiplier
144
+ end = start + rotation_sign * scan.scan_width_deg
145
+ scan.omega_start_deg = end
146
+ scan.rotation_direction = next_rotation_direction
147
+ next_rotation_direction = next_rotation_direction.opposite
148
+
149
+ scan_template, location = yield scan
@@ -29,6 +29,7 @@ def setup_beamline_for_OAV(
29
29
  backlight: Backlight,
30
30
  aperture_scatterguard: ApertureScatterguard,
31
31
  group=CONST.WAIT.READY_FOR_OAV,
32
+ wait=False,
32
33
  ):
33
34
  max_vel = yield from bps.rd(smargon.omega.max_velocity)
34
35
  yield from bps.abs_set(smargon.omega.velocity, max_vel, group=group)
@@ -36,6 +37,8 @@ def setup_beamline_for_OAV(
36
37
  yield from bps.abs_set(
37
38
  aperture_scatterguard.selected_aperture, ApertureValue.OUT_OF_BEAM, group=group
38
39
  )
40
+ if wait:
41
+ yield from bps.wait(group)
39
42
 
40
43
 
41
44
  def oav_snapshot_plan(
@@ -19,7 +19,7 @@ from dodal.devices.i03.undulator_dcm import UndulatorDCM
19
19
  from dodal.devices.motors import XYZPositioner
20
20
  from dodal.devices.oav.oav_detector import OAV
21
21
  from dodal.devices.robot import BartRobot, SampleLocation
22
- from dodal.devices.smargon import Smargon, StubPosition
22
+ from dodal.devices.smargon import CombinedMove, Smargon, StubPosition
23
23
  from dodal.devices.thawer import Thawer
24
24
  from dodal.devices.webcam import Webcam
25
25
  from dodal.devices.xbpm_feedback import XBPMFeedback
@@ -104,16 +104,7 @@ def prepare_for_robot_load(
104
104
 
105
105
  yield from bps.mv(smargon.stub_offsets, StubPosition.RESET_TO_ROBOT_LOAD)
106
106
 
107
- # fmt: off
108
- yield from bps.mv(
109
- smargon.x, 0,
110
- smargon.y, 0,
111
- smargon.z, 0,
112
- smargon.omega, 0,
113
- smargon.chi, 0,
114
- smargon.phi, 0
115
- )
116
- # fmt: on
107
+ yield from bps.mv(smargon, CombinedMove(x=0, y=0, z=0, chi=0, phi=0, omega=0))
117
108
 
118
109
  yield from bps.wait("prepare_robot_load")
119
110
 
@@ -19,7 +19,7 @@ from dodal.devices.oav.oav_detector import OAV
19
19
  from dodal.devices.oav.oav_parameters import OAVParameters
20
20
  from dodal.devices.robot import BartRobot
21
21
  from dodal.devices.s4_slit_gaps import S4SlitGaps
22
- from dodal.devices.smargon import Smargon
22
+ from dodal.devices.smargon import CombinedMove, Smargon
23
23
  from dodal.devices.synchrotron import Synchrotron
24
24
  from dodal.devices.undulator import Undulator
25
25
  from dodal.devices.xbpm_feedback import XBPMFeedback
@@ -32,8 +32,6 @@ from dodal.plans.preprocessors.verify_undulator_gap import (
32
32
 
33
33
  from mx_bluesky.common.device_setup_plans.manipulate_sample import (
34
34
  cleanup_sample_environment,
35
- move_phi_chi_omega,
36
- move_x_y_z,
37
35
  setup_sample_environment,
38
36
  )
39
37
  from mx_bluesky.common.parameters.components import WithSnapshot
@@ -62,8 +60,8 @@ from mx_bluesky.hyperion.experiment_plans.oav_snapshot_plan import (
62
60
  )
63
61
  from mx_bluesky.hyperion.parameters.constants import CONST
64
62
  from mx_bluesky.hyperion.parameters.rotation import (
65
- MultiRotationScan,
66
63
  RotationScan,
64
+ SingleRotationScan,
67
65
  )
68
66
 
69
67
 
@@ -118,7 +116,7 @@ class RotationMotionProfile:
118
116
 
119
117
 
120
118
  def calculate_motion_profile(
121
- params: RotationScan,
119
+ params: SingleRotationScan,
122
120
  motor_time_to_speed_s: float,
123
121
  max_velocity_deg_s: float,
124
122
  ) -> RotationMotionProfile:
@@ -212,7 +210,7 @@ def calculate_motion_profile(
212
210
 
213
211
  def rotation_scan_plan(
214
212
  composite: RotationScanComposite,
215
- params: RotationScan,
213
+ params: SingleRotationScan,
216
214
  motion_values: RotationMotionProfile,
217
215
  ):
218
216
  """A stub plan to collect diffraction images from a sample continuously rotating
@@ -319,7 +317,7 @@ def _cleanup_plan(composite: RotationScanComposite, **kwargs):
319
317
 
320
318
  def _move_and_rotation(
321
319
  composite: RotationScanComposite,
322
- params: RotationScan,
320
+ params: SingleRotationScan,
323
321
  oav_params: OAVParameters,
324
322
  ):
325
323
  motor_time_to_speed = yield from bps.rd(composite.smargon.omega.acceleration_time)
@@ -330,19 +328,18 @@ def _move_and_rotation(
330
328
  return num / 1000 if num else num
331
329
 
332
330
  LOGGER.info("moving to position (if specified)")
333
- yield from move_x_y_z(
331
+ yield from bps.abs_set(
334
332
  composite.smargon,
335
- _div_by_1000_if_not_none(params.x_start_um),
336
- _div_by_1000_if_not_none(params.y_start_um),
337
- _div_by_1000_if_not_none(params.z_start_um),
338
- group=CONST.WAIT.MOVE_GONIO_TO_START,
339
- )
340
- yield from move_phi_chi_omega(
341
- composite.smargon,
342
- params.phi_start_deg,
343
- params.chi_start_deg,
333
+ CombinedMove(
334
+ x=_div_by_1000_if_not_none(params.x_start_um),
335
+ y=_div_by_1000_if_not_none(params.y_start_um),
336
+ z=_div_by_1000_if_not_none(params.z_start_um),
337
+ phi=params.phi_start_deg,
338
+ chi=params.chi_start_deg,
339
+ ),
344
340
  group=CONST.WAIT.MOVE_GONIO_TO_START,
345
341
  )
342
+
346
343
  if params.take_snapshots:
347
344
  yield from bps.wait(CONST.WAIT.MOVE_GONIO_TO_START)
348
345
  yield from setup_beamline_for_OAV(
@@ -359,9 +356,9 @@ def _move_and_rotation(
359
356
  yield from rotation_scan_plan(composite, params, motion_values)
360
357
 
361
358
 
362
- def multi_rotation_scan(
359
+ def rotation_scan(
363
360
  composite: RotationScanComposite,
364
- parameters: MultiRotationScan,
361
+ parameters: RotationScan,
365
362
  oav_params: OAVParameters | None = None,
366
363
  ) -> MsgGenerator:
367
364
  @bpp.set_run_key_decorator(CONST.PLAN.ROTATION_MULTI_OUTER)
@@ -373,15 +370,15 @@ def multi_rotation_scan(
373
370
  ),
374
371
  }
375
372
  )
376
- def _wrapped_multi_rotation_scan():
377
- yield from multi_rotation_scan_internal(composite, parameters, oav_params)
373
+ def _wrapped_rotation_scan():
374
+ yield from rotation_scan_internal(composite, parameters, oav_params)
378
375
 
379
- yield from _wrapped_multi_rotation_scan()
376
+ yield from _wrapped_rotation_scan()
380
377
 
381
378
 
382
- def multi_rotation_scan_internal(
379
+ def rotation_scan_internal(
383
380
  composite: RotationScanComposite,
384
- parameters: MultiRotationScan,
381
+ parameters: RotationScan,
385
382
  oav_params: OAVParameters | None = None,
386
383
  ) -> MsgGenerator:
387
384
  parameters.features.update_self_from_server()
@@ -419,7 +416,7 @@ def multi_rotation_scan_internal(
419
416
  }
420
417
  )
421
418
  def rotation_scan_core(
422
- params: RotationScan,
419
+ params: SingleRotationScan,
423
420
  ):
424
421
  yield from _move_and_rotation(composite, params, oav_params)
425
422