mx-bluesky 1.4.9__py3-none-any.whl → 1.5.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/_version.py +2 -2
- mx_bluesky/beamlines/i24/serial/__init__.py +4 -2
- mx_bluesky/beamlines/i24/serial/blueapi_config.yaml +4 -0
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +8 -8
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +36 -4
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +6 -5
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +2 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +5 -5
- mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +79 -10
- mx_bluesky/common/device_setup_plans/manipulate_sample.py +4 -1
- mx_bluesky/common/device_setup_plans/robot_load_unload.py +123 -0
- mx_bluesky/common/device_setup_plans/utils.py +49 -0
- mx_bluesky/common/{plans → experiment_plans}/common_flyscan_xray_centre_plan.py +12 -19
- mx_bluesky/{hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py → common/experiment_plans/common_grid_detect_then_xray_centre_plan.py} +108 -136
- mx_bluesky/common/{plans → experiment_plans}/inner_plans/do_fgs.py +1 -1
- mx_bluesky/common/experiment_plans/oav_grid_detection_plan.py +5 -13
- mx_bluesky/{hyperion → common}/experiment_plans/oav_snapshot_plan.py +5 -2
- mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +26 -24
- mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +0 -1
- mx_bluesky/common/external_interaction/nexus/write_nexus.py +2 -2
- mx_bluesky/common/parameters/components.py +8 -3
- mx_bluesky/common/parameters/constants.py +4 -3
- mx_bluesky/common/parameters/device_composites.py +65 -0
- mx_bluesky/common/utils/__init__.py +0 -0
- mx_bluesky/common/xrc_result.py +25 -2
- mx_bluesky/hyperion/device_setup_plans/utils.py +0 -48
- mx_bluesky/hyperion/experiment_plans/__init__.py +3 -3
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +3 -3
- mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +46 -41
- mx_bluesky/hyperion/experiment_plans/hyperion_grid_detect_then_xray_centre_plan.py +60 -0
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +26 -8
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +26 -15
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +21 -75
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +10 -8
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +20 -15
- mx_bluesky/hyperion/external_interaction/agamemnon.py +4 -4
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/{robot_load → robot_actions}/ispyb_callback.py +28 -19
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/snapshot_callback.py +3 -0
- mx_bluesky/hyperion/external_interaction/config_server.py +0 -11
- mx_bluesky/hyperion/parameters/constants.py +1 -6
- mx_bluesky/hyperion/parameters/device_composites.py +5 -27
- mx_bluesky/hyperion/parameters/gridscan.py +2 -6
- mx_bluesky/hyperion/parameters/load_centre_collect.py +15 -0
- mx_bluesky/hyperion/parameters/rotation.py +7 -3
- {mx_bluesky-1.4.9.dist-info → mx_bluesky-1.5.1.dist-info}/METADATA +5 -4
- {mx_bluesky-1.4.9.dist-info → mx_bluesky-1.5.1.dist-info}/RECORD +56 -52
- mx_bluesky/hyperion/utils/validation.py +0 -196
- /mx_bluesky/common/{plans → experiment_plans}/__init__.py +0 -0
- /mx_bluesky/common/{plans → experiment_plans}/inner_plans/__init__ .py +0 -0
- /mx_bluesky/common/{plans → experiment_plans}/read_hardware.py +0 -0
- /mx_bluesky/common/{plans → experiment_plans}/write_sample_status.py +0 -0
- {mx_bluesky-1.4.9.dist-info → mx_bluesky-1.5.1.dist-info}/WHEEL +0 -0
- {mx_bluesky-1.4.9.dist-info → mx_bluesky-1.5.1.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.4.9.dist-info → mx_bluesky-1.5.1.dist-info}/licenses/LICENSE +0 -0
- {mx_bluesky-1.4.9.dist-info → mx_bluesky-1.5.1.dist-info}/top_level.txt +0 -0
|
@@ -10,22 +10,25 @@ import bluesky.preprocessors as bpp
|
|
|
10
10
|
import pydantic
|
|
11
11
|
from blueapi.core import BlueskyContext
|
|
12
12
|
from bluesky.utils import Msg
|
|
13
|
-
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
13
|
+
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
14
14
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
15
15
|
from dodal.devices.backlight import Backlight, BacklightPosition
|
|
16
16
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
17
17
|
from dodal.devices.i03.dcm import DCM
|
|
18
18
|
from dodal.devices.i03.undulator_dcm import UndulatorDCM
|
|
19
|
-
from dodal.devices.motors import
|
|
19
|
+
from dodal.devices.motors import XYZStage
|
|
20
20
|
from dodal.devices.oav.oav_detector import OAV
|
|
21
21
|
from dodal.devices.robot import BartRobot, SampleLocation
|
|
22
|
-
from dodal.devices.smargon import
|
|
22
|
+
from dodal.devices.smargon import Smargon
|
|
23
23
|
from dodal.devices.thawer import Thawer
|
|
24
24
|
from dodal.devices.webcam import Webcam
|
|
25
25
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
26
|
-
from dodal.plan_stubs.motor_utils import MoveTooLarge, home_and_reset_wrapper
|
|
27
26
|
|
|
28
|
-
from mx_bluesky.common.
|
|
27
|
+
from mx_bluesky.common.device_setup_plans.robot_load_unload import (
|
|
28
|
+
do_plan_while_lower_gonio_at_home,
|
|
29
|
+
prepare_for_robot_load,
|
|
30
|
+
wait_for_smargon_not_disabled,
|
|
31
|
+
)
|
|
29
32
|
from mx_bluesky.hyperion.experiment_plans.set_energy_plan import (
|
|
30
33
|
SetEnergyComposite,
|
|
31
34
|
set_energy_plan,
|
|
@@ -47,7 +50,7 @@ class RobotLoadAndEnergyChangeComposite:
|
|
|
47
50
|
# RobotLoad fields
|
|
48
51
|
robot: BartRobot
|
|
49
52
|
webcam: Webcam
|
|
50
|
-
lower_gonio:
|
|
53
|
+
lower_gonio: XYZStage
|
|
51
54
|
thawer: Thawer
|
|
52
55
|
oav: OAV
|
|
53
56
|
smargon: Smargon
|
|
@@ -61,25 +64,6 @@ def create_devices(context: BlueskyContext) -> RobotLoadAndEnergyChangeComposite
|
|
|
61
64
|
return device_composite_from_context(context, RobotLoadAndEnergyChangeComposite)
|
|
62
65
|
|
|
63
66
|
|
|
64
|
-
def wait_for_smargon_not_disabled(smargon: Smargon, timeout=60):
|
|
65
|
-
"""Waits for the smargon disabled flag to go low. The robot hardware is responsible
|
|
66
|
-
for setting this to low when it is safe to move. It does this through a physical
|
|
67
|
-
connection between the robot and the smargon.
|
|
68
|
-
"""
|
|
69
|
-
LOGGER.info("Waiting for smargon enabled")
|
|
70
|
-
SLEEP_PER_CHECK = 0.1
|
|
71
|
-
times_to_check = int(timeout / SLEEP_PER_CHECK)
|
|
72
|
-
for _ in range(times_to_check):
|
|
73
|
-
smargon_disabled = yield from bps.rd(smargon.disabled)
|
|
74
|
-
if not smargon_disabled:
|
|
75
|
-
LOGGER.info("Smargon now enabled")
|
|
76
|
-
return
|
|
77
|
-
yield from bps.sleep(SLEEP_PER_CHECK)
|
|
78
|
-
raise TimeoutError(
|
|
79
|
-
"Timed out waiting for smargon to become enabled after robot load"
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
|
|
83
67
|
def take_robot_snapshots(oav: OAV, webcam: Webcam, directory: Path):
|
|
84
68
|
time_now = datetime.now()
|
|
85
69
|
snapshot_format = f"{time_now.strftime('%H%M%S')}_{{device}}_after_load"
|
|
@@ -93,28 +77,15 @@ def take_robot_snapshots(oav: OAV, webcam: Webcam, directory: Path):
|
|
|
93
77
|
yield from bps.wait("snapshots")
|
|
94
78
|
|
|
95
79
|
|
|
96
|
-
def prepare_for_robot_load(
|
|
97
|
-
aperture_scatterguard: ApertureScatterguard, smargon: Smargon
|
|
98
|
-
):
|
|
99
|
-
yield from bps.abs_set(
|
|
100
|
-
aperture_scatterguard.selected_aperture,
|
|
101
|
-
ApertureValue.OUT_OF_BEAM,
|
|
102
|
-
group="prepare_robot_load",
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
yield from bps.mv(smargon.stub_offsets, StubPosition.RESET_TO_ROBOT_LOAD)
|
|
106
|
-
|
|
107
|
-
yield from bps.mv(smargon, CombinedMove(x=0, y=0, z=0, chi=0, phi=0, omega=0))
|
|
108
|
-
|
|
109
|
-
yield from bps.wait("prepare_robot_load")
|
|
110
|
-
|
|
111
|
-
|
|
112
80
|
def do_robot_load(
|
|
113
81
|
composite: RobotLoadAndEnergyChangeComposite,
|
|
114
82
|
sample_location: SampleLocation,
|
|
83
|
+
sample_id: int,
|
|
115
84
|
demand_energy_ev: float | None,
|
|
116
85
|
thawing_time: float,
|
|
117
86
|
):
|
|
87
|
+
yield from bps.abs_set(composite.robot.next_sample_id, sample_id, wait=True)
|
|
88
|
+
|
|
118
89
|
yield from bps.abs_set(
|
|
119
90
|
composite.robot,
|
|
120
91
|
sample_location,
|
|
@@ -133,16 +104,6 @@ def do_robot_load(
|
|
|
133
104
|
yield from wait_for_smargon_not_disabled(composite.smargon)
|
|
134
105
|
|
|
135
106
|
|
|
136
|
-
def raise_exception_if_moved_out_of_cryojet(exception):
|
|
137
|
-
yield from bps.null()
|
|
138
|
-
if isinstance(exception, MoveTooLarge):
|
|
139
|
-
raise Exception(
|
|
140
|
-
f"Moving {exception.axis} back to {exception.position} after \
|
|
141
|
-
robot load would move it out of the cryojet. The max safe \
|
|
142
|
-
distance is {exception.maximum_move}"
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
|
|
146
107
|
def pin_already_loaded(
|
|
147
108
|
robot: BartRobot, sample_location: SampleLocation
|
|
148
109
|
) -> Generator[Msg, None, bool]:
|
|
@@ -158,6 +119,7 @@ def robot_load_and_snapshots(
|
|
|
158
119
|
composite: RobotLoadAndEnergyChangeComposite,
|
|
159
120
|
location: SampleLocation,
|
|
160
121
|
snapshot_directory: Path,
|
|
122
|
+
sample_id: int,
|
|
161
123
|
thawing_time: float,
|
|
162
124
|
demand_energy_ev: float | None,
|
|
163
125
|
):
|
|
@@ -166,37 +128,25 @@ def robot_load_and_snapshots(
|
|
|
166
128
|
robot_load_plan = do_robot_load(
|
|
167
129
|
composite,
|
|
168
130
|
location,
|
|
131
|
+
sample_id,
|
|
169
132
|
demand_energy_ev,
|
|
170
133
|
thawing_time,
|
|
171
134
|
)
|
|
172
135
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
# to the lower gonio and the move is quicker than the robot takes to get to the
|
|
176
|
-
# load position.
|
|
177
|
-
yield from bpp.contingency_wrapper(
|
|
178
|
-
home_and_reset_wrapper(
|
|
179
|
-
robot_load_plan,
|
|
180
|
-
composite.lower_gonio,
|
|
181
|
-
BartRobot.LOAD_TOLERANCE_MM,
|
|
182
|
-
CONST.HARDWARE.CRYOJET_MARGIN_MM,
|
|
183
|
-
"lower_gonio",
|
|
184
|
-
wait_for_all=False,
|
|
185
|
-
),
|
|
186
|
-
except_plan=raise_exception_if_moved_out_of_cryojet,
|
|
136
|
+
gonio_finished = yield from do_plan_while_lower_gonio_at_home(
|
|
137
|
+
robot_load_plan, composite.lower_gonio
|
|
187
138
|
)
|
|
188
|
-
|
|
189
139
|
yield from bps.wait(group="snapshot")
|
|
190
140
|
|
|
191
141
|
yield from take_robot_snapshots(composite.oav, composite.webcam, snapshot_directory)
|
|
192
142
|
|
|
193
|
-
yield from bps.create(name=CONST.DESCRIPTORS.
|
|
194
|
-
yield from bps.read(composite.robot
|
|
143
|
+
yield from bps.create(name=CONST.DESCRIPTORS.ROBOT_UPDATE)
|
|
144
|
+
yield from bps.read(composite.robot)
|
|
195
145
|
yield from bps.read(composite.oav.snapshot)
|
|
196
146
|
yield from bps.read(composite.webcam)
|
|
197
147
|
yield from bps.save()
|
|
198
148
|
|
|
199
|
-
yield from bps.wait(
|
|
149
|
+
yield from bps.wait(gonio_finished)
|
|
200
150
|
|
|
201
151
|
|
|
202
152
|
def robot_load_and_change_energy_plan(
|
|
@@ -218,17 +168,13 @@ def robot_load_and_change_energy_plan(
|
|
|
218
168
|
composite,
|
|
219
169
|
sample_location,
|
|
220
170
|
params.snapshot_directory,
|
|
171
|
+
params.sample_id,
|
|
221
172
|
params.thawing_time,
|
|
222
173
|
params.demand_energy_ev,
|
|
223
174
|
),
|
|
224
175
|
md={
|
|
225
176
|
"subplan_name": CONST.PLAN.ROBOT_LOAD,
|
|
226
|
-
"metadata": {
|
|
227
|
-
"visit": params.visit,
|
|
228
|
-
"sample_id": params.sample_id,
|
|
229
|
-
"sample_puck": sample_location.puck,
|
|
230
|
-
"sample_pin": sample_location.pin,
|
|
231
|
-
},
|
|
177
|
+
"metadata": {"visit": params.visit, "sample_id": params.sample_id},
|
|
232
178
|
"activate_callbacks": [
|
|
233
179
|
"RobotLoadISPyBCallback",
|
|
234
180
|
],
|
|
@@ -18,7 +18,7 @@ from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVolta
|
|
|
18
18
|
from dodal.devices.i03 import Beamstop
|
|
19
19
|
from dodal.devices.i03.dcm import DCM
|
|
20
20
|
from dodal.devices.i03.undulator_dcm import UndulatorDCM
|
|
21
|
-
from dodal.devices.motors import
|
|
21
|
+
from dodal.devices.motors import XYZStage
|
|
22
22
|
from dodal.devices.oav.oav_detector import OAV
|
|
23
23
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
24
24
|
from dodal.devices.robot import BartRobot, SampleLocation
|
|
@@ -35,13 +35,12 @@ from dodal.devices.zocalo import ZocaloResults
|
|
|
35
35
|
from dodal.log import LOGGER
|
|
36
36
|
from ophyd_async.fastcs.panda import HDFPanda
|
|
37
37
|
|
|
38
|
+
from mx_bluesky.common.device_setup_plans.utils import (
|
|
39
|
+
start_preparing_data_collection_then_do_plan,
|
|
40
|
+
)
|
|
38
41
|
from mx_bluesky.common.parameters.constants import OavConstants
|
|
39
42
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
40
43
|
fill_in_energy_if_not_supplied,
|
|
41
|
-
start_preparing_data_collection_then_do_plan,
|
|
42
|
-
)
|
|
43
|
-
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
44
|
-
GridDetectThenXRayCentreComposite,
|
|
45
44
|
)
|
|
46
45
|
from mx_bluesky.hyperion.experiment_plans.pin_centre_then_xray_centre_plan import (
|
|
47
46
|
pin_centre_then_flyscan_plan,
|
|
@@ -56,6 +55,9 @@ from mx_bluesky.hyperion.experiment_plans.set_energy_plan import (
|
|
|
56
55
|
set_energy_plan,
|
|
57
56
|
)
|
|
58
57
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
58
|
+
from mx_bluesky.hyperion.parameters.device_composites import (
|
|
59
|
+
HyperionGridDetectThenXRayCentreComposite,
|
|
60
|
+
)
|
|
59
61
|
from mx_bluesky.hyperion.parameters.robot_load import RobotLoadThenCentre
|
|
60
62
|
|
|
61
63
|
|
|
@@ -65,7 +67,7 @@ class RobotLoadThenCentreComposite:
|
|
|
65
67
|
xbpm_feedback: XBPMFeedback
|
|
66
68
|
attenuator: BinaryFilterAttenuator
|
|
67
69
|
|
|
68
|
-
#
|
|
70
|
+
# HyperionGridDetectThenXRayCentreComposite fields
|
|
69
71
|
aperture_scatterguard: ApertureScatterguard
|
|
70
72
|
backlight: Backlight
|
|
71
73
|
detector_motion: DetectorMotion
|
|
@@ -94,7 +96,7 @@ class RobotLoadThenCentreComposite:
|
|
|
94
96
|
# RobotLoad fields
|
|
95
97
|
robot: BartRobot
|
|
96
98
|
webcam: Webcam
|
|
97
|
-
lower_gonio:
|
|
99
|
+
lower_gonio: XYZStage
|
|
98
100
|
beamstop: Beamstop
|
|
99
101
|
|
|
100
102
|
|
|
@@ -110,7 +112,7 @@ def _flyscan_plan_from_robot_load_params(
|
|
|
110
112
|
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
111
113
|
):
|
|
112
114
|
yield from pin_centre_then_flyscan_plan(
|
|
113
|
-
cast(
|
|
115
|
+
cast(HyperionGridDetectThenXRayCentreComposite, composite),
|
|
114
116
|
params.pin_centre_then_xray_centre_params,
|
|
115
117
|
oav_config_file,
|
|
116
118
|
)
|
|
@@ -34,12 +34,20 @@ from mx_bluesky.common.device_setup_plans.manipulate_sample import (
|
|
|
34
34
|
cleanup_sample_environment,
|
|
35
35
|
setup_sample_environment,
|
|
36
36
|
)
|
|
37
|
-
from mx_bluesky.common.
|
|
38
|
-
|
|
37
|
+
from mx_bluesky.common.device_setup_plans.utils import (
|
|
38
|
+
start_preparing_data_collection_then_do_plan,
|
|
39
|
+
)
|
|
40
|
+
from mx_bluesky.common.experiment_plans.oav_snapshot_plan import (
|
|
41
|
+
OavSnapshotComposite,
|
|
42
|
+
oav_snapshot_plan,
|
|
43
|
+
setup_beamline_for_OAV,
|
|
44
|
+
)
|
|
45
|
+
from mx_bluesky.common.experiment_plans.read_hardware import (
|
|
39
46
|
read_hardware_for_zocalo,
|
|
40
47
|
standard_read_hardware_during_collection,
|
|
41
48
|
standard_read_hardware_pre_collection,
|
|
42
49
|
)
|
|
50
|
+
from mx_bluesky.common.parameters.components import WithSnapshot
|
|
43
51
|
from mx_bluesky.common.preprocessors.preprocessors import (
|
|
44
52
|
transmission_and_xbpm_feedback_for_collection_decorator,
|
|
45
53
|
)
|
|
@@ -50,14 +58,6 @@ from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
|
|
|
50
58
|
setup_zebra_for_rotation,
|
|
51
59
|
tidy_up_zebra_after_rotation_scan,
|
|
52
60
|
)
|
|
53
|
-
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
54
|
-
start_preparing_data_collection_then_do_plan,
|
|
55
|
-
)
|
|
56
|
-
from mx_bluesky.hyperion.experiment_plans.oav_snapshot_plan import (
|
|
57
|
-
OavSnapshotComposite,
|
|
58
|
-
oav_snapshot_plan,
|
|
59
|
-
setup_beamline_for_OAV,
|
|
60
|
-
)
|
|
61
61
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
62
62
|
from mx_bluesky.hyperion.parameters.rotation import (
|
|
63
63
|
RotationScan,
|
|
@@ -342,15 +342,20 @@ def _move_and_rotation(
|
|
|
342
342
|
|
|
343
343
|
if params.take_snapshots:
|
|
344
344
|
yield from bps.wait(CONST.WAIT.MOVE_GONIO_TO_START)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
345
|
+
|
|
346
|
+
if not params.use_grid_snapshots:
|
|
347
|
+
yield from setup_beamline_for_OAV(
|
|
348
|
+
composite.smargon,
|
|
349
|
+
composite.backlight,
|
|
350
|
+
composite.aperture_scatterguard,
|
|
351
|
+
wait=True,
|
|
352
|
+
)
|
|
353
|
+
|
|
349
354
|
if params.selected_aperture:
|
|
350
355
|
yield from bps.prepare(
|
|
351
356
|
composite.aperture_scatterguard,
|
|
352
357
|
params.selected_aperture,
|
|
353
|
-
group=CONST.WAIT.
|
|
358
|
+
group=CONST.WAIT.PREPARE_APERTURE,
|
|
354
359
|
)
|
|
355
360
|
yield from oav_snapshot_plan(composite, params, oav_params)
|
|
356
361
|
yield from rotation_scan_plan(composite, params, motion_values)
|
|
@@ -148,6 +148,7 @@ def populate_parameters_from_agamemnon(agamemnon_params) -> Sequence[LoadCentreC
|
|
|
148
148
|
"name": "TopNByMaxCount",
|
|
149
149
|
"n": pin_type.expected_number_of_crystals,
|
|
150
150
|
},
|
|
151
|
+
"features": {"use_gpu_results": True},
|
|
151
152
|
"robot_load_then_centre": {
|
|
152
153
|
"storage_directory": str(visit_directory) + "/xraycentring",
|
|
153
154
|
"file_name": file_name,
|
|
@@ -156,7 +157,6 @@ def populate_parameters_from_agamemnon(agamemnon_params) -> Sequence[LoadCentreC
|
|
|
156
157
|
"omega_start_deg": 0.0,
|
|
157
158
|
"chi_start_deg": collection["chi"],
|
|
158
159
|
"transmission_frac": 1.0,
|
|
159
|
-
"features": {"use_gpu_results": True},
|
|
160
160
|
**with_energy_params,
|
|
161
161
|
},
|
|
162
162
|
"multi_rotation_scan": {
|
|
@@ -228,10 +228,10 @@ def update_params_from_agamemnon(parameters: T) -> T:
|
|
|
228
228
|
parameters.robot_load_then_centre.grid_width_um = pin_type.full_width
|
|
229
229
|
parameters.select_centres.n = pin_type.expected_number_of_crystals
|
|
230
230
|
if pin_type != SinglePin():
|
|
231
|
-
#
|
|
232
|
-
#
|
|
233
|
-
# this will give no snapshots but that's preferable
|
|
231
|
+
# Rotation snapshots will be generated from the gridscan snapshots,
|
|
232
|
+
# no need to specify snapshot omega.
|
|
234
233
|
parameters.multi_rotation_scan.snapshot_omegas_deg = []
|
|
234
|
+
parameters.multi_rotation_scan.use_grid_snapshots = True
|
|
235
235
|
except (ValueError, ValidationError) as e:
|
|
236
236
|
LOGGER.warning(f"Failed to update parameters: {e}")
|
|
237
237
|
except Exception as e:
|
|
@@ -29,7 +29,7 @@ from mx_bluesky.common.utils.log import (
|
|
|
29
29
|
_get_logging_dirs,
|
|
30
30
|
tag_filter,
|
|
31
31
|
)
|
|
32
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.
|
|
32
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.robot_actions.ispyb_callback import (
|
|
33
33
|
RobotLoadISPyBCallback,
|
|
34
34
|
)
|
|
35
35
|
from mx_bluesky.hyperion.external_interaction.callbacks.rotation.ispyb_callback import (
|
mx_bluesky/hyperion/external_interaction/callbacks/{robot_load → robot_actions}/ispyb_callback.py
RENAMED
|
@@ -12,6 +12,7 @@ from mx_bluesky.common.external_interaction.ispyb.exp_eye_store import (
|
|
|
12
12
|
BLSampleStatus,
|
|
13
13
|
ExpeyeInteraction,
|
|
14
14
|
RobotActionID,
|
|
15
|
+
create_update_data_from_event_doc,
|
|
15
16
|
)
|
|
16
17
|
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER
|
|
17
18
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
@@ -20,11 +21,21 @@ if TYPE_CHECKING:
|
|
|
20
21
|
from event_model.documents import Event, EventDescriptor, RunStart, RunStop
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
robot_update_mapping = {
|
|
25
|
+
"robot-barcode": "sampleBarcode",
|
|
26
|
+
"robot-current_pin": "containerLocation",
|
|
27
|
+
"robot-current_puck": "dewarLocation",
|
|
28
|
+
# I03 uses webcam/oav snapshots in place of before/after snapshots
|
|
29
|
+
"webcam-last_saved_path": "xtalSnapshotBefore",
|
|
30
|
+
"oav-snapshot-last_saved_path": "xtalSnapshotAfter",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
23
34
|
class RobotLoadISPyBCallback(PlanReactiveCallback):
|
|
24
35
|
def __init__(self) -> None:
|
|
25
36
|
ISPYB_ZOCALO_CALLBACK_LOGGER.debug("Initialising ISPyB Robot Load Callback")
|
|
26
37
|
super().__init__(log=ISPYB_ZOCALO_CALLBACK_LOGGER)
|
|
27
|
-
self.
|
|
38
|
+
self._sample_id: int | None = None
|
|
28
39
|
|
|
29
40
|
self.run_uid: str | None = None
|
|
30
41
|
self.descriptors: dict[str, EventDescriptor] = {}
|
|
@@ -35,22 +46,24 @@ class RobotLoadISPyBCallback(PlanReactiveCallback):
|
|
|
35
46
|
ISPYB_ZOCALO_CALLBACK_LOGGER.debug(
|
|
36
47
|
"ISPyB robot load callback received start document."
|
|
37
48
|
)
|
|
38
|
-
|
|
49
|
+
subplan = doc.get("subplan_name")
|
|
50
|
+
if subplan == CONST.PLAN.ROBOT_LOAD or subplan == CONST.PLAN.ROBOT_UNLOAD:
|
|
39
51
|
ISPYB_ZOCALO_CALLBACK_LOGGER.debug(
|
|
40
52
|
f"ISPyB robot load callback received: {doc}"
|
|
41
53
|
)
|
|
42
54
|
self.run_uid = doc.get("uid")
|
|
43
|
-
|
|
44
|
-
assert isinstance(
|
|
55
|
+
metadata = doc.get("metadata")
|
|
56
|
+
assert isinstance(metadata, dict)
|
|
57
|
+
self._sample_id = metadata["sample_id"]
|
|
58
|
+
assert isinstance(self._sample_id, int)
|
|
45
59
|
proposal, session = get_proposal_and_session_from_visit_string(
|
|
46
|
-
|
|
60
|
+
metadata["visit"]
|
|
47
61
|
)
|
|
48
|
-
self.action_id = self.expeye.
|
|
62
|
+
self.action_id = self.expeye.start_robot_action(
|
|
63
|
+
"LOAD" if subplan == CONST.PLAN.ROBOT_LOAD else "UNLOAD",
|
|
49
64
|
proposal,
|
|
50
65
|
session,
|
|
51
|
-
self.
|
|
52
|
-
self._metadata["sample_puck"],
|
|
53
|
-
self._metadata["sample_pin"],
|
|
66
|
+
self._sample_id,
|
|
54
67
|
)
|
|
55
68
|
return super().activity_gated_start(doc)
|
|
56
69
|
|
|
@@ -62,18 +75,14 @@ class RobotLoadISPyBCallback(PlanReactiveCallback):
|
|
|
62
75
|
event_descriptor = self.descriptors.get(doc["descriptor"])
|
|
63
76
|
if (
|
|
64
77
|
event_descriptor
|
|
65
|
-
and event_descriptor.get("name") == CONST.DESCRIPTORS.
|
|
78
|
+
and event_descriptor.get("name") == CONST.DESCRIPTORS.ROBOT_UPDATE
|
|
66
79
|
):
|
|
67
80
|
assert self.action_id is not None, (
|
|
68
81
|
"ISPyB Robot load callback event called unexpectedly"
|
|
69
82
|
)
|
|
70
|
-
barcode = doc["data"]["robot-barcode"]
|
|
71
|
-
oav_snapshot = doc["data"]["oav-snapshot-last_saved_path"]
|
|
72
|
-
webcam_snapshot = doc["data"]["webcam-last_saved_path"]
|
|
73
83
|
# I03 uses webcam/oav snapshots in place of before/after snapshots
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
84
|
+
update_data = create_update_data_from_event_doc(robot_update_mapping, doc)
|
|
85
|
+
self.expeye.update_robot_action(self.action_id, update_data)
|
|
77
86
|
|
|
78
87
|
return super().activity_gated_event(doc)
|
|
79
88
|
|
|
@@ -87,12 +96,12 @@ class RobotLoadISPyBCallback(PlanReactiveCallback):
|
|
|
87
96
|
)
|
|
88
97
|
exit_status = doc.get("exit_status")
|
|
89
98
|
assert exit_status, "Exit status not available in stop document!"
|
|
90
|
-
assert self.
|
|
99
|
+
assert self._sample_id is not None, "Stop called before start"
|
|
91
100
|
reason = doc.get("reason") or "OK"
|
|
92
101
|
|
|
93
|
-
self.expeye.
|
|
102
|
+
self.expeye.end_robot_action(self.action_id, exit_status, reason)
|
|
94
103
|
self.expeye.update_sample_status(
|
|
95
|
-
self.
|
|
104
|
+
self._sample_id,
|
|
96
105
|
BLSampleStatus.LOADED
|
|
97
106
|
if exit_status == "success"
|
|
98
107
|
else BLSampleStatus.ERROR_BEAMLINE,
|
|
@@ -54,6 +54,7 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
54
54
|
super().__init__(emit=emit)
|
|
55
55
|
self.last_sample_id: int | None = None
|
|
56
56
|
self.ispyb_ids: IspybIds = IspybIds()
|
|
57
|
+
self.ispyb = StoreInIspyb(self.ispyb_config)
|
|
57
58
|
|
|
58
59
|
def activity_gated_start(self, doc: RunStart):
|
|
59
60
|
if doc.get("subplan_name") == CONST.PLAN.ROTATION_OUTER:
|
|
@@ -82,7 +83,6 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
82
83
|
f"Collection is {self.params.ispyb_experiment_type} - storing sampleID to bundle images"
|
|
83
84
|
)
|
|
84
85
|
self.last_sample_id = self.params.sample_id
|
|
85
|
-
self.ispyb = StoreInIspyb(self.ispyb_config)
|
|
86
86
|
ISPYB_ZOCALO_CALLBACK_LOGGER.info("Beginning ispyb deposition")
|
|
87
87
|
data_collection_group_info = populate_data_collection_group(self.params)
|
|
88
88
|
data_collection_info = populate_data_collection_info_for_rotation(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import dataclasses
|
|
2
|
+
import os
|
|
2
3
|
import re
|
|
3
4
|
from collections.abc import Iterator
|
|
4
5
|
from datetime import datetime
|
|
@@ -172,6 +173,8 @@ class BeamDrawingCallback(PlanReactiveCallback):
|
|
|
172
173
|
f"Generating snapshot at {current_sample_pos_mm} from base snapshot {snapshot_info}"
|
|
173
174
|
)
|
|
174
175
|
output_snapshot_directory = data["oav-snapshot-directory"]
|
|
176
|
+
if not os.path.exists(output_snapshot_directory):
|
|
177
|
+
os.mkdir(output_snapshot_directory)
|
|
175
178
|
base_file_stem = Path(snapshot_info.snapshot_path).stem
|
|
176
179
|
output_snapshot_filename = _snapshot_filename(base_file_stem)
|
|
177
180
|
output_snapshot_path = (
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from functools import cache
|
|
2
2
|
|
|
3
3
|
from daq_config_server.client import ConfigServer
|
|
4
|
-
from pydantic import model_validator
|
|
5
4
|
|
|
6
5
|
from mx_bluesky.common.external_interaction.config_server import FeatureFlags
|
|
7
6
|
from mx_bluesky.common.utils.log import LOGGER
|
|
@@ -14,8 +13,6 @@ class HyperionFeatureFlags(FeatureFlags):
|
|
|
14
13
|
|
|
15
14
|
Attributes:
|
|
16
15
|
use_panda_for_gridscan: If True then the PandA is used for gridscans, otherwise the zebra is used
|
|
17
|
-
compare_cpu_and_gpu_zocalo: If True then GPU result processing is enabled
|
|
18
|
-
alongside CPU and the results are compared. The CPU result is still take.n
|
|
19
16
|
use_gpu_results: If True then GPU result processing is enabled
|
|
20
17
|
and the GPU result is taken.
|
|
21
18
|
set_stub_offsets: If True then set the stub offsets after moving to the crystal (ignored for
|
|
@@ -31,15 +28,7 @@ class HyperionFeatureFlags(FeatureFlags):
|
|
|
31
28
|
def get_config_server() -> ConfigServer:
|
|
32
29
|
return ConfigServer(CONST.CONFIG_SERVER_URL, LOGGER)
|
|
33
30
|
|
|
34
|
-
@model_validator(mode="after")
|
|
35
|
-
def use_gpu_and_compare_cannot_both_be_true(self):
|
|
36
|
-
assert not (self.use_gpu_results and self.compare_cpu_and_gpu_zocalo), (
|
|
37
|
-
"Cannot both use GPU results and compare them to CPU"
|
|
38
|
-
)
|
|
39
|
-
return self
|
|
40
|
-
|
|
41
31
|
use_panda_for_gridscan: bool = CONST.I03.USE_PANDA_FOR_GRIDSCAN
|
|
42
|
-
compare_cpu_and_gpu_zocalo: bool = CONST.I03.COMPARE_CPU_AND_GPU_ZOCALO
|
|
43
32
|
use_gpu_results: bool = CONST.I03.USE_GPU_RESULTS
|
|
44
33
|
set_stub_offsets: bool = CONST.I03.SET_STUB_OFFSETS
|
|
45
34
|
omega_flip: bool = CONST.I03.OMEGA_FLIP
|
|
@@ -19,7 +19,6 @@ TEST_MODE = os.environ.get("HYPERION_TEST_MODE")
|
|
|
19
19
|
|
|
20
20
|
@dataclass(frozen=True)
|
|
21
21
|
class I03Constants:
|
|
22
|
-
BASE_DATA_DIR = "/tmp/dls/i03/data/" if TEST_MODE else "/dls/i03/data/"
|
|
23
22
|
BEAMLINE = "BL03S" if TEST_MODE else "BL03I"
|
|
24
23
|
DETECTOR = EIGER2_X_16M_SIZE
|
|
25
24
|
INSERTION_PREFIX = "SR03S" if TEST_MODE else "SR03I"
|
|
@@ -30,12 +29,8 @@ class I03Constants:
|
|
|
30
29
|
OMEGA_FLIP = True
|
|
31
30
|
ALTERNATE_ROTATION_DIRECTION = True
|
|
32
31
|
|
|
33
|
-
# Turns on GPU processing for zocalo and logs a comparison between GPU and CPU-
|
|
34
|
-
# processed results.
|
|
35
|
-
COMPARE_CPU_AND_GPU_ZOCALO = False
|
|
36
|
-
|
|
37
32
|
# Turns on GPU processing for zocalo and uses the results that come back
|
|
38
|
-
USE_GPU_RESULTS =
|
|
33
|
+
USE_GPU_RESULTS = True
|
|
39
34
|
|
|
40
35
|
|
|
41
36
|
@dataclass(frozen=True)
|
|
@@ -7,19 +7,14 @@ from dodal.devices.aperturescatterguard import (
|
|
|
7
7
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
8
8
|
from dodal.devices.backlight import Backlight
|
|
9
9
|
from dodal.devices.common_dcm import BaseDCM
|
|
10
|
-
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
11
10
|
from dodal.devices.eiger import EigerDetector
|
|
12
11
|
from dodal.devices.fast_grid_scan import (
|
|
13
12
|
PandAFastGridScan,
|
|
14
13
|
ZebraFastGridScan,
|
|
15
14
|
)
|
|
16
15
|
from dodal.devices.flux import Flux
|
|
17
|
-
from dodal.devices.i03 import Beamstop
|
|
18
|
-
from dodal.devices.oav.oav_detector import OAV
|
|
19
|
-
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
20
16
|
from dodal.devices.robot import BartRobot
|
|
21
17
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
22
|
-
from dodal.devices.smargon import Smargon
|
|
23
18
|
from dodal.devices.synchrotron import Synchrotron
|
|
24
19
|
from dodal.devices.undulator import Undulator
|
|
25
20
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
@@ -28,9 +23,12 @@ from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
|
|
|
28
23
|
from dodal.devices.zocalo import ZocaloResults
|
|
29
24
|
from ophyd_async.fastcs.panda import HDFPanda
|
|
30
25
|
|
|
31
|
-
from mx_bluesky.common.
|
|
26
|
+
from mx_bluesky.common.experiment_plans.common_flyscan_xray_centre_plan import (
|
|
32
27
|
FlyScanEssentialDevices,
|
|
33
28
|
)
|
|
29
|
+
from mx_bluesky.common.parameters.device_composites import (
|
|
30
|
+
GridDetectThenXRayCentreComposite,
|
|
31
|
+
)
|
|
34
32
|
|
|
35
33
|
|
|
36
34
|
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
@@ -57,28 +55,8 @@ class HyperionFlyScanXRayCentreComposite(FlyScanEssentialDevices):
|
|
|
57
55
|
|
|
58
56
|
|
|
59
57
|
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
60
|
-
class GridDetectThenXRayCentreComposite:
|
|
58
|
+
class HyperionGridDetectThenXRayCentreComposite(GridDetectThenXRayCentreComposite):
|
|
61
59
|
"""All devices which are directly or indirectly required by this plan"""
|
|
62
60
|
|
|
63
|
-
aperture_scatterguard: ApertureScatterguard
|
|
64
|
-
attenuator: BinaryFilterAttenuator
|
|
65
|
-
backlight: Backlight
|
|
66
|
-
beamstop: Beamstop
|
|
67
|
-
dcm: BaseDCM
|
|
68
|
-
detector_motion: DetectorMotion
|
|
69
|
-
eiger: EigerDetector
|
|
70
|
-
zebra_fast_grid_scan: ZebraFastGridScan
|
|
71
|
-
flux: Flux
|
|
72
|
-
oav: OAV
|
|
73
|
-
pin_tip_detection: PinTipDetection
|
|
74
|
-
smargon: Smargon
|
|
75
|
-
synchrotron: Synchrotron
|
|
76
|
-
s4_slit_gaps: S4SlitGaps
|
|
77
|
-
undulator: Undulator
|
|
78
|
-
xbpm_feedback: XBPMFeedback
|
|
79
|
-
zebra: Zebra
|
|
80
|
-
zocalo: ZocaloResults
|
|
81
61
|
panda: HDFPanda
|
|
82
62
|
panda_fast_grid_scan: PandAFastGridScan
|
|
83
|
-
robot: BartRobot
|
|
84
|
-
sample_shutter: ZebraShutter
|
|
@@ -20,9 +20,7 @@ class GridCommonWithHyperionDetectorParams(GridCommon, WithHyperionUDCFeatures):
|
|
|
20
20
|
@property
|
|
21
21
|
def detector_params(self):
|
|
22
22
|
params = super().detector_params
|
|
23
|
-
params.enable_dev_shm =
|
|
24
|
-
self.features.compare_cpu_and_gpu_zocalo or self.features.use_gpu_results
|
|
25
|
-
)
|
|
23
|
+
params.enable_dev_shm = self.features.use_gpu_results
|
|
26
24
|
return params
|
|
27
25
|
|
|
28
26
|
|
|
@@ -35,9 +33,7 @@ class HyperionSpecifiedThreeDGridScan(WithHyperionUDCFeatures, SpecifiedThreeDGr
|
|
|
35
33
|
@property
|
|
36
34
|
def detector_params(self):
|
|
37
35
|
params = super().detector_params
|
|
38
|
-
params.enable_dev_shm =
|
|
39
|
-
self.features.compare_cpu_and_gpu_zocalo or self.features.use_gpu_results
|
|
40
|
-
)
|
|
36
|
+
params.enable_dev_shm = self.features.use_gpu_results
|
|
41
37
|
return params
|
|
42
38
|
|
|
43
39
|
# Relative to common grid scan, stub offsets are defined by config server
|
|
@@ -50,6 +50,12 @@ class LoadCentreCollect(
|
|
|
50
50
|
f"Unexpected fields found in LoadCentreCollect {disallowed_keys}"
|
|
51
51
|
)
|
|
52
52
|
|
|
53
|
+
assert "features" not in values["robot_load_then_centre"], (
|
|
54
|
+
"Features flags must be specified at top-level in LoadCentreCollect"
|
|
55
|
+
)
|
|
56
|
+
assert "features" not in values["multi_rotation_scan"], (
|
|
57
|
+
"Features flags must be specified at top-level in LoadCentreCollect"
|
|
58
|
+
)
|
|
53
59
|
keys_from_outer_load_centre_collect = (
|
|
54
60
|
MxBlueskyParameters.model_fields.keys()
|
|
55
61
|
| WithSample.model_fields.keys()
|
|
@@ -70,6 +76,9 @@ class LoadCentreCollect(
|
|
|
70
76
|
f"Unexpected keys in multi_rotation_scan: {', '.join(duplicated_multi_rotation_scan_keys)}"
|
|
71
77
|
)
|
|
72
78
|
|
|
79
|
+
for rotation in values["multi_rotation_scan"]["rotation_scans"]:
|
|
80
|
+
rotation["sample_id"] = values["sample_id"]
|
|
81
|
+
|
|
73
82
|
new_robot_load_then_centre_params = construct_from_values(
|
|
74
83
|
values, values["robot_load_then_centre"], RobotLoadThenCentre
|
|
75
84
|
)
|
|
@@ -80,6 +89,12 @@ class LoadCentreCollect(
|
|
|
80
89
|
values["robot_load_then_centre"] = new_robot_load_then_centre_params
|
|
81
90
|
return values
|
|
82
91
|
|
|
92
|
+
@model_validator(mode="after")
|
|
93
|
+
def _ensure_features_are_internally_consistent(self) -> Self:
|
|
94
|
+
self.robot_load_then_centre.features = self.features
|
|
95
|
+
self.multi_rotation_scan.features = self.features
|
|
96
|
+
return self
|
|
97
|
+
|
|
83
98
|
@model_validator(mode="after")
|
|
84
99
|
def _check_rotation_start_xyz_is_not_specified(self) -> Self:
|
|
85
100
|
for scan in self.multi_rotation_scan.single_rotation_scans:
|