mx-bluesky 1.5.14__py3-none-any.whl → 1.5.16__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/Getting started.ipynb +1 -0
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/i04/callbacks/murko_callback.py +18 -0
- mx_bluesky/beamlines/i04/experiment_plans/i04_grid_detect_then_xray_centre_plan.py +6 -7
- mx_bluesky/beamlines/i04/thawing_plan.py +1 -0
- mx_bluesky/beamlines/i24/jungfrau_commissioning/__init__.py +13 -0
- mx_bluesky/beamlines/i24/jungfrau_commissioning/callbacks/__init__.py +0 -0
- mx_bluesky/beamlines/i24/jungfrau_commissioning/callbacks/metadata_writer.py +86 -0
- mx_bluesky/beamlines/i24/jungfrau_commissioning/composites.py +35 -0
- mx_bluesky/beamlines/i24/jungfrau_commissioning/experiment_plans/do_darks.py +18 -19
- mx_bluesky/beamlines/i24/jungfrau_commissioning/experiment_plans/rotation_scan_plan.py +292 -0
- mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/do_external_acquisition.py +3 -8
- mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/do_internal_acquisition.py +4 -5
- mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/plan_utils.py +14 -18
- mx_bluesky/beamlines/i24/parameters/__init__.py +0 -0
- mx_bluesky/beamlines/i24/parameters/constants.py +9 -0
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_extruder_collect_py3v2.py +1 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +2 -2
- mx_bluesky/beamlines/i24/serial/web_gui_plans/oav_plans.py +21 -0
- mx_bluesky/common/device_setup_plans/robot_load_unload.py +2 -24
- mx_bluesky/common/device_setup_plans/setup_zebra_and_shutter.py +5 -2
- mx_bluesky/common/experiment_plans/common_flyscan_xray_centre_plan.py +1 -1
- mx_bluesky/common/experiment_plans/inner_plans/read_hardware.py +2 -0
- mx_bluesky/common/experiment_plans/rotation/__init__.py +0 -0
- mx_bluesky/common/experiment_plans/rotation/rotation_utils.py +127 -0
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +14 -2
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_mapping.py +1 -2
- mx_bluesky/common/external_interaction/ispyb/data_model.py +4 -1
- mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +3 -1
- mx_bluesky/common/parameters/components.py +17 -7
- mx_bluesky/common/parameters/constants.py +6 -0
- mx_bluesky/{hyperion → common}/parameters/rotation.py +10 -8
- mx_bluesky/common/preprocessors/preprocessors.py +98 -36
- mx_bluesky/hyperion/__main__.py +55 -22
- mx_bluesky/hyperion/baton_handler.py +24 -64
- mx_bluesky/hyperion/blueapi_config.yaml +17 -0
- mx_bluesky/hyperion/blueapi_dev_config.yaml +16 -0
- mx_bluesky/hyperion/blueapi_plans/__init__.py +96 -0
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +8 -6
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +1 -1
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +3 -1
- mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +4 -5
- mx_bluesky/hyperion/experiment_plans/hyperion_grid_detect_then_xray_centre_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +3 -1
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +17 -6
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +0 -3
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +12 -126
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/udc_default_state.py +8 -2
- mx_bluesky/hyperion/external_interaction/agamemnon.py +3 -8
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +121 -47
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +3 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +6 -3
- mx_bluesky/hyperion/external_interaction/callbacks/stomp/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/stomp/dispatcher.py +33 -0
- mx_bluesky/hyperion/in_process_runner.py +132 -0
- mx_bluesky/hyperion/parameters/cli.py +43 -4
- mx_bluesky/hyperion/parameters/components.py +13 -0
- mx_bluesky/hyperion/parameters/constants.py +2 -9
- mx_bluesky/hyperion/parameters/load_centre_collect.py +3 -1
- mx_bluesky/hyperion/plan_runner.py +45 -66
- mx_bluesky/hyperion/plan_runner_api.py +3 -4
- mx_bluesky/hyperion/supervisor/__init__.py +3 -0
- mx_bluesky/hyperion/supervisor/_supervisor.py +116 -0
- mx_bluesky/hyperion/supervisor/client_config.yaml +6 -0
- mx_bluesky/hyperion/supervisor/supervisor_config.yaml +10 -0
- mx_bluesky/hyperion/supervisor/supervisor_dev_config.yaml +9 -0
- {mx_bluesky-1.5.14.dist-info → mx_bluesky-1.5.16.dist-info}/METADATA +3 -31
- {mx_bluesky-1.5.14.dist-info → mx_bluesky-1.5.16.dist-info}/RECORD +74 -54
- {mx_bluesky-1.5.14.dist-info → mx_bluesky-1.5.16.dist-info}/WHEEL +0 -0
- {mx_bluesky-1.5.14.dist-info → mx_bluesky-1.5.16.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.5.14.dist-info → mx_bluesky-1.5.16.dist-info}/licenses/LICENSE +0 -0
- {mx_bluesky-1.5.14.dist-info → mx_bluesky-1.5.16.dist-info}/top_level.txt +0 -0
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
|
|
3
|
+
import bluesky.plan_stubs as bps
|
|
1
4
|
from bluesky import preprocessors as bpp
|
|
2
5
|
from bluesky.preprocessors import plan_mutator
|
|
3
6
|
from bluesky.utils import Msg, MsgGenerator, make_decorator
|
|
@@ -12,15 +15,61 @@ from mx_bluesky.common.protocols.protocols import (
|
|
|
12
15
|
)
|
|
13
16
|
|
|
14
17
|
|
|
15
|
-
def
|
|
18
|
+
def _create_insert_plans_mutator(
|
|
19
|
+
run_key_to_wrap: PlanNameConstants | None = None,
|
|
20
|
+
on_open: Callable[[Msg], MsgGenerator] | None = None,
|
|
21
|
+
on_close: Callable[[], MsgGenerator] | None = None,
|
|
22
|
+
) -> Callable[[Msg], tuple[MsgGenerator | None, MsgGenerator | None]]:
|
|
23
|
+
"""
|
|
24
|
+
Inserts plans to be executed when the run with the given name opens/closes.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
run_key_to_wrap: The run name to insert before/after. If None (default) then
|
|
28
|
+
insert on the first open/close run regardless of its name.
|
|
29
|
+
on_open: The plan to perform just before the run opens
|
|
30
|
+
on_close: The plan to perform just after the run closes
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
_wrapped_run_name: None | str = None
|
|
34
|
+
|
|
35
|
+
def insert_plans(msg: Msg):
|
|
36
|
+
# Wrap the specified run, or, if none specified, wrap the first run encountered
|
|
37
|
+
nonlocal _wrapped_run_name
|
|
38
|
+
|
|
39
|
+
match msg.command:
|
|
40
|
+
case "open_run":
|
|
41
|
+
# If we specified a run key, did we encounter it
|
|
42
|
+
# If we didn't specify, then insert the plans and track the name of the run
|
|
43
|
+
if on_open is not None and (
|
|
44
|
+
not (run_key_to_wrap or _wrapped_run_name)
|
|
45
|
+
or run_key_to_wrap is msg.run
|
|
46
|
+
):
|
|
47
|
+
_wrapped_run_name = msg.run if msg.run else "unnamed_run"
|
|
48
|
+
return on_open(msg), None
|
|
49
|
+
case "close_run":
|
|
50
|
+
# Check if the run tracked from above was closed
|
|
51
|
+
# An exception is raised in the RunEngine if two unnamed runs are opened
|
|
52
|
+
# at the same time, so we are safe from unpausing on the wrong run
|
|
53
|
+
if on_close is not None and (
|
|
54
|
+
(_wrapped_run_name == "unnamed_run" and not msg.run)
|
|
55
|
+
or (msg.run and _wrapped_run_name and _wrapped_run_name is msg.run)
|
|
56
|
+
):
|
|
57
|
+
return None, on_close()
|
|
58
|
+
|
|
59
|
+
return None, None
|
|
60
|
+
|
|
61
|
+
return insert_plans
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def pause_xbpm_feedback_during_collection_at_desired_transmission_wrapper(
|
|
16
65
|
plan: MsgGenerator,
|
|
17
66
|
devices: XBPMPauseDevices,
|
|
18
67
|
desired_transmission_fraction: float,
|
|
19
68
|
run_key_to_wrap: PlanNameConstants | None = None,
|
|
20
69
|
):
|
|
21
70
|
"""
|
|
22
|
-
Sets the transmission for the data collection, ensuring the xbpm feedback is valid, then
|
|
23
|
-
|
|
71
|
+
Sets the transmission for the data collection, ensuring the xbpm feedback is valid, then pauses
|
|
72
|
+
XBPM feedback. Resets transmission and unpauses XBPM immediately after the run has finished.
|
|
24
73
|
|
|
25
74
|
This wrapper should be attached to the entry point of any beamline-specific plan that may disrupt the XBPM feedback,
|
|
26
75
|
such as a data collection or an x-ray center grid scan.
|
|
@@ -38,15 +87,13 @@ def transmission_and_xbpm_feedback_for_collection_wrapper(
|
|
|
38
87
|
Args:
|
|
39
88
|
plan: The plan performing the data collection.
|
|
40
89
|
devices (XBPMPauseDevices): Composite device including The XBPM device that is responsible for keeping
|
|
41
|
-
|
|
90
|
+
the beam in position, and attenuator
|
|
42
91
|
desired_transmission_fraction (float): The desired transmission for the collection
|
|
43
|
-
run_key_to_wrap: (str | None): Pausing XBPM and setting transmission is inserted
|
|
44
|
-
|
|
45
|
-
|
|
92
|
+
run_key_to_wrap: (str | None): Pausing XBPM and setting transmission is inserted before the 'open_run' message is seen with
|
|
93
|
+
the matching run key, and unpausing and resetting transmission is inserted after the corresponding 'close_run' message is
|
|
94
|
+
seen. If not specified, instead wrap the first run encountered.
|
|
46
95
|
"""
|
|
47
96
|
|
|
48
|
-
_wrapped_run_name: None | str = None
|
|
49
|
-
|
|
50
97
|
def head(msg: Msg):
|
|
51
98
|
yield from check_and_pause_feedback(
|
|
52
99
|
devices.xbpm_feedback,
|
|
@@ -62,36 +109,13 @@ def transmission_and_xbpm_feedback_for_collection_wrapper(
|
|
|
62
109
|
devices.xbpm_feedback, devices.attenuator
|
|
63
110
|
)
|
|
64
111
|
|
|
65
|
-
|
|
66
|
-
# Wrap the specified run, or, if none specified, wrap the first run encountered
|
|
67
|
-
nonlocal _wrapped_run_name
|
|
68
|
-
|
|
69
|
-
match msg.command:
|
|
70
|
-
case "open_run":
|
|
71
|
-
# If we specified a run key, did we encounter it
|
|
72
|
-
# If we didn't specify, then insert the plans and track the name of the run
|
|
73
|
-
if (
|
|
74
|
-
not (run_key_to_wrap or _wrapped_run_name)
|
|
75
|
-
or run_key_to_wrap is msg.run
|
|
76
|
-
):
|
|
77
|
-
_wrapped_run_name = msg.run if msg.run else "unnamed_run"
|
|
78
|
-
return head(msg), None
|
|
79
|
-
case "close_run":
|
|
80
|
-
# Check if the run tracked from above was closed
|
|
81
|
-
# An exception is raised in the RunEngine if two unnamed runs are opened
|
|
82
|
-
# at the same time, so we are safe from unpausing on the wrong run
|
|
83
|
-
if (_wrapped_run_name == "unnamed_run" and not msg.run) or (
|
|
84
|
-
msg.run and _wrapped_run_name and _wrapped_run_name is msg.run
|
|
85
|
-
):
|
|
86
|
-
return None, tail()
|
|
87
|
-
|
|
88
|
-
return None, None
|
|
112
|
+
mutator = _create_insert_plans_mutator(run_key_to_wrap, head, tail)
|
|
89
113
|
|
|
90
114
|
# Contingency wrapper can cause unpausing to occur on exception and again on close_run.
|
|
91
115
|
# Not needed after https://github.com/bluesky/bluesky/issues/1891
|
|
92
116
|
return (
|
|
93
117
|
yield from bpp.contingency_wrapper(
|
|
94
|
-
plan_mutator(plan,
|
|
118
|
+
plan_mutator(plan, mutator),
|
|
95
119
|
except_plan=lambda _: unpause_xbpm_feedback_and_set_transmission_to_1(
|
|
96
120
|
devices.xbpm_feedback,
|
|
97
121
|
devices.attenuator,
|
|
@@ -100,6 +124,44 @@ def transmission_and_xbpm_feedback_for_collection_wrapper(
|
|
|
100
124
|
)
|
|
101
125
|
|
|
102
126
|
|
|
103
|
-
|
|
104
|
-
|
|
127
|
+
def set_transmission_and_trigger_xbpm_feedback_before_collection_wrapper(
|
|
128
|
+
plan: MsgGenerator,
|
|
129
|
+
devices: XBPMPauseDevices,
|
|
130
|
+
desired_transmission_fraction: float,
|
|
131
|
+
run_key_to_wrap: PlanNameConstants | None = None,
|
|
132
|
+
):
|
|
133
|
+
"""
|
|
134
|
+
Sets the transmission and triggers xbpm feedback immediately before
|
|
135
|
+
doing the specified run. Doesn't revert transmission at the end of the plan.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
plan: The plan performing the data collection.
|
|
139
|
+
devices (XBPMPauseDevices): Composite device including The XBPM device that is responsible for keeping
|
|
140
|
+
the beam in position, and the attenuator
|
|
141
|
+
desired_transmission_fraction (float): The desired transmission for the collection
|
|
142
|
+
run_key_to_wrap: (str | None): 'Set transmission' and 'trigger XBPM device' is inserted before the 'open_run' message with
|
|
143
|
+
the matching run key is seen. If not specified, instead wrap the first run encountered.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
def head(msg: Msg):
|
|
147
|
+
yield from bps.mv(devices.attenuator, desired_transmission_fraction)
|
|
148
|
+
yield from bps.trigger(devices.xbpm_feedback)
|
|
149
|
+
|
|
150
|
+
# Allow 'open_run' message to pass through
|
|
151
|
+
yield msg
|
|
152
|
+
|
|
153
|
+
mutator = _create_insert_plans_mutator(run_key_to_wrap, head)
|
|
154
|
+
|
|
155
|
+
return (yield from plan_mutator(plan, mutator))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
set_transmission_and_trigger_xbpm_feedback_before_collection_decorator = make_decorator(
|
|
159
|
+
set_transmission_and_trigger_xbpm_feedback_before_collection_wrapper
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
pause_xbpm_feedback_during_collection_at_desired_transmission_decorator = (
|
|
164
|
+
make_decorator(
|
|
165
|
+
pause_xbpm_feedback_during_collection_at_desired_transmission_wrapper
|
|
166
|
+
)
|
|
105
167
|
)
|
mx_bluesky/hyperion/__main__.py
CHANGED
|
@@ -2,9 +2,11 @@ import json
|
|
|
2
2
|
import signal
|
|
3
3
|
import threading
|
|
4
4
|
from dataclasses import asdict
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
from sys import argv
|
|
6
7
|
from traceback import format_exception
|
|
7
8
|
|
|
9
|
+
from blueapi.config import ApplicationConfig, ConfigLoader
|
|
8
10
|
from blueapi.core import BlueskyContext
|
|
9
11
|
from flask import Flask, request
|
|
10
12
|
from flask_restful import Api, Resource
|
|
@@ -28,6 +30,7 @@ from mx_bluesky.hyperion.external_interaction.agamemnon import (
|
|
|
28
30
|
compare_params,
|
|
29
31
|
update_params_from_agamemnon,
|
|
30
32
|
)
|
|
33
|
+
from mx_bluesky.hyperion.in_process_runner import InProcessRunner
|
|
31
34
|
from mx_bluesky.hyperion.parameters.cli import (
|
|
32
35
|
HyperionArgs,
|
|
33
36
|
HyperionMode,
|
|
@@ -42,6 +45,7 @@ from mx_bluesky.hyperion.runner import (
|
|
|
42
45
|
StatusAndMessage,
|
|
43
46
|
make_error_status_and_message,
|
|
44
47
|
)
|
|
48
|
+
from mx_bluesky.hyperion.supervisor import SupervisorRunner
|
|
45
49
|
from mx_bluesky.hyperion.utils.context import setup_context
|
|
46
50
|
|
|
47
51
|
|
|
@@ -152,7 +156,11 @@ def create_app(runner: GDARunner, test_config=None) -> Flask:
|
|
|
152
156
|
def initialise_globals(args: HyperionArgs):
|
|
153
157
|
"""Do all early main low-level application initialisation."""
|
|
154
158
|
do_default_logging_setup(
|
|
155
|
-
CONST.
|
|
159
|
+
CONST.SUPERVISOR_LOG_FILE_NAME
|
|
160
|
+
if args.mode == HyperionMode.SUPERVISOR
|
|
161
|
+
else CONST.LOG_FILE_NAME,
|
|
162
|
+
CONST.GRAYLOG_PORT,
|
|
163
|
+
dev_mode=args.dev_mode,
|
|
156
164
|
)
|
|
157
165
|
LOGGER.info(f"Hyperion launched with args:{argv}")
|
|
158
166
|
alerting.set_alerting_service(LoggingAlertService(CONST.GRAYLOG_STREAM_ID))
|
|
@@ -163,27 +171,52 @@ def main():
|
|
|
163
171
|
args = parse_cli_args()
|
|
164
172
|
initialise_globals(args)
|
|
165
173
|
hyperion_port = HyperionConstants.HYPERION_PORT
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
174
|
+
|
|
175
|
+
match args.mode:
|
|
176
|
+
case HyperionMode.GDA:
|
|
177
|
+
context = setup_context(dev_mode=args.dev_mode)
|
|
178
|
+
runner = GDARunner(context=context)
|
|
179
|
+
app = create_app(runner)
|
|
180
|
+
flask_thread = threading.Thread(
|
|
181
|
+
target=lambda: app.run(
|
|
182
|
+
host="0.0.0.0", port=hyperion_port, debug=True, use_reloader=False
|
|
183
|
+
),
|
|
184
|
+
daemon=True,
|
|
185
|
+
)
|
|
186
|
+
flask_thread.start()
|
|
187
|
+
LOGGER.info(
|
|
188
|
+
f"Hyperion now listening on {hyperion_port} ({'IN DEV' if args.dev_mode else ''})"
|
|
189
|
+
)
|
|
190
|
+
runner.wait_on_queue()
|
|
191
|
+
case HyperionMode.UDC:
|
|
192
|
+
context = setup_context(dev_mode=args.dev_mode)
|
|
193
|
+
plan_runner = InProcessRunner(context, args.dev_mode)
|
|
194
|
+
create_server_for_udc(plan_runner, HyperionConstants.HYPERION_PORT)
|
|
195
|
+
_register_sigterm_handler(plan_runner)
|
|
196
|
+
run_forever(plan_runner)
|
|
197
|
+
case HyperionMode.SUPERVISOR:
|
|
198
|
+
if not args.client_config:
|
|
199
|
+
raise RuntimeError(
|
|
200
|
+
"BlueAPI client configuration file must be specified in supervisor mode."
|
|
201
|
+
)
|
|
202
|
+
if not args.supervisor_config:
|
|
203
|
+
raise RuntimeError(
|
|
204
|
+
"BlueAPI supervisor configuration file must be specified in supervisor mode."
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
client_config = _load_config_from_yaml(Path(args.client_config))
|
|
208
|
+
supervisor_config = _load_config_from_yaml(Path(args.supervisor_config))
|
|
209
|
+
context = BlueskyContext(configuration=supervisor_config)
|
|
210
|
+
plan_runner = SupervisorRunner(context, client_config, args.dev_mode)
|
|
211
|
+
create_server_for_udc(plan_runner, HyperionConstants.SUPERVISOR_PORT)
|
|
212
|
+
_register_sigterm_handler(plan_runner)
|
|
213
|
+
run_forever(plan_runner)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _load_config_from_yaml(config_path: Path):
|
|
217
|
+
loader = ConfigLoader(ApplicationConfig)
|
|
218
|
+
loader.use_values_from_yaml(config_path)
|
|
219
|
+
return loader.load()
|
|
187
220
|
|
|
188
221
|
|
|
189
222
|
def _register_sigterm_handler(runner: PlanRunner):
|
|
@@ -1,45 +1,30 @@
|
|
|
1
1
|
from collections.abc import Sequence
|
|
2
|
-
from functools import partial
|
|
3
|
-
from typing import Any
|
|
4
2
|
|
|
5
3
|
from blueapi.core.context import BlueskyContext
|
|
6
4
|
from bluesky import plan_stubs as bps
|
|
7
5
|
from bluesky import preprocessors as bpp
|
|
8
6
|
from bluesky.utils import MsgGenerator, RunEngineInterrupted
|
|
9
7
|
from dodal.common.beamlines.commissioning_mode import set_commissioning_signal
|
|
10
|
-
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
11
8
|
from dodal.devices.baton import Baton
|
|
12
|
-
from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
|
|
13
|
-
from dodal.devices.motors import XYZStage
|
|
14
|
-
from dodal.devices.robot import BartRobot
|
|
15
|
-
from dodal.devices.smargon import Smargon
|
|
16
9
|
|
|
17
|
-
from mx_bluesky.common.device_setup_plans.robot_load_unload import robot_unload
|
|
18
10
|
from mx_bluesky.common.external_interaction.alerting import (
|
|
19
11
|
AlertService,
|
|
20
12
|
get_alerting_service,
|
|
21
13
|
)
|
|
22
|
-
from mx_bluesky.common.parameters.components import
|
|
14
|
+
from mx_bluesky.common.parameters.components import (
|
|
15
|
+
MxBlueskyParameters,
|
|
16
|
+
get_param_version,
|
|
17
|
+
)
|
|
23
18
|
from mx_bluesky.common.utils.context import (
|
|
24
|
-
device_composite_from_context,
|
|
25
19
|
find_device_in_context,
|
|
26
20
|
)
|
|
27
21
|
from mx_bluesky.common.utils.exceptions import BeamlineCheckFailureError
|
|
28
22
|
from mx_bluesky.common.utils.log import LOGGER
|
|
29
|
-
from mx_bluesky.hyperion.experiment_plans.load_centre_collect_full_plan import (
|
|
30
|
-
create_devices,
|
|
31
|
-
load_centre_collect_full,
|
|
32
|
-
)
|
|
33
|
-
from mx_bluesky.hyperion.experiment_plans.udc_default_state import (
|
|
34
|
-
UDCDefaultDevices,
|
|
35
|
-
move_to_udc_default_state,
|
|
36
|
-
)
|
|
37
23
|
from mx_bluesky.hyperion.external_interaction.agamemnon import (
|
|
38
24
|
create_parameters_from_agamemnon,
|
|
39
25
|
)
|
|
40
26
|
from mx_bluesky.hyperion.external_interaction.alerting.constants import Subjects
|
|
41
|
-
from mx_bluesky.hyperion.parameters.components import
|
|
42
|
-
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
|
|
27
|
+
from mx_bluesky.hyperion.parameters.components import UDCCleanup, UDCDefaultState
|
|
43
28
|
from mx_bluesky.hyperion.plan_runner import PlanError, PlanRunner
|
|
44
29
|
from mx_bluesky.hyperion.utils.context import (
|
|
45
30
|
clear_all_device_caches,
|
|
@@ -102,7 +87,14 @@ def run_udc_when_requested(context: BlueskyContext, runner: PlanRunner):
|
|
|
102
87
|
"""
|
|
103
88
|
_raise_udc_start_alert(get_alerting_service())
|
|
104
89
|
yield from bpp.contingency_wrapper(
|
|
105
|
-
|
|
90
|
+
runner.decode_and_execute(
|
|
91
|
+
None,
|
|
92
|
+
[
|
|
93
|
+
UDCDefaultState.model_validate(
|
|
94
|
+
{"parameter_model_version": get_param_version()}
|
|
95
|
+
)
|
|
96
|
+
],
|
|
97
|
+
),
|
|
106
98
|
except_plan=trap_default_state_exception,
|
|
107
99
|
auto_raise=False,
|
|
108
100
|
)
|
|
@@ -115,7 +107,14 @@ def run_udc_when_requested(context: BlueskyContext, runner: PlanRunner):
|
|
|
115
107
|
baton, runner, current_visit
|
|
116
108
|
)
|
|
117
109
|
if current_visit:
|
|
118
|
-
yield from
|
|
110
|
+
yield from runner.decode_and_execute(
|
|
111
|
+
current_visit,
|
|
112
|
+
[
|
|
113
|
+
UDCCleanup.model_validate(
|
|
114
|
+
{"parameter_model_version": get_param_version()}
|
|
115
|
+
)
|
|
116
|
+
],
|
|
117
|
+
)
|
|
119
118
|
|
|
120
119
|
def release_baton() -> MsgGenerator:
|
|
121
120
|
# If hyperion has given up the baton itself we need to also release requested
|
|
@@ -177,23 +176,9 @@ def _fetch_and_process_agamemnon_instruction(
|
|
|
177
176
|
) -> MsgGenerator[str | None]:
|
|
178
177
|
parameter_list: Sequence[MxBlueskyParameters] = create_parameters_from_agamemnon()
|
|
179
178
|
if parameter_list:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
)
|
|
184
|
-
match parameters:
|
|
185
|
-
case LoadCentreCollect():
|
|
186
|
-
current_visit = parameters.visit
|
|
187
|
-
devices: Any = create_devices(runner.context)
|
|
188
|
-
yield from runner.execute_plan(
|
|
189
|
-
partial(load_centre_collect_full, devices, parameters)
|
|
190
|
-
)
|
|
191
|
-
case Wait():
|
|
192
|
-
yield from runner.execute_plan(partial(_runner_sleep, parameters))
|
|
193
|
-
case _:
|
|
194
|
-
raise AssertionError(
|
|
195
|
-
f"Unsupported instruction decoded from agamemnon {type(parameters)}"
|
|
196
|
-
)
|
|
179
|
+
current_visit = yield from runner.decode_and_execute(
|
|
180
|
+
current_visit, parameter_list
|
|
181
|
+
)
|
|
197
182
|
else:
|
|
198
183
|
_raise_udc_completed_alert(get_alerting_service())
|
|
199
184
|
# Release the baton for orderly exit from the instruction loop
|
|
@@ -224,20 +209,11 @@ def _raise_udc_completed_alert(alert_service: AlertService):
|
|
|
224
209
|
)
|
|
225
210
|
|
|
226
211
|
|
|
227
|
-
def _runner_sleep(parameters: Wait) -> MsgGenerator:
|
|
228
|
-
yield from bps.sleep(parameters.duration_s)
|
|
229
|
-
|
|
230
|
-
|
|
231
212
|
def _is_requesting_baton(baton: Baton) -> MsgGenerator:
|
|
232
213
|
requested_user = yield from bps.rd(baton.requested_user)
|
|
233
214
|
return requested_user == HYPERION_USER
|
|
234
215
|
|
|
235
216
|
|
|
236
|
-
def _move_to_udc_default_state(context: BlueskyContext):
|
|
237
|
-
udc_default_devices = device_composite_from_context(context, UDCDefaultDevices)
|
|
238
|
-
yield from move_to_udc_default_state(udc_default_devices)
|
|
239
|
-
|
|
240
|
-
|
|
241
217
|
def _get_baton(context: BlueskyContext) -> Baton:
|
|
242
218
|
return find_device_in_context(context, "baton", Baton)
|
|
243
219
|
|
|
@@ -255,19 +231,3 @@ def _unrequest_baton(baton: Baton) -> MsgGenerator[str]:
|
|
|
255
231
|
yield from bps.abs_set(baton.requested_user, NO_USER)
|
|
256
232
|
return NO_USER
|
|
257
233
|
return requested_user
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
def _clean_up_udc(context: BlueskyContext, visit: str) -> MsgGenerator:
|
|
261
|
-
cleanup_group = "cleanup"
|
|
262
|
-
robot = find_device_in_context(context, "robot", BartRobot)
|
|
263
|
-
smargon = find_device_in_context(context, "smargon", Smargon)
|
|
264
|
-
aperture_scatterguard = find_device_in_context(
|
|
265
|
-
context, "aperture_scatterguard", ApertureScatterguard
|
|
266
|
-
)
|
|
267
|
-
lower_gonio = find_device_in_context(context, "lower_gonio", XYZStage)
|
|
268
|
-
detector_motion = find_device_in_context(context, "detector_motion", DetectorMotion)
|
|
269
|
-
yield from bps.abs_set(
|
|
270
|
-
detector_motion.shutter, ShutterState.CLOSED, group=cleanup_group
|
|
271
|
-
)
|
|
272
|
-
yield from robot_unload(robot, smargon, aperture_scatterguard, lower_gonio, visit)
|
|
273
|
-
yield from bps.wait(cleanup_group)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
env:
|
|
2
|
+
sources:
|
|
3
|
+
- kind: deviceManager
|
|
4
|
+
module: dodal.beamlines.i03
|
|
5
|
+
- kind: planFunctions
|
|
6
|
+
module: mx_bluesky.hyperion.blueapi_plans
|
|
7
|
+
events:
|
|
8
|
+
broadcast_status_events: false
|
|
9
|
+
api:
|
|
10
|
+
url: http://localhost:5005
|
|
11
|
+
stomp:
|
|
12
|
+
enabled: true
|
|
13
|
+
url: tcp://localhost:61613
|
|
14
|
+
logging:
|
|
15
|
+
graylog:
|
|
16
|
+
url: "tcp://graylog-log-target.diamond.ac.uk:12232"
|
|
17
|
+
enabled: true
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
env:
|
|
2
|
+
sources:
|
|
3
|
+
- kind: deviceManager
|
|
4
|
+
module: dodal.beamlines.i03
|
|
5
|
+
mock: true
|
|
6
|
+
- kind: planFunctions
|
|
7
|
+
module: mx_bluesky.hyperion.blueapi_plans
|
|
8
|
+
events:
|
|
9
|
+
broadcast_status_events: false
|
|
10
|
+
api:
|
|
11
|
+
url: http://localhost:5005
|
|
12
|
+
stomp:
|
|
13
|
+
enabled: true
|
|
14
|
+
url: tcp://localhost:61613
|
|
15
|
+
logging:
|
|
16
|
+
level: DEBUG
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the bluesky plan entry points for use with hyperion-blueapi.
|
|
3
|
+
The json schema and documentation therein generated by the blueapi /plans endpoint
|
|
4
|
+
from this file constitutes the hyperion-blueapi interface to the hyperion supervisor
|
|
5
|
+
process.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from bluesky import plan_stubs as bps
|
|
9
|
+
from bluesky.utils import MsgGenerator
|
|
10
|
+
from dodal.common import inject
|
|
11
|
+
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
12
|
+
from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
|
|
13
|
+
from dodal.devices.motors import XYZStage
|
|
14
|
+
from dodal.devices.robot import BartRobot
|
|
15
|
+
from dodal.devices.smargon import Smargon
|
|
16
|
+
|
|
17
|
+
from mx_bluesky.common.device_setup_plans.robot_load_unload import (
|
|
18
|
+
robot_unload as _robot_unload,
|
|
19
|
+
)
|
|
20
|
+
from mx_bluesky.hyperion.experiment_plans.load_centre_collect_full_plan import (
|
|
21
|
+
LoadCentreCollectComposite,
|
|
22
|
+
)
|
|
23
|
+
from mx_bluesky.hyperion.experiment_plans.load_centre_collect_full_plan import (
|
|
24
|
+
load_centre_collect_full as _load_centre_collect_full,
|
|
25
|
+
)
|
|
26
|
+
from mx_bluesky.hyperion.experiment_plans.udc_default_state import (
|
|
27
|
+
UDCDefaultDevices,
|
|
28
|
+
)
|
|
29
|
+
from mx_bluesky.hyperion.experiment_plans.udc_default_state import (
|
|
30
|
+
move_to_udc_default_state as _move_to_udc_default_state,
|
|
31
|
+
)
|
|
32
|
+
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"LoadCentreCollectComposite",
|
|
36
|
+
"LoadCentreCollect",
|
|
37
|
+
"UDCDefaultDevices",
|
|
38
|
+
"clean_up_udc",
|
|
39
|
+
"load_centre_collect",
|
|
40
|
+
"move_to_udc_default_state",
|
|
41
|
+
"robot_unload",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def load_centre_collect(
|
|
46
|
+
parameters: LoadCentreCollect, composite: LoadCentreCollectComposite = inject()
|
|
47
|
+
) -> MsgGenerator:
|
|
48
|
+
"""
|
|
49
|
+
Attempt a complete data collection experiment, consisting of the following:
|
|
50
|
+
* Load the sample if necessary
|
|
51
|
+
* Move to the specified goniometer start angles
|
|
52
|
+
* Perform optical centring, then X-ray centring
|
|
53
|
+
* If X-ray centring finds one or more diffracting centres then for each centre
|
|
54
|
+
that satisfies the chosen selection function,
|
|
55
|
+
move to that centre and do a collection with the specified parameters.
|
|
56
|
+
"""
|
|
57
|
+
yield from _load_centre_collect_full(composite, parameters)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def robot_unload(
|
|
61
|
+
visit: str,
|
|
62
|
+
robot: BartRobot = inject("robot"),
|
|
63
|
+
smargon: Smargon = inject("smargon"),
|
|
64
|
+
aperture_scatterguard: ApertureScatterguard = inject("aperture_scatterguard"),
|
|
65
|
+
lower_gonio: XYZStage = inject("lower_gonio"),
|
|
66
|
+
) -> MsgGenerator:
|
|
67
|
+
"""
|
|
68
|
+
Unload the currently mounted pin into the location that it was loaded from.
|
|
69
|
+
This is to be invoked as the final step upon successful completion of the UDC queue.
|
|
70
|
+
"""
|
|
71
|
+
yield from _robot_unload(robot, smargon, aperture_scatterguard, lower_gonio, visit)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def clean_up_udc(
|
|
75
|
+
visit: str,
|
|
76
|
+
cleanup_group: str = "cleanup",
|
|
77
|
+
robot: BartRobot = inject("robot"),
|
|
78
|
+
smargon: Smargon = inject("smargon"),
|
|
79
|
+
aperture_scatterguard: ApertureScatterguard = inject("aperture_scatterguard"),
|
|
80
|
+
lower_gonio: XYZStage = inject("lower_gonio"),
|
|
81
|
+
detector_motion: DetectorMotion = inject("detector_motion"),
|
|
82
|
+
) -> MsgGenerator:
|
|
83
|
+
yield from bps.abs_set(
|
|
84
|
+
detector_motion.shutter, ShutterState.CLOSED, group=cleanup_group
|
|
85
|
+
)
|
|
86
|
+
yield from _robot_unload(robot, smargon, aperture_scatterguard, lower_gonio, visit)
|
|
87
|
+
yield from bps.wait(cleanup_group)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def move_to_udc_default_state(
|
|
91
|
+
composite: UDCDefaultDevices = inject(),
|
|
92
|
+
) -> MsgGenerator:
|
|
93
|
+
"""
|
|
94
|
+
Move beamline hardware to known positions prior to UDC start.
|
|
95
|
+
"""
|
|
96
|
+
yield from _move_to_udc_default_state(composite)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
|
-
|
|
3
1
|
import bluesky.plan_stubs as bps
|
|
4
2
|
from dodal.devices.focusing_mirror import (
|
|
5
3
|
FocusingMirrorWithStripes,
|
|
@@ -17,6 +15,9 @@ from mx_bluesky.common.utils.log import LOGGER
|
|
|
17
15
|
from mx_bluesky.common.utils.utils import (
|
|
18
16
|
energy_to_bragg_angle,
|
|
19
17
|
)
|
|
18
|
+
from mx_bluesky.hyperion.external_interaction.config_server import (
|
|
19
|
+
get_hyperion_config_client,
|
|
20
|
+
)
|
|
20
21
|
|
|
21
22
|
MIRROR_VOLTAGE_GROUP = "MIRROR_VOLTAGE_GROUP"
|
|
22
23
|
DCM_GROUP = "DCM_GROUP"
|
|
@@ -27,11 +28,12 @@ def _apply_and_wait_for_voltages_to_settle(
|
|
|
27
28
|
stripe: MirrorStripe,
|
|
28
29
|
mirror_voltages: MirrorVoltages,
|
|
29
30
|
):
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
config_server = get_hyperion_config_client()
|
|
32
|
+
config_dict = config_server.get_file_contents(
|
|
33
|
+
mirror_voltages.voltage_lookup_table_path, dict
|
|
34
|
+
)
|
|
33
35
|
# sample mode is the only mode supported
|
|
34
|
-
sample_data =
|
|
36
|
+
sample_data = config_dict["sample"]
|
|
35
37
|
if stripe == MirrorStripe.BARE:
|
|
36
38
|
stripe_key = "bare"
|
|
37
39
|
elif stripe == MirrorStripe.RHODIUM:
|
|
@@ -16,8 +16,8 @@ from ophyd_async.fastcs.panda import (
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
from mx_bluesky.common.device_setup_plans.setup_panda import load_panda_from_yaml
|
|
19
|
+
from mx_bluesky.common.parameters.constants import DeviceSettingsConstants
|
|
19
20
|
from mx_bluesky.common.utils.log import LOGGER
|
|
20
|
-
from mx_bluesky.hyperion.parameters.constants import DeviceSettingsConstants
|
|
21
21
|
|
|
22
22
|
MM_TO_ENCODER_COUNTS = 200000
|
|
23
23
|
GENERAL_TIMEOUT = 60
|
|
@@ -4,6 +4,9 @@ from collections.abc import Callable
|
|
|
4
4
|
from typing import TypedDict
|
|
5
5
|
|
|
6
6
|
import mx_bluesky.hyperion.experiment_plans.rotation_scan_plan as rotation_scan_plan
|
|
7
|
+
from mx_bluesky.common.parameters.rotation import (
|
|
8
|
+
RotationScan,
|
|
9
|
+
)
|
|
7
10
|
from mx_bluesky.hyperion.experiment_plans import (
|
|
8
11
|
hyperion_grid_detect_then_xray_centre_plan,
|
|
9
12
|
load_centre_collect_full_plan,
|
|
@@ -15,7 +18,6 @@ from mx_bluesky.hyperion.parameters.gridscan import (
|
|
|
15
18
|
PinTipCentreThenXrayCentre,
|
|
16
19
|
)
|
|
17
20
|
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
|
|
18
|
-
from mx_bluesky.hyperion.parameters.rotation import RotationScan
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
def not_implemented():
|
|
@@ -49,11 +49,8 @@ def construct_hyperion_specific_features(
|
|
|
49
49
|
signals_to_read_pre_flyscan = [
|
|
50
50
|
xrc_composite.undulator.current_gap,
|
|
51
51
|
xrc_composite.synchrotron.synchrotron_mode,
|
|
52
|
-
xrc_composite.s4_slit_gaps
|
|
53
|
-
xrc_composite.
|
|
54
|
-
xrc_composite.smargon.x,
|
|
55
|
-
xrc_composite.smargon.y,
|
|
56
|
-
xrc_composite.smargon.z,
|
|
52
|
+
xrc_composite.s4_slit_gaps,
|
|
53
|
+
xrc_composite.smargon,
|
|
57
54
|
xrc_composite.dcm.energy_in_keV,
|
|
58
55
|
]
|
|
59
56
|
|
|
@@ -64,6 +61,8 @@ def construct_hyperion_specific_features(
|
|
|
64
61
|
xrc_composite.dcm.energy_in_keV,
|
|
65
62
|
xrc_composite.eiger.bit_depth,
|
|
66
63
|
xrc_composite.beamsize,
|
|
64
|
+
xrc_composite.eiger.cam.roi_mode,
|
|
65
|
+
xrc_composite.eiger.ispyb_detector_id,
|
|
67
66
|
]
|
|
68
67
|
|
|
69
68
|
setup_trigger_plan: Callable[..., MsgGenerator]
|
|
@@ -11,7 +11,7 @@ from mx_bluesky.common.experiment_plans.common_grid_detect_then_xray_centre_plan
|
|
|
11
11
|
)
|
|
12
12
|
from mx_bluesky.common.parameters.constants import OavConstants, PlanNameConstants
|
|
13
13
|
from mx_bluesky.common.preprocessors.preprocessors import (
|
|
14
|
-
|
|
14
|
+
pause_xbpm_feedback_during_collection_at_desired_transmission_decorator,
|
|
15
15
|
)
|
|
16
16
|
from mx_bluesky.common.utils.context import device_composite_from_context
|
|
17
17
|
from mx_bluesky.hyperion.experiment_plans.hyperion_flyscan_xray_centre_plan import (
|
|
@@ -45,7 +45,7 @@ def hyperion_grid_detect_then_xray_centre(
|
|
|
45
45
|
"""
|
|
46
46
|
|
|
47
47
|
@verify_undulator_gap_before_run_decorator(composite)
|
|
48
|
-
@
|
|
48
|
+
@pause_xbpm_feedback_during_collection_at_desired_transmission_decorator(
|
|
49
49
|
composite, parameters.transmission_frac, PlanNameConstants.GRIDSCAN_OUTER
|
|
50
50
|
)
|
|
51
51
|
def plan_to_perform():
|