refactor(mo1-bragg-positioner): remove move_type, cleanupt of angle pvs in mo1_bragg_positioner

This commit is contained in:
gac-x01da
2025-05-09 08:36:26 +02:00
parent 20759e7ff1
commit 5bb0df2ddf
3 changed files with 17 additions and 63 deletions

View File

@@ -81,7 +81,7 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner):
The prefix to connect to the soft IOC is X01DA-OP-MO1:BRAGG:
"""
USER_ACCESS = ["set_advanced_xas_settings"]
USER_ACCESS = ["set_advanced_xas_settings", "set_xtal"]
def __init__(self, name: str, prefix: str = "", scan_info: ScanInfo | None = None, **kwargs): # type: ignore
"""
@@ -315,13 +315,8 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner):
high (float): High energy/angle value of the scan
scan_time (float): Time for a half oscillation
"""
move_type = self.move_type.get()
if move_type == MoveType.ENERGY:
self.scan_settings.s_scan_energy_lo.put(low)
self.scan_settings.s_scan_energy_hi.put(high)
else:
self.scan_settings.s_scan_angle_lo.put(low)
self.scan_settings.s_scan_angle_hi.put(high)
self.scan_settings.s_scan_energy_lo.put(low)
self.scan_settings.s_scan_energy_hi.put(high)
self.scan_settings.s_scan_scantime.put(scan_time)
def wait_for_signal(self, signal: Cpt, value: Any, timeout: float | None = None) -> None:
@@ -381,18 +376,10 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner):
p_kink (float): Position of kink in %
e_kink (float): Energy of kink in eV
"""
# TODO Add fallback solution for automatic testing, otherwise test will fail
# because no monochromator will calculate the angle
# Unsure how to implement this
move_type = self.move_type.get()
if move_type == MoveType.ENERGY:
e_kink_deg = self.convert_angle_energy(mode="EnergyToAngle", inp=e_kink)
# Angle and Energy are inverse proportional!
high_deg = self.convert_angle_energy(mode="EnergyToAngle", inp=low)
low_deg = self.convert_angle_energy(mode="EnergyToAngle", inp=high)
else:
raise Mo1BraggError("MoveType Angle not implemented for advanced scans, use Energy")
e_kink_deg = self.convert_angle_energy(mode="EnergyToAngle", inp=e_kink)
# Angle and Energy are inverse proportional!
high_deg = self.convert_angle_energy(mode="EnergyToAngle", inp=low)
low_deg = self.convert_angle_energy(mode="EnergyToAngle", inp=high)
pos, vel, dt = compute_spline(
low_deg=low_deg,

View File

@@ -189,13 +189,13 @@ class Mo1BraggScanControl(Device):
class Mo1BraggPositioner(Device, PositionerBase):
"""
Positioner implementation of the MO1 Bragg positioner.
Positioner implementation with readback energy of the MO1 Bragg positioner.
The prefix to connect to the soft IOC is X01DA-OP-MO1:BRAGG:
This soft IOC connects to the NI motor and its control loop.
"""
USER_ACCESS = ["set_advanced_xas_settings"]
USER_ACCESS = ["set_xtal"]
####### Sub-components ########
# Namespace is cleaner and easier to maintain
@@ -207,10 +207,6 @@ class Mo1BraggPositioner(Device, PositionerBase):
scan_control = Cpt(Mo1BraggScanControl, "")
status = Cpt(Mo1BraggStatus, "")
############# switch between energy and angle #############
# TODO should be removed/replaced once decision about pseudo motor is made
move_type = Cpt(MoveTypeSignal, value=MoveType.ENERGY, kind="config")
############# Energy PVs #############
readback = Cpt(
@@ -226,22 +222,6 @@ class Mo1BraggPositioner(Device, PositionerBase):
high_lim = Cpt(EpicsSignalRO, suffix="hi_lim_pos_energy_RBV", kind="config", auto_monitor=True)
velocity = Cpt(EpicsSignalWithRBV, suffix="move_velocity", kind="config", auto_monitor=True)
########### Angle PVs #############
# TODO Pseudo motor for angle?
feedback_pos_angle = Cpt(
EpicsSignalRO, suffix="feedback_pos_angle_RBV", kind="normal", auto_monitor=True
)
setpoint_abs_angle = Cpt(
EpicsSignalWithRBV, suffix="set_abs_pos_angle", kind="normal", auto_monitor=True
)
low_limit_angle = Cpt(
EpicsSignalRO, suffix="lo_lim_pos_angle_RBV", kind="config", auto_monitor=True
)
high_limit_angle = Cpt(
EpicsSignalRO, suffix="hi_lim_pos_angle_RBV", kind="config", auto_monitor=True
)
########## Move Command PVs ##########
move_abs = Cpt(EpicsSignal, suffix="move_abs", kind="config", put_complete=True)
@@ -290,9 +270,7 @@ class Mo1BraggPositioner(Device, PositionerBase):
@property
def limits(self) -> tuple:
"""Return limits of the Bragg positioner"""
if self.move_type.get() == MoveType.ENERGY:
return (self.low_lim.get(), self.high_lim.get())
return (self.low_limit_angle.get(), self.high_limit_angle.get())
return (self.low_lim.get(), self.high_lim.get())
@property
def low_limit(self) -> float:
@@ -307,16 +285,12 @@ class Mo1BraggPositioner(Device, PositionerBase):
@property
def egu(self) -> str:
"""Return the engineering units of the positioner"""
if self.move_type.get() == MoveType.ENERGY:
return "eV"
return "deg"
return "eV"
@property
def position(self) -> float:
"""Return the current position of Mo1Bragg, considering the move type"""
move_type = self.move_type.get()
move_cpt = self.readback if move_type == MoveType.ENERGY else self.feedback_pos_angle
return move_cpt.get()
return self.readback.get()
# pylint: disable=arguments-differ
def check_value(self, value: float) -> None:
@@ -332,7 +306,7 @@ class Mo1BraggPositioner(Device, PositionerBase):
raise LimitError(f"position={value} not within limits {self.limits}")
def _move_and_finish(
self, target_pos: float, move_cpt: Cpt, status: DeviceStatus, update_frequency: float = 0.1
self, target_pos: float, status: DeviceStatus, update_frequency: float = 0.1
) -> None:
"""
Method to be called in the move thread to move the Bragg positioner
@@ -351,7 +325,7 @@ class Mo1BraggPositioner(Device, PositionerBase):
"""
try:
# Set the target position on IOC
move_cpt.put(target_pos)
self.setpoint.put(target_pos)
self.move_abs.put(1)
# Currently sleep is needed due to delay in updates on PVs, maybe time can be reduced
time.sleep(0.5)
@@ -367,7 +341,7 @@ class Mo1BraggPositioner(Device, PositionerBase):
logger.error(f"Error in move thread of device {self.name}: {content}")
status.set_exception(exc=exc)
def move(self, value: float, move_type: str | MoveType = None, **kwargs) -> DeviceStatus:
def move(self, value: float, **kwargs) -> DeviceStatus:
"""
Move the Bragg positioner to the specified value, allows to
switch between move types angle and energy.
@@ -381,16 +355,12 @@ class Mo1BraggPositioner(Device, PositionerBase):
DeviceStatus : status object to track the motion
"""
self._stopped = False
if move_type is not None:
self.move_type.put(move_type)
move_type = self.move_type.get()
move_cpt = self.setpoint if move_type == MoveType.ENERGY else self.setpoint_abs_angle
self.check_value(value)
status = DeviceStatus(device=self)
self._move_thread = threading.Thread(
target=self._move_and_finish, args=(value, move_cpt, status, 0.1)
target=self._move_and_finish, args=(value, status, 0.1)
)
self._move_thread.start()
return status

View File

@@ -72,11 +72,8 @@ class XASSimpleScan(AsyncFlyScanBase):
yield None
def pre_scan(self):
"""Pre Scan action. Ensure the motor movetype is set to energy, then check
limits for start/end energy.
#TODO Remove once the motor movetype is removed and ANGLE motion is a pseudo motor.
"""Pre Scan action.
"""
yield from self.stubs.send_rpc_and_wait(self.motor, "move_type.set", "energy")
self._check_limits()
# Ensure parent class pre_scan actions to be called.