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
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import pydantic
|
|
2
|
+
from dodal.devices.aperturescatterguard import (
|
|
3
|
+
ApertureScatterguard,
|
|
4
|
+
)
|
|
5
|
+
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
6
|
+
from dodal.devices.backlight import Backlight
|
|
7
|
+
from dodal.devices.common_dcm import BaseDCM
|
|
8
|
+
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
9
|
+
from dodal.devices.eiger import EigerDetector
|
|
10
|
+
from dodal.devices.fast_grid_scan import (
|
|
11
|
+
ZebraFastGridScan,
|
|
12
|
+
)
|
|
13
|
+
from dodal.devices.flux import Flux
|
|
14
|
+
from dodal.devices.i03 import Beamstop
|
|
15
|
+
from dodal.devices.oav.oav_detector import OAV
|
|
16
|
+
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
17
|
+
from dodal.devices.robot import BartRobot
|
|
18
|
+
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
19
|
+
from dodal.devices.smargon import Smargon
|
|
20
|
+
from dodal.devices.synchrotron import Synchrotron
|
|
21
|
+
from dodal.devices.undulator import Undulator
|
|
22
|
+
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
23
|
+
from dodal.devices.zebra.zebra import Zebra
|
|
24
|
+
from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
|
|
25
|
+
from dodal.devices.zocalo import ZocaloResults
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
29
|
+
class FlyScanEssentialDevices:
|
|
30
|
+
eiger: EigerDetector
|
|
31
|
+
synchrotron: Synchrotron
|
|
32
|
+
zocalo: ZocaloResults
|
|
33
|
+
smargon: Smargon
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
37
|
+
class OavGridDetectionComposite:
|
|
38
|
+
"""All devices which are directly or indirectly required by this plan"""
|
|
39
|
+
|
|
40
|
+
backlight: Backlight
|
|
41
|
+
oav: OAV
|
|
42
|
+
smargon: Smargon
|
|
43
|
+
pin_tip_detection: PinTipDetection
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
47
|
+
class GridDetectThenXRayCentreComposite(FlyScanEssentialDevices):
|
|
48
|
+
"""All devices which are directly or indirectly required by this plan"""
|
|
49
|
+
|
|
50
|
+
aperture_scatterguard: ApertureScatterguard
|
|
51
|
+
attenuator: BinaryFilterAttenuator
|
|
52
|
+
backlight: Backlight
|
|
53
|
+
beamstop: Beamstop
|
|
54
|
+
dcm: BaseDCM
|
|
55
|
+
detector_motion: DetectorMotion
|
|
56
|
+
zebra_fast_grid_scan: ZebraFastGridScan
|
|
57
|
+
flux: Flux
|
|
58
|
+
oav: OAV
|
|
59
|
+
pin_tip_detection: PinTipDetection
|
|
60
|
+
s4_slit_gaps: S4SlitGaps
|
|
61
|
+
undulator: Undulator
|
|
62
|
+
xbpm_feedback: XBPMFeedback
|
|
63
|
+
zebra: Zebra
|
|
64
|
+
robot: BartRobot
|
|
65
|
+
sample_shutter: ZebraShutter
|
|
File without changes
|
mx_bluesky/common/xrc_result.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
+
from collections import defaultdict
|
|
4
5
|
from collections.abc import Callable, Sequence
|
|
5
6
|
from functools import partial
|
|
6
7
|
|
|
@@ -10,6 +11,7 @@ from event_model import RunStart
|
|
|
10
11
|
|
|
11
12
|
from mx_bluesky.common.parameters.components import (
|
|
12
13
|
MultiXtalSelection,
|
|
14
|
+
TopNByMaxCountForEachSampleSelection,
|
|
13
15
|
TopNByMaxCountSelection,
|
|
14
16
|
)
|
|
15
17
|
|
|
@@ -39,18 +41,21 @@ class XRayCentreResult:
|
|
|
39
41
|
containing the crystal
|
|
40
42
|
max_count: The maximum spot count encountered in any one grid box in the crystal
|
|
41
43
|
total_count: The total count across all boxes in the crystal.
|
|
44
|
+
sample_id: The sample id associated with the centre.
|
|
42
45
|
"""
|
|
43
46
|
|
|
44
47
|
centre_of_mass_mm: np.ndarray
|
|
45
48
|
bounding_box_mm: tuple[np.ndarray, np.ndarray]
|
|
46
49
|
max_count: int
|
|
47
50
|
total_count: int
|
|
51
|
+
sample_id: int | None
|
|
48
52
|
|
|
49
53
|
def __eq__(self, o):
|
|
50
54
|
return (
|
|
51
55
|
isinstance(o, XRayCentreResult)
|
|
52
56
|
and o.max_count == self.max_count
|
|
53
57
|
and o.total_count == self.total_count
|
|
58
|
+
and o.sample_id == self.sample_id
|
|
54
59
|
and all(o.centre_of_mass_mm == self.centre_of_mass_mm)
|
|
55
60
|
and all(o.bounding_box_mm[0] == self.bounding_box_mm[0])
|
|
56
61
|
and all(o.bounding_box_mm[1] == self.bounding_box_mm[1])
|
|
@@ -64,9 +69,27 @@ def top_n_by_max_count(
|
|
|
64
69
|
return sorted_hits[:n]
|
|
65
70
|
|
|
66
71
|
|
|
72
|
+
def top_n_by_max_count_for_each_sample(
|
|
73
|
+
unfiltered: Sequence[XRayCentreResult], n: int
|
|
74
|
+
) -> Sequence[XRayCentreResult]:
|
|
75
|
+
xrc_results_by_sample_id: dict[int | None, list[XRayCentreResult]] = defaultdict(
|
|
76
|
+
list[XRayCentreResult]
|
|
77
|
+
)
|
|
78
|
+
for result in unfiltered:
|
|
79
|
+
xrc_results_by_sample_id[result.sample_id].append(result)
|
|
80
|
+
return [
|
|
81
|
+
result
|
|
82
|
+
for results in xrc_results_by_sample_id.values()
|
|
83
|
+
for result in sorted(results, key=lambda x: x.max_count, reverse=True)[:n]
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
|
|
67
87
|
def resolve_selection_fn(
|
|
68
88
|
params: MultiXtalSelection,
|
|
69
89
|
) -> Callable[[Sequence[XRayCentreResult]], Sequence[XRayCentreResult]]:
|
|
70
|
-
|
|
71
|
-
|
|
90
|
+
match params:
|
|
91
|
+
case TopNByMaxCountSelection():
|
|
92
|
+
return partial(top_n_by_max_count, n=params.n)
|
|
93
|
+
case TopNByMaxCountForEachSampleSelection():
|
|
94
|
+
return partial(top_n_by_max_count_for_each_sample, n=params.n)
|
|
72
95
|
raise ValueError(f"Invalid selection function {params.name}")
|
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
from collections.abc import Generator
|
|
2
|
-
|
|
3
1
|
from bluesky import plan_stubs as bps
|
|
4
|
-
from bluesky import preprocessors as bpp
|
|
5
|
-
from bluesky.utils import Msg
|
|
6
2
|
from dodal.devices.detector import (
|
|
7
3
|
DetectorParams,
|
|
8
4
|
)
|
|
9
|
-
from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
|
|
10
|
-
from dodal.devices.eiger import EigerDetector
|
|
11
5
|
from dodal.devices.i03.dcm import DCM
|
|
12
|
-
from dodal.devices.mx_phase1.beamstop import Beamstop, BeamstopPositions
|
|
13
|
-
|
|
14
|
-
from mx_bluesky.common.device_setup_plans.position_detector import (
|
|
15
|
-
set_detector_z_position,
|
|
16
|
-
set_shutter,
|
|
17
|
-
)
|
|
18
6
|
|
|
19
7
|
|
|
20
8
|
def fill_in_energy_if_not_supplied(dcm: DCM, detector_params: DetectorParams):
|
|
@@ -22,39 +10,3 @@ def fill_in_energy_if_not_supplied(dcm: DCM, detector_params: DetectorParams):
|
|
|
22
10
|
actual_energy_ev = 1000 * (yield from bps.rd(dcm.energy_in_kev))
|
|
23
11
|
detector_params.expected_energy_ev = actual_energy_ev
|
|
24
12
|
return detector_params
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def start_preparing_data_collection_then_do_plan(
|
|
28
|
-
beamstop: Beamstop,
|
|
29
|
-
eiger: EigerDetector,
|
|
30
|
-
detector_motion: DetectorMotion,
|
|
31
|
-
detector_distance_mm: float | None,
|
|
32
|
-
plan_to_run: Generator[Msg, None, None],
|
|
33
|
-
group="ready_for_data_collection",
|
|
34
|
-
) -> Generator[Msg, None, None]:
|
|
35
|
-
"""Starts preparing for the next data collection and then runs the
|
|
36
|
-
given plan.
|
|
37
|
-
|
|
38
|
-
Preparation consists of:
|
|
39
|
-
* Arming the Eiger
|
|
40
|
-
* Moving the detector to the specified position
|
|
41
|
-
* Opening the detect shutter
|
|
42
|
-
If the plan fails it will disarm the eiger.
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
def wrapped_plan():
|
|
46
|
-
yield from bps.abs_set(eiger.do_arm, 1, group=group) # type: ignore # Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
|
|
47
|
-
yield from bps.abs_set(
|
|
48
|
-
beamstop.selected_pos, BeamstopPositions.DATA_COLLECTION, group=group
|
|
49
|
-
)
|
|
50
|
-
if detector_distance_mm:
|
|
51
|
-
yield from set_detector_z_position(
|
|
52
|
-
detector_motion, detector_distance_mm, group
|
|
53
|
-
)
|
|
54
|
-
yield from set_shutter(detector_motion, ShutterState.OPEN, group)
|
|
55
|
-
yield from plan_to_run
|
|
56
|
-
|
|
57
|
-
yield from bpp.contingency_wrapper(
|
|
58
|
-
wrapped_plan(),
|
|
59
|
-
except_plan=lambda e: (yield from bps.stop(eiger)), # type: ignore # Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
|
|
60
|
-
)
|
|
@@ -3,8 +3,8 @@
|
|
|
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.
|
|
7
|
-
|
|
6
|
+
from mx_bluesky.hyperion.experiment_plans.hyperion_grid_detect_then_xray_centre_plan import (
|
|
7
|
+
hyperion_grid_detect_then_xray_centre,
|
|
8
8
|
)
|
|
9
9
|
from mx_bluesky.hyperion.experiment_plans.load_centre_collect_full_plan import (
|
|
10
10
|
load_centre_collect_full,
|
|
@@ -17,7 +17,7 @@ from mx_bluesky.hyperion.experiment_plans.rotation_scan_plan import (
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
__all__ = [
|
|
20
|
-
"
|
|
20
|
+
"hyperion_grid_detect_then_xray_centre",
|
|
21
21
|
"pin_tip_centre_then_xray_centre",
|
|
22
22
|
"rotation_scan",
|
|
23
23
|
"load_centre_collect_full",
|
|
@@ -5,7 +5,7 @@ from typing import TypedDict
|
|
|
5
5
|
|
|
6
6
|
import mx_bluesky.hyperion.experiment_plans.rotation_scan_plan as rotation_scan_plan
|
|
7
7
|
from mx_bluesky.hyperion.experiment_plans import (
|
|
8
|
-
|
|
8
|
+
hyperion_grid_detect_then_xray_centre_plan,
|
|
9
9
|
load_centre_collect_full_plan,
|
|
10
10
|
pin_centre_then_xray_centre_plan,
|
|
11
11
|
)
|
|
@@ -38,8 +38,8 @@ class ExperimentRegistryEntry(TypedDict):
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
PLAN_REGISTRY: dict[str, ExperimentRegistryEntry] = {
|
|
41
|
-
"
|
|
42
|
-
"setup":
|
|
41
|
+
"hyperion_grid_detect_then_xray_centre": {
|
|
42
|
+
"setup": hyperion_grid_detect_then_xray_centre_plan.create_devices,
|
|
43
43
|
"param_type": GridScanWithEdgeDetect,
|
|
44
44
|
},
|
|
45
45
|
"pin_tip_centre_then_xray_centre": {
|
|
@@ -9,7 +9,7 @@ from dodal.devices.fast_grid_scan import (
|
|
|
9
9
|
set_fast_grid_scan_params,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
from mx_bluesky.common.
|
|
12
|
+
from mx_bluesky.common.experiment_plans.common_flyscan_xray_centre_plan import (
|
|
13
13
|
construct_beamline_specific_FGS_features,
|
|
14
14
|
)
|
|
15
15
|
from mx_bluesky.common.utils.log import LOGGER
|
|
@@ -34,51 +34,50 @@ class SmargonSpeedException(Exception):
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def construct_hyperion_specific_features(
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
xrc_composite: HyperionFlyScanXRayCentreComposite,
|
|
38
|
+
xrc_parameters: HyperionSpecifiedThreeDGridScan,
|
|
39
39
|
):
|
|
40
40
|
"""
|
|
41
41
|
Get all the information needed to do the Hyperion-specific parts of the XRC flyscan.
|
|
42
42
|
"""
|
|
43
|
-
|
|
44
43
|
signals_to_read_pre_flyscan = [
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
xrc_composite.undulator.current_gap,
|
|
45
|
+
xrc_composite.synchrotron.synchrotron_mode,
|
|
46
|
+
xrc_composite.s4_slit_gaps.xgap,
|
|
47
|
+
xrc_composite.s4_slit_gaps.ygap,
|
|
48
|
+
xrc_composite.smargon.x,
|
|
49
|
+
xrc_composite.smargon.y,
|
|
50
|
+
xrc_composite.smargon.z,
|
|
51
|
+
xrc_composite.dcm.energy_in_kev,
|
|
53
52
|
]
|
|
54
53
|
|
|
55
54
|
signals_to_read_during_collection = [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
xrc_composite.aperture_scatterguard,
|
|
56
|
+
xrc_composite.attenuator.actual_transmission,
|
|
57
|
+
xrc_composite.flux.flux_reading,
|
|
58
|
+
xrc_composite.dcm.energy_in_kev,
|
|
59
|
+
xrc_composite.eiger.bit_depth,
|
|
61
60
|
]
|
|
62
61
|
|
|
63
|
-
if
|
|
62
|
+
if xrc_parameters.features.use_panda_for_gridscan:
|
|
64
63
|
setup_trigger_plan = _panda_triggering_setup
|
|
65
64
|
tidy_plan = _panda_tidy
|
|
66
65
|
set_flyscan_params_plan = partial(
|
|
67
66
|
set_fast_grid_scan_params,
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
xrc_composite.panda_fast_grid_scan,
|
|
68
|
+
xrc_parameters.panda_FGS_params,
|
|
70
69
|
)
|
|
71
|
-
fgs_motors =
|
|
70
|
+
fgs_motors = xrc_composite.panda_fast_grid_scan
|
|
72
71
|
|
|
73
72
|
else:
|
|
74
73
|
setup_trigger_plan = _zebra_triggering_setup
|
|
75
74
|
tidy_plan = partial(_generic_tidy, group="flyscan_zebra_tidy", wait=True)
|
|
76
75
|
set_flyscan_params_plan = partial(
|
|
77
76
|
set_fast_grid_scan_params,
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
xrc_composite.zebra_fast_grid_scan,
|
|
78
|
+
xrc_parameters.FGS_params,
|
|
80
79
|
)
|
|
81
|
-
fgs_motors =
|
|
80
|
+
fgs_motors = xrc_composite.zebra_fast_grid_scan
|
|
82
81
|
return construct_beamline_specific_FGS_features(
|
|
83
82
|
setup_trigger_plan,
|
|
84
83
|
tidy_plan,
|
|
@@ -91,47 +90,53 @@ def construct_hyperion_specific_features(
|
|
|
91
90
|
|
|
92
91
|
|
|
93
92
|
def _generic_tidy(
|
|
94
|
-
|
|
93
|
+
xrc_composite: HyperionFlyScanXRayCentreComposite, group, wait=True
|
|
95
94
|
) -> MsgGenerator:
|
|
96
95
|
LOGGER.info("Tidying up Zebra")
|
|
97
96
|
yield from tidy_up_zebra_after_gridscan(
|
|
98
|
-
|
|
97
|
+
xrc_composite.zebra, xrc_composite.sample_shutter, group=group, wait=wait
|
|
99
98
|
)
|
|
100
99
|
LOGGER.info("Tidying up Zocalo")
|
|
101
100
|
# make sure we don't consume any other results
|
|
102
|
-
yield from bps.unstage(
|
|
101
|
+
yield from bps.unstage(xrc_composite.zocalo, group=group, wait=wait)
|
|
103
102
|
|
|
104
103
|
# Turn off dev/shm streaming to avoid filling disk, see https://github.com/DiamondLightSource/hyperion/issues/1395
|
|
105
104
|
LOGGER.info("Turning off Eiger dev/shm streaming")
|
|
106
|
-
|
|
105
|
+
# Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
|
|
106
|
+
yield from bps.abs_set(
|
|
107
|
+
xrc_composite.eiger.odin.fan.dev_shm_enable, # type: ignore
|
|
108
|
+
0,
|
|
109
|
+
group=group,
|
|
110
|
+
wait=wait,
|
|
111
|
+
)
|
|
107
112
|
|
|
108
113
|
|
|
109
|
-
def _panda_tidy(
|
|
114
|
+
def _panda_tidy(xrc_composite: HyperionFlyScanXRayCentreComposite):
|
|
110
115
|
group = "panda_flyscan_tidy"
|
|
111
116
|
LOGGER.info("Disabling panda blocks")
|
|
112
|
-
yield from disarm_panda_for_gridscan(
|
|
113
|
-
yield from _generic_tidy(
|
|
117
|
+
yield from disarm_panda_for_gridscan(xrc_composite.panda, group)
|
|
118
|
+
yield from _generic_tidy(xrc_composite, group, False)
|
|
114
119
|
yield from bps.wait(group, timeout=10)
|
|
115
|
-
yield from bps.unstage(
|
|
120
|
+
yield from bps.unstage(xrc_composite.panda)
|
|
116
121
|
|
|
117
122
|
|
|
118
123
|
def _zebra_triggering_setup(
|
|
119
|
-
|
|
124
|
+
xrc_composite: HyperionFlyScanXRayCentreComposite,
|
|
120
125
|
parameters: HyperionSpecifiedThreeDGridScan,
|
|
121
126
|
) -> MsgGenerator:
|
|
122
127
|
yield from setup_zebra_for_gridscan(
|
|
123
|
-
|
|
128
|
+
xrc_composite.zebra, xrc_composite.sample_shutter, wait=True
|
|
124
129
|
)
|
|
125
130
|
|
|
126
131
|
|
|
127
132
|
def _panda_triggering_setup(
|
|
128
|
-
|
|
133
|
+
xrc_composite: HyperionFlyScanXRayCentreComposite,
|
|
129
134
|
parameters: HyperionSpecifiedThreeDGridScan,
|
|
130
135
|
) -> MsgGenerator:
|
|
131
136
|
LOGGER.info("Setting up Panda for flyscan")
|
|
132
137
|
|
|
133
138
|
run_up_distance_mm = yield from bps.rd(
|
|
134
|
-
|
|
139
|
+
xrc_composite.panda_fast_grid_scan.run_up_distance_mm
|
|
135
140
|
)
|
|
136
141
|
|
|
137
142
|
# Set the time between x steps pv
|
|
@@ -140,7 +145,7 @@ def _panda_triggering_setup(
|
|
|
140
145
|
time_between_x_steps_ms = (DEADTIME_S + parameters.exposure_time_s) * 1e3
|
|
141
146
|
|
|
142
147
|
smargon_speed_limit_mm_per_s = yield from bps.rd(
|
|
143
|
-
|
|
148
|
+
xrc_composite.smargon.x.max_velocity
|
|
144
149
|
)
|
|
145
150
|
|
|
146
151
|
sample_velocity_mm_per_s = (
|
|
@@ -161,7 +166,7 @@ def _panda_triggering_setup(
|
|
|
161
166
|
)
|
|
162
167
|
|
|
163
168
|
yield from bps.mv(
|
|
164
|
-
|
|
169
|
+
xrc_composite.panda_fast_grid_scan.time_between_x_steps_ms, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
165
170
|
time_between_x_steps_ms, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
166
171
|
)
|
|
167
172
|
|
|
@@ -169,9 +174,9 @@ def _panda_triggering_setup(
|
|
|
169
174
|
yield from set_panda_directory(directory_provider_root)
|
|
170
175
|
|
|
171
176
|
yield from setup_panda_for_flyscan(
|
|
172
|
-
|
|
177
|
+
xrc_composite.panda,
|
|
173
178
|
parameters.panda_FGS_params,
|
|
174
|
-
|
|
179
|
+
xrc_composite.smargon,
|
|
175
180
|
parameters.exposure_time_s,
|
|
176
181
|
time_between_x_steps_ms,
|
|
177
182
|
sample_velocity_mm_per_s,
|
|
@@ -179,5 +184,5 @@ def _panda_triggering_setup(
|
|
|
179
184
|
|
|
180
185
|
LOGGER.info("Setting up Zebra for panda flyscan")
|
|
181
186
|
yield from setup_zebra_for_panda_flyscan(
|
|
182
|
-
|
|
187
|
+
xrc_composite.zebra, xrc_composite.sample_shutter, wait=True
|
|
183
188
|
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from blueapi.core import BlueskyContext
|
|
4
|
+
from bluesky.utils import MsgGenerator
|
|
5
|
+
from dodal.plans.preprocessors.verify_undulator_gap import (
|
|
6
|
+
verify_undulator_gap_before_run_decorator,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from mx_bluesky.common.experiment_plans.common_grid_detect_then_xray_centre_plan import (
|
|
10
|
+
grid_detect_then_xray_centre,
|
|
11
|
+
)
|
|
12
|
+
from mx_bluesky.common.parameters.constants import OavConstants, PlanNameConstants
|
|
13
|
+
from mx_bluesky.common.preprocessors.preprocessors import (
|
|
14
|
+
transmission_and_xbpm_feedback_for_collection_decorator,
|
|
15
|
+
)
|
|
16
|
+
from mx_bluesky.common.utils.context import device_composite_from_context
|
|
17
|
+
from mx_bluesky.hyperion.experiment_plans.hyperion_flyscan_xray_centre_plan import (
|
|
18
|
+
construct_hyperion_specific_features,
|
|
19
|
+
)
|
|
20
|
+
from mx_bluesky.hyperion.parameters.device_composites import (
|
|
21
|
+
HyperionGridDetectThenXRayCentreComposite,
|
|
22
|
+
)
|
|
23
|
+
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
24
|
+
GridScanWithEdgeDetect,
|
|
25
|
+
HyperionSpecifiedThreeDGridScan,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def create_devices(
|
|
30
|
+
context: BlueskyContext,
|
|
31
|
+
) -> HyperionGridDetectThenXRayCentreComposite:
|
|
32
|
+
return device_composite_from_context(
|
|
33
|
+
context, HyperionGridDetectThenXRayCentreComposite
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def hyperion_grid_detect_then_xray_centre(
|
|
38
|
+
composite: HyperionGridDetectThenXRayCentreComposite,
|
|
39
|
+
parameters: GridScanWithEdgeDetect,
|
|
40
|
+
oav_config: str = OavConstants.OAV_CONFIG_JSON,
|
|
41
|
+
) -> MsgGenerator:
|
|
42
|
+
"""
|
|
43
|
+
A plan which combines the collection of snapshots from the OAV and the determination
|
|
44
|
+
of the grid dimensions to use for the following grid scan.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
@verify_undulator_gap_before_run_decorator(composite)
|
|
48
|
+
@transmission_and_xbpm_feedback_for_collection_decorator(
|
|
49
|
+
composite, parameters.transmission_frac, PlanNameConstants.GRIDSCAN_OUTER
|
|
50
|
+
)
|
|
51
|
+
def plan_to_perform():
|
|
52
|
+
yield from grid_detect_then_xray_centre(
|
|
53
|
+
composite=composite,
|
|
54
|
+
parameters=parameters,
|
|
55
|
+
xrc_params_type=HyperionSpecifiedThreeDGridScan,
|
|
56
|
+
construct_beamline_specific=construct_hyperion_specific_features,
|
|
57
|
+
oav_config=oav_config,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
yield from plan_to_perform()
|
|
@@ -76,17 +76,29 @@ def load_centre_collect_full(
|
|
|
76
76
|
flyscan_event_handler,
|
|
77
77
|
)
|
|
78
78
|
|
|
79
|
-
locations_to_collect_um: list[np.ndarray]
|
|
79
|
+
locations_to_collect_um: list[np.ndarray]
|
|
80
|
+
samples_to_collect: list[int]
|
|
80
81
|
|
|
81
82
|
if flyscan_event_handler.xray_centre_results:
|
|
82
83
|
selection_func = flyscan_result.resolve_selection_fn(
|
|
83
84
|
parameters.selection_params
|
|
84
85
|
)
|
|
85
86
|
hits = selection_func(flyscan_event_handler.xray_centre_results)
|
|
86
|
-
|
|
87
|
+
hits_to_collect = []
|
|
88
|
+
for hit in hits:
|
|
89
|
+
if hit.sample_id is None:
|
|
90
|
+
LOGGER.warning(
|
|
91
|
+
f"Diffracting centre {hit} not collected because no sample id was assigned."
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
hits_to_collect.append(hit)
|
|
87
95
|
|
|
96
|
+
locations_to_collect_um = [
|
|
97
|
+
hit.centre_of_mass_mm * 1000 for hit in hits_to_collect
|
|
98
|
+
]
|
|
99
|
+
samples_to_collect = [hit.sample_id for hit in hits_to_collect]
|
|
88
100
|
LOGGER.info(
|
|
89
|
-
f"Selected hits {
|
|
101
|
+
f"Selected hits {hits_to_collect} using {selection_func}, args={parameters.selection_params}"
|
|
90
102
|
)
|
|
91
103
|
else:
|
|
92
104
|
# If the xray centring hasn't found a result but has not thrown an error it
|
|
@@ -98,6 +110,7 @@ def load_centre_collect_full(
|
|
|
98
110
|
locations_to_collect_um = [
|
|
99
111
|
np.array([initial_x_mm, initial_y_mm, initial_z_mm]) * 1000
|
|
100
112
|
]
|
|
113
|
+
samples_to_collect = [parameters.sample_id]
|
|
101
114
|
|
|
102
115
|
multi_rotation = parameters.multi_rotation_scan
|
|
103
116
|
rotation_template = multi_rotation.rotation_scans.copy()
|
|
@@ -108,9 +121,11 @@ def load_centre_collect_full(
|
|
|
108
121
|
|
|
109
122
|
generator = rotation_scan_generator(is_alternating)
|
|
110
123
|
next(generator)
|
|
111
|
-
for location in
|
|
124
|
+
for location, sample_id in zip(
|
|
125
|
+
locations_to_collect_um, samples_to_collect, strict=True
|
|
126
|
+
):
|
|
112
127
|
for rot in rotation_template:
|
|
113
|
-
combination = generator.send((rot, location))
|
|
128
|
+
combination = generator.send((rot, location, sample_id))
|
|
114
129
|
multi_rotation.rotation_scans.append(combination)
|
|
115
130
|
multi_rotation = RotationScan.model_validate(multi_rotation)
|
|
116
131
|
|
|
@@ -125,8 +140,10 @@ def load_centre_collect_full(
|
|
|
125
140
|
|
|
126
141
|
def rotation_scan_generator(
|
|
127
142
|
is_alternating: bool,
|
|
128
|
-
) -> Generator[
|
|
129
|
-
|
|
143
|
+
) -> Generator[
|
|
144
|
+
RotationScanPerSweep, tuple[RotationScanPerSweep, np.ndarray, int], None
|
|
145
|
+
]:
|
|
146
|
+
scan_template, location, sample_id = yield # type: ignore
|
|
130
147
|
next_rotation_direction = scan_template.rotation_direction
|
|
131
148
|
while True:
|
|
132
149
|
scan = scan_template.model_copy()
|
|
@@ -135,6 +152,7 @@ def rotation_scan_generator(
|
|
|
135
152
|
scan.y_start_um,
|
|
136
153
|
scan.z_start_um,
|
|
137
154
|
) = location
|
|
155
|
+
scan.sample_id = sample_id
|
|
138
156
|
if is_alternating:
|
|
139
157
|
if next_rotation_direction != scan.rotation_direction:
|
|
140
158
|
# If originally specified direction of the current scan is different
|
|
@@ -146,4 +164,4 @@ def rotation_scan_generator(
|
|
|
146
164
|
scan.rotation_direction = next_rotation_direction
|
|
147
165
|
next_rotation_direction = next_rotation_direction.opposite
|
|
148
166
|
|
|
149
|
-
scan_template, location = yield scan
|
|
167
|
+
scan_template, location, sample_id = yield scan
|
|
@@ -9,9 +9,18 @@ from dodal.devices.eiger import EigerDetector
|
|
|
9
9
|
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
10
10
|
|
|
11
11
|
from mx_bluesky.common.device_setup_plans.manipulate_sample import move_phi_chi_omega
|
|
12
|
+
from mx_bluesky.common.device_setup_plans.utils import (
|
|
13
|
+
start_preparing_data_collection_then_do_plan,
|
|
14
|
+
)
|
|
12
15
|
from mx_bluesky.common.experiment_plans.change_aperture_then_move_plan import (
|
|
13
16
|
change_aperture_then_move_to_xtal,
|
|
14
17
|
)
|
|
18
|
+
from mx_bluesky.common.experiment_plans.common_grid_detect_then_xray_centre_plan import (
|
|
19
|
+
detect_grid_and_do_gridscan,
|
|
20
|
+
)
|
|
21
|
+
from mx_bluesky.common.experiment_plans.oav_snapshot_plan import (
|
|
22
|
+
setup_beamline_for_OAV,
|
|
23
|
+
)
|
|
15
24
|
from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import (
|
|
16
25
|
ispyb_activation_wrapper,
|
|
17
26
|
)
|
|
@@ -19,32 +28,33 @@ from mx_bluesky.common.parameters.constants import OavConstants
|
|
|
19
28
|
from mx_bluesky.common.utils.context import device_composite_from_context
|
|
20
29
|
from mx_bluesky.common.utils.log import LOGGER
|
|
21
30
|
from mx_bluesky.common.xrc_result import XRayCentreEventHandler
|
|
22
|
-
from mx_bluesky.hyperion.
|
|
23
|
-
|
|
24
|
-
)
|
|
25
|
-
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
26
|
-
GridDetectThenXRayCentreComposite,
|
|
27
|
-
detect_grid_and_do_gridscan,
|
|
28
|
-
)
|
|
29
|
-
from mx_bluesky.hyperion.experiment_plans.oav_snapshot_plan import (
|
|
30
|
-
setup_beamline_for_OAV,
|
|
31
|
+
from mx_bluesky.hyperion.experiment_plans.hyperion_flyscan_xray_centre_plan import (
|
|
32
|
+
construct_hyperion_specific_features,
|
|
31
33
|
)
|
|
32
34
|
from mx_bluesky.hyperion.experiment_plans.pin_tip_centring_plan import (
|
|
33
35
|
PinTipCentringComposite,
|
|
34
36
|
pin_tip_centre_plan,
|
|
35
37
|
)
|
|
36
38
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
39
|
+
from mx_bluesky.hyperion.parameters.device_composites import (
|
|
40
|
+
HyperionGridDetectThenXRayCentreComposite,
|
|
41
|
+
)
|
|
37
42
|
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
38
43
|
GridScanWithEdgeDetect,
|
|
44
|
+
HyperionSpecifiedThreeDGridScan,
|
|
39
45
|
PinTipCentreThenXrayCentre,
|
|
40
46
|
)
|
|
41
47
|
|
|
42
48
|
|
|
43
|
-
def create_devices(
|
|
49
|
+
def create_devices(
|
|
50
|
+
context: BlueskyContext,
|
|
51
|
+
) -> HyperionGridDetectThenXRayCentreComposite:
|
|
44
52
|
"""
|
|
45
|
-
|
|
53
|
+
HyperionGridDetectThenXRayCentreComposite contains all the devices we need, reuse that.
|
|
46
54
|
"""
|
|
47
|
-
return device_composite_from_context(
|
|
55
|
+
return device_composite_from_context(
|
|
56
|
+
context, HyperionGridDetectThenXRayCentreComposite
|
|
57
|
+
)
|
|
48
58
|
|
|
49
59
|
|
|
50
60
|
def create_parameters_for_grid_detection(
|
|
@@ -60,7 +70,7 @@ def create_parameters_for_grid_detection(
|
|
|
60
70
|
|
|
61
71
|
|
|
62
72
|
def pin_centre_then_flyscan_plan(
|
|
63
|
-
composite:
|
|
73
|
+
composite: HyperionGridDetectThenXRayCentreComposite,
|
|
64
74
|
parameters: PinTipCentreThenXrayCentre,
|
|
65
75
|
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
66
76
|
):
|
|
@@ -92,20 +102,21 @@ def pin_centre_then_flyscan_plan(
|
|
|
92
102
|
)
|
|
93
103
|
|
|
94
104
|
grid_detect_params = create_parameters_for_grid_detection(parameters)
|
|
95
|
-
|
|
96
105
|
oav_params = OAVParameters("xrayCentring", oav_config_file)
|
|
97
106
|
|
|
98
107
|
yield from detect_grid_and_do_gridscan(
|
|
99
108
|
composite,
|
|
100
109
|
grid_detect_params,
|
|
101
110
|
oav_params,
|
|
111
|
+
HyperionSpecifiedThreeDGridScan,
|
|
112
|
+
construct_hyperion_specific_features,
|
|
102
113
|
)
|
|
103
114
|
|
|
104
115
|
yield from ispyb_activation_wrapper(_pin_centre_then_flyscan_plan(), parameters)
|
|
105
116
|
|
|
106
117
|
|
|
107
118
|
def pin_tip_centre_then_xray_centre(
|
|
108
|
-
composite:
|
|
119
|
+
composite: HyperionGridDetectThenXRayCentreComposite,
|
|
109
120
|
parameters: PinTipCentreThenXrayCentre,
|
|
110
121
|
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
111
122
|
) -> MsgGenerator:
|