mx-bluesky 1.2.0__py3-none-any.whl → 1.4.1a0__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/__init__.py +8 -3
- mx_bluesky/__main__.py +12 -7
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/i04/callbacks/murko_callback.py +14 -4
- mx_bluesky/beamlines/i04/thawing_plan.py +49 -11
- mx_bluesky/beamlines/i24/serial/__init__.py +3 -0
- mx_bluesky/beamlines/i24/serial/dcid.py +19 -21
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +69 -91
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +2 -5
- mx_bluesky/beamlines/i24/serial/fixed_target/ft_utils.py +0 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +111 -143
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +141 -222
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +7 -216
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +18 -17
- mx_bluesky/beamlines/i24/serial/log.py +58 -49
- mx_bluesky/beamlines/i24/serial/parameters/constants.py +0 -1
- mx_bluesky/beamlines/i24/serial/parameters/fixed_target/cs/cs_maker.json +3 -3
- mx_bluesky/beamlines/i24/serial/run_extruder.sh +30 -5
- mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +30 -5
- mx_bluesky/beamlines/i24/serial/run_serial.py +24 -8
- mx_bluesky/beamlines/i24/serial/setup_beamline/ca.py +0 -2
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +79 -81
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +9 -20
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +26 -28
- mx_bluesky/beamlines/i24/serial/write_nexus.py +11 -11
- mx_bluesky/common/__init__.py +0 -0
- mx_bluesky/common/device_setup_plans/read_hardware_for_setup.py +14 -0
- mx_bluesky/common/external_interaction/config_server.py +46 -0
- mx_bluesky/common/parameters/components.py +258 -0
- mx_bluesky/common/parameters/constants.py +138 -0
- mx_bluesky/common/parameters/gridscan.py +94 -0
- mx_bluesky/common/parameters/robot_load.py +16 -0
- mx_bluesky/common/plans/__init__.py +1 -0
- mx_bluesky/common/plans/do_fgs.py +121 -0
- mx_bluesky/common/utils/log.py +118 -0
- mx_bluesky/{hyperion → common/utils}/tracing.py +2 -2
- mx_bluesky/hyperion/__main__.py +13 -10
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +31 -26
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +6 -12
- mx_bluesky/hyperion/device_setup_plans/setup_oav.py +6 -12
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +5 -6
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +49 -18
- mx_bluesky/hyperion/device_setup_plans/smargon.py +6 -6
- mx_bluesky/hyperion/device_setup_plans/utils.py +2 -2
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +4 -4
- mx_bluesky/hyperion/experiment_plans/__init__.py +4 -0
- mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +83 -0
- mx_bluesky/hyperion/experiment_plans/common/xrc_result.py +47 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -9
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +145 -161
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +56 -22
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +52 -10
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +21 -20
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +11 -14
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +2 -2
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +40 -21
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +19 -19
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +21 -21
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +51 -13
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +24 -7
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +5 -6
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -2
- mx_bluesky/hyperion/external_interaction/callbacks/common/abstract_event.py +66 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +30 -25
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +29 -12
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +7 -4
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +5 -3
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +28 -20
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +5 -4
- mx_bluesky/hyperion/external_interaction/config_server.py +11 -28
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +1 -1
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +1 -1
- mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +2 -2
- mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +1 -1
- mx_bluesky/hyperion/log.py +0 -84
- mx_bluesky/hyperion/parameters/components.py +4 -251
- mx_bluesky/hyperion/parameters/constants.py +22 -119
- mx_bluesky/hyperion/parameters/gridscan.py +35 -74
- mx_bluesky/hyperion/parameters/load_centre_collect.py +16 -11
- mx_bluesky/hyperion/parameters/rotation.py +23 -10
- mx_bluesky/hyperion/utils/utils.py +17 -0
- mx_bluesky/hyperion/utils/validation.py +5 -6
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/METADATA +36 -33
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/RECORD +91 -81
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/WHEEL +1 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +0 -161
- mx_bluesky/example.py +0 -19
- mx_bluesky/hyperion/parameters/robot_load.py +0 -16
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.2.0.dist-info → mx_bluesky-1.4.1a0.dist-info}/top_level.txt +0 -0
|
@@ -5,10 +5,16 @@ from time import time
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
|
-
from blueapi.core import MsgGenerator
|
|
9
8
|
from bluesky import preprocessors as bpp
|
|
10
|
-
from
|
|
9
|
+
from bluesky.utils import MsgGenerator
|
|
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
|
|
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") ==
|
|
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")
|
|
@@ -93,7 +98,9 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
93
98
|
"ISPyB callback received start document with experiment parameters and "
|
|
94
99
|
f"uid: {self.uid_to_finalize_on}"
|
|
95
100
|
)
|
|
96
|
-
|
|
101
|
+
hyperion_params = doc.get("hyperion_parameters")
|
|
102
|
+
assert isinstance(hyperion_params, str)
|
|
103
|
+
self.params = GridCommon.model_validate_json(hyperion_params)
|
|
97
104
|
self.ispyb = StoreInIspyb(self.ispyb_config)
|
|
98
105
|
data_collection_group_info = populate_data_collection_group(self.params)
|
|
99
106
|
|
|
@@ -147,7 +154,8 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
147
154
|
ISPYB_LOGGER.info(
|
|
148
155
|
f"Amending comment based on Zocalo reading doc: {format_doc_for_log(doc)}"
|
|
149
156
|
)
|
|
150
|
-
|
|
157
|
+
|
|
158
|
+
raw_results = get_processing_results_from_event("zocalo", doc)
|
|
151
159
|
if len(raw_results) > 0:
|
|
152
160
|
for n, res in enumerate(raw_results):
|
|
153
161
|
bb = res["bounding_box"]
|
|
@@ -178,25 +186,25 @@ class GridscanISPyBCallback(BaseISPyBCallback):
|
|
|
178
186
|
data = doc["data"]
|
|
179
187
|
data_collection_id = None
|
|
180
188
|
data_collection_info = DataCollectionInfo(
|
|
181
|
-
xtal_snapshot1=data.get("
|
|
182
|
-
xtal_snapshot2=data.get("
|
|
183
|
-
xtal_snapshot3=data.get("
|
|
189
|
+
xtal_snapshot1=data.get("oav-grid_snapshot-last_path_full_overlay"),
|
|
190
|
+
xtal_snapshot2=data.get("oav-grid_snapshot-last_path_outer"),
|
|
191
|
+
xtal_snapshot3=data.get("oav-grid_snapshot-last_saved_path"),
|
|
184
192
|
n_images=(
|
|
185
|
-
data["
|
|
186
|
-
* data["
|
|
193
|
+
data["oav-grid_snapshot-num_boxes_x"]
|
|
194
|
+
* data["oav-grid_snapshot-num_boxes_y"]
|
|
187
195
|
),
|
|
188
196
|
)
|
|
189
|
-
microns_per_pixel_x = data["
|
|
190
|
-
microns_per_pixel_y = data["
|
|
197
|
+
microns_per_pixel_x = data["oav-microns_per_pixel_x"]
|
|
198
|
+
microns_per_pixel_y = data["oav-microns_per_pixel_y"]
|
|
191
199
|
data_collection_grid_info = DataCollectionGridInfo(
|
|
192
|
-
dx_in_mm=data["
|
|
193
|
-
dy_in_mm=data["
|
|
194
|
-
steps_x=data["
|
|
195
|
-
steps_y=data["
|
|
200
|
+
dx_in_mm=data["oav-grid_snapshot-box_width"] * microns_per_pixel_x / 1000,
|
|
201
|
+
dy_in_mm=data["oav-grid_snapshot-box_width"] * microns_per_pixel_y / 1000,
|
|
202
|
+
steps_x=data["oav-grid_snapshot-num_boxes_x"],
|
|
203
|
+
steps_y=data["oav-grid_snapshot-num_boxes_y"],
|
|
196
204
|
microns_per_pixel_x=microns_per_pixel_x,
|
|
197
205
|
microns_per_pixel_y=microns_per_pixel_y,
|
|
198
|
-
snapshot_offset_x_pixel=int(data["
|
|
199
|
-
snapshot_offset_y_pixel=int(data["
|
|
206
|
+
snapshot_offset_x_pixel=int(data["oav-grid_snapshot-top_left_x"]),
|
|
207
|
+
snapshot_offset_y_pixel=int(data["oav-grid_snapshot-top_left_y"]),
|
|
200
208
|
orientation=Orientation.HORIZONTAL,
|
|
201
209
|
snaked=True,
|
|
202
210
|
)
|
|
@@ -12,7 +12,7 @@ from mx_bluesky.hyperion.external_interaction.nexus.nexus_utils import (
|
|
|
12
12
|
from mx_bluesky.hyperion.external_interaction.nexus.write_nexus import NexusWriter
|
|
13
13
|
from mx_bluesky.hyperion.log import NEXUS_LOGGER
|
|
14
14
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
15
|
-
from mx_bluesky.hyperion.parameters.gridscan import
|
|
15
|
+
from mx_bluesky.hyperion.parameters.gridscan import HyperionThreeDGridScan
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
18
|
from event_model.documents import Event, EventDescriptor, RunStart
|
|
@@ -45,11 +45,12 @@ class GridscanNexusFileCallback(PlanReactiveCallback):
|
|
|
45
45
|
|
|
46
46
|
def activity_gated_start(self, doc: RunStart):
|
|
47
47
|
if doc.get("subplan_name") == CONST.PLAN.GRIDSCAN_OUTER:
|
|
48
|
-
|
|
48
|
+
hyperion_params = doc.get("hyperion_parameters")
|
|
49
|
+
assert isinstance(hyperion_params, str)
|
|
49
50
|
NEXUS_LOGGER.info(
|
|
50
|
-
f"Nexus writer received start document with experiment parameters {
|
|
51
|
+
f"Nexus writer received start document with experiment parameters {hyperion_params}"
|
|
51
52
|
)
|
|
52
|
-
parameters =
|
|
53
|
+
parameters = HyperionThreeDGridScan.model_validate_json(hyperion_params)
|
|
53
54
|
d_size = parameters.detector_params.detector_size_constants.det_size_pixels
|
|
54
55
|
grid_n_img_1 = parameters.scan_indices[1]
|
|
55
56
|
grid_n_img_2 = parameters.num_images - grid_n_img_1
|
|
@@ -1,35 +1,18 @@
|
|
|
1
|
+
from functools import cache
|
|
2
|
+
|
|
1
3
|
from daq_config_server.client import ConfigServer
|
|
2
|
-
from pydantic import BaseModel
|
|
3
4
|
|
|
5
|
+
from mx_bluesky.common.external_interaction.config_server import FeatureFlags
|
|
4
6
|
from mx_bluesky.hyperion.log import LOGGER
|
|
5
7
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
6
8
|
|
|
7
|
-
_CONFIG_SERVER: ConfigServer | None = None
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def config_server() -> ConfigServer:
|
|
11
|
-
global _CONFIG_SERVER
|
|
12
|
-
if _CONFIG_SERVER is None:
|
|
13
|
-
_CONFIG_SERVER = ConfigServer(CONST.CONFIG_SERVER_URL, LOGGER)
|
|
14
|
-
return _CONFIG_SERVER
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class FeatureFlags(BaseModel):
|
|
18
|
-
# The default value will be used as the fallback when doing a best-effort fetch
|
|
19
|
-
# from the service
|
|
20
|
-
use_panda_for_gridscan: bool = False
|
|
21
|
-
use_gpu_for_gridscan: bool = False
|
|
22
|
-
set_stub_offsets: bool = False
|
|
23
|
-
|
|
24
|
-
@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()}
|
|
28
9
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
10
|
+
class HyperionFeatureFlags(FeatureFlags):
|
|
11
|
+
@staticmethod
|
|
12
|
+
@cache
|
|
13
|
+
def get_config_server() -> ConfigServer:
|
|
14
|
+
return ConfigServer(CONST.CONFIG_SERVER_URL, LOGGER)
|
|
32
15
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
16
|
+
use_panda_for_gridscan: bool = CONST.I03.USE_PANDA_FOR_GRIDSCAN
|
|
17
|
+
compare_cpu_and_gpu_zocalo: bool = CONST.I03.COMPARE_CPU_AND_GPU_ZOCALO
|
|
18
|
+
set_stub_offsets: bool = CONST.I03.SET_STUB_OFFSETS
|
|
@@ -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.
|
|
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:
|
mx_bluesky/hyperion/log.py
CHANGED
|
@@ -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
|
|
@@ -1,254 +1,7 @@
|
|
|
1
|
-
from
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
from abc import abstractmethod
|
|
5
|
-
from collections.abc import Sequence
|
|
6
|
-
from enum import StrEnum
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import SupportsInt, TypeVar
|
|
3
|
+
from mx_bluesky.hyperion.external_interaction.config_server import HyperionFeatureFlags
|
|
9
4
|
|
|
10
|
-
from dodal.devices.aperturescatterguard import ApertureValue
|
|
11
|
-
from dodal.devices.detector import (
|
|
12
|
-
DetectorParams,
|
|
13
|
-
TriggerMode,
|
|
14
|
-
)
|
|
15
|
-
from pydantic import (
|
|
16
|
-
BaseModel,
|
|
17
|
-
ConfigDict,
|
|
18
|
-
Field,
|
|
19
|
-
field_serializer,
|
|
20
|
-
field_validator,
|
|
21
|
-
model_validator,
|
|
22
|
-
)
|
|
23
|
-
from scanspec.core import AxesPoints
|
|
24
|
-
from semver import Version
|
|
25
5
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
T = TypeVar("T")
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class ParameterVersion(Version):
|
|
33
|
-
@classmethod
|
|
34
|
-
def _parse(cls, version):
|
|
35
|
-
if isinstance(version, cls):
|
|
36
|
-
return version
|
|
37
|
-
return cls.parse(version)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
PARAMETER_VERSION = ParameterVersion.parse("5.1.0")
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class RotationAxis(StrEnum):
|
|
44
|
-
OMEGA = "omega"
|
|
45
|
-
PHI = "phi"
|
|
46
|
-
CHI = "chi"
|
|
47
|
-
KAPPA = "kappa"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
class XyzAxis(StrEnum):
|
|
51
|
-
X = "sam_x"
|
|
52
|
-
Y = "sam_y"
|
|
53
|
-
Z = "sam_z"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class IspybExperimentType(StrEnum):
|
|
57
|
-
# Enum values from ispyb column data type
|
|
58
|
-
SAD = "SAD" # at or slightly above the peak
|
|
59
|
-
SAD_INVERSE_BEAM = "SAD - Inverse Beam"
|
|
60
|
-
OSC = "OSC" # "native" (in the absence of a heavy atom)
|
|
61
|
-
COLLECT_MULTIWEDGE = (
|
|
62
|
-
"Collect - Multiwedge" # "poorly determined" ~ EDNA complex strategy???
|
|
63
|
-
)
|
|
64
|
-
MAD = "MAD"
|
|
65
|
-
HELICAL = "Helical"
|
|
66
|
-
MULTI_POSITIONAL = "Multi-positional"
|
|
67
|
-
MESH = "Mesh"
|
|
68
|
-
BURN = "Burn"
|
|
69
|
-
MAD_INVERSE_BEAM = "MAD - Inverse Beam"
|
|
70
|
-
CHARACTERIZATION = "Characterization"
|
|
71
|
-
DEHYDRATION = "Dehydration"
|
|
72
|
-
TOMO = "tomo"
|
|
73
|
-
EXPERIMENT = "experiment"
|
|
74
|
-
EM = "EM"
|
|
75
|
-
PDF = "PDF"
|
|
76
|
-
PDF_BRAGG = "PDF+Bragg"
|
|
77
|
-
BRAGG = "Bragg"
|
|
78
|
-
SINGLE_PARTICLE = "single particle"
|
|
79
|
-
SERIAL_FIXED = "Serial Fixed"
|
|
80
|
-
SERIAL_JET = "Serial Jet"
|
|
81
|
-
STANDARD = "Standard" # Routine structure determination experiment
|
|
82
|
-
TIME_RESOLVED = "Time Resolved" # Investigate the change of a system over time
|
|
83
|
-
DLS_ANVIL_HP = "Diamond Anvil High Pressure" # HP sample environment pressure cell
|
|
84
|
-
CUSTOM = "Custom" # Special or non-standard data collection
|
|
85
|
-
XRF_MAP = "XRF map"
|
|
86
|
-
ENERGY_SCAN = "Energy scan"
|
|
87
|
-
XRF_SPECTRUM = "XRF spectrum"
|
|
88
|
-
XRF_MAP_XAS = "XRF map xas"
|
|
89
|
-
MESH_3D = "Mesh3D"
|
|
90
|
-
SCREENING = "Screening"
|
|
91
|
-
STILL = "Still"
|
|
92
|
-
SSX_CHIP = "SSX-Chip"
|
|
93
|
-
SSX_JET = "SSX-Jet"
|
|
94
|
-
|
|
95
|
-
# Aliases for historic hyperion experiment type mapping
|
|
96
|
-
ROTATION = "SAD"
|
|
97
|
-
GRIDSCAN_2D = "mesh"
|
|
98
|
-
GRIDSCAN_3D = "Mesh3D"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class HyperionParameters(BaseModel):
|
|
102
|
-
model_config = ConfigDict(
|
|
103
|
-
arbitrary_types_allowed=True,
|
|
104
|
-
extra="allow",
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
def __hash__(self) -> int:
|
|
108
|
-
return self.json().__hash__()
|
|
109
|
-
|
|
110
|
-
features: FeatureFlags = Field(default=FeatureFlags())
|
|
111
|
-
parameter_model_version: ParameterVersion
|
|
112
|
-
|
|
113
|
-
@field_serializer("parameter_model_version")
|
|
114
|
-
def serialize_parameter_version(self, version: ParameterVersion):
|
|
115
|
-
return str(version)
|
|
116
|
-
|
|
117
|
-
@field_validator("parameter_model_version", mode="before")
|
|
118
|
-
@classmethod
|
|
119
|
-
def _validate_version(cls, version_str: str):
|
|
120
|
-
version = ParameterVersion.parse(version_str)
|
|
121
|
-
assert (
|
|
122
|
-
version >= ParameterVersion(major=PARAMETER_VERSION.major)
|
|
123
|
-
), f"Parameter version too old! This version of hyperion uses {PARAMETER_VERSION}"
|
|
124
|
-
assert (
|
|
125
|
-
version <= ParameterVersion(major=PARAMETER_VERSION.major + 1)
|
|
126
|
-
), f"Parameter version too new! This version of hyperion uses {PARAMETER_VERSION}"
|
|
127
|
-
return version
|
|
128
|
-
|
|
129
|
-
@classmethod
|
|
130
|
-
def from_json(cls, input: str | None):
|
|
131
|
-
assert input is not None
|
|
132
|
-
return cls(**json.loads(input))
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
class WithSnapshot(BaseModel):
|
|
136
|
-
snapshot_directory: Path
|
|
137
|
-
snapshot_omegas_deg: list[float] | None = None
|
|
138
|
-
|
|
139
|
-
@property
|
|
140
|
-
def take_snapshots(self) -> bool:
|
|
141
|
-
return bool(self.snapshot_omegas_deg)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
class WithOptionalEnergyChange(BaseModel):
|
|
145
|
-
demand_energy_ev: float | None = Field(default=None, gt=0)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
class WithVisit(BaseModel):
|
|
149
|
-
visit: str = Field(min_length=1)
|
|
150
|
-
zocalo_environment: str = Field(default=CONST.ZOCALO_ENV)
|
|
151
|
-
beamline: str = Field(default=CONST.I03.BEAMLINE, pattern=r"BL\d{2}[BIJS]")
|
|
152
|
-
det_dist_to_beam_converter_path: str = Field(
|
|
153
|
-
default=CONST.PARAM.DETECTOR.BEAM_XY_LUT_PATH
|
|
154
|
-
)
|
|
155
|
-
insertion_prefix: str = Field(
|
|
156
|
-
default=CONST.I03.INSERTION_PREFIX, pattern=r"SR\d{2}[BIJS]"
|
|
157
|
-
)
|
|
158
|
-
detector_distance_mm: float | None = Field(default=None, gt=0)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
class DiffractionExperiment(
|
|
162
|
-
HyperionParameters, WithSnapshot, WithOptionalEnergyChange, WithVisit
|
|
163
|
-
):
|
|
164
|
-
"""For all experiments which use beam"""
|
|
165
|
-
|
|
166
|
-
file_name: str
|
|
167
|
-
exposure_time_s: float = Field(gt=0)
|
|
168
|
-
comment: str = Field(default="")
|
|
169
|
-
trigger_mode: TriggerMode = Field(default=TriggerMode.FREE_RUN)
|
|
170
|
-
run_number: int | None = Field(default=None, ge=0)
|
|
171
|
-
selected_aperture: ApertureValue | None = Field(default=None)
|
|
172
|
-
transmission_frac: float = Field(default=0.1)
|
|
173
|
-
ispyb_experiment_type: IspybExperimentType
|
|
174
|
-
storage_directory: str
|
|
175
|
-
|
|
176
|
-
@model_validator(mode="before")
|
|
177
|
-
@classmethod
|
|
178
|
-
def validate_snapshot_directory(cls, values):
|
|
179
|
-
snapshot_dir = values.get(
|
|
180
|
-
"snapshot_directory", Path(values["storage_directory"], "snapshots")
|
|
181
|
-
)
|
|
182
|
-
values["snapshot_directory"] = (
|
|
183
|
-
snapshot_dir if isinstance(snapshot_dir, Path) else Path(snapshot_dir)
|
|
184
|
-
)
|
|
185
|
-
return values
|
|
186
|
-
|
|
187
|
-
@property
|
|
188
|
-
def num_images(self) -> int:
|
|
189
|
-
return 0
|
|
190
|
-
|
|
191
|
-
@property
|
|
192
|
-
@abstractmethod
|
|
193
|
-
def detector_params(self) -> DetectorParams: ...
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
class WithScan(BaseModel):
|
|
197
|
-
"""For experiments where the scan is known"""
|
|
198
|
-
|
|
199
|
-
@property
|
|
200
|
-
@abstractmethod
|
|
201
|
-
def scan_points(self) -> AxesPoints: ...
|
|
202
|
-
|
|
203
|
-
@property
|
|
204
|
-
@abstractmethod
|
|
205
|
-
def num_images(self) -> int: ...
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
class SplitScan(BaseModel):
|
|
209
|
-
@property
|
|
210
|
-
@abstractmethod
|
|
211
|
-
def scan_indices(self) -> Sequence[SupportsInt]:
|
|
212
|
-
"""Should return the first index of each scan (i.e. for each nexus file)"""
|
|
213
|
-
...
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
class WithSample(BaseModel):
|
|
217
|
-
sample_id: int
|
|
218
|
-
sample_puck: int | None = None
|
|
219
|
-
sample_pin: int | None = None
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
class DiffractionExperimentWithSample(DiffractionExperiment, WithSample): ...
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
class WithOavCentring(BaseModel):
|
|
226
|
-
oav_centring_file: str = Field(default=CONST.I03.OAV_CENTRING_FILE)
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
class OptionalXyzStarts(BaseModel):
|
|
230
|
-
x_start_um: float | None = None
|
|
231
|
-
y_start_um: float | None = None
|
|
232
|
-
z_start_um: float | None = None
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
class XyzStarts(BaseModel):
|
|
236
|
-
x_start_um: float
|
|
237
|
-
y_start_um: float
|
|
238
|
-
z_start_um: float
|
|
239
|
-
|
|
240
|
-
def _start_for_axis(self, axis: XyzAxis) -> float:
|
|
241
|
-
match axis:
|
|
242
|
-
case XyzAxis.X:
|
|
243
|
-
return self.x_start_um
|
|
244
|
-
case XyzAxis.Y:
|
|
245
|
-
return self.y_start_um
|
|
246
|
-
case XyzAxis.Z:
|
|
247
|
-
return self.z_start_um
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
class OptionalGonioAngleStarts(BaseModel):
|
|
251
|
-
omega_start_deg: float | None = None
|
|
252
|
-
phi_start_deg: float | None = None
|
|
253
|
-
chi_start_deg: float | None = None
|
|
254
|
-
kappa_start_deg: float | None = None
|
|
6
|
+
class WithHyperionFeatures(BaseModel):
|
|
7
|
+
features: HyperionFeatureFlags = Field(default=HyperionFeatureFlags())
|