mx-bluesky 1.5.11__py3-none-any.whl → 1.5.12__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 (85) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/aithre_lasershaping/experiment_plans/__init__.py +0 -0
  3. mx_bluesky/beamlines/aithre_lasershaping/experiment_plans/robot_load_plan.py +198 -0
  4. mx_bluesky/beamlines/aithre_lasershaping/parameters/__init__.py +0 -0
  5. mx_bluesky/beamlines/aithre_lasershaping/parameters/constants.py +17 -0
  6. mx_bluesky/beamlines/aithre_lasershaping/parameters/robot_load_parameters.py +13 -0
  7. mx_bluesky/beamlines/aithre_lasershaping/pin_tip_centring.py +31 -0
  8. mx_bluesky/beamlines/aithre_lasershaping/robot_load.py +80 -0
  9. mx_bluesky/beamlines/i04/__init__.py +6 -2
  10. mx_bluesky/beamlines/i04/callbacks/murko_callback.py +27 -12
  11. mx_bluesky/beamlines/i04/experiment_plans/i04_grid_detect_then_xray_centre_plan.py +87 -13
  12. mx_bluesky/beamlines/i04/external_interaction/__init__.py +0 -0
  13. mx_bluesky/beamlines/i04/external_interaction/config_server.py +15 -0
  14. mx_bluesky/beamlines/i04/oav_centering_plans/__init__.py +0 -0
  15. mx_bluesky/beamlines/i04/oav_centering_plans/oav_imaging.py +115 -0
  16. mx_bluesky/beamlines/i04/parameters/__init__.py +0 -0
  17. mx_bluesky/beamlines/i04/parameters/constants.py +21 -0
  18. mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +24 -1
  19. mx_bluesky/beamlines/i04/thawing_plan.py +147 -152
  20. mx_bluesky/beamlines/i24/serial/dcid.py +4 -5
  21. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_extruder_collect_py3v2.py +5 -2
  22. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/CustomChip_py3v1.edl +11 -11
  23. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DetStage.edl +3 -3
  24. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +142 -142
  25. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/MappingLite-oxford_py3v1.edl +135 -135
  26. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/PMAC_Command.edl +8 -8
  27. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +13 -13
  28. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_chip_collect_py3v1.py +7 -4
  29. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_chip_manager_py3v1.py +35 -32
  30. mx_bluesky/beamlines/i24/serial/parameters/utils.py +5 -5
  31. mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +113 -306
  32. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +8 -2
  33. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +1 -1
  34. mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +1 -1
  35. mx_bluesky/beamlines/i24/serial/web_gui_plans/oav_plans.py +64 -0
  36. mx_bluesky/{hyperion/device_setup_plans/smargon.py → common/device_setup_plans/gonio.py} +9 -6
  37. mx_bluesky/common/device_setup_plans/manipulate_sample.py +8 -1
  38. mx_bluesky/common/device_setup_plans/robot_load_unload.py +1 -1
  39. mx_bluesky/common/device_setup_plans/setup_oav.py +8 -0
  40. mx_bluesky/common/device_setup_plans/setup_zebra_and_shutter.py +0 -5
  41. mx_bluesky/common/device_setup_plans/xbpm_feedback.py +8 -1
  42. mx_bluesky/common/experiment_plans/beamstop_check.py +229 -0
  43. mx_bluesky/common/experiment_plans/common_flyscan_xray_centre_plan.py +2 -0
  44. mx_bluesky/common/experiment_plans/inner_plans/read_hardware.py +5 -2
  45. mx_bluesky/common/experiment_plans/oav_snapshot_plan.py +0 -1
  46. mx_bluesky/{hyperion → common}/experiment_plans/pin_tip_centring_plan.py +20 -21
  47. mx_bluesky/common/external_interaction/callbacks/common/grid_detection_callback.py +5 -0
  48. mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +10 -12
  49. mx_bluesky/common/external_interaction/callbacks/common/ispyb_mapping.py +3 -5
  50. mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +5 -5
  51. mx_bluesky/common/external_interaction/config_server.py +2 -2
  52. mx_bluesky/common/external_interaction/ispyb/data_model.py +11 -4
  53. mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +159 -2
  54. mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +76 -166
  55. mx_bluesky/common/external_interaction/ispyb/ispyb_utils.py +0 -14
  56. mx_bluesky/common/parameters/components.py +1 -0
  57. mx_bluesky/common/parameters/constants.py +3 -2
  58. mx_bluesky/common/parameters/device_composites.py +4 -2
  59. mx_bluesky/common/utils/exceptions.py +15 -0
  60. mx_bluesky/common/utils/log.py +9 -0
  61. mx_bluesky/common/utils/utils.py +48 -0
  62. mx_bluesky/hyperion/__main__.py +3 -13
  63. mx_bluesky/hyperion/baton_handler.py +23 -6
  64. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +5 -6
  65. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +3 -10
  66. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +4 -2
  67. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +8 -2
  68. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
  69. mx_bluesky/hyperion/experiment_plans/udc_default_state.py +160 -0
  70. mx_bluesky/hyperion/external_interaction/agamemnon.py +1 -1
  71. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +2 -2
  72. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +1 -0
  73. mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +1 -4
  74. mx_bluesky/hyperion/external_interaction/config_server.py +5 -5
  75. mx_bluesky/hyperion/parameters/constants.py +10 -3
  76. mx_bluesky/hyperion/parameters/device_composites.py +2 -2
  77. mx_bluesky/hyperion/parameters/robot_load.py +1 -9
  78. {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/METADATA +6 -5
  79. {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/RECORD +83 -69
  80. mx_bluesky/common/experiment_plans/inner_plans/udc_default_state.py +0 -86
  81. mx_bluesky/common/external_interaction/callbacks/common/logging_callback.py +0 -29
  82. {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/WHEEL +0 -0
  83. {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/entry_points.txt +0 -0
  84. {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/licenses/LICENSE +0 -0
  85. {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/top_level.txt +0 -0
@@ -6,7 +6,9 @@ from mx_bluesky.common.utils.log import LOGGER
6
6
 
7
7
 
8
8
  def unpause_xbpm_feedback_and_set_transmission_to_1(
9
- xbpm_feedback: XBPMFeedback, attenuator: BinaryFilterAttenuator
9
+ xbpm_feedback: XBPMFeedback,
10
+ attenuator: BinaryFilterAttenuator,
11
+ timeout_for_stable: float = 0,
10
12
  ):
11
13
  """Turns the XBPM feedback back on and sets transmission to 1 so that it keeps the
12
14
  beam aligned whilst not collecting.
@@ -15,8 +17,13 @@ def unpause_xbpm_feedback_and_set_transmission_to_1(
15
17
  xbpm_feedback (XBPMFeedback): The XBPM device that is responsible for keeping
16
18
  the beam in position
17
19
  attenuator (BinaryFilterAttenuator): The attenuator used to set transmission
20
+ timeout_for_stable: If specified and non-zero, specifies the time in seconds to wait for
21
+ feedback to stabilise, otherwise we do not wait.
18
22
  """
19
23
  yield from bps.mv(xbpm_feedback.pause_feedback, Pause.RUN, attenuator, 1.0)
24
+ if timeout_for_stable:
25
+ yield from bps.trigger(xbpm_feedback, group="feedback")
26
+ yield from bps.wait(group="feedback", timeout=timeout_for_stable)
20
27
 
21
28
 
22
29
  def check_and_pause_feedback(
@@ -0,0 +1,229 @@
1
+ import pydantic
2
+ from bluesky import plan_stubs as bps
3
+ from bluesky.utils import MsgGenerator
4
+ from dodal.common.beamlines.beamline_parameters import GDABeamlineParameters
5
+ from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
6
+ from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
7
+ from dodal.devices.backlight import Backlight
8
+ from dodal.devices.baton import Baton
9
+ from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
10
+ from dodal.devices.ipin import IPin, IPinGain
11
+ from dodal.devices.mx_phase1.beamstop import Beamstop, BeamstopPositions
12
+ from dodal.devices.xbpm_feedback import XBPMFeedback
13
+ from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter, ZebraShutterState
14
+ from ophyd_async.core import InOut
15
+
16
+ from mx_bluesky.common.device_setup_plans.xbpm_feedback import (
17
+ unpause_xbpm_feedback_and_set_transmission_to_1,
18
+ )
19
+ from mx_bluesky.common.utils.exceptions import BeamlineCheckFailureError
20
+ from mx_bluesky.common.utils.log import LOGGER
21
+
22
+ _GROUP_PRE_BEAMSTOP_OUT_CHECK = "pre_background_check"
23
+ _GROUP_POST_BEAMSTOP_OUT_CHECK = "post_background_check"
24
+ _PARAM_IPIN_THRESHOLD = "ipin_threshold"
25
+
26
+ _FEEDBACK_TIMEOUT_S = 10
27
+
28
+
29
+ @pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
30
+ class BeamstopCheckDevices:
31
+ aperture_scatterguard: ApertureScatterguard
32
+ attenuator: BinaryFilterAttenuator
33
+ backlight: Backlight
34
+ baton: Baton
35
+ beamstop: Beamstop
36
+ detector_motion: DetectorMotion
37
+ ipin: IPin
38
+ sample_shutter: ZebraShutter
39
+ xbpm_feedback: XBPMFeedback
40
+
41
+
42
+ class SampleCurrentBelowThresholdError(BeamlineCheckFailureError): ...
43
+
44
+
45
+ class BeamstopNotInPositionError(BeamlineCheckFailureError): ...
46
+
47
+
48
+ class BeamObstructedError(BeamlineCheckFailureError): ...
49
+
50
+
51
+ def move_beamstop_in_and_verify_using_diode(
52
+ devices: BeamstopCheckDevices,
53
+ beamline_parameters: GDABeamlineParameters,
54
+ detector_min_z_mm: float,
55
+ detector_max_z_mm: float,
56
+ ) -> MsgGenerator:
57
+ """
58
+ Move the beamstop into the data collection position, checking the beam current
59
+ via the diode on the detector shutter, first with the beamstop out and then with
60
+ the beamstop in.
61
+ These checks aim to ensure that
62
+ * The beam is not obstructed by something other than the beamstop
63
+ * The beamstop has been successfully moved and is intercepting the beam
64
+
65
+ As a side-effect, this plan also does the following things:
66
+ * Move the detector z-axis in range
67
+ * Move the backlight out
68
+ * Unpauses feedback
69
+ * Sets xmission to 100%
70
+ * Sets IPin gain to 10^4 low noise
71
+ * Moves aperture scatterguard to OUT_OF_BEAM if it is currently in beam
72
+
73
+ Implementation note:
74
+ Some checks are repeated here such as closing the sample shutter, so that at a
75
+ future point this plan may be run independently of the udc default state script
76
+ if desired.
77
+ Note on commissioning mode:
78
+ When commissioning mode is enabled, the beamstop check will execute normally except
79
+ where it expects beam to be present, the absence of beam will be ignored.
80
+ Args:
81
+ devices: The device composite containing the necessary devices
82
+ beamline_parameters: A mapping containing the beamlineParameters
83
+ detector_min_z_mm: Detector minimum distance at which beamstop is effective
84
+ detector_max_z_mm: Detector maximum distance at which beamstop is effective
85
+ Raises:
86
+ SampleCurrentBelowThresholdError: If we do not have sufficient sample current to perform
87
+ the check.
88
+ BeamstopNotInPositionError: If the ipin current is too high, indicating that the
89
+ beamstop is not in the correct position.
90
+ BeamObstructedError: If the ipin current is too low after the first check
91
+ with the beamstop out, indicating a likely obstruction.
92
+ """
93
+ LOGGER.info("Performing beamstop check...")
94
+ commissioning_mode_enabled = yield from bps.rd(devices.baton.commissioning)
95
+ beamstop_threshold_uA = beamline_parameters[_PARAM_IPIN_THRESHOLD] # noqa: N806
96
+
97
+ yield from _start_moving_detector_if_needed(
98
+ devices, detector_min_z_mm, detector_max_z_mm, _GROUP_POST_BEAMSTOP_OUT_CHECK
99
+ )
100
+ yield from _pre_beamstop_out_check_actions(devices)
101
+ yield from _beamstop_out_check(
102
+ devices, beamstop_threshold_uA, commissioning_mode_enabled
103
+ )
104
+ yield from _post_beamstop_out_check_actions(devices, _GROUP_POST_BEAMSTOP_OUT_CHECK)
105
+ yield from _beamstop_in_check(devices, beamstop_threshold_uA)
106
+
107
+
108
+ def _pre_beamstop_out_check_actions(devices: BeamstopCheckDevices):
109
+ # Re-verify that the sample shutter is closed
110
+ yield from bps.abs_set(devices.sample_shutter, ZebraShutterState.CLOSE, wait=True)
111
+ LOGGER.info("Unpausing feedback, transmission to 100%, wait for feedback stable...")
112
+ try:
113
+ yield from unpause_xbpm_feedback_and_set_transmission_to_1(
114
+ devices.xbpm_feedback,
115
+ devices.attenuator,
116
+ _FEEDBACK_TIMEOUT_S,
117
+ )
118
+ except TimeoutError as e:
119
+ raise SampleCurrentBelowThresholdError(
120
+ "Unable to perform beamstop check - xbpm feedback did not become stable "
121
+ " - check if beam present?"
122
+ ) from e
123
+
124
+ yield from bps.abs_set(
125
+ devices.backlight, InOut.OUT, group=_GROUP_PRE_BEAMSTOP_OUT_CHECK
126
+ )
127
+
128
+ yield from bps.abs_set(
129
+ devices.aperture_scatterguard.selected_aperture,
130
+ ApertureValue.OUT_OF_BEAM,
131
+ group=_GROUP_PRE_BEAMSTOP_OUT_CHECK,
132
+ )
133
+
134
+ yield from bps.abs_set(
135
+ devices.ipin.gain,
136
+ IPinGain.GAIN_10E4_LOW_NOISE,
137
+ group=_GROUP_PRE_BEAMSTOP_OUT_CHECK,
138
+ )
139
+ yield from bps.abs_set(
140
+ devices.detector_motion.shutter,
141
+ ShutterState.CLOSED,
142
+ group=_GROUP_PRE_BEAMSTOP_OUT_CHECK,
143
+ )
144
+ yield from bps.abs_set(
145
+ devices.beamstop.selected_pos,
146
+ BeamstopPositions.OUT_OF_BEAM,
147
+ group=_GROUP_PRE_BEAMSTOP_OUT_CHECK,
148
+ )
149
+
150
+ LOGGER.info("Waiting for pre-background-check motions to complete...")
151
+ yield from bps.wait(group=_GROUP_PRE_BEAMSTOP_OUT_CHECK)
152
+
153
+ # Check detector shutter is closed
154
+ detector_shutter_state = yield from bps.rd(devices.detector_motion.shutter)
155
+ detector_shutter_is_closed = detector_shutter_state == ShutterState.CLOSED
156
+ if not detector_shutter_is_closed:
157
+ raise RuntimeError(
158
+ "Unable to proceed with beamstop background check, detector shutter did not close"
159
+ )
160
+
161
+
162
+ def _start_moving_detector_if_needed(
163
+ devices: BeamstopCheckDevices,
164
+ detector_min_z_mm: float,
165
+ detector_max_z_mm: float,
166
+ group: str = None,
167
+ ):
168
+ detector_current_z = yield from bps.rd(devices.detector_motion.z)
169
+ target_z = max(min(detector_current_z, detector_max_z_mm), detector_min_z_mm)
170
+ if detector_current_z != target_z:
171
+ LOGGER.info(
172
+ f"Detector distance {detector_current_z}mm outside acceptable range for diode "
173
+ f"check {detector_min_z_mm} <= z <= {detector_max_z_mm}, moving it."
174
+ )
175
+ yield from bps.abs_set(devices.detector_motion.z, target_z, group=group)
176
+
177
+
178
+ def _post_beamstop_out_check_actions(devices: BeamstopCheckDevices, group: str):
179
+ yield from bps.abs_set(
180
+ devices.beamstop.selected_pos,
181
+ BeamstopPositions.DATA_COLLECTION,
182
+ group=group,
183
+ )
184
+
185
+ LOGGER.info("Waiting for detector motion to complete...")
186
+ yield from bps.wait(group=group)
187
+
188
+
189
+ def _beamstop_out_check(
190
+ devices: BeamstopCheckDevices,
191
+ beamstop_threshold_uA: float, # noqa: N803
192
+ commissioning_mode_enabled: bool,
193
+ ):
194
+ ipin_beamstop_out_uA = yield from _check_ipin(devices) # noqa: N806
195
+
196
+ LOGGER.info(f"Beamstop out ipin = {ipin_beamstop_out_uA}uA")
197
+ if ipin_beamstop_out_uA < beamstop_threshold_uA:
198
+ msg = (
199
+ f"IPin current {ipin_beamstop_out_uA}uA below threshold "
200
+ f"{beamstop_threshold_uA} with beamstop out - check "
201
+ f"that beam is not obstructed."
202
+ )
203
+ if commissioning_mode_enabled:
204
+ LOGGER.warning(msg + " - commissioning mode enabled - ignoring this")
205
+ else:
206
+ raise BeamObstructedError(msg)
207
+
208
+
209
+ def _beamstop_in_check(devices: BeamstopCheckDevices, beamstop_threshold_uA: float): # noqa: N803
210
+ ipin_in_beam_uA = yield from _check_ipin(devices) # noqa: N806
211
+ if ipin_in_beam_uA > beamstop_threshold_uA:
212
+ raise BeamstopNotInPositionError(
213
+ f"Ipin is too high at {ipin_in_beam_uA} - check that beamstop is "
214
+ f"in the correct position."
215
+ )
216
+
217
+
218
+ def _check_ipin(devices: BeamstopCheckDevices):
219
+ try:
220
+ yield from bps.abs_set(
221
+ devices.sample_shutter, ZebraShutterState.OPEN, wait=True
222
+ )
223
+ yield from bps.sleep(1) # wait for reading to settle
224
+
225
+ return (yield from bps.rd(devices.ipin.pin_readback)) # noqa: N806
226
+ finally:
227
+ yield from bps.abs_set(
228
+ devices.sample_shutter, ZebraShutterState.CLOSE, wait=True
229
+ )
@@ -279,6 +279,8 @@ def run_gridscan(
279
279
  raise SampleError(
280
280
  "Scan invalid - gridscan not valid for detected pin position"
281
281
  ) from e
282
+ else:
283
+ raise e
282
284
 
283
285
  LOGGER.info("Waiting for arming to finish")
284
286
  yield from bps.wait(PlanGroupCheckpointConstants.GRID_READY_FOR_DC)
@@ -4,13 +4,14 @@ import bluesky.plan_stubs as bps
4
4
  from bluesky.protocols import Readable
5
5
  from dodal.devices.aperturescatterguard import ApertureScatterguard
6
6
  from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
7
+ from dodal.devices.beamsize.beamsize import BeamsizeBase
7
8
  from dodal.devices.common_dcm import DoubleCrystalMonochromator
8
9
  from dodal.devices.eiger import EigerDetector
9
10
  from dodal.devices.flux import Flux
10
11
  from dodal.devices.s4_slit_gaps import S4SlitGaps
11
12
  from dodal.devices.smargon import Smargon
12
13
  from dodal.devices.synchrotron import Synchrotron
13
- from dodal.devices.undulator import Undulator
14
+ from dodal.devices.undulator import UndulatorInKeV
14
15
 
15
16
  from mx_bluesky.common.parameters.constants import (
16
17
  DocDescriptorNames,
@@ -40,7 +41,7 @@ def read_hardware_for_zocalo(detector: EigerDetector):
40
41
 
41
42
 
42
43
  def standard_read_hardware_pre_collection(
43
- undulator: Undulator,
44
+ undulator: UndulatorInKeV,
44
45
  synchrotron: Synchrotron,
45
46
  s4_slit_gaps: S4SlitGaps,
46
47
  dcm: DoubleCrystalMonochromator,
@@ -65,6 +66,7 @@ def standard_read_hardware_during_collection(
65
66
  flux: Flux,
66
67
  dcm: DoubleCrystalMonochromator,
67
68
  detector: EigerDetector,
69
+ beamsize: BeamsizeBase,
68
70
  ):
69
71
  signals_to_read_during_collection = [
70
72
  aperture_scatterguard,
@@ -72,6 +74,7 @@ def standard_read_hardware_during_collection(
72
74
  flux.flux_reading,
73
75
  dcm.energy_in_keV,
74
76
  detector.bit_depth,
77
+ beamsize,
75
78
  ]
76
79
  yield from read_hardware_plan(
77
80
  signals_to_read_during_collection, DocDescriptorNames.HARDWARE_READ_DURING
@@ -24,7 +24,6 @@ class OavSnapshotComposite(Protocol):
24
24
  smargon: Smargon
25
25
  oav: OAV
26
26
  aperture_scatterguard: ApertureScatterguard
27
- backlight: Backlight
28
27
 
29
28
 
30
29
  def setup_beamline_for_oav(
@@ -4,7 +4,7 @@ import bluesky.plan_stubs as bps
4
4
  import pydantic
5
5
  from blueapi.core import BlueskyContext
6
6
  from bluesky.utils import Msg
7
- from dodal.devices.backlight import Backlight
7
+ from dodal.devices.motors import XYZOmegaStage
8
8
  from dodal.devices.oav.oav_detector import OAV
9
9
  from dodal.devices.oav.oav_parameters import OAV_CONFIG_JSON, OAVParameters
10
10
  from dodal.devices.oav.pin_image_recognition import PinTipDetection, Tip
@@ -14,27 +14,26 @@ from dodal.devices.oav.utils import (
14
14
  get_move_required_so_that_beam_is_at_pixel,
15
15
  wait_for_tip_to_be_found,
16
16
  )
17
- from dodal.devices.smargon import Smargon
18
17
 
18
+ from mx_bluesky.common.device_setup_plans.gonio import (
19
+ move_gonio_warn_on_out_of_range,
20
+ )
19
21
  from mx_bluesky.common.device_setup_plans.setup_oav import pre_centring_setup_oav
22
+ from mx_bluesky.common.parameters.constants import HardwareConstants
20
23
  from mx_bluesky.common.utils.context import device_composite_from_context
21
24
  from mx_bluesky.common.utils.exceptions import SampleError, catch_exception_and_warn
22
25
  from mx_bluesky.common.utils.log import LOGGER
23
- from mx_bluesky.hyperion.device_setup_plans.smargon import (
24
- move_smargon_warn_on_out_of_range,
25
- )
26
- from mx_bluesky.hyperion.parameters.constants import CONST
27
26
 
28
27
  DEFAULT_STEP_SIZE = 0.5
28
+ CONST = HardwareConstants()
29
29
 
30
30
 
31
31
  @pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
32
32
  class PinTipCentringComposite:
33
33
  """All devices which are directly or indirectly required by this plan"""
34
34
 
35
- backlight: Backlight
36
35
  oav: OAV
37
- smargon: Smargon
36
+ gonio: XYZOmegaStage
38
37
  pin_tip_detection: PinTipDetection
39
38
 
40
39
 
@@ -53,7 +52,7 @@ def trigger_and_return_pin_tip(
53
52
 
54
53
  def move_pin_into_view(
55
54
  pin_tip_device: PinTipDetection,
56
- smargon: Smargon,
55
+ gonio: XYZOmegaStage,
57
56
  step_magnitude_mm: float = DEFAULT_STEP_SIZE,
58
57
  max_steps: int = 2,
59
58
  ) -> Generator[Msg, None, Pixel]:
@@ -63,7 +62,7 @@ def move_pin_into_view(
63
62
 
64
63
  Args:
65
64
  pin_tip_device (PinTipDetection): The device being used to detect the pin
66
- smargon (Smargon): The gonio to move the tip
65
+ gonio (XYZOmegaStage): The stage(gonio) to move the tip
67
66
  step_magnitude_mm (float, optional): Distance to move the gonio (in mm) for each
68
67
  step of the search. Defaults to 0.5.
69
68
  max_steps (int, optional): The number of steps to search with. Defaults to 2.
@@ -88,20 +87,20 @@ def move_pin_into_view(
88
87
  direction_multiple = -1 if tip_xy_px[0] == 0 else 1
89
88
  step_vector_mm = step_magnitude_mm * direction_multiple
90
89
 
91
- smargon_x = yield from bps.rd(smargon.x.user_readback)
92
- ideal_move_to_find_pin = float(smargon_x) + step_vector_mm
93
- high_limit = yield from bps.rd(smargon.x.high_limit_travel)
94
- low_limit = yield from bps.rd(smargon.x.low_limit_travel)
90
+ stage_x = yield from bps.rd(gonio.x.user_readback)
91
+ ideal_move_to_find_pin = float(stage_x) + step_vector_mm
92
+ high_limit = yield from bps.rd(gonio.x.high_limit_travel)
93
+ low_limit = yield from bps.rd(gonio.x.low_limit_travel)
95
94
  move_within_limits = max(min(ideal_move_to_find_pin, high_limit), low_limit)
96
95
  if move_within_limits != ideal_move_to_find_pin:
97
96
  LOGGER.warning(
98
97
  f"Pin tip is off screen, and moving {step_vector_mm}mm would cross limits, "
99
98
  f"moving to {move_within_limits} instead"
100
99
  )
101
- yield from bps.mv(smargon.x, move_within_limits)
100
+ yield from bps.mv(gonio.x, move_within_limits)
102
101
 
103
102
  # Some time for the view to settle after the move
104
- yield from bps.sleep(CONST.HARDWARE.OAV_REFRESH_DELAY)
103
+ yield from bps.sleep(CONST.OAV_REFRESH_DELAY)
105
104
 
106
105
  tip_xy_px = yield from trigger_and_return_pin_tip(pin_tip_device)
107
106
 
@@ -127,7 +126,7 @@ def pin_tip_centre_plan(
127
126
  to be.
128
127
  """
129
128
  oav: OAV = composite.oav
130
- smargon: Smargon = composite.smargon
129
+ gonio: XYZOmegaStage = composite.gonio
131
130
  oav_params = OAVParameters("pinTipCentring", oav_config_file)
132
131
 
133
132
  pin_tip_setup = composite.pin_tip_detection
@@ -139,10 +138,10 @@ def pin_tip_centre_plan(
139
138
  def offset_and_move(tip: Pixel):
140
139
  pixel_to_move_to = (tip[0] + tip_offset_px, tip[1])
141
140
  position_mm = yield from get_move_required_so_that_beam_is_at_pixel(
142
- smargon, pixel_to_move_to, oav
141
+ gonio, pixel_to_move_to, oav
143
142
  )
144
143
  LOGGER.info(f"Tip centring moving to : {position_mm}")
145
- yield from move_smargon_warn_on_out_of_range(smargon, position_mm)
144
+ yield from move_gonio_warn_on_out_of_range(gonio, position_mm)
146
145
 
147
146
  LOGGER.info(f"Tip offset in pixels: {tip_offset_px}")
148
147
 
@@ -152,10 +151,10 @@ def pin_tip_centre_plan(
152
151
 
153
152
  yield from pre_centring_setup_oav(oav, oav_params, pin_tip_setup)
154
153
 
155
- tip = yield from move_pin_into_view(pin_tip_detect, smargon)
154
+ tip = yield from move_pin_into_view(pin_tip_detect, gonio)
156
155
  yield from offset_and_move(tip)
157
156
 
158
- yield from bps.mvr(smargon.omega, -90)
157
+ yield from bps.mvr(gonio.omega, -90)
159
158
 
160
159
  # need to wait for the OAV image to update
161
160
  # See #673 for improvements
@@ -83,12 +83,17 @@ class GridDetectionCallback(CallbackBase):
83
83
  beam_x = data["oav-beam_centre_i"]
84
84
  beam_y = data["oav-beam_centre_j"]
85
85
 
86
+ x_direction = data["oav-x_direction"]
87
+ y_direction = data["oav-y_direction"]
88
+ z_direction = data["oav-z_direction"]
89
+
86
90
  position_grid_start_mm = calculate_x_y_z_of_pixel(
87
91
  current_xyz,
88
92
  smargon_omega,
89
93
  centre_of_first_box,
90
94
  (beam_x, beam_y),
91
95
  (microns_per_pixel_x, microns_per_pixel_y),
96
+ (x_direction, y_direction, z_direction),
92
97
  )
93
98
  LOGGER.info(f"Calculated start position {position_grid_start_mm}")
94
99
 
@@ -5,14 +5,10 @@ from collections.abc import Callable, Sequence
5
5
  from pathlib import Path
6
6
  from typing import TYPE_CHECKING, Any, TypeVar, cast
7
7
 
8
- from dodal.beamline_specific_utils.i03 import beam_size_from_aperture
9
8
  from dodal.devices.detector import DetectorParams
10
9
  from dodal.devices.detector.det_resolution import resolution
11
10
  from dodal.devices.synchrotron import SynchrotronMode
12
11
 
13
- from mx_bluesky.common.external_interaction.callbacks.common.logging_callback import (
14
- format_doc_for_log,
15
- )
16
12
  from mx_bluesky.common.external_interaction.callbacks.common.plan_reactive_callback import (
17
13
  PlanReactiveCallback,
18
14
  )
@@ -28,7 +24,11 @@ from mx_bluesky.common.external_interaction.ispyb.ispyb_store import (
28
24
  from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import get_ispyb_config
29
25
  from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
30
26
  from mx_bluesky.common.parameters.constants import DocDescriptorNames
31
- from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER, set_dcgid_tag
27
+ from mx_bluesky.common.utils.log import (
28
+ ISPYB_ZOCALO_CALLBACK_LOGGER,
29
+ format_doc_for_log,
30
+ set_dcgid_tag,
31
+ )
32
32
  from mx_bluesky.common.utils.utils import convert_ev_to_angstrom
33
33
 
34
34
  D = TypeVar("D")
@@ -147,18 +147,16 @@ class BaseISPyBCallback(PlanReactiveCallback):
147
147
  )
148
148
  return scan_data_infos
149
149
 
150
- def _handle_ispyb_transmission_flux_read(self, doc) -> Sequence[ScanDataInfo]:
150
+ def _handle_ispyb_transmission_flux_read(
151
+ self, doc: Event
152
+ ) -> Sequence[ScanDataInfo]:
151
153
  assert self.params
152
154
  aperture = doc["data"]["aperture_scatterguard-selected_aperture"]
153
- aperture_radius = doc["data"]["aperture_scatterguard-radius"]
154
- beamsize = beam_size_from_aperture(aperture_radius)
155
- beamsize_x_mm = beamsize.x_um / 1000 if beamsize.x_um else None
156
- beamsize_y_mm = beamsize.y_um / 1000 if beamsize.y_um else None
155
+ beamsize_x_mm = doc["data"]["beamsize-x_um"] / 1000
156
+ beamsize_y_mm = doc["data"]["beamsize-y_um"] / 1000
157
157
  hwscan_data_collection_info = DataCollectionInfo(
158
158
  beamsize_at_samplex=beamsize_x_mm,
159
159
  beamsize_at_sampley=beamsize_y_mm,
160
- focal_spot_size_at_samplex=beamsize_x_mm,
161
- focal_spot_size_at_sampley=beamsize_y_mm,
162
160
  flux=doc["data"]["flux-flux_reading"],
163
161
  )
164
162
  if transmission := doc["data"]["attenuator-actual_transmission"]:
@@ -4,15 +4,14 @@ from mx_bluesky.common.external_interaction.ispyb.data_model import (
4
4
  DataCollectionGroupInfo,
5
5
  DataCollectionInfo,
6
6
  )
7
- from mx_bluesky.common.external_interaction.ispyb.ispyb_store import (
8
- EIGER_FILE_SUFFIX,
9
- I03_EIGER_DETECTOR,
10
- )
11
7
  from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import (
12
8
  get_current_time_string,
13
9
  )
14
10
  from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
15
11
 
12
+ I03_EIGER_DETECTOR = 78
13
+ EIGER_FILE_SUFFIX = "h5"
14
+
16
15
 
17
16
  def populate_data_collection_group(params: DiffractionExperimentWithSample):
18
17
  dcg_info = DataCollectionGroupInfo(
@@ -31,7 +30,6 @@ def populate_remaining_data_collection_info(
31
30
  ):
32
31
  data_collection_info.visit_string = params.visit
33
32
  data_collection_info.parent_id = data_collection_group_id
34
- data_collection_info.sample_id = params.sample_id
35
33
  data_collection_info.detector_id = I03_EIGER_DETECTOR
36
34
  data_collection_info.comments = comment
37
35
  data_collection_info.detector_distance = params.detector_params.detector_distance
@@ -240,7 +240,7 @@ class GridscanISPyBCallback(BaseISPyBCallback):
240
240
  f"{y_steps} by {z_steps}."
241
241
  )
242
242
 
243
- self._populate_axis_info(data_collection_info, omega)
243
+ self._populate_axis_info(data_collection_info, doc["data"])
244
244
 
245
245
  scan_data_info = ScanDataInfo(
246
246
  data_collection_info=data_collection_info,
@@ -254,15 +254,15 @@ class GridscanISPyBCallback(BaseISPyBCallback):
254
254
  self._oav_snapshot_event_idx += 1
255
255
  return [scan_data_info]
256
256
 
257
- def _populate_axis_info(
258
- self, data_collection_info: DataCollectionInfo, omega_start: float | None
259
- ):
260
- if omega_start is not None:
257
+ def _populate_axis_info(self, data_collection_info: DataCollectionInfo, doc: dict):
258
+ if (omega_start := doc.get("smargon-omega")) is not None:
261
259
  omega_in_gda_space = -omega_start
262
260
  data_collection_info.omega_start = omega_in_gda_space
263
261
  data_collection_info.axis_start = omega_in_gda_space
264
262
  data_collection_info.axis_end = omega_in_gda_space
265
263
  data_collection_info.axis_range = 0
264
+ if (chi_start := doc.get("smargon-chi")) is not None:
265
+ data_collection_info.chi_start = chi_start
266
266
 
267
267
  def populate_info_for_update(
268
268
  self,
@@ -9,7 +9,7 @@ from pydantic import TypeAdapter
9
9
 
10
10
  from mx_bluesky.common.parameters.constants import (
11
11
  GDA_DOMAIN_PROPERTIES_PATH,
12
- FeatureSetting,
12
+ FeatureSettings,
13
13
  FeatureSettingSources,
14
14
  OavConstants,
15
15
  )
@@ -19,7 +19,7 @@ FEATURE_FLAG_CACHE_LENGTH_S = 60 * 5
19
19
  # Used by the config server when refreshing its cache
20
20
  _JSON_CONFIG_PATHS = [OavConstants.OAV_CONFIG_JSON]
21
21
 
22
- T = TypeVar("T", bound=FeatureSetting)
22
+ T = TypeVar("T", bound=FeatureSettings)
23
23
 
24
24
 
25
25
  class MXConfigClient(ConfigServer, Generic[T]):
@@ -1,3 +1,8 @@
1
+ """
2
+ TODO replace these with autogenerated schema classes from the ExpEye API
3
+ https://github.com/DiamondLightSource/mx-bluesky/issues/1419
4
+ """
5
+
1
6
  from dataclasses import asdict, dataclass
2
7
  from enum import Enum
3
8
 
@@ -18,6 +23,9 @@ class DataCollectionGroupInfo:
18
23
 
19
24
  @dataclass(kw_only=True)
20
25
  class DataCollectionInfo:
26
+ # This is used internally to keep track of the DataCollectionGroup ID
27
+ parent_id: int | None = None
28
+
21
29
  omega_start: float | None = None
22
30
  data_collection_number: int | None = None
23
31
  xtal_snapshot1: str | None = None
@@ -28,15 +36,12 @@ class DataCollectionInfo:
28
36
  n_images: int | None = None
29
37
  axis_range: float | None = None
30
38
  axis_end: float | None = None
39
+ chi_start: float | None = None
31
40
  kappa_start: float | None = None
32
41
 
33
- parent_id: int | None = None
34
42
  visit_string: str | None = None
35
- sample_id: int | None = None
36
43
  detector_id: int | None = None
37
44
  axis_start: float | None = None
38
- focal_spot_size_at_samplex: float | None = None
39
- focal_spot_size_at_sampley: float | None = None
40
45
  slitgap_vertical: float | None = None
41
46
  slitgap_horizontal: float | None = None
42
47
  beamsize_at_samplex: float | None = None
@@ -60,6 +65,8 @@ class DataCollectionInfo:
60
65
  synchrotron_mode: str | None = None
61
66
  undulator_gap1: float | None = None
62
67
  start_time: str | None = None
68
+ end_time: str | None = None
69
+ run_status: str | None = None
63
70
 
64
71
 
65
72
  @dataclass