mx-bluesky 1.4.3__py3-none-any.whl → 1.4.5__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/i24/serial/fixed_target/i24ssx_moveonclick.py +2 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +2 -2
- mx_bluesky/common/device_setup_plans/setup_panda.py +9 -0
- mx_bluesky/common/external_interaction/callbacks/common/zocalo_callback.py +4 -15
- mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +9 -1
- mx_bluesky/common/parameters/components.py +0 -1
- mx_bluesky/common/parameters/constants.py +16 -0
- mx_bluesky/common/parameters/gridscan.py +6 -1
- mx_bluesky/common/plans/do_fgs.py +0 -6
- mx_bluesky/common/utils/exceptions.py +2 -1
- mx_bluesky/definitions.py +4 -0
- mx_bluesky/hyperion/__main__.py +8 -43
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +9 -8
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +10 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +0 -15
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +11 -8
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +8 -0
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +23 -16
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +1 -5
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +1 -8
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +12 -4
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +24 -5
- mx_bluesky/hyperion/external_interaction/config_server.py +13 -2
- mx_bluesky/hyperion/parameters/cli.py +1 -9
- mx_bluesky/hyperion/parameters/constants.py +6 -1
- mx_bluesky/hyperion/parameters/gridscan.py +5 -5
- mx_bluesky/hyperion/resources/panda/panda-gridscan.yaml +1006 -964
- mx_bluesky/hyperion/utils/validation.py +20 -17
- {mx_bluesky-1.4.3.dist-info → mx_bluesky-1.4.5.dist-info}/METADATA +3 -3
- {mx_bluesky-1.4.3.dist-info → mx_bluesky-1.4.5.dist-info}/RECORD +36 -36
- mx_bluesky/hyperion/external_interaction/callbacks/common/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +0 -80
- {mx_bluesky-1.4.3.dist-info → mx_bluesky-1.4.5.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.4.3.dist-info → mx_bluesky-1.4.5.dist-info}/WHEEL +0 -0
- {mx_bluesky-1.4.3.dist-info → mx_bluesky-1.4.5.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.4.3.dist-info → mx_bluesky-1.4.5.dist-info}/top_level.txt +0 -0
mx_bluesky/_version.py
CHANGED
|
@@ -215,6 +215,6 @@ def start_viewer(oav: OAV, pmac: PMAC, RE: RunEngine, oav1: str = OAV1_CAM):
|
|
|
215
215
|
if __name__ == "__main__":
|
|
216
216
|
RE = RunEngine(call_returns_result=True)
|
|
217
217
|
# Get devices out of dodal
|
|
218
|
-
oav: OAV = i24.oav()
|
|
219
|
-
pmac: PMAC = i24.pmac()
|
|
218
|
+
oav: OAV = i24.oav(connect_immediately=True)
|
|
219
|
+
pmac: PMAC = i24.pmac(connect_immediately=True)
|
|
220
220
|
start_viewer(oav, pmac, RE)
|
|
@@ -21,9 +21,9 @@ from mx_bluesky.beamlines.i24.serial.setup_beamline.ca import caget, caput
|
|
|
21
21
|
|
|
22
22
|
def get_beam_center_device(detector_in_use: str) -> DetectorBeamCenter:
|
|
23
23
|
if detector_in_use == "eiger":
|
|
24
|
-
return i24.eiger_beam_center()
|
|
24
|
+
return i24.eiger_beam_center(connect_immediately=True)
|
|
25
25
|
else:
|
|
26
|
-
return i24.pilatus_beam_center()
|
|
26
|
+
return i24.pilatus_beam_center(connect_immediately=True)
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def compute_beam_center_position_from_lut(
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from ophyd_async.core import YamlSettingsProvider
|
|
2
|
+
from ophyd_async.fastcs.panda import HDFPanda
|
|
3
|
+
from ophyd_async.plan_stubs import apply_panda_settings, retrieve_settings
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def load_panda_from_yaml(yaml_directory: str, yaml_file_name: str, panda: HDFPanda):
|
|
7
|
+
provider = YamlSettingsProvider(yaml_directory)
|
|
8
|
+
settings = yield from retrieve_settings(provider, yaml_file_name, panda)
|
|
9
|
+
yield from apply_panda_settings(settings)
|
|
@@ -7,7 +7,6 @@ from dodal.devices.zocalo import ZocaloStartInfo, ZocaloTrigger
|
|
|
7
7
|
|
|
8
8
|
from mx_bluesky.common.parameters.constants import (
|
|
9
9
|
DocDescriptorNames,
|
|
10
|
-
TriggerConstants,
|
|
11
10
|
)
|
|
12
11
|
from mx_bluesky.common.utils.exceptions import ISPyBDepositionNotMade
|
|
13
12
|
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER
|
|
@@ -30,27 +29,17 @@ class ZocaloCallback(CallbackBase):
|
|
|
30
29
|
|
|
31
30
|
def _reset_state(self):
|
|
32
31
|
self.run_uid: str | None = None
|
|
33
|
-
self.triggering_plan: str | None = None
|
|
34
|
-
self.zocalo_interactor: ZocaloTrigger | None = None
|
|
35
32
|
self.zocalo_info: list[ZocaloStartInfo] = []
|
|
36
33
|
self.descriptors: dict[str, EventDescriptor] = {}
|
|
37
34
|
|
|
38
|
-
def __init__(
|
|
39
|
-
self,
|
|
40
|
-
):
|
|
35
|
+
def __init__(self, triggering_plan: str, zocalo_environment: str):
|
|
41
36
|
super().__init__()
|
|
37
|
+
self.triggering_plan = triggering_plan
|
|
38
|
+
self.zocalo_interactor = ZocaloTrigger(zocalo_environment)
|
|
42
39
|
self._reset_state()
|
|
43
40
|
|
|
44
41
|
def start(self, doc: RunStart):
|
|
45
42
|
ISPYB_ZOCALO_CALLBACK_LOGGER.info("Zocalo handler received start document.")
|
|
46
|
-
if triggering_plan := doc.get(TriggerConstants.ZOCALO):
|
|
47
|
-
self.triggering_plan = triggering_plan
|
|
48
|
-
assert isinstance(zocalo_environment := doc.get("zocalo_environment"), str)
|
|
49
|
-
ISPYB_ZOCALO_CALLBACK_LOGGER.info(
|
|
50
|
-
f"Zocalo environment set to {zocalo_environment}."
|
|
51
|
-
)
|
|
52
|
-
self.zocalo_interactor = ZocaloTrigger(zocalo_environment)
|
|
53
|
-
|
|
54
43
|
if self.triggering_plan and doc.get("subplan_name") == self.triggering_plan:
|
|
55
44
|
self.run_uid = doc.get("uid")
|
|
56
45
|
assert isinstance(scan_points := doc.get("scan_points"), list)
|
|
@@ -58,6 +47,7 @@ class ZocaloCallback(CallbackBase):
|
|
|
58
47
|
isinstance(ispyb_ids := doc.get("ispyb_dcids"), tuple)
|
|
59
48
|
and len(ispyb_ids) > 0
|
|
60
49
|
):
|
|
50
|
+
ISPYB_ZOCALO_CALLBACK_LOGGER.info(f"Zocalo triggering for {ispyb_ids}")
|
|
61
51
|
ids_and_shape = list(zip(ispyb_ids, scan_points, strict=False))
|
|
62
52
|
start_frame = 0
|
|
63
53
|
self.zocalo_info = []
|
|
@@ -82,7 +72,6 @@ class ZocaloCallback(CallbackBase):
|
|
|
82
72
|
filename = doc["data"]["eiger_odin_file_writer_id"]
|
|
83
73
|
for start_info in self.zocalo_info:
|
|
84
74
|
start_info.filename = filename
|
|
85
|
-
assert self.zocalo_interactor is not None
|
|
86
75
|
self.zocalo_interactor.run_start(start_info)
|
|
87
76
|
return doc
|
|
88
77
|
|
|
@@ -43,7 +43,10 @@ from mx_bluesky.common.parameters.constants import DocDescriptorNames, PlanNameC
|
|
|
43
43
|
from mx_bluesky.common.parameters.gridscan import (
|
|
44
44
|
GridCommon,
|
|
45
45
|
)
|
|
46
|
-
from mx_bluesky.common.utils.exceptions import
|
|
46
|
+
from mx_bluesky.common.utils.exceptions import (
|
|
47
|
+
ISPyBDepositionNotMade,
|
|
48
|
+
SampleException,
|
|
49
|
+
)
|
|
47
50
|
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER, set_dcgid_tag
|
|
48
51
|
|
|
49
52
|
if TYPE_CHECKING:
|
|
@@ -281,5 +284,10 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
281
284
|
)
|
|
282
285
|
if self.ispyb_ids == IspybIds():
|
|
283
286
|
raise ISPyBDepositionNotMade("ispyb was not initialised at run start")
|
|
287
|
+
exception_type, message = SampleException.type_and_message_from_reason(
|
|
288
|
+
doc.get("reason", "")
|
|
289
|
+
)
|
|
290
|
+
if exception_type:
|
|
291
|
+
doc["reason"] = message
|
|
284
292
|
return super().activity_gated_stop(doc)
|
|
285
293
|
return self._tag_doc(doc)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from enum import Enum
|
|
2
3
|
|
|
3
4
|
from dodal.devices.aperturescatterguard import ApertureValue
|
|
@@ -6,6 +7,8 @@ from dodal.devices.zocalo.zocalo_constants import ZOCALO_ENV as ZOCALO_ENV_FROM_
|
|
|
6
7
|
from dodal.utils import get_beamline_name
|
|
7
8
|
from pydantic.dataclasses import dataclass
|
|
8
9
|
|
|
10
|
+
from mx_bluesky.definitions import ROOT_DIR
|
|
11
|
+
|
|
9
12
|
BEAMLINE = get_beamline_name("test")
|
|
10
13
|
TEST_MODE = BEAMLINE == "test"
|
|
11
14
|
|
|
@@ -75,6 +78,10 @@ class HardwareConstants:
|
|
|
75
78
|
THAWING_TIME = 20
|
|
76
79
|
TIP_OFFSET_UM = 0
|
|
77
80
|
|
|
81
|
+
# Value quoted in https://www.dectris.com/en/detectors/x-ray-detectors/eiger2/eiger2-for-synchrotrons/eiger2-x/,
|
|
82
|
+
# causes dropped frames, so increase value for safety
|
|
83
|
+
PANDA_FGS_EIGER_DEADTIME_S = 5e-5
|
|
84
|
+
|
|
78
85
|
|
|
79
86
|
@dataclass(frozen=True)
|
|
80
87
|
class GridscanParamConstants:
|
|
@@ -118,6 +125,15 @@ class PlanGroupCheckpointConstants:
|
|
|
118
125
|
READY_FOR_OAV = "ready_for_oav"
|
|
119
126
|
|
|
120
127
|
|
|
128
|
+
# Eventually replace below with https://github.com/DiamondLightSource/mx-bluesky/issues/798
|
|
129
|
+
@dataclass(frozen=True)
|
|
130
|
+
class DeviceSettingsConstants:
|
|
131
|
+
PANDA_FLYSCAN_SETTINGS_FILENAME = "panda-gridscan"
|
|
132
|
+
PANDA_FLYSCAN_SETTINGS_DIR = os.path.abspath(
|
|
133
|
+
f"{ROOT_DIR}/hyperion/resources/panda/{PANDA_FLYSCAN_SETTINGS_FILENAME}"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
121
137
|
@dataclass(frozen=True)
|
|
122
138
|
class SimConstants:
|
|
123
139
|
BEAMLINE = "BL03S"
|
|
@@ -29,8 +29,13 @@ class GridCommon(
|
|
|
29
29
|
DiffractionExperimentWithSample,
|
|
30
30
|
OptionalGonioAngleStarts,
|
|
31
31
|
):
|
|
32
|
-
"""
|
|
32
|
+
"""
|
|
33
|
+
Parameters used in every MX diffraction experiment using grids. This model should
|
|
34
|
+
be used by plans which have no knowledge of the grid specifications - i.e before
|
|
35
|
+
automatic grid detection has completed
|
|
36
|
+
"""
|
|
33
37
|
|
|
38
|
+
box_size_um: float = Field(default=GridscanParamConstants.BOX_WIDTH_UM)
|
|
34
39
|
grid_width_um: float = Field(default=GridscanParamConstants.WIDTH_UM)
|
|
35
40
|
exposure_time_s: float = Field(default=GridscanParamConstants.EXPOSURE_TIME_S)
|
|
36
41
|
|
|
@@ -18,9 +18,7 @@ from mx_bluesky.common.device_setup_plans.read_hardware_for_setup import (
|
|
|
18
18
|
read_hardware_for_zocalo,
|
|
19
19
|
)
|
|
20
20
|
from mx_bluesky.common.parameters.constants import (
|
|
21
|
-
EnvironmentConstants,
|
|
22
21
|
PlanNameConstants,
|
|
23
|
-
TriggerConstants,
|
|
24
22
|
)
|
|
25
23
|
from mx_bluesky.common.utils.tracing import TRACER
|
|
26
24
|
|
|
@@ -70,7 +68,6 @@ def kickoff_and_complete_gridscan(
|
|
|
70
68
|
scan_points: list[AxesPoints[Axis]],
|
|
71
69
|
scan_start_indices: list[int],
|
|
72
70
|
plan_during_collection: Callable[[], MsgGenerator] | None = None,
|
|
73
|
-
zocalo_environment: str = EnvironmentConstants.ZOCALO_ENV,
|
|
74
71
|
):
|
|
75
72
|
"""Triggers a grid scan motion program and waits for completion, accounting for synchrotron topup.
|
|
76
73
|
If the RunEngine is subscribed to ZocaloCallback, this plan will also trigger Zocalo.
|
|
@@ -86,7 +83,6 @@ def kickoff_and_complete_gridscan(
|
|
|
86
83
|
scan_start_indices (list[int]): Contains the first index of each grid scan
|
|
87
84
|
plan_during_collection (Optional, MsgGenerator): Generic plan called in between kickoff and completion,
|
|
88
85
|
eg waiting on zocalo.
|
|
89
|
-
zocalo_environment (Optional, str) Used for zocalo connection
|
|
90
86
|
"""
|
|
91
87
|
|
|
92
88
|
assert len(scan_points) == len(scan_start_indices), (
|
|
@@ -100,10 +96,8 @@ def kickoff_and_complete_gridscan(
|
|
|
100
96
|
@bpp.run_decorator(
|
|
101
97
|
md={
|
|
102
98
|
"subplan_name": plan_name,
|
|
103
|
-
TriggerConstants.ZOCALO: plan_name,
|
|
104
99
|
"scan_points": scan_points,
|
|
105
100
|
"scan_start_indices": scan_start_indices,
|
|
106
|
-
"zocalo_environment": zocalo_environment,
|
|
107
101
|
}
|
|
108
102
|
)
|
|
109
103
|
@bpp.contingency_decorator(
|
|
@@ -39,7 +39,8 @@ T = TypeVar("T")
|
|
|
39
39
|
class CrystalNotFoundException(SampleException):
|
|
40
40
|
"""Raised if grid detection completed normally but no crystal was found."""
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
def __init__(self, *args):
|
|
43
|
+
super().__init__("Diffraction not found, skipping sample.")
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
def catch_exception_and_warn(
|
mx_bluesky/hyperion/__main__.py
CHANGED
|
@@ -4,6 +4,7 @@ import threading
|
|
|
4
4
|
from collections.abc import Callable
|
|
5
5
|
from dataclasses import asdict
|
|
6
6
|
from queue import Queue
|
|
7
|
+
from sys import argv
|
|
7
8
|
from traceback import format_exception
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
@@ -37,12 +38,6 @@ from mx_bluesky.hyperion.experiment_plans.experiment_registry import (
|
|
|
37
38
|
PLAN_REGISTRY,
|
|
38
39
|
PlanNotFound,
|
|
39
40
|
)
|
|
40
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.__main__ import (
|
|
41
|
-
setup_logging as setup_callback_logging,
|
|
42
|
-
)
|
|
43
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.common.callback_util import (
|
|
44
|
-
CallbacksFactory,
|
|
45
|
-
)
|
|
46
41
|
from mx_bluesky.hyperion.parameters.cli import parse_cli_args
|
|
47
42
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
48
43
|
from mx_bluesky.hyperion.utils.context import setup_context
|
|
@@ -56,7 +51,6 @@ class Command:
|
|
|
56
51
|
devices: Any | None = None
|
|
57
52
|
experiment: Callable[[Any, Any], MsgGenerator] | None = None
|
|
58
53
|
parameters: MxBlueskyParameters | None = None
|
|
59
|
-
callbacks: CallbacksFactory | None = None
|
|
60
54
|
|
|
61
55
|
|
|
62
56
|
@dataclass
|
|
@@ -88,7 +82,6 @@ class BlueskyRunner:
|
|
|
88
82
|
RE: RunEngine,
|
|
89
83
|
context: BlueskyContext,
|
|
90
84
|
skip_startup_connection=False,
|
|
91
|
-
use_external_callbacks: bool = False,
|
|
92
85
|
) -> None:
|
|
93
86
|
self.command_queue: Queue[Command] = Queue()
|
|
94
87
|
self.current_status: StatusAndMessage = StatusAndMessage(Status.IDLE)
|
|
@@ -99,15 +92,12 @@ class BlueskyRunner:
|
|
|
99
92
|
|
|
100
93
|
self.RE = RE
|
|
101
94
|
self.context = context
|
|
102
|
-
self.subscribed_per_plan_callbacks: list[int] = []
|
|
103
95
|
RE.subscribe(self.aperture_change_callback)
|
|
104
96
|
RE.subscribe(self.logging_uid_tag_callback)
|
|
105
97
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
self.publisher = Publisher(f"localhost:{CONST.CALLBACK_0MQ_PROXY_PORTS[0]}")
|
|
110
|
-
RE.subscribe(self.publisher)
|
|
98
|
+
LOGGER.info("Connecting to external callback ZMQ proxy...")
|
|
99
|
+
self.publisher = Publisher(f"localhost:{CONST.CALLBACK_0MQ_PROXY_PORTS[0]}")
|
|
100
|
+
RE.subscribe(self.publisher)
|
|
111
101
|
|
|
112
102
|
if VERBOSE_EVENT_LOGGING:
|
|
113
103
|
RE.subscribe(VerbosePlanExecutionLoggingCallback())
|
|
@@ -123,7 +113,6 @@ class BlueskyRunner:
|
|
|
123
113
|
experiment: Callable,
|
|
124
114
|
parameters: MxBlueskyParameters,
|
|
125
115
|
plan_name: str,
|
|
126
|
-
callbacks: CallbacksFactory | None,
|
|
127
116
|
) -> StatusAndMessage:
|
|
128
117
|
LOGGER.info(f"Started with parameters: {parameters.model_dump_json(indent=2)}")
|
|
129
118
|
|
|
@@ -142,7 +131,6 @@ class BlueskyRunner:
|
|
|
142
131
|
devices=devices,
|
|
143
132
|
experiment=experiment,
|
|
144
133
|
parameters=parameters,
|
|
145
|
-
callbacks=callbacks,
|
|
146
134
|
)
|
|
147
135
|
)
|
|
148
136
|
return StatusAndMessage(Status.SUCCESS)
|
|
@@ -181,17 +169,6 @@ class BlueskyRunner:
|
|
|
181
169
|
if command.experiment is None:
|
|
182
170
|
raise ValueError("No experiment provided for START")
|
|
183
171
|
try:
|
|
184
|
-
if (
|
|
185
|
-
not self.use_external_callbacks
|
|
186
|
-
and command.callbacks
|
|
187
|
-
and (cbs := command.callbacks())
|
|
188
|
-
):
|
|
189
|
-
LOGGER.info(
|
|
190
|
-
f"Using callbacks for this plan: {not self.use_external_callbacks} - {cbs}"
|
|
191
|
-
)
|
|
192
|
-
self.subscribed_per_plan_callbacks += [
|
|
193
|
-
self.RE.subscribe(cb) for cb in cbs
|
|
194
|
-
]
|
|
195
172
|
with TRACER.start_span("do_run"):
|
|
196
173
|
self.RE(command.experiment(command.devices, command.parameters))
|
|
197
174
|
|
|
@@ -212,11 +189,6 @@ class BlueskyRunner:
|
|
|
212
189
|
self.last_run_aborted = False
|
|
213
190
|
else:
|
|
214
191
|
self.current_status = make_error_status_and_message(exception)
|
|
215
|
-
finally:
|
|
216
|
-
[
|
|
217
|
-
self.RE.unsubscribe(cb)
|
|
218
|
-
for cb in self.subscribed_per_plan_callbacks
|
|
219
|
-
]
|
|
220
192
|
|
|
221
193
|
|
|
222
194
|
def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions):
|
|
@@ -225,7 +197,6 @@ def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions)
|
|
|
225
197
|
raise PlanNotFound(f"Experiment plan '{plan_name}' not found in registry.")
|
|
226
198
|
|
|
227
199
|
experiment_internal_param_type = experiment_registry_entry.get("param_type")
|
|
228
|
-
callback_type = experiment_registry_entry.get("callback_collection_type")
|
|
229
200
|
plan = context.plan_functions.get(plan_name)
|
|
230
201
|
if experiment_internal_param_type is None:
|
|
231
202
|
raise PlanNotFound(
|
|
@@ -243,7 +214,7 @@ def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions)
|
|
|
243
214
|
raise ValueError(
|
|
244
215
|
f"Supplied parameters don't match the plan for this endpoint {request.data}, for plan {plan_name}"
|
|
245
216
|
) from e
|
|
246
|
-
return plan, parameters, plan_name
|
|
217
|
+
return plan, parameters, plan_name
|
|
247
218
|
|
|
248
219
|
|
|
249
220
|
class RunExperiment(Resource):
|
|
@@ -256,12 +227,10 @@ class RunExperiment(Resource):
|
|
|
256
227
|
status_and_message = StatusAndMessage(Status.FAILED, f"{action} not understood")
|
|
257
228
|
if action == Actions.START.value:
|
|
258
229
|
try:
|
|
259
|
-
plan, params, plan_name
|
|
230
|
+
plan, params, plan_name = compose_start_args(
|
|
260
231
|
self.context, plan_name, action
|
|
261
232
|
)
|
|
262
|
-
status_and_message = self.runner.start(
|
|
263
|
-
plan, params, plan_name, callback_type
|
|
264
|
-
)
|
|
233
|
+
status_and_message = self.runner.start(plan, params, plan_name)
|
|
265
234
|
except Exception as e:
|
|
266
235
|
status_and_message = make_error_status_and_message(e)
|
|
267
236
|
LOGGER.error(format_exception(e))
|
|
@@ -312,7 +281,6 @@ def create_app(
|
|
|
312
281
|
test_config=None,
|
|
313
282
|
RE: RunEngine = RunEngine({}),
|
|
314
283
|
skip_startup_connection: bool = False,
|
|
315
|
-
use_external_callbacks: bool = False,
|
|
316
284
|
) -> tuple[Flask, BlueskyRunner]:
|
|
317
285
|
context = setup_context(
|
|
318
286
|
wait_for_connection=not skip_startup_connection,
|
|
@@ -320,7 +288,6 @@ def create_app(
|
|
|
320
288
|
runner = BlueskyRunner(
|
|
321
289
|
RE,
|
|
322
290
|
context=context,
|
|
323
|
-
use_external_callbacks=use_external_callbacks,
|
|
324
291
|
skip_startup_connection=skip_startup_connection,
|
|
325
292
|
)
|
|
326
293
|
app = Flask(__name__)
|
|
@@ -350,11 +317,9 @@ def create_targets():
|
|
|
350
317
|
do_default_logging_setup(
|
|
351
318
|
CONST.LOG_FILE_NAME, CONST.GRAYLOG_PORT, dev_mode=args.dev_mode
|
|
352
319
|
)
|
|
353
|
-
|
|
354
|
-
setup_callback_logging(args.dev_mode)
|
|
320
|
+
LOGGER.info(f"Hyperion launched with args:{argv}")
|
|
355
321
|
app, runner = create_app(
|
|
356
322
|
skip_startup_connection=args.skip_startup_connection,
|
|
357
|
-
use_external_callbacks=args.use_external_callbacks,
|
|
358
323
|
)
|
|
359
324
|
return app, runner, hyperion_port, args.dev_mode
|
|
360
325
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
from enum import Enum
|
|
3
|
-
from importlib import resources
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
|
|
6
5
|
import bluesky.plan_stubs as bps
|
|
@@ -8,15 +7,15 @@ from bluesky.utils import MsgGenerator
|
|
|
8
7
|
from dodal.common.beamlines.beamline_utils import get_path_provider
|
|
9
8
|
from dodal.devices.fast_grid_scan import PandAGridScanParams
|
|
10
9
|
from dodal.devices.smargon import Smargon
|
|
11
|
-
from ophyd_async.core import load_device
|
|
12
10
|
from ophyd_async.fastcs.panda import (
|
|
13
11
|
HDFPanda,
|
|
14
12
|
SeqTable,
|
|
15
13
|
SeqTrigger,
|
|
16
14
|
)
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
from mx_bluesky.common.device_setup_plans.setup_panda import load_panda_from_yaml
|
|
19
17
|
from mx_bluesky.common.utils.log import LOGGER
|
|
18
|
+
from mx_bluesky.hyperion.parameters.constants import DeviceSettingsConstants
|
|
20
19
|
|
|
21
20
|
MM_TO_ENCODER_COUNTS = 200000
|
|
22
21
|
GENERAL_TIMEOUT = 60
|
|
@@ -76,7 +75,8 @@ def _get_seq_table(
|
|
|
76
75
|
|
|
77
76
|
num_pulses = parameters.x_steps
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
# Integer precision here is 1e-6s, so casting is safe
|
|
79
|
+
delay_between_pulses = int(time_between_steps_ms * TICKS_PER_MS)
|
|
80
80
|
|
|
81
81
|
assert delay_between_pulses > PULSE_WIDTH_US
|
|
82
82
|
|
|
@@ -145,10 +145,11 @@ def setup_panda_for_flyscan(
|
|
|
145
145
|
|
|
146
146
|
yield from bps.stage(panda, group="panda-config")
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
yield from load_panda_from_yaml(
|
|
149
|
+
DeviceSettingsConstants.PANDA_FLYSCAN_SETTINGS_DIR,
|
|
150
|
+
DeviceSettingsConstants.PANDA_FLYSCAN_SETTINGS_FILENAME,
|
|
151
|
+
panda,
|
|
152
|
+
)
|
|
152
153
|
|
|
153
154
|
initial_x = yield from bps.rd(smargon.x.user_readback)
|
|
154
155
|
initial_y = yield from bps.rd(smargon.y.user_readback)
|
|
@@ -2,6 +2,8 @@ from bluesky import plan_stubs as bps
|
|
|
2
2
|
from bluesky.preprocessors import finalize_wrapper
|
|
3
3
|
from bluesky.utils import make_decorator
|
|
4
4
|
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
5
|
+
from dodal.devices.dcm import DCM
|
|
6
|
+
from dodal.devices.undulator import Undulator
|
|
5
7
|
from dodal.devices.xbpm_feedback import Pause, XBPMFeedback
|
|
6
8
|
|
|
7
9
|
from mx_bluesky.common.utils.log import LOGGER
|
|
@@ -49,8 +51,10 @@ def _unpause_xbpm_feedback_and_set_transmission_to_1(
|
|
|
49
51
|
|
|
50
52
|
def transmission_and_xbpm_feedback_for_collection_wrapper(
|
|
51
53
|
plan,
|
|
54
|
+
undulator: Undulator,
|
|
52
55
|
xbpm_feedback: XBPMFeedback,
|
|
53
56
|
attenuator: BinaryFilterAttenuator,
|
|
57
|
+
dcm: DCM,
|
|
54
58
|
desired_transmission_fraction: float,
|
|
55
59
|
):
|
|
56
60
|
"""Sets the transmission for the data collection, ensuring the xbpm feedback is valid
|
|
@@ -66,6 +70,9 @@ def transmission_and_xbpm_feedback_for_collection_wrapper(
|
|
|
66
70
|
mostly accounts for slow thermal drift so it is safe to assume that the beam is
|
|
67
71
|
stable during a collection.
|
|
68
72
|
|
|
73
|
+
In the case of a beam dump, undulator gap may not return. Therefore, we check here
|
|
74
|
+
that the undulator gap is correct after XBPM is stable, and before collection.
|
|
75
|
+
|
|
69
76
|
Args:
|
|
70
77
|
plan: The plan performing the data collection
|
|
71
78
|
xbpm_feedback (XBPMFeedback): The XBPM device that is responsible for keeping
|
|
@@ -78,6 +85,9 @@ def transmission_and_xbpm_feedback_for_collection_wrapper(
|
|
|
78
85
|
yield from _check_and_pause_feedback(
|
|
79
86
|
xbpm_feedback, attenuator, desired_transmission_fraction
|
|
80
87
|
)
|
|
88
|
+
# Verify Undulator gap is correct, as may not be after a beam dump
|
|
89
|
+
energy_in_kev = yield from bps.rd(dcm.energy_in_kev.user_readback)
|
|
90
|
+
yield from bps.abs_set(undulator, energy_in_kev, wait=True)
|
|
81
91
|
return (yield from plan)
|
|
82
92
|
|
|
83
93
|
return (
|
|
@@ -11,13 +11,6 @@ from mx_bluesky.hyperion.experiment_plans import (
|
|
|
11
11
|
pin_centre_then_xray_centre_plan,
|
|
12
12
|
robot_load_then_centre_plan,
|
|
13
13
|
)
|
|
14
|
-
from mx_bluesky.hyperion.external_interaction.callbacks.common.callback_util import (
|
|
15
|
-
CallbacksFactory,
|
|
16
|
-
create_gridscan_callbacks,
|
|
17
|
-
create_load_centre_collect_callbacks,
|
|
18
|
-
create_robot_load_and_centre_callbacks,
|
|
19
|
-
create_rotation_callbacks,
|
|
20
|
-
)
|
|
21
14
|
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
22
15
|
GridScanWithEdgeDetect,
|
|
23
16
|
HyperionSpecifiedThreeDGridScan,
|
|
@@ -47,44 +40,36 @@ class ExperimentRegistryEntry(TypedDict):
|
|
|
47
40
|
| LoadCentreCollect
|
|
48
41
|
| RobotLoadThenCentre
|
|
49
42
|
]
|
|
50
|
-
callbacks_factory: CallbacksFactory
|
|
51
43
|
|
|
52
44
|
|
|
53
45
|
PLAN_REGISTRY: dict[str, ExperimentRegistryEntry] = {
|
|
54
46
|
"flyscan_xray_centre": {
|
|
55
47
|
"setup": flyscan_xray_centre_plan.create_devices,
|
|
56
48
|
"param_type": HyperionSpecifiedThreeDGridScan,
|
|
57
|
-
"callbacks_factory": create_gridscan_callbacks,
|
|
58
49
|
},
|
|
59
50
|
"grid_detect_then_xray_centre": {
|
|
60
51
|
"setup": grid_detect_then_xray_centre_plan.create_devices,
|
|
61
52
|
"param_type": GridScanWithEdgeDetect,
|
|
62
|
-
"callbacks_factory": create_gridscan_callbacks,
|
|
63
53
|
},
|
|
64
54
|
"rotation_scan": {
|
|
65
55
|
"setup": rotation_scan_plan.create_devices,
|
|
66
56
|
"param_type": RotationScan,
|
|
67
|
-
"callbacks_factory": create_rotation_callbacks,
|
|
68
57
|
},
|
|
69
58
|
"pin_tip_centre_then_xray_centre": {
|
|
70
59
|
"setup": pin_centre_then_xray_centre_plan.create_devices,
|
|
71
60
|
"param_type": PinTipCentreThenXrayCentre,
|
|
72
|
-
"callbacks_factory": create_gridscan_callbacks,
|
|
73
61
|
},
|
|
74
62
|
"robot_load_then_centre": {
|
|
75
63
|
"setup": robot_load_then_centre_plan.create_devices,
|
|
76
64
|
"param_type": RobotLoadThenCentre,
|
|
77
|
-
"callbacks_factory": create_robot_load_and_centre_callbacks,
|
|
78
65
|
},
|
|
79
66
|
"multi_rotation_scan": {
|
|
80
67
|
"setup": rotation_scan_plan.create_devices,
|
|
81
68
|
"param_type": MultiRotationScan,
|
|
82
|
-
"callbacks_factory": create_rotation_callbacks,
|
|
83
69
|
},
|
|
84
70
|
"load_centre_collect_full": {
|
|
85
71
|
"setup": load_centre_collect_full_plan.create_devices,
|
|
86
72
|
"param_type": LoadCentreCollect,
|
|
87
|
-
"callbacks_factory": create_load_centre_collect_callbacks,
|
|
88
73
|
},
|
|
89
74
|
}
|
|
90
75
|
|
|
@@ -50,6 +50,7 @@ from ophyd_async.fastcs.panda import HDFPanda
|
|
|
50
50
|
from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import (
|
|
51
51
|
ispyb_activation_wrapper,
|
|
52
52
|
)
|
|
53
|
+
from mx_bluesky.common.parameters.constants import HardwareConstants
|
|
53
54
|
from mx_bluesky.common.plans.do_fgs import kickoff_and_complete_gridscan
|
|
54
55
|
from mx_bluesky.common.utils.exceptions import (
|
|
55
56
|
CrystalNotFoundException,
|
|
@@ -119,10 +120,10 @@ class XRayCentreEventHandler(CallbackBase):
|
|
|
119
120
|
self.xray_centre_results: Sequence[XRayCentreResult] | None = None
|
|
120
121
|
|
|
121
122
|
def start(self, doc: RunStart) -> RunStart | None:
|
|
122
|
-
if
|
|
123
|
+
if CONST.PLAN.FLYSCAN_RESULTS in doc:
|
|
123
124
|
self.xray_centre_results = [
|
|
124
125
|
XRayCentreResult(**result_dict)
|
|
125
|
-
for result_dict in doc[
|
|
126
|
+
for result_dict in doc[CONST.PLAN.FLYSCAN_RESULTS] # type: ignore
|
|
126
127
|
]
|
|
127
128
|
return doc
|
|
128
129
|
|
|
@@ -140,6 +141,7 @@ def flyscan_xray_centre_no_move(
|
|
|
140
141
|
composite.eiger.set_detector_parameters(parameters.detector_params)
|
|
141
142
|
composite.zocalo.zocalo_environment = CONST.ZOCALO_ENV
|
|
142
143
|
composite.zocalo.use_cpu_and_gpu = parameters.features.compare_cpu_and_gpu_zocalo
|
|
144
|
+
composite.zocalo.use_gpu = parameters.features.use_gpu_results
|
|
143
145
|
|
|
144
146
|
feature_controlled = _get_feature_controlled(composite, parameters)
|
|
145
147
|
|
|
@@ -155,8 +157,10 @@ def flyscan_xray_centre_no_move(
|
|
|
155
157
|
)
|
|
156
158
|
@bpp.finalize_decorator(lambda: feature_controlled.tidy_plan(composite))
|
|
157
159
|
@transmission_and_xbpm_feedback_for_collection_decorator(
|
|
160
|
+
composite.undulator,
|
|
158
161
|
composite.xbpm_feedback,
|
|
159
162
|
composite.attenuator,
|
|
163
|
+
composite.dcm,
|
|
160
164
|
parameters.transmission_frac,
|
|
161
165
|
)
|
|
162
166
|
def run_gridscan_and_fetch_and_tidy(
|
|
@@ -303,7 +307,7 @@ def _fire_xray_centre_result_event(results: Sequence[XRayCentreResult]):
|
|
|
303
307
|
|
|
304
308
|
yield from bpp.run_wrapper(
|
|
305
309
|
empty_plan(),
|
|
306
|
-
md={
|
|
310
|
+
md={CONST.PLAN.FLYSCAN_RESULTS: [dataclasses.asdict(r) for r in results]},
|
|
307
311
|
)
|
|
308
312
|
|
|
309
313
|
|
|
@@ -468,10 +472,9 @@ def _panda_triggering_setup(
|
|
|
468
472
|
fgs_composite.panda_fast_grid_scan.run_up_distance_mm
|
|
469
473
|
)
|
|
470
474
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
time_between_x_steps_ms = (DEADTIME_S + parameters.exposure_time_s) * 1e3
|
|
475
|
+
time_between_x_steps_ms = (
|
|
476
|
+
HardwareConstants.PANDA_FGS_EIGER_DEADTIME_S + parameters.exposure_time_s
|
|
477
|
+
) * 1e3
|
|
475
478
|
|
|
476
479
|
smargon_speed_limit_mm_per_s = yield from bps.rd(
|
|
477
480
|
fgs_composite.smargon.x.max_velocity
|
|
@@ -490,7 +493,7 @@ def _panda_triggering_setup(
|
|
|
490
493
|
)
|
|
491
494
|
else:
|
|
492
495
|
LOGGER.info(
|
|
493
|
-
f"Panda grid scan: Smargon speed set to {
|
|
496
|
+
f"Panda grid scan: Smargon speed set to {sample_velocity_mm_per_s} mm/s"
|
|
494
497
|
f" and using a run-up distance of {run_up_distance_mm}"
|
|
495
498
|
)
|
|
496
499
|
|
|
@@ -142,6 +142,14 @@ def detect_grid_and_do_gridscan(
|
|
|
142
142
|
parameters.box_size_um,
|
|
143
143
|
)
|
|
144
144
|
|
|
145
|
+
if parameters.selected_aperture:
|
|
146
|
+
# Start moving the aperture/scatterguard into position without moving it in
|
|
147
|
+
yield from bps.prepare(
|
|
148
|
+
composite.aperture_scatterguard,
|
|
149
|
+
parameters.selected_aperture,
|
|
150
|
+
group=CONST.WAIT.GRID_READY_FOR_DC,
|
|
151
|
+
)
|
|
152
|
+
|
|
145
153
|
yield from run_grid_detection_plan(
|
|
146
154
|
oav_params,
|
|
147
155
|
snapshot_template,
|