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
@@ -4,23 +4,25 @@ from math import asin
4
4
  from scanspec.core import AxesPoints, Axis
5
5
  from scipy.constants import physical_constants
6
6
 
7
- hc_in_eV_and_Angstrom: float = (
7
+ from mx_bluesky.common.utils.log import LOGGER
8
+
9
+ hc_in_ev_and_angstrom: float = (
8
10
  physical_constants["speed of light in vacuum"][0]
9
11
  * physical_constants["Planck constant in eV/Hz"][0]
10
12
  * 1e10 # Angstroms per metre
11
13
  )
12
14
 
13
15
 
14
- def interconvert_eV_Angstrom(wavelength_or_energy: float) -> float:
15
- return hc_in_eV_and_Angstrom / wavelength_or_energy
16
+ def interconvert_ev_angstrom(wavelength_or_energy: float) -> float:
17
+ return hc_in_ev_and_angstrom / wavelength_or_energy
16
18
 
17
19
 
18
- def convert_eV_to_angstrom(hv: float) -> float:
19
- return interconvert_eV_Angstrom(hv)
20
+ def convert_ev_to_angstrom(hv: float) -> float:
21
+ return interconvert_ev_angstrom(hv)
20
22
 
21
23
 
22
- def convert_angstrom_to_eV(wavelength: float) -> float:
23
- return interconvert_eV_Angstrom(wavelength)
24
+ def convert_angstrom_to_ev(wavelength: float) -> float:
25
+ return interconvert_ev_angstrom(wavelength)
24
26
 
25
27
 
26
28
  def number_of_frames_from_scan_spec(scan_points: AxesPoints[Axis]):
@@ -37,6 +39,52 @@ def energy_to_bragg_angle(energy_kev: float, d_a: float) -> float:
37
39
  Returns:
38
40
  The bragg angle in degrees
39
41
  """
40
- wavelength_a = convert_eV_to_angstrom(energy_kev * 1000)
42
+ wavelength_a = convert_ev_to_angstrom(energy_kev * 1000)
41
43
  d = d_a
42
44
  return asin(wavelength_a / (2 * d)) * 180 / math.pi
45
+
46
+
47
+ def fix_transmission_and_exposure_time_for_current_wavelength(
48
+ current_wavelength_a: float,
49
+ assumed_wavelength_a_from_settings: float,
50
+ requested_trans_frac: float = 100,
51
+ requested_exposure_time_s: float = 0.004,
52
+ ) -> tuple[float, float]:
53
+ """
54
+ Calculates an exposure time and transmission fraction for XRC which will provide a good signal
55
+ on the detector by using a known good wavelength, comparing it to the beamlines current wavelength,
56
+ then scaling accordingly.
57
+
58
+ Args:
59
+ current_wavelength_a: Current energy of the beamline in angstroms.
60
+ assumed_wavelength_a_from_settings: The known "good" wavelength. This should be read from
61
+ 'gda.px.expttable.default.wavelength' in GDA's domain.properties, via the config server.
62
+ requested_trans_frac: Requested transmission fraction to use.
63
+ requested_exposure_time_s: Requested exposure time to use.
64
+
65
+ Returns:
66
+ The scaled transmission fraction and exposure time respectively, in a tuple.
67
+ """
68
+
69
+ wavelength_scale = (assumed_wavelength_a_from_settings / current_wavelength_a) ** 2
70
+
71
+ # Transmission frac needed to get ideal signal
72
+ ideal_trans_frac = requested_trans_frac * wavelength_scale
73
+ if ideal_trans_frac <= 1:
74
+ new_trans_frac = ideal_trans_frac
75
+ new_exposure_time_s = requested_exposure_time_s
76
+ else:
77
+ # If the scaling would result in transmission fraction > 1,
78
+ # cap it to 1, find remaining scaling needed, and apply it
79
+ # to exposure time instead.
80
+ new_trans_frac = 1
81
+ scaling_applied_to_trans = new_trans_frac / requested_trans_frac
82
+ remaining_scaling_needed = wavelength_scale / scaling_applied_to_trans
83
+ new_exposure_time_s = requested_exposure_time_s * remaining_scaling_needed
84
+
85
+ LOGGER.info(
86
+ f"Fixing transmission fraction to {new_trans_frac} and exposure time to {new_exposure_time_s}s"
87
+ )
88
+
89
+ # Exposure time in FGS IOC is in ms, and must be an integer, so round it here
90
+ return new_trans_frac, round(new_exposure_time_s, 3)
@@ -22,7 +22,7 @@ from mx_bluesky.common.utils.log import (
22
22
  from mx_bluesky.hyperion.baton_handler import run_forever
23
23
  from mx_bluesky.hyperion.experiment_plans.experiment_registry import (
24
24
  PLAN_REGISTRY,
25
- PlanNotFound,
25
+ PlanNotFoundError,
26
26
  )
27
27
  from mx_bluesky.hyperion.external_interaction.agamemnon import (
28
28
  compare_params,
@@ -45,21 +45,13 @@ from mx_bluesky.hyperion.runner import (
45
45
  from mx_bluesky.hyperion.utils.context import setup_context
46
46
 
47
47
 
48
- def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions):
48
+ def compose_start_args(context: BlueskyContext, plan_name: str):
49
49
  experiment_registry_entry = PLAN_REGISTRY.get(plan_name)
50
50
  if experiment_registry_entry is None:
51
- raise PlanNotFound(f"Experiment plan '{plan_name}' not found in registry.")
51
+ raise PlanNotFoundError(f"Experiment plan '{plan_name}' not found in registry.")
52
52
 
53
53
  experiment_internal_param_type = experiment_registry_entry.get("param_type")
54
54
  plan = context.plan_functions.get(plan_name)
55
- if experiment_internal_param_type is None:
56
- raise PlanNotFound(
57
- f"Corresponding internal param type for '{plan_name}' not found in registry."
58
- )
59
- if plan is None:
60
- raise PlanNotFound(
61
- f"Experiment plan '{plan_name}' not found in context. Context has {context.plan_functions.keys()}"
62
- )
63
55
  try:
64
56
  parameters = experiment_internal_param_type(**json.loads(request.data))
65
57
  parameters = update_params_from_agamemnon(parameters)
@@ -80,13 +72,11 @@ class RunExperiment(Resource):
80
72
  self.runner = runner
81
73
  self.context = context
82
74
 
83
- def put(self, plan_name: str, action: Actions):
75
+ def put(self, plan_name: str, action: str):
84
76
  status_and_message = StatusAndMessage(Status.FAILED, f"{action} not understood")
85
77
  if action == Actions.START.value:
86
78
  try:
87
- plan, params, plan_name = compose_start_args(
88
- self.context, plan_name, action
89
- )
79
+ plan, params, plan_name = compose_start_args(self.context, plan_name)
90
80
  status_and_message = self.runner.start(plan, params, plan_name)
91
81
  except Exception as e:
92
82
  status_and_message = make_error_status_and_message(e)
@@ -115,7 +105,7 @@ class StopOrStatus(Resource):
115
105
  status_and_message = StatusAndMessage(Status.FAILED, f"{action} not understood")
116
106
  if action == Actions.STATUS.value:
117
107
  LOGGER.debug(
118
- f"Runner received status request - state of the runner object is: {self.runner.__dict__} - state of the RE is: {self.runner.RE.__dict__}"
108
+ f"Runner received status request - state of the runner object is: {self.runner.__dict__} - state of the run_engine is: {self.runner.run_engine.__dict__}"
119
109
  )
120
110
  status_and_message = self.runner.current_status
121
111
  return asdict(status_and_message)
@@ -9,15 +9,12 @@ from bluesky.utils import MsgGenerator, RunEngineInterrupted
9
9
  from dodal.common.beamlines.commissioning_mode import set_commissioning_signal
10
10
  from dodal.devices.aperturescatterguard import ApertureScatterguard
11
11
  from dodal.devices.baton import Baton
12
+ from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
12
13
  from dodal.devices.motors import XYZStage
13
14
  from dodal.devices.robot import BartRobot
14
15
  from dodal.devices.smargon import Smargon
15
16
 
16
17
  from mx_bluesky.common.device_setup_plans.robot_load_unload import robot_unload
17
- from mx_bluesky.common.experiment_plans.inner_plans.udc_default_state import (
18
- UDCDefaultDevices,
19
- move_to_udc_default_state,
20
- )
21
18
  from mx_bluesky.common.external_interaction.alerting import (
22
19
  AlertService,
23
20
  get_alerting_service,
@@ -27,18 +24,23 @@ from mx_bluesky.common.utils.context import (
27
24
  device_composite_from_context,
28
25
  find_device_in_context,
29
26
  )
27
+ from mx_bluesky.common.utils.exceptions import BeamlineCheckFailureError
30
28
  from mx_bluesky.common.utils.log import LOGGER
31
29
  from mx_bluesky.hyperion.experiment_plans.load_centre_collect_full_plan import (
32
30
  create_devices,
33
31
  load_centre_collect_full,
34
32
  )
33
+ from mx_bluesky.hyperion.experiment_plans.udc_default_state import (
34
+ UDCDefaultDevices,
35
+ move_to_udc_default_state,
36
+ )
35
37
  from mx_bluesky.hyperion.external_interaction.agamemnon import (
36
38
  create_parameters_from_agamemnon,
37
39
  )
38
40
  from mx_bluesky.hyperion.external_interaction.alerting.constants import Subjects
39
41
  from mx_bluesky.hyperion.parameters.components import Wait
40
42
  from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
41
- from mx_bluesky.hyperion.plan_runner import PlanException, PlanRunner
43
+ from mx_bluesky.hyperion.plan_runner import PlanError, PlanRunner
42
44
  from mx_bluesky.hyperion.utils.context import (
43
45
  clear_all_device_caches,
44
46
  setup_devices,
@@ -53,7 +55,7 @@ def run_forever(runner: PlanRunner):
53
55
  while True:
54
56
  try:
55
57
  run_udc_when_requested(runner.context, runner)
56
- except PlanException as e:
58
+ except PlanError as e:
57
59
  LOGGER.info(
58
60
  "Caught exception during plan execution, stopped and waiting for baton.",
59
61
  exc_info=e,
@@ -64,7 +66,7 @@ def run_forever(runner: PlanRunner):
64
66
  # RunEngine.abort() will have been called and we will get RunEngineInterrupted
65
67
  LOGGER.info(
66
68
  f"RunEngine was interrupted. Runner state is {runner.current_status}, "
67
- f"run engine is {runner.RE.state}"
69
+ f"run engine is {runner.run_engine.state}"
68
70
  )
69
71
 
70
72
 
@@ -93,13 +95,17 @@ def run_udc_when_requested(context: BlueskyContext, runner: PlanRunner):
93
95
  * A user requests the baton away from Hyperion
94
96
  * Hyperion releases the baton when Agamemnon has no more instructions
95
97
  * The RunEngine raises a RequestAbort exception, most likely due to a shutdown command
96
- * A plan raises an exception not of type WarningException (which is then wrapped as a PlanException)
98
+ * A plan raises an exception not of type WarningError (which is then wrapped as a PlanError)
97
99
  Args:
98
100
  baton: The baton device
99
101
  runner: The runner
100
102
  """
101
103
  _raise_udc_start_alert(get_alerting_service())
102
- yield from _move_to_udc_default_state(context)
104
+ yield from bpp.contingency_wrapper(
105
+ _move_to_udc_default_state(context),
106
+ except_plan=trap_default_state_exception,
107
+ auto_raise=False,
108
+ )
103
109
 
104
110
  # re-fetch the baton because the device has been reinstantiated
105
111
  baton = _get_baton(context)
@@ -109,7 +115,7 @@ def run_udc_when_requested(context: BlueskyContext, runner: PlanRunner):
109
115
  baton, runner, current_visit
110
116
  )
