mx-bluesky 1.5.15__py3-none-any.whl → 1.6.3__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/i02_1/parameters/gridscan.py +1 -1
- mx_bluesky/beamlines/i04/__init__.py +4 -0
- mx_bluesky/beamlines/i04/callbacks/murko_callback.py +18 -0
- mx_bluesky/beamlines/i04/experiment_plans/i04_grid_detect_then_xray_centre_plan.py +5 -4
- mx_bluesky/beamlines/i04/oav_centering_plans/oav_imaging.py +224 -10
- mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +5 -2
- mx_bluesky/beamlines/i04/thawing_plan.py +3 -2
- 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 +19 -20
- 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 +4 -9
- 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 +15 -19
- mx_bluesky/beamlines/i24/parameters/__init__.py +0 -0
- mx_bluesky/beamlines/i24/parameters/constants.py +9 -0
- mx_bluesky/beamlines/i24/serial/dcid.py +3 -3
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_extruder_collect_py3v2.py +7 -7
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_chip_collect_py3v1.py +7 -7
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_chip_manager_py3v1.py +3 -3
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +3 -3
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +5 -5
- mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +7 -7
- mx_bluesky/beamlines/i24/serial/web_gui_plans/oav_plans.py +1 -1
- 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 +2 -2
- mx_bluesky/common/experiment_plans/inner_plans/read_hardware.py +1 -0
- mx_bluesky/common/experiment_plans/oav_grid_detection_plan.py +1 -1
- mx_bluesky/common/experiment_plans/pin_tip_centring_plan.py +2 -2
- 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 +13 -2
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_mapping.py +0 -2
- mx_bluesky/common/external_interaction/ispyb/data_model.py +1 -1
- mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +1 -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 +9 -7
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +1 -1
- mx_bluesky/hyperion/device_setup_plans/utils.py +1 -1
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +3 -1
- mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +1 -0
- 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 +2 -5
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +3 -3
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +14 -128
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +4 -4
- mx_bluesky/hyperion/experiment_plans/udc_default_state.py +19 -6
- 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/device_composites.py +1 -1
- 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.15.dist-info → mx_bluesky-1.6.3.dist-info}/METADATA +3 -31
- {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/RECORD +88 -68
- {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/WHEEL +1 -1
- {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/licenses/LICENSE +0 -0
- {mx_bluesky-1.5.15.dist-info → mx_bluesky-1.6.3.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
3
|
import bluesky.plan_stubs as bps
|
|
4
|
+
from dodal.devices.beamlines.i24.aperture import Aperture, AperturePositions
|
|
5
|
+
from dodal.devices.beamlines.i24.beam_center import DetectorBeamCenter
|
|
6
|
+
from dodal.devices.beamlines.i24.beamstop import Beamstop, BeamstopPositions
|
|
7
|
+
from dodal.devices.beamlines.i24.dcm import DCM
|
|
8
|
+
from dodal.devices.beamlines.i24.dual_backlight import BacklightPositions, DualBacklight
|
|
4
9
|
from dodal.devices.detector.det_dim_constants import DetectorSizeConstants
|
|
5
|
-
from dodal.devices.i24.aperture import Aperture, AperturePositions
|
|
6
|
-
from dodal.devices.i24.beam_center import DetectorBeamCenter
|
|
7
|
-
from dodal.devices.i24.beamstop import Beamstop, BeamstopPositions
|
|
8
|
-
from dodal.devices.i24.dcm import DCM
|
|
9
|
-
from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
|
|
10
10
|
from dodal.devices.motors import YZStage
|
|
11
11
|
from dodal.devices.util.lookup_tables import (
|
|
12
12
|
linear_interpolation_lut,
|
|
@@ -8,14 +8,14 @@ from bluesky.utils import MsgGenerator
|
|
|
8
8
|
from dodal.beamlines import i24
|
|
9
9
|
from dodal.common import inject
|
|
10
10
|
from dodal.devices.attenuator.attenuator import EnumFilterAttenuator
|
|
11
|
+
from dodal.devices.beamlines.i24.aperture import Aperture
|
|
12
|
+
from dodal.devices.beamlines.i24.beam_center import DetectorBeamCenter
|
|
13
|
+
from dodal.devices.beamlines.i24.beamstop import Beamstop
|
|
14
|
+
from dodal.devices.beamlines.i24.dcm import DCM
|
|
15
|
+
from dodal.devices.beamlines.i24.dual_backlight import BacklightPositions, DualBacklight
|
|
16
|
+
from dodal.devices.beamlines.i24.focus_mirrors import FocusMirrorsMode
|
|
17
|
+
from dodal.devices.beamlines.i24.pmac import PMAC
|
|
11
18
|
from dodal.devices.hutch_shutter import HutchShutter
|
|
12
|
-
from dodal.devices.i24.aperture import Aperture
|
|
13
|
-
from dodal.devices.i24.beam_center import DetectorBeamCenter
|
|
14
|
-
from dodal.devices.i24.beamstop import Beamstop
|
|
15
|
-
from dodal.devices.i24.dcm import DCM
|
|
16
|
-
from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
|
|
17
|
-
from dodal.devices.i24.focus_mirrors import FocusMirrorsMode
|
|
18
|
-
from dodal.devices.i24.pmac import PMAC
|
|
19
19
|
from dodal.devices.motors import YZStage
|
|
20
20
|
from dodal.devices.oav.oav_detector import OAVBeamCentreFile
|
|
21
21
|
from dodal.devices.zebra.zebra import Zebra
|
|
@@ -5,7 +5,7 @@ import bluesky.preprocessors as bpp
|
|
|
5
5
|
from bluesky.utils import MsgGenerator
|
|
6
6
|
from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
|
|
7
7
|
from dodal.devices.motors import XYZStage
|
|
8
|
-
from dodal.devices.robot import BartRobot
|
|
8
|
+
from dodal.devices.robot import SAMPLE_LOCATION_EMPTY, BartRobot
|
|
9
9
|
from dodal.devices.smargon import CombinedMove, Smargon, StubPosition
|
|
10
10
|
from dodal.plan_stubs.motor_utils import MoveTooLargeError, home_and_reset_wrapper
|
|
11
11
|
|
|
@@ -14,27 +14,6 @@ from mx_bluesky.common.parameters.constants import (
|
|
|
14
14
|
HardwareConstants,
|
|
15
15
|
PlanNameConstants,
|
|
16
16
|
)
|
|
17
|
-
from mx_bluesky.common.utils.log import LOGGER
|
|
18
|
-
|
|
19
|
-
SLEEP_PER_CHECK = 0.1
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def wait_for_smargon_not_disabled(smargon: Smargon, timeout=60):
|
|
23
|
-
"""Waits for the smargon disabled flag to go low. The robot hardware is responsible
|
|
24
|
-
for setting this to low when it is safe to move. It does this through a physical
|
|
25
|
-
connection between the robot and the smargon.
|
|
26
|
-
"""
|
|
27
|
-
LOGGER.info("Waiting for smargon enabled")
|
|
28
|
-
times_to_check = int(timeout / SLEEP_PER_CHECK)
|
|
29
|
-
for _ in range(times_to_check):
|
|
30
|
-
smargon_disabled = yield from bps.rd(smargon.disabled)
|
|
31
|
-
if not smargon_disabled:
|
|
32
|
-
LOGGER.info("Smargon now enabled")
|
|
33
|
-
return
|
|
34
|
-
yield from bps.sleep(SLEEP_PER_CHECK)
|
|
35
|
-
raise TimeoutError(
|
|
36
|
-
"Timed out waiting for smargon to become enabled after robot load"
|
|
37
|
-
)
|
|
38
17
|
|
|
39
18
|
|
|
40
19
|
def _raise_exception_if_moved_out_of_cryojet(exception):
|
|
@@ -117,8 +96,7 @@ def robot_unload(
|
|
|
117
96
|
yield from bps.save()
|
|
118
97
|
|
|
119
98
|
def _unload():
|
|
120
|
-
yield from bps.abs_set(robot,
|
|
121
|
-
yield from wait_for_smargon_not_disabled(smargon)
|
|
99
|
+
yield from bps.abs_set(robot, SAMPLE_LOCATION_EMPTY, wait=True)
|
|
122
100
|
|
|
123
101
|
gonio_finished = yield from do_plan_while_lower_gonio_at_home(
|
|
124
102
|
_unload(), lower_gonio
|
|
@@ -14,7 +14,10 @@ from dodal.devices.zebra.zebra_controlled_shutter import (
|
|
|
14
14
|
ZebraShutterControl,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
from mx_bluesky.common.parameters.constants import
|
|
17
|
+
from mx_bluesky.common.parameters.constants import (
|
|
18
|
+
ZEBRA_STATUS_TIMEOUT,
|
|
19
|
+
PlanGroupCheckpointConstants,
|
|
20
|
+
)
|
|
18
21
|
from mx_bluesky.common.utils.log import LOGGER
|
|
19
22
|
|
|
20
23
|
"""Plans in this file will work as intended if the zebra has the following configuration:
|
|
@@ -154,7 +157,7 @@ def setup_zebra_for_rotation(
|
|
|
154
157
|
shutter_opening_deg: float = 2.5,
|
|
155
158
|
shutter_opening_s: float = 0.04,
|
|
156
159
|
direction: RotationDirection = RotationDirection.POSITIVE,
|
|
157
|
-
group: str =
|
|
160
|
+
group: str = PlanGroupCheckpointConstants.SETUP_ZEBRA_FOR_ROTATION,
|
|
158
161
|
wait: bool = True,
|
|
159
162
|
ttl_input_for_detector_to_use: int | None = None,
|
|
160
163
|
):
|
|
@@ -154,7 +154,7 @@ def common_flyscan_xray_centre(
|
|
|
154
154
|
|
|
155
155
|
This plan will also push data to ispyb when used with the ispyb_activation_decorator.
|
|
156
156
|
|
|
157
|
-
There are a few other useful decorators to use with this plan, see: verify_undulator_gap_before_run_decorator,
|
|
157
|
+
There are a few other useful decorators to use with this plan, see: verify_undulator_gap_before_run_decorator, common/preprocessors/preprocessors.py
|
|
158
158
|
"""
|
|
159
159
|
|
|
160
160
|
def _overall_tidy():
|
|
@@ -210,7 +210,7 @@ def _fetch_xrc_results_from_zocalo(
|
|
|
210
210
|
|
|
211
211
|
LOGGER.info("Getting X-ray center Zocalo results...")
|
|
212
212
|
|
|
213
|
-
yield from bps.trigger(zocalo_results)
|
|
213
|
+
yield from bps.trigger(zocalo_results, wait=True)
|
|
214
214
|
LOGGER.info("Zocalo triggered and read, interpreting results.")
|
|
215
215
|
xrc_results = yield from get_full_processing_results(zocalo_results)
|
|
216
216
|
LOGGER.info(f"Got xray centres, top 5: {xrc_results[:5]}")
|
|
@@ -104,7 +104,7 @@ def grid_detection_plan(
|
|
|
104
104
|
for angle in (yield from optimum_grid_detect_angles(smargon)):
|
|
105
105
|
yield from bps.mv(smargon.omega, angle)
|
|
106
106
|
# need to wait for the OAV image to update
|
|
107
|
-
# See
|
|
107
|
+
# See https://github.com/DiamondLightSource/mx-bluesky/issues/416 for improvements
|
|
108
108
|
yield from bps.sleep(HardwareConstants.OAV_REFRESH_DELAY)
|
|
109
109
|
|
|
110
110
|
tip_x_px, tip_y_px = yield from catch_exception_and_warn(
|
|
@@ -146,7 +146,7 @@ def pin_tip_centre_plan(
|
|
|
146
146
|
LOGGER.info(f"Tip offset in pixels: {tip_offset_px}")
|
|
147
147
|
|
|
148
148
|
# need to wait for the OAV image to update
|
|
149
|
-
# See
|
|
149
|
+
# See https://github.com/DiamondLightSource/mx-bluesky/issues/416 for improvements
|
|
150
150
|
yield from bps.sleep(0.3)
|
|
151
151
|
|
|
152
152
|
yield from pre_centring_setup_oav(oav, oav_params, pin_tip_setup)
|
|
@@ -157,7 +157,7 @@ def pin_tip_centre_plan(
|
|
|
157
157
|
yield from bps.mvr(gonio.omega, -90)
|
|
158
158
|
|
|
159
159
|
# need to wait for the OAV image to update
|
|
160
|
-
# See
|
|
160
|
+
# See https://github.com/DiamondLightSource/mx-bluesky/issues/416 for improvements
|
|
161
161
|
yield from bps.sleep(0.3)
|
|
162
162
|
tip = yield from catch_exception_and_warn(
|
|
163
163
|
PinNotFoundError, wait_for_tip_to_be_found, pin_tip_detect
|
|
File without changes
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
|
|
5
|
+
from dodal.devices.zebra.zebra import RotationDirection
|
|
6
|
+
from dodal.utils import get_beamline_name
|
|
7
|
+
|
|
8
|
+
from mx_bluesky.common.parameters.constants import RotationParamConstants
|
|
9
|
+
from mx_bluesky.common.parameters.rotation import SingleRotationScan
|
|
10
|
+
from mx_bluesky.common.utils.log import LOGGER
|
|
11
|
+
|
|
12
|
+
DEFAULT_DIRECTION = RotationDirection.NEGATIVE
|
|
13
|
+
DEFAULT_MAX_VELOCITY = 120
|
|
14
|
+
# Use a slightly larger time to acceleration than EPICS as it's better to be cautious
|
|
15
|
+
ACCELERATION_MARGIN = 1.5
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclasses.dataclass
|
|
19
|
+
class RotationMotionProfile:
|
|
20
|
+
start_scan_deg: float
|
|
21
|
+
start_motion_deg: float
|
|
22
|
+
scan_width_deg: float
|
|
23
|
+
shutter_time_s: float
|
|
24
|
+
direction: RotationDirection
|
|
25
|
+
speed_for_rotation_deg_s: float
|
|
26
|
+
acceleration_offset_deg: float
|
|
27
|
+
shutter_opening_deg: float
|
|
28
|
+
total_exposure_s: float
|
|
29
|
+
distance_to_move_deg: float
|
|
30
|
+
max_velocity_deg_s: float
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def calculate_motion_profile(
|
|
34
|
+
params: SingleRotationScan,
|
|
35
|
+
motor_time_to_speed_s: float,
|
|
36
|
+
max_velocity_deg_s: float,
|
|
37
|
+
) -> RotationMotionProfile:
|
|
38
|
+
"""Calculates the various numbers needed for motions in the rotation scan.
|
|
39
|
+
Rotates through "scan width" plus twice an "offset" to take into account
|
|
40
|
+
acceleration at the start and deceleration at the end, plus the number of extra
|
|
41
|
+
degrees of rotation needed to make sure the fast shutter has fully opened before the
|
|
42
|
+
detector trigger is sent.
|
|
43
|
+
See https://github.com/DiamondLightSource/hyperion/wiki/rotation-scan-geometry
|
|
44
|
+
for a simple pictorial explanation."""
|
|
45
|
+
|
|
46
|
+
assert params.rotation_increment_deg > 0
|
|
47
|
+
|
|
48
|
+
direction = params.rotation_direction
|
|
49
|
+
start_scan_deg = params.omega_start_deg
|
|
50
|
+
|
|
51
|
+
if RotationParamConstants.OMEGA_FLIP:
|
|
52
|
+
# If omega_flip is True then the motor omega axis is inverted with respect to the
|
|
53
|
+
# coordinate system.
|
|
54
|
+
start_scan_deg = -start_scan_deg
|
|
55
|
+
direction = (
|
|
56
|
+
direction.POSITIVE
|
|
57
|
+
if direction == direction.NEGATIVE
|
|
58
|
+
else direction.NEGATIVE
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
num_images = params.num_images
|
|
62
|
+
shutter_time_s = params.shutter_opening_time_s
|
|
63
|
+
image_width_deg = params.rotation_increment_deg
|
|
64
|
+
exposure_time_s = params.exposure_time_s
|
|
65
|
+
motor_time_to_speed_s *= ACCELERATION_MARGIN
|
|
66
|
+
|
|
67
|
+
LOGGER.info("Calculating rotation scan motion profile:")
|
|
68
|
+
LOGGER.info(
|
|
69
|
+
f"{num_images=}, {shutter_time_s=}, {image_width_deg=}, {exposure_time_s=}, {direction=}"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
scan_width_deg = num_images * params.rotation_increment_deg
|
|
73
|
+
LOGGER.info(f"{scan_width_deg=} = {num_images=} * {params.rotation_increment_deg=}")
|
|
74
|
+
|
|
75
|
+
speed_for_rotation_deg_s = image_width_deg / exposure_time_s
|
|
76
|
+
LOGGER.info("speed_for_rotation_deg_s = image_width_deg / exposure_time_s")
|
|
77
|
+
LOGGER.info(
|
|
78
|
+
f"{speed_for_rotation_deg_s=} = {image_width_deg=} / {exposure_time_s=}"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
acceleration_offset_deg = motor_time_to_speed_s * speed_for_rotation_deg_s
|
|
82
|
+
LOGGER.info(
|
|
83
|
+
f"{acceleration_offset_deg=} = {motor_time_to_speed_s=} * {speed_for_rotation_deg_s=}"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
start_motion_deg = start_scan_deg - (acceleration_offset_deg * direction.multiplier)
|
|
87
|
+
LOGGER.info(
|
|
88
|
+
f"{start_motion_deg=} = {start_scan_deg=} - ({acceleration_offset_deg=} * {direction.multiplier=})"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
shutter_opening_deg = speed_for_rotation_deg_s * shutter_time_s
|
|
92
|
+
LOGGER.info(
|
|
93
|
+
f"{shutter_opening_deg=} = {speed_for_rotation_deg_s=} * {shutter_time_s=}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
shutter_opening_deg = speed_for_rotation_deg_s * shutter_time_s
|
|
97
|
+
LOGGER.info(
|
|
98
|
+
f"{shutter_opening_deg=} = {speed_for_rotation_deg_s=} * {shutter_time_s=}"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
total_exposure_s = num_images * exposure_time_s
|
|
102
|
+
LOGGER.info(f"{total_exposure_s=} = {num_images=} * {exposure_time_s=}")
|
|
103
|
+
|
|
104
|
+
distance_to_move_deg = (
|
|
105
|
+
scan_width_deg + shutter_opening_deg + acceleration_offset_deg * 2
|
|
106
|
+
) * direction.multiplier
|
|
107
|
+
LOGGER.info(
|
|
108
|
+
f"{distance_to_move_deg=} = ({scan_width_deg=} + {shutter_opening_deg=} + {acceleration_offset_deg=} * 2) * {direction=})"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# See https://github.com/DiamondLightSource/mx-bluesky/issues/1224
|
|
112
|
+
if get_beamline_name("i03") == "i24":
|
|
113
|
+
acceleration_offset_deg = 10
|
|
114
|
+
|
|
115
|
+
return RotationMotionProfile(
|
|
116
|
+
start_scan_deg=start_scan_deg,
|
|
117
|
+
start_motion_deg=start_motion_deg,
|
|
118
|
+
scan_width_deg=scan_width_deg,
|
|
119
|
+
shutter_time_s=shutter_time_s,
|
|
120
|
+
direction=direction,
|
|
121
|
+
speed_for_rotation_deg_s=speed_for_rotation_deg_s,
|
|
122
|
+
acceleration_offset_deg=acceleration_offset_deg,
|
|
123
|
+
shutter_opening_deg=shutter_opening_deg,
|
|
124
|
+
total_exposure_s=total_exposure_s,
|
|
125
|
+
distance_to_move_deg=distance_to_move_deg,
|
|
126
|
+
max_velocity_deg_s=max_velocity_deg_s,
|
|
127
|
+
)
|
|
@@ -23,7 +23,7 @@ from mx_bluesky.common.external_interaction.ispyb.ispyb_store import (
|
|
|
23
23
|
)
|
|
24
24
|
from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import get_ispyb_config
|
|
25
25
|
from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
|
|
26
|
-
from mx_bluesky.common.parameters.constants import DocDescriptorNames
|
|
26
|
+
from mx_bluesky.common.parameters.constants import USE_NUMTRACKER, DocDescriptorNames
|
|
27
27
|
from mx_bluesky.common.utils.log import (
|
|
28
28
|
ISPYB_ZOCALO_CALLBACK_LOGGER,
|
|
29
29
|
format_doc_for_log,
|
|
@@ -86,6 +86,17 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
86
86
|
|
|
87
87
|
def activity_gated_start(self, doc: RunStart):
|
|
88
88
|
self._oav_snapshot_event_idx = 0
|
|
89
|
+
|
|
90
|
+
if self.params and self.params.visit == USE_NUMTRACKER:
|
|
91
|
+
try:
|
|
92
|
+
visit = doc.get("instrument_session")
|
|
93
|
+
assert isinstance(visit, str)
|
|
94
|
+
self.params.visit = visit
|
|
95
|
+
except Exception as e:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
f"Error trying to retrieve instrument session from document {doc}"
|
|
98
|
+
) from e
|
|
99
|
+
|
|
89
100
|
return self.tag_doc(doc)
|
|
90
101
|
|
|
91
102
|
def activity_gated_descriptor(self, doc: EventDescriptor):
|
|
@@ -124,7 +135,6 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
124
135
|
)
|
|
125
136
|
synchrotron_mode = doc["data"]["synchrotron-synchrotron_mode"]
|
|
126
137
|
assert isinstance(synchrotron_mode, SynchrotronMode)
|
|
127
|
-
|
|
128
138
|
hwscan_data_collection_info = DataCollectionInfo(
|
|
129
139
|
undulator_gap1=doc["data"]["undulator-current_gap"],
|
|
130
140
|
synchrotron_mode=synchrotron_mode.value,
|
|
@@ -159,6 +169,7 @@ class BaseISPyBCallback(PlanReactiveCallback):
|
|
|
159
169
|
beamsize_at_sampley=beamsize_y_mm,
|
|
160
170
|
flux=doc["data"]["flux-flux_reading"],
|
|
161
171
|
detector_mode="ROI" if doc["data"]["eiger_cam_roi_mode"] else "FULL",
|
|
172
|
+
ispyb_detector_id=doc["data"]["eiger-ispyb_detector_id"],
|
|
162
173
|
)
|
|
163
174
|
if transmission := doc["data"]["attenuator-actual_transmission"]:
|
|
164
175
|
# Ispyb wants the transmission in a percentage, we use fractions
|
|
@@ -9,7 +9,6 @@ from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import (
|
|
|
9
9
|
)
|
|
10
10
|
from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
|
|
11
11
|
|
|
12
|
-
I03_EIGER_DETECTOR = 78
|
|
13
12
|
EIGER_FILE_SUFFIX = "h5"
|
|
14
13
|
|
|
15
14
|
|
|
@@ -31,7 +30,6 @@ def populate_remaining_data_collection_info(
|
|
|
31
30
|
data_collection_info.sample_id = params.sample_id
|
|
32
31
|
data_collection_info.visit_string = params.visit
|
|
33
32
|
data_collection_info.parent_id = data_collection_group_id
|
|
34
|
-
data_collection_info.detector_id = I03_EIGER_DETECTOR
|
|
35
33
|
data_collection_info.comments = comment
|
|
36
34
|
data_collection_info.detector_distance = params.detector_params.detector_distance
|
|
37
35
|
data_collection_info.exp_time = params.detector_params.exposure_time_s
|
|
@@ -40,7 +40,7 @@ class DataCollectionInfo:
|
|
|
40
40
|
kappa_start: float | None = None
|
|
41
41
|
|
|
42
42
|
visit_string: str | None = None
|
|
43
|
-
|
|
43
|
+
ispyb_detector_id: int | None = None
|
|
44
44
|
axis_start: float | None = None
|
|
45
45
|
slitgap_vertical: float | None = None
|
|
46
46
|
slitgap_horizontal: float | None = None
|
|
@@ -282,7 +282,7 @@ def _data_collection_info_to_json(data: DataCollectionInfo) -> dict:
|
|
|
282
282
|
"axisEnd": data.axis_end,
|
|
283
283
|
"chiStart": data.chi_start,
|
|
284
284
|
"kappaStart": data.kappa_start,
|
|
285
|
-
"detectorId": data.
|
|
285
|
+
"detectorId": data.ispyb_detector_id,
|
|
286
286
|
"axisStart": data.axis_start,
|
|
287
287
|
"slitGapVertical": data.slitgap_vertical,
|
|
288
288
|
"slitGapHorizontal": data.slitgap_horizontal,
|
|
@@ -25,6 +25,7 @@ from semver import Version
|
|
|
25
25
|
|
|
26
26
|
from mx_bluesky.common.parameters.constants import (
|
|
27
27
|
TEST_MODE,
|
|
28
|
+
USE_NUMTRACKER,
|
|
28
29
|
DetectorParamConstants,
|
|
29
30
|
GridscanParamConstants,
|
|
30
31
|
)
|
|
@@ -32,6 +33,10 @@ from mx_bluesky.common.parameters.constants import (
|
|
|
32
33
|
PARAMETER_VERSION = Version.parse("5.3.0")
|
|
33
34
|
|
|
34
35
|
|
|
36
|
+
def get_param_version() -> SemanticVersion:
|
|
37
|
+
return SemanticVersion.validate_from_str(str(PARAMETER_VERSION))
|
|
38
|
+
|
|
39
|
+
|
|
35
40
|
class RotationAxis(StrEnum):
|
|
36
41
|
OMEGA = "omega"
|
|
37
42
|
PHI = "phi"
|
|
@@ -152,8 +157,8 @@ class WithVisit(BaseModel):
|
|
|
152
157
|
det_dist_to_beam_converter_path: str = Field(
|
|
153
158
|
default=DetectorParamConstants.BEAM_XY_LUT_PATH
|
|
154
159
|
)
|
|
155
|
-
insertion_prefix: str = "SR03S" if TEST_MODE else "SR03I"
|
|
156
160
|
detector_distance_mm: float | None = Field(default=None, gt=0)
|
|
161
|
+
insertion_prefix: str = "SR03S" if TEST_MODE else "SR03I"
|
|
157
162
|
|
|
158
163
|
|
|
159
164
|
class DiffractionExperiment(
|
|
@@ -176,12 +181,17 @@ class DiffractionExperiment(
|
|
|
176
181
|
@model_validator(mode="before")
|
|
177
182
|
@classmethod
|
|
178
183
|
def validate_directories(cls, values):
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
values["
|
|
182
|
-
"
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
# Plans using numtracker currently won't work with snapshot directories:
|
|
185
|
+
# see https://github.com/DiamondLightSource/mx-bluesky/issues/1527
|
|
186
|
+
if values["storage_directory"] != USE_NUMTRACKER:
|
|
187
|
+
os.makedirs(values["storage_directory"], exist_ok=True)
|
|
188
|
+
|
|
189
|
+
values["snapshot_directory"] = values.get(
|
|
190
|
+
"snapshot_directory",
|
|
191
|
+
Path(values["storage_directory"], "snapshots").as_posix(),
|
|
192
|
+
)
|
|
193
|
+
else:
|
|
194
|
+
values["snapshot_directory"] = Path("/tmp")
|
|
185
195
|
return values
|
|
186
196
|
|
|
187
197
|
@property
|
|
@@ -9,6 +9,9 @@ from pydantic.dataclasses import dataclass
|
|
|
9
9
|
|
|
10
10
|
from mx_bluesky.definitions import ROOT_DIR
|
|
11
11
|
|
|
12
|
+
# Use as visit if numtracker is being used
|
|
13
|
+
USE_NUMTRACKER = "from numtracker"
|
|
14
|
+
|
|
12
15
|
BEAMLINE = get_beamline_name("test")
|
|
13
16
|
TEST_MODE = BEAMLINE == "test"
|
|
14
17
|
ZEBRA_STATUS_TIMEOUT = 30
|
|
@@ -111,6 +114,8 @@ class GridscanParamConstants:
|
|
|
111
114
|
@dataclass(frozen=True)
|
|
112
115
|
class RotationParamConstants:
|
|
113
116
|
DEFAULT_APERTURE_POSITION = ApertureValue.LARGE
|
|
117
|
+
DEFAULT_SHUTTER_TIME_S = 0.06
|
|
118
|
+
OMEGA_FLIP = True # See https://github.com/DiamondLightSource/mx-bluesky/issues/1223 to make beamline-specific
|
|
114
119
|
|
|
115
120
|
|
|
116
121
|
@dataclass(frozen=True)
|
|
@@ -138,6 +143,7 @@ class PlanGroupCheckpointConstants:
|
|
|
138
143
|
MOVE_GONIO_TO_START = "move_gonio_to_start"
|
|
139
144
|
READY_FOR_OAV = "ready_for_oav"
|
|
140
145
|
PREPARE_APERTURE = "prepare_aperture"
|
|
146
|
+
SETUP_ZEBRA_FOR_ROTATION = "setup_zebra_for_rotation"
|
|
141
147
|
|
|
142
148
|
|
|
143
149
|
# Eventually replace below with https://github.com/DiamondLightSource/mx-bluesky/issues/798
|
|
@@ -28,9 +28,9 @@ from mx_bluesky.common.parameters.components import (
|
|
|
28
28
|
WithSample,
|
|
29
29
|
WithScan,
|
|
30
30
|
)
|
|
31
|
-
from mx_bluesky.
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
from mx_bluesky.common.parameters.constants import (
|
|
32
|
+
DetectorParamConstants,
|
|
33
|
+
RotationParamConstants,
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
|
|
@@ -56,7 +56,9 @@ class RotationScanPerSweep(OptionalGonioAngleStarts, OptionalXyzStarts, WithSamp
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
class RotationExperiment(DiffractionExperiment):
|
|
59
|
-
shutter_opening_time_s: float = Field(
|
|
59
|
+
shutter_opening_time_s: float = Field(
|
|
60
|
+
default=RotationParamConstants.DEFAULT_SHUTTER_TIME_S
|
|
61
|
+
)
|
|
60
62
|
rotation_increment_deg: float = Field(default=0.1, gt=0)
|
|
61
63
|
ispyb_experiment_type: IspybExperimentType = Field(
|
|
62
64
|
default=IspybExperimentType.ROTATION
|
|
@@ -67,7 +69,7 @@ class RotationExperiment(DiffractionExperiment):
|
|
|
67
69
|
) -> DetectorParams:
|
|
68
70
|
self.det_dist_to_beam_converter_path = (
|
|
69
71
|
self.det_dist_to_beam_converter_path
|
|
70
|
-
or
|
|
72
|
+
or DetectorParamConstants.BEAM_XY_LUT_PATH
|
|
71
73
|
)
|
|
72
74
|
optional_args = {}
|
|
73
75
|
if self.run_number:
|
|
@@ -75,7 +77,7 @@ class RotationExperiment(DiffractionExperiment):
|
|
|
75
77
|
assert self.detector_distance_mm is not None
|
|
76
78
|
os.makedirs(self.storage_directory, exist_ok=True)
|
|
77
79
|
return DetectorParams(
|
|
78
|
-
detector_size_constants=
|
|
80
|
+
detector_size_constants=DetectorParamConstants.DETECTOR,
|
|
79
81
|
expected_energy_ev=self.demand_energy_ev,
|
|
80
82
|
exposure_time_s=self.exposure_time_s,
|
|
81
83
|
directory=self.storage_directory,
|
|
@@ -97,7 +99,7 @@ class RotationExperiment(DiffractionExperiment):
|
|
|
97
99
|
@classmethod
|
|
98
100
|
def _set_default_aperture_position(cls, aperture_position: ApertureValue | None):
|
|
99
101
|
if not aperture_position:
|
|
100
|
-
default_aperture =
|
|
102
|
+
default_aperture = RotationParamConstants.DEFAULT_APERTURE_POSITION
|
|
101
103
|
LOGGER.warning(
|
|
102
104
|
f"No aperture position selected. Defaulting to {default_aperture}"
|
|
103
105
|
)
|
|
@@ -107,7 +109,7 @@ class RotationExperiment(DiffractionExperiment):
|
|
|
107
109
|
|
|
108
110
|
|
|
109
111
|
class SingleRotationScan(
|
|
110
|
-
WithScan,
|
|
112
|
+
WithScan, RotationExperiment, RotationScanPerSweep, DiffractionExperimentWithSample
|
|
111
113
|
):
|
|
112
114
|
@property
|
|
113
115
|
def detector_params(self):
|