diff --git a/ophyd_devices/epics/db/x12sa_database.yml b/ophyd_devices/epics/db/x12sa_database.yml index 6c351d1..874dd47 100644 --- a/ophyd_devices/epics/db/x12sa_database.yml +++ b/ophyd_devices/epics/db/x12sa_database.yml @@ -159,13 +159,27 @@ motrz1: deviceGroup: beamlineMotor status: {enabled: true} type: EpicsMotor -mopush1: - desc: 'Monochromator crystal 1 angle' +motrz1e: + desc: 'Monochromator crystal 1 axial movement encoder' acquisition: {schedule: sync} - config: {name: mopush1, prefix: 'X12SA-OP-MO:ROX1'} - deviceGroup: beamlineMotor + config: {name: motrz1e, prefix: 'X12SA-OP-MO:ECZ1'} + deviceGroup: monitor status: {enabled: true} - type: EpicsMotor + 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 +moth1e: + desc: 'Monochromator crystal 1 theta encoder' + acquisition: {schedule: sync} + config: {name: moth1e, prefix: 'X12SA-OP-MO:ECX1'} + deviceGroup: monitor + status: {enabled: true} + type: EpicsSignalRO moroll1: desc: 'Monochromator crystal 1 roll' acquisition: {schedule: sync} @@ -187,13 +201,20 @@ motry2: deviceGroup: beamlineMotor status: {enabled: true} type: EpicsMotor -mopush2: - desc: 'Monochromator crystal 2 angle' +#mopush2: +# desc: 'Monochromator crystal 2 angle' +# acquisition: {schedule: sync} +# config: {name: mopush2, prefix: 'X12SA-OP-MO:ROX2'} +# deviceGroup: beamlineMotor +# status: {enabled: true} +# type: EpicsMotor +moth2e: + desc: 'Monochromator crystal 2 theta encoder' acquisition: {schedule: sync} - config: {name: mopush2, prefix: 'X12SA-OP-MO:ROX2'} - deviceGroup: beamlineMotor + config: {name: moth2e, prefix: 'X12SA-OP-MO:ECX2'} + deviceGroup: monitor status: {enabled: true} - type: EpicsMotor + type: EpicsSignalRO #monot: # desc: 'Monochromator temperature' # acquisition: {schedule: sync} @@ -216,33 +237,41 @@ moroll2: status: {enabled: true} type: EpicsMotor mobdai: - desc: 'Monochromator ??? inner motor' + desc: 'Monochromator bender inner motor' acquisition: {schedule: sync} config: {name: mobdai, prefix: 'X12SA-OP-MO:TRYA'} deviceGroup: beamlineMotor status: {enabled: true} type: EpicsMotor mobdbo: - desc: 'Monochromator ??? outer motor' + desc: 'Monochromator bender outer motor' acquisition: {schedule: sync} config: {name: mobdbo, prefix: 'X12SA-OP-MO:TRYB'} deviceGroup: beamlineMotor status: {enabled: true} type: EpicsMotor mobdco: - desc: 'Monochromator ??? outer motor' + desc: 'Monochromator bender outer motor' acquisition: {schedule: sync} config: {name: mobdco, prefix: 'X12SA-OP-MO:TRYC'} deviceGroup: beamlineMotor status: {enabled: true} type: EpicsMotor mobddi: - desc: 'Monochromator ??? inner motor' + desc: 'Monochromator bender inner motor' acquisition: {schedule: sync} config: {name: mobddi, prefix: 'X12SA-OP-MO:TRYD'} deviceGroup: beamlineMotor status: {enabled: true} type: EpicsMotor +mobd: + desc: 'Monochromator bender virtual motor' + acquisition: {schedule: sync} + config: {name: mobd, prefix: 'X12SA-OP-MO:'} + deviceGroup: beamlineMotor + status: {enabled: true} + type: PmMonoBender + bm4trx: desc: 'OpticsHutch XBPM 2 horizontal movement' acquisition: {schedule: sync} @@ -475,12 +504,19 @@ dttrz: status: {enabled: true} type: EpicsMotor dtpush: - desc: 'Detector tower motion' + desc: 'Detector tower tilt pusher' acquisition: {schedule: sync} config: {name: dtpush, prefix: 'X12SA-ES1-DETT:ROX1'} deviceGroup: beamlineMotor status: {enabled: true} type: EpicsMotor +dtth: + desc: 'Detector tower tilt rotation' + acquisition: {schedule: sync} + config: {name: dtth, prefix: 'X12SA-ES1-DETT:ROX1'} + deviceGroup: beamlineMotor + status: {enabled: true} + type: PmDetectorRotation dettrx: desc: 'Detector tower motion' acquisition: {schedule: sync} @@ -841,3 +877,4 @@ FBPMUY: deviceGroup: monitor status: {enabled: true} type: EpicsSignalRO + diff --git a/ophyd_devices/epics/devices/__init__.py b/ophyd_devices/epics/devices/__init__.py index 5ea635e..b3a5a5a 100644 --- a/ophyd_devices/epics/devices/__init__.py +++ b/ophyd_devices/epics/devices/__init__.py @@ -3,6 +3,8 @@ from .slits import SlitH, SlitV from .XbpmBase import XbpmBase, XbpmCsaxsOp from .SpmBase import SpmBase from .InsertionDevice import InsertionDevice +from .specMotors import PmMonoBender, PmDetectorRotation + # Standard ophyd classes from ophyd import EpicsSignal, EpicsSignalRO, EpicsMotor diff --git a/ophyd_devices/epics/devices/specMotors.py b/ophyd_devices/epics/devices/specMotors.py new file mode 100644 index 0000000..f5d4e71 --- /dev/null +++ b/ophyd_devices/epics/devices/specMotors.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +""" +Created on Wed Oct 13 18:06:15 2021 + +@author: mohacsi_i + +IMPORTANT: Virtual monochromator axes should be implemented already in EPICS!!! +""" + +import numpy as np +from math import isclose +from ophyd import ( + EpicsSignal, + EpicsSignalRO, + EpicsMotor, + PseudoPositioner, + PseudoSingle, + Device, + Component, + Kind, +) +from ophyd.pseudopos import pseudo_position_argument, real_position_argument +from ophyd.sim import SynAxis, Syn2DGauss + + +class PmMonoBender(PseudoPositioner): + """Monochromator bender + + Small wrapper to combine the four monochromator bender motors. + """ + + # Real axes + ai = Component(EpicsMotor, "TRYA", name="ai") + bo = Component(EpicsMotor, "TRYB", name="bo") + co = Component(EpicsMotor, "TRYC", name="co") + di = Component(EpicsMotor, "TRYD", name="di") + + # Virtual axis + bend = Component(PseudoSingle, name="bend") + + _real = ["ai", "bo", "co", "di"] + + @pseudo_position_argument + def forward(self, pseudo_pos): + delta = pseudo_pos.bend - 0.25 * ( + self.ai.position + self.bo.position + self.co.position + self.di.position + ) + return self.RealPosition( + ai=self.ai.position + delta, + bo=self.bo.position + delta, + co=self.co.position + delta, + di=self.di.position + delta, + ) + + @real_position_argument + def inverse(self, real_pos): + return self.PseudoPosition( + bend=0.25 * (real_pos.ai + real_pos.bo + real_pos.co + real_pos.di) + ) + + +def r2d(radians): + return radians * 180 / 3.141592 + + +def d2r(degrees): + return degrees * 3.141592 / 180.0 + + +class PmDetectorRotation(PseudoPositioner): + """Detector rotation pseudo motor + + Small wrapper to convert detector pusher position to rotation angle. + """ + + _tables_dt_push_dist_mm = 890 + # Real axes + dtpush = Component(EpicsMotor, "", name="dtpush") + + # Virtual axis + dtth = Component(PseudoSingle, name="dtth") + + _real = ["dtpush"] + + @pseudo_position_argument + def forward(self, pseudo_pos): + return self.RealPosition( + dtpush=d2r(tan(-3.14 / 180 * pseudo_pos.dtth)) * self._tables_dt_push_dist_mm + ) + + @real_position_argument + def inverse(self, real_pos): + return self.PseudoPosition(dtth=r2d(-atan(real_pos.dtpush / self._tables_dt_push_dist_mm)))