mx-bluesky 0.3.1__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mx_bluesky/_version.py +2 -2
- mx_bluesky/beamlines/i04/__init__.py +3 -0
- mx_bluesky/{i04 → beamlines/i04}/thawing_plan.py +5 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/blueapi_config.yaml +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/dcid.py +2 -2
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/DetStage.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +7 -7
- mx_bluesky/{i24 → beamlines/i24}/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +12 -9
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/CustomChip_py3v1.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/DetStage.edl +3 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +245 -200
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/MappingLite-oxford_py3v1.edl +4 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +8 -8
- mx_bluesky/beamlines/i24/serial/fixed_target/__init__.py +0 -0
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +80 -70
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +20 -21
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +5 -5
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +7 -4
- mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/i24ssx_moveonclick.py +59 -39
- mx_bluesky/{i24 → beamlines/i24}/serial/log.py +1 -9
- mx_bluesky/beamlines/i24/serial/parameters/__init__.py +15 -0
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/constants.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/experiment_parameters.py +4 -25
- mx_bluesky/{i24 → beamlines/i24}/serial/parameters/utils.py +5 -3
- mx_bluesky/{i24 → beamlines/i24}/serial/run_serial.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/pv_abstract.py +1 -1
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_beamline.py +2 -2
- mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_detector.py +5 -5
- mx_bluesky/{i24 → beamlines/i24}/serial/write_nexus.py +6 -3
- mx_bluesky/hyperion/__init__.py +1 -0
- mx_bluesky/hyperion/__main__.py +374 -0
- mx_bluesky/hyperion/device_setup_plans/__init__.py +0 -0
- mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +134 -0
- mx_bluesky/hyperion/device_setup_plans/manipulate_sample.py +110 -0
- mx_bluesky/hyperion/device_setup_plans/position_detector.py +16 -0
- mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +60 -0
- mx_bluesky/hyperion/device_setup_plans/setup_oav.py +87 -0
- mx_bluesky/hyperion/device_setup_plans/setup_panda.py +210 -0
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +214 -0
- mx_bluesky/hyperion/device_setup_plans/smargon.py +25 -0
- mx_bluesky/hyperion/device_setup_plans/utils.py +55 -0
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +93 -0
- mx_bluesky/hyperion/exceptions.py +47 -0
- mx_bluesky/hyperion/experiment_plans/__init__.py +30 -0
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +93 -0
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +537 -0
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +209 -0
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +46 -0
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +173 -0
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +81 -0
- mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +463 -0
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +119 -0
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +164 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +237 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +162 -0
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +436 -0
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +60 -0
- mx_bluesky/hyperion/external_interaction/__init__.py +9 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__init__.py +10 -0
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +148 -0
- mx_bluesky/hyperion/external_interaction/callbacks/aperture_change_callback.py +22 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +64 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +62 -0
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +88 -0
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +203 -0
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +20 -0
- mx_bluesky/hyperion/external_interaction/callbacks/logging_callback.py +29 -0
- mx_bluesky/hyperion/external_interaction/callbacks/plan_reactive_callback.py +101 -0
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +86 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +174 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +17 -0
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +102 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +269 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_mapping.py +53 -0
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/nexus_callback.py +95 -0
- mx_bluesky/hyperion/external_interaction/callbacks/zocalo_callback.py +92 -0
- mx_bluesky/hyperion/external_interaction/config_server.py +35 -0
- mx_bluesky/hyperion/external_interaction/exceptions.py +13 -0
- mx_bluesky/hyperion/external_interaction/ispyb/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/ispyb/data_model.py +95 -0
- mx_bluesky/hyperion/external_interaction/ispyb/exp_eye_store.py +125 -0
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +276 -0
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_utils.py +27 -0
- mx_bluesky/hyperion/external_interaction/nexus/__init__.py +0 -0
- mx_bluesky/hyperion/external_interaction/nexus/nexus_utils.py +148 -0
- mx_bluesky/hyperion/external_interaction/nexus/write_nexus.py +114 -0
- mx_bluesky/hyperion/log.py +99 -0
- mx_bluesky/hyperion/parameters/__init__.py +2 -0
- mx_bluesky/hyperion/parameters/cli.py +68 -0
- mx_bluesky/{parameters → hyperion/parameters}/components.py +80 -26
- mx_bluesky/hyperion/parameters/constants.py +158 -0
- mx_bluesky/hyperion/parameters/gridscan.py +221 -0
- mx_bluesky/hyperion/parameters/load_centre_collect.py +50 -0
- mx_bluesky/hyperion/parameters/robot_load.py +16 -0
- mx_bluesky/hyperion/parameters/rotation.py +160 -0
- mx_bluesky/hyperion/resources/panda/panda-gridscan.yaml +964 -0
- mx_bluesky/hyperion/tracing.py +28 -0
- mx_bluesky/hyperion/utils/context.py +84 -0
- mx_bluesky/hyperion/utils/utils.py +25 -0
- mx_bluesky/hyperion/utils/validation.py +196 -0
- mx_bluesky/jupyter_example.ipynb +3 -2
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.2.0.dist-info}/METADATA +26 -11
- mx_bluesky-1.2.0.dist-info/RECORD +140 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.2.0.dist-info}/WHEEL +1 -1
- mx_bluesky-1.2.0.dist-info/entry_points.txt +8 -0
- mx_bluesky/i04/__init__.py +0 -3
- mx_bluesky/i24/serial/parameters/__init__.py +0 -15
- mx_bluesky/parameters/__init__.py +0 -31
- mx_bluesky-0.3.1.dist-info/RECORD +0 -67
- mx_bluesky-0.3.1.dist-info/entry_points.txt +0 -4
- /mx_bluesky/{i24 → beamlines}/__init__.py +0 -0
- /mx_bluesky/{i04 → beamlines/i04}/callbacks/murko_callback.py +0 -0
- /mx_bluesky/{i24/serial/extruder → beamlines/i24}/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/extruder/EX-gui-edm/microdrop_alignment.edl +0 -0
- /mx_bluesky/{i24/serial/fixed_target → beamlines/i24/serial/extruder}/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/ME14E-GeneralPurpose.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/PMAC_Command.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/Shutter_Control.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/microdrop_alignment.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/nudgechip.edl +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/short1-laser.png +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/FT-gui-edm/short2-laser.png +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/fixed_target/ft_utils.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/cs/cs_maker.json +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/cs/motor_direction.txt +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/pvar_files/minichip-oxford.pvar +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/parameters/fixed_target/pvar_files/oxford.pvar +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_extruder.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_fixed_target.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/run_ssx.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/set_visit_directory.sh +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/__init__.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/ca.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/pv.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/setup_beamline/setup_zebra_plans.py +0 -0
- /mx_bluesky/{i24 → beamlines/i24}/serial/start_blueapi.sh +0 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.2.0.dist-info}/LICENSE +0 -0
- {mx_bluesky-0.3.1.dist-info → mx_bluesky-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from dataclasses import asdict
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import ispyb
|
|
8
|
+
import ispyb.sqlalchemy
|
|
9
|
+
from ispyb.connector.mysqlsp.main import ISPyBMySQLSPConnector as Connector
|
|
10
|
+
from ispyb.sp.mxacquisition import MXAcquisition
|
|
11
|
+
from ispyb.strictordereddict import StrictOrderedDict
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
from mx_bluesky.hyperion.external_interaction.ispyb.data_model import (
|
|
15
|
+
DataCollectionGridInfo,
|
|
16
|
+
DataCollectionGroupInfo,
|
|
17
|
+
DataCollectionInfo,
|
|
18
|
+
ScanDataInfo,
|
|
19
|
+
)
|
|
20
|
+
from mx_bluesky.hyperion.external_interaction.ispyb.ispyb_utils import (
|
|
21
|
+
get_current_time_string,
|
|
22
|
+
get_session_id_from_visit,
|
|
23
|
+
)
|
|
24
|
+
from mx_bluesky.hyperion.log import ISPYB_LOGGER
|
|
25
|
+
from mx_bluesky.hyperion.tracing import TRACER
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
I03_EIGER_DETECTOR = 78
|
|
31
|
+
EIGER_FILE_SUFFIX = "h5"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class IspybIds(BaseModel):
|
|
35
|
+
data_collection_ids: tuple[int, ...] = ()
|
|
36
|
+
data_collection_group_id: int | None = None
|
|
37
|
+
grid_ids: tuple[int, ...] = ()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class StoreInIspyb:
|
|
41
|
+
def __init__(self, ispyb_config: str) -> None:
|
|
42
|
+
self.ISPYB_CONFIG_PATH: str = ispyb_config
|
|
43
|
+
self._data_collection_group_id: int | None
|
|
44
|
+
|
|
45
|
+
def begin_deposition(
|
|
46
|
+
self,
|
|
47
|
+
data_collection_group_info: DataCollectionGroupInfo,
|
|
48
|
+
scan_data_infos: Sequence[ScanDataInfo],
|
|
49
|
+
) -> IspybIds:
|
|
50
|
+
ispyb_ids = IspybIds()
|
|
51
|
+
if scan_data_infos[0].data_collection_info:
|
|
52
|
+
ispyb_ids.data_collection_group_id = scan_data_infos[
|
|
53
|
+
0
|
|
54
|
+
].data_collection_info.parent_id
|
|
55
|
+
|
|
56
|
+
return self._begin_or_update_deposition(
|
|
57
|
+
ispyb_ids, data_collection_group_info, scan_data_infos
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def update_deposition(
|
|
61
|
+
self,
|
|
62
|
+
ispyb_ids,
|
|
63
|
+
scan_data_infos: Sequence[ScanDataInfo],
|
|
64
|
+
) -> IspybIds:
|
|
65
|
+
assert (
|
|
66
|
+
ispyb_ids.data_collection_group_id
|
|
67
|
+
), "Attempted to store scan data without a collection group"
|
|
68
|
+
assert (
|
|
69
|
+
ispyb_ids.data_collection_ids
|
|
70
|
+
), "Attempted to store scan data without a collection"
|
|
71
|
+
return self._begin_or_update_deposition(ispyb_ids, None, scan_data_infos)
|
|
72
|
+
|
|
73
|
+
def _begin_or_update_deposition(
|
|
74
|
+
self,
|
|
75
|
+
ispyb_ids,
|
|
76
|
+
data_collection_group_info: DataCollectionGroupInfo | None,
|
|
77
|
+
scan_data_infos,
|
|
78
|
+
) -> IspybIds:
|
|
79
|
+
with ispyb.open(self.ISPYB_CONFIG_PATH) as conn:
|
|
80
|
+
assert conn is not None, "Failed to connect to ISPyB"
|
|
81
|
+
if data_collection_group_info:
|
|
82
|
+
ispyb_ids.data_collection_group_id = (
|
|
83
|
+
self._store_data_collection_group_table(
|
|
84
|
+
conn,
|
|
85
|
+
data_collection_group_info,
|
|
86
|
+
ispyb_ids.data_collection_group_id,
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
assert ispyb_ids.data_collection_group_id, "Attempt to update data collection without a data collection group ID"
|
|
91
|
+
|
|
92
|
+
grid_ids = list(ispyb_ids.grid_ids)
|
|
93
|
+
data_collection_ids_out = list(ispyb_ids.data_collection_ids)
|
|
94
|
+
for scan_data_info in scan_data_infos:
|
|
95
|
+
data_collection_id = scan_data_info.data_collection_id
|
|
96
|
+
if (
|
|
97
|
+
scan_data_info.data_collection_info
|
|
98
|
+
and not scan_data_info.data_collection_info.parent_id
|
|
99
|
+
):
|
|
100
|
+
scan_data_info.data_collection_info.parent_id = (
|
|
101
|
+
ispyb_ids.data_collection_group_id
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
new_data_collection_id, grid_id = self._store_single_scan_data(
|
|
105
|
+
conn, scan_data_info, data_collection_id
|
|
106
|
+
)
|
|
107
|
+
if not data_collection_id:
|
|
108
|
+
data_collection_ids_out.append(new_data_collection_id)
|
|
109
|
+
if grid_id:
|
|
110
|
+
grid_ids.append(grid_id)
|
|
111
|
+
ispyb_ids = IspybIds(
|
|
112
|
+
data_collection_ids=tuple(data_collection_ids_out),
|
|
113
|
+
grid_ids=tuple(grid_ids),
|
|
114
|
+
data_collection_group_id=ispyb_ids.data_collection_group_id,
|
|
115
|
+
)
|
|
116
|
+
return ispyb_ids
|
|
117
|
+
|
|
118
|
+
def end_deposition(self, ispyb_ids: IspybIds, success: str, reason: str):
|
|
119
|
+
assert (
|
|
120
|
+
ispyb_ids.data_collection_ids
|
|
121
|
+
), "Can't end ISPyB deposition, data_collection IDs are missing"
|
|
122
|
+
assert (
|
|
123
|
+
ispyb_ids.data_collection_group_id is not None
|
|
124
|
+
), "Cannot end ISPyB deposition without data collection group ID"
|
|
125
|
+
|
|
126
|
+
for id_ in ispyb_ids.data_collection_ids:
|
|
127
|
+
ISPYB_LOGGER.info(
|
|
128
|
+
f"End ispyb deposition with status '{success}' and reason '{reason}'."
|
|
129
|
+
)
|
|
130
|
+
if success == "fail" or success == "abort":
|
|
131
|
+
run_status = "DataCollection Unsuccessful"
|
|
132
|
+
else:
|
|
133
|
+
run_status = "DataCollection Successful"
|
|
134
|
+
current_time = get_current_time_string()
|
|
135
|
+
self._update_scan_with_end_time_and_status(
|
|
136
|
+
current_time,
|
|
137
|
+
run_status,
|
|
138
|
+
reason,
|
|
139
|
+
id_,
|
|
140
|
+
ispyb_ids.data_collection_group_id,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
def append_to_comment(
|
|
144
|
+
self, data_collection_id: int, comment: str, delimiter: str = " "
|
|
145
|
+
) -> None:
|
|
146
|
+
with ispyb.open(self.ISPYB_CONFIG_PATH) as conn:
|
|
147
|
+
assert conn is not None, "Failed to connect to ISPyB!"
|
|
148
|
+
mx_acquisition: MXAcquisition = conn.mx_acquisition
|
|
149
|
+
mx_acquisition.update_data_collection_append_comments(
|
|
150
|
+
data_collection_id, comment, delimiter
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def _update_scan_with_end_time_and_status(
|
|
154
|
+
self,
|
|
155
|
+
end_time: str,
|
|
156
|
+
run_status: str,
|
|
157
|
+
reason: str,
|
|
158
|
+
data_collection_id: int,
|
|
159
|
+
data_collection_group_id: int,
|
|
160
|
+
) -> None:
|
|
161
|
+
if reason is not None and reason != "":
|
|
162
|
+
self.append_to_comment(data_collection_id, f"{run_status} reason: {reason}")
|
|
163
|
+
|
|
164
|
+
with ispyb.open(self.ISPYB_CONFIG_PATH) as conn:
|
|
165
|
+
assert conn is not None, "Failed to connect to ISPyB!"
|
|
166
|
+
|
|
167
|
+
mx_acquisition: MXAcquisition = conn.mx_acquisition
|
|
168
|
+
|
|
169
|
+
params = mx_acquisition.get_data_collection_params()
|
|
170
|
+
params["id"] = data_collection_id
|
|
171
|
+
params["parentid"] = data_collection_group_id
|
|
172
|
+
params["endtime"] = end_time
|
|
173
|
+
params["run_status"] = run_status
|
|
174
|
+
|
|
175
|
+
mx_acquisition.upsert_data_collection(list(params.values()))
|
|
176
|
+
|
|
177
|
+
def _store_position_table(
|
|
178
|
+
self, conn: Connector, dc_pos_info, data_collection_id
|
|
179
|
+
) -> int:
|
|
180
|
+
mx_acquisition: MXAcquisition = conn.mx_acquisition
|
|
181
|
+
|
|
182
|
+
params = mx_acquisition.get_dc_position_params()
|
|
183
|
+
params["id"] = data_collection_id
|
|
184
|
+
params |= asdict(dc_pos_info)
|
|
185
|
+
|
|
186
|
+
return mx_acquisition.update_dc_position(list(params.values()))
|
|
187
|
+
|
|
188
|
+
def _store_data_collection_group_table(
|
|
189
|
+
self,
|
|
190
|
+
conn: Connector,
|
|
191
|
+
dcg_info: DataCollectionGroupInfo,
|
|
192
|
+
data_collection_group_id: int | None = None,
|
|
193
|
+
) -> int:
|
|
194
|
+
mx_acquisition: MXAcquisition = conn.mx_acquisition
|
|
195
|
+
|
|
196
|
+
params = mx_acquisition.get_data_collection_group_params()
|
|
197
|
+
if data_collection_group_id:
|
|
198
|
+
params["id"] = data_collection_group_id
|
|
199
|
+
params["parent_id"] = get_session_id_from_visit(conn, dcg_info.visit_string)
|
|
200
|
+
params |= {k: v for k, v in asdict(dcg_info).items() if k != "visit_string"}
|
|
201
|
+
|
|
202
|
+
return self._upsert_data_collection_group(conn, params)
|
|
203
|
+
|
|
204
|
+
def _store_data_collection_table(
|
|
205
|
+
self, conn, data_collection_id, data_collection_info
|
|
206
|
+
):
|
|
207
|
+
params = self._fill_common_data_collection_params(
|
|
208
|
+
conn, data_collection_id, data_collection_info
|
|
209
|
+
)
|
|
210
|
+
return self._upsert_data_collection(conn, params)
|
|
211
|
+
|
|
212
|
+
def _store_single_scan_data(
|
|
213
|
+
self, conn, scan_data_info, data_collection_id=None
|
|
214
|
+
) -> tuple[int, int | None]:
|
|
215
|
+
data_collection_id = self._store_data_collection_table(
|
|
216
|
+
conn, data_collection_id, scan_data_info.data_collection_info
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
if scan_data_info.data_collection_position_info:
|
|
220
|
+
self._store_position_table(
|
|
221
|
+
conn,
|
|
222
|
+
scan_data_info.data_collection_position_info,
|
|
223
|
+
data_collection_id,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
grid_id = None
|
|
227
|
+
if scan_data_info.data_collection_grid_info:
|
|
228
|
+
grid_id = self._store_grid_info_table(
|
|
229
|
+
conn,
|
|
230
|
+
data_collection_id,
|
|
231
|
+
scan_data_info.data_collection_grid_info,
|
|
232
|
+
)
|
|
233
|
+
return data_collection_id, grid_id
|
|
234
|
+
|
|
235
|
+
def _store_grid_info_table(
|
|
236
|
+
self,
|
|
237
|
+
conn: Connector,
|
|
238
|
+
ispyb_data_collection_id: int,
|
|
239
|
+
dc_grid_info: DataCollectionGridInfo,
|
|
240
|
+
) -> int:
|
|
241
|
+
mx_acquisition: MXAcquisition = conn.mx_acquisition
|
|
242
|
+
params = mx_acquisition.get_dc_grid_params()
|
|
243
|
+
params |= dc_grid_info.as_dict()
|
|
244
|
+
params["parentid"] = ispyb_data_collection_id
|
|
245
|
+
return mx_acquisition.upsert_dc_grid(list(params.values()))
|
|
246
|
+
|
|
247
|
+
def _fill_common_data_collection_params(
|
|
248
|
+
self, conn, data_collection_id, data_collection_info: DataCollectionInfo
|
|
249
|
+
) -> StrictOrderedDict:
|
|
250
|
+
mx_acquisition: MXAcquisition = conn.mx_acquisition
|
|
251
|
+
params = mx_acquisition.get_data_collection_params()
|
|
252
|
+
|
|
253
|
+
if data_collection_id:
|
|
254
|
+
params["id"] = data_collection_id
|
|
255
|
+
if data_collection_info.visit_string:
|
|
256
|
+
# This is only needed for populating the DataCollectionGroup
|
|
257
|
+
params["visit_id"] = get_session_id_from_visit(
|
|
258
|
+
conn, data_collection_info.visit_string
|
|
259
|
+
)
|
|
260
|
+
params |= {
|
|
261
|
+
k: v for k, v in asdict(data_collection_info).items() if k != "visit_string"
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return params
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
@TRACER.start_as_current_span("_upsert_data_collection_group")
|
|
268
|
+
def _upsert_data_collection_group(
|
|
269
|
+
conn: Connector, params: StrictOrderedDict
|
|
270
|
+
) -> int:
|
|
271
|
+
return conn.mx_acquisition.upsert_data_collection_group(list(params.values()))
|
|
272
|
+
|
|
273
|
+
@staticmethod
|
|
274
|
+
@TRACER.start_as_current_span("_upsert_data_collection")
|
|
275
|
+
def _upsert_data_collection(conn: Connector, params: StrictOrderedDict) -> int:
|
|
276
|
+
return conn.mx_acquisition.upsert_data_collection(list(params.values()))
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from ispyb import NoResult
|
|
7
|
+
from ispyb.connector.mysqlsp.main import ISPyBMySQLSPConnector as Connector
|
|
8
|
+
from ispyb.sp.core import Core
|
|
9
|
+
|
|
10
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_ispyb_config():
|
|
14
|
+
return os.environ.get("ISPYB_CONFIG_PATH", CONST.SIM.ISPYB_CONFIG)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_session_id_from_visit(conn: Connector, visit: str):
|
|
18
|
+
try:
|
|
19
|
+
core: Core = conn.core
|
|
20
|
+
return core.retrieve_visit_id(visit)
|
|
21
|
+
except NoResult as e:
|
|
22
|
+
raise NoResult(f"No session ID found in ispyb for visit {visit}") from e
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_current_time_string():
|
|
26
|
+
now = datetime.datetime.now()
|
|
27
|
+
return now.strftime("%Y-%m-%d %H:%M:%S")
|
|
File without changes
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from dodal.devices.detector import DetectorParams
|
|
8
|
+
from dodal.devices.zebra import RotationDirection
|
|
9
|
+
from nexgen.nxs_utils import Attenuator, Axis, Beam, Detector, EigerDetector, Goniometer
|
|
10
|
+
from nexgen.nxs_utils.axes import TransformationType
|
|
11
|
+
from numpy.typing import DTypeLike
|
|
12
|
+
|
|
13
|
+
from mx_bluesky.hyperion.log import NEXUS_LOGGER
|
|
14
|
+
from mx_bluesky.hyperion.utils.utils import convert_eV_to_angstrom
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def vds_type_based_on_bit_depth(detector_bit_depth: int) -> DTypeLike:
|
|
18
|
+
"""Works out the datatype for the VDS, based on the bit depth from the detector."""
|
|
19
|
+
if detector_bit_depth == 8:
|
|
20
|
+
return np.uint8
|
|
21
|
+
elif detector_bit_depth == 16:
|
|
22
|
+
return np.uint16
|
|
23
|
+
elif detector_bit_depth == 32:
|
|
24
|
+
return np.uint32
|
|
25
|
+
else:
|
|
26
|
+
NEXUS_LOGGER.error(
|
|
27
|
+
f"Unknown detector bit depth {detector_bit_depth}, assuming 16-bit"
|
|
28
|
+
)
|
|
29
|
+
return np.uint16
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def create_goniometer_axes(
|
|
33
|
+
omega_start: float,
|
|
34
|
+
scan_points: dict | None,
|
|
35
|
+
x_y_z_increments: tuple[float, float, float] = (0.0, 0.0, 0.0),
|
|
36
|
+
chi: float = 0.0,
|
|
37
|
+
phi: float = 0.0,
|
|
38
|
+
rotation_direction: RotationDirection = RotationDirection.NEGATIVE,
|
|
39
|
+
):
|
|
40
|
+
"""Returns a Nexgen 'Goniometer' object with the dependency chain of I03's Smargon
|
|
41
|
+
goniometer. If scan points is provided these values will be used in preference to
|
|
42
|
+
those from the params object.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
omega_start (float): the starting position of omega, the only extra value that
|
|
46
|
+
needs to be specified except for the scan points.
|
|
47
|
+
scan_points (dict): a dictionary of points in the scan for each axis. Obtained
|
|
48
|
+
by calculating the scan path with scanspec and calling
|
|
49
|
+
consume() on it.
|
|
50
|
+
x_y_z_increments: optionally, specify the increments between each image for
|
|
51
|
+
the x, y, and z axes. Will be ignored if scan_points
|
|
52
|
+
is provided.
|
|
53
|
+
"""
|
|
54
|
+
gonio_axes = [
|
|
55
|
+
Axis(
|
|
56
|
+
"omega",
|
|
57
|
+
".",
|
|
58
|
+
TransformationType.ROTATION,
|
|
59
|
+
(1.0 * rotation_direction.multiplier, 0.0, 0.0),
|
|
60
|
+
omega_start,
|
|
61
|
+
),
|
|
62
|
+
Axis(
|
|
63
|
+
name="sam_z",
|
|
64
|
+
depends="omega",
|
|
65
|
+
transformation_type=TransformationType.TRANSLATION,
|
|
66
|
+
vector=(0.0, 0.0, 1.0),
|
|
67
|
+
start_pos=0.0,
|
|
68
|
+
increment=x_y_z_increments[2],
|
|
69
|
+
),
|
|
70
|
+
Axis(
|
|
71
|
+
name="sam_y",
|
|
72
|
+
depends="sam_z",
|
|
73
|
+
transformation_type=TransformationType.TRANSLATION,
|
|
74
|
+
vector=(0.0, 1.0, 0.0),
|
|
75
|
+
start_pos=0.0,
|
|
76
|
+
increment=x_y_z_increments[1],
|
|
77
|
+
),
|
|
78
|
+
Axis(
|
|
79
|
+
name="sam_x",
|
|
80
|
+
depends="sam_y",
|
|
81
|
+
transformation_type=TransformationType.TRANSLATION,
|
|
82
|
+
vector=(1.0, 0.0, 0.0),
|
|
83
|
+
start_pos=0.0,
|
|
84
|
+
increment=x_y_z_increments[0],
|
|
85
|
+
),
|
|
86
|
+
Axis(
|
|
87
|
+
"chi", "sam_x", TransformationType.ROTATION, (0.006, -0.0264, 0.9996), chi
|
|
88
|
+
),
|
|
89
|
+
Axis("phi", "chi", TransformationType.ROTATION, (-1, -0.0025, -0.0056), phi),
|
|
90
|
+
]
|
|
91
|
+
return Goniometer(gonio_axes, scan_points)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_start_and_predicted_end_time(time_expected: float) -> tuple[str, str]:
|
|
95
|
+
time_format = r"%Y-%m-%dT%H:%M:%SZ"
|
|
96
|
+
start = datetime.utcfromtimestamp(time.time())
|
|
97
|
+
end_est = start + timedelta(seconds=time_expected)
|
|
98
|
+
return start.strftime(time_format), end_est.strftime(time_format)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def create_detector_parameters(detector_params: DetectorParams) -> Detector:
|
|
102
|
+
"""Returns the detector information in a format that nexgen wants.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
detector_params (DetectorParams): The detector params as Hyperion stores them.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Detector: Detector description for nexgen.
|
|
109
|
+
"""
|
|
110
|
+
detector_pixels = detector_params.get_detector_size_pizels()
|
|
111
|
+
|
|
112
|
+
eiger_params = EigerDetector(
|
|
113
|
+
"Eiger 16M", (detector_pixels.height, detector_pixels.width), "Si", 46051, 0
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
detector_axes = [
|
|
117
|
+
Axis(
|
|
118
|
+
"det_z",
|
|
119
|
+
".",
|
|
120
|
+
TransformationType.TRANSLATION,
|
|
121
|
+
(0.0, 0.0, 1.0),
|
|
122
|
+
detector_params.detector_distance,
|
|
123
|
+
)
|
|
124
|
+
]
|
|
125
|
+
# Eiger parameters, axes, beam_center, exp_time, [fast, slow]
|
|
126
|
+
return Detector(
|
|
127
|
+
eiger_params,
|
|
128
|
+
detector_axes,
|
|
129
|
+
list(
|
|
130
|
+
detector_params.get_beam_position_pixels(detector_params.detector_distance)
|
|
131
|
+
),
|
|
132
|
+
detector_params.exposure_time,
|
|
133
|
+
[(-1.0, 0.0, 0.0), (0.0, -1.0, 0.0)],
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def create_beam_and_attenuator_parameters(
|
|
138
|
+
energy_kev: float, flux: float, transmission_fraction: float
|
|
139
|
+
) -> tuple[Beam, Attenuator]:
|
|
140
|
+
"""Create beam and attenuator objects that nexgen can understands
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
tuple[Beam, Attenuator]: Descriptions of the beam and attenuator for nexgen.
|
|
144
|
+
"""
|
|
145
|
+
return (
|
|
146
|
+
Beam(convert_eV_to_angstrom(energy_kev * 1000), flux), # pyright: ignore
|
|
147
|
+
Attenuator(transmission_fraction), # pyright: ignore
|
|
148
|
+
)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Define beamline parameters for I03, Eiger detector and give an example of writing a
|
|
3
|
+
gridscan.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from dodal.devices.zebra import RotationDirection
|
|
12
|
+
from dodal.utils import get_beamline_name
|
|
13
|
+
from nexgen.nxs_utils import Attenuator, Beam, Detector, Goniometer, Source
|
|
14
|
+
from nexgen.nxs_write.nxmx_writer import NXmxFileWriter
|
|
15
|
+
from numpy.typing import DTypeLike
|
|
16
|
+
from scanspec.core import AxesPoints
|
|
17
|
+
|
|
18
|
+
from mx_bluesky.hyperion.external_interaction.nexus.nexus_utils import (
|
|
19
|
+
create_detector_parameters,
|
|
20
|
+
create_goniometer_axes,
|
|
21
|
+
get_start_and_predicted_end_time,
|
|
22
|
+
)
|
|
23
|
+
from mx_bluesky.hyperion.parameters.components import DiffractionExperimentWithSample
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class NexusWriter:
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
parameters: DiffractionExperimentWithSample,
|
|
30
|
+
data_shape: tuple[int, int, int],
|
|
31
|
+
scan_points: AxesPoints,
|
|
32
|
+
*,
|
|
33
|
+
run_number: int | None = None,
|
|
34
|
+
omega_start_deg: float = 0,
|
|
35
|
+
chi_start_deg: float = 0,
|
|
36
|
+
phi_start_deg: float = 0,
|
|
37
|
+
vds_start_index: int = 0,
|
|
38
|
+
# override default values when there is more than one collection per
|
|
39
|
+
# detector arming event:
|
|
40
|
+
full_num_of_images: int | None = None,
|
|
41
|
+
meta_data_run_number: int | None = None,
|
|
42
|
+
rotation_direction: RotationDirection = RotationDirection.NEGATIVE,
|
|
43
|
+
) -> None:
|
|
44
|
+
self.beam: Beam | None = None
|
|
45
|
+
self.attenuator: Attenuator | None = None
|
|
46
|
+
self.scan_points: dict = scan_points
|
|
47
|
+
self.data_shape: tuple[int, int, int] = data_shape
|
|
48
|
+
self.run_number: int = (
|
|
49
|
+
run_number if run_number else parameters.detector_params.run_number
|
|
50
|
+
)
|
|
51
|
+
self.detector: Detector = create_detector_parameters(parameters.detector_params)
|
|
52
|
+
self.source: Source = Source(get_beamline_name("S03"))
|
|
53
|
+
self.directory: Path = Path(parameters.storage_directory)
|
|
54
|
+
self.start_index: int = vds_start_index
|
|
55
|
+
self.full_num_of_images: int = full_num_of_images or parameters.num_images
|
|
56
|
+
self.data_filename: str = (
|
|
57
|
+
f"{parameters.file_name}_{meta_data_run_number}"
|
|
58
|
+
if meta_data_run_number
|
|
59
|
+
else parameters.detector_params.full_filename
|
|
60
|
+
)
|
|
61
|
+
self.nexus_file: Path = (
|
|
62
|
+
self.directory / f"{parameters.file_name}_{self.run_number}.nxs"
|
|
63
|
+
)
|
|
64
|
+
self.master_file: Path = (
|
|
65
|
+
self.directory / f"{parameters.file_name}_{self.run_number}_master.h5"
|
|
66
|
+
)
|
|
67
|
+
self.goniometer: Goniometer = create_goniometer_axes(
|
|
68
|
+
omega_start_deg,
|
|
69
|
+
self.scan_points,
|
|
70
|
+
chi=chi_start_deg,
|
|
71
|
+
phi=phi_start_deg,
|
|
72
|
+
rotation_direction=rotation_direction,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def create_nexus_file(self, bit_depth: DTypeLike):
|
|
76
|
+
"""
|
|
77
|
+
Creates a nexus file based on the parameters supplied when this object was
|
|
78
|
+
initialised.
|
|
79
|
+
"""
|
|
80
|
+
start_time, est_end_time = get_start_and_predicted_end_time(
|
|
81
|
+
self.detector.exp_time * self.full_num_of_images
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
assert self.beam is not None
|
|
85
|
+
assert self.attenuator is not None
|
|
86
|
+
|
|
87
|
+
vds_shape = self.data_shape
|
|
88
|
+
|
|
89
|
+
for filename in [self.nexus_file, self.master_file]:
|
|
90
|
+
NXmx_Writer = NXmxFileWriter(
|
|
91
|
+
filename,
|
|
92
|
+
self.goniometer,
|
|
93
|
+
self.detector,
|
|
94
|
+
self.source,
|
|
95
|
+
self.beam,
|
|
96
|
+
self.attenuator,
|
|
97
|
+
self.full_num_of_images,
|
|
98
|
+
)
|
|
99
|
+
NXmx_Writer.write(
|
|
100
|
+
image_filename=f"{self.data_filename}",
|
|
101
|
+
start_time=start_time,
|
|
102
|
+
est_end_time=est_end_time,
|
|
103
|
+
)
|
|
104
|
+
NXmx_Writer.write_vds(
|
|
105
|
+
vds_offset=self.start_index, vds_shape=vds_shape, vds_dtype=bit_depth
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def get_image_datafiles(self, max_images_per_file=1000):
|
|
109
|
+
return [
|
|
110
|
+
self.directory / f"{self.data_filename}_{h5_num + 1:06}.h5"
|
|
111
|
+
for h5_num in range(
|
|
112
|
+
math.ceil(self.full_num_of_images / max_images_per_file)
|
|
113
|
+
)
|
|
114
|
+
]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from logging.handlers import TimedRotatingFileHandler
|
|
3
|
+
from os import environ
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
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
|
+
from dodal.log import LOGGER as dodal_logger
|
|
14
|
+
|
|
15
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
16
|
+
|
|
17
|
+
LOGGER = logging.getLogger("Hyperion")
|
|
18
|
+
LOGGER.setLevel("DEBUG")
|
|
19
|
+
LOGGER.parent = dodal_logger
|
|
20
|
+
__logger_handlers: DodalLogHandlers | None = None
|
|
21
|
+
|
|
22
|
+
ISPYB_LOGGER = logging.getLogger("Hyperion ISPyB and Zocalo callbacks")
|
|
23
|
+
ISPYB_LOGGER.setLevel(logging.DEBUG)
|
|
24
|
+
|
|
25
|
+
NEXUS_LOGGER = logging.getLogger("Hyperion NeXus callbacks")
|
|
26
|
+
NEXUS_LOGGER.setLevel(logging.DEBUG)
|
|
27
|
+
|
|
28
|
+
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
|