mx-bluesky 1.2.0__py3-none-any.whl → 1.4.1a0__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/__init__.py +8 -3
- mx_bluesky/__main__.py +12 -7
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/i04/callbacks/murko_callback.py +14 -4
- mx_bluesky/beamlines/i04/thawing_plan.py +49 -11
- mx_bluesky/beamlines/i24/serial/__init__.py +3 -0
- mx_bluesky/beamlines/i24/serial/dcid.py +19 -21
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +69 -91
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +2 -5
- mx_bluesky/beamlines/i24/serial/fixed_target/ft_utils.py +0 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +111 -143
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +141 -222
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +7 -216
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +18 -17
- mx_bluesky/beamlines/i24/serial/log.py +58 -49
- mx_bluesky/beamlines/i24/serial/parameters/constants.py +0 -1
- mx_bluesky/beamlines/i24/serial/parameters/fixed_target/cs/cs_maker.json +3 -3
- mx_bluesky/beamlines/i24/serial/run_extruder.sh +30 -5
- mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +30 -5
- mx_bluesky/beamlines/i24/serial/run_serial.py +24 -8
- mx_bluesky/beamlines/i24/serial/setup_beamline/ca.py +0 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +79 -81
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +9 -20
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +26 -28
- mx_bluesky/beamlines/i24/serial/write_nexus.py +11 -11
- mx_bluesky/common/__init__.py +0 -0
- mx_bluesky/common/device_setup_plans/read_hardware_for_setup.py +14 -0
- mx_bluesky/common/external_interaction/config_server.py +46 -0
- mx_bluesky/common/parameters/components.py +258 -0
- mx_bluesky/common/parameters/constants.py +138 -0
- mx_bluesky/common/parameters/gridscan.py +94 -0
- mx_bluesky/common/parameters/robot_load.py +16 -0
- mx_bluesky/common/plans/__init__.py +1 -0
- mx_bluesky/common/plans/do_fgs.py +121 -0
- mx_bluesky/common/utils/log.py +118 -0
- mx_bluesky/{hyperion → common/utils}/tracing.py +2 -2
- mx_bluesky/hyperion/__main__.py +13 -10
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +31 -26
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +6 -12
- mx_bluesky/hyperion/device_setup_plans/setup_oav.py +6 -12
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +5 -6
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +49 -18
- mx_bluesky/hyperion/device_setup_plans/smargon.py +6 -6
- mx_bluesky/hyperion/device_setup_plans/utils.py +2 -2
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +4 -4
- mx_bluesky/hyperion/experiment_plans/__init__.py +4 -0
- mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +83 -0
- mx_bluesky/hyperion/experiment_plans/common/xrc_result.py +47 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -9
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +145 -161
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +56 -22
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +52 -10
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +21 -20
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +11 -14
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +40 -21
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +19 -19
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +21 -21
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +51 -13
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +24 -7
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +5 -6
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -2
- mx_bluesky/hyperion/external_interaction/callbacks/common/abstract_event.py +66 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +30 -25
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +29 -12
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +7 -4
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +5 -3
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +28 -20
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +5 -4
- mx_bluesky/hyperion/external_interaction/config_server.py +11 -28
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +1 -1
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +1 -1
- mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +2 -2
- mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +1 -1
- mx_bluesky/hyperion/log.py +0 -84
- mx_bluesky/hyperion/parameters/components.py +4 -251
- mx_bluesky/hyperion/parameters/constants.py +22 -119
- mx_bluesky/hyperion/parameters/gridscan.py +35 -74
- mx_bluesky/hyperion/parameters/load_centre_collect.py +16 -11
- mx_bluesky/hyperion/parameters/rotation.py +23 -10
- mx_bluesky/hyperion/utils/utils.py +17 -0
- mx_bluesky/hyperion/utils/validation.py +5 -6
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/METADATA +36 -33
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/RECORD +91 -81
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/WHEEL +1 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +0 -161
- mx_bluesky/example.py +0 -19
- mx_bluesky/hyperion/parameters/robot_load.py +0 -16
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import dataclasses
|
|
4
3
|
from typing import cast
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
import bluesky.preprocessors as bpp
|
|
6
|
+
import pydantic
|
|
7
|
+
from blueapi.core import BlueskyContext
|
|
8
|
+
from bluesky.utils import MsgGenerator
|
|
7
9
|
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
8
10
|
from dodal.devices.attenuator import Attenuator
|
|
9
11
|
from dodal.devices.backlight import Backlight
|
|
@@ -12,7 +14,7 @@ from dodal.devices.detector.detector_motion import DetectorMotion
|
|
|
12
14
|
from dodal.devices.eiger import EigerDetector
|
|
13
15
|
from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScan
|
|
14
16
|
from dodal.devices.flux import Flux
|
|
15
|
-
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes,
|
|
17
|
+
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
16
18
|
from dodal.devices.motors import XYZPositioner
|
|
17
19
|
from dodal.devices.oav.oav_detector import OAV
|
|
18
20
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
@@ -31,15 +33,23 @@ from dodal.devices.zocalo import ZocaloResults
|
|
|
31
33
|
from dodal.log import LOGGER
|
|
32
34
|
from ophyd_async.fastcs.panda import HDFPanda
|
|
33
35
|
|
|
36
|
+
from mx_bluesky.common.parameters.constants import OavConstants
|
|
37
|
+
from mx_bluesky.common.parameters.gridscan import RobotLoadThenCentre
|
|
34
38
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
35
39
|
fill_in_energy_if_not_supplied,
|
|
36
40
|
start_preparing_data_collection_then_do_plan,
|
|
37
41
|
)
|
|
42
|
+
from mx_bluesky.hyperion.experiment_plans.change_aperture_then_move_plan import (
|
|
43
|
+
change_aperture_then_move_to_xtal,
|
|
44
|
+
)
|
|
45
|
+
from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import (
|
|
46
|
+
XRayCentreEventHandler,
|
|
47
|
+
)
|
|
38
48
|
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
39
49
|
GridDetectThenXRayCentreComposite,
|
|
40
50
|
)
|
|
41
51
|
from mx_bluesky.hyperion.experiment_plans.pin_centre_then_xray_centre_plan import (
|
|
42
|
-
|
|
52
|
+
pin_centre_then_flyscan_plan,
|
|
43
53
|
)
|
|
44
54
|
from mx_bluesky.hyperion.experiment_plans.robot_load_and_change_energy import (
|
|
45
55
|
RobotLoadAndEnergyChangeComposite,
|
|
@@ -47,10 +57,9 @@ from mx_bluesky.hyperion.experiment_plans.robot_load_and_change_energy import (
|
|
|
47
57
|
robot_load_and_change_energy_plan,
|
|
48
58
|
)
|
|
49
59
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
50
|
-
from mx_bluesky.hyperion.parameters.gridscan import RobotLoadThenCentre
|
|
51
60
|
|
|
52
61
|
|
|
53
|
-
@dataclasses.dataclass
|
|
62
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
54
63
|
class RobotLoadThenCentreComposite:
|
|
55
64
|
# common fields
|
|
56
65
|
xbpm_feedback: XBPMFeedback
|
|
@@ -78,7 +87,7 @@ class RobotLoadThenCentreComposite:
|
|
|
78
87
|
|
|
79
88
|
# SetEnergyComposite fields
|
|
80
89
|
vfm: FocusingMirrorWithStripes
|
|
81
|
-
|
|
90
|
+
mirror_voltages: MirrorVoltages
|
|
82
91
|
dcm: DCM
|
|
83
92
|
undulator_dcm: UndulatorDCM
|
|
84
93
|
|
|
@@ -87,6 +96,10 @@ class RobotLoadThenCentreComposite:
|
|
|
87
96
|
webcam: Webcam
|
|
88
97
|
lower_gonio: XYZPositioner
|
|
89
98
|
|
|
99
|
+
@property
|
|
100
|
+
def sample_motors(self):
|
|
101
|
+
return self.smargon
|
|
102
|
+
|
|
90
103
|
|
|
91
104
|
def create_devices(context: BlueskyContext) -> RobotLoadThenCentreComposite:
|
|
92
105
|
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
@@ -94,32 +107,57 @@ def create_devices(context: BlueskyContext) -> RobotLoadThenCentreComposite:
|
|
|
94
107
|
return device_composite_from_context(context, RobotLoadThenCentreComposite)
|
|
95
108
|
|
|
96
109
|
|
|
97
|
-
def
|
|
110
|
+
def _flyscan_plan_from_robot_load_params(
|
|
98
111
|
composite: RobotLoadThenCentreComposite,
|
|
99
112
|
params: RobotLoadThenCentre,
|
|
113
|
+
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
100
114
|
):
|
|
101
|
-
yield from
|
|
115
|
+
yield from pin_centre_then_flyscan_plan(
|
|
102
116
|
cast(GridDetectThenXRayCentreComposite, composite),
|
|
103
117
|
params.pin_centre_then_xray_centre_params(),
|
|
104
118
|
)
|
|
105
119
|
|
|
106
120
|
|
|
107
|
-
def
|
|
121
|
+
def _robot_load_then_flyscan_plan(
|
|
108
122
|
composite: RobotLoadThenCentreComposite,
|
|
109
123
|
params: RobotLoadThenCentre,
|
|
124
|
+
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
110
125
|
):
|
|
111
126
|
yield from robot_load_and_change_energy_plan(
|
|
112
127
|
cast(RobotLoadAndEnergyChangeComposite, composite),
|
|
113
128
|
params.robot_load_params(),
|
|
114
129
|
)
|
|
115
130
|
|
|
116
|
-
yield from
|
|
131
|
+
yield from _flyscan_plan_from_robot_load_params(composite, params, oav_config_file)
|
|
117
132
|
|
|
118
133
|
|
|
119
134
|
def robot_load_then_centre(
|
|
120
135
|
composite: RobotLoadThenCentreComposite,
|
|
121
136
|
parameters: RobotLoadThenCentre,
|
|
122
137
|
) -> MsgGenerator:
|
|
138
|
+
"""Perform pin-tip detection followed by a flyscan to determine centres of interest.
|
|
139
|
+
Performs a robot load if necessary. Centre on the best diffracting centre.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
xray_centre_event_handler = XRayCentreEventHandler()
|
|
143
|
+
|
|
144
|
+
yield from bpp.subs_wrapper(
|
|
145
|
+
robot_load_then_xray_centre(composite, parameters), xray_centre_event_handler
|
|
146
|
+
)
|
|
147
|
+
flyscan_results = xray_centre_event_handler.xray_centre_results
|
|
148
|
+
if flyscan_results is not None:
|
|
149
|
+
yield from change_aperture_then_move_to_xtal(
|
|
150
|
+
flyscan_results[0], composite.smargon, composite.aperture_scatterguard
|
|
151
|
+
)
|
|
152
|
+
# else no chi change, no need to recentre.
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def robot_load_then_xray_centre(
|
|
156
|
+
composite: RobotLoadThenCentreComposite,
|
|
157
|
+
parameters: RobotLoadThenCentre,
|
|
158
|
+
) -> MsgGenerator:
|
|
159
|
+
"""Perform pin-tip detection followed by a flyscan to determine centres of interest.
|
|
160
|
+
Performs a robot load if necessary."""
|
|
123
161
|
eiger: EigerDetector = composite.eiger
|
|
124
162
|
|
|
125
163
|
# TODO: get these from one source of truth #254
|
|
@@ -135,13 +173,13 @@ def robot_load_then_centre(
|
|
|
135
173
|
doing_chi_change = parameters.chi_start_deg is not None
|
|
136
174
|
|
|
137
175
|
if doing_sample_load:
|
|
138
|
-
plan =
|
|
176
|
+
plan = _robot_load_then_flyscan_plan(
|
|
139
177
|
composite,
|
|
140
178
|
parameters,
|
|
141
179
|
)
|
|
142
180
|
LOGGER.info("Pin not loaded, loading and centring")
|
|
143
181
|
elif doing_chi_change:
|
|
144
|
-
plan =
|
|
182
|
+
plan = _flyscan_plan_from_robot_load_params(composite, parameters)
|
|
145
183
|
LOGGER.info("Pin already loaded but chi changed so centring")
|
|
146
184
|
else:
|
|
147
185
|
LOGGER.info("Pin already loaded and chi not changed so doing nothing")
|
|
@@ -4,7 +4,9 @@ import dataclasses
|
|
|
4
4
|
|
|
5
5
|
import bluesky.plan_stubs as bps
|
|
6
6
|
import bluesky.preprocessors as bpp
|
|
7
|
-
|
|
7
|
+
import pydantic
|
|
8
|
+
from blueapi.core import BlueskyContext
|
|
9
|
+
from bluesky.utils import MsgGenerator
|
|
8
10
|
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
9
11
|
from dodal.devices.attenuator import Attenuator
|
|
10
12
|
from dodal.devices.backlight import Backlight
|
|
@@ -22,8 +24,11 @@ from dodal.devices.undulator import Undulator
|
|
|
22
24
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
23
25
|
from dodal.devices.zebra import RotationDirection, Zebra
|
|
24
26
|
from dodal.devices.zebra_controlled_shutter import ZebraShutter
|
|
25
|
-
from dodal.
|
|
27
|
+
from dodal.plan_stubs.check_topup import check_topup_and_wait_if_necessary
|
|
26
28
|
|
|
29
|
+
from mx_bluesky.common.device_setup_plans.read_hardware_for_setup import (
|
|
30
|
+
read_hardware_for_zocalo,
|
|
31
|
+
)
|
|
27
32
|
from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import (
|
|
28
33
|
cleanup_sample_environment,
|
|
29
34
|
move_phi_chi_omega,
|
|
@@ -32,7 +37,6 @@ from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import (
|
|
|
32
37
|
)
|
|
33
38
|
from mx_bluesky.hyperion.device_setup_plans.read_hardware_for_setup import (
|
|
34
39
|
read_hardware_during_collection,
|
|
35
|
-
read_hardware_for_zocalo,
|
|
36
40
|
read_hardware_pre_collection,
|
|
37
41
|
)
|
|
38
42
|
from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
|
|
@@ -60,7 +64,7 @@ from mx_bluesky.hyperion.parameters.rotation import (
|
|
|
60
64
|
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
61
65
|
|
|
62
66
|
|
|
63
|
-
@dataclasses.dataclass
|
|
67
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
64
68
|
class RotationScanComposite(OavSnapshotComposite):
|
|
65
69
|
"""All devices which are directly or indirectly required by this plan"""
|
|
66
70
|
|
|
@@ -252,7 +256,7 @@ def rotation_scan_plan(
|
|
|
252
256
|
composite.undulator,
|
|
253
257
|
composite.synchrotron,
|
|
254
258
|
composite.s4_slit_gaps,
|
|
255
|
-
composite.
|
|
259
|
+
composite.dcm,
|
|
256
260
|
composite.smargon,
|
|
257
261
|
)
|
|
258
262
|
|
|
@@ -327,6 +331,13 @@ def _move_and_rotation(
|
|
|
327
331
|
yield from setup_beamline_for_OAV(
|
|
328
332
|
composite.smargon, composite.backlight, composite.aperture_scatterguard
|
|
329
333
|
)
|
|
334
|
+
yield from bps.wait(group=CONST.WAIT.READY_FOR_OAV)
|
|
335
|
+
if params.selected_aperture:
|
|
336
|
+
yield from bps.abs_set(
|
|
337
|
+
composite.aperture_scatterguard.aperture_outside_beam,
|
|
338
|
+
params.selected_aperture,
|
|
339
|
+
group=CONST.WAIT.ROTATION_READY_FOR_DC,
|
|
340
|
+
)
|
|
330
341
|
yield from oav_snapshot_plan(composite, params, oav_params)
|
|
331
342
|
yield from rotation_scan_plan(
|
|
332
343
|
composite,
|
|
@@ -348,7 +359,7 @@ def rotation_scan(
|
|
|
348
359
|
md={
|
|
349
360
|
"subplan_name": CONST.PLAN.ROTATION_OUTER,
|
|
350
361
|
CONST.TRIGGER.ZOCALO: CONST.PLAN.ROTATION_MAIN,
|
|
351
|
-
"zocalo_environment":
|
|
362
|
+
"zocalo_environment": CONST.ZOCALO_ENV,
|
|
352
363
|
"hyperion_parameters": parameters.model_dump_json(),
|
|
353
364
|
"activate_callbacks": [
|
|
354
365
|
"RotationISPyBCallback",
|
|
@@ -379,7 +390,7 @@ def rotation_scan(
|
|
|
379
390
|
rotation_with_cleanup_and_stage(params),
|
|
380
391
|
group=CONST.WAIT.ROTATION_READY_FOR_DC,
|
|
381
392
|
)
|
|
382
|
-
yield from bps.unstage(eiger)
|
|
393
|
+
yield from bps.unstage(eiger) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
383
394
|
|
|
384
395
|
yield from rotation_scan_plan_with_stage_and_cleanup(parameters)
|
|
385
396
|
|
|
@@ -407,6 +418,11 @@ def multi_rotation_scan(
|
|
|
407
418
|
}
|
|
408
419
|
)
|
|
409
420
|
@bpp.stage_decorator([eiger])
|
|
421
|
+
@transmission_and_xbpm_feedback_for_collection_decorator(
|
|
422
|
+
composite.xbpm_feedback,
|
|
423
|
+
composite.attenuator,
|
|
424
|
+
parameters.transmission_frac,
|
|
425
|
+
)
|
|
410
426
|
@bpp.finalize_decorator(lambda: _cleanup_plan(composite))
|
|
411
427
|
def _multi_rotation_scan():
|
|
412
428
|
for single_scan in parameters.single_rotation_scans:
|
|
@@ -416,6 +432,7 @@ def multi_rotation_scan(
|
|
|
416
432
|
md={
|
|
417
433
|
"subplan_name": CONST.PLAN.ROTATION_OUTER,
|
|
418
434
|
CONST.TRIGGER.ZOCALO: CONST.PLAN.ROTATION_MAIN,
|
|
435
|
+
"zocalo_environment": CONST.ZOCALO_ENV,
|
|
419
436
|
"hyperion_parameters": single_scan.model_dump_json(),
|
|
420
437
|
}
|
|
421
438
|
)
|
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
* reenable feedback
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
|
|
8
|
+
import pydantic
|
|
10
9
|
from bluesky import plan_stubs as bps
|
|
11
10
|
from dodal.devices.attenuator import Attenuator
|
|
12
11
|
from dodal.devices.dcm import DCM
|
|
13
|
-
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes,
|
|
12
|
+
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
14
13
|
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
15
14
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
16
15
|
|
|
@@ -24,10 +23,10 @@ DESIRED_TRANSMISSION_FRACTION = 0.1
|
|
|
24
23
|
UNDULATOR_GROUP = "UNDULATOR_GROUP"
|
|
25
24
|
|
|
26
25
|
|
|
27
|
-
@dataclasses.dataclass
|
|
26
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
28
27
|
class SetEnergyComposite:
|
|
29
28
|
vfm: FocusingMirrorWithStripes
|
|
30
|
-
|
|
29
|
+
mirror_voltages: MirrorVoltages
|
|
31
30
|
dcm: DCM
|
|
32
31
|
undulator_dcm: UndulatorDCM
|
|
33
32
|
xbpm_feedback: XBPMFeedback
|
|
@@ -42,7 +41,7 @@ def _set_energy_plan(
|
|
|
42
41
|
yield from dcm_pitch_roll_mirror_adjuster.adjust_dcm_pitch_roll_vfm_from_lut(
|
|
43
42
|
composite.undulator_dcm,
|
|
44
43
|
composite.vfm,
|
|
45
|
-
composite.
|
|
44
|
+
composite.mirror_voltages,
|
|
46
45
|
energy_kev,
|
|
47
46
|
)
|
|
48
47
|
yield from bps.wait(group=UNDULATOR_GROUP)
|
|
@@ -7,6 +7,7 @@ from bluesky.callbacks.zmq import Proxy, RemoteDispatcher
|
|
|
7
7
|
from dodal.log import LOGGER as dodal_logger
|
|
8
8
|
from dodal.log import set_up_all_logging_handlers
|
|
9
9
|
|
|
10
|
+
from mx_bluesky.common.utils.log import _get_logging_dir, tag_filter
|
|
10
11
|
from mx_bluesky.hyperion.external_interaction.callbacks.log_uid_tag_callback import (
|
|
11
12
|
LogUidTaggingCallback,
|
|
12
13
|
)
|
|
@@ -31,8 +32,6 @@ from mx_bluesky.hyperion.external_interaction.callbacks.zocalo_callback import (
|
|
|
31
32
|
from mx_bluesky.hyperion.log import (
|
|
32
33
|
ISPYB_LOGGER,
|
|
33
34
|
NEXUS_LOGGER,
|
|
34
|
-
_get_logging_dir,
|
|
35
|
-
tag_filter,
|
|
36
35
|
)
|
|
37
36
|
from mx_bluesky.hyperion.parameters.cli import parse_callback_dev_mode_arg
|
|
38
37
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import builtins
|
|
2
|
+
import dataclasses
|
|
3
|
+
import time
|
|
4
|
+
from abc import ABC
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from bluesky.protocols import Readable, Reading
|
|
8
|
+
from event_model import DataKey
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclasses.dataclass(frozen=True)
|
|
12
|
+
class AbstractEvent(Readable, ABC):
|
|
13
|
+
"""An abstract superclass that can be extended to provide lightweight software events
|
|
14
|
+
for bluesky plans, without having to incur the overhead of creating ophyd-async devices
|
|
15
|
+
specifically for the purpose.
|
|
16
|
+
|
|
17
|
+
The currently supported types for field annotations in the event are ``str``, ``int``, ``float``, ``bool``
|
|
18
|
+
|
|
19
|
+
In future array types may be supported.
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
Subclasses should extend this class and decorate with::
|
|
23
|
+
|
|
24
|
+
@dataclasses.dataclass(frozen=True)
|
|
25
|
+
|
|
26
|
+
To raise an event, simply construct the event and then ``read`` it as you would a device::
|
|
27
|
+
|
|
28
|
+
yield from bps.create("MY_EVENT_NAME")
|
|
29
|
+
my_event = MyEvent(an_int=1)
|
|
30
|
+
yield from bps.read(my_event)
|
|
31
|
+
yield from bps.save()
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def read(self) -> dict[str, Reading]:
|
|
35
|
+
return {
|
|
36
|
+
f.name: AbstractEvent._reading_from_value(getattr(self, f.name))
|
|
37
|
+
for f in dataclasses.fields(self)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
def describe(self) -> dict[str, DataKey]:
|
|
41
|
+
return {
|
|
42
|
+
f.name: DataKey(dtype=AbstractEvent._dtype_of(f.type), shape=[], source="")
|
|
43
|
+
for f in dataclasses.fields(self)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def _reading_from_value(cls, value):
|
|
48
|
+
return Reading(timestamp=time.time(), value=value)
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def _dtype_of(cls, t) -> Literal["string", "number", "boolean", "integer"]:
|
|
52
|
+
match t:
|
|
53
|
+
case builtins.str:
|
|
54
|
+
return "string"
|
|
55
|
+
case builtins.bool:
|
|
56
|
+
return "boolean"
|
|
57
|
+
case builtins.int:
|
|
58
|
+
return "integer"
|
|
59
|
+
case builtins.float:
|
|
60
|
+
return "number"
|
|
61
|
+
# TODO array support
|
|
62
|
+
raise ValueError(f"Unsupported type for AbstractEvent: {t}")
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def name(self) -> str:
|
|
66
|
+
return type(self).__name__
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
|
|
3
4
|
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
|
|
4
5
|
DataCollectionGroupInfo,
|
|
5
6
|
DataCollectionInfo,
|
|
@@ -11,7 +12,6 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
|
|
|
11
12
|
from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_utils import (
|
|
12
13
|
get_current_time_string,
|
|
13
14
|
)
|
|
14
|
-
from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def populate_data_collection_group(params: DiffractionExperimentWithSample):
|
|
@@ -2,7 +2,6 @@ from typing import TypedDict
|
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from bluesky.callbacks import CallbackBase
|
|
5
|
-
from dodal.devices.oav.oav_detector import OAVConfigParams
|
|
6
5
|
from dodal.devices.oav.utils import calculate_x_y_z_of_pixel
|
|
7
6
|
from event_model.documents import Event
|
|
8
7
|
|
|
@@ -26,21 +25,19 @@ class GridParamUpdate(TypedDict):
|
|
|
26
25
|
class GridDetectionCallback(CallbackBase):
|
|
27
26
|
def __init__(
|
|
28
27
|
self,
|
|
29
|
-
oav_params: OAVConfigParams,
|
|
30
28
|
*args,
|
|
31
29
|
) -> None:
|
|
32
30
|
super().__init__(*args)
|
|
33
|
-
self.
|
|
34
|
-
self.start_positions: list = []
|
|
31
|
+
self.start_positions_mm: list = []
|
|
35
32
|
self.box_numbers: list = []
|
|
36
33
|
|
|
37
34
|
def event(self, doc: Event):
|
|
38
35
|
data = doc.get("data")
|
|
39
|
-
top_left_x_px = data["
|
|
40
|
-
box_width_px = data["
|
|
36
|
+
top_left_x_px = data["oav-grid_snapshot-top_left_x"]
|
|
37
|
+
box_width_px = data["oav-grid_snapshot-box_width"]
|
|
41
38
|
x_of_centre_of_first_box_px = top_left_x_px + box_width_px / 2
|
|
42
39
|
|
|
43
|
-
top_left_y_px = data["
|
|
40
|
+
top_left_y_px = data["oav-grid_snapshot-top_left_y"]
|
|
44
41
|
y_of_centre_of_first_box_px = top_left_y_px + box_width_px / 2
|
|
45
42
|
|
|
46
43
|
smargon_omega = data["smargon-omega"]
|
|
@@ -53,36 +50,44 @@ class GridDetectionCallback(CallbackBase):
|
|
|
53
50
|
y_of_centre_of_first_box_px,
|
|
54
51
|
)
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
microns_per_pixel_x = data["oav-microns_per_pixel_x"]
|
|
54
|
+
microns_per_pixel_y = data["oav-microns_per_pixel_y"]
|
|
55
|
+
beam_x = data["oav-beam_centre_i"]
|
|
56
|
+
beam_y = data["oav-beam_centre_j"]
|
|
59
57
|
|
|
60
|
-
|
|
58
|
+
position_grid_start_mm = calculate_x_y_z_of_pixel(
|
|
59
|
+
current_xyz,
|
|
60
|
+
smargon_omega,
|
|
61
|
+
centre_of_first_box,
|
|
62
|
+
(beam_x, beam_y),
|
|
63
|
+
(microns_per_pixel_x, microns_per_pixel_y),
|
|
64
|
+
)
|
|
65
|
+
LOGGER.info(f"Calculated start position {position_grid_start_mm}")
|
|
61
66
|
|
|
62
|
-
self.
|
|
67
|
+
self.start_positions_mm.append(position_grid_start_mm)
|
|
63
68
|
self.box_numbers.append(
|
|
64
69
|
(
|
|
65
|
-
data["
|
|
66
|
-
data["
|
|
70
|
+
data["oav-grid_snapshot-num_boxes_x"],
|
|
71
|
+
data["oav-grid_snapshot-num_boxes_y"],
|
|
67
72
|
)
|
|
68
73
|
)
|
|
69
74
|
|
|
70
|
-
self.
|
|
71
|
-
self.
|
|
72
|
-
self.
|
|
75
|
+
self.x_step_size_um = box_width_px * microns_per_pixel_x
|
|
76
|
+
self.y_step_size_um = box_width_px * microns_per_pixel_y
|
|
77
|
+
self.z_step_size_um = box_width_px * microns_per_pixel_y
|
|
73
78
|
return doc
|
|
74
79
|
|
|
75
80
|
def get_grid_parameters(self) -> GridParamUpdate:
|
|
76
81
|
return {
|
|
77
|
-
"x_start_um": self.
|
|
78
|
-
"y_start_um": self.
|
|
79
|
-
"y2_start_um": self.
|
|
80
|
-
"z_start_um": self.
|
|
81
|
-
"z2_start_um": self.
|
|
82
|
+
"x_start_um": self.start_positions_mm[0][0] * 1000,
|
|
83
|
+
"y_start_um": self.start_positions_mm[0][1] * 1000,
|
|
84
|
+
"y2_start_um": self.start_positions_mm[0][1] * 1000,
|
|
85
|
+
"z_start_um": self.start_positions_mm[1][2] * 1000,
|
|
86
|
+
"z2_start_um": self.start_positions_mm[1][2] * 1000,
|
|
82
87
|
"x_steps": self.box_numbers[0][0],
|
|
83
88
|
"y_steps": self.box_numbers[0][1],
|
|
84
89
|
"z_steps": self.box_numbers[1][1],
|
|
85
|
-
"x_step_size_um": self.
|
|
86
|
-
"y_step_size_um": self.
|
|
87
|
-
"z_step_size_um": self.
|
|
90
|
+
"x_step_size_um": self.x_step_size_um,
|
|
91
|
+
"y_step_size_um": self.y_step_size_um,
|
|
92
|
+
"z_step_size_um": self.z_step_size_um,
|
|
88
93
|
}
|
|
@@ -5,9 +5,12 @@ from collections.abc import Callable, Sequence
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any, TypeVar, cast
|
|
6
6
|
|
|
7
7
|
from dodal.beamline_specific_utils.i03 import beam_size_from_aperture
|
|
8
|
+
from dodal.devices.detector import DetectorParams
|
|
8
9
|
from dodal.devices.detector.det_resolution import resolution
|
|
9
10
|
from dodal.devices.synchrotron import SynchrotronMode
|
|
10
11
|
|
|
12
|
+
from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
|
|
13
|
+
from mx_bluesky.common.utils.log import set_dcgid_tag
|
|
11
14
|
from mx_bluesky.hyperion.external_interaction.callbacks.plan_reactive_callback import (
|
|
12
15
|
PlanReactiveCallback,
|
|
13
16
|
)
|
|
@@ -21,8 +24,7 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
|
|
|
21
24
|
StoreInIspyb,
|
|
22
25
|
)
|
|
23
26
|
from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_utils import get_ispyb_config
|
|
24
|
-
from mx_bluesky.hyperion.log import ISPYB_LOGGER
|
|
25
|
-
from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
|
|
27
|
+
from mx_bluesky.hyperion.log import ISPYB_LOGGER
|
|
26
28
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
27
29
|
from mx_bluesky.hyperion.utils.utils import convert_eV_to_angstrom
|
|
28
30
|
|
|
@@ -33,6 +35,25 @@ if TYPE_CHECKING:
|
|
|
33
35
|
from event_model.documents import Event, EventDescriptor, RunStart, RunStop
|
|
34
36
|
|
|
35
37
|
|
|
38
|
+
def _update_based_on_energy(
|
|
39
|
+
doc: Event,
|
|
40
|
+
detector_params: DetectorParams,
|
|
41
|
+
data_collection_info: DataCollectionInfo,
|
|
42
|
+
):
|
|
43
|
+
"""If energy has been read as part of this reading then add it into the data
|
|
44
|
+
collection info along with the other fields that depend on it."""
|
|
45
|
+
if energy_kev := doc["data"].get("dcm-energy_in_kev", None):
|
|
46
|
+
energy_ev = energy_kev * 1000
|
|
47
|
+
wavelength_angstroms = convert_eV_to_angstrom(energy_ev)
|
|
48
|
+
data_collection_info.wavelength = wavelength_angstroms
|
|
49
|
+
data_collection_info.resolution = resolution(
|
|
50
|
+
detector_params,
|
|
51
|
+
wavelength_angstroms,
|
|
52
|
+
detector_params.detector_distance,
|
|
53
|
+
)
|
|
54
|
+
return data_collection_info
|
|
55
|
+
|
|
56
|
+
|
|
36
57
|
class BaseISPyBCallback(PlanReactiveCallback):
|
|
37
58
|
def __init__(
|
|
38
59
|
self,
|
|
@@ -109,6 +130,9 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
109
130
|
slitgap_horizontal=doc["data"]["s4_slit_gaps_xgap"],
|
|
110
131
|
slitgap_vertical=doc["data"]["s4_slit_gaps_ygap"],
|
|
111
132
|
)
|
|
133
|
+
hwscan_data_collection_info = _update_based_on_energy(
|
|
134
|
+
doc, self.params.detector_params, hwscan_data_collection_info
|
|
135
|
+
)
|
|
112
136
|
hwscan_position_info = DataCollectionPositionInfo(
|
|
113
137
|
pos_x=float(doc["data"]["smargon-x"]),
|
|
114
138
|
pos_y=float(doc["data"]["smargon-y"]),
|
|
@@ -137,16 +161,9 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
137
161
|
if transmission := doc["data"]["attenuator-actual_transmission"]:
|
|
138
162
|
# Ispyb wants the transmission in a percentage, we use fractions
|
|
139
163
|
hwscan_data_collection_info.transmission = transmission * 100
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
wavelength_angstroms = convert_eV_to_angstrom(energy_ev)
|
|
144
|
-
hwscan_data_collection_info.wavelength = wavelength_angstroms
|
|
145
|
-
hwscan_data_collection_info.resolution = resolution(
|
|
146
|
-
self.params.detector_params,
|
|
147
|
-
wavelength_angstroms,
|
|
148
|
-
self.params.detector_params.detector_distance,
|
|
149
|
-
)
|
|
164
|
+
hwscan_data_collection_info = _update_based_on_energy(
|
|
165
|
+
doc, self.params.detector_params, hwscan_data_collection_info
|
|
166
|
+
)
|
|
150
167
|
scan_data_infos = self.populate_info_for_update(
|
|
151
168
|
hwscan_data_collection_info, None, self.params
|
|
152
169
|
)
|
|
@@ -62,7 +62,7 @@ class RobotLoadISPyBCallback(PlanReactiveCallback):
|
|
|
62
62
|
self.action_id is not None
|
|
63
63
|
), "ISPyB Robot load callback event called unexpectedly"
|
|
64
64
|
barcode = doc["data"]["robot-barcode"]
|
|
65
|
-
oav_snapshot = doc["data"]["
|
|
65
|
+
oav_snapshot = doc["data"]["oav-snapshot-last_saved_path"]
|
|
66
66
|
webcam_snapshot = doc["data"]["webcam-last_saved_path"]
|
|
67
67
|
# I03 uses webcam/oav snapshots in place of before/after snapshots
|
|
68
68
|
self.expeye.update_barcode_and_snapshots(
|
|
@@ -3,6 +3,8 @@ 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.parameters.components import IspybExperimentType
|
|
7
|
+
from mx_bluesky.common.utils.log import set_dcgid_tag
|
|
6
8
|
from mx_bluesky.hyperion.external_interaction.callbacks.common.ispyb_mapping import (
|
|
7
9
|
populate_data_collection_group,
|
|
8
10
|
populate_remaining_data_collection_info,
|
|
@@ -22,8 +24,7 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
|
|
|
22
24
|
IspybIds,
|
|
23
25
|
StoreInIspyb,
|
|
24
26
|
)
|
|
25
|
-
from mx_bluesky.hyperion.log import ISPYB_LOGGER
|
|
26
|
-
from mx_bluesky.hyperion.parameters.components import IspybExperimentType
|
|
27
|
+
from mx_bluesky.hyperion.log import ISPYB_LOGGER
|
|
27
28
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
28
29
|
from mx_bluesky.hyperion.parameters.rotation import RotationScan
|
|
29
30
|
|
|
@@ -60,7 +61,9 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
60
61
|
ISPYB_LOGGER.info(
|
|
61
62
|
"ISPyB callback received start document with experiment parameters."
|
|
62
63
|
)
|
|
63
|
-
|
|
64
|
+
hyperion_params = doc.get("hyperion_parameters")
|
|
65
|
+
assert isinstance(hyperion_params, str)
|
|
66
|
+
self.params = RotationScan.model_validate_json(hyperion_params)
|
|
64
67
|
dcgid = (
|
|
65
68
|
self.ispyb_ids.data_collection_group_id
|
|
66
69
|
if (self.params.sample_id == self.last_sample_id)
|
|
@@ -157,7 +160,7 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
157
160
|
data_collection_info = DataCollectionInfo(
|
|
158
161
|
**{
|
|
159
162
|
f"xtal_snapshot{self._oav_snapshot_event_idx}": data.get(
|
|
160
|
-
"
|
|
163
|
+
"oav-snapshot-last_saved_path"
|
|
161
164
|
)
|
|
162
165
|
}
|
|
163
166
|
)
|
|
@@ -78,12 +78,14 @@ class RotationNexusFileCallback(PlanReactiveCallback):
|
|
|
78
78
|
self.meta_data_run_number = doc.get("meta_data_run_number")
|
|
79
79
|
if doc.get("subplan_name") == CONST.PLAN.ROTATION_OUTER:
|
|
80
80
|
self.run_uid = doc.get("uid")
|
|
81
|
-
|
|
81
|
+
hyperion_params = doc.get("hyperion_parameters")
|
|
82
|
+
assert isinstance(hyperion_params, str)
|
|
82
83
|
NEXUS_LOGGER.info(
|
|
83
|
-
f"Nexus writer received start document with experiment parameters {
|
|
84
|
+
f"Nexus writer received start document with experiment parameters {hyperion_params}"
|
|
84
85
|
)
|
|
85
|
-
parameters = RotationScan.
|
|
86
|
+
parameters = RotationScan.model_validate_json(hyperion_params)
|
|
86
87
|
NEXUS_LOGGER.info("Setting up nexus file...")
|
|
88
|
+
|
|
87
89
|
det_size = (
|
|
88
90
|
parameters.detector_params.detector_size_constants.det_size_pixels
|
|
89
91
|
)
|