mx-bluesky 1.5.10__py3-none-any.whl → 1.5.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/aithre_lasershaping/goniometer_controls.py +2 -2
- mx_bluesky/beamlines/i02_1/parameters/gridscan.py +1 -1
- mx_bluesky/beamlines/i04/experiment_plans/i04_grid_detect_then_xray_centre_plan.py +7 -7
- mx_bluesky/beamlines/i04/thawing_plan.py +9 -9
- mx_bluesky/beamlines/i24/jungfrau_commissioning/experiment_plans/do_darks.py +55 -10
- mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/do_external_acquisition.py +1 -1
- mx_bluesky/beamlines/i24/jungfrau_commissioning/plan_stubs/plan_utils.py +1 -1
- mx_bluesky/beamlines/i24/serial/__init__.py +7 -5
- mx_bluesky/beamlines/i24/serial/dcid.py +3 -3
- mx_bluesky/beamlines/i24/serial/extruder/{i24ssx_Extruder_Collect_py3v2.py → i24ssx_extruder_collect_py3v2.py} +65 -35
- mx_bluesky/beamlines/i24/serial/fixed_target/{i24ssx_Chip_Collect_py3v1.py → i24ssx_chip_collect_py3v1.py} +5 -5
- mx_bluesky/beamlines/i24/serial/fixed_target/{i24ssx_Chip_Manager_py3v1.py → i24ssx_chip_manager_py3v1.py} +46 -46
- mx_bluesky/beamlines/i24/serial/fixed_target/{i24ssx_Chip_StartUp_py3v1.py → i24ssx_chip_startup_py3v1.py} +3 -3
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +33 -33
- mx_bluesky/beamlines/i24/serial/log.py +11 -11
- mx_bluesky/beamlines/i24/serial/parameters/fixed_target/cs/cs_maker.json +3 -3
- mx_bluesky/beamlines/i24/serial/setup_beamline/ca.py +0 -12
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +13 -32
- mx_bluesky/beamlines/i24/serial/setup_beamline/pv_abstract.py +5 -5
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +22 -249
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +2 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +4 -4
- mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +102 -15
- mx_bluesky/beamlines/i24/serial/write_nexus.py +4 -4
- mx_bluesky/common/experiment_plans/common_flyscan_xray_centre_plan.py +6 -6
- mx_bluesky/common/experiment_plans/common_grid_detect_then_xray_centre_plan.py +2 -2
- mx_bluesky/common/experiment_plans/inner_plans/do_fgs.py +1 -1
- mx_bluesky/common/experiment_plans/inner_plans/read_hardware.py +2 -2
- mx_bluesky/common/experiment_plans/inner_plans/udc_default_state.py +22 -1
- mx_bluesky/common/experiment_plans/inner_plans/write_sample_status.py +2 -2
- mx_bluesky/common/experiment_plans/oav_snapshot_plan.py +1 -1
- mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +3 -3
- mx_bluesky/common/external_interaction/callbacks/common/plan_reactive_callback.py +1 -1
- mx_bluesky/common/external_interaction/callbacks/common/zocalo_callback.py +2 -2
- mx_bluesky/common/external_interaction/callbacks/sample_handling/sample_handling_callback.py +3 -3
- mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +7 -5
- mx_bluesky/common/external_interaction/callbacks/xray_centre/nexus_callback.py +2 -2
- mx_bluesky/common/external_interaction/config_server.py +2 -2
- mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +4 -2
- mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +0 -1
- mx_bluesky/common/external_interaction/nexus/nexus_utils.py +2 -2
- mx_bluesky/common/external_interaction/nexus/write_nexus.py +3 -3
- mx_bluesky/common/parameters/constants.py +1 -1
- mx_bluesky/common/parameters/gridscan.py +2 -2
- mx_bluesky/common/utils/exceptions.py +9 -7
- mx_bluesky/common/utils/log.py +4 -4
- mx_bluesky/common/utils/tracing.py +5 -5
- mx_bluesky/common/utils/utils.py +8 -8
- mx_bluesky/hyperion/__main__.py +5 -5
- mx_bluesky/hyperion/baton_handler.py +15 -8
- mx_bluesky/hyperion/device_setup_plans/smargon.py +5 -5
- mx_bluesky/hyperion/device_setup_plans/utils.py +1 -1
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +1 -1
- mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +15 -13
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +9 -9
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +3 -3
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +2 -2
- mx_bluesky/hyperion/external_interaction/agamemnon.py +2 -2
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +2 -2
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +2 -2
- mx_bluesky/hyperion/external_interaction/config_server.py +2 -2
- mx_bluesky/hyperion/parameters/constants.py +2 -2
- mx_bluesky/hyperion/parameters/gridscan.py +4 -4
- mx_bluesky/hyperion/plan_runner.py +6 -6
- mx_bluesky/hyperion/runner.py +10 -8
- mx_bluesky/jupyter_example.ipynb +3 -3
- {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.11.dist-info}/METADATA +6 -5
- {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.11.dist-info}/RECORD +76 -76
- {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.11.dist-info}/WHEEL +0 -0
- {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.11.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.11.dist-info}/licenses/LICENSE +0 -0
- {mx_bluesky-1.5.10.dist-info → mx_bluesky-1.5.11.dist-info}/top_level.txt +0 -0
|
@@ -52,7 +52,7 @@ def standard_read_hardware_pre_collection(
|
|
|
52
52
|
synchrotron.synchrotron_mode,
|
|
53
53
|
s4_slit_gaps,
|
|
54
54
|
smargon,
|
|
55
|
-
dcm.
|
|
55
|
+
dcm.energy_in_keV,
|
|
56
56
|
]
|
|
57
57
|
yield from read_hardware_plan(
|
|
58
58
|
signals_to_read_pre_flyscan, DocDescriptorNames.HARDWARE_READ_PRE
|
|
@@ -70,7 +70,7 @@ def standard_read_hardware_during_collection(
|
|
|
70
70
|
aperture_scatterguard,
|
|
71
71
|
attenuator.actual_transmission,
|
|
72
72
|
flux.flux_reading,
|
|
73
|
-
dcm.
|
|
73
|
+
dcm.energy_in_keV,
|
|
74
74
|
detector.bit_depth,
|
|
75
75
|
]
|
|
76
76
|
yield from read_hardware_plan(
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import bluesky.plan_stubs as bps
|
|
2
2
|
import pydantic
|
|
3
|
+
from bluesky.utils import MsgGenerator
|
|
3
4
|
from dodal.devices.aperturescatterguard import ApertureScatterguard, ApertureValue
|
|
4
5
|
from dodal.devices.collimation_table import CollimationTable
|
|
5
|
-
from dodal.devices.cryostream import CryoStream
|
|
6
|
+
from dodal.devices.cryostream import CryoStream, CryoStreamGantry, CryoStreamSelection
|
|
6
7
|
from dodal.devices.cryostream import InOut as CryoInOut
|
|
7
8
|
from dodal.devices.fluorescence_detector_motion import (
|
|
8
9
|
FluorescenceDetector,
|
|
9
10
|
)
|
|
10
11
|
from dodal.devices.fluorescence_detector_motion import InOut as FlouInOut
|
|
12
|
+
from dodal.devices.hutch_shutter import HutchShutter, ShutterDemand
|
|
11
13
|
from dodal.devices.mx_phase1.beamstop import Beamstop, BeamstopPositions
|
|
12
14
|
from dodal.devices.scintillator import InOut as ScinInOut
|
|
13
15
|
from dodal.devices.scintillator import Scintillator
|
|
@@ -16,15 +18,18 @@ from dodal.devices.scintillator import Scintillator
|
|
|
16
18
|
@pydantic.dataclasses.dataclass(config={"arbitrary_types_allowed": True})
|
|
17
19
|
class UDCDefaultDevices:
|
|
18
20
|
cryostream: CryoStream
|
|
21
|
+
cryostream_gantry: CryoStreamGantry
|
|
19
22
|
fluorescence_det_motion: FluorescenceDetector
|
|
20
23
|
beamstop: Beamstop
|
|
21
24
|
scintillator: Scintillator
|
|
22
25
|
aperture_scatterguard: ApertureScatterguard
|
|
23
26
|
collimation_table: CollimationTable
|
|
27
|
+
hutch_shutter: HutchShutter
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
def move_to_udc_default_state(devices: UDCDefaultDevices):
|
|
27
31
|
"""Moves beamline to known positions prior to UDC start"""
|
|
32
|
+
yield from _verify_correct_cryostream_selected(devices.cryostream_gantry)
|
|
28
33
|
|
|
29
34
|
cryostream_temp = yield from bps.rd(devices.cryostream.temperature_k)
|
|
30
35
|
cryostream_pressure = yield from bps.rd(devices.cryostream.back_pressure_bar)
|
|
@@ -33,6 +38,10 @@ def move_to_udc_default_state(devices: UDCDefaultDevices):
|
|
|
33
38
|
if cryostream_pressure > devices.cryostream.MAX_PRESSURE_BAR:
|
|
34
39
|
raise ValueError("Cryostream back pressure is too high, not starting UDC")
|
|
35
40
|
|
|
41
|
+
yield from bps.abs_set(
|
|
42
|
+
devices.hutch_shutter, ShutterDemand.OPEN, group="udc_default"
|
|
43
|
+
)
|
|
44
|
+
|
|
36
45
|
yield from bps.abs_set(devices.scintillator.selected_pos, ScinInOut.OUT, wait=True)
|
|
37
46
|
|
|
38
47
|
yield from bps.abs_set(
|
|
@@ -63,3 +72,15 @@ def move_to_udc_default_state(devices: UDCDefaultDevices):
|
|
|
63
72
|
yield from bps.abs_set(devices.cryostream.fine, CryoInOut.IN, group="udc_default")
|
|
64
73
|
|
|
65
74
|
yield from bps.wait("udc_default")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _verify_correct_cryostream_selected(
|
|
78
|
+
cryostream_gantry: CryoStreamGantry,
|
|
79
|
+
) -> MsgGenerator:
|
|
80
|
+
cryostream_selection = yield from bps.rd(cryostream_gantry.cryostream_selector)
|
|
81
|
+
cryostream_selected = yield from bps.rd(cryostream_gantry.cryostream_selected)
|
|
82
|
+
if cryostream_selection != CryoStreamSelection.CRYOJET or cryostream_selected != 1:
|
|
83
|
+
raise ValueError(
|
|
84
|
+
f"Cryostream is not selected for use, control PV selection = {cryostream_selection}, "
|
|
85
|
+
f"current status {cryostream_selected}"
|
|
86
|
+
)
|
|
@@ -6,7 +6,7 @@ import bluesky.preprocessors as bpp
|
|
|
6
6
|
from mx_bluesky.common.external_interaction.callbacks.sample_handling.sample_handling_callback import (
|
|
7
7
|
SampleHandlingCallback,
|
|
8
8
|
)
|
|
9
|
-
from mx_bluesky.common.utils.exceptions import
|
|
9
|
+
from mx_bluesky.common.utils.exceptions import SampleError
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class SampleStatusExceptionType(StrEnum):
|
|
@@ -27,7 +27,7 @@ def deposit_sample_error(exception_type: SampleStatusExceptionType, sample_id: i
|
|
|
27
27
|
if exception_type == SampleStatusExceptionType.BEAMLINE:
|
|
28
28
|
raise AssertionError()
|
|
29
29
|
elif exception_type == SampleStatusExceptionType.SAMPLE:
|
|
30
|
-
raise
|
|
30
|
+
raise SampleError
|
|
31
31
|
|
|
32
32
|
yield from _inner()
|
|
33
33
|
|
|
@@ -29,7 +29,7 @@ from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import get_ispyb_c
|
|
|
29
29
|
from mx_bluesky.common.parameters.components import DiffractionExperimentWithSample
|
|
30
30
|
from mx_bluesky.common.parameters.constants import DocDescriptorNames
|
|
31
31
|
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER, set_dcgid_tag
|
|
32
|
-
from mx_bluesky.common.utils.utils import
|
|
32
|
+
from mx_bluesky.common.utils.utils import convert_ev_to_angstrom
|
|
33
33
|
|
|
34
34
|
D = TypeVar("D")
|
|
35
35
|
if TYPE_CHECKING:
|
|
@@ -43,9 +43,9 @@ def _update_based_on_energy(
|
|
|
43
43
|
):
|
|
44
44
|
"""If energy has been read as part of this reading then add it into the data
|
|
45
45
|
collection info along with the other fields that depend on it."""
|
|
46
|
-
if energy_kev := doc["data"].get("dcm-
|
|
46
|
+
if energy_kev := doc["data"].get("dcm-energy_in_keV", None):
|
|
47
47
|
energy_ev = energy_kev * 1000
|
|
48
|
-
wavelength_angstroms =
|
|
48
|
+
wavelength_angstroms = convert_ev_to_angstrom(energy_ev)
|
|
49
49
|
data_collection_info.wavelength = wavelength_angstroms
|
|
50
50
|
data_collection_info.resolution = resolution(
|
|
51
51
|
detector_params,
|
|
@@ -40,7 +40,7 @@ class PlanReactiveCallback(CallbackBase):
|
|
|
40
40
|
self.log = log
|
|
41
41
|
|
|
42
42
|
def _run_activity_gated(self, name: str, func, doc, override=False):
|
|
43
|
-
# Runs `func` if self.active is True or
|
|
43
|
+
# Runs `func` if self.active is True or override is true. Override can be used
|
|
44
44
|
# to run the function even after setting self.active to False, i.e. in the last
|
|
45
45
|
# handler of a run.
|
|
46
46
|
|
|
@@ -9,7 +9,7 @@ from dodal.devices.zocalo import ZocaloStartInfo, ZocaloTrigger
|
|
|
9
9
|
from mx_bluesky.common.parameters.constants import (
|
|
10
10
|
DocDescriptorNames,
|
|
11
11
|
)
|
|
12
|
-
from mx_bluesky.common.utils.exceptions import
|
|
12
|
+
from mx_bluesky.common.utils.exceptions import ISPyBDepositionNotMadeError
|
|
13
13
|
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
@@ -89,7 +89,7 @@ class ZocaloCallback(CallbackBase):
|
|
|
89
89
|
f"Zocalo handler received stop document, for run {doc.get('run_start')}."
|
|
90
90
|
)
|
|
91
91
|
if not self._started_zocalo_collections:
|
|
92
|
-
raise
|
|
92
|
+
raise ISPyBDepositionNotMadeError(
|
|
93
93
|
f"No ISPyB IDs received by the end of {self.triggering_plan=}"
|
|
94
94
|
)
|
|
95
95
|
for info in self._started_zocalo_collections:
|
mx_bluesky/common/external_interaction/callbacks/sample_handling/sample_handling_callback.py
CHANGED
|
@@ -12,7 +12,7 @@ from mx_bluesky.common.external_interaction.ispyb.exp_eye_store import (
|
|
|
12
12
|
BLSampleStatus,
|
|
13
13
|
ExpeyeInteraction,
|
|
14
14
|
)
|
|
15
|
-
from mx_bluesky.common.utils.exceptions import
|
|
15
|
+
from mx_bluesky.common.utils.exceptions import CrystalNotFoundError, SampleError
|
|
16
16
|
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER
|
|
17
17
|
|
|
18
18
|
|
|
@@ -47,7 +47,7 @@ class SampleHandlingCallback(PlanReactiveCallback):
|
|
|
47
47
|
expeye = ExpeyeInteraction()
|
|
48
48
|
if doc["exit_status"] != "success":
|
|
49
49
|
reason = doc.get("reason", "")
|
|
50
|
-
exception_type, message =
|
|
50
|
+
exception_type, message = SampleError.type_and_message_from_reason(
|
|
51
51
|
reason
|
|
52
52
|
)
|
|
53
53
|
self.log.info(
|
|
@@ -83,7 +83,7 @@ class SampleHandlingCallback(PlanReactiveCallback):
|
|
|
83
83
|
|
|
84
84
|
def _decode_sample_status(self, exception_type: str) -> BLSampleStatus:
|
|
85
85
|
match exception_type:
|
|
86
|
-
case
|
|
86
|
+
case SampleError.__name__ | CrystalNotFoundError.__name__:
|
|
87
87
|
return BLSampleStatus.ERROR_SAMPLE
|
|
88
88
|
return BLSampleStatus.ERROR_BEAMLINE
|
|
89
89
|
|
|
@@ -40,8 +40,8 @@ from mx_bluesky.common.parameters.components import DiffractionExperimentWithSam
|
|
|
40
40
|
from mx_bluesky.common.parameters.constants import DocDescriptorNames, PlanNameConstants
|
|
41
41
|
from mx_bluesky.common.parameters.gridscan import GridCommon
|
|
42
42
|
from mx_bluesky.common.utils.exceptions import (
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
ISPyBDepositionNotMadeError,
|
|
44
|
+
SampleError,
|
|
45
45
|
)
|
|
46
46
|
from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER, set_dcgid_tag
|
|
47
47
|
from mx_bluesky.common.utils.utils import number_of_frames_from_scan_spec
|
|
@@ -87,7 +87,7 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
87
87
|
To use, subscribe the Bluesky RunEngine to an instance of this class.
|
|
88
88
|
E.g.:
|
|
89
89
|
ispyb_handler_callback = FGSISPyBCallback(parameters)
|
|
90
|
-
|
|
90
|
+
run_engine.subscribe(ispyb_handler_callback)
|
|
91
91
|
Or decorate a plan using bluesky.preprocessors.subs_decorator.
|
|
92
92
|
|
|
93
93
|
See: https://blueskyproject.io/bluesky/callbacks.html#ways-to-invoke-callbacks
|
|
@@ -303,8 +303,10 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
303
303
|
f"with uid: {self.uid_to_finalize_on}."
|
|
304
304
|
)
|
|
305
305
|
if self.ispyb_ids == IspybIds():
|
|
306
|
-
raise
|
|
307
|
-
|
|
306
|
+
raise ISPyBDepositionNotMadeError(
|
|
307
|
+
"ispyb was not initialised at run start"
|
|
308
|
+
)
|
|
309
|
+
exception_type, message = SampleError.type_and_message_from_reason(
|
|
308
310
|
doc.get("reason", "")
|
|
309
311
|
)
|
|
310
312
|
if exception_type:
|
|
@@ -33,7 +33,7 @@ class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
|
33
33
|
To use, subscribe the Bluesky RunEngine to an instance of this class.
|
|
34
34
|
E.g.:
|
|
35
35
|
nexus_file_handler_callback = NexusFileCallback(parameters)
|
|
36
|
-
|
|
36
|
+
run_engine.subscribe(nexus_file_handler_callback)
|
|
37
37
|
Or decorate a plan using bluesky.preprocessors.subs_decorator.
|
|
38
38
|
|
|
39
39
|
See: https://blueskyproject.io/bluesky/callbacks.html#ways-to-invoke-callbacks
|
|
@@ -89,7 +89,7 @@ class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
|
89
89
|
nexus_writer.beam,
|
|
90
90
|
nexus_writer.attenuator,
|
|
91
91
|
) = create_beam_and_attenuator_parameters(
|
|
92
|
-
data["dcm-
|
|
92
|
+
data["dcm-energy_in_keV"],
|
|
93
93
|
data["flux-flux_reading"],
|
|
94
94
|
data["attenuator-actual_transmission"],
|
|
95
95
|
)
|
|
@@ -10,7 +10,7 @@ from pydantic import TypeAdapter
|
|
|
10
10
|
from mx_bluesky.common.parameters.constants import (
|
|
11
11
|
GDA_DOMAIN_PROPERTIES_PATH,
|
|
12
12
|
FeatureSetting,
|
|
13
|
-
|
|
13
|
+
FeatureSettingSources,
|
|
14
14
|
OavConstants,
|
|
15
15
|
)
|
|
16
16
|
from mx_bluesky.common.utils.log import LOGGER
|
|
@@ -25,7 +25,7 @@ T = TypeVar("T", bound=FeatureSetting)
|
|
|
25
25
|
class MXConfigClient(ConfigServer, Generic[T]):
|
|
26
26
|
def __init__(
|
|
27
27
|
self,
|
|
28
|
-
feature_sources: type[
|
|
28
|
+
feature_sources: type[FeatureSettingSources],
|
|
29
29
|
feature_dc: type[T],
|
|
30
30
|
url: str = "https://daq-config.diamond.ac.uk",
|
|
31
31
|
):
|
|
@@ -11,7 +11,7 @@ from mx_bluesky.common.external_interaction.ispyb.ispyb_utils import (
|
|
|
11
11
|
get_current_time_string,
|
|
12
12
|
get_ispyb_config,
|
|
13
13
|
)
|
|
14
|
-
from mx_bluesky.common.utils.exceptions import
|
|
14
|
+
from mx_bluesky.common.utils.exceptions import ISPyBDepositionNotMadeError
|
|
15
15
|
|
|
16
16
|
RobotActionID = int
|
|
17
17
|
|
|
@@ -40,7 +40,9 @@ def _send_and_get_response(auth, url, data, send_func) -> dict:
|
|
|
40
40
|
resp_txt = str(response.json())
|
|
41
41
|
except JSONDecodeError:
|
|
42
42
|
resp_txt = str(response)
|
|
43
|
-
raise
|
|
43
|
+
raise ISPyBDepositionNotMadeError(
|
|
44
|
+
f"Could not write {data} to {url}: {resp_txt}"
|
|
45
|
+
)
|
|
44
46
|
return response.json()
|
|
45
47
|
|
|
46
48
|
|
|
@@ -11,7 +11,7 @@ from nexgen.nxs_utils.axes import TransformationType
|
|
|
11
11
|
from numpy.typing import DTypeLike
|
|
12
12
|
|
|
13
13
|
from mx_bluesky.common.utils.log import NEXUS_LOGGER
|
|
14
|
-
from mx_bluesky.common.utils.utils import
|
|
14
|
+
from mx_bluesky.common.utils.utils import convert_ev_to_angstrom
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class AxisDirection(Enum):
|
|
@@ -158,6 +158,6 @@ def create_beam_and_attenuator_parameters(
|
|
|
158
158
|
tuple[Beam, Attenuator]: Descriptions of the beam and attenuator for nexgen.
|
|
159
159
|
"""
|
|
160
160
|
return (
|
|
161
|
-
Beam(wavelength=
|
|
161
|
+
Beam(wavelength=convert_ev_to_angstrom(energy_kev * 1000), flux=flux),
|
|
162
162
|
Attenuator(transmission=transmission_fraction),
|
|
163
163
|
)
|
|
@@ -87,7 +87,7 @@ class NexusWriter:
|
|
|
87
87
|
vds_shape = self.data_shape
|
|
88
88
|
|
|
89
89
|
for filename in [self.nexus_file, self.master_file]:
|
|
90
|
-
|
|
90
|
+
nxmx_writer = NXmxFileWriter(
|
|
91
91
|
filename,
|
|
92
92
|
self.goniometer,
|
|
93
93
|
self.detector,
|
|
@@ -96,12 +96,12 @@ class NexusWriter:
|
|
|
96
96
|
self.attenuator,
|
|
97
97
|
self.full_num_of_images,
|
|
98
98
|
)
|
|
99
|
-
|
|
99
|
+
nxmx_writer.write(
|
|
100
100
|
image_filename=f"{self.data_filename}",
|
|
101
101
|
start_time=start_time,
|
|
102
102
|
est_end_time=est_end_time,
|
|
103
103
|
)
|
|
104
|
-
|
|
104
|
+
nxmx_writer.write_vds(
|
|
105
105
|
vds_offset=self.start_index, vds_shape=vds_shape, vds_dtype=bit_depth
|
|
106
106
|
)
|
|
107
107
|
|
|
@@ -166,6 +166,6 @@ class Status(Enum):
|
|
|
166
166
|
class FeatureSetting: ... # List of features and their default values. Subclasses must also be a pydantic dataclass
|
|
167
167
|
|
|
168
168
|
|
|
169
|
-
class
|
|
169
|
+
class FeatureSettingSources(
|
|
170
170
|
StrEnum
|
|
171
171
|
): ... # List of features and the name of that property in domain.properties
|
|
@@ -109,7 +109,7 @@ class SpecifiedGrid(GridCommon, XyzStarts, WithScan, Generic[GridScanParamType])
|
|
|
109
109
|
|
|
110
110
|
@property
|
|
111
111
|
@abstractmethod
|
|
112
|
-
def
|
|
112
|
+
def fast_gridscan_params(self) -> GridScanParamType: ...
|
|
113
113
|
|
|
114
114
|
def do_set_stub_offsets(self, value: bool):
|
|
115
115
|
self._set_stub_offsets = value
|
|
@@ -167,7 +167,7 @@ class SpecifiedThreeDGridScan(
|
|
|
167
167
|
grid2_omega_deg: float = Field(default=GridscanParamConstants.OMEGA_2)
|
|
168
168
|
|
|
169
169
|
@property
|
|
170
|
-
def
|
|
170
|
+
def fast_gridscan_params(self) -> ZebraGridScanParamsThreeD:
|
|
171
171
|
return ZebraGridScanParamsThreeD(
|
|
172
172
|
x_steps=self.x_steps,
|
|
173
173
|
y_steps=self.y_steps,
|
|
@@ -7,20 +7,22 @@ from bluesky.preprocessors import contingency_wrapper
|
|
|
7
7
|
from bluesky.utils import Msg
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class
|
|
10
|
+
class WarningError(
|
|
11
|
+
Exception
|
|
12
|
+
): # see https://github.com/DiamondLightSource/mx-bluesky/issues/1394 on naming
|
|
11
13
|
"""An exception used when we want to warn GDA of a
|
|
12
14
|
problem but continue with UDC anyway"""
|
|
13
15
|
|
|
14
16
|
pass
|
|
15
17
|
|
|
16
18
|
|
|
17
|
-
class
|
|
19
|
+
class ISPyBDepositionNotMadeError(Exception):
|
|
18
20
|
"""Raised when the ISPyB or Zocalo callbacks can't access ISPyB deposition numbers."""
|
|
19
21
|
|
|
20
22
|
pass
|
|
21
23
|
|
|
22
24
|
|
|
23
|
-
class
|
|
25
|
+
class SampleError(WarningError):
|
|
24
26
|
"""An exception which identifies an issue relating to the sample."""
|
|
25
27
|
|
|
26
28
|
def __str__(self):
|
|
@@ -36,7 +38,7 @@ class SampleException(WarningException):
|
|
|
36
38
|
T = TypeVar("T")
|
|
37
39
|
|
|
38
40
|
|
|
39
|
-
class
|
|
41
|
+
class CrystalNotFoundError(SampleError):
|
|
40
42
|
"""Raised if grid detection completed normally but no crystal was found."""
|
|
41
43
|
|
|
42
44
|
def __init__(self, *args):
|
|
@@ -49,7 +51,7 @@ def catch_exception_and_warn(
|
|
|
49
51
|
*args,
|
|
50
52
|
**kwargs,
|
|
51
53
|
) -> Generator[Msg, None, T]:
|
|
52
|
-
"""A plan wrapper to catch a specific exception and instead raise a
|
|
54
|
+
"""A plan wrapper to catch a specific exception and instead raise a WarningError,
|
|
53
55
|
so that UDC is not halted
|
|
54
56
|
|
|
55
57
|
Example usage:
|
|
@@ -58,12 +60,12 @@ def catch_exception_and_warn(
|
|
|
58
60
|
...
|
|
59
61
|
yield from catch_exception_and_warn(ExceptionA, plan_which_can_raise_exception_a, **args, **kwargs)'
|
|
60
62
|
|
|
61
|
-
This will catch ExceptionA raised by the plan and instead raise a
|
|
63
|
+
This will catch ExceptionA raised by the plan and instead raise a WarningError
|
|
62
64
|
"""
|
|
63
65
|
|
|
64
66
|
def warn_if_exception_matches(exception: Exception):
|
|
65
67
|
if isinstance(exception, exception_to_catch):
|
|
66
|
-
raise
|
|
68
|
+
raise SampleError(str(exception)) from exception
|
|
67
69
|
yield from null()
|
|
68
70
|
|
|
69
71
|
return (
|
mx_bluesky/common/utils/log.py
CHANGED
|
@@ -10,11 +10,11 @@ from dodal.log import (
|
|
|
10
10
|
integrate_bluesky_and_ophyd_logging,
|
|
11
11
|
set_up_all_logging_handlers,
|
|
12
12
|
)
|
|
13
|
-
from dodal.log import LOGGER as
|
|
13
|
+
from dodal.log import LOGGER as DODAL_LOGGER
|
|
14
14
|
|
|
15
15
|
LOGGER = logging.getLogger("MX-Bluesky")
|
|
16
16
|
LOGGER.setLevel("DEBUG")
|
|
17
|
-
LOGGER.parent =
|
|
17
|
+
LOGGER.parent = DODAL_LOGGER
|
|
18
18
|
|
|
19
19
|
ISPYB_ZOCALO_CALLBACK_LOGGER = logging.getLogger("ISPyB and Zocalo callbacks")
|
|
20
20
|
ISPYB_ZOCALO_CALLBACK_LOGGER.setLevel(logging.DEBUG)
|
|
@@ -68,7 +68,7 @@ def do_default_logging_setup(
|
|
|
68
68
|
and bluesky and ophyd-async are optionally included."""
|
|
69
69
|
logging_path, debug_logging_path = _get_logging_dirs(dev_mode)
|
|
70
70
|
handlers = set_up_all_logging_handlers(
|
|
71
|
-
|
|
71
|
+
DODAL_LOGGER,
|
|
72
72
|
logging_path,
|
|
73
73
|
file_name,
|
|
74
74
|
dev_mode,
|
|
@@ -78,7 +78,7 @@ def do_default_logging_setup(
|
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
if integrate_all_logs:
|
|
81
|
-
integrate_bluesky_and_ophyd_logging(
|
|
81
|
+
integrate_bluesky_and_ophyd_logging(DODAL_LOGGER)
|
|
82
82
|
|
|
83
83
|
handlers["graylog_handler"].addFilter(tag_filter)
|
|
84
84
|
|
|
@@ -11,18 +11,18 @@ from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
|
11
11
|
def setup_tracing(service_name: str = "Hyperion"):
|
|
12
12
|
resource = Resource(attributes={SERVICE_NAME: service_name})
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
trace_provider = TracerProvider(resource=resource)
|
|
15
15
|
processor = BatchSpanProcessor(
|
|
16
16
|
OTLPSpanExporter(endpoint="http://0.0.0.0:4318/v1/traces")
|
|
17
17
|
)
|
|
18
|
-
|
|
19
|
-
trace.set_tracer_provider(
|
|
18
|
+
trace_provider.add_span_processor(processor)
|
|
19
|
+
trace.set_tracer_provider(trace_provider)
|
|
20
20
|
|
|
21
21
|
reader = PeriodicExportingMetricReader(
|
|
22
22
|
OTLPMetricExporter(endpoint="http://0.0.0.0:4318/v1/metrics")
|
|
23
23
|
)
|
|
24
|
-
|
|
25
|
-
metrics.set_meter_provider(
|
|
24
|
+
meter_provider = MeterProvider(resource=resource, metric_readers=[reader])
|
|
25
|
+
metrics.set_meter_provider(meter_provider)
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
TRACER = trace.get_tracer(__name__)
|
mx_bluesky/common/utils/utils.py
CHANGED
|
@@ -4,23 +4,23 @@ from math import asin
|
|
|
4
4
|
from scanspec.core import AxesPoints, Axis
|
|
5
5
|
from scipy.constants import physical_constants
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
hc_in_ev_and_angstrom: float = (
|
|
8
8
|
physical_constants["speed of light in vacuum"][0]
|
|
9
9
|
* physical_constants["Planck constant in eV/Hz"][0]
|
|
10
10
|
* 1e10 # Angstroms per metre
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def
|
|
15
|
-
return
|
|
14
|
+
def interconvert_ev_angstrom(wavelength_or_energy: float) -> float:
|
|
15
|
+
return hc_in_ev_and_angstrom / wavelength_or_energy
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def
|
|
19
|
-
return
|
|
18
|
+
def convert_ev_to_angstrom(hv: float) -> float:
|
|
19
|
+
return interconvert_ev_angstrom(hv)
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def
|
|
23
|
-
return
|
|
22
|
+
def convert_angstrom_to_ev(wavelength: float) -> float:
|
|
23
|
+
return interconvert_ev_angstrom(wavelength)
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def number_of_frames_from_scan_spec(scan_points: AxesPoints[Axis]):
|
|
@@ -37,6 +37,6 @@ def energy_to_bragg_angle(energy_kev: float, d_a: float) -> float:
|
|
|
37
37
|
Returns:
|
|
38
38
|
The bragg angle in degrees
|
|
39
39
|
"""
|
|
40
|
-
wavelength_a =
|
|
40
|
+
wavelength_a = convert_ev_to_angstrom(energy_kev * 1000)
|
|
41
41
|
d = d_a
|
|
42
42
|
return asin(wavelength_a / (2 * d)) * 180 / math.pi
|
mx_bluesky/hyperion/__main__.py
CHANGED
|
@@ -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
|
-
|
|
25
|
+
PlanNotFoundError,
|
|
26
26
|
)
|
|
27
27
|
from mx_bluesky.hyperion.external_interaction.agamemnon import (
|
|
28
28
|
compare_params,
|
|
@@ -48,16 +48,16 @@ from mx_bluesky.hyperion.utils.context import setup_context
|
|
|
48
48
|
def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions):
|
|
49
49
|
experiment_registry_entry = PLAN_REGISTRY.get(plan_name)
|
|
50
50
|
if experiment_registry_entry is None:
|
|
51
|
-
raise
|
|
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
55
|
if experiment_internal_param_type is None:
|
|
56
|
-
raise
|
|
56
|
+
raise PlanNotFoundError(
|
|
57
57
|
f"Corresponding internal param type for '{plan_name}' not found in registry."
|
|
58
58
|
)
|
|
59
59
|
if plan is None:
|
|
60
|
-
raise
|
|
60
|
+
raise PlanNotFoundError(
|
|
61
61
|
f"Experiment plan '{plan_name}' not found in context. Context has {context.plan_functions.keys()}"
|
|
62
62
|
)
|
|
63
63
|
try:
|
|
@@ -115,7 +115,7 @@ class StopOrStatus(Resource):
|
|
|
115
115
|
status_and_message = StatusAndMessage(Status.FAILED, f"{action} not understood")
|
|
116
116
|
if action == Actions.STATUS.value:
|
|
117
117
|
LOGGER.debug(
|
|
118
|
-
f"Runner received status request - state of the runner object is: {self.runner.__dict__} - state of the
|
|
118
|
+
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
119
|
)
|
|
120
120
|
status_and_message = self.runner.current_status
|
|
121
121
|
return asdict(status_and_message)
|
|
@@ -9,6 +9,7 @@ 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
|
|
@@ -38,7 +39,7 @@ from mx_bluesky.hyperion.external_interaction.agamemnon import (
|
|
|
38
39
|
from mx_bluesky.hyperion.external_interaction.alerting.constants import Subjects
|
|
39
40
|
from mx_bluesky.hyperion.parameters.components import Wait
|
|
40
41
|
from mx_bluesky.hyperion.parameters.load_centre_collect import LoadCentreCollect
|
|
41
|
-
from mx_bluesky.hyperion.plan_runner import
|
|
42
|
+
from mx_bluesky.hyperion.plan_runner import PlanError, PlanRunner
|
|
42
43
|
from mx_bluesky.hyperion.utils.context import (
|
|
43
44
|
clear_all_device_caches,
|
|
44
45
|
setup_devices,
|
|
@@ -53,7 +54,7 @@ def run_forever(runner: PlanRunner):
|
|
|
53
54
|
while True:
|
|
54
55
|
try:
|
|
55
56
|
run_udc_when_requested(runner.context, runner)
|
|
56
|
-
except
|
|
57
|
+
except PlanError as e:
|
|
57
58
|
LOGGER.info(
|
|
58
59
|
"Caught exception during plan execution, stopped and waiting for baton.",
|
|
59
60
|
exc_info=e,
|
|
@@ -64,7 +65,7 @@ def run_forever(runner: PlanRunner):
|
|
|
64
65
|
# RunEngine.abort() will have been called and we will get RunEngineInterrupted
|
|
65
66
|
LOGGER.info(
|
|
66
67
|
f"RunEngine was interrupted. Runner state is {runner.current_status}, "
|
|
67
|
-
f"run engine is {runner.
|
|
68
|
+
f"run engine is {runner.run_engine.state}"
|
|
68
69
|
)
|
|
69
70
|
|
|
70
71
|
|
|
@@ -93,7 +94,7 @@ def run_udc_when_requested(context: BlueskyContext, runner: PlanRunner):
|
|
|
93
94
|
* A user requests the baton away from Hyperion
|
|
94
95
|
* Hyperion releases the baton when Agamemnon has no more instructions
|
|
95
96
|
* The RunEngine raises a RequestAbort exception, most likely due to a shutdown command
|
|
96
|
-
* A plan raises an exception not of type
|
|
97
|
+
* A plan raises an exception not of type WarningError (which is then wrapped as a PlanError)
|
|
97
98
|
Args:
|
|
98
99
|
baton: The baton device
|
|
99
100
|
runner: The runner
|
|
@@ -109,7 +110,7 @@ def run_udc_when_requested(context: BlueskyContext, runner: PlanRunner):
|
|
|
109
110
|
baton, runner, current_visit
|
|
110
111
|
)
|
|
111
112
|
if current_visit:
|
|
112
|
-
yield from
|
|
113
|
+
yield from _clean_up_udc(runner.context, current_visit)
|
|
113
114
|
|
|
114
115
|
def release_baton() -> MsgGenerator:
|
|
115
116
|
# If hyperion has given up the baton itself we need to also release requested
|
|
@@ -145,13 +146,13 @@ def _initialise_udc(context: BlueskyContext, dev_mode: bool):
|
|
|
145
146
|
|
|
146
147
|
def _wait_for_hyperion_requested(baton: Baton):
|
|
147
148
|
LOGGER.debug("Hyperion waiting for baton...")
|
|
148
|
-
|
|
149
|
+
sleep_per_check = 0.1
|
|
149
150
|
while True:
|
|
150
151
|
requested_user = yield from bps.rd(baton.requested_user)
|
|
151
152
|
if requested_user == HYPERION_USER:
|
|
152
153
|
LOGGER.debug("Baton requested for Hyperion")
|
|
153
154
|
break
|
|
154
|
-
yield from bps.sleep(
|
|
155
|
+
yield from bps.sleep(sleep_per_check)
|
|
155
156
|
|
|
156
157
|
|
|
157
158
|
def _fetch_and_process_agamemnon_instruction(
|
|
@@ -239,11 +240,17 @@ def _unrequest_baton(baton: Baton) -> MsgGenerator[str]:
|
|
|
239
240
|
return requested_user
|
|
240
241
|
|
|
241
242
|
|
|
242
|
-
def
|
|
243
|
+
def _clean_up_udc(context: BlueskyContext, visit: str) -> MsgGenerator:
|
|
244
|
+
cleanup_group = "cleanup"
|
|
243
245
|
robot = find_device_in_context(context, "robot", BartRobot)
|
|
244
246
|
smargon = find_device_in_context(context, "smargon", Smargon)
|
|
245
247
|
aperture_scatterguard = find_device_in_context(
|
|
246
248
|
context, "aperture_scatterguard", ApertureScatterguard
|
|
247
249
|
)
|
|
248
250
|
lower_gonio = find_device_in_context(context, "lower_gonio", XYZStage)
|
|
251
|
+
detector_motion = find_device_in_context(context, "detector_motion", DetectorMotion)
|
|
252
|
+
yield from bps.abs_set(
|
|
253
|
+
detector_motion.shutter, ShutterState.CLOSED, group=cleanup_group
|
|
254
|
+
)
|
|
249
255
|
yield from robot_unload(robot, smargon, aperture_scatterguard, lower_gonio, visit)
|
|
256
|
+
yield from bps.wait(cleanup_group)
|