Source code for dodal.devices.electron_analyser.specs_analyser_io
import numpy as np
from ophyd_async.core import Array1D, SignalR, StandardReadableFormat, derived_signal_r
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
from dodal.devices.electron_analyser.abstract_analyser_io import (
AbstractAnalyserDriverIO,
)
[docs]
class SpecsAnalyserDriverIO(AbstractAnalyserDriverIO):
def __init__(self, prefix: str, name: str = "") -> None:
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
# Used for setting up region data acquisition.
self.psu_mode = epics_signal_rw(str, prefix + "SCAN_RANGE")
self.snapshot_values = epics_signal_rw(int, prefix + "VALUES")
self.centre_energy = epics_signal_rw(float, prefix + "KINETIC_ENERGY")
# Used to read detector data after acqusition.
self.min_angle_axis = epics_signal_r(float, prefix + "Y_MIN_RBV")
self.max_angle_axis = epics_signal_r(float, prefix + "Y_MAX_RBV")
super().__init__(prefix, name)
def _create_angle_axis_signal(self, prefix: str) -> SignalR[Array1D[np.float64]]:
angle_axis = derived_signal_r(
self._calculate_angle_axis,
min_angle=self.min_angle_axis,
max_angle=self.max_angle_axis,
slices=self.slices,
)
return angle_axis
def _calculate_angle_axis(
self, min_angle: float, max_angle: float, slices: int
) -> Array1D[np.float64]:
# SPECS returns the extreme edges of the range, not the centre of the pixels
width = (max_angle - min_angle) / slices
offset = width / 2
axis = np.array([min_angle + offset + i * width for i in range(slices)])
return axis
def _create_energy_axis_signal(self, prefix: str) -> SignalR[Array1D[np.float64]]:
energy_axis = derived_signal_r(
self._calculate_energy_axis,
"eV",
min_energy=self.low_energy,
max_energy=self.high_energy,
total_points_iterations=self.slices,
)
return energy_axis
def _calculate_energy_axis(
self, min_energy: float, max_energy: float, total_points_iterations: int
) -> Array1D[np.float64]:
# Note: Don't use the energy step because of the case where the step doesn't
# exactly fill the range
step = (max_energy - min_energy) / (total_points_iterations - 1)
axis = np.array([min_energy + i * step for i in range(total_points_iterations)])
return axis
def _create_total_steps_signal(self, prefix: str) -> SignalR[int]:
return epics_signal_r(int, prefix + "TOTAL_POINTS_RBV")
@property
def pass_energy_type(self) -> type:
return float