mx-bluesky 1.5.15__py3-none-any.whl → 1.6.3__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 (88) hide show
  1. mx_bluesky/Getting started.ipynb +1 -0
  2. mx_bluesky/_version.py +2 -2
  3. mx_bluesky/beamlines/i02_1/parameters/gridscan.py +1 -1
  4. mx_bluesky/beamlines/i04/__init__.py +4 -0
  5. mx_bluesky/beamlines/i04/callbacks/murko_callback.py +18 -0
  6. mx_bluesky/beamlines/i04/experiment_plans/i04_grid_detect_then_xray_centre_plan.py +5 -4
  7. mx_bluesky/beamlines/i04/oav_centering_plans/oav_imaging.py +224 -10
  8. mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +5 -2
  9. mx_bluesky/beamlines/i04/thawing_plan.py +3 -2
  10. mx_bluesky/beamlines/i24/jungfrau_commissioning/__init__.py +13 -0
  11. mx_bluesky/beamlines/i24/jungfrau_commissioning/callbacks/__init__.py +0 -0
  12. mx_bluesky/beamlines/i24/jungfrau_commissioning/callbacks/metadata_writer.py +86 -0
  13. mx_bluesky/beamlines/i24/jungfrau_commissioning/composites.py +35 -0
  14. mx_bluesky/beamlines/i24/jungfrau_commissioning/experiment_plans/do_darks.py +19 -20
  15. mx_bluesky/beamlines/i24/jungfrau_commissioning/experiment_plans/rotation_scan_plan.py +292 -0
  16. mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/do_external_acquisition.py +4 -9
  17. mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/do_internal_acquisition.py +4 -5
  18. mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/plan_utils.py +15 -19
  19. mx_bluesky/beamlines/i24/parameters/__init__.py +0 -0
  20. mx_bluesky/beamlines/i24/parameters/constants.py +9 -0
  21. mx_bluesky/beamlines/i24/serial/dcid.py +3 -3
  22. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_extruder_collect_py3v2.py +7 -7
  23. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_chip_collect_py3v1.py +7 -7
  24. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_chip_manager_py3v1.py +3 -3
  25. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +3 -3
  26. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +5 -5
  27. mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +7 -7
  28. mx_bluesky/beamlines/i24/serial/web_gui_plans/oav_plans.py +1 -1
  29. mx_bluesky/common/device_setup_plans/robot_load_unload.py +2 -24
  30. mx_bluesky/common/device_setup_plans/setup_zebra_and_shutter.py +5 -2
  31. mx_bluesky/common/experiment_plans/common_flyscan_xray_centre_plan.py +2 -2
  32. mx_bluesky/common/experiment_plans/inner_plans/read_hardware.py +1 -0
  33. mx_bluesky/common/experiment_plans/oav_grid_detection_plan.py +1 -1
  34. mx_bluesky/common/experiment_plans/pin_tip_centring_plan.py +2 -2
  35. mx_bluesky/common/experiment_plans/rotation/__init__.py +0 -0
  36. mx_bluesky/common/experiment_plans/rotation/rotation_utils.py +127 -0
  37. mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +13 -2
  38. mx_bluesky/common/external_interaction/callbacks/common/ispyb_mapping.py +0 -2
  39. mx_bluesky/common/external_interaction/ispyb/data_model.py +1 -1
  40. mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +1 -1
  41. mx_bluesky/common/parameters/components.py +17 -7
  42. mx_bluesky/common/parameters/constants.py +6 -0
  43. mx_bluesky/{hyperion → common}/parameters/rotation.py +10 -8
  44. mx_bluesky/common/preprocessors/preprocessors.py +98 -36
  45. mx_bluesky/hyperion/__main__.py +55 -22
  46. mx_bluesky/hyperion/baton_handler.py +24 -64
  47. mx_bluesky/hyperion/blueapi_config.yaml +17 -0
  48. mx_bluesky/hyperion/blueapi_dev_config.yaml +16 -0
  49. mx_bluesky/hyperion/blueapi_plans/__init__.py +96 -0
  50. mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +9 -7
  51. mx_bluesky/hyperion/device_setup_plans/setup_panda.py +1 -1
  52. mx_bluesky/hyperion/device_setup_plans/utils.py +1 -1
  53. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +3 -1
  54. mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +1 -0
  55. mx_bluesky/hyperion/experiment_plans/hyperion_grid_detect_then_xray_centre_plan.py +2 -2
  56. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +3 -1
  57. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +17 -6
  58. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +2 -5
  59. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +3 -3
  60. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +14 -128
  61. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +4 -4
  62. mx_bluesky/hyperion/experiment_plans/udc_default_state.py +19 -6
  63. mx_bluesky/hyperion/external_interaction/agamemnon.py +3 -8
  64. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +121 -47
  65. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -1
  66. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +3 -1
  67. mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +6 -3
  68. mx_bluesky/hyperion/external_interaction/callbacks/stomp/__init__.py +0 -0
  69. mx_bluesky/hyperion/external_interaction/callbacks/stomp/dispatcher.py +33 -0
  70. mx_bluesky/hyperion/in_process_runner.py +132 -0
  71. mx_bluesky/hyperion/parameters/cli.py +43 -4
  72. mx_bluesky/hyperion/parameters/components.py +13 -0
  73. mx_bluesky/hyperion/parameters/constants.py +2 -9
  74. mx_bluesky/hyperion/parameters/device_composites.py +1 -1
  75. mx_bluesky/hyperion/parameters/load_centre_collect.py +3 -1
  76. mx_bluesky/hyperion/plan_runner.py +45 -66
  77. mx_bluesky/hyperion/plan_runner_api.py +3 -4
  78. mx_bluesky/hyperion/supervisor/__init__.py +3 -0
  79. mx_bluesky/hyperion/supervisor/_supervisor.py +116 -0
  80. mx_bluesky/hyperion/supervisor/client_config.yaml +6 -0
  81. mx_bluesky/hyperion/supervisor/supervisor_config.yaml +10 -0
  82. mx_bluesky/hyperion/supervisor/supervisor_dev_config.yaml +9 -0
  83. {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/METADATA +3 -31
  84. {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/RECORD +88 -68
  85. {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/WHEEL +1 -1
  86. {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/entry_points.txt +0 -0
  87. {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/licenses/LICENSE +0 -0
  88. {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,12 @@
1
1
  from pathlib import Path
2
2
 
3
3
  import bluesky.plan_stubs as bps
4
+ from dodal.devices.beamlines.i24.aperture import Aperture, AperturePositions
5
+ from dodal.devices.beamlines.i24.beam_center import DetectorBeamCenter
6
+ from dodal.devices.beamlines.i24.beamstop import Beamstop, BeamstopPositions
7
+ from dodal.devices.beamlines.i24.dcm import DCM
8
+ from dodal.devices.beamlines.i24.dual_backlight import BacklightPositions, DualBacklight
4
9
  from dodal.devices.detector.det_dim_constants import DetectorSizeConstants
5
- from dodal.devices.i24.aperture import Aperture, AperturePositions
6
- from dodal.devices.i24.beam_center import DetectorBeamCenter
7
- from dodal.devices.i24.beamstop import Beamstop, BeamstopPositions
8
- from dodal.devices.i24.dcm import DCM
9
- from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
10
10
  from dodal.devices.motors import YZStage
11
11
  from dodal.devices.util.lookup_tables import (
12
12
  linear_interpolation_lut,
@@ -8,14 +8,14 @@ from bluesky.utils import MsgGenerator
8
8
  from dodal.beamlines import i24
9
9
  from dodal.common import inject
10
10
  from dodal.devices.attenuator.attenuator import EnumFilterAttenuator
11
+ from dodal.devices.beamlines.i24.aperture import Aperture
12
+ from dodal.devices.beamlines.i24.beam_center import DetectorBeamCenter
13
+ from dodal.devices.beamlines.i24.beamstop import Beamstop
14
+ from dodal.devices.beamlines.i24.dcm import DCM
15
+ from dodal.devices.beamlines.i24.dual_backlight import BacklightPositions, DualBacklight
16
+ from dodal.devices.beamlines.i24.focus_mirrors import FocusMirrorsMode
17
+ from dodal.devices.beamlines.i24.pmac import PMAC
11
18
  from dodal.devices.hutch_shutter import HutchShutter
12
- from dodal.devices.i24.aperture import Aperture
13
- from dodal.devices.i24.beam_center import DetectorBeamCenter
14
- from dodal.devices.i24.beamstop import Beamstop
15
- from dodal.devices.i24.dcm import DCM
16
- from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
17
- from dodal.devices.i24.focus_mirrors import FocusMirrorsMode
18
- from dodal.devices.i24.pmac import PMAC
19
19
  from dodal.devices.motors import YZStage
20
20
  from dodal.devices.oav.oav_detector import OAVBeamCentreFile
21
21
  from dodal.devices.zebra.zebra import Zebra
@@ -3,7 +3,7 @@ from enum import Enum
3
3
  import bluesky.plan_stubs as bps
4
4
  from bluesky.utils import MsgGenerator
5
5
  from dodal.common import inject
6
- from dodal.devices.i24.pmac import PMAC
6
+ from dodal.devices.beamlines.i24.pmac import PMAC
7
7
 
8
8
 
9
9
  class MoveSize(Enum):
@@ -5,7 +5,7 @@ import bluesky.preprocessors as bpp
5
5
  from bluesky.utils import MsgGenerator
6
6
  from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
7
7
  from dodal.devices.motors import XYZStage
8
- from dodal.devices.robot import BartRobot
8
+ from dodal.devices.robot import SAMPLE_LOCATION_EMPTY, BartRobot
9
9
  from dodal.devices.smargon import CombinedMove, Smargon, StubPosition
10
10
  from dodal.plan_stubs.motor_utils import MoveTooLargeError, home_and_reset_wrapper
11
11
 
@@ -14,27 +14,6 @@ from mx_bluesky.common.parameters.constants import (
14
14
  HardwareConstants,
15
15
  PlanNameConstants,
16
16
  )
17
- from mx_bluesky.common.utils.log import LOGGER
18
-
19
- SLEEP_PER_CHECK = 0.1
20
-
21
-
22
- def wait_for_smargon_not_disabled(smargon: Smargon, timeout=60):
23
- """Waits for the smargon disabled flag to go low. The robot hardware is responsible
24
- for setting this to low when it is safe to move. It does this through a physical
25
- connection between the robot and the smargon.
26
- """
27
- LOGGER.info("Waiting for smargon enabled")
28
- times_to_check = int(timeout / SLEEP_PER_CHECK)
29
- for _ in range(times_to_check):
30
- smargon_disabled = yield from bps.rd(smargon.disabled)
31
- if not smargon_disabled:
32
- LOGGER.info("Smargon now enabled")
33
- return
34
- yield from bps.sleep(SLEEP_PER_CHECK)
35
- raise TimeoutError(
36
- "Timed out waiting for smargon to become enabled after robot load"
37
- )
38
17
 
39
18
 
40
19
  def _raise_exception_if_moved_out_of_cryojet(exception):
@@ -117,8 +96,7 @@ def robot_unload(
117
96
  yield from bps.save()
118
97
 
119
98
  def _unload():
120
- yield from bps.abs_set(robot, None, wait=True)
121
- yield from wait_for_smargon_not_disabled(smargon)
99
+ yield from bps.abs_set(robot, SAMPLE_LOCATION_EMPTY, wait=True)
122
100
 
123
101
  gonio_finished = yield from do_plan_while_lower_gonio_at_home(
124
102
  _unload(), lower_gonio
@@ -14,7 +14,10 @@ from dodal.devices.zebra.zebra_controlled_shutter import (
14
14
  ZebraShutterControl,
15
15
  )
16
16
 
17
- from mx_bluesky.common.parameters.constants import ZEBRA_STATUS_TIMEOUT
17
+ from mx_bluesky.common.parameters.constants import (
18
+ ZEBRA_STATUS_TIMEOUT,
19
+ PlanGroupCheckpointConstants,
20
+ )
18
21
  from mx_bluesky.common.utils.log import LOGGER
19
22
 
20
23
  """Plans in this file will work as intended if the zebra has the following configuration:
@@ -154,7 +157,7 @@ def setup_zebra_for_rotation(
154
157
  shutter_opening_deg: float = 2.5,
155
158
  shutter_opening_s: float = 0.04,
156
159
  direction: RotationDirection = RotationDirection.POSITIVE,
157
- group: str = "setup_zebra_for_rotation",
160
+ group: str = PlanGroupCheckpointConstants.SETUP_ZEBRA_FOR_ROTATION,
158
161
  wait: bool = True,
159
162
  ttl_input_for_detector_to_use: int | None = None,
160
163
  ):
@@ -154,7 +154,7 @@ def common_flyscan_xray_centre(
154
154
 
155
155
  This plan will also push data to ispyb when used with the ispyb_activation_decorator.
156
156
 
157
- There are a few other useful decorators to use with this plan, see: verify_undulator_gap_before_run_decorator, transmission_and_xbpm_feedback_for_collection_decorator
157
+ There are a few other useful decorators to use with this plan, see: verify_undulator_gap_before_run_decorator, common/preprocessors/preprocessors.py
158
158
  """
159
159
 
160
160
  def _overall_tidy():
@@ -210,7 +210,7 @@ def _fetch_xrc_results_from_zocalo(
210
210
 
211
211
  LOGGER.info("Getting X-ray center Zocalo results...")
212
212
 
213
- yield from bps.trigger(zocalo_results)
213
+ yield from bps.trigger(zocalo_results, wait=True)
214
214
  LOGGER.info("Zocalo triggered and read, interpreting results.")
215
215
  xrc_results = yield from get_full_processing_results(zocalo_results)
216
216
  LOGGER.info(f"Got xray centres, top 5: {xrc_results[:5]}")
@@ -76,6 +76,7 @@ def standard_read_hardware_during_collection(
76
76
  detector.bit_depth,
77
77
  beamsize,
78
78
  detector.cam.roi_mode,
79
+ detector.ispyb_detector_id,
79
80
  ]
80
81
  yield from read_hardware_plan(
81
82
  signals_to_read_during_collection, DocDescriptorNames.HARDWARE_READ_DURING
@@ -104,7 +104,7 @@ def grid_detection_plan(
104
104
  for angle in (yield from optimum_grid_detect_angles(smargon)):
105
105
  yield from bps.mv(smargon.omega, angle)
106
106
  # need to wait for the OAV image to update
107
- # See #673 for improvements
107
+ # See https://github.com/DiamondLightSource/mx-bluesky/issues/416 for improvements
108
108
  yield from bps.sleep(HardwareConstants.OAV_REFRESH_DELAY)
109
109
 
110
110
  tip_x_px, tip_y_px = yield from catch_exception_and_warn(
@@ -146,7 +146,7 @@ def pin_tip_centre_plan(
146
146
  LOGGER.info(f"Tip offset in pixels: {tip_offset_px}")
147
147
 
148
148
  # need to wait for the OAV image to update
149
- # See #673 for improvements
149
+ # See https://github.com/DiamondLightSource/mx-bluesky/issues/416 for improvements
150
150
  yield from bps.sleep(0.3)
151
151
 
152
152
  yield from pre_centring_setup_oav(oav, oav_params, pin_tip_setup)
@@ -157,7 +157,7 @@ def pin_tip_centre_plan(
157
157
  yield from bps.mvr(gonio.omega, -90)
158
158
 
159
159
  # need to wait for the OAV image to update
160
- # See #673 for improvements
160
+ # See https://github.com/DiamondLightSource/mx-bluesky/issues/416 for improvements
161
161
  yield from bps.sleep(0.3)
162
162
  tip = yield from catch_exception_and_warn(
163
163
  PinNotFoundError, wait_for_tip_to_be_found, pin_tip_detect
@@ -0,0 +1,127 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+
5
+ from dodal.devices.zebra.zebra import RotationDirection
6
+ from dodal.utils import get_beamline_name
7
+
8
+ from mx_bluesky.common.parameters.constants import RotationParamConstants
9
+ from mx_bluesky.common.parameters.rotation import SingleRotationScan
10
+ from mx_bluesky.common.utils.log import LOGGER
11
+
12
+ DEFAULT_DIRECTION = RotationDirection.NEGATIVE
13
+ DEFAULT_MAX_VELOCITY = 120
14
+ # Use a slightly larger time to acceleration than EPICS as it's better to be cautious
15
+ ACCELERATION_MARGIN = 1.5
16
+
17
+
18
+ @dataclasses.dataclass
19
+ class RotationMotionProfile:
20
+ start_scan_deg: float
21
+ start_motion_deg: float
22
+ scan_width_deg: float
23
+ shutter_time_s: float
24
+ direction: RotationDirection
25
+ speed_for_rotation_deg_s: float
26
+ acceleration_offset_deg: float
27
+ shutter_opening_deg: float
28
+ total_exposure_s: float
29
+ distance_to_move_deg: float
30
+ max_velocity_deg_s: float
31
+
32
+
33
+ def calculate_motion_profile(
34
+ params: SingleRotationScan,
35
+ motor_time_to_speed_s: float,
36
+ max_velocity_deg_s: float,
37
+ ) -> RotationMotionProfile:
38
+ """Calculates the various numbers needed for motions in the rotation scan.
39
+ Rotates through "scan width" plus twice an "offset" to take into account
40
+ acceleration at the start and deceleration at the end, plus the number of extra
41
+ degrees of rotation needed to make sure the fast shutter has fully opened before the
42
+ detector trigger is sent.
43
+ See https://github.com/DiamondLightSource/hyperion/wiki/rotation-scan-geometry
44
+ for a simple pictorial explanation."""
45
+
46
+ assert params.rotation_increment_deg > 0
47
+
48
+ direction = params.rotation_direction
49
+ start_scan_deg = params.omega_start_deg
50
+
51
+ if RotationParamConstants.OMEGA_FLIP:
52
+ # If omega_flip is True then the motor omega axis is inverted with respect to the
53
+ # coordinate system.
54
+ start_scan_deg = -start_scan_deg
55
+ direction = (
56
+ direction.POSITIVE
57
+ if direction == direction.NEGATIVE
58
+ else direction.NEGATIVE
59
+ )
60
+
61
+ num_images = params.num_images
62
+ shutter_time_s = params.shutter_opening_time_s
63
+ image_width_deg = params.rotation_increment_deg
64
+ exposure_time_s = params.exposure_time_s
65
+ motor_time_to_speed_s *= ACCELERATION_MARGIN
66
+
67
+ LOGGER.info("Calculating rotation scan motion profile:")
68
+ LOGGER.info(
69
+ f"{num_images=}, {shutter_time_s=}, {image_width_deg=}, {exposure_time_s=}, {direction=}"
70
+ )
71
+
72
+ scan_width_deg = num_images * params.rotation_increment_deg
73
+ LOGGER.info(f"{scan_width_deg=} = {num_images=} * {params.rotation_increment_deg=}")
74
+
75
+ speed_for_rotation_deg_s = image_width_deg / exposure_time_s
76
+ LOGGER.info("speed_for_rotation_deg_s = image_width_deg / exposure_time_s")
77
+ LOGGER.info(
78
+ f"{speed_for_rotation_deg_s=} = {image_width_deg=} / {exposure_time_s=}"
79
+ )
80
+
81
+ acceleration_offset_deg = motor_time_to_speed_s * speed_for_rotation_deg_s
82
+ LOGGER.info(
83
+ f"{acceleration_offset_deg=} = {motor_time_to_speed_s=} * {speed_for_rotation_deg_s=}"
84
+ )
85
+
86
+ start_motion_deg = start_scan_deg - (acceleration_offset_deg * direction.multiplier)
87
+ LOGGER.info(
88
+ f"{start_motion_deg=} = {start_scan_deg=} - ({acceleration_offset_deg=} * {direction.multiplier=})"
89
+ )
90
+
91
+ shutter_opening_deg = speed_for_rotation_deg_s * shutter_time_s
92
+ LOGGER.info(
93
+ f"{shutter_opening_deg=} = {speed_for_rotation_deg_s=} * {shutter_time_s=}"
94
+ )
95
+
96
+ shutter_opening_deg = speed_for_rotation_deg_s * shutter_time_s
97
+ LOGGER.info(
98
+ f"{shutter_opening_deg=} = {speed_for_rotation_deg_s=} * {shutter_time_s=}"
99
+ )
100
+
101
+ total_exposure_s = num_images * exposure_time_s
102
+ LOGGER.info(f"{total_exposure_s=} = {num_images=} * {exposure_time_s=}")
103
+
104
+ distance_to_move_deg = (
105
+ scan_width_deg + shutter_opening_deg + acceleration_offset_deg * 2
106
+ ) * direction.multiplier
107
+ LOGGER.info(
108
+ f"{distance_to_move_deg=} = ({scan_width_deg=} + {shutter_opening_deg=} + {acceleration_offset_deg=} * 2) * {direction=})"
109
+ )
110
+
111
+ # See https://github.com/DiamondLightSource/mx-bluesky/issues/1224
112
+ if get_beamline_name("i03") == "i24":
113
+ acceleration_offset_deg = 10
114
+
115
+ return RotationMotionProfile(
116
+ start_scan_deg=start_scan_deg,
117
+ start_motion_deg=start_motion_deg,
118
+ scan_width_deg=scan_width_deg,
119
+ shutter_time_s=shutter_time_s,
120
+ direction=direction,
121
+ speed_for_rotation_deg_s=speed_for_rotation_deg_s,
122
+ acceleration_offset_deg=acceleration_offset_deg,
123
+ shutter_opening_deg=shutter_opening_deg,
124
+ total_exposure_s=total_exposure_s,
125
+ distance_to_move_deg=distance_to_move_deg,
126
+ max_velocity_deg_s=max_velocity_deg_s,
127
+ )
@@ -23,7 +23,7 @@ from mx_bluesky.common.external_interaction.ispyb.ispyb_store import (
23
23
  )
24
24
  from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import get_ispyb_config
25
25
  from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
26
- from mx_bluesky.common.parameters.constants import DocDescriptorNames
26
+ from mx_bluesky.common.parameters.constants import USE_NUMTRACKER, DocDescriptorNames
27
27
  from mx_bluesky.common.utils.log import (
28
28
  ISPYB_ZOCALO_CALLBACK_LOGGER,
29
29
  format_doc_for_log,
@@ -86,6 +86,17 @@ class BaseISPyBCallback(PlanReactiveCallback):
86
86
 
87
87
  def activity_gated_start(self, doc: RunStart):
88
88
  self._oav_snapshot_event_idx = 0
89
+
90
+ if self.params and self.params.visit == USE_NUMTRACKER:
91
+ try:
92
+ visit = doc.get("instrument_session")
93
+ assert isinstance(visit, str)
94
+ self.params.visit = visit
95
+ except Exception as e:
96
+ raise ValueError(
97
+ f"Error trying to retrieve instrument session from document {doc}"
98
+ ) from e
99
+
89
100
  return self.tag_doc(doc)
90
101
 
91
102
  def activity_gated_descriptor(self, doc: EventDescriptor):
@@ -124,7 +135,6 @@ class BaseISPyBCallback(PlanReactiveCallback):
124
135
  )
125
136
  synchrotron_mode = doc["data"]["synchrotron-synchrotron_mode"]
126
137
  assert isinstance(synchrotron_mode, SynchrotronMode)
127
-
128
138
  hwscan_data_collection_info = DataCollectionInfo(
129
139
  undulator_gap1=doc["data"]["undulator-current_gap"],
130
140
  synchrotron_mode=synchrotron_mode.value,
@@ -159,6 +169,7 @@ class BaseISPyBCallback(PlanReactiveCallback):
159
169
  beamsize_at_sampley=beamsize_y_mm,
160
170
  flux=doc["data"]["flux-flux_reading"],
161
171
  detector_mode="ROI" if doc["data"]["eiger_cam_roi_mode"] else "FULL",
172
+ ispyb_detector_id=doc["data"]["eiger-ispyb_detector_id"],
162
173
  )
163
174
  if transmission := doc["data"]["attenuator-actual_transmission"]:
164
175
  # Ispyb wants the transmission in a percentage, we use fractions
@@ -9,7 +9,6 @@ from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import (
9
9
  )
10
10
  from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
11
11
 
12
- I03_EIGER_DETECTOR = 78
13
12
  EIGER_FILE_SUFFIX = "h5"
14
13
 
15
14
 
@@ -31,7 +30,6 @@ def populate_remaining_data_collection_info(
31
30
  data_collection_info.sample_id = params.sample_id
32
31
  data_collection_info.visit_string = params.visit
33
32
  data_collection_info.parent_id = data_collection_group_id
34
- data_collection_info.detector_id = I03_EIGER_DETECTOR
35
33
  data_collection_info.comments = comment
36
34
  data_collection_info.detector_distance = params.detector_params.detector_distance
37
35
  data_collection_info.exp_time = params.detector_params.exposure_time_s
@@ -40,7 +40,7 @@ class DataCollectionInfo:
40
40
  kappa_start: float | None = None
41
41
 
42
42
  visit_string: str | None = None
43
- detector_id: int | None = None
43
+ ispyb_detector_id: int | None = None
44
44
  axis_start: float | None = None
45
45
  slitgap_vertical: float | None = None
46
46
  slitgap_horizontal: float | None = None
@@ -282,7 +282,7 @@ def _data_collection_info_to_json(data: DataCollectionInfo) -> dict:
282
282
  "axisEnd": data.axis_end,
283
283
  "chiStart": data.chi_start,
284
284
  "kappaStart": data.kappa_start,
285
- "detectorId": data.detector_id,
285
+ "detectorId": data.ispyb_detector_id,
286
286
  "axisStart": data.axis_start,
287
287
  "slitGapVertical": data.slitgap_vertical,
288
288
  "slitGapHorizontal": data.slitgap_horizontal,
@@ -25,6 +25,7 @@ from semver import Version
25
25
 
26
26
  from mx_bluesky.common.parameters.constants import (
27
27
  TEST_MODE,
28
+ USE_NUMTRACKER,
28
29
  DetectorParamConstants,
29
30
  GridscanParamConstants,
30
31
  )
@@ -32,6 +33,10 @@ from mx_bluesky.common.parameters.constants import (
32
33
  PARAMETER_VERSION = Version.parse("5.3.0")
33
34
 
34
35
 
36
+ def get_param_version() -> SemanticVersion:
37
+ return SemanticVersion.validate_from_str(str(PARAMETER_VERSION))
38
+
39
+
35
40
  class RotationAxis(StrEnum):
36
41
  OMEGA = "omega"
37
42
  PHI = "phi"
@@ -152,8 +157,8 @@ class WithVisit(BaseModel):
152
157
  det_dist_to_beam_converter_path: str = Field(
153
158
  default=DetectorParamConstants.BEAM_XY_LUT_PATH
154
159
  )
155
- insertion_prefix: str = "SR03S" if TEST_MODE else "SR03I"
156
160
  detector_distance_mm: float | None = Field(default=None, gt=0)
161
+ insertion_prefix: str = "SR03S" if TEST_MODE else "SR03I"
157
162
 
158
163
 
159
164
  class DiffractionExperiment(
@@ -176,12 +181,17 @@ class DiffractionExperiment(
176
181
  @model_validator(mode="before")
177
182
  @classmethod
178
183
  def validate_directories(cls, values):
179
- os.makedirs(values["storage_directory"], exist_ok=True)
180
-
181
- values["snapshot_directory"] = values.get(
182
- "snapshot_directory",
183
- Path(values["storage_directory"], "snapshots").as_posix(),
184
- )
184
+ # Plans using numtracker currently won't work with snapshot directories:
185
+ # see https://github.com/DiamondLightSource/mx-bluesky/issues/1527
186
+ if values["storage_directory"] != USE_NUMTRACKER:
187
+ os.makedirs(values["storage_directory"], exist_ok=True)
188
+
189
+ values["snapshot_directory"] = values.get(
190
+ "snapshot_directory",
191
+ Path(values["storage_directory"], "snapshots").as_posix(),
192
+ )
193
+ else:
194
+ values["snapshot_directory"] = Path("/tmp")
185
195
  return values
186
196
 
187
197
  @property
@@ -9,6 +9,9 @@ from pydantic.dataclasses import dataclass
9
9
 
10
10
  from mx_bluesky.definitions import ROOT_DIR
11
11
 
12
+ # Use as visit if numtracker is being used
13
+ USE_NUMTRACKER = "from numtracker"
14
+
12
15
  BEAMLINE = get_beamline_name("test")
13
16
  TEST_MODE = BEAMLINE == "test"
14
17
  ZEBRA_STATUS_TIMEOUT = 30
@@ -111,6 +114,8 @@ class GridscanParamConstants:
111
114
  @dataclass(frozen=True)
112
115
  class RotationParamConstants:
113
116
  DEFAULT_APERTURE_POSITION = ApertureValue.LARGE
117
+ DEFAULT_SHUTTER_TIME_S = 0.06
118
+ OMEGA_FLIP = True # See https://github.com/DiamondLightSource/mx-bluesky/issues/1223 to make beamline-specific
114
119
 
115
120
 
116
121
  @dataclass(frozen=True)
@@ -138,6 +143,7 @@ class PlanGroupCheckpointConstants:
138
143
  MOVE_GONIO_TO_START = "move_gonio_to_start"
139
144
  READY_FOR_OAV = "ready_for_oav"
140
145
  PREPARE_APERTURE = "prepare_aperture"
146
+ SETUP_ZEBRA_FOR_ROTATION = "setup_zebra_for_rotation"
141
147
 
142
148
 
143
149
  # Eventually replace below with https://github.com/DiamondLightSource/mx-bluesky/issues/798
@@ -28,9 +28,9 @@ from mx_bluesky.common.parameters.components import (
28
28
  WithSample,
29
29
  WithScan,
30
30
  )
31
- from mx_bluesky.hyperion.parameters.constants import (
32
- CONST,
33
- I03Constants,
31
+ from mx_bluesky.common.parameters.constants import (
32
+ DetectorParamConstants,
33
+ RotationParamConstants,
34
34
  )
35
35
 
36
36
 
@@ -56,7 +56,9 @@ class RotationScanPerSweep(OptionalGonioAngleStarts, OptionalXyzStarts, WithSamp
56
56
 
57
57
 
58
58
  class RotationExperiment(DiffractionExperiment):
59
- shutter_opening_time_s: float = Field(default=CONST.I03.SHUTTER_TIME_S)
59
+ shutter_opening_time_s: float = Field(
60
+ default=RotationParamConstants.DEFAULT_SHUTTER_TIME_S
61
+ )
60
62
  rotation_increment_deg: float = Field(default=0.1, gt=0)
61
63
  ispyb_experiment_type: IspybExperimentType = Field(
62
64
  default=IspybExperimentType.ROTATION
@@ -67,7 +69,7 @@ class RotationExperiment(DiffractionExperiment):
67
69
  ) -> DetectorParams:
68
70
  self.det_dist_to_beam_converter_path = (
69
71
  self.det_dist_to_beam_converter_path
70
- or CONST.PARAM.DETECTOR.BEAM_XY_LUT_PATH
72
+ or DetectorParamConstants.BEAM_XY_LUT_PATH
71
73
  )
72
74
  optional_args = {}
73
75
  if self.run_number:
@@ -75,7 +77,7 @@ class RotationExperiment(DiffractionExperiment):
75
77
  assert self.detector_distance_mm is not None
76
78
  os.makedirs(self.storage_directory, exist_ok=True)
77
79
  return DetectorParams(
78
- detector_size_constants=I03Constants.DETECTOR,
80
+ detector_size_constants=DetectorParamConstants.DETECTOR,
79
81
  expected_energy_ev=self.demand_energy_ev,
80
82
  exposure_time_s=self.exposure_time_s,
81
83
  directory=self.storage_directory,
@@ -97,7 +99,7 @@ class RotationExperiment(DiffractionExperiment):
97
99
  @classmethod
98
100
  def _set_default_aperture_position(cls, aperture_position: ApertureValue | None):
99
101
  if not aperture_position:
100
- default_aperture = CONST.PARAM.ROTATION.DEFAULT_APERTURE_POSITION
102
+ default_aperture = RotationParamConstants.DEFAULT_APERTURE_POSITION
101
103
  LOGGER.warning(
102
104
  f"No aperture position selected. Defaulting to {default_aperture}"
103
105
  )
@@ -107,7 +109,7 @@ class RotationExperiment(DiffractionExperiment):
107
109
 
108
110
 
109
111
  class SingleRotationScan(
110
- WithScan, RotationScanPerSweep, RotationExperiment, DiffractionExperimentWithSample
112
+ WithScan, RotationExperiment, RotationScanPerSweep, DiffractionExperimentWithSample
111
113
  ):
112
114
  @property
113
115
  def detector_params(self):