dls-dodal 1.58.0__py3-none-any.whl → 1.59.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.58.0.dist-info → dls_dodal-1.59.1.dist-info}/METADATA +2 -1
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.59.1.dist-info}/RECORD +58 -43
- dodal/_version.py +2 -2
- dodal/beamlines/b07.py +10 -5
- dodal/beamlines/b07_1.py +10 -5
- dodal/beamlines/b21.py +22 -0
- dodal/beamlines/i02_1.py +80 -0
- dodal/beamlines/i03.py +5 -3
- dodal/beamlines/i04.py +5 -3
- dodal/beamlines/i09.py +10 -9
- dodal/beamlines/i09_1.py +10 -5
- dodal/beamlines/i10-1.py +25 -0
- dodal/beamlines/i10.py +17 -1
- dodal/beamlines/i11.py +0 -17
- dodal/beamlines/i19_2.py +11 -0
- dodal/beamlines/i21.py +27 -0
- dodal/beamlines/i22.py +12 -2
- dodal/beamlines/i24.py +32 -3
- dodal/beamlines/k07.py +31 -0
- dodal/beamlines/p60.py +10 -9
- dodal/common/watcher_utils.py +1 -1
- dodal/devices/apple2_undulator.py +18 -142
- dodal/devices/attenuator/attenuator.py +48 -2
- dodal/devices/attenuator/filter.py +3 -0
- dodal/devices/attenuator/filter_selections.py +26 -0
- dodal/devices/eiger.py +2 -1
- dodal/devices/electron_analyser/__init__.py +4 -0
- dodal/devices/electron_analyser/abstract/base_driver_io.py +30 -18
- dodal/devices/electron_analyser/energy_sources.py +101 -0
- dodal/devices/electron_analyser/specs/detector.py +6 -6
- dodal/devices/electron_analyser/specs/driver_io.py +7 -15
- dodal/devices/electron_analyser/vgscienta/detector.py +6 -6
- dodal/devices/electron_analyser/vgscienta/driver_io.py +7 -14
- dodal/devices/fast_grid_scan.py +130 -64
- dodal/devices/focusing_mirror.py +30 -0
- dodal/devices/i02_1/__init__.py +0 -0
- dodal/devices/i02_1/fast_grid_scan.py +61 -0
- dodal/devices/i02_1/sample_motors.py +19 -0
- dodal/devices/i04/murko_results.py +69 -23
- dodal/devices/i10/i10_apple2.py +282 -140
- dodal/devices/i21/__init__.py +3 -0
- dodal/devices/i21/enums.py +8 -0
- dodal/devices/i22/nxsas.py +2 -0
- dodal/devices/i24/commissioning_jungfrau.py +114 -0
- dodal/devices/smargon.py +0 -56
- dodal/devices/temperture_controller/__init__.py +3 -0
- dodal/devices/temperture_controller/lakeshore/__init__.py +0 -0
- dodal/devices/temperture_controller/lakeshore/lakeshore.py +204 -0
- dodal/devices/temperture_controller/lakeshore/lakeshore_io.py +112 -0
- dodal/devices/tetramm.py +38 -16
- dodal/devices/v2f.py +39 -0
- dodal/devices/zebra/zebra.py +1 -0
- dodal/devices/zebra/zebra_constants_mapping.py +1 -1
- dodal/parameters/experiment_parameter_base.py +1 -5
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.59.1.dist-info}/WHEEL +0 -0
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.59.1.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.59.1.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.58.0.dist-info → dls_dodal-1.59.1.dist-info}/top_level.txt +0 -0
|
@@ -70,3 +70,29 @@ class I02_1FilterFourSelections(SubsetEnum):
|
|
|
70
70
|
TI300 = "Ti300"
|
|
71
71
|
TI400 = "Ti400"
|
|
72
72
|
TI500 = "Ti500"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class I24_FilterOneSelections(SubsetEnum):
|
|
76
|
+
EMPTY = "Empty"
|
|
77
|
+
AL12_5 = "Al12.5"
|
|
78
|
+
AL25 = "Al25"
|
|
79
|
+
AL50 = "Al50"
|
|
80
|
+
AL75 = "Al75"
|
|
81
|
+
AL1000 = "Al1000"
|
|
82
|
+
AL2000 = "Al2000"
|
|
83
|
+
AL3000 = "Al3000"
|
|
84
|
+
PT25 = "Pt25"
|
|
85
|
+
TI500 = "Ti500"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class I24_FilterTwoSelections(SubsetEnum):
|
|
89
|
+
EMPTY = "Empty"
|
|
90
|
+
AL100 = "Al100"
|
|
91
|
+
AL200 = "Al200"
|
|
92
|
+
AL300 = "Al300"
|
|
93
|
+
AL400 = "Al400"
|
|
94
|
+
AL500 = "Al500"
|
|
95
|
+
AL600 = "Al600"
|
|
96
|
+
AL700 = "Al700"
|
|
97
|
+
AL800 = "Al800"
|
|
98
|
+
AL900 = "Al900"
|
dodal/devices/eiger.py
CHANGED
|
@@ -23,6 +23,7 @@ class EigerTimeouts:
|
|
|
23
23
|
meta_file_ready_timeout: int = 30
|
|
24
24
|
all_frames_timeout: int = 120
|
|
25
25
|
arming_timeout: int = 60
|
|
26
|
+
odin_stop_timeout: int = 30
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class InternalEigerTriggerMode(Enum):
|
|
@@ -139,7 +140,7 @@ class EigerDetector(Device, Stageable):
|
|
|
139
140
|
).wait(self.timeouts.all_frames_timeout)
|
|
140
141
|
finally:
|
|
141
142
|
LOGGER.info("Stopping Odin")
|
|
142
|
-
self.odin.stop().wait(
|
|
143
|
+
self.odin.stop().wait(self.timeouts.odin_stop_timeout)
|
|
143
144
|
|
|
144
145
|
def unstage(self) -> bool:
|
|
145
146
|
assert self.detector_params is not None
|
|
@@ -4,6 +4,7 @@ from .detector import (
|
|
|
4
4
|
TElectronAnalyserDetector,
|
|
5
5
|
TElectronAnalyserRegionDetector,
|
|
6
6
|
)
|
|
7
|
+
from .energy_sources import DualEnergySource, EnergySource
|
|
7
8
|
from .enums import EnergyMode, SelectedSource
|
|
8
9
|
from .types import (
|
|
9
10
|
ElectronAnalyserDetectorImpl,
|
|
@@ -16,6 +17,9 @@ from .util import to_binding_energy, to_kinetic_energy
|
|
|
16
17
|
__all__ = [
|
|
17
18
|
"to_binding_energy",
|
|
18
19
|
"to_kinetic_energy",
|
|
20
|
+
"DualEnergySource",
|
|
21
|
+
"SelectedSource",
|
|
22
|
+
"EnergySource",
|
|
19
23
|
"EnergyMode",
|
|
20
24
|
"SelectedSource",
|
|
21
25
|
"ElectronAnalyserDetector",
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from collections.abc import Mapping
|
|
3
2
|
from typing import Generic, TypeVar
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
@@ -25,7 +24,11 @@ from dodal.devices.electron_analyser.abstract.types import (
|
|
|
25
24
|
TPassEnergy,
|
|
26
25
|
TPsuMode,
|
|
27
26
|
)
|
|
28
|
-
from dodal.devices.electron_analyser.
|
|
27
|
+
from dodal.devices.electron_analyser.energy_sources import (
|
|
28
|
+
DualEnergySource,
|
|
29
|
+
EnergySource,
|
|
30
|
+
)
|
|
31
|
+
from dodal.devices.electron_analyser.enums import EnergyMode
|
|
29
32
|
from dodal.devices.electron_analyser.util import to_binding_energy
|
|
30
33
|
|
|
31
34
|
|
|
@@ -49,7 +52,7 @@ class AbstractAnalyserDriverIO(
|
|
|
49
52
|
lens_mode_type: type[TLensMode],
|
|
50
53
|
psu_mode_type: type[TPsuMode],
|
|
51
54
|
pass_energy_type: type[TPassEnergy],
|
|
52
|
-
|
|
55
|
+
energy_source: EnergySource | DualEnergySource,
|
|
53
56
|
name: str = "",
|
|
54
57
|
) -> None:
|
|
55
58
|
"""
|
|
@@ -65,11 +68,11 @@ class AbstractAnalyserDriverIO(
|
|
|
65
68
|
pass_energy_type: Can be enum or float, depends on electron analyser model.
|
|
66
69
|
If enum, it determines the available pass energies for
|
|
67
70
|
this device.
|
|
68
|
-
|
|
71
|
+
energy_source: Device that can give us the correct excitation energy and
|
|
72
|
+
switch sources if applicable.
|
|
69
73
|
(in eV).
|
|
70
74
|
name: Name of the device.
|
|
71
75
|
"""
|
|
72
|
-
self.energy_sources = energy_sources
|
|
73
76
|
self.acquisition_mode_type = acquisition_mode_type
|
|
74
77
|
self.lens_mode_type = lens_mode_type
|
|
75
78
|
self.psu_mode_type = psu_mode_type
|
|
@@ -84,7 +87,7 @@ class AbstractAnalyserDriverIO(
|
|
|
84
87
|
self.total_intensity = derived_signal_r(
|
|
85
88
|
self._calculate_total_intensity, spectrum=self.spectrum
|
|
86
89
|
)
|
|
87
|
-
self.
|
|
90
|
+
self.energy_source = energy_source
|
|
88
91
|
|
|
89
92
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
90
93
|
# Read once per scan after data acquired
|
|
@@ -104,7 +107,6 @@ class AbstractAnalyserDriverIO(
|
|
|
104
107
|
self.acquisition_mode = epics_signal_rw(
|
|
105
108
|
acquisition_mode_type, prefix + "ACQ_MODE"
|
|
106
109
|
)
|
|
107
|
-
self.excitation_energy_source = soft_signal_rw(str, initial_value="")
|
|
108
110
|
# This is used by each electron analyser, however it depends on the electron
|
|
109
111
|
# analyser type to know if is moved with region settings.
|
|
110
112
|
self.psu_mode = epics_signal_rw(psu_mode_type, prefix + "PSU_MODE")
|
|
@@ -119,7 +121,7 @@ class AbstractAnalyserDriverIO(
|
|
|
119
121
|
self._calculate_binding_energy_axis,
|
|
120
122
|
"eV",
|
|
121
123
|
energy_axis=self.energy_axis,
|
|
122
|
-
excitation_energy=self.
|
|
124
|
+
excitation_energy=self.energy_source.energy,
|
|
123
125
|
energy_mode=self.energy_mode,
|
|
124
126
|
)
|
|
125
127
|
self.angle_axis = self._create_angle_axis_signal(prefix)
|
|
@@ -137,9 +139,28 @@ class AbstractAnalyserDriverIO(
|
|
|
137
139
|
await self.image_mode.set(ADImageMode.SINGLE)
|
|
138
140
|
await super().stage()
|
|
139
141
|
|
|
140
|
-
@abstractmethod
|
|
141
142
|
@AsyncStatus.wrap
|
|
142
143
|
async def set(self, region: TAbstractBaseRegion):
|
|
144
|
+
"""
|
|
145
|
+
Take a region object and setup the driver with it. If using a DualEnergySource,
|
|
146
|
+
set it to use the source selected by the region. It also converts the region to
|
|
147
|
+
kinetic mode before we move the driver signals to the region parameter values:
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
region: Contains the parameters to setup the driver for a scan.
|
|
151
|
+
"""
|
|
152
|
+
if isinstance(self.energy_source, DualEnergySource):
|
|
153
|
+
self.energy_source.selected_source.set(region.excitation_energy_source)
|
|
154
|
+
excitation_energy = await self.energy_source.energy.get_value()
|
|
155
|
+
|
|
156
|
+
# Copy region so doesn't alter the actual region and switch to kinetic energy
|
|
157
|
+
ke_region = region.model_copy()
|
|
158
|
+
ke_region.switch_energy_mode(EnergyMode.KINETIC, excitation_energy)
|
|
159
|
+
|
|
160
|
+
await self._set_region(ke_region)
|
|
161
|
+
|
|
162
|
+
@abstractmethod
|
|
163
|
+
async def _set_region(self, ke_region: TAbstractBaseRegion):
|
|
143
164
|
"""
|
|
144
165
|
Move a group of signals defined in a region. Each implementation of this class
|
|
145
166
|
is responsible for implementing this method correctly.
|
|
@@ -148,15 +169,6 @@ class AbstractAnalyserDriverIO(
|
|
|
148
169
|
region: Contains the parameters to setup the driver for a scan.
|
|
149
170
|
"""
|
|
150
171
|
|
|
151
|
-
def _get_energy_source(self, alias_name: SelectedSource) -> SignalR[float]:
|
|
152
|
-
energy_source = self.energy_sources.get(alias_name)
|
|
153
|
-
if energy_source is None:
|
|
154
|
-
raise KeyError(
|
|
155
|
-
f"'{energy_source}' is an invalid energy source. Avaliable energy "
|
|
156
|
-
+ f"sources are '{list(self.energy_sources.keys())}'"
|
|
157
|
-
)
|
|
158
|
-
return energy_source
|
|
159
|
-
|
|
160
172
|
@abstractmethod
|
|
161
173
|
def _create_angle_axis_signal(self, prefix: str) -> SignalR[Array1D[np.float64]]:
|
|
162
174
|
"""
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from ophyd_async.core import (
|
|
4
|
+
Reference,
|
|
5
|
+
SignalR,
|
|
6
|
+
StandardReadable,
|
|
7
|
+
StandardReadableFormat,
|
|
8
|
+
derived_signal_r,
|
|
9
|
+
soft_signal_r_and_setter,
|
|
10
|
+
soft_signal_rw,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from dodal.devices.electron_analyser.enums import SelectedSource
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AbstractEnergySource(StandardReadable):
|
|
17
|
+
"""
|
|
18
|
+
Abstract device that wraps an energy source signal and provides common interface via
|
|
19
|
+
a energy signal.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, name: str = "") -> None:
|
|
23
|
+
super().__init__(name)
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def energy(self) -> SignalR[float]:
|
|
28
|
+
"""
|
|
29
|
+
Signal to provide the excitation energy value in eV.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class EnergySource(AbstractEnergySource):
|
|
34
|
+
"""
|
|
35
|
+
Wraps a signal that relates to energy and provides common interface via energy
|
|
36
|
+
signal. It provides the name of the wrapped signal as a child signal in the
|
|
37
|
+
read_configuration via wrapped_device_name and adds the signal as a readable.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, source: SignalR[float], name: str = "") -> None:
|
|
41
|
+
self.add_readables([source])
|
|
42
|
+
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
43
|
+
self.wrapped_device_name, _ = soft_signal_r_and_setter(
|
|
44
|
+
str, initial_value=source.name
|
|
45
|
+
)
|
|
46
|
+
self._source_ref = Reference(source)
|
|
47
|
+
super().__init__(name)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def energy(self) -> SignalR[float]:
|
|
51
|
+
return self._source_ref()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DualEnergySource(AbstractEnergySource):
|
|
55
|
+
"""
|
|
56
|
+
Holds two EnergySource devices and provides a signal to read energy depending on
|
|
57
|
+
which source is selected. This is controlled by a selected_source signal which can
|
|
58
|
+
switch source using SelectedSource enum. Both sources energy is recorded in the
|
|
59
|
+
read, the energy signal is used as a helper signal to know which source is being
|
|
60
|
+
used.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self, source1: SignalR[float], source2: SignalR[float], name: str = ""
|
|
65
|
+
):
|
|
66
|
+
"""
|
|
67
|
+
Args:
|
|
68
|
+
source1: Default energy signal to select.
|
|
69
|
+
source2: Secondary energy signal to select.
|
|
70
|
+
name: name of this device.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
with self.add_children_as_readables():
|
|
74
|
+
self.selected_source = soft_signal_rw(
|
|
75
|
+
SelectedSource, initial_value=SelectedSource.SOURCE1
|
|
76
|
+
)
|
|
77
|
+
self.source1 = EnergySource(source1)
|
|
78
|
+
self.source2 = EnergySource(source2)
|
|
79
|
+
|
|
80
|
+
self._selected_energy = derived_signal_r(
|
|
81
|
+
self._get_excitation_energy,
|
|
82
|
+
"eV",
|
|
83
|
+
selected_source=self.selected_source,
|
|
84
|
+
source1=self.source1.energy,
|
|
85
|
+
source2=self.source2.energy,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
super().__init__(name)
|
|
89
|
+
|
|
90
|
+
def _get_excitation_energy(
|
|
91
|
+
self, selected_source: SelectedSource, source1: float, source2: float
|
|
92
|
+
) -> float:
|
|
93
|
+
match selected_source:
|
|
94
|
+
case SelectedSource.SOURCE1:
|
|
95
|
+
return source1
|
|
96
|
+
case SelectedSource.SOURCE2:
|
|
97
|
+
return source2
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def energy(self) -> SignalR[float]:
|
|
101
|
+
return self._selected_energy
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
from collections.abc import Mapping
|
|
2
1
|
from typing import Generic
|
|
3
2
|
|
|
4
|
-
from ophyd_async.core import SignalR
|
|
5
|
-
|
|
6
3
|
from dodal.devices.electron_analyser.abstract.types import TLensMode, TPsuMode
|
|
7
4
|
from dodal.devices.electron_analyser.detector import (
|
|
8
5
|
ElectronAnalyserDetector,
|
|
9
6
|
)
|
|
10
|
-
from dodal.devices.electron_analyser.
|
|
7
|
+
from dodal.devices.electron_analyser.energy_sources import (
|
|
8
|
+
DualEnergySource,
|
|
9
|
+
EnergySource,
|
|
10
|
+
)
|
|
11
11
|
from dodal.devices.electron_analyser.specs.driver_io import SpecsAnalyserDriverIO
|
|
12
12
|
from dodal.devices.electron_analyser.specs.region import SpecsRegion, SpecsSequence
|
|
13
13
|
|
|
@@ -25,10 +25,10 @@ class SpecsDetector(
|
|
|
25
25
|
prefix: str,
|
|
26
26
|
lens_mode_type: type[TLensMode],
|
|
27
27
|
psu_mode_type: type[TPsuMode],
|
|
28
|
-
|
|
28
|
+
energy_source: DualEnergySource | EnergySource,
|
|
29
29
|
name: str = "",
|
|
30
30
|
):
|
|
31
31
|
driver = SpecsAnalyserDriverIO[TLensMode, TPsuMode](
|
|
32
|
-
prefix, lens_mode_type, psu_mode_type,
|
|
32
|
+
prefix, lens_mode_type, psu_mode_type, energy_source
|
|
33
33
|
)
|
|
34
34
|
super().__init__(SpecsSequence[lens_mode_type, psu_mode_type], driver, name)
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from collections.abc import Mapping
|
|
3
2
|
from typing import Generic
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
6
5
|
from ophyd_async.core import (
|
|
7
6
|
Array1D,
|
|
8
|
-
AsyncStatus,
|
|
9
7
|
SignalR,
|
|
10
8
|
StandardReadableFormat,
|
|
11
9
|
derived_signal_r,
|
|
@@ -16,7 +14,10 @@ from dodal.devices.electron_analyser.abstract.base_driver_io import (
|
|
|
16
14
|
AbstractAnalyserDriverIO,
|
|
17
15
|
)
|
|
18
16
|
from dodal.devices.electron_analyser.abstract.types import TLensMode, TPsuMode
|
|
19
|
-
from dodal.devices.electron_analyser.
|
|
17
|
+
from dodal.devices.electron_analyser.energy_sources import (
|
|
18
|
+
DualEnergySource,
|
|
19
|
+
EnergySource,
|
|
20
|
+
)
|
|
20
21
|
from dodal.devices.electron_analyser.specs.enums import AcquisitionMode
|
|
21
22
|
from dodal.devices.electron_analyser.specs.region import SpecsRegion
|
|
22
23
|
|
|
@@ -36,7 +37,7 @@ class SpecsAnalyserDriverIO(
|
|
|
36
37
|
prefix: str,
|
|
37
38
|
lens_mode_type: type[TLensMode],
|
|
38
39
|
psu_mode_type: type[TPsuMode],
|
|
39
|
-
|
|
40
|
+
energy_source: EnergySource | DualEnergySource,
|
|
40
41
|
name: str = "",
|
|
41
42
|
) -> None:
|
|
42
43
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
@@ -58,18 +59,11 @@ class SpecsAnalyserDriverIO(
|
|
|
58
59
|
lens_mode_type=lens_mode_type,
|
|
59
60
|
psu_mode_type=psu_mode_type,
|
|
60
61
|
pass_energy_type=float,
|
|
61
|
-
|
|
62
|
+
energy_source=energy_source,
|
|
62
63
|
name=name,
|
|
63
64
|
)
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
async def set(self, region: SpecsRegion[TLensMode, TPsuMode]):
|
|
67
|
-
source = self._get_energy_source(region.excitation_energy_source)
|
|
68
|
-
excitation_energy = await source.get_value() # eV
|
|
69
|
-
# Copy region so doesn't alter the actual region and switch to kinetic energy
|
|
70
|
-
ke_region = region.model_copy()
|
|
71
|
-
ke_region.switch_energy_mode(EnergyMode.KINETIC, excitation_energy)
|
|
72
|
-
|
|
66
|
+
async def _set_region(self, ke_region: SpecsRegion[TLensMode, TPsuMode]):
|
|
73
67
|
await asyncio.gather(
|
|
74
68
|
self.region_name.set(ke_region.name),
|
|
75
69
|
self.energy_mode.set(ke_region.energy_mode),
|
|
@@ -81,8 +75,6 @@ class SpecsAnalyserDriverIO(
|
|
|
81
75
|
self.pass_energy.set(ke_region.pass_energy),
|
|
82
76
|
self.iterations.set(ke_region.iterations),
|
|
83
77
|
self.acquisition_mode.set(ke_region.acquisition_mode),
|
|
84
|
-
self.excitation_energy.set(excitation_energy),
|
|
85
|
-
self.excitation_energy_source.set(source.name),
|
|
86
78
|
self.snapshot_values.set(ke_region.values),
|
|
87
79
|
self.psu_mode.set(ke_region.psu_mode),
|
|
88
80
|
)
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
from collections.abc import Mapping
|
|
2
1
|
from typing import Generic
|
|
3
2
|
|
|
4
|
-
from ophyd_async.core import SignalR
|
|
5
|
-
|
|
6
3
|
from dodal.devices.electron_analyser.abstract.types import (
|
|
7
4
|
TLensMode,
|
|
8
5
|
TPassEnergyEnum,
|
|
@@ -11,7 +8,10 @@ from dodal.devices.electron_analyser.abstract.types import (
|
|
|
11
8
|
from dodal.devices.electron_analyser.detector import (
|
|
12
9
|
ElectronAnalyserDetector,
|
|
13
10
|
)
|
|
14
|
-
from dodal.devices.electron_analyser.
|
|
11
|
+
from dodal.devices.electron_analyser.energy_sources import (
|
|
12
|
+
DualEnergySource,
|
|
13
|
+
EnergySource,
|
|
14
|
+
)
|
|
15
15
|
from dodal.devices.electron_analyser.vgscienta.driver_io import (
|
|
16
16
|
VGScientaAnalyserDriverIO,
|
|
17
17
|
)
|
|
@@ -35,11 +35,11 @@ class VGScientaDetector(
|
|
|
35
35
|
lens_mode_type: type[TLensMode],
|
|
36
36
|
psu_mode_type: type[TPsuMode],
|
|
37
37
|
pass_energy_type: type[TPassEnergyEnum],
|
|
38
|
-
|
|
38
|
+
energy_source: DualEnergySource | EnergySource,
|
|
39
39
|
name: str = "",
|
|
40
40
|
):
|
|
41
41
|
driver = VGScientaAnalyserDriverIO[TLensMode, TPsuMode, TPassEnergyEnum](
|
|
42
|
-
prefix, lens_mode_type, psu_mode_type, pass_energy_type,
|
|
42
|
+
prefix, lens_mode_type, psu_mode_type, pass_energy_type, energy_source
|
|
43
43
|
)
|
|
44
44
|
super().__init__(
|
|
45
45
|
VGScientaSequence[lens_mode_type, psu_mode_type, pass_energy_type],
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from collections.abc import Mapping
|
|
3
2
|
from typing import Generic
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
6
5
|
from ophyd_async.core import (
|
|
7
6
|
Array1D,
|
|
8
|
-
AsyncStatus,
|
|
9
7
|
SignalR,
|
|
10
8
|
StandardReadableFormat,
|
|
11
9
|
)
|
|
@@ -19,7 +17,10 @@ from dodal.devices.electron_analyser.abstract.types import (
|
|
|
19
17
|
TPassEnergyEnum,
|
|
20
18
|
TPsuMode,
|
|
21
19
|
)
|
|
22
|
-
from dodal.devices.electron_analyser.
|
|
20
|
+
from dodal.devices.electron_analyser.energy_sources import (
|
|
21
|
+
DualEnergySource,
|
|
22
|
+
EnergySource,
|
|
23
|
+
)
|
|
23
24
|
from dodal.devices.electron_analyser.vgscienta.enums import (
|
|
24
25
|
AcquisitionMode,
|
|
25
26
|
DetectorMode,
|
|
@@ -45,7 +46,7 @@ class VGScientaAnalyserDriverIO(
|
|
|
45
46
|
lens_mode_type: type[TLensMode],
|
|
46
47
|
psu_mode_type: type[TPsuMode],
|
|
47
48
|
pass_energy_type: type[TPassEnergyEnum],
|
|
48
|
-
|
|
49
|
+
energy_source: EnergySource | DualEnergySource,
|
|
49
50
|
name: str = "",
|
|
50
51
|
) -> None:
|
|
51
52
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
@@ -66,17 +67,11 @@ class VGScientaAnalyserDriverIO(
|
|
|
66
67
|
lens_mode_type,
|
|
67
68
|
psu_mode_type,
|
|
68
69
|
pass_energy_type,
|
|
69
|
-
|
|
70
|
+
energy_source,
|
|
70
71
|
name,
|
|
71
72
|
)
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
async def set(self, region: VGScientaRegion[TLensMode, TPassEnergyEnum]):
|
|
75
|
-
source = self._get_energy_source(region.excitation_energy_source)
|
|
76
|
-
excitation_energy = await source.get_value() # eV
|
|
77
|
-
# Copy region so doesn't alter the actual region and switch to kinetic energy
|
|
78
|
-
ke_region = region.model_copy()
|
|
79
|
-
ke_region.switch_energy_mode(EnergyMode.KINETIC, excitation_energy)
|
|
74
|
+
async def _set_region(self, ke_region: VGScientaRegion[TLensMode, TPassEnergyEnum]):
|
|
80
75
|
await asyncio.gather(
|
|
81
76
|
self.region_name.set(ke_region.name),
|
|
82
77
|
self.energy_mode.set(ke_region.energy_mode),
|
|
@@ -89,8 +84,6 @@ class VGScientaAnalyserDriverIO(
|
|
|
89
84
|
self.iterations.set(ke_region.iterations),
|
|
90
85
|
self.acquire_time.set(ke_region.acquire_time),
|
|
91
86
|
self.acquisition_mode.set(ke_region.acquisition_mode),
|
|
92
|
-
self.excitation_energy.set(excitation_energy),
|
|
93
|
-
self.excitation_energy_source.set(source.name),
|
|
94
87
|
self.energy_step.set(ke_region.energy_step),
|
|
95
88
|
self.detector_mode.set(ke_region.detector_mode),
|
|
96
89
|
self.region_min_x.set(ke_region.min_x),
|