Source code for dodal.devices.undulator

from enum import Enum

from ophyd_async.core import ConfigSignal, StandardReadable, soft_signal_r_and_setter
from ophyd_async.epics.motion import Motor
from ophyd_async.epics.signal import epics_signal_r

# The acceptable difference, in mm, between the undulator gap and the DCM
# energy, when the latter is converted to mm using lookup tables
UNDULATOR_DISCREPANCY_THRESHOLD_MM = 2e-3


[docs] class UndulatorGapAccess(str, Enum): ENABLED = "ENABLED" DISABLED = "DISABLED"
[docs] class Undulator(StandardReadable): """ An Undulator-type insertion device, used to control photon emission at a given beam energy. """ def __init__( self, prefix: str, name: str = "", poles: int | None = None, length: float | None = None, ) -> None: """Constructor Args: prefix: PV prefix poles (int): Number of magnetic poles built into the undulator length (float): Length of the undulator in meters name (str, optional): Name for device. Defaults to "". """ with self.add_children_as_readables(): self.gap_motor = Motor(prefix + "BLGAPMTR") self.current_gap = epics_signal_r(float, prefix + "CURRGAPD") self.gap_access = epics_signal_r(UndulatorGapAccess, prefix + "IDBLENA") with self.add_children_as_readables(ConfigSignal): self.gap_discrepancy_tolerance_mm, _ = soft_signal_r_and_setter( float, initial_value=UNDULATOR_DISCREPANCY_THRESHOLD_MM, ) if poles is not None: self.poles, _ = soft_signal_r_and_setter( int, initial_value=poles, ) else: self.poles = None if length is not None: self.length, _ = soft_signal_r_and_setter( float, initial_value=length, ) else: self.length = None super().__init__(name)