dls-dodal 1.67.0__py3-none-any.whl → 1.68.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.67.0.dist-info → dls_dodal-1.68.0.dist-info}/METADATA +2 -2
- {dls_dodal-1.67.0.dist-info → dls_dodal-1.68.0.dist-info}/RECORD +50 -50
- dodal/_version.py +2 -2
- dodal/beamlines/b07.py +1 -1
- dodal/beamlines/b07_1.py +1 -1
- dodal/beamlines/i05.py +1 -1
- dodal/beamlines/i06.py +1 -1
- dodal/beamlines/i09.py +1 -1
- dodal/beamlines/i09_1.py +1 -1
- dodal/beamlines/i09_2.py +5 -4
- dodal/beamlines/i10_optics.py +1 -1
- dodal/beamlines/i16.py +23 -0
- dodal/beamlines/i17.py +1 -1
- dodal/beamlines/i21.py +61 -2
- dodal/beamlines/p60.py +1 -1
- dodal/devices/eiger.py +15 -9
- dodal/devices/electron_analyser/__init__.py +0 -33
- dodal/devices/electron_analyser/base/__init__.py +58 -0
- dodal/devices/electron_analyser/base/base_controller.py +73 -0
- dodal/devices/electron_analyser/base/base_detector.py +214 -0
- dodal/devices/electron_analyser/{abstract → base}/base_driver_io.py +23 -42
- dodal/devices/electron_analyser/{abstract → base}/base_region.py +47 -11
- dodal/devices/electron_analyser/{util.py → base/base_util.py} +1 -1
- dodal/devices/electron_analyser/{energy_sources.py → base/energy_sources.py} +1 -1
- dodal/devices/electron_analyser/specs/__init__.py +4 -4
- dodal/devices/electron_analyser/specs/specs_detector.py +46 -0
- dodal/devices/electron_analyser/specs/{driver_io.py → specs_driver_io.py} +23 -26
- dodal/devices/electron_analyser/specs/{region.py → specs_region.py} +4 -3
- dodal/devices/electron_analyser/vgscienta/__init__.py +4 -4
- dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py +52 -0
- dodal/devices/electron_analyser/vgscienta/{driver_io.py → vgscienta_driver_io.py} +25 -31
- dodal/devices/electron_analyser/vgscienta/{region.py → vgscienta_region.py} +6 -6
- dodal/devices/i09_2_shared/i09_apple2.py +0 -72
- dodal/devices/i10/i10_apple2.py +2 -2
- dodal/devices/i21/__init__.py +3 -1
- dodal/devices/insertion_device/__init__.py +58 -0
- dodal/devices/insertion_device/apple2_undulator.py +66 -16
- dodal/devices/insertion_device/energy_motor_lookup.py +1 -1
- dodal/devices/insertion_device/id_enum.py +17 -0
- dodal/devices/insertion_device/lookup_table_models.py +65 -35
- dodal/testing/electron_analyser/device_factory.py +4 -4
- dodal/testing/fixtures/devices/apple2.py +1 -1
- dodal/testing/fixtures/run_engine.py +4 -0
- dodal/devices/electron_analyser/abstract/__init__.py +0 -25
- dodal/devices/electron_analyser/abstract/base_detector.py +0 -63
- dodal/devices/electron_analyser/abstract/types.py +0 -12
- dodal/devices/electron_analyser/detector.py +0 -143
- dodal/devices/electron_analyser/specs/detector.py +0 -34
- dodal/devices/electron_analyser/types.py +0 -57
- dodal/devices/electron_analyser/vgscienta/detector.py +0 -48
- {dls_dodal-1.67.0.dist-info → dls_dodal-1.68.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.67.0.dist-info → dls_dodal-1.68.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.67.0.dist-info → dls_dodal-1.68.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.67.0.dist-info → dls_dodal-1.68.0.dist-info}/top_level.txt +0 -0
- /dodal/devices/electron_analyser/{enums.py → base/base_enums.py} +0 -0
- /dodal/devices/electron_analyser/specs/{enums.py → specs_enums.py} +0 -0
- /dodal/devices/electron_analyser/vgscienta/{enums.py → vgscienta_enums.py} +0 -0
|
@@ -2,12 +2,13 @@ from typing import Generic
|
|
|
2
2
|
|
|
3
3
|
from pydantic import Field
|
|
4
4
|
|
|
5
|
-
from dodal.devices.electron_analyser.
|
|
5
|
+
from dodal.devices.electron_analyser.base.base_region import (
|
|
6
6
|
AbstractBaseRegion,
|
|
7
7
|
AbstractBaseSequence,
|
|
8
|
+
TLensMode,
|
|
9
|
+
TPsuMode,
|
|
8
10
|
)
|
|
9
|
-
from dodal.devices.electron_analyser.
|
|
10
|
-
from dodal.devices.electron_analyser.specs.enums import AcquisitionMode
|
|
11
|
+
from dodal.devices.electron_analyser.specs.specs_enums import AcquisitionMode
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class SpecsRegion(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from .
|
|
2
|
-
from .
|
|
3
|
-
from .
|
|
4
|
-
from .
|
|
1
|
+
from .vgscienta_detector import VGScientaDetector
|
|
2
|
+
from .vgscienta_driver_io import VGScientaAnalyserDriverIO
|
|
3
|
+
from .vgscienta_enums import AcquisitionMode, DetectorMode
|
|
4
|
+
from .vgscienta_region import VGScientaRegion, VGScientaSequence
|
|
5
5
|
|
|
6
6
|
__all__ = [
|
|
7
7
|
"VGScientaDetector",
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import Generic
|
|
2
|
+
|
|
3
|
+
from dodal.devices.electron_analyser.base.base_controller import (
|
|
4
|
+
ElectronAnalyserController,
|
|
5
|
+
)
|
|
6
|
+
from dodal.devices.electron_analyser.base.base_detector import ElectronAnalyserDetector
|
|
7
|
+
from dodal.devices.electron_analyser.base.base_region import TLensMode, TPsuMode
|
|
8
|
+
from dodal.devices.electron_analyser.base.energy_sources import (
|
|
9
|
+
DualEnergySource,
|
|
10
|
+
EnergySource,
|
|
11
|
+
)
|
|
12
|
+
from dodal.devices.electron_analyser.vgscienta.vgscienta_driver_io import (
|
|
13
|
+
VGScientaAnalyserDriverIO,
|
|
14
|
+
)
|
|
15
|
+
from dodal.devices.electron_analyser.vgscienta.vgscienta_region import (
|
|
16
|
+
TPassEnergyEnum,
|
|
17
|
+
VGScientaRegion,
|
|
18
|
+
VGScientaSequence,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class VGScientaDetector(
|
|
23
|
+
ElectronAnalyserDetector[
|
|
24
|
+
VGScientaSequence[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
25
|
+
VGScientaAnalyserDriverIO[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
26
|
+
VGScientaRegion[TLensMode, TPassEnergyEnum],
|
|
27
|
+
],
|
|
28
|
+
Generic[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
29
|
+
):
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
prefix: str,
|
|
33
|
+
lens_mode_type: type[TLensMode],
|
|
34
|
+
psu_mode_type: type[TPsuMode],
|
|
35
|
+
pass_energy_type: type[TPassEnergyEnum],
|
|
36
|
+
energy_source: DualEnergySource | EnergySource,
|
|
37
|
+
name: str = "",
|
|
38
|
+
):
|
|
39
|
+
# Save to class so takes part with connect()
|
|
40
|
+
self.driver = VGScientaAnalyserDriverIO[TLensMode, TPsuMode, TPassEnergyEnum](
|
|
41
|
+
prefix, lens_mode_type, psu_mode_type, pass_energy_type
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
controller = ElectronAnalyserController[
|
|
45
|
+
VGScientaAnalyserDriverIO[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
46
|
+
VGScientaRegion[TLensMode, TPassEnergyEnum],
|
|
47
|
+
](self.driver, energy_source, 0)
|
|
48
|
+
|
|
49
|
+
sequence_class = VGScientaSequence[
|
|
50
|
+
lens_mode_type, psu_mode_type, pass_energy_type
|
|
51
|
+
]
|
|
52
|
+
super().__init__(sequence_class, controller, name)
|
|
@@ -4,28 +4,22 @@ from typing import Generic
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from ophyd_async.core import (
|
|
6
6
|
Array1D,
|
|
7
|
+
AsyncStatus,
|
|
7
8
|
SignalR,
|
|
8
9
|
StandardReadableFormat,
|
|
9
10
|
)
|
|
10
11
|
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
11
12
|
|
|
12
|
-
from dodal.devices.electron_analyser.
|
|
13
|
+
from dodal.devices.electron_analyser.base.base_driver_io import (
|
|
13
14
|
AbstractAnalyserDriverIO,
|
|
14
15
|
)
|
|
15
|
-
from dodal.devices.electron_analyser.
|
|
16
|
-
|
|
17
|
-
TPassEnergyEnum,
|
|
18
|
-
TPsuMode,
|
|
19
|
-
)
|
|
20
|
-
from dodal.devices.electron_analyser.energy_sources import (
|
|
21
|
-
DualEnergySource,
|
|
22
|
-
EnergySource,
|
|
23
|
-
)
|
|
24
|
-
from dodal.devices.electron_analyser.vgscienta.enums import (
|
|
16
|
+
from dodal.devices.electron_analyser.base.base_region import TLensMode, TPsuMode
|
|
17
|
+
from dodal.devices.electron_analyser.vgscienta.vgscienta_enums import (
|
|
25
18
|
AcquisitionMode,
|
|
26
19
|
DetectorMode,
|
|
27
20
|
)
|
|
28
|
-
from dodal.devices.electron_analyser.vgscienta.
|
|
21
|
+
from dodal.devices.electron_analyser.vgscienta.vgscienta_region import (
|
|
22
|
+
TPassEnergyEnum,
|
|
29
23
|
VGScientaRegion,
|
|
30
24
|
)
|
|
31
25
|
|
|
@@ -46,7 +40,6 @@ class VGScientaAnalyserDriverIO(
|
|
|
46
40
|
lens_mode_type: type[TLensMode],
|
|
47
41
|
psu_mode_type: type[TPsuMode],
|
|
48
42
|
pass_energy_type: type[TPassEnergyEnum],
|
|
49
|
-
energy_source: EnergySource | DualEnergySource,
|
|
50
43
|
name: str = "",
|
|
51
44
|
) -> None:
|
|
52
45
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
@@ -67,28 +60,29 @@ class VGScientaAnalyserDriverIO(
|
|
|
67
60
|
lens_mode_type,
|
|
68
61
|
psu_mode_type,
|
|
69
62
|
pass_energy_type,
|
|
70
|
-
energy_source,
|
|
71
63
|
name,
|
|
72
64
|
)
|
|
73
65
|
|
|
74
|
-
|
|
66
|
+
@AsyncStatus.wrap
|
|
67
|
+
async def set(self, epics_region: VGScientaRegion[TLensMode, TPassEnergyEnum]):
|
|
75
68
|
await asyncio.gather(
|
|
76
|
-
self.region_name.set(
|
|
77
|
-
self.low_energy.set(
|
|
78
|
-
self.centre_energy.set(
|
|
79
|
-
self.high_energy.set(
|
|
80
|
-
self.slices.set(
|
|
81
|
-
self.lens_mode.set(
|
|
82
|
-
self.pass_energy.set(
|
|
83
|
-
self.iterations.set(
|
|
84
|
-
self.acquire_time.set(
|
|
85
|
-
self.acquisition_mode.set(
|
|
86
|
-
self.energy_step.set(
|
|
87
|
-
self.detector_mode.set(
|
|
88
|
-
self.region_min_x.set(
|
|
89
|
-
self.region_size_x.set(
|
|
90
|
-
self.region_min_y.set(
|
|
91
|
-
self.region_size_y.set(
|
|
69
|
+
self.region_name.set(epics_region.name),
|
|
70
|
+
self.low_energy.set(epics_region.low_energy),
|
|
71
|
+
self.centre_energy.set(epics_region.centre_energy),
|
|
72
|
+
self.high_energy.set(epics_region.high_energy),
|
|
73
|
+
self.slices.set(epics_region.slices),
|
|
74
|
+
self.lens_mode.set(epics_region.lens_mode),
|
|
75
|
+
self.pass_energy.set(epics_region.pass_energy),
|
|
76
|
+
self.iterations.set(epics_region.iterations),
|
|
77
|
+
self.acquire_time.set(epics_region.acquire_time),
|
|
78
|
+
self.acquisition_mode.set(epics_region.acquisition_mode),
|
|
79
|
+
self.energy_step.set(epics_region.energy_step),
|
|
80
|
+
self.detector_mode.set(epics_region.detector_mode),
|
|
81
|
+
self.region_min_x.set(epics_region.min_x),
|
|
82
|
+
self.region_size_x.set(epics_region.size_x),
|
|
83
|
+
self.region_min_y.set(epics_region.min_y),
|
|
84
|
+
self.region_size_y.set(epics_region.size_y),
|
|
85
|
+
self.energy_mode.set(epics_region.energy_mode),
|
|
92
86
|
)
|
|
93
87
|
|
|
94
88
|
def _create_energy_axis_signal(self, prefix: str) -> SignalR[Array1D[np.float64]]:
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import uuid
|
|
2
|
-
from typing import Generic
|
|
2
|
+
from typing import Generic, TypeVar
|
|
3
3
|
|
|
4
|
+
from ophyd_async.core import StrictEnum
|
|
4
5
|
from pydantic import Field, field_validator
|
|
5
6
|
|
|
6
|
-
from dodal.devices.electron_analyser.
|
|
7
|
+
from dodal.devices.electron_analyser.base.base_region import (
|
|
7
8
|
AbstractBaseRegion,
|
|
8
9
|
AbstractBaseSequence,
|
|
9
|
-
)
|
|
10
|
-
from dodal.devices.electron_analyser.abstract.types import (
|
|
11
10
|
TLensMode,
|
|
12
|
-
TPassEnergyEnum,
|
|
13
11
|
TPsuMode,
|
|
14
12
|
)
|
|
15
|
-
from dodal.devices.electron_analyser.vgscienta.
|
|
13
|
+
from dodal.devices.electron_analyser.vgscienta.vgscienta_enums import (
|
|
16
14
|
AcquisitionMode,
|
|
17
15
|
DetectorMode,
|
|
18
16
|
)
|
|
19
17
|
|
|
18
|
+
TPassEnergyEnum = TypeVar("TPassEnergyEnum", bound=StrictEnum)
|
|
19
|
+
|
|
20
20
|
|
|
21
21
|
class VGScientaRegion(
|
|
22
22
|
AbstractBaseRegion[AcquisitionMode, TLensMode, TPassEnergyEnum],
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
from dodal.devices.insertion_device.apple2_undulator import (
|
|
2
|
-
MAXIMUM_MOVE_TIME,
|
|
3
|
-
Apple2,
|
|
4
|
-
Apple2Controller,
|
|
5
|
-
Apple2PhasesVal,
|
|
6
|
-
Apple2Val,
|
|
7
|
-
Pol,
|
|
8
|
-
UndulatorPhaseAxes,
|
|
9
|
-
)
|
|
10
|
-
from dodal.devices.insertion_device.energy_motor_lookup import EnergyMotorLookup
|
|
11
|
-
|
|
12
1
|
J09_GAP_POLY_DEG_COLUMNS = [
|
|
13
2
|
"9th-order",
|
|
14
3
|
"8th-order",
|
|
@@ -23,64 +12,3 @@ J09_GAP_POLY_DEG_COLUMNS = [
|
|
|
23
12
|
]
|
|
24
13
|
|
|
25
14
|
J09_PHASE_POLY_DEG_COLUMNS = ["0th-order"]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class J09Apple2Controller(Apple2Controller[Apple2[UndulatorPhaseAxes]]):
|
|
29
|
-
def __init__(
|
|
30
|
-
self,
|
|
31
|
-
apple2: Apple2[UndulatorPhaseAxes],
|
|
32
|
-
gap_energy_motor_lut: EnergyMotorLookup,
|
|
33
|
-
phase_energy_motor_lut: EnergyMotorLookup,
|
|
34
|
-
units: str = "keV",
|
|
35
|
-
name: str = "",
|
|
36
|
-
) -> None:
|
|
37
|
-
"""
|
|
38
|
-
Parameters:
|
|
39
|
-
-----------
|
|
40
|
-
apple2 : Apple2
|
|
41
|
-
An Apple2 device.
|
|
42
|
-
gap_energy_motor_lut: EnergyMotorLookup
|
|
43
|
-
The class that handles the gap look up table logic for the insertion device.
|
|
44
|
-
phase_energy_motor_lut: EnergyMotorLookup
|
|
45
|
-
The class that handles the phase look up table logic for the insertion device.
|
|
46
|
-
units:
|
|
47
|
-
the units of this device. Defaults to eV.
|
|
48
|
-
name : str, optional
|
|
49
|
-
New device name.
|
|
50
|
-
"""
|
|
51
|
-
self.gap_energy_motor_lut = gap_energy_motor_lut
|
|
52
|
-
self.phase_energy_motor_lut = phase_energy_motor_lut
|
|
53
|
-
super().__init__(
|
|
54
|
-
apple2=apple2,
|
|
55
|
-
gap_energy_motor_converter=gap_energy_motor_lut.find_value_in_lookup_table,
|
|
56
|
-
phase_energy_motor_converter=phase_energy_motor_lut.find_value_in_lookup_table,
|
|
57
|
-
units=units,
|
|
58
|
-
name=name,
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
def _get_apple2_value(self, gap: float, phase: float, pol: Pol) -> Apple2Val:
|
|
62
|
-
return Apple2Val(
|
|
63
|
-
gap=f"{gap:.6f}",
|
|
64
|
-
phase=Apple2PhasesVal(
|
|
65
|
-
top_outer=f"{phase:.6f}",
|
|
66
|
-
top_inner=f"{0.0:.6f}",
|
|
67
|
-
btm_inner=f"{phase:.6f}",
|
|
68
|
-
btm_outer=f"{0.0:.6f}",
|
|
69
|
-
),
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
async def _set_pol(
|
|
73
|
-
self,
|
|
74
|
-
value: Pol,
|
|
75
|
-
) -> None:
|
|
76
|
-
# I09 require all palarisation change to go via LH.
|
|
77
|
-
target_energy = await self.energy.get_value()
|
|
78
|
-
if value is not Pol.LH:
|
|
79
|
-
self._polarisation_setpoint_set(Pol.LH)
|
|
80
|
-
max_lh_energy = self.gap_energy_motor_lut.lut.root[Pol.LH].max_energy
|
|
81
|
-
lh_setpoint = (
|
|
82
|
-
max_lh_energy if target_energy > max_lh_energy else target_energy
|
|
83
|
-
)
|
|
84
|
-
await self.energy.set(lh_setpoint, timeout=MAXIMUM_MOVE_TIME)
|
|
85
|
-
self._polarisation_setpoint_set(value)
|
|
86
|
-
await self.energy.set(target_energy, timeout=MAXIMUM_MOVE_TIME)
|
dodal/devices/i10/i10_apple2.py
CHANGED
|
@@ -11,18 +11,18 @@ from ophyd_async.core import (
|
|
|
11
11
|
soft_signal_rw,
|
|
12
12
|
)
|
|
13
13
|
|
|
14
|
-
from dodal.devices.insertion_device
|
|
14
|
+
from dodal.devices.insertion_device import (
|
|
15
15
|
MAXIMUM_MOVE_TIME,
|
|
16
16
|
Apple2,
|
|
17
17
|
Apple2Controller,
|
|
18
18
|
Apple2PhasesVal,
|
|
19
19
|
Apple2Val,
|
|
20
|
-
Pol,
|
|
21
20
|
UndulatorGap,
|
|
22
21
|
UndulatorJawPhase,
|
|
23
22
|
UndulatorPhaseAxes,
|
|
24
23
|
)
|
|
25
24
|
from dodal.devices.insertion_device.energy_motor_lookup import EnergyMotorLookup
|
|
25
|
+
from dodal.devices.insertion_device.id_enum import Pol
|
|
26
26
|
|
|
27
27
|
ROW_PHASE_MOTOR_TOLERANCE = 0.004
|
|
28
28
|
MAXIMUM_ROW_PHASE_MOTOR_POSITION = 24.0
|
dodal/devices/i21/__init__.py
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from .apple2_undulator import (
|
|
2
|
+
DEFAULT_MOTOR_MIN_TIMEOUT,
|
|
3
|
+
MAXIMUM_MOVE_TIME,
|
|
4
|
+
Apple2,
|
|
5
|
+
Apple2Controller,
|
|
6
|
+
Apple2EnforceLHMoveController,
|
|
7
|
+
Apple2LockedPhasesVal,
|
|
8
|
+
Apple2PhasesVal,
|
|
9
|
+
Apple2Val,
|
|
10
|
+
BeamEnergy,
|
|
11
|
+
EnabledDisabledUpper,
|
|
12
|
+
EnergyMotorConvertor,
|
|
13
|
+
InsertionDeviceEnergy,
|
|
14
|
+
InsertionDevicePolarisation,
|
|
15
|
+
UndulatorGap,
|
|
16
|
+
UndulatorJawPhase,
|
|
17
|
+
UndulatorLockedPhaseAxes,
|
|
18
|
+
UndulatorPhaseAxes,
|
|
19
|
+
)
|
|
20
|
+
from .energy_motor_lookup import (
|
|
21
|
+
ConfigServerEnergyMotorLookup,
|
|
22
|
+
EnergyMotorLookup,
|
|
23
|
+
)
|
|
24
|
+
from .id_enum import Pol, UndulatorGateStatus
|
|
25
|
+
from .lookup_table_models import (
|
|
26
|
+
EnergyCoverage,
|
|
27
|
+
LookupTable,
|
|
28
|
+
LookupTableColumnConfig,
|
|
29
|
+
convert_csv_to_lookup,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
"Apple2",
|
|
34
|
+
"Apple2Controller",
|
|
35
|
+
"Apple2EnforceLHMoveController",
|
|
36
|
+
"UndulatorGap",
|
|
37
|
+
"UndulatorPhaseAxes",
|
|
38
|
+
"UndulatorJawPhase",
|
|
39
|
+
"Apple2Val",
|
|
40
|
+
"Apple2PhasesVal",
|
|
41
|
+
"MAXIMUM_MOVE_TIME",
|
|
42
|
+
"LookupTable",
|
|
43
|
+
"LookupTableColumnConfig",
|
|
44
|
+
"convert_csv_to_lookup",
|
|
45
|
+
"InsertionDeviceEnergy",
|
|
46
|
+
"InsertionDevicePolarisation",
|
|
47
|
+
"BeamEnergy",
|
|
48
|
+
"UndulatorLockedPhaseAxes",
|
|
49
|
+
"EnergyCoverage",
|
|
50
|
+
"Pol",
|
|
51
|
+
"DEFAULT_MOTOR_MIN_TIMEOUT",
|
|
52
|
+
"EnabledDisabledUpper",
|
|
53
|
+
"UndulatorGateStatus",
|
|
54
|
+
"Apple2LockedPhasesVal",
|
|
55
|
+
"EnergyMotorLookup",
|
|
56
|
+
"ConfigServerEnergyMotorLookup",
|
|
57
|
+
"EnergyMotorConvertor",
|
|
58
|
+
]
|
|
@@ -14,7 +14,6 @@ from ophyd_async.core import (
|
|
|
14
14
|
SignalW,
|
|
15
15
|
StandardReadable,
|
|
16
16
|
StandardReadableFormat,
|
|
17
|
-
StrictEnum,
|
|
18
17
|
derived_signal_rw,
|
|
19
18
|
soft_signal_r_and_setter,
|
|
20
19
|
soft_signal_rw,
|
|
@@ -24,6 +23,8 @@ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal
|
|
|
24
23
|
from ophyd_async.epics.motor import Motor
|
|
25
24
|
|
|
26
25
|
from dodal.common.enums import EnabledDisabledUpper
|
|
26
|
+
from dodal.devices.insertion_device.energy_motor_lookup import EnergyMotorLookup
|
|
27
|
+
from dodal.devices.insertion_device.id_enum import Pol, UndulatorGateStatus
|
|
27
28
|
from dodal.log import LOGGER
|
|
28
29
|
|
|
29
30
|
T = TypeVar("T")
|
|
@@ -32,11 +33,6 @@ DEFAULT_MOTOR_MIN_TIMEOUT = 10
|
|
|
32
33
|
MAXIMUM_MOVE_TIME = 550 # There is no useful movements take longer than this.
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
class UndulatorGateStatus(StrictEnum):
|
|
36
|
-
OPEN = "Open"
|
|
37
|
-
CLOSE = "Closed"
|
|
38
|
-
|
|
39
|
-
|
|
40
36
|
@dataclass
|
|
41
37
|
class Apple2LockedPhasesVal:
|
|
42
38
|
top_outer: str
|
|
@@ -58,16 +54,6 @@ class Apple2Val:
|
|
|
58
54
|
return self.phase
|
|
59
55
|
|
|
60
56
|
|
|
61
|
-
class Pol(StrictEnum):
|
|
62
|
-
NONE = "None"
|
|
63
|
-
LH = "lh"
|
|
64
|
-
LV = "lv"
|
|
65
|
-
PC = "pc"
|
|
66
|
-
NC = "nc"
|
|
67
|
-
LA = "la"
|
|
68
|
-
LH3 = "lh3"
|
|
69
|
-
|
|
70
|
-
|
|
71
57
|
ROW_PHASE_MOTOR_TOLERANCE = 0.004
|
|
72
58
|
MAXIMUM_ROW_PHASE_MOTOR_POSITION = 24.0
|
|
73
59
|
MAXIMUM_GAP_MOTOR_POSITION = 100
|
|
@@ -666,6 +652,70 @@ class Apple2Controller(abc.ABC, StandardReadable, Generic[Apple2Type]):
|
|
|
666
652
|
return Pol.NONE, 0.0
|
|
667
653
|
|
|
668
654
|
|
|
655
|
+
class Apple2EnforceLHMoveController(Apple2Controller[Apple2]):
|
|
656
|
+
"""The latest Apple2 version allows unrestricted motor movement.
|
|
657
|
+
However, because of the high forces involved in polarization changes,
|
|
658
|
+
all movements must be performed using the Linear Horizontal (LH) mode.
|
|
659
|
+
A look-up table must also be used to determine the highest energy that can
|
|
660
|
+
be reached in LH mode."""
|
|
661
|
+
|
|
662
|
+
def __init__(
|
|
663
|
+
self,
|
|
664
|
+
apple2: Apple2,
|
|
665
|
+
gap_energy_motor_lut: EnergyMotorLookup,
|
|
666
|
+
phase_energy_motor_lut: EnergyMotorLookup,
|
|
667
|
+
units: str = "eV",
|
|
668
|
+
name: str = "",
|
|
669
|
+
) -> None:
|
|
670
|
+
self.gap_energy_motor_lu = gap_energy_motor_lut
|
|
671
|
+
self.phase_energy_motor_lu = phase_energy_motor_lut
|
|
672
|
+
super().__init__(
|
|
673
|
+
apple2=apple2,
|
|
674
|
+
gap_energy_motor_converter=gap_energy_motor_lut.find_value_in_lookup_table,
|
|
675
|
+
phase_energy_motor_converter=phase_energy_motor_lut.find_value_in_lookup_table,
|
|
676
|
+
units=units,
|
|
677
|
+
name=name,
|
|
678
|
+
)
|
|
679
|
+
|
|
680
|
+
def _get_apple2_value(self, gap: float, phase: float, pol: Pol) -> Apple2Val:
|
|
681
|
+
apple2_val = Apple2Val(
|
|
682
|
+
gap=f"{gap:.6f}",
|
|
683
|
+
phase=Apple2PhasesVal(
|
|
684
|
+
top_outer=f"{phase:.6f}",
|
|
685
|
+
top_inner=f"{0.0:.6f}",
|
|
686
|
+
btm_inner=f"{phase:.6f}",
|
|
687
|
+
btm_outer=f"{0.0:.6f}",
|
|
688
|
+
),
|
|
689
|
+
)
|
|
690
|
+
LOGGER.info(f"Getting apple2 value for pol={pol}, gap={gap}, phase={phase}.")
|
|
691
|
+
LOGGER.info(f"Apple2 motor values: {apple2_val}.")
|
|
692
|
+
|
|
693
|
+
return apple2_val
|
|
694
|
+
|
|
695
|
+
async def _set_pol(
|
|
696
|
+
self,
|
|
697
|
+
value: Pol,
|
|
698
|
+
) -> None:
|
|
699
|
+
# I09/I21 require all polarisation change to go via LH.
|
|
700
|
+
current_pol = await self.polarisation.get_value()
|
|
701
|
+
if current_pol == value:
|
|
702
|
+
LOGGER.info(f"Polarisation already at {value}")
|
|
703
|
+
else:
|
|
704
|
+
target_energy = await self.energy.get_value()
|
|
705
|
+
if (value is not Pol.LH) and (current_pol is not Pol.LH):
|
|
706
|
+
self._polarisation_setpoint_set(Pol.LH)
|
|
707
|
+
max_lh_energy = float(
|
|
708
|
+
self.gap_energy_motor_lu.lut.root[Pol("lh")].max_energy
|
|
709
|
+
)
|
|
710
|
+
lh_setpoint = (
|
|
711
|
+
max_lh_energy if target_energy > max_lh_energy else target_energy
|
|
712
|
+
)
|
|
713
|
+
LOGGER.info(f"Changing polarisation to {value} via {Pol.LH}")
|
|
714
|
+
await self.energy.set(lh_setpoint, timeout=MAXIMUM_MOVE_TIME)
|
|
715
|
+
self._polarisation_setpoint_set(value)
|
|
716
|
+
await self.energy.set(target_energy, timeout=MAXIMUM_MOVE_TIME)
|
|
717
|
+
|
|
718
|
+
|
|
669
719
|
class InsertionDeviceEnergyBase(abc.ABC, StandardReadable, Movable):
|
|
670
720
|
"""Base class for ID energy movable device."""
|
|
671
721
|
|
|
@@ -2,7 +2,7 @@ from pathlib import Path
|
|
|
2
2
|
|
|
3
3
|
from daq_config_server.client import ConfigServer
|
|
4
4
|
|
|
5
|
-
from dodal.devices.insertion_device.
|
|
5
|
+
from dodal.devices.insertion_device.id_enum import Pol
|
|
6
6
|
from dodal.devices.insertion_device.lookup_table_models import (
|
|
7
7
|
LookupTable,
|
|
8
8
|
LookupTableColumnConfig,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from ophyd_async.core import StrictEnum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Pol(StrictEnum):
|
|
5
|
+
NONE = "None"
|
|
6
|
+
LH = "lh"
|
|
7
|
+
LV = "lv"
|
|
8
|
+
PC = "pc"
|
|
9
|
+
NC = "nc"
|
|
10
|
+
LA = "la"
|
|
11
|
+
LH3 = "lh3"
|
|
12
|
+
LV3 = "lv3"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class UndulatorGateStatus(StrictEnum):
|
|
16
|
+
OPEN = "Open"
|
|
17
|
+
CLOSE = "Closed"
|