Source code for csaxs_bec.devices.pseudo_devices.bpm

"""Module for a BPM pseudo device that computes the position and intensity from the blade signals."""

from ophyd import Component as Cpt
from ophyd import Kind, Signal
from ophyd_devices.interfaces.base_classes.psi_pseudo_device_base import PSIPseudoDeviceBase
from ophyd_devices.utils.bec_processed_signal import BECProcessedSignal


[docs] class BPM(PSIPseudoDeviceBase): """BPM positioner pseudo device.""" # Blade signals, a,b,c,d left_top = Cpt( BECProcessedSignal, name="left_top", model_config=None, kind=Kind.normal, doc="BPM left_top blade", ) right_top = Cpt( BECProcessedSignal, name="right_top", model_config=None, kind=Kind.normal, doc="BPM right_top blade", ) right_bot = Cpt( BECProcessedSignal, name="right_bot", model_config=None, kind=Kind.normal, doc="BPM right_bottom blade", ) left_bot = Cpt( BECProcessedSignal, name="left_bot", model_config=None, kind=Kind.normal, doc="BPM left_bot blade", ) # Virtual signals pos_x = Cpt( BECProcessedSignal, name="pos_x", model_config=None, kind=Kind.normal, doc="BPM X position, -1 fully left, 1 fully right", ) pos_y = Cpt( BECProcessedSignal, name="pos_y", model_config=None, kind=Kind.normal, doc="BPM Y position, -1 fully bottom, 1 fully top", ) diagonal = Cpt( BECProcessedSignal, name="diagonal", model_config=None, kind=Kind.normal, doc="BPM diagonal, -1 fully diagonal left_top-right_bot, 1 fully diagonal right_top-left_bot", ) intensity = Cpt( BECProcessedSignal, name="intensity", model_config=None, kind=Kind.normal, doc="BPM intensity", ) def __init__( self, name, left_top: str, right_top: str, right_bot: str, left_bot: str, device_manager=None, scan_info=None, **kwargs, ): super().__init__(name=name, device_manager=device_manager, scan_info=scan_info, **kwargs) # Get all blade signal objects from utility method signal_t = self.left_top.get_device_object_from_bec( object_name=left_top, signal_name=self.name, device_manager=device_manager ) signal_r = self.right_top.get_device_object_from_bec( object_name=right_top, signal_name=self.name, device_manager=device_manager ) signal_b = self.right_bot.get_device_object_from_bec( object_name=right_bot, signal_name=self.name, device_manager=device_manager ) signal_l = self.left_bot.get_device_object_from_bec( object_name=left_bot, signal_name=self.name, device_manager=device_manager ) # Set compute methods for blade signals and virtual signals self.left_top.set_compute_method(self._compute_blade_signal, signal=signal_t) self.right_top.set_compute_method(self._compute_blade_signal, signal=signal_r) self.right_bot.set_compute_method(self._compute_blade_signal, signal=signal_b) self.left_bot.set_compute_method(self._compute_blade_signal, signal=signal_l) self.intensity.set_compute_method( self._compute_intensity, left_top=self.left_top, right_top=self.right_top, right_bot=self.right_bot, left_bot=self.left_bot, ) self.pos_x.set_compute_method( self._compute_pos_x, left_bot=self.left_bot, left_top=self.left_top, right_top=self.right_top, right_bot=self.right_bot, ) self.pos_y.set_compute_method( self._compute_pos_y, left_bot=self.left_bot, left_top=self.left_top, right_top=self.right_top, right_bot=self.right_bot, ) self.diagonal.set_compute_method( self._compute_diagonal, left_bot=self.left_bot, left_top=self.left_top, right_top=self.right_top, right_bot=self.right_bot, ) def _compute_blade_signal(self, signal: Signal) -> float: return signal.get() def _compute_intensity( self, left_top: Signal, right_top: Signal, right_bot: Signal, left_bot: Signal ) -> float: intensity = left_top.get() + right_top.get() + right_bot.get() + left_bot.get() return intensity def _compute_pos_x( self, left_bot: Signal, left_top: Signal, right_top: Signal, right_bot: Signal ) -> float: """X position from -1 to 1, where -1 means beam fully on the left side, 1 means beam fully on the right side.""" sum_left = left_bot.get() + left_top.get() sum_right = right_top.get() + right_bot.get() sum_total = sum_left + sum_right if sum_total == 0: return 0.0 return (sum_right - sum_left) / sum_total def _compute_pos_y( self, left_bot: Signal, left_top: Signal, right_top: Signal, right_bot: Signal ) -> float: """Y position from -1 to 1, where -1 means beam fully on the bottom side, 1 means beam fully on the top side.""" sum_top = left_top.get() + right_top.get() sum_bot = right_bot.get() + left_bot.get() sum_total = sum_top + sum_bot if sum_total == 0: return 0.0 return (sum_top - sum_bot) / sum_total def _compute_diagonal( self, left_bot: Signal, left_top: Signal, right_top: Signal, right_bot: Signal ) -> float: sum_diag1 = left_bot.get() + right_top.get() sum_diag2 = left_top.get() + right_bot.get() sum_total = sum_diag1 + sum_diag2 if sum_total == 0: return 0.0 return (sum_diag1 - sum_diag2) / sum_total