mx-bluesky 1.4.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.
Files changed (78) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +178 -0
  3. mx_bluesky/beamlines/i04/thawing_plan.py +1 -1
  4. mx_bluesky/beamlines/i24/serial/dcid.py +143 -171
  5. mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +1 -1
  6. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +54 -21
  7. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +2 -5
  8. mx_bluesky/beamlines/i24/serial/fixed_target/ft_utils.py +0 -1
  9. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +67 -50
  10. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +26 -79
  11. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +0 -199
  12. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +4 -6
  13. mx_bluesky/beamlines/i24/serial/log.py +1 -1
  14. mx_bluesky/beamlines/i24/serial/parameters/__init__.py +4 -0
  15. mx_bluesky/beamlines/i24/serial/parameters/constants.py +6 -1
  16. mx_bluesky/beamlines/i24/serial/parameters/experiment_parameters.py +42 -15
  17. mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +4 -3
  18. mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +2 -0
  19. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +103 -81
  20. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +1 -2
  21. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +24 -26
  22. mx_bluesky/beamlines/i24/serial/write_nexus.py +74 -72
  23. mx_bluesky/common/external_interaction/config_server.py +46 -0
  24. mx_bluesky/common/parameters/components.py +52 -15
  25. mx_bluesky/common/parameters/constants.py +11 -1
  26. mx_bluesky/common/parameters/gridscan.py +94 -0
  27. mx_bluesky/{hyperion → common}/parameters/robot_load.py +2 -2
  28. mx_bluesky/common/plans/do_fgs.py +2 -2
  29. mx_bluesky/common/utils/log.py +2 -0
  30. mx_bluesky/hyperion/__main__.py +2 -1
  31. mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +21 -31
  32. mx_bluesky/hyperion/device_setup_plans/setup_panda.py +4 -4
  33. mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +1 -1
  34. mx_bluesky/hyperion/device_setup_plans/smargon.py +3 -3
  35. mx_bluesky/hyperion/exceptions.py +13 -1
  36. mx_bluesky/hyperion/experiment_plans/__init__.py +4 -0
  37. mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +83 -0
  38. mx_bluesky/hyperion/experiment_plans/common/xrc_result.py +47 -0
  39. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -9
  40. mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +133 -97
  41. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +42 -18
  42. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +75 -9
  43. mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +2 -2
  44. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +1 -1
  45. mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +2 -2
  46. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +36 -17
  47. mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +5 -5
  48. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +28 -28
  49. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +64 -16
  50. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +11 -3
  51. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +10 -10
  52. mx_bluesky/hyperion/external_interaction/callbacks/__init__.py +0 -4
  53. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +4 -0
  54. mx_bluesky/hyperion/external_interaction/callbacks/common/abstract_event.py +66 -0
  55. mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +5 -0
  56. mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +15 -15
  57. mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +18 -10
  58. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -1
  59. mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +5 -3
  60. mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/__init__.py +0 -0
  61. mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/sample_handling_callback.py +84 -0
  62. mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +15 -9
  63. mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +5 -4
  64. mx_bluesky/hyperion/external_interaction/config_server.py +8 -37
  65. mx_bluesky/hyperion/external_interaction/exceptions.py +0 -9
  66. mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +65 -15
  67. mx_bluesky/hyperion/parameters/components.py +4 -9
  68. mx_bluesky/hyperion/parameters/constants.py +0 -1
  69. mx_bluesky/hyperion/parameters/gridscan.py +33 -76
  70. mx_bluesky/hyperion/parameters/load_centre_collect.py +14 -9
  71. mx_bluesky/hyperion/parameters/rotation.py +15 -6
  72. {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1.dist-info}/METADATA +35 -34
  73. {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1.dist-info}/RECORD +77 -70
  74. {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1.dist-info}/WHEEL +1 -1
  75. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +0 -150
  76. {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1.dist-info}/LICENSE +0 -0
  77. {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1.dist-info}/entry_points.txt +0 -0
  78. {mx_bluesky-1.4.0.dist-info → mx_bluesky-1.4.1.dist-info}/top_level.txt +0 -0
mx_bluesky/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.4.0'
16
- __version_tuple__ = version_tuple = (1, 4, 0)
15
+ __version__ = version = '1.4.1'
16
+ __version_tuple__ = version_tuple = (1, 4, 1)
@@ -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()
@@ -3,7 +3,7 @@ from collections.abc import Callable
3
3
  import bluesky.plan_stubs as bps
4
4
  import bluesky.preprocessors as bpp
5
5
  from bluesky.preprocessors import run_decorator, subs_decorator
6
- from dls_bluesky_core.core import MsgGenerator
6
+ from bluesky.utils import MsgGenerator
7
7
  from dodal.beamlines.i04 import MURKO_REDIS_DB, REDIS_HOST, REDIS_PASSWORD
8
8
  from dodal.common import inject
9
9
  from dodal.devices.oav.oav_detector import OAV