mx-bluesky 1.4.1a0__py3-none-any.whl → 1.4.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 (105) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +178 -0
  3. mx_bluesky/beamlines/i24/serial/__init__.py +0 -6
  4. mx_bluesky/beamlines/i24/serial/dcid.py +125 -151
  5. mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +1 -1
  6. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +88 -43
  7. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +1 -1
  8. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/MappingLite-oxford_py3v1.edl +2 -46
  9. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +85 -122
  10. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +58 -66
  11. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +1 -19
  12. mx_bluesky/beamlines/i24/serial/parameters/__init__.py +11 -2
  13. mx_bluesky/beamlines/i24/serial/parameters/constants.py +16 -2
  14. mx_bluesky/beamlines/i24/serial/parameters/experiment_parameters.py +94 -19
  15. mx_bluesky/beamlines/i24/serial/parameters/utils.py +19 -0
  16. mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +2 -0
  17. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +61 -8
  18. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +81 -40
  19. mx_bluesky/beamlines/i24/serial/write_nexus.py +66 -67
  20. mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/aperture_change_callback.py +1 -1
  21. mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/grid_detection_callback.py +19 -1
  22. mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/ispyb_callback_base.py +40 -34
  23. mx_bluesky/{hyperion → common}/external_interaction/callbacks/common/ispyb_mapping.py +4 -4
  24. mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/logging_callback.py +1 -1
  25. mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/zocalo_callback.py +14 -9
  26. mx_bluesky/{hyperion → common}/external_interaction/callbacks/xray_centre/ispyb_callback.py +46 -38
  27. mx_bluesky/{hyperion → common}/external_interaction/callbacks/xray_centre/ispyb_mapping.py +2 -2
  28. mx_bluesky/{hyperion → common}/external_interaction/callbacks/xray_centre/nexus_callback.py +20 -15
  29. mx_bluesky/common/external_interaction/config_server.py +11 -0
  30. mx_bluesky/common/external_interaction/ispyb/__init__.py +0 -0
  31. mx_bluesky/{hyperion → common}/external_interaction/ispyb/data_model.py +2 -0
  32. mx_bluesky/{hyperion → common}/external_interaction/ispyb/exp_eye_store.py +67 -17
  33. mx_bluesky/{hyperion → common}/external_interaction/ispyb/ispyb_store.py +20 -18
  34. mx_bluesky/{hyperion → common}/external_interaction/ispyb/ispyb_utils.py +2 -2
  35. mx_bluesky/common/external_interaction/nexus/__init__.py +0 -0
  36. mx_bluesky/{hyperion → common}/external_interaction/nexus/nexus_utils.py +21 -6
  37. mx_bluesky/{hyperion → common}/external_interaction/nexus/write_nexus.py +5 -5
  38. mx_bluesky/common/external_interaction/test_config_server.py +38 -0
  39. mx_bluesky/common/parameters/components.py +10 -8
  40. mx_bluesky/common/parameters/constants.py +6 -0
  41. mx_bluesky/common/parameters/gridscan.py +102 -53
  42. mx_bluesky/common/plans/do_fgs.py +4 -4
  43. mx_bluesky/{hyperion → common/utils}/exceptions.py +27 -1
  44. mx_bluesky/common/utils/log.py +17 -7
  45. mx_bluesky/hyperion/__main__.py +15 -14
  46. mx_bluesky/hyperion/device_setup_plans/check_beamstop.py +27 -0
  47. mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +34 -37
  48. mx_bluesky/hyperion/device_setup_plans/manipulate_sample.py +7 -7
  49. mx_bluesky/hyperion/device_setup_plans/position_detector.py +1 -1
  50. mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +3 -3
  51. mx_bluesky/hyperion/device_setup_plans/setup_panda.py +21 -4
  52. mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +62 -36
  53. mx_bluesky/hyperion/device_setup_plans/smargon.py +3 -3
  54. mx_bluesky/hyperion/device_setup_plans/utils.py +4 -0
  55. mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +8 -8
  56. mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +28 -17
  57. mx_bluesky/hyperion/experiment_plans/common/xrc_result.py +10 -1
  58. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -9
  59. mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +54 -58
  60. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +22 -31
  61. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +57 -40
  62. mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +3 -3
  63. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +8 -2
  64. mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +6 -14
  65. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +12 -11
  66. mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +4 -4
  67. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +39 -30
  68. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +36 -18
  69. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +33 -21
  70. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +10 -9
  71. mx_bluesky/hyperion/external_interaction/callbacks/__init__.py +0 -4
  72. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +31 -20
  73. mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +46 -30
  74. mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +39 -24
  75. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +25 -24
  76. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +1 -1
  77. mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +13 -9
  78. mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/__init__.py +0 -0
  79. mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/sample_handling_callback.py +50 -0
  80. mx_bluesky/hyperion/external_interaction/config_server.py +15 -1
  81. mx_bluesky/hyperion/parameters/components.py +3 -2
  82. mx_bluesky/hyperion/parameters/constants.py +1 -0
  83. mx_bluesky/hyperion/parameters/gridscan.py +56 -89
  84. mx_bluesky/hyperion/parameters/load_centre_collect.py +51 -6
  85. mx_bluesky/hyperion/parameters/robot_load.py +40 -0
  86. mx_bluesky/hyperion/parameters/rotation.py +28 -3
  87. mx_bluesky/hyperion/utils/context.py +1 -1
  88. mx_bluesky/hyperion/utils/validation.py +5 -3
  89. {mx_bluesky-1.4.1a0.dist-info → mx_bluesky-1.4.3.dist-info}/METADATA +6 -6
  90. mx_bluesky-1.4.3.dist-info/RECORD +155 -0
  91. {mx_bluesky-1.4.1a0.dist-info → mx_bluesky-1.4.3.dist-info}/WHEEL +1 -1
  92. mx_bluesky/common/parameters/robot_load.py +0 -16
  93. mx_bluesky/hyperion/external_interaction/exceptions.py +0 -13
  94. mx_bluesky/hyperion/log.py +0 -15
  95. mx_bluesky-1.4.1a0.dist-info/RECORD +0 -150
  96. /mx_bluesky/{hyperion/external_interaction/callbacks/xray_centre → common/external_interaction}/__init__.py +0 -0
  97. /mx_bluesky/{hyperion/external_interaction/ispyb → common/external_interaction/callbacks/common}/__init__.py +0 -0
  98. /mx_bluesky/{hyperion → common}/external_interaction/callbacks/common/abstract_event.py +0 -0
  99. /mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/log_uid_tag_callback.py +0 -0
  100. /mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/plan_reactive_callback.py +0 -0
  101. /mx_bluesky/{hyperion/external_interaction/nexus → common/external_interaction/callbacks/xray_centre}/__init__.py +0 -0
  102. /mx_bluesky/{hyperion → common}/utils/utils.py +0 -0
  103. {mx_bluesky-1.4.1a0.dist-info → mx_bluesky-1.4.3.dist-info}/LICENSE +0 -0
  104. {mx_bluesky-1.4.1a0.dist-info → mx_bluesky-1.4.3.dist-info}/entry_points.txt +0 -0
  105. {mx_bluesky-1.4.1a0.dist-info → mx_bluesky-1.4.3.dist-info}/top_level.txt +0 -0
