mx-bluesky 1.1.0__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +48 -10
- mx_bluesky/beamlines/i24/serial/__init__.py +3 -0
- mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +68 -90
- mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +1 -1
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +104 -126
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +139 -162
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Mapping_py3v1.py +25 -36
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_StartUp_py3v1.py +24 -34
- mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +14 -11
- mx_bluesky/beamlines/i24/serial/log.py +58 -49
- 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 +31 -7
- 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 +1 -1
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +8 -18
- mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +2 -2
- mx_bluesky/common/__init__.py +0 -0
- mx_bluesky/common/device_setup_plans/read_hardware_for_setup.py +14 -0
- mx_bluesky/common/parameters/components.py +221 -0
- mx_bluesky/common/parameters/constants.py +133 -0
- mx_bluesky/common/plans/__init__.py +1 -0
- mx_bluesky/common/plans/do_fgs.py +121 -0
- mx_bluesky/common/utils/log.py +116 -0
- mx_bluesky/{hyperion → common/utils}/tracing.py +2 -2
- mx_bluesky/hyperion/__main__.py +11 -9
- 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 +1 -2
- mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +48 -17
- mx_bluesky/hyperion/device_setup_plans/smargon.py +6 -6
- mx_bluesky/hyperion/device_setup_plans/utils.py +13 -2
- mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +4 -4
- mx_bluesky/hyperion/experiment_plans/experiment_registry.py +9 -0
- mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +59 -108
- mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +7 -5
- mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +46 -0
- mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +19 -18
- mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +8 -5
- mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +4 -4
- mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +17 -17
- mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +241 -0
- mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +24 -181
- mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +6 -4
- mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +3 -11
- mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -2
- mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +18 -0
- mx_bluesky/hyperion/external_interaction/callbacks/common/ispyb_mapping.py +1 -9
- mx_bluesky/hyperion/external_interaction/callbacks/grid_detection_callback.py +18 -13
- mx_bluesky/hyperion/external_interaction/callbacks/ispyb_callback_base.py +32 -15
- mx_bluesky/hyperion/external_interaction/callbacks/log_uid_tag_callback.py +1 -1
- mx_bluesky/hyperion/external_interaction/callbacks/robot_load/ispyb_callback.py +3 -5
- mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +4 -3
- mx_bluesky/hyperion/external_interaction/callbacks/xray_centre/ispyb_callback.py +23 -18
- mx_bluesky/hyperion/external_interaction/config_server.py +22 -10
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_store.py +1 -1
- mx_bluesky/hyperion/external_interaction/ispyb/ispyb_utils.py +0 -2
- 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 +1 -242
- mx_bluesky/hyperion/parameters/constants.py +22 -118
- mx_bluesky/hyperion/parameters/gridscan.py +20 -11
- 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 +9 -5
- mx_bluesky/hyperion/utils/utils.py +17 -0
- mx_bluesky/hyperion/utils/validation.py +5 -6
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.4.0.dist-info}/METADATA +4 -2
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.4.0.dist-info}/RECORD +80 -70
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.4.0.dist-info}/WHEEL +1 -1
- mx_bluesky/example.py +0 -19
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.4.0.dist-info}/LICENSE +0 -0
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.4.0.dist-info}/entry_points.txt +0 -0
- {mx_bluesky-1.1.0.dist-info → mx_bluesky-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
__logger_handlers: DodalLogHandlers | None = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ExperimentMetadataTagFilter(logging.Filter):
|
|
19
|
+
"""When an instance of this custom filter is added to a logging handler, dc_group_id
|
|
20
|
+
and run_id will be tagged in that handlers' log messages."""
|
|
21
|
+
|
|
22
|
+
dc_group_id: str | None = None
|
|
23
|
+
run_uid: str | None = None
|
|
24
|
+
|
|
25
|
+
def filter(self, record):
|
|
26
|
+
if self.dc_group_id:
|
|
27
|
+
record.dc_group_id = self.dc_group_id
|
|
28
|
+
if self.run_uid:
|
|
29
|
+
record.run_uid = self.run_uid
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
tag_filter = ExperimentMetadataTagFilter()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def set_dcgid_tag(dcgid):
|
|
37
|
+
"""Set the datacollection group id as a tag on all subsequent log messages.
|
|
38
|
+
Setting to None will remove the tag."""
|
|
39
|
+
tag_filter.dc_group_id = dcgid
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def set_uid_tag(uid):
|
|
43
|
+
"""Set the unique id as a tag on all subsequent log messages.
|
|
44
|
+
Setting to None will remove the tag."""
|
|
45
|
+
tag_filter.run_uid = uid
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def do_default_logging_setup(
|
|
49
|
+
file_name: str,
|
|
50
|
+
graylog_port: int,
|
|
51
|
+
dev_mode: bool = False,
|
|
52
|
+
integrate_all_logs: bool = True,
|
|
53
|
+
):
|
|
54
|
+
"""Configures dodal logger so that separate debug and info log files are created,
|
|
55
|
+
info logs are sent to Graylog, info logs are streamed to sys.sterr, and logs from ophyd
|
|
56
|
+
and bluesky and ophyd-async are optionally included."""
|
|
57
|
+
|
|
58
|
+
handlers = set_up_all_logging_handlers(
|
|
59
|
+
dodal_logger,
|
|
60
|
+
_get_logging_dir(),
|
|
61
|
+
file_name,
|
|
62
|
+
dev_mode,
|
|
63
|
+
ERROR_LOG_BUFFER_LINES,
|
|
64
|
+
graylog_port,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if integrate_all_logs:
|
|
68
|
+
integrate_bluesky_and_ophyd_logging(dodal_logger)
|
|
69
|
+
|
|
70
|
+
handlers["graylog_handler"].addFilter(tag_filter)
|
|
71
|
+
|
|
72
|
+
global __logger_handlers
|
|
73
|
+
__logger_handlers = handlers
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _get_debug_handler() -> CircularMemoryHandler:
|
|
77
|
+
assert (
|
|
78
|
+
__logger_handlers is not None
|
|
79
|
+
), "You can only use this after running the default logging setup"
|
|
80
|
+
return __logger_handlers["debug_memory_handler"]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def flush_debug_handler() -> str:
|
|
84
|
+
"""Writes the contents of the circular debug log buffer to disk and returns the written filename"""
|
|
85
|
+
handler = _get_debug_handler()
|
|
86
|
+
assert isinstance(
|
|
87
|
+
handler.target, TimedRotatingFileHandler
|
|
88
|
+
), "Circular memory handler doesn't have an appropriate fileHandler target"
|
|
89
|
+
handler.flush()
|
|
90
|
+
return handler.target.baseFilename
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _get_logging_dir() -> Path:
|
|
94
|
+
"""Get the path to write the mx_bluesky log files to.
|
|
95
|
+
|
|
96
|
+
Log location can be specified in the LOG_DIR environment variable, otherwise MX bluesky logs are written to 'dls_sw/ixx/logs/bluesky'.
|
|
97
|
+
This directory will be created if it is not found
|
|
98
|
+
|
|
99
|
+
Logs are written to ./tmp/logs/bluesky if BEAMLINE environment variable is not found
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
logging_path (Path): Path to the log file for the file handler to write to.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
logging_str = environ.get("LOG_DIR")
|
|
106
|
+
if logging_str:
|
|
107
|
+
logging_path = Path(logging_str)
|
|
108
|
+
else:
|
|
109
|
+
beamline = environ.get("BEAMLINE")
|
|
110
|
+
logging_path = (
|
|
111
|
+
Path(f"/dls_sw/{beamline}/logs/bluesky/")
|
|
112
|
+
if beamline
|
|
113
|
+
else Path("/tmp/logs/bluesky")
|
|
114
|
+
)
|
|
115
|
+
Path.mkdir(logging_path, exist_ok=True, parents=True)
|
|
116
|
+
return logging_path
|
|
@@ -8,8 +8,8 @@ from opentelemetry.sdk.trace import TracerProvider
|
|
|
8
8
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def setup_tracing():
|
|
12
|
-
resource = Resource(attributes={SERVICE_NAME:
|
|
11
|
+
def setup_tracing(service_name: str = "Hyperion"):
|
|
12
|
+
resource = Resource(attributes={SERVICE_NAME: service_name})
|
|
13
13
|
|
|
14
14
|
traceProvider = TracerProvider(resource=resource)
|
|
15
15
|
processor = BatchSpanProcessor(
|
mx_bluesky/hyperion/__main__.py
CHANGED
|
@@ -14,6 +14,10 @@ from flask import Flask, request
|
|
|
14
14
|
from flask_restful import Api, Resource
|
|
15
15
|
from pydantic.dataclasses import dataclass
|
|
16
16
|
|
|
17
|
+
from mx_bluesky.common.parameters.components import MxBlueskyParameters
|
|
18
|
+
from mx_bluesky.common.parameters.constants import Actions, Status
|
|
19
|
+
from mx_bluesky.common.utils.log import do_default_logging_setup, flush_debug_handler
|
|
20
|
+
from mx_bluesky.common.utils.tracing import TRACER
|
|
17
21
|
from mx_bluesky.hyperion.exceptions import WarningException
|
|
18
22
|
from mx_bluesky.hyperion.experiment_plans.experiment_registry import (
|
|
19
23
|
PLAN_REGISTRY,
|
|
@@ -36,13 +40,9 @@ from mx_bluesky.hyperion.external_interaction.callbacks.logging_callback import
|
|
|
36
40
|
)
|
|
37
41
|
from mx_bluesky.hyperion.log import (
|
|
38
42
|
LOGGER,
|
|
39
|
-
do_default_logging_setup,
|
|
40
|
-
flush_debug_handler,
|
|
41
43
|
)
|
|
42
44
|
from mx_bluesky.hyperion.parameters.cli import parse_cli_args
|
|
43
|
-
from mx_bluesky.hyperion.parameters.
|
|
44
|
-
from mx_bluesky.hyperion.parameters.constants import CONST, Actions, Status
|
|
45
|
-
from mx_bluesky.hyperion.tracing import TRACER
|
|
45
|
+
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
46
46
|
from mx_bluesky.hyperion.utils.context import setup_context
|
|
47
47
|
|
|
48
48
|
VERBOSE_EVENT_LOGGING: bool | None = None
|
|
@@ -53,7 +53,7 @@ class Command:
|
|
|
53
53
|
action: Actions
|
|
54
54
|
devices: Any | None = None
|
|
55
55
|
experiment: Callable[[Any, Any], MsgGenerator] | None = None
|
|
56
|
-
parameters:
|
|
56
|
+
parameters: MxBlueskyParameters | None = None
|
|
57
57
|
callbacks: CallbacksFactory | None = None
|
|
58
58
|
|
|
59
59
|
|
|
@@ -119,7 +119,7 @@ class BlueskyRunner:
|
|
|
119
119
|
def start(
|
|
120
120
|
self,
|
|
121
121
|
experiment: Callable,
|
|
122
|
-
parameters:
|
|
122
|
+
parameters: MxBlueskyParameters,
|
|
123
123
|
plan_name: str,
|
|
124
124
|
callbacks: CallbacksFactory | None,
|
|
125
125
|
) -> StatusAndMessage:
|
|
@@ -239,7 +239,7 @@ def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions)
|
|
|
239
239
|
raise ValueError(f"Extra fields not allowed {parameters.model_extra}")
|
|
240
240
|
except Exception as e:
|
|
241
241
|
raise ValueError(
|
|
242
|
-
f"Supplied parameters don't match the plan for this endpoint {request.data}"
|
|
242
|
+
f"Supplied parameters don't match the plan for this endpoint {request.data}, for plan {plan_name}"
|
|
243
243
|
) from e
|
|
244
244
|
return plan, parameters, plan_name, callback_type
|
|
245
245
|
|
|
@@ -345,7 +345,9 @@ def create_app(
|
|
|
345
345
|
def create_targets():
|
|
346
346
|
hyperion_port = 5005
|
|
347
347
|
args = parse_cli_args()
|
|
348
|
-
do_default_logging_setup(
|
|
348
|
+
do_default_logging_setup(
|
|
349
|
+
CONST.LOG_FILE_NAME, CONST.GRAYLOG_PORT, dev_mode=args.dev_mode
|
|
350
|
+
)
|
|
349
351
|
if not args.use_external_callbacks:
|
|
350
352
|
setup_callback_logging(args.dev_mode)
|
|
351
353
|
app, runner = create_app(
|
|
@@ -4,7 +4,7 @@ import bluesky.plan_stubs as bps
|
|
|
4
4
|
from dodal.devices.focusing_mirror import (
|
|
5
5
|
FocusingMirrorWithStripes,
|
|
6
6
|
MirrorStripe,
|
|
7
|
-
|
|
7
|
+
MirrorVoltages,
|
|
8
8
|
)
|
|
9
9
|
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
10
10
|
from dodal.devices.util.adjuster_plans import lookup_table_adjuster
|
|
@@ -13,6 +13,9 @@ from dodal.devices.util.lookup_tables import (
|
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
from mx_bluesky.hyperion.log import LOGGER
|
|
16
|
+
from mx_bluesky.hyperion.utils.utils import (
|
|
17
|
+
energy_to_bragg_angle,
|
|
18
|
+
)
|
|
16
19
|
|
|
17
20
|
MIRROR_VOLTAGE_GROUP = "MIRROR_VOLTAGE_GROUP"
|
|
18
21
|
DCM_GROUP = "DCM_GROUP"
|
|
@@ -20,40 +23,41 @@ DCM_GROUP = "DCM_GROUP"
|
|
|
20
23
|
|
|
21
24
|
def _apply_and_wait_for_voltages_to_settle(
|
|
22
25
|
stripe: MirrorStripe,
|
|
23
|
-
|
|
24
|
-
mirror_voltages: VFMMirrorVoltages,
|
|
26
|
+
mirror_voltages: MirrorVoltages,
|
|
25
27
|
):
|
|
26
28
|
with open(mirror_voltages.voltage_lookup_table_path) as lut_file:
|
|
27
29
|
json_obj = json.load(lut_file)
|
|
28
30
|
|
|
29
31
|
# sample mode is the only mode supported
|
|
30
32
|
sample_data = json_obj["sample"]
|
|
31
|
-
mirror_key = mirror.name.lower()
|
|
32
33
|
if stripe == MirrorStripe.BARE:
|
|
33
34
|
stripe_key = "bare"
|
|
34
35
|
elif stripe == MirrorStripe.RHODIUM:
|
|
35
36
|
stripe_key = "rh"
|
|
36
37
|
elif stripe == MirrorStripe.PLATINUM:
|
|
37
38
|
stripe_key = "pt"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
|
|
40
|
+
for mirror_key, channels in {
|
|
41
|
+
"hfm": mirror_voltages.horizontal_voltages,
|
|
42
|
+
"vfm": mirror_voltages.vertical_voltages,
|
|
43
|
+
}.items():
|
|
44
|
+
required_voltages = sample_data[stripe_key][mirror_key]
|
|
45
|
+
|
|
46
|
+
for voltage_channel, required_voltage in zip(
|
|
47
|
+
channels.values(), required_voltages, strict=True
|
|
48
|
+
):
|
|
49
|
+
LOGGER.debug(
|
|
50
|
+
f"Applying and waiting for voltage {voltage_channel.name} = {required_voltage}"
|
|
51
|
+
)
|
|
52
|
+
yield from bps.abs_set(
|
|
53
|
+
voltage_channel, required_voltage, group=MIRROR_VOLTAGE_GROUP
|
|
54
|
+
)
|
|
51
55
|
|
|
52
56
|
yield from bps.wait(group=MIRROR_VOLTAGE_GROUP)
|
|
53
57
|
|
|
54
58
|
|
|
55
59
|
def adjust_mirror_stripe(
|
|
56
|
-
energy_kev, mirror: FocusingMirrorWithStripes, mirror_voltages:
|
|
60
|
+
energy_kev, mirror: FocusingMirrorWithStripes, mirror_voltages: MirrorVoltages
|
|
57
61
|
):
|
|
58
62
|
"""Feedback should be OFF prior to entry, in order to prevent
|
|
59
63
|
feedback from making unnecessary corrections while beam is being adjusted."""
|
|
@@ -66,26 +70,27 @@ def adjust_mirror_stripe(
|
|
|
66
70
|
yield from bps.trigger(mirror.apply_stripe)
|
|
67
71
|
|
|
68
72
|
LOGGER.info("Adjusting mirror voltages...")
|
|
69
|
-
yield from _apply_and_wait_for_voltages_to_settle(stripe,
|
|
73
|
+
yield from _apply_and_wait_for_voltages_to_settle(stripe, mirror_voltages)
|
|
70
74
|
|
|
71
75
|
|
|
72
76
|
def adjust_dcm_pitch_roll_vfm_from_lut(
|
|
73
77
|
undulator_dcm: UndulatorDCM,
|
|
74
78
|
vfm: FocusingMirrorWithStripes,
|
|
75
|
-
|
|
79
|
+
mirror_voltages: MirrorVoltages,
|
|
76
80
|
energy_kev,
|
|
77
81
|
):
|
|
78
82
|
"""Beamline energy-change post-adjustments : Adjust DCM and VFM directly from lookup tables.
|
|
79
|
-
Lookups are performed against the Bragg angle which
|
|
80
|
-
|
|
83
|
+
Lookups are performed against the Bragg angle which is computed directly from the target energy
|
|
84
|
+
rather than waiting for the EPICS controls PV to reach it.
|
|
81
85
|
Feedback should be OFF prior to entry, in order to prevent
|
|
82
86
|
feedback from making unnecessary corrections while beam is being adjusted."""
|
|
83
87
|
|
|
84
|
-
# DCM Pitch
|
|
88
|
+
# Adjust DCM Pitch
|
|
85
89
|
dcm = undulator_dcm.dcm
|
|
86
90
|
LOGGER.info(f"Adjusting DCM and VFM for {energy_kev} keV")
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
d_spacing_a: float = yield from bps.rd(undulator_dcm.dcm.crystal_metadata_d_spacing)
|
|
92
|
+
bragg_deg = energy_to_bragg_angle(energy_kev, d_spacing_a)
|
|
93
|
+
LOGGER.info(f"Target Bragg angle = {bragg_deg} degrees")
|
|
89
94
|
dcm_pitch_adjuster = lookup_table_adjuster(
|
|
90
95
|
linear_interpolation_lut(undulator_dcm.pitch_energy_table_path),
|
|
91
96
|
dcm.pitch_in_mrad,
|
|
@@ -119,7 +124,7 @@ def adjust_dcm_pitch_roll_vfm_from_lut(
|
|
|
119
124
|
# not sure how we check this
|
|
120
125
|
|
|
121
126
|
# VFM Stripe selection
|
|
122
|
-
yield from adjust_mirror_stripe(energy_kev, vfm,
|
|
127
|
+
yield from adjust_mirror_stripe(energy_kev, vfm, mirror_voltages)
|
|
123
128
|
yield from bps.wait(DCM_GROUP)
|
|
124
129
|
|
|
125
130
|
# VFM Adjust - for I03 this table always returns the same value
|
|
@@ -6,7 +6,6 @@ from dodal.devices.attenuator import Attenuator
|
|
|
6
6
|
from dodal.devices.dcm import DCM
|
|
7
7
|
from dodal.devices.eiger import EigerDetector
|
|
8
8
|
from dodal.devices.flux import Flux
|
|
9
|
-
from dodal.devices.robot import BartRobot
|
|
10
9
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
11
10
|
from dodal.devices.smargon import Smargon
|
|
12
11
|
from dodal.devices.synchrotron import Synchrotron
|
|
@@ -20,7 +19,7 @@ def read_hardware_pre_collection(
|
|
|
20
19
|
undulator: Undulator,
|
|
21
20
|
synchrotron: Synchrotron,
|
|
22
21
|
s4_slit_gaps: S4SlitGaps,
|
|
23
|
-
|
|
22
|
+
dcm: DCM,
|
|
24
23
|
smargon: Smargon,
|
|
25
24
|
):
|
|
26
25
|
LOGGER.info("Reading status of beamline for callbacks, pre collection.")
|
|
@@ -29,11 +28,12 @@ def read_hardware_pre_collection(
|
|
|
29
28
|
) # gives name to event *descriptor* document
|
|
30
29
|
yield from bps.read(undulator.current_gap)
|
|
31
30
|
yield from bps.read(synchrotron.synchrotron_mode)
|
|
32
|
-
yield from bps.read(s4_slit_gaps.xgap)
|
|
33
|
-
yield from bps.read(s4_slit_gaps.ygap)
|
|
31
|
+
yield from bps.read(s4_slit_gaps.xgap) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
32
|
+
yield from bps.read(s4_slit_gaps.ygap) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
34
33
|
yield from bps.read(smargon.x)
|
|
35
34
|
yield from bps.read(smargon.y)
|
|
36
35
|
yield from bps.read(smargon.z)
|
|
36
|
+
yield from bps.read(dcm.energy_in_kev)
|
|
37
37
|
yield from bps.save()
|
|
38
38
|
|
|
39
39
|
|
|
@@ -48,13 +48,7 @@ def read_hardware_during_collection(
|
|
|
48
48
|
yield from bps.create(name=CONST.DESCRIPTORS.HARDWARE_READ_DURING)
|
|
49
49
|
yield from bps.read(aperture_scatterguard)
|
|
50
50
|
yield from bps.read(attenuator.actual_transmission)
|
|
51
|
-
yield from bps.read(flux.flux_reading)
|
|
51
|
+
yield from bps.read(flux.flux_reading) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
52
52
|
yield from bps.read(dcm.energy_in_kev)
|
|
53
|
-
yield from bps.read(detector.bit_depth)
|
|
54
|
-
yield from bps.save()
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def read_hardware_for_zocalo(detector: EigerDetector):
|
|
58
|
-
yield from bps.create(name=CONST.DESCRIPTORS.ZOCALO_HW_READ)
|
|
59
|
-
yield from bps.read(detector.odin.file_writer.id)
|
|
53
|
+
yield from bps.read(detector.bit_depth) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
60
54
|
yield from bps.save()
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
from functools import partial
|
|
2
2
|
|
|
3
3
|
import bluesky.plan_stubs as bps
|
|
4
|
+
from dodal.devices.areadetector.plugins.CAM import ColorMode
|
|
4
5
|
from dodal.devices.oav.oav_detector import OAV
|
|
5
|
-
from dodal.devices.oav.oav_errors import OAVError_ZoomLevelNotFound
|
|
6
6
|
from dodal.devices.oav.oav_parameters import OAVParameters
|
|
7
7
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
8
|
-
from dodal.devices.oav.utils import ColorMode
|
|
9
8
|
|
|
10
9
|
from mx_bluesky.hyperion.parameters.constants import CONST
|
|
11
10
|
|
|
@@ -56,19 +55,14 @@ def setup_pin_tip_detection_params(
|
|
|
56
55
|
|
|
57
56
|
|
|
58
57
|
def setup_general_oav_params(oav: OAV, parameters: OAVParameters):
|
|
59
|
-
yield from set_using_group(oav.cam.color_mode, ColorMode.RGB1)
|
|
60
|
-
yield from set_using_group(oav.cam.acquire_period, parameters.acquire_period)
|
|
61
|
-
yield from set_using_group(oav.cam.acquire_time, parameters.exposure)
|
|
62
|
-
yield from set_using_group(oav.cam.gain, parameters.gain)
|
|
58
|
+
yield from set_using_group(oav.cam.color_mode, ColorMode.RGB1) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
59
|
+
yield from set_using_group(oav.cam.acquire_period, parameters.acquire_period) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
60
|
+
yield from set_using_group(oav.cam.acquire_time, parameters.exposure) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
61
|
+
yield from set_using_group(oav.cam.gain, parameters.gain) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
63
62
|
|
|
64
63
|
zoom_level_str = f"{float(parameters.zoom)}x"
|
|
65
|
-
if zoom_level_str not in oav.zoom_controller.allowed_zoom_levels:
|
|
66
|
-
raise OAVError_ZoomLevelNotFound(
|
|
67
|
-
f"Found {zoom_level_str} as a zoom level but expected one of {oav.zoom_controller.allowed_zoom_levels}"
|
|
68
|
-
)
|
|
69
|
-
|
|
70
64
|
yield from bps.abs_set(
|
|
71
|
-
oav.zoom_controller,
|
|
65
|
+
oav.zoom_controller, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
72
66
|
zoom_level_str,
|
|
73
67
|
wait=True,
|
|
74
68
|
)
|
|
@@ -20,6 +20,7 @@ from mx_bluesky.hyperion.log import LOGGER
|
|
|
20
20
|
MM_TO_ENCODER_COUNTS = 200000
|
|
21
21
|
GENERAL_TIMEOUT = 60
|
|
22
22
|
TICKS_PER_MS = 1000 # Panda sequencer prescaler will be set to us
|
|
23
|
+
PULSE_WIDTH_US = 50
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class Enabled(Enum):
|
|
@@ -76,8 +77,6 @@ def _get_seq_table(
|
|
|
76
77
|
|
|
77
78
|
delay_between_pulses = time_between_steps_ms * TICKS_PER_MS
|
|
78
79
|
|
|
79
|
-
PULSE_WIDTH_US = 1
|
|
80
|
-
|
|
81
80
|
assert delay_between_pulses > PULSE_WIDTH_US
|
|
82
81
|
|
|
83
82
|
# BITA_1 trigger wired from TTLIN1, this is the trigger input
|
|
@@ -6,13 +6,15 @@ import bluesky.preprocessors as bpp
|
|
|
6
6
|
from blueapi.core import MsgGenerator
|
|
7
7
|
from dodal.devices.zebra import (
|
|
8
8
|
AUTO_SHUTTER_GATE,
|
|
9
|
-
|
|
9
|
+
AUTO_SHUTTER_INPUT_1,
|
|
10
|
+
AUTO_SHUTTER_INPUT_2,
|
|
10
11
|
DISCONNECT,
|
|
11
12
|
IN1_TTL,
|
|
12
13
|
IN3_TTL,
|
|
13
14
|
IN4_TTL,
|
|
14
15
|
PC_GATE,
|
|
15
16
|
PC_PULSE,
|
|
17
|
+
SOFT_IN1,
|
|
16
18
|
TTL_DETECTOR,
|
|
17
19
|
TTL_PANDA,
|
|
18
20
|
TTL_XSPRESS3,
|
|
@@ -55,7 +57,7 @@ def bluesky_retry(func: Callable):
|
|
|
55
57
|
|
|
56
58
|
|
|
57
59
|
def arm_zebra(zebra: Zebra):
|
|
58
|
-
yield from bps.abs_set(zebra.pc.arm, ArmDemand.ARM, wait=True)
|
|
60
|
+
yield from bps.abs_set(zebra.pc.arm, ArmDemand.ARM, wait=True) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
59
61
|
|
|
60
62
|
|
|
61
63
|
def tidy_up_zebra_after_rotation_scan(
|
|
@@ -64,7 +66,7 @@ def tidy_up_zebra_after_rotation_scan(
|
|
|
64
66
|
group="tidy_up_zebra_after_rotation",
|
|
65
67
|
wait=True,
|
|
66
68
|
):
|
|
67
|
-
yield from bps.abs_set(zebra.pc.arm, ArmDemand.DISARM, group=group)
|
|
69
|
+
yield from bps.abs_set(zebra.pc.arm, ArmDemand.DISARM, group=group) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
68
70
|
yield from bps.abs_set(
|
|
69
71
|
zebra_shutter.control_mode, ZebraShutterControl.MANUAL, group=group
|
|
70
72
|
)
|
|
@@ -73,15 +75,45 @@ def tidy_up_zebra_after_rotation_scan(
|
|
|
73
75
|
|
|
74
76
|
|
|
75
77
|
def set_shutter_auto_input(zebra: Zebra, input: int, group="set_shutter_trigger"):
|
|
76
|
-
"""Set the
|
|
78
|
+
"""Set the signal that controls the shutter. We use the second input to the
|
|
79
|
+
Zebra's AND2 gate for this input. ZebraShutter control mode must be in auto for this input to take control
|
|
77
80
|
|
|
78
81
|
For more details see the ZebraShutter device."""
|
|
79
82
|
auto_shutter_control = zebra.logic_gates.and_gates[AUTO_SHUTTER_GATE]
|
|
80
83
|
yield from bps.abs_set(
|
|
81
|
-
auto_shutter_control.sources[
|
|
84
|
+
auto_shutter_control.sources[AUTO_SHUTTER_INPUT_2], input, group
|
|
82
85
|
)
|
|
83
86
|
|
|
84
87
|
|
|
88
|
+
def configure_zebra_and_shutter_for_auto_shutter(
|
|
89
|
+
zebra: Zebra, zebra_shutter: ZebraShutter, input: int, group="use_automatic_shutter"
|
|
90
|
+
):
|
|
91
|
+
"""Set the shutter to auto mode, and configure the zebra to trigger the shutter on
|
|
92
|
+
an input source. For the input, use one of the source constants in zebra.py
|
|
93
|
+
|
|
94
|
+
When the shutter is in auto/manual, logic in EPICS sets the Zebra's
|
|
95
|
+
SOFT_IN1 to low/high respectively. The Zebra's AND2 gate should be used to control the shutter while in auto mode.
|
|
96
|
+
To do this, we need (AND2 = SOFT_IN1 AND input), where input is the zebra signal we want to control the shutter when in auto mode.
|
|
97
|
+
"""
|
|
98
|
+
# See https://github.com/DiamondLightSource/dodal/issues/813 for better typing here.
|
|
99
|
+
|
|
100
|
+
# Set shutter to auto mode
|
|
101
|
+
yield from bps.abs_set(
|
|
102
|
+
zebra_shutter.control_mode, ZebraShutterControl.AUTO, group=group
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Set first input of AND2 gate to SOFT_IN1, which is high when shutter is in auto mode
|
|
106
|
+
# Note the Zebra should ALWAYS be setup this way. See https://github.com/DiamondLightSource/mx-bluesky/issues/551
|
|
107
|
+
yield from bps.abs_set(
|
|
108
|
+
zebra.logic_gates.and_gates[AUTO_SHUTTER_GATE].sources[AUTO_SHUTTER_INPUT_1],
|
|
109
|
+
SOFT_IN1,
|
|
110
|
+
group=group,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Set the second input of AND2 gate to the requested zebra input source
|
|
114
|
+
yield from set_shutter_auto_input(zebra, input, group=group)
|
|
115
|
+
|
|
116
|
+
|
|
85
117
|
@bluesky_retry
|
|
86
118
|
def setup_zebra_for_rotation(
|
|
87
119
|
zebra: Zebra,
|
|
@@ -137,11 +169,10 @@ def setup_zebra_for_rotation(
|
|
|
137
169
|
yield from bps.abs_set(zebra.pc.pulse_start, abs(shutter_opening_s), group=group)
|
|
138
170
|
# Set gate position to be angle of interest
|
|
139
171
|
yield from bps.abs_set(zebra.pc.gate_trigger, axis.value, group=group)
|
|
140
|
-
#
|
|
141
|
-
yield from
|
|
142
|
-
zebra_shutter
|
|
172
|
+
# Set shutter to automatic and to trigger via PC_GATE
|
|
173
|
+
yield from configure_zebra_and_shutter_for_auto_shutter(
|
|
174
|
+
zebra, zebra_shutter, PC_GATE, group=group
|
|
143
175
|
)
|
|
144
|
-
yield from set_shutter_auto_input(zebra, PC_GATE, group=group)
|
|
145
176
|
# Trigger the detector with a pulse
|
|
146
177
|
yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], PC_PULSE, group=group)
|
|
147
178
|
# Don't use the fluorescence detector
|
|
@@ -159,11 +190,12 @@ def setup_zebra_for_gridscan(
|
|
|
159
190
|
group="setup_zebra_for_gridscan",
|
|
160
191
|
wait=True,
|
|
161
192
|
):
|
|
162
|
-
|
|
163
|
-
yield from
|
|
164
|
-
zebra_shutter
|
|
193
|
+
# Set shutter to automatic and to trigger via motion controller GPIO signal (IN4_TTL)
|
|
194
|
+
yield from configure_zebra_and_shutter_for_auto_shutter(
|
|
195
|
+
zebra, zebra_shutter, IN4_TTL, group=group
|
|
165
196
|
)
|
|
166
|
-
|
|
197
|
+
|
|
198
|
+
yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], IN3_TTL, group=group)
|
|
167
199
|
yield from bps.abs_set(zebra.output.out_pvs[TTL_XSPRESS3], DISCONNECT, group=group)
|
|
168
200
|
yield from bps.abs_set(zebra.output.pulse_1.input, DISCONNECT, group=group)
|
|
169
201
|
|
|
@@ -198,11 +230,10 @@ def setup_zebra_for_panda_flyscan(
|
|
|
198
230
|
# Forwards eiger trigger signal from panda
|
|
199
231
|
yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], IN1_TTL, group=group)
|
|
200
232
|
|
|
201
|
-
#
|
|
202
|
-
yield from
|
|
203
|
-
zebra_shutter
|
|
233
|
+
# Set shutter to automatic and to trigger via motion controller GPIO signal (IN4_TTL)
|
|
234
|
+
yield from configure_zebra_and_shutter_for_auto_shutter(
|
|
235
|
+
zebra, zebra_shutter, IN4_TTL, group=group
|
|
204
236
|
)
|
|
205
|
-
yield from set_shutter_auto_input(zebra, IN4_TTL, group=group)
|
|
206
237
|
|
|
207
238
|
yield from bps.abs_set(zebra.output.out_pvs[TTL_XSPRESS3], DISCONNECT, group=group)
|
|
208
239
|
|
|
@@ -16,10 +16,10 @@ def move_smargon_warn_on_out_of_range(
|
|
|
16
16
|
"Pin tip centring failed - pin too long/short/bent and out of range"
|
|
17
17
|
)
|
|
18
18
|
yield from bps.mv(
|
|
19
|
-
smargon.x,
|
|
20
|
-
position[0],
|
|
21
|
-
smargon.y,
|
|
22
|
-
position[1],
|
|
23
|
-
smargon.z,
|
|
24
|
-
position[2],
|
|
19
|
+
smargon.x, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
20
|
+
position[0], # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
21
|
+
smargon.y, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
22
|
+
position[1], # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
23
|
+
smargon.z, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
24
|
+
position[2], # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
25
25
|
)
|
|
@@ -3,6 +3,10 @@ from collections.abc import Generator
|
|
|
3
3
|
from bluesky import plan_stubs as bps
|
|
4
4
|
from bluesky import preprocessors as bpp
|
|
5
5
|
from bluesky.utils import Msg
|
|
6
|
+
from dodal.devices.dcm import DCM
|
|
7
|
+
from dodal.devices.detector import (
|
|
8
|
+
DetectorParams,
|
|
9
|
+
)
|
|
6
10
|
from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState
|
|
7
11
|
from dodal.devices.eiger import EigerDetector
|
|
8
12
|
|
|
@@ -12,6 +16,13 @@ from mx_bluesky.hyperion.device_setup_plans.position_detector import (
|
|
|
12
16
|
)
|
|
13
17
|
|
|
14
18
|
|
|
19
|
+
def fill_in_energy_if_not_supplied(dcm: DCM, detector_params: DetectorParams):
|
|
20
|
+
if not detector_params.expected_energy_ev:
|
|
21
|
+
actual_energy_ev = 1000 * (yield from bps.rd(dcm.energy_in_kev))
|
|
22
|
+
detector_params.expected_energy_ev = actual_energy_ev
|
|
23
|
+
return detector_params
|
|
24
|
+
|
|
25
|
+
|
|
15
26
|
def start_preparing_data_collection_then_do_plan(
|
|
16
27
|
eiger: EigerDetector,
|
|
17
28
|
detector_motion: DetectorMotion,
|
|
@@ -30,7 +41,7 @@ def start_preparing_data_collection_then_do_plan(
|
|
|
30
41
|
"""
|
|
31
42
|
|
|
32
43
|
def wrapped_plan():
|
|
33
|
-
yield from bps.abs_set(eiger.do_arm, 1, group=group)
|
|
44
|
+
yield from bps.abs_set(eiger.do_arm, 1, group=group) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
34
45
|
if detector_distance_mm:
|
|
35
46
|
yield from set_detector_z_position(
|
|
36
47
|
detector_motion, detector_distance_mm, group
|
|
@@ -40,5 +51,5 @@ def start_preparing_data_collection_then_do_plan(
|
|
|
40
51
|
|
|
41
52
|
yield from bpp.contingency_wrapper(
|
|
42
53
|
wrapped_plan(),
|
|
43
|
-
except_plan=lambda e: (yield from bps.stop(eiger)),
|
|
54
|
+
except_plan=lambda e: (yield from bps.stop(eiger)), # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
44
55
|
)
|
|
@@ -23,14 +23,14 @@ def _check_and_pause_feedback(
|
|
|
23
23
|
turning XBPM feedback off.
|
|
24
24
|
|
|
25
25
|
"""
|
|
26
|
-
yield from bps.mv(attenuator, 1.0)
|
|
26
|
+
yield from bps.mv(attenuator, 1.0) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
27
27
|
LOGGER.info("Waiting for XBPM feedback to be stable")
|
|
28
28
|
yield from bps.trigger(xbpm_feedback, wait=True)
|
|
29
29
|
LOGGER.info(
|
|
30
30
|
f"XPBM feedback in position, pausing and setting transmission to {desired_transmission_fraction}"
|
|
31
31
|
)
|
|
32
|
-
yield from bps.mv(xbpm_feedback.pause_feedback, Pause.PAUSE)
|
|
33
|
-
yield from bps.mv(attenuator, desired_transmission_fraction)
|
|
32
|
+
yield from bps.mv(xbpm_feedback.pause_feedback, Pause.PAUSE) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
33
|
+
yield from bps.mv(attenuator, desired_transmission_fraction) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def _unpause_xbpm_feedback_and_set_transmission_to_1(
|
|
@@ -44,7 +44,7 @@ def _unpause_xbpm_feedback_and_set_transmission_to_1(
|
|
|
44
44
|
the beam in position
|
|
45
45
|
attenuator (Attenuator): The attenuator used to set transmission
|
|
46
46
|
"""
|
|
47
|
-
yield from bps.mv(xbpm_feedback.pause_feedback, Pause.RUN, attenuator, 1.0)
|
|
47
|
+
yield from bps.mv(xbpm_feedback.pause_feedback, Pause.RUN, attenuator, 1.0) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
def transmission_and_xbpm_feedback_for_collection_wrapper(
|