mx-bluesky 1.4.2__py3-none-any.whl → 1.4.3__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 +14 -9
- 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 -7
- mx_bluesky/common/parameters/constants.py +1 -0
- mx_bluesky/common/parameters/gridscan.py +102 -53
- mx_bluesky/common/plans/do_fgs.py +4 -4
- 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 -14
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +28 -21
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +43 -32
- 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 +56 -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.3.dist-info}/METADATA +6 -6
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.3.dist-info}/RECORD +89 -87
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.3.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.3.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.3.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.4.2.dist-info → mx_bluesky-1.4.3.dist-info}/top_level.txt +0 -0
|
@@ -9,26 +9,26 @@ from dodal.devices.detector import DetectorParams
|
|
|
9
9
|
from dodal.devices.detector.det_resolution import resolution
|
|
10
10
|
from dodal.devices.synchrotron import SynchrotronMode
|
|
11
11
|
|
|
12
|
-
from mx_bluesky.common.
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
from mx_bluesky.common.external_interaction.callbacks.common.logging_callback import (
|
|
13
|
+
format_doc_for_log,
|
|
14
|
+
)
|
|
15
|
+
from mx_bluesky.common.external_interaction.callbacks.common.plan_reactive_callback import (
|
|
15
16
|
PlanReactiveCallback,
|
|
16
17
|
)
|
|
17
|
-
from mx_bluesky.
|
|
18
|
+
from mx_bluesky.common.external_interaction.ispyb.data_model import (
|
|
18
19
|
DataCollectionInfo,
|
|
19
20
|
DataCollectionPositionInfo,
|
|
20
21
|
ScanDataInfo,
|
|
21
22
|
)
|
|
22
|
-
from mx_bluesky.
|
|
23
|
+
from mx_bluesky.common.external_interaction.ispyb.ispyb_store import (
|
|
23
24
|
IspybIds,
|
|
24
25
|
StoreInIspyb,
|
|
25
26
|
)
|
|
26
|
-
from mx_bluesky.
|
|
27
|
-
from mx_bluesky.
|
|
28
|
-
from mx_bluesky.
|
|
29
|
-
from mx_bluesky.
|
|
30
|
-
|
|
31
|
-
from .logging_callback import format_doc_for_log
|
|
27
|
+
from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import get_ispyb_config
|
|
28
|
+
from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
|
|
29
|
+
from mx_bluesky.common.parameters.constants import DocDescriptorNames, SimConstants
|
|
30
|
+
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER, set_dcgid_tag
|
|
31
|
+
from mx_bluesky.common.utils.utils import convert_eV_to_angstrom
|
|
32
32
|
|
|
33
33
|
D = TypeVar("D")
|
|
34
34
|
if TYPE_CHECKING:
|
|
@@ -63,25 +63,25 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
63
63
|
"""Subclasses should run super().__init__() with parameters, then set
|
|
64
64
|
self.ispyb to the type of ispyb relevant to the experiment and define the type
|
|
65
65
|
for self.ispyb_ids."""
|
|
66
|
-
|
|
67
|
-
super().__init__(log=
|
|
66
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.debug("Initialising ISPyB callback")
|
|
67
|
+
super().__init__(log=ISPYB_ZOCALO_CALLBACK_LOGGER, emit=emit)
|
|
68
68
|
self._oav_snapshot_event_idx: int = 0
|
|
69
69
|
self.params: DiffractionExperimentWithSample | None = None
|
|
70
70
|
self.ispyb: StoreInIspyb
|
|
71
71
|
self.descriptors: dict[str, EventDescriptor] = {}
|
|
72
72
|
self.ispyb_config = get_ispyb_config()
|
|
73
73
|
if (
|
|
74
|
-
self.ispyb_config ==
|
|
75
|
-
or self.ispyb_config ==
|
|
74
|
+
self.ispyb_config == SimConstants.ISPYB_CONFIG
|
|
75
|
+
or self.ispyb_config == SimConstants.DEV_ISPYB_DATABASE_CFG
|
|
76
76
|
):
|
|
77
|
-
|
|
77
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.warning(
|
|
78
78
|
f"{self.__class__} using dev ISPyB config: {self.ispyb_config}. If you"
|
|
79
79
|
"want to use the real database, please set the ISPYB_CONFIG_PATH "
|
|
80
80
|
"environment variable."
|
|
81
81
|
)
|
|
82
82
|
self.uid_to_finalize_on: str | None = None
|
|
83
83
|
self.ispyb_ids: IspybIds = IspybIds()
|
|
84
|
-
self.log =
|
|
84
|
+
self.log = ISPYB_ZOCALO_CALLBACK_LOGGER
|
|
85
85
|
|
|
86
86
|
def activity_gated_start(self, doc: RunStart):
|
|
87
87
|
self._oav_snapshot_event_idx = 0
|
|
@@ -94,31 +94,33 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
94
94
|
def activity_gated_event(self, doc: Event) -> Event:
|
|
95
95
|
"""Subclasses should extend this to add a call to set_dcig_tag from
|
|
96
96
|
hyperion.log"""
|
|
97
|
-
|
|
97
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.debug("ISPyB handler received event document.")
|
|
98
98
|
assert self.ispyb is not None, "ISPyB deposition wasn't initialised!"
|
|
99
99
|
assert self.params is not None, "ISPyB handler didn't receive parameters!"
|
|
100
100
|
|
|
101
101
|
event_descriptor = self.descriptors.get(doc["descriptor"])
|
|
102
102
|
if event_descriptor is None:
|
|
103
|
-
|
|
103
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.warning(
|
|
104
104
|
f"Ispyb handler {self} received event doc {format_doc_for_log(doc)} and "
|
|
105
105
|
"has no corresponding descriptor record"
|
|
106
106
|
)
|
|
107
107
|
return doc
|
|
108
108
|
match event_descriptor.get("name"):
|
|
109
|
-
case
|
|
109
|
+
case DocDescriptorNames.HARDWARE_READ_PRE:
|
|
110
110
|
scan_data_infos = self._handle_ispyb_hardware_read(doc)
|
|
111
|
-
case
|
|
111
|
+
case DocDescriptorNames.HARDWARE_READ_DURING:
|
|
112
112
|
scan_data_infos = self._handle_ispyb_transmission_flux_read(doc)
|
|
113
113
|
case _:
|
|
114
114
|
return self._tag_doc(doc)
|
|
115
115
|
self.ispyb_ids = self.ispyb.update_deposition(self.ispyb_ids, scan_data_infos)
|
|
116
|
-
|
|
116
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(f"Received ISPYB IDs: {self.ispyb_ids}")
|
|
117
117
|
return self._tag_doc(doc)
|
|
118
118
|
|
|
119
119
|
def _handle_ispyb_hardware_read(self, doc) -> Sequence[ScanDataInfo]:
|
|
120
120
|
assert self.params, "Event handled before activity_gated_start received params"
|
|
121
|
-
|
|
121
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
122
|
+
"ISPyB handler received event from read hardware"
|
|
123
|
+
)
|
|
122
124
|
assert isinstance(
|
|
123
125
|
synchrotron_mode := doc["data"]["synchrotron-synchrotron_mode"],
|
|
124
126
|
SynchrotronMode,
|
|
@@ -127,8 +129,8 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
127
129
|
hwscan_data_collection_info = DataCollectionInfo(
|
|
128
130
|
undulator_gap1=doc["data"]["undulator-current_gap"],
|
|
129
131
|
synchrotron_mode=synchrotron_mode.value,
|
|
130
|
-
slitgap_horizontal=doc["data"]["
|
|
131
|
-
slitgap_vertical=doc["data"]["
|
|
132
|
+
slitgap_horizontal=doc["data"]["s4_slit_gaps-xgap"],
|
|
133
|
+
slitgap_vertical=doc["data"]["s4_slit_gaps-ygap"],
|
|
132
134
|
)
|
|
133
135
|
hwscan_data_collection_info = _update_based_on_energy(
|
|
134
136
|
doc, self.params.detector_params, hwscan_data_collection_info
|
|
@@ -141,7 +143,9 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
141
143
|
scan_data_infos = self.populate_info_for_update(
|
|
142
144
|
hwscan_data_collection_info, hwscan_position_info, self.params
|
|
143
145
|
)
|
|
144
|
-
|
|
146
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
147
|
+
"Updating ispyb data collection after hardware read."
|
|
148
|
+
)
|
|
145
149
|
return scan_data_infos
|
|
146
150
|
|
|
147
151
|
def _handle_ispyb_transmission_flux_read(self, doc) -> Sequence[ScanDataInfo]:
|
|
@@ -156,7 +160,7 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
156
160
|
beamsize_at_sampley=beamsize_y_mm,
|
|
157
161
|
focal_spot_size_at_samplex=beamsize_x_mm,
|
|
158
162
|
focal_spot_size_at_sampley=beamsize_y_mm,
|
|
159
|
-
flux=doc["data"]["
|
|
163
|
+
flux=doc["data"]["flux-flux_reading"],
|
|
160
164
|
)
|
|
161
165
|
if transmission := doc["data"]["attenuator-actual_transmission"]:
|
|
162
166
|
# Ispyb wants the transmission in a percentage, we use fractions
|
|
@@ -167,7 +171,9 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
167
171
|
scan_data_infos = self.populate_info_for_update(
|
|
168
172
|
hwscan_data_collection_info, None, self.params
|
|
169
173
|
)
|
|
170
|
-
|
|
174
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
175
|
+
"Updating ispyb data collection after flux read."
|
|
176
|
+
)
|
|
171
177
|
self.append_to_comment(f"Aperture: {aperture}. ")
|
|
172
178
|
return scan_data_infos
|
|
173
179
|
|
|
@@ -183,10 +189,10 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
183
189
|
def activity_gated_stop(self, doc: RunStop) -> RunStop:
|
|
184
190
|
"""Subclasses must check that they are recieving a stop document for the correct
|
|
185
191
|
uid to use this method!"""
|
|
186
|
-
assert (
|
|
187
|
-
|
|
188
|
-
)
|
|
189
|
-
|
|
192
|
+
assert self.ispyb is not None, (
|
|
193
|
+
"ISPyB handler received stop document, but deposition object doesn't exist!"
|
|
194
|
+
)
|
|
195
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.debug("ISPyB handler received stop document.")
|
|
190
196
|
exit_status = (
|
|
191
197
|
doc.get("exit_status") or "Exit status not available in stop document!"
|
|
192
198
|
)
|
|
@@ -195,7 +201,7 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
195
201
|
try:
|
|
196
202
|
self.ispyb.end_deposition(self.ispyb_ids, exit_status, reason)
|
|
197
203
|
except Exception as e:
|
|
198
|
-
|
|
204
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.warning(
|
|
199
205
|
f"Failed to finalise ISPyB deposition on stop document: {format_doc_for_log(doc)} with exception: {e}"
|
|
200
206
|
)
|
|
201
207
|
return self._tag_doc(doc)
|
|
@@ -205,7 +211,7 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
205
211
|
try:
|
|
206
212
|
self.ispyb.append_to_comment(id, comment)
|
|
207
213
|
except TypeError:
|
|
208
|
-
|
|
214
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.warning(
|
|
209
215
|
"ISPyB deposition not initialised, can't update comment."
|
|
210
216
|
)
|
|
211
217
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from mx_bluesky.common.
|
|
4
|
-
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
|
|
3
|
+
from mx_bluesky.common.external_interaction.ispyb.data_model import (
|
|
5
4
|
DataCollectionGroupInfo,
|
|
6
5
|
DataCollectionInfo,
|
|
7
6
|
)
|
|
8
|
-
from mx_bluesky.
|
|
7
|
+
from mx_bluesky.common.external_interaction.ispyb.ispyb_store import (
|
|
9
8
|
EIGER_FILE_SUFFIX,
|
|
10
9
|
I03_EIGER_DETECTOR,
|
|
11
10
|
)
|
|
12
|
-
from mx_bluesky.
|
|
11
|
+
from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import (
|
|
13
12
|
get_current_time_string,
|
|
14
13
|
)
|
|
14
|
+
from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def populate_data_collection_group(params: DiffractionExperimentWithSample):
|
|
@@ -5,10 +5,13 @@ from typing import TYPE_CHECKING
|
|
|
5
5
|
from bluesky.callbacks import CallbackBase
|
|
6
6
|
from dodal.devices.zocalo import ZocaloStartInfo, ZocaloTrigger
|
|
7
7
|
|
|
8
|
-
from mx_bluesky.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
from mx_bluesky.common.parameters.constants import (
|
|
9
|
+
DocDescriptorNames,
|
|
10
|
+
TriggerConstants,
|
|
11
|
+
)
|
|
12
|
+
from mx_bluesky.common.utils.exceptions import ISPyBDepositionNotMade
|
|
13
|
+
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER
|
|
14
|
+
from mx_bluesky.common.utils.utils import number_of_frames_from_scan_spec
|
|
12
15
|
|
|
13
16
|
if TYPE_CHECKING:
|
|
14
17
|
from event_model.documents import Event, EventDescriptor, RunStart, RunStop
|
|
@@ -39,11 +42,13 @@ class ZocaloCallback(CallbackBase):
|
|
|
39
42
|
self._reset_state()
|
|
40
43
|
|
|
41
44
|
def start(self, doc: RunStart):
|
|
42
|
-
|
|
43
|
-
if triggering_plan := doc.get(
|
|
45
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info("Zocalo handler received start document.")
|
|
46
|
+
if triggering_plan := doc.get(TriggerConstants.ZOCALO):
|
|
44
47
|
self.triggering_plan = triggering_plan
|
|
45
48
|
assert isinstance(zocalo_environment := doc.get("zocalo_environment"), str)
|
|
46
|
-
|
|
49
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
50
|
+
f"Zocalo environment set to {zocalo_environment}."
|
|
51
|
+
)
|
|
47
52
|
self.zocalo_interactor = ZocaloTrigger(zocalo_environment)
|
|
48
53
|
|
|
49
54
|
if self.triggering_plan and doc.get("subplan_name") == self.triggering_plan:
|
|
@@ -73,7 +78,7 @@ class ZocaloCallback(CallbackBase):
|
|
|
73
78
|
|
|
74
79
|
def event(self, doc: Event) -> Event:
|
|
75
80
|
event_descriptor = self.descriptors[doc["descriptor"]]
|
|
76
|
-
if event_descriptor.get("name") ==
|
|
81
|
+
if event_descriptor.get("name") == DocDescriptorNames.ZOCALO_HW_READ:
|
|
77
82
|
filename = doc["data"]["eiger_odin_file_writer_id"]
|
|
78
83
|
for start_info in self.zocalo_info:
|
|
79
84
|
start_info.filename = filename
|
|
@@ -83,7 +88,7 @@ class ZocaloCallback(CallbackBase):
|
|
|
83
88
|
|
|
84
89
|
def stop(self, doc: RunStop):
|
|
85
90
|
if doc.get("run_start") == self.run_uid:
|
|
86
|
-
|
|
91
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
87
92
|
f"Zocalo handler received stop document, for run {doc.get('run_start')}."
|
|
88
93
|
)
|
|
89
94
|
assert self.zocalo_interactor is not None
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable, Sequence
|
|
4
4
|
from time import time
|
|
5
|
-
from typing import TYPE_CHECKING, Any
|
|
5
|
+
from typing import TYPE_CHECKING, Any, TypeVar
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
from bluesky import preprocessors as bpp
|
|
@@ -12,41 +12,39 @@ from dodal.devices.zocalo.zocalo_results import (
|
|
|
12
12
|
get_processing_results_from_event,
|
|
13
13
|
)
|
|
14
14
|
|
|
15
|
-
from mx_bluesky.common.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
from mx_bluesky.
|
|
15
|
+
from mx_bluesky.common.external_interaction.callbacks.common.ispyb_callback_base import (
|
|
16
|
+
BaseISPyBCallback,
|
|
17
|
+
)
|
|
18
|
+
from mx_bluesky.common.external_interaction.callbacks.common.ispyb_mapping import (
|
|
19
19
|
populate_data_collection_group,
|
|
20
20
|
populate_remaining_data_collection_info,
|
|
21
21
|
)
|
|
22
|
-
from mx_bluesky.
|
|
23
|
-
BaseISPyBCallback,
|
|
24
|
-
)
|
|
25
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.logging_callback import (
|
|
22
|
+
from mx_bluesky.common.external_interaction.callbacks.common.logging_callback import (
|
|
26
23
|
format_doc_for_log,
|
|
27
24
|
)
|
|
28
|
-
from mx_bluesky.
|
|
25
|
+
from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_mapping import (
|
|
29
26
|
construct_comment_for_gridscan,
|
|
30
27
|
populate_xy_data_collection_info,
|
|
31
28
|
populate_xz_data_collection_info,
|
|
32
29
|
)
|
|
33
|
-
from mx_bluesky.
|
|
34
|
-
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
|
|
30
|
+
from mx_bluesky.common.external_interaction.ispyb.data_model import (
|
|
35
31
|
DataCollectionGridInfo,
|
|
36
32
|
DataCollectionInfo,
|
|
37
33
|
DataCollectionPositionInfo,
|
|
38
34
|
Orientation,
|
|
39
35
|
ScanDataInfo,
|
|
40
36
|
)
|
|
41
|
-
from mx_bluesky.
|
|
37
|
+
from mx_bluesky.common.external_interaction.ispyb.ispyb_store import (
|
|
42
38
|
IspybIds,
|
|
43
39
|
StoreInIspyb,
|
|
44
40
|
)
|
|
45
|
-
from mx_bluesky.
|
|
46
|
-
from mx_bluesky.
|
|
47
|
-
from mx_bluesky.
|
|
41
|
+
from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
|
|
42
|
+
from mx_bluesky.common.parameters.constants import DocDescriptorNames, PlanNameConstants
|
|
43
|
+
from mx_bluesky.common.parameters.gridscan import (
|
|
48
44
|
GridCommon,
|
|
49
45
|
)
|
|
46
|
+
from mx_bluesky.common.utils.exceptions import ISPyBDepositionNotMade
|
|
47
|
+
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER, set_dcgid_tag
|
|
50
48
|
|
|
51
49
|
if TYPE_CHECKING:
|
|
52
50
|
from event_model import Event, RunStart, RunStop
|
|
@@ -58,14 +56,17 @@ def ispyb_activation_wrapper(plan_generator: MsgGenerator, parameters):
|
|
|
58
56
|
plan_generator,
|
|
59
57
|
md={
|
|
60
58
|
"activate_callbacks": ["GridscanISPyBCallback"],
|
|
61
|
-
"subplan_name":
|
|
62
|
-
"
|
|
59
|
+
"subplan_name": PlanNameConstants.GRID_DETECT_AND_DO_GRIDSCAN,
|
|
60
|
+
"mx_bluesky_parameters": parameters.model_dump_json(),
|
|
63
61
|
},
|
|
64
62
|
),
|
|
65
|
-
|
|
63
|
+
PlanNameConstants.ISPYB_ACTIVATION,
|
|
66
64
|
)
|
|
67
65
|
|
|
68
66
|
|
|
67
|
+
T = TypeVar("T", bound="GridCommon")
|
|
68
|
+
|
|
69
|
+
|
|
69
70
|
class GridscanISPyBCallback(BaseISPyBCallback):
|
|
70
71
|
"""Callback class to handle the deposition of experiment parameters into the ISPyB
|
|
71
72
|
database. Listens for 'event' and 'descriptor' documents. Creates the ISpyB entry on
|
|
@@ -83,27 +84,29 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
83
84
|
|
|
84
85
|
def __init__(
|
|
85
86
|
self,
|
|
87
|
+
param_type: type[T],
|
|
86
88
|
*,
|
|
87
89
|
emit: Callable[..., Any] | None = None,
|
|
88
90
|
) -> None:
|
|
89
91
|
super().__init__(emit=emit)
|
|
90
92
|
self.ispyb: StoreInIspyb
|
|
91
93
|
self.ispyb_ids: IspybIds = IspybIds()
|
|
94
|
+
self.param_type = param_type
|
|
92
95
|
self._start_of_fgs_uid: str | None = None
|
|
93
96
|
self._processing_start_time: float | None = None
|
|
94
97
|
|
|
95
98
|
def activity_gated_start(self, doc: RunStart):
|
|
96
99
|
if doc.get("subplan_name") == PlanNameConstants.DO_FGS:
|
|
97
100
|
self._start_of_fgs_uid = doc.get("uid")
|
|
98
|
-
if doc.get("subplan_name") ==
|
|
101
|
+
if doc.get("subplan_name") == PlanNameConstants.GRID_DETECT_AND_DO_GRIDSCAN:
|
|
99
102
|
self.uid_to_finalize_on = doc.get("uid")
|
|
100
|
-
|
|
103
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
101
104
|
"ISPyB callback received start document with experiment parameters and "
|
|
102
105
|
f"uid: {self.uid_to_finalize_on}"
|
|
103
106
|
)
|
|
104
|
-
|
|
105
|
-
assert isinstance(
|
|
106
|
-
self.params =
|
|
107
|
+
mx_bluesky_parameters = doc.get("mx_bluesky_parameters")
|
|
108
|
+
assert isinstance(mx_bluesky_parameters, str)
|
|
109
|
+
self.params = self.param_type.model_validate_json(mx_bluesky_parameters)
|
|
107
110
|
self.ispyb = StoreInIspyb(self.ispyb_config)
|
|
108
111
|
data_collection_group_info = populate_data_collection_group(self.params)
|
|
109
112
|
|
|
@@ -140,7 +143,7 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
140
143
|
descriptor_name = self.descriptors[doc["descriptor"]].get("name")
|
|
141
144
|
if descriptor_name == ZOCALO_READING_PLAN_NAME:
|
|
142
145
|
self._handle_zocalo_read_event(doc)
|
|
143
|
-
elif descriptor_name ==
|
|
146
|
+
elif descriptor_name == DocDescriptorNames.OAV_GRID_SNAPSHOT_TRIGGERED:
|
|
144
147
|
scan_data_infos = self._handle_oav_grid_snapshot_triggered(doc)
|
|
145
148
|
self.ispyb_ids = self.ispyb.update_deposition(
|
|
146
149
|
self.ispyb_ids, scan_data_infos
|
|
@@ -154,7 +157,7 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
154
157
|
proc_time = time() - self._processing_start_time
|
|
155
158
|
crystal_summary = f"Zocalo processing took {proc_time:.2f} s. "
|
|
156
159
|
bboxes: list[np.ndarray] = []
|
|
157
|
-
|
|
160
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
158
161
|
f"Amending comment based on Zocalo reading doc: {format_doc_for_log(doc)}"
|
|
159
162
|
)
|
|
160
163
|
|
|
@@ -176,9 +179,9 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
176
179
|
)
|
|
177
180
|
else:
|
|
178
181
|
crystal_summary += "Zocalo found no crystals in this gridscan."
|
|
179
|
-
assert (
|
|
180
|
-
|
|
181
|
-
)
|
|
182
|
+
assert self.ispyb_ids.data_collection_ids, (
|
|
183
|
+
"No data collection to add results to"
|
|
184
|
+
)
|
|
182
185
|
self.ispyb.append_to_comment(
|
|
183
186
|
self.ispyb_ids.data_collection_ids[0], crystal_summary
|
|
184
187
|
)
|
|
@@ -225,7 +228,9 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
225
228
|
data_collection_id=data_collection_id,
|
|
226
229
|
data_collection_grid_info=data_collection_grid_info,
|
|
227
230
|
)
|
|
228
|
-
|
|
231
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
232
|
+
"Updating ispyb data collection after oav snapshot."
|
|
233
|
+
)
|
|
229
234
|
self._oav_snapshot_event_idx += 1
|
|
230
235
|
return [scan_data_info]
|
|
231
236
|
|
|
@@ -245,9 +250,9 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
245
250
|
event_sourced_position_info: DataCollectionPositionInfo | None,
|
|
246
251
|
params: DiffractionExperimentWithSample,
|
|
247
252
|
) -> Sequence[ScanDataInfo]:
|
|
248
|
-
assert (
|
|
249
|
-
|
|
250
|
-
)
|
|
253
|
+
assert self.ispyb_ids.data_collection_ids, (
|
|
254
|
+
"Expect at least one valid data collection to record scan data"
|
|
255
|
+
)
|
|
251
256
|
xy_scan_data_info = ScanDataInfo(
|
|
252
257
|
data_collection_info=event_sourced_data_collection_info,
|
|
253
258
|
data_collection_id=self.ispyb_ids.data_collection_ids[0],
|
|
@@ -270,7 +275,7 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
270
275
|
if doc.get("run_start") == self._start_of_fgs_uid:
|
|
271
276
|
self._processing_start_time = time()
|
|
272
277
|
if doc.get("run_start") == self.uid_to_finalize_on:
|
|
273
|
-
|
|
278
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
274
279
|
"ISPyB callback received stop document corresponding to start document "
|
|
275
280
|
f"with uid: {self.uid_to_finalize_on}."
|
|
276
281
|
)
|
|
@@ -4,7 +4,7 @@ import numpy
|
|
|
4
4
|
from dodal.devices.detector import DetectorParams
|
|
5
5
|
from dodal.devices.oav import utils as oav_utils
|
|
6
6
|
|
|
7
|
-
from mx_bluesky.
|
|
7
|
+
from mx_bluesky.common.external_interaction.ispyb.data_model import (
|
|
8
8
|
DataCollectionGridInfo,
|
|
9
9
|
DataCollectionInfo,
|
|
10
10
|
)
|
|
@@ -43,7 +43,7 @@ def construct_comment_for_gridscan(grid_info: DataCollectionGridInfo) -> str:
|
|
|
43
43
|
grid_info.microns_per_pixel_y,
|
|
44
44
|
)
|
|
45
45
|
return (
|
|
46
|
-
"
|
|
46
|
+
"MX-Bluesky: Xray centring - Diffraction grid scan of "
|
|
47
47
|
f"{grid_info.steps_x} by "
|
|
48
48
|
f"{grid_info.steps_y} images in "
|
|
49
49
|
f"{(grid_info.dx_in_mm * 1e3):.1f} um by "
|
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, TypeVar
|
|
4
4
|
|
|
5
|
-
from mx_bluesky.
|
|
5
|
+
from mx_bluesky.common.external_interaction.callbacks.common.plan_reactive_callback import (
|
|
6
6
|
PlanReactiveCallback,
|
|
7
7
|
)
|
|
8
|
-
from mx_bluesky.
|
|
8
|
+
from mx_bluesky.common.external_interaction.nexus.nexus_utils import (
|
|
9
9
|
create_beam_and_attenuator_parameters,
|
|
10
10
|
vds_type_based_on_bit_depth,
|
|
11
11
|
)
|
|
12
|
-
from mx_bluesky.
|
|
13
|
-
from mx_bluesky.
|
|
14
|
-
from mx_bluesky.
|
|
15
|
-
|
|
12
|
+
from mx_bluesky.common.external_interaction.nexus.write_nexus import NexusWriter
|
|
13
|
+
from mx_bluesky.common.parameters.constants import DocDescriptorNames, PlanNameConstants
|
|
14
|
+
from mx_bluesky.common.parameters.gridscan import (
|
|
15
|
+
SpecifiedThreeDGridScan,
|
|
16
|
+
)
|
|
17
|
+
from mx_bluesky.common.utils.log import NEXUS_LOGGER
|
|
16
18
|
|
|
17
19
|
if TYPE_CHECKING:
|
|
18
20
|
from event_model.documents import Event, EventDescriptor, RunStart
|
|
19
21
|
|
|
22
|
+
T = TypeVar("T", bound="SpecifiedThreeDGridScan")
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
22
26
|
"""Callback class to handle the creation of Nexus files based on experiment \
|
|
@@ -35,8 +39,9 @@ class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
|
35
39
|
See: https://blueskyproject.io/bluesky/callbacks.html#ways-to-invoke-callbacks
|
|
36
40
|
"""
|
|
37
41
|
|
|
38
|
-
def __init__(self) -> None:
|
|
42
|
+
def __init__(self, param_type: type[T]) -> None:
|
|
39
43
|
super().__init__(NEXUS_LOGGER)
|
|
44
|
+
self.param_type = param_type
|
|
40
45
|
self.run_start_uid: str | None = None
|
|
41
46
|
self.nexus_writer_1: NexusWriter | None = None
|
|
42
47
|
self.nexus_writer_2: NexusWriter | None = None
|
|
@@ -44,13 +49,13 @@ class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
|
44
49
|
self.log = NEXUS_LOGGER
|
|
45
50
|
|
|
46
51
|
def activity_gated_start(self, doc: RunStart):
|
|
47
|
-
if doc.get("subplan_name") ==
|
|
48
|
-
|
|
49
|
-
assert isinstance(
|
|
52
|
+
if doc.get("subplan_name") == PlanNameConstants.GRIDSCAN_OUTER:
|
|
53
|
+
mx_bluesky_parameters = doc.get("mx_bluesky_parameters")
|
|
54
|
+
assert isinstance(mx_bluesky_parameters, str)
|
|
50
55
|
NEXUS_LOGGER.info(
|
|
51
|
-
f"Nexus writer received start document with experiment parameters {
|
|
56
|
+
f"Nexus writer received start document with experiment parameters {mx_bluesky_parameters}"
|
|
52
57
|
)
|
|
53
|
-
parameters =
|
|
58
|
+
parameters = self.param_type.model_validate_json(mx_bluesky_parameters)
|
|
54
59
|
d_size = parameters.detector_params.detector_size_constants.det_size_pixels
|
|
55
60
|
grid_n_img_1 = parameters.scan_indices[1]
|
|
56
61
|
grid_n_img_2 = parameters.num_images - grid_n_img_1
|
|
@@ -75,7 +80,7 @@ class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
|
75
80
|
|
|
76
81
|
def activity_gated_event(self, doc: Event) -> Event | None:
|
|
77
82
|
assert (event_descriptor := self.descriptors.get(doc["descriptor"])) is not None
|
|
78
|
-
if event_descriptor.get("name") ==
|
|
83
|
+
if event_descriptor.get("name") == DocDescriptorNames.HARDWARE_READ_DURING:
|
|
79
84
|
data = doc["data"]
|
|
80
85
|
for nexus_writer in [self.nexus_writer_1, self.nexus_writer_2]:
|
|
81
86
|
assert nexus_writer, "Nexus callback did not receive start doc"
|
|
@@ -84,7 +89,7 @@ class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
|
84
89
|
nexus_writer.attenuator,
|
|
85
90
|
) = create_beam_and_attenuator_parameters(
|
|
86
91
|
data["dcm-energy_in_kev"],
|
|
87
|
-
data["
|
|
92
|
+
data["flux-flux_reading"],
|
|
88
93
|
data["attenuator-actual_transmission"],
|
|
89
94
|
)
|
|
90
95
|
vds_data_type = vds_type_based_on_bit_depth(
|
|
@@ -29,8 +29,19 @@ class FeatureFlags(BaseModel, ABC):
|
|
|
29
29
|
def mark_overridden_features(cls, values):
|
|
30
30
|
assert isinstance(values, dict)
|
|
31
31
|
values["overriden_features"] = values.copy()
|
|
32
|
+
cls._validate_overridden_features(values)
|
|
32
33
|
return values
|
|
33
34
|
|
|
35
|
+
@classmethod
|
|
36
|
+
def _validate_overridden_features(cls, values: dict):
|
|
37
|
+
"""Validates overridden features to ensure they are defined in the model fields."""
|
|
38
|
+
defined_fields = cls.model_fields.keys()
|
|
39
|
+
invalid_features = [key for key in values.keys() if key not in defined_fields]
|
|
40
|
+
|
|
41
|
+
if invalid_features:
|
|
42
|
+
message = f"Invalid feature toggle(s) supplied: {invalid_features}. "
|
|
43
|
+
raise ValueError(message)
|
|
44
|
+
|
|
34
45
|
def _get_flags(self):
|
|
35
46
|
flags = type(self).get_config_server().best_effort_get_all_feature_flags()
|
|
36
47
|
return {f: flags[f] for f in flags if f in self.model_fields.keys()}
|
|
File without changes
|
|
@@ -5,11 +5,11 @@ from enum import StrEnum
|
|
|
5
5
|
from requests import patch, post
|
|
6
6
|
from requests.auth import AuthBase
|
|
7
7
|
|
|
8
|
-
from mx_bluesky.
|
|
9
|
-
from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_utils import (
|
|
8
|
+
from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import (
|
|
10
9
|
get_current_time_string,
|
|
11
10
|
get_ispyb_config,
|
|
12
11
|
)
|
|
12
|
+
from mx_bluesky.common.utils.exceptions import ISPyBDepositionNotMade
|
|
13
13
|
|
|
14
14
|
RobotActionID = int
|
|
15
15
|
|
|
@@ -54,9 +54,9 @@ class BLSampleStatus(StrEnum):
|
|
|
54
54
|
ERROR_BEAMLINE = "ERROR - beamline"
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
assert all(
|
|
58
|
-
|
|
59
|
-
)
|
|
57
|
+
assert all(len(value) <= 20 for value in BLSampleStatus), (
|
|
58
|
+
"Column size limit of 20 for BLSampleStatus"
|
|
59
|
+
)
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
class ExpeyeInteraction:
|