@@ -10,15 +10,17 @@ from dodal.devices.undulator_dcm import UndulatorDCM
10
10
  from dodal.devices.util.adjuster_plans import lookup_table_adjuster
11
11
  from dodal.devices.util.lookup_tables import (
12
12
  linear_interpolation_lut,
13
+ parse_lookup_table,
13
14
  )
14
15
 
15
- from mx_bluesky.hyperion.log import LOGGER
16
- from mx_bluesky.hyperion.utils.utils import (
16
+ from mx_bluesky.common.utils.log import LOGGER
17
+ from mx_bluesky.common.utils.utils import (
17
18
  energy_to_bragg_angle,
18
19
  )
19
20
 
20
21
  MIRROR_VOLTAGE_GROUP = "MIRROR_VOLTAGE_GROUP"
21
22
  DCM_GROUP = "DCM_GROUP"
23
+ YAW_LAT_TIMEOUT_S = 30
22
24
 
23
25
 
24
26
  def _apply_and_wait_for_voltages_to_settle(
@@ -46,31 +48,42 @@ def _apply_and_wait_for_voltages_to_settle(
46
48
  for voltage_channel, required_voltage in zip(
47
49
  channels.values(), required_voltages, strict=True
48
50
  ):
49
- LOGGER.debug(
51
+ LOGGER.info(
50
52
  f"Applying and waiting for voltage {voltage_channel.name} = {required_voltage}"
51
53
  )
52
54
  yield from bps.abs_set(
53
- voltage_channel, required_voltage, group=MIRROR_VOLTAGE_GROUP
55
+ voltage_channel, required_voltage, group=MIRROR_VOLTAGE_GROUP, wait=True
54
56
  )
55
57
 
56
- yield from bps.wait(group=MIRROR_VOLTAGE_GROUP)
57
-
58
58
 
59
59
  def adjust_mirror_stripe(
60
60
  energy_kev, mirror: FocusingMirrorWithStripes, mirror_voltages: MirrorVoltages
61
61
  ):
62
62
  """Feedback should be OFF prior to entry, in order to prevent
63
63
  feedback from making unnecessary corrections while beam is being adjusted."""
64
- stripe = mirror.energy_to_stripe(energy_kev)
64
+ mirror_config = mirror.energy_to_stripe(energy_kev)
65
65
 
66
66
  LOGGER.info(
67
- f"Adjusting mirror stripe for {energy_kev}keV selecting {stripe} stripe"
67
+ f"Adjusting mirror stripe for {energy_kev}keV selecting {mirror_config['stripe']} stripe"
68
68
  )
69
- yield from bps.abs_set(mirror.stripe, stripe, wait=True)
69
+ yield from bps.abs_set(mirror.stripe, mirror_config["stripe"], wait=True)
70
70
  yield from bps.trigger(mirror.apply_stripe)
71
71
 
72
+ # yaw, lat cannot be done simultaneously
73
+ LOGGER.info(f"Adjusting {mirror.name} lat to {mirror_config['lat_mm']}")
74
+ yield from bps.abs_set(
75
+ mirror.x_mm, mirror_config["lat_mm"], wait=True, timeout=YAW_LAT_TIMEOUT_S
76
+ )
77
+
78
+ LOGGER.info(f"Adjusting {mirror.name} yaw to {mirror_config['yaw_mrad']}")
79
+ yield from bps.abs_set(
80
+ mirror.yaw_mrad, mirror_config["yaw_mrad"], wait=True, timeout=YAW_LAT_TIMEOUT_S
81
+ )
82
+
72
83
  LOGGER.info("Adjusting mirror voltages...")
73
- yield from _apply_and_wait_for_voltages_to_settle(stripe, mirror_voltages)
84
+ yield from _apply_and_wait_for_voltages_to_settle(
85
+ mirror_config["stripe"], mirror_voltages
86
+ )
74
87
 
75
88
 
76
89
  def adjust_dcm_pitch_roll_vfm_from_lut(
@@ -86,13 +99,17 @@ def adjust_dcm_pitch_roll_vfm_from_lut(
86
99
  feedback from making unnecessary corrections while beam is being adjusted."""
87
100
 
88
101
  # Adjust DCM Pitch
89
- dcm = undulator_dcm.dcm
102
+ dcm = undulator_dcm.dcm_ref()
90
103
  LOGGER.info(f"Adjusting DCM and VFM for {energy_kev} keV")
91
- d_spacing_a: float = yield from bps.rd(undulator_dcm.dcm.crystal_metadata_d_spacing)
104
+ d_spacing_a: float = yield from bps.rd(
105
+ undulator_dcm.dcm_ref().crystal_metadata_d_spacing
106
+ )
92
107
  bragg_deg = energy_to_bragg_angle(energy_kev, d_spacing_a)
93
108
  LOGGER.info(f"Target Bragg angle = {bragg_deg} degrees")
94
109
  dcm_pitch_adjuster = lookup_table_adjuster(
95
- linear_interpolation_lut(undulator_dcm.pitch_energy_table_path),
110
+ linear_interpolation_lut(
111
+ *parse_lookup_table(undulator_dcm.pitch_energy_table_path)
112
+ ),
96
113
  dcm.pitch_in_mrad,
97
114
  bragg_deg,
98
115
  )
@@ -102,38 +119,18 @@ def adjust_dcm_pitch_roll_vfm_from_lut(
102
119
 
103
120
  # DCM Roll
104
121
  dcm_roll_adjuster = lookup_table_adjuster(
105
- linear_interpolation_lut(undulator_dcm.roll_energy_table_path),
122
+ linear_interpolation_lut(
123
+ *parse_lookup_table(undulator_dcm.roll_energy_table_path)
124
+ ),
106
125
  dcm.roll_in_mrad,
107
126
  bragg_deg,
108
127
  )
109
128
  yield from dcm_roll_adjuster(DCM_GROUP)
110
129
  LOGGER.info("Waiting for DCM roll adjust to complete...")
111
130
 
112
- # DCM Perp pitch
113
- offset_mm = undulator_dcm.dcm_fixed_offset_mm
114
- LOGGER.info(f"Adjusting DCM offset to {offset_mm} mm")
115
- yield from bps.abs_set(dcm.offset_in_mm, offset_mm, group=DCM_GROUP)
116
-
117
131
  #
118
- # Adjust mirrors
132
+ # Adjust vfm mirror stripe and mirror voltages
119
133
  #
120
134
 
121
- # No need to change HFM
122
-
123
- # Assumption is focus mode is already set to "sample"
124
- # not sure how we check this
125
-
126
135
  # VFM Stripe selection
127
136
  yield from adjust_mirror_stripe(energy_kev, vfm, mirror_voltages)
128
- yield from bps.wait(DCM_GROUP)
129
-
130
- # VFM Adjust - for I03 this table always returns the same value
131
- vfm_lut = vfm.bragg_to_lat_lookup_table_path
132
- assert vfm_lut is not None
133
- vfm_x_adjuster = lookup_table_adjuster(
134
- linear_interpolation_lut(vfm_lut),
135
- vfm.x_mm,
136
- bragg_deg,
137
- )
138
- LOGGER.info("Waiting for VFM Lat (Horizontal Translation) to complete...")
139
- yield from vfm_x_adjuster()
@@ -9,7 +9,7 @@ from dodal.devices.backlight import Backlight, BacklightPosition
9
9
  from dodal.devices.detector.detector_motion import DetectorMotion
10
10
  from dodal.devices.smargon import Smargon
11
11
 
12
- from mx_bluesky.hyperion.log import LOGGER
12
+ from mx_bluesky.common.utils.log import LOGGER
13
13
 
14
14
  LOWER_DETECTOR_SHUTTER_AFTER_SCAN = True
15
15
 
@@ -78,11 +78,11 @@ def move_x_y_z(
78
78
  axes are optional."""
79
79
 
80
80
  LOGGER.info(f"Moving smargon to x, y, z: {(x_mm, y_mm, z_mm)}")
81
- if x_mm:
81
+ if x_mm is not None:
82
82
  yield from bps.abs_set(smargon.x, x_mm, group=group)
83
- if y_mm:
83
+ if y_mm is not None:
84
84
  yield from bps.abs_set(smargon.y, y_mm, group=group)
85
- if z_mm:
85
+ if z_mm is not None:
86
86
  yield from bps.abs_set(smargon.z, z_mm, group=group)
87
87
  if wait:
88
88
  yield from bps.wait(group)
@@ -100,11 +100,11 @@ def move_phi_chi_omega(
100
100
  axes are optional."""
101
101
 
102
102
  LOGGER.info(f"Moving smargon to phi, chi, omega: {(phi, chi, omega)}")
103
- if phi:
103
+ if phi is not None:
104
104
  yield from bps.abs_set(smargon.phi, phi, group=group)
105
- if chi:
105
+ if chi is not None:
106
106
  yield from bps.abs_set(smargon.chi, chi, group=group)
107
- if omega:
107
+ if omega is not None:
108
108
  yield from bps.abs_set(smargon.omega, omega, group=group)
109
109
  if wait:
110
110
  yield from bps.wait(group)
@@ -1,7 +1,7 @@
1
1
  from bluesky import plan_stubs as bps
2
2
  from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
3
3
 
4
- from mx_bluesky.hyperion.log import LOGGER
4
+ from mx_bluesky.common.utils.log import LOGGER
5
5
 
6
6
 
7
7
  def set_detector_z_position(
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import bluesky.plan_stubs as bps
4
4
  from dodal.devices.aperturescatterguard import ApertureScatterguard
5
- from dodal.devices.attenuator import Attenuator
5
+ from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
6
6
  from dodal.devices.dcm import DCM
7
7
  from dodal.devices.eiger import EigerDetector
8
8
  from dodal.devices.flux import Flux
@@ -11,7 +11,7 @@ from dodal.devices.smargon import Smargon
11
11
  from dodal.devices.synchrotron import Synchrotron
12
12
  from dodal.devices.undulator import Undulator
13
13
 
14
- from mx_bluesky.hyperion.log import LOGGER
14
+ from mx_bluesky.common.utils.log import LOGGER
15
15
  from mx_bluesky.hyperion.parameters.constants import CONST
16
16
 
17
17
 
@@ -39,7 +39,7 @@ def read_hardware_pre_collection(
39
39
 
40
40
  def read_hardware_during_collection(
41
41
  aperture_scatterguard: ApertureScatterguard,
42
- attenuator: Attenuator,
42
+ attenuator: BinaryFilterAttenuator,
43
43
  flux: Flux,
44
44
  dcm: DCM,
45
45
  detector: EigerDetector,
@@ -7,6 +7,7 @@ import bluesky.plan_stubs as bps
7
7
  from bluesky.utils import MsgGenerator
8
8
  from dodal.common.beamlines.beamline_utils import get_path_provider
9
9
  from dodal.devices.fast_grid_scan import PandAGridScanParams
10
+ from dodal.devices.smargon import Smargon
10
11
  from ophyd_async.core import load_device
11
12
  from ophyd_async.fastcs.panda import (
12
13
  HDFPanda,
@@ -15,7 +16,7 @@ from ophyd_async.fastcs.panda import (
15
16
  )
16
17
 
17
18
  import mx_bluesky.hyperion.resources.panda as panda_resource
18
- from mx_bluesky.hyperion.log import LOGGER
19
+ from mx_bluesky.common.utils.log import LOGGER
19
20
 
20
21
  MM_TO_ENCODER_COUNTS = 200000
21
22
  GENERAL_TIMEOUT = 60
@@ -114,7 +115,7 @@ def _get_seq_table(
114
115
  def setup_panda_for_flyscan(
115
116
  panda: HDFPanda,
116
117
  parameters: PandAGridScanParams,
117
- initial_x: float,
118
+ smargon: Smargon,
118
119
  exposure_time_s: float,
119
120
  time_between_x_steps_ms: float,
120
121
  sample_velocity_mm_per_s: float,
@@ -127,7 +128,7 @@ def setup_panda_for_flyscan(
127
128
  Args:
128
129
  panda (HDFPanda): The PandA Ophyd device
129
130
  parameters (PandAGridScanParams): Grid parameters
130
- initial_x (float): Motor positions at time of PandA setup
131
+ smargon (Smargon): The Smargon Ophyd device
131
132
  exposure_time_s (float): Detector exposure time per trigger
132
133
  time_between_x_steps_ms (float): Time, in ms, between each trigger. Equal to deadtime + exposure time
133
134
  sample_velocity_mm_per_s (float): Velocity of the sample in mm/s = x_step_size_mm * 1000 /
@@ -149,13 +150,29 @@ def setup_panda_for_flyscan(
149
150
  ) as config_yaml_path:
150
151
  yield from load_device(panda, str(config_yaml_path))
151
152
 
152
- # Home the PandA X encoder using current motor position
153
+ initial_x = yield from bps.rd(smargon.x.user_readback)
154
+ initial_y = yield from bps.rd(smargon.y.user_readback)
155
+ initial_z = yield from bps.rd(smargon.z.user_readback)
156
+
157
+ # Home the PandA X, Y, and Z encoders using current motor position
153
158
  yield from bps.abs_set(
154
159
  panda.inenc[1].setp, # type: ignore
155
160
  initial_x * MM_TO_ENCODER_COUNTS,
156
161
  wait=True,
157
162
  )
158
163
 
164
+ yield from bps.abs_set(
165
+ panda.inenc[2].setp, # type: ignore
166
+ initial_y * MM_TO_ENCODER_COUNTS,
167
+ wait=True,
168
+ )
169
+
170
+ yield from bps.abs_set(
171
+ panda.inenc[3].setp, # type: ignore
172
+ initial_z * MM_TO_ENCODER_COUNTS,
173
+ wait=True,
174
+ )
175
+
159
176
  yield from bps.abs_set(panda.pulse[1].width, exposure_time_s, group="panda-config")
160
177
 
161
178
  exposure_distance_mm = sample_velocity_mm_per_s * exposure_time_s
@@ -4,29 +4,19 @@ from functools import wraps
4
4
  import bluesky.plan_stubs as bps
5
5
  import bluesky.preprocessors as bpp
6
6
  from bluesky.utils import MsgGenerator
7
- from dodal.devices.zebra import (
8
- AUTO_SHUTTER_GATE,
9
- AUTO_SHUTTER_INPUT_1,
10
- AUTO_SHUTTER_INPUT_2,
11
- DISCONNECT,
12
- IN1_TTL,
13
- IN3_TTL,
14
- IN4_TTL,
15
- PC_GATE,
16
- PC_PULSE,
17
- SOFT_IN1,
18
- TTL_DETECTOR,
19
- TTL_PANDA,
20
- TTL_XSPRESS3,
7
+ from dodal.devices.zebra.zebra import (
21
8
  ArmDemand,
22
9
  EncEnum,
23
10
  I03Axes,
24
11
  RotationDirection,
25
12
  Zebra,
26
13
  )
27
- from dodal.devices.zebra_controlled_shutter import ZebraShutter, ZebraShutterControl
14
+ from dodal.devices.zebra.zebra_controlled_shutter import (
15
+ ZebraShutter,
16
+ ZebraShutterControl,
17
+ )
28
18
 
29
- from mx_bluesky.hyperion.log import LOGGER
19
+ from mx_bluesky.common.utils.log import LOGGER
30
20
 
31
21
  ZEBRA_STATUS_TIMEOUT = 30
32
22
 
@@ -79,10 +69,9 @@ def set_shutter_auto_input(zebra: Zebra, input: int, group="set_shutter_trigger"
79
69
  Zebra's AND2 gate for this input. ZebraShutter control mode must be in auto for this input to take control
80
70
 
81
71
  For more details see the ZebraShutter device."""
82
- auto_shutter_control = zebra.logic_gates.and_gates[AUTO_SHUTTER_GATE]
83
- yield from bps.abs_set(
84
- auto_shutter_control.sources[AUTO_SHUTTER_INPUT_2], input, group
85
- )
72
+ auto_gate = zebra.mapping.AND_GATE_FOR_AUTO_SHUTTER
73
+ auto_shutter_control = zebra.logic_gates.and_gates[auto_gate]
74
+ yield from bps.abs_set(auto_shutter_control.sources[2], input, group)
86
75
 
87
76
 
88
77
  def configure_zebra_and_shutter_for_auto_shutter(
@@ -102,11 +91,13 @@ def configure_zebra_and_shutter_for_auto_shutter(
102
91
  zebra_shutter.control_mode, ZebraShutterControl.AUTO, group=group
103
92
  )
104
93
 
94
+ auto_gate = zebra.mapping.AND_GATE_FOR_AUTO_SHUTTER
95
+
105
96
  # Set first input of AND2 gate to SOFT_IN1, which is high when shutter is in auto mode
106
97
  # Note the Zebra should ALWAYS be setup this way. See https://github.com/DiamondLightSource/mx-bluesky/issues/551
107
98
  yield from bps.abs_set(
108
- zebra.logic_gates.and_gates[AUTO_SHUTTER_GATE].sources[AUTO_SHUTTER_INPUT_1],
109
- SOFT_IN1,
99
+ zebra.logic_gates.and_gates[auto_gate].sources[1],
100
+ zebra.mapping.sources.SOFT_IN1,
110
101
  group=group,
111
102
  )
112
103
 
@@ -147,6 +138,7 @@ def setup_zebra_for_rotation(
147
138
  group: A name for the group of statuses generated
148
139
  wait: Block until all the settings have completed
149
140
  """
141
+
150
142
  if not isinstance(direction, RotationDirection):
151
143
  raise ValueError(
152
144
  "Disallowed rotation direction provided to Zebra setup plan. "
@@ -171,13 +163,23 @@ def setup_zebra_for_rotation(
171
163
  yield from bps.abs_set(zebra.pc.gate_trigger, axis.value, group=group)
172
164
  # Set shutter to automatic and to trigger via PC_GATE
173
165
  yield from configure_zebra_and_shutter_for_auto_shutter(
174
- zebra, zebra_shutter, PC_GATE, group=group
166
+ zebra, zebra_shutter, zebra.mapping.sources.PC_GATE, group=group
175
167
  )
176
168
  # Trigger the detector with a pulse
177
- yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], PC_PULSE, group=group)
169
+ yield from bps.abs_set(
170
+ zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR],
171
+ zebra.mapping.sources.PC_PULSE,
172
+ group=group,
173
+ )
178
174
  # Don't use the fluorescence detector
179
- yield from bps.abs_set(zebra.output.out_pvs[TTL_XSPRESS3], DISCONNECT, group=group)
180
- yield from bps.abs_set(zebra.output.pulse_1.input, DISCONNECT, group=group)
175
+ yield from bps.abs_set(
176
+ zebra.output.out_pvs[zebra.mapping.outputs.TTL_XSPRESS3],
177
+ zebra.mapping.sources.DISCONNECT,
178
+ group=group,
179
+ )
180
+ yield from bps.abs_set(
181
+ zebra.output.pulse_1.input, zebra.mapping.sources.DISCONNECT, group=group
182
+ )
181
183
  LOGGER.info(f"ZEBRA SETUP: END - {'' if wait else 'not'} waiting for completion")
182
184
  if wait:
183
185
  yield from bps.wait(group, timeout=ZEBRA_STATUS_TIMEOUT)
@@ -192,12 +194,22 @@ def setup_zebra_for_gridscan(
192
194
  ):
193
195
  # Set shutter to automatic and to trigger via motion controller GPIO signal (IN4_TTL)
194
196
  yield from configure_zebra_and_shutter_for_auto_shutter(
195
- zebra, zebra_shutter, IN4_TTL, group=group
197
+ zebra, zebra_shutter, zebra.mapping.sources.IN4_TTL, group=group
196
198
  )
197
199
 
198
- yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], IN3_TTL, group=group)
199
- yield from bps.abs_set(zebra.output.out_pvs[TTL_XSPRESS3], DISCONNECT, group=group)
200
- yield from bps.abs_set(zebra.output.pulse_1.input, DISCONNECT, group=group)
200
+ yield from bps.abs_set(
201
+ zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR],
202
+ zebra.mapping.sources.IN3_TTL,
203
+ group=group,
204
+ )
205
+ yield from bps.abs_set(
206
+ zebra.output.out_pvs[zebra.mapping.outputs.TTL_XSPRESS3],
207
+ zebra.mapping.sources.DISCONNECT,
208
+ group=group,
209
+ )
210
+ yield from bps.abs_set(
211
+ zebra.output.pulse_1.input, zebra.mapping.sources.DISCONNECT, group=group
212
+ )
201
213
 
202
214
  if wait:
203
215
  yield from bps.wait(group, timeout=ZEBRA_STATUS_TIMEOUT)
@@ -210,11 +222,15 @@ def tidy_up_zebra_after_gridscan(
210
222
  group="tidy_up_zebra_after_gridscan",
211
223
  wait=True,
212
224
  ) -> MsgGenerator:
213
- yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], PC_PULSE, group=group)
225
+ yield from bps.abs_set(
226
+ zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR],
227
+ zebra.mapping.sources.PC_PULSE,
228
+ group=group,
229
+ )
214
230
  yield from bps.abs_set(
215
231
  zebra_shutter.control_mode, ZebraShutterControl.MANUAL, group=group
216
232
  )
217
- yield from set_shutter_auto_input(zebra, PC_GATE, group=group)
233
+ yield from set_shutter_auto_input(zebra, zebra.mapping.sources.PC_GATE, group=group)
218
234
 
219
235
  if wait:
220
236
  yield from bps.wait(group, timeout=ZEBRA_STATUS_TIMEOUT)
@@ -228,17 +244,27 @@ def setup_zebra_for_panda_flyscan(
228
244
  wait=True,
229
245
  ):
230
246
  # Forwards eiger trigger signal from panda
231
- yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], IN1_TTL, group=group)
247
+ yield from bps.abs_set(
248
+ zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR],
249
+ zebra.mapping.sources.IN1_TTL,
250
+ group=group,
251
+ )
232
252
 
233
253
  # Set shutter to automatic and to trigger via motion controller GPIO signal (IN4_TTL)
234
254
  yield from configure_zebra_and_shutter_for_auto_shutter(
235
- zebra, zebra_shutter, IN4_TTL, group=group
255
+ zebra, zebra_shutter, zebra.mapping.sources.IN4_TTL, group=group
236
256
  )
237
257
 
238
- yield from bps.abs_set(zebra.output.out_pvs[TTL_XSPRESS3], DISCONNECT, group=group)
258
+ yield from bps.abs_set(
259
+ zebra.output.out_pvs[zebra.mapping.outputs.TTL_XSPRESS3],
260
+ zebra.mapping.sources.DISCONNECT,
261
+ group=group,
262
+ )
239
263
 
240
264
  yield from bps.abs_set(
241
- zebra.output.out_pvs[TTL_PANDA], IN3_TTL, group=group
265
+ zebra.output.out_pvs[zebra.mapping.outputs.TTL_PANDA],
266
+ zebra.mapping.sources.IN3_TTL,
267
+ group=group,
242
268
  ) # Tells panda that motion is beginning/changing direction
243
269
 
244
270
  if wait:
@@ -2,17 +2,17 @@ import numpy as np
2
2
  from bluesky import plan_stubs as bps
3
3
  from dodal.devices.smargon import Smargon
4
4
 
5
- from mx_bluesky.hyperion.exceptions import WarningException
5
+ from mx_bluesky.common.utils.exceptions import SampleException
6
6
 
7
7
 
8
8
  def move_smargon_warn_on_out_of_range(
9
9
  smargon: Smargon, position: np.ndarray | list[float] | tuple[float, float, float]
10
10
  ):
11
- """Throws a WarningException if the specified position is out of range for the
11
+ """Throws a SampleException if the specified position is out of range for the
12
12
  smargon. Otherwise moves to that position."""
13
13
  limits = yield from smargon.get_xyz_limits()
14
14
  if not limits.position_valid(position):
15
- raise WarningException(
15
+ raise SampleException(
16
16
  "Pin tip centring failed - pin too long/short/bent and out of range"
17
17
  )
18
18
  yield from bps.mv(
@@ -9,7 +9,9 @@ from dodal.devices.detector import (
9
9
  )
10
10
  from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
11
11
  from dodal.devices.eiger import EigerDetector
12
+ from dodal.devices.i03.beamstop import Beamstop
12
13
 
14
+ from mx_bluesky.hyperion.device_setup_plans.check_beamstop import check_beamstop
13
15
  from mx_bluesky.hyperion.device_setup_plans.position_detector import (
14
16
  set_detector_z_position,
15
17
  set_shutter,
@@ -24,6 +26,7 @@ def fill_in_energy_if_not_supplied(dcm: DCM, detector_params: DetectorParams):
24
26
 
25
27
 
26
28
  def start_preparing_data_collection_then_do_plan(
29
+ beamstop: Beamstop,
27
30
  eiger: EigerDetector,
28
31
  detector_motion: DetectorMotion,
29
32
  detector_distance_mm: float | None,
@@ -49,6 +52,7 @@ def start_preparing_data_collection_then_do_plan(
49
52
  yield from set_shutter(detector_motion, ShutterState.OPEN, group)
50
53
  yield from plan_to_run
51
54
 
55
+ yield from check_beamstop(beamstop)
52
56
  yield from bpp.contingency_wrapper(
53
57
  wrapped_plan(),
54
58
  except_plan=lambda e: (yield from bps.stop(eiger)), # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
@@ -1,15 +1,15 @@
1
1
  from bluesky import plan_stubs as bps
2
2
  from bluesky.preprocessors import finalize_wrapper
3
3
  from bluesky.utils import make_decorator
4
- from dodal.devices.attenuator import Attenuator
4
+ from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
5
5
  from dodal.devices.xbpm_feedback import Pause, XBPMFeedback
6
6
 
7
- from mx_bluesky.hyperion.log import LOGGER
7
+ from mx_bluesky.common.utils.log import LOGGER
8
8
 
9
9
 
10
10
  def _check_and_pause_feedback(
11
11
  xbpm_feedback: XBPMFeedback,
12
- attenuator: Attenuator,
12
+ attenuator: BinaryFilterAttenuator,
13
13
  desired_transmission_fraction: float,
14
14
  ):
15
15
  """Checks that the xbpm is in position before then turning it off and setting a new
@@ -18,7 +18,7 @@ def _check_and_pause_feedback(
18
18
  Args:
19
19
  xbpm_feedback (XBPMFeedback): The XBPM device that is responsible for keeping
20
20
  the beam in position
21
- attenuator (Attenuator): The attenuator used to set transmission
21
+ attenuator (BinaryFilterAttenuator): The attenuator used to set transmission
22
22
  desired_transmission_fraction (float): The desired transmission to set after
23
23
  turning XBPM feedback off.
24
24
 
@@ -34,7 +34,7 @@ def _check_and_pause_feedback(
34
34
 
35
35
 
36
36
  def _unpause_xbpm_feedback_and_set_transmission_to_1(
37
- xbpm_feedback: XBPMFeedback, attenuator: Attenuator
37
+ xbpm_feedback: XBPMFeedback, attenuator: BinaryFilterAttenuator
38
38
  ):
39
39
  """Turns the XBPM feedback back on and sets transmission to 1 so that it keeps the
40
40
  beam aligned whilst not collecting.
@@ -42,7 +42,7 @@ def _unpause_xbpm_feedback_and_set_transmission_to_1(
42
42
  Args:
43
43
  xbpm_feedback (XBPMFeedback): The XBPM device that is responsible for keeping
44
44
  the beam in position
45
- attenuator (Attenuator): The attenuator used to set transmission
45
+ attenuator (BinaryFilterAttenuator): The attenuator used to set transmission
46
46
  """
47
47
  yield from bps.mv(xbpm_feedback.pause_feedback, Pause.RUN, attenuator, 1.0) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
48
48
 
@@ -50,7 +50,7 @@ def _unpause_xbpm_feedback_and_set_transmission_to_1(
50
50
  def transmission_and_xbpm_feedback_for_collection_wrapper(
51
51
  plan,
52
52
  xbpm_feedback: XBPMFeedback,
53
- attenuator: Attenuator,
53
+ attenuator: BinaryFilterAttenuator,
54
54
  desired_transmission_fraction: float,
55
55
  ):
56
56
  """Sets the transmission for the data collection, ensuring the xbpm feedback is valid
@@ -70,7 +70,7 @@ def transmission_and_xbpm_feedback_for_collection_wrapper(
70
70
  plan: The plan performing the data collection
71
71
  xbpm_feedback (XBPMFeedback): The XBPM device that is responsible for keeping
72
72
  the beam in position
73
- attenuator (Attenuator): The attenuator used to set transmission
73
+ attenuator (BinaryFilterAttenuator): The attenuator used to set transmission
74
74
  desired_transmission_fraction (float): The desired transmission for the collection
75
75
  """
76
76
 
@@ -4,18 +4,18 @@ import numpy
4
4
  from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
5
5
  from dodal.devices.smargon import Smargon, StubPosition
6
6
 
7
+ from mx_bluesky.common.utils.log import LOGGER
7
8
  from mx_bluesky.common.utils.tracing import TRACER
8
9
  from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import move_x_y_z
9
10
  from mx_bluesky.hyperion.experiment_plans.common.xrc_result import XRayCentreResult
10
- from mx_bluesky.hyperion.log import LOGGER
11
- from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan
11
+ from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan
12
12
 
13
13
 
14
14
  def change_aperture_then_move_to_xtal(
15
15
  best_hit: XRayCentreResult,
16
16
  smargon: Smargon,
17
17
  aperture_scatterguard: ApertureScatterguard,
18
- parameters: HyperionThreeDGridScan | None = None,
18
+ parameters: HyperionSpecifiedThreeDGridScan | None = None,
19
19
  ):
20
20
  """For the given x-ray centring result,
21
21
  * Change the aperture so that the beam size is comparable to the crystal size
@@ -26,8 +26,9 @@ def change_aperture_then_move_to_xtal(
26
26
  best_hit.bounding_box_mm[1] - best_hit.bounding_box_mm[0]
27
27
  )
28
28
  with TRACER.start_span("change_aperture"):
29
- yield from _set_aperture_for_bbox_mm(
30
- aperture_scatterguard, bounding_box_size
29
+ yield from set_aperture_for_bbox_mm(
30
+ aperture_scatterguard,
31
+ bounding_box_size,
31
32
  )
32
33
  else:
33
34
  LOGGER.warning("No bounding box size received")
@@ -49,25 +50,35 @@ def change_aperture_then_move_to_xtal(
49
50
  )
50
51
 
51
52
 
52
- def _set_aperture_for_bbox_mm(
53
- aperture_device: ApertureScatterguard, bbox_size_mm: list[float] | numpy.ndarray
53
+ def set_aperture_for_bbox_mm(
54
+ aperture_device: ApertureScatterguard,
55
+ bbox_size_mm: list[float] | numpy.ndarray,
54
56
  ):
55
- # TODO confirm correction factor see https://github.com/DiamondLightSource/mx-bluesky/issues/618
56
- ASSUMED_BOX_SIZE_MM = 0.020
57
- bbox_size_boxes = [round(mm / ASSUMED_BOX_SIZE_MM) for mm in bbox_size_mm]
58
- yield from set_aperture_for_bbox_size(aperture_device, bbox_size_boxes)
57
+ """Sets aperture size based on bbox_size.
59
58
 
59
+ This function determines the aperture size needed to accomodate the bounding box
60
+ of a crystal. The x-axis length of the bounding box is used, setting the aperture
61
+ to Medium if this is less than 50um, and Large otherwise.
62
+
63
+ Args:
64
+ aperture_device: The aperture scatter gaurd device we are controlling.
65
+ bbox_size_mm: The [x,y,z] lengths, in mm, of a bounding box
66
+ containing a crystal. This describes (in no particular order):
67
+ * The maximum width a crystal occupies
68
+ * The maximum height a crystal occupies
69
+ * The maximum depth a crystal occupies
70
+ constructing a three dimensional cuboid, completely encapsulating the crystal.
71
+
72
+ Yields:
73
+ Iterator[MsgGenerator]
74
+ """
60
75
 
61
- def set_aperture_for_bbox_size(
62
- aperture_device: ApertureScatterguard,
63
- bbox_size: list[int] | numpy.ndarray,
64
- ):
65
76
  # bbox_size is [x,y,z], for i03 we only care about x
66
77
  new_selected_aperture = (
67
- ApertureValue.MEDIUM if bbox_size[0] < 2 else ApertureValue.LARGE
78
+ ApertureValue.MEDIUM if bbox_size_mm[0] < 0.05 else ApertureValue.LARGE
68
79
  )
69
80
  LOGGER.info(
70
- f"Setting aperture to {new_selected_aperture} based on bounding box size {bbox_size}."
81
+ f"Setting aperture to {new_selected_aperture} based on bounding box size {bbox_size_mm}."
71
82
  )
72
83
 
73
84
  @bpp.set_run_key_decorator("change_aperture")
@@ -14,7 +14,16 @@ from mx_bluesky.common.parameters.components import (
14
14
 
15
15
  @dataclasses.dataclass
16
16
  class XRayCentreResult:
17
- """Represents information about a hit from an X-ray centring."""
17
+ """
18
+ Represents information about a hit from an X-ray centring.
19
+
20
+ Attributes:
21
+ centre_of_mass_mm: coordinates in mm of the centre of mass
22
+ bounding_box_mm: coordinates in mm of opposite corners of the bounding box
23
+ containing the crystal
24
+ max_count: The maximum spot count encountered in any one grid box in the crystal
25
+ total_count: The total count across all boxes in the crystal.
26
+ """
18
27
 
19
28
  centre_of_mass_mm: np.ndarray
20
29
  bounding_box_mm: tuple[np.ndarray, np.ndarray]