mx-bluesky 1.5.11__py3-none-any.whl → 1.5.12__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/aithre_lasershaping/experiment_plans/__init__.py +0 -0
- mx_bluesky/beamlines/aithre_lasershaping/experiment_plans/robot_load_plan.py +198 -0
- mx_bluesky/beamlines/aithre_lasershaping/parameters/__init__.py +0 -0
- mx_bluesky/beamlines/aithre_lasershaping/parameters/constants.py +17 -0
- mx_bluesky/beamlines/aithre_lasershaping/parameters/robot_load_parameters.py +13 -0
- mx_bluesky/beamlines/aithre_lasershaping/pin_tip_centring.py +31 -0
- mx_bluesky/beamlines/aithre_lasershaping/robot_load.py +80 -0
- mx_bluesky/beamlines/i04/__init__.py +6 -2
- mx_bluesky/beamlines/i04/callbacks/murko_callback.py +27 -12
- mx_bluesky/beamlines/i04/experiment_plans/i04_grid_detect_then_xray_centre_plan.py +87 -13
- mx_bluesky/beamlines/i04/external_interaction/__init__.py +0 -0
- mx_bluesky/beamlines/i04/external_interaction/config_server.py +15 -0
- mx_bluesky/beamlines/i04/oav_centering_plans/__init__.py +0 -0
- mx_bluesky/beamlines/i04/oav_centering_plans/oav_imaging.py +115 -0
- mx_bluesky/beamlines/i04/parameters/__init__.py +0 -0
- mx_bluesky/beamlines/i04/parameters/constants.py +21 -0
- mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +24 -1
- mx_bluesky/beamlines/i04/thawing_plan.py +147 -152
- mx_bluesky/beamlines/i24/serial/dcid.py +4 -5
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_extruder_collect_py3v2.py +5 -2
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/CustomChip_py3v1.edl +11 -11
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DetStage.edl +3 -3
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +142 -142
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/MappingLite-oxford_py3v1.edl +135 -135
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/PMAC_Command.edl +8 -8
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +13 -13
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_chip_collect_py3v1.py +7 -4
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_chip_manager_py3v1.py +35 -32
- mx_bluesky/beamlines/i24/serial/parameters/utils.py +5 -5
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +113 -306
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +8 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +1 -1
- mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +1 -1
- mx_bluesky/beamlines/i24/serial/web_gui_plans/oav_plans.py +64 -0
- mx_bluesky/{hyperion/device_setup_plans/smargon.py → common/device_setup_plans/gonio.py} +9 -6
- mx_bluesky/common/device_setup_plans/manipulate_sample.py +8 -1
- mx_bluesky/common/device_setup_plans/robot_load_unload.py +1 -1
- mx_bluesky/common/device_setup_plans/setup_oav.py +8 -0
- mx_bluesky/common/device_setup_plans/setup_zebra_and_shutter.py +0 -5
- mx_bluesky/common/device_setup_plans/xbpm_feedback.py +8 -1
- mx_bluesky/common/experiment_plans/beamstop_check.py +229 -0
- mx_bluesky/common/experiment_plans/common_flyscan_xray_centre_plan.py +2 -0
- mx_bluesky/common/experiment_plans/inner_plans/read_hardware.py +5 -2
- mx_bluesky/common/experiment_plans/oav_snapshot_plan.py +0 -1
- mx_bluesky/{hyperion → common}/experiment_plans/pin_tip_centring_plan.py +20 -21
- mx_bluesky/common/external_interaction/callbacks/common/grid_detection_callback.py +5 -0
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +10 -12
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_mapping.py +3 -5
- mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +5 -5
- mx_bluesky/common/external_interaction/config_server.py +2 -2
- mx_bluesky/common/external_interaction/ispyb/data_model.py +11 -4
- mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +159 -2
- mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +76 -166
- mx_bluesky/common/external_interaction/ispyb/ispyb_utils.py +0 -14
- mx_bluesky/common/parameters/components.py +1 -0
- mx_bluesky/common/parameters/constants.py +3 -2
- mx_bluesky/common/parameters/device_composites.py +4 -2
- mx_bluesky/common/utils/exceptions.py +15 -0
- mx_bluesky/common/utils/log.py +9 -0
- mx_bluesky/common/utils/utils.py +48 -0
- mx_bluesky/hyperion/__main__.py +3 -13
- mx_bluesky/hyperion/baton_handler.py +23 -6
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +5 -6
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +3 -10
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +4 -2
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +8 -2
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/udc_default_state.py +160 -0
- mx_bluesky/hyperion/external_interaction/agamemnon.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +2 -2
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +1 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +1 -4
- mx_bluesky/hyperion/external_interaction/config_server.py +5 -5
- mx_bluesky/hyperion/parameters/constants.py +10 -3
- mx_bluesky/hyperion/parameters/device_composites.py +2 -2
- mx_bluesky/hyperion/parameters/robot_load.py +1 -9
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/METADATA +6 -5
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/RECORD +83 -69
- mx_bluesky/common/experiment_plans/inner_plans/udc_default_state.py +0 -86
- mx_bluesky/common/external_interaction/callbacks/common/logging_callback.py +0 -29
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/WHEEL +0 -0
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/licenses/LICENSE +0 -0
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.12.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
import bluesky.plan_stubs as bps
|
|
5
|
+
from bluesky.utils import MsgGenerator
|
|
6
|
+
from dodal.common import inject
|
|
7
|
+
from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
|
|
8
|
+
from dodal.devices.backlight import Backlight
|
|
9
|
+
from dodal.devices.mx_phase1.beamstop import Beamstop, BeamstopPositions
|
|
10
|
+
from dodal.devices.oav.oav_detector import OAV
|
|
11
|
+
from dodal.devices.robot import BartRobot, PinMounted
|
|
12
|
+
from dodal.devices.scintillator import InOut, Scintillator
|
|
13
|
+
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
14
|
+
from dodal.devices.zebra.zebra_controlled_shutter import (
|
|
15
|
+
ZebraShutter,
|
|
16
|
+
ZebraShutterControl,
|
|
17
|
+
ZebraShutterState,
|
|
18
|
+
)
|
|
19
|
+
from ophyd_async.core import InOut as core_INOUT
|
|
20
|
+
|
|
21
|
+
from mx_bluesky.common.utils.exceptions import BeamlineStateError
|
|
22
|
+
|
|
23
|
+
initial_wait_group = "Wait for scint to move in"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def take_oav_image_with_scintillator_in(
|
|
27
|
+
image_name: str | None = None,
|
|
28
|
+
image_path: str = "dls_sw/i04/software/bluesky/scratch",
|
|
29
|
+
transmission: float = 1,
|
|
30
|
+
attenuator: BinaryFilterAttenuator = inject("attenuator"),
|
|
31
|
+
shutter: ZebraShutter = inject("sample_shutter"),
|
|
32
|
+
oav: OAV = inject("oav"),
|
|
33
|
+
robot: BartRobot = inject("robot"),
|
|
34
|
+
beamstop: Beamstop = inject("beamstop"),
|
|
35
|
+
backlight: Backlight = inject("backlight"),
|
|
36
|
+
scintillator: Scintillator = inject("scintillator"),
|
|
37
|
+
xbpm_feedback: XBPMFeedback = inject("xbpm_feedback"),
|
|
38
|
+
) -> MsgGenerator:
|
|
39
|
+
"""
|
|
40
|
+
Takes an OAV image at specified transmission after necessary checks and preparation steps.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
image_name: Name of the OAV image to be saved
|
|
44
|
+
image_path: Path where the image should be saved
|
|
45
|
+
transmission: Transmission of the beam, takes a value from 0 to 1 where
|
|
46
|
+
1 lets all the beam through and 0 lets none of the beam through.
|
|
47
|
+
devices: These are the specific ophyd-devices used for the plan, the
|
|
48
|
+
defaults are always correct.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
yield from _prepare_beamline_for_scintillator_images(
|
|
52
|
+
robot, beamstop, backlight, scintillator, xbpm_feedback, initial_wait_group
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
yield from bps.abs_set(attenuator, transmission, group=initial_wait_group)
|
|
56
|
+
|
|
57
|
+
if image_name is None:
|
|
58
|
+
image_name = f"{time.time_ns()}ATT{transmission * 100}"
|
|
59
|
+
|
|
60
|
+
yield from bps.wait(initial_wait_group)
|
|
61
|
+
|
|
62
|
+
yield from bps.abs_set(shutter.control_mode, ZebraShutterControl.MANUAL, wait=True)
|
|
63
|
+
yield from bps.abs_set(shutter, ZebraShutterState.OPEN, wait=True)
|
|
64
|
+
|
|
65
|
+
take_and_save_oav_image(file_path=image_path, file_name=image_name, oav=oav)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _prepare_beamline_for_scintillator_images(
|
|
69
|
+
robot: BartRobot,
|
|
70
|
+
beamstop: Beamstop,
|
|
71
|
+
backlight: Backlight,
|
|
72
|
+
scintillator: Scintillator,
|
|
73
|
+
xbpm_feedback: XBPMFeedback,
|
|
74
|
+
group: str,
|
|
75
|
+
) -> MsgGenerator:
|
|
76
|
+
"""
|
|
77
|
+
Prepares the beamline for oav image by making sure the pin is NOT mounted and
|
|
78
|
+
the beam is on (feedback check). Finally, the scintillator is moved in.
|
|
79
|
+
"""
|
|
80
|
+
pin_mounted = yield from bps.rd(robot.gonio_pin_sensor)
|
|
81
|
+
if pin_mounted == PinMounted.PIN_MOUNTED:
|
|
82
|
+
raise BeamlineStateError("Pin should not be mounted!")
|
|
83
|
+
|
|
84
|
+
yield from bps.trigger(xbpm_feedback, group=group)
|
|
85
|
+
|
|
86
|
+
yield from bps.abs_set(
|
|
87
|
+
beamstop.selected_pos, BeamstopPositions.DATA_COLLECTION, group=group
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
yield from bps.abs_set(backlight, core_INOUT.OUT, group=group)
|
|
91
|
+
|
|
92
|
+
yield from bps.abs_set(scintillator.selected_pos, InOut.IN, group=group)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def take_and_save_oav_image(
|
|
96
|
+
file_name: str,
|
|
97
|
+
file_path: str,
|
|
98
|
+
oav: OAV,
|
|
99
|
+
) -> MsgGenerator:
|
|
100
|
+
"""
|
|
101
|
+
Plan which takes and saves an OAV image to the specified path.
|
|
102
|
+
Args:
|
|
103
|
+
file_name: Filename specifying the name of the image,
|
|
104
|
+
file_path: Path as a string specifying where the image should be saved,
|
|
105
|
+
oav: The OAV to take the image with
|
|
106
|
+
"""
|
|
107
|
+
group = "oav image path setting"
|
|
108
|
+
full_file_path = file_path + "/" + file_name
|
|
109
|
+
if not os.path.exists(full_file_path):
|
|
110
|
+
yield from bps.abs_set(oav.snapshot.filename, file_name, group=group)
|
|
111
|
+
yield from bps.abs_set(oav.snapshot.directory, file_path, group=group)
|
|
112
|
+
yield from bps.wait(group)
|
|
113
|
+
yield from bps.trigger(oav.snapshot, wait=True)
|
|
114
|
+
else:
|
|
115
|
+
raise FileExistsError("OAV image file path already exists")
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from pydantic.dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from mx_bluesky.common.parameters.constants import (
|
|
4
|
+
FeatureSettings,
|
|
5
|
+
FeatureSettingSources,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# These currently exist in GDA domain.properties
|
|
10
|
+
class I04FeatureSettingsSources(FeatureSettingSources):
|
|
11
|
+
ASSUMED_WAVELENGTH_IN_A = "gda.px.expttable.default.wavelength"
|
|
12
|
+
XRC_UNSCALED_TRANSMISSION_FRAC = "gda.mx.bluesky.i04.xrc.unscaled_transmission_frac"
|
|
13
|
+
XRC_UNSCALED_EXPOSURE_TIME_S = "gda.mx.bluesky.i04.xrc.unscaled_exposure_time_s"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Use these defaults if we can't read from the config server
|
|
17
|
+
@dataclass
|
|
18
|
+
class I04FeatureSettings(FeatureSettings):
|
|
19
|
+
ASSUMED_WAVELENGTH_IN_A: float = 0.95373
|
|
20
|
+
XRC_UNSCALED_TRANSMISSION_FRAC: int = 1
|
|
21
|
+
XRC_UNSCALED_EXPOSURE_TIME_S: float = 0.007
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import io
|
|
2
2
|
import json
|
|
3
|
+
import logging
|
|
3
4
|
import pickle
|
|
4
5
|
from datetime import timedelta
|
|
6
|
+
from logging import StreamHandler
|
|
5
7
|
from typing import TypedDict
|
|
6
8
|
|
|
7
9
|
import numpy as np
|
|
8
10
|
import zmq
|
|
9
11
|
from dodal.devices.i04.constants import RedisConstants
|
|
10
|
-
from dodal.devices.i04.murko_results import MurkoResult
|
|
12
|
+
from dodal.devices.i04.murko_results import RESULTS_COMPLETE_MESSAGE, MurkoResult
|
|
11
13
|
from numpy.typing import NDArray
|
|
12
14
|
from PIL import Image
|
|
13
15
|
from redis import StrictRedis
|
|
14
16
|
|
|
17
|
+
from mx_bluesky.beamlines.i04.callbacks.murko_callback import (
|
|
18
|
+
FORWARDING_COMPLETE_MESSAGE,
|
|
19
|
+
)
|
|
15
20
|
from mx_bluesky.common.utils.log import LOGGER
|
|
16
21
|
|
|
17
22
|
MURKO_ADDRESS = "tcp://i04-murko-prod.diamond.ac.uk:8008"
|
|
18
23
|
|
|
24
|
+
|
|
19
25
|
FullMurkoResults = dict[str, list[MurkoResult]]
|
|
20
26
|
|
|
21
27
|
|
|
@@ -112,6 +118,12 @@ class BatchMurkoForwarder:
|
|
|
112
118
|
self.redis_client.expire(redis_key, timedelta(days=7))
|
|
113
119
|
self.redis_client.publish("murko-results", pickle.dumps(results))
|
|
114
120
|
|
|
121
|
+
def send_stop_message_to_redis(self):
|
|
122
|
+
LOGGER.info(f"Publishing results complete message: {RESULTS_COMPLETE_MESSAGE}")
|
|
123
|
+
self.redis_client.publish(
|
|
124
|
+
"murko-results", pickle.dumps(RESULTS_COMPLETE_MESSAGE)
|
|
125
|
+
)
|
|
126
|
+
|
|
115
127
|
def add(self, sample_id: str, uuid: str, image: NDArray):
|
|
116
128
|
"""Add an image to the batch to send to murko."""
|
|
117
129
|
image_size = get_image_size(image)
|
|
@@ -159,6 +171,13 @@ class RedisListener:
|
|
|
159
171
|
if message and message["type"] == "message":
|
|
160
172
|
data = json.loads(message["data"])
|
|
161
173
|
LOGGER.info(f"Received from redis: {data}")
|
|
174
|
+
if data == FORWARDING_COMPLETE_MESSAGE:
|
|
175
|
+
LOGGER.info(
|
|
176
|
+
f"Received forwarding complete message: {FORWARDING_COMPLETE_MESSAGE}"
|
|
177
|
+
)
|
|
178
|
+
self.forwarder.flush()
|
|
179
|
+
self.forwarder.send_stop_message_to_redis()
|
|
180
|
+
return
|
|
162
181
|
uuid = data["uuid"]
|
|
163
182
|
sample_id = data["sample_id"]
|
|
164
183
|
|
|
@@ -188,6 +207,10 @@ class RedisListener:
|
|
|
188
207
|
|
|
189
208
|
|
|
190
209
|
def main():
|
|
210
|
+
stream_handler = StreamHandler()
|
|
211
|
+
stream_handler.setLevel(logging.INFO)
|
|
212
|
+
LOGGER.addHandler(stream_handler)
|
|
213
|
+
|
|
191
214
|
client = RedisListener()
|
|
192
215
|
client.listen_for_image_data_forever()
|
|
193
216
|
|
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
from collections.abc import Callable
|
|
2
|
-
from functools import partial
|
|
3
|
-
|
|
4
1
|
import bluesky.plan_stubs as bps
|
|
5
2
|
import bluesky.preprocessors as bpp
|
|
6
|
-
from bluesky.preprocessors import run_decorator, subs_decorator
|
|
3
|
+
from bluesky.preprocessors import contingency_decorator, run_decorator, subs_decorator
|
|
7
4
|
from bluesky.utils import MsgGenerator
|
|
8
5
|
from dodal.common import inject
|
|
9
6
|
from dodal.devices.i04.constants import RedisConstants
|
|
10
7
|
from dodal.devices.i04.murko_results import MurkoResultsDevice
|
|
11
|
-
from dodal.devices.oav.oav_detector import OAV
|
|
12
8
|
from dodal.devices.oav.oav_to_redis_forwarder import OAVToRedisForwarder, Source
|
|
13
9
|
from dodal.devices.robot import BartRobot
|
|
14
10
|
from dodal.devices.smargon import Smargon
|
|
15
11
|
from dodal.devices.thawer import OnOff, Thawer
|
|
12
|
+
from dodal.log import LOGGER
|
|
16
13
|
|
|
17
14
|
from mx_bluesky.beamlines.i04.callbacks.murko_callback import MurkoCallback
|
|
18
15
|
|
|
@@ -29,53 +26,26 @@ def thaw(
|
|
|
29
26
|
|
|
30
27
|
Args:
|
|
31
28
|
time_to_thaw (float): Time to thaw for, in seconds.
|
|
32
|
-
rotation (float
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
defaults are always correct.
|
|
29
|
+
rotation (float): How much to rotate by whilst thawing, in degrees.
|
|
30
|
+
thawer (Thawer): The thawing device.
|
|
31
|
+
smargon (Smargon): The smargon used to rotate.
|
|
36
32
|
"""
|
|
37
|
-
yield from
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def thaw_and_stream_to_redis(
|
|
41
|
-
time_to_thaw: float,
|
|
42
|
-
rotation: float = 360,
|
|
43
|
-
robot: BartRobot = inject("robot"),
|
|
44
|
-
thawer: Thawer = inject("thawer"),
|
|
45
|
-
smargon: Smargon = inject("smargon"),
|
|
46
|
-
oav: OAV = inject("oav_full_screen"),
|
|
47
|
-
oav_to_redis_forwarder: OAVToRedisForwarder = inject("oav_to_redis_forwarder"),
|
|
48
|
-
) -> MsgGenerator:
|
|
49
|
-
"""Turns on the thawer and rotates the sample by {rotation} degrees to thaw it, then
|
|
50
|
-
rotates {rotation} degrees back and turns the thawer off. The speed of the goniometer
|
|
51
|
-
is set such that the process takes whole process will take {time_to_thaw} time.
|
|
33
|
+
initial_velocity = yield from bps.rd(smargon.omega.velocity)
|
|
34
|
+
new_velocity = abs(rotation / time_to_thaw) * 2.0
|
|
52
35
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
36
|
+
def do_thaw():
|
|
37
|
+
yield from bps.abs_set(smargon.omega.velocity, new_velocity, wait=True)
|
|
38
|
+
yield from bps.abs_set(thawer, OnOff.ON, wait=True)
|
|
39
|
+
yield from bps.rel_set(smargon.omega, rotation, wait=True)
|
|
40
|
+
yield from bps.rel_set(smargon.omega, -rotation, wait=True)
|
|
56
41
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Defaults to 360.
|
|
61
|
-
... devices: These are the specific ophyd-devices used for the plan, the
|
|
62
|
-
defaults are always correct
|
|
63
|
-
"""
|
|
42
|
+
def cleanup():
|
|
43
|
+
yield from bps.abs_set(smargon.omega.velocity, initial_velocity, wait=True)
|
|
44
|
+
yield from bps.abs_set(thawer, OnOff.OFF, wait=True)
|
|
64
45
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
yield from bps.kickoff(oav_to_redis_forwarder, wait=True)
|
|
69
|
-
|
|
70
|
-
yield from _thaw_and_stream_to_redis(
|
|
71
|
-
time_to_thaw,
|
|
72
|
-
rotation,
|
|
73
|
-
robot,
|
|
74
|
-
thawer,
|
|
75
|
-
smargon,
|
|
76
|
-
oav,
|
|
77
|
-
oav_to_redis_forwarder,
|
|
78
|
-
switch_forwarder_to_roi,
|
|
46
|
+
yield from bpp.contingency_wrapper(
|
|
47
|
+
do_thaw(),
|
|
48
|
+
final_plan=cleanup,
|
|
79
49
|
)
|
|
80
50
|
|
|
81
51
|
|
|
@@ -85,14 +55,13 @@ def thaw_and_murko_centre(
|
|
|
85
55
|
robot: BartRobot = inject("robot"),
|
|
86
56
|
thawer: Thawer = inject("thawer"),
|
|
87
57
|
smargon: Smargon = inject("smargon"),
|
|
88
|
-
oav: OAV = inject("oav_full_screen"),
|
|
89
58
|
murko_results: MurkoResultsDevice = inject("murko_results"),
|
|
90
59
|
oav_to_redis_forwarder: OAVToRedisForwarder = inject("oav_to_redis_forwarder"),
|
|
91
60
|
) -> MsgGenerator:
|
|
92
61
|
"""Thaws the sample and centres it using murko by:
|
|
93
62
|
1. Turns on the thawer
|
|
94
63
|
2. Rotates the sample by {rotation} degrees, whilst this is happening images from
|
|
95
|
-
the
|
|
64
|
+
the full screen OAV are being fed to murko
|
|
96
65
|
3. After the rotation has completed moves to the average centre returned by murko
|
|
97
66
|
from these images
|
|
98
67
|
4. Rotate {rotation} degrees back to the start, whilst this is happening images
|
|
@@ -109,147 +78,173 @@ def thaw_and_murko_centre(
|
|
|
109
78
|
... devices: These are the specific ophyd-devices used for the plan, the
|
|
110
79
|
defaults are always correct
|
|
111
80
|
"""
|
|
112
|
-
|
|
113
81
|
murko_results_group = "get_results"
|
|
114
82
|
|
|
115
|
-
|
|
116
|
-
|
|
83
|
+
sample_id = yield from bps.rd(robot.sample_id)
|
|
84
|
+
sample_id = int(sample_id)
|
|
117
85
|
|
|
118
|
-
|
|
86
|
+
oav_fs = oav_to_redis_forwarder.sources[Source.FULL_SCREEN].oav_ref()
|
|
119
87
|
|
|
88
|
+
initial_zoom_level = yield from bps.rd(oav_fs.zoom_controller.level)
|
|
89
|
+
initial_velocity = yield from bps.rd(smargon.omega.velocity)
|
|
90
|
+
new_velocity = abs(rotation / time_to_thaw) * 2.0
|
|
91
|
+
murko_callback = MurkoCallback(
|
|
92
|
+
RedisConstants.REDIS_HOST,
|
|
93
|
+
RedisConstants.REDIS_PASSWORD,
|
|
94
|
+
RedisConstants.MURKO_REDIS_DB,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def cleanup():
|
|
98
|
+
yield from bps.mv(oav_fs.zoom_controller.level, initial_zoom_level)
|
|
99
|
+
yield from bps.abs_set(smargon.omega.velocity, initial_velocity, wait=True)
|
|
100
|
+
yield from bps.abs_set(thawer, OnOff.OFF, wait=True)
|
|
101
|
+
|
|
102
|
+
def centre_from_murko():
|
|
120
103
|
yield from bps.wait(murko_results_group)
|
|
104
|
+
|
|
121
105
|
x_predict = yield from bps.rd(murko_results.x_mm)
|
|
122
106
|
y_predict = yield from bps.rd(murko_results.y_mm)
|
|
123
107
|
z_predict = yield from bps.rd(murko_results.z_mm)
|
|
124
108
|
|
|
109
|
+
LOGGER.info(f"Got results: {x_predict, y_predict, z_predict}")
|
|
110
|
+
|
|
125
111
|
yield from bps.rel_set(smargon.x, x_predict)
|
|
126
112
|
yield from bps.rel_set(smargon.y, y_predict)
|
|
127
113
|
yield from bps.rel_set(smargon.z, z_predict)
|
|
128
114
|
|
|
129
|
-
|
|
115
|
+
@subs_decorator(murko_callback)
|
|
116
|
+
@contingency_decorator(final_plan=cleanup)
|
|
117
|
+
def do_thaw_and_murko_centre():
|
|
118
|
+
yield from bps.mv(
|
|
119
|
+
murko_results.sample_id,
|
|
120
|
+
str(sample_id),
|
|
121
|
+
oav_to_redis_forwarder.sample_id,
|
|
122
|
+
sample_id,
|
|
123
|
+
oav_fs.zoom_controller.level,
|
|
124
|
+
"1.0x",
|
|
125
|
+
)
|
|
126
|
+
yield from bps.abs_set(smargon.omega.velocity, new_velocity, wait=True)
|
|
127
|
+
yield from bps.abs_set(thawer, OnOff.ON, wait=True)
|
|
130
128
|
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
def rotate_in_one_direction_then_murko_centre(
|
|
130
|
+
rotation: float, oav_mode: Source
|
|
131
|
+
):
|
|
132
|
+
@run_decorator(md={"sample_id": sample_id})
|
|
133
|
+
def rotate_in_one_direction_and_start_murko_and_stream_to_redis():
|
|
134
|
+
yield from bps.stage(murko_results, wait=True)
|
|
135
|
+
yield from bps.trigger(murko_results, group=murko_results_group)
|
|
133
136
|
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
yield from _rotate_in_one_direction_and_stream_to_redis(
|
|
138
|
+
smargon, oav_to_redis_forwarder, oav_mode, rotation
|
|
139
|
+
)
|
|
136
140
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
robot,
|
|
142
|
-
thawer,
|
|
143
|
-
smargon,
|
|
144
|
-
oav,
|
|
145
|
-
oav_to_redis_forwarder,
|
|
146
|
-
centre_then_switch_forwarder_to_roi,
|
|
147
|
-
),
|
|
148
|
-
final_plan=partial(bps.unstage, murko_results, wait=True),
|
|
149
|
-
)
|
|
141
|
+
yield from rotate_in_one_direction_and_start_murko_and_stream_to_redis()
|
|
142
|
+
|
|
143
|
+
yield from centre_from_murko()
|
|
144
|
+
yield from bps.unstage(murko_results, wait=True)
|
|
150
145
|
|
|
146
|
+
yield from rotate_in_one_direction_then_murko_centre(
|
|
147
|
+
rotation, Source.FULL_SCREEN
|
|
148
|
+
)
|
|
149
|
+
yield from rotate_in_one_direction_then_murko_centre(-rotation, Source.ROI)
|
|
150
|
+
|
|
151
|
+
yield from do_thaw_and_murko_centre()
|
|
151
152
|
|
|
152
|
-
|
|
153
|
+
|
|
154
|
+
def thaw_and_stream_to_redis(
|
|
153
155
|
time_to_thaw: float,
|
|
154
|
-
rotation: float,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
rotation: float = 360,
|
|
157
|
+
robot: BartRobot = inject("robot"),
|
|
158
|
+
thawer: Thawer = inject("thawer"),
|
|
159
|
+
smargon: Smargon = inject("smargon"),
|
|
160
|
+
oav_to_redis_forwarder: OAVToRedisForwarder = inject("oav_to_redis_forwarder"),
|
|
158
161
|
) -> MsgGenerator:
|
|
159
162
|
"""Turns on the thawer and rotates the sample by {rotation} degrees to thaw it, then
|
|
160
163
|
rotates {rotation} degrees back and turns the thawer off. The speed of the goniometer
|
|
161
164
|
is set such that the process takes whole process will take {time_to_thaw} time.
|
|
162
165
|
|
|
166
|
+
At the same time streams OAV images to redis for later processing (e.g. by murko).
|
|
167
|
+
On the first rotation the images from the large ROI are streamed, on the second the
|
|
168
|
+
smaller ROI is used.
|
|
169
|
+
|
|
163
170
|
Args:
|
|
164
171
|
time_to_thaw (float): Time to thaw for, in seconds.
|
|
165
|
-
rotation (float): How much to rotate by whilst thawing, in degrees.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
of the smargon. Defaults to no plan.
|
|
172
|
+
rotation (float, optional): How much to rotate by whilst thawing, in degrees.
|
|
173
|
+
Defaults to 360.
|
|
174
|
+
... devices: These are the specific ophyd-devices used for the plan, the
|
|
175
|
+
defaults are always correct
|
|
170
176
|
"""
|
|
177
|
+
sample_id = yield from bps.rd(robot.sample_id)
|
|
178
|
+
sample_id = int(sample_id)
|
|
179
|
+
|
|
180
|
+
oav_fs = oav_to_redis_forwarder.sources[Source.FULL_SCREEN].oav_ref()
|
|
181
|
+
|
|
182
|
+
initial_zoom_level = yield from bps.rd(oav_fs.zoom_controller.level)
|
|
171
183
|
initial_velocity = yield from bps.rd(smargon.omega.velocity)
|
|
172
184
|
new_velocity = abs(rotation / time_to_thaw) * 2.0
|
|
173
185
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
yield from plan_between_rotations()
|
|
180
|
-
yield from bps.rel_set(smargon.omega, -rotation, wait=True)
|
|
186
|
+
murko_callback = MurkoCallback(
|
|
187
|
+
RedisConstants.REDIS_HOST,
|
|
188
|
+
RedisConstants.REDIS_PASSWORD,
|
|
189
|
+
RedisConstants.MURKO_REDIS_DB,
|
|
190
|
+
)
|
|
181
191
|
|
|
182
192
|
def cleanup():
|
|
193
|
+
yield from bps.mv(oav_fs.zoom_controller.level, initial_zoom_level)
|
|
183
194
|
yield from bps.abs_set(smargon.omega.velocity, initial_velocity, wait=True)
|
|
184
|
-
yield from bps.abs_set(thawer
|
|
195
|
+
yield from bps.abs_set(thawer, OnOff.OFF, wait=True)
|
|
185
196
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
final_plan=cleanup,
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
def _thaw_and_stream_to_redis(
|
|
194
|
-
time_to_thaw: float,
|
|
195
|
-
rotation: float,
|
|
196
|
-
robot: BartRobot,
|
|
197
|
-
thawer: Thawer,
|
|
198
|
-
smargon: Smargon,
|
|
199
|
-
oav: OAV,
|
|
200
|
-
oav_to_redis_forwarder: OAVToRedisForwarder,
|
|
201
|
-
plan_between_rotations: Callable[[], MsgGenerator],
|
|
202
|
-
) -> MsgGenerator:
|
|
203
|
-
zoom_percentage = yield from bps.rd(oav.zoom_controller.percentage)
|
|
204
|
-
sample_id = yield from bps.rd(robot.sample_id)
|
|
205
|
-
|
|
206
|
-
sample_id = int(sample_id)
|
|
207
|
-
zoom_level_before_thawing = yield from bps.rd(oav.zoom_controller.level)
|
|
208
|
-
|
|
209
|
-
yield from bps.mv(oav.zoom_controller.level, "1.0x")
|
|
210
|
-
|
|
211
|
-
microns_per_pixel_x = yield from bps.rd(oav.microns_per_pixel_x)
|
|
212
|
-
microns_per_pixel_y = yield from bps.rd(oav.microns_per_pixel_y)
|
|
213
|
-
beam_centre_i = yield from bps.rd(oav.beam_centre_i)
|
|
214
|
-
beam_centre_j = yield from bps.rd(oav.beam_centre_j)
|
|
215
|
-
|
|
216
|
-
@subs_decorator(
|
|
217
|
-
MurkoCallback(
|
|
218
|
-
RedisConstants.REDIS_HOST,
|
|
219
|
-
RedisConstants.REDIS_PASSWORD,
|
|
220
|
-
RedisConstants.MURKO_REDIS_DB,
|
|
221
|
-
)
|
|
222
|
-
)
|
|
223
|
-
@run_decorator(
|
|
224
|
-
md={
|
|
225
|
-
"microns_per_x_pixel": microns_per_pixel_x,
|
|
226
|
-
"microns_per_y_pixel": microns_per_pixel_y,
|
|
227
|
-
"beam_centre_i": beam_centre_i,
|
|
228
|
-
"beam_centre_j": beam_centre_j,
|
|
229
|
-
"zoom_percentage": zoom_percentage,
|
|
230
|
-
"sample_id": sample_id,
|
|
231
|
-
}
|
|
232
|
-
)
|
|
233
|
-
def _main_plan():
|
|
197
|
+
@subs_decorator(murko_callback)
|
|
198
|
+
@contingency_decorator(final_plan=cleanup)
|
|
199
|
+
def do_thaw_and_stream_to_redis():
|
|
234
200
|
yield from bps.mv(
|
|
235
201
|
oav_to_redis_forwarder.sample_id,
|
|
236
202
|
sample_id,
|
|
237
|
-
|
|
238
|
-
|
|
203
|
+
oav_fs.zoom_controller.level,
|
|
204
|
+
"1.0x",
|
|
239
205
|
)
|
|
240
|
-
|
|
241
|
-
yield from bps.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
206
|
+
yield from bps.abs_set(smargon.omega.velocity, new_velocity, wait=True)
|
|
207
|
+
yield from bps.abs_set(thawer, OnOff.ON, wait=True)
|
|
208
|
+
|
|
209
|
+
@run_decorator(md={"sample_id": sample_id})
|
|
210
|
+
def rotate_in_one_direction_and_stream_to_redis(
|
|
211
|
+
rotation: float, oav_mode: Source
|
|
212
|
+
):
|
|
213
|
+
yield from _rotate_in_one_direction_and_stream_to_redis(
|
|
214
|
+
smargon, oav_to_redis_forwarder, oav_mode, rotation
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
yield from rotate_in_one_direction_and_stream_to_redis(
|
|
218
|
+
rotation, Source.FULL_SCREEN
|
|
246
219
|
)
|
|
247
|
-
yield from
|
|
220
|
+
yield from rotate_in_one_direction_and_stream_to_redis(-rotation, Source.ROI)
|
|
248
221
|
|
|
249
|
-
|
|
250
|
-
yield from bps.mv(oav.zoom_controller.level, zoom_level_before_thawing)
|
|
222
|
+
yield from do_thaw_and_stream_to_redis()
|
|
251
223
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
224
|
+
|
|
225
|
+
def _rotate_in_one_direction_and_stream_to_redis(
|
|
226
|
+
smargon: Smargon,
|
|
227
|
+
oav_to_redis_forwarder: OAVToRedisForwarder,
|
|
228
|
+
oav_mode: Source,
|
|
229
|
+
rotation: float,
|
|
230
|
+
):
|
|
231
|
+
def get_metadata_from_current_oav():
|
|
232
|
+
current_source_idx = yield from bps.rd(oav_to_redis_forwarder.selected_source)
|
|
233
|
+
oav = oav_to_redis_forwarder.sources[current_source_idx].oav_ref()
|
|
234
|
+
yield from bps.create()
|
|
235
|
+
oav_info = yield from bps.read(oav)
|
|
236
|
+
LOGGER.info(f"Got oav information: {oav_info}")
|
|
237
|
+
yield from bps.save()
|
|
238
|
+
|
|
239
|
+
yield from bps.mv(
|
|
240
|
+
oav_to_redis_forwarder.selected_source,
|
|
241
|
+
oav_mode.value,
|
|
255
242
|
)
|
|
243
|
+
|
|
244
|
+
yield from get_metadata_from_current_oav()
|
|
245
|
+
yield from bps.monitor(smargon.omega.user_readback, name="smargon")
|
|
246
|
+
yield from bps.monitor(oav_to_redis_forwarder.uuid, name="oav")
|
|
247
|
+
|
|
248
|
+
yield from bps.kickoff(oav_to_redis_forwarder, wait=True)
|
|
249
|
+
yield from bps.rel_set(smargon.omega, rotation, wait=True)
|
|
250
|
+
yield from bps.complete(oav_to_redis_forwarder, wait=True)
|
|
@@ -112,6 +112,8 @@ class DCID:
|
|
|
112
112
|
match expt_params.detector_name:
|
|
113
113
|
case "eiger":
|
|
114
114
|
self.detector = Eiger()
|
|
115
|
+
case _:
|
|
116
|
+
raise ValueError("Unknown detector:", expt_params.detector_name)
|
|
115
117
|
|
|
116
118
|
self.server = server or DEFAULT_ISPYB_SERVER
|
|
117
119
|
self.emit_errors = emit_errors
|
|
@@ -144,7 +146,7 @@ class DCID:
|
|
|
144
146
|
try:
|
|
145
147
|
if not start_time:
|
|
146
148
|
start_time = datetime.datetime.now().astimezone()
|
|
147
|
-
|
|
149
|
+
else:
|
|
148
150
|
start_time = start_time.astimezone()
|
|
149
151
|
|
|
150
152
|
resolution = get_resolution(
|
|
@@ -156,10 +158,7 @@ class DCID:
|
|
|
156
158
|
transmission = self.parameters.transmission * 100
|
|
157
159
|
xbeam, ybeam = beam_settings.beam_center_in_mm
|
|
158
160
|
|
|
159
|
-
|
|
160
|
-
start_image_number = 1
|
|
161
|
-
else:
|
|
162
|
-
raise ValueError("Unknown detector:", self.detector)
|
|
161
|
+
start_image_number = 1
|
|
163
162
|
|
|
164
163
|
events = [
|
|
165
164
|
{
|
|
@@ -253,6 +253,7 @@ def main_extruder_plan(
|
|
|
253
253
|
parameters.exposure_time_s,
|
|
254
254
|
],
|
|
255
255
|
dcm,
|
|
256
|
+
detector_stage,
|
|
256
257
|
)
|
|
257
258
|
yield from setup_zebra_for_extruder_with_pump_probe_plan(
|
|
258
259
|
zebra,
|
|
@@ -275,6 +276,7 @@ def main_extruder_plan(
|
|
|
275
276
|
parameters.exposure_time_s,
|
|
276
277
|
],
|
|
277
278
|
dcm,
|
|
279
|
+
detector_stage,
|
|
278
280
|
)
|
|
279
281
|
yield from setup_zebra_for_quickshot_plan(
|
|
280
282
|
zebra, parameters.exposure_time_s, parameters.num_images, wait=True
|
|
@@ -374,6 +376,7 @@ def tidy_up_at_collection_end_plan(
|
|
|
374
376
|
parameters: ExtruderParameters,
|
|
375
377
|
dcid: DCID,
|
|
376
378
|
dcm: DCM,
|
|
379
|
+
detector_stage: YZStage,
|
|
377
380
|
) -> MsgGenerator:
|
|
378
381
|
"""A plan to tidy up at the end of a collection, successful or aborted.
|
|
379
382
|
|
|
@@ -386,7 +389,7 @@ def tidy_up_at_collection_end_plan(
|
|
|
386
389
|
|
|
387
390
|
# Clean Up
|
|
388
391
|
if parameters.detector_name == "eiger":
|
|
389
|
-
yield from sup.eiger("return-to-normal", None, dcm)
|
|
392
|
+
yield from sup.eiger("return-to-normal", None, dcm, detector_stage)
|
|
390
393
|
SSX_LOGGER.debug(f"{parameters.filename}_{caget(pv.eiger_seq_id)}")
|
|
391
394
|
SSX_LOGGER.debug("End of Run")
|
|
392
395
|
SSX_LOGGER.info("Close hutch shutter")
|
|
@@ -452,7 +455,7 @@ def run_plan_in_wrapper(
|
|
|
452
455
|
),
|
|
453
456
|
final_plan=lambda: (
|
|
454
457
|
yield from tidy_up_at_collection_end_plan(
|
|
455
|
-
zebra, shutter, parameters, dcid, dcm
|
|
458
|
+
zebra, shutter, parameters, dcid, dcm, detector_stage
|
|
456
459
|
)
|
|
457
460
|
),
|
|
458
461
|
auto_raise=False,
|