111
117
  if current_visit:
112
- yield from _perform_robot_unload(runner.context, current_visit)
118
+ yield from _clean_up_udc(runner.context, current_visit)
113
119
 
114
120
  def release_baton() -> MsgGenerator:
115
121
  # If hyperion has given up the baton itself we need to also release requested
@@ -120,8 +126,20 @@ def run_udc_when_requested(context: BlueskyContext, runner: PlanRunner):
120
126
  yield from bps.abs_set(baton.current_user, NO_USER, wait=True)
121
127
  _raise_baton_released_alert(get_alerting_service(), previous_requested_user)
122
128
 
129
+ def trap_default_state_exception(e: Exception):
130
+ yield from bps.null()
131
+ if isinstance(e, BeamlineCheckFailureError):
132
+ LOGGER.warning("Caught default state check failure:", exc_info=e)
133
+ raise PlanError("Caught default state check failure") from e
134
+ else:
135
+ LOGGER.warning("Caught unexpected exception", exc_info=e)
136
+ raise PlanError("Unexpected exception from UDC Default State plan") from e
137
+
123
138
  def collect_then_release() -> MsgGenerator:
124
- yield from bpp.contingency_wrapper(collect(), final_plan=release_baton)
139
+ yield from bpp.contingency_wrapper(
140
+ collect(),
141
+ final_plan=release_baton,
142
+ )
125
143
 
