mx-bluesky 1.4.6__py3-none-any.whl → 1.4.8__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/aithre_lasershaping/__init__.py +13 -0
- mx_bluesky/beamlines/aithre_lasershaping/check_goniometer_performance.py +29 -0
- mx_bluesky/beamlines/aithre_lasershaping/goniometer_controls.py +18 -0
- mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +35 -29
- mx_bluesky/beamlines/i04/thawing_plan.py +18 -3
- mx_bluesky/beamlines/i23/__init__.py +3 -0
- mx_bluesky/beamlines/i23/serial.py +71 -0
- mx_bluesky/beamlines/i24/serial/__init__.py +2 -0
- mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +12 -12
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +36 -30
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +3 -3
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +15 -66
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +8 -10
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +10 -3
- mx_bluesky/beamlines/i24/serial/log.py +9 -9
- mx_bluesky/beamlines/i24/serial/parameters/utils.py +36 -7
- mx_bluesky/beamlines/i24/serial/set_visit_directory.sh +1 -1
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +16 -17
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv_abstract.py +4 -4
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +51 -52
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +3 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +9 -7
- mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +71 -11
- mx_bluesky/beamlines/i24/serial/write_nexus.py +6 -5
- mx_bluesky/{hyperion → common}/device_setup_plans/check_beamstop.py +1 -1
- mx_bluesky/{hyperion → common}/device_setup_plans/manipulate_sample.py +1 -1
- mx_bluesky/{hyperion → common}/device_setup_plans/setup_oav.py +12 -6
- mx_bluesky/common/device_setup_plans/xbpm_feedback.py +45 -0
- mx_bluesky/{hyperion → common}/experiment_plans/change_aperture_then_move_plan.py +13 -29
- mx_bluesky/{hyperion → common}/experiment_plans/oav_grid_detection_plan.py +6 -6
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +8 -9
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_mapping.py +1 -1
- mx_bluesky/common/external_interaction/callbacks/common/zocalo_callback.py +18 -15
- mx_bluesky/{hyperion → common}/external_interaction/callbacks/sample_handling/sample_handling_callback.py +16 -4
- mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +50 -45
- mx_bluesky/common/external_interaction/callbacks/xray_centre/nexus_callback.py +2 -1
- mx_bluesky/common/external_interaction/ispyb/data_model.py +1 -0
- mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +18 -2
- mx_bluesky/common/external_interaction/ispyb/ispyb_utils.py +4 -4
- mx_bluesky/common/external_interaction/nexus/nexus_utils.py +1 -1
- mx_bluesky/common/parameters/components.py +22 -2
- mx_bluesky/common/parameters/constants.py +6 -16
- mx_bluesky/common/parameters/gridscan.py +36 -32
- mx_bluesky/common/plans/common_flyscan_xray_centre_plan.py +316 -0
- mx_bluesky/common/plans/inner_plans/__init__ .py +0 -0
- mx_bluesky/common/plans/read_hardware.py +3 -3
- mx_bluesky/common/plans/write_sample_status.py +46 -0
- mx_bluesky/common/preprocessors/__init__.py +0 -0
- mx_bluesky/common/preprocessors/preprocessors.py +105 -0
- mx_bluesky/common/protocols/__init__.py +0 -0
- mx_bluesky/common/protocols/protocols.py +10 -0
- mx_bluesky/common/utils/log.py +15 -12
- mx_bluesky/hyperion/__main__.py +5 -24
- mx_bluesky/hyperion/baton_handler.py +84 -0
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +4 -4
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +5 -1
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +0 -33
- mx_bluesky/hyperion/device_setup_plans/utils.py +4 -4
- mx_bluesky/hyperion/experiment_plans/__init__.py +0 -10
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +0 -16
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +71 -88
- mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +183 -0
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +17 -8
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +29 -8
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +4 -4
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +6 -4
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +11 -3
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +9 -34
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +35 -68
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +27 -8
- mx_bluesky/hyperion/external_interaction/agamemnon.py +140 -10
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +17 -9
- mx_bluesky/hyperion/external_interaction/callbacks/snapshot_callback.py +259 -0
- mx_bluesky/hyperion/parameters/cli.py +2 -10
- mx_bluesky/hyperion/parameters/constants.py +0 -5
- mx_bluesky/hyperion/parameters/device_composites.py +40 -5
- mx_bluesky/hyperion/parameters/gridscan.py +9 -58
- mx_bluesky/hyperion/parameters/rotation.py +1 -5
- mx_bluesky/hyperion/utils/context.py +2 -5
- mx_bluesky/hyperion/utils/validation.py +13 -10
- {mx_bluesky-1.4.6.dist-info → mx_bluesky-1.4.8.dist-info}/METADATA +10 -9
- {mx_bluesky-1.4.6.dist-info → mx_bluesky-1.4.8.dist-info}/RECORD +92 -79
- {mx_bluesky-1.4.6.dist-info → mx_bluesky-1.4.8.dist-info}/WHEEL +1 -1
- mx_bluesky/common/external_interaction/callbacks/common/aperture_change_callback.py +0 -22
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +0 -103
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +0 -466
- /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short1-laser.png → s1l.png} +0 -0
- /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short2-laser.png → s2l.png} +0 -0
- /mx_bluesky/{hyperion → common}/device_setup_plans/position_detector.py +0 -0
- /mx_bluesky/{hyperion → common}/external_interaction/callbacks/sample_handling/__init__.py +0 -0
- /mx_bluesky/common/plans/{do_fgs.py → inner_plans/do_fgs.py} +0 -0
- {mx_bluesky-1.4.6.dist-info → mx_bluesky-1.4.8.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.4.6.dist-info → mx_bluesky-1.4.8.dist-info/licenses}/LICENSE +0 -0
- {mx_bluesky-1.4.6.dist-info → mx_bluesky-1.4.8.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
from math import isclose
|
|
4
4
|
from typing import cast
|
|
5
5
|
|
|
6
|
-
import bluesky.preprocessors as bpp
|
|
7
6
|
import pydantic
|
|
8
7
|
from blueapi.core import BlueskyContext
|
|
9
8
|
from bluesky import plan_stubs as bps
|
|
@@ -11,13 +10,14 @@ from bluesky.utils import MsgGenerator
|
|
|
11
10
|
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
12
11
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
13
12
|
from dodal.devices.backlight import Backlight
|
|
14
|
-
from dodal.devices.dcm import DCM
|
|
15
13
|
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
16
14
|
from dodal.devices.eiger import EigerDetector
|
|
17
15
|
from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScan
|
|
18
16
|
from dodal.devices.flux import Flux
|
|
19
17
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
20
|
-
from dodal.devices.i03
|
|
18
|
+
from dodal.devices.i03 import Beamstop
|
|
19
|
+
from dodal.devices.i03.dcm import DCM
|
|
20
|
+
from dodal.devices.i03.undulator_dcm import UndulatorDCM
|
|
21
21
|
from dodal.devices.motors import XYZPositioner
|
|
22
22
|
from dodal.devices.oav.oav_detector import OAV
|
|
23
23
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
@@ -27,7 +27,6 @@ from dodal.devices.smargon import Smargon
|
|
|
27
27
|
from dodal.devices.synchrotron import Synchrotron
|
|
28
28
|
from dodal.devices.thawer import Thawer
|
|
29
29
|
from dodal.devices.undulator import Undulator
|
|
30
|
-
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
31
30
|
from dodal.devices.webcam import Webcam
|
|
32
31
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
33
32
|
from dodal.devices.zebra.zebra import Zebra
|
|
@@ -37,14 +36,10 @@ from dodal.log import LOGGER
|
|
|
37
36
|
from ophyd_async.fastcs.panda import HDFPanda
|
|
38
37
|
|
|
39
38
|
from mx_bluesky.common.parameters.constants import OavConstants
|
|
40
|
-
from mx_bluesky.common.xrc_result import XRayCentreEventHandler
|
|
41
39
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
42
40
|
fill_in_energy_if_not_supplied,
|
|
43
41
|
start_preparing_data_collection_then_do_plan,
|
|
44
42
|
)
|
|
45
|
-
from mx_bluesky.hyperion.experiment_plans.change_aperture_then_move_plan import (
|
|
46
|
-
change_aperture_then_move_to_xtal,
|
|
47
|
-
)
|
|
48
43
|
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
49
44
|
GridDetectThenXRayCentreComposite,
|
|
50
45
|
)
|
|
@@ -117,6 +112,7 @@ def _flyscan_plan_from_robot_load_params(
|
|
|
117
112
|
yield from pin_centre_then_flyscan_plan(
|
|
118
113
|
cast(GridDetectThenXRayCentreComposite, composite),
|
|
119
114
|
params.pin_centre_then_xray_centre_params,
|
|
115
|
+
oav_config_file,
|
|
120
116
|
)
|
|
121
117
|
|
|
122
118
|
|
|
@@ -133,30 +129,10 @@ def _robot_load_then_flyscan_plan(
|
|
|
133
129
|
yield from _flyscan_plan_from_robot_load_params(composite, params, oav_config_file)
|
|
134
130
|
|
|
135
131
|
|
|
136
|
-
def robot_load_then_centre(
|
|
137
|
-
composite: RobotLoadThenCentreComposite,
|
|
138
|
-
parameters: RobotLoadThenCentre,
|
|
139
|
-
) -> MsgGenerator:
|
|
140
|
-
"""Perform pin-tip detection followed by a flyscan to determine centres of interest.
|
|
141
|
-
Performs a robot load if necessary. Centre on the best diffracting centre.
|
|
142
|
-
"""
|
|
143
|
-
|
|
144
|
-
xray_centre_event_handler = XRayCentreEventHandler()
|
|
145
|
-
|
|
146
|
-
yield from bpp.subs_wrapper(
|
|
147
|
-
robot_load_then_xray_centre(composite, parameters), xray_centre_event_handler
|
|
148
|
-
)
|
|
149
|
-
flyscan_results = xray_centre_event_handler.xray_centre_results
|
|
150
|
-
if flyscan_results is not None:
|
|
151
|
-
yield from change_aperture_then_move_to_xtal(
|
|
152
|
-
flyscan_results[0], composite.smargon, composite.aperture_scatterguard
|
|
153
|
-
)
|
|
154
|
-
# else no chi change, no need to recentre.
|
|
155
|
-
|
|
156
|
-
|
|
157
132
|
def robot_load_then_xray_centre(
|
|
158
133
|
composite: RobotLoadThenCentreComposite,
|
|
159
134
|
parameters: RobotLoadThenCentre,
|
|
135
|
+
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
160
136
|
) -> MsgGenerator:
|
|
161
137
|
"""Perform pin-tip detection followed by a flyscan to determine centres of interest.
|
|
162
138
|
Performs a robot load if necessary."""
|
|
@@ -180,10 +156,7 @@ def robot_load_then_xray_centre(
|
|
|
180
156
|
|
|
181
157
|
if doing_sample_load:
|
|
182
158
|
LOGGER.info("Pin not loaded, loading and centring")
|
|
183
|
-
plan = _robot_load_then_flyscan_plan(
|
|
184
|
-
composite,
|
|
185
|
-
parameters,
|
|
186
|
-
)
|
|
159
|
+
plan = _robot_load_then_flyscan_plan(composite, parameters, oav_config_file)
|
|
187
160
|
else:
|
|
188
161
|
# Robot load normally sets the energy so we should do this explicitly if no load is
|
|
189
162
|
# being done
|
|
@@ -194,7 +167,9 @@ def robot_load_then_xray_centre(
|
|
|
194
167
|
)
|
|
195
168
|
|
|
196
169
|
if doing_chi_change:
|
|
197
|
-
plan = _flyscan_plan_from_robot_load_params(
|
|
170
|
+
plan = _flyscan_plan_from_robot_load_params(
|
|
171
|
+
composite, parameters, oav_config_file
|
|
172
|
+
)
|
|
198
173
|
LOGGER.info("Pin already loaded but chi changed so centring")
|
|
199
174
|
else:
|
|
200
175
|
LOGGER.info("Pin already loaded and chi not changed so doing nothing")
|
|
@@ -10,11 +10,11 @@ from bluesky.utils import MsgGenerator
|
|
|
10
10
|
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
11
11
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
12
12
|
from dodal.devices.backlight import Backlight
|
|
13
|
-
from dodal.devices.dcm import DCM
|
|
14
13
|
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
15
14
|
from dodal.devices.eiger import EigerDetector
|
|
16
15
|
from dodal.devices.flux import Flux
|
|
17
|
-
from dodal.devices.i03
|
|
16
|
+
from dodal.devices.i03 import Beamstop
|
|
17
|
+
from dodal.devices.i03.dcm import DCM
|
|
18
18
|
from dodal.devices.oav.oav_detector import OAV
|
|
19
19
|
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
20
20
|
from dodal.devices.robot import BartRobot
|
|
@@ -26,20 +26,27 @@ from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
|
26
26
|
from dodal.devices.zebra.zebra import RotationDirection, Zebra
|
|
27
27
|
from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
|
|
28
28
|
from dodal.plan_stubs.check_topup import check_topup_and_wait_if_necessary
|
|
29
|
+
from dodal.plans.preprocessors.verify_undulator_gap import (
|
|
30
|
+
verify_undulator_gap_before_run_decorator,
|
|
31
|
+
)
|
|
29
32
|
|
|
33
|
+
from mx_bluesky.common.device_setup_plans.manipulate_sample import (
|
|
34
|
+
cleanup_sample_environment,
|
|
35
|
+
move_phi_chi_omega,
|
|
36
|
+
move_x_y_z,
|
|
37
|
+
setup_sample_environment,
|
|
38
|
+
)
|
|
39
|
+
from mx_bluesky.common.parameters.components import WithSnapshot
|
|
30
40
|
from mx_bluesky.common.plans.read_hardware import (
|
|
31
41
|
read_hardware_for_zocalo,
|
|
32
42
|
standard_read_hardware_during_collection,
|
|
33
43
|
standard_read_hardware_pre_collection,
|
|
34
44
|
)
|
|
45
|
+
from mx_bluesky.common.preprocessors.preprocessors import (
|
|
46
|
+
transmission_and_xbpm_feedback_for_collection_decorator,
|
|
47
|
+
)
|
|
35
48
|
from mx_bluesky.common.utils.context import device_composite_from_context
|
|
36
49
|
from mx_bluesky.common.utils.log import LOGGER
|
|
37
|
-
from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import (
|
|
38
|
-
cleanup_sample_environment,
|
|
39
|
-
move_phi_chi_omega,
|
|
40
|
-
move_x_y_z,
|
|
41
|
-
setup_sample_environment,
|
|
42
|
-
)
|
|
43
50
|
from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
|
|
44
51
|
arm_zebra,
|
|
45
52
|
setup_zebra_for_rotation,
|
|
@@ -48,9 +55,6 @@ from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
|
|
|
48
55
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
49
56
|
start_preparing_data_collection_then_do_plan,
|
|
50
57
|
)
|
|
51
|
-
from mx_bluesky.hyperion.device_setup_plans.xbpm_feedback import (
|
|
52
|
-
transmission_and_xbpm_feedback_for_collection_decorator,
|
|
53
|
-
)
|
|
54
58
|
from mx_bluesky.hyperion.experiment_plans.oav_snapshot_plan import (
|
|
55
59
|
OavSnapshotComposite,
|
|
56
60
|
oav_snapshot_plan,
|
|
@@ -352,66 +356,30 @@ def _move_and_rotation(
|
|
|
352
356
|
group=CONST.WAIT.ROTATION_READY_FOR_DC,
|
|
353
357
|
)
|
|
354
358
|
yield from oav_snapshot_plan(composite, params, oav_params)
|
|
355
|
-
yield from rotation_scan_plan(
|
|
356
|
-
composite,
|
|
357
|
-
params,
|
|
358
|
-
motion_values,
|
|
359
|
-
)
|
|
359
|
+
yield from rotation_scan_plan(composite, params, motion_values)
|
|
360
360
|
|
|
361
361
|
|
|
362
|
-
def
|
|
362
|
+
def multi_rotation_scan(
|
|
363
363
|
composite: RotationScanComposite,
|
|
364
|
-
parameters:
|
|
364
|
+
parameters: MultiRotationScan,
|
|
365
365
|
oav_params: OAVParameters | None = None,
|
|
366
366
|
) -> MsgGenerator:
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
if not oav_params:
|
|
370
|
-
oav_params = OAVParameters(context="xrayCentring")
|
|
371
|
-
|
|
372
|
-
@bpp.set_run_key_decorator("rotation_scan")
|
|
373
|
-
@bpp.run_decorator( # attach experiment metadata to the start document
|
|
367
|
+
@bpp.set_run_key_decorator(CONST.PLAN.ROTATION_MULTI_OUTER)
|
|
368
|
+
@bpp.run_decorator(
|
|
374
369
|
md={
|
|
375
|
-
"
|
|
376
|
-
"
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
"RotationNexusFileCallback",
|
|
380
|
-
],
|
|
370
|
+
"activate_callbacks": ["BeamDrawingCallback"],
|
|
371
|
+
"with_snapshot": parameters.model_dump_json(
|
|
372
|
+
include=WithSnapshot.model_fields.keys() # type: ignore
|
|
373
|
+
),
|
|
381
374
|
}
|
|
382
375
|
)
|
|
383
|
-
|
|
384
|
-
composite
|
|
385
|
-
composite.xbpm_feedback,
|
|
386
|
-
composite.attenuator,
|
|
387
|
-
composite.dcm,
|
|
388
|
-
parameters.transmission_frac,
|
|
389
|
-
)
|
|
390
|
-
def rotation_scan_plan_with_stage_and_cleanup(
|
|
391
|
-
params: RotationScan,
|
|
392
|
-
):
|
|
393
|
-
eiger: EigerDetector = composite.eiger
|
|
394
|
-
eiger.set_detector_parameters(params.detector_params)
|
|
395
|
-
|
|
396
|
-
@bpp.finalize_decorator(lambda: _cleanup_plan(composite))
|
|
397
|
-
def rotation_with_cleanup_and_stage(params: RotationScan):
|
|
398
|
-
yield from _move_and_rotation(composite, params, oav_params)
|
|
399
|
-
|
|
400
|
-
LOGGER.info("setting up and staging eiger...")
|
|
401
|
-
yield from start_preparing_data_collection_then_do_plan(
|
|
402
|
-
composite.beamstop,
|
|
403
|
-
eiger,
|
|
404
|
-
composite.detector_motion,
|
|
405
|
-
params.detector_distance_mm,
|
|
406
|
-
rotation_with_cleanup_and_stage(params),
|
|
407
|
-
group=CONST.WAIT.ROTATION_READY_FOR_DC,
|
|
408
|
-
)
|
|
409
|
-
yield from bps.unstage(eiger)
|
|
376
|
+
def _wrapped_multi_rotation_scan():
|
|
377
|
+
yield from multi_rotation_scan_internal(composite, parameters, oav_params)
|
|
410
378
|
|
|
411
|
-
yield from
|
|
379
|
+
yield from _wrapped_multi_rotation_scan()
|
|
412
380
|
|
|
413
381
|
|
|
414
|
-
def
|
|
382
|
+
def multi_rotation_scan_internal(
|
|
415
383
|
composite: RotationScanComposite,
|
|
416
384
|
parameters: MultiRotationScan,
|
|
417
385
|
oav_params: OAVParameters | None = None,
|
|
@@ -422,6 +390,10 @@ def multi_rotation_scan(
|
|
|
422
390
|
eiger: EigerDetector = composite.eiger
|
|
423
391
|
eiger.set_detector_parameters(parameters.detector_params)
|
|
424
392
|
|
|
393
|
+
@transmission_and_xbpm_feedback_for_collection_decorator(
|
|
394
|
+
composite,
|
|
395
|
+
parameters.transmission_frac,
|
|
396
|
+
)
|
|
425
397
|
@bpp.set_run_key_decorator("multi_rotation_scan")
|
|
426
398
|
@bpp.run_decorator(
|
|
427
399
|
md={
|
|
@@ -434,17 +406,11 @@ def multi_rotation_scan(
|
|
|
434
406
|
],
|
|
435
407
|
}
|
|
436
408
|
)
|
|
437
|
-
@transmission_and_xbpm_feedback_for_collection_decorator(
|
|
438
|
-
composite.undulator,
|
|
439
|
-
composite.xbpm_feedback,
|
|
440
|
-
composite.attenuator,
|
|
441
|
-
composite.dcm,
|
|
442
|
-
parameters.transmission_frac,
|
|
443
|
-
)
|
|
444
409
|
@bpp.finalize_decorator(lambda: _cleanup_plan(composite))
|
|
445
410
|
def _multi_rotation_scan():
|
|
446
411
|
for single_scan in parameters.single_rotation_scans:
|
|
447
412
|
|
|
413
|
+
@verify_undulator_gap_before_run_decorator(composite)
|
|
448
414
|
@bpp.set_run_key_decorator("rotation_scan")
|
|
449
415
|
@bpp.run_decorator( # attach experiment metadata to the start document
|
|
450
416
|
md={
|
|
@@ -459,6 +425,8 @@ def multi_rotation_scan(
|
|
|
459
425
|
|
|
460
426
|
yield from rotation_scan_core(single_scan)
|
|
461
427
|
|
|
428
|
+
yield from bps.unstage(eiger)
|
|
429
|
+
|
|
462
430
|
LOGGER.info("setting up and staging eiger...")
|
|
463
431
|
yield from start_preparing_data_collection_then_do_plan(
|
|
464
432
|
composite.beamstop,
|
|
@@ -468,4 +436,3 @@ def multi_rotation_scan(
|
|
|
468
436
|
_multi_rotation_scan(),
|
|
469
437
|
group=CONST.WAIT.ROTATION_READY_FOR_DC,
|
|
470
438
|
)
|
|
471
|
-
yield from bps.unstage(eiger)
|
|
@@ -5,18 +5,21 @@
|
|
|
5
5
|
* reenable feedback
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import bluesky.preprocessors as bpp
|
|
8
9
|
import pydantic
|
|
9
10
|
from bluesky import plan_stubs as bps
|
|
10
11
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
11
|
-
from dodal.devices.dcm import DCM
|
|
12
12
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
13
|
-
from dodal.devices.
|
|
13
|
+
from dodal.devices.i03.dcm import DCM
|
|
14
|
+
from dodal.devices.i03.undulator_dcm import UndulatorDCM
|
|
15
|
+
from dodal.devices.undulator import Undulator
|
|
14
16
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
15
17
|
|
|
16
|
-
from mx_bluesky.
|
|
17
|
-
from mx_bluesky.
|
|
18
|
+
from mx_bluesky.common.parameters.constants import PlanNameConstants
|
|
19
|
+
from mx_bluesky.common.preprocessors.preprocessors import (
|
|
18
20
|
transmission_and_xbpm_feedback_for_collection_wrapper,
|
|
19
21
|
)
|
|
22
|
+
from mx_bluesky.hyperion.device_setup_plans import dcm_pitch_roll_mirror_adjuster
|
|
20
23
|
|
|
21
24
|
DESIRED_TRANSMISSION_FRACTION = 0.1
|
|
22
25
|
|
|
@@ -33,6 +36,17 @@ class SetEnergyComposite:
|
|
|
33
36
|
attenuator: BinaryFilterAttenuator
|
|
34
37
|
|
|
35
38
|
|
|
39
|
+
# Remove composite after https://github.com/DiamondLightSource/dodal/issues/1092
|
|
40
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
41
|
+
class XBPMWrapperComposite:
|
|
42
|
+
undulator: Undulator
|
|
43
|
+
xbpm_feedback: XBPMFeedback
|
|
44
|
+
attenuator: BinaryFilterAttenuator
|
|
45
|
+
dcm: DCM
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@bpp.set_run_key_decorator(PlanNameConstants.SET_ENERGY)
|
|
49
|
+
@bpp.run_decorator()
|
|
36
50
|
def _set_energy_plan(
|
|
37
51
|
energy_kev,
|
|
38
52
|
composite: SetEnergyComposite,
|
|
@@ -51,12 +65,17 @@ def set_energy_plan(
|
|
|
51
65
|
energy_ev: float | None,
|
|
52
66
|
composite: SetEnergyComposite,
|
|
53
67
|
):
|
|
68
|
+
# Remove conversion after https://github.com/DiamondLightSource/dodal/issues/1092
|
|
69
|
+
composite_for_wrapper = XBPMWrapperComposite(
|
|
70
|
+
composite.undulator_dcm.undulator_ref._obj, # noqa: SLF001
|
|
71
|
+
composite.xbpm_feedback,
|
|
72
|
+
composite.attenuator,
|
|
73
|
+
composite.dcm,
|
|
74
|
+
)
|
|
75
|
+
|
|
54
76
|
if energy_ev:
|
|
55
77
|
yield from transmission_and_xbpm_feedback_for_collection_wrapper(
|
|
56
78
|
_set_energy_plan(energy_ev / 1000, composite),
|
|
57
|
-
|
|
58
|
-
composite.xbpm_feedback,
|
|
59
|
-
composite.attenuator,
|
|
60
|
-
composite.dcm,
|
|
79
|
+
composite_for_wrapper,
|
|
61
80
|
DESIRED_TRANSMISSION_FRACTION,
|
|
62
81
|
)
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import json
|
|
3
3
|
import re
|
|
4
|
-
|
|
4
|
+
import traceback
|
|
5
|
+
from os import path
|
|
6
|
+
from typing import Any, TypeVar
|
|
5
7
|
|
|
6
8
|
import requests
|
|
9
|
+
from deepdiff.diff import DeepDiff
|
|
7
10
|
from dodal.utils import get_beamline_name
|
|
8
|
-
|
|
9
|
-
from
|
|
10
|
-
|
|
11
|
+
from jsonschema import ValidationError
|
|
12
|
+
from pydantic_extra_types.semantic_version import SemanticVersion
|
|
13
|
+
|
|
14
|
+
from mx_bluesky.common.parameters.components import (
|
|
15
|
+
PARAMETER_VERSION,
|
|
16
|
+
WithVisit,
|
|
17
|
+
)
|
|
18
|
+
from mx_bluesky.common.parameters.constants import (
|
|
19
|
+
GridscanParamConstants,
|
|
20
|
+
)
|
|
11
21
|
from mx_bluesky.common.utils.log import LOGGER
|
|
22
|
+
from mx_bluesky.common.utils.utils import convert_angstrom_to_eV
|
|
12
23
|
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
|
|
13
24
|
|
|
14
25
|
T = TypeVar("T", bound=WithVisit)
|
|
@@ -16,6 +27,7 @@ AGAMEMNON_URL = "http://agamemnon.diamond.ac.uk/"
|
|
|
16
27
|
MULTIPIN_PREFIX = "multipin"
|
|
17
28
|
MULTIPIN_FORMAT_DESC = "Expected multipin format is multipin_{number_of_wells}x{well_size}+{distance_between_tip_and_first_well}"
|
|
18
29
|
MULTIPIN_REGEX = rf"^{MULTIPIN_PREFIX}_(\d+)x(\d+(?:\.\d+)?)\+(\d+(?:\.\d+)?)$"
|
|
30
|
+
MX_GENERAL_ROOT_REGEX = r"^/dls/(?P<beamline>[^/]+)/data/[^/]*/(?P<visit>[^/]+)(?:/|$)"
|
|
19
31
|
|
|
20
32
|
|
|
21
33
|
@dataclasses.dataclass
|
|
@@ -60,7 +72,7 @@ def _get_parameters_from_url(url: str) -> dict:
|
|
|
60
72
|
raise KeyError(f"Unexpected json from agamemnon: {response_json}") from e
|
|
61
73
|
|
|
62
74
|
|
|
63
|
-
def
|
|
75
|
+
def get_pin_type_from_agamemnon_parameters(parameters: dict) -> PinType:
|
|
64
76
|
loop_type_name: str | None = parameters["sample"]["loopType"]
|
|
65
77
|
if loop_type_name:
|
|
66
78
|
regex_search = re.search(MULTIPIN_REGEX, loop_type_name)
|
|
@@ -81,15 +93,130 @@ def get_next_instruction(beamline: str) -> dict:
|
|
|
81
93
|
return _get_parameters_from_url(AGAMEMNON_URL + f"getnextcollect/{beamline}")
|
|
82
94
|
|
|
83
95
|
|
|
84
|
-
def
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
def get_withvisit_parameters_from_agamemnon(parameters: dict) -> tuple:
|
|
97
|
+
try:
|
|
98
|
+
prefix = parameters["prefix"]
|
|
99
|
+
collection = parameters["collection"]
|
|
100
|
+
# Assuming distance is identical for multiple collections. Remove after https://github.com/DiamondLightSource/mx-bluesky/issues/773
|
|
101
|
+
detector_distance = collection[0]["distance"]
|
|
102
|
+
except KeyError as e:
|
|
103
|
+
raise KeyError("Unexpected json from agamemnon") from e
|
|
104
|
+
|
|
105
|
+
match = re.match(MX_GENERAL_ROOT_REGEX, prefix) if prefix else None
|
|
106
|
+
|
|
107
|
+
if match:
|
|
108
|
+
return (match.group("visit"), detector_distance)
|
|
109
|
+
|
|
110
|
+
raise ValueError(
|
|
111
|
+
f"Agamemnon prefix '{prefix}' does not match MX-General root structure"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_withenergy_parameters_from_agamemnon(parameters: dict) -> dict[str, Any]:
|
|
116
|
+
try:
|
|
117
|
+
first_collection: dict = parameters["collection"][0]
|
|
118
|
+
wavelength = first_collection.get("wavelength")
|
|
119
|
+
assert isinstance(wavelength, float)
|
|
120
|
+
demand_energy_ev = convert_angstrom_to_eV(wavelength)
|
|
121
|
+
return {"demand_energy_ev": demand_energy_ev}
|
|
122
|
+
except (KeyError, IndexError, AttributeError, TypeError):
|
|
123
|
+
return {"demand_energy_ev": None}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_param_version() -> SemanticVersion:
|
|
127
|
+
return SemanticVersion.validate_from_str(str(PARAMETER_VERSION))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def populate_parameters_from_agamemnon(agamemnon_params):
|
|
131
|
+
visit, detector_distance = get_withvisit_parameters_from_agamemnon(agamemnon_params)
|
|
132
|
+
with_energy_params = get_withenergy_parameters_from_agamemnon(agamemnon_params)
|
|
133
|
+
pin_type = get_pin_type_from_agamemnon_parameters(agamemnon_params)
|
|
134
|
+
first_collection = agamemnon_params["collection"][0]
|
|
135
|
+
visit_directory, file_name = path.split(agamemnon_params["prefix"])
|
|
136
|
+
return LoadCentreCollect.model_validate(
|
|
137
|
+
{
|
|
138
|
+
"parameter_model_version": get_param_version(),
|
|
139
|
+
"visit": visit,
|
|
140
|
+
"detector_distance_mm": detector_distance,
|
|
141
|
+
"sample_id": agamemnon_params["sample"]["id"],
|
|
142
|
+
"sample_puck": agamemnon_params["sample"]["container"],
|
|
143
|
+
"sample_pin": agamemnon_params["sample"]["position"],
|
|
144
|
+
"select_centres": {
|
|
145
|
+
"name": "TopNByMaxCount",
|
|
146
|
+
"n": pin_type.expected_number_of_crystals,
|
|
147
|
+
},
|
|
148
|
+
"robot_load_then_centre": {
|
|
149
|
+
"storage_directory": str(visit_directory) + "/xraycentring",
|
|
150
|
+
"file_name": file_name,
|
|
151
|
+
"tip_offset_um": pin_type.full_width / 2,
|
|
152
|
+
"grid_width_um": pin_type.full_width,
|
|
153
|
+
"omega_start_deg": 0.0,
|
|
154
|
+
"chi_start_deg": first_collection["chi"],
|
|
155
|
+
"transmission_frac": 1.0,
|
|
156
|
+
"features": {"use_gpu_results": True},
|
|
157
|
+
**with_energy_params,
|
|
158
|
+
},
|
|
159
|
+
"multi_rotation_scan": {
|
|
160
|
+
"comment": first_collection["comment"],
|
|
161
|
+
"storage_directory": str(visit_directory),
|
|
162
|
+
"exposure_time_s": first_collection["exposure_time"],
|
|
163
|
+
"file_name": file_name,
|
|
164
|
+
"transmission_frac": first_collection["transmission"],
|
|
165
|
+
"rotation_increment_deg": first_collection["omega_increment"],
|
|
166
|
+
"ispyb_experiment_type": first_collection["experiment_type"],
|
|
167
|
+
"snapshot_omegas_deg": [0.0, 90.0, 180.0, 270.0],
|
|
168
|
+
"rotation_scans": [
|
|
169
|
+
{
|
|
170
|
+
"scan_width_deg": (
|
|
171
|
+
first_collection["number_of_images"]
|
|
172
|
+
* first_collection["omega_increment"]
|
|
173
|
+
),
|
|
174
|
+
"omega_start_deg": first_collection["omega_start"],
|
|
175
|
+
"phi_start_deg": first_collection["phi_start"],
|
|
176
|
+
"chi_start_deg": first_collection["chi"],
|
|
177
|
+
"rotation_direction": "Positive",
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
**with_energy_params,
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def create_parameters_from_agamemnon() -> LoadCentreCollect | None:
|
|
187
|
+
beamline_name = get_beamline_name("i03")
|
|
188
|
+
agamemnon_params = get_next_instruction(beamline_name)
|
|
189
|
+
return (
|
|
190
|
+
populate_parameters_from_agamemnon(agamemnon_params)
|
|
191
|
+
if agamemnon_params
|
|
192
|
+
else None
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def compare_params(load_centre_collect_params):
|
|
197
|
+
try:
|
|
198
|
+
parameters = create_parameters_from_agamemnon()
|
|
199
|
+
# Log differences against GDA populated parameters
|
|
200
|
+
differences = DeepDiff(
|
|
201
|
+
parameters, load_centre_collect_params, math_epsilon=1e-5
|
|
202
|
+
)
|
|
203
|
+
if differences:
|
|
204
|
+
LOGGER.info(
|
|
205
|
+
f"Different parameters found when directly reading from Hyperion: {differences}"
|
|
206
|
+
)
|
|
207
|
+
except (ValueError, KeyError):
|
|
208
|
+
LOGGER.warning(f"Failed to compare parameters: {traceback.format_exc()}")
|
|
209
|
+
except Exception:
|
|
210
|
+
LOGGER.warning(
|
|
211
|
+
f"Unexpected error occurred. Failed to compare parameters: {traceback.format_exc()}"
|
|
212
|
+
)
|
|
87
213
|
|
|
88
214
|
|
|
89
215
|
def update_params_from_agamemnon(parameters: T) -> T:
|
|
90
216
|
try:
|
|
91
217
|
beamline_name = get_beamline_name("i03")
|
|
92
|
-
|
|
218
|
+
agamemnon_params = get_next_instruction(beamline_name)
|
|
219
|
+
pin_type = get_pin_type_from_agamemnon_parameters(agamemnon_params)
|
|
93
220
|
if isinstance(parameters, LoadCentreCollect):
|
|
94
221
|
parameters.robot_load_then_centre.tip_offset_um = pin_type.full_width / 2
|
|
95
222
|
parameters.robot_load_then_centre.grid_width_um = pin_type.full_width
|
|
@@ -99,6 +226,9 @@ def update_params_from_agamemnon(parameters: T) -> T:
|
|
|
99
226
|
# Before we do https://github.com/DiamondLightSource/mx-bluesky/issues/226
|
|
100
227
|
# this will give no snapshots but that's preferable
|
|
101
228
|
parameters.multi_rotation_scan.snapshot_omegas_deg = []
|
|
229
|
+
except (ValueError, ValidationError) as e:
|
|
230
|
+
LOGGER.warning(f"Failed to update parameters: {e}")
|
|
102
231
|
except Exception as e:
|
|
103
|
-
LOGGER.warning(f"
|
|
232
|
+
LOGGER.warning(f"Unexpected error occurred. Failed to update parameters: {e}")
|
|
233
|
+
|
|
104
234
|
return parameters
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from collections.abc import Callable, Sequence
|
|
3
3
|
from threading import Thread
|
|
4
|
-
from time import sleep
|
|
4
|
+
from time import sleep # noqa
|
|
5
5
|
|
|
6
6
|
from bluesky.callbacks import CallbackBase
|
|
7
7
|
from bluesky.callbacks.zmq import Proxy, RemoteDispatcher
|
|
@@ -14,6 +14,9 @@ from mx_bluesky.common.external_interaction.callbacks.common.log_uid_tag_callbac
|
|
|
14
14
|
from mx_bluesky.common.external_interaction.callbacks.common.zocalo_callback import (
|
|
15
15
|
ZocaloCallback,
|
|
16
16
|
)
|
|
17
|
+
from mx_bluesky.common.external_interaction.callbacks.sample_handling.sample_handling_callback import (
|
|
18
|
+
SampleHandlingCallback,
|
|
19
|
+
)
|
|
17
20
|
from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import (
|
|
18
21
|
GridscanISPyBCallback,
|
|
19
22
|
)
|
|
@@ -23,7 +26,7 @@ from mx_bluesky.common.external_interaction.callbacks.xray_centre.nexus_callback
|
|
|
23
26
|
from mx_bluesky.common.utils.log import (
|
|
24
27
|
ISPYB_ZOCALO_CALLBACK_LOGGER,
|
|
25
28
|
NEXUS_LOGGER,
|
|
26
|
-
|
|
29
|
+
_get_logging_dirs,
|
|
27
30
|
tag_filter,
|
|
28
31
|
)
|
|
29
32
|
from mx_bluesky.hyperion.external_interaction.callbacks.robot_load.ispyb_callback import (
|
|
@@ -35,8 +38,8 @@ from mx_bluesky.hyperion.external_interaction.callbacks.rotation.ispyb_callback
|
|
|
35
38
|
from mx_bluesky.hyperion.external_interaction.callbacks.rotation.nexus_callback import (
|
|
36
39
|
RotationNexusFileCallback,
|
|
37
40
|
)
|
|
38
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.
|
|
39
|
-
|
|
41
|
+
from mx_bluesky.hyperion.external_interaction.callbacks.snapshot_callback import (
|
|
42
|
+
BeamDrawingCallback,
|
|
40
43
|
)
|
|
41
44
|
from mx_bluesky.hyperion.parameters.cli import parse_callback_dev_mode_arg
|
|
42
45
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
@@ -67,15 +70,18 @@ def create_rotation_callbacks() -> tuple[
|
|
|
67
70
|
return (
|
|
68
71
|
RotationNexusFileCallback(),
|
|
69
72
|
RotationISPyBCallback(
|
|
70
|
-
emit=ZocaloCallback(CONST.PLAN.
|
|
73
|
+
emit=ZocaloCallback(CONST.PLAN.ROTATION_MULTI, CONST.ZOCALO_ENV)
|
|
71
74
|
),
|
|
72
75
|
)
|
|
73
76
|
|
|
74
77
|
|
|
75
78
|
def setup_callbacks() -> list[CallbackBase]:
|
|
79
|
+
rot_nexus_cb, rot_ispyb_cb = create_rotation_callbacks()
|
|
80
|
+
snapshot_cb = BeamDrawingCallback(emit=rot_ispyb_cb)
|
|
76
81
|
return [
|
|
77
82
|
*create_gridscan_callbacks(),
|
|
78
|
-
|
|
83
|
+
rot_nexus_cb,
|
|
84
|
+
snapshot_cb,
|
|
79
85
|
LogUidTaggingCallback(),
|
|
80
86
|
RobotLoadISPyBCallback(),
|
|
81
87
|
SampleHandlingCallback(),
|
|
@@ -87,14 +93,16 @@ def setup_logging(dev_mode: bool):
|
|
|
87
93
|
(ISPYB_ZOCALO_CALLBACK_LOGGER, "hyperion_ispyb_callback.log"),
|
|
88
94
|
(NEXUS_LOGGER, "hyperion_nexus_callback.log"),
|
|
89
95
|
]:
|
|
96
|
+
logging_path, debug_logging_path = _get_logging_dirs()
|
|
90
97
|
if logger.handlers == []:
|
|
91
98
|
handlers = set_up_all_logging_handlers(
|
|
92
99
|
logger,
|
|
93
|
-
|
|
100
|
+
logging_path,
|
|
94
101
|
filename,
|
|
95
102
|
dev_mode,
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
ERROR_LOG_BUFFER_LINES,
|
|
104
|
+
CONST.GRAYLOG_PORT,
|
|
105
|
+
debug_logging_path,
|
|
98
106
|
)
|
|
99
107
|
handlers["graylog_handler"].addFilter(tag_filter)
|
|
100
108
|
log_info(f"Loggers initialised with dev_mode={dev_mode}")
|