mx-bluesky 1.1.0__py3-none-any.whl → 1.2.0__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/hyperion/device_setup_plans/utils.py +11 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -0
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +47 -38
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +46 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +237 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +18 -178
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +0 -8
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +18 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +0 -8
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +3 -3
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +2 -4
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_utils.py +0 -2
- mx_bluesky/hyperion/parameters/components.py +19 -18
- mx_bluesky/hyperion/parameters/gridscan.py +7 -2
- mx_bluesky/hyperion/parameters/load_centre_collect.py +50 -0
- mx_bluesky/hyperion/parameters/robot_load.py +16 -0
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.2.0.dist-info}/METADATA +2 -2
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.2.0.dist-info}/RECORD +23 -19
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.2.0.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.2.0.dist-info}/WHEEL +0 -0
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.2.0.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.2.0.dist-info}/top_level.txt +0 -0
mx_bluesky/_version.py
CHANGED
|
@@ -3,6 +3,10 @@ from collections.abc import Generator
|
|
|
3
3
|
from bluesky import plan_stubs as bps
|
|
4
4
|
from bluesky import preprocessors as bpp
|
|
5
5
|
from bluesky.utils import Msg
|
|
6
|
+
from dodal.devices.dcm import DCM
|
|
7
|
+
from dodal.devices.detector import (
|
|
8
|
+
DetectorParams,
|
|
9
|
+
)
|
|
6
10
|
from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
|
|
7
11
|
from dodal.devices.eiger import EigerDetector
|
|
8
12
|
|
|
@@ -12,6 +16,13 @@ from mx_bluesky.hyperion.device_setup_plans.position_detector import (
|
|
|
12
16
|
)
|
|
13
17
|
|
|
14
18
|
|
|
19
|
+
def fill_in_energy_if_not_supplied(dcm: DCM, detector_params: DetectorParams):
|
|
20
|
+
if not detector_params.expected_energy_ev:
|
|
21
|
+
actual_energy_ev = 1000 * (yield from bps.rd(dcm.energy_in_kev))
|
|
22
|
+
detector_params.expected_energy_ev = actual_energy_ev
|
|
23
|
+
return detector_params
|
|
24
|
+
|
|
25
|
+
|
|
15
26
|
def start_preparing_data_collection_then_do_plan(
|
|
16
27
|
eiger: EigerDetector,
|
|
17
28
|
detector_motion: DetectorMotion,
|
|
@@ -7,12 +7,14 @@ import mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan as flyscan_
|
|
|
7
7
|
import mx_bluesky.hyperion.experiment_plans.rotation_scan_plan as rotation_scan_plan
|
|
8
8
|
from mx_bluesky.hyperion.experiment_plans import (
|
|
9
9
|
grid_detect_then_xray_centre_plan,
|
|
10
|
+
load_centre_collect_full_plan,
|
|
10
11
|
pin_centre_then_xray_centre_plan,
|
|
11
12
|
robot_load_then_centre_plan,
|
|
12
13
|
)
|
|
13
14
|
from mx_bluesky.hyperion.external_interaction.callbacks.common.callback_util import (
|
|
14
15
|
CallbacksFactory,
|
|
15
16
|
create_gridscan_callbacks,
|
|
17
|
+
create_load_centre_collect_callbacks,
|
|
16
18
|
create_robot_load_and_centre_callbacks,
|
|
17
19
|
create_rotation_callbacks,
|
|
18
20
|
)
|
|
@@ -22,6 +24,7 @@ from mx_bluesky.hyperion.parameters.gridscan import (
|
|
|
22
24
|
RobotLoadThenCentre,
|
|
23
25
|
ThreeDGridScan,
|
|
24
26
|
)
|
|
27
|
+
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
|
|
25
28
|
from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan, RotationScan
|
|
26
29
|
|
|
27
30
|
|
|
@@ -42,6 +45,7 @@ class ExperimentRegistryEntry(TypedDict):
|
|
|
42
45
|
| MultiRotationScan
|
|
43
46
|
| PinTipCentreThenXrayCentre
|
|
44
47
|
| RobotLoadThenCentre
|
|
48
|
+
| LoadCentreCollect
|
|
45
49
|
]
|
|
46
50
|
callbacks_factory: CallbacksFactory
|
|
47
51
|
|
|
@@ -77,6 +81,11 @@ PLAN_REGISTRY: dict[str, ExperimentRegistryEntry] = {
|
|
|
77
81
|
"param_type": MultiRotationScan,
|
|
78
82
|
"callbacks_factory": create_rotation_callbacks,
|
|
79
83
|
},
|
|
84
|
+
"load_centre_collect_full_plan": {
|
|
85
|
+
"setup": load_centre_collect_full_plan.create_devices,
|
|
86
|
+
"param_type": LoadCentreCollect,
|
|
87
|
+
"callbacks_factory": create_load_centre_collect_callbacks,
|
|
88
|
+
},
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
|
|
@@ -77,6 +77,12 @@ class SmargonSpeedException(Exception):
|
|
|
77
77
|
pass
|
|
78
78
|
|
|
79
79
|
|
|
80
|
+
class CrystalNotFoundException(WarningException):
|
|
81
|
+
"""Raised if grid detection completed normally but no crystal was found."""
|
|
82
|
+
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
|
|
80
86
|
@dataclasses.dataclass
|
|
81
87
|
class FlyScanXRayCentreComposite:
|
|
82
88
|
"""All devices which are directly or indirectly required by this plan"""
|
|
@@ -190,47 +196,50 @@ def run_gridscan_and_move(
|
|
|
190
196
|
|
|
191
197
|
LOGGER.info("Grid scan finished, getting results.")
|
|
192
198
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
LOGGER.info("Zocalo triggered and read, interpreting results.")
|
|
198
|
-
xray_centre, bbox_size = yield from get_processing_result(fgs_composite.zocalo)
|
|
199
|
-
LOGGER.info(f"Got xray centre: {xray_centre}, bbox size: {bbox_size}")
|
|
200
|
-
if xray_centre is not None:
|
|
201
|
-
xray_centre = parameters.FGS_params.grid_position_to_motor_position(
|
|
202
|
-
xray_centre
|
|
199
|
+
try:
|
|
200
|
+
with TRACER.start_span("wait_for_zocalo"):
|
|
201
|
+
yield from bps.trigger_and_read(
|
|
202
|
+
[fgs_composite.zocalo], name=ZOCALO_READING_PLAN_NAME
|
|
203
203
|
)
|
|
204
|
-
|
|
205
|
-
xray_centre =
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
204
|
+
LOGGER.info("Zocalo triggered and read, interpreting results.")
|
|
205
|
+
xray_centre, bbox_size = yield from get_processing_result(
|
|
206
|
+
fgs_composite.zocalo
|
|
207
|
+
)
|
|
208
|
+
LOGGER.info(f"Got xray centre: {xray_centre}, bbox size: {bbox_size}")
|
|
209
|
+
if xray_centre is not None:
|
|
210
|
+
xray_centre = parameters.FGS_params.grid_position_to_motor_position(
|
|
211
|
+
xray_centre
|
|
211
212
|
)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
213
|
+
else:
|
|
214
|
+
LOGGER.warning("No X-ray centre received")
|
|
215
|
+
raise CrystalNotFoundException()
|
|
216
|
+
if bbox_size is not None:
|
|
217
|
+
with TRACER.start_span("change_aperture"):
|
|
218
|
+
yield from set_aperture_for_bbox_size(
|
|
219
|
+
fgs_composite.aperture_scatterguard, bbox_size
|
|
220
|
+
)
|
|
221
|
+
else:
|
|
222
|
+
LOGGER.warning("No bounding box size received")
|
|
223
|
+
|
|
224
|
+
# once we have the results, go to the appropriate position
|
|
225
|
+
LOGGER.info("Moving to centre of mass.")
|
|
226
|
+
with TRACER.start_span("move_to_result"):
|
|
227
|
+
x, y, z = xray_centre
|
|
228
|
+
yield from move_x_y_z(fgs_composite.sample_motors, x, y, z, wait=True)
|
|
229
|
+
|
|
230
|
+
if parameters.FGS_params.set_stub_offsets:
|
|
231
|
+
LOGGER.info("Recentring smargon co-ordinate system to this point.")
|
|
232
|
+
yield from bps.mv(
|
|
233
|
+
fgs_composite.sample_motors.stub_offsets, StubPosition.CURRENT_AS_CENTER
|
|
234
|
+
)
|
|
235
|
+
finally:
|
|
236
|
+
# Turn off dev/shm streaming to avoid filling disk, see https://github.com/DiamondLightSource/hyperion/issues/1395
|
|
237
|
+
LOGGER.info("Turning off Eiger dev/shm streaming")
|
|
238
|
+
yield from bps.abs_set(fgs_composite.eiger.odin.fan.dev_shm_enable, 0)
|
|
230
239
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
240
|
+
# Wait on everything before returning to GDA (particularly apertures), can be removed
|
|
241
|
+
# when we do not return to GDA here
|
|
242
|
+
yield from bps.wait()
|
|
234
243
|
|
|
235
244
|
|
|
236
245
|
@bpp.set_run_key_decorator(CONST.PLAN.GRIDSCAN_MAIN)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
|
|
3
|
+
from blueapi.core import BlueskyContext
|
|
4
|
+
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
5
|
+
|
|
6
|
+
from mx_bluesky.hyperion.experiment_plans.robot_load_then_centre_plan import (
|
|
7
|
+
RobotLoadThenCentreComposite,
|
|
8
|
+
robot_load_then_centre,
|
|
9
|
+
)
|
|
10
|
+
from mx_bluesky.hyperion.experiment_plans.rotation_scan_plan import (
|
|
11
|
+
RotationScanComposite,
|
|
12
|
+
multi_rotation_scan,
|
|
13
|
+
)
|
|
14
|
+
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
|
|
15
|
+
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclasses.dataclass
|
|
19
|
+
class LoadCentreCollectComposite(RobotLoadThenCentreComposite, RotationScanComposite):
|
|
20
|
+
"""Composite that provides access to the required devices."""
|
|
21
|
+
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def create_devices(context: BlueskyContext) -> LoadCentreCollectComposite:
|
|
26
|
+
"""Create the necessary devices for the plan."""
|
|
27
|
+
return device_composite_from_context(context, LoadCentreCollectComposite)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def load_centre_collect_full_plan(
|
|
31
|
+
composite: LoadCentreCollectComposite,
|
|
32
|
+
params: LoadCentreCollect,
|
|
33
|
+
oav_params: OAVParameters | None = None,
|
|
34
|
+
):
|
|
35
|
+
"""Attempt a complete data collection experiment, consisting of the following:
|
|
36
|
+
* Load the sample if necessary
|
|
37
|
+
* Move to the specified goniometer start angles
|
|
38
|
+
* Perform optical centring, then X-ray centring
|
|
39
|
+
* If X-ray centring finds a diffracting centre then move to that centre and
|
|
40
|
+
* do a collection with the specified parameters.
|
|
41
|
+
"""
|
|
42
|
+
if not oav_params:
|
|
43
|
+
oav_params = OAVParameters(context="xrayCentring")
|
|
44
|
+
yield from robot_load_then_centre(composite, params.robot_load_then_centre)
|
|
45
|
+
|
|
46
|
+
yield from multi_rotation_scan(composite, params.multi_rotation_scan, oav_params)
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
from collections.abc import Generator
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import cast
|
|
8
|
+
|
|
9
|
+
import bluesky.plan_stubs as bps
|
|
10
|
+
import bluesky.preprocessors as bpp
|
|
11
|
+
from blueapi.core import BlueskyContext
|
|
12
|
+
from bluesky.utils import Msg
|
|
13
|
+
from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
|
|
14
|
+
from dodal.devices.attenuator import Attenuator
|
|
15
|
+
from dodal.devices.dcm import DCM
|
|
16
|
+
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, VFMMirrorVoltages
|
|
17
|
+
from dodal.devices.motors import XYZPositioner
|
|
18
|
+
from dodal.devices.oav.oav_detector import OAV
|
|
19
|
+
from dodal.devices.robot import BartRobot, SampleLocation
|
|
20
|
+
from dodal.devices.smargon import Smargon, StubPosition
|
|
21
|
+
from dodal.devices.thawer import Thawer
|
|
22
|
+
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
23
|
+
from dodal.devices.webcam import Webcam
|
|
24
|
+
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
25
|
+
from dodal.plans.motor_util_plans import MoveTooLarge, home_and_reset_wrapper
|
|
26
|
+
|
|
27
|
+
from mx_bluesky.hyperion.experiment_plans.set_energy_plan import (
|
|
28
|
+
SetEnergyComposite,
|
|
29
|
+
set_energy_plan,
|
|
30
|
+
)
|
|
31
|
+
from mx_bluesky.hyperion.log import LOGGER
|
|
32
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
33
|
+
from mx_bluesky.hyperion.parameters.robot_load import RobotLoadAndEnergyChange
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclasses.dataclass
|
|
37
|
+
class RobotLoadAndEnergyChangeComposite:
|
|
38
|
+
# SetEnergyComposite fields
|
|
39
|
+
vfm: FocusingMirrorWithStripes
|
|
40
|
+
vfm_mirror_voltages: VFMMirrorVoltages
|
|
41
|
+
dcm: DCM
|
|
42
|
+
undulator_dcm: UndulatorDCM
|
|
43
|
+
xbpm_feedback: XBPMFeedback
|
|
44
|
+
attenuator: Attenuator
|
|
45
|
+
|
|
46
|
+
# RobotLoad fields
|
|
47
|
+
robot: BartRobot
|
|
48
|
+
webcam: Webcam
|
|
49
|
+
lower_gonio: XYZPositioner
|
|
50
|
+
thawer: Thawer
|
|
51
|
+
oav: OAV
|
|
52
|
+
smargon: Smargon
|
|
53
|
+
aperture_scatterguard: ApertureScatterguard
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def create_devices(context: BlueskyContext) -> RobotLoadAndEnergyChangeComposite:
|
|
57
|
+
from mx_bluesky.hyperion.utils.context import device_composite_from_context
|
|
58
|
+
|
|
59
|
+
return device_composite_from_context(context, RobotLoadAndEnergyChangeComposite)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def wait_for_smargon_not_disabled(smargon: Smargon, timeout=60):
|
|
63
|
+
"""Waits for the smargon disabled flag to go low. The robot hardware is responsible
|
|
64
|
+
for setting this to low when it is safe to move. It does this through a physical
|
|
65
|
+
connection between the robot and the smargon.
|
|
66
|
+
"""
|
|
67
|
+
LOGGER.info("Waiting for smargon enabled")
|
|
68
|
+
SLEEP_PER_CHECK = 0.1
|
|
69
|
+
times_to_check = int(timeout / SLEEP_PER_CHECK)
|
|
70
|
+
for _ in range(times_to_check):
|
|
71
|
+
smargon_disabled = yield from bps.rd(smargon.disabled)
|
|
72
|
+
if not smargon_disabled:
|
|
73
|
+
LOGGER.info("Smargon now enabled")
|
|
74
|
+
return
|
|
75
|
+
yield from bps.sleep(SLEEP_PER_CHECK)
|
|
76
|
+
raise TimeoutError(
|
|
77
|
+
"Timed out waiting for smargon to become enabled after robot load"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def take_robot_snapshots(oav: OAV, webcam: Webcam, directory: Path):
|
|
82
|
+
time_now = datetime.now()
|
|
83
|
+
snapshot_format = f"{time_now.strftime('%H%M%S')}_{{device}}_after_load"
|
|
84
|
+
for device in [oav.snapshot, webcam]:
|
|
85
|
+
yield from bps.abs_set(
|
|
86
|
+
device.filename, snapshot_format.format(device=device.name)
|
|
87
|
+
)
|
|
88
|
+
yield from bps.abs_set(device.directory, str(directory))
|
|
89
|
+
# Note: should be able to use `wait=True` after https://github.com/bluesky/bluesky/issues/1795
|
|
90
|
+
yield from bps.trigger(device, group="snapshots")
|
|
91
|
+
yield from bps.wait("snapshots")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def prepare_for_robot_load(
|
|
95
|
+
aperture_scatterguard: ApertureScatterguard, smargon: Smargon
|
|
96
|
+
):
|
|
97
|
+
yield from bps.abs_set(
|
|
98
|
+
aperture_scatterguard,
|
|
99
|
+
ApertureValue.ROBOT_LOAD,
|
|
100
|
+
group="prepare_robot_load",
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
yield from bps.mv(smargon.stub_offsets, StubPosition.RESET_TO_ROBOT_LOAD)
|
|
104
|
+
|
|
105
|
+
# fmt: off
|
|
106
|
+
yield from bps.mv(smargon.x, 0,
|
|
107
|
+
smargon.y, 0,
|
|
108
|
+
smargon.z, 0,
|
|
109
|
+
smargon.omega, 0,
|
|
110
|
+
smargon.chi, 0,
|
|
111
|
+
smargon.phi, 0)
|
|
112
|
+
# fmt: on
|
|
113
|
+
|
|
114
|
+
yield from bps.wait("prepare_robot_load")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def do_robot_load(
|
|
118
|
+
composite: RobotLoadAndEnergyChangeComposite,
|
|
119
|
+
sample_location: SampleLocation,
|
|
120
|
+
demand_energy_ev: float | None,
|
|
121
|
+
thawing_time: float,
|
|
122
|
+
):
|
|
123
|
+
yield from bps.abs_set(
|
|
124
|
+
composite.robot,
|
|
125
|
+
sample_location,
|
|
126
|
+
group="robot_load",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if demand_energy_ev:
|
|
130
|
+
yield from set_energy_plan(
|
|
131
|
+
demand_energy_ev / 1000,
|
|
132
|
+
cast(SetEnergyComposite, composite),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
yield from bps.wait("robot_load")
|
|
136
|
+
|
|
137
|
+
yield from bps.abs_set(
|
|
138
|
+
composite.thawer.thaw_for_time_s, thawing_time, group="thawing_finished"
|
|
139
|
+
)
|
|
140
|
+
yield from wait_for_smargon_not_disabled(composite.smargon)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def raise_exception_if_moved_out_of_cryojet(exception):
|
|
144
|
+
yield from bps.null()
|
|
145
|
+
if isinstance(exception, MoveTooLarge):
|
|
146
|
+
raise Exception(
|
|
147
|
+
f"Moving {exception.axis} back to {exception.position} after \
|
|
148
|
+
robot load would move it out of the cryojet. The max safe \
|
|
149
|
+
distance is {exception.maximum_move}"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def pin_already_loaded(
|
|
154
|
+
robot: BartRobot, sample_location: SampleLocation
|
|
155
|
+
) -> Generator[Msg, None, bool]:
|
|
156
|
+
current_puck = yield from bps.rd(robot.current_puck)
|
|
157
|
+
current_pin = yield from bps.rd(robot.current_pin)
|
|
158
|
+
return (
|
|
159
|
+
int(current_puck) == sample_location.puck
|
|
160
|
+
and int(current_pin) == sample_location.pin
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def robot_load_and_snapshots(
|
|
165
|
+
composite: RobotLoadAndEnergyChangeComposite,
|
|
166
|
+
location: SampleLocation,
|
|
167
|
+
snapshot_directory: Path,
|
|
168
|
+
thawing_time: float,
|
|
169
|
+
demand_energy_ev: float | None,
|
|
170
|
+
):
|
|
171
|
+
robot_load_plan = do_robot_load(
|
|
172
|
+
composite,
|
|
173
|
+
location,
|
|
174
|
+
demand_energy_ev,
|
|
175
|
+
thawing_time,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# The lower gonio must be in the correct position for the robot load and we
|
|
179
|
+
# want to put it back afterwards. Note we don't wait the robot is interlocked
|
|
180
|
+
# to the lower gonio and the move is quicker than the robot takes to get to the
|
|
181
|
+
# load position.
|
|
182
|
+
yield from bpp.contingency_wrapper(
|
|
183
|
+
home_and_reset_wrapper(
|
|
184
|
+
robot_load_plan,
|
|
185
|
+
composite.lower_gonio,
|
|
186
|
+
BartRobot.LOAD_TOLERANCE_MM,
|
|
187
|
+
CONST.HARDWARE.CRYOJET_MARGIN_MM,
|
|
188
|
+
"lower_gonio",
|
|
189
|
+
wait_for_all=False,
|
|
190
|
+
),
|
|
191
|
+
except_plan=raise_exception_if_moved_out_of_cryojet,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
yield from take_robot_snapshots(composite.oav, composite.webcam, snapshot_directory)
|
|
195
|
+
|
|
196
|
+
yield from bps.create(name=CONST.DESCRIPTORS.ROBOT_LOAD)
|
|
197
|
+
yield from bps.read(composite.robot.barcode)
|
|
198
|
+
yield from bps.read(composite.oav.snapshot)
|
|
199
|
+
yield from bps.read(composite.webcam)
|
|
200
|
+
yield from bps.save()
|
|
201
|
+
|
|
202
|
+
yield from bps.wait("reset-lower_gonio")
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def robot_load_and_change_energy_plan(
|
|
206
|
+
composite: RobotLoadAndEnergyChangeComposite,
|
|
207
|
+
params: RobotLoadAndEnergyChange,
|
|
208
|
+
):
|
|
209
|
+
assert params.sample_puck is not None
|
|
210
|
+
assert params.sample_pin is not None
|
|
211
|
+
|
|
212
|
+
sample_location = SampleLocation(params.sample_puck, params.sample_pin)
|
|
213
|
+
|
|
214
|
+
yield from prepare_for_robot_load(
|
|
215
|
+
composite.aperture_scatterguard, composite.smargon
|
|
216
|
+
)
|
|
217
|
+
yield from bpp.run_wrapper(
|
|
218
|
+
robot_load_and_snapshots(
|
|
219
|
+
composite,
|
|
220
|
+
sample_location,
|
|
221
|
+
params.snapshot_directory,
|
|
222
|
+
params.thawing_time,
|
|
223
|
+
params.demand_energy_ev,
|
|
224
|
+
),
|
|
225
|
+
md={
|
|
226
|
+
"subplan_name": CONST.PLAN.ROBOT_LOAD,
|
|
227
|
+
"metadata": {
|
|
228
|
+
"visit": params.visit,
|
|
229
|
+
"sample_id": params.sample_id,
|
|
230
|
+
"sample_puck": sample_location.puck,
|
|
231
|
+
"sample_pin": sample_location.pin,
|
|
232
|
+
},
|
|
233
|
+
"activate_callbacks": [
|
|
234
|
+
"RobotLoadISPyBCallback",
|
|
235
|
+
],
|
|
236
|
+
},
|
|
237
|
+
)
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
from collections.abc import Generator
|
|
5
|
-
from datetime import datetime
|
|
6
|
-
from pathlib import Path
|
|
7
4
|
from typing import cast
|
|
8
5
|
|
|
9
|
-
import bluesky.plan_stubs as bps
|
|
10
|
-
import bluesky.preprocessors as bpp
|
|
11
6
|
from blueapi.core import BlueskyContext, MsgGenerator
|
|
12
|
-
from
|
|
13
|
-
from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
|
|
7
|
+
from dodal.devices.aperturescatterguard import ApertureScatterguard
|
|
14
8
|
from dodal.devices.attenuator import Attenuator
|
|
15
9
|
from dodal.devices.backlight import Backlight
|
|
16
10
|
from dodal.devices.dcm import DCM
|
|
@@ -24,7 +18,7 @@ from dodal.devices.oav.oav_detector import OAV
|
|
|
24
18
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
25
19
|
from dodal.devices.robot import BartRobot, SampleLocation
|
|
26
20
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
27
|
-
from dodal.devices.smargon import Smargon
|
|
21
|
+
from dodal.devices.smargon import Smargon
|
|
28
22
|
from dodal.devices.synchrotron import Synchrotron
|
|
29
23
|
from dodal.devices.thawer import Thawer
|
|
30
24
|
from dodal.devices.undulator import Undulator
|
|
@@ -34,10 +28,11 @@ from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
|
34
28
|
from dodal.devices.zebra import Zebra
|
|
35
29
|
from dodal.devices.zebra_controlled_shutter import ZebraShutter
|
|
36
30
|
from dodal.devices.zocalo import ZocaloResults
|
|
37
|
-
from dodal.
|
|
31
|
+
from dodal.log import LOGGER
|
|
38
32
|
from ophyd_async.fastcs.panda import HDFPanda
|
|
39
33
|
|
|
40
34
|
from mx_bluesky.hyperion.device_setup_plans.utils import (
|
|
35
|
+
fill_in_energy_if_not_supplied,
|
|
41
36
|
start_preparing_data_collection_then_do_plan,
|
|
42
37
|
)
|
|
43
38
|
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
|
|
@@ -46,12 +41,11 @@ from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan impo
|
|
|
46
41
|
from mx_bluesky.hyperion.experiment_plans.pin_centre_then_xray_centre_plan import (
|
|
47
42
|
pin_centre_then_xray_centre_plan,
|
|
48
43
|
)
|
|
49
|
-
from mx_bluesky.hyperion.experiment_plans.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
from mx_bluesky.hyperion.experiment_plans.robot_load_and_change_energy import (
|
|
45
|
+
RobotLoadAndEnergyChangeComposite,
|
|
46
|
+
pin_already_loaded,
|
|
47
|
+
robot_load_and_change_energy_plan,
|
|
53
48
|
)
|
|
54
|
-
from mx_bluesky.hyperion.log import LOGGER
|
|
55
49
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
56
50
|
from mx_bluesky.hyperion.parameters.gridscan import RobotLoadThenCentre
|
|
57
51
|
|
|
@@ -100,144 +94,6 @@ def create_devices(context: BlueskyContext) -> RobotLoadThenCentreComposite:
|
|
|
100
94
|
return device_composite_from_context(context, RobotLoadThenCentreComposite)
|
|
101
95
|
|
|
102
96
|
|
|
103
|
-
def wait_for_smargon_not_disabled(smargon: Smargon, timeout=60):
|
|
104
|
-
"""Waits for the smargon disabled flag to go low. The robot hardware is responsible
|
|
105
|
-
for setting this to low when it is safe to move. It does this through a physical
|
|
106
|
-
connection between the robot and the smargon.
|
|
107
|
-
"""
|
|
108
|
-
LOGGER.info("Waiting for smargon enabled")
|
|
109
|
-
SLEEP_PER_CHECK = 0.1
|
|
110
|
-
times_to_check = int(timeout / SLEEP_PER_CHECK)
|
|
111
|
-
for _ in range(times_to_check):
|
|
112
|
-
smargon_disabled = yield from bps.rd(smargon.disabled)
|
|
113
|
-
if not smargon_disabled:
|
|
114
|
-
LOGGER.info("Smargon now enabled")
|
|
115
|
-
return
|
|
116
|
-
yield from bps.sleep(SLEEP_PER_CHECK)
|
|
117
|
-
raise TimeoutError(
|
|
118
|
-
"Timed out waiting for smargon to become enabled after robot load"
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def take_robot_snapshots(oav: OAV, webcam: Webcam, directory: Path):
|
|
123
|
-
time_now = datetime.now()
|
|
124
|
-
snapshot_format = f"{time_now.strftime('%H%M%S')}_{{device}}_after_load"
|
|
125
|
-
for device in [oav.snapshot, webcam]:
|
|
126
|
-
yield from bps.abs_set(
|
|
127
|
-
device.filename, snapshot_format.format(device=device.name)
|
|
128
|
-
)
|
|
129
|
-
yield from bps.abs_set(device.directory, str(directory))
|
|
130
|
-
# Note: should be able to use `wait=True` after https://github.com/bluesky/bluesky/issues/1795
|
|
131
|
-
yield from bps.trigger(device, group="snapshots")
|
|
132
|
-
yield from bps.wait("snapshots")
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def prepare_for_robot_load(composite: RobotLoadThenCentreComposite):
|
|
136
|
-
yield from bps.abs_set(
|
|
137
|
-
composite.aperture_scatterguard,
|
|
138
|
-
ApertureValue.ROBOT_LOAD,
|
|
139
|
-
group="prepare_robot_load",
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
yield from bps.mv(composite.smargon.stub_offsets, StubPosition.RESET_TO_ROBOT_LOAD)
|
|
143
|
-
|
|
144
|
-
# fmt: off
|
|
145
|
-
yield from bps.mv(composite.smargon.x, 0,
|
|
146
|
-
composite.smargon.y, 0,
|
|
147
|
-
composite.smargon.z, 0,
|
|
148
|
-
composite.smargon.omega, 0,
|
|
149
|
-
composite.smargon.chi, 0,
|
|
150
|
-
composite.smargon.phi, 0)
|
|
151
|
-
# fmt: on
|
|
152
|
-
|
|
153
|
-
yield from bps.wait("prepare_robot_load")
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def do_robot_load(
|
|
157
|
-
composite: RobotLoadThenCentreComposite,
|
|
158
|
-
sample_location: SampleLocation,
|
|
159
|
-
demand_energy_ev: float | None,
|
|
160
|
-
thawing_time: float,
|
|
161
|
-
):
|
|
162
|
-
yield from bps.abs_set(
|
|
163
|
-
composite.robot,
|
|
164
|
-
sample_location,
|
|
165
|
-
group="robot_load",
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
if demand_energy_ev:
|
|
169
|
-
yield from set_energy_plan(
|
|
170
|
-
demand_energy_ev / 1000,
|
|
171
|
-
cast(SetEnergyComposite, composite),
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
yield from bps.wait("robot_load")
|
|
175
|
-
|
|
176
|
-
yield from bps.abs_set(
|
|
177
|
-
composite.thawer.thaw_for_time_s, thawing_time, group="thawing_finished"
|
|
178
|
-
)
|
|
179
|
-
yield from wait_for_smargon_not_disabled(composite.smargon)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
def raise_exception_if_moved_out_of_cryojet(exception):
|
|
183
|
-
yield from bps.null()
|
|
184
|
-
if isinstance(exception, MoveTooLarge):
|
|
185
|
-
raise Exception(
|
|
186
|
-
f"Moving {exception.axis} back to {exception.position} after \
|
|
187
|
-
robot load would move it out of the cryojet. The max safe \
|
|
188
|
-
distance is {exception.maximum_move}"
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def _pin_already_loaded(
|
|
193
|
-
robot: BartRobot, pin_to_load: int, puck_to_load: int
|
|
194
|
-
) -> Generator[Msg, None, bool]:
|
|
195
|
-
current_puck = yield from bps.rd(robot.current_puck)
|
|
196
|
-
current_pin = yield from bps.rd(robot.current_pin)
|
|
197
|
-
return int(current_puck) == puck_to_load and int(current_pin) == pin_to_load
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
def robot_load_and_snapshots(
|
|
201
|
-
composite: RobotLoadThenCentreComposite,
|
|
202
|
-
params: RobotLoadThenCentre,
|
|
203
|
-
location: SampleLocation,
|
|
204
|
-
):
|
|
205
|
-
robot_load_plan = do_robot_load(
|
|
206
|
-
composite,
|
|
207
|
-
location,
|
|
208
|
-
params.demand_energy_ev,
|
|
209
|
-
params.thawing_time,
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
# The lower gonio must be in the correct position for the robot load and we
|
|
213
|
-
# want to put it back afterwards. Note we don't wait the robot is interlocked
|
|
214
|
-
# to the lower gonio and the move is quicker than the robot takes to get to the
|
|
215
|
-
# load position.
|
|
216
|
-
yield from bpp.contingency_wrapper(
|
|
217
|
-
home_and_reset_wrapper(
|
|
218
|
-
robot_load_plan,
|
|
219
|
-
composite.lower_gonio,
|
|
220
|
-
BartRobot.LOAD_TOLERANCE_MM,
|
|
221
|
-
CONST.HARDWARE.CRYOJET_MARGIN_MM,
|
|
222
|
-
"lower_gonio",
|
|
223
|
-
wait_for_all=False,
|
|
224
|
-
),
|
|
225
|
-
except_plan=raise_exception_if_moved_out_of_cryojet,
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
yield from take_robot_snapshots(
|
|
229
|
-
composite.oav, composite.webcam, params.snapshot_directory
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
yield from bps.create(name=CONST.DESCRIPTORS.ROBOT_LOAD)
|
|
233
|
-
yield from bps.read(composite.robot.barcode)
|
|
234
|
-
yield from bps.read(composite.oav.snapshot)
|
|
235
|
-
yield from bps.read(composite.webcam)
|
|
236
|
-
yield from bps.save()
|
|
237
|
-
|
|
238
|
-
yield from bps.wait("reset-lower_gonio")
|
|
239
|
-
|
|
240
|
-
|
|
241
97
|
def centring_plan_from_robot_load_params(
|
|
242
98
|
composite: RobotLoadThenCentreComposite,
|
|
243
99
|
params: RobotLoadThenCentre,
|
|
@@ -251,23 +107,10 @@ def centring_plan_from_robot_load_params(
|
|
|
251
107
|
def robot_load_then_centre_plan(
|
|
252
108
|
composite: RobotLoadThenCentreComposite,
|
|
253
109
|
params: RobotLoadThenCentre,
|
|
254
|
-
sample_location: SampleLocation,
|
|
255
110
|
):
|
|
256
|
-
yield from
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
md={
|
|
260
|
-
"subplan_name": CONST.PLAN.ROBOT_LOAD,
|
|
261
|
-
"metadata": {
|
|
262
|
-
"visit_path": str(params.visit_directory),
|
|
263
|
-
"sample_id": params.sample_id,
|
|
264
|
-
"sample_puck": params.sample_puck,
|
|
265
|
-
"sample_pin": params.sample_pin,
|
|
266
|
-
},
|
|
267
|
-
"activate_callbacks": [
|
|
268
|
-
"RobotLoadISPyBCallback",
|
|
269
|
-
],
|
|
270
|
-
},
|
|
111
|
+
yield from robot_load_and_change_energy_plan(
|
|
112
|
+
cast(RobotLoadAndEnergyChangeComposite, composite),
|
|
113
|
+
params.robot_load_params(),
|
|
271
114
|
)
|
|
272
115
|
|
|
273
116
|
yield from centring_plan_from_robot_load_params(composite, params)
|
|
@@ -283,10 +126,10 @@ def robot_load_then_centre(
|
|
|
283
126
|
assert parameters.sample_puck is not None
|
|
284
127
|
assert parameters.sample_pin is not None
|
|
285
128
|
|
|
129
|
+
sample_location = SampleLocation(parameters.sample_puck, parameters.sample_pin)
|
|
130
|
+
|
|
286
131
|
doing_sample_load = not (
|
|
287
|
-
yield from
|
|
288
|
-
composite.robot, parameters.sample_pin, parameters.sample_puck
|
|
289
|
-
)
|
|
132
|
+
yield from pin_already_loaded(composite.robot, sample_location)
|
|
290
133
|
)
|
|
291
134
|
|
|
292
135
|
doing_chi_change = parameters.chi_start_deg is not None
|
|
@@ -295,7 +138,6 @@ def robot_load_then_centre(
|
|
|
295
138
|
plan = robot_load_then_centre_plan(
|
|
296
139
|
composite,
|
|
297
140
|
parameters,
|
|
298
|
-
SampleLocation(parameters.sample_puck, parameters.sample_pin),
|
|
299
141
|
)
|
|
300
142
|
LOGGER.info("Pin not loaded, loading and centring")
|
|
301
143
|
elif doing_chi_change:
|
|
@@ -305,12 +147,10 @@ def robot_load_then_centre(
|
|
|
305
147
|
LOGGER.info("Pin already loaded and chi not changed so doing nothing")
|
|
306
148
|
return
|
|
307
149
|
|
|
308
|
-
detector_params =
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
)
|
|
313
|
-
detector_params.expected_energy_ev = actual_energy_ev
|
|
150
|
+
detector_params = yield from fill_in_energy_if_not_supplied(
|
|
151
|
+
composite.dcm, parameters.detector_params
|
|
152
|
+
)
|
|
153
|
+
|
|
314
154
|
eiger.set_detector_parameters(detector_params)
|
|
315
155
|
|
|
316
156
|
yield from start_preparing_data_collection_then_do_plan(
|
|
@@ -6,11 +6,8 @@
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import dataclasses
|
|
9
|
-
from collections.abc import Generator
|
|
10
|
-
from typing import Any
|
|
11
9
|
|
|
12
10
|
from bluesky import plan_stubs as bps
|
|
13
|
-
from bluesky.utils import Msg
|
|
14
11
|
from dodal.devices.attenuator import Attenuator
|
|
15
12
|
from dodal.devices.dcm import DCM
|
|
16
13
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, VFMMirrorVoltages
|
|
@@ -51,11 +48,6 @@ def _set_energy_plan(
|
|
|
51
48
|
yield from bps.wait(group=UNDULATOR_GROUP)
|
|
52
49
|
|
|
53
50
|
|
|
54
|
-
def read_energy(composite: SetEnergyComposite) -> Generator[Msg, Any, float]:
|
|
55
|
-
"""Obtain the energy in kev"""
|
|
56
|
-
return (yield from bps.rd(composite.dcm.energy_in_kev)) # type: ignore
|
|
57
|
-
|
|
58
|
-
|
|
59
51
|
def set_energy_plan(
|
|
60
52
|
energy_kev,
|
|
61
53
|
composite: SetEnergyComposite,
|
|
@@ -44,3 +44,21 @@ def create_rotation_callbacks() -> (
|
|
|
44
44
|
tuple[RotationNexusFileCallback, RotationISPyBCallback]
|
|
45
45
|
):
|
|
46
46
|
return (RotationNexusFileCallback(), RotationISPyBCallback(emit=ZocaloCallback()))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_load_centre_collect_callbacks() -> (
|
|
50
|
+
tuple[
|
|
51
|
+
GridscanNexusFileCallback,
|
|
52
|
+
GridscanISPyBCallback,
|
|
53
|
+
RobotLoadISPyBCallback,
|
|
54
|
+
RotationNexusFileCallback,
|
|
55
|
+
RotationISPyBCallback,
|
|
56
|
+
]
|
|
57
|
+
):
|
|
58
|
+
return (
|
|
59
|
+
GridscanNexusFileCallback(),
|
|
60
|
+
GridscanISPyBCallback(emit=ZocaloCallback()),
|
|
61
|
+
RobotLoadISPyBCallback(),
|
|
62
|
+
RotationNexusFileCallback(),
|
|
63
|
+
RotationISPyBCallback(emit=ZocaloCallback()),
|
|
64
|
+
)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import re
|
|
4
|
-
|
|
5
3
|
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
|
|
6
4
|
DataCollectionGroupInfo,
|
|
7
5
|
DataCollectionInfo,
|
|
@@ -11,7 +9,6 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
|
|
|
11
9
|
I03_EIGER_DETECTOR,
|
|
12
10
|
)
|
|
13
11
|
from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_utils import (
|
|
14
|
-
VISIT_PATH_REGEX,
|
|
15
12
|
get_current_time_string,
|
|
16
13
|
)
|
|
17
14
|
from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
|
|
@@ -63,8 +60,3 @@ def get_proposal_and_session_from_visit_string(visit_string: str) -> tuple[str,
|
|
|
63
60
|
visit_parts = visit_string.split("-")
|
|
64
61
|
assert len(visit_parts) == 2, f"Unexpected visit string {visit_string}"
|
|
65
62
|
return visit_parts[0], int(visit_parts[1])
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def get_visit_string_from_path(path: str | None) -> str | None:
|
|
69
|
-
match = re.search(VISIT_PATH_REGEX, path) if path else None
|
|
70
|
-
return str(match.group(1)) if match else None
|
|
@@ -110,9 +110,9 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
110
110
|
slitgap_vertical=doc["data"]["s4_slit_gaps_ygap"],
|
|
111
111
|
)
|
|
112
112
|
hwscan_position_info = DataCollectionPositionInfo(
|
|
113
|
-
pos_x=doc["data"]["smargon-x"],
|
|
114
|
-
pos_y=doc["data"]["smargon-y"],
|
|
115
|
-
pos_z=doc["data"]["smargon-z"],
|
|
113
|
+
pos_x=float(doc["data"]["smargon-x"]),
|
|
114
|
+
pos_y=float(doc["data"]["smargon-y"]),
|
|
115
|
+
pos_z=float(doc["data"]["smargon-z"]),
|
|
116
116
|
)
|
|
117
117
|
scan_data_infos = self.populate_info_for_update(
|
|
118
118
|
hwscan_data_collection_info, hwscan_position_info, self.params
|
|
@@ -6,7 +6,6 @@ from event_model.documents import EventDescriptor
|
|
|
6
6
|
|
|
7
7
|
from mx_bluesky.hyperion.external_interaction.callbacks.common.ispyb_mapping import (
|
|
8
8
|
get_proposal_and_session_from_visit_string,
|
|
9
|
-
get_visit_string_from_path,
|
|
10
9
|
)
|
|
11
10
|
from mx_bluesky.hyperion.external_interaction.callbacks.plan_reactive_callback import (
|
|
12
11
|
PlanReactiveCallback,
|
|
@@ -37,10 +36,9 @@ class RobotLoadISPyBCallback(PlanReactiveCallback):
|
|
|
37
36
|
ISPYB_LOGGER.debug(f"ISPyB robot load callback received: {doc}")
|
|
38
37
|
self.run_uid = doc.get("uid")
|
|
39
38
|
assert isinstance(metadata := doc.get("metadata"), dict)
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
proposal, session = get_proposal_and_session_from_visit_string(
|
|
40
|
+
metadata["visit"]
|
|
42
41
|
)
|
|
43
|
-
proposal, session = get_proposal_and_session_from_visit_string(visit)
|
|
44
42
|
self.action_id = self.expeye.start_load(
|
|
45
43
|
proposal,
|
|
46
44
|
session,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import datetime
|
|
4
3
|
import json
|
|
5
4
|
from abc import abstractmethod
|
|
6
5
|
from collections.abc import Sequence
|
|
@@ -142,24 +141,32 @@ class WithSnapshot(BaseModel):
|
|
|
142
141
|
return bool(self.snapshot_omegas_deg)
|
|
143
142
|
|
|
144
143
|
|
|
145
|
-
class
|
|
146
|
-
|
|
144
|
+
class WithOptionalEnergyChange(BaseModel):
|
|
145
|
+
demand_energy_ev: float | None = Field(default=None, gt=0)
|
|
147
146
|
|
|
147
|
+
|
|
148
|
+
class WithVisit(BaseModel):
|
|
148
149
|
visit: str = Field(min_length=1)
|
|
149
|
-
|
|
150
|
-
exposure_time_s: float = Field(gt=0)
|
|
151
|
-
comment: str = Field(default="")
|
|
150
|
+
zocalo_environment: str = Field(default=CONST.ZOCALO_ENV)
|
|
152
151
|
beamline: str = Field(default=CONST.I03.BEAMLINE, pattern=r"BL\d{2}[BIJS]")
|
|
153
|
-
insertion_prefix: str = Field(
|
|
154
|
-
default=CONST.I03.INSERTION_PREFIX, pattern=r"SR\d{2}[BIJS]"
|
|
155
|
-
)
|
|
156
152
|
det_dist_to_beam_converter_path: str = Field(
|
|
157
153
|
default=CONST.PARAM.DETECTOR.BEAM_XY_LUT_PATH
|
|
158
154
|
)
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
insertion_prefix: str = Field(
|
|
156
|
+
default=CONST.I03.INSERTION_PREFIX, pattern=r"SR\d{2}[BIJS]"
|
|
157
|
+
)
|
|
161
158
|
detector_distance_mm: float | None = Field(default=None, gt=0)
|
|
162
|
-
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class DiffractionExperiment(
|
|
162
|
+
HyperionParameters, WithSnapshot, WithOptionalEnergyChange, WithVisit
|
|
163
|
+
):
|
|
164
|
+
"""For all experiments which use beam"""
|
|
165
|
+
|
|
166
|
+
file_name: str
|
|
167
|
+
exposure_time_s: float = Field(gt=0)
|
|
168
|
+
comment: str = Field(default="")
|
|
169
|
+
trigger_mode: TriggerMode = Field(default=TriggerMode.FREE_RUN)
|
|
163
170
|
run_number: int | None = Field(default=None, ge=0)
|
|
164
171
|
selected_aperture: ApertureValue | None = Field(default=None)
|
|
165
172
|
transmission_frac: float = Field(default=0.1)
|
|
@@ -177,12 +184,6 @@ class DiffractionExperiment(HyperionParameters, WithSnapshot):
|
|
|
177
184
|
)
|
|
178
185
|
return values
|
|
179
186
|
|
|
180
|
-
@property
|
|
181
|
-
def visit_directory(self) -> Path:
|
|
182
|
-
return (
|
|
183
|
-
Path(CONST.I03.BASE_DATA_DIR) / str(datetime.date.today().year) / self.visit
|
|
184
|
-
)
|
|
185
|
-
|
|
186
187
|
@property
|
|
187
188
|
def num_images(self) -> int:
|
|
188
189
|
return 0
|
|
@@ -20,10 +20,12 @@ from mx_bluesky.hyperion.parameters.components import (
|
|
|
20
20
|
OptionalGonioAngleStarts,
|
|
21
21
|
SplitScan,
|
|
22
22
|
WithOavCentring,
|
|
23
|
+
WithOptionalEnergyChange,
|
|
23
24
|
WithScan,
|
|
24
25
|
XyzStarts,
|
|
25
26
|
)
|
|
26
27
|
from mx_bluesky.hyperion.parameters.constants import CONST, I03Constants
|
|
28
|
+
from mx_bluesky.hyperion.parameters.robot_load import RobotLoadAndEnergyChange
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
class GridCommon(
|
|
@@ -85,6 +87,10 @@ class PinTipCentreThenXrayCentre(GridCommon):
|
|
|
85
87
|
class RobotLoadThenCentre(GridCommon):
|
|
86
88
|
thawing_time: float = Field(default=CONST.I03.THAWING_TIME)
|
|
87
89
|
|
|
90
|
+
def robot_load_params(self):
|
|
91
|
+
my_params = self.model_dump()
|
|
92
|
+
return RobotLoadAndEnergyChange(**my_params)
|
|
93
|
+
|
|
88
94
|
def pin_centre_then_xray_centre_params(self):
|
|
89
95
|
my_params = self.model_dump()
|
|
90
96
|
del my_params["thawing_time"]
|
|
@@ -99,11 +105,10 @@ class SpecifiedGridScan(GridCommon, XyzStarts, WithScan):
|
|
|
99
105
|
...
|
|
100
106
|
|
|
101
107
|
|
|
102
|
-
class ThreeDGridScan(SpecifiedGridScan, SplitScan):
|
|
108
|
+
class ThreeDGridScan(SpecifiedGridScan, SplitScan, WithOptionalEnergyChange):
|
|
103
109
|
"""Parameters representing a so-called 3D grid scan, which consists of doing a
|
|
104
110
|
gridscan in X and Y, followed by one in X and Z."""
|
|
105
111
|
|
|
106
|
-
demand_energy_ev: float | None = Field(default=None)
|
|
107
112
|
grid1_omega_deg: float = Field(default=CONST.PARAM.GRIDSCAN.OMEGA_1) # type: ignore
|
|
108
113
|
grid2_omega_deg: float = Field(default=CONST.PARAM.GRIDSCAN.OMEGA_2)
|
|
109
114
|
x_step_size_um: float = Field(default=CONST.PARAM.GRIDSCAN.BOX_WIDTH_UM)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from typing import TypeVar
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, model_validator
|
|
4
|
+
|
|
5
|
+
from mx_bluesky.hyperion.parameters.components import (
|
|
6
|
+
HyperionParameters,
|
|
7
|
+
WithSample,
|
|
8
|
+
WithVisit,
|
|
9
|
+
)
|
|
10
|
+
from mx_bluesky.hyperion.parameters.gridscan import (
|
|
11
|
+
RobotLoadThenCentre,
|
|
12
|
+
)
|
|
13
|
+
from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan
|
|
14
|
+
|
|
15
|
+
T = TypeVar("T", bound=BaseModel)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def construct_from_values(parent_context: dict, key: str, t: type[T]) -> T:
|
|
19
|
+
values = dict(parent_context)
|
|
20
|
+
values |= values[key]
|
|
21
|
+
return t(**values)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LoadCentreCollect(HyperionParameters, WithVisit, WithSample):
|
|
25
|
+
"""Experiment parameters to perform the combined robot load,
|
|
26
|
+
pin-tip centre and rotation scan operations."""
|
|
27
|
+
|
|
28
|
+
robot_load_then_centre: RobotLoadThenCentre
|
|
29
|
+
multi_rotation_scan: MultiRotationScan
|
|
30
|
+
|
|
31
|
+
@model_validator(mode="before")
|
|
32
|
+
@classmethod
|
|
33
|
+
def validate_model(cls, values):
|
|
34
|
+
allowed_keys = (
|
|
35
|
+
LoadCentreCollect.model_fields.keys()
|
|
36
|
+
| RobotLoadThenCentre.model_fields.keys()
|
|
37
|
+
| MultiRotationScan.model_fields.keys()
|
|
38
|
+
)
|
|
39
|
+
disallowed_keys = values.keys() - allowed_keys
|
|
40
|
+
assert (
|
|
41
|
+
disallowed_keys == set()
|
|
42
|
+
), f"Unexpected fields found in LoadCentreCollect {disallowed_keys}"
|
|
43
|
+
|
|
44
|
+
values["robot_load_then_centre"] = construct_from_values(
|
|
45
|
+
values, "robot_load_then_centre", RobotLoadThenCentre
|
|
46
|
+
)
|
|
47
|
+
values["multi_rotation_scan"] = construct_from_values(
|
|
48
|
+
values, "multi_rotation_scan", MultiRotationScan
|
|
49
|
+
)
|
|
50
|
+
return values
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from pydantic import Field
|
|
2
|
+
|
|
3
|
+
from mx_bluesky.hyperion.parameters.components import (
|
|
4
|
+
HyperionParameters,
|
|
5
|
+
WithOptionalEnergyChange,
|
|
6
|
+
WithSample,
|
|
7
|
+
WithSnapshot,
|
|
8
|
+
WithVisit,
|
|
9
|
+
)
|
|
10
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RobotLoadAndEnergyChange(
|
|
14
|
+
HyperionParameters, WithSample, WithSnapshot, WithOptionalEnergyChange, WithVisit
|
|
15
|
+
):
|
|
16
|
+
thawing_time: float = Field(default=CONST.I03.THAWING_TIME)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mx-bluesky
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Bluesky tools for MX Beamlines at DLS
|
|
5
5
|
Author-email: Dominic Oram <dominic.oram@diamond.ac.uk>
|
|
6
6
|
License: Apache License
|
|
@@ -237,7 +237,7 @@ Requires-Dist: daq-config-server >=0.1.1
|
|
|
237
237
|
Requires-Dist: ophyd ==1.9.0
|
|
238
238
|
Requires-Dist: ophyd-async >=0.3a5
|
|
239
239
|
Requires-Dist: bluesky >=1.13.0a4
|
|
240
|
-
Requires-Dist: dls-dodal ==1.
|
|
240
|
+
Requires-Dist: dls-dodal ==1.33.0
|
|
241
241
|
Provides-Extra: dev
|
|
242
242
|
Requires-Dist: black ; extra == 'dev'
|
|
243
243
|
Requires-Dist: build ; extra == 'dev'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
mx_bluesky/__init__.py,sha256=twUymKa_5teVCbYPgxRDu87WyQhJa8nMRb8HLTCFJZ8,115
|
|
2
2
|
mx_bluesky/__main__.py,sha256=bmFrxcsN8zGadkDLRnE3qV3-iXJcEWVPp5GNx2rsTJ0,383
|
|
3
|
-
mx_bluesky/_version.py,sha256=
|
|
3
|
+
mx_bluesky/_version.py,sha256=zMnMemknXglcJs59xkicNzeEJTVgYd1omSfLWj76yWw,411
|
|
4
4
|
mx_bluesky/example.py,sha256=_zBoGrKAI1ReOvBz51F9PDorKWQufrb0_ydmoqJ2UAA,478
|
|
5
5
|
mx_bluesky/jupyter_example.ipynb,sha256=wpwvPrBvwtRMS5AIFk8F54cIlUoD0o4ji8tKK5cZHA4,1672
|
|
6
6
|
mx_bluesky/beamlines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -72,20 +72,22 @@ mx_bluesky/hyperion/device_setup_plans/setup_oav.py,sha256=LkhhcAyiNiTpeHCzW7vbz
|
|
|
72
72
|
mx_bluesky/hyperion/device_setup_plans/setup_panda.py,sha256=ZnH2hTMR-Q35D0Gu00cwr-aobIRrfRxoQKW3A0j3fk4,7783
|
|
73
73
|
mx_bluesky/hyperion/device_setup_plans/setup_zebra.py,sha256=rzzxU1d3ahe5tIk0h2TULvabKlY57OhrtO4mM8oKyuc,8049
|
|
74
74
|
mx_bluesky/hyperion/device_setup_plans/smargon.py,sha256=sSqrURldwwqPvbS-y7y-9Y1LM6Rq3AO0JgA9cHCPais,788
|
|
75
|
-
mx_bluesky/hyperion/device_setup_plans/utils.py,sha256=
|
|
75
|
+
mx_bluesky/hyperion/device_setup_plans/utils.py,sha256=5xuz4SFYfAA14pvYycvw3zQiwUq2_gscn3LiTdKRz8M,1813
|
|
76
76
|
mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py,sha256=tx9Sl3LMw4r9ls8J8TGf6COz__ISgLjJaEpInzlmnP8,3679
|
|
77
77
|
mx_bluesky/hyperion/experiment_plans/__init__.py,sha256=Tq9XXh8-N4obZMizxi5H1laV-toJQ9olu4K05gMFo8E,936
|
|
78
|
-
mx_bluesky/hyperion/experiment_plans/experiment_registry.py,sha256=
|
|
79
|
-
mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py,sha256=
|
|
78
|
+
mx_bluesky/hyperion/experiment_plans/experiment_registry.py,sha256=n7A0yK4ftpwB0GoNop4ZM1jcFvdqEQuq6qLabzprLKo,2995
|
|
79
|
+
mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py,sha256=mGxz_6rMR3_z9hihP-e_DDtWzMulxdJrgIU2qoWGNEc,19321
|
|
80
80
|
mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py,sha256=C03cKIQLyDAeGnI05tW6Z2kzItTIfHL_wlXqd0X8TcM,7186
|
|
81
|
+
mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py,sha256=vmqqlZANQB9LAl9QgMNmGU3yB624_gMuM7pJlglPOOc,1711
|
|
81
82
|
mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py,sha256=lzkC1mZCuXW_GmGhgWeTjKGTgAP1uqNWlcEpY5_dOgc,6943
|
|
82
83
|
mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py,sha256=7OcQ3nm7m-xLdPkct41-HrrQKrs9q_U8qOy80QqhnFg,2821
|
|
83
84
|
mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py,sha256=JZJW3hOzcxFyCEmsMYWWGwA9tAgGgg85nBKxBxKXeX0,16276
|
|
84
85
|
mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py,sha256=vV9UOubh2v6clL4LHFSQhqVBGcKPaNVWqK2rDrdPcQI,4146
|
|
85
86
|
mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py,sha256=YcGGckesXe_5NhaIEd0SFOPbtTYkpDKLSi3g7_2d52o,5969
|
|
86
|
-
mx_bluesky/hyperion/experiment_plans/
|
|
87
|
+
mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py,sha256=jogvdhNYIb5B2dZihPX3EgL_o3iFUYMTNumNWZNRHRI,7802
|
|
88
|
+
mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py,sha256=lIGqj_ugGUfiS-1eTbO_5Q6MRfhA5QgINbUvY9JMhjI,5422
|
|
87
89
|
mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py,sha256=iYsLw3nlIlpdccK1EeWH1S7nN1JoINvVxNRfZG52DE4,15802
|
|
88
|
-
mx_bluesky/hyperion/experiment_plans/set_energy_plan.py,sha256=
|
|
90
|
+
mx_bluesky/hyperion/experiment_plans/set_energy_plan.py,sha256=sBCwDxtBb-XzWPIYeIOqjKSeeOmdLzDvDihONA_Qcwg,1729
|
|
89
91
|
mx_bluesky/hyperion/external_interaction/__init__.py,sha256=95DwXDmKsx36RgAL-AtLZl2LQoLPKbzeYdlkkP_4Coc,559
|
|
90
92
|
mx_bluesky/hyperion/external_interaction/config_server.py,sha256=hA5r4v071gkV91F9YPwTVQGLPq3iMb1pjcBEE14Uxh4,1077
|
|
91
93
|
mx_bluesky/hyperion/external_interaction/exceptions.py,sha256=XBDES13VaW9fhxRZYNvSfLC_Mvg4M4RqMseW_u18Mb8,342
|
|
@@ -93,15 +95,15 @@ mx_bluesky/hyperion/external_interaction/callbacks/__init__.py,sha256=njGhxi0Qf0
|
|
|
93
95
|
mx_bluesky/hyperion/external_interaction/callbacks/__main__.py,sha256=Ke_3nKJXOnPu06rq3r9oULoTqgfwfbQYQgt5GDEidYE,4860
|
|
94
96
|
mx_bluesky/hyperion/external_interaction/callbacks/aperture_change_callback.py,sha256=pWd84QldTGLoxPdyqXZk6_SLhvF7O-CQRsiXqWDQEkg,837
|
|
95
97
|
mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py,sha256=tWtbpdq3dcTpoVpuDIeSAf-naziky38wgMeW6S1Dh7c,2914
|
|
96
|
-
mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py,sha256=
|
|
98
|
+
mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py,sha256=ynztJNtM-Njs_kTIFI6aM1YzcX7TK3c_7p4gge2QUCg,8875
|
|
97
99
|
mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py,sha256=MnpHKTwBbI5_xDtm5VK1cSObrfkWBuWP0_OXnU1qQCA,622
|
|
98
100
|
mx_bluesky/hyperion/external_interaction/callbacks/logging_callback.py,sha256=W5jO7uHvi84FmEwVC_wNk93oc3-SJ8pZq61cYS-qalU,708
|
|
99
101
|
mx_bluesky/hyperion/external_interaction/callbacks/plan_reactive_callback.py,sha256=7UtkXZluAag_Mx_JnESd7ODPSN3WrcNCgN8mquIpxjE,4086
|
|
100
102
|
mx_bluesky/hyperion/external_interaction/callbacks/zocalo_callback.py,sha256=Jwf_jFLnC1lRm-WIlZ6ZozbQyw_SHtXK_5HUA5RT7Fw,3960
|
|
101
103
|
mx_bluesky/hyperion/external_interaction/callbacks/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
102
|
-
mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py,sha256=
|
|
103
|
-
mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py,sha256=
|
|
104
|
-
mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py,sha256=
|
|
104
|
+
mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py,sha256=CjB3SOITmwv9I7pokwN0pmPomDAri7fJrg7Ww2kpXPo,1981
|
|
105
|
+
mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py,sha256=g7g_YmW3ZqFSN_uIXV-gONoMWS_mrQUdv51vJ2UOe0s,2584
|
|
106
|
+
mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py,sha256=R60oJdMwx8l0qqfRoyNrcj7Qg0fL0VU9IDm0YzR8xi0,3580
|
|
105
107
|
mx_bluesky/hyperion/external_interaction/callbacks/rotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
108
|
mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py,sha256=tYc5B1UN8K_69rRBhx1KjpLv_r6htRJxjG05sAIFKvg,7220
|
|
107
109
|
mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py,sha256=gXub8lt04ClC4sU_QGaBW4w3wrH8hJK7Tjy0AY4zf7g,718
|
|
@@ -114,23 +116,25 @@ mx_bluesky/hyperion/external_interaction/ispyb/__init__.py,sha256=47DEQpj8HBSa-_
|
|
|
114
116
|
mx_bluesky/hyperion/external_interaction/ispyb/data_model.py,sha256=7P2Tz3Y9k-vKSGsdk8ppvKg15z1iBGGKbw3RNv_8y-E,2632
|
|
115
117
|
mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py,sha256=ekMaDRkshbC72_hY0VWjaBA5b1vQgUfHoYBW22wEzNw,4487
|
|
116
118
|
mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py,sha256=K71lAHoqMBh-ayqFdfafIwRd8AIqnyj6LR6rzk00nl8,10318
|
|
117
|
-
mx_bluesky/hyperion/external_interaction/ispyb/ispyb_utils.py,sha256=
|
|
119
|
+
mx_bluesky/hyperion/external_interaction/ispyb/ispyb_utils.py,sha256=2Vl5qvGoCvbZ-lJFJSSNpTkbE4YfHAhy79jP7Oap6gg,720
|
|
118
120
|
mx_bluesky/hyperion/external_interaction/nexus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
119
121
|
mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py,sha256=dVeKUc92TQcO1rpssqTsufwzlIdlHUu2e6zWm4mUYqs,5131
|
|
120
122
|
mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py,sha256=L67UUdauzbXqsf2GJveGT6NP5YxbSzvcD0RjK5zrErI,4136
|
|
121
123
|
mx_bluesky/hyperion/parameters/__init__.py,sha256=kf2wfcILBUBpT0tJ8-W39BywQUkn67yxl9IVsfrr1LE,115
|
|
122
124
|
mx_bluesky/hyperion/parameters/cli.py,sha256=FGzvEB76YnQvBydUMPUNHJuqxvEe7Zc627w7gA2KODY,2125
|
|
123
|
-
mx_bluesky/hyperion/parameters/components.py,sha256=
|
|
125
|
+
mx_bluesky/hyperion/parameters/components.py,sha256=ayIH6QLX15Qeebbz5W66kXUpLpH70JuwdF2E3YyjEmE,7171
|
|
124
126
|
mx_bluesky/hyperion/parameters/constants.py,sha256=U21htONRj9Tvr7nyRbnrSyW6SRAADIkS0wLU0A3gvUQ,4458
|
|
125
|
-
mx_bluesky/hyperion/parameters/gridscan.py,sha256=
|
|
127
|
+
mx_bluesky/hyperion/parameters/gridscan.py,sha256=eTBsjMmzRpS5BacbDmRhH4uncLS96EKrMgKQ1u4Chpg,8310
|
|
128
|
+
mx_bluesky/hyperion/parameters/load_centre_collect.py,sha256=Q0TpVoAZeqPvRBayWPacU3wOWdawmlqhB7361xRKVvc,1583
|
|
129
|
+
mx_bluesky/hyperion/parameters/robot_load.py,sha256=nWiFrakYIn55Y9FDM10TN3Leq5TsAVFpDfY59FU3pIw,435
|
|
126
130
|
mx_bluesky/hyperion/parameters/rotation.py,sha256=HP25ZPlM0U7rRsUxUQFvBPs5pI5NWE2PHSlCg3fI_2Y,5602
|
|
127
131
|
mx_bluesky/hyperion/resources/panda/panda-gridscan.yaml,sha256=xrhgok-9X2VXdyLEWiYOUEeRCBqhYM6IJFAefnNdgzw,26521
|
|
128
132
|
mx_bluesky/hyperion/utils/context.py,sha256=TYG3e4lu88ssngoNbsR5pfEXI0DveDemLWaBuThtvbI,2710
|
|
129
133
|
mx_bluesky/hyperion/utils/utils.py,sha256=GoxupsUcAhGg0TmK_KMgGSB2rDDSd8tV5zGGLOfiAKk,731
|
|
130
134
|
mx_bluesky/hyperion/utils/validation.py,sha256=Cw8TDODble039-lqnSUmFu01p9jdgf-bchcTkByRxok,6569
|
|
131
|
-
mx_bluesky-1.
|
|
132
|
-
mx_bluesky-1.
|
|
133
|
-
mx_bluesky-1.
|
|
134
|
-
mx_bluesky-1.
|
|
135
|
-
mx_bluesky-1.
|
|
136
|
-
mx_bluesky-1.
|
|
135
|
+
mx_bluesky-1.2.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
136
|
+
mx_bluesky-1.2.0.dist-info/METADATA,sha256=6yz0owOp839jruq_KMLvJ2WlDWnlHZ1pgz7mLenyKKI,17163
|
|
137
|
+
mx_bluesky-1.2.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
138
|
+
mx_bluesky-1.2.0.dist-info/entry_points.txt,sha256=Bt3iHCqzZtHYnnSKoh_qM2k3K4LbK1Uxr0gF8B34F98,528
|
|
139
|
+
mx_bluesky-1.2.0.dist-info/top_level.txt,sha256=S4rrzXIUef58ulf_04wn01XGZ3xeJjXs4LPEJ_xoF-I,11
|
|
140
|
+
mx_bluesky-1.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|