126
144
  context.run_engine(acquire_baton())
127
145
  _initialise_udc(context, runner.is_dev_mode)
@@ -145,13 +163,13 @@ def _initialise_udc(context: BlueskyContext, dev_mode: bool):
145
163
 
146
164
  def _wait_for_hyperion_requested(baton: Baton):
147
165
  LOGGER.debug("Hyperion waiting for baton...")
148
- SLEEP_PER_CHECK = 0.1
166
+ sleep_per_check = 0.1
149
167
  while True:
150
168
  requested_user = yield from bps.rd(baton.requested_user)
151
169
  if requested_user == HYPERION_USER:
152
170
  LOGGER.debug("Baton requested for Hyperion")
153
171
  break
154
- yield from bps.sleep(SLEEP_PER_CHECK)
172
+ yield from bps.sleep(sleep_per_check)
155
173
 
156
174
 
157
175
  def _fetch_and_process_agamemnon_instruction(
@@ -239,11 +257,17 @@ def _unrequest_baton(baton: Baton) -> MsgGenerator[str]:
239
257
  return requested_user
240
258
 
241
259
 
242
- def _perform_robot_unload(context: BlueskyContext, visit: str) -> MsgGenerator:
260
+ def _clean_up_udc(context: BlueskyContext, visit: str) -> MsgGenerator:
261
+ cleanup_group = "cleanup"
243
262
  robot = find_device_in_context(context, "robot", BartRobot)
244
263
  smargon = find_device_in_context(context, "smargon", Smargon)
245
264
  aperture_scatterguard = find_device_in_context(
246
265
  context, "aperture_scatterguard", ApertureScatterguard
247
266
  )
248
267
  lower_gonio = find_device_in_context(context, "lower_gonio", XYZStage)
268
+ detector_motion = find_device_in_context(context, "detector_motion", DetectorMotion)
269
+ yield from bps.abs_set(
270
+ detector_motion.shutter, ShutterState.CLOSED, group=cleanup_group
271
+ )
249
272
  yield from robot_unload(robot, smargon, aperture_scatterguard, lower_gonio, visit)
273
+ yield from bps.wait(cleanup_group)
@@ -7,6 +7,6 @@ from dodal.devices.i03.dcm import DCM
7
7
 
8
8
  def fill_in_energy_if_not_supplied(dcm: DCM, detector_params: DetectorParams):
9
9
  if not detector_params.expected_energy_ev:
10
- actual_energy_ev = 1000 * (yield from bps.rd(dcm.energy_in_kev))
10
+ actual_energy_ev = 1000 * (yield from bps.rd(dcm.energy_in_keV))
11
11
  detector_params.expected_energy_ev = actual_energy_ev
12
12
  return detector_params
@@ -57,5 +57,5 @@ PLAN_REGISTRY: dict[str, ExperimentRegistryEntry] = {
57
57
  }
58
58
 
59
59
 
60
- class PlanNotFound(Exception):
60
+ class PlanNotFoundError(Exception):
61
61
  pass
@@ -15,7 +15,7 @@ from mx_bluesky.common.device_setup_plans.setup_zebra_and_shutter import (
15
15
  tidy_up_zebra_after_gridscan,
16
16
  )
17
17
  from mx_bluesky.common.experiment_plans.common_flyscan_xray_centre_plan import (
18
- construct_beamline_specific_FGS_features,
18
+ construct_beamline_specific_fast_gridscan_features,
19
19
  )
20
20
  from mx_bluesky.common.utils.log import LOGGER
21
21
  from mx_bluesky.hyperion.device_setup_plans.setup_panda import (
@@ -35,7 +35,7 @@ from mx_bluesky.hyperion.parameters.device_composites import (
35
35
  from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan
36
36
 
37
37
 
38
- class SmargonSpeedException(Exception):
38
+ class SmargonSpeedError(Exception):
39
39
  pass
40
40
 
41
41
 
@@ -54,14 +54,14 @@ def construct_hyperion_specific_features(
54
54
  xrc_composite.smargon.x,
55
55
  xrc_composite.smargon.y,
56
56
  xrc_composite.smargon.z,
57
- xrc_composite.dcm.energy_in_kev,
57
+ xrc_composite.dcm.energy_in_keV,
58
58
  ]
59
59
 
60
60
  signals_to_read_during_collection = [
61
61
  xrc_composite.aperture_scatterguard,
62
62
  xrc_composite.attenuator.actual_transmission,
63
63
  xrc_composite.flux.flux_reading,
64
- xrc_composite.dcm.energy_in_kev,
64
+ xrc_composite.dcm.energy_in_keV,
65
65
  xrc_composite.eiger.bit_depth,
66
66
  ]
67
67
 
@@ -73,7 +73,7 @@ def construct_hyperion_specific_features(
73
73
  set_flyscan_params_plan = partial(
74
74
  set_fast_grid_scan_params,
75
75
  xrc_composite.panda_fast_grid_scan,
76
- xrc_parameters.panda_FGS_params,
76
+ xrc_parameters.panda_fast_gridscan_params,
77
77
  )
78
78
  fgs_motors = xrc_composite.panda_fast_grid_scan
79
79
 
@@ -91,10 +91,10 @@ def construct_hyperion_specific_features(
91
91
  set_flyscan_params_plan = partial(
92
92
  set_fast_grid_scan_params,
93
93
  xrc_composite.zebra_fast_grid_scan,
94
- xrc_parameters.FGS_params,
94
+ xrc_parameters.fast_gridscan_params,
95
95
  )
96
96
  fgs_motors = xrc_composite.zebra_fast_grid_scan
97
- return construct_beamline_specific_FGS_features(
97
+ return construct_beamline_specific_fast_gridscan_features(
98
98
  setup_trigger_plan,
99
99
  tidy_plan,
100
100
  set_flyscan_params_plan,
@@ -126,21 +126,23 @@ def _panda_triggering_setup(
126
126
  xrc_composite.panda_fast_grid_scan.run_up_distance_mm
127
127
  )
128
128
 
129
- DETECTOR_DEADTIME_S = 1e-4 # This value was empirically found to be safer than the documented deadtime in the Eiger manual
129
+ detector_deadtime_s = 1e-4 # This value was empirically found to be safer than the documented deadtime in the Eiger manual
130
130
 
131
- time_between_x_steps_ms = (DETECTOR_DEADTIME_S + parameters.exposure_time_s) * 1e3
131
+ time_between_x_steps_ms = (detector_deadtime_s + parameters.exposure_time_s) * 1e3
132
132
 
133
133
  smargon_speed_limit_mm_per_s = yield from bps.rd(
134
134
  xrc_composite.smargon.x.max_velocity
135
135
  )
136
136
 
137
137
  sample_velocity_mm_per_s = (
138
- parameters.panda_FGS_params.x_step_size_mm * 1e3 / time_between_x_steps_ms
138
+ parameters.panda_fast_gridscan_params.x_step_size_mm
139
+ * 1e3
140
+ / time_between_x_steps_ms
139
141
  )
140
142
  if sample_velocity_mm_per_s > smargon_speed_limit_mm_per_s:
141
- raise SmargonSpeedException(
143
+ raise SmargonSpeedError(
142
144
  f"Smargon speed was calculated from x step size\
143
- {parameters.panda_FGS_params.x_step_size_mm}mm and\
145
+ {parameters.panda_fast_gridscan_params.x_step_size_mm}mm and\
144
146
  time_between_x_steps_ms {time_between_x_steps_ms} as\
145
147
  {sample_velocity_mm_per_s}mm/s. The smargon's speed limit is\
146
148
  {smargon_speed_limit_mm_per_s}mm/s."
@@ -161,7 +163,7 @@ def _panda_triggering_setup(
161
163
 
162
164
  yield from setup_panda_for_flyscan(
163
165
  xrc_composite.panda,
164
- parameters.panda_FGS_params,
166
+ parameters.panda_fast_gridscan_params,
165
167
  xrc_composite.smargon,
166
168
  parameters.exposure_time_s,
167
169
  time_between_x_steps_ms,
@@ -14,7 +14,7 @@ from dodal.devices.oav.oav_parameters import OAVParameters
14
14
  import mx_bluesky.common.xrc_result as flyscan_result
15
15
  from mx_bluesky.common.parameters.components import WithSnapshot
16
16
  from mx_bluesky.common.utils.context import device_composite_from_context
17
- from mx_bluesky.common.utils.exceptions import CrystalNotFoundException
17
+ from mx_bluesky.common.utils.exceptions import CrystalNotFoundError
18
18
  from mx_bluesky.common.utils.log import LOGGER
19
19
  from mx_bluesky.common.xrc_result import XRayCentreEventHandler
20
20
  from mx_bluesky.hyperion.experiment_plans.robot_load_then_centre_plan import (
@@ -93,7 +93,7 @@ def load_centre_collect_full(
93
93
  ),
94
94
  flyscan_event_handler,
95
95
  )
96
- except CrystalNotFoundException:
96
+ except CrystalNotFoundError:
97
97
  if parameters.select_centres.ignore_xtal_not_found:
98
98
  LOGGER.info("Ignoring crystal not found due to parameter settings.")
99
99
  else:
@@ -13,7 +13,7 @@ from mx_bluesky.common.utils.context import device_composite_from_context
13
13
  from mx_bluesky.common.utils.log import LOGGER
14
14
 
15
15
 
16
- class AttenuationOptimisationFailedException(Exception):
16
+ class AttenuationOptimisationFailedError(Exception):
17
17
  pass
18
18
 
19
19
 
@@ -59,7 +59,7 @@ def check_parameters(
59
59
 
60
60
  if upper_transmission < lower_transmission:
61
61
  raise ValueError(
62
- f"Upper transmission limit {upper_transmission} must be greater than lower tranmission limit {lower_transmission}"
62
+ f"Upper transmission limit {upper_transmission} must be greater than lower transmission limit {lower_transmission}"
63
63
  )
64
64
 
65
65
  if not upper_transmission >= initial_transmission >= lower_transmission:
@@ -80,7 +80,7 @@ def calculate_new_direction(direction: Direction, deadtime, deadtime_threshold):
80
80
  if deadtime > deadtime_threshold:
81
81
  direction = Direction.NEGATIVE
82
82
  LOGGER.info(
83
- "Found tranmission to go above deadtime threshold. Reducing transmission..."
83
+ "Found transmission to go above deadtime threshold. Reducing transmission..."
84
84
  )
85
85
  return direction
86
86
 
@@ -111,7 +111,7 @@ def deadtime_calc_new_transmission(
111
111
  Minimum expected transmission. Raise an error if transmission goes lower.
112
112
 
113
113
  Raises:
114
- AttenuationOptimisationFailedException:
114
+ AttenuationOptimisationFailedError:
115
115
  This error is thrown if the transmission goes below the expected value or if the maximum cycles are reached
116
116
 
117
117
  Returns:
@@ -124,7 +124,7 @@ def deadtime_calc_new_transmission(
124
124
  else:
125
125
  transmission /= increment
126
126
  if transmission < lower_transmission_limit:
127
- raise AttenuationOptimisationFailedException(
127
+ raise AttenuationOptimisationFailedError(
128
128
  "Calculated transmission is below expected limit"
129
129
  )
130
130
  return transmission
@@ -218,7 +218,7 @@ def deadtime_optimisation(
218
218
  Minimum expected transmission. Raise an error if transmission goes lower.
219
219
 
220
220
  Raises:
221
- AttenuationOptimisationFailedException:
221
+ AttenuationOptimisationFailedError:
222
222
  This error is thrown if the transmission goes below the expected value or the maximum cycles are reached
223
223
 
224
224
  Returns:
@@ -262,7 +262,7 @@ def deadtime_optimisation(
262
262
  break
263
263
 
264
264
  if cycle == max_cycles - 1:
265
- raise AttenuationOptimisationFailedException(
265
+ raise AttenuationOptimisationFailedError(
266
266
  f"Unable to optimise attenuation after maximum cycles.\
267
267
  Deadtime did not get lower than threshold: {deadtime_threshold} in maximum cycles {max_cycles}"
268
268
  )
@@ -367,12 +367,12 @@ def total_counts_optimisation(
367
367
  if transmission > upper_transmission_limit:
368
368
  transmission = upper_transmission_limit
369
369
  elif transmission < lower_transmission_limit:
370
- raise AttenuationOptimisationFailedException(
370
+ raise AttenuationOptimisationFailedError(
371
371
  f"Transmission has gone below lower threshold {lower_transmission_limit}"
372
372
  )
373
373
 
374
374
  if cycle == max_cycles - 1:
375
- raise AttenuationOptimisationFailedException(
375
+ raise AttenuationOptimisationFailedError(
376
376
  f"Unable to optimise attenuation after maximum cycles.\
377
377
  Total count is not within limits: {lower_count_limit} <= {total_count}\
378
378
  <= {upper_count_limit}"
@@ -19,7 +19,11 @@ from mx_bluesky.common.experiment_plans.common_grid_detect_then_xray_centre_plan
19
19
  detect_grid_and_do_gridscan,
20
20
  )
21
21
  from mx_bluesky.common.experiment_plans.oav_snapshot_plan import (
22
- setup_beamline_for_OAV,
22
+ setup_beamline_for_oav,
23
+ )
24
+ from mx_bluesky.common.experiment_plans.pin_tip_centring_plan import (
25
+ PinTipCentringComposite,
26
+ pin_tip_centre_plan,
23
27
  )
24
28
  from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import (
25
29
  ispyb_activation_wrapper,
@@ -31,10 +35,6 @@ from mx_bluesky.common.xrc_result import XRayCentreEventHandler
31
35
  from mx_bluesky.hyperion.experiment_plans.hyperion_flyscan_xray_centre_plan import (
32
36
  construct_hyperion_specific_features,
33
37
  )
34
- from mx_bluesky.hyperion.experiment_plans.pin_tip_centring_plan import (
35
- PinTipCentringComposite,
36
- pin_tip_centre_plan,
37
- )
38
38
  from mx_bluesky.hyperion.parameters.constants import CONST
39
39
  from mx_bluesky.hyperion.parameters.device_composites import (
40
40
  HyperionGridDetectThenXRayCentreComposite,
@@ -78,13 +78,12 @@ def pin_centre_then_flyscan_plan(
78
78
 
79
79
  pin_tip_centring_composite = PinTipCentringComposite(
80
80
  oav=composite.oav,
81
- smargon=composite.smargon,
82
- backlight=composite.backlight,
81
+ gonio=composite.smargon,
83
82
  pin_tip_detection=composite.pin_tip_detection,
84
83
  )
85
84
 
86
85
  def _pin_centre_then_flyscan_plan():
87
- yield from setup_beamline_for_OAV(
86
+ yield from setup_beamline_for_oav(
88
87
  composite.smargon, composite.backlight, composite.aperture_scatterguard
89
88
  )
90
89
 
@@ -20,7 +20,7 @@ from dodal.devices.motors import XYZStage
20
20
  from dodal.devices.oav.oav_detector import OAV
21
21
  from dodal.devices.robot import BartRobot, SampleLocation
22
22
  from dodal.devices.smargon import Smargon
23
- from dodal.devices.thawer import Thawer
23
+ from dodal.devices.thawer import OnOff, Thawer
24
24
  from dodal.devices.webcam import Webcam
25
25
  from dodal.devices.xbpm_feedback import XBPMFeedback
26
26
 
@@ -82,7 +82,6 @@ def do_robot_load(
82
82
  sample_location: SampleLocation,
83
83
  sample_id: int,
84
84
  demand_energy_ev: float | None,
85
- thawing_time: float,
86
85
  ):
87
86
  yield from bps.abs_set(composite.robot.next_sample_id, sample_id, wait=True)
88
87
 
@@ -96,13 +95,10 @@ def do_robot_load(
96
95
 
97
96
  yield from bps.wait("robot_load")
98
97
 
99
- yield from bps.abs_set(
100
- composite.thawer.thaw_for_time_s,
101
- thawing_time,
102
- group="thawing_finished",
103
- )
104
98
  yield from wait_for_smargon_not_disabled(composite.smargon)
105
99
 
100
+ yield from bps.mv(composite.thawer, OnOff.ON)
101
+
106
102
 
107
103
  def pin_already_loaded(
108
104
  robot: BartRobot, sample_location: SampleLocation
@@ -120,7 +116,6 @@ def robot_load_and_snapshots(
120
116
  location: SampleLocation,
121
117
  snapshot_directory: Path,
122
118
  sample_id: int,
123
- thawing_time: float,
124
119
  demand_energy_ev: float | None,
125
120
  ):
126
121
  yield from bps.abs_set(composite.backlight, InOut.IN, group="snapshot")
@@ -134,7 +129,6 @@ def robot_load_and_snapshots(
134
129
  location,
135
130
  sample_id,
136
131
  demand_energy_ev,
137
- thawing_time,
138
132
  )
139
133
 
140
134
  gonio_finished = yield from do_plan_while_lower_gonio_at_home(
@@ -173,7 +167,6 @@ def robot_load_and_change_energy_plan(
173
167
  sample_location,
174
168
  params.snapshot_directory,
175
169
  params.sample_id,
176
- params.thawing_time,
177
170
  params.demand_energy_ev,
178
171
  ),
179
172
  md={
@@ -10,6 +10,7 @@ from bluesky.utils import MsgGenerator
10
10
  from dodal.devices.aperturescatterguard import ApertureScatterguard
11
11
  from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
12
12
  from dodal.devices.backlight import Backlight
13
+ from dodal.devices.beamsize.beamsize import BeamsizeBase
13
14
  from dodal.devices.detector.detector_motion import DetectorMotion
14
15
  from dodal.devices.eiger import EigerDetector
15
16
  from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScanThreeD
@@ -26,7 +27,7 @@ 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
29
  from dodal.devices.thawer import Thawer
29
- from dodal.devices.undulator import Undulator
30
+ from dodal.devices.undulator import UndulatorInKeV
30
31
  from dodal.devices.webcam import Webcam
31
32
  from dodal.devices.xbpm_feedback import XBPMFeedback
32
33
  from dodal.devices.zebra.zebra import Zebra
@@ -70,6 +71,7 @@ class RobotLoadThenCentreComposite:
70
71
  # HyperionGridDetectThenXRayCentreComposite fields
71
72
  aperture_scatterguard: ApertureScatterguard
72
73
  backlight: Backlight
74
+ beamsize: BeamsizeBase
73
75
  detector_motion: DetectorMotion
74
76
  eiger: EigerDetector
75
77
  zebra_fast_grid_scan: ZebraFastGridScanThreeD
@@ -79,7 +81,7 @@ class RobotLoadThenCentreComposite:
79
81
  smargon: Smargon
80
82
  synchrotron: Synchrotron
81
83
  s4_slit_gaps: S4SlitGaps
82
- undulator: Undulator
84
+ undulator: UndulatorInKeV
83
85
  zebra: Zebra
84
86
  zocalo: ZocaloResults
85
87
  panda: HDFPanda