163 lines
4.7 KiB
Python
Executable File
163 lines
4.7 KiB
Python
Executable File
from ..devices_general.motors import MotorRecord
|
|
from epics import PV
|
|
from ..devices_general.utilities import Changer
|
|
from time import sleep
|
|
import numpy as np
|
|
|
|
class Double_Crystal_Mono:
|
|
def __init__(self,Id):
|
|
self.Id = Id
|
|
self.theta = MotorRecord(Id+':RX12')
|
|
self.x = MotorRecord(Id+':TX12')
|
|
self.gap = MotorRecord(Id+':T2')
|
|
self.roll1 = MotorRecord(Id+':RZ1')
|
|
self.roll2 = MotorRecord(Id+':RZ2')
|
|
self.pitch2 = MotorRecord(Id+':RX2')
|
|
|
|
self.energy_rbk = PV(Id+':ENERGY')
|
|
self.energy_sp = PV(Id+':ENERGY_SP')
|
|
self.moving = PV(Id+':MOVING')
|
|
self._stop = PV(Id +':STOP.PROC')
|
|
|
|
def move_and_wait(self,value,checktime=.01,precision=.5):
|
|
self.energy_sp.put(value)
|
|
while abs(self.wait_for_valid_value()-value)>precision:
|
|
sleep(checktime)
|
|
|
|
def changeTo(self,value,hold=False):
|
|
changer = lambda value: self.move_and_wait(value)
|
|
return Changer(
|
|
target=value,
|
|
parent=self,
|
|
changer=changer,
|
|
hold=hold,
|
|
stopper=self.stop)
|
|
|
|
def stop(self):
|
|
self._stop.put(1)
|
|
|
|
def get_current_value(self):
|
|
currentenergy = self.energy_rbk.get()
|
|
return currentenergy
|
|
|
|
def wait_for_valid_value(self):
|
|
tval = np.nan
|
|
while not np.isfinite(tval):
|
|
tval = self.energy_rbk.get()
|
|
return(tval)
|
|
|
|
def set_current_value(self,value):
|
|
self.energy_sp.put(value)
|
|
|
|
def get_moveDone(self):
|
|
inmotion = int(self.moving.get())
|
|
return inmotion
|
|
|
|
# spec-inspired convenience methods
|
|
def mv(self,value):
|
|
self._currentChange = self.changeTo(value)
|
|
def wm(self,*args,**kwargs):
|
|
return self.get_current_value(*args,**kwargs)
|
|
def mvr(self,value,*args,**kwargs):
|
|
|
|
if(self.get_moveDone == 1):
|
|
startvalue = self.get_current_value(*args,**kwargs)
|
|
else:
|
|
startvalue = self.get_current_value(*args,**kwargs)
|
|
self._currentChange = self.changeTo(value+startvalue,*args,**kwargs)
|
|
def wait(self):
|
|
self._currentChange.wait()
|
|
|
|
def __str__(self):
|
|
s = "**Double crystal monochromator**\n\n"
|
|
motors = "theta gap x roll1 roll2 pitch2".split()
|
|
for motor in motors:
|
|
s+= " - %s = %.4f\n" %(motor, getattr(self,motor).wm())
|
|
pvs = "energy_rbk".split()
|
|
for pv in pvs:
|
|
s+= " - %s = %.4f\n" %(pv, getattr(self,pv).value)
|
|
return s
|
|
|
|
def __repr__(self):
|
|
return self.__str__()
|
|
|
|
def __call__(self,value):
|
|
self._currentChange = self.changeTo(value)
|
|
|
|
|
|
class EcolEnergy:
|
|
def __init__(self,Id, val='SARCL02-MBND100:P-SET',rb='SARCL02-MBND100:P-READ' ,dmov='SFB_BEAM_ENERGY_ECOL:SUM-ERROR-OK'):
|
|
self.Id = Id
|
|
self.setter = PV(val)
|
|
self.readback = PV(rb)
|
|
self.dmov = PV(dmov)
|
|
self.done = False
|
|
|
|
def get_current_value(self):
|
|
return self.readback.get()
|
|
|
|
def move_and_wait(self,value,checktime=.01,precision=2):
|
|
curr = self.setter.get()
|
|
while abs(curr-value)>0.1:
|
|
curr = self.setter.get()
|
|
self.setter.put(curr + np.sign(value-curr)*.1)
|
|
sleep(0.3)
|
|
|
|
self.setter.put(value)
|
|
while abs(self.get_current_value() - value)>precision:
|
|
sleep(checktime)
|
|
while not self.dmov.get():
|
|
#print(self.dmov.get())
|
|
sleep(checktime)
|
|
|
|
def changeTo(self,value,hold=False):
|
|
changer = lambda value: self.move_and_wait(value)
|
|
return Changer(
|
|
target=value,
|
|
parent=self,
|
|
changer=changer,
|
|
hold=hold,
|
|
stopper=None)
|
|
|
|
|
|
class MonoEcolEnergy:
|
|
def __init__(self,Id):
|
|
self.Id = Id
|
|
self.name = 'energy_collimator'
|
|
self.dcm = Double_Crystal_Mono(Id)
|
|
self.ecol = EcolEnergy('ecol_dummy')
|
|
self.offset = None
|
|
self.MeVperEV = 0.78333
|
|
|
|
|
|
def get_current_value(self):
|
|
return self.dcm.get_current_value()
|
|
|
|
def move_and_wait(self,value):
|
|
ch = [self.dcm.changeTo(value),
|
|
self.ecol.changeTo(self.calcEcol(value))]
|
|
for tc in ch:
|
|
tc.wait()
|
|
|
|
def changeTo(self,value,hold=False):
|
|
changer = lambda value: self.move_and_wait(value)
|
|
return Changer(
|
|
target=value,
|
|
parent=self,
|
|
changer=changer,
|
|
hold=hold,
|
|
stopper=self.dcm.stop)
|
|
|
|
def alignOffsets(self):
|
|
mrb = self.dcm.get_current_value()
|
|
erb = self.ecol.get_current_value()
|
|
self.offset = {'dcm':mrb, 'ecol':erb}
|
|
|
|
def calcEcol(self,eV):
|
|
return (eV-self.offset['dcm'])*self.MeVperEV + self.offset['ecol']
|
|
|
|
|
|
|
|
|
|
|