mx-bluesky 0.3.1__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/i04/__init__.py +3 -0
- mx_bluesky/{i04 → beamlines/i04}/thawing_plan.py +5 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/blueapi_config.yaml +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/dcid.py +2 -2
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/DetStage.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +7 -7
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +12 -9
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/CustomChip_py3v1.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/DetStage.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +245 -200
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/MappingLite-oxford_py3v1.edl +4 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +8 -8
- mx_bluesky/beamlines/i24/serial/fixed_target/__init__.py +0 -0
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +80 -70
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +20 -21
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +5 -5
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +7 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_moveonclick.py +59 -39
- mx_bluesky/{i24 → beamlines/i24}/serial/log.py +1 -9
- mx_bluesky/beamlines/i24/serial/parameters/__init__.py +15 -0
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/constants.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/experiment_parameters.py +4 -25
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/utils.py +5 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/run_serial.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/pv_abstract.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_beamline.py +2 -2
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_detector.py +5 -5
- mx_bluesky/{i24 → beamlines/i24}/serial/write_nexus.py +6 -3
- mx_bluesky/hyperion/__init__.py +1 -0
- mx_bluesky/hyperion/__main__.py +374 -0
- mx_bluesky/hyperion/device_setup_plans/__init__.py +0 -0
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +134 -0
- mx_bluesky/hyperion/device_setup_plans/manipulate_sample.py +110 -0
- mx_bluesky/hyperion/device_setup_plans/position_detector.py +16 -0
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +60 -0
- mx_bluesky/hyperion/device_setup_plans/setup_oav.py +87 -0
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +210 -0
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +214 -0
- mx_bluesky/hyperion/device_setup_plans/smargon.py +25 -0
- mx_bluesky/hyperion/device_setup_plans/utils.py +44 -0
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +93 -0
- mx_bluesky/hyperion/exceptions.py +47 -0
- mx_bluesky/hyperion/experiment_plans/__init__.py +30 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +84 -0
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +528 -0
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +209 -0
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +173 -0
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +81 -0
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +463 -0
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +119 -0
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +164 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +322 -0
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +436 -0
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +68 -0
- mx_bluesky/hyperion/external_interaction/__init__.py +9 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__init__.py +10 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +148 -0
- mx_bluesky/hyperion/external_interaction/callbacks/aperture_change_callback.py +22 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +46 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +70 -0
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +88 -0
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +203 -0
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +20 -0
- mx_bluesky/hyperion/external_interaction/callbacks/logging_callback.py +29 -0
- mx_bluesky/hyperion/external_interaction/callbacks/plan_reactive_callback.py +101 -0
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +88 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +174 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +17 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +102 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +269 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_mapping.py +53 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +95 -0
- mx_bluesky/hyperion/external_interaction/callbacks/zocalo_callback.py +92 -0
- mx_bluesky/hyperion/external_interaction/config_server.py +35 -0
- mx_bluesky/hyperion/external_interaction/exceptions.py +13 -0
- mx_bluesky/hyperion/external_interaction/ispyb/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/ispyb/data_model.py +95 -0
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +125 -0
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +276 -0
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_utils.py +29 -0
- mx_bluesky/hyperion/external_interaction/nexus/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +148 -0
- mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +114 -0
- mx_bluesky/hyperion/log.py +99 -0
- mx_bluesky/hyperion/parameters/__init__.py +2 -0
- mx_bluesky/hyperion/parameters/cli.py +68 -0
- mx_bluesky/{parameters → hyperion/parameters}/components.py +77 -24
- mx_bluesky/hyperion/parameters/constants.py +158 -0
- mx_bluesky/hyperion/parameters/gridscan.py +216 -0
- mx_bluesky/hyperion/parameters/rotation.py +160 -0
- mx_bluesky/hyperion/resources/panda/panda-gridscan.yaml +964 -0
- mx_bluesky/hyperion/tracing.py +28 -0
- mx_bluesky/hyperion/utils/context.py +84 -0
- mx_bluesky/hyperion/utils/utils.py +25 -0
- mx_bluesky/hyperion/utils/validation.py +196 -0
- mx_bluesky/jupyter_example.ipynb +3 -2
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.1.0.dist-info}/METADATA +26 -11
- mx_bluesky-1.1.0.dist-info/RECORD +136 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.1.0.dist-info}/WHEEL +1 -1
- mx_bluesky-1.1.0.dist-info/entry_points.txt +8 -0
- mx_bluesky/i04/__init__.py +0 -3
- mx_bluesky/i24/serial/parameters/__init__.py +0 -15
- mx_bluesky/parameters/__init__.py +0 -31
- mx_bluesky-0.3.1.dist-info/RECORD +0 -67
- mx_bluesky-0.3.1.dist-info/entry_points.txt +0 -4
- /mx_bluesky/{i24 → beamlines}/__init__.py +0 -0
- /mx_bluesky/{i04 → beamlines/i04}/callbacks/murko_callback.py +0 -0
- /mx_bluesky/{i24/serial/extruder → beamlines/i24}/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/microdrop_alignment.edl +0 -0
- /mx_bluesky/{i24/serial/fixed_target → beamlines/i24/serial/extruder}/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/ME14E-GeneralPurpose.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/PMAC_Command.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/Shutter_Control.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/microdrop_alignment.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/nudgechip.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/short1-laser.png +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/short2-laser.png +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/ft_utils.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/cs/cs_maker.json +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/cs/motor_direction.txt +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/pvar_files/minichip-oxford.pvar +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/pvar_files/oxford.pvar +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_extruder.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_fixed_target.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_ssx.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/set_visit_directory.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/ca.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/pv.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_zebra_plans.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/start_blueapi.sh +0 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.1.0.dist-info}/LICENSE +0 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Sequence
|
|
4
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
5
|
+
|
|
6
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.common.ispyb_mapping import (
|
|
7
|
+
populate_data_collection_group,
|
|
8
|
+
populate_remaining_data_collection_info,
|
|
9
|
+
)
|
|
10
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.ispyb_callback_base import (
|
|
11
|
+
BaseISPyBCallback,
|
|
12
|
+
)
|
|
13
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.rotation.ispyb_mapping import (
|
|
14
|
+
populate_data_collection_info_for_rotation,
|
|
15
|
+
)
|
|
16
|
+
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
|
|
17
|
+
DataCollectionInfo,
|
|
18
|
+
DataCollectionPositionInfo,
|
|
19
|
+
ScanDataInfo,
|
|
20
|
+
)
|
|
21
|
+
from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
|
|
22
|
+
IspybIds,
|
|
23
|
+
StoreInIspyb,
|
|
24
|
+
)
|
|
25
|
+
from mx_bluesky.hyperion.log import ISPYB_LOGGER, set_dcgid_tag
|
|
26
|
+
from mx_bluesky.hyperion.parameters.components import IspybExperimentType
|
|
27
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
28
|
+
from mx_bluesky.hyperion.parameters.rotation import RotationScan
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from event_model.documents import Event, RunStart, RunStop
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class RotationISPyBCallback(BaseISPyBCallback):
|
|
35
|
+
"""Callback class to handle the deposition of experiment parameters into the ISPyB
|
|
36
|
+
database. Listens for 'event' and 'descriptor' documents. Creates the ISpyB entry on
|
|
37
|
+
recieving an 'event' document for the 'ispyb_reading_hardware' event, and updates the
|
|
38
|
+
deposition on recieving its final 'stop' document.
|
|
39
|
+
|
|
40
|
+
To use, subscribe the Bluesky RunEngine to an instance of this class.
|
|
41
|
+
E.g.:
|
|
42
|
+
ispyb_handler_callback = RotationISPyBCallback(parameters)
|
|
43
|
+
RE.subscribe(ispyb_handler_callback)
|
|
44
|
+
Or decorate a plan using bluesky.preprocessors.subs_decorator.
|
|
45
|
+
|
|
46
|
+
See: https://blueskyproject.io/bluesky/callbacks.html#ways-to-invoke-callbacks
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
*,
|
|
52
|
+
emit: Callable[..., Any] | None = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
super().__init__(emit=emit)
|
|
55
|
+
self.last_sample_id: int | None = None
|
|
56
|
+
self.ispyb_ids: IspybIds = IspybIds()
|
|
57
|
+
|
|
58
|
+
def activity_gated_start(self, doc: RunStart):
|
|
59
|
+
if doc.get("subplan_name") == CONST.PLAN.ROTATION_OUTER:
|
|
60
|
+
ISPYB_LOGGER.info(
|
|
61
|
+
"ISPyB callback received start document with experiment parameters."
|
|
62
|
+
)
|
|
63
|
+
self.params = RotationScan.from_json(doc.get("hyperion_parameters"))
|
|
64
|
+
dcgid = (
|
|
65
|
+
self.ispyb_ids.data_collection_group_id
|
|
66
|
+
if (self.params.sample_id == self.last_sample_id)
|
|
67
|
+
else None
|
|
68
|
+
)
|
|
69
|
+
if (
|
|
70
|
+
self.params.ispyb_experiment_type
|
|
71
|
+
== IspybExperimentType.CHARACTERIZATION
|
|
72
|
+
):
|
|
73
|
+
ISPYB_LOGGER.info("Screening collection - using new DCG")
|
|
74
|
+
dcgid = None
|
|
75
|
+
self.last_sample_id = None
|
|
76
|
+
else:
|
|
77
|
+
ISPYB_LOGGER.info(
|
|
78
|
+
f"Collection is {self.params.ispyb_experiment_type} - storing sampleID to bundle images"
|
|
79
|
+
)
|
|
80
|
+
self.last_sample_id = self.params.sample_id
|
|
81
|
+
self.ispyb = StoreInIspyb(self.ispyb_config)
|
|
82
|
+
ISPYB_LOGGER.info("Beginning ispyb deposition")
|
|
83
|
+
data_collection_group_info = populate_data_collection_group(self.params)
|
|
84
|
+
data_collection_info = populate_data_collection_info_for_rotation(
|
|
85
|
+
cast(RotationScan, self.params)
|
|
86
|
+
)
|
|
87
|
+
data_collection_info = populate_remaining_data_collection_info(
|
|
88
|
+
self.params.comment,
|
|
89
|
+
dcgid,
|
|
90
|
+
data_collection_info,
|
|
91
|
+
self.params,
|
|
92
|
+
)
|
|
93
|
+
data_collection_info.parent_id = dcgid
|
|
94
|
+
scan_data_info = ScanDataInfo(
|
|
95
|
+
data_collection_info=data_collection_info,
|
|
96
|
+
)
|
|
97
|
+
self.ispyb_ids = self.ispyb.begin_deposition(
|
|
98
|
+
data_collection_group_info, [scan_data_info]
|
|
99
|
+
)
|
|
100
|
+
ISPYB_LOGGER.info("ISPYB handler received start document.")
|
|
101
|
+
if doc.get("subplan_name") == CONST.PLAN.ROTATION_MAIN:
|
|
102
|
+
self.uid_to_finalize_on = doc.get("uid")
|
|
103
|
+
return super().activity_gated_start(doc)
|
|
104
|
+
|
|
105
|
+
def populate_info_for_update(
|
|
106
|
+
self,
|
|
107
|
+
event_sourced_data_collection_info: DataCollectionInfo,
|
|
108
|
+
event_sourced_position_info: DataCollectionPositionInfo | None,
|
|
109
|
+
params,
|
|
110
|
+
) -> Sequence[ScanDataInfo]:
|
|
111
|
+
assert (
|
|
112
|
+
self.ispyb_ids.data_collection_ids
|
|
113
|
+
), "Expect an existing DataCollection to update"
|
|
114
|
+
|
|
115
|
+
return [
|
|
116
|
+
ScanDataInfo(
|
|
117
|
+
data_collection_info=event_sourced_data_collection_info,
|
|
118
|
+
data_collection_id=self.ispyb_ids.data_collection_ids[0],
|
|
119
|
+
data_collection_position_info=event_sourced_position_info,
|
|
120
|
+
)
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
def _handle_ispyb_hardware_read(self, doc: Event):
|
|
124
|
+
"""Use the hardware read values to create the ispyb comment"""
|
|
125
|
+
scan_data_infos = super()._handle_ispyb_hardware_read(doc)
|
|
126
|
+
motor_positions_mm = [
|
|
127
|
+
doc["data"]["smargon-x"],
|
|
128
|
+
doc["data"]["smargon-y"],
|
|
129
|
+
doc["data"]["smargon-z"],
|
|
130
|
+
]
|
|
131
|
+
assert (
|
|
132
|
+
self.params
|
|
133
|
+
), "handle_ispyb_hardware_read triggered before activity_gated_start"
|
|
134
|
+
motor_positions_um = [position * 1000 for position in motor_positions_mm]
|
|
135
|
+
comment = f"Sample position (µm): ({motor_positions_um[0]:.0f}, {motor_positions_um[1]:.0f}, {motor_positions_um[2]:.0f}) {self.params.comment} "
|
|
136
|
+
scan_data_infos[0].data_collection_info.comments = comment
|
|
137
|
+
return scan_data_infos
|
|
138
|
+
|
|
139
|
+
def activity_gated_event(self, doc: Event):
|
|
140
|
+
doc = super().activity_gated_event(doc)
|
|
141
|
+
set_dcgid_tag(self.ispyb_ids.data_collection_group_id)
|
|
142
|
+
|
|
143
|
+
descriptor_name = self.descriptors[doc["descriptor"]].get("name")
|
|
144
|
+
if descriptor_name == CONST.DESCRIPTORS.OAV_ROTATION_SNAPSHOT_TRIGGERED:
|
|
145
|
+
scan_data_infos = self._handle_oav_rotation_snapshot_triggered(doc)
|
|
146
|
+
self.ispyb_ids = self.ispyb.update_deposition(
|
|
147
|
+
self.ispyb_ids, scan_data_infos
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return doc
|
|
151
|
+
|
|
152
|
+
def _handle_oav_rotation_snapshot_triggered(self, doc) -> Sequence[ScanDataInfo]:
|
|
153
|
+
assert self.ispyb_ids.data_collection_ids, "No current data collection"
|
|
154
|
+
assert self.params, "ISPyB handler didn't receive parameters!"
|
|
155
|
+
data = doc["data"]
|
|
156
|
+
self._oav_snapshot_event_idx += 1
|
|
157
|
+
data_collection_info = DataCollectionInfo(
|
|
158
|
+
**{
|
|
159
|
+
f"xtal_snapshot{self._oav_snapshot_event_idx}": data.get(
|
|
160
|
+
"oav_snapshot_last_saved_path"
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
scan_data_info = ScanDataInfo(
|
|
165
|
+
data_collection_id=self.ispyb_ids.data_collection_ids[-1],
|
|
166
|
+
data_collection_info=data_collection_info,
|
|
167
|
+
)
|
|
168
|
+
return [scan_data_info]
|
|
169
|
+
|
|
170
|
+
def activity_gated_stop(self, doc: RunStop) -> RunStop:
|
|
171
|
+
if doc.get("run_start") == self.uid_to_finalize_on:
|
|
172
|
+
self.uid_to_finalize_on = None
|
|
173
|
+
return super().activity_gated_stop(doc)
|
|
174
|
+
return self._tag_doc(doc)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import DataCollectionInfo
|
|
4
|
+
from mx_bluesky.hyperion.parameters.rotation import RotationScan
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def populate_data_collection_info_for_rotation(params: RotationScan):
|
|
8
|
+
info = DataCollectionInfo(
|
|
9
|
+
omega_start=params.omega_start_deg,
|
|
10
|
+
data_collection_number=params.detector_params.run_number, # type:ignore # the validator always makes this int
|
|
11
|
+
n_images=params.num_images,
|
|
12
|
+
axis_range=params.rotation_increment_deg,
|
|
13
|
+
axis_start=params.omega_start_deg,
|
|
14
|
+
axis_end=(params.omega_start_deg + params.scan_width_deg),
|
|
15
|
+
kappa_start=params.kappa_start_deg,
|
|
16
|
+
)
|
|
17
|
+
return info
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.plan_reactive_callback import (
|
|
6
|
+
PlanReactiveCallback,
|
|
7
|
+
)
|
|
8
|
+
from mx_bluesky.hyperion.external_interaction.nexus.nexus_utils import (
|
|
9
|
+
create_beam_and_attenuator_parameters,
|
|
10
|
+
vds_type_based_on_bit_depth,
|
|
11
|
+
)
|
|
12
|
+
from mx_bluesky.hyperion.external_interaction.nexus.write_nexus import NexusWriter
|
|
13
|
+
from mx_bluesky.hyperion.log import NEXUS_LOGGER
|
|
14
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
15
|
+
from mx_bluesky.hyperion.parameters.rotation import RotationScan
|
|
16
|
+
|
|
17
|
+
from ..logging_callback import format_doc_for_log
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from event_model.documents import Event, EventDescriptor, RunStart
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class RotationNexusFileCallback(PlanReactiveCallback):
|
|
24
|
+
"""Callback class to handle the creation of Nexus files based on experiment
|
|
25
|
+
parameters for rotation scans
|
|
26
|
+
|
|
27
|
+
To use, subscribe the Bluesky RunEngine to an instance of this class.
|
|
28
|
+
E.g.:
|
|
29
|
+
nexus_file_handler_callback = NexusFileCallback(parameters)
|
|
30
|
+
RE.subscribe(nexus_file_handler_callback)
|
|
31
|
+
Or decorate a plan using bluesky.preprocessors.subs_decorator.
|
|
32
|
+
|
|
33
|
+
See: https://blueskyproject.io/bluesky/callbacks.html#ways-to-invoke-callbacks
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self) -> None:
|
|
37
|
+
super().__init__(NEXUS_LOGGER)
|
|
38
|
+
self.run_uid: str | None = None
|
|
39
|
+
self.writer: NexusWriter | None = None
|
|
40
|
+
self.descriptors: dict[str, EventDescriptor] = {}
|
|
41
|
+
# used when multiple collections are made in one detector arming event:
|
|
42
|
+
self.full_num_of_images: int | None = None
|
|
43
|
+
self.meta_data_run_number: int | None = None
|
|
44
|
+
|
|
45
|
+
def activity_gated_descriptor(self, doc: EventDescriptor):
|
|
46
|
+
self.descriptors[doc["uid"]] = doc
|
|
47
|
+
|
|
48
|
+
def activity_gated_event(self, doc: Event):
|
|
49
|
+
event_descriptor = self.descriptors.get(doc["descriptor"])
|
|
50
|
+
if event_descriptor is None:
|
|
51
|
+
NEXUS_LOGGER.warning(
|
|
52
|
+
f"Rotation Nexus handler {self} received event doc {format_doc_for_log(doc)} and "
|
|
53
|
+
"has no corresponding descriptor record"
|
|
54
|
+
)
|
|
55
|
+
return doc
|
|
56
|
+
if event_descriptor.get("name") == CONST.DESCRIPTORS.HARDWARE_READ_DURING:
|
|
57
|
+
NEXUS_LOGGER.info(
|
|
58
|
+
f"Nexus handler received event from read hardware {format_doc_for_log(doc)}"
|
|
59
|
+
)
|
|
60
|
+
data = doc["data"]
|
|
61
|
+
assert self.writer, "Nexus writer not initialised"
|
|
62
|
+
(
|
|
63
|
+
self.writer.beam,
|
|
64
|
+
self.writer.attenuator,
|
|
65
|
+
) = create_beam_and_attenuator_parameters(
|
|
66
|
+
data["dcm-energy_in_kev"],
|
|
67
|
+
data["flux_flux_reading"],
|
|
68
|
+
data["attenuator-actual_transmission"],
|
|
69
|
+
)
|
|
70
|
+
vds_data_type = vds_type_based_on_bit_depth(doc["data"]["eiger_bit_depth"])
|
|
71
|
+
self.writer.create_nexus_file(vds_data_type)
|
|
72
|
+
NEXUS_LOGGER.info(f"Nexus file created at {self.writer.data_filename}")
|
|
73
|
+
return doc
|
|
74
|
+
|
|
75
|
+
def activity_gated_start(self, doc: RunStart):
|
|
76
|
+
if doc.get("subplan_name") == CONST.PLAN.ROTATION_MULTI:
|
|
77
|
+
self.full_num_of_images = doc.get("full_num_of_images")
|
|
78
|
+
self.meta_data_run_number = doc.get("meta_data_run_number")
|
|
79
|
+
if doc.get("subplan_name") == CONST.PLAN.ROTATION_OUTER:
|
|
80
|
+
self.run_uid = doc.get("uid")
|
|
81
|
+
json_params = doc.get("hyperion_parameters")
|
|
82
|
+
NEXUS_LOGGER.info(
|
|
83
|
+
f"Nexus writer received start document with experiment parameters {json_params}"
|
|
84
|
+
)
|
|
85
|
+
parameters = RotationScan.from_json(json_params)
|
|
86
|
+
NEXUS_LOGGER.info("Setting up nexus file...")
|
|
87
|
+
det_size = (
|
|
88
|
+
parameters.detector_params.detector_size_constants.det_size_pixels
|
|
89
|
+
)
|
|
90
|
+
shape = (parameters.num_images, det_size.width, det_size.height)
|
|
91
|
+
self.writer = NexusWriter(
|
|
92
|
+
parameters,
|
|
93
|
+
shape,
|
|
94
|
+
parameters.scan_points,
|
|
95
|
+
omega_start_deg=parameters.omega_start_deg,
|
|
96
|
+
chi_start_deg=parameters.chi_start_deg or 0,
|
|
97
|
+
phi_start_deg=parameters.phi_start_deg or 0,
|
|
98
|
+
vds_start_index=parameters.nexus_vds_start_img,
|
|
99
|
+
full_num_of_images=self.full_num_of_images,
|
|
100
|
+
meta_data_run_number=self.meta_data_run_number,
|
|
101
|
+
rotation_direction=parameters.rotation_direction,
|
|
102
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Sequence
|
|
4
|
+
from time import time
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from blueapi.core import MsgGenerator
|
|
9
|
+
from bluesky import preprocessors as bpp
|
|
10
|
+
from dodal.devices.zocalo.zocalo_results import ZOCALO_READING_PLAN_NAME
|
|
11
|
+
|
|
12
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.common.ispyb_mapping import (
|
|
13
|
+
populate_data_collection_group,
|
|
14
|
+
populate_remaining_data_collection_info,
|
|
15
|
+
)
|
|
16
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.ispyb_callback_base import (
|
|
17
|
+
BaseISPyBCallback,
|
|
18
|
+
)
|
|
19
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.logging_callback import (
|
|
20
|
+
format_doc_for_log,
|
|
21
|
+
)
|
|
22
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.xray_centre.ispyb_mapping import (
|
|
23
|
+
construct_comment_for_gridscan,
|
|
24
|
+
populate_xy_data_collection_info,
|
|
25
|
+
populate_xz_data_collection_info,
|
|
26
|
+
)
|
|
27
|
+
from mx_bluesky.hyperion.external_interaction.exceptions import ISPyBDepositionNotMade
|
|
28
|
+
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
|
|
29
|
+
DataCollectionGridInfo,
|
|
30
|
+
DataCollectionInfo,
|
|
31
|
+
DataCollectionPositionInfo,
|
|
32
|
+
Orientation,
|
|
33
|
+
ScanDataInfo,
|
|
34
|
+
)
|
|
35
|
+
from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
|
|
36
|
+
IspybIds,
|
|
37
|
+
StoreInIspyb,
|
|
38
|
+
)
|
|
39
|
+
from mx_bluesky.hyperion.log import ISPYB_LOGGER, set_dcgid_tag
|
|
40
|
+
from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
|
|
41
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
42
|
+
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
43
|
+
GridCommon,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from event_model import Event, RunStart, RunStop
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def ispyb_activation_wrapper(plan_generator: MsgGenerator, parameters):
|
|
51
|
+
return bpp.run_wrapper(
|
|
52
|
+
plan_generator,
|
|
53
|
+
md={
|
|
54
|
+
"activate_callbacks": ["GridscanISPyBCallback"],
|
|
55
|
+
"subplan_name": CONST.PLAN.GRID_DETECT_AND_DO_GRIDSCAN,
|
|
56
|
+
"hyperion_parameters": parameters.model_dump_json(),
|
|
57
|
+
},
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class GridscanISPyBCallback(BaseISPyBCallback):
|
|
62
|
+
"""Callback class to handle the deposition of experiment parameters into the ISPyB
|
|
63
|
+
database. Listens for 'event' and 'descriptor' documents. Creates the ISpyB entry on
|
|
64
|
+
recieving an 'event' document for the 'ispyb_reading_hardware' event, and updates the
|
|
65
|
+
deposition on recieving its final 'stop' document.
|
|
66
|
+
|
|
67
|
+
To use, subscribe the Bluesky RunEngine to an instance of this class.
|
|
68
|
+
E.g.:
|
|
69
|
+
ispyb_handler_callback = FGSISPyBCallback(parameters)
|
|
70
|
+
RE.subscribe(ispyb_handler_callback)
|
|
71
|
+
Or decorate a plan using bluesky.preprocessors.subs_decorator.
|
|
72
|
+
|
|
73
|
+
See: https://blueskyproject.io/bluesky/callbacks.html#ways-to-invoke-callbacks
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(
|
|
77
|
+
self,
|
|
78
|
+
*,
|
|
79
|
+
emit: Callable[..., Any] | None = None,
|
|
80
|
+
) -> None:
|
|
81
|
+
super().__init__(emit=emit)
|
|
82
|
+
self.ispyb: StoreInIspyb
|
|
83
|
+
self.ispyb_ids: IspybIds = IspybIds()
|
|
84
|
+
self._start_of_fgs_uid: str | None = None
|
|
85
|
+
self._processing_start_time: float | None = None
|
|
86
|
+
|
|
87
|
+
def activity_gated_start(self, doc: RunStart):
|
|
88
|
+
if doc.get("subplan_name") == CONST.PLAN.DO_FGS:
|
|
89
|
+
self._start_of_fgs_uid = doc.get("uid")
|
|
90
|
+
if doc.get("subplan_name") == CONST.PLAN.GRID_DETECT_AND_DO_GRIDSCAN:
|
|
91
|
+
self.uid_to_finalize_on = doc.get("uid")
|
|
92
|
+
ISPYB_LOGGER.info(
|
|
93
|
+
"ISPyB callback received start document with experiment parameters and "
|
|
94
|
+
f"uid: {self.uid_to_finalize_on}"
|
|
95
|
+
)
|
|
96
|
+
self.params = GridCommon.from_json(doc.get("hyperion_parameters"))
|
|
97
|
+
self.ispyb = StoreInIspyb(self.ispyb_config)
|
|
98
|
+
data_collection_group_info = populate_data_collection_group(self.params)
|
|
99
|
+
|
|
100
|
+
scan_data_infos = [
|
|
101
|
+
ScanDataInfo(
|
|
102
|
+
data_collection_info=populate_remaining_data_collection_info(
|
|
103
|
+
None,
|
|
104
|
+
None,
|
|
105
|
+
populate_xy_data_collection_info(
|
|
106
|
+
self.params.detector_params,
|
|
107
|
+
),
|
|
108
|
+
self.params,
|
|
109
|
+
),
|
|
110
|
+
),
|
|
111
|
+
ScanDataInfo(
|
|
112
|
+
data_collection_info=populate_remaining_data_collection_info(
|
|
113
|
+
None,
|
|
114
|
+
None,
|
|
115
|
+
populate_xz_data_collection_info(self.params.detector_params),
|
|
116
|
+
self.params,
|
|
117
|
+
)
|
|
118
|
+
),
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
self.ispyb_ids = self.ispyb.begin_deposition(
|
|
122
|
+
data_collection_group_info, scan_data_infos
|
|
123
|
+
)
|
|
124
|
+
set_dcgid_tag(self.ispyb_ids.data_collection_group_id)
|
|
125
|
+
return super().activity_gated_start(doc)
|
|
126
|
+
|
|
127
|
+
def activity_gated_event(self, doc: Event):
|
|
128
|
+
doc = super().activity_gated_event(doc)
|
|
129
|
+
|
|
130
|
+
descriptor_name = self.descriptors[doc["descriptor"]].get("name")
|
|
131
|
+
if descriptor_name == ZOCALO_READING_PLAN_NAME:
|
|
132
|
+
self._handle_zocalo_read_event(doc)
|
|
133
|
+
elif descriptor_name == CONST.DESCRIPTORS.OAV_GRID_SNAPSHOT_TRIGGERED:
|
|
134
|
+
scan_data_infos = self._handle_oav_grid_snapshot_triggered(doc)
|
|
135
|
+
self.ispyb_ids = self.ispyb.update_deposition(
|
|
136
|
+
self.ispyb_ids, scan_data_infos
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return doc
|
|
140
|
+
|
|
141
|
+
def _handle_zocalo_read_event(self, doc):
|
|
142
|
+
crystal_summary = ""
|
|
143
|
+
if self._processing_start_time is not None:
|
|
144
|
+
proc_time = time() - self._processing_start_time
|
|
145
|
+
crystal_summary = f"Zocalo processing took {proc_time:.2f} s. "
|
|
146
|
+
bboxes: list[np.ndarray] = []
|
|
147
|
+
ISPYB_LOGGER.info(
|
|
148
|
+
f"Amending comment based on Zocalo reading doc: {format_doc_for_log(doc)}"
|
|
149
|
+
)
|
|
150
|
+
raw_results = doc["data"]["zocalo-results"]
|
|
151
|
+
if len(raw_results) > 0:
|
|
152
|
+
for n, res in enumerate(raw_results):
|
|
153
|
+
bb = res["bounding_box"]
|
|
154
|
+
diff = np.array(bb[1]) - np.array(bb[0])
|
|
155
|
+
bboxes.append(diff)
|
|
156
|
+
|
|
157
|
+
nicely_formatted_com = [
|
|
158
|
+
f"{np.round(com, 2)}" for com in res["centre_of_mass"]
|
|
159
|
+
]
|
|
160
|
+
crystal_summary += (
|
|
161
|
+
f"Crystal {n + 1}: "
|
|
162
|
+
f"Strength {res['total_count']}; "
|
|
163
|
+
f"Position (grid boxes) {nicely_formatted_com}; "
|
|
164
|
+
f"Size (grid boxes) {bboxes[n]}; "
|
|
165
|
+
)
|
|
166
|
+
else:
|
|
167
|
+
crystal_summary += "Zocalo found no crystals in this gridscan."
|
|
168
|
+
assert (
|
|
169
|
+
self.ispyb_ids.data_collection_ids
|
|
170
|
+
), "No data collection to add results to"
|
|
171
|
+
self.ispyb.append_to_comment(
|
|
172
|
+
self.ispyb_ids.data_collection_ids[0], crystal_summary
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
def _handle_oav_grid_snapshot_triggered(self, doc) -> Sequence[ScanDataInfo]:
|
|
176
|
+
assert self.ispyb_ids.data_collection_ids, "No current data collection"
|
|
177
|
+
assert self.params, "ISPyB handler didn't receive parameters!"
|
|
178
|
+
data = doc["data"]
|
|
179
|
+
data_collection_id = None
|
|
180
|
+
data_collection_info = DataCollectionInfo(
|
|
181
|
+
xtal_snapshot1=data.get("oav_grid_snapshot_last_path_full_overlay"),
|
|
182
|
+
xtal_snapshot2=data.get("oav_grid_snapshot_last_path_outer"),
|
|
183
|
+
xtal_snapshot3=data.get("oav_grid_snapshot_last_saved_path"),
|
|
184
|
+
n_images=(
|
|
185
|
+
data["oav_grid_snapshot_num_boxes_x"]
|
|
186
|
+
* data["oav_grid_snapshot_num_boxes_y"]
|
|
187
|
+
),
|
|
188
|
+
)
|
|
189
|
+
microns_per_pixel_x = data["oav_grid_snapshot_microns_per_pixel_x"]
|
|
190
|
+
microns_per_pixel_y = data["oav_grid_snapshot_microns_per_pixel_y"]
|
|
191
|
+
data_collection_grid_info = DataCollectionGridInfo(
|
|
192
|
+
dx_in_mm=data["oav_grid_snapshot_box_width"] * microns_per_pixel_x / 1000,
|
|
193
|
+
dy_in_mm=data["oav_grid_snapshot_box_width"] * microns_per_pixel_y / 1000,
|
|
194
|
+
steps_x=data["oav_grid_snapshot_num_boxes_x"],
|
|
195
|
+
steps_y=data["oav_grid_snapshot_num_boxes_y"],
|
|
196
|
+
microns_per_pixel_x=microns_per_pixel_x,
|
|
197
|
+
microns_per_pixel_y=microns_per_pixel_y,
|
|
198
|
+
snapshot_offset_x_pixel=int(data["oav_grid_snapshot_top_left_x"]),
|
|
199
|
+
snapshot_offset_y_pixel=int(data["oav_grid_snapshot_top_left_y"]),
|
|
200
|
+
orientation=Orientation.HORIZONTAL,
|
|
201
|
+
snaked=True,
|
|
202
|
+
)
|
|
203
|
+
data_collection_info.comments = construct_comment_for_gridscan(
|
|
204
|
+
data_collection_grid_info
|
|
205
|
+
)
|
|
206
|
+
if len(self.ispyb_ids.data_collection_ids) > self._oav_snapshot_event_idx:
|
|
207
|
+
data_collection_id = self.ispyb_ids.data_collection_ids[
|
|
208
|
+
self._oav_snapshot_event_idx
|
|
209
|
+
]
|
|
210
|
+
self._populate_axis_info(data_collection_info, doc["data"]["smargon-omega"])
|
|
211
|
+
|
|
212
|
+
scan_data_info = ScanDataInfo(
|
|
213
|
+
data_collection_info=data_collection_info,
|
|
214
|
+
data_collection_id=data_collection_id,
|
|
215
|
+
data_collection_grid_info=data_collection_grid_info,
|
|
216
|
+
)
|
|
217
|
+
ISPYB_LOGGER.info("Updating ispyb data collection after oav snapshot.")
|
|
218
|
+
self._oav_snapshot_event_idx += 1
|
|
219
|
+
return [scan_data_info]
|
|
220
|
+
|
|
221
|
+
def _populate_axis_info(
|
|
222
|
+
self, data_collection_info: DataCollectionInfo, omega_start: float | None
|
|
223
|
+
):
|
|
224
|
+
if omega_start is not None:
|
|
225
|
+
omega_in_gda_space = -omega_start
|
|
226
|
+
data_collection_info.omega_start = omega_in_gda_space
|
|
227
|
+
data_collection_info.axis_start = omega_in_gda_space
|
|
228
|
+
data_collection_info.axis_end = omega_in_gda_space
|
|
229
|
+
data_collection_info.axis_range = 0
|
|
230
|
+
|
|
231
|
+
def populate_info_for_update(
|
|
232
|
+
self,
|
|
233
|
+
event_sourced_data_collection_info: DataCollectionInfo,
|
|
234
|
+
event_sourced_position_info: DataCollectionPositionInfo | None,
|
|
235
|
+
params: DiffractionExperimentWithSample,
|
|
236
|
+
) -> Sequence[ScanDataInfo]:
|
|
237
|
+
assert (
|
|
238
|
+
self.ispyb_ids.data_collection_ids
|
|
239
|
+
), "Expect at least one valid data collection to record scan data"
|
|
240
|
+
xy_scan_data_info = ScanDataInfo(
|
|
241
|
+
data_collection_info=event_sourced_data_collection_info,
|
|
242
|
+
data_collection_id=self.ispyb_ids.data_collection_ids[0],
|
|
243
|
+
)
|
|
244
|
+
scan_data_infos = [xy_scan_data_info]
|
|
245
|
+
|
|
246
|
+
data_collection_id = (
|
|
247
|
+
self.ispyb_ids.data_collection_ids[1]
|
|
248
|
+
if len(self.ispyb_ids.data_collection_ids) > 1
|
|
249
|
+
else None
|
|
250
|
+
)
|
|
251
|
+
xz_scan_data_info = ScanDataInfo(
|
|
252
|
+
data_collection_info=event_sourced_data_collection_info,
|
|
253
|
+
data_collection_id=data_collection_id,
|
|
254
|
+
)
|
|
255
|
+
scan_data_infos.append(xz_scan_data_info)
|
|
256
|
+
return scan_data_infos
|
|
257
|
+
|
|
258
|
+
def activity_gated_stop(self, doc: RunStop) -> RunStop:
|
|
259
|
+
if doc.get("run_start") == self._start_of_fgs_uid:
|
|
260
|
+
self._processing_start_time = time()
|
|
261
|
+
if doc.get("run_start") == self.uid_to_finalize_on:
|
|
262
|
+
ISPYB_LOGGER.info(
|
|
263
|
+
"ISPyB callback received stop document corresponding to start document "
|
|
264
|
+
f"with uid: {self.uid_to_finalize_on}."
|
|
265
|
+
)
|
|
266
|
+
if self.ispyb_ids == IspybIds():
|
|
267
|
+
raise ISPyBDepositionNotMade("ispyb was not initialised at run start")
|
|
268
|
+
return super().activity_gated_stop(doc)
|
|
269
|
+
return self._tag_doc(doc)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import numpy
|
|
4
|
+
from dodal.devices.detector import DetectorParams
|
|
5
|
+
from dodal.devices.oav import utils as oav_utils
|
|
6
|
+
|
|
7
|
+
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
|
|
8
|
+
DataCollectionGridInfo,
|
|
9
|
+
DataCollectionInfo,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def populate_xz_data_collection_info(detector_params: DetectorParams):
|
|
14
|
+
assert (
|
|
15
|
+
detector_params.omega_start is not None
|
|
16
|
+
and detector_params.run_number is not None
|
|
17
|
+
), "StoreGridscanInIspyb failed to get parameters"
|
|
18
|
+
run_number = detector_params.run_number + 1
|
|
19
|
+
info = DataCollectionInfo(
|
|
20
|
+
data_collection_number=run_number,
|
|
21
|
+
)
|
|
22
|
+
return info
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def populate_xy_data_collection_info(detector_params: DetectorParams):
|
|
26
|
+
return DataCollectionInfo(
|
|
27
|
+
data_collection_number=detector_params.run_number,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def construct_comment_for_gridscan(grid_info: DataCollectionGridInfo) -> str:
|
|
32
|
+
assert grid_info is not None, "StoreGridScanInIspyb failed to get parameters"
|
|
33
|
+
|
|
34
|
+
bottom_right = oav_utils.bottom_right_from_top_left(
|
|
35
|
+
numpy.array(
|
|
36
|
+
[grid_info.snapshot_offset_x_pixel, grid_info.snapshot_offset_y_pixel]
|
|
37
|
+
), # type: ignore
|
|
38
|
+
grid_info.steps_x,
|
|
39
|
+
grid_info.steps_y,
|
|
40
|
+
grid_info.dx_in_mm,
|
|
41
|
+
grid_info.dy_in_mm,
|
|
42
|
+
grid_info.microns_per_pixel_x,
|
|
43
|
+
grid_info.microns_per_pixel_y,
|
|
44
|
+
)
|
|
45
|
+
return (
|
|
46
|
+
"Hyperion: Xray centring - Diffraction grid scan of "
|
|
47
|
+
f"{grid_info.steps_x} by "
|
|
48
|
+
f"{grid_info.steps_y} images in "
|
|
49
|
+
f"{(grid_info.dx_in_mm * 1e3):.1f} um by "
|
|
50
|
+
f"{(grid_info.dy_in_mm * 1e3):.1f} um steps. "
|
|
51
|
+
f"Top left (px): [{int(grid_info.snapshot_offset_x_pixel)},{int(grid_info.snapshot_offset_y_pixel)}], "
|
|
52
|
+
f"bottom right (px): [{bottom_right[0]},{bottom_right[1]}]."
|
|
53
|
+
)
|