mx-bluesky 1.2.0__py3-none-any.whl → 1.4.0__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 (77) hide show
  1. mx_bluesky/__init__.py +8 -3
  2. mx_bluesky/__main__.py +12 -7
  3. mx_bluesky/_version.py +2 -2
  4. mx_bluesky/beamlines/i04/callbacks/murko_callback.py +14 -4
  5. mx_bluesky/beamlines/i04/thawing_plan.py +48 -10
  6. mx_bluesky/beamlines/i24/serial/__init__.py +3 -0
  7. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +68 -90
  8. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +1 -1
  9. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +104 -126
  10. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +139 -162
  11. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +25 -36
  12. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +24 -34
  13. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +14 -11
  14. mx_bluesky/beamlines/i24/serial/log.py +58 -49
  15. mx_bluesky/beamlines/i24/serial/parameters/fixed_target/cs/cs_maker.json +3 -3
  16. mx_bluesky/beamlines/i24/serial/run_extruder.sh +30 -5
  17. mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +31 -7
  18. mx_bluesky/beamlines/i24/serial/run_serial.py +24 -8
  19. mx_bluesky/beamlines/i24/serial/setup_beamline/ca.py +0 -2
  20. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +1 -1
  21. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +8 -18
  22. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +2 -2
  23. mx_bluesky/common/__init__.py +0 -0
  24. mx_bluesky/common/device_setup_plans/read_hardware_for_setup.py +14 -0
  25. mx_bluesky/common/parameters/components.py +221 -0
  26. mx_bluesky/common/parameters/constants.py +133 -0
  27. mx_bluesky/common/plans/__init__.py +1 -0
  28. mx_bluesky/common/plans/do_fgs.py +121 -0
  29. mx_bluesky/common/utils/log.py +116 -0
  30. mx_bluesky/{hyperion → common/utils}/tracing.py +2 -2
  31. mx_bluesky/hyperion/__main__.py +11 -9
  32. mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +31 -26
  33. mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +6 -12
  34. mx_bluesky/hyperion/device_setup_plans/setup_oav.py +6 -12
  35. mx_bluesky/hyperion/device_setup_plans/setup_panda.py +1 -2
  36. mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +48 -17
  37. mx_bluesky/hyperion/device_setup_plans/smargon.py +6 -6
  38. mx_bluesky/hyperion/device_setup_plans/utils.py +2 -2
  39. mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +4 -4
  40. mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +25 -83
  41. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +7 -5
  42. mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +19 -18
  43. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +8 -5
  44. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +4 -4
  45. mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +17 -17
  46. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +15 -11
  47. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +6 -3
  48. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +6 -4
  49. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +3 -3
  50. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -2
  51. mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +1 -1
  52. mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +18 -13
  53. mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +29 -12
  54. mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +1 -1
  55. mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +1 -1
  56. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +4 -3
  57. mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +23 -18
  58. mx_bluesky/hyperion/external_interaction/config_server.py +22 -10
  59. mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +1 -1
  60. mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +2 -2
  61. mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +1 -1
  62. mx_bluesky/hyperion/log.py +0 -84
  63. mx_bluesky/hyperion/parameters/components.py +1 -243
  64. mx_bluesky/hyperion/parameters/constants.py +22 -118
  65. mx_bluesky/hyperion/parameters/gridscan.py +13 -9
  66. mx_bluesky/hyperion/parameters/load_centre_collect.py +3 -3
  67. mx_bluesky/hyperion/parameters/robot_load.py +3 -3
  68. mx_bluesky/hyperion/parameters/rotation.py +9 -5
  69. mx_bluesky/hyperion/utils/utils.py +17 -0
  70. mx_bluesky/hyperion/utils/validation.py +5 -6
  71. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/METADATA +4 -2
  72. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/RECORD +76 -70
  73. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/WHEEL +1 -1
  74. mx_bluesky/example.py +0 -19
  75. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/LICENSE +0 -0
  76. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/entry_points.txt +0 -0
  77. {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.0.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,7 @@ import dataclasses
10
10
  from bluesky import plan_stubs as bps
11
11
  from dodal.devices.attenuator import Attenuator
12
12
  from dodal.devices.dcm import DCM
13
- from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, VFMMirrorVoltages
13
+ from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
14
14
  from dodal.devices.undulator_dcm import UndulatorDCM
15
15
  from dodal.devices.xbpm_feedback import XBPMFeedback
16
16
 
@@ -27,7 +27,7 @@ UNDULATOR_GROUP = "UNDULATOR_GROUP"
27
27
  @dataclasses.dataclass
28
28
  class SetEnergyComposite:
29
29
  vfm: FocusingMirrorWithStripes
30
- vfm_mirror_voltages: VFMMirrorVoltages
30
+ mirror_voltages: MirrorVoltages
31
31
  dcm: DCM
32
32
  undulator_dcm: UndulatorDCM
33
33
  xbpm_feedback: XBPMFeedback
@@ -42,7 +42,7 @@ def _set_energy_plan(
42
42
  yield from dcm_pitch_roll_mirror_adjuster.adjust_dcm_pitch_roll_vfm_from_lut(
43
43
  composite.undulator_dcm,
44
44
  composite.vfm,
45
- composite.vfm_mirror_voltages,
45
+ composite.mirror_voltages,
46
46
  energy_kev,
47
47
  )
48
48
  yield from bps.wait(group=UNDULATOR_GROUP)
@@ -7,6 +7,7 @@ from bluesky.callbacks.zmq import Proxy, RemoteDispatcher
7
7
  from dodal.log import LOGGER as dodal_logger
8
8
  from dodal.log import set_up_all_logging_handlers
9
9
 
10
+ from mx_bluesky.common.utils.log import _get_logging_dir, tag_filter
10
11
  from mx_bluesky.hyperion.external_interaction.callbacks.log_uid_tag_callback import (
11
12
  LogUidTaggingCallback,
12
13
  )
@@ -31,8 +32,6 @@ from mx_bluesky.hyperion.external_interaction.callbacks.zocalo_callback import (
31
32
  from mx_bluesky.hyperion.log import (
32
33
  ISPYB_LOGGER,
33
34
  NEXUS_LOGGER,
34
- _get_logging_dir,
35
- tag_filter,
36
35
  )
37
36
  from mx_bluesky.hyperion.parameters.cli import parse_callback_dev_mode_arg
38
37
  from mx_bluesky.hyperion.parameters.constants import CONST
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
3
4
  from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
4
5
  DataCollectionGroupInfo,
5
6
  DataCollectionInfo,
@@ -11,7 +12,6 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
11
12
  from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_utils import (
12
13
  get_current_time_string,
13
14
  )
14
- from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
15
15
 
16
16
 
17
17
  def populate_data_collection_group(params: DiffractionExperimentWithSample):
@@ -2,7 +2,6 @@ from typing import TypedDict
2
2
 
3
3
  import numpy as np
4
4
  from bluesky.callbacks import CallbackBase
5
- from dodal.devices.oav.oav_detector import OAVConfigParams
6
5
  from dodal.devices.oav.utils import calculate_x_y_z_of_pixel
7
6
  from event_model.documents import Event
8
7
 
@@ -26,21 +25,19 @@ class GridParamUpdate(TypedDict):
26
25
  class GridDetectionCallback(CallbackBase):
27
26
  def __init__(
28
27
  self,
29
- oav_params: OAVConfigParams,
30
28
  *args,
31
29
  ) -> None:
32
30
  super().__init__(*args)
33
- self.oav_params = oav_params
34
31
  self.start_positions: list = []
35
32
  self.box_numbers: list = []
36
33
 
37
34
  def event(self, doc: Event):
38
35
  data = doc.get("data")
39
- top_left_x_px = data["oav_grid_snapshot_top_left_x"]
40
- box_width_px = data["oav_grid_snapshot_box_width"]
36
+ top_left_x_px = data["oav-grid_snapshot-top_left_x"]
37
+ box_width_px = data["oav-grid_snapshot-box_width"]
41
38
  x_of_centre_of_first_box_px = top_left_x_px + box_width_px / 2
42
39
 
43
- top_left_y_px = data["oav_grid_snapshot_top_left_y"]
40
+ top_left_y_px = data["oav-grid_snapshot-top_left_y"]
44
41
  y_of_centre_of_first_box_px = top_left_y_px + box_width_px / 2
45
42
 
46
43
  smargon_omega = data["smargon-omega"]
@@ -53,23 +50,31 @@ class GridDetectionCallback(CallbackBase):
53
50
  y_of_centre_of_first_box_px,
54
51
  )
55
52
 
53
+ microns_per_pixel_x = data["oav-microns_per_pixel_x"]
54
+ microns_per_pixel_y = data["oav-microns_per_pixel_y"]
55
+ beam_x = data["oav-beam_centre_i"]
56
+ beam_y = data["oav-beam_centre_j"]
57
+
56
58
  position_grid_start = calculate_x_y_z_of_pixel(
57
- current_xyz, smargon_omega, centre_of_first_box, self.oav_params
59
+ current_xyz,
60
+ smargon_omega,
61
+ centre_of_first_box,
62
+ (beam_x, beam_y),
63
+ (microns_per_pixel_x, microns_per_pixel_y),
58
64
  )
59
-
60
65
  LOGGER.info(f"Calculated start position {position_grid_start}")
61
66
 
62
67
  self.start_positions.append(position_grid_start)
63
68
  self.box_numbers.append(
64
69
  (
65
- data["oav_grid_snapshot_num_boxes_x"],
66
- data["oav_grid_snapshot_num_boxes_y"],
70
+ data["oav-grid_snapshot-num_boxes_x"],
71
+ data["oav-grid_snapshot-num_boxes_y"],
67
72
  )
68
73
  )
69
74
 
70
- self.x_step_size_mm = box_width_px * self.oav_params.micronsPerXPixel / 1000
71
- self.y_step_size_mm = box_width_px * self.oav_params.micronsPerYPixel / 1000
72
- self.z_step_size_mm = box_width_px * self.oav_params.micronsPerYPixel / 1000
75
+ self.x_step_size_mm = box_width_px * microns_per_pixel_x / 1000
76
+ self.y_step_size_mm = box_width_px * microns_per_pixel_y / 1000
77
+ self.z_step_size_mm = box_width_px * microns_per_pixel_y / 1000
73
78
  return doc
74
79
 
75
80
  def get_grid_parameters(self) -> GridParamUpdate:
@@ -5,9 +5,12 @@ from collections.abc import Callable, Sequence
5
5
  from typing import TYPE_CHECKING, Any, TypeVar, cast
6
6
 
7
7
  from dodal.beamline_specific_utils.i03 import beam_size_from_aperture
8
+ from dodal.devices.detector import DetectorParams
8
9
  from dodal.devices.detector.det_resolution import resolution
9
10
  from dodal.devices.synchrotron import SynchrotronMode
10
11
 
12
+ from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
13
+ from mx_bluesky.common.utils.log import set_dcgid_tag
11
14
  from mx_bluesky.hyperion.external_interaction.callbacks.plan_reactive_callback import (
12
15
  PlanReactiveCallback,
13
16
  )
@@ -21,8 +24,7 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
21
24
  StoreInIspyb,
22
25
  )
23
26
  from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_utils import get_ispyb_config
24
- from mx_bluesky.hyperion.log import ISPYB_LOGGER, set_dcgid_tag
25
- from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
27
+ from mx_bluesky.hyperion.log import ISPYB_LOGGER
26
28
  from mx_bluesky.hyperion.parameters.constants import CONST
27
29
  from mx_bluesky.hyperion.utils.utils import convert_eV_to_angstrom
28
30
 
@@ -33,6 +35,25 @@ if TYPE_CHECKING:
33
35
  from event_model.documents import Event, EventDescriptor, RunStart, RunStop
34
36
 
35
37
 
38
+ def _update_based_on_energy(
39
+ doc: Event,
40
+ detector_params: DetectorParams,
41
+ data_collection_info: DataCollectionInfo,
42
+ ):
43
+ """If energy has been read as part of this reading then add it into the data
44
+ collection info along with the other fields that depend on it."""
45
+ if energy_kev := doc["data"].get("dcm-energy_in_kev", None):
46
+ energy_ev = energy_kev * 1000
47
+ wavelength_angstroms = convert_eV_to_angstrom(energy_ev)
48
+ data_collection_info.wavelength = wavelength_angstroms
49
+ data_collection_info.resolution = resolution(
50
+ detector_params,
51
+ wavelength_angstroms,
52
+ detector_params.detector_distance,
53
+ )
54
+ return data_collection_info
55
+
56
+
36
57
  class BaseISPyBCallback(PlanReactiveCallback):
37
58
  def __init__(
38
59
  self,
@@ -109,6 +130,9 @@ class BaseISPyBCallback(PlanReactiveCallback):
109
130
  slitgap_horizontal=doc["data"]["s4_slit_gaps_xgap"],
110
131
  slitgap_vertical=doc["data"]["s4_slit_gaps_ygap"],
111
132
  )
133
+ hwscan_data_collection_info = _update_based_on_energy(
134
+ doc, self.params.detector_params, hwscan_data_collection_info
135
+ )
112
136
  hwscan_position_info = DataCollectionPositionInfo(
113
137
  pos_x=float(doc["data"]["smargon-x"]),
114
138
  pos_y=float(doc["data"]["smargon-y"]),
@@ -137,16 +161,9 @@ class BaseISPyBCallback(PlanReactiveCallback):
137
161
  if transmission := doc["data"]["attenuator-actual_transmission"]:
138
162
  # Ispyb wants the transmission in a percentage, we use fractions
139
163
  hwscan_data_collection_info.transmission = transmission * 100
140
- event_energy = doc["data"]["dcm-energy_in_kev"]
141
- if event_energy:
142
- energy_ev = event_energy * 1000
143
- wavelength_angstroms = convert_eV_to_angstrom(energy_ev)
144
- hwscan_data_collection_info.wavelength = wavelength_angstroms
145
- hwscan_data_collection_info.resolution = resolution(
146
- self.params.detector_params,
147
- wavelength_angstroms,
148
- self.params.detector_params.detector_distance,
149
- )
164
+ hwscan_data_collection_info = _update_based_on_energy(
165
+ doc, self.params.detector_params, hwscan_data_collection_info
166
+ )
150
167
  scan_data_infos = self.populate_info_for_update(
151
168
  hwscan_data_collection_info, None, self.params
152
169
  )
@@ -1,7 +1,7 @@
1
1
  from bluesky.callbacks import CallbackBase
2
2
  from event_model import RunStart, RunStop
3
3
 
4
- from mx_bluesky.hyperion.log import set_uid_tag
4
+ from mx_bluesky.common.utils.log import set_uid_tag
5
5
 
6
6
 
7
7
  class LogUidTaggingCallback(CallbackBase):
@@ -62,7 +62,7 @@ class RobotLoadISPyBCallback(PlanReactiveCallback):
62
62
  self.action_id is not None
63
63
  ), "ISPyB Robot load callback event called unexpectedly"
64
64
  barcode = doc["data"]["robot-barcode"]
65
- oav_snapshot = doc["data"]["oav_snapshot_last_saved_path"]
65
+ oav_snapshot = doc["data"]["oav-snapshot-last_saved_path"]
66
66
  webcam_snapshot = doc["data"]["webcam-last_saved_path"]
67
67
  # I03 uses webcam/oav snapshots in place of before/after snapshots
68
68
  self.expeye.update_barcode_and_snapshots(
@@ -3,6 +3,8 @@ from __future__ import annotations
3
3
  from collections.abc import Callable, Sequence
4
4
  from typing import TYPE_CHECKING, Any, cast
5
5
 
6
+ from mx_bluesky.common.parameters.components import IspybExperimentType
7
+ from mx_bluesky.common.utils.log import set_dcgid_tag
6
8
  from mx_bluesky.hyperion.external_interaction.callbacks.common.ispyb_mapping import (
7
9
  populate_data_collection_group,
8
10
  populate_remaining_data_collection_info,
@@ -22,8 +24,7 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
22
24
  IspybIds,
23
25
  StoreInIspyb,
24
26
  )
25
- from mx_bluesky.hyperion.log import ISPYB_LOGGER, set_dcgid_tag
26
- from mx_bluesky.hyperion.parameters.components import IspybExperimentType
27
+ from mx_bluesky.hyperion.log import ISPYB_LOGGER
27
28
  from mx_bluesky.hyperion.parameters.constants import CONST
28
29
  from mx_bluesky.hyperion.parameters.rotation import RotationScan
29
30
 
@@ -157,7 +158,7 @@ class RotationISPyBCallback(BaseISPyBCallback):
157
158
  data_collection_info = DataCollectionInfo(
158
159
  **{
159
160
  f"xtal_snapshot{self._oav_snapshot_event_idx}": data.get(
160
- "oav_snapshot_last_saved_path"
161
+ "oav-snapshot-last_saved_path"
161
162
  )
162
163
  }
163
164
  )
@@ -7,8 +7,14 @@ from typing import TYPE_CHECKING, Any
7
7
  import numpy as np
8
8
  from blueapi.core import MsgGenerator
9
9
  from bluesky import preprocessors as bpp
10
- from dodal.devices.zocalo.zocalo_results import ZOCALO_READING_PLAN_NAME
10
+ from dodal.devices.zocalo.zocalo_results import (
11
+ ZOCALO_READING_PLAN_NAME,
12
+ get_processing_results_from_event,
13
+ )
11
14
 
15
+ from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
16
+ from mx_bluesky.common.parameters.constants import PlanNameConstants
17
+ from mx_bluesky.common.utils.log import set_dcgid_tag
12
18
  from mx_bluesky.hyperion.external_interaction.callbacks.common.ispyb_mapping import (
13
19
  populate_data_collection_group,
14
20
  populate_remaining_data_collection_info,
@@ -36,8 +42,7 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_store import (
36
42
  IspybIds,
37
43
  StoreInIspyb,
38
44
  )
39
- from mx_bluesky.hyperion.log import ISPYB_LOGGER, set_dcgid_tag
40
- from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
45
+ from mx_bluesky.hyperion.log import ISPYB_LOGGER
41
46
  from mx_bluesky.hyperion.parameters.constants import CONST
42
47
  from mx_bluesky.hyperion.parameters.gridscan import (
43
48
  GridCommon,
@@ -85,7 +90,7 @@ class GridscanISPyBCallback(BaseISPyBCallback):
85
90
  self._processing_start_time: float | None = None
86
91
 
87
92
  def activity_gated_start(self, doc: RunStart):
88
- if doc.get("subplan_name") == CONST.PLAN.DO_FGS:
93
+ if doc.get("subplan_name") == PlanNameConstants.DO_FGS:
89
94
  self._start_of_fgs_uid = doc.get("uid")
90
95
  if doc.get("subplan_name") == CONST.PLAN.GRID_DETECT_AND_DO_GRIDSCAN:
91
96
  self.uid_to_finalize_on = doc.get("uid")
@@ -147,7 +152,7 @@ class GridscanISPyBCallback(BaseISPyBCallback):
147
152
  ISPYB_LOGGER.info(
148
153
  f"Amending comment based on Zocalo reading doc: {format_doc_for_log(doc)}"
149
154
  )
150
- raw_results = doc["data"]["zocalo-results"]
155
+ raw_results = get_processing_results_from_event("zocalo", doc)
151
156
  if len(raw_results) > 0:
152
157
  for n, res in enumerate(raw_results):
153
158
  bb = res["bounding_box"]
@@ -178,25 +183,25 @@ class GridscanISPyBCallback(BaseISPyBCallback):
178
183
  data = doc["data"]
179
184
  data_collection_id = None
180
185
  data_collection_info = DataCollectionInfo(
181
- xtal_snapshot1=data.get("oav_grid_snapshot_last_path_full_overlay"),
182
- xtal_snapshot2=data.get("oav_grid_snapshot_last_path_outer"),
183
- xtal_snapshot3=data.get("oav_grid_snapshot_last_saved_path"),
186
+ xtal_snapshot1=data.get("oav-grid_snapshot-last_path_full_overlay"),
187
+ xtal_snapshot2=data.get("oav-grid_snapshot-last_path_outer"),
188
+ xtal_snapshot3=data.get("oav-grid_snapshot-last_saved_path"),
184
189
  n_images=(
185
- data["oav_grid_snapshot_num_boxes_x"]
186
- * data["oav_grid_snapshot_num_boxes_y"]
190
+ data["oav-grid_snapshot-num_boxes_x"]
191
+ * data["oav-grid_snapshot-num_boxes_y"]
187
192
  ),
188
193
  )
189
- microns_per_pixel_x = data["oav_grid_snapshot_microns_per_pixel_x"]
190
- microns_per_pixel_y = data["oav_grid_snapshot_microns_per_pixel_y"]
194
+ microns_per_pixel_x = data["oav-microns_per_pixel_x"]
195
+ microns_per_pixel_y = data["oav-microns_per_pixel_y"]
191
196
  data_collection_grid_info = DataCollectionGridInfo(
192
- dx_in_mm=data["oav_grid_snapshot_box_width"] * microns_per_pixel_x / 1000,
193
- dy_in_mm=data["oav_grid_snapshot_box_width"] * microns_per_pixel_y / 1000,
194
- steps_x=data["oav_grid_snapshot_num_boxes_x"],
195
- steps_y=data["oav_grid_snapshot_num_boxes_y"],
197
+ dx_in_mm=data["oav-grid_snapshot-box_width"] * microns_per_pixel_x / 1000,
198
+ dy_in_mm=data["oav-grid_snapshot-box_width"] * microns_per_pixel_y / 1000,
199
+ steps_x=data["oav-grid_snapshot-num_boxes_x"],
200
+ steps_y=data["oav-grid_snapshot-num_boxes_y"],
196
201
  microns_per_pixel_x=microns_per_pixel_x,
197
202
  microns_per_pixel_y=microns_per_pixel_y,
198
- snapshot_offset_x_pixel=int(data["oav_grid_snapshot_top_left_x"]),
199
- snapshot_offset_y_pixel=int(data["oav_grid_snapshot_top_left_y"]),
203
+ snapshot_offset_x_pixel=int(data["oav-grid_snapshot-top_left_x"]),
204
+ snapshot_offset_y_pixel=int(data["oav-grid_snapshot-top_left_y"]),
200
205
  orientation=Orientation.HORIZONTAL,
201
206
  snaked=True,
202
207
  )
@@ -1,5 +1,5 @@
1
1
  from daq_config_server.client import ConfigServer
2
- from pydantic import BaseModel
2
+ from pydantic import BaseModel, Field, model_validator
3
3
 
4
4
  from mx_bluesky.hyperion.log import LOGGER
5
5
  from mx_bluesky.hyperion.parameters.constants import CONST
@@ -17,19 +17,31 @@ def config_server() -> ConfigServer:
17
17
  class FeatureFlags(BaseModel):
18
18
  # The default value will be used as the fallback when doing a best-effort fetch
19
19
  # from the service
20
- use_panda_for_gridscan: bool = False
21
- use_gpu_for_gridscan: bool = False
22
- set_stub_offsets: bool = False
20
+ use_panda_for_gridscan: bool = CONST.I03.USE_PANDA_FOR_GRIDSCAN
21
+ compare_cpu_and_gpu_zocalo: bool = CONST.I03.COMPARE_CPU_AND_GPU_ZOCALO
22
+ set_stub_offsets: bool = CONST.I03.SET_STUB_OFFSETS
23
23
 
24
+ # Feature values supplied at construction will override values from the config server
25
+ overriden_features: dict = Field(default_factory=dict, exclude=True)
26
+
27
+ @model_validator(mode="before")
24
28
  @classmethod
25
- def _get_flags(cls):
26
- flags = config_server().best_effort_get_all_feature_flags()
27
- return {f: flags[f] for f in flags if f in cls.__fields__.keys()}
29
+ def mark_overridden_features(cls, values):
30
+ assert isinstance(values, dict)
31
+ values["overriden_features"] = values.copy()
32
+ return values
28
33
 
29
34
  @classmethod
30
- def best_effort(cls):
31
- return cls(**cls._get_flags())
35
+ def _get_flags(cls):
36
+ flags = config_server().best_effort_get_all_feature_flags()
37
+ return {f: flags[f] for f in flags if f in cls.model_fields.keys()}
32
38
 
33
39
  def update_self_from_server(self):
40
+ """Used to update the feature flags from the server during a plan. Where there are flags which were explicitly set from externally supplied parameters, these values will be used instead."""
34
41
  for flag, value in self._get_flags().items():
35
- setattr(self, flag, value)
42
+ updated_value = (
43
+ value
44
+ if flag not in self.overriden_features.keys()
45
+ else self.overriden_features[flag]
46
+ )
47
+ setattr(self, flag, updated_value)
@@ -11,6 +11,7 @@ from ispyb.sp.mxacquisition import MXAcquisition
11
11
  from ispyb.strictordereddict import StrictOrderedDict
12
12
  from pydantic import BaseModel
13
13
 
14
+ from mx_bluesky.common.utils.tracing import TRACER
14
15
  from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
15
16
  DataCollectionGridInfo,
16
17
  DataCollectionGroupInfo,
@@ -22,7 +23,6 @@ from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_utils import (
22
23
  get_session_id_from_visit,
23
24
  )
24
25
  from mx_bluesky.hyperion.log import ISPYB_LOGGER
25
- from mx_bluesky.hyperion.tracing import TRACER
26
26
 
27
27
  if TYPE_CHECKING:
28
28
  pass
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import time
4
- from datetime import datetime, timedelta
4
+ from datetime import UTC, datetime, timedelta
5
5
 
6
6
  import numpy as np
7
7
  from dodal.devices.detector import DetectorParams
@@ -93,7 +93,7 @@ def create_goniometer_axes(
93
93
 
94
94
  def get_start_and_predicted_end_time(time_expected: float) -> tuple[str, str]:
95
95
  time_format = r"%Y-%m-%dT%H:%M:%SZ"
96
- start = datetime.utcfromtimestamp(time.time())
96
+ start = datetime.fromtimestamp(time.time(), tz=UTC)
97
97
  end_est = start + timedelta(seconds=time_expected)
98
98
  return start.strftime(time_format), end_est.strftime(time_format)
99
99
 
@@ -15,12 +15,12 @@ from nexgen.nxs_write.nxmx_writer import NXmxFileWriter
15
15
  from numpy.typing import DTypeLike
16
16
  from scanspec.core import AxesPoints
17
17
 
18
+ from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
18
19
  from mx_bluesky.hyperion.external_interaction.nexus.nexus_utils import (
19
20
  create_detector_parameters,
20
21
  create_goniometer_axes,
21
22
  get_start_and_predicted_end_time,
22
23
  )
23
- from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
24
24
 
25
25
 
26
26
  class NexusWriter:
@@ -1,23 +1,10 @@
1
1
  import logging
2
- from logging.handlers import TimedRotatingFileHandler
3
- from os import environ
4
- from pathlib import Path
5
2
 
6
- from dodal.log import (
7
- ERROR_LOG_BUFFER_LINES,
8
- CircularMemoryHandler,
9
- DodalLogHandlers,
10
- integrate_bluesky_and_ophyd_logging,
11
- set_up_all_logging_handlers,
12
- )
13
3
  from dodal.log import LOGGER as dodal_logger
14
4
 
15
- from mx_bluesky.hyperion.parameters.constants import CONST
16
-
17
5
  LOGGER = logging.getLogger("Hyperion")
18
6
  LOGGER.setLevel("DEBUG")
19
7
  LOGGER.parent = dodal_logger
20
- __logger_handlers: DodalLogHandlers | None = None
21
8
 
22
9
  ISPYB_LOGGER = logging.getLogger("Hyperion ISPyB and Zocalo callbacks")
23
10
  ISPYB_LOGGER.setLevel(logging.DEBUG)
@@ -26,74 +13,3 @@ NEXUS_LOGGER = logging.getLogger("Hyperion NeXus callbacks")
26
13
  NEXUS_LOGGER.setLevel(logging.DEBUG)
27
14
 
28
15
  ALL_LOGGERS = [LOGGER, ISPYB_LOGGER, NEXUS_LOGGER]
29
-
30
-
31
- class ExperimentMetadataTagFilter(logging.Filter):
32
- dc_group_id: str | None = None
33
- run_uid: str | None = None
34
-
35
- def filter(self, record):
36
- if self.dc_group_id:
37
- record.dc_group_id = self.dc_group_id
38
- if self.run_uid:
39
- record.run_uid = self.run_uid
40
- return True
41
-
42
-
43
- tag_filter = ExperimentMetadataTagFilter()
44
-
45
-
46
- def set_dcgid_tag(dcgid):
47
- """Set the datacollection group id as a tag on all subsequent log messages.
48
- Setting to None will remove the tag."""
49
- tag_filter.dc_group_id = dcgid
50
-
51
-
52
- def set_uid_tag(uid):
53
- tag_filter.run_uid = uid
54
-
55
-
56
- def do_default_logging_setup(dev_mode=False):
57
- handlers = set_up_all_logging_handlers(
58
- dodal_logger,
59
- _get_logging_dir(),
60
- "hyperion.log",
61
- dev_mode,
62
- ERROR_LOG_BUFFER_LINES,
63
- CONST.GRAYLOG_PORT,
64
- )
65
- integrate_bluesky_and_ophyd_logging(dodal_logger)
66
- handlers["graylog_handler"].addFilter(tag_filter)
67
-
68
- global __logger_handlers
69
- __logger_handlers = handlers
70
-
71
-
72
- def _get_debug_handler() -> CircularMemoryHandler:
73
- assert (
74
- __logger_handlers is not None
75
- ), "You can only use this after running the default logging setup"
76
- return __logger_handlers["debug_memory_handler"]
77
-
78
-
79
- def flush_debug_handler() -> str:
80
- """Writes the contents of the circular debug log buffer to disk and returns the written filename"""
81
- handler = _get_debug_handler()
82
- assert isinstance(
83
- handler.target, TimedRotatingFileHandler
84
- ), "Circular memory handler doesn't have an appropriate fileHandler target"
85
- handler.flush()
86
- return handler.target.baseFilename
87
-
88
-
89
- def _get_logging_dir() -> Path:
90
- """Get the path to write the hyperion log files to.
91
-
92
- If the HYPERION_LOG_DIR environment variable exists then logs will be put in here.
93
- If no environment variable is found it will default it to the ./tmp/dev directory.
94
-
95
- Returns:
96
- logging_path (Path): Path to the log file for the file handler to write to.
97
- """
98
- logging_path = Path(environ.get("HYPERION_LOG_DIR") or "./tmp/dev/")
99
- return logging_path