mx-bluesky 0.3.1__py3-none-any.whl → 1.2.0__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/_version.py +2 -2
- mx_bluesky/beamlines/i04/__init__.py +3 -0
- mx_bluesky/{i04 → beamlines/i04}/thawing_plan.py +5 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/blueapi_config.yaml +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/dcid.py +2 -2
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/DetStage.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +7 -7
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +12 -9
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/CustomChip_py3v1.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/DetStage.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +245 -200
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/MappingLite-oxford_py3v1.edl +4 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +8 -8
- mx_bluesky/beamlines/i24/serial/fixed_target/__init__.py +0 -0
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +80 -70
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +20 -21
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +5 -5
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +7 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_moveonclick.py +59 -39
- mx_bluesky/{i24 → beamlines/i24}/serial/log.py +1 -9
- mx_bluesky/beamlines/i24/serial/parameters/__init__.py +15 -0
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/constants.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/experiment_parameters.py +4 -25
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/utils.py +5 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/run_serial.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/pv_abstract.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_beamline.py +2 -2
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_detector.py +5 -5
- mx_bluesky/{i24 → beamlines/i24}/serial/write_nexus.py +6 -3
- mx_bluesky/hyperion/__init__.py +1 -0
- mx_bluesky/hyperion/__main__.py +374 -0
- mx_bluesky/hyperion/device_setup_plans/__init__.py +0 -0
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +134 -0
- mx_bluesky/hyperion/device_setup_plans/manipulate_sample.py +110 -0
- mx_bluesky/hyperion/device_setup_plans/position_detector.py +16 -0
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +60 -0
- mx_bluesky/hyperion/device_setup_plans/setup_oav.py +87 -0
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +210 -0
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +214 -0
- mx_bluesky/hyperion/device_setup_plans/smargon.py +25 -0
- mx_bluesky/hyperion/device_setup_plans/utils.py +55 -0
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +93 -0
- mx_bluesky/hyperion/exceptions.py +47 -0
- mx_bluesky/hyperion/experiment_plans/__init__.py +30 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +93 -0
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +537 -0
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +209 -0
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +46 -0
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +173 -0
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +81 -0
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +463 -0
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +119 -0
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +164 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +237 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +162 -0
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +436 -0
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +60 -0
- mx_bluesky/hyperion/external_interaction/__init__.py +9 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__init__.py +10 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +148 -0
- mx_bluesky/hyperion/external_interaction/callbacks/aperture_change_callback.py +22 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +64 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +62 -0
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +88 -0
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +203 -0
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +20 -0
- mx_bluesky/hyperion/external_interaction/callbacks/logging_callback.py +29 -0
- mx_bluesky/hyperion/external_interaction/callbacks/plan_reactive_callback.py +101 -0
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +86 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +174 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +17 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +102 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +269 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_mapping.py +53 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +95 -0
- mx_bluesky/hyperion/external_interaction/callbacks/zocalo_callback.py +92 -0
- mx_bluesky/hyperion/external_interaction/config_server.py +35 -0
- mx_bluesky/hyperion/external_interaction/exceptions.py +13 -0
- mx_bluesky/hyperion/external_interaction/ispyb/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/ispyb/data_model.py +95 -0
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +125 -0
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +276 -0
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_utils.py +27 -0
- mx_bluesky/hyperion/external_interaction/nexus/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +148 -0
- mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +114 -0
- mx_bluesky/hyperion/log.py +99 -0
- mx_bluesky/hyperion/parameters/__init__.py +2 -0
- mx_bluesky/hyperion/parameters/cli.py +68 -0
- mx_bluesky/{parameters → hyperion/parameters}/components.py +80 -26
- mx_bluesky/hyperion/parameters/constants.py +158 -0
- mx_bluesky/hyperion/parameters/gridscan.py +221 -0
- mx_bluesky/hyperion/parameters/load_centre_collect.py +50 -0
- mx_bluesky/hyperion/parameters/robot_load.py +16 -0
- mx_bluesky/hyperion/parameters/rotation.py +160 -0
- mx_bluesky/hyperion/resources/panda/panda-gridscan.yaml +964 -0
- mx_bluesky/hyperion/tracing.py +28 -0
- mx_bluesky/hyperion/utils/context.py +84 -0
- mx_bluesky/hyperion/utils/utils.py +25 -0
- mx_bluesky/hyperion/utils/validation.py +196 -0
- mx_bluesky/jupyter_example.ipynb +3 -2
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.2.0.dist-info}/METADATA +26 -11
- mx_bluesky-1.2.0.dist-info/RECORD +140 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.2.0.dist-info}/WHEEL +1 -1
- mx_bluesky-1.2.0.dist-info/entry_points.txt +8 -0
- mx_bluesky/i04/__init__.py +0 -3
- mx_bluesky/i24/serial/parameters/__init__.py +0 -15
- mx_bluesky/parameters/__init__.py +0 -31
- mx_bluesky-0.3.1.dist-info/RECORD +0 -67
- mx_bluesky-0.3.1.dist-info/entry_points.txt +0 -4
- /mx_bluesky/{i24 → beamlines}/__init__.py +0 -0
- /mx_bluesky/{i04 → beamlines/i04}/callbacks/murko_callback.py +0 -0
- /mx_bluesky/{i24/serial/extruder → beamlines/i24}/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/microdrop_alignment.edl +0 -0
- /mx_bluesky/{i24/serial/fixed_target → beamlines/i24/serial/extruder}/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/ME14E-GeneralPurpose.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/PMAC_Command.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/Shutter_Control.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/microdrop_alignment.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/nudgechip.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/short1-laser.png +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/short2-laser.png +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/ft_utils.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/cs/cs_maker.json +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/cs/motor_direction.txt +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/pvar_files/minichip-oxford.pvar +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/pvar_files/oxford.pvar +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_extruder.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_fixed_target.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_ssx.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/set_visit_directory.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/ca.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/pv.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_zebra_plans.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/start_blueapi.sh +0 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.2.0.dist-info}/LICENSE +0 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from functools import partial
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from time import time
|
|
8
|
+
from typing import Protocol
|
|
9
|
+
|
|
10
|
+
import bluesky.plan_stubs as bps
|
|
11
|
+
import bluesky.preprocessors as bpp
|
|
12
|
+
import numpy as np
|
|
13
|
+
from blueapi.core import BlueskyContext, MsgGenerator
|
|
14
|
+
from dodal.devices.aperturescatterguard import (
|
|
15
|
+
ApertureScatterguard,
|
|
16
|
+
ApertureValue,
|
|
17
|
+
)
|
|
18
|
+
from dodal.devices.attenuator import Attenuator
|
|
19
|
+
from dodal.devices.backlight import Backlight
|
|
20
|
+
from dodal.devices.dcm import DCM
|
|
21
|
+
from dodal.devices.eiger import EigerDetector
|
|
22
|
+
from dodal.devices.fast_grid_scan import (
|
|
23
|
+
FastGridScanCommon,
|
|
24
|
+
PandAFastGridScan,
|
|
25
|
+
ZebraFastGridScan,
|
|
26
|
+
)
|
|
27
|
+
from dodal.devices.fast_grid_scan import (
|
|
28
|
+
set_fast_grid_scan_params as set_flyscan_params,
|
|
29
|
+
)
|
|
30
|
+
from dodal.devices.flux import Flux
|
|
31
|
+
from dodal.devices.robot import BartRobot
|
|
32
|
+
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
33
|
+
from dodal.devices.smargon import Smargon, StubPosition
|
|
34
|
+
from dodal.devices.synchrotron import Synchrotron
|
|
35
|
+
from dodal.devices.undulator import Undulator
|
|
36
|
+
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
37
|
+
from dodal.devices.zebra import Zebra
|
|
38
|
+
from dodal.devices.zebra_controlled_shutter import ZebraShutter
|
|
39
|
+
from dodal.devices.zocalo.zocalo_results import (
|
|
40
|
+
ZOCALO_READING_PLAN_NAME,
|
|
41
|
+
ZOCALO_STAGE_GROUP,
|
|
42
|
+
ZocaloResults,
|
|
43
|
+
get_processing_result,
|
|
44
|
+
)
|
|
45
|
+
from dodal.plans.check_topup import check_topup_and_wait_if_necessary
|
|
46
|
+
from ophyd_async.fastcs.panda import HDFPanda
|
|
47
|
+
from scanspec.core import AxesPoints, Axis
|
|
48
|
+
|
|
49
|
+
from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import move_x_y_z
|
|
50
|
+
from mx_bluesky.hyperion.device_setup_plans.read_hardware_for_setup import (
|
|
51
|
+
read_hardware_during_collection,
|
|
52
|
+
read_hardware_for_zocalo,
|
|
53
|
+
read_hardware_pre_collection,
|
|
54
|
+
)
|
|
55
|
+
from mx_bluesky.hyperion.device_setup_plans.setup_panda import (
|
|
56
|
+
disarm_panda_for_gridscan,
|
|
57
|
+
set_panda_directory,
|
|
58
|
+
setup_panda_for_flyscan,
|
|
59
|
+
)
|
|
60
|
+
from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
|
|
61
|
+
setup_zebra_for_gridscan,
|
|
62
|
+
setup_zebra_for_panda_flyscan,
|
|
63
|
+
tidy_up_zebra_after_gridscan,
|
|
64
|
+
)
|
|
65
|
+
from mx_bluesky.hyperion.device_setup_plans.xbpm_feedback import (
|
|
66
|
+
transmission_and_xbpm_feedback_for_collection_decorator,
|
|
67
|
+
)
|
|
68
|
+
from mx_bluesky.hyperion.exceptions import WarningException
|
|
69
|
+
from mx_bluesky.hyperion.log import LOGGER
|
|
70
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
71
|
+
from mx_bluesky.hyperion.parameters.gridscan import ThreeDGridScan
|
|
72
|
+
from mx_bluesky.hyperion.tracing import TRACER
|
|
73
|
+
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class SmargonSpeedException(Exception):
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class CrystalNotFoundException(WarningException):
|
|
81
|
+
"""Raised if grid detection completed normally but no crystal was found."""
|
|
82
|
+
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclasses.dataclass
|
|
87
|
+
class FlyScanXRayCentreComposite:
|
|
88
|
+
"""All devices which are directly or indirectly required by this plan"""
|
|
89
|
+
|
|
90
|
+
aperture_scatterguard: ApertureScatterguard
|
|
91
|
+
attenuator: Attenuator
|
|
92
|
+
backlight: Backlight
|
|
93
|
+
dcm: DCM
|
|
94
|
+
eiger: EigerDetector
|
|
95
|
+
zebra_fast_grid_scan: ZebraFastGridScan
|
|
96
|
+
flux: Flux
|
|
97
|
+
s4_slit_gaps: S4SlitGaps
|
|
98
|
+
smargon: Smargon
|
|
99
|
+
undulator: Undulator
|
|
100
|
+
synchrotron: Synchrotron
|
|
101
|
+
xbpm_feedback: XBPMFeedback
|
|
102
|
+
zebra: Zebra
|
|
103
|
+
zocalo: ZocaloResults
|
|
104
|
+
panda: HDFPanda
|
|
105
|
+
panda_fast_grid_scan: PandAFastGridScan
|
|
106
|
+
robot: BartRobot
|
|
107
|
+
sample_shutter: ZebraShutter
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def sample_motors(self) -> Smargon:
|
|
111
|
+
"""Convenience alias with a more user-friendly name"""
|
|
112
|
+
return self.smargon
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def create_devices(context: BlueskyContext) -> FlyScanXRayCentreComposite:
|
|
116
|
+
"""Creates the devices required for the plan and connect to them"""
|
|
117
|
+
return device_composite_from_context(context, FlyScanXRayCentreComposite)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def flyscan_xray_centre(
|
|
121
|
+
composite: FlyScanXRayCentreComposite,
|
|
122
|
+
parameters: ThreeDGridScan,
|
|
123
|
+
) -> MsgGenerator:
|
|
124
|
+
"""Create the plan to run the grid scan based on provided parameters.
|
|
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
|
+
"""
|
|
135
|
+
parameters.features.update_self_from_server()
|
|
136
|
+
composite.eiger.set_detector_parameters(parameters.detector_params)
|
|
137
|
+
composite.zocalo.zocalo_environment = parameters.zocalo_environment
|
|
138
|
+
composite.zocalo.use_cpu_and_gpu = parameters.use_cpu_and_gpu_zocalo
|
|
139
|
+
|
|
140
|
+
feature_controlled = _get_feature_controlled(composite, parameters)
|
|
141
|
+
|
|
142
|
+
@bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_OUTER)
|
|
143
|
+
@bpp.run_decorator( # attach experiment metadata to the start document
|
|
144
|
+
md={
|
|
145
|
+
"subplan_name": CONST.PLAN.GRIDSCAN_OUTER,
|
|
146
|
+
CONST.TRIGGER.ZOCALO: CONST.PLAN.DO_FGS,
|
|
147
|
+
"zocalo_environment": parameters.zocalo_environment,
|
|
148
|
+
"hyperion_parameters": parameters.model_dump_json(),
|
|
149
|
+
"activate_callbacks": [
|
|
150
|
+
"GridscanNexusFileCallback",
|
|
151
|
+
],
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
@bpp.finalize_decorator(lambda: feature_controlled.tidy_plan(composite))
|
|
155
|
+
@transmission_and_xbpm_feedback_for_collection_decorator(
|
|
156
|
+
composite.xbpm_feedback,
|
|
157
|
+
composite.attenuator,
|
|
158
|
+
parameters.transmission_frac,
|
|
159
|
+
)
|
|
160
|
+
def run_gridscan_and_move_and_tidy(
|
|
161
|
+
fgs_composite: FlyScanXRayCentreComposite,
|
|
162
|
+
params: ThreeDGridScan,
|
|
163
|
+
feature_controlled: _FeatureControlled,
|
|
164
|
+
):
|
|
165
|
+
yield from run_gridscan_and_move(fgs_composite, params, feature_controlled)
|
|
166
|
+
|
|
167
|
+
return run_gridscan_and_move_and_tidy(composite, parameters, feature_controlled)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_AND_MOVE)
|
|
171
|
+
@bpp.run_decorator(md={"subplan_name": CONST.PLAN.GRIDSCAN_AND_MOVE})
|
|
172
|
+
def run_gridscan_and_move(
|
|
173
|
+
fgs_composite: FlyScanXRayCentreComposite,
|
|
174
|
+
parameters: ThreeDGridScan,
|
|
175
|
+
feature_controlled: _FeatureControlled,
|
|
176
|
+
) -> MsgGenerator:
|
|
177
|
+
"""A multi-run plan which runs a gridscan, gets the results from zocalo
|
|
178
|
+
and moves to the centre of mass determined by zocalo"""
|
|
179
|
+
|
|
180
|
+
# We get the initial motor positions so we can return to them on zocalo failure
|
|
181
|
+
initial_xyz = np.array(
|
|
182
|
+
[
|
|
183
|
+
(yield from bps.rd(fgs_composite.sample_motors.x)),
|
|
184
|
+
(yield from bps.rd(fgs_composite.sample_motors.y)),
|
|
185
|
+
(yield from bps.rd(fgs_composite.sample_motors.z)),
|
|
186
|
+
]
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
yield from feature_controlled.setup_trigger(fgs_composite, parameters, initial_xyz)
|
|
190
|
+
|
|
191
|
+
LOGGER.info("Starting grid scan")
|
|
192
|
+
yield from bps.stage(
|
|
193
|
+
fgs_composite.zocalo, group=ZOCALO_STAGE_GROUP
|
|
194
|
+
) # connect to zocalo and make sure the queue is clear
|
|
195
|
+
yield from run_gridscan(fgs_composite, parameters, feature_controlled)
|
|
196
|
+
|
|
197
|
+
LOGGER.info("Grid scan finished, getting results.")
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
with TRACER.start_span("wait_for_zocalo"):
|
|
201
|
+
yield from bps.trigger_and_read(
|
|
202
|
+
[fgs_composite.zocalo], name=ZOCALO_READING_PLAN_NAME
|
|
203
|
+
)
|
|
204
|
+
LOGGER.info("Zocalo triggered and read, interpreting results.")
|
|
205
|
+
xray_centre, bbox_size = yield from get_processing_result(
|
|
206
|
+
fgs_composite.zocalo
|
|
207
|
+
)
|
|
208
|
+
LOGGER.info(f"Got xray centre: {xray_centre}, bbox size: {bbox_size}")
|
|
209
|
+
if xray_centre is not None:
|
|
210
|
+
xray_centre = parameters.FGS_params.grid_position_to_motor_position(
|
|
211
|
+
xray_centre
|
|
212
|
+
)
|
|
213
|
+
else:
|
|
214
|
+
LOGGER.warning("No X-ray centre received")
|
|
215
|
+
raise CrystalNotFoundException()
|
|
216
|
+
if bbox_size is not None:
|
|
217
|
+
with TRACER.start_span("change_aperture"):
|
|
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
|
+
)
|
|
235
|
+
finally:
|
|
236
|
+
# Turn off dev/shm streaming to avoid filling disk, see https://github.com/DiamondLightSource/hyperion/issues/1395
|
|
237
|
+
LOGGER.info("Turning off Eiger dev/shm streaming")
|
|
238
|
+
yield from bps.abs_set(fgs_composite.eiger.odin.fan.dev_shm_enable, 0)
|
|
239
|
+
|
|
240
|
+
# Wait on everything before returning to GDA (particularly apertures), can be removed
|
|
241
|
+
# when we do not return to GDA here
|
|
242
|
+
yield from bps.wait()
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_MAIN)
|
|
246
|
+
@bpp.run_decorator(md={"subplan_name": CONST.PLAN.GRIDSCAN_MAIN})
|
|
247
|
+
def run_gridscan(
|
|
248
|
+
fgs_composite: FlyScanXRayCentreComposite,
|
|
249
|
+
parameters: ThreeDGridScan,
|
|
250
|
+
feature_controlled: _FeatureControlled,
|
|
251
|
+
md={ # noqa
|
|
252
|
+
"plan_name": CONST.PLAN.GRIDSCAN_MAIN,
|
|
253
|
+
},
|
|
254
|
+
):
|
|
255
|
+
sample_motors = fgs_composite.sample_motors
|
|
256
|
+
|
|
257
|
+
# Currently gridscan only works for omega 0, see #
|
|
258
|
+
with TRACER.start_span("moving_omega_to_0"):
|
|
259
|
+
yield from bps.abs_set(sample_motors.omega, 0)
|
|
260
|
+
|
|
261
|
+
# We only subscribe to the communicator callback for run_gridscan, so this is where
|
|
262
|
+
# we should generate an event reading the values which need to be included in the
|
|
263
|
+
# ispyb deposition
|
|
264
|
+
with TRACER.start_span("ispyb_hardware_readings"):
|
|
265
|
+
yield from read_hardware_pre_collection(
|
|
266
|
+
fgs_composite.undulator,
|
|
267
|
+
fgs_composite.synchrotron,
|
|
268
|
+
fgs_composite.s4_slit_gaps,
|
|
269
|
+
fgs_composite.robot,
|
|
270
|
+
fgs_composite.smargon,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
read_during_collection = partial(
|
|
274
|
+
read_hardware_during_collection,
|
|
275
|
+
fgs_composite.aperture_scatterguard,
|
|
276
|
+
fgs_composite.attenuator,
|
|
277
|
+
fgs_composite.flux,
|
|
278
|
+
fgs_composite.dcm,
|
|
279
|
+
fgs_composite.eiger,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
LOGGER.info("Setting fgs params")
|
|
283
|
+
yield from feature_controlled.set_flyscan_params()
|
|
284
|
+
|
|
285
|
+
LOGGER.info("Waiting for gridscan validity check")
|
|
286
|
+
yield from wait_for_gridscan_valid(feature_controlled.fgs_motors)
|
|
287
|
+
|
|
288
|
+
LOGGER.info("Waiting for arming to finish")
|
|
289
|
+
yield from bps.wait(CONST.WAIT.GRID_READY_FOR_DC)
|
|
290
|
+
yield from bps.stage(fgs_composite.eiger)
|
|
291
|
+
|
|
292
|
+
yield from kickoff_and_complete_gridscan(
|
|
293
|
+
feature_controlled.fgs_motors,
|
|
294
|
+
fgs_composite.eiger,
|
|
295
|
+
fgs_composite.synchrotron,
|
|
296
|
+
[parameters.scan_points_first_grid, parameters.scan_points_second_grid],
|
|
297
|
+
parameters.scan_indices,
|
|
298
|
+
do_during_run=read_during_collection,
|
|
299
|
+
)
|
|
300
|
+
yield from bps.abs_set(feature_controlled.fgs_motors.z_steps, 0, wait=False)
|
|
301
|
+
|
|
302
|
+
|
|
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
|
+
def wait_for_gridscan_valid(fgs_motors: FastGridScanCommon, timeout=0.5):
|
|
359
|
+
LOGGER.info("Waiting for valid fgs_params")
|
|
360
|
+
SLEEP_PER_CHECK = 0.1
|
|
361
|
+
times_to_check = int(timeout / SLEEP_PER_CHECK)
|
|
362
|
+
for _ in range(times_to_check):
|
|
363
|
+
scan_invalid = yield from bps.rd(fgs_motors.scan_invalid)
|
|
364
|
+
pos_counter = yield from bps.rd(fgs_motors.position_counter)
|
|
365
|
+
LOGGER.debug(
|
|
366
|
+
f"Scan invalid: {scan_invalid} and position counter: {pos_counter}"
|
|
367
|
+
)
|
|
368
|
+
if not scan_invalid and pos_counter == 0:
|
|
369
|
+
LOGGER.info("Gridscan scan valid and position counter reset")
|
|
370
|
+
return
|
|
371
|
+
yield from bps.sleep(SLEEP_PER_CHECK)
|
|
372
|
+
raise WarningException("Scan invalid - pin too long/short/bent and out of range")
|
|
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()
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
@dataclasses.dataclass
|
|
401
|
+
class _FeatureControlled:
|
|
402
|
+
class _ZebraSetup(Protocol):
|
|
403
|
+
def __call__(
|
|
404
|
+
self, zebra: Zebra, group="setup_zebra_for_gridscan", wait=True
|
|
405
|
+
) -> MsgGenerator: ...
|
|
406
|
+
|
|
407
|
+
class _ExtraSetup(Protocol):
|
|
408
|
+
def __call__(
|
|
409
|
+
self,
|
|
410
|
+
fgs_composite: FlyScanXRayCentreComposite,
|
|
411
|
+
parameters: ThreeDGridScan,
|
|
412
|
+
initial_xyz: np.ndarray,
|
|
413
|
+
) -> MsgGenerator: ...
|
|
414
|
+
|
|
415
|
+
setup_trigger: _ExtraSetup
|
|
416
|
+
tidy_plan: Callable[[FlyScanXRayCentreComposite], MsgGenerator]
|
|
417
|
+
set_flyscan_params: Callable[[], MsgGenerator]
|
|
418
|
+
fgs_motors: FastGridScanCommon
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _get_feature_controlled(
|
|
422
|
+
fgs_composite: FlyScanXRayCentreComposite,
|
|
423
|
+
parameters: ThreeDGridScan,
|
|
424
|
+
):
|
|
425
|
+
if parameters.features.use_panda_for_gridscan:
|
|
426
|
+
return _FeatureControlled(
|
|
427
|
+
setup_trigger=_panda_triggering_setup,
|
|
428
|
+
tidy_plan=_panda_tidy,
|
|
429
|
+
set_flyscan_params=partial(
|
|
430
|
+
set_flyscan_params,
|
|
431
|
+
fgs_composite.panda_fast_grid_scan,
|
|
432
|
+
parameters.panda_FGS_params,
|
|
433
|
+
),
|
|
434
|
+
fgs_motors=fgs_composite.panda_fast_grid_scan,
|
|
435
|
+
)
|
|
436
|
+
else:
|
|
437
|
+
return _FeatureControlled(
|
|
438
|
+
setup_trigger=_zebra_triggering_setup,
|
|
439
|
+
tidy_plan=partial(_generic_tidy, group="flyscan_zebra_tidy", wait=True),
|
|
440
|
+
set_flyscan_params=partial(
|
|
441
|
+
set_flyscan_params,
|
|
442
|
+
fgs_composite.zebra_fast_grid_scan,
|
|
443
|
+
parameters.FGS_params,
|
|
444
|
+
),
|
|
445
|
+
fgs_motors=fgs_composite.zebra_fast_grid_scan,
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def _generic_tidy(
|
|
450
|
+
fgs_composite: FlyScanXRayCentreComposite, group, wait=True
|
|
451
|
+
) -> MsgGenerator:
|
|
452
|
+
LOGGER.info("Tidying up Zebra")
|
|
453
|
+
yield from tidy_up_zebra_after_gridscan(
|
|
454
|
+
fgs_composite.zebra, fgs_composite.sample_shutter, group=group, wait=wait
|
|
455
|
+
)
|
|
456
|
+
LOGGER.info("Tidying up Zocalo")
|
|
457
|
+
# make sure we don't consume any other results
|
|
458
|
+
yield from bps.unstage(fgs_composite.zocalo, group=group, wait=wait)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def _panda_tidy(fgs_composite: FlyScanXRayCentreComposite):
|
|
462
|
+
group = "panda_flyscan_tidy"
|
|
463
|
+
LOGGER.info("Disabling panda blocks")
|
|
464
|
+
yield from disarm_panda_for_gridscan(fgs_composite.panda, group)
|
|
465
|
+
yield from _generic_tidy(fgs_composite, group, False)
|
|
466
|
+
yield from bps.wait(group, timeout=10)
|
|
467
|
+
yield from bps.unstage(fgs_composite.panda)
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def _zebra_triggering_setup(
|
|
471
|
+
fgs_composite: FlyScanXRayCentreComposite,
|
|
472
|
+
parameters: ThreeDGridScan,
|
|
473
|
+
initial_xyz: np.ndarray,
|
|
474
|
+
):
|
|
475
|
+
yield from setup_zebra_for_gridscan(
|
|
476
|
+
fgs_composite.zebra, fgs_composite.sample_shutter, wait=True
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def _panda_triggering_setup(
|
|
481
|
+
fgs_composite: FlyScanXRayCentreComposite,
|
|
482
|
+
parameters: ThreeDGridScan,
|
|
483
|
+
initial_xyz: np.ndarray,
|
|
484
|
+
):
|
|
485
|
+
LOGGER.info("Setting up Panda for flyscan")
|
|
486
|
+
|
|
487
|
+
run_up_distance_mm = yield from bps.rd(
|
|
488
|
+
fgs_composite.panda_fast_grid_scan.run_up_distance_mm
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
# Set the time between x steps pv
|
|
492
|
+
DEADTIME_S = 1e-6 # according to https://www.dectris.com/en/detectors/x-ray-detectors/eiger2/eiger2-for-synchrotrons/eiger2-x/
|
|
493
|
+
|
|
494
|
+
time_between_x_steps_ms = (DEADTIME_S + parameters.exposure_time_s) * 1e3
|
|
495
|
+
|
|
496
|
+
smargon_speed_limit_mm_per_s = yield from bps.rd(
|
|
497
|
+
fgs_composite.smargon.x.max_velocity
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
sample_velocity_mm_per_s = (
|
|
501
|
+
parameters.panda_FGS_params.x_step_size * 1e3 / time_between_x_steps_ms
|
|
502
|
+
)
|
|
503
|
+
if sample_velocity_mm_per_s > smargon_speed_limit_mm_per_s:
|
|
504
|
+
raise SmargonSpeedException(
|
|
505
|
+
f"Smargon speed was calculated from x step size\
|
|
506
|
+
{parameters.panda_FGS_params.x_step_size} and\
|
|
507
|
+
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} mm/s."
|
|
510
|
+
)
|
|
511
|
+
else:
|
|
512
|
+
LOGGER.info(
|
|
513
|
+
f"Panda grid scan: Smargon speed set to {smargon_speed_limit_mm_per_s} mm/s"
|
|
514
|
+
f" and using a run-up distance of {run_up_distance_mm}"
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
yield from bps.mv(
|
|
518
|
+
fgs_composite.panda_fast_grid_scan.time_between_x_steps_ms,
|
|
519
|
+
time_between_x_steps_ms,
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
directory_provider_root = Path(parameters.storage_directory)
|
|
523
|
+
yield from set_panda_directory(directory_provider_root)
|
|
524
|
+
|
|
525
|
+
yield from setup_panda_for_flyscan(
|
|
526
|
+
fgs_composite.panda,
|
|
527
|
+
parameters.panda_FGS_params,
|
|
528
|
+
initial_xyz[0],
|
|
529
|
+
parameters.exposure_time_s,
|
|
530
|
+
time_between_x_steps_ms,
|
|
531
|
+
sample_velocity_mm_per_s,
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
LOGGER.info("Setting up Zebra for panda flyscan")
|
|
535
|
+
yield from setup_zebra_for_panda_flyscan(
|
|
536
|
+
fgs_composite.zebra, fgs_composite.sample_shutter, wait=True
|
|
537
|
+
)
|