mx-bluesky 1.5.11__py3-none-any.whl → 1.5.14__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 +170 -0
- 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 +74 -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 +88 -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 +6 -6
- 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 +5 -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/hyperion_flyscan_xray_centre_plan.py +1 -0
- 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 +166 -0
- mx_bluesky/hyperion/external_interaction/agamemnon.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +48 -21
- 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 +4 -2
- mx_bluesky/hyperion/parameters/robot_load.py +1 -9
- mx_bluesky/hyperion/plan_runner.py +31 -0
- mx_bluesky/hyperion/plan_runner_api.py +14 -1
- mx_bluesky/hyperion/utils/context.py +2 -2
- mx_bluesky/jupyter_example.ipynb +9 -1
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.14.dist-info}/METADATA +7 -6
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.14.dist-info}/RECORD +90 -75
- 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.14.dist-info}/WHEEL +0 -0
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.14.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.14.dist-info}/licenses/LICENSE +0 -0
- {mx_bluesky-1.5.11.dist-info → mx_bluesky-1.5.14.dist-info}/top_level.txt +0 -0
|
@@ -17,6 +17,7 @@ from dodal.devices.fast_grid_scan import (
|
|
|
17
17
|
set_fast_grid_scan_params,
|
|
18
18
|
)
|
|
19
19
|
from dodal.devices.flux import Flux
|
|
20
|
+
from dodal.devices.i04.beamsize import Beamsize
|
|
20
21
|
from dodal.devices.i04.transfocator import Transfocator
|
|
21
22
|
from dodal.devices.mx_phase1.beamstop import Beamstop
|
|
22
23
|
from dodal.devices.oav.oav_detector import OAV
|
|
@@ -25,7 +26,7 @@ from dodal.devices.robot import BartRobot
|
|
|
25
26
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
26
27
|
from dodal.devices.smargon import Smargon
|
|
27
28
|
from dodal.devices.synchrotron import Synchrotron
|
|
28
|
-
from dodal.devices.undulator import
|
|
29
|
+
from dodal.devices.undulator import UndulatorInKeV
|
|
29
30
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
30
31
|
from dodal.devices.zebra.zebra import Zebra
|
|
31
32
|
from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
|
|
@@ -33,7 +34,11 @@ from dodal.devices.zocalo import ZocaloResults
|
|
|
33
34
|
from dodal.plans.preprocessors.verify_undulator_gap import (
|
|
34
35
|
verify_undulator_gap_before_run_decorator,
|
|
35
36
|
)
|
|
37
|
+
from pydantic import BaseModel
|
|
36
38
|
|
|
39
|
+
from mx_bluesky.beamlines.i04.external_interaction.config_server import (
|
|
40
|
+
get_i04_config_client,
|
|
41
|
+
)
|
|
37
42
|
from mx_bluesky.common.device_setup_plans.setup_zebra_and_shutter import (
|
|
38
43
|
setup_zebra_for_gridscan,
|
|
39
44
|
tidy_up_zebra_after_gridscan,
|
|
@@ -58,6 +63,7 @@ from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback
|
|
|
58
63
|
from mx_bluesky.common.external_interaction.callbacks.xray_centre.nexus_callback import (
|
|
59
64
|
GridscanNexusFileCallback,
|
|
60
65
|
)
|
|
66
|
+
from mx_bluesky.common.parameters.components import PARAMETER_VERSION
|
|
61
67
|
from mx_bluesky.common.parameters.constants import (
|
|
62
68
|
EnvironmentConstants,
|
|
63
69
|
OavConstants,
|
|
@@ -67,13 +73,28 @@ from mx_bluesky.common.parameters.constants import (
|
|
|
67
73
|
from mx_bluesky.common.parameters.device_composites import (
|
|
68
74
|
GridDetectThenXRayCentreComposite,
|
|
69
75
|
)
|
|
70
|
-
from mx_bluesky.common.parameters.gridscan import
|
|
76
|
+
from mx_bluesky.common.parameters.gridscan import (
|
|
77
|
+
GridCommon,
|
|
78
|
+
SpecifiedThreeDGridScan,
|
|
79
|
+
)
|
|
71
80
|
from mx_bluesky.common.preprocessors.preprocessors import (
|
|
72
81
|
transmission_and_xbpm_feedback_for_collection_decorator,
|
|
73
82
|
)
|
|
83
|
+
from mx_bluesky.common.utils.exceptions import CrystalNotFoundError
|
|
74
84
|
from mx_bluesky.common.utils.log import LOGGER
|
|
85
|
+
from mx_bluesky.common.utils.utils import (
|
|
86
|
+
fix_transmission_and_exposure_time_for_current_wavelength,
|
|
87
|
+
)
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
DEFAULT_XRC_BEAMSIZE_MICRONS = 20
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class I04AutoXrcParams(BaseModel):
|
|
93
|
+
sample_id: int
|
|
94
|
+
file_name: str
|
|
95
|
+
visit: str
|
|
96
|
+
detector_distance_mm: float
|
|
97
|
+
storage_directory: str
|
|
77
98
|
|
|
78
99
|
|
|
79
100
|
def _change_beamsize(
|
|
@@ -91,19 +112,20 @@ def _change_beamsize(
|
|
|
91
112
|
|
|
92
113
|
|
|
93
114
|
# See https://github.com/DiamondLightSource/blueapi/issues/506 for using device composites
|
|
94
|
-
def
|
|
95
|
-
parameters:
|
|
115
|
+
def i04_default_grid_detect_and_xray_centre(
|
|
116
|
+
parameters: I04AutoXrcParams,
|
|
96
117
|
aperture_scatterguard: ApertureScatterguard = inject("aperture_scatterguard"),
|
|
97
118
|
attenuator: BinaryFilterAttenuator = inject("attenuator"),
|
|
98
119
|
backlight: Backlight = inject("backlight"),
|
|
99
120
|
beamstop: Beamstop = inject("beamstop"),
|
|
121
|
+
beamsize: Beamsize = inject("beamsize"),
|
|
100
122
|
dcm: DoubleCrystalMonochromator = inject("dcm"),
|
|
101
123
|
zebra_fast_grid_scan: ZebraFastGridScanThreeD = inject("zebra_fast_grid_scan"),
|
|
102
124
|
flux: Flux = inject("flux"),
|
|
103
125
|
oav: OAV = inject("oav"),
|
|
104
126
|
pin_tip_detection: PinTipDetection = inject("pin_tip_detection"),
|
|
105
127
|
s4_slit_gaps: S4SlitGaps = inject("s4_slit_gaps"),
|
|
106
|
-
undulator:
|
|
128
|
+
undulator: UndulatorInKeV = inject("undulator"),
|
|
107
129
|
xbpm_feedback: XBPMFeedback = inject("xbpm_feedback"),
|
|
108
130
|
zebra: Zebra = inject("zebra"),
|
|
109
131
|
robot: BartRobot = inject("robot"),
|
|
@@ -124,7 +146,6 @@ def i04_grid_detect_then_xray_centre(
|
|
|
124
146
|
- Changes the aperture to match the beam size to the crystal size
|
|
125
147
|
- Moves the sample to the crystal centre of mass
|
|
126
148
|
|
|
127
|
-
|
|
128
149
|
i04's implementation of this plan is very similar to Hyperion. However, since i04
|
|
129
150
|
isn't running in a continuous Bluesky UDC loop, we take additional steps in beamline
|
|
130
151
|
tidy-up.
|
|
@@ -139,6 +160,7 @@ def i04_grid_detect_then_xray_centre(
|
|
|
139
160
|
attenuator,
|
|
140
161
|
backlight,
|
|
141
162
|
beamstop,
|
|
163
|
+
beamsize,
|
|
142
164
|
dcm,
|
|
143
165
|
detector_motion,
|
|
144
166
|
zebra_fast_grid_scan,
|
|
@@ -152,9 +174,18 @@ def i04_grid_detect_then_xray_centre(
|
|
|
152
174
|
robot,
|
|
153
175
|
sample_shutter,
|
|
154
176
|
)
|
|
155
|
-
initial_beamsize = yield from bps.rd(transfocator.
|
|
177
|
+
initial_beamsize = yield from bps.rd(transfocator.current_vertical_size_rbv)
|
|
178
|
+
|
|
179
|
+
initial_x = yield from bps.rd(smargon.x.user_readback)
|
|
180
|
+
initial_y = yield from bps.rd(smargon.y.user_readback)
|
|
181
|
+
initial_z = yield from bps.rd(smargon.z.user_readback)
|
|
182
|
+
|
|
183
|
+
_current_wavelength_a = yield from bps.rd(composite.dcm.wavelength_in_a)
|
|
184
|
+
grid_common_params = _get_grid_common_params(_current_wavelength_a, parameters)
|
|
156
185
|
|
|
157
186
|
def tidy_beamline():
|
|
187
|
+
yield from bps.mv(transfocator, initial_beamsize)
|
|
188
|
+
|
|
158
189
|
if not udc:
|
|
159
190
|
yield from get_ready_for_oav_and_close_shutter(
|
|
160
191
|
composite.smargon,
|
|
@@ -162,7 +193,6 @@ def i04_grid_detect_then_xray_centre(
|
|
|
162
193
|
composite.aperture_scatterguard,
|
|
163
194
|
composite.detector_motion,
|
|
164
195
|
)
|
|
165
|
-
yield from bps.mv(transfocator, initial_beamsize)
|
|
166
196
|
|
|
167
197
|
@bpp.finalize_decorator(tidy_beamline)
|
|
168
198
|
def _inner_grid_detect_then_xrc():
|
|
@@ -174,20 +204,30 @@ def i04_grid_detect_then_xray_centre(
|
|
|
174
204
|
@bpp.subs_decorator(callbacks)
|
|
175
205
|
@verify_undulator_gap_before_run_decorator(composite)
|
|
176
206
|
@transmission_and_xbpm_feedback_for_collection_decorator(
|
|
177
|
-
composite,
|
|
207
|
+
composite,
|
|
208
|
+
grid_common_params.transmission_frac,
|
|
209
|
+
PlanNameConstants.GRIDSCAN_OUTER,
|
|
178
210
|
)
|
|
179
211
|
def grid_detect_then_xray_centre_with_callbacks():
|
|
180
212
|
yield from grid_detect_then_xray_centre(
|
|
181
213
|
composite=composite,
|
|
182
|
-
parameters=
|
|
214
|
+
parameters=grid_common_params,
|
|
183
215
|
xrc_params_type=SpecifiedThreeDGridScan,
|
|
184
216
|
construct_beamline_specific=construct_i04_specific_features,
|
|
185
217
|
oav_config=oav_config,
|
|
186
218
|
)
|
|
187
219
|
|
|
188
|
-
|
|
220
|
+
try:
|
|
221
|
+
yield from grid_detect_then_xray_centre_with_callbacks()
|
|
222
|
+
except CrystalNotFoundError:
|
|
223
|
+
yield from bps.mv(
|
|
224
|
+
smargon.x, initial_x, smargon.y, initial_y, smargon.z, initial_z
|
|
225
|
+
)
|
|
226
|
+
raise
|
|
189
227
|
|
|
190
|
-
yield from _change_beamsize(
|
|
228
|
+
yield from _change_beamsize(
|
|
229
|
+
transfocator, DEFAULT_XRC_BEAMSIZE_MICRONS, grid_common_params
|
|
230
|
+
)
|
|
191
231
|
yield from _inner_grid_detect_then_xrc()
|
|
192
232
|
|
|
193
233
|
|
|
@@ -252,6 +292,7 @@ def construct_i04_specific_features(
|
|
|
252
292
|
xrc_composite.flux.flux_reading,
|
|
253
293
|
xrc_composite.dcm.energy_in_keV,
|
|
254
294
|
xrc_composite.eiger.bit_depth,
|
|
295
|
+
xrc_composite.beamsize,
|
|
255
296
|
]
|
|
256
297
|
|
|
257
298
|
tidy_plan = partial(
|
|
@@ -278,3 +319,37 @@ def construct_i04_specific_features(
|
|
|
278
319
|
signals_to_read_during_collection,
|
|
279
320
|
get_xrc_results_from_zocalo=True,
|
|
280
321
|
)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def _get_grid_common_params(
|
|
325
|
+
_current_wavelength_a: float, parameters: I04AutoXrcParams
|
|
326
|
+
) -> GridCommon:
|
|
327
|
+
"""Calculate scaled transmission and exposure by comparing current beamline energy to default energy"""
|
|
328
|
+
_assumed_wavelength_a = (
|
|
329
|
+
get_i04_config_client().get_feature_flags().ASSUMED_WAVELENGTH_IN_A
|
|
330
|
+
)
|
|
331
|
+
_unscaled_transmission = (
|
|
332
|
+
get_i04_config_client().get_feature_flags().XRC_UNSCALED_TRANSMISSION_FRAC
|
|
333
|
+
)
|
|
334
|
+
_unscaled_exposure_time_s = (
|
|
335
|
+
get_i04_config_client().get_feature_flags().XRC_UNSCALED_EXPOSURE_TIME_S
|
|
336
|
+
)
|
|
337
|
+
transmission_frac, exposure_time_s = (
|
|
338
|
+
fix_transmission_and_exposure_time_for_current_wavelength(
|
|
339
|
+
_current_wavelength_a,
|
|
340
|
+
_assumed_wavelength_a,
|
|
341
|
+
_unscaled_transmission,
|
|
342
|
+
_unscaled_exposure_time_s,
|
|
343
|
+
)
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
return GridCommon(
|
|
347
|
+
sample_id=parameters.sample_id,
|
|
348
|
+
file_name=parameters.file_name,
|
|
349
|
+
visit=parameters.visit,
|
|
350
|
+
detector_distance_mm=parameters.detector_distance_mm,
|
|
351
|
+
storage_directory=parameters.storage_directory,
|
|
352
|
+
transmission_frac=transmission_frac,
|
|
353
|
+
exposure_time_s=exposure_time_s,
|
|
354
|
+
parameter_model_version=PARAMETER_VERSION,
|
|
355
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from functools import cache
|
|
2
|
+
|
|
3
|
+
from mx_bluesky.beamlines.i04.parameters.constants import (
|
|
4
|
+
I04FeatureSettings,
|
|
5
|
+
I04FeatureSettingsSources,
|
|
6
|
+
)
|
|
7
|
+
from mx_bluesky.common.external_interaction.config_server import MXConfigClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@cache
|
|
11
|
+
def get_i04_config_client() -> MXConfigClient[I04FeatureSettings]:
|
|
12
|
+
return MXConfigClient(
|
|
13
|
+
feature_sources=I04FeatureSettingsSources,
|
|
14
|
+
feature_dc=I04FeatureSettings,
|
|
15
|
+
)
|
|
File without changes
|
|
@@ -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
|
|