mx-bluesky 1.2.0__py3-none-any.whl → 1.4.1__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/redis_to_murko_forwarder.py +178 -0
- 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 +143 -171
- mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +1 -1
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +121 -110
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +3 -6
- mx_bluesky/beamlines/i24/serial/fixed_target/ft_utils.py +0 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +164 -169
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +149 -225
- 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/__init__.py +4 -0
- mx_bluesky/beamlines/i24/serial/parameters/constants.py +6 -1
- mx_bluesky/beamlines/i24/serial/parameters/experiment_parameters.py +42 -15
- 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/pv.py +2 -0
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +104 -82
- 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 +74 -72
- 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 +143 -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 +47 -52
- 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 +9 -9
- mx_bluesky/hyperion/device_setup_plans/utils.py +2 -2
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +4 -4
- mx_bluesky/hyperion/exceptions.py +13 -1
- 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 +147 -169
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +48 -22
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +75 -9
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +21 -20
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +9 -6
- 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 +22 -22
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +43 -39
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +69 -18
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +17 -7
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +13 -13
- mx_bluesky/hyperion/external_interaction/callbacks/__init__.py +0 -4
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +5 -2
- mx_bluesky/hyperion/external_interaction/callbacks/common/abstract_event.py +66 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +5 -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 +19 -11
- 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/sample_handling/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/sample_handling_callback.py +84 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +38 -27
- 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/exceptions.py +0 -9
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +65 -15
- 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.1.dist-info}/METADATA +36 -33
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.dist-info}/RECORD +102 -89
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.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.1.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.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 (
|
|
@@ -65,11 +66,17 @@ from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
|
|
|
65
66
|
from mx_bluesky.hyperion.device_setup_plans.xbpm_feedback import (
|
|
66
67
|
transmission_and_xbpm_feedback_for_collection_decorator,
|
|
67
68
|
)
|
|
68
|
-
from mx_bluesky.hyperion.exceptions import
|
|
69
|
+
from mx_bluesky.hyperion.exceptions import CrystalNotFoundException, SampleException
|
|
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
|
|
|
@@ -77,13 +84,7 @@ class SmargonSpeedException(Exception):
|
|
|
77
84
|
pass
|
|
78
85
|
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
"""Raised if grid detection completed normally but no crystal was found."""
|
|
82
|
-
|
|
83
|
-
pass
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@dataclasses.dataclass
|
|
87
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
87
88
|
class FlyScanXRayCentreComposite:
|
|
88
89
|
"""All devices which are directly or indirectly required by this plan"""
|
|
89
90
|
|
|
@@ -112,30 +113,33 @@ class FlyScanXRayCentreComposite:
|
|
|
112
113
|
return self.smargon
|
|
113
114
|
|
|
114
115
|
|
|
116
|
+
class XRayCentreEventHandler(CallbackBase):
|
|
117
|
+
def __init__(self):
|
|
118
|
+
super().__init__()
|
|
119
|
+
self.xray_centre_results: Sequence[XRayCentreResult] | None = None
|
|
120
|
+
|
|
121
|
+
def start(self, doc: RunStart) -> RunStart | None:
|
|
122
|
+
if "xray_centre_results" in doc:
|
|
123
|
+
self.xray_centre_results = [
|
|
124
|
+
XRayCentreResult(**result_dict)
|
|
125
|
+
for result_dict in doc["xray_centre_results"] # type: ignore
|
|
126
|
+
]
|
|
127
|
+
return doc
|
|
128
|
+
|
|
129
|
+
|
|
115
130
|
def create_devices(context: BlueskyContext) -> FlyScanXRayCentreComposite:
|
|
116
131
|
"""Creates the devices required for the plan and connect to them"""
|
|
117
132
|
return device_composite_from_context(context, FlyScanXRayCentreComposite)
|
|
118
133
|
|
|
119
134
|
|
|
120
|
-
def
|
|
121
|
-
composite: FlyScanXRayCentreComposite,
|
|
122
|
-
parameters: ThreeDGridScan,
|
|
135
|
+
def flyscan_xray_centre_no_move(
|
|
136
|
+
composite: FlyScanXRayCentreComposite, parameters: HyperionThreeDGridScan
|
|
123
137
|
) -> 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
|
-
"""
|
|
138
|
+
"""Perform a flyscan and determine the centres of interest"""
|
|
135
139
|
parameters.features.update_self_from_server()
|
|
136
140
|
composite.eiger.set_detector_parameters(parameters.detector_params)
|
|
137
|
-
composite.zocalo.zocalo_environment =
|
|
138
|
-
composite.zocalo.use_cpu_and_gpu = parameters.
|
|
141
|
+
composite.zocalo.zocalo_environment = CONST.ZOCALO_ENV
|
|
142
|
+
composite.zocalo.use_cpu_and_gpu = parameters.features.compare_cpu_and_gpu_zocalo
|
|
139
143
|
|
|
140
144
|
feature_controlled = _get_feature_controlled(composite, parameters)
|
|
141
145
|
|
|
@@ -143,8 +147,6 @@ def flyscan_xray_centre(
|
|
|
143
147
|
@bpp.run_decorator( # attach experiment metadata to the start document
|
|
144
148
|
md={
|
|
145
149
|
"subplan_name": CONST.PLAN.GRIDSCAN_OUTER,
|
|
146
|
-
CONST.TRIGGER.ZOCALO: CONST.PLAN.DO_FGS,
|
|
147
|
-
"zocalo_environment": parameters.zocalo_environment,
|
|
148
150
|
"hyperion_parameters": parameters.model_dump_json(),
|
|
149
151
|
"activate_callbacks": [
|
|
150
152
|
"GridscanNexusFileCallback",
|
|
@@ -157,25 +159,66 @@ def flyscan_xray_centre(
|
|
|
157
159
|
composite.attenuator,
|
|
158
160
|
parameters.transmission_frac,
|
|
159
161
|
)
|
|
160
|
-
def
|
|
162
|
+
def run_gridscan_and_fetch_and_tidy(
|
|
161
163
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
162
|
-
params:
|
|
164
|
+
params: HyperionThreeDGridScan,
|
|
163
165
|
feature_controlled: _FeatureControlled,
|
|
164
|
-
):
|
|
165
|
-
yield from
|
|
166
|
+
) -> MsgGenerator:
|
|
167
|
+
yield from run_gridscan_and_fetch_results(
|
|
168
|
+
fgs_composite, params, feature_controlled
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
yield from run_gridscan_and_fetch_and_tidy(
|
|
172
|
+
composite, parameters, feature_controlled
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def flyscan_xray_centre(
|
|
177
|
+
composite: FlyScanXRayCentreComposite,
|
|
178
|
+
parameters: HyperionThreeDGridScan,
|
|
179
|
+
) -> MsgGenerator:
|
|
180
|
+
"""Create the plan to run the grid scan based on provided parameters.
|
|
181
|
+
|
|
182
|
+
The ispyb handler should be added to the whole gridscan as we want to capture errors
|
|
183
|
+
at any point in it.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
parameters (ThreeDGridScan): The parameters to run the scan.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Generator: The plan for the gridscan
|
|
190
|
+
"""
|
|
191
|
+
xrc_event_handler = XRayCentreEventHandler()
|
|
192
|
+
|
|
193
|
+
@bpp.subs_decorator(xrc_event_handler)
|
|
194
|
+
def flyscan_and_fetch_results() -> MsgGenerator:
|
|
195
|
+
yield from ispyb_activation_wrapper(
|
|
196
|
+
flyscan_xray_centre_no_move(composite, parameters), parameters
|
|
197
|
+
)
|
|
166
198
|
|
|
167
|
-
|
|
199
|
+
yield from flyscan_and_fetch_results()
|
|
200
|
+
|
|
201
|
+
xray_centre_results = xrc_event_handler.xray_centre_results
|
|
202
|
+
assert (
|
|
203
|
+
xray_centre_results
|
|
204
|
+
), "Flyscan result event not received or no crystal found and exception not raised"
|
|
205
|
+
yield from change_aperture_then_move_to_xtal(
|
|
206
|
+
xray_centre_results[0],
|
|
207
|
+
composite.smargon,
|
|
208
|
+
composite.aperture_scatterguard,
|
|
209
|
+
parameters,
|
|
210
|
+
)
|
|
168
211
|
|
|
169
212
|
|
|
170
213
|
@bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_AND_MOVE)
|
|
171
214
|
@bpp.run_decorator(md={"subplan_name": CONST.PLAN.GRIDSCAN_AND_MOVE})
|
|
172
|
-
def
|
|
215
|
+
def run_gridscan_and_fetch_results(
|
|
173
216
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
174
|
-
parameters:
|
|
217
|
+
parameters: HyperionThreeDGridScan,
|
|
175
218
|
feature_controlled: _FeatureControlled,
|
|
176
219
|
) -> MsgGenerator:
|
|
177
220
|
"""A multi-run plan which runs a gridscan, gets the results from zocalo
|
|
178
|
-
and
|
|
221
|
+
and fires an event with the centres of mass determined by zocalo"""
|
|
179
222
|
|
|
180
223
|
# We get the initial motor positions so we can return to them on zocalo failure
|
|
181
224
|
initial_xyz = np.array(
|
|
@@ -202,51 +245,66 @@ def run_gridscan_and_move(
|
|
|
202
245
|
[fgs_composite.zocalo], name=ZOCALO_READING_PLAN_NAME
|
|
203
246
|
)
|
|
204
247
|
LOGGER.info("Zocalo triggered and read, interpreting results.")
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
)
|
|
248
|
+
xrc_results = yield from get_full_processing_results(fgs_composite.zocalo)
|
|
249
|
+
LOGGER.info(f"Got xray centres, top 5: {xrc_results[:5]}")
|
|
250
|
+
if xrc_results:
|
|
251
|
+
flyscan_results = [
|
|
252
|
+
_xrc_result_in_boxes_to_result_in_mm(xr, parameters)
|
|
253
|
+
for xr in xrc_results
|
|
254
|
+
]
|
|
213
255
|
else:
|
|
214
256
|
LOGGER.warning("No X-ray centre received")
|
|
215
257
|
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
|
-
)
|
|
258
|
+
yield from _fire_xray_centre_result_event(flyscan_results)
|
|
259
|
+
|
|
235
260
|
finally:
|
|
236
261
|
# Turn off dev/shm streaming to avoid filling disk, see https://github.com/DiamondLightSource/hyperion/issues/1395
|
|
237
262
|
LOGGER.info("Turning off Eiger dev/shm streaming")
|
|
238
|
-
yield from bps.abs_set(fgs_composite.eiger.odin.fan.dev_shm_enable, 0)
|
|
263
|
+
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
264
|
|
|
240
265
|
# Wait on everything before returning to GDA (particularly apertures), can be removed
|
|
241
266
|
# when we do not return to GDA here
|
|
242
267
|
yield from bps.wait()
|
|
243
268
|
|
|
244
269
|
|
|
270
|
+
def _xrc_result_in_boxes_to_result_in_mm(
|
|
271
|
+
xrc_result: XrcResult, parameters: HyperionThreeDGridScan
|
|
272
|
+
) -> XRayCentreResult:
|
|
273
|
+
fgs_params = parameters.FGS_params
|
|
274
|
+
xray_centre = fgs_params.grid_position_to_motor_position(
|
|
275
|
+
np.array(xrc_result["centre_of_mass"])
|
|
276
|
+
)
|
|
277
|
+
return XRayCentreResult(
|
|
278
|
+
centre_of_mass_mm=xray_centre,
|
|
279
|
+
bounding_box_mm=(
|
|
280
|
+
fgs_params.grid_position_to_motor_position(
|
|
281
|
+
np.array(xrc_result["bounding_box"][0])
|
|
282
|
+
),
|
|
283
|
+
fgs_params.grid_position_to_motor_position(
|
|
284
|
+
np.array(xrc_result["bounding_box"][1])
|
|
285
|
+
),
|
|
286
|
+
),
|
|
287
|
+
max_count=xrc_result["max_count"],
|
|
288
|
+
total_count=xrc_result["total_count"],
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
@bpp.set_run_key_decorator(CONST.PLAN.FLYSCAN_RESULTS)
|
|
293
|
+
def _fire_xray_centre_result_event(results: Sequence[XRayCentreResult]):
|
|
294
|
+
def empty_plan():
|
|
295
|
+
return iter([])
|
|
296
|
+
|
|
297
|
+
yield from bpp.run_wrapper(
|
|
298
|
+
empty_plan(),
|
|
299
|
+
md={"xray_centre_results": [dataclasses.asdict(r) for r in results]},
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
|
|
245
303
|
@bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_MAIN)
|
|
246
304
|
@bpp.run_decorator(md={"subplan_name": CONST.PLAN.GRIDSCAN_MAIN})
|
|
247
305
|
def run_gridscan(
|
|
248
306
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
249
|
-
parameters:
|
|
307
|
+
parameters: HyperionThreeDGridScan,
|
|
250
308
|
feature_controlled: _FeatureControlled,
|
|
251
309
|
md={ # noqa
|
|
252
310
|
"plan_name": CONST.PLAN.GRIDSCAN_MAIN,
|
|
@@ -266,7 +324,7 @@ def run_gridscan(
|
|
|
266
324
|
fgs_composite.undulator,
|
|
267
325
|
fgs_composite.synchrotron,
|
|
268
326
|
fgs_composite.s4_slit_gaps,
|
|
269
|
-
fgs_composite.
|
|
327
|
+
fgs_composite.dcm,
|
|
270
328
|
fgs_composite.smargon,
|
|
271
329
|
)
|
|
272
330
|
|
|
@@ -287,7 +345,7 @@ def run_gridscan(
|
|
|
287
345
|
|
|
288
346
|
LOGGER.info("Waiting for arming to finish")
|
|
289
347
|
yield from bps.wait(CONST.WAIT.GRID_READY_FOR_DC)
|
|
290
|
-
yield from bps.stage(fgs_composite.eiger)
|
|
348
|
+
yield from bps.stage(fgs_composite.eiger) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
291
349
|
|
|
292
350
|
yield from kickoff_and_complete_gridscan(
|
|
293
351
|
feature_controlled.fgs_motors,
|
|
@@ -295,66 +353,11 @@ def run_gridscan(
|
|
|
295
353
|
fgs_composite.synchrotron,
|
|
296
354
|
[parameters.scan_points_first_grid, parameters.scan_points_second_grid],
|
|
297
355
|
parameters.scan_indices,
|
|
298
|
-
|
|
356
|
+
plan_during_collection=read_during_collection,
|
|
299
357
|
)
|
|
300
358
|
yield from bps.abs_set(feature_controlled.fgs_motors.z_steps, 0, wait=False)
|
|
301
359
|
|
|
302
360
|
|
|
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
361
|
def wait_for_gridscan_valid(fgs_motors: FastGridScanCommon, timeout=0.5):
|
|
359
362
|
LOGGER.info("Waiting for valid fgs_params")
|
|
360
363
|
SLEEP_PER_CHECK = 0.1
|
|
@@ -369,32 +372,7 @@ def wait_for_gridscan_valid(fgs_motors: FastGridScanCommon, timeout=0.5):
|
|
|
369
372
|
LOGGER.info("Gridscan scan valid and position counter reset")
|
|
370
373
|
return
|
|
371
374
|
yield from bps.sleep(SLEEP_PER_CHECK)
|
|
372
|
-
raise
|
|
373
|
-
|
|
374
|
-
|
|
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()
|
|
375
|
+
raise SampleException("Scan invalid - pin too long/short/bent and out of range")
|
|
398
376
|
|
|
399
377
|
|
|
400
378
|
@dataclasses.dataclass
|
|
@@ -408,7 +386,7 @@ class _FeatureControlled:
|
|
|
408
386
|
def __call__(
|
|
409
387
|
self,
|
|
410
388
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
411
|
-
parameters:
|
|
389
|
+
parameters: HyperionThreeDGridScan,
|
|
412
390
|
initial_xyz: np.ndarray,
|
|
413
391
|
) -> MsgGenerator: ...
|
|
414
392
|
|
|
@@ -420,7 +398,7 @@ class _FeatureControlled:
|
|
|
420
398
|
|
|
421
399
|
def _get_feature_controlled(
|
|
422
400
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
423
|
-
parameters:
|
|
401
|
+
parameters: HyperionThreeDGridScan,
|
|
424
402
|
):
|
|
425
403
|
if parameters.features.use_panda_for_gridscan:
|
|
426
404
|
return _FeatureControlled(
|
|
@@ -469,7 +447,7 @@ def _panda_tidy(fgs_composite: FlyScanXRayCentreComposite):
|
|
|
469
447
|
|
|
470
448
|
def _zebra_triggering_setup(
|
|
471
449
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
472
|
-
parameters:
|
|
450
|
+
parameters: HyperionThreeDGridScan,
|
|
473
451
|
initial_xyz: np.ndarray,
|
|
474
452
|
):
|
|
475
453
|
yield from setup_zebra_for_gridscan(
|
|
@@ -479,7 +457,7 @@ def _zebra_triggering_setup(
|
|
|
479
457
|
|
|
480
458
|
def _panda_triggering_setup(
|
|
481
459
|
fgs_composite: FlyScanXRayCentreComposite,
|
|
482
|
-
parameters:
|
|
460
|
+
parameters: HyperionThreeDGridScan,
|
|
483
461
|
initial_xyz: np.ndarray,
|
|
484
462
|
):
|
|
485
463
|
LOGGER.info("Setting up Panda for flyscan")
|
|
@@ -498,15 +476,15 @@ def _panda_triggering_setup(
|
|
|
498
476
|
)
|
|
499
477
|
|
|
500
478
|
sample_velocity_mm_per_s = (
|
|
501
|
-
parameters.panda_FGS_params.
|
|
479
|
+
parameters.panda_FGS_params.x_step_size_mm * 1e3 / time_between_x_steps_ms
|
|
502
480
|
)
|
|
503
481
|
if sample_velocity_mm_per_s > smargon_speed_limit_mm_per_s:
|
|
504
482
|
raise SmargonSpeedException(
|
|
505
483
|
f"Smargon speed was calculated from x step size\
|
|
506
|
-
{parameters.panda_FGS_params.
|
|
484
|
+
{parameters.panda_FGS_params.x_step_size_mm}mm and\
|
|
507
485
|
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}
|
|
486
|
+
{sample_velocity_mm_per_s}mm/s. The smargon's speed limit is\
|
|
487
|
+
{smargon_speed_limit_mm_per_s}mm/s."
|
|
510
488
|
)
|
|
511
489
|
else:
|
|
512
490
|
LOGGER.info(
|
|
@@ -515,8 +493,8 @@ def _panda_triggering_setup(
|
|
|
515
493
|
)
|
|
516
494
|
|
|
517
495
|
yield from bps.mv(
|
|
518
|
-
fgs_composite.panda_fast_grid_scan.time_between_x_steps_ms,
|
|
519
|
-
time_between_x_steps_ms,
|
|
496
|
+
fgs_composite.panda_fast_grid_scan.time_between_x_steps_ms, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
497
|
+
time_between_x_steps_ms, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
520
498
|
)
|
|
521
499
|
|
|
522
500
|
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,8 @@ 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,
|
|
133
145
|
)
|
|
134
146
|
|
|
135
147
|
yield from run_grid_detection_plan(
|
|
@@ -148,7 +160,7 @@ def detect_grid_and_do_gridscan(
|
|
|
148
160
|
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
149
161
|
)
|
|
150
162
|
|
|
151
|
-
yield from
|
|
163
|
+
yield from flyscan_xray_centre_no_move(
|
|
152
164
|
FlyScanXRayCentreComposite(
|
|
153
165
|
aperture_scatterguard=composite.aperture_scatterguard,
|
|
154
166
|
attenuator=composite.attenuator,
|
|
@@ -178,7 +190,7 @@ def detect_grid_and_do_gridscan(
|
|
|
178
190
|
def grid_detect_then_xray_centre(
|
|
179
191
|
composite: GridDetectThenXRayCentreComposite,
|
|
180
192
|
parameters: GridScanWithEdgeDetect,
|
|
181
|
-
oav_config: str = OAV_CONFIG_JSON,
|
|
193
|
+
oav_config: str = OavConstants.OAV_CONFIG_JSON,
|
|
182
194
|
) -> MsgGenerator:
|
|
183
195
|
"""
|
|
184
196
|
A plan which combines the collection of snapshots from the OAV and the determination
|
|
@@ -191,19 +203,33 @@ def grid_detect_then_xray_centre(
|
|
|
191
203
|
|
|
192
204
|
oav_params = OAVParameters("xrayCentring", oav_config)
|
|
193
205
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
206
|
+
flyscan_event_handler = XRayCentreEventHandler()
|
|
207
|
+
|
|
208
|
+
@subs_decorator(flyscan_event_handler)
|
|
209
|
+
def plan_to_perform():
|
|
210
|
+
yield from ispyb_activation_wrapper(
|
|
211
|
+
detect_grid_and_do_gridscan(
|
|
212
|
+
composite,
|
|
213
|
+
parameters,
|
|
214
|
+
oav_params,
|
|
215
|
+
),
|
|
197
216
|
parameters,
|
|
198
|
-
|
|
199
|
-
),
|
|
200
|
-
parameters,
|
|
201
|
-
)
|
|
217
|
+
)
|
|
202
218
|
|
|
203
|
-
|
|
219
|
+
yield from start_preparing_data_collection_then_do_plan(
|
|
204
220
|
eiger,
|
|
205
221
|
composite.detector_motion,
|
|
206
222
|
parameters.detector_params.detector_distance,
|
|
207
|
-
plan_to_perform,
|
|
223
|
+
plan_to_perform(),
|
|
208
224
|
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
209
225
|
)
|
|
226
|
+
|
|
227
|
+
assert (
|
|
228
|
+
flyscan_event_handler.xray_centre_results
|
|
229
|
+
), "Flyscan result event not received or no crystal found and exception not raised"
|
|
230
|
+
|
|
231
|
+
yield from change_aperture_then_move_to_xtal(
|
|
232
|
+
flyscan_event_handler.xray_centre_results[0],
|
|
233
|
+
composite.smargon,
|
|
234
|
+
composite.aperture_scatterguard,
|
|
235
|
+
)
|