From bbf53a3e64a770c86d97172e48928c33c7c8a859 Mon Sep 17 00:00:00 2001 From: Mohacsi Istvan Date: Tue, 22 Nov 2022 17:52:45 +0100 Subject: [PATCH] Mono motors in read only mode --- ophyd_devices/epics/DeviceFactory.py | 4 +- ophyd_devices/epics/db/x12sa_database.yml | 88 ++++++++++++++--- ophyd_devices/epics/devices/__init__.py | 2 +- ophyd_devices/epics/devices/specMotors.py | 111 +++++++++++++++++++++- 4 files changed, 186 insertions(+), 19 deletions(-) diff --git a/ophyd_devices/epics/DeviceFactory.py b/ophyd_devices/epics/DeviceFactory.py index 7eafe8a..05d37a8 100644 --- a/ophyd_devices/epics/DeviceFactory.py +++ b/ophyd_devices/epics/DeviceFactory.py @@ -57,8 +57,8 @@ if __name__ == "__main__": for key in lut_db: try: dut = createProxy(str(key)) - # print(f"{key}\t: {type(dut)}\t{dut.read()}") - print(f"{key}\t: {type(dut)}") + print(f"{key}\t: {type(dut)}\t{dut.read()}") + # print(f"{key}\t: {type(dut)}") except Exception as ex: num_errors += 1 print(key) diff --git a/ophyd_devices/epics/db/x12sa_database.yml b/ophyd_devices/epics/db/x12sa_database.yml index 8bdae37..987ba9c 100644 --- a/ophyd_devices/epics/db/x12sa_database.yml +++ b/ophyd_devices/epics/db/x12sa_database.yml @@ -166,13 +166,13 @@ motrz1e: deviceGroup: monitor status: {enabled: true} type: EpicsSignalRO -#mopush1: -# desc: 'Monochromator crystal 1 angle' -# acquisition: {schedule: sync} -# config: {name: mopush1, prefix: 'X12SA-OP-MO:ROX1'} -# deviceGroup: beamlineMotor -# status: {enabled: true} -# type: EpicsMotor +mopush1: + desc: 'Monochromator crystal 1 angle' + acquisition: {schedule: sync} + config: {name: mopush1, read_pv: 'X12SA-OP-MO:ROX1'} + deviceGroup: monitor + status: {enabled: true} + type: EpicsSignalRO moth1e: desc: 'Monochromator crystal 1 theta encoder' acquisition: {schedule: sync} @@ -201,13 +201,13 @@ motry2: deviceGroup: beamlineMotor status: {enabled: true} type: EpicsMotor -#mopush2: -# desc: 'Monochromator crystal 2 angle' -# acquisition: {schedule: sync} -# config: {name: mopush2, prefix: 'X12SA-OP-MO:ROX2'} -# deviceGroup: beamlineMotor -# status: {enabled: true} -# type: EpicsMotor +mopush2: + desc: 'Monochromator crystal 2 angle' + acquisition: {schedule: sync} + config: {name: mopush2, read_pv: 'X12SA-OP-MO:ROX2.VAL'} + deviceGroup: monitor + status: {enabled: true} + type: EpicsSignalRO moth2e: desc: 'Monochromator crystal 2 theta encoder' acquisition: {schedule: sync} @@ -878,3 +878,63 @@ FBPMUY: status: {enabled: true} type: EpicsSignalRO +sttrx: + desc: 'Girder X translation' + acquisition: {schedule: sync} + config: {name: sttrx, prefix: 'X12SA-HG'} + deviceGroup: beamlineMotor + status: {enabled: true} + type: GirderMotorX1 +sttry: + desc: 'Girder Y translation' + acquisition: {schedule: sync} + config: {name: sttry, prefix: 'X12SA-HG'} + deviceGroup: beamlineMotor + status: {enabled: true} + type: GirderMotorY1 +strox: + desc: 'Girder virtual pitch' + acquisition: {schedule: sync} + config: {name: strox, prefix: 'X12SA-HG'} + deviceGroup: beamlineMotor + status: {enabled: true} + type: GirderMotorPITCH +stroy: + desc: 'Girder virtual yaw' + acquisition: {schedule: sync} + config: {name: stroy, prefix: 'X12SA-HG'} + deviceGroup: beamlineMotor + status: {enabled: true} + type: GirderMotorYAW +stroz: + desc: 'Girder virtual roll' + acquisition: {schedule: sync} + config: {name: stroz, prefix: 'X12SA-HG'} + deviceGroup: beamlineMotor + status: {enabled: true} + type: GirderMotorROLL +mokev: + desc: 'Monochromator energy in keV' + acquisition: {schedule: sync} + config: {name: mokev, read_pv: 'X12SA-OP-MO:ROX2.VAL'} + deviceGroup: monitor + status: {enabled: true} + type: EnergyKev +moth1: + desc: 'Monochromator Theta 1' + acquisition: {schedule: sync} + config: {name: moth1, read_pv: 'X12SA-OP-MO:ECX1'} + deviceGroup: monitor + status: {enabled: true} + type: MonoTheta1 +moth2: + desc: 'Monochromator Theta 2' + acquisition: {schedule: sync} + config: {name: moth1, read_pv: 'X12SA-OP-MO:ECX2'} + deviceGroup: monitor + status: {enabled: true} + type: MonoTheta2 + + + + diff --git a/ophyd_devices/epics/devices/__init__.py b/ophyd_devices/epics/devices/__init__.py index b3a5a5a..d3c347b 100644 --- a/ophyd_devices/epics/devices/__init__.py +++ b/ophyd_devices/epics/devices/__init__.py @@ -3,7 +3,7 @@ from .slits import SlitH, SlitV from .XbpmBase import XbpmBase, XbpmCsaxsOp from .SpmBase import SpmBase from .InsertionDevice import InsertionDevice -from .specMotors import PmMonoBender, PmDetectorRotation +from .specMotors import PmMonoBender, PmDetectorRotation, GirderMotorX1, GirderMotorY1, GirderMotorROLL, GirderMotorYAW, GirderMotorPITCH, MonoTheta1, MonoTheta2, EnergyKev # Standard ophyd classes diff --git a/ophyd_devices/epics/devices/specMotors.py b/ophyd_devices/epics/devices/specMotors.py index 7afb824..b167dea 100644 --- a/ophyd_devices/epics/devices/specMotors.py +++ b/ophyd_devices/epics/devices/specMotors.py @@ -8,19 +8,20 @@ IMPORTANT: Virtual monochromator axes should be implemented already in EPICS!!! """ import numpy as np -from math import isclose, tan, atan +from math import isclose, tan, atan, sqrt, sin, asin from ophyd import ( EpicsSignal, EpicsSignalRO, EpicsMotor, PseudoPositioner, PseudoSingle, + PVPositioner, Device, Component, Kind, ) from ophyd.pseudopos import pseudo_position_argument, real_position_argument - +from ophyd.utils.epics_pvs import data_type class PmMonoBender(PseudoPositioner): @@ -91,3 +92,109 @@ class PmDetectorRotation(PseudoPositioner): @real_position_argument def inverse(self, real_pos): return self.PseudoPosition(dtth=r2d(-atan(real_pos.dtpush / self._tables_dt_push_dist_mm))) + + +class GirderMotorX1(PVPositioner): + """Girder X translation pseudo motor + """ + setpoint = Component(EpicsSignal, ":X_SET", name="sp") + readback = Component(EpicsSignalRO, ":X1", name="rbv") + done = Component(EpicsSignal, ":M-DMOV", name="dmov") + +class GirderMotorY1(PVPositioner): + """Girder Y translation pseudo motor + """ + setpoint = Component(EpicsSignal, ":Y_SET", name="sp") + readback = Component(EpicsSignalRO, ":Y1", name="rbv") + done = Component(EpicsSignal, ":M-DMOV", name="dmov") + +class GirderMotorYAW(PVPositioner): + """Girder YAW pseudo motor + """ + setpoint = Component(EpicsSignal, ":YAW_SET", name="sp") + readback = Component(EpicsSignalRO, ":YAW1", name="rbv") + done = Component(EpicsSignal, ":M-DMOV", name="dmov") + +class GirderMotorROLL(PVPositioner): + """Girder ROLL pseudo motor + """ + setpoint = Component(EpicsSignal, ":ROLL_SET", name="sp") + readback = Component(EpicsSignalRO, ":ROLL1", name="rbv") + done = Component(EpicsSignal, ":M-DMOV", name="dmov") + +class GirderMotorPITCH(PVPositioner): + """Girder YAW pseudo motor + """ + setpoint = Component(EpicsSignal, ":PITCH_SET", name="sp") + readback = Component(EpicsSignalRO, ":PITCH1", name="rbv") + done = Component(EpicsSignal, ":M-DMOV", name="dmov") + + +class VirtualSignalBase(EpicsSignalRO): + """This is a test class to create derives signals from one or + multiple original signals... + """ + def calc(self, val): + return val + + def get(self, *args, **kwargs): + raw = super().get(*args, **kwargs) + return self.calc(raw) + + def describe(self): + val = self.get() + d = super().describe() + d[self.name]["dtype"] = data_type(val) + return d + +class MonoTheta1(VirtualSignalBase): + """Converts the pusher motor position to theta angle + """ + _mono_a0_enc_scale1 = -1.0 + _mono_a1_lever_length1 = 206.706 + _mono_a2_pusher_offs1 = 6.85858 + _mono_a3_enc_offs1 = -16.9731 + def calc(self, val): + asin_arg = (val - self._mono_a2_pusher_offs1) / self._mono_a1_lever_length1 + theta1 = self._mono_a0_enc_scale1 * asin( asin_arg ) / 3.141592 * 180.0 + self._mono_a3_enc_offs1 + return theta1 + +class MonoTheta2(VirtualSignalBase): + """Converts the pusher motor position to theta angle + """ + _mono_a3_enc_offs2 = -19.7072 + _mono_a2_pusher_offs2 = 5.93905 + _mono_a1_lever_length2 = 206.572 + _mono_a0_enc_scale2 = -1.0 + + def calc(self, val): + asin_arg = (val - self._mono_a2_pusher_offs2) / self._mono_a1_lever_length2 + theta2 = self._mono_a0_enc_scale2 * asin( asin_arg ) / 3.141592 * 180.0 + self._mono_a3_enc_offs2 + return theta2 + +class EnergyKev(VirtualSignalBase): + """Converts the pusher motor position to energy in keV + """ + _mono_hce = 12.39852066 + _mono_2d2 = 2*5.43102/sqrt(3) + def calc(self, val): + theta_deg = atan(50 / val) / 2.0 * 180.0 / 3.141592 + E_keV = -self._mono_hce / self._mono_2d2 / sin(theta_deg/180.0*3.14152) + return E_keV + + + + + + + + + + + + + + + + +