mx-bluesky 1.2.0__py3-none-any.whl → 1.4.1a0__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.
- mx_bluesky/__init__.py +8 -3
- mx_bluesky/__main__.py +12 -7
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/i04/callbacks/murko_callback.py +14 -4
- mx_bluesky/beamlines/i04/thawing_plan.py +49 -11
- mx_bluesky/beamlines/i24/serial/__init__.py +3 -0
- mx_bluesky/beamlines/i24/serial/dcid.py +19 -21
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +69 -91
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +2 -5
- mx_bluesky/beamlines/i24/serial/fixed_target/ft_utils.py +0 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +111 -143
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +141 -222
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +7 -216
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +18 -17
- mx_bluesky/beamlines/i24/serial/log.py +58 -49
- mx_bluesky/beamlines/i24/serial/parameters/constants.py +0 -1
- mx_bluesky/beamlines/i24/serial/parameters/fixed_target/cs/cs_maker.json +3 -3
- mx_bluesky/beamlines/i24/serial/run_extruder.sh +30 -5
- mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +30 -5
- mx_bluesky/beamlines/i24/serial/run_serial.py +24 -8
- mx_bluesky/beamlines/i24/serial/setup_beamline/ca.py +0 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +79 -81
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +9 -20
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +26 -28
- mx_bluesky/beamlines/i24/serial/write_nexus.py +11 -11
- mx_bluesky/common/__init__.py +0 -0
- mx_bluesky/common/device_setup_plans/read_hardware_for_setup.py +14 -0
- mx_bluesky/common/external_interaction/config_server.py +46 -0
- mx_bluesky/common/parameters/components.py +258 -0
- mx_bluesky/common/parameters/constants.py +138 -0
- mx_bluesky/common/parameters/gridscan.py +94 -0
- mx_bluesky/common/parameters/robot_load.py +16 -0
- mx_bluesky/common/plans/__init__.py +1 -0
- mx_bluesky/common/plans/do_fgs.py +121 -0
- mx_bluesky/common/utils/log.py +118 -0
- mx_bluesky/{hyperion → common/utils}/tracing.py +2 -2
- mx_bluesky/hyperion/__main__.py +13 -10
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +31 -26
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +6 -12
- mx_bluesky/hyperion/device_setup_plans/setup_oav.py +6 -12
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +5 -6
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +49 -18
- mx_bluesky/hyperion/device_setup_plans/smargon.py +6 -6
- mx_bluesky/hyperion/device_setup_plans/utils.py +2 -2
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +4 -4
- mx_bluesky/hyperion/experiment_plans/__init__.py +4 -0
- mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +83 -0
- mx_bluesky/hyperion/experiment_plans/common/xrc_result.py +47 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -9
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +145 -161
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +56 -22
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +52 -10
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +21 -20
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +11 -14
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +40 -21
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +19 -19
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +21 -21
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +51 -13
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +24 -7
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +5 -6
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -2
- mx_bluesky/hyperion/external_interaction/callbacks/common/abstract_event.py +66 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +30 -25
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +29 -12
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +7 -4
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +5 -3
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +28 -20
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +5 -4
- mx_bluesky/hyperion/external_interaction/config_server.py +11 -28
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +1 -1
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +1 -1
- mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +2 -2
- mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +1 -1
- mx_bluesky/hyperion/log.py +0 -84
- mx_bluesky/hyperion/parameters/components.py +4 -251
- mx_bluesky/hyperion/parameters/constants.py +22 -119
- mx_bluesky/hyperion/parameters/gridscan.py +35 -74
- mx_bluesky/hyperion/parameters/load_centre_collect.py +16 -11
- mx_bluesky/hyperion/parameters/rotation.py +23 -10
- mx_bluesky/hyperion/utils/utils.py +17 -0
- mx_bluesky/hyperion/utils/validation.py +5 -6
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/METADATA +36 -33
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/RECORD +91 -81
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/WHEEL +1 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +0 -161
- mx_bluesky/example.py +0 -19
- mx_bluesky/hyperion/parameters/robot_load.py +0 -16
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
from collections.abc import Callable
|
|
4
|
+
from collections.abc import Callable, Sequence
|
|
5
5
|
from functools import partial
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from time import time
|
|
8
7
|
from typing import Protocol
|
|
9
8
|
|
|
10
9
|
import bluesky.plan_stubs as bps
|
|
11
10
|
import bluesky.preprocessors as bpp
|
|
12
11
|
import numpy as np
|
|
13
|
-
|
|
12
|
+
import pydantic
|
|
13
|
+
from blueapi.core import BlueskyContext
|
|
14
|
+
from bluesky.callbacks import CallbackBase
|
|
15
|
+
from bluesky.utils import MsgGenerator
|
|
14
16
|
from dodal.devices.aperturescatterguard import (
|
|
15
17
|
ApertureScatterguard,
|
|
16
|
-
ApertureValue,
|
|
17
18
|
)
|
|
18
19
|
from dodal.devices.attenuator import Attenuator
|
|
19
20
|
from dodal.devices.backlight import Backlight
|
|
@@ -30,7 +31,7 @@ from dodal.devices.fast_grid_scan import (
|
|
|
30
31
|
from dodal.devices.flux import Flux
|
|
31
32
|
from dodal.devices.robot import BartRobot
|
|
32
33
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
33
|
-
from dodal.devices.smargon import Smargon
|
|
34
|
+
from dodal.devices.smargon import Smargon
|
|
34
35
|
from dodal.devices.synchrotron import Synchrotron
|
|
35
36
|
from dodal.devices.undulator import Undulator
|
|
36
37
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
@@ -39,17 +40,17 @@ from dodal.devices.zebra_controlled_shutter import ZebraShutter
|
|
|
39
40
|
from dodal.devices.zocalo.zocalo_results import (
|
|
40
41
|
ZOCALO_READING_PLAN_NAME,
|
|
41
42
|
ZOCALO_STAGE_GROUP,
|
|
43
|
+
XrcResult,
|
|
42
44
|
ZocaloResults,
|
|
43
|
-
|
|
45
|
+
get_full_processing_results,
|
|
44
46
|
)
|
|
45
|
-
from
|
|
47
|
+
from event_model import RunStart
|
|
46
48
|
from ophyd_async.fastcs.panda import HDFPanda
|
|
47
|
-
from scanspec.core import AxesPoints, Axis
|
|
48
49
|
|
|
49
|
-
from mx_bluesky.
|
|
50
|
+
from mx_bluesky.common.plans.do_fgs import kickoff_and_complete_gridscan
|
|
51
|
+
from mx_bluesky.common.utils.tracing import TRACER
|
|
50
52
|
from mx_bluesky.hyperion.device_setup_plans.read_hardware_for_setup import (
|
|
51
53
|
read_hardware_during_collection,
|
|
52
|
-
read_hardware_for_zocalo,
|
|
53
54
|
read_hardware_pre_collection,
|
|
54
55
|
)
|
|
55
56
|
from mx_bluesky.hyperion.device_setup_plans.setup_panda import (
|
|
@@ -66,10 +67,16 @@ from mx_bluesky.hyperion.device_setup_plans.xbpm_feedback import (
|
|
|
66
67
|
transmission_and_xbpm_feedback_for_collection_decorator,
|
|
67
68
|
)
|
|
68
69
|
from mx_bluesky.hyperion.exceptions import WarningException
|
|
70
|
+
from mx_bluesky.hyperion.experiment_plans.change_aperture_then_move_plan import (
|
|
71
|
+
change_aperture_then_move_to_xtal,
|
|
72
|
+
)
|
|
73
|
+
from mx_bluesky.hyperion.experiment_plans.common.xrc_result import XRayCentreResult
|
|
74
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.xray_centre.ispyb_callback import (
|
|
75
|
+
ispyb_activation_wrapper,
|
|
76
|
+
)
|
|
69
77
|
from mx_bluesky.hyperion.log import LOGGER
|
|
70
78
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
71
|
-
from mx_bluesky.hyperion.parameters.gridscan import
|
|
72
|
-
from mx_bluesky.hyperion.tracing import TRACER
|
|
79
|
+
from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan
|
|
73
80
|
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
74
81
|
|
|
75
82
|
|
|
@@ -83,7 +90,7 @@ class CrystalNotFoundException(WarningException):
|
|
|
83
90
|
pass
|
|
84
91
|
|
|
85
92
|
|
|
86
|
-
@dataclasses.dataclass
|
|
93
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
87
94
|
class FlyScanXRayCentreComposite:
|
|
88
95
|
"""All devices which are directly or indirectly required by this plan"""
|
|
89
96
|
|
|
@@ -112,30 +119,33 @@ class FlyScanXRayCentreComposite:
|
|
|
112
119
|
return self.smargon
|
|
113
120
|
|
|
114
121
|
|
|
122
|
+
class XRayCentreEventHandler(CallbackBase):
|
|
123
|
+
def __init__(self):
|
|
124
|
+
super().__init__()
|
|
125
|
+
self.xray_centre_results: Sequence[XRayCentreResult] | None = None
|
|
126
|
+
|
|
127
|
+
def start(self, doc: RunStart) -> RunStart | None:
|
|
128
|
+
if "xray_centre_results" in doc:
|
|
129
|
+
self.xray_centre_results = [
|
|
130
|
+
XRayCentreResult(**result_dict)
|
|
131
|
+
for result_dict in doc["xray_centre_results"] # type: ignore
|
|
132
|
+
]
|
|
133
|
+
return doc
|
|
134
|
+
|
|
135
|
+
|
|
115
136
|
def create_devices(context: BlueskyContext) -> FlyScanXRayCentreComposite:
|
|
116
137
|
"""Creates the devices required for the plan and connect to them"""
|
|
117
138
|
return device_composite_from_context(context, FlyScanXRayCentreComposite)
|
|
118
139
|
|
|
119
140
|
|
|
120
|
-
def
|
|
121
|
-
composite: FlyScanXRayCentreComposite,
|
|
122
|
-
parameters: ThreeDGridScan,
|
|
141
|
+
def flyscan_xray_centre_no_move(
|
|
142
|
+
composite: FlyScanXRayCentreComposite, parameters: HyperionThreeDGridScan
|
|
123
143
|
) -> MsgGenerator:
|
|
124
|
-
"""
|
|
125
|
-
|
|
126
|
-
The ispyb handler should be added to the whole gridscan as we want to capture errors
|
|
127
|
-
at any point in it.
|
|
128
|
-
|
|
129
|
-
Args:
|
|
130
|
-
parameters (ThreeDGridScan): The parameters to run the scan.
|
|
131
|
-
|
|
132
|
-
Returns:
|
|
133
|
-
Generator: The plan for the gridscan
|
|
134
|
-
"""
|
|
144
|
+
"""Perform a flyscan and determine the centres of interest"""
|
|
135
145
|
parameters.features.update_self_from_server()
|
|
136
146
|
composite.eiger.set_detector_parameters(parameters.detector_params)
|
|
137
|
-
composite.zocalo.zocalo_environment =
|
|
138
|
-
composite.zocalo.use_cpu_and_gpu = parameters.
|
|
147
|
+
composite.zocalo.zocalo_environment = CONST.ZOCALO_ENV
|
|
148
|
+
composite.zocalo.use_cpu_and_gpu = parameters.features.compare_cpu_and_gpu_zocalo
|
|
139
149
|
|
|
140
150
|
feature_controlled = _get_feature_controlled(composite, parameters)
|
|
141
151
|
|
|
@@ -143,8 +153,6 @@ def flyscan_xray_centre(
|
|
|
143
153
|
@bpp.run_decorator( # attach experiment metadata to the start document
|
|
144
154
|
md={
|
|
145
155
|
"subplan_name": CONST.PLAN.GRIDSCAN_OUTER,
|
|
146
|
-
CONST.TRIGGER.ZOCALO: CONST.PLAN.DO_FGS,
|
|
147
|
-
"zocalo_environment": parameters.zocalo_environment,
|
|
148
156
|
"hyperion_parameters": parameters.model_dump_json(),
|
|
149
157
|
"activate_callbacks": [
|
|
150
158
|
"GridscanNexusFileCallback",
|
|
@@ -157,25 +165,66 @@ def flyscan_xray_centre(
|
|
|
157
165
|
composite.attenuator,
|
|
158
166
|
parameters.transmission_frac,
|
|
159
167
|
)
|
|
160
|
-
def
|
|
168
|
+
def run_gridscan_and_fetch_and_tidy(
|
|
161
169
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
162
|
-
params:
|
|
170
|
+
params: HyperionThreeDGridScan,
|
|
163
171
|
feature_controlled: _FeatureControlled,
|
|
164
|
-
):
|
|
165
|
-
yield from
|
|
172
|
+
) -> MsgGenerator:
|
|
173
|
+
yield from run_gridscan_and_fetch_results(
|
|
174
|
+
fgs_composite, params, feature_controlled
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
yield from run_gridscan_and_fetch_and_tidy(
|
|
178
|
+
composite, parameters, feature_controlled
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def flyscan_xray_centre(
|
|
183
|
+
composite: FlyScanXRayCentreComposite,
|
|
184
|
+
parameters: HyperionThreeDGridScan,
|
|
185
|
+
) -> MsgGenerator:
|
|
186
|
+
"""Create the plan to run the grid scan based on provided parameters.
|
|
187
|
+
|
|
188
|
+
The ispyb handler should be added to the whole gridscan as we want to capture errors
|
|
189
|
+
at any point in it.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
parameters (ThreeDGridScan): The parameters to run the scan.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Generator: The plan for the gridscan
|
|
196
|
+
"""
|
|
197
|
+
xrc_event_handler = XRayCentreEventHandler()
|
|
198
|
+
|
|
199
|
+
@bpp.subs_decorator(xrc_event_handler)
|
|
200
|
+
def flyscan_and_fetch_results() -> MsgGenerator:
|
|
201
|
+
yield from ispyb_activation_wrapper(
|
|
202
|
+
flyscan_xray_centre_no_move(composite, parameters), parameters
|
|
203
|
+
)
|
|
166
204
|
|
|
167
|
-
|
|
205
|
+
yield from flyscan_and_fetch_results()
|
|
206
|
+
|
|
207
|
+
xray_centre_results = xrc_event_handler.xray_centre_results
|
|
208
|
+
assert (
|
|
209
|
+
xray_centre_results
|
|
210
|
+
), "Flyscan result event not received or no crystal found and exception not raised"
|
|
211
|
+
yield from change_aperture_then_move_to_xtal(
|
|
212
|
+
xray_centre_results[0],
|
|
213
|
+
composite.smargon,
|
|
214
|
+
composite.aperture_scatterguard,
|
|
215
|
+
parameters,
|
|
216
|
+
)
|
|
168
217
|
|
|
169
218
|
|
|
170
219
|
@bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_AND_MOVE)
|
|
171
220
|
@bpp.run_decorator(md={"subplan_name": CONST.PLAN.GRIDSCAN_AND_MOVE})
|
|
172
|
-
def
|
|
221
|
+
def run_gridscan_and_fetch_results(
|
|
173
222
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
174
|
-
parameters:
|
|
223
|
+
parameters: HyperionThreeDGridScan,
|
|
175
224
|
feature_controlled: _FeatureControlled,
|
|
176
225
|
) -> MsgGenerator:
|
|
177
226
|
"""A multi-run plan which runs a gridscan, gets the results from zocalo
|
|
178
|
-
and
|
|
227
|
+
and fires an event with the centres of mass determined by zocalo"""
|
|
179
228
|
|
|
180
229
|
# We get the initial motor positions so we can return to them on zocalo failure
|
|
181
230
|
initial_xyz = np.array(
|
|
@@ -202,51 +251,66 @@ def run_gridscan_and_move(
|
|
|
202
251
|
[fgs_composite.zocalo], name=ZOCALO_READING_PLAN_NAME
|
|
203
252
|
)
|
|
204
253
|
LOGGER.info("Zocalo triggered and read, interpreting results.")
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
)
|
|
254
|
+
xrc_results = yield from get_full_processing_results(fgs_composite.zocalo)
|
|
255
|
+
LOGGER.info(f"Got xray centres, top 5: {xrc_results[:5]}")
|
|
256
|
+
if xrc_results:
|
|
257
|
+
flyscan_results = [
|
|
258
|
+
_xrc_result_in_boxes_to_result_in_mm(xr, parameters)
|
|
259
|
+
for xr in xrc_results
|
|
260
|
+
]
|
|
213
261
|
else:
|
|
214
262
|
LOGGER.warning("No X-ray centre received")
|
|
215
263
|
raise CrystalNotFoundException()
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
yield from set_aperture_for_bbox_size(
|
|
219
|
-
fgs_composite.aperture_scatterguard, bbox_size
|
|
220
|
-
)
|
|
221
|
-
else:
|
|
222
|
-
LOGGER.warning("No bounding box size received")
|
|
223
|
-
|
|
224
|
-
# once we have the results, go to the appropriate position
|
|
225
|
-
LOGGER.info("Moving to centre of mass.")
|
|
226
|
-
with TRACER.start_span("move_to_result"):
|
|
227
|
-
x, y, z = xray_centre
|
|
228
|
-
yield from move_x_y_z(fgs_composite.sample_motors, x, y, z, wait=True)
|
|
229
|
-
|
|
230
|
-
if parameters.FGS_params.set_stub_offsets:
|
|
231
|
-
LOGGER.info("Recentring smargon co-ordinate system to this point.")
|
|
232
|
-
yield from bps.mv(
|
|
233
|
-
fgs_composite.sample_motors.stub_offsets, StubPosition.CURRENT_AS_CENTER
|
|
234
|
-
)
|
|
264
|
+
yield from _fire_xray_centre_result_event(flyscan_results)
|
|
265
|
+
|
|
235
266
|
finally:
|
|
236
267
|
# Turn off dev/shm streaming to avoid filling disk, see https://github.com/DiamondLightSource/hyperion/issues/1395
|
|
237
268
|
LOGGER.info("Turning off Eiger dev/shm streaming")
|
|
238
|
-
yield from bps.abs_set(fgs_composite.eiger.odin.fan.dev_shm_enable, 0)
|
|
269
|
+
yield from bps.abs_set(fgs_composite.eiger.odin.fan.dev_shm_enable, 0) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
239
270
|
|
|
240
271
|
# Wait on everything before returning to GDA (particularly apertures), can be removed
|
|
241
272
|
# when we do not return to GDA here
|
|
242
273
|
yield from bps.wait()
|
|
243
274
|
|
|
244
275
|
|
|
276
|
+
def _xrc_result_in_boxes_to_result_in_mm(
|
|
277
|
+
xrc_result: XrcResult, parameters: HyperionThreeDGridScan
|
|
278
|
+
) -> XRayCentreResult:
|
|
279
|
+
fgs_params = parameters.FGS_params
|
|
280
|
+
xray_centre = fgs_params.grid_position_to_motor_position(
|
|
281
|
+
np.array(xrc_result["centre_of_mass"])
|
|
282
|
+
)
|
|
283
|
+
return XRayCentreResult(
|
|
284
|
+
centre_of_mass_mm=xray_centre,
|
|
285
|
+
bounding_box_mm=(
|
|
286
|
+
fgs_params.grid_position_to_motor_position(
|
|
287
|
+
np.array(xrc_result["bounding_box"][0])
|
|
288
|
+
),
|
|
289
|
+
fgs_params.grid_position_to_motor_position(
|
|
290
|
+
np.array(xrc_result["bounding_box"][1])
|
|
291
|
+
),
|
|
292
|
+
),
|
|
293
|
+
max_count=xrc_result["max_count"],
|
|
294
|
+
total_count=xrc_result["total_count"],
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@bpp.set_run_key_decorator(CONST.PLAN.FLYSCAN_RESULTS)
|
|
299
|
+
def _fire_xray_centre_result_event(results: Sequence[XRayCentreResult]):
|
|
300
|
+
def empty_plan():
|
|
301
|
+
return iter([])
|
|
302
|
+
|
|
303
|
+
yield from bpp.run_wrapper(
|
|
304
|
+
empty_plan(),
|
|
305
|
+
md={"xray_centre_results": [dataclasses.asdict(r) for r in results]},
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
245
309
|
@bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_MAIN)
|
|
246
310
|
@bpp.run_decorator(md={"subplan_name": CONST.PLAN.GRIDSCAN_MAIN})
|
|
247
311
|
def run_gridscan(
|
|
248
312
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
249
|
-
parameters:
|
|
313
|
+
parameters: HyperionThreeDGridScan,
|
|
250
314
|
feature_controlled: _FeatureControlled,
|
|
251
315
|
md={ # noqa
|
|
252
316
|
"plan_name": CONST.PLAN.GRIDSCAN_MAIN,
|
|
@@ -266,7 +330,7 @@ def run_gridscan(
|
|
|
266
330
|
fgs_composite.undulator,
|
|
267
331
|
fgs_composite.synchrotron,
|
|
268
332
|
fgs_composite.s4_slit_gaps,
|
|
269
|
-
fgs_composite.
|
|
333
|
+
fgs_composite.dcm,
|
|
270
334
|
fgs_composite.smargon,
|
|
271
335
|
)
|
|
272
336
|
|
|
@@ -287,7 +351,7 @@ def run_gridscan(
|
|
|
287
351
|
|
|
288
352
|
LOGGER.info("Waiting for arming to finish")
|
|
289
353
|
yield from bps.wait(CONST.WAIT.GRID_READY_FOR_DC)
|
|
290
|
-
yield from bps.stage(fgs_composite.eiger)
|
|
354
|
+
yield from bps.stage(fgs_composite.eiger) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
291
355
|
|
|
292
356
|
yield from kickoff_and_complete_gridscan(
|
|
293
357
|
feature_controlled.fgs_motors,
|
|
@@ -295,66 +359,11 @@ def run_gridscan(
|
|
|
295
359
|
fgs_composite.synchrotron,
|
|
296
360
|
[parameters.scan_points_first_grid, parameters.scan_points_second_grid],
|
|
297
361
|
parameters.scan_indices,
|
|
298
|
-
|
|
362
|
+
plan_during_collection=read_during_collection,
|
|
299
363
|
)
|
|
300
364
|
yield from bps.abs_set(feature_controlled.fgs_motors.z_steps, 0, wait=False)
|
|
301
365
|
|
|
302
366
|
|
|
303
|
-
def kickoff_and_complete_gridscan(
|
|
304
|
-
gridscan: FastGridScanCommon,
|
|
305
|
-
eiger: EigerDetector,
|
|
306
|
-
synchrotron: Synchrotron,
|
|
307
|
-
scan_points: list[AxesPoints[Axis]],
|
|
308
|
-
scan_start_indices: list[int],
|
|
309
|
-
do_during_run: Callable[[], MsgGenerator] | None = None,
|
|
310
|
-
):
|
|
311
|
-
@TRACER.start_as_current_span(CONST.PLAN.DO_FGS)
|
|
312
|
-
@bpp.set_run_key_decorator(CONST.PLAN.DO_FGS)
|
|
313
|
-
@bpp.run_decorator(
|
|
314
|
-
md={
|
|
315
|
-
"subplan_name": CONST.PLAN.DO_FGS,
|
|
316
|
-
"scan_points": scan_points,
|
|
317
|
-
"scan_start_indices": scan_start_indices,
|
|
318
|
-
}
|
|
319
|
-
)
|
|
320
|
-
@bpp.contingency_decorator(
|
|
321
|
-
except_plan=lambda e: (yield from bps.stop(eiger)),
|
|
322
|
-
else_plan=lambda: (yield from bps.unstage(eiger)),
|
|
323
|
-
)
|
|
324
|
-
def do_fgs():
|
|
325
|
-
# Check topup gate
|
|
326
|
-
expected_images = yield from bps.rd(gridscan.expected_images)
|
|
327
|
-
exposure_sec_per_image = yield from bps.rd(eiger.cam.acquire_time)
|
|
328
|
-
LOGGER.info("waiting for topup if necessary...")
|
|
329
|
-
yield from check_topup_and_wait_if_necessary(
|
|
330
|
-
synchrotron,
|
|
331
|
-
expected_images * exposure_sec_per_image,
|
|
332
|
-
30.0,
|
|
333
|
-
)
|
|
334
|
-
yield from read_hardware_for_zocalo(eiger)
|
|
335
|
-
LOGGER.info("Wait for all moves with no assigned group")
|
|
336
|
-
yield from bps.wait()
|
|
337
|
-
LOGGER.info("kicking off FGS")
|
|
338
|
-
yield from bps.kickoff(gridscan, wait=True)
|
|
339
|
-
gridscan_start_time = time()
|
|
340
|
-
LOGGER.info("Waiting for Zocalo device queue to have been cleared...")
|
|
341
|
-
yield from bps.wait(
|
|
342
|
-
ZOCALO_STAGE_GROUP
|
|
343
|
-
) # Make sure ZocaloResults queue is clear and ready to accept our new data
|
|
344
|
-
if do_during_run:
|
|
345
|
-
LOGGER.info(f"Running {do_during_run} during FGS")
|
|
346
|
-
yield from do_during_run()
|
|
347
|
-
LOGGER.info("completing FGS")
|
|
348
|
-
yield from bps.complete(gridscan, wait=True)
|
|
349
|
-
|
|
350
|
-
# Remove this logging statement once metrics have been added
|
|
351
|
-
LOGGER.info(
|
|
352
|
-
f"Gridscan motion program took {round(time()-gridscan_start_time,2)} to complete"
|
|
353
|
-
)
|
|
354
|
-
|
|
355
|
-
yield from do_fgs()
|
|
356
|
-
|
|
357
|
-
|
|
358
367
|
def wait_for_gridscan_valid(fgs_motors: FastGridScanCommon, timeout=0.5):
|
|
359
368
|
LOGGER.info("Waiting for valid fgs_params")
|
|
360
369
|
SLEEP_PER_CHECK = 0.1
|
|
@@ -372,31 +381,6 @@ def wait_for_gridscan_valid(fgs_motors: FastGridScanCommon, timeout=0.5):
|
|
|
372
381
|
raise WarningException("Scan invalid - pin too long/short/bent and out of range")
|
|
373
382
|
|
|
374
383
|
|
|
375
|
-
def set_aperture_for_bbox_size(
|
|
376
|
-
aperture_device: ApertureScatterguard,
|
|
377
|
-
bbox_size: list[int] | np.ndarray,
|
|
378
|
-
):
|
|
379
|
-
# bbox_size is [x,y,z], for i03 we only care about x
|
|
380
|
-
new_selected_aperture = (
|
|
381
|
-
ApertureValue.MEDIUM if bbox_size[0] < 2 else ApertureValue.LARGE
|
|
382
|
-
)
|
|
383
|
-
LOGGER.info(
|
|
384
|
-
f"Setting aperture to {new_selected_aperture} based on bounding box size {bbox_size}."
|
|
385
|
-
)
|
|
386
|
-
|
|
387
|
-
@bpp.set_run_key_decorator("change_aperture")
|
|
388
|
-
@bpp.run_decorator(
|
|
389
|
-
md={
|
|
390
|
-
"subplan_name": "change_aperture",
|
|
391
|
-
"aperture_size": new_selected_aperture.value,
|
|
392
|
-
}
|
|
393
|
-
)
|
|
394
|
-
def set_aperture():
|
|
395
|
-
yield from bps.abs_set(aperture_device, new_selected_aperture)
|
|
396
|
-
|
|
397
|
-
yield from set_aperture()
|
|
398
|
-
|
|
399
|
-
|
|
400
384
|
@dataclasses.dataclass
|
|
401
385
|
class _FeatureControlled:
|
|
402
386
|
class _ZebraSetup(Protocol):
|
|
@@ -408,7 +392,7 @@ class _FeatureControlled:
|
|
|
408
392
|
def __call__(
|
|
409
393
|
self,
|
|
410
394
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
411
|
-
parameters:
|
|
395
|
+
parameters: HyperionThreeDGridScan,
|
|
412
396
|
initial_xyz: np.ndarray,
|
|
413
397
|
) -> MsgGenerator: ...
|
|
414
398
|
|
|
@@ -420,7 +404,7 @@ class _FeatureControlled:
|
|
|
420
404
|
|
|
421
405
|
def _get_feature_controlled(
|
|
422
406
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
423
|
-
parameters:
|
|
407
|
+
parameters: HyperionThreeDGridScan,
|
|
424
408
|
):
|
|
425
409
|
if parameters.features.use_panda_for_gridscan:
|
|
426
410
|
return _FeatureControlled(
|
|
@@ -469,7 +453,7 @@ def _panda_tidy(fgs_composite: FlyScanXRayCentreComposite):
|
|
|
469
453
|
|
|
470
454
|
def _zebra_triggering_setup(
|
|
471
455
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
472
|
-
parameters:
|
|
456
|
+
parameters: HyperionThreeDGridScan,
|
|
473
457
|
initial_xyz: np.ndarray,
|
|
474
458
|
):
|
|
475
459
|
yield from setup_zebra_for_gridscan(
|
|
@@ -479,7 +463,7 @@ def _zebra_triggering_setup(
|
|
|
479
463
|
|
|
480
464
|
def _panda_triggering_setup(
|
|
481
465
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
482
|
-
parameters:
|
|
466
|
+
parameters: HyperionThreeDGridScan,
|
|
483
467
|
initial_xyz: np.ndarray,
|
|
484
468
|
):
|
|
485
469
|
LOGGER.info("Setting up Panda for flyscan")
|
|
@@ -498,15 +482,15 @@ def _panda_triggering_setup(
|
|
|
498
482
|
)
|
|
499
483
|
|
|
500
484
|
sample_velocity_mm_per_s = (
|
|
501
|
-
parameters.panda_FGS_params.
|
|
485
|
+
parameters.panda_FGS_params.x_step_size_mm * 1e3 / time_between_x_steps_ms
|
|
502
486
|
)
|
|
503
487
|
if sample_velocity_mm_per_s > smargon_speed_limit_mm_per_s:
|
|
504
488
|
raise SmargonSpeedException(
|
|
505
489
|
f"Smargon speed was calculated from x step size\
|
|
506
|
-
{parameters.panda_FGS_params.
|
|
490
|
+
{parameters.panda_FGS_params.x_step_size_mm}mm and\
|
|
507
491
|
time_between_x_steps_ms {time_between_x_steps_ms} as\
|
|
508
|
-
{sample_velocity_mm_per_s}. The smargon's speed limit is\
|
|
509
|
-
{smargon_speed_limit_mm_per_s}
|
|
492
|
+
{sample_velocity_mm_per_s}mm/s. The smargon's speed limit is\
|
|
493
|
+
{smargon_speed_limit_mm_per_s}mm/s."
|
|
510
494
|
)
|
|
511
495
|
else:
|
|
512
496
|
LOGGER.info(
|
|
@@ -515,8 +499,8 @@ def _panda_triggering_setup(
|
|
|
515
499
|
)
|
|
516
500
|
|
|
517
501
|
yield from bps.mv(
|
|
518
|
-
fgs_composite.panda_fast_grid_scan.time_between_x_steps_ms,
|
|
519
|
-
time_between_x_steps_ms,
|
|
502
|
+
fgs_composite.panda_fast_grid_scan.time_between_x_steps_ms, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
503
|
+
time_between_x_steps_ms, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
520
504
|
)
|
|
521
505
|
|
|
522
506
|
directory_provider_root = Path(parameters.storage_directory)
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import dataclasses
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
import pydantic
|
|
6
|
+
from blueapi.core import BlueskyContext
|
|
7
7
|
from bluesky import plan_stubs as bps
|
|
8
8
|
from bluesky import preprocessors as bpp
|
|
9
|
+
from bluesky.preprocessors import subs_decorator
|
|
10
|
+
from bluesky.utils import MsgGenerator
|
|
9
11
|
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
10
12
|
from dodal.devices.attenuator import Attenuator
|
|
11
13
|
from dodal.devices.backlight import Backlight, BacklightPosition
|
|
@@ -15,7 +17,7 @@ from dodal.devices.eiger import EigerDetector
|
|
|
15
17
|
from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScan
|
|
16
18
|
from dodal.devices.flux import Flux
|
|
17
19
|
from dodal.devices.oav.oav_detector import OAV
|
|
18
|
-
from dodal.devices.oav.oav_parameters import
|
|
20
|
+
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
19
21
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
20
22
|
from dodal.devices.robot import BartRobot
|
|
21
23
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
@@ -28,17 +30,23 @@ from dodal.devices.zebra_controlled_shutter import ZebraShutter
|
|
|
28
30
|
from dodal.devices.zocalo import ZocaloResults
|
|
29
31
|
from ophyd_async.fastcs.panda import HDFPanda
|
|
30
32
|
|
|
33
|
+
from mx_bluesky.common.parameters.constants import OavConstants
|
|
34
|
+
from mx_bluesky.common.parameters.gridscan import GridScanWithEdgeDetect
|
|
31
35
|
from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import (
|
|
32
36
|
move_aperture_if_required,
|
|
33
37
|
)
|
|
34
38
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
35
39
|
start_preparing_data_collection_then_do_plan,
|
|
36
40
|
)
|
|
41
|
+
from mx_bluesky.hyperion.experiment_plans.change_aperture_then_move_plan import (
|
|
42
|
+
change_aperture_then_move_to_xtal,
|
|
43
|
+
)
|
|
37
44
|
from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import (
|
|
38
45
|
FlyScanXRayCentreComposite as FlyScanXRayCentreComposite,
|
|
39
46
|
)
|
|
40
47
|
from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import (
|
|
41
|
-
|
|
48
|
+
XRayCentreEventHandler,
|
|
49
|
+
flyscan_xray_centre_no_move,
|
|
42
50
|
)
|
|
43
51
|
from mx_bluesky.hyperion.experiment_plans.oav_grid_detection_plan import (
|
|
44
52
|
OavGridDetectionComposite,
|
|
@@ -54,13 +62,12 @@ from mx_bluesky.hyperion.external_interaction.callbacks.xray_centre.ispyb_callba
|
|
|
54
62
|
from mx_bluesky.hyperion.log import LOGGER
|
|
55
63
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
56
64
|
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
57
|
-
|
|
58
|
-
ThreeDGridScan,
|
|
65
|
+
HyperionThreeDGridScan,
|
|
59
66
|
)
|
|
60
67
|
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
61
68
|
|
|
62
69
|
|
|
63
|
-
@dataclasses.dataclass
|
|
70
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
64
71
|
class GridDetectThenXRayCentreComposite:
|
|
65
72
|
"""All devices which are directly or indirectly required by this plan"""
|
|
66
73
|
|
|
@@ -86,6 +93,10 @@ class GridDetectThenXRayCentreComposite:
|
|
|
86
93
|
robot: BartRobot
|
|
87
94
|
sample_shutter: ZebraShutter
|
|
88
95
|
|
|
96
|
+
@property
|
|
97
|
+
def sample_motors(self):
|
|
98
|
+
return self.smargon
|
|
99
|
+
|
|
89
100
|
|
|
90
101
|
def create_devices(context: BlueskyContext) -> GridDetectThenXRayCentreComposite:
|
|
91
102
|
return device_composite_from_context(context, GridDetectThenXRayCentreComposite)
|
|
@@ -94,10 +105,10 @@ def create_devices(context: BlueskyContext) -> GridDetectThenXRayCentreComposite
|
|
|
94
105
|
def create_parameters_for_flyscan_xray_centre(
|
|
95
106
|
grid_scan_with_edge_params: GridScanWithEdgeDetect,
|
|
96
107
|
grid_parameters: GridParamUpdate,
|
|
97
|
-
) ->
|
|
108
|
+
) -> HyperionThreeDGridScan:
|
|
98
109
|
params_json = grid_scan_with_edge_params.model_dump()
|
|
99
110
|
params_json.update(grid_parameters)
|
|
100
|
-
flyscan_xray_centre_parameters =
|
|
111
|
+
flyscan_xray_centre_parameters = HyperionThreeDGridScan(**params_json)
|
|
101
112
|
LOGGER.info(f"Parameters for FGS: {flyscan_xray_centre_parameters}")
|
|
102
113
|
return flyscan_xray_centre_parameters
|
|
103
114
|
|
|
@@ -109,7 +120,7 @@ def detect_grid_and_do_gridscan(
|
|
|
109
120
|
):
|
|
110
121
|
snapshot_template = f"{parameters.detector_params.prefix}_{parameters.detector_params.run_number}_{{angle}}"
|
|
111
122
|
|
|
112
|
-
grid_params_callback = GridDetectionCallback(
|
|
123
|
+
grid_params_callback = GridDetectionCallback()
|
|
113
124
|
|
|
114
125
|
@bpp.subs_decorator([grid_params_callback])
|
|
115
126
|
def run_grid_detection_plan(
|
|
@@ -129,7 +140,16 @@ def detect_grid_and_do_gridscan(
|
|
|
129
140
|
oav_params,
|
|
130
141
|
snapshot_template,
|
|
131
142
|
str(snapshot_dir),
|
|
132
|
-
|
|
143
|
+
parameters.grid_width_um,
|
|
144
|
+
parameters.box_size_um,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if parameters.selected_aperture:
|
|
148
|
+
# Start moving the aperture/scatterguard into position without moving it in
|
|
149
|
+
yield from bps.abs_set(
|
|
150
|
+
composite.aperture_scatterguard.aperture_outside_beam,
|
|
151
|
+
parameters.selected_aperture,
|
|
152
|
+
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
133
153
|
)
|
|
134
154
|
|
|
135
155
|
yield from run_grid_detection_plan(
|
|
@@ -148,7 +168,7 @@ def detect_grid_and_do_gridscan(
|
|
|
148
168
|
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
149
169
|
)
|
|
150
170
|
|
|
151
|
-
yield from
|
|
171
|
+
yield from flyscan_xray_centre_no_move(
|
|
152
172
|
FlyScanXRayCentreComposite(
|
|
153
173
|
aperture_scatterguard=composite.aperture_scatterguard,
|
|
154
174
|
attenuator=composite.attenuator,
|
|
@@ -178,7 +198,7 @@ def detect_grid_and_do_gridscan(
|
|
|
178
198
|
def grid_detect_then_xray_centre(
|
|
179
199
|
composite: GridDetectThenXRayCentreComposite,
|
|
180
200
|
parameters: GridScanWithEdgeDetect,
|
|
181
|
-
oav_config: str = OAV_CONFIG_JSON,
|
|
201
|
+
oav_config: str = OavConstants.OAV_CONFIG_JSON,
|
|
182
202
|
) -> MsgGenerator:
|
|
183
203
|
"""
|
|
184
204
|
A plan which combines the collection of snapshots from the OAV and the determination
|
|
@@ -191,19 +211,33 @@ def grid_detect_then_xray_centre(
|
|
|
191
211
|
|
|
192
212
|
oav_params = OAVParameters("xrayCentring", oav_config)
|
|
193
213
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
214
|
+
flyscan_event_handler = XRayCentreEventHandler()
|
|
215
|
+
|
|
216
|
+
@subs_decorator(flyscan_event_handler)
|
|
217
|
+
def plan_to_perform():
|
|
218
|
+
yield from ispyb_activation_wrapper(
|
|
219
|
+
detect_grid_and_do_gridscan(
|
|
220
|
+
composite,
|
|
221
|
+
parameters,
|
|
222
|
+
oav_params,
|
|
223
|
+
),
|
|
197
224
|
parameters,
|
|
198
|
-
|
|
199
|
-
),
|
|
200
|
-
parameters,
|
|
201
|
-
)
|
|
225
|
+
)
|
|
202
226
|
|
|
203
|
-
|
|
227
|
+
yield from start_preparing_data_collection_then_do_plan(
|
|
204
228
|
eiger,
|
|
205
229
|
composite.detector_motion,
|
|
206
230
|
parameters.detector_params.detector_distance,
|
|
207
|
-
plan_to_perform,
|
|
231
|
+
plan_to_perform(),
|
|
208
232
|
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
209
233
|
)
|
|
234
|
+
|
|
235
|
+
assert (
|
|
236
|
+
flyscan_event_handler.xray_centre_results
|
|
237
|
+
), "Flyscan result event not received or no crystal found and exception not raised"
|
|
238
|
+
|
|
239
|
+
yield from change_aperture_then_move_to_xtal(
|
|
240
|
+
flyscan_event_handler.xray_centre_results[0],
|
|
241
|
+
composite.smargon,
|
|
242
|
+
composite.aperture_scatterguard,
|
|
243
|
+
)
|