702 lines
23 KiB
Python
702 lines
23 KiB
Python
"""
|
|
Class library for the Pearl PGM
|
|
|
|
OTF scans of monochromator angles
|
|
|
|
Author:
|
|
Juraj Krempasky
|
|
Matthias Muntwiler
|
|
|
|
Created:
|
|
Feb 19, 2013
|
|
"""
|
|
import time, os, os.path, sys, string, re
|
|
ARCH = os.environ['EPICS_HOST_ARCH']
|
|
sys.path.insert(0, '/afs/psi.ch/user/w/wang_x1/public/'+ARCH)
|
|
sys.path.append('/afs/psi.ch/user/k/krempasky/public')
|
|
from jkpkg.app import epicsMotor
|
|
from jkpkg.app import epv
|
|
import threading
|
|
import blstatus
|
|
|
|
MAXARRAY = 6000
|
|
|
|
#!OTF
|
|
class OTFscan_th(threading.Thread):
|
|
def __init__(self, worker):
|
|
threading.Thread.__init__(self)
|
|
self.worker = worker
|
|
self.running = 1 # assign 0 to end the thread
|
|
self.start()
|
|
|
|
def run(self):
|
|
try:
|
|
#self.worker.eopt = 0 # do not drive PGM+ID
|
|
parm = {'FOLDER':self.worker.folder, 'FILE':self.worker.file}
|
|
(isok,rstring) = self.worker.makefile(parm, set=1, xmcd=self.worker.xmcd)
|
|
if isok:
|
|
self.worker.msg = "%s"%(os.path.basename(rstring))
|
|
self.worker.path = rstring
|
|
else:
|
|
self.worker.msg = "%s"%(rstring)
|
|
raise Exception, self.worker.msg
|
|
|
|
print self.worker.msg
|
|
self.worker.outparam['done']=0
|
|
uprate = self.worker.uparam['uprate']
|
|
#(E1,E2,tr_time)=self.worker.uparam['otf']
|
|
#(beta1, beta2, theta1, theta2, ttime) = self.uparam['angles']
|
|
print "update interval is %g seconds" % (uprate * 0.01)
|
|
cnt = 0
|
|
|
|
while self.running:
|
|
time.sleep(0.01)
|
|
if cnt >= uprate:
|
|
cnt = 0
|
|
else:
|
|
cnt = cnt + 1
|
|
continue
|
|
|
|
try:
|
|
self.worker.getdata()
|
|
except:
|
|
self.worker.msg = "EPICS channels missing"
|
|
break
|
|
if not self.running:
|
|
break
|
|
if not self.worker.isbusy():
|
|
break
|
|
E_act = self.worker.E_rbk
|
|
#self.worker.outparam['pb_set']=int(100*(E_act-E1)/(E2-E1))
|
|
self.worker.outparam['Erbk']=("%.1f eV"%(E_act))
|
|
|
|
# do not overshoot
|
|
if self.worker.check_endpoint():
|
|
self.worker.stop()
|
|
break
|
|
if self.worker.pntcnt > MAXARRAY:
|
|
self.worker.msg = "OTF points exceed %d, abort..."%(MAXARRAY)
|
|
raise Exception, self.worker.msg
|
|
|
|
self.worker.msg = self.worker.msg + ' done'
|
|
print self.worker.msg
|
|
self.worker.savedata(self.worker.path, self.worker.file)
|
|
finally:
|
|
print "scan thread exit"
|
|
self.worker.stop()
|
|
self.worker.outparam['done']=1
|
|
self.worker.running = 0
|
|
|
|
|
|
##!1###################################################################
|
|
class epicsPGM(object):
|
|
"""
|
|
detector = "kei6517", "ah401", or "cadc" (default)
|
|
"""
|
|
def __init__(self, detector = "cadc"):
|
|
# keep the identifiers consistent with the region.py module
|
|
self.err = None
|
|
self.pvs = {} #to monitor
|
|
self.xpvs = {} #to monitor
|
|
self.pvsdata = {}
|
|
self.setpvs = {}
|
|
self.mm = epicsMotor.motor("X03DA-PGM:MI")
|
|
self.gm = epicsMotor.motor("X03DA-PGM:GR")
|
|
self.detector = detector
|
|
|
|
#uparam['cadc_otf']= sclock, sbuffer, srate
|
|
#sclock: 0:1kHz 1:5kHz 2:10kHz 3:50kHz 4:100kHz
|
|
#srate: Idle 1 10 100 Hz
|
|
|
|
self.uparam={'uprate':10,\
|
|
'ptpsp':[(560,600,10),(600,615,5)],\
|
|
'otf':[840.0, 880.0, 1.0],\
|
|
'angles':[-87.0, -87.0, 86.0, 86.0, 1.0],\
|
|
'cadc_otf':[4,600,3],\
|
|
'cadc_ptp':[2,10000,0]}
|
|
#'cadc_otf':[3,1000,3],'cadc_ptp':[1,10000,0]}
|
|
|
|
self.outparam={'pb_len':0,'pb_set':0,'Erbk':0,'done':0}
|
|
self.running = 0
|
|
self.xmcd = None
|
|
self.xmcdrunning = 0
|
|
self.pntcnt = 0
|
|
self.cmd = '???'
|
|
self.msg = 'X03DA OTF (%s)' % (self.detector)
|
|
self.folder = 'TEST'
|
|
self.file = 'test'
|
|
self.format = 'itx'
|
|
self.path = "/tmp/otfdata" + '.' + self.format
|
|
self.connect()
|
|
|
|
def connect(self):
|
|
self.err = None
|
|
if 1:
|
|
# PVs read via getdata()
|
|
self.pvs['E'] = epv.epv('X03DA-PGM:energy')
|
|
self.pvs['E_rbk'] = epv.epv('X03DA-PGM:rbkenergy')
|
|
self.pvs['E_crbk'] = epv.epv('X03DA-PGM:CERBK')
|
|
self.pvs['cff_rbk'] = epv.epv('X03DA-PGM:rbkcff')
|
|
self.pvs['theta'] = epv.epv('X03DA-PGM:theta')
|
|
self.pvs['theta_rbk'] = epv.epv('X03DA-PGM:rbktheta')
|
|
self.pvs['beta'] = epv.epv('X03DA-PGM:beta')
|
|
self.pvs['beta_rbk'] = epv.epv('X03DA-PGM:rbkbeta')
|
|
self.pvs['grating'] = epv.epv('X03DA-PGM:grating')
|
|
self.pvs['dmov'] = epv.epv('X03DA-PGM:dmov')
|
|
if self.detector == 'kei6517':
|
|
self.pvs['K1'] = epv.epv('X03DA-KEI11:READOUT')
|
|
self.pvs['K2'] = epv.epv('X03DA-KEI12:READOUT')
|
|
elif self.detector == 'ah401':
|
|
self.pvs['K1'] = epv.epv('X03DA-AH401B:CH1')
|
|
self.pvs['K2'] = epv.epv('X03DA-AH401B:CH2')
|
|
elif self.detector == 'cadc3':
|
|
self.pvs['K1'] = epv.epv('X03DA-OP:CURRENT3')
|
|
self.pvs['K2'] = epv.epv('X03DA-OP:CURRENT2')
|
|
else: # cadc
|
|
self.pvs['K1'] = epv.epv('X03DA-OP:CURRENT1')
|
|
self.pvs['K2'] = epv.epv('X03DA-OP:CURRENT2')
|
|
|
|
print "selected detector: " + self.detector
|
|
|
|
self.pvs['machine current (mA)'] = epv.epv('ARIDI-PCT:CURRENT')
|
|
self.xpvs['HALT'] = epv.epv('X03DA-PGM:stop')
|
|
self.xpvs['alldone'] = epv.epv('X03DA-PGM:dmov')
|
|
|
|
# set PVs
|
|
self.setpvs['set_E'] = epv.epv('X03DA-PGM:setE.PROC')
|
|
self.setpvs['set_cff'] = epv.epv('X03DA-PGM:dftcff.C')
|
|
self.setpvs['set_beta'] = epv.epv('X03DA-PGM:ronbeta.A ')
|
|
self.setpvs['set_theta'] = epv.epv('X03DA-PGM:rontheta.A ')
|
|
#self.pvs[E].pend_io()
|
|
|
|
self.ResetPvsData()
|
|
|
|
# Wait for all PVs to connect
|
|
try:
|
|
self.pvs['E'].pend_io()
|
|
except:
|
|
self.err = 'EPICS channels not available'
|
|
print ("connect() ERROR:%s"%(self.err))
|
|
return 0
|
|
return 1
|
|
|
|
def addIgorWave(self, id, wave, figor, unit='', phystype='', axiswave=''):
|
|
"""
|
|
adds a one-dimensional dataset to the open igor file.
|
|
id = key of the data source in the pvsdata dictionary
|
|
wave = target name of the igor wave
|
|
figor = file object with the open igor file
|
|
unit = physical unit. is overridden by EPICS EGU field if available
|
|
phystype = physical data type (see pearl-optics-import-data.itx)
|
|
axiswave = wave name of independent axis
|
|
"""
|
|
if not id in self.pvsdata.keys():
|
|
print "id. %s unknown\n"%(id)
|
|
return
|
|
vec = self.pvsdata[id]
|
|
# wave header and data
|
|
if id in self.pvs.keys():
|
|
pvname = self.pvs[id].pvname
|
|
try:
|
|
unit = self.pvs[id].callBack.pv_units
|
|
except:
|
|
pass
|
|
else:
|
|
pvname = ''
|
|
if pvname:
|
|
line = 'X // %s\n' % (pvname)
|
|
figor.write(line)
|
|
line = 'WAVES/D/O/N=(%d) %s\nBEGIN\n' % (len(vec),wave)
|
|
figor.write(line)
|
|
svec = string.replace(str(vec),',',' ')
|
|
figor.write(svec[1:len(svec)-1]+'\n')
|
|
figor.write('END\n')
|
|
# scaling and meta-data
|
|
if unit:
|
|
line = 'X setscale d 0,0,"%s",%s\n' % (unit, wave)
|
|
figor.write(line)
|
|
if pvname:
|
|
line = 'X note %s, "PV=%s"\n' % (wave, pvname)
|
|
figor.write(line)
|
|
if phystype:
|
|
line = 'X note %s, "PhysicalType=%s"\n' % (wave, phystype)
|
|
figor.write(line)
|
|
if axiswave:
|
|
line = 'X note %s, "Axis1=%s"\n' % (wave, axiswave)
|
|
figor.write(line)
|
|
figor.write('\n')
|
|
|
|
def savedata_itx(self, path='/tmp/otfdata.itx', comment=None):
|
|
"""
|
|
saves measured data in an igor text file.
|
|
path = file name including path.
|
|
the file name will be used as igor data folder name.
|
|
it should not be longer than 32 characters
|
|
and not contain too many special characters.
|
|
non-alphanumeric characters are changed to underscores for folder names.
|
|
"""
|
|
try:
|
|
fo = open(path,'w')
|
|
except:
|
|
print 'savedata_itx(): cannot open %s\n' % (path,)
|
|
return
|
|
|
|
line = 'IGOR\n'
|
|
fo.write(line)
|
|
line = 'X // X03DA OTF scan version 2013-04-02\n'
|
|
fo.write(line)
|
|
(datafolder, ext) = os.path.splitext(os.path.basename(path))
|
|
datafolder = re.sub('[^a-zA-Z0-9_]', '_', datafolder, count=0)
|
|
if datafolder:
|
|
line = '\nX newdatafolder /s/o root:raw'
|
|
#fo.write(line)
|
|
line = '\nX newdatafolder /s/o %s\n\n' % (datafolder)
|
|
#fo.write(line)
|
|
if comment:
|
|
line = 'X string comment = "%s"\n\n' % (comment)
|
|
|
|
# wave names should conform to the list in pearl-optics-import-data.itx
|
|
self.addIgorWave('elapsed_time_secs', 'elapsed_time', fo, \
|
|
phystype='time', unit='s')
|
|
self.addIgorWave('machine current (mA)', 'ringcurrent', fo, \
|
|
phystype='ring current', unit='mA', axiswave='photonenergy')
|
|
self.addIgorWave('E_crbk', 'photonenergy', fo, \
|
|
phystype='photon energy', unit='eV', axiswave='elapsed_time')
|
|
self.addIgorWave('cff_rbk', 'cff', fo, \
|
|
phystype='focus constant', unit='', axiswave='photonenergy')
|
|
if self.scanType == "angle":
|
|
self.addIgorWave('beta_rbk', 'beta_rbk', fo, \
|
|
phystype='grating angle', unit='deg', axiswave='photonenergy')
|
|
self.addIgorWave('theta_rbk', 'theta_rbk', fo, \
|
|
phystype='mirror angle', unit='deg', axiswave='photonenergy')
|
|
# write data if channel is available
|
|
if self.pvs['K1'].getw() <> 0.0:
|
|
self.addIgorWave('K1', 'current_ch1', fo, \
|
|
phystype='current', unit='A', axiswave='photonenergy')
|
|
line = 'X current_ch1 *= 400/ringcurrent\n'
|
|
fo.write(line)
|
|
line = 'X note current_ch1, "normalized to ringcurrent"\n\n'
|
|
fo.write(line)
|
|
if self.pvs['K2'].getw() <> 0.0:
|
|
self.addIgorWave('K2', 'current_ch2', fo, \
|
|
phystype='current', unit='A', axiswave='photonenergy')
|
|
line = 'X current_ch2 *= 400/ringcurrent\n'
|
|
fo.write(line)
|
|
line = 'X note current_ch2, "normalized to ringcurrent"\n\n'
|
|
fo.write(line)
|
|
|
|
bls = blstatus.BLStatus()
|
|
bls.save_itx_waves(fo)
|
|
|
|
fo.close()
|
|
|
|
|
|
def makefile(self, parm, set = 0, xmcd=None):
|
|
'''
|
|
parm: string dictionary to be evaluated
|
|
set: create the file
|
|
'''
|
|
set = set
|
|
keys=['FOLDER','FILE']
|
|
try:
|
|
parm = eval(str(parm))
|
|
except:
|
|
return (0,"ERROR:%s format"%(str(parm)))
|
|
if type(parm)<>type({}):
|
|
return (0,"ERROR:%s not dict"%(str(parm)))
|
|
if len(parm.keys())<>2:
|
|
return (0,"ERROR:%s 2 keys needed"%(str(parm)))
|
|
|
|
if 'FOLDER' not in parm.keys():
|
|
return (0,"ERROR: FOLDER key mising")
|
|
if 'FILE' not in parm.keys():
|
|
return (0,"ERROR: FILE key mising")
|
|
|
|
upath = os.getenv('HOME')+'/Data1/'
|
|
folder = parm['FOLDER']
|
|
folder = os.path.join(upath, folder)
|
|
|
|
if not os.path.exists(folder):
|
|
try:
|
|
os.makedirs(folder)
|
|
except:
|
|
return (0,'ERROR mkdir %s'%(folder))
|
|
|
|
tstamp = time.strftime("%y%m%d-%H%M%S", time.localtime())
|
|
fname = "otf-%s.%s" % (tstamp, self.format)
|
|
path = os.path.join(folder, fname)
|
|
if set:
|
|
try:
|
|
fd = open(path,'w')
|
|
fd.close()
|
|
except:
|
|
msg = '%s %s'%(sys.exc_info()[0],sys.exc_info()[1])
|
|
return (0,msg)
|
|
|
|
return (1,path)
|
|
|
|
def savedata(self, path='/tmp/otfdata.txt', comment=None):
|
|
if self.format == 'itx':
|
|
self.savedata_itx(path, comment)
|
|
return
|
|
|
|
try:
|
|
fd=open(path,'w')
|
|
except:
|
|
print 'savedata(): cannot open %s\n'%(path,)
|
|
return
|
|
#Frithjof wants this order:
|
|
keys=['E_crbk','K1','K2','K3','K4','machine current (mA)','cff_rbk','elapsed_time_secs']
|
|
#keys = self.pvs.keys()
|
|
header=str(keys)[1:-1];
|
|
header = string.replace(header,"elapsed_time_secs",'time')
|
|
header = string.replace(header,',',' ')
|
|
#header = string.replace(header,' ','')
|
|
header = string.replace(header,"'",'')
|
|
header = string.replace(header,",",' ')
|
|
header = string.replace(header,"_",'')
|
|
header = string.replace(header,"machine current (mA)",'MCurr')
|
|
fd.write(header+'\n')
|
|
|
|
vec = self.pvsdata[keys[0]]
|
|
cnt = len(vec)-1
|
|
print '%s data length %d\n'%(keys[0],cnt,)
|
|
|
|
for i in range(cnt):
|
|
txt = ''
|
|
for key in keys:
|
|
#print ('%s %s\n')%(i,key)
|
|
vec = self.pvsdata[key]
|
|
#print vec
|
|
s = str(vec[i])
|
|
#s = str(dili[i].values())[1:-1];string.replace(s,',',' ')
|
|
txt=txt+s+ ' '
|
|
txt=txt+'\n'
|
|
fd.write(txt)
|
|
|
|
fd.close()
|
|
|
|
def ResetPvsData(self):
|
|
self.start = time.time()
|
|
self.pvsdata['timestamp'] = [0]
|
|
self.pvsdata['elapsed_time_secs'] = [0]
|
|
|
|
self.pvsdata['machine current (mA)'] = [0]
|
|
self.pvsdata['E'] = [0]
|
|
self.pvsdata['E_rbk'] = [0]
|
|
self.pvsdata['E_crbk'] = [0]
|
|
self.pvsdata['cff'] = [0]
|
|
self.pvsdata['cff_rbk'] = [0]
|
|
self.pvsdata['theta'] = [0]
|
|
self.pvsdata['theta_rbk'] = [0]
|
|
self.pvsdata['theta_set'] = [0]
|
|
self.pvsdata['beta'] = [0]
|
|
self.pvsdata['beta_rbk'] = [0]
|
|
self.pvsdata['beta_set'] = [0]
|
|
self.pvsdata['grating'] = [0]
|
|
self.pvsdata['dmov'] = [0]
|
|
self.pvsdata['K1'] = [0]
|
|
self.pvsdata['K2'] = [0]
|
|
|
|
|
|
#!setE
|
|
def setE(self,E,fast=0, mode=None, id=None):
|
|
''' mode: 0:LINEAR 1:CIRC+, 2:CIRC-'''
|
|
if fast:
|
|
self.velo()
|
|
#if self.E == E:
|
|
# return
|
|
|
|
self.E = E
|
|
self.set_E = 1
|
|
|
|
def velo(self, maxspeed = 0.03):
|
|
'''
|
|
set velocities to custom or maximum values
|
|
'''
|
|
if maxspeed > 0.03:
|
|
maxspeed = 0.03
|
|
(self.mm.VELO, self.gm.VELO) = (maxspeed, maxspeed)
|
|
time.sleep(0.05)
|
|
#print "mirror: vbas=%f velo=%f acc=%f"%(self.mm.VELO, self.mm.VBAS, self.mm.ACCL)
|
|
#print "grating: vbas=%f velo=%f acc=%f"%(self.gm.VELO, self.gm.VBAS, self.gm.ACCL)
|
|
|
|
def setDft(self):
|
|
'''
|
|
reset velocities to default values
|
|
'''
|
|
(self.mm.VELO, self.gm.VELO) = (0.03, 0.03)
|
|
(self.mm.VBAS, self.gm.VBAS) = (0.003, 0.003)
|
|
|
|
def set_EnergyScan(self, E1, E2, tr_time = 2):
|
|
'''
|
|
sets up an energy scan
|
|
E1 = start energy in eV
|
|
E2 = end energy in eV
|
|
tr_time = travel time in minutes
|
|
call start_scan() to actuall start the scan
|
|
'''
|
|
self.travel_time = tr_time
|
|
self.E = E1
|
|
time.sleep(0.05)
|
|
(self.E1, self.theta1, self.beta1) = (self.E, self.theta, self.beta)
|
|
self.E = E2
|
|
time.sleep(0.05)
|
|
(self.E2, self.theta2, self.beta2) = (self.E, self.theta, self.beta)
|
|
self.scanType = 'energy'
|
|
print "Start: E = %f, theta = %f, beta = %f" % (self.E1, self.theta1, self.beta1)
|
|
print "End: E = %f, theta = %f, beta = %f\n" % (self.E2, self.theta2, self.beta2)
|
|
|
|
def set_AngleScan(self, beta1, beta2, theta1, theta2, tr_time = 2):
|
|
'''
|
|
sets up a linear angle scan
|
|
beta1 = start angle in degrees
|
|
beta2 = end angle in degrees
|
|
theta1 = start angle in degrees
|
|
theta2 = end angle in degrees
|
|
tr_time is travel time in minutes
|
|
call start_scan() to actuall start the scan
|
|
'''
|
|
self.travel_time = tr_time
|
|
self.theta1 = theta1
|
|
self.theta2 = theta2
|
|
self.beta1 = beta1
|
|
self.beta2 = beta2
|
|
self.scanType = 'angle'
|
|
print "Start: theta = %f, beta = %f" % (self.theta1, self.beta1)
|
|
print "End: theta = %f, beta = %f\n" % (self.theta2, self.beta2)
|
|
|
|
def start_scan(self):
|
|
'''
|
|
starts an on-the-fly scan
|
|
which was set up by one of the set_XxxxScan() functions
|
|
'''
|
|
|
|
self.msg = "moving to start..."
|
|
print self.msg
|
|
mbeta = abs(self.beta1 - self.beta_rbk) > 0.0001
|
|
mtheta = abs(self.theta1 - self.theta_rbk) > 0.0001
|
|
# note: do not read back from self.beta or self.theta!
|
|
if mbeta:
|
|
self.set_beta = self.beta1
|
|
if mtheta:
|
|
self.set_theta = self.theta1
|
|
nretries = 5
|
|
while (mbeta or mtheta) and (nretries > 0):
|
|
nretries = nretries - 1
|
|
if self.waitdone(timeout = 30 / 0.1):
|
|
time.sleep(2)
|
|
print "Readback: theta = %f, beta = %f" % (self.theta_rbk, self.beta_rbk)
|
|
mbeta = abs(self.beta1 - self.beta_rbk) > 0.0001
|
|
mtheta = abs(self.theta1 - self.theta_rbk) > 0.0001
|
|
if mbeta:
|
|
self.set_beta = self.beta1
|
|
if mtheta:
|
|
self.set_theta = self.theta1
|
|
if not mbeta and not mtheta:
|
|
self.msg = "start point reached"
|
|
else:
|
|
self.msg = "timeout while moving to start"
|
|
return False
|
|
|
|
if mbeta or mtheta:
|
|
self.msg = "failed to reach start point"
|
|
print self.msg
|
|
return False
|
|
print self.msg
|
|
|
|
maxspeed = 0.03
|
|
tr_time = self.travel_time * 60
|
|
dbeta = abs(self.beta2 - self.beta1)
|
|
dtheta = abs(self.theta2 - self.theta1)
|
|
mbeta = dbeta > 0.0001
|
|
mtheta = dtheta > 0.0001
|
|
print "dtheta = %f, dbeta = %f\n" % (dtheta, dbeta)
|
|
vtheta = dtheta / tr_time
|
|
vbeta = dbeta / tr_time
|
|
print "vtheta = %f, vbeta = %f\n"%(vtheta,vbeta)
|
|
if vtheta > maxspeed or not mtheta:
|
|
vtheta = maxspeed
|
|
if vbeta > maxspeed or not mbeta:
|
|
vbeta = maxspeed
|
|
|
|
(self.mm.VBAS, self.gm.VBAS) = (vtheta/10, vbeta/10)
|
|
time.sleep (0.1)
|
|
(self.mm.VELO, self.gm.VELO) = (vtheta, vbeta)
|
|
time.sleep (0.1)
|
|
print "mirror: velo=%f vbas=%f acc=%f" % (self.mm.VELO, self.mm.VBAS, self.mm.ACCL)
|
|
print "grating: velo=%f vbas=%f acc=%f\n" % (self.gm.VELO, self.gm.VBAS, self.gm.ACCL)
|
|
|
|
#self.outparam['pb_len']=int(E2-E1)
|
|
self.ResetPvsData()
|
|
if mbeta:
|
|
self.set_beta = self.beta2
|
|
if mtheta:
|
|
self.set_theta = self.theta2
|
|
result = self.waitbusy()
|
|
if result:
|
|
self.msg = "flying to destination..."
|
|
else:
|
|
self.msg = "timeout while starting scan"
|
|
print self.msg
|
|
return result
|
|
|
|
def check_endpoint(self):
|
|
"""
|
|
returns true if the scan has passed the end point, False otherwise.
|
|
"""
|
|
result = ((self.beta_rbk - self.beta2) * (self.beta2 - self.beta1) > 0) \
|
|
or ((self.theta_rbk - self.theta2) * (self.theta2 - self.theta1) > 0)
|
|
return result
|
|
|
|
def otfp(self, E1, E2, tr_time = 2):
|
|
'''
|
|
starts an energy scan
|
|
obsolete - use set_EnergyScan() and start_scan() instead
|
|
'''
|
|
self.set_EnergyScan(E1, E2, tr_time)
|
|
self.start_scan()
|
|
|
|
########################################################################
|
|
def __getattr__(self, attrname):
|
|
try:
|
|
if (attrname == 'E'): return self.pvs['E'].getw()
|
|
elif (attrname == 'E_rbk'): return self.pvs['E_rbk'].getw()
|
|
elif (attrname == 'E_crbk'): return self.pvs['E_crbk'].getw()
|
|
elif (attrname == 'cff'): return self.pvs['cff'].getw()
|
|
elif (attrname == 'cff_rbk'): return self.pvs['cff_rbk'].getw()
|
|
elif (attrname == 'theta'): return self.pvs['theta'].getw()
|
|
elif (attrname == 'theta_rbk'): return self.pvs['theta_rbk'].getw()
|
|
elif (attrname == 'beta'): return self.pvs['beta'].getw()
|
|
elif (attrname == 'beta_rbk'): return self.pvs['beta_rbk'].getw()
|
|
elif (attrname == 'alldone'): return self.xpvs['alldone'].getw()
|
|
elif (attrname == 'dmov'): return self.pvs['dmov'].getw()
|
|
elif (attrname == 'grating'): return self.pvs['grating'].getw()
|
|
elif (attrname == 'K1'): return self.pvs['K1'].getw()
|
|
elif (attrname == 'K2'): return self.pvs['K2'].getw()
|
|
#else: raise AttributeError, attrname
|
|
else: return self.__dict__[attrname]
|
|
except:
|
|
msg = 'epicsPGM() __getattr__ %s %s'%(sys.exc_info()[0],sys.exc_info()[1])
|
|
print msg
|
|
|
|
def __setattr__(self, attrname, value):
|
|
try:
|
|
if (attrname == 'E'): self.pvs['E'].putw(value)
|
|
elif (attrname == 'set_E'): self.setpvs['set_E'].putw(value)
|
|
elif (attrname == 'HALT'): self.xpvs['HALT'].putw(1)
|
|
elif (attrname == 'set_cff'): self.pvs['set_cff'].putw(value)
|
|
elif (attrname == 'set_theta'): self.setpvs['set_theta'].putw(value)
|
|
elif (attrname == 'set_beta'): self.setpvs['set_beta'].putw(value)
|
|
#else: raise AttributeError, attrname
|
|
else: self.__dict__[attrname] = value
|
|
except:
|
|
msg = 'epicsPGM() __setattr__ %s %s'%(sys.exc_info()[0],sys.exc_info()[1])
|
|
print msg
|
|
|
|
def xmcdgo(self):
|
|
raise Exception, "xmcdgo method not implemented for PEARL"
|
|
|
|
|
|
#!go##############################
|
|
def otfgo(self):
|
|
'''
|
|
handles energy scan command
|
|
'''
|
|
if self.running:
|
|
return
|
|
print "otfgo..."
|
|
self.pntcnt = 0
|
|
(E1,E2,ttime)=self.uparam['otf']
|
|
self.running = 1
|
|
self.set_EnergyScan(E1, E2, ttime)
|
|
self.start_scan()
|
|
self.thread = OTFscan_th(self)
|
|
|
|
def go_angle(self):
|
|
'''
|
|
handles angle scan command
|
|
'''
|
|
if self.running:
|
|
return
|
|
print "go_angle..."
|
|
self.pntcnt = 0
|
|
(beta1, beta2, theta1, theta2, ttime) = self.uparam['angles']
|
|
self.running = 1
|
|
self.set_AngleScan(beta1, beta2, theta1, theta2, ttime)
|
|
self.start_scan()
|
|
self.thread = OTFscan_th(self)
|
|
|
|
def stop(self):
|
|
try:
|
|
self.thread.running = 0
|
|
self.thread.join()
|
|
except:
|
|
pass
|
|
self.HALT=1
|
|
self.setDft()
|
|
|
|
def getdata(self):
|
|
#if not self.pvs['K1'].checkMonitor():
|
|
# return
|
|
|
|
if self.pntcnt == 0:
|
|
self.pvsdata['elapsed_time_secs'] = [time.time() - self.start]
|
|
self.pvsdata['timestamp'] = [time.ctime()]
|
|
for pv in self.pvs.keys():
|
|
self.pvsdata[pv] = [self.pvs[pv].getw()]
|
|
else:
|
|
self.pvsdata['elapsed_time_secs'].append(time.time() - self.start)
|
|
self.pvsdata['timestamp'].append(time.ctime())
|
|
for pv in self.pvs.keys():
|
|
self.pvsdata[pv].append(self.pvs[pv].getw() )
|
|
self.pntcnt +=1
|
|
|
|
#tstamp =time.strftime("%d/%b/%y %H:%M:%S",time.localtime())
|
|
|
|
def isbusy(self):
|
|
if self.alldone:
|
|
return 0
|
|
else:
|
|
return 1
|
|
|
|
def waitbusy(self):
|
|
"""
|
|
wait until motors have started
|
|
"""
|
|
tick = 0
|
|
#print 'waitbusy...'
|
|
while not self.isbusy():
|
|
time.sleep(0.1)
|
|
tick = tick+1
|
|
if tick >= 5:
|
|
return 0
|
|
#print '.'
|
|
return 1
|
|
|
|
def waitdone(self, timeout = 100):
|
|
self.waitbusy()
|
|
tick = 0
|
|
while self.isbusy():
|
|
if not self.running:
|
|
break
|
|
time.sleep(0.1)
|
|
tick = tick+1
|
|
self.msg = "current energy %.1f eV" % (self.E_crbk)
|
|
if tick >= timeout:
|
|
self.msg = "TIMEOUT"
|
|
return 0
|
|
return 1
|
|
|
|
def test():
|
|
gds = epicsPGM()
|
|
gds.ResetPvsData()
|
|
gds.getdata()
|
|
print str(gds.pvsdata)
|
|
gds.ResetPvsData()
|
|
gds.getdata()
|
|
print str(gds.pvsdata)
|
|
|
|
if __name__ == '__main__':
|
|
test()
|