mx-bluesky 1.4.7__py3-none-any.whl → 1.4.8__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/redis_to_murko_forwarder.py +4 -4
- mx_bluesky/beamlines/i04/thawing_plan.py +8 -2
- mx_bluesky/beamlines/i23/__init__.py +3 -0
- mx_bluesky/beamlines/i23/serial.py +71 -0
- mx_bluesky/beamlines/i24/serial/__init__.py +2 -0
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +7 -2
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +3 -3
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +6 -56
- mx_bluesky/beamlines/i24/serial/log.py +9 -10
- mx_bluesky/beamlines/i24/serial/parameters/utils.py +36 -7
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +0 -1
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv_abstract.py +4 -4
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +4 -4
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +2 -1
- mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +71 -11
- mx_bluesky/beamlines/i24/serial/write_nexus.py +3 -3
- mx_bluesky/{hyperion → common}/device_setup_plans/check_beamstop.py +1 -1
- mx_bluesky/{hyperion → common}/device_setup_plans/manipulate_sample.py +1 -1
- mx_bluesky/{hyperion → common}/device_setup_plans/setup_oav.py +12 -6
- mx_bluesky/{hyperion → common}/experiment_plans/change_aperture_then_move_plan.py +4 -5
- mx_bluesky/{hyperion → common}/experiment_plans/oav_grid_detection_plan.py +6 -6
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +6 -5
- mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +16 -47
- mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +4 -1
- mx_bluesky/common/external_interaction/ispyb/ispyb_utils.py +4 -4
- mx_bluesky/common/parameters/components.py +22 -2
- mx_bluesky/common/parameters/constants.py +4 -16
- mx_bluesky/common/parameters/gridscan.py +36 -32
- mx_bluesky/common/plans/common_flyscan_xray_centre_plan.py +316 -0
- mx_bluesky/common/plans/inner_plans/__init__ .py +0 -0
- mx_bluesky/common/plans/read_hardware.py +3 -3
- mx_bluesky/common/utils/log.py +15 -12
- mx_bluesky/hyperion/__main__.py +2 -15
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +4 -4
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +0 -33
- mx_bluesky/hyperion/device_setup_plans/utils.py +4 -4
- mx_bluesky/hyperion/experiment_plans/__init__.py +0 -6
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +0 -9
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +71 -88
- mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +183 -0
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +12 -7
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +28 -7
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +4 -4
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +1 -1
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +11 -3
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +9 -8
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +18 -56
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
- mx_bluesky/hyperion/external_interaction/agamemnon.py +62 -70
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +8 -6
- mx_bluesky/hyperion/external_interaction/callbacks/snapshot_callback.py +183 -31
- mx_bluesky/hyperion/parameters/cli.py +2 -10
- mx_bluesky/hyperion/parameters/constants.py +0 -5
- mx_bluesky/hyperion/parameters/device_composites.py +40 -5
- mx_bluesky/hyperion/parameters/gridscan.py +9 -58
- mx_bluesky/hyperion/parameters/rotation.py +0 -4
- mx_bluesky/hyperion/utils/context.py +2 -5
- mx_bluesky/hyperion/utils/validation.py +13 -10
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/METADATA +5 -4
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/RECORD +69 -65
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/WHEEL +1 -1
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +0 -467
- /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short1-laser.png → s1l.png} +0 -0
- /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short2-laser.png → s2l.png} +0 -0
- /mx_bluesky/{hyperion → common}/device_setup_plans/position_detector.py +0 -0
- /mx_bluesky/common/plans/{do_fgs.py → inner_plans/do_fgs.py} +0 -0
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/licenses/LICENSE +0 -0
- {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
from collections.abc import Callable, Sequence
|
|
5
|
+
from functools import partial
|
|
6
|
+
|
|
7
|
+
import bluesky.plan_stubs as bps
|
|
8
|
+
import bluesky.preprocessors as bpp
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pydantic
|
|
11
|
+
from bluesky.protocols import Readable
|
|
12
|
+
from bluesky.utils import MsgGenerator
|
|
13
|
+
from dodal.devices.eiger import EigerDetector
|
|
14
|
+
from dodal.devices.fast_grid_scan import (
|
|
15
|
+
FastGridScanCommon,
|
|
16
|
+
)
|
|
17
|
+
from dodal.devices.smargon import Smargon
|
|
18
|
+
from dodal.devices.synchrotron import Synchrotron
|
|
19
|
+
from dodal.devices.zocalo import ZocaloResults
|
|
20
|
+
from dodal.devices.zocalo.zocalo_results import (
|
|
21
|
+
XrcResult,
|
|
22
|
+
get_full_processing_results,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from mx_bluesky.common.parameters.constants import (
|
|
26
|
+
DocDescriptorNames,
|
|
27
|
+
GridscanParamConstants,
|
|
28
|
+
PlanGroupCheckpointConstants,
|
|
29
|
+
PlanNameConstants,
|
|
30
|
+
)
|
|
31
|
+
from mx_bluesky.common.parameters.gridscan import SpecifiedThreeDGridScan
|
|
32
|
+
from mx_bluesky.common.plans.inner_plans.do_fgs import (
|
|
33
|
+
ZOCALO_STAGE_GROUP,
|
|
34
|
+
kickoff_and_complete_gridscan,
|
|
35
|
+
)
|
|
36
|
+
from mx_bluesky.common.plans.read_hardware import (
|
|
37
|
+
read_hardware_plan,
|
|
38
|
+
)
|
|
39
|
+
from mx_bluesky.common.utils.exceptions import (
|
|
40
|
+
CrystalNotFoundException,
|
|
41
|
+
SampleException,
|
|
42
|
+
)
|
|
43
|
+
from mx_bluesky.common.utils.log import LOGGER
|
|
44
|
+
from mx_bluesky.common.utils.tracing import TRACER
|
|
45
|
+
from mx_bluesky.common.xrc_result import XRayCentreResult
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
49
|
+
class FlyScanEssentialDevices:
|
|
50
|
+
eiger: EigerDetector
|
|
51
|
+
synchrotron: Synchrotron
|
|
52
|
+
zocalo: ZocaloResults
|
|
53
|
+
smargon: Smargon
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclasses.dataclass
|
|
57
|
+
class BeamlineSpecificFGSFeatures:
|
|
58
|
+
setup_trigger_plan: Callable[..., MsgGenerator]
|
|
59
|
+
tidy_plan: Callable[..., MsgGenerator]
|
|
60
|
+
set_flyscan_params_plan: Callable[..., MsgGenerator]
|
|
61
|
+
fgs_motors: FastGridScanCommon
|
|
62
|
+
read_pre_flyscan_plan: Callable[
|
|
63
|
+
..., MsgGenerator
|
|
64
|
+
] # Eventually replace with https://github.com/DiamondLightSource/mx-bluesky/issues/819
|
|
65
|
+
read_during_collection_plan: Callable[..., MsgGenerator]
|
|
66
|
+
get_xrc_results_from_zocalo: bool
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def construct_beamline_specific_FGS_features(
|
|
70
|
+
setup_trigger_plan: Callable[..., MsgGenerator],
|
|
71
|
+
tidy_plan: Callable[..., MsgGenerator],
|
|
72
|
+
set_flyscan_params_plan: Callable[..., MsgGenerator],
|
|
73
|
+
fgs_motors: FastGridScanCommon,
|
|
74
|
+
signals_to_read_pre_flyscan: list[Readable],
|
|
75
|
+
signals_to_read_during_collection: list[Readable],
|
|
76
|
+
get_xrc_results_from_zocalo: bool = False,
|
|
77
|
+
) -> BeamlineSpecificFGSFeatures:
|
|
78
|
+
"""Construct the class needed to do beamline-specific parts of the XRC FGS
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
setup_trigger_plan (Callable): Configure triggering, for example with the Zebra or PandA device.
|
|
82
|
+
Ran directly before kicking off the gridscan.
|
|
83
|
+
|
|
84
|
+
tidy_plan (Callable): Tidy up states of devices. Ran at the end of the flyscan, regardless of
|
|
85
|
+
whether or not it finished successfully.
|
|
86
|
+
|
|
87
|
+
set_flyscan_params_plan (Callable): Set PV's for the relevant Fast Grid Scan dodal device
|
|
88
|
+
|
|
89
|
+
fgs_motors (Callable): Composite device representing the fast grid scan's motion program parameters.
|
|
90
|
+
|
|
91
|
+
signals_to_read_pre_flyscan (Callable): Signals which will be read and saved as a bluesky event document
|
|
92
|
+
after all configuration, but before the gridscan.
|
|
93
|
+
|
|
94
|
+
signals_to_read_during_collection (Callable): Signals which will be read and saved as a bluesky event
|
|
95
|
+
document whilst the gridscan motion is in progress
|
|
96
|
+
|
|
97
|
+
get_xrc_results_from_zocalo (bool): If true, fetch grid scan results from zocalo after completion, as well as
|
|
98
|
+
update the ispyb comment field with information about the results. See _fetch_xrc_results_from_zocalo
|
|
99
|
+
"""
|
|
100
|
+
read_pre_flyscan_plan = partial(
|
|
101
|
+
read_hardware_plan,
|
|
102
|
+
signals_to_read_pre_flyscan,
|
|
103
|
+
DocDescriptorNames.HARDWARE_READ_PRE,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
read_during_collection_plan = partial(
|
|
107
|
+
read_hardware_plan,
|
|
108
|
+
signals_to_read_during_collection,
|
|
109
|
+
DocDescriptorNames.HARDWARE_READ_DURING,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
return BeamlineSpecificFGSFeatures(
|
|
113
|
+
setup_trigger_plan,
|
|
114
|
+
tidy_plan,
|
|
115
|
+
set_flyscan_params_plan,
|
|
116
|
+
fgs_motors,
|
|
117
|
+
read_pre_flyscan_plan,
|
|
118
|
+
read_during_collection_plan,
|
|
119
|
+
get_xrc_results_from_zocalo,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def common_flyscan_xray_centre(
|
|
124
|
+
composite: FlyScanEssentialDevices,
|
|
125
|
+
parameters: SpecifiedThreeDGridScan,
|
|
126
|
+
beamline_specific: BeamlineSpecificFGSFeatures,
|
|
127
|
+
) -> MsgGenerator:
|
|
128
|
+
"""Main entry point of the MX-Bluesky x-ray centering flyscan
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
composite (FlyScanEssentialDevices): Devices required to perform this plan.
|
|
132
|
+
|
|
133
|
+
parameters (SpecifiedThreeDGridScan): Parameters required to perform this plan.
|
|
134
|
+
|
|
135
|
+
beamline_specific (BeamlineSpecificFGSFeatures): Configure the beamline-specific version
|
|
136
|
+
of this plan: For example triggering setup and tidy up plans, as well as what to do with the
|
|
137
|
+
centering results.
|
|
138
|
+
|
|
139
|
+
With a minimum set of devices and parameters, prepares for; performs; and tidies up a flyscan
|
|
140
|
+
x-ray-center plan. This includes: Configuring desired triggering; writing nexus files; triggering zocalo;
|
|
141
|
+
reading hardware before and during the scan; and tidying up devices after
|
|
142
|
+
the plan is complete. Optionally fetch results from zocalo after completing the grid scan.
|
|
143
|
+
|
|
144
|
+
This plan will also push data to ispyb when used with the ispyb_activation_decorator.
|
|
145
|
+
|
|
146
|
+
There are a few other useful decorators to use with this plan, see: verify_undulator_gap_before_run_decorator, transmission_and_xbpm_feedback_for_collection_decorator
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def _decorated_flyscan():
|
|
150
|
+
@bpp.set_run_key_decorator(PlanNameConstants.GRIDSCAN_OUTER)
|
|
151
|
+
@bpp.run_decorator( # attach experiment metadata to the start document
|
|
152
|
+
md={
|
|
153
|
+
"subplan_name": PlanNameConstants.GRIDSCAN_OUTER,
|
|
154
|
+
"mx_bluesky_parameters": parameters.model_dump_json(),
|
|
155
|
+
"activate_callbacks": [
|
|
156
|
+
"GridscanNexusFileCallback",
|
|
157
|
+
],
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
@bpp.finalize_decorator(lambda: beamline_specific.tidy_plan(composite))
|
|
161
|
+
def run_gridscan_and_tidy(
|
|
162
|
+
fgs_composite: FlyScanEssentialDevices,
|
|
163
|
+
params: SpecifiedThreeDGridScan,
|
|
164
|
+
beamline_specific: BeamlineSpecificFGSFeatures,
|
|
165
|
+
) -> MsgGenerator:
|
|
166
|
+
yield from beamline_specific.setup_trigger_plan(fgs_composite, parameters)
|
|
167
|
+
|
|
168
|
+
LOGGER.info("Starting grid scan")
|
|
169
|
+
yield from bps.stage(
|
|
170
|
+
fgs_composite.zocalo, group=ZOCALO_STAGE_GROUP
|
|
171
|
+
) # connect to zocalo and make sure the queue is clear
|
|
172
|
+
yield from run_gridscan(fgs_composite, params, beamline_specific)
|
|
173
|
+
|
|
174
|
+
LOGGER.info("Grid scan finished")
|
|
175
|
+
|
|
176
|
+
if beamline_specific.get_xrc_results_from_zocalo:
|
|
177
|
+
yield from _fetch_xrc_results_from_zocalo(composite.zocalo, parameters)
|
|
178
|
+
|
|
179
|
+
yield from run_gridscan_and_tidy(composite, parameters, beamline_specific)
|
|
180
|
+
|
|
181
|
+
composite.eiger.set_detector_parameters(parameters.detector_params)
|
|
182
|
+
yield from _decorated_flyscan()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _fetch_xrc_results_from_zocalo(
|
|
186
|
+
zocalo_results: ZocaloResults,
|
|
187
|
+
parameters: SpecifiedThreeDGridScan,
|
|
188
|
+
) -> MsgGenerator:
|
|
189
|
+
"""
|
|
190
|
+
Get XRC results from the ZocaloResults device which was staged during a grid scan,
|
|
191
|
+
and store them in XRayCentreEventHandler.xray_centre_results by firing an event.
|
|
192
|
+
|
|
193
|
+
The RunEngine must be subscribed to XRayCentreEventHandler for this plan to work.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
LOGGER.info("Getting X-ray center Zocalo results...")
|
|
197
|
+
|
|
198
|
+
yield from bps.trigger(zocalo_results)
|
|
199
|
+
LOGGER.info("Zocalo triggered and read, interpreting results.")
|
|
200
|
+
xrc_results = yield from get_full_processing_results(zocalo_results)
|
|
201
|
+
LOGGER.info(f"Got xray centres, top 5: {xrc_results[:5]}")
|
|
202
|
+
filtered_results = [
|
|
203
|
+
result
|
|
204
|
+
for result in xrc_results
|
|
205
|
+
if result["total_count"]
|
|
206
|
+
>= GridscanParamConstants.ZOCALO_MIN_TOTAL_COUNT_THRESHOLD
|
|
207
|
+
]
|
|
208
|
+
discarded_count = len(xrc_results) - len(filtered_results)
|
|
209
|
+
if discarded_count > 0:
|
|
210
|
+
LOGGER.info(f"Removed {discarded_count} results because below threshold")
|
|
211
|
+
if filtered_results:
|
|
212
|
+
flyscan_results = [
|
|
213
|
+
_xrc_result_in_boxes_to_result_in_mm(xr, parameters)
|
|
214
|
+
for xr in filtered_results
|
|
215
|
+
]
|
|
216
|
+
else:
|
|
217
|
+
LOGGER.warning("No X-ray centre received")
|
|
218
|
+
raise CrystalNotFoundException()
|
|
219
|
+
yield from _fire_xray_centre_result_event(flyscan_results)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@bpp.set_run_key_decorator(PlanNameConstants.GRIDSCAN_MAIN)
|
|
223
|
+
@bpp.run_decorator(md={"subplan_name": PlanNameConstants.GRIDSCAN_MAIN})
|
|
224
|
+
def run_gridscan(
|
|
225
|
+
fgs_composite: FlyScanEssentialDevices,
|
|
226
|
+
parameters: SpecifiedThreeDGridScan,
|
|
227
|
+
beamline_specific: BeamlineSpecificFGSFeatures,
|
|
228
|
+
):
|
|
229
|
+
# Currently gridscan only works for omega 0, see https://github.com/DiamondLightSource/mx-bluesky/issues/410
|
|
230
|
+
with TRACER.start_span("moving_omega_to_0"):
|
|
231
|
+
yield from bps.abs_set(fgs_composite.smargon.omega, 0)
|
|
232
|
+
|
|
233
|
+
with TRACER.start_span("ispyb_hardware_readings"):
|
|
234
|
+
yield from beamline_specific.read_pre_flyscan_plan()
|
|
235
|
+
|
|
236
|
+
LOGGER.info("Setting fgs params")
|
|
237
|
+
yield from beamline_specific.set_flyscan_params_plan()
|
|
238
|
+
|
|
239
|
+
LOGGER.info("Waiting for gridscan validity check")
|
|
240
|
+
yield from wait_for_gridscan_valid(beamline_specific.fgs_motors)
|
|
241
|
+
|
|
242
|
+
LOGGER.info("Waiting for arming to finish")
|
|
243
|
+
yield from bps.wait(PlanGroupCheckpointConstants.GRID_READY_FOR_DC)
|
|
244
|
+
yield from bps.stage(fgs_composite.eiger) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
245
|
+
|
|
246
|
+
yield from kickoff_and_complete_gridscan(
|
|
247
|
+
beamline_specific.fgs_motors,
|
|
248
|
+
fgs_composite.eiger,
|
|
249
|
+
fgs_composite.synchrotron,
|
|
250
|
+
[parameters.scan_points_first_grid, parameters.scan_points_second_grid],
|
|
251
|
+
parameters.scan_indices,
|
|
252
|
+
plan_during_collection=beamline_specific.read_during_collection_plan,
|
|
253
|
+
)
|
|
254
|
+
yield from bps.abs_set(beamline_specific.fgs_motors.z_steps, 0, wait=False)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def wait_for_gridscan_valid(fgs_motors: FastGridScanCommon, timeout=0.5):
|
|
258
|
+
LOGGER.info("Waiting for valid fgs_params")
|
|
259
|
+
SLEEP_PER_CHECK = 0.1
|
|
260
|
+
times_to_check = int(timeout / SLEEP_PER_CHECK)
|
|
261
|
+
for _ in range(times_to_check):
|
|
262
|
+
scan_invalid = yield from bps.rd(fgs_motors.scan_invalid)
|
|
263
|
+
pos_counter = yield from bps.rd(fgs_motors.position_counter)
|
|
264
|
+
LOGGER.debug(
|
|
265
|
+
f"Scan invalid: {scan_invalid} and position counter: {pos_counter}"
|
|
266
|
+
)
|
|
267
|
+
if not scan_invalid and pos_counter == 0:
|
|
268
|
+
LOGGER.info("Gridscan scan valid and position counter reset")
|
|
269
|
+
return
|
|
270
|
+
yield from bps.sleep(SLEEP_PER_CHECK)
|
|
271
|
+
raise SampleException("Scan invalid - pin too long/short/bent and out of range")
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _xrc_result_in_boxes_to_result_in_mm(
|
|
275
|
+
xrc_result: XrcResult, parameters: SpecifiedThreeDGridScan
|
|
276
|
+
) -> XRayCentreResult:
|
|
277
|
+
fgs_params = parameters.FGS_params
|
|
278
|
+
xray_centre = fgs_params.grid_position_to_motor_position(
|
|
279
|
+
np.array(xrc_result["centre_of_mass"])
|
|
280
|
+
)
|
|
281
|
+
# A correction is applied to the bounding box to map discrete grid coordinates to
|
|
282
|
+
# the corners of the box in motor-space; we do not apply this correction
|
|
283
|
+
# to the xray-centre as it is already in continuous space and the conversion has
|
|
284
|
+
# been performed already
|
|
285
|
+
# In other words, xrc_result["bounding_box"] contains the position of the box centre,
|
|
286
|
+
# so we subtract half a box to get the corner of the box
|
|
287
|
+
return XRayCentreResult(
|
|
288
|
+
centre_of_mass_mm=xray_centre,
|
|
289
|
+
bounding_box_mm=(
|
|
290
|
+
fgs_params.grid_position_to_motor_position(
|
|
291
|
+
np.array(xrc_result["bounding_box"][0]) - 0.5
|
|
292
|
+
),
|
|
293
|
+
fgs_params.grid_position_to_motor_position(
|
|
294
|
+
np.array(xrc_result["bounding_box"][1]) - 0.5
|
|
295
|
+
),
|
|
296
|
+
),
|
|
297
|
+
max_count=xrc_result["max_count"],
|
|
298
|
+
total_count=xrc_result["total_count"],
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _fire_xray_centre_result_event(results: Sequence[XRayCentreResult]):
|
|
303
|
+
def empty_plan():
|
|
304
|
+
return iter([])
|
|
305
|
+
|
|
306
|
+
yield from bpp.set_run_key_wrapper(
|
|
307
|
+
bpp.run_wrapper(
|
|
308
|
+
empty_plan(),
|
|
309
|
+
md={
|
|
310
|
+
PlanNameConstants.FLYSCAN_RESULTS: [
|
|
311
|
+
dataclasses.asdict(r) for r in results
|
|
312
|
+
]
|
|
313
|
+
},
|
|
314
|
+
),
|
|
315
|
+
PlanNameConstants.FLYSCAN_RESULTS,
|
|
316
|
+
)
|
|
File without changes
|
|
@@ -4,7 +4,7 @@ import bluesky.plan_stubs as bps
|
|
|
4
4
|
from bluesky.protocols import Readable
|
|
5
5
|
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
6
6
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
7
|
-
from dodal.devices.
|
|
7
|
+
from dodal.devices.common_dcm import BaseDCM
|
|
8
8
|
from dodal.devices.eiger import EigerDetector
|
|
9
9
|
from dodal.devices.flux import Flux
|
|
10
10
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
@@ -43,7 +43,7 @@ def standard_read_hardware_pre_collection(
|
|
|
43
43
|
undulator: Undulator,
|
|
44
44
|
synchrotron: Synchrotron,
|
|
45
45
|
s4_slit_gaps: S4SlitGaps,
|
|
46
|
-
dcm:
|
|
46
|
+
dcm: BaseDCM,
|
|
47
47
|
smargon: Smargon,
|
|
48
48
|
):
|
|
49
49
|
LOGGER.info("Reading status of beamline for callbacks, pre collection.")
|
|
@@ -63,7 +63,7 @@ def standard_read_hardware_during_collection(
|
|
|
63
63
|
aperture_scatterguard: ApertureScatterguard,
|
|
64
64
|
attenuator: BinaryFilterAttenuator,
|
|
65
65
|
flux: Flux,
|
|
66
|
-
dcm:
|
|
66
|
+
dcm: BaseDCM,
|
|
67
67
|
detector: EigerDetector,
|
|
68
68
|
):
|
|
69
69
|
signals_to_read_during_collection = [
|
mx_bluesky/common/utils/log.py
CHANGED
|
@@ -66,14 +66,15 @@ def do_default_logging_setup(
|
|
|
66
66
|
"""Configures dodal logger so that separate debug and info log files are created,
|
|
67
67
|
info logs are sent to Graylog, info logs are streamed to sys.sterr, and logs from ophyd
|
|
68
68
|
and bluesky and ophyd-async are optionally included."""
|
|
69
|
-
|
|
69
|
+
logging_path, debug_logging_path = _get_logging_dirs()
|
|
70
70
|
handlers = set_up_all_logging_handlers(
|
|
71
71
|
dodal_logger,
|
|
72
|
-
|
|
72
|
+
logging_path,
|
|
73
73
|
file_name,
|
|
74
74
|
dev_mode,
|
|
75
75
|
ERROR_LOG_BUFFER_LINES,
|
|
76
76
|
graylog_port,
|
|
77
|
+
debug_logging_path,
|
|
77
78
|
)
|
|
78
79
|
|
|
79
80
|
if integrate_all_logs:
|
|
@@ -102,8 +103,8 @@ def flush_debug_handler() -> str:
|
|
|
102
103
|
return handler.target.baseFilename
|
|
103
104
|
|
|
104
105
|
|
|
105
|
-
def
|
|
106
|
-
"""Get the
|
|
106
|
+
def _get_logging_dirs() -> tuple[Path, Path]:
|
|
107
|
+
"""Get the paths to write the mx_bluesky log files to.
|
|
107
108
|
|
|
108
109
|
Log location can be specified in the LOG_DIR environment variable, otherwise MX bluesky logs are written to 'dls_sw/ixx/logs/bluesky'.
|
|
109
110
|
This directory will be created if it is not found
|
|
@@ -111,18 +112,20 @@ def _get_logging_dir() -> Path:
|
|
|
111
112
|
Logs are written to ./tmp/logs/bluesky if BEAMLINE environment variable is not found
|
|
112
113
|
|
|
113
114
|
Returns:
|
|
114
|
-
|
|
115
|
+
tuple[Path, Path]: Paths to the standard log file and to the debug log file, for the file handlers to write to
|
|
115
116
|
"""
|
|
116
117
|
|
|
117
118
|
logging_str = environ.get("LOG_DIR")
|
|
119
|
+
beamline = environ.get("BEAMLINE")
|
|
118
120
|
if logging_str:
|
|
119
121
|
logging_path = Path(logging_str)
|
|
122
|
+
debug_logging_path = logging_path
|
|
123
|
+
elif beamline:
|
|
124
|
+
logging_path = Path(f"/dls_sw/{beamline}/logs/bluesky/")
|
|
125
|
+
debug_logging_path = Path(f"/dls/tmp/{beamline}/logs/bluesky/")
|
|
120
126
|
else:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Path(f"/dls_sw/{beamline}/logs/bluesky/")
|
|
124
|
-
if beamline
|
|
125
|
-
else Path("/tmp/logs/bluesky")
|
|
126
|
-
)
|
|
127
|
+
logging_path = Path("/tmp/logs/bluesky")
|
|
128
|
+
debug_logging_path = logging_path
|
|
127
129
|
Path.mkdir(logging_path, exist_ok=True, parents=True)
|
|
128
|
-
|
|
130
|
+
Path.mkdir(debug_logging_path, exist_ok=True, parents=True)
|
|
131
|
+
return logging_path, debug_logging_path
|
mx_bluesky/hyperion/__main__.py
CHANGED
|
@@ -82,7 +82,6 @@ class BlueskyRunner:
|
|
|
82
82
|
self,
|
|
83
83
|
RE: RunEngine,
|
|
84
84
|
context: BlueskyContext,
|
|
85
|
-
skip_startup_connection=False,
|
|
86
85
|
) -> None:
|
|
87
86
|
self.command_queue: Queue[Command] = Queue()
|
|
88
87
|
self.current_status: StatusAndMessage = StatusAndMessage(Status.IDLE)
|
|
@@ -101,12 +100,6 @@ class BlueskyRunner:
|
|
|
101
100
|
if VERBOSE_EVENT_LOGGING:
|
|
102
101
|
RE.subscribe(VerbosePlanExecutionLoggingCallback())
|
|
103
102
|
|
|
104
|
-
self.skip_startup_connection = skip_startup_connection
|
|
105
|
-
if not self.skip_startup_connection:
|
|
106
|
-
LOGGER.info("Initialising dodal devices...")
|
|
107
|
-
for plan_name in PLAN_REGISTRY:
|
|
108
|
-
PLAN_REGISTRY[plan_name]["setup"](context)
|
|
109
|
-
|
|
110
103
|
def start(
|
|
111
104
|
self,
|
|
112
105
|
experiment: Callable,
|
|
@@ -278,15 +271,11 @@ class FlushLogs(Resource):
|
|
|
278
271
|
def create_app(
|
|
279
272
|
test_config=None,
|
|
280
273
|
RE: RunEngine = RunEngine({}),
|
|
281
|
-
skip_startup_connection: bool = False,
|
|
282
274
|
) -> tuple[Flask, BlueskyRunner]:
|
|
283
|
-
context = setup_context(
|
|
284
|
-
wait_for_connection=not skip_startup_connection,
|
|
285
|
-
)
|
|
275
|
+
context = setup_context()
|
|
286
276
|
runner = BlueskyRunner(
|
|
287
277
|
RE,
|
|
288
278
|
context=context,
|
|
289
|
-
skip_startup_connection=skip_startup_connection,
|
|
290
279
|
)
|
|
291
280
|
app = Flask(__name__)
|
|
292
281
|
if test_config:
|
|
@@ -316,9 +305,7 @@ def create_targets():
|
|
|
316
305
|
CONST.LOG_FILE_NAME, CONST.GRAYLOG_PORT, dev_mode=args.dev_mode
|
|
317
306
|
)
|
|
318
307
|
LOGGER.info(f"Hyperion launched with args:{argv}")
|
|
319
|
-
app, runner = create_app(
|
|
320
|
-
skip_startup_connection=args.skip_startup_connection,
|
|
321
|
-
)
|
|
308
|
+
app, runner = create_app()
|
|
322
309
|
return app, runner, hyperion_port, args.dev_mode
|
|
323
310
|
|
|
324
311
|
|
|
@@ -6,7 +6,7 @@ from dodal.devices.focusing_mirror import (
|
|
|
6
6
|
MirrorStripe,
|
|
7
7
|
MirrorVoltages,
|
|
8
8
|
)
|
|
9
|
-
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
9
|
+
from dodal.devices.i03.undulator_dcm import UndulatorDCM
|
|
10
10
|
from dodal.devices.util.adjuster_plans import lookup_table_adjuster
|
|
11
11
|
from dodal.devices.util.lookup_tables import (
|
|
12
12
|
linear_interpolation_lut,
|
|
@@ -102,7 +102,7 @@ def adjust_dcm_pitch_roll_vfm_from_lut(
|
|
|
102
102
|
dcm = undulator_dcm.dcm_ref()
|
|
103
103
|
LOGGER.info(f"Adjusting DCM and VFM for {energy_kev} keV")
|
|
104
104
|
d_spacing_a: float = yield from bps.rd(
|
|
105
|
-
undulator_dcm.dcm_ref().
|
|
105
|
+
undulator_dcm.dcm_ref().crystal_metadata_d_spacing_a
|
|
106
106
|
)
|
|
107
107
|
bragg_deg = energy_to_bragg_angle(energy_kev, d_spacing_a)
|
|
108
108
|
LOGGER.info(f"Target Bragg angle = {bragg_deg} degrees")
|
|
@@ -110,7 +110,7 @@ def adjust_dcm_pitch_roll_vfm_from_lut(
|
|
|
110
110
|
linear_interpolation_lut(
|
|
111
111
|
*parse_lookup_table(undulator_dcm.pitch_energy_table_path)
|
|
112
112
|
),
|
|
113
|
-
dcm.pitch_in_mrad,
|
|
113
|
+
dcm.xtal_1.pitch_in_mrad,
|
|
114
114
|
bragg_deg,
|
|
115
115
|
)
|
|
116
116
|
yield from dcm_pitch_adjuster(DCM_GROUP)
|
|
@@ -122,7 +122,7 @@ def adjust_dcm_pitch_roll_vfm_from_lut(
|
|
|
122
122
|
linear_interpolation_lut(
|
|
123
123
|
*parse_lookup_table(undulator_dcm.roll_energy_table_path)
|
|
124
124
|
),
|
|
125
|
-
dcm.roll_in_mrad,
|
|
125
|
+
dcm.xtal_1.roll_in_mrad,
|
|
126
126
|
bragg_deg,
|
|
127
127
|
)
|
|
128
128
|
yield from dcm_roll_adjuster(DCM_GROUP)
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
from collections.abc import Callable
|
|
2
|
-
from functools import wraps
|
|
3
|
-
|
|
4
1
|
import bluesky.plan_stubs as bps
|
|
5
|
-
import bluesky.preprocessors as bpp
|
|
6
2
|
from bluesky.utils import MsgGenerator
|
|
7
3
|
from dodal.devices.zebra.zebra import (
|
|
8
4
|
ArmDemand,
|
|
@@ -21,31 +17,6 @@ from mx_bluesky.common.utils.log import LOGGER
|
|
|
21
17
|
ZEBRA_STATUS_TIMEOUT = 30
|
|
22
18
|
|
|
23
19
|
|
|
24
|
-
def bluesky_retry(func: Callable):
|
|
25
|
-
"""Decorator that will retry the decorated plan if it fails.
|
|
26
|
-
|
|
27
|
-
Use this with care as it knows nothing about the state of the world when things fail.
|
|
28
|
-
If it is possible that your plan fails when the beamline is in a transient state that
|
|
29
|
-
the plan could not act on do not use this decorator without doing some more intelligent
|
|
30
|
-
clean up.
|
|
31
|
-
|
|
32
|
-
You should avoid using this decorator often in general production as it hides errors,
|
|
33
|
-
instead it should be used only for debugging these underlying errors.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
@wraps(func)
|
|
37
|
-
def newfunc(*args, **kwargs):
|
|
38
|
-
def log_and_retry(exception):
|
|
39
|
-
LOGGER.error(f"Function {func.__name__} failed with {exception}, retrying")
|
|
40
|
-
yield from func(*args, **kwargs)
|
|
41
|
-
|
|
42
|
-
yield from bpp.contingency_wrapper(
|
|
43
|
-
func(*args, **kwargs), except_plan=log_and_retry, auto_raise=False
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
return newfunc
|
|
47
|
-
|
|
48
|
-
|
|
49
20
|
def arm_zebra(zebra: Zebra):
|
|
50
21
|
yield from bps.abs_set(zebra.pc.arm, ArmDemand.ARM, wait=True)
|
|
51
22
|
|
|
@@ -105,7 +76,6 @@ def configure_zebra_and_shutter_for_auto_shutter(
|
|
|
105
76
|
yield from set_shutter_auto_input(zebra, input, group=group)
|
|
106
77
|
|
|
107
78
|
|
|
108
|
-
@bluesky_retry
|
|
109
79
|
def setup_zebra_for_rotation(
|
|
110
80
|
zebra: Zebra,
|
|
111
81
|
zebra_shutter: ZebraShutter,
|
|
@@ -185,7 +155,6 @@ def setup_zebra_for_rotation(
|
|
|
185
155
|
yield from bps.wait(group, timeout=ZEBRA_STATUS_TIMEOUT)
|
|
186
156
|
|
|
187
157
|
|
|
188
|
-
@bluesky_retry
|
|
189
158
|
def setup_zebra_for_gridscan(
|
|
190
159
|
zebra: Zebra,
|
|
191
160
|
zebra_shutter: ZebraShutter,
|
|
@@ -215,7 +184,6 @@ def setup_zebra_for_gridscan(
|
|
|
215
184
|
yield from bps.wait(group, timeout=ZEBRA_STATUS_TIMEOUT)
|
|
216
185
|
|
|
217
186
|
|
|
218
|
-
@bluesky_retry
|
|
219
187
|
def tidy_up_zebra_after_gridscan(
|
|
220
188
|
zebra: Zebra,
|
|
221
189
|
zebra_shutter: ZebraShutter,
|
|
@@ -236,7 +204,6 @@ def tidy_up_zebra_after_gridscan(
|
|
|
236
204
|
yield from bps.wait(group, timeout=ZEBRA_STATUS_TIMEOUT)
|
|
237
205
|
|
|
238
206
|
|
|
239
|
-
@bluesky_retry
|
|
240
207
|
def setup_zebra_for_panda_flyscan(
|
|
241
208
|
zebra: Zebra,
|
|
242
209
|
zebra_shutter: ZebraShutter,
|
|
@@ -3,16 +3,16 @@ from collections.abc import Generator
|
|
|
3
3
|
from bluesky import plan_stubs as bps
|
|
4
4
|
from bluesky import preprocessors as bpp
|
|
5
5
|
from bluesky.utils import Msg
|
|
6
|
-
from dodal.devices.dcm import DCM
|
|
7
6
|
from dodal.devices.detector import (
|
|
8
7
|
DetectorParams,
|
|
9
8
|
)
|
|
10
9
|
from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
|
|
11
10
|
from dodal.devices.eiger import EigerDetector
|
|
12
|
-
from dodal.devices.i03
|
|
11
|
+
from dodal.devices.i03 import Beamstop
|
|
12
|
+
from dodal.devices.i03.dcm import DCM
|
|
13
13
|
|
|
14
|
-
from mx_bluesky.
|
|
15
|
-
from mx_bluesky.
|
|
14
|
+
from mx_bluesky.common.device_setup_plans.check_beamstop import check_beamstop
|
|
15
|
+
from mx_bluesky.common.device_setup_plans.position_detector import (
|
|
16
16
|
set_detector_z_position,
|
|
17
17
|
set_shutter,
|
|
18
18
|
)
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
The __all__ list in here are the plans that are externally available from outside Hyperion.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import (
|
|
7
|
-
flyscan_xray_centre,
|
|
8
|
-
)
|
|
9
6
|
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
10
7
|
grid_detect_then_xray_centre,
|
|
11
8
|
)
|
|
@@ -17,13 +14,10 @@ from mx_bluesky.hyperion.experiment_plans.pin_centre_then_xray_centre_plan impor
|
|
|
17
14
|
)
|
|
18
15
|
from mx_bluesky.hyperion.experiment_plans.rotation_scan_plan import (
|
|
19
16
|
multi_rotation_scan,
|
|
20
|
-
rotation_scan,
|
|
21
17
|
)
|
|
22
18
|
|
|
23
19
|
__all__ = [
|
|
24
|
-
"flyscan_xray_centre",
|
|
25
20
|
"grid_detect_then_xray_centre",
|
|
26
|
-
"rotation_scan",
|
|
27
21
|
"pin_tip_centre_then_xray_centre",
|
|
28
22
|
"multi_rotation_scan",
|
|
29
23
|
"load_centre_collect_full",
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
4
|
from typing import TypedDict
|
|
5
5
|
|
|
6
|
-
import mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan as flyscan_xray_centre_plan
|
|
7
6
|
import mx_bluesky.hyperion.experiment_plans.rotation_scan_plan as rotation_scan_plan
|
|
8
7
|
from mx_bluesky.hyperion.experiment_plans import (
|
|
9
8
|
grid_detect_then_xray_centre_plan,
|
|
@@ -40,18 +39,10 @@ class ExperimentRegistryEntry(TypedDict):
|
|
|
40
39
|
|
|
41
40
|
|
|
42
41
|
PLAN_REGISTRY: dict[str, ExperimentRegistryEntry] = {
|
|
43
|
-
"flyscan_xray_centre": {
|
|
44
|
-
"setup": flyscan_xray_centre_plan.create_devices,
|
|
45
|
-
"param_type": HyperionSpecifiedThreeDGridScan,
|
|
46
|
-
},
|
|
47
42
|
"grid_detect_then_xray_centre": {
|
|
48
43
|
"setup": grid_detect_then_xray_centre_plan.create_devices,
|
|
49
44
|
"param_type": GridScanWithEdgeDetect,
|
|
50
45
|
},
|
|
51
|
-
"rotation_scan": {
|
|
52
|
-
"setup": rotation_scan_plan.create_devices,
|
|
53
|
-
"param_type": RotationScan,
|
|
54
|
-
},
|
|
55
46
|
"pin_tip_centre_then_xray_centre": {
|
|
56
47
|
"setup": pin_centre_then_xray_centre_plan.create_devices,
|
|
57
48
|
"param_type": PinTipCentreThenXrayCentre,
|