mx-bluesky 1.4.2__py3-none-any.whl → 1.4.4__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/dcid.py +3 -3
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +24 -9
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +13 -4
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +1 -1
- mx_bluesky/beamlines/i24/serial/parameters/__init__.py +2 -1
- mx_bluesky/beamlines/i24/serial/parameters/constants.py +13 -5
- mx_bluesky/beamlines/i24/serial/parameters/experiment_parameters.py +20 -4
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +40 -11
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +81 -40
- mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/aperture_change_callback.py +1 -1
- mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/grid_detection_callback.py +19 -1
- mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/ispyb_callback_base.py +40 -34
- mx_bluesky/{hyperion → common}/external_interaction/callbacks/common/ispyb_mapping.py +4 -4
- mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/logging_callback.py +1 -1
- mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/zocalo_callback.py +13 -19
- mx_bluesky/{hyperion → common}/external_interaction/callbacks/xray_centre/ispyb_callback.py +39 -34
- mx_bluesky/{hyperion → common}/external_interaction/callbacks/xray_centre/ispyb_mapping.py +2 -2
- mx_bluesky/{hyperion → common}/external_interaction/callbacks/xray_centre/nexus_callback.py +20 -15
- mx_bluesky/common/external_interaction/config_server.py +11 -0
- mx_bluesky/common/external_interaction/ispyb/__init__.py +0 -0
- mx_bluesky/{hyperion → common}/external_interaction/ispyb/data_model.py +2 -0
- mx_bluesky/{hyperion → common}/external_interaction/ispyb/exp_eye_store.py +5 -5
- mx_bluesky/{hyperion → common}/external_interaction/ispyb/ispyb_store.py +20 -18
- mx_bluesky/{hyperion → common}/external_interaction/ispyb/ispyb_utils.py +2 -2
- mx_bluesky/common/external_interaction/nexus/__init__.py +0 -0
- mx_bluesky/{hyperion → common}/external_interaction/nexus/nexus_utils.py +21 -6
- mx_bluesky/{hyperion → common}/external_interaction/nexus/write_nexus.py +5 -5
- mx_bluesky/common/external_interaction/test_config_server.py +38 -0
- mx_bluesky/common/parameters/components.py +9 -8
- mx_bluesky/common/parameters/constants.py +1 -0
- mx_bluesky/common/parameters/gridscan.py +107 -53
- mx_bluesky/common/plans/do_fgs.py +4 -10
- mx_bluesky/{hyperion → common/utils}/exceptions.py +15 -1
- mx_bluesky/common/utils/log.py +17 -7
- mx_bluesky/hyperion/__main__.py +15 -14
- mx_bluesky/hyperion/device_setup_plans/check_beamstop.py +27 -0
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +13 -6
- mx_bluesky/hyperion/device_setup_plans/manipulate_sample.py +1 -1
- mx_bluesky/hyperion/device_setup_plans/position_detector.py +1 -1
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +3 -3
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +21 -4
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +62 -36
- mx_bluesky/hyperion/device_setup_plans/smargon.py +1 -1
- mx_bluesky/hyperion/device_setup_plans/utils.py +4 -0
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +8 -8
- mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +28 -17
- mx_bluesky/hyperion/experiment_plans/common/xrc_result.py +10 -1
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -9
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +39 -49
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +22 -23
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +4 -11
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +3 -3
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +6 -14
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +12 -11
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +9 -4
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +10 -11
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +33 -17
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +32 -23
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +60 -34
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +22 -15
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +25 -24
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +13 -9
- mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/sample_handling_callback.py +12 -46
- mx_bluesky/hyperion/external_interaction/config_server.py +15 -1
- mx_bluesky/hyperion/parameters/components.py +3 -2
- mx_bluesky/hyperion/parameters/constants.py +1 -0
- mx_bluesky/hyperion/parameters/gridscan.py +54 -89
- mx_bluesky/hyperion/parameters/load_centre_collect.py +51 -6
- mx_bluesky/hyperion/parameters/robot_load.py +40 -0
- mx_bluesky/hyperion/parameters/rotation.py +28 -3
- mx_bluesky/hyperion/utils/context.py +1 -1
- mx_bluesky/hyperion/utils/validation.py +4 -2
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.4.dist-info}/METADATA +6 -6
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.4.dist-info}/RECORD +89 -87
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.4.dist-info}/WHEEL +1 -1
- mx_bluesky/common/parameters/robot_load.py +0 -16
- mx_bluesky/hyperion/external_interaction/exceptions.py +0 -4
- mx_bluesky/hyperion/log.py +0 -15
- /mx_bluesky/{hyperion/external_interaction/callbacks/xray_centre → common/external_interaction}/__init__.py +0 -0
- /mx_bluesky/{hyperion/external_interaction/ispyb → common/external_interaction/callbacks/common}/__init__.py +0 -0
- /mx_bluesky/{hyperion → common}/external_interaction/callbacks/common/abstract_event.py +0 -0
- /mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/log_uid_tag_callback.py +0 -0
- /mx_bluesky/{hyperion/external_interaction/callbacks → common/external_interaction/callbacks/common}/plan_reactive_callback.py +0 -0
- /mx_bluesky/{hyperion/external_interaction/nexus → common/external_interaction/callbacks/xray_centre}/__init__.py +0 -0
- /mx_bluesky/{hyperion → common}/utils/utils.py +0 -0
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.4.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.4.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.4.dist-info}/top_level.txt +0 -0
|
@@ -3,28 +3,27 @@ from __future__ import annotations
|
|
|
3
3
|
from collections.abc import Callable, Sequence
|
|
4
4
|
from typing import TYPE_CHECKING, Any, cast
|
|
5
5
|
|
|
6
|
-
from mx_bluesky.common.
|
|
7
|
-
from mx_bluesky.common.utils.log import set_dcgid_tag
|
|
8
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.common.ispyb_mapping import (
|
|
9
|
-
populate_data_collection_group,
|
|
10
|
-
populate_remaining_data_collection_info,
|
|
11
|
-
)
|
|
12
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.ispyb_callback_base import (
|
|
6
|
+
from mx_bluesky.common.external_interaction.callbacks.common.ispyb_callback_base import (
|
|
13
7
|
BaseISPyBCallback,
|
|
14
8
|
)
|
|
15
|
-
from mx_bluesky.
|
|
16
|
-
|
|
9
|
+
from mx_bluesky.common.external_interaction.callbacks.common.ispyb_mapping import (
|
|
10
|
+
populate_data_collection_group,
|
|
11
|
+
populate_remaining_data_collection_info,
|
|
17
12
|
)
|
|
18
|
-
from mx_bluesky.
|
|
13
|
+
from mx_bluesky.common.external_interaction.ispyb.data_model import (
|
|
19
14
|
DataCollectionInfo,
|
|
20
15
|
DataCollectionPositionInfo,
|
|
21
16
|
ScanDataInfo,
|
|
22
17
|
)
|
|
23
|
-
from mx_bluesky.
|
|
18
|
+
from mx_bluesky.common.external_interaction.ispyb.ispyb_store import (
|
|
24
19
|
IspybIds,
|
|
25
20
|
StoreInIspyb,
|
|
26
21
|
)
|
|
27
|
-
from mx_bluesky.
|
|
22
|
+
from mx_bluesky.common.parameters.components import IspybExperimentType
|
|
23
|
+
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER, set_dcgid_tag
|
|
24
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.rotation.ispyb_mapping import (
|
|
25
|
+
populate_data_collection_info_for_rotation,
|
|
26
|
+
)
|
|
28
27
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
29
28
|
from mx_bluesky.hyperion.parameters.rotation import RotationScan
|
|
30
29
|
|
|
@@ -58,10 +57,10 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
58
57
|
|
|
59
58
|
def activity_gated_start(self, doc: RunStart):
|
|
60
59
|
if doc.get("subplan_name") == CONST.PLAN.ROTATION_OUTER:
|
|
61
|
-
|
|
60
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
62
61
|
"ISPyB callback received start document with experiment parameters."
|
|
63
62
|
)
|
|
64
|
-
hyperion_params = doc.get("
|
|
63
|
+
hyperion_params = doc.get("mx_bluesky_parameters")
|
|
65
64
|
assert isinstance(hyperion_params, str)
|
|
66
65
|
self.params = RotationScan.model_validate_json(hyperion_params)
|
|
67
66
|
dcgid = (
|
|
@@ -73,16 +72,18 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
73
72
|
self.params.ispyb_experiment_type
|
|
74
73
|
== IspybExperimentType.CHARACTERIZATION
|
|
75
74
|
):
|
|
76
|
-
|
|
75
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
76
|
+
"Screening collection - using new DCG"
|
|
77
|
+
)
|
|
77
78
|
dcgid = None
|
|
78
79
|
self.last_sample_id = None
|
|
79
80
|
else:
|
|
80
|
-
|
|
81
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
81
82
|
f"Collection is {self.params.ispyb_experiment_type} - storing sampleID to bundle images"
|
|
82
83
|
)
|
|
83
84
|
self.last_sample_id = self.params.sample_id
|
|
84
85
|
self.ispyb = StoreInIspyb(self.ispyb_config)
|
|
85
|
-
|
|
86
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info("Beginning ispyb deposition")
|
|
86
87
|
data_collection_group_info = populate_data_collection_group(self.params)
|
|
87
88
|
data_collection_info = populate_data_collection_info_for_rotation(
|
|
88
89
|
cast(RotationScan, self.params)
|
|
@@ -100,7 +101,7 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
100
101
|
self.ispyb_ids = self.ispyb.begin_deposition(
|
|
101
102
|
data_collection_group_info, [scan_data_info]
|
|
102
103
|
)
|
|
103
|
-
|
|
104
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info("ISPYB handler received start document.")
|
|
104
105
|
if doc.get("subplan_name") == CONST.PLAN.ROTATION_MAIN:
|
|
105
106
|
self.uid_to_finalize_on = doc.get("uid")
|
|
106
107
|
return super().activity_gated_start(doc)
|
|
@@ -111,9 +112,9 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
111
112
|
event_sourced_position_info: DataCollectionPositionInfo | None,
|
|
112
113
|
params,
|
|
113
114
|
) -> Sequence[ScanDataInfo]:
|
|
114
|
-
assert (
|
|
115
|
-
|
|
116
|
-
)
|
|
115
|
+
assert self.ispyb_ids.data_collection_ids, (
|
|
116
|
+
"Expect an existing DataCollection to update"
|
|
117
|
+
)
|
|
117
118
|
|
|
118
119
|
return [
|
|
119
120
|
ScanDataInfo(
|
|
@@ -131,9 +132,9 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
131
132
|
doc["data"]["smargon-y"],
|
|
132
133
|
doc["data"]["smargon-z"],
|
|
133
134
|
]
|
|
134
|
-
assert (
|
|
135
|
-
|
|
136
|
-
)
|
|
135
|
+
assert self.params, (
|
|
136
|
+
"handle_ispyb_hardware_read triggered before activity_gated_start"
|
|
137
|
+
)
|
|
137
138
|
motor_positions_um = [position * 1000 for position in motor_positions_mm]
|
|
138
139
|
comment = f"Sample position (µm): ({motor_positions_um[0]:.0f}, {motor_positions_um[1]:.0f}, {motor_positions_um[2]:.0f}) {self.params.comment} "
|
|
139
140
|
scan_data_infos[0].data_collection_info.comments = comment
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from mx_bluesky.
|
|
3
|
+
from mx_bluesky.common.external_interaction.ispyb.data_model import DataCollectionInfo
|
|
4
4
|
from mx_bluesky.hyperion.parameters.rotation import RotationScan
|
|
5
5
|
|
|
6
6
|
|
|
@@ -2,20 +2,22 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
-
from mx_bluesky.
|
|
5
|
+
from mx_bluesky.common.external_interaction.callbacks.common.logging_callback import (
|
|
6
|
+
format_doc_for_log,
|
|
7
|
+
)
|
|
8
|
+
from mx_bluesky.common.external_interaction.callbacks.common.plan_reactive_callback import (
|
|
6
9
|
PlanReactiveCallback,
|
|
7
10
|
)
|
|
8
|
-
from mx_bluesky.
|
|
11
|
+
from mx_bluesky.common.external_interaction.nexus.nexus_utils import (
|
|
12
|
+
AxisDirection,
|
|
9
13
|
create_beam_and_attenuator_parameters,
|
|
10
14
|
vds_type_based_on_bit_depth,
|
|
11
15
|
)
|
|
12
|
-
from mx_bluesky.
|
|
13
|
-
from mx_bluesky.
|
|
16
|
+
from mx_bluesky.common.external_interaction.nexus.write_nexus import NexusWriter
|
|
17
|
+
from mx_bluesky.common.utils.log import NEXUS_LOGGER
|
|
14
18
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
15
19
|
from mx_bluesky.hyperion.parameters.rotation import RotationScan
|
|
16
20
|
|
|
17
|
-
from ..logging_callback import format_doc_for_log
|
|
18
|
-
|
|
19
21
|
if TYPE_CHECKING:
|
|
20
22
|
from event_model.documents import Event, EventDescriptor, RunStart
|
|
21
23
|
|
|
@@ -64,7 +66,7 @@ class RotationNexusFileCallback(PlanReactiveCallback):
|
|
|
64
66
|
self.writer.attenuator,
|
|
65
67
|
) = create_beam_and_attenuator_parameters(
|
|
66
68
|
data["dcm-energy_in_kev"],
|
|
67
|
-
data["
|
|
69
|
+
data["flux-flux_reading"],
|
|
68
70
|
data["attenuator-actual_transmission"],
|
|
69
71
|
)
|
|
70
72
|
vds_data_type = vds_type_based_on_bit_depth(doc["data"]["eiger_bit_depth"])
|
|
@@ -78,7 +80,7 @@ class RotationNexusFileCallback(PlanReactiveCallback):
|
|
|
78
80
|
self.meta_data_run_number = doc.get("meta_data_run_number")
|
|
79
81
|
if doc.get("subplan_name") == CONST.PLAN.ROTATION_OUTER:
|
|
80
82
|
self.run_uid = doc.get("uid")
|
|
81
|
-
hyperion_params = doc.get("
|
|
83
|
+
hyperion_params = doc.get("mx_bluesky_parameters")
|
|
82
84
|
assert isinstance(hyperion_params, str)
|
|
83
85
|
NEXUS_LOGGER.info(
|
|
84
86
|
f"Nexus writer received start document with experiment parameters {hyperion_params}"
|
|
@@ -100,5 +102,7 @@ class RotationNexusFileCallback(PlanReactiveCallback):
|
|
|
100
102
|
vds_start_index=parameters.nexus_vds_start_img,
|
|
101
103
|
full_num_of_images=self.full_num_of_images,
|
|
102
104
|
meta_data_run_number=self.meta_data_run_number,
|
|
103
|
-
|
|
105
|
+
axis_direction=AxisDirection.NEGATIVE
|
|
106
|
+
if parameters.features.omega_flip
|
|
107
|
+
else AxisDirection.POSITIVE,
|
|
104
108
|
)
|
mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/sample_handling_callback.py
CHANGED
|
@@ -1,45 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
from collections.abc import Generator
|
|
3
|
-
from functools import partial
|
|
4
|
-
from typing import Any
|
|
1
|
+
from event_model import RunStart, RunStop
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
from bluesky.preprocessors import contingency_wrapper
|
|
8
|
-
from bluesky.utils import Msg, make_decorator
|
|
9
|
-
from event_model import Event, EventDescriptor, RunStart
|
|
10
|
-
|
|
11
|
-
from mx_bluesky.hyperion.exceptions import CrystalNotFoundException, SampleException
|
|
12
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.common.abstract_event import (
|
|
13
|
-
AbstractEvent,
|
|
14
|
-
)
|
|
15
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.plan_reactive_callback import (
|
|
3
|
+
from mx_bluesky.common.external_interaction.callbacks.common.plan_reactive_callback import (
|
|
16
4
|
PlanReactiveCallback,
|
|
17
5
|
)
|
|
18
|
-
from mx_bluesky.
|
|
6
|
+
from mx_bluesky.common.external_interaction.ispyb.exp_eye_store import (
|
|
19
7
|
BLSampleStatus,
|
|
20
8
|
ExpeyeInteraction,
|
|
21
9
|
)
|
|
22
|
-
from mx_bluesky.
|
|
23
|
-
from mx_bluesky.
|
|
24
|
-
|
|
25
|
-
# TODO remove this event-raising shenanigans once
|
|
26
|
-
# https://github.com/bluesky/bluesky/issues/1829 is addressed
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@dataclasses.dataclass(frozen=True)
|
|
30
|
-
class _ExceptionEvent(AbstractEvent):
|
|
31
|
-
exception_type: str
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _exception_interceptor(exception: Exception) -> Generator[Msg, Any, Any]:
|
|
35
|
-
yield from bps.create(CONST.DESCRIPTORS.SAMPLE_HANDLING_EXCEPTION)
|
|
36
|
-
yield from bps.read(_ExceptionEvent(type(exception).__name__))
|
|
37
|
-
yield from bps.save()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
sample_handling_callback_decorator = make_decorator(
|
|
41
|
-
partial(contingency_wrapper, except_plan=_exception_interceptor)
|
|
42
|
-
)
|
|
10
|
+
from mx_bluesky.common.utils.exceptions import CrystalNotFoundException, SampleException
|
|
11
|
+
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER
|
|
43
12
|
|
|
44
13
|
|
|
45
14
|
class SampleHandlingCallback(PlanReactiveCallback):
|
|
@@ -47,7 +16,7 @@ class SampleHandlingCallback(PlanReactiveCallback):
|
|
|
47
16
|
field according to the type of exception raised."""
|
|
48
17
|
|
|
49
18
|
def __init__(self):
|
|
50
|
-
super().__init__(log=
|
|
19
|
+
super().__init__(log=ISPYB_ZOCALO_CALLBACK_LOGGER)
|
|
51
20
|
self._sample_id: int | None = None
|
|
52
21
|
self._descriptor: str | None = None
|
|
53
22
|
|
|
@@ -57,16 +26,13 @@ class SampleHandlingCallback(PlanReactiveCallback):
|
|
|
57
26
|
self.log.info(f"Recording sample ID at run start {sample_id}")
|
|
58
27
|
self._sample_id = sample_id
|
|
59
28
|
|
|
60
|
-
def
|
|
61
|
-
if doc
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def activity_gated_event(self, doc: Event) -> Event | None:
|
|
66
|
-
if doc["descriptor"] == self._descriptor:
|
|
67
|
-
exception_type = doc["data"]["exception_type"]
|
|
29
|
+
def activity_gated_stop(self, doc: RunStop) -> RunStop:
|
|
30
|
+
if doc["exit_status"] != "success":
|
|
31
|
+
exception_type, message = SampleException.type_and_message_from_reason(
|
|
32
|
+
doc.get("reason", "")
|
|
33
|
+
)
|
|
68
34
|
self.log.info(
|
|
69
|
-
f"Sample handling callback intercepted exception of type {exception_type}"
|
|
35
|
+
f"Sample handling callback intercepted exception of type {exception_type}: {message}"
|
|
70
36
|
)
|
|
71
37
|
self._record_exception(exception_type)
|
|
72
38
|
return doc
|
|
@@ -3,11 +3,24 @@ from functools import cache
|
|
|
3
3
|
from daq_config_server.client import ConfigServer
|
|
4
4
|
|
|
5
5
|
from mx_bluesky.common.external_interaction.config_server import FeatureFlags
|
|
6
|
-
from mx_bluesky.
|
|
6
|
+
from mx_bluesky.common.utils.log import LOGGER
|
|
7
7
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class HyperionFeatureFlags(FeatureFlags):
|
|
11
|
+
"""
|
|
12
|
+
Feature flags specific to Hyperion.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
use_panda_for_gridscan: If True then the PandA is used for gridscans, otherwise the zebra is used
|
|
16
|
+
compare_cpu_and_gpu_zocalo: If True then GPU result processing is enabled alongside CPU, if False then
|
|
17
|
+
CPU only is used.
|
|
18
|
+
set_stub_offsets: If True then set the stub offsets after moving to the crystal (ignored for
|
|
19
|
+
multi-centre)
|
|
20
|
+
omega_flip: If True then invert the smargon omega motor rotation commands with respect to
|
|
21
|
+
the hyperion request.
|
|
22
|
+
"""
|
|
23
|
+
|
|
11
24
|
@staticmethod
|
|
12
25
|
@cache
|
|
13
26
|
def get_config_server() -> ConfigServer:
|
|
@@ -16,3 +29,4 @@ class HyperionFeatureFlags(FeatureFlags):
|
|
|
16
29
|
use_panda_for_gridscan: bool = CONST.I03.USE_PANDA_FOR_GRIDSCAN
|
|
17
30
|
compare_cpu_and_gpu_zocalo: bool = CONST.I03.COMPARE_CPU_AND_GPU_ZOCALO
|
|
18
31
|
set_stub_offsets: bool = CONST.I03.SET_STUB_OFFSETS
|
|
32
|
+
omega_flip: bool = CONST.I03.OMEGA_FLIP
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from pydantic import
|
|
1
|
+
from pydantic import Field
|
|
2
2
|
|
|
3
|
+
from mx_bluesky.common.parameters.components import WithPandaGridScan
|
|
3
4
|
from mx_bluesky.hyperion.external_interaction.config_server import HyperionFeatureFlags
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
class
|
|
7
|
+
class WithHyperionUDCFeatures(WithPandaGridScan):
|
|
7
8
|
features: HyperionFeatureFlags = Field(default=HyperionFeatureFlags())
|
|
@@ -28,6 +28,7 @@ class I03Constants:
|
|
|
28
28
|
SHUTTER_TIME_S = 0.06
|
|
29
29
|
USE_PANDA_FOR_GRIDSCAN = False
|
|
30
30
|
SET_STUB_OFFSETS = False
|
|
31
|
+
OMEGA_FLIP = True
|
|
31
32
|
|
|
32
33
|
# Turns on GPU processing for zocalo and logs a comparison between GPU and CPU-
|
|
33
34
|
# processed results. GPU results never used in analysis for now
|
|
@@ -7,27 +7,20 @@ from dodal.devices.fast_grid_scan import (
|
|
|
7
7
|
PandAGridScanParams,
|
|
8
8
|
ZebraGridScanParams,
|
|
9
9
|
)
|
|
10
|
-
|
|
11
|
-
from scanspec.core import Path as ScanPath
|
|
12
|
-
from scanspec.specs import Line, Static
|
|
13
|
-
|
|
14
|
-
from mx_bluesky.common.parameters.components import (
|
|
15
|
-
SplitScan,
|
|
16
|
-
WithOptionalEnergyChange,
|
|
17
|
-
WithPandaGridScan,
|
|
18
|
-
)
|
|
10
|
+
|
|
19
11
|
from mx_bluesky.common.parameters.gridscan import (
|
|
20
12
|
GridCommon,
|
|
21
|
-
|
|
13
|
+
SpecifiedThreeDGridScan,
|
|
22
14
|
)
|
|
23
|
-
from mx_bluesky.hyperion.parameters.components import
|
|
15
|
+
from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures
|
|
24
16
|
from mx_bluesky.hyperion.parameters.constants import CONST, I03Constants
|
|
25
17
|
|
|
26
18
|
|
|
27
|
-
class
|
|
28
|
-
|
|
29
|
-
# https://github.com/DiamondLightSource/hyperion/issues/1395"""
|
|
19
|
+
class GridCommonWithHyperionDetectorParams(GridCommon, WithHyperionUDCFeatures):
|
|
20
|
+
"""Used by models which require detector parameters but have no specifications of the grid"""
|
|
30
21
|
|
|
22
|
+
# These detector params only exist so that we can properly select enable_dev_shm. Remove in
|
|
23
|
+
# https://github.com/DiamondLightSource/hyperion/issues/1395"""
|
|
31
24
|
@property
|
|
32
25
|
def detector_params(self):
|
|
33
26
|
self.det_dist_to_beam_converter_path = (
|
|
@@ -37,9 +30,9 @@ class HyperionGridCommon(GridCommon, WithHyperionFeatures):
|
|
|
37
30
|
optional_args = {}
|
|
38
31
|
if self.run_number:
|
|
39
32
|
optional_args["run_number"] = self.run_number
|
|
40
|
-
assert (
|
|
41
|
-
|
|
42
|
-
)
|
|
33
|
+
assert self.detector_distance_mm is not None, (
|
|
34
|
+
"Detector distance must be filled before generating DetectorParams"
|
|
35
|
+
)
|
|
43
36
|
return DetectorParams(
|
|
44
37
|
detector_size_constants=I03Constants.DETECTOR,
|
|
45
38
|
expected_energy_ev=self.demand_energy_ev,
|
|
@@ -59,28 +52,42 @@ class HyperionGridCommon(GridCommon, WithHyperionFeatures):
|
|
|
59
52
|
)
|
|
60
53
|
|
|
61
54
|
|
|
62
|
-
class
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
):
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
55
|
+
class HyperionSpecifiedThreeDGridScan(SpecifiedThreeDGridScan, WithHyperionUDCFeatures):
|
|
56
|
+
"""Hyperion's 3D grid scan deviates from the common class due to: optionally using a PandA, optionally using dev_shm for GPU analysis, and using a config server for features"""
|
|
57
|
+
|
|
58
|
+
# These detector params only exist so that we can properly select enable_dev_shm. Remove in
|
|
59
|
+
# https://github.com/DiamondLightSource/hyperion/issues/1395"""
|
|
60
|
+
@property
|
|
61
|
+
def detector_params(self):
|
|
62
|
+
self.det_dist_to_beam_converter_path = (
|
|
63
|
+
self.det_dist_to_beam_converter_path
|
|
64
|
+
or CONST.PARAM.DETECTOR.BEAM_XY_LUT_PATH
|
|
65
|
+
)
|
|
66
|
+
optional_args = {}
|
|
67
|
+
if self.run_number:
|
|
68
|
+
optional_args["run_number"] = self.run_number
|
|
69
|
+
assert self.detector_distance_mm is not None, (
|
|
70
|
+
"Detector distance must be filled before generating DetectorParams"
|
|
71
|
+
)
|
|
72
|
+
return DetectorParams(
|
|
73
|
+
detector_size_constants=I03Constants.DETECTOR,
|
|
74
|
+
expected_energy_ev=self.demand_energy_ev,
|
|
75
|
+
exposure_time=self.exposure_time_s,
|
|
76
|
+
directory=self.storage_directory,
|
|
77
|
+
prefix=self.file_name,
|
|
78
|
+
detector_distance=self.detector_distance_mm,
|
|
79
|
+
omega_start=self.omega_start_deg or 0,
|
|
80
|
+
omega_increment=0,
|
|
81
|
+
num_images_per_trigger=1,
|
|
82
|
+
num_triggers=self.num_images,
|
|
83
|
+
use_roi_mode=self.use_roi_mode,
|
|
84
|
+
det_dist_to_beam_converter_path=self.det_dist_to_beam_converter_path,
|
|
85
|
+
trigger_mode=self.trigger_mode,
|
|
86
|
+
enable_dev_shm=self.features.compare_cpu_and_gpu_zocalo,
|
|
87
|
+
**optional_args,
|
|
88
|
+
)
|
|
83
89
|
|
|
90
|
+
# Relative to common grid scan, stub offsets are defined by config server
|
|
84
91
|
@property
|
|
85
92
|
def FGS_params(self) -> ZebraGridScanParams:
|
|
86
93
|
return ZebraGridScanParams(
|
|
@@ -124,59 +131,17 @@ class HyperionThreeDGridScan(
|
|
|
124
131
|
transmission_fraction=self.transmission_frac,
|
|
125
132
|
)
|
|
126
133
|
|
|
127
|
-
def do_set_stub_offsets(self, value: bool):
|
|
128
|
-
self._set_stub_offsets = value
|
|
129
|
-
|
|
130
|
-
@property
|
|
131
|
-
def grid_1_spec(self):
|
|
132
|
-
x_end = self.x_start_um + self.x_step_size_um * (self.x_steps - 1)
|
|
133
|
-
y1_end = self.y_start_um + self.y_step_size_um * (self.y_steps - 1)
|
|
134
|
-
grid_1_x = Line("sam_x", self.x_start_um, x_end, self.x_steps)
|
|
135
|
-
grid_1_y = Line("sam_y", self.y_start_um, y1_end, self.y_steps)
|
|
136
|
-
grid_1_z = Static("sam_z", self.z_start_um)
|
|
137
|
-
return grid_1_y.zip(grid_1_z) * ~grid_1_x
|
|
138
|
-
|
|
139
|
-
@property
|
|
140
|
-
def grid_2_spec(self):
|
|
141
|
-
x_end = self.x_start_um + self.x_step_size_um * (self.x_steps - 1)
|
|
142
|
-
z2_end = self.z2_start_um + self.z_step_size_um * (self.z_steps - 1)
|
|
143
|
-
grid_2_x = Line("sam_x", self.x_start_um, x_end, self.x_steps)
|
|
144
|
-
grid_2_z = Line("sam_z", self.z2_start_um, z2_end, self.z_steps)
|
|
145
|
-
grid_2_y = Static("sam_y", self.y2_start_um)
|
|
146
|
-
return grid_2_z.zip(grid_2_y) * ~grid_2_x
|
|
147
|
-
|
|
148
|
-
@property
|
|
149
|
-
def scan_indices(self):
|
|
150
|
-
"""The first index of each gridscan, useful for writing nexus files/VDS"""
|
|
151
|
-
return [
|
|
152
|
-
0,
|
|
153
|
-
len(ScanPath(self.grid_1_spec.calculate()).consume().midpoints["sam_x"]),
|
|
154
|
-
]
|
|
155
|
-
|
|
156
|
-
@property
|
|
157
|
-
def scan_spec(self):
|
|
158
|
-
"""A fully specified ScanSpec object representing both grids, with x, y, z and
|
|
159
|
-
omega positions."""
|
|
160
|
-
return self.grid_1_spec.concat(self.grid_2_spec)
|
|
161
134
|
|
|
162
|
-
|
|
163
|
-
def scan_points(self):
|
|
164
|
-
"""A list of all the points in the scan_spec."""
|
|
165
|
-
return ScanPath(self.scan_spec.calculate()).consume().midpoints
|
|
166
|
-
|
|
167
|
-
@property
|
|
168
|
-
def scan_points_first_grid(self):
|
|
169
|
-
"""A list of all the points in the first grid scan."""
|
|
170
|
-
return ScanPath(self.grid_1_spec.calculate()).consume().midpoints
|
|
135
|
+
class OddYStepsException(Exception): ...
|
|
171
136
|
|
|
172
|
-
@property
|
|
173
|
-
def scan_points_second_grid(self):
|
|
174
|
-
"""A list of all the points in the second grid scan."""
|
|
175
|
-
return ScanPath(self.grid_2_spec.calculate()).consume().midpoints
|
|
176
137
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
138
|
+
class PinTipCentreThenXrayCentre(
|
|
139
|
+
GridCommonWithHyperionDetectorParams, WithHyperionUDCFeatures
|
|
140
|
+
):
|
|
141
|
+
tip_offset_um: float = 0
|
|
180
142
|
|
|
181
143
|
|
|
182
|
-
class
|
|
144
|
+
class GridScanWithEdgeDetect(
|
|
145
|
+
GridCommonWithHyperionDetectorParams, WithHyperionUDCFeatures
|
|
146
|
+
):
|
|
147
|
+
pass
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import TypeVar
|
|
1
|
+
from typing import Self, TypeVar
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, model_validator
|
|
4
4
|
|
|
@@ -8,7 +8,8 @@ from mx_bluesky.common.parameters.components import (
|
|
|
8
8
|
WithSample,
|
|
9
9
|
WithVisit,
|
|
10
10
|
)
|
|
11
|
-
from mx_bluesky.
|
|
11
|
+
from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures
|
|
12
|
+
from mx_bluesky.hyperion.parameters.robot_load import (
|
|
12
13
|
RobotLoadThenCentre,
|
|
13
14
|
)
|
|
14
15
|
from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan
|
|
@@ -23,7 +24,11 @@ def construct_from_values(parent_context: dict, child_dict: dict, t: type[T]) ->
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class LoadCentreCollect(
|
|
26
|
-
MxBlueskyParameters,
|
|
27
|
+
MxBlueskyParameters,
|
|
28
|
+
WithVisit,
|
|
29
|
+
WithSample,
|
|
30
|
+
WithCentreSelection,
|
|
31
|
+
WithHyperionUDCFeatures,
|
|
27
32
|
):
|
|
28
33
|
"""Experiment parameters to perform the combined robot load,
|
|
29
34
|
pin-tip centre and rotation scan operations."""
|
|
@@ -39,10 +44,31 @@ class LoadCentreCollect(
|
|
|
39
44
|
| RobotLoadThenCentre.model_fields.keys()
|
|
40
45
|
| MultiRotationScan.model_fields.keys()
|
|
41
46
|
)
|
|
47
|
+
|
|
42
48
|
disallowed_keys = values.keys() - allowed_keys
|
|
43
|
-
assert (
|
|
44
|
-
|
|
45
|
-
)
|
|
49
|
+
assert disallowed_keys == set(), (
|
|
50
|
+
f"Unexpected fields found in LoadCentreCollect {disallowed_keys}"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
keys_from_outer_load_centre_collect = (
|
|
54
|
+
MxBlueskyParameters.model_fields.keys()
|
|
55
|
+
| WithSample.model_fields.keys()
|
|
56
|
+
| WithVisit.model_fields.keys()
|
|
57
|
+
)
|
|
58
|
+
duplicated_robot_load_then_centre_keys = (
|
|
59
|
+
keys_from_outer_load_centre_collect
|
|
60
|
+
& values["robot_load_then_centre"].keys()
|
|
61
|
+
)
|
|
62
|
+
assert not (duplicated_robot_load_then_centre_keys), (
|
|
63
|
+
f"Unexpected keys in robot_load_then_centre: {', '.join(duplicated_robot_load_then_centre_keys)}"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
duplicated_multi_rotation_scan_keys = (
|
|
67
|
+
keys_from_outer_load_centre_collect & values["multi_rotation_scan"].keys()
|
|
68
|
+
)
|
|
69
|
+
assert not (duplicated_multi_rotation_scan_keys), (
|
|
70
|
+
f"Unexpected keys in multi_rotation_scan: {', '.join(duplicated_multi_rotation_scan_keys)}"
|
|
71
|
+
)
|
|
46
72
|
|
|
47
73
|
new_robot_load_then_centre_params = construct_from_values(
|
|
48
74
|
values, values["robot_load_then_centre"], RobotLoadThenCentre
|
|
@@ -53,3 +79,22 @@ class LoadCentreCollect(
|
|
|
53
79
|
values["multi_rotation_scan"] = new_multi_rotation_scan_params
|
|
54
80
|
values["robot_load_then_centre"] = new_robot_load_then_centre_params
|
|
55
81
|
return values
|
|
82
|
+
|
|
83
|
+
@model_validator(mode="after")
|
|
84
|
+
def _check_rotation_start_xyz_is_not_specified(self) -> Self:
|
|
85
|
+
for scan in self.multi_rotation_scan.single_rotation_scans:
|
|
86
|
+
assert (
|
|
87
|
+
not scan.x_start_um and not scan.y_start_um and not scan.z_start_um
|
|
88
|
+
), (
|
|
89
|
+
"Specifying start xyz for sweeps is not supported in combination with centring."
|
|
90
|
+
)
|
|
91
|
+
return self
|
|
92
|
+
|
|
93
|
+
@model_validator(mode="after")
|
|
94
|
+
def _check_different_gridscan_and_rotation_energy_not_specified(self) -> Self:
|
|
95
|
+
assert (
|
|
96
|
+
self.multi_rotation_scan.demand_energy_ev is None
|
|
97
|
+
or self.multi_rotation_scan.demand_energy_ev
|
|
98
|
+
== self.robot_load_then_centre.demand_energy_ev
|
|
99
|
+
), "Setting a different energy for gridscan and rotation is not supported."
|
|
100
|
+
return self
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from pydantic import Field
|
|
2
|
+
|
|
3
|
+
from mx_bluesky.common.parameters.components import (
|
|
4
|
+
MxBlueskyParameters,
|
|
5
|
+
WithOptionalEnergyChange,
|
|
6
|
+
WithSample,
|
|
7
|
+
WithSnapshot,
|
|
8
|
+
WithVisit,
|
|
9
|
+
)
|
|
10
|
+
from mx_bluesky.common.parameters.constants import (
|
|
11
|
+
HardwareConstants,
|
|
12
|
+
)
|
|
13
|
+
from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures
|
|
14
|
+
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
15
|
+
GridCommonWithHyperionDetectorParams,
|
|
16
|
+
PinTipCentreThenXrayCentre,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RobotLoadAndEnergyChange(
|
|
21
|
+
MxBlueskyParameters, WithSample, WithSnapshot, WithOptionalEnergyChange, WithVisit
|
|
22
|
+
):
|
|
23
|
+
thawing_time: float = Field(default=HardwareConstants.THAWING_TIME)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RobotLoadThenCentre(
|
|
27
|
+
GridCommonWithHyperionDetectorParams, WithHyperionUDCFeatures
|
|
28
|
+
):
|
|
29
|
+
thawing_time: float = Field(default=HardwareConstants.THAWING_TIME)
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def robot_load_params(self) -> RobotLoadAndEnergyChange:
|
|
33
|
+
my_params = self.model_dump()
|
|
34
|
+
return RobotLoadAndEnergyChange(**my_params)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def pin_centre_then_xray_centre_params(self) -> PinTipCentreThenXrayCentre:
|
|
38
|
+
my_params = self.model_dump()
|
|
39
|
+
del my_params["thawing_time"]
|
|
40
|
+
return PinTipCentreThenXrayCentre(**my_params)
|