dls-dodal 1.43.0__py3-none-any.whl → 1.44.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.
- {dls_dodal-1.43.0.dist-info → dls_dodal-1.44.0.dist-info}/METADATA +4 -3
- {dls_dodal-1.43.0.dist-info → dls_dodal-1.44.0.dist-info}/RECORD +42 -34
- {dls_dodal-1.43.0.dist-info → dls_dodal-1.44.0.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamlines/b01_1.py +8 -0
- dodal/beamlines/i03.py +11 -0
- dodal/beamlines/i13_1.py +22 -48
- dodal/beamlines/i19_1.py +16 -5
- dodal/beamlines/i19_2.py +12 -3
- dodal/beamlines/i19_optics.py +4 -2
- dodal/common/data_util.py +20 -0
- dodal/common/signal_utils.py +43 -4
- dodal/devices/aperturescatterguard.py +3 -3
- dodal/devices/baton.py +17 -0
- dodal/devices/current_amplifiers/current_amplifier.py +1 -6
- dodal/devices/current_amplifiers/current_amplifier_detector.py +2 -2
- dodal/devices/current_amplifiers/femto.py +0 -5
- dodal/devices/current_amplifiers/sr570.py +0 -5
- dodal/devices/electron_analyser/__init__.py +0 -0
- dodal/devices/electron_analyser/base_region.py +64 -0
- dodal/devices/electron_analyser/specs/__init__.py +0 -0
- dodal/devices/electron_analyser/specs/specs_region.py +24 -0
- dodal/devices/electron_analyser/vgscienta/__init__.py +0 -0
- dodal/devices/electron_analyser/vgscienta/vgscienta_region.py +77 -0
- dodal/devices/fast_grid_scan.py +2 -2
- dodal/devices/i03/beamstop.py +2 -2
- dodal/devices/i13_1/merlin.py +1 -2
- dodal/devices/i13_1/merlin_controller.py +12 -8
- dodal/devices/i19/beamstop.py +30 -0
- dodal/devices/i19/hutch_access.py +2 -0
- dodal/devices/i19/shutter.py +52 -30
- dodal/devices/i22/nxsas.py +1 -3
- dodal/devices/i24/focus_mirrors.py +3 -3
- dodal/devices/i24/pilatus_metadata.py +2 -2
- dodal/devices/oav/oav_detector.py +7 -9
- dodal/devices/oav/snapshots/snapshot.py +21 -0
- dodal/devices/oav/snapshots/snapshot_image_processing.py +74 -0
- dodal/plan_stubs/motor_utils.py +10 -12
- dodal/utils.py +0 -7
- dodal/devices/i13_1/merlin_io.py +0 -17
- dodal/devices/oav/microns_for_zoom_levels.json +0 -55
- dodal/devices/oav/snapshots/snapshot_with_beam_centre.py +0 -64
- {dls_dodal-1.43.0.dist-info → dls_dodal-1.44.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.43.0.dist-info → dls_dodal-1.44.0.dist-info/licenses}/LICENSE +0 -0
- {dls_dodal-1.43.0.dist-info → dls_dodal-1.44.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from PIL import Image
|
|
2
|
+
|
|
3
|
+
from dodal.devices.areadetector.plugins.MJPG import MJPG
|
|
4
|
+
|
|
5
|
+
CROSSHAIR_LENGTH_PX = 20
|
|
6
|
+
CROSSHAIR_OUTLINE_COLOUR = "Black"
|
|
7
|
+
CROSSHAIR_FILL_COLOUR = "White"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Snapshot(MJPG):
|
|
11
|
+
"""A child of MJPG which, when triggered, saves the image to disk."""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
prefix: str,
|
|
16
|
+
name: str = "",
|
|
17
|
+
) -> None:
|
|
18
|
+
super().__init__(prefix, name)
|
|
19
|
+
|
|
20
|
+
async def post_processing(self, image: Image.Image):
|
|
21
|
+
await self._save_image(image)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from PIL import Image, ImageDraw
|
|
2
|
+
|
|
3
|
+
from dodal.devices.oav.utils import Pixel
|
|
4
|
+
|
|
5
|
+
CROSSHAIR_LENGTH_PX = 20
|
|
6
|
+
CROSSHAIR_OUTLINE_COLOUR = "Black"
|
|
7
|
+
CROSSHAIR_FILL_COLOUR = "White"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def draw_crosshair(image: Image.Image, beam_x: int, beam_y: int):
|
|
11
|
+
"""
|
|
12
|
+
Draw a crosshair at the beam centre coordinates specified.
|
|
13
|
+
Args:
|
|
14
|
+
image: The image to draw the crosshair onto. This is mutated.
|
|
15
|
+
beam_x: The x-coordinate of the crosshair (pixels)
|
|
16
|
+
beam_y: The y-coordinate of the crosshair (pixels)
|
|
17
|
+
"""
|
|
18
|
+
draw = ImageDraw.Draw(image)
|
|
19
|
+
OUTLINE_WIDTH = 1
|
|
20
|
+
HALF_LEN = CROSSHAIR_LENGTH_PX / 2
|
|
21
|
+
draw.rectangle(
|
|
22
|
+
[
|
|
23
|
+
beam_x - OUTLINE_WIDTH,
|
|
24
|
+
beam_y - HALF_LEN - OUTLINE_WIDTH,
|
|
25
|
+
beam_x + OUTLINE_WIDTH,
|
|
26
|
+
beam_y + HALF_LEN + OUTLINE_WIDTH,
|
|
27
|
+
],
|
|
28
|
+
fill=CROSSHAIR_OUTLINE_COLOUR,
|
|
29
|
+
)
|
|
30
|
+
draw.rectangle(
|
|
31
|
+
[
|
|
32
|
+
beam_x - HALF_LEN - OUTLINE_WIDTH,
|
|
33
|
+
beam_y - OUTLINE_WIDTH,
|
|
34
|
+
beam_x + HALF_LEN + OUTLINE_WIDTH,
|
|
35
|
+
beam_y + OUTLINE_WIDTH,
|
|
36
|
+
],
|
|
37
|
+
fill=CROSSHAIR_OUTLINE_COLOUR,
|
|
38
|
+
)
|
|
39
|
+
draw.line(
|
|
40
|
+
((beam_x, beam_y - HALF_LEN), (beam_x, beam_y + HALF_LEN)),
|
|
41
|
+
fill=CROSSHAIR_FILL_COLOUR,
|
|
42
|
+
)
|
|
43
|
+
draw.line(
|
|
44
|
+
((beam_x - HALF_LEN, beam_y), (beam_x + HALF_LEN, beam_y)),
|
|
45
|
+
fill=CROSSHAIR_FILL_COLOUR,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def compute_beam_centre_pixel_xy_for_mm_position(
|
|
50
|
+
sample_pos_mm: tuple[float, float],
|
|
51
|
+
beam_pos_at_origin_px: Pixel,
|
|
52
|
+
microns_per_pixel: tuple[float, float],
|
|
53
|
+
) -> Pixel:
|
|
54
|
+
"""
|
|
55
|
+
Compute the location of the beam centre in pixels on a reference image.
|
|
56
|
+
Args:
|
|
57
|
+
sample_pos_mm: x, y location of the sample in mm relative to when the reference image
|
|
58
|
+
was taken.
|
|
59
|
+
beam_pos_at_origin_px: x, y position of the beam centre in the reference image (pixels)
|
|
60
|
+
microns_per_pixel: x, y scaling factor relating the sample position to the position in the image.
|
|
61
|
+
Returns:
|
|
62
|
+
x, y location of the beam centre (pixels)
|
|
63
|
+
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def centre(sample_pos, beam_pos, um_per_px) -> int:
|
|
67
|
+
return beam_pos + sample_pos * 1000 / um_per_px
|
|
68
|
+
|
|
69
|
+
return Pixel(
|
|
70
|
+
centre(sp, bp, mpp)
|
|
71
|
+
for sp, bp, mpp in zip(
|
|
72
|
+
sample_pos_mm, beam_pos_at_origin_px, microns_per_pixel, strict=True
|
|
73
|
+
)
|
|
74
|
+
)
|
dodal/plan_stubs/motor_utils.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import uuid
|
|
2
2
|
from collections.abc import Generator
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from bluesky import plan_stubs as bps
|
|
6
6
|
from bluesky.preprocessors import finalize_wrapper, pchain
|
|
@@ -8,14 +8,14 @@ from bluesky.utils import Msg, MsgGenerator, make_decorator
|
|
|
8
8
|
from ophyd_async.core import Device
|
|
9
9
|
from ophyd_async.epics.motor import Motor
|
|
10
10
|
|
|
11
|
-
from dodal.utils import MovableReadable
|
|
12
|
-
|
|
13
|
-
MovableReadableDevice = TypeVar("MovableReadableDevice", bound=MovableReadable)
|
|
14
|
-
|
|
15
11
|
|
|
16
12
|
class MoveTooLarge(Exception):
|
|
17
13
|
def __init__(
|
|
18
|
-
self,
|
|
14
|
+
self,
|
|
15
|
+
axis: Motor,
|
|
16
|
+
maximum_move: float,
|
|
17
|
+
position: float,
|
|
18
|
+
*args: object,
|
|
19
19
|
) -> None:
|
|
20
20
|
self.axis = axis
|
|
21
21
|
self.maximum_move = maximum_move
|
|
@@ -24,10 +24,10 @@ class MoveTooLarge(Exception):
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def check_and_cache_values(
|
|
27
|
-
devices_and_positions: dict[
|
|
27
|
+
devices_and_positions: dict[Motor, float],
|
|
28
28
|
smallest_move: float,
|
|
29
29
|
maximum_move: float,
|
|
30
|
-
) -> Generator[Msg, Any, dict[
|
|
30
|
+
) -> Generator[Msg, Any, dict[Motor, float]]:
|
|
31
31
|
"""Caches the positions of all Motors on specified device if they are within
|
|
32
32
|
smallest_move of home_position. Throws MoveTooLarge if they are outside maximum_move
|
|
33
33
|
of the home_position
|
|
@@ -51,9 +51,7 @@ def home_and_reset_wrapper(
|
|
|
51
51
|
wait_for_all: bool = True,
|
|
52
52
|
) -> MsgGenerator:
|
|
53
53
|
home_positions = {
|
|
54
|
-
|
|
55
|
-
for _, axis in device.children()
|
|
56
|
-
if isinstance(axis, Motor)
|
|
54
|
+
axis: 0.0 for _, axis in device.children() if isinstance(axis, Motor)
|
|
57
55
|
}
|
|
58
56
|
return move_and_reset_wrapper(
|
|
59
57
|
plan, home_positions, smallest_move, maximum_move, group, wait_for_all
|
|
@@ -62,7 +60,7 @@ def home_and_reset_wrapper(
|
|
|
62
60
|
|
|
63
61
|
def move_and_reset_wrapper(
|
|
64
62
|
plan: MsgGenerator,
|
|
65
|
-
device_and_positions: dict[
|
|
63
|
+
device_and_positions: dict[Motor, float],
|
|
66
64
|
smallest_move: float,
|
|
67
65
|
maximum_move: float,
|
|
68
66
|
group: str | None = None,
|
dodal/utils.py
CHANGED
|
@@ -15,11 +15,9 @@ from types import ModuleType
|
|
|
15
15
|
from typing import (
|
|
16
16
|
Any,
|
|
17
17
|
Generic,
|
|
18
|
-
Protocol,
|
|
19
18
|
TypeAlias,
|
|
20
19
|
TypeGuard,
|
|
21
20
|
TypeVar,
|
|
22
|
-
runtime_checkable,
|
|
23
21
|
)
|
|
24
22
|
|
|
25
23
|
from bluesky.protocols import (
|
|
@@ -62,11 +60,6 @@ BLUESKY_PROTOCOLS = [
|
|
|
62
60
|
Triggerable,
|
|
63
61
|
]
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
@runtime_checkable
|
|
67
|
-
class MovableReadable(Movable, Readable, Protocol): ...
|
|
68
|
-
|
|
69
|
-
|
|
70
63
|
AnyDevice: TypeAlias = OphydV1Device | OphydV2Device
|
|
71
64
|
V1DeviceFactory: TypeAlias = Callable[..., OphydV1Device]
|
|
72
65
|
V2DeviceFactory: TypeAlias = Callable[..., OphydV2Device]
|
dodal/devices/i13_1/merlin_io.py
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
from ophyd_async.core import StrictEnum
|
|
2
|
-
from ophyd_async.epics import adcore
|
|
3
|
-
from ophyd_async.epics.core import epics_signal_rw_rbv
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class MerlinImageMode(StrictEnum):
|
|
7
|
-
SINGLE = "Single"
|
|
8
|
-
MULTIPLE = "Multiple"
|
|
9
|
-
CONTINUOUS = "Continuous"
|
|
10
|
-
THRESHOLD = "Threshold"
|
|
11
|
-
BACKGROUND = "Background"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class MerlinDriverIO(adcore.ADBaseIO):
|
|
15
|
-
def __init__(self, prefix: str, name: str = "") -> None:
|
|
16
|
-
super().__init__(prefix, name)
|
|
17
|
-
self.image_mode = epics_signal_rw_rbv(MerlinImageMode, prefix + "ImageMode")
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"XRatio": 0.485,
|
|
3
|
-
"YRatio": 0.353,
|
|
4
|
-
"tolerance": 1.0,
|
|
5
|
-
"1.0": {
|
|
6
|
-
"position": 1.0,
|
|
7
|
-
"micronsPerXPixel": 2.309,
|
|
8
|
-
"micronsPerYPixel": 3.266
|
|
9
|
-
},
|
|
10
|
-
"2.0": {
|
|
11
|
-
"position": 2.0,
|
|
12
|
-
"micronsPerXPixel": 1.775,
|
|
13
|
-
"micronsPerYPixel": 2.493
|
|
14
|
-
},
|
|
15
|
-
"3.0": {
|
|
16
|
-
"position": 3.0,
|
|
17
|
-
"micronsPerXPixel": 1.334,
|
|
18
|
-
"micronsPerYPixel": 1.856
|
|
19
|
-
},
|
|
20
|
-
"4.0": {
|
|
21
|
-
"position": 4.0,
|
|
22
|
-
"micronsPerXPixel": 1.037,
|
|
23
|
-
"micronsPerYPixel": 1.425
|
|
24
|
-
},
|
|
25
|
-
"5.0": {
|
|
26
|
-
"position": 5.0,
|
|
27
|
-
"micronsPerXPixel": 0.798,
|
|
28
|
-
"micronsPerYPixel": 1.091
|
|
29
|
-
},
|
|
30
|
-
"6.0": {
|
|
31
|
-
"position": 6.0,
|
|
32
|
-
"micronsPerXPixel": 0.627,
|
|
33
|
-
"micronsPerYPixel": 0.870
|
|
34
|
-
},
|
|
35
|
-
"7.0": {
|
|
36
|
-
"position": 7.0,
|
|
37
|
-
"micronsPerXPixel": 0.487,
|
|
38
|
-
"micronsPerYPixel": 0.666
|
|
39
|
-
},
|
|
40
|
-
"8.0": {
|
|
41
|
-
"position": 8.0,
|
|
42
|
-
"micronsPerXPixel": 0.379,
|
|
43
|
-
"micronsPerYPixel": 0.516
|
|
44
|
-
},
|
|
45
|
-
"9.0": {
|
|
46
|
-
"position": 9.0,
|
|
47
|
-
"micronsPerXPixel": 0.289,
|
|
48
|
-
"micronsPerYPixel": 0.405
|
|
49
|
-
},
|
|
50
|
-
"10.0": {
|
|
51
|
-
"position": 10.0,
|
|
52
|
-
"micronsPerXPixel": 0.227,
|
|
53
|
-
"micronsPerYPixel": 0.314
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
from ophyd_async.core import Reference, SignalR
|
|
2
|
-
from PIL import Image, ImageDraw
|
|
3
|
-
|
|
4
|
-
from dodal.devices.areadetector.plugins.MJPG import MJPG
|
|
5
|
-
|
|
6
|
-
CROSSHAIR_LENGTH_PX = 20
|
|
7
|
-
CROSSHAIR_OUTLINE_COLOUR = "Black"
|
|
8
|
-
CROSSHAIR_FILL_COLOUR = "White"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def draw_crosshair(image: Image.Image, beam_x: int, beam_y: int):
|
|
12
|
-
draw = ImageDraw.Draw(image)
|
|
13
|
-
OUTLINE_WIDTH = 1
|
|
14
|
-
HALF_LEN = CROSSHAIR_LENGTH_PX / 2
|
|
15
|
-
draw.rectangle(
|
|
16
|
-
[
|
|
17
|
-
beam_x - OUTLINE_WIDTH,
|
|
18
|
-
beam_y - HALF_LEN - OUTLINE_WIDTH,
|
|
19
|
-
beam_x + OUTLINE_WIDTH,
|
|
20
|
-
beam_y + HALF_LEN + OUTLINE_WIDTH,
|
|
21
|
-
],
|
|
22
|
-
fill=CROSSHAIR_OUTLINE_COLOUR,
|
|
23
|
-
)
|
|
24
|
-
draw.rectangle(
|
|
25
|
-
[
|
|
26
|
-
beam_x - HALF_LEN - OUTLINE_WIDTH,
|
|
27
|
-
beam_y - OUTLINE_WIDTH,
|
|
28
|
-
beam_x + HALF_LEN + OUTLINE_WIDTH,
|
|
29
|
-
beam_y + OUTLINE_WIDTH,
|
|
30
|
-
],
|
|
31
|
-
fill=CROSSHAIR_OUTLINE_COLOUR,
|
|
32
|
-
)
|
|
33
|
-
draw.line(
|
|
34
|
-
((beam_x, beam_y - HALF_LEN), (beam_x, beam_y + HALF_LEN)),
|
|
35
|
-
fill=CROSSHAIR_FILL_COLOUR,
|
|
36
|
-
)
|
|
37
|
-
draw.line(
|
|
38
|
-
((beam_x - HALF_LEN, beam_y), (beam_x + HALF_LEN, beam_y)),
|
|
39
|
-
fill=CROSSHAIR_FILL_COLOUR,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class SnapshotWithBeamCentre(MJPG):
|
|
44
|
-
"""A child of MJPG which, when triggered, draws an outlined crosshair at the beam
|
|
45
|
-
centre in the image and saves the image to disk."""
|
|
46
|
-
|
|
47
|
-
def __init__(
|
|
48
|
-
self,
|
|
49
|
-
prefix: str,
|
|
50
|
-
beam_x_signal: SignalR,
|
|
51
|
-
beam_y_signal: SignalR,
|
|
52
|
-
name: str = "",
|
|
53
|
-
) -> None:
|
|
54
|
-
with self.add_children_as_readables():
|
|
55
|
-
self._beam_centre_i_ref = Reference(beam_x_signal)
|
|
56
|
-
self._beam_centre_j_ref = Reference(beam_y_signal)
|
|
57
|
-
super().__init__(prefix, name)
|
|
58
|
-
|
|
59
|
-
async def post_processing(self, image: Image.Image):
|
|
60
|
-
beam_x = await self._beam_centre_i_ref().get_value()
|
|
61
|
-
beam_y = await self._beam_centre_j_ref().get_value()
|
|
62
|
-
draw_crosshair(image, beam_x, beam_y)
|
|
63
|
-
|
|
64
|
-
await self._save_image(image)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|