mx-bluesky 1.4.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/_version.py +2 -2
- mx_bluesky/beamlines/i04/thawing_plan.py +1 -1
- mx_bluesky/beamlines/i24/serial/dcid.py +19 -21
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +2 -2
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +1 -4
- mx_bluesky/beamlines/i24/serial/fixed_target/ft_utils.py +0 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +14 -24
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +18 -76
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +0 -199
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +4 -6
- mx_bluesky/beamlines/i24/serial/log.py +1 -1
- mx_bluesky/beamlines/i24/serial/parameters/constants.py +0 -1
- mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +4 -3
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +78 -80
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +1 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +24 -26
- mx_bluesky/beamlines/i24/serial/write_nexus.py +11 -11
- mx_bluesky/common/external_interaction/config_server.py +46 -0
- mx_bluesky/common/parameters/components.py +52 -15
- mx_bluesky/common/parameters/constants.py +6 -1
- mx_bluesky/common/parameters/gridscan.py +94 -0
- mx_bluesky/{hyperion → common}/parameters/robot_load.py +2 -2
- mx_bluesky/common/plans/do_fgs.py +2 -2
- mx_bluesky/common/utils/log.py +2 -0
- mx_bluesky/hyperion/__main__.py +2 -1
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +4 -4
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +1 -1
- 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 +131 -89
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +50 -18
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +52 -10
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +3 -9
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +36 -17
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +6 -10
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +46 -11
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +18 -3
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -3
- mx_bluesky/hyperion/external_interaction/callbacks/common/abstract_event.py +66 -0
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +15 -15
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +5 -3
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +5 -2
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +5 -4
- mx_bluesky/hyperion/external_interaction/config_server.py +8 -37
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +1 -1
- mx_bluesky/hyperion/parameters/components.py +4 -9
- mx_bluesky/hyperion/parameters/constants.py +0 -1
- mx_bluesky/hyperion/parameters/gridscan.py +33 -76
- mx_bluesky/hyperion/parameters/load_centre_collect.py +14 -9
- mx_bluesky/hyperion/parameters/rotation.py +15 -6
- {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/METADATA +35 -34
- {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/RECORD +62 -58
- {mx_bluesky-1.4.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 -150
- {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/top_level.txt +0 -0
|
@@ -2,15 +2,27 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import bluesky.preprocessors as bpp
|
|
6
|
+
from blueapi.core import BlueskyContext
|
|
7
|
+
from bluesky.utils import MsgGenerator
|
|
6
8
|
from dodal.devices.eiger import EigerDetector
|
|
7
9
|
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
8
10
|
|
|
9
11
|
from mx_bluesky.common.parameters.constants import OavConstants
|
|
12
|
+
from mx_bluesky.common.parameters.gridscan import (
|
|
13
|
+
GridScanWithEdgeDetect,
|
|
14
|
+
PinTipCentreThenXrayCentre,
|
|
15
|
+
)
|
|
10
16
|
from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import move_phi_chi_omega
|
|
11
17
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
12
18
|
start_preparing_data_collection_then_do_plan,
|
|
13
19
|
)
|
|
20
|
+
from mx_bluesky.hyperion.experiment_plans.change_aperture_then_move_plan import (
|
|
21
|
+
change_aperture_then_move_to_xtal,
|
|
22
|
+
)
|
|
23
|
+
from mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan import (
|
|
24
|
+
XRayCentreEventHandler,
|
|
25
|
+
)
|
|
14
26
|
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
15
27
|
GridDetectThenXRayCentreComposite,
|
|
16
28
|
detect_grid_and_do_gridscan,
|
|
@@ -27,10 +39,6 @@ from mx_bluesky.hyperion.external_interaction.callbacks.xray_centre.ispyb_callba
|
|
|
27
39
|
)
|
|
28
40
|
from mx_bluesky.hyperion.log import LOGGER
|
|
29
41
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
30
|
-
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
31
|
-
GridScanWithEdgeDetect,
|
|
32
|
-
PinTipCentreThenXrayCentre,
|
|
33
|
-
)
|
|
34
42
|
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
35
43
|
|
|
36
44
|
|
|
@@ -53,13 +61,12 @@ def create_parameters_for_grid_detection(
|
|
|
53
61
|
return grid_detect_and_xray_centre
|
|
54
62
|
|
|
55
63
|
|
|
56
|
-
def
|
|
64
|
+
def pin_centre_then_flyscan_plan(
|
|
57
65
|
composite: GridDetectThenXRayCentreComposite,
|
|
58
66
|
parameters: PinTipCentreThenXrayCentre,
|
|
59
67
|
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
60
68
|
):
|
|
61
|
-
"""Plan that
|
|
62
|
-
centre the sample"""
|
|
69
|
+
"""Plan that performs a pin tip centre followed by a flyscan to determine the centres of interest"""
|
|
63
70
|
|
|
64
71
|
pin_tip_centring_composite = PinTipCentringComposite(
|
|
65
72
|
oav=composite.oav,
|
|
@@ -68,7 +75,7 @@ def pin_centre_then_xray_centre_plan(
|
|
|
68
75
|
pin_tip_detection=composite.pin_tip_detection,
|
|
69
76
|
)
|
|
70
77
|
|
|
71
|
-
def
|
|
78
|
+
def _pin_centre_then_flyscan_plan():
|
|
72
79
|
yield from setup_beamline_for_OAV(
|
|
73
80
|
composite.smargon, composite.backlight, composite.aperture_scatterguard
|
|
74
81
|
)
|
|
@@ -96,7 +103,7 @@ def pin_centre_then_xray_centre_plan(
|
|
|
96
103
|
oav_params,
|
|
97
104
|
)
|
|
98
105
|
|
|
99
|
-
yield from ispyb_activation_wrapper(
|
|
106
|
+
yield from ispyb_activation_wrapper(_pin_centre_then_flyscan_plan(), parameters)
|
|
100
107
|
|
|
101
108
|
|
|
102
109
|
def pin_tip_centre_then_xray_centre(
|
|
@@ -105,15 +112,27 @@ def pin_tip_centre_then_xray_centre(
|
|
|
105
112
|
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
106
113
|
) -> MsgGenerator:
|
|
107
114
|
"""Starts preparing for collection then performs the pin tip centre and xray centre"""
|
|
108
|
-
|
|
109
115
|
eiger: EigerDetector = composite.eiger
|
|
110
116
|
|
|
111
117
|
eiger.set_detector_parameters(parameters.detector_params)
|
|
112
118
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
flyscan_event_handler = XRayCentreEventHandler()
|
|
120
|
+
|
|
121
|
+
@bpp.subs_decorator(flyscan_event_handler)
|
|
122
|
+
def pin_centre_flyscan_then_fetch_results() -> MsgGenerator:
|
|
123
|
+
yield from start_preparing_data_collection_then_do_plan(
|
|
124
|
+
eiger,
|
|
125
|
+
composite.detector_motion,
|
|
126
|
+
parameters.detector_params.detector_distance,
|
|
127
|
+
pin_centre_then_flyscan_plan(composite, parameters, oav_config_file),
|
|
128
|
+
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
yield from pin_centre_flyscan_then_fetch_results()
|
|
132
|
+
flyscan_results = flyscan_event_handler.xray_centre_results
|
|
133
|
+
assert (
|
|
134
|
+
flyscan_results
|
|
135
|
+
), "Flyscan result event not received or no crystal found and exception not raised"
|
|
136
|
+
yield from change_aperture_then_move_to_xtal(
|
|
137
|
+
flyscan_results[0], composite.smargon, composite.aperture_scatterguard
|
|
119
138
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import dataclasses
|
|
2
1
|
from collections.abc import Generator
|
|
3
2
|
|
|
4
3
|
import bluesky.plan_stubs as bps
|
|
4
|
+
import pydantic
|
|
5
5
|
from blueapi.core import BlueskyContext
|
|
6
6
|
from bluesky.utils import Msg
|
|
7
7
|
from dodal.devices.backlight import Backlight
|
|
@@ -27,7 +27,7 @@ from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
|
27
27
|
DEFAULT_STEP_SIZE = 0.5
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
@dataclasses.dataclass
|
|
30
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
31
31
|
class PinTipCentringComposite:
|
|
32
32
|
"""All devices which are directly or indirectly required by this plan"""
|
|
33
33
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import dataclasses
|
|
4
3
|
from collections.abc import Generator
|
|
5
4
|
from datetime import datetime
|
|
6
5
|
from pathlib import Path
|
|
@@ -8,9 +7,10 @@ from typing import cast
|
|
|
8
7
|
|
|
9
8
|
import bluesky.plan_stubs as bps
|
|
10
9
|
import bluesky.preprocessors as bpp
|
|
10
|
+
import pydantic
|
|
11
11
|
from blueapi.core import BlueskyContext
|
|
12
12
|
from bluesky.utils import Msg
|
|
13
|
-
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
13
|
+
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
14
14
|
from dodal.devices.attenuator import Attenuator
|
|
15
15
|
from dodal.devices.dcm import DCM
|
|
16
16
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
|
|
@@ -22,18 +22,18 @@ from dodal.devices.thawer import Thawer
|
|
|
22
22
|
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
23
23
|
from dodal.devices.webcam import Webcam
|
|
24
24
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
25
|
-
from dodal.
|
|
25
|
+
from dodal.plan_stubs.motor_utils import MoveTooLarge, home_and_reset_wrapper
|
|
26
26
|
|
|
27
|
+
from mx_bluesky.common.parameters.robot_load import RobotLoadAndEnergyChange
|
|
27
28
|
from mx_bluesky.hyperion.experiment_plans.set_energy_plan import (
|
|
28
29
|
SetEnergyComposite,
|
|
29
30
|
set_energy_plan,
|
|
30
31
|
)
|
|
31
32
|
from mx_bluesky.hyperion.log import LOGGER
|
|
32
33
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
33
|
-
from mx_bluesky.hyperion.parameters.robot_load import RobotLoadAndEnergyChange
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
@dataclasses.dataclass
|
|
36
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
37
37
|
class RobotLoadAndEnergyChangeComposite:
|
|
38
38
|
# SetEnergyComposite fields
|
|
39
39
|
vfm: FocusingMirrorWithStripes
|
|
@@ -94,11 +94,7 @@ def take_robot_snapshots(oav: OAV, webcam: Webcam, directory: Path):
|
|
|
94
94
|
def prepare_for_robot_load(
|
|
95
95
|
aperture_scatterguard: ApertureScatterguard, smargon: Smargon
|
|
96
96
|
):
|
|
97
|
-
yield from bps.
|
|
98
|
-
aperture_scatterguard,
|
|
99
|
-
ApertureValue.ROBOT_LOAD,
|
|
100
|
-
group="prepare_robot_load",
|
|
101
|
-
)
|
|
97
|
+
yield from bps.trigger(aperture_scatterguard.move_out, group="prepare_robot_load")
|
|
102
98
|
|
|
103
99
|
yield from bps.mv(smargon.stub_offsets, StubPosition.RESET_TO_ROBOT_LOAD) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
104
100
|
|
|
@@ -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
|
|
@@ -32,15 +34,22 @@ from dodal.log import LOGGER
|
|
|
32
34
|
from ophyd_async.fastcs.panda import HDFPanda
|
|
33
35
|
|
|
34
36
|
from mx_bluesky.common.parameters.constants import OavConstants
|
|
37
|
+
from mx_bluesky.common.parameters.gridscan import RobotLoadThenCentre
|
|
35
38
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
36
39
|
fill_in_energy_if_not_supplied,
|
|
37
40
|
start_preparing_data_collection_then_do_plan,
|
|
38
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
|
+
)
|
|
39
48
|
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
40
49
|
GridDetectThenXRayCentreComposite,
|
|
41
50
|
)
|
|
42
51
|
from mx_bluesky.hyperion.experiment_plans.pin_centre_then_xray_centre_plan import (
|
|
43
|
-
|
|
52
|
+
pin_centre_then_flyscan_plan,
|
|
44
53
|
)
|
|
45
54
|
from mx_bluesky.hyperion.experiment_plans.robot_load_and_change_energy import (
|
|
46
55
|
RobotLoadAndEnergyChangeComposite,
|
|
@@ -48,10 +57,9 @@ from mx_bluesky.hyperion.experiment_plans.robot_load_and_change_energy import (
|
|
|
48
57
|
robot_load_and_change_energy_plan,
|
|
49
58
|
)
|
|
50
59
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
51
|
-
from mx_bluesky.hyperion.parameters.gridscan import RobotLoadThenCentre
|
|
52
60
|
|
|
53
61
|
|
|
54
|
-
@dataclasses.dataclass
|
|
62
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
55
63
|
class RobotLoadThenCentreComposite:
|
|
56
64
|
# common fields
|
|
57
65
|
xbpm_feedback: XBPMFeedback
|
|
@@ -88,6 +96,10 @@ class RobotLoadThenCentreComposite:
|
|
|
88
96
|
webcam: Webcam
|
|
89
97
|
lower_gonio: XYZPositioner
|
|
90
98
|
|
|
99
|
+
@property
|
|
100
|
+
def sample_motors(self):
|
|
101
|
+
return self.smargon
|
|
102
|
+
|
|
91
103
|
|
|
92
104
|
def create_devices(context: BlueskyContext) -> RobotLoadThenCentreComposite:
|
|
93
105
|
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
@@ -95,18 +107,18 @@ def create_devices(context: BlueskyContext) -> RobotLoadThenCentreComposite:
|
|
|
95
107
|
return device_composite_from_context(context, RobotLoadThenCentreComposite)
|
|
96
108
|
|
|
97
109
|
|
|
98
|
-
def
|
|
110
|
+
def _flyscan_plan_from_robot_load_params(
|
|
99
111
|
composite: RobotLoadThenCentreComposite,
|
|
100
112
|
params: RobotLoadThenCentre,
|
|
101
113
|
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
102
114
|
):
|
|
103
|
-
yield from
|
|
115
|
+
yield from pin_centre_then_flyscan_plan(
|
|
104
116
|
cast(GridDetectThenXRayCentreComposite, composite),
|
|
105
117
|
params.pin_centre_then_xray_centre_params(),
|
|
106
118
|
)
|
|
107
119
|
|
|
108
120
|
|
|
109
|
-
def
|
|
121
|
+
def _robot_load_then_flyscan_plan(
|
|
110
122
|
composite: RobotLoadThenCentreComposite,
|
|
111
123
|
params: RobotLoadThenCentre,
|
|
112
124
|
oav_config_file: str = OavConstants.OAV_CONFIG_JSON,
|
|
@@ -116,13 +128,36 @@ def robot_load_then_centre_plan(
|
|
|
116
128
|
params.robot_load_params(),
|
|
117
129
|
)
|
|
118
130
|
|
|
119
|
-
yield from
|
|
131
|
+
yield from _flyscan_plan_from_robot_load_params(composite, params, oav_config_file)
|
|
120
132
|
|
|
121
133
|
|
|
122
134
|
def robot_load_then_centre(
|
|
123
135
|
composite: RobotLoadThenCentreComposite,
|
|
124
136
|
parameters: RobotLoadThenCentre,
|
|
125
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."""
|
|
126
161
|
eiger: EigerDetector = composite.eiger
|
|
127
162
|
|
|
128
163
|
# TODO: get these from one source of truth #254
|
|
@@ -138,13 +173,13 @@ def robot_load_then_centre(
|
|
|
138
173
|
doing_chi_change = parameters.chi_start_deg is not None
|
|
139
174
|
|
|
140
175
|
if doing_sample_load:
|
|
141
|
-
plan =
|
|
176
|
+
plan = _robot_load_then_flyscan_plan(
|
|
142
177
|
composite,
|
|
143
178
|
parameters,
|
|
144
179
|
)
|
|
145
180
|
LOGGER.info("Pin not loaded, loading and centring")
|
|
146
181
|
elif doing_chi_change:
|
|
147
|
-
plan =
|
|
182
|
+
plan = _flyscan_plan_from_robot_load_params(composite, parameters)
|
|
148
183
|
LOGGER.info("Pin already loaded but chi changed so centring")
|
|
149
184
|
else:
|
|
150
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,7 +24,7 @@ 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
|
|
|
27
29
|
from mx_bluesky.common.device_setup_plans.read_hardware_for_setup import (
|
|
28
30
|
read_hardware_for_zocalo,
|
|
@@ -62,7 +64,7 @@ from mx_bluesky.hyperion.parameters.rotation import (
|
|
|
62
64
|
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
63
65
|
|
|
64
66
|
|
|
65
|
-
@dataclasses.dataclass
|
|
67
|
+
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
66
68
|
class RotationScanComposite(OavSnapshotComposite):
|
|
67
69
|
"""All devices which are directly or indirectly required by this plan"""
|
|
68
70
|
|
|
@@ -329,6 +331,13 @@ def _move_and_rotation(
|
|
|
329
331
|
yield from setup_beamline_for_OAV(
|
|
330
332
|
composite.smargon, composite.backlight, composite.aperture_scatterguard
|
|
331
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
|
+
)
|
|
332
341
|
yield from oav_snapshot_plan(composite, params, oav_params)
|
|
333
342
|
yield from rotation_scan_plan(
|
|
334
343
|
composite,
|
|
@@ -409,6 +418,11 @@ def multi_rotation_scan(
|
|
|
409
418
|
}
|
|
410
419
|
)
|
|
411
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
|
+
)
|
|
412
426
|
@bpp.finalize_decorator(lambda: _cleanup_plan(composite))
|
|
413
427
|
def _multi_rotation_scan():
|
|
414
428
|
for single_scan in parameters.single_rotation_scans:
|
|
@@ -418,6 +432,7 @@ def multi_rotation_scan(
|
|
|
418
432
|
md={
|
|
419
433
|
"subplan_name": CONST.PLAN.ROTATION_OUTER,
|
|
420
434
|
CONST.TRIGGER.ZOCALO: CONST.PLAN.ROTATION_MAIN,
|
|
435
|
+
"zocalo_environment": CONST.ZOCALO_ENV,
|
|
421
436
|
"hyperion_parameters": single_scan.model_dump_json(),
|
|
422
437
|
}
|
|
423
438
|
)
|
|
@@ -5,8 +5,7 @@
|
|
|
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
|
|
@@ -24,7 +23,7 @@ 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
|
|
@@ -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__
|
|
@@ -28,7 +28,7 @@ class GridDetectionCallback(CallbackBase):
|
|
|
28
28
|
*args,
|
|
29
29
|
) -> None:
|
|
30
30
|
super().__init__(*args)
|
|
31
|
-
self.
|
|
31
|
+
self.start_positions_mm: list = []
|
|
32
32
|
self.box_numbers: list = []
|
|
33
33
|
|
|
34
34
|
def event(self, doc: Event):
|
|
@@ -55,16 +55,16 @@ class GridDetectionCallback(CallbackBase):
|
|
|
55
55
|
beam_x = data["oav-beam_centre_i"]
|
|
56
56
|
beam_y = data["oav-beam_centre_j"]
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
position_grid_start_mm = calculate_x_y_z_of_pixel(
|
|
59
59
|
current_xyz,
|
|
60
60
|
smargon_omega,
|
|
61
61
|
centre_of_first_box,
|
|
62
62
|
(beam_x, beam_y),
|
|
63
63
|
(microns_per_pixel_x, microns_per_pixel_y),
|
|
64
64
|
)
|
|
65
|
-
LOGGER.info(f"Calculated start position {
|
|
65
|
+
LOGGER.info(f"Calculated start position {position_grid_start_mm}")
|
|
66
66
|
|
|
67
|
-
self.
|
|
67
|
+
self.start_positions_mm.append(position_grid_start_mm)
|
|
68
68
|
self.box_numbers.append(
|
|
69
69
|
(
|
|
70
70
|
data["oav-grid_snapshot-num_boxes_x"],
|
|
@@ -72,22 +72,22 @@ class GridDetectionCallback(CallbackBase):
|
|
|
72
72
|
)
|
|
73
73
|
)
|
|
74
74
|
|
|
75
|
-
self.
|
|
76
|
-
self.
|
|
77
|
-
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
|
|
78
78
|
return doc
|
|
79
79
|
|
|
80
80
|
def get_grid_parameters(self) -> GridParamUpdate:
|
|
81
81
|
return {
|
|
82
|
-
"x_start_um": self.
|
|
83
|
-
"y_start_um": self.
|
|
84
|
-
"y2_start_um": self.
|
|
85
|
-
"z_start_um": self.
|
|
86
|
-
"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,
|
|
87
87
|
"x_steps": self.box_numbers[0][0],
|
|
88
88
|
"y_steps": self.box_numbers[0][1],
|
|
89
89
|
"z_steps": self.box_numbers[1][1],
|
|
90
|
-
"x_step_size_um": self.
|
|
91
|
-
"y_step_size_um": self.
|
|
92
|
-
"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,
|
|
93
93
|
}
|
|
@@ -61,7 +61,9 @@ class RotationISPyBCallback(BaseISPyBCallback):
|
|
|
61
61
|
ISPYB_LOGGER.info(
|
|
62
62
|
"ISPyB callback received start document with experiment parameters."
|
|
63
63
|
)
|
|
64
|
-
|
|
64
|
+
hyperion_params = doc.get("hyperion_parameters")
|
|
65
|
+
assert isinstance(hyperion_params, str)
|
|
66
|
+
self.params = RotationScan.model_validate_json(hyperion_params)
|
|
65
67
|
dcgid = (
|
|
66
68
|
self.ispyb_ids.data_collection_group_id
|
|
67
69
|
if (self.params.sample_id == self.last_sample_id)
|
|
@@ -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
|
)
|
|
@@ -5,8 +5,8 @@ from time import time
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
|
-
from blueapi.core import MsgGenerator
|
|
9
8
|
from bluesky import preprocessors as bpp
|
|
9
|
+
from bluesky.utils import MsgGenerator
|
|
10
10
|
from dodal.devices.zocalo.zocalo_results import (
|
|
11
11
|
ZOCALO_READING_PLAN_NAME,
|
|
12
12
|
get_processing_results_from_event,
|
|
@@ -98,7 +98,9 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
98
98
|
"ISPyB callback received start document with experiment parameters and "
|
|
99
99
|
f"uid: {self.uid_to_finalize_on}"
|
|
100
100
|
)
|
|
101
|
-
|
|
101
|
+
hyperion_params = doc.get("hyperion_parameters")
|
|
102
|
+
assert isinstance(hyperion_params, str)
|
|
103
|
+
self.params = GridCommon.model_validate_json(hyperion_params)
|
|
102
104
|
self.ispyb = StoreInIspyb(self.ispyb_config)
|
|
103
105
|
data_collection_group_info = populate_data_collection_group(self.params)
|
|
104
106
|
|
|
@@ -152,6 +154,7 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
152
154
|
ISPYB_LOGGER.info(
|
|
153
155
|
f"Amending comment based on Zocalo reading doc: {format_doc_for_log(doc)}"
|
|
154
156
|
)
|
|
157
|
+
|
|
155
158
|
raw_results = get_processing_results_from_event("zocalo", doc)
|
|
156
159
|
if len(raw_results) > 0:
|
|
157
160
|
for n, res in enumerate(raw_results):
|
|
@@ -12,7 +12,7 @@ from mx_bluesky.hyperion.external_interaction.nexus.nexus_utils import (
|
|
|
12
12
|
from mx_bluesky.hyperion.external_interaction.nexus.write_nexus import NexusWriter
|
|
13
13
|
from mx_bluesky.hyperion.log import NEXUS_LOGGER
|
|
14
14
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
15
|
-
from mx_bluesky.hyperion.parameters.gridscan import
|
|
15
|
+
from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
18
|
from event_model.documents import Event, EventDescriptor, RunStart
|
|
@@ -45,11 +45,12 @@ class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
|
45
45
|
|
|
46
46
|
def activity_gated_start(self, doc: RunStart):
|
|
47
47
|
if doc.get("subplan_name") == CONST.PLAN.GRIDSCAN_OUTER:
|
|
48
|
-
|
|
48
|
+
hyperion_params = doc.get("hyperion_parameters")
|
|
49
|
+
assert isinstance(hyperion_params, str)
|
|
49
50
|
NEXUS_LOGGER.info(
|
|
50
|
-
f"Nexus writer received start document with experiment parameters {
|
|
51
|
+
f"Nexus writer received start document with experiment parameters {hyperion_params}"
|
|
51
52
|
)
|
|
52
|
-
parameters =
|
|
53
|
+
parameters = HyperionThreeDGridScan.model_validate_json(hyperion_params)
|
|
53
54
|
d_size = parameters.detector_params.detector_size_constants.det_size_pixels
|
|
54
55
|
grid_n_img_1 = parameters.scan_indices[1]
|
|
55
56
|
grid_n_img_2 = parameters.num_images - grid_n_img_1
|
|
@@ -1,47 +1,18 @@
|
|
|
1
|
+
from functools import cache
|
|
2
|
+
|
|
1
3
|
from daq_config_server.client import ConfigServer
|
|
2
|
-
from pydantic import BaseModel, Field, model_validator
|
|
3
4
|
|
|
5
|
+
from mx_bluesky.common.external_interaction.config_server import FeatureFlags
|
|
4
6
|
from mx_bluesky.hyperion.log import LOGGER
|
|
5
7
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
6
8
|
|
|
7
|
-
_CONFIG_SERVER: ConfigServer | None = None
|
|
8
|
-
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
class HyperionFeatureFlags(FeatureFlags):
|
|
11
|
+
@staticmethod
|
|
12
|
+
@cache
|
|
13
|
+
def get_config_server() -> ConfigServer:
|
|
14
|
+
return ConfigServer(CONST.CONFIG_SERVER_URL, LOGGER)
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
class FeatureFlags(BaseModel):
|
|
18
|
-
# The default value will be used as the fallback when doing a best-effort fetch
|
|
19
|
-
# from the service
|
|
20
16
|
use_panda_for_gridscan: bool = CONST.I03.USE_PANDA_FOR_GRIDSCAN
|
|
21
17
|
compare_cpu_and_gpu_zocalo: bool = CONST.I03.COMPARE_CPU_AND_GPU_ZOCALO
|
|
22
18
|
set_stub_offsets: bool = CONST.I03.SET_STUB_OFFSETS
|
|
23
|
-
|
|
24
|
-
# Feature values supplied at construction will override values from the config server
|
|
25
|
-
overriden_features: dict = Field(default_factory=dict, exclude=True)
|
|
26
|
-
|
|
27
|
-
@model_validator(mode="before")
|
|
28
|
-
@classmethod
|
|
29
|
-
def mark_overridden_features(cls, values):
|
|
30
|
-
assert isinstance(values, dict)
|
|
31
|
-
values["overriden_features"] = values.copy()
|
|
32
|
-
return values
|
|
33
|
-
|
|
34
|
-
@classmethod
|
|
35
|
-
def _get_flags(cls):
|
|
36
|
-
flags = config_server().best_effort_get_all_feature_flags()
|
|
37
|
-
return {f: flags[f] for f in flags if f in cls.model_fields.keys()}
|
|
38
|
-
|
|
39
|
-
def update_self_from_server(self):
|
|
40
|
-
"""Used to update the feature flags from the server during a plan. Where there are flags which were explicitly set from externally supplied parameters, these values will be used instead."""
|
|
41
|
-
for flag, value in self._get_flags().items():
|
|
42
|
-
updated_value = (
|
|
43
|
-
value
|
|
44
|
-
if flag not in self.overriden_features.keys()
|
|
45
|
-
else self.overriden_features[flag]
|
|
46
|
-
)
|
|
47
|
-
setattr(self, flag, updated_value)
|