dls-dodal 1.30.0__py3-none-any.whl → 1.31.1__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.
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.1.dist-info}/METADATA +4 -4
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.1.dist-info}/RECORD +65 -63
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.1.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamline_specific_utils/i03.py +1 -4
- dodal/beamlines/__init__.py +4 -0
- dodal/beamlines/i03.py +8 -8
- dodal/beamlines/i04.py +10 -9
- dodal/beamlines/i13_1.py +7 -7
- dodal/beamlines/i22.py +18 -18
- dodal/beamlines/p38.py +14 -14
- dodal/beamlines/p45.py +11 -11
- dodal/beamlines/training_rig.py +64 -0
- dodal/common/beamlines/beamline_parameters.py +5 -4
- dodal/common/beamlines/beamline_utils.py +9 -9
- dodal/common/types.py +4 -2
- dodal/common/udc_directory_provider.py +29 -22
- dodal/common/visit.py +59 -60
- dodal/devices/CTAB.py +1 -1
- dodal/devices/aperture.py +1 -1
- dodal/devices/aperturescatterguard.py +140 -188
- dodal/devices/areadetector/plugins/MJPG.py +2 -1
- dodal/devices/backlight.py +12 -1
- dodal/devices/dcm.py +1 -1
- dodal/devices/detector/detector.py +31 -30
- dodal/devices/detector/detector_motion.py +1 -1
- dodal/devices/fast_grid_scan.py +14 -24
- dodal/devices/focusing_mirror.py +2 -2
- dodal/devices/i22/dcm.py +1 -1
- dodal/devices/i22/fswitch.py +6 -2
- dodal/devices/i22/nxsas.py +32 -11
- dodal/devices/i24/aperture.py +1 -1
- dodal/devices/i24/beamstop.py +1 -1
- dodal/devices/i24/dcm.py +1 -1
- dodal/devices/i24/i24_detector_motion.py +1 -1
- dodal/devices/i24/pmac.py +24 -8
- dodal/devices/linkam3.py +1 -1
- dodal/devices/motors.py +1 -1
- dodal/devices/oav/oav_to_redis_forwarder.py +46 -17
- dodal/devices/robot.py +1 -2
- dodal/devices/scatterguard.py +1 -1
- dodal/devices/scintillator.py +1 -1
- dodal/devices/slits.py +1 -1
- dodal/devices/smargon.py +1 -1
- dodal/devices/tetramm.py +20 -16
- dodal/devices/training_rig/__init__.py +0 -0
- dodal/devices/training_rig/sample_stage.py +10 -0
- dodal/devices/turbo_slit.py +1 -1
- dodal/devices/undulator.py +1 -1
- dodal/devices/util/adjuster_plans.py +1 -1
- dodal/devices/util/lookup_tables.py +1 -1
- dodal/devices/util/save_panda.py +1 -1
- dodal/devices/util/test_utils.py +1 -1
- dodal/devices/xbpm_feedback.py +1 -2
- dodal/devices/xspress3/xspress3.py +1 -1
- dodal/devices/zebra.py +5 -0
- dodal/devices/zebra_controlled_shutter.py +24 -9
- dodal/devices/zocalo/zocalo_results.py +6 -2
- dodal/log.py +32 -10
- dodal/plans/check_topup.py +65 -10
- dodal/plans/data_session_metadata.py +8 -10
- dodal/plans/motor_util_plans.py +1 -1
- dodal/devices/beamstop.py +0 -8
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.1.dist-info}/LICENSE +0 -0
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.1.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.1.dist-info}/top_level.txt +0 -0
|
@@ -11,8 +11,12 @@ import workflows.recipe
|
|
|
11
11
|
import workflows.transport
|
|
12
12
|
from bluesky.protocols import Descriptor, Triggerable
|
|
13
13
|
from numpy.typing import NDArray
|
|
14
|
-
from ophyd_async.core import
|
|
15
|
-
|
|
14
|
+
from ophyd_async.core import (
|
|
15
|
+
AsyncStatus,
|
|
16
|
+
HintedSignal,
|
|
17
|
+
StandardReadable,
|
|
18
|
+
soft_signal_r_and_setter,
|
|
19
|
+
)
|
|
16
20
|
from workflows.transport.common_transport import CommonTransport
|
|
17
21
|
|
|
18
22
|
from dodal.devices.zocalo.zocalo_interaction import _get_zocalo_connection
|
dodal/log.py
CHANGED
|
@@ -8,28 +8,50 @@ from os import environ
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import TypedDict
|
|
10
10
|
|
|
11
|
+
import colorlog
|
|
11
12
|
from bluesky.log import logger as bluesky_logger
|
|
12
13
|
from graypy import GELFTCPHandler
|
|
13
14
|
from ophyd.log import logger as ophyd_logger
|
|
14
|
-
from ophyd_async.log import (
|
|
15
|
-
DEFAULT_DATE_FORMAT,
|
|
16
|
-
DEFAULT_FORMAT,
|
|
17
|
-
DEFAULT_LOG_COLORS,
|
|
18
|
-
ColoredFormatterWithDeviceName,
|
|
19
|
-
)
|
|
20
|
-
from ophyd_async.log import logger as ophyd_async_logger
|
|
21
15
|
|
|
22
16
|
LOGGER = logging.getLogger("Dodal")
|
|
17
|
+
# Temporarily duplicated https://github.com/bluesky/ophyd-async/issues/550
|
|
18
|
+
ophyd_async_logger = logging.getLogger("ophyd_async")
|
|
23
19
|
LOGGER.setLevel(logging.DEBUG)
|
|
24
20
|
|
|
25
|
-
DEFAULT_FORMATTER = ColoredFormatterWithDeviceName(
|
|
26
|
-
fmt=DEFAULT_FORMAT, datefmt=DEFAULT_DATE_FORMAT, log_colors=DEFAULT_LOG_COLORS
|
|
27
|
-
)
|
|
28
21
|
ERROR_LOG_BUFFER_LINES = 20000
|
|
29
22
|
INFO_LOG_DAYS = 30
|
|
30
23
|
DEBUG_LOG_FILES_TO_KEEP = 7
|
|
31
24
|
DEFAULT_GRAYLOG_PORT = 12231
|
|
32
25
|
|
|
26
|
+
# Temporarily duplicated https://github.com/bluesky/ophyd-async/issues/550
|
|
27
|
+
DEFAULT_FORMAT = (
|
|
28
|
+
"%(log_color)s[%(levelname)1.1s %(asctime)s.%(msecs)03d "
|
|
29
|
+
"%(module)s:%(lineno)d] %(message)s"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
DEFAULT_DATE_FORMAT = "%y%m%d %H:%M:%S"
|
|
33
|
+
|
|
34
|
+
DEFAULT_LOG_COLORS = {
|
|
35
|
+
"DEBUG": "cyan",
|
|
36
|
+
"INFO": "green",
|
|
37
|
+
"WARNING": "yellow",
|
|
38
|
+
"ERROR": "red",
|
|
39
|
+
"CRITICAL": "red,bg_white",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ColoredFormatterWithDeviceName(colorlog.ColoredFormatter):
|
|
44
|
+
def format(self, record):
|
|
45
|
+
message = super().format(record)
|
|
46
|
+
if device_name := getattr(record, "ophyd_async_device_name", None):
|
|
47
|
+
message = f"[{device_name}]{message}"
|
|
48
|
+
return message
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
DEFAULT_FORMATTER = ColoredFormatterWithDeviceName(
|
|
52
|
+
fmt=DEFAULT_FORMAT, datefmt=DEFAULT_DATE_FORMAT, log_colors=DEFAULT_LOG_COLORS
|
|
53
|
+
)
|
|
54
|
+
|
|
33
55
|
|
|
34
56
|
class CircularMemoryHandler(logging.Handler):
|
|
35
57
|
"""Loosely based on the MemoryHandler, which keeps a buffer and writes it when full
|
dodal/plans/check_topup.py
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
1
3
|
import bluesky.plan_stubs as bps
|
|
2
4
|
|
|
5
|
+
from dodal.common.beamlines.beamline_parameters import (
|
|
6
|
+
get_beamline_parameters,
|
|
7
|
+
)
|
|
3
8
|
from dodal.devices.synchrotron import Synchrotron, SynchrotronMode
|
|
4
9
|
from dodal.log import LOGGER
|
|
5
10
|
|
|
@@ -7,6 +12,20 @@ ALLOWED_MODES = [SynchrotronMode.USER, SynchrotronMode.SPECIAL]
|
|
|
7
12
|
DECAY_MODE_COUNTDOWN = -1 # Value of the start_countdown PV when in decay mode
|
|
8
13
|
COUNTDOWN_DURING_TOPUP = 0
|
|
9
14
|
|
|
15
|
+
DEFAULT_THRESHOLD_EXPOSURE_S = 120
|
|
16
|
+
DEFAULT_TOPUP_GATE_DELAY_S = 1
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TopupConfig:
|
|
20
|
+
# For planned exposures less than this value, wait for topup to finish instead of
|
|
21
|
+
# collecting throughout topup.
|
|
22
|
+
THRESHOLD_EXPOSURE_S = "dodal_topup_threshold_exposure_s"
|
|
23
|
+
# Additional configurable safety margin to wait after the end of topup, as the start
|
|
24
|
+
# and end countdowns do not have the same precision, and in addition we want to be sure
|
|
25
|
+
# that collection does not overlap with any transients that may occur after the
|
|
26
|
+
# nominal endpoint.
|
|
27
|
+
TOPUP_GATE_DELAY_S = "dodal_topup_end_delay_s"
|
|
28
|
+
|
|
10
29
|
|
|
11
30
|
def _in_decay_mode(time_to_topup):
|
|
12
31
|
if time_to_topup == DECAY_MODE_COUNTDOWN:
|
|
@@ -23,15 +42,38 @@ def _gating_permitted(machine_mode: SynchrotronMode):
|
|
|
23
42
|
return False
|
|
24
43
|
|
|
25
44
|
|
|
26
|
-
def _delay_to_avoid_topup(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
45
|
+
def _delay_to_avoid_topup(
|
|
46
|
+
total_run_time_s: float,
|
|
47
|
+
time_to_topup_s: float,
|
|
48
|
+
topup_configuration: dict,
|
|
49
|
+
total_exposure_time_s: float,
|
|
50
|
+
) -> bool:
|
|
51
|
+
"""Determine whether we should delay collection until after a topup. Generally
|
|
52
|
+
if a topup is due to occur during the collection we will delay collection until after the topup.
|
|
53
|
+
However for long-running collections, impact of the topup is potentially less and collection-duration may be
|
|
54
|
+
a significant fraction of the topup-interval, therefore we may wish to collect during a topup.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
total_run_time_s: Anticipated time until end of the collection in seconds
|
|
58
|
+
time_to_topup_s: Time to the start of the topup as measured from the PV
|
|
59
|
+
topup_configuration: configuration dictionary
|
|
60
|
+
total_exposure_time_s: Total exposure time of the sample in s"""
|
|
61
|
+
if total_run_time_s > time_to_topup_s:
|
|
62
|
+
limit_s = topup_configuration.get(
|
|
63
|
+
TopupConfig.THRESHOLD_EXPOSURE_S, DEFAULT_THRESHOLD_EXPOSURE_S
|
|
33
64
|
)
|
|
34
|
-
|
|
65
|
+
gate = total_exposure_time_s < limit_s
|
|
66
|
+
if gate:
|
|
67
|
+
LOGGER.info(f"""
|
|
68
|
+
Exposure time of {total_exposure_time_s}s below the threshold of {limit_s}s.
|
|
69
|
+
Collection delayed until topup done.
|
|
70
|
+
""")
|
|
71
|
+
else:
|
|
72
|
+
LOGGER.info(f"""
|
|
73
|
+
Exposure time of {total_exposure_time_s}s meets the threshold of {limit_s}s.
|
|
74
|
+
Collection proceeding through topup.
|
|
75
|
+
""")
|
|
76
|
+
return gate
|
|
35
77
|
LOGGER.info(
|
|
36
78
|
"""
|
|
37
79
|
Total run time less than time to next topup. Proceeding with collection.
|
|
@@ -71,12 +113,25 @@ def check_topup_and_wait_if_necessary(
|
|
|
71
113
|
return
|
|
72
114
|
tot_run_time = total_exposure_time + ops_time
|
|
73
115
|
end_topup = yield from bps.rd(synchrotron.top_up_end_countdown)
|
|
74
|
-
|
|
75
|
-
|
|
116
|
+
topup_configuration = _load_topup_configuration_from_properties_file()
|
|
117
|
+
should_wait = _delay_to_avoid_topup(
|
|
118
|
+
tot_run_time,
|
|
119
|
+
time_to_topup,
|
|
120
|
+
topup_configuration,
|
|
121
|
+
total_exposure_time,
|
|
122
|
+
)
|
|
123
|
+
topup_gate_delay = topup_configuration.get(
|
|
124
|
+
TopupConfig.TOPUP_GATE_DELAY_S, DEFAULT_TOPUP_GATE_DELAY_S
|
|
76
125
|
)
|
|
126
|
+
time_to_wait = end_topup + topup_gate_delay if should_wait else 0.0
|
|
77
127
|
|
|
78
128
|
yield from bps.sleep(time_to_wait)
|
|
79
129
|
|
|
80
130
|
check_start = yield from bps.rd(synchrotron.top_up_start_countdown)
|
|
81
131
|
if check_start == COUNTDOWN_DURING_TOPUP:
|
|
82
132
|
yield from wait_for_topup_complete(synchrotron)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _load_topup_configuration_from_properties_file() -> dict[str, Any]:
|
|
136
|
+
params = get_beamline_parameters()
|
|
137
|
+
return params.params
|
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
from bluesky import plan_stubs as bps
|
|
2
2
|
from bluesky import preprocessors as bpp
|
|
3
3
|
from bluesky.utils import make_decorator
|
|
4
|
-
from ophyd_async.core import DirectoryInfo
|
|
5
4
|
|
|
6
5
|
from dodal.common.beamlines import beamline_utils
|
|
7
|
-
from dodal.common.types import MsgGenerator,
|
|
6
|
+
from dodal.common.types import MsgGenerator, UpdatingPathProvider
|
|
8
7
|
|
|
9
8
|
DATA_SESSION = "data_session"
|
|
10
9
|
DATA_GROUPS = "data_groups"
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
def attach_data_session_metadata_wrapper(
|
|
14
|
-
plan: MsgGenerator, provider:
|
|
13
|
+
plan: MsgGenerator, provider: UpdatingPathProvider | None = None
|
|
15
14
|
) -> MsgGenerator:
|
|
16
15
|
"""
|
|
17
16
|
Attach data session metadata to the runs within a plan and make it correlate
|
|
18
|
-
with an ophyd-async
|
|
17
|
+
with an ophyd-async PathProvider.
|
|
19
18
|
|
|
20
|
-
This updates the
|
|
19
|
+
This updates the path provider (which in turn makes a call to to a service
|
|
21
20
|
to figure out which scan number we are using for such a scan), and ensures the
|
|
22
21
|
start document contains the correct data session.
|
|
23
22
|
|
|
24
23
|
Args:
|
|
25
24
|
plan: The plan to preprocess
|
|
26
|
-
provider: The
|
|
25
|
+
provider: The path provider that participating detectors are aware of.
|
|
27
26
|
|
|
28
27
|
Returns:
|
|
29
28
|
MsgGenerator: A plan
|
|
@@ -32,13 +31,12 @@ def attach_data_session_metadata_wrapper(
|
|
|
32
31
|
Iterator[Msg]: Plan messages
|
|
33
32
|
"""
|
|
34
33
|
if provider is None:
|
|
35
|
-
provider = beamline_utils.
|
|
34
|
+
provider = beamline_utils.get_path_provider()
|
|
36
35
|
yield from bps.wait_for([provider.update])
|
|
37
|
-
|
|
36
|
+
ress = yield from bps.wait_for([provider.data_session])
|
|
37
|
+
data_session = ress[0].result()
|
|
38
38
|
# https://github.com/DiamondLightSource/dodal/issues/452
|
|
39
39
|
# As part of 452, write each dataCollection into their own folder, then can use resource_dir directly
|
|
40
|
-
assert directory_info.prefix is not None
|
|
41
|
-
data_session = directory_info.prefix.removesuffix("-")
|
|
42
40
|
yield from bpp.inject_md_wrapper(plan, md={DATA_SESSION: data_session})
|
|
43
41
|
|
|
44
42
|
|
dodal/plans/motor_util_plans.py
CHANGED
|
@@ -6,7 +6,7 @@ from bluesky import plan_stubs as bps
|
|
|
6
6
|
from bluesky.preprocessors import finalize_wrapper, pchain
|
|
7
7
|
from bluesky.utils import Msg, make_decorator
|
|
8
8
|
from ophyd_async.core import Device
|
|
9
|
-
from ophyd_async.epics.
|
|
9
|
+
from ophyd_async.epics.motor import Motor
|
|
10
10
|
|
|
11
11
|
from dodal.common import MsgGenerator
|
|
12
12
|
|
dodal/devices/beamstop.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|