mx-bluesky 1.2.0__py3-none-any.whl → 1.4.1__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/__init__.py +8 -3
- mx_bluesky/__main__.py +12 -7
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/i04/callbacks/murko_callback.py +14 -4
- mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +178 -0
- mx_bluesky/beamlines/i04/thawing_plan.py +49 -11
- mx_bluesky/beamlines/i24/serial/__init__.py +3 -0
- mx_bluesky/beamlines/i24/serial/dcid.py +143 -171
- mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +1 -1
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +121 -110
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +3 -6
- mx_bluesky/beamlines/i24/serial/fixed_target/ft_utils.py +0 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +164 -169
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +149 -225
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +7 -216
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +18 -17
- mx_bluesky/beamlines/i24/serial/log.py +58 -49
- mx_bluesky/beamlines/i24/serial/parameters/__init__.py +4 -0
- mx_bluesky/beamlines/i24/serial/parameters/constants.py +6 -1
- mx_bluesky/beamlines/i24/serial/parameters/experiment_parameters.py +42 -15
- mx_bluesky/beamlines/i24/serial/parameters/fixed_target/cs/cs_maker.json +3 -3
- mx_bluesky/beamlines/i24/serial/run_extruder.sh +30 -5
- mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +30 -5
- mx_bluesky/beamlines/i24/serial/run_serial.py +24 -8
- mx_bluesky/beamlines/i24/serial/setup_beamline/ca.py +0 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +2 -0
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +104 -82
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +9 -20
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +26 -28
- mx_bluesky/beamlines/i24/serial/write_nexus.py +74 -72
- mx_bluesky/common/__init__.py +0 -0
- mx_bluesky/common/device_setup_plans/read_hardware_for_setup.py +14 -0
- mx_bluesky/common/external_interaction/config_server.py +46 -0
- mx_bluesky/common/parameters/components.py +258 -0
- mx_bluesky/common/parameters/constants.py +143 -0
- mx_bluesky/common/parameters/gridscan.py +94 -0
- mx_bluesky/common/parameters/robot_load.py +16 -0
- mx_bluesky/common/plans/__init__.py +1 -0
- mx_bluesky/common/plans/do_fgs.py +121 -0
- mx_bluesky/common/utils/log.py +118 -0
- mx_bluesky/{hyperion → common/utils}/tracing.py +2 -2
- mx_bluesky/hyperion/__main__.py +13 -10
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +47 -52
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +6 -12
- mx_bluesky/hyperion/device_setup_plans/setup_oav.py +6 -12
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +5 -6
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +49 -18
- mx_bluesky/hyperion/device_setup_plans/smargon.py +9 -9
- mx_bluesky/hyperion/device_setup_plans/utils.py +2 -2
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +4 -4
- mx_bluesky/hyperion/exceptions.py +13 -1
- mx_bluesky/hyperion/experiment_plans/__init__.py +4 -0
- mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +83 -0
- mx_bluesky/hyperion/experiment_plans/common/xrc_result.py +47 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -9
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +147 -169
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +48 -22
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +75 -9
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +21 -20
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +9 -6
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +40 -21
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +22 -22
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +43 -39
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +69 -18
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +17 -7
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +13 -13
- mx_bluesky/hyperion/external_interaction/callbacks/__init__.py +0 -4
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +5 -2
- mx_bluesky/hyperion/external_interaction/callbacks/common/abstract_event.py +66 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +5 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +30 -25
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +29 -12
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +19 -11
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +7 -4
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +5 -3
- mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/sample_handling_callback.py +84 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +38 -27
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +5 -4
- mx_bluesky/hyperion/external_interaction/config_server.py +11 -28
- mx_bluesky/hyperion/external_interaction/exceptions.py +0 -9
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +65 -15
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +1 -1
- mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +2 -2
- mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +1 -1
- mx_bluesky/hyperion/log.py +0 -84
- mx_bluesky/hyperion/parameters/components.py +4 -251
- mx_bluesky/hyperion/parameters/constants.py +22 -119
- mx_bluesky/hyperion/parameters/gridscan.py +35 -74
- mx_bluesky/hyperion/parameters/load_centre_collect.py +16 -11
- mx_bluesky/hyperion/parameters/rotation.py +23 -10
- mx_bluesky/hyperion/utils/utils.py +17 -0
- mx_bluesky/hyperion/utils/validation.py +5 -6
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.dist-info}/METADATA +36 -33
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.dist-info}/RECORD +102 -89
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.dist-info}/WHEEL +1 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +0 -161
- mx_bluesky/example.py +0 -19
- mx_bluesky/hyperion/parameters/robot_load.py +0 -16
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1.dist-info}/top_level.txt +0 -0
mx_bluesky/__init__.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
"""Top level API.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
.. data:: __version__
|
|
4
|
+
:type: str
|
|
5
|
+
|
|
6
|
+
Version number as calculated by https://github.com/pypa/setuptools_scm
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from ._version import __version__
|
|
5
10
|
|
|
6
11
|
__all__ = ["__version__"]
|
mx_bluesky/__main__.py
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
"""Interface for ``python -m mx_bluesky``."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from argparse import ArgumentParser
|
|
4
|
+
from collections.abc import Sequence
|
|
4
5
|
|
|
5
6
|
from . import __version__
|
|
6
7
|
|
|
7
8
|
__all__ = ["main"]
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
def main(args=None):
|
|
11
|
+
def main(args: Sequence[str] | None = None) -> None:
|
|
12
|
+
"""Argument parser for the CLI."""
|
|
11
13
|
parser = ArgumentParser()
|
|
12
|
-
parser.add_argument(
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"-v",
|
|
16
|
+
"--version",
|
|
17
|
+
action="version",
|
|
18
|
+
version=__version__,
|
|
19
|
+
)
|
|
20
|
+
parser.parse_args(args)
|
|
15
21
|
|
|
16
22
|
|
|
17
|
-
# test with: python -m mx_bluesky
|
|
18
23
|
if __name__ == "__main__":
|
|
19
24
|
main()
|
mx_bluesky/_version.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import json
|
|
3
|
+
from datetime import timedelta
|
|
3
4
|
|
|
4
5
|
from bluesky.callbacks import CallbackBase
|
|
5
6
|
from dodal.log import LOGGER
|
|
6
|
-
from event_model.documents import Event, RunStart
|
|
7
|
+
from event_model.documents import Event, RunStart, RunStop
|
|
7
8
|
from redis import StrictRedis
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class MurkoCallback(CallbackBase):
|
|
12
|
+
DATA_EXPIRY_DAYS = 7
|
|
13
|
+
|
|
11
14
|
def __init__(self, redis_host: str, redis_password: str, redis_db: int = 0):
|
|
12
15
|
self.redis_client = StrictRedis(
|
|
13
16
|
host=redis_host, password=redis_password, db=redis_db
|
|
@@ -15,15 +18,17 @@ class MurkoCallback(CallbackBase):
|
|
|
15
18
|
self.last_uuid = None
|
|
16
19
|
|
|
17
20
|
def start(self, doc: RunStart) -> RunStart | None:
|
|
21
|
+
self.sample_id = doc.get("sample_id")
|
|
18
22
|
self.murko_metadata = {
|
|
19
23
|
"zoom_percentage": doc.get("zoom_percentage"),
|
|
20
24
|
"microns_per_x_pixel": doc.get("microns_per_x_pixel"),
|
|
21
25
|
"microns_per_y_pixel": doc.get("microns_per_y_pixel"),
|
|
22
26
|
"beam_centre_i": doc.get("beam_centre_i"),
|
|
23
27
|
"beam_centre_j": doc.get("beam_centre_j"),
|
|
24
|
-
"sample_id":
|
|
28
|
+
"sample_id": self.sample_id,
|
|
25
29
|
}
|
|
26
30
|
self.last_uuid = None
|
|
31
|
+
LOGGER.info(f"Starting to stream metadata to murko under {self.sample_id}")
|
|
27
32
|
return doc
|
|
28
33
|
|
|
29
34
|
def event(self, doc: Event) -> Event:
|
|
@@ -40,6 +45,11 @@ class MurkoCallback(CallbackBase):
|
|
|
40
45
|
metadata["uuid"] = uuid
|
|
41
46
|
|
|
42
47
|
# Send metadata to REDIS and trigger murko
|
|
43
|
-
|
|
48
|
+
redis_key = f"murko:{metadata['sample_id']}:metadata"
|
|
49
|
+
self.redis_client.hset(redis_key, uuid, json.dumps(metadata))
|
|
50
|
+
self.redis_client.expire(redis_key, timedelta(days=self.DATA_EXPIRY_DAYS))
|
|
44
51
|
self.redis_client.publish("murko", json.dumps(metadata))
|
|
45
|
-
|
|
52
|
+
|
|
53
|
+
def stop(self, doc: RunStop) -> RunStop | None:
|
|
54
|
+
LOGGER.info(f"Finished streaming {self.sample_id} to murko")
|
|
55
|
+
return doc
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import json
|
|
3
|
+
import pickle
|
|
4
|
+
from typing import TypedDict
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import zmq
|
|
8
|
+
from dodal.beamlines.i04 import MURKO_REDIS_DB, REDIS_HOST, REDIS_PASSWORD
|
|
9
|
+
from numpy.typing import NDArray
|
|
10
|
+
from PIL import Image
|
|
11
|
+
from redis import StrictRedis
|
|
12
|
+
|
|
13
|
+
from mx_bluesky.common.utils.log import LOGGER
|
|
14
|
+
|
|
15
|
+
MURKO_ADDRESS = "tcp://i04-murko-prod.diamond.ac.uk:8008"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MurkoRequest(TypedDict):
|
|
19
|
+
to_predict: NDArray
|
|
20
|
+
model_img_size: tuple[int, int]
|
|
21
|
+
save: bool
|
|
22
|
+
min_size: int
|
|
23
|
+
description: list
|
|
24
|
+
prefix: list[str]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_image_size(image: NDArray) -> tuple[int, int]:
|
|
28
|
+
"""Returns the width and height of a numpy image"""
|
|
29
|
+
return image.shape[1], image.shape[0]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def send_to_murko_and_get_results(request: MurkoRequest) -> dict:
|
|
33
|
+
LOGGER.info(f"Sending {request['prefix']} to murko")
|
|
34
|
+
context = zmq.Context()
|
|
35
|
+
socket = context.socket(zmq.REQ)
|
|
36
|
+
socket.connect(MURKO_ADDRESS)
|
|
37
|
+
socket.send(pickle.dumps(request))
|
|
38
|
+
raw_results = socket.recv()
|
|
39
|
+
results = pickle.loads(raw_results)
|
|
40
|
+
LOGGER.info(f"Got {len(results['descriptions'])} results")
|
|
41
|
+
return results
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def correlate_results_to_uuids(request: MurkoRequest, murko_results: dict) -> list:
|
|
45
|
+
results = []
|
|
46
|
+
uuids = request["prefix"]
|
|
47
|
+
|
|
48
|
+
width, height = get_image_size(request["to_predict"][0])
|
|
49
|
+
|
|
50
|
+
for uuid, prediction in zip(uuids, murko_results["descriptions"], strict=False):
|
|
51
|
+
coords = prediction["most_likely_click"]
|
|
52
|
+
y_coord = coords[0] * height
|
|
53
|
+
x_coord = coords[1] * width
|
|
54
|
+
results.append(
|
|
55
|
+
{"uuid": uuid, "x_pixel_coord": x_coord, "y_pixel_coord": y_coord}
|
|
56
|
+
)
|
|
57
|
+
return results
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class BatchMurkoForwarder:
|
|
61
|
+
def __init__(self, redis_client: StrictRedis, batch_size: int):
|
|
62
|
+
"""
|
|
63
|
+
Holds image data streamed from redis and forwards it to murko when:
|
|
64
|
+
* A set number have been received
|
|
65
|
+
* The shape of the images changes
|
|
66
|
+
* When `flush` is called
|
|
67
|
+
|
|
68
|
+
Once data has been forwarded this will then wait on the results and put them
|
|
69
|
+
back in redis.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
redis_client: The client to send murko results back to redis.
|
|
73
|
+
batch_size: How many results to accumulate until they are flushed to redis.
|
|
74
|
+
"""
|
|
75
|
+
self.redis_client = redis_client
|
|
76
|
+
self.batch_size = batch_size
|
|
77
|
+
self._uuids_and_images: dict[str, NDArray] = {}
|
|
78
|
+
self._last_image_size: tuple[int, int] | None = None
|
|
79
|
+
self._last_sample_id = ""
|
|
80
|
+
|
|
81
|
+
def _handle_batch_of_images(self, sample_id, images, uuids):
|
|
82
|
+
request_arguments: MurkoRequest = {
|
|
83
|
+
"model_img_size": (256, 320),
|
|
84
|
+
"to_predict": np.array(images),
|
|
85
|
+
"save": False,
|
|
86
|
+
"min_size": 64,
|
|
87
|
+
"description": [
|
|
88
|
+
"foreground",
|
|
89
|
+
"crystal",
|
|
90
|
+
"loop_inside",
|
|
91
|
+
"loop",
|
|
92
|
+
["crystal", "loop"],
|
|
93
|
+
["crystal", "loop", "stem"],
|
|
94
|
+
],
|
|
95
|
+
"prefix": uuids,
|
|
96
|
+
}
|
|
97
|
+
predictions = send_to_murko_and_get_results(request_arguments)
|
|
98
|
+
results = correlate_results_to_uuids(request_arguments, predictions)
|
|
99
|
+
self._send_murko_results_to_redis(sample_id, results)
|
|
100
|
+
|
|
101
|
+
def _send_murko_results_to_redis(self, sample_id: str, results: list):
|
|
102
|
+
for result in results:
|
|
103
|
+
self.redis_client.hset(
|
|
104
|
+
f"murko:{sample_id}:results", result["uuid"], json.dumps(result)
|
|
105
|
+
)
|
|
106
|
+
self.redis_client.publish("murko-results", json.dumps(results))
|
|
107
|
+
|
|
108
|
+
def add(self, sample_id: str, uuid: str, image: NDArray):
|
|
109
|
+
"""Add an image to the batch to send to murko."""
|
|
110
|
+
image_size = get_image_size(image)
|
|
111
|
+
self._last_sample_id = sample_id
|
|
112
|
+
if self._last_image_size and self._last_image_size != image_size:
|
|
113
|
+
self.flush()
|
|
114
|
+
self._uuids_and_images[uuid] = image
|
|
115
|
+
self._last_image_size = image_size
|
|
116
|
+
if len(self._uuids_and_images.keys()) >= self.batch_size:
|
|
117
|
+
self.flush()
|
|
118
|
+
|
|
119
|
+
def flush(self):
|
|
120
|
+
"""Flush the batch to murko."""
|
|
121
|
+
if self._uuids_and_images:
|
|
122
|
+
self._handle_batch_of_images(
|
|
123
|
+
self._last_sample_id,
|
|
124
|
+
list(self._uuids_and_images.values()),
|
|
125
|
+
list(self._uuids_and_images.keys()),
|
|
126
|
+
)
|
|
127
|
+
self._uuids_and_images = {}
|
|
128
|
+
self._last_image_size = None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class RedisListener:
|
|
132
|
+
TIMEOUT_S = 2
|
|
133
|
+
|
|
134
|
+
def __init__(
|
|
135
|
+
self,
|
|
136
|
+
redis_host=REDIS_HOST,
|
|
137
|
+
redis_password=REDIS_PASSWORD,
|
|
138
|
+
db=MURKO_REDIS_DB,
|
|
139
|
+
redis_channel="murko",
|
|
140
|
+
):
|
|
141
|
+
self.redis_client = StrictRedis(
|
|
142
|
+
host=redis_host,
|
|
143
|
+
password=redis_password,
|
|
144
|
+
db=db,
|
|
145
|
+
)
|
|
146
|
+
self.pubsub = self.redis_client.pubsub()
|
|
147
|
+
self.channel = redis_channel
|
|
148
|
+
self.forwarder = BatchMurkoForwarder(self.redis_client, 10)
|
|
149
|
+
|
|
150
|
+
def _get_and_handle_message(self):
|
|
151
|
+
message = self.pubsub.get_message(timeout=self.TIMEOUT_S)
|
|
152
|
+
if message and message["type"] == "message":
|
|
153
|
+
data = json.loads(message["data"])
|
|
154
|
+
LOGGER.info(f"Received from redis: {data}")
|
|
155
|
+
uuid = data["uuid"]
|
|
156
|
+
sample_id = data["sample_id"]
|
|
157
|
+
|
|
158
|
+
# Images are put in redis as raw jpeg bytes, murko needs numpy arrays
|
|
159
|
+
raw_image = self.redis_client.hget(f"murko:{sample_id}:raw", uuid)
|
|
160
|
+
assert isinstance(raw_image, bytes)
|
|
161
|
+
image = Image.open(io.BytesIO(raw_image))
|
|
162
|
+
image = np.asarray(image)
|
|
163
|
+
|
|
164
|
+
self.forwarder.add(sample_id, uuid, image)
|
|
165
|
+
|
|
166
|
+
elif not message:
|
|
167
|
+
self.forwarder.flush()
|
|
168
|
+
|
|
169
|
+
def listen_for_image_data_forever(self):
|
|
170
|
+
self.pubsub.subscribe(self.channel)
|
|
171
|
+
|
|
172
|
+
while True:
|
|
173
|
+
self._get_and_handle_message()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if __name__ == "__main__":
|
|
177
|
+
client = RedisListener()
|
|
178
|
+
client.listen_for_image_data_forever()
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
|
|
1
3
|
import bluesky.plan_stubs as bps
|
|
2
4
|
import bluesky.preprocessors as bpp
|
|
3
5
|
from bluesky.preprocessors import run_decorator, subs_decorator
|
|
4
|
-
from
|
|
6
|
+
from bluesky.utils import MsgGenerator
|
|
5
7
|
from dodal.beamlines.i04 import MURKO_REDIS_DB, REDIS_HOST, REDIS_PASSWORD
|
|
6
8
|
from dodal.common import inject
|
|
7
9
|
from dodal.devices.oav.oav_detector import OAV
|
|
8
|
-
from dodal.devices.oav.oav_to_redis_forwarder import OAVToRedisForwarder
|
|
10
|
+
from dodal.devices.oav.oav_to_redis_forwarder import OAVToRedisForwarder, Source
|
|
9
11
|
from dodal.devices.robot import BartRobot
|
|
10
12
|
from dodal.devices.smargon import Smargon
|
|
11
13
|
from dodal.devices.thawer import Thawer, ThawerStates
|
|
@@ -22,31 +24,62 @@ def thaw_and_stream_to_redis(
|
|
|
22
24
|
oav: OAV = inject("oav"),
|
|
23
25
|
oav_to_redis_forwarder: OAVToRedisForwarder = inject("oav_to_redis_forwarder"),
|
|
24
26
|
) -> MsgGenerator:
|
|
25
|
-
zoom_percentage = yield from bps.rd(oav.zoom_controller.percentage)
|
|
27
|
+
zoom_percentage = yield from bps.rd(oav.zoom_controller.percentage) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
26
28
|
sample_id = yield from bps.rd(robot.sample_id)
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
yield from bps.
|
|
30
|
+
sample_id = int(sample_id)
|
|
31
|
+
zoom_level_before_thawing = yield from bps.rd(oav.zoom_controller.level) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
32
|
+
|
|
33
|
+
yield from bps.mv(oav.zoom_controller.level, "1.0x") # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
34
|
+
|
|
35
|
+
def switch_forwarder_to_ROI() -> MsgGenerator:
|
|
36
|
+
yield from bps.complete(oav_to_redis_forwarder, wait=True)
|
|
37
|
+
yield from bps.mv(
|
|
38
|
+
# See: https://github.com/bluesky/bluesky/issues/1809
|
|
39
|
+
oav_to_redis_forwarder.selected_source, # type: ignore
|
|
40
|
+
Source.ROI.value, # type: ignore
|
|
41
|
+
)
|
|
42
|
+
yield from bps.kickoff(oav_to_redis_forwarder, wait=True)
|
|
43
|
+
|
|
44
|
+
microns_per_pixel_x = yield from bps.rd(oav.microns_per_pixel_x)
|
|
45
|
+
microns_per_pixel_y = yield from bps.rd(oav.microns_per_pixel_y)
|
|
46
|
+
beam_centre_i = yield from bps.rd(oav.beam_centre_i)
|
|
47
|
+
beam_centre_j = yield from bps.rd(oav.beam_centre_j)
|
|
30
48
|
|
|
31
49
|
@subs_decorator(MurkoCallback(REDIS_HOST, REDIS_PASSWORD, MURKO_REDIS_DB))
|
|
32
50
|
@run_decorator(
|
|
33
51
|
md={
|
|
34
|
-
"microns_per_x_pixel":
|
|
35
|
-
"microns_per_y_pixel":
|
|
36
|
-
"beam_centre_i":
|
|
37
|
-
"beam_centre_j":
|
|
52
|
+
"microns_per_x_pixel": microns_per_pixel_x,
|
|
53
|
+
"microns_per_y_pixel": microns_per_pixel_y,
|
|
54
|
+
"beam_centre_i": beam_centre_i,
|
|
55
|
+
"beam_centre_j": beam_centre_j,
|
|
38
56
|
"zoom_percentage": zoom_percentage,
|
|
39
57
|
"sample_id": sample_id,
|
|
40
58
|
}
|
|
41
59
|
)
|
|
42
60
|
def _thaw_and_stream_to_redis():
|
|
61
|
+
yield from bps.mv(
|
|
62
|
+
oav_to_redis_forwarder.sample_id, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
63
|
+
sample_id, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
64
|
+
oav_to_redis_forwarder.selected_source, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
65
|
+
Source.FULL_SCREEN.value, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
66
|
+
)
|
|
67
|
+
|
|
43
68
|
yield from bps.kickoff(oav_to_redis_forwarder, wait=True)
|
|
44
69
|
yield from bps.monitor(smargon.omega.user_readback, name="smargon")
|
|
45
70
|
yield from bps.monitor(oav_to_redis_forwarder.uuid, name="oav")
|
|
46
|
-
yield from thaw(
|
|
71
|
+
yield from thaw(
|
|
72
|
+
time_to_thaw, rotation, thawer, smargon, switch_forwarder_to_ROI
|
|
73
|
+
)
|
|
47
74
|
yield from bps.complete(oav_to_redis_forwarder)
|
|
48
75
|
|
|
49
|
-
|
|
76
|
+
def cleanup():
|
|
77
|
+
yield from bps.mv(oav.zoom_controller.level, zoom_level_before_thawing) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
78
|
+
|
|
79
|
+
yield from bpp.contingency_wrapper(
|
|
80
|
+
_thaw_and_stream_to_redis(),
|
|
81
|
+
final_plan=cleanup,
|
|
82
|
+
)
|
|
50
83
|
|
|
51
84
|
|
|
52
85
|
def thaw(
|
|
@@ -54,6 +87,7 @@ def thaw(
|
|
|
54
87
|
rotation: float = 360,
|
|
55
88
|
thawer: Thawer = inject("thawer"),
|
|
56
89
|
smargon: Smargon = inject("smargon"),
|
|
90
|
+
plan_between_rotations: Callable[[], MsgGenerator] | None = None,
|
|
57
91
|
) -> MsgGenerator:
|
|
58
92
|
"""Rotates the sample and thaws it at the same time.
|
|
59
93
|
|
|
@@ -64,6 +98,8 @@ def thaw(
|
|
|
64
98
|
thawer (Thawer, optional): The thawing device. Defaults to inject("thawer").
|
|
65
99
|
smargon (Smargon, optional): The smargon used to rotate.
|
|
66
100
|
Defaults to inject("smargon")
|
|
101
|
+
plan_between_rotations (MsgGenerator, optional): A plan to run between rotations
|
|
102
|
+
of the smargon. Defaults to no plan.
|
|
67
103
|
"""
|
|
68
104
|
inital_velocity = yield from bps.rd(smargon.omega.velocity)
|
|
69
105
|
new_velocity = abs(rotation / time_to_thaw) * 2.0
|
|
@@ -72,6 +108,8 @@ def thaw(
|
|
|
72
108
|
yield from bps.abs_set(smargon.omega.velocity, new_velocity, wait=True)
|
|
73
109
|
yield from bps.abs_set(thawer.control, ThawerStates.ON, wait=True)
|
|
74
110
|
yield from bps.rel_set(smargon.omega, rotation, wait=True)
|
|
111
|
+
if plan_between_rotations:
|
|
112
|
+
yield from plan_between_rotations()
|
|
75
113
|
yield from bps.rel_set(smargon.omega, -rotation, wait=True)
|
|
76
114
|
|
|
77
115
|
def cleanup():
|
|
@@ -22,6 +22,7 @@ from .fixed_target.i24ssx_Chip_Manager_py3v1 import (
|
|
|
22
22
|
upload_parameters,
|
|
23
23
|
write_parameter_file,
|
|
24
24
|
)
|
|
25
|
+
from .log import clean_up_log_config_at_end, setup_collection_logs
|
|
25
26
|
from .setup_beamline.setup_detector import setup_detector_stage
|
|
26
27
|
|
|
27
28
|
__all__ = [
|
|
@@ -46,4 +47,6 @@ __all__ = [
|
|
|
46
47
|
"save_screen_map",
|
|
47
48
|
"upload_parameters",
|
|
48
49
|
"write_parameter_file",
|
|
50
|
+
"setup_collection_logs",
|
|
51
|
+
"clean_up_log_config_at_end",
|
|
49
52
|
]
|