mx-bluesky 1.5.10__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.
Files changed (121) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/aithre_lasershaping/experiment_plans/__init__.py +0 -0
  3. mx_bluesky/beamlines/aithre_lasershaping/experiment_plans/robot_load_plan.py +198 -0
  4. mx_bluesky/beamlines/aithre_lasershaping/goniometer_controls.py +2 -2
  5. mx_bluesky/beamlines/aithre_lasershaping/parameters/__init__.py +0 -0
  6. mx_bluesky/beamlines/aithre_lasershaping/parameters/constants.py +17 -0
  7. mx_bluesky/beamlines/aithre_lasershaping/parameters/robot_load_parameters.py +13 -0
  8. mx_bluesky/beamlines/aithre_lasershaping/pin_tip_centring.py +31 -0
  9. mx_bluesky/beamlines/aithre_lasershaping/robot_load.py +80 -0
  10. mx_bluesky/beamlines/i02_1/parameters/gridscan.py +1 -1
  11. mx_bluesky/beamlines/i04/__init__.py +6 -2
  12. mx_bluesky/beamlines/i04/callbacks/murko_callback.py +27 -12
  13. mx_bluesky/beamlines/i04/experiment_plans/i04_grid_detect_then_xray_centre_plan.py +94 -20
  14. mx_bluesky/beamlines/i04/external_interaction/__init__.py +0 -0
  15. mx_bluesky/beamlines/i04/external_interaction/config_server.py +15 -0
  16. mx_bluesky/beamlines/i04/oav_centering_plans/__init__.py +0 -0
  17. mx_bluesky/beamlines/i04/oav_centering_plans/oav_imaging.py +115 -0
  18. mx_bluesky/beamlines/i04/parameters/__init__.py +0 -0
  19. mx_bluesky/beamlines/i04/parameters/constants.py +21 -0
  20. mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +24 -1
  21. mx_bluesky/beamlines/i04/thawing_plan.py +149 -154
  22. mx_bluesky/beamlines/i24/jungfrau_commissioning/experiment_plans/do_darks.py +55 -10
  23. mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/do_external_acquisition.py +1 -1
  24. mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/plan_utils.py +1 -1
  25. mx_bluesky/beamlines/i24/serial/__init__.py +7 -5
  26. mx_bluesky/beamlines/i24/serial/dcid.py +6 -7
  27. mx_bluesky/beamlines/i24/serial/extruder/{i24ssx_Extruder_Collect_py3v2.py → i24ssx_extruder_collect_py3v2.py} +70 -37
  28. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/CustomChip_py3v1.edl +11 -11
  29. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DetStage.edl +3 -3
  30. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +142 -142
  31. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/MappingLite-oxford_py3v1.edl +135 -135
  32. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/PMAC_Command.edl +8 -8
  33. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +13 -13
  34. mx_bluesky/beamlines/i24/serial/fixed_target/{i24ssx_Chip_Collect_py3v1.py → i24ssx_chip_collect_py3v1.py} +12 -9
  35. mx_bluesky/beamlines/i24/serial/fixed_target/{i24ssx_Chip_Manager_py3v1.py → i24ssx_chip_manager_py3v1.py} +81 -78
  36. mx_bluesky/beamlines/i24/serial/fixed_target/{i24ssx_Chip_StartUp_py3v1.py → i24ssx_chip_startup_py3v1.py} +3 -3
  37. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +33 -33
  38. mx_bluesky/beamlines/i24/serial/log.py +11 -11
  39. mx_bluesky/beamlines/i24/serial/parameters/fixed_target/cs/cs_maker.json +3 -3
  40. mx_bluesky/beamlines/i24/serial/parameters/utils.py +5 -5
  41. mx_bluesky/beamlines/i24/serial/setup_beamline/ca.py +0 -12
  42. mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +122 -334
  43. mx_bluesky/beamlines/i24/serial/setup_beamline/pv_abstract.py +5 -5
  44. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +30 -251
  45. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +3 -3
  46. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +4 -4
  47. mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +103 -16
  48. mx_bluesky/beamlines/i24/serial/web_gui_plans/oav_plans.py +64 -0
  49. mx_bluesky/beamlines/i24/serial/write_nexus.py +4 -4
  50. mx_bluesky/common/device_setup_plans/gonio.py +28 -0
  51. mx_bluesky/common/device_setup_plans/manipulate_sample.py +8 -1
  52. mx_bluesky/common/device_setup_plans/robot_load_unload.py +1 -1
  53. mx_bluesky/common/device_setup_plans/setup_oav.py +8 -0
  54. mx_bluesky/common/device_setup_plans/setup_zebra_and_shutter.py +0 -5
  55. mx_bluesky/common/device_setup_plans/xbpm_feedback.py +8 -1
  56. mx_bluesky/common/experiment_plans/beamstop_check.py +229 -0
  57. mx_bluesky/common/experiment_plans/common_flyscan_xray_centre_plan.py +8 -6
  58. mx_bluesky/common/experiment_plans/common_grid_detect_then_xray_centre_plan.py +2 -2
  59. mx_bluesky/common/experiment_plans/inner_plans/do_fgs.py +1 -1
  60. mx_bluesky/common/experiment_plans/inner_plans/read_hardware.py +7 -4
  61. mx_bluesky/common/experiment_plans/inner_plans/write_sample_status.py +2 -2
  62. mx_bluesky/common/experiment_plans/oav_snapshot_plan.py +1 -2
  63. mx_bluesky/{hyperion → common}/experiment_plans/pin_tip_centring_plan.py +23 -24
  64. mx_bluesky/common/external_interaction/callbacks/common/grid_detection_callback.py +5 -0
  65. mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +13 -15
  66. mx_bluesky/common/external_interaction/callbacks/common/ispyb_mapping.py +3 -5
  67. mx_bluesky/common/external_interaction/callbacks/common/plan_reactive_callback.py +1 -1
  68. mx_bluesky/common/external_interaction/callbacks/common/zocalo_callback.py +2 -2
  69. mx_bluesky/common/external_interaction/callbacks/sample_handling/sample_handling_callback.py +3 -3
  70. mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +12 -10
  71. mx_bluesky/common/external_interaction/callbacks/xray_centre/nexus_callback.py +2 -2
  72. mx_bluesky/common/external_interaction/config_server.py +4 -4
  73. mx_bluesky/common/external_interaction/ispyb/data_model.py +11 -4
  74. mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +163 -4
  75. mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +76 -167
  76. mx_bluesky/common/external_interaction/ispyb/ispyb_utils.py +0 -14
  77. mx_bluesky/common/external_interaction/nexus/nexus_utils.py +2 -2
  78. mx_bluesky/common/external_interaction/nexus/write_nexus.py +3 -3
  79. mx_bluesky/common/parameters/components.py +1 -0
  80. mx_bluesky/common/parameters/constants.py +4 -3
  81. mx_bluesky/common/parameters/device_composites.py +4 -2
  82. mx_bluesky/common/parameters/gridscan.py +2 -2
  83. mx_bluesky/common/utils/exceptions.py +24 -7
  84. mx_bluesky/common/utils/log.py +13 -4
  85. mx_bluesky/common/utils/tracing.py +5 -5
  86. mx_bluesky/common/utils/utils.py +56 -8
  87. mx_bluesky/hyperion/__main__.py +6 -16
  88. mx_bluesky/hyperion/baton_handler.py +38 -14
  89. mx_bluesky/hyperion/device_setup_plans/utils.py +1 -1
  90. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +1 -1
  91. mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +15 -13
  92. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +2 -2
  93. mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +9 -9
  94. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +7 -8
  95. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +3 -10
  96. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +4 -2
  97. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +10 -4
  98. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
  99. mx_bluesky/hyperion/experiment_plans/udc_default_state.py +160 -0
  100. mx_bluesky/hyperion/external_interaction/agamemnon.py +3 -3
  101. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +2 -2
  102. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -3
  103. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +1 -0
  104. mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +3 -6
  105. mx_bluesky/hyperion/external_interaction/config_server.py +5 -5
  106. mx_bluesky/hyperion/parameters/constants.py +11 -4
  107. mx_bluesky/hyperion/parameters/device_composites.py +2 -2
  108. mx_bluesky/hyperion/parameters/gridscan.py +4 -4
  109. mx_bluesky/hyperion/parameters/robot_load.py +1 -9
  110. mx_bluesky/hyperion/plan_runner.py +6 -6
  111. mx_bluesky/hyperion/runner.py +10 -8
  112. mx_bluesky/jupyter_example.ipynb +3 -3
  113. {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.12.dist-info}/METADATA +9 -7
  114. {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.12.dist-info}/RECORD +118 -104
  115. mx_bluesky/common/experiment_plans/inner_plans/udc_default_state.py +0 -65
  116. mx_bluesky/common/external_interaction/callbacks/common/logging_callback.py +0 -29
  117. mx_bluesky/hyperion/device_setup_plans/smargon.py +0 -25
  118. {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.12.dist-info}/WHEEL +0 -0
  119. {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.12.dist-info}/entry_points.txt +0 -0
  120. {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.12.dist-info}/licenses/LICENSE +0 -0
  121. {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.12.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 Undulator
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,20 +34,24 @@ 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,
40
45
  )
41
46
  from mx_bluesky.common.experiment_plans.common_flyscan_xray_centre_plan import (
42
47
  BeamlineSpecificFGSFeatures,
43
- construct_beamline_specific_FGS_features,
48
+ construct_beamline_specific_fast_gridscan_features,
44
49
  )
45
50
  from mx_bluesky.common.experiment_plans.common_grid_detect_then_xray_centre_plan import (
46
51
  grid_detect_then_xray_centre,
47
52
  )
48
53
  from mx_bluesky.common.experiment_plans.oav_snapshot_plan import (
49
- setup_beamline_for_OAV,
54
+ setup_beamline_for_oav,
50
55
  )
51
56
  from mx_bluesky.common.external_interaction.callbacks.common.zocalo_callback import (
52
57
  ZocaloCallback,
@@ -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 GridCommon, SpecifiedThreeDGridScan
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
- DEFAULT_BEAMSIZE_MICRONS = 20
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 i04_grid_detect_then_xray_centre(
95
- parameters: GridCommon,
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: Undulator = inject("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.beamsize_set_microns)
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, parameters.transmission_frac, PlanNameConstants.GRIDSCAN_OUTER
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=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
- yield from grid_detect_then_xray_centre_with_callbacks()
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(transfocator, DEFAULT_BEAMSIZE_MICRONS, parameters)
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
 
@@ -200,7 +240,7 @@ def get_ready_for_oav_and_close_shutter(
200
240
  yield from bps.wait(PlanGroupCheckpointConstants.GRID_READY_FOR_DC)
201
241
  group = "get_ready_for_oav_and_close_shutter"
202
242
  LOGGER.info("Non-udc tidy: Setting up beamline for OAV")
203
- yield from setup_beamline_for_OAV(
243
+ yield from setup_beamline_for_oav(
204
244
  smargon, backlight, aperture_scatterguard, group=group
205
245
  )
206
246
  LOGGER.info("Non-udc tidy: Closing detector shutter")
@@ -243,14 +283,14 @@ def construct_i04_specific_features(
243
283
  xrc_composite.smargon.x,
244
284
  xrc_composite.smargon.y,
245
285
  xrc_composite.smargon.z,
246
- xrc_composite.dcm.energy_in_kev,
286
+ xrc_composite.dcm.energy_in_keV,
247
287
  ]
248
288
 
249
289
  signals_to_read_during_collection = [
250
290
  xrc_composite.aperture_scatterguard,
251
291
  xrc_composite.attenuator.actual_transmission,
252
292
  xrc_composite.flux.flux_reading,
253
- xrc_composite.dcm.energy_in_kev,
293
+ xrc_composite.dcm.energy_in_keV,
254
294
  xrc_composite.eiger.bit_depth,
255
295
  ]
256
296
 
@@ -264,10 +304,10 @@ def construct_i04_specific_features(
264
304
  set_flyscan_params_plan = partial(
265
305
  set_fast_grid_scan_params,
266
306
  xrc_composite.zebra_fast_grid_scan,
267
- xrc_parameters.FGS_params,
307
+ xrc_parameters.fast_gridscan_params,
268
308
  )
269
309
  fgs_motors = xrc_composite.zebra_fast_grid_scan
270
- return construct_beamline_specific_FGS_features(
310
+ return construct_beamline_specific_fast_gridscan_features(
271
311
  partial(
272
312
  setup_zebra_for_gridscan,
273
313
  ),
@@ -278,3 +318,37 @@ def construct_i04_specific_features(
278
318
  signals_to_read_during_collection,
279
319
  get_xrc_results_from_zocalo=True,
280
320
  )
321
+
322
+
323
+ def _get_grid_common_params(
324
+ _current_wavelength_a: float, parameters: I04AutoXrcParams
325
+ ) -> GridCommon:
326
+ """Calculate scaled transmission and exposure by comparing current beamline energy to default energy"""
327
+ _assumed_wavelength_a = (
328
+ get_i04_config_client().get_feature_flags().ASSUMED_WAVELENGTH_IN_A
329
+ )
330
+ _unscaled_transmission = (
331
+ get_i04_config_client().get_feature_flags().XRC_UNSCALED_TRANSMISSION_FRAC
332
+ )
333
+ _unscaled_exposure_time_s = (
334
+ get_i04_config_client().get_feature_flags().XRC_UNSCALED_EXPOSURE_TIME_S
335
+ )
336
+ transmission_frac, exposure_time_s = (
337
+ fix_transmission_and_exposure_time_for_current_wavelength(
338
+ _current_wavelength_a,
339
+ _assumed_wavelength_a,
340
+ _unscaled_transmission,
341
+ _unscaled_exposure_time_s,
342
+ )
343
+ )
344
+
345
+ return GridCommon(
346
+ sample_id=parameters.sample_id,
347
+ file_name=parameters.file_name,
348
+ visit=parameters.visit,
349
+ detector_distance_mm=parameters.detector_distance_mm,
350
+ storage_directory=parameters.storage_directory,
351
+ transmission_frac=transmission_frac,
352
+ exposure_time_s=exposure_time_s,
353
+ parameter_model_version=PARAMETER_VERSION,
354
+ )
@@ -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
+ )
@@ -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