Files
OM/OMEpics.py
T

716 lines
18 KiB
Python

import PyCafe
from OMSLS2Magnet import *
import pickle
from time import sleep
class EpicsChannel:
def __init__(self,S2,VA=False,Default=False):
# "Dictionary" for the epics channels,
# the names of which may be changing
# S2 is an instance of OMFacility
# The names are temporary. Change them only in this script.
# The actual epics name shoud not be used
# in other script for consistency.
if VA:
self.pf=VA+'-'
else:
self.pf=''
self.cafe=PyCafe.CyCafe()
self.cafe.init()
self.cyca=PyCafe.CyCa()
if S2:
# Relevant modules
self.S2=S2
self.SM=SLS2Magnet()
# Some important channels
# RF frequency
self.frf=self.pf+'AGARF-TIM:BO-FREQ-SET' # This should be used. 'AGARF' is not typo
#self.frf=self.pf+'AGERF-MO01:FREQ-SET'
# from 0.1 Hz to 100000(?) Hz == 10 Hz/s to 10 MHz/s
self.frfrate=self.pf+'AGERF-MO01:FREQ-STEP'
# Trigger
self.TriggerEnable=self.pf+'AGETI-CVME-MASTER-TMA:SR-Inj-Status-Sel'
#self.Trigger=self.pf+'ALIRF-VME-A-GUN:CH1-SWTRIG' # Gun trigger
#self.Trigger=self.pf+'ALIRF-VME-A-GUN:CH1-MODE' # Gun trigger
self.Trigger=self.pf+'AGETI-CVME-MASTER-TMA:Evt-10-Ena-Sel'
self.BPMTrigger='AGETI-CVME-MASTER-TMA:Evt-11-Ena-Sel'
# This may be used to keep the booster and the linac running. Masked -> Down ramp, not extracted
self.TriggerMask=self.pf+'AGETI-CVME-MASTER-TMA:Evt-BO-Ext-Mask-SP'
self.ch={}
self.Handle={}
#TbT
self.TbTopen=False
# Edit here in case Epics channel is changed...
self.Atr_PS={'I':'I-SET',
'I-READ':'I-READ',
'ON':'ONOFF'}
# Kicker power supply
self.Atr_KPS={'I':'I-SET',
'I-READ':'I-READ',
'DELAY':'DELAY',
'ON':'ONOFF'}
if self.pf:
self.Atr_BPM={'X':'X',
'Y':'Y',
'Q':'Q',
'OX':'OFFS-X',
'OY':'OFFS-Y',
'TBTX':'TBT-X',
'TBTY':'TBT-Y',
'TBTZ':'TBT-Z',
'TBTQ':'TBT-Q',
'MODE':'MODE'}
else:
self.Atr_BPM={'X':'POS-STG2-X',
'Y':'POS-STG2-Y',
'Q':'POS-STG2-CHARGE',
'OX':'OFF-BBA-X',
'OY':'OFF-BBA-Y',
'OMX':'OFF-PU-X', # Mechanical
'OMY':'OFF-PU-Y',
'OEX':'OFF-EL-X', # Electronics
'OEY':'OFF-EL-Y',
'TBTX':'TBT-STG0-X',
'TBTY':'TBT-STG0-Y',
'TBTQ':'TBT-STG0-Q',
'TBTX2':'DAQ-BEAM-STG0-X',
'TBTY2':'DAQ-BEAM-STG0-Y',
'TBTQ2':'DAQ-BEAM-STG0-CHARGE',
'REF-OP-X':'X-B-REF-OP',
'REF-OP-Y':'Y-B-REF-OP',
'MODE':'MODE'}
self.Atr_ID={'GAP':'GAP-SET',
'GAP-READ':'GAP-READ'}
self.Atr_RF={'Phase':'PHASE-SHIFT'}
# Phase of 500 MHz (for all 4 cavities)
self.rfphase=self.pf+'ARS05-RSYS-0000:'+self.Atr_RF['Phase']
if Default and S2:
def bySN(SN,attribute):
elem=S2.listElement_SN(SN)
#for s in attribute:
# self.ch[SN+'_'+s[0]]=[self.pf+e+':'+s[1] for e in elem]
for k in attribute.keys():
self.ch[SN+'_'+k]=[self.pf+e+':'+attribute[k] for e in elem]
def byTYPE(TYPE,attribute,bothIO):
elem=S2.listElement_TYPE(TYPE,bothIO)
#for s in attribute:
# self.ch[TYPE+'_'+s[0]]=[self.pf+e+':'+s[1] for e in elem]
for k in attribute.keys():
self.ch[TYPE+'_'+k]=[self.pf+e+':'+attribute[k] for e in elem]
#def byTYPE(TYPE,bothIO):
# Atr[i]=['Name easy to remember','Real Epics attribute (it is subject to be changed)']
Atr=self.Atr_PS
bySN('MQUA', Atr)
for t in S2.SN['MQUA']:
byTYPE(t, Atr, True)
#bySN('MSXT', Atr)
#for t in S2.SN['MSXT']:
# byTYPE(t, Atr, True)
# Sextupole are in families...
SFamily,Dad=S2.getSextFamily()
for k in Atr.keys():
self.ch['MSXT_'+k]=[self.pf+e+':'+Atr[k] for e in Dad]
for t in S2.SN['MSXT']:
elem=S2.listElement_TYPE(t,True)
for k in Atr.keys():
self.ch[t+'_'+k]=[]
for e in elem:
if e in Dad:
self.ch[t+'_'+k].append(self.pf+e+':'+Atr[k])
bySN('MOCT', Atr)
for t in S2.SN['MOCT']:
byTYPE(t, Atr, True)
bySN('MCOX', Atr)
for t in S2.SN['MCOX']:
byTYPE(t, Atr, True)
bySN('MCOY', Atr)
for t in S2.SN['MCOY']:
byTYPE(t, Atr, True)
bySN('MQCO', Atr)
for t in S2.SN['MQCO']:
byTYPE(t, Atr, True)
bySN('MQSK', Atr)
for t in S2.SN['MQSK']:
byTYPE(t, Atr, True)
Atr=self.Atr_KPS
byTYPE('KIN', Atr, False)
Atr=self.Atr_ID
bySN('UIND', Atr)
Atr=self.Atr_BPM
if VA:
Atr['SIMX']='SIM-X'
Atr['SIMY']='SIM-Y'
bySN('DBPM', Atr)
for t in S2.SN['DBPM']:
byTYPE(t, Atr, True)
# For convenience.
self.ch['BPM_X']=self.ch['DBPM_X']
self.ch['BPM_Y']=self.ch['DBPM_Y']
self.ch['BPM_OX']=self.ch['DBPM_OX']
self.ch['BPM_OY']=self.ch['DBPM_OY']
self.ch['BPM_MODE']=self.ch['DBPM_MODE']
self.ch['BPM_TBTX']=self.ch['DBPM_TBTX']
self.ch['BPM_TBTY']=self.ch['DBPM_TBTY']
self.ch['BPM_TBTQ']=self.ch['DBPM_TBTQ']
if VA:
# Beam position from simultion
# X=SIM-X + OFFS-X
# The operator in the above equation (+ or -) is subject to be confirmed.
self.ch['BPM_SIMX']=self.ch['DBPM_SIMX']
self.ch['BPM_SIMY']=self.ch['DBPM_SIMY']
# creating handles
self.createHandle(self.ch.keys())
def get(self, Channel,stat=False,dtype='native'):
if type(Channel)==list:
v=[]
for n in Channel:
vi=self.cafe.get(n,dt=dtype)
v.append(vi)
return v
elif Channel in self.Handle.keys():
[values, s, slist]=self.cafe.getGroup(self.Handle[Channel],dtype)
if stat:
return values, s, slist
else:
return values
elif ':' in Channel:
v=self.cafe.get(Channel,dt=dtype)
return v
else:
print ('Error: Input to EC.get "'+Channel+'" is wrong')
return -1
def getNtimes(self, Channel,N,stat=False,dtype='native',waiting=1):
if type(Channel)==list:
v=[[] for _ in range(0,len(Channel))]
for nm in range(0,N):
for i in range(0,len(Channel)):
vi=self.cafe.get(Channel[i],dt=dtype)
v[i].append(vi)
sleep(waiting)
vstd=[]
vmean=[]
for vi in v:
vi=np.array(vi)
vstd.append(vi.std())
vmean.append(vi.mean())
return v.tolist(),vmean.tolist(),vstd.tolist()
elif Channel in self.Handle.keys():
values=[]
s=[]
slist=[]
for i in range(0,n):
[valuesi, si, slisti]=self.cafe.getGroup(self.Handle[Channel],dtype)
sleep (waiting)
values.append(i)
s.append(si)
slist.append(slisti)
values=np.array(values)
values=values.transpose()
s=np.array(s)
s=s.transpose()
slist=np.array(slist)
slist=slist.transpose()
vstd=[]
vmean=[]
for vi in v:
vi=np.array(vi)
vstd.append(vi.std())
vmean.append(vi.mean())
if stat:
return values.tolist(), vmean.tolist(), vstd.tolist(),s.tolist(), slist.tolist()
else:
return values.tolist(), vmean.tolist(), vstd.tolist()
elif ':' in Channel:
v=[]
for i in range(0,N):
vi=self.cafe.get(Channel,dt=dtype)
v.append(vi)
sleep(waiting)
v=np.array(v)
vmean=v.mean()
vstd=v.std()
return v.tolist(),vmean.tolist(),vstd.tolist()
else:
print ('Error: Input to EC.get "'+Channel+'" is wrong')
return -1
def put(self, Channel, value):
if type(Channel)==list:
for i in range(0,len(Channel)):
self.cafe.set(Channel[i],value[i],dt=dtype)
return v
elif Channel in self.Handle.keys():
if len(value)!=len(self.ch[Channel]):
print ('Error: the number of input values does not match to the number of channels of the group, '+Channel)
return
s,slist=self.cafe.setGroup(self.Handle[Channel],value)
return s, slist
elif ':' in Channel:
s=self.cafe.set(Channel,value)
return s
def createHandle(self,key):
self.cafe.openGroupPrepare()
if type(key)=='str':
key=[key]
for k in key:
if k in self.ch.keys() and k not in self.Handle.keys():
if self.pf:
for i in range(0,len(self.ch[k])):
if self.pf not in self.ch[k][i]:
self.ch[k][i]=self.pf+self.ch[k][i]
self.Handle[k]=self.cafe.grouping(k, self.ch[k])
if len(key)<30:
wait=len(key)*0.5
else:
wait=20
self.cafe.openGroupNowAndWait(wait)
def getHandle(self,key):
if key not in self.Handle.keys():
print('OMEpics: No such a handle',key)
return None
return self.Handle[key]
def createGroup(self,key,Channel):
if self.pf:
for i in range(0,len(Channel)):
c=Channel[i]
if self.pf not in c:
Channel[i]=self.pf+c
self.cafe.openGroupPrepare()
Handle=self.cafe.grouping(key, Channel)
self.cafe.openGroupNowAndWait(1)
self.Handle[key]=Handle
self.ch[key]=Channel
return Handle
# Interface to the machine
def updateMachine_TYPE(self,TYPE):
KL=self.S2.getKL_TYPE(TYPE,bothIO=True)
I=self.SM.KL2I(TYPE,KL)
if TYPE in self.S2.SN['MQUA']+self.S2.SN['MSXT']+['KIN']:
I=list(np.abs(np.array(I))) # All quad and sext PSs are unipolar
self.put(TYPE+'_I',I)
def updateModel_TYPE(self,TYPE):
# Machine to Model
I,s,status=self.get(TYPE+'_I',stat=True)
KL=self.SM.I2KL(TYPE,I)
elem=self.S2.getElement_TYPE(TYPE,bothIO=True)
for i in range(0,len(elem)):
e=elem[i]
if e.SN=='MQUA' or e.SN=='MSXT' or e.TYPE=='KIN':
if e.POL==-1:
KL[i]=-KL[i]
#print (e.SN, e.POL, KL[i])
#if TYPE=='QSOS2A':
# print ('debuggingggg',KL)
self.S2.setKL_TYPE(TYPE,KL,bothIO=True)
def updateQuad_Machine(self,S2):
# Model to Machine
self.S2=S2 # synchronization
for t in self.S2.SN['MQUA']:
self.updateMachine_TYPE(t)
def updateQuad_Model(self):
# Machine to Model
for t in self.S2.SN['MQUA']:
self.updateModel_TYPE(t)
return self.S2
def updateSext_Machine(self,S2):
# Model to Machine
self.S2=S2 # synchronization
SFamily,Dad=self.S2.getSextFamily()
for t in self.S2.SN['MSXT']:
#self.updateMachine_TYPE(t)
elem=self.S2.getElement_TYPE(t,bothIO=True)
KL=[]
for e in elem:
if e.NAME in Dad:
KL.append(e.KL())
I=self.SM.KL2I(t,KL)
I=list(np.abs(np.array(I))) # All sext PSs are unipolar
self.put(t+'_I',I)
def updateSext_Model(self):
# Machine to Model
SFamily,Dad=self.S2.getSextFamily()
for t in self.S2.SN['MSXT']:
#self.updateModel_TYPE(t)
I,s,status=self.get(t+'_I',stat=True)
KL=self.SM.I2KL(t,I)
#elem=self.S2.getElement_TYPE(TYPE,bothIO=True)
for n in Dad:
e=self.S2.getElement(n)
if e.TYPE==t:
if e.POL==-1:
KL[0]=-KL[0]
e.setKL(KL[0])
KL.pop(0) # fine to consume
self.S2.bindSextFamily()
return self.S2
def updateOct_Machine(self,S2):
# Model to Machine
self.S2=S2 # synchronization
for t in self.S2.SN['MOCT']:
self.updateMachine_TYPE(t)
def updateOct_Model(self):
# Machine to Model
for t in self.S2.SN['MOCT']:
self.updateModel_TYPE(t)
return self.S2
def updateCH_Machine(self,S2):
# Model to Machine
self.S2=S2 # synchronization
for t in self.S2.SN['MCOX']:
self.updateMachine_TYPE(t)
def updateCH_Model(self):
# Machine to Model
for t in self.S2.SN['MCOX']:
self.updateModel_TYPE(t)
return self.S2
def updateCV_Machine(self,S2):
# Model to Machine
self.S2=S2 # synchronization
for t in self.S2.SN['MCOY']:
self.updateMachine_TYPE(t)
def updateCV_Model(self):
# Machine to Model
for t in self.S2.SN['MCOY']:
self.updateModel_TYPE(t)
return self.S2
def updateCorr_Machine(self,S2):
# Model to Machine
self.updateCH_Machine(S2)
self.updateCV_Machine(S2)
def updateCorr_Model(self):
# Machine to Model
self.updateCH_Model()
self.updateCV_Model()
return self.S2
def updateQcorr_Machine(self,S2):
# Model to Machine
self.S2=S2 # synchronization
for t in self.S2.SN['MQCO']:
self.updateMachine_TYPE(t)
def updateQcorr_Model(self):
# Machine to Model
for t in self.S2.SN['MQCO']:
self.updateModel_TYPE(t)
return self.S2
def updateSkewQ_Machine(self,S2):
# Model to Machine
self.S2=S2 # synchronization
for t in self.S2.SN['MQSK']:
self.updateMachine_TYPE(t)
def updateSkewQ_Model(self):
# Machine to Model
for t in self.S2.SN['MQSK']:
self.updateModel_TYPE(t)
return self.S2
def updateInjKicker_Machine(self,S2):
# Model to Machine
self.S2=S2 # synchronization
self.updateMachine_TYPE('KIN')
def updateInjKicker_Model(self):
# Machine to Model
self.updateModel_TYPE('KIN')
return self.S2
def updateMachine(self,S2):
# Model to Machine, all electromagnets
# Superconducting superbend is not included
self.updateQuad_Machine(S2)
self.updateSext_Machine(S2)
self.updateOct_Machine(S2)
self.updateCorr_Machine(S2)
self.updateQcorr_Machine(S2)
self.updateSkewQ_Machine(S2)
self.updateInjKicker_Machine(S2)
def updateModel(self):
# Machine to Model, all electromagnets
# Superconducting superbend is not included
self.updateQuad_Model()
self.updateSext_Model()
self.updateOct_Model()
self.updateCorr_Model()
self.updateQcorr_Model()
self.updateSkewQ_Model()
self.updateInjKicker_Model()
return self.S2
def getTbT(self,Nturn=4000):
# Used in Virtual accelerator but general function
# "TbT DAQ server" from Jan may be available in the future
if Nturn>4000:
Nturn=4000
if self.ch.keys():
sx,vx,v=self.cafe.getGroup(self.getHandle('BPM_TBTX'))
sy,vy,v=self.cafe.getGroup(self.getHandle('BPM_TBTY'))
if vx and vy:
return sx,sy
else:
print ('Error: Something wrong with TbT channels')
return -1,-1
else:
print ('Error: Default group must be listed before getting TbT data.')
return -1,-1
def putTbT(self,X,Y,Q):
# Method for Virtual Accelerator
if self.ch.keys():
self.cafe.setGroup(self.getHandle('BPM_TBTX'),X)
self.cafe.setGroup(self.getHandle('BPM_TBTY'),Y)
self.cafe.setGroup(self.getHandle('BPM_TBTQ'),Q)
else:
print ('Error: Default group must be listed before putting TbT data.')
return -1
#self.cafe.set(EpicsName,)