dls-dodal 1.50.0__py3-none-any.whl → 1.51.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.50.0.dist-info → dls_dodal-1.51.0.dist-info}/METADATA +3 -4
- {dls_dodal-1.50.0.dist-info → dls_dodal-1.51.0.dist-info}/RECORD +63 -59
- dodal/_version.py +2 -2
- dodal/beamlines/adsim.py +5 -3
- dodal/beamlines/b01_1.py +41 -5
- dodal/beamlines/b07.py +11 -1
- dodal/beamlines/b07_1.py +11 -1
- dodal/beamlines/b16.py +8 -4
- dodal/beamlines/b21.py +148 -0
- dodal/beamlines/i03.py +6 -11
- dodal/beamlines/i04.py +5 -5
- dodal/beamlines/i09.py +22 -1
- dodal/beamlines/i09_1.py +9 -1
- dodal/beamlines/i09_2.py +24 -0
- dodal/beamlines/i10.py +5 -6
- dodal/beamlines/i13_1.py +5 -5
- dodal/beamlines/i18.py +5 -6
- dodal/beamlines/i22.py +7 -1
- dodal/beamlines/i24.py +3 -3
- dodal/beamlines/p45.py +4 -3
- dodal/beamlines/p60.py +18 -1
- dodal/beamlines/p99.py +5 -5
- dodal/beamlines/training_rig.py +3 -3
- dodal/common/beamlines/beamline_utils.py +5 -2
- dodal/devices/aithre_lasershaping/goniometer.py +4 -5
- dodal/devices/aperture.py +4 -7
- dodal/devices/aperturescatterguard.py +2 -2
- dodal/devices/b07/__init__.py +3 -0
- dodal/devices/b07/grating.py +9 -0
- dodal/devices/b07_1/__init__.py +3 -0
- dodal/devices/b07_1/grating.py +10 -0
- dodal/devices/detector/detector_motion.py +19 -17
- dodal/devices/electron_analyser/abstract/base_driver_io.py +24 -25
- dodal/devices/electron_analyser/detector.py +3 -13
- dodal/devices/electron_analyser/specs/detector.py +9 -3
- dodal/devices/electron_analyser/specs/driver_io.py +5 -2
- dodal/devices/electron_analyser/vgscienta/detector.py +9 -3
- dodal/devices/electron_analyser/vgscienta/driver_io.py +5 -6
- dodal/devices/electron_analyser/vgscienta/region.py +0 -1
- dodal/devices/fast_grid_scan.py +1 -2
- dodal/devices/i04/constants.py +1 -1
- dodal/devices/i09/__init__.py +4 -0
- dodal/devices/i09/dcm.py +26 -0
- dodal/devices/i09/grating.py +7 -0
- dodal/devices/i10/mirrors.py +4 -6
- dodal/devices/i10/rasor/rasor_motors.py +0 -14
- dodal/devices/i19/beamstop.py +3 -7
- dodal/devices/i24/aperture.py +4 -6
- dodal/devices/i24/beamstop.py +5 -8
- dodal/devices/i24/pmac.py +4 -8
- dodal/devices/motors.py +92 -35
- dodal/devices/p45.py +0 -12
- dodal/devices/p60/__init__.py +3 -0
- dodal/devices/p60/lab_xray_source.py +21 -0
- dodal/devices/pgm.py +1 -1
- dodal/devices/robot.py +11 -7
- dodal/devices/smargon.py +8 -9
- dodal/devices/zocalo/zocalo_results.py +27 -78
- dodal/plans/configure_arm_trigger_and_disarm_detector.py +7 -5
- dodal/devices/adsim.py +0 -13
- dodal/devices/i18/table.py +0 -14
- dodal/devices/i18/thor_labs_stage.py +0 -12
- dodal/devices/i24/i24_detector_motion.py +0 -12
- dodal/devices/scatterguard.py +0 -11
- dodal/devices/training_rig/__init__.py +0 -0
- dodal/devices/training_rig/sample_stage.py +0 -10
- {dls_dodal-1.50.0.dist-info → dls_dodal-1.51.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.50.0.dist-info → dls_dodal-1.51.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.50.0.dist-info → dls_dodal-1.51.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.50.0.dist-info → dls_dodal-1.51.0.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
|
+
from collections.abc import Mapping
|
|
3
4
|
from typing import Generic, TypeVar
|
|
4
5
|
|
|
5
6
|
import numpy as np
|
|
6
|
-
from bluesky.protocols import Movable
|
|
7
|
+
from bluesky.protocols import Movable
|
|
7
8
|
from ophyd_async.core import (
|
|
8
9
|
Array1D,
|
|
9
10
|
AsyncStatus,
|
|
@@ -16,7 +17,6 @@ from ophyd_async.core import (
|
|
|
16
17
|
)
|
|
17
18
|
from ophyd_async.epics.adcore import ADBaseIO
|
|
18
19
|
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
19
|
-
from ophyd_async.epics.motor import Motor
|
|
20
20
|
|
|
21
21
|
from dodal.devices.electron_analyser.abstract.base_region import (
|
|
22
22
|
TAbstractBaseRegion,
|
|
@@ -29,7 +29,6 @@ class AbstractAnalyserDriverIO(
|
|
|
29
29
|
ABC,
|
|
30
30
|
StandardReadable,
|
|
31
31
|
ADBaseIO,
|
|
32
|
-
Preparable,
|
|
33
32
|
Movable[TAbstractBaseRegion],
|
|
34
33
|
Generic[TAbstractBaseRegion],
|
|
35
34
|
):
|
|
@@ -39,8 +38,14 @@ class AbstractAnalyserDriverIO(
|
|
|
39
38
|
"""
|
|
40
39
|
|
|
41
40
|
def __init__(
|
|
42
|
-
self,
|
|
41
|
+
self,
|
|
42
|
+
prefix: str,
|
|
43
|
+
acquisition_mode_type: type[StrictEnum],
|
|
44
|
+
energy_sources: Mapping[str, SignalR[float]],
|
|
45
|
+
name: str = "",
|
|
43
46
|
) -> None:
|
|
47
|
+
self.energy_sources = energy_sources
|
|
48
|
+
|
|
44
49
|
with self.add_children_as_readables():
|
|
45
50
|
self.image = epics_signal_r(Array1D[np.float64], prefix + "IMAGE")
|
|
46
51
|
self.spectrum = epics_signal_r(Array1D[np.float64], prefix + "INT_SPECTRUM")
|
|
@@ -92,26 +97,6 @@ class AbstractAnalyserDriverIO(
|
|
|
92
97
|
|
|
93
98
|
super().__init__(prefix=prefix, name=name)
|
|
94
99
|
|
|
95
|
-
@AsyncStatus.wrap
|
|
96
|
-
async def prepare(self, value: Motor):
|
|
97
|
-
"""
|
|
98
|
-
Prepare the driver for a region by passing in the energy source motor selected
|
|
99
|
-
by a region.
|
|
100
|
-
|
|
101
|
-
Args:
|
|
102
|
-
value: The motor that contains the information on the current excitation
|
|
103
|
-
energy. Needed to prepare region for epics to accuratly calculate
|
|
104
|
-
kinetic energy for an energy scan when in binding energy mode.
|
|
105
|
-
"""
|
|
106
|
-
energy_source = value
|
|
107
|
-
excitation_energy_value = await energy_source.user_readback.get_value() # eV
|
|
108
|
-
excitation_energy_source_name = energy_source.name
|
|
109
|
-
|
|
110
|
-
await asyncio.gather(
|
|
111
|
-
self.excitation_energy.set(excitation_energy_value),
|
|
112
|
-
self.excitation_energy_source.set(excitation_energy_source_name),
|
|
113
|
-
)
|
|
114
|
-
|
|
115
100
|
@AsyncStatus.wrap
|
|
116
101
|
async def set(self, region: TAbstractBaseRegion):
|
|
117
102
|
"""
|
|
@@ -121,10 +106,13 @@ class AbstractAnalyserDriverIO(
|
|
|
121
106
|
Args:
|
|
122
107
|
region: Contains the parameters to setup the driver for a scan.
|
|
123
108
|
"""
|
|
109
|
+
|
|
110
|
+
source = self._get_energy_source(region.excitation_energy_source)
|
|
111
|
+
excitation_energy = await source.get_value() # eV
|
|
112
|
+
|
|
124
113
|
pass_energy_type = self.pass_energy_type
|
|
125
114
|
pass_energy = pass_energy_type(region.pass_energy)
|
|
126
115
|
|
|
127
|
-
excitation_energy = await self.excitation_energy.get_value()
|
|
128
116
|
low_energy = to_kinetic_energy(
|
|
129
117
|
region.low_energy, region.energy_mode, excitation_energy
|
|
130
118
|
)
|
|
@@ -141,8 +129,19 @@ class AbstractAnalyserDriverIO(
|
|
|
141
129
|
self.pass_energy.set(pass_energy),
|
|
142
130
|
self.iterations.set(region.iterations),
|
|
143
131
|
self.acquisition_mode.set(region.acquisition_mode),
|
|
132
|
+
self.excitation_energy.set(excitation_energy),
|
|
133
|
+
self.excitation_energy_source.set(source.name),
|
|
144
134
|
)
|
|
145
135
|
|
|
136
|
+
def _get_energy_source(self, alias_name: str) -> SignalR[float]:
|
|
137
|
+
energy_source = self.energy_sources.get(alias_name)
|
|
138
|
+
if energy_source is None:
|
|
139
|
+
raise KeyError(
|
|
140
|
+
f"'{energy_source}' is an invalid energy source. Avaliable energy "
|
|
141
|
+
+ f"sources are '{list(self.energy_sources.keys())}'"
|
|
142
|
+
)
|
|
143
|
+
return energy_source
|
|
144
|
+
|
|
146
145
|
@abstractmethod
|
|
147
146
|
def _create_angle_axis_signal(self, prefix: str) -> SignalR[Array1D[np.float64]]:
|
|
148
147
|
"""
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
from typing import Generic, TypeVar
|
|
2
2
|
|
|
3
|
-
from bluesky.protocols import Preparable
|
|
4
3
|
from ophyd_async.core import (
|
|
5
4
|
AsyncStatus,
|
|
6
5
|
Reference,
|
|
7
6
|
)
|
|
8
|
-
from ophyd_async.epics.motor import Motor
|
|
9
7
|
|
|
10
8
|
from dodal.common.data_util import load_json_file_to_class
|
|
11
9
|
from dodal.devices.electron_analyser.abstract.base_detector import (
|
|
@@ -22,7 +20,6 @@ from dodal.devices.electron_analyser.abstract.base_region import (
|
|
|
22
20
|
|
|
23
21
|
class ElectronAnalyserRegionDetector(
|
|
24
22
|
AbstractElectronAnalyserDetector[TAbstractAnalyserDriverIO],
|
|
25
|
-
Preparable,
|
|
26
23
|
Generic[TAbstractAnalyserDriverIO, TAbstractBaseRegion],
|
|
27
24
|
):
|
|
28
25
|
"""
|
|
@@ -48,16 +45,10 @@ class ElectronAnalyserRegionDetector(
|
|
|
48
45
|
return self._driver_ref()
|
|
49
46
|
|
|
50
47
|
@AsyncStatus.wrap
|
|
51
|
-
async def
|
|
52
|
-
|
|
53
|
-
Prepare driver with the region stored and energy_source motor.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
value: The excitation energy source that the region has selected.
|
|
57
|
-
"""
|
|
58
|
-
excitation_energy_source = value
|
|
59
|
-
await self.driver.prepare(excitation_energy_source)
|
|
48
|
+
async def trigger(self) -> None:
|
|
49
|
+
# Configure region parameters on the driver first before data collection.
|
|
60
50
|
await self.driver.set(self.region)
|
|
51
|
+
super().trigger()
|
|
61
52
|
|
|
62
53
|
|
|
63
54
|
TElectronAnalyserRegionDetector = TypeVar(
|
|
@@ -82,7 +73,6 @@ class ElectronAnalyserDetector(
|
|
|
82
73
|
|
|
83
74
|
def __init__(
|
|
84
75
|
self,
|
|
85
|
-
prefix: str,
|
|
86
76
|
sequence_class: type[TAbstractBaseSequence],
|
|
87
77
|
driver: TAbstractAnalyserDriverIO,
|
|
88
78
|
name: str = "",
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
|
|
3
|
+
from ophyd_async.core import SignalR
|
|
4
|
+
|
|
1
5
|
from dodal.devices.electron_analyser.detector import (
|
|
2
6
|
ElectronAnalyserDetector,
|
|
3
7
|
)
|
|
@@ -8,6 +12,8 @@ from dodal.devices.electron_analyser.specs.region import SpecsRegion, SpecsSeque
|
|
|
8
12
|
class SpecsDetector(
|
|
9
13
|
ElectronAnalyserDetector[SpecsAnalyserDriverIO, SpecsSequence, SpecsRegion]
|
|
10
14
|
):
|
|
11
|
-
def __init__(
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
def __init__(
|
|
16
|
+
self, prefix: str, energy_sources: Mapping[str, SignalR[float]], name: str = ""
|
|
17
|
+
):
|
|
18
|
+
driver = SpecsAnalyserDriverIO(prefix, energy_sources)
|
|
19
|
+
super().__init__(SpecsSequence, driver, name)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
from collections.abc import Mapping
|
|
2
3
|
|
|
3
4
|
import numpy as np
|
|
4
5
|
from ophyd_async.core import (
|
|
@@ -18,7 +19,9 @@ from dodal.devices.electron_analyser.specs.region import SpecsRegion
|
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class SpecsAnalyserDriverIO(AbstractAnalyserDriverIO[SpecsRegion]):
|
|
21
|
-
def __init__(
|
|
22
|
+
def __init__(
|
|
23
|
+
self, prefix: str, energy_sources: Mapping[str, SignalR[float]], name: str = ""
|
|
24
|
+
) -> None:
|
|
22
25
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
23
26
|
# Used for setting up region data acquisition.
|
|
24
27
|
self.psu_mode = epics_signal_rw(str, prefix + "SCAN_RANGE")
|
|
@@ -29,7 +32,7 @@ class SpecsAnalyserDriverIO(AbstractAnalyserDriverIO[SpecsRegion]):
|
|
|
29
32
|
self.min_angle_axis = epics_signal_r(float, prefix + "Y_MIN_RBV")
|
|
30
33
|
self.max_angle_axis = epics_signal_r(float, prefix + "Y_MAX_RBV")
|
|
31
34
|
|
|
32
|
-
super().__init__(prefix, AcquisitionMode, name)
|
|
35
|
+
super().__init__(prefix, AcquisitionMode, energy_sources, name)
|
|
33
36
|
|
|
34
37
|
@AsyncStatus.wrap
|
|
35
38
|
async def set(self, region: SpecsRegion):
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
|
|
3
|
+
from ophyd_async.core import SignalR
|
|
4
|
+
|
|
1
5
|
from dodal.devices.electron_analyser.detector import (
|
|
2
6
|
ElectronAnalyserDetector,
|
|
3
7
|
)
|
|
@@ -17,6 +21,8 @@ class VGScientaDetector(
|
|
|
17
21
|
VGScientaRegion,
|
|
18
22
|
]
|
|
19
23
|
):
|
|
20
|
-
def __init__(
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
def __init__(
|
|
25
|
+
self, prefix: str, energy_sources: Mapping[str, SignalR], name: str = ""
|
|
26
|
+
):
|
|
27
|
+
driver = VGScientaAnalyserDriverIO(prefix, energy_sources)
|
|
28
|
+
super().__init__(VGScientaSequence, driver, name)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
from collections.abc import Mapping
|
|
2
3
|
|
|
3
4
|
import numpy as np
|
|
4
5
|
from ophyd_async.core import (
|
|
@@ -22,7 +23,9 @@ from dodal.devices.electron_analyser.vgscienta.region import (
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class VGScientaAnalyserDriverIO(AbstractAnalyserDriverIO[VGScientaRegion]):
|
|
25
|
-
def __init__(
|
|
26
|
+
def __init__(
|
|
27
|
+
self, prefix: str, energy_sources: Mapping[str, SignalR[float]], name: str = ""
|
|
28
|
+
) -> None:
|
|
26
29
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
27
30
|
# Used for setting up region data acquisition.
|
|
28
31
|
self.centre_energy = epics_signal_rw(float, prefix + "CENTRE_ENERGY")
|
|
@@ -32,11 +35,7 @@ class VGScientaAnalyserDriverIO(AbstractAnalyserDriverIO[VGScientaRegion]):
|
|
|
32
35
|
self.y_channel_size = epics_signal_rw(int, prefix + "SizeY")
|
|
33
36
|
self.detector_mode = epics_signal_rw(DetectorMode, prefix + "DETECTOR_MODE")
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
# Used to read detector data after acqusition.
|
|
37
|
-
self.external_io = epics_signal_r(Array1D[np.float64], prefix + "EXTIO")
|
|
38
|
-
|
|
39
|
-
super().__init__(prefix, AcquisitionMode, name)
|
|
38
|
+
super().__init__(prefix, AcquisitionMode, energy_sources, name)
|
|
40
39
|
|
|
41
40
|
@AsyncStatus.wrap
|
|
42
41
|
async def set(self, region: VGScientaRegion):
|
dodal/devices/fast_grid_scan.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import asyncio
|
|
2
1
|
from abc import ABC, abstractmethod
|
|
3
2
|
from typing import Generic, TypeVar
|
|
4
3
|
|
|
@@ -258,7 +257,7 @@ class FastGridScanCommon(StandardReadable, Flyable, ABC, Generic[ParamType]):
|
|
|
258
257
|
async def complete(self):
|
|
259
258
|
try:
|
|
260
259
|
await wait_for_value(self.status, 0, self.COMPLETE_STATUS)
|
|
261
|
-
except
|
|
260
|
+
except TimeoutError:
|
|
262
261
|
LOGGER.error(
|
|
263
262
|
"Hyperion timed out waiting for FGS motion to complete. This may have been caused by a goniometer stage getting stuck.\n\
|
|
264
263
|
Forcibly stopping the FGS motion program..."
|
dodal/devices/i04/constants.py
CHANGED
|
@@ -4,6 +4,6 @@ from dataclasses import dataclass
|
|
|
4
4
|
|
|
5
5
|
@dataclass(frozen=True)
|
|
6
6
|
class RedisConstants:
|
|
7
|
-
REDIS_HOST = os.environ.get("
|
|
7
|
+
REDIS_HOST = os.environ.get("VALKEY_FOR_MURKO_PROD_SVC_SERVICE_HOST", "test_redis")
|
|
8
8
|
REDIS_PASSWORD = os.environ.get("VALKEY_PASSWORD", "test_redis_password")
|
|
9
9
|
MURKO_REDIS_DB = 7
|
dodal/devices/i09/dcm.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from ophyd_async.core import derived_signal_r
|
|
2
|
+
|
|
3
|
+
from dodal.devices.common_dcm import BaseDCM, PitchAndRollCrystal, StationaryCrystal
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DCM(BaseDCM[PitchAndRollCrystal, StationaryCrystal]):
|
|
7
|
+
"""
|
|
8
|
+
I09 double crystal monochromator (DCM), used to select the energy of the beam.
|
|
9
|
+
Differences:
|
|
10
|
+
|
|
11
|
+
1. Can provide energy in eV via dcm.energy_in_ev read signal
|
|
12
|
+
|
|
13
|
+
This DCM is available on i09 and i09_1 endstations.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
17
|
+
super().__init__(prefix, PitchAndRollCrystal, StationaryCrystal, name)
|
|
18
|
+
self.energy_in_ev = derived_signal_r(
|
|
19
|
+
self._convert_keV_to_eV, energy_signal=self.energy_in_kev.user_readback
|
|
20
|
+
)
|
|
21
|
+
# Set name so that new child signals get correct name
|
|
22
|
+
# need to do it until https://github.com/bluesky/ophyd-async/pull/899 merged
|
|
23
|
+
self.set_name(self.name)
|
|
24
|
+
|
|
25
|
+
def _convert_keV_to_eV(self, energy_signal: float) -> float:
|
|
26
|
+
return energy_signal * 1000
|
dodal/devices/i10/mirrors.py
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
from ophyd_async.core import StandardReadable
|
|
2
1
|
from ophyd_async.epics.core import epics_signal_rw
|
|
3
2
|
from ophyd_async.epics.motor import Motor
|
|
4
3
|
|
|
4
|
+
from dodal.devices.motors import XYZStage
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
class PiezoMirror(XYZStage):
|
|
7
8
|
def __init__(
|
|
8
9
|
self,
|
|
9
10
|
prefix: str,
|
|
10
11
|
name: str = "",
|
|
11
12
|
):
|
|
12
13
|
with self.add_children_as_readables():
|
|
13
|
-
self.x = Motor(prefix + "X")
|
|
14
|
-
self.y = Motor(prefix + "Y")
|
|
15
|
-
self.z = Motor(prefix + "Z")
|
|
16
14
|
self.yaw = Motor(prefix + "YAW")
|
|
17
15
|
self.pitch = Motor(prefix + "PITCH")
|
|
18
16
|
self.roll = Motor(prefix + "ROLL")
|
|
@@ -21,4 +19,4 @@ class PiezoMirror(StandardReadable):
|
|
|
21
19
|
read_pv=prefix + "FPITCH:RBV:AI",
|
|
22
20
|
write_pv=prefix + "FPITCH:DMD:AO",
|
|
23
21
|
)
|
|
24
|
-
super().__init__(name
|
|
22
|
+
super().__init__(prefix, name)
|
|
@@ -2,20 +2,6 @@ from ophyd_async.core import StandardReadable
|
|
|
2
2
|
from ophyd_async.epics.motor import Motor
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
class PinHole(StandardReadable):
|
|
6
|
-
"Two motors stage for rasor pinhole"
|
|
7
|
-
|
|
8
|
-
def __init__(
|
|
9
|
-
self,
|
|
10
|
-
prefix: str,
|
|
11
|
-
name: str = "",
|
|
12
|
-
):
|
|
13
|
-
with self.add_children_as_readables():
|
|
14
|
-
self.x = Motor(prefix + "X")
|
|
15
|
-
self.y = Motor(prefix + "Y")
|
|
16
|
-
super().__init__(name=name)
|
|
17
|
-
|
|
18
|
-
|
|
19
5
|
class Diffractometer(StandardReadable):
|
|
20
6
|
def __init__(
|
|
21
7
|
self,
|
dodal/devices/i19/beamstop.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from ophyd_async.core import StandardReadable, StrictEnum
|
|
2
2
|
from ophyd_async.epics.core import epics_signal_rw, epics_signal_x
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
from dodal.devices.motors import XYZStage
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class HomeGroup(StrictEnum):
|
|
@@ -18,13 +19,8 @@ class HomingControl(StandardReadable):
|
|
|
18
19
|
super().__init__(name)
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
class BeamStop(
|
|
22
|
+
class BeamStop(XYZStage):
|
|
22
23
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
23
|
-
with self.add_children_as_readables():
|
|
24
|
-
self.x = Motor(f"{prefix}X")
|
|
25
|
-
self.y = Motor(f"{prefix}Y")
|
|
26
|
-
self.z = Motor(f"{prefix}Z")
|
|
27
|
-
|
|
28
24
|
self.homing = HomingControl(f"{prefix}HM", name)
|
|
29
25
|
|
|
30
26
|
super().__init__(name)
|
dodal/devices/i24/aperture.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from ophyd_async.core import
|
|
1
|
+
from ophyd_async.core import StrictEnum
|
|
2
2
|
from ophyd_async.epics.core import epics_signal_rw
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
from dodal.devices.motors import XYStage
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class AperturePositions(StrictEnum):
|
|
@@ -10,7 +11,7 @@ class AperturePositions(StrictEnum):
|
|
|
10
11
|
MANUAL = "Manual Mounting"
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
class Aperture(
|
|
14
|
+
class Aperture(XYStage):
|
|
14
15
|
"""Device to trigger the aperture motor move on I24.
|
|
15
16
|
|
|
16
17
|
The aperture positioner has 4 possible positions: In, Out, Robot and Manual.
|
|
@@ -20,8 +21,5 @@ class Aperture(StandardReadable):
|
|
|
20
21
|
"""
|
|
21
22
|
|
|
22
23
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
23
|
-
self.x = Motor(prefix + "X")
|
|
24
|
-
self.y = Motor(prefix + "Y")
|
|
25
|
-
|
|
26
24
|
self.position = epics_signal_rw(AperturePositions, prefix + "MP:SELECT")
|
|
27
25
|
super().__init__(name)
|
dodal/devices/i24/beamstop.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
from ophyd_async.core import
|
|
1
|
+
from ophyd_async.core import StrictEnum
|
|
2
2
|
from ophyd_async.epics.core import epics_signal_rw
|
|
3
3
|
from ophyd_async.epics.motor import Motor
|
|
4
4
|
|
|
5
|
+
from dodal.devices.motors import XYZStage
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
class BeamstopPositions(StrictEnum):
|
|
7
9
|
CHECK_BEAM = "CheckBeam"
|
|
@@ -12,7 +14,7 @@ class BeamstopPositions(StrictEnum):
|
|
|
12
14
|
ROBOT = "Robot"
|
|
13
15
|
|
|
14
16
|
|
|
15
|
-
class Beamstop(
|
|
17
|
+
class Beamstop(XYZStage):
|
|
16
18
|
"""Device to move the beamstop.
|
|
17
19
|
|
|
18
20
|
The positioner moves the x,y,z motors when a position is selected.
|
|
@@ -25,12 +27,7 @@ class Beamstop(StandardReadable):
|
|
|
25
27
|
"""
|
|
26
28
|
|
|
27
29
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
28
|
-
self.x = Motor(prefix + "X")
|
|
29
|
-
self.y = Motor(prefix + "Y")
|
|
30
|
-
self.z = Motor(prefix + "Z")
|
|
31
|
-
|
|
32
30
|
self.y_rotation = Motor(prefix + "ROTY")
|
|
33
|
-
|
|
34
31
|
self.pos_select = epics_signal_rw(BeamstopPositions, prefix + "MP:SELECT")
|
|
35
32
|
|
|
36
|
-
super().__init__(name)
|
|
33
|
+
super().__init__(prefix, name)
|
dodal/devices/i24/pmac.py
CHANGED
|
@@ -9,13 +9,13 @@ from ophyd_async.core import (
|
|
|
9
9
|
Reference,
|
|
10
10
|
SignalR,
|
|
11
11
|
SignalRW,
|
|
12
|
-
StandardReadable,
|
|
13
12
|
observe_signals_value,
|
|
14
13
|
soft_signal_rw,
|
|
15
14
|
wait_for_value,
|
|
16
15
|
)
|
|
17
16
|
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
from dodal.devices.motors import XYZStage
|
|
19
19
|
|
|
20
20
|
HOME_STR = r"\#1hmz\#2hmz\#3hmz" # Command to home the PMAC motors
|
|
21
21
|
ZERO_STR = "!x0y0z0" # Command to blend any ongoing move into new position
|
|
@@ -192,7 +192,7 @@ class ProgramAbort(Triggerable):
|
|
|
192
192
|
)
|
|
193
193
|
|
|
194
194
|
|
|
195
|
-
class PMAC(
|
|
195
|
+
class PMAC(XYZStage):
|
|
196
196
|
"""Device to control the chip stage on I24."""
|
|
197
197
|
|
|
198
198
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
@@ -209,10 +209,6 @@ class PMAC(StandardReadable):
|
|
|
209
209
|
self.pmac_string,
|
|
210
210
|
)
|
|
211
211
|
|
|
212
|
-
self.x = Motor(prefix + "X")
|
|
213
|
-
self.y = Motor(prefix + "Y")
|
|
214
|
-
self.z = Motor(prefix + "Z")
|
|
215
|
-
|
|
216
212
|
# These next signals are readback values on PVARS which are set by the motion
|
|
217
213
|
# program.
|
|
218
214
|
self.scanstatus = epics_signal_r(float, "BL24I-MO-STEP-14:signal:P2401")
|
|
@@ -232,4 +228,4 @@ class PMAC(StandardReadable):
|
|
|
232
228
|
)
|
|
233
229
|
self.abort_program = ProgramAbort(self.pmac_string, self.scanstatus)
|
|
234
230
|
|
|
235
|
-
super().__init__(name)
|
|
231
|
+
super().__init__(prefix, name)
|
dodal/devices/motors.py
CHANGED
|
@@ -1,61 +1,118 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
|
|
1
3
|
from ophyd_async.core import StandardReadable
|
|
2
4
|
from ophyd_async.epics.motor import Motor
|
|
3
5
|
|
|
6
|
+
_X, _Y, _Z = "X", "Y", "Z"
|
|
4
7
|
|
|
5
|
-
class XYZPositioner(StandardReadable):
|
|
6
|
-
"""
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
class Stage(StandardReadable, ABC):
|
|
10
|
+
"""
|
|
11
|
+
For these devices, the following co-ordinates are typical but not enforced:
|
|
12
|
+
- z is horizontal & parallel to the direction of beam travel
|
|
13
|
+
- y is vertical and antiparallel to the force of gravity
|
|
14
|
+
- x is the cross product of y🞬z
|
|
10
15
|
|
|
11
16
|
Parameters
|
|
12
17
|
----------
|
|
13
18
|
prefix:
|
|
14
|
-
EPICS PV
|
|
19
|
+
Common part of the EPICS PV for all motors, including ":".
|
|
15
20
|
name:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Notes
|
|
20
|
-
-----
|
|
21
|
-
Example usage::
|
|
22
|
-
async with init_devices():
|
|
23
|
-
xyz_stage = XYZPositioner("BLXX-MO-STAGE-XX:")
|
|
24
|
-
Or::
|
|
25
|
-
with init_devices():
|
|
26
|
-
xyz_stage = XYZPositioner("BLXX-MO-STAGE-XX:", infix = ("A", "B", "C"))
|
|
27
|
-
|
|
21
|
+
Name of the stage, each child motor will be named "{name}-{field_name}"
|
|
22
|
+
*_infix:
|
|
23
|
+
Infix between the common prefix and the EPICS motor record fields for the field.
|
|
28
24
|
"""
|
|
29
25
|
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class XThetaStage(Stage):
|
|
30
|
+
def __init__(
|
|
31
|
+
self, prefix: str, name: str = "", x_infix: str = _X, theta_infix: str = "A"
|
|
32
|
+
):
|
|
33
|
+
with self.add_children_as_readables():
|
|
34
|
+
self.x = Motor(prefix + x_infix)
|
|
35
|
+
self.theta = Motor(prefix + theta_infix)
|
|
36
|
+
super().__init__(name=name)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class XYStage(Stage):
|
|
40
|
+
def __init__(
|
|
41
|
+
self, prefix: str, name: str = "", x_infix: str = _X, y_infix: str = _Y
|
|
42
|
+
):
|
|
43
|
+
with self.add_children_as_readables():
|
|
44
|
+
self.x = Motor(prefix + x_infix)
|
|
45
|
+
self.y = Motor(prefix + y_infix)
|
|
46
|
+
super().__init__(name=name)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class XYZStage(XYStage):
|
|
30
50
|
def __init__(
|
|
31
51
|
self,
|
|
32
52
|
prefix: str,
|
|
33
53
|
name: str = "",
|
|
34
|
-
|
|
54
|
+
x_infix: str = _X,
|
|
55
|
+
y_infix: str = _Y,
|
|
56
|
+
z_infix: str = _Z,
|
|
35
57
|
):
|
|
36
58
|
with self.add_children_as_readables():
|
|
37
|
-
self.
|
|
38
|
-
|
|
39
|
-
self.z = Motor(prefix + infix[2])
|
|
40
|
-
super().__init__(name=name)
|
|
59
|
+
self.z = Motor(prefix + z_infix)
|
|
60
|
+
super().__init__(prefix, name, x_infix, y_infix)
|
|
41
61
|
|
|
42
62
|
|
|
43
|
-
class
|
|
63
|
+
class XYZThetaStage(XYZStage):
|
|
44
64
|
def __init__(
|
|
45
65
|
self,
|
|
46
66
|
prefix: str,
|
|
47
67
|
name: str = "",
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
),
|
|
68
|
+
x_infix: str = _X,
|
|
69
|
+
y_infix: str = _Y,
|
|
70
|
+
z_infix: str = _Z,
|
|
71
|
+
theta_infix: str = _Z,
|
|
72
|
+
) -> None:
|
|
73
|
+
with self.add_children_as_readables():
|
|
74
|
+
self.theta = Motor(prefix + theta_infix)
|
|
75
|
+
super().__init__(prefix, name, x_infix, y_infix, z_infix)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class XYPitchStage(XYStage):
|
|
79
|
+
def __init__(
|
|
80
|
+
self,
|
|
81
|
+
prefix: str,
|
|
82
|
+
x_infix: str = _X,
|
|
83
|
+
y_infix: str = _Y,
|
|
84
|
+
pitch_infix: str = "PITCH",
|
|
85
|
+
name: str = "",
|
|
86
|
+
) -> None:
|
|
87
|
+
with self.add_children_as_readables():
|
|
88
|
+
self.pitch = Motor(prefix + pitch_infix)
|
|
89
|
+
super().__init__(prefix, name, x_infix, y_infix)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class SixAxisGonio(XYZStage):
|
|
93
|
+
def __init__(
|
|
94
|
+
self,
|
|
95
|
+
prefix: str,
|
|
96
|
+
name: str = "",
|
|
97
|
+
x_infix: str = _X,
|
|
98
|
+
y_infix: str = _Y,
|
|
99
|
+
z_infix: str = _Z,
|
|
100
|
+
kappa_infix: str = "KAPPA",
|
|
101
|
+
phi_infix: str = "PHI",
|
|
102
|
+
omega_infix: str = "OMEGA",
|
|
56
103
|
):
|
|
57
104
|
with self.add_children_as_readables():
|
|
58
|
-
self.kappa = Motor(prefix +
|
|
59
|
-
self.phi = Motor(prefix +
|
|
60
|
-
self.omega = Motor(prefix +
|
|
61
|
-
super().__init__(name
|
|
105
|
+
self.kappa = Motor(prefix + kappa_infix)
|
|
106
|
+
self.phi = Motor(prefix + phi_infix)
|
|
107
|
+
self.omega = Motor(prefix + omega_infix)
|
|
108
|
+
super().__init__(prefix, name, x_infix, y_infix, z_infix)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class YZStage(Stage):
|
|
112
|
+
def __init__(
|
|
113
|
+
self, prefix: str, name: str = "", y_infix: str = _Y, z_infix: str = _Z
|
|
114
|
+
) -> None:
|
|
115
|
+
with self.add_children_as_readables():
|
|
116
|
+
self.y = Motor(prefix + y_infix)
|
|
117
|
+
self.z = Motor(prefix + z_infix)
|
|
118
|
+
super().__init__(name)
|
dodal/devices/p45.py
CHANGED
|
@@ -41,15 +41,3 @@ class TomoStageWithStretchAndSkew(StandardReadable):
|
|
|
41
41
|
self.y = SampleY(prefix)
|
|
42
42
|
self.theta = SampleTheta(prefix)
|
|
43
43
|
super().__init__(name)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class Choppers(StandardReadable):
|
|
47
|
-
"""
|
|
48
|
-
Grouping for the P45 chopper motors
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
def __init__(self, prefix: str, name: str = ""):
|
|
52
|
-
with self.add_children_as_readables():
|
|
53
|
-
self.x = Motor(prefix + "ENDAT")
|
|
54
|
-
self.y = Motor(prefix + "BISS")
|
|
55
|
-
super().__init__(name)
|