716 lines
18 KiB
Python
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,)
|