3080 lines
103 KiB
Python
3080 lines
103 KiB
Python
from copy import deepcopy, copy
|
|
|
|
from math import *
|
|
from random import gauss, seed
|
|
|
|
from os import system
|
|
|
|
import numpy as np
|
|
|
|
class Facility:
|
|
|
|
def __init__(self,LayoutFile):
|
|
|
|
self.D2R=pi/180.0
|
|
|
|
|
|
self.LayoutFile=LayoutFile
|
|
|
|
self.Parser()
|
|
|
|
|
|
self.TypeComp()
|
|
self.CommonComp()
|
|
|
|
self.FMapComp()
|
|
|
|
|
|
|
|
#exit()
|
|
|
|
|
|
self.BeamEnergy=2.7e9
|
|
self.Ring=None
|
|
self.Ring0=None # A copy of self.Ring without cycling
|
|
self.OverlapC={}
|
|
|
|
# When field map(s) is(are) included and the layout is used to generate
|
|
# a lattice for tracy-null (statements),
|
|
# this switch should be turned on (directly)
|
|
self.TracyFM=False
|
|
|
|
self.Description=''
|
|
|
|
seed(42)
|
|
|
|
|
|
def LayoutBL(self,expand='full',Kingdom='',cycle=0):
|
|
# Beamline or ring in general
|
|
|
|
layout=self.flatten(expand)
|
|
|
|
self.individuateBL(layout,Kingdom,cycle)
|
|
|
|
|
|
|
|
def Layout(self,expand='full',cycle=0):
|
|
|
|
layout=self.flatten(expand)
|
|
|
|
self.individuateS2(layout,cycle)
|
|
|
|
|
|
|
|
def CustomizedLayout(self,Pattern):
|
|
|
|
# A cutomized layout is needed to keep the common line structure in output.
|
|
# This method could be implemented in a better way..
|
|
|
|
|
|
TempSeq=[]
|
|
|
|
TempRing=[]
|
|
for i in range(1,13):
|
|
k='ARS'+str(i).zfill(2)
|
|
for e in self.Sector[k]:
|
|
TempRing.append(e)
|
|
TempSeq.append(deepcopy(TempRing))
|
|
|
|
|
|
|
|
|
|
|
|
alldone=0
|
|
while alldone==0:
|
|
alldone=1
|
|
TempRing=[]
|
|
for e in TempSeq[0]:
|
|
if e in self.Common.keys():
|
|
TempRing.append(deepcopy(self.Common[e][1]))
|
|
else:
|
|
TempRing.append(e)
|
|
TempSeq.insert(0,deepcopy(TempRing))
|
|
TempRing=[]
|
|
for e in TempSeq[0]:
|
|
if type(e)==list:
|
|
for le in e:
|
|
#if le in self.Overlap.keys():
|
|
# for oe in self.Overlap[le]:
|
|
# le=le+'|'+oe
|
|
TempRing.append(le)
|
|
else:
|
|
#if e in self.Overlap.keys():
|
|
# for oe in self.Overlap[e]:
|
|
# e=e+'|'+oe
|
|
TempRing.append(e)
|
|
TempSeq.insert(0,deepcopy(TempRing))
|
|
for e in TempSeq[0]:
|
|
if e in self.Common.keys():
|
|
alldone=0
|
|
|
|
|
|
|
|
|
|
|
|
#print (TempSeq[1])
|
|
#exit()
|
|
#nw=0
|
|
#n=0
|
|
#for e in TempSeq[0]:
|
|
# if e=='QAW|OQW':
|
|
# nw=nw+1
|
|
# if e=='QA|OQ':
|
|
# n=n+1
|
|
#print(nw,n)
|
|
#exit()
|
|
|
|
|
|
|
|
|
|
TypeV={}
|
|
Drift=[]
|
|
# Applying Pattern
|
|
Nqp=0
|
|
for i in range(0,len(TempSeq[1])):
|
|
e=TempSeq[1][i]
|
|
if type(e)==list:
|
|
for j in range(0,len(e)):
|
|
le=e[j]
|
|
if type(le)==str:
|
|
if '|' in le: # This is a bit crazy...
|
|
les=le.split('|')
|
|
fe=[]
|
|
ft=[]
|
|
for es in les:
|
|
if self.Type[es]['SN'] in Pattern.keys():
|
|
fe.append(Pattern[self.Type[es]['SN']][0])
|
|
ft.append(deepcopy(self.Type[es]))
|
|
ft[-1]['ORIGINAL']=es
|
|
Pattern[self.Type[es]['SN']].pop(0)
|
|
else:
|
|
fe.append(es)
|
|
ft.append(deepcopy(self.Type[es]))
|
|
fef='|'.join(fe)
|
|
TempSeq[1][i][j]=fef
|
|
TypeV[fef]={}
|
|
TypeV[fef]['SN']='Overlap'
|
|
TypeV[fef]['Type']=ft
|
|
else:
|
|
if self.Type[le]['SN'] in Pattern.keys():
|
|
TempSeq[1][i][j]=Pattern[self.Type[le]['SN']][0]
|
|
#TypeV[self.Type[le]['SN'][0]]=deepcopy(self.Type[le])
|
|
#TypeV[self.Type[le]['SN'][0]]['ORIGINAL']=le
|
|
TypeV[Pattern[self.Type[le]['SN']][0]]=deepcopy(self.Type[le])
|
|
TypeV[Pattern[self.Type[le]['SN']][0]]['ORIGINAL']=le
|
|
Pattern[self.Type[le]['SN']].pop(0)
|
|
else:
|
|
TypeV[le]=deepcopy(self.Type[le])
|
|
elif type(le)==float or type(le)==int:
|
|
if le not in Drift:
|
|
Drift.append(le)
|
|
elif type(e)==str:
|
|
if '|' in e: # This is a bit crazy...
|
|
es=e.split('|')
|
|
fe=[]
|
|
ft=[]
|
|
for s in es:
|
|
if self.Type[s]['SN'] in Pattern.keys():
|
|
|
|
fe.append(Pattern[self.Type[s]['SN']][0])
|
|
ft.append(deepcopy(self.Type[s]))
|
|
ft[-1]['ORIGINAL']=s
|
|
Pattern[self.Type[s]['SN']].pop(0)
|
|
else:
|
|
fe.append(s)
|
|
ft.append(deepcopy(self.Type[s]))
|
|
fef='|'.join(fe)
|
|
TempSeq[1][i]=fef
|
|
TypeV[fef]={}
|
|
TypeV[fef]['SN']='Overlap'
|
|
TypeV[fef]['Type']=ft
|
|
else:
|
|
if self.Type[e]['SN'] in Pattern.keys():
|
|
TempSeq[1][i]=Pattern[self.Type[e]['SN']][0]
|
|
TypeV[Pattern[self.Type[e]['SN']][0]]=deepcopy(self.Type[e])
|
|
TypeV[Pattern[self.Type[e]['SN']][0]]['ORIGINAL']=e
|
|
Pattern[self.Type[e]['SN']].pop(0)
|
|
else:
|
|
TypeV[e]=deepcopy(self.Type[e])
|
|
|
|
elif type(e)==float or type(e)==int:
|
|
if e not in Drift:
|
|
Drift.append(e)
|
|
|
|
#print ('=============')
|
|
#for k in sorted(list(TypeV.keys())):
|
|
# print (k,TypeV[k])
|
|
#exit()
|
|
|
|
#print (TempSeq[1])
|
|
#exit()
|
|
|
|
TempSeq.pop(0)
|
|
|
|
|
|
|
|
|
|
CommonVinv={}
|
|
Cmissed=[]
|
|
CC={}
|
|
while len(TempSeq)>2:
|
|
for i in range(0,len(TempSeq[0])):
|
|
e0=TempSeq[0][i]
|
|
e1=TempSeq[1][i]
|
|
if type(e0)==float or type(e0)==float:
|
|
pass
|
|
elif type(e0)==str:
|
|
#if e0 in TypeV.keys():
|
|
# pass
|
|
#elif e0 in self.Type.keys():
|
|
# pass
|
|
# #TypeV[e0]=self.Type[e0] # All types are already stored?
|
|
if e0!=e1:
|
|
TempSeq[1][i]=e0
|
|
elif e0!=self.Common[e1][1]:
|
|
if tuple(e0) in CommonVinv.keys():
|
|
pass
|
|
else:
|
|
if e1 not in CC.keys():
|
|
CC[e1]=0
|
|
CommonVinv[tuple(e0)]=e1
|
|
else:
|
|
CC[e1]=CC[e1]+1
|
|
CommonVinv[tuple(e0)]=e1+'_V'+str(CC[e1])
|
|
TempSeq[1][i]=CommonVinv[tuple(e0)]
|
|
|
|
else:
|
|
if tuple(e0) in CommonVinv.keys():
|
|
if CommonVinv[tuple(e0)]!=e1:
|
|
Cmissed.append(e1)
|
|
|
|
CommonVinv[tuple(e0)]=e1
|
|
|
|
|
|
TempSeq.pop(0)
|
|
|
|
#print (TempSeq[0])
|
|
#exit()
|
|
|
|
#TempSeqT=deepcopy(TempSeq[1])
|
|
ioff=0
|
|
for i in range(0,len(TempSeq[1])):
|
|
e1=TempSeq[1][i]
|
|
if type(e1)==list:
|
|
for j in range(0,len(e1)):
|
|
e0=TempSeq[0][i+ioff+j]
|
|
if e0!=e1[j]:
|
|
TempSeq[1][i][j]=e0
|
|
ioff=ioff+len(e1)-1
|
|
else:
|
|
e0=TempSeq[0][i+ioff]
|
|
if e0!=e1:
|
|
TempSeq[1][i]=e0
|
|
|
|
|
|
TempSeq.pop(0)
|
|
|
|
|
|
for i in range(0,len(TempSeq[0])):
|
|
e0=TempSeq[0][i]
|
|
e1=TempSeq[1][i]
|
|
if type(e0)==float or type(e0)==float:
|
|
pass
|
|
elif type(e0)==str:
|
|
#if e0 in TypeV.keys():
|
|
# pass
|
|
#elif e0 in self.Type.keys():
|
|
# pass
|
|
# #TypeV[e0]=self.Type[e0]
|
|
if e0!=e1:
|
|
TempSeq[1][i]=e0
|
|
elif e0!=self.Common[e1][1]:
|
|
if tuple(e0) in CommonVinv.keys():
|
|
pass
|
|
else:
|
|
if e1 not in CC.keys():
|
|
CC[e1]=0
|
|
CommonVinv[tuple(e0)]=e1
|
|
else:
|
|
CC[e1]=CC[e1]+1
|
|
CommonVinv[tuple(e0)]=e1+'_V'+str(CC[e1])
|
|
|
|
TempSeq[1][i]=CommonVinv[tuple(e0)]
|
|
|
|
else:
|
|
if tuple(e0) in CommonVinv.keys():
|
|
if CommonVinv[tuple(e0)]!=e1:
|
|
Cmissed.append(e1)
|
|
if tuple(e0) not in CommonVinv.keys():
|
|
CommonVinv[tuple(e0)]=e1
|
|
|
|
|
|
#for k in CommonVinv.values():
|
|
# if 'SS' in k:
|
|
# print (k)
|
|
#exit()
|
|
|
|
CommonV= {y:list(x) for x,y in CommonVinv.items()}
|
|
for k in Cmissed:
|
|
CommonV[k]=self.Common[k][1]
|
|
|
|
#print (TempSeq[1])
|
|
#print (self.Sector)
|
|
|
|
Ne=0
|
|
SectorV=[]
|
|
for i in range(1,13):
|
|
k='ARS'+str(i).zfill(2)
|
|
l=len(self.Sector[k])
|
|
SectorV.append(TempSeq[1][Ne:Ne+l])
|
|
Ne=Ne+l
|
|
|
|
#print (SectorV)
|
|
|
|
|
|
#for k in sorted(list(TypeV.keys())):
|
|
# print (k,TypeV[k])
|
|
#exit()
|
|
|
|
#print (sorted(Drift))
|
|
|
|
return TypeV,CommonV,SectorV,Drift
|
|
|
|
|
|
|
|
#print (Cmissed)
|
|
|
|
|
|
|
|
def Parser(self):
|
|
|
|
# Variables have to be self.xx to allow user-defined constants in Layout file...
|
|
|
|
|
|
self.Type={}
|
|
self.Common={} # CommonLine
|
|
self.Sector={}
|
|
self.Overlap={} # This will be removed...
|
|
self.Mode=None
|
|
|
|
try:
|
|
self.fin=open(self.LayoutFile,'r')
|
|
except:
|
|
print ('File does not exist?')
|
|
exit()
|
|
|
|
|
|
self.ftmp=[]
|
|
|
|
# Removing comments
|
|
for self.line in self.fin:
|
|
self.line=self.line
|
|
if self.line[0]=='!':
|
|
self.line=''
|
|
elif '!' in self.line:
|
|
self.line=self.line.split('!')[0]
|
|
else:
|
|
self.line=self.line.replace('\n','')
|
|
|
|
if self.line: self.ftmp.append(self.line)
|
|
|
|
self.fin.close()
|
|
|
|
self.AS=''
|
|
self.cont=0
|
|
for self.line in self.ftmp:
|
|
if '\\' in self.line:
|
|
if self.cont:
|
|
self.AS=self.AS+self.line.replace('\\','')
|
|
else:
|
|
self.AS=self.AS+'V^O^V'+self.line.replace('\\','')
|
|
self.cont=1
|
|
elif self.cont:
|
|
self.AS=self.AS+self.line.replace('\\','')
|
|
self.cont=0
|
|
else:
|
|
self.cont=0
|
|
if self.AS:
|
|
self.AS=self.AS+'V^O^V'+self.line # Hope this special pattern does not appear in Layout file...
|
|
else:
|
|
self.AS=self.line
|
|
|
|
self.AS=self.AS.upper().replace('CLASS','CLASS:').replace(' ','').replace('\t','')
|
|
self.AS=self.AS.upper().replace('VERSION','VERSION:').replace(' ','').replace('\t','')
|
|
|
|
self.fclean=self.AS.split('V^O^V')
|
|
|
|
|
|
self.SNtmp={}
|
|
|
|
for self.line in self.fclean:
|
|
try:
|
|
if 'CLASS' in self.line.lower().split(':')[0].upper():
|
|
self.Mode=self.line.split(':')[1].upper()
|
|
self.line=''
|
|
#print (Mode,len(Mode))
|
|
except:
|
|
pass
|
|
|
|
if 'VERSION' in self.line:
|
|
self.Version=self.line.replace('VERSION:','')
|
|
|
|
|
|
if self.Mode=='CONSTANT' and self.line:
|
|
try:
|
|
exec(self.line.upper())
|
|
|
|
#exec(self.line.split('=')[0].upper()+'='+self.line.split('=')[1])
|
|
|
|
|
|
|
|
except:
|
|
print ('Something wrong in Constant')
|
|
exit()
|
|
|
|
elif self.Mode=='TYPE' and self.line:
|
|
self.Ttmp={}
|
|
|
|
try:
|
|
if ':' in self.line:
|
|
self.sline=self.line.split(':')
|
|
self.TN=self.sline[0].upper() # Type
|
|
self.ssline=self.sline[1].split(',')
|
|
self.SN=self.ssline[0].upper() # Short name
|
|
self.Ttmp['SN']=self.SN
|
|
if self.SN not in self.SNtmp.keys():
|
|
self.SNtmp[self.SN]=[self.TN]
|
|
else:
|
|
self.SNtmp[self.SN].append(self.TN)
|
|
# From on-line model point of view, no need to distinguish'I' and 'O' types
|
|
if self.SNtmp[self.SN][-1][-1]=='I' or self.SNtmp[self.SN][-1][-1]=='O':
|
|
self.SNtmp[self.SN][-1]=self.SNtmp[self.SN][-1][:-1]
|
|
#print (self.P5)
|
|
for self.i in range(1,len(self.ssline)):
|
|
self.p=self.ssline[self.i]
|
|
self.p=self.p.split('=')
|
|
if self.p[0]=='ANG':
|
|
self.p[0]='ANGLE'
|
|
#print ('====',self.p[1])
|
|
if self.p[0]=='OVERLAP':
|
|
exec('self.v = '+self.p[1].replace('/',','))
|
|
self.Ttmp['FM'+self.p[0]]=self.v
|
|
elif '[' in self.p[1]:
|
|
self.sp=self.p[1].replace('[','').replace(']','').split('|')
|
|
#print ('++++',self.sp)
|
|
self.V=[]
|
|
for self.d in self.sp:
|
|
try:
|
|
exec('self.v = '+self.d)
|
|
self.V.append(self.v)
|
|
except:
|
|
print ('Something wrong!! 1')
|
|
exit()
|
|
self.Ttmp[self.p[0]]=self.V
|
|
else:
|
|
try:
|
|
exec('self.v = '+self.p[1])
|
|
self.Ttmp[self.p[0]]=self.v
|
|
except:
|
|
#print (self.p[1])
|
|
print ('Something wrong!! 2')
|
|
exit()
|
|
self.Type[self.TN]=deepcopy(self.Ttmp)
|
|
except:
|
|
print ('Something wrong in Type',self.line)
|
|
exit()
|
|
elif self.Mode=='COMMONLINE' and self.line:
|
|
try:
|
|
if ':' in self.line:
|
|
self.sline=self.line.split(':')
|
|
self.Unit=self.sline[0].replace(' ','').upper() # Unit
|
|
self.ssline=self.sline[1].split(',')
|
|
self.SN=self.ssline[0].replace(' ','').upper() # Short name
|
|
self.ssline=self.ssline[1:]
|
|
|
|
self.Ctmp=[]
|
|
for self.i in range(0,len(self.ssline)):
|
|
self.p=self.ssline[self.i].replace('[','').replace(']','').replace(' ','')
|
|
try:
|
|
exec('self.d = '+self.p)
|
|
self.Ctmp.append(self.d) # Drift described with constant
|
|
except:
|
|
#if '|' in self.ssline[self.i]:
|
|
# self.sp=self.p.split('|')
|
|
# self.Overlap[self.sp[0]]=self.sp[1:]
|
|
# self.Ctmp.append(self.sp[0])
|
|
#else:
|
|
# self.Ctmp.append(self.p)
|
|
self.Ctmp.append(self.p)
|
|
self.Common[self.Unit]=[self.SN,deepcopy(self.Ctmp)]
|
|
|
|
except:
|
|
print ('Something wrong in CommonLine')
|
|
exit()
|
|
|
|
elif self.Mode=='SEQUENCE' and self.line:
|
|
try:
|
|
self.Stmp=[]
|
|
if ':' in self.line:
|
|
self.sline=self.line.split(':')
|
|
self.SN=self.sline[0].upper() # Sector
|
|
#print ('++',self.sline[1])
|
|
self.ssline=self.sline[1].replace('[','').replace(']','').split(',')
|
|
for self.p in self.ssline:
|
|
try:
|
|
exec('self.d = '+self.p)
|
|
self.Stmp.append(self.d) # Drift described with constant
|
|
except:
|
|
#if '|' in self.p:
|
|
# self.sp=self.p.split('|')
|
|
# self.Overlap[self.sp[0]]=self.sp[1:]
|
|
# self.Stmp.append(self.sp[0])
|
|
#else:
|
|
# self.Stmp.append(self.p)
|
|
self.Stmp.append(self.p)
|
|
self.Sector[self.SN]=self.Stmp
|
|
except:
|
|
print ('Something wrong in Sequence')
|
|
exit()
|
|
|
|
#print (self.Sector)
|
|
|
|
self.Type['CYCLE']={'SN': 'GCYC', 'L': 0, 'RL': 0}
|
|
|
|
|
|
|
|
for self.p in self.Type.keys():
|
|
if 'L' not in self.Type[self.p].keys():
|
|
self.Type[self.p]['L']=0
|
|
if 'RL' not in self.Type[self.p].keys():
|
|
self.Type[self.p]['RL']=0
|
|
if 'ANGLE' in self.Type[self.p].keys(): # For BS, both E1 and E2 exist and this block is not relevant.
|
|
if ('E1' in self.Type[self.p].keys()) and ('E2' not in self.Type[self.p].keys()):
|
|
self.Type[self.p]['E2']=self.Type[self.p]['ANGLE']-self.Type[self.p]['E1']
|
|
elif ('E2' in self.Type[self.p].keys()) and ('E1' not in self.Type[self.p].keys()):
|
|
self.Type[self.p]['E2']=self.Type[self.p]['ANGLE']-self.Type[self.p]['E2']
|
|
elif ('E1' not in self.Type[self.p].keys()) and ('E2' not in self.Type[self.p].keys()):
|
|
self.Type[self.p]['E1']=self.Type[self.p]['ANGLE']/2
|
|
self.Type[self.p]['E2']=self.Type[self.p]['ANGLE']/2
|
|
|
|
|
|
|
|
self.Ttmp={}
|
|
for self.p in self.Type.keys():
|
|
|
|
#if ('E1' in self.Type[self.p].keys()) and ('E2' in self.Type[self.p].keys()):
|
|
if self.p=='VB': # Only -VB is needed. # VB no longer exists. It is VBI or VBO
|
|
self.d='-'+self.p # Reversed element, only dipoles
|
|
self.Ttmp[self.d]=deepcopy(self.Type[self.p])
|
|
self.Ttmp[self.d]['E1'],self.Ttmp[self.d]['E2']=self.Ttmp[self.d]['E2'],self.Ttmp[self.d]['E1']
|
|
#if type(self.Ttmp[self.d]['E1'])==list:
|
|
# self.Ttmp[self.d]['E1'].reverse()
|
|
# self.Ttmp[self.d]['E2'].reverse()
|
|
# self.Ttmp[self.d]['L'].reverse()
|
|
# self.Ttmp[self.d]['ANGLE'].reverse()
|
|
|
|
|
|
self.Type.update(deepcopy(self.Ttmp))
|
|
|
|
|
|
|
|
|
|
#print ('***************')
|
|
|
|
#print (self.Ttmp)
|
|
|
|
|
|
|
|
#print (self.Type)
|
|
|
|
|
|
#exit()
|
|
|
|
self.SN=self.SNtmp
|
|
for k in self.SN:
|
|
self.SN[k]=list(set(self.SN[k]))
|
|
|
|
|
|
for self.v in ['self.fin','self.ftmp','self.fclean','self.AS','self.cont','self.line','self.sline','self.ssline','self.Mode','self.SNtmp','self.i','self.v','self.p','self.sp','self.d','self.Ttmp','self.Ctmp','self.Unit']:
|
|
try:
|
|
exec('del '+self.v)
|
|
except:
|
|
pass
|
|
|
|
del self.v
|
|
|
|
|
|
|
|
def flatten(self,expand='full'):
|
|
# expand='full' - All the CommonLine will be flattened
|
|
# expand='common' - The unit defined in CommonLine will remain unflattened if short name is given (not None)
|
|
|
|
|
|
def flattenMixList(l):
|
|
# No built-in to flatten Mixed type list...
|
|
for i in l:
|
|
if isinstance(i, (str, bytes)):
|
|
yield i
|
|
else:
|
|
try:
|
|
for ii in flattenMixList(i):
|
|
yield ii
|
|
except TypeError:
|
|
yield i
|
|
|
|
|
|
|
|
def unnest(N):
|
|
nested=0
|
|
for i in range(0,len(N)):
|
|
e=N[i]
|
|
#print ('mmm',e,expand)
|
|
#print (N)
|
|
if e in self.Common.keys() and expand=='full':
|
|
N[i]=self.Common[e][1]
|
|
nested=1
|
|
elif e in self.Common.keys():
|
|
if self.Common[e][0]=='NONE':
|
|
N[i]=self.Common[e][1]
|
|
nested=1
|
|
|
|
|
|
if nested:
|
|
N=list(flattenMixList(N))
|
|
N=unnest(N)
|
|
return N
|
|
|
|
if expand!='full' and expand!='unit':
|
|
PL=deepcopy(self.Common[expand][1])
|
|
expand='full'
|
|
PL=unnest(PL)
|
|
return PL
|
|
|
|
|
|
if 'ARS12' in self.Sector.keys():
|
|
Sec=[]
|
|
for i in range(1,13):
|
|
k='ARS'+str(i).zfill(2)
|
|
PS=deepcopy(self.Sector[k])
|
|
#print ('lll',PS)
|
|
#exit()
|
|
Sec.append(unnest(PS))
|
|
if PS[0]!='GINI_SEC':
|
|
print ('Sector '+str(i)+' does not start with GINI_SEC')
|
|
exit()
|
|
Ring=list(flattenMixList(Sec))
|
|
else:
|
|
#if expand=='full':
|
|
# PS=deepcopy(self.Sector)
|
|
# Ring=unnest(list(PS.values())[0])
|
|
#else:
|
|
# Ring=list(self.Sector.values())[0]
|
|
|
|
PS=deepcopy(self.Sector)
|
|
Ring=unnest(list(PS.values())[0])
|
|
|
|
return Ring
|
|
|
|
def TypeComp(self):
|
|
# Some computation for sliced element
|
|
# This is not done for MMAP (field map), which is experimental
|
|
# and not intended to be linked with Holy list
|
|
|
|
for k in self.Type.keys():
|
|
if ('ANGLE' in self.Type[k].keys()) and (type(self.Type[k]['ANGLE'])==list):
|
|
dx=0
|
|
dy=0
|
|
ang=0
|
|
l=0
|
|
#print ('tgsbhstbhs',k,type(self.Type[k]['ANGLE']),self.Type[k])
|
|
for i in range(0,len(self.Type[k]['ANGLE'])):
|
|
rho=self.Type[k]['L'][i]/(self.D2R*self.Type[k]['ANGLE'][i])
|
|
N=2*rho*sin(self.D2R*self.Type[k]['ANGLE'][i]/2)
|
|
dx=dx+N*cos(self.D2R*ang+self.D2R*self.Type[k]['ANGLE'][i]/2)
|
|
dy=dy+N*sin(self.D2R*ang+self.D2R*self.Type[k]['ANGLE'][i]/2)
|
|
l=l+self.Type[k]['L'][i]
|
|
ang=ang+self.Type[k]['ANGLE'][i]
|
|
if i+1==len(self.Type[k]['ANGLE'])/2: # Even number slicing is assumed...
|
|
mdx=dx
|
|
mdy=dy
|
|
|
|
self.Type[k]['TL']=l # Total length
|
|
self.Type[k]['TANGLE']=ang # Total angle
|
|
self.Type[k]['DX']=dx # Total DX
|
|
self.Type[k]['DY']=dy # Total DY
|
|
self.Type[k]['MDX']=mdx # DX in the middle
|
|
self.Type[k]['MDY']=mdy # DY in the middle
|
|
#self.Type[k]['RL']=0
|
|
|
|
|
|
|
|
def CommonComp(self):
|
|
|
|
# Some computation for common line
|
|
cont=1
|
|
while cont:
|
|
cont=0
|
|
for k in self.Common.keys():
|
|
dx=0
|
|
dy=0
|
|
ang=0
|
|
l=0
|
|
d=1
|
|
if k in self.Common.keys() and len(self.Common[k])!=6:
|
|
d=0
|
|
cc=0
|
|
for ki in self.Common[k][1]:
|
|
if ki in self.Common.keys():
|
|
if len(self.Common[ki])==6:
|
|
l=l+self.Common[ki][2]
|
|
N=sqrt(self.Common[ki][4]**2+self.Common[ki][5]**2)
|
|
dx=dx+N*cos(self.D2R*ang+self.D2R*self.Common[ki][3]/2)
|
|
dy=dy+N*sin(self.D2R*ang+self.D2R*self.Common[ki][3]/2)
|
|
ang=ang+self.Common[ki][3]
|
|
else:
|
|
cc=1 # Common in common is not yet done
|
|
|
|
elif type(ki)==float or type(ki)==float:
|
|
l=l+ki
|
|
dx=dx+ki*cos(self.D2R*ang)
|
|
dy=dy+ki*sin(self.D2R*ang)
|
|
|
|
else:
|
|
if '|' in ki:
|
|
ki=ki.split('|')[0]
|
|
#print (ki,k,self.Common[k][1])
|
|
if 'ANGLE' in self.Type[ki].keys():
|
|
if type(self.Type[ki]['ANGLE'])==list:
|
|
l=l+self.Type[ki]['TL']
|
|
N=sqrt(self.Type[ki]['DX']**2+self.Type[ki]['DY']**2)
|
|
dx=dx+N*cos(self.D2R*ang+self.D2R*self.Type[ki]['TANGLE']/2)
|
|
dy=dy+N*sin(self.D2R*ang+self.D2R*self.Type[ki]['TANGLE']/2)
|
|
ang=ang+self.Type[ki]['TANGLE']
|
|
elif self.Type[ki]['ANGLE']:
|
|
rho=self.Type[ki]['L']/(self.D2R*self.Type[ki]['ANGLE'])
|
|
N=2*rho*sin(self.D2R*self.Type[ki]['ANGLE']/2)
|
|
dx=dx+N*cos(self.D2R*ang+self.D2R*self.Type[ki]['ANGLE']/2)
|
|
dy=dy+N*sin(self.D2R*ang+self.D2R*self.Type[ki]['ANGLE']/2)
|
|
l=l+self.Type[ki]['L']
|
|
ang=ang+self.Type[ki]['ANGLE']
|
|
else:
|
|
#if 'RL' not in self.Type[ki].keys():
|
|
# self.Type[ki]['RL']=0
|
|
#if 'L' not in self.Type[ki].keys():
|
|
# self.Type[ki]['L']=0
|
|
dl=self.Type[ki]['L']+self.Type[ki]['RL']*2
|
|
l=l+dl
|
|
dx=dx+dl*cos(self.D2R*ang)
|
|
dy=dy+dl*sin(self.D2R*ang)
|
|
|
|
else:
|
|
d=1
|
|
|
|
if d==0 and cc==0: # self.Common[NameOfCommonLine]=[SN,[List of elems],L,ANGLE,DX,DY]
|
|
self.Common[k].append(l)
|
|
self.Common[k].append(ang)
|
|
self.Common[k].append(dx)
|
|
self.Common[k].append(dy)
|
|
cont=1
|
|
#if d==1:
|
|
# cont=0
|
|
|
|
|
|
def FMapComp(self):
|
|
|
|
# Some computaion for MMAP
|
|
# Implementation assuming order=(6,6) always
|
|
|
|
# In Master layout file, L is total length,
|
|
# which is actually not used here!.
|
|
# L is now replaced by a list
|
|
# Total length is then stored as TL
|
|
for k in self.Type.keys():
|
|
if self.Type[k]['SN']=='MMAP':
|
|
self.Type[k]['L']=[]
|
|
self.Type[k]['TL']=0
|
|
self.Type[k]['STRENGTH']=[]
|
|
fin=open(self.Type[k]['FILENAME'].lower(),'r')
|
|
for line in fin:
|
|
sline=line.split()
|
|
if len(sline)>10:
|
|
l=float(sline[1])
|
|
self.Type[k]['TL']=self.Type[k]['TL']+l
|
|
self.Type[k]['L'].append(l)
|
|
self.Type[k]['STRENGTH'].append([float(sline[4]),
|
|
float(sline[6]),
|
|
float(sline[8]),
|
|
float(sline[10]),
|
|
float(sline[12]),
|
|
float(sline[14]),
|
|
float(sline[16]),
|
|
float(sline[18]),
|
|
float(sline[22]),
|
|
float(sline[24]),
|
|
float(sline[28]),
|
|
float(sline[34])])
|
|
|
|
fin.close()
|
|
|
|
#print (self.Type[k])
|
|
#exit()
|
|
|
|
|
|
def individuateBL(self,Ring,Kingdom,cycle=0):
|
|
|
|
|
|
# This method is for beam line or ring in general
|
|
|
|
del self.Ring
|
|
del self.OverlapC
|
|
self.OverlapC={}
|
|
RingClass=[]
|
|
|
|
# These short names are difined for SLS2 naming convention
|
|
# but used here since they are rather general
|
|
Gmark=['GMRK','GSRC']
|
|
# 'DSCR', screen monitor. Experimental, 08.12.2020
|
|
# DICT added 07.11.2022
|
|
Diag=['DBPM','DSCR','DICT']
|
|
Dmag=['MBEN','MBCF','MBSC']
|
|
Qmag=['MQUA','MQCO']
|
|
Sext=['MSXT']
|
|
Oct=['MOCT']
|
|
HKIK=['MCOX','MKIK','MSEP']
|
|
VKIK=['MCOY']
|
|
FM=['MMAP'] # Field map, experimental
|
|
RFcav=['RCAV','R3HC']
|
|
Coll=['VCOL'] # Collimator, 21.11.2023
|
|
|
|
CommonLineSN=[]
|
|
for k in self.Common.keys():
|
|
if self.Common[k][0]!='NONE':
|
|
CommonLineSN.append(self.Common[k][0])
|
|
|
|
|
|
|
|
|
|
s=0.0 # Longitudinal location
|
|
gl=0.0
|
|
gi=-1 # GIRDER number starts from zero. (Can be from 1, to be determined)
|
|
ang= 0 #total angle from the beginning (exclusive of its bending angle)
|
|
GL=[]
|
|
Prop=[]
|
|
# First survey
|
|
ndri=0
|
|
drir=[]
|
|
drirn=[]
|
|
for e in range(0,len(Ring)):
|
|
ele=Ring[e]
|
|
if Ring[e] in self.Common.keys():
|
|
p={}
|
|
p['L']=self.Common[Ring[e]][2]
|
|
p['ANGLE']=self.Common[Ring[e]][3]
|
|
p['TL']=self.Common[Ring[e]][2]
|
|
p['TANGLE']=self.Common[Ring[e]][3]
|
|
p['DX']=self.Common[Ring[e]][4]
|
|
p['DY']=self.Common[Ring[e]][5]
|
|
p['RL']=0
|
|
p['SN']=self.Common[Ring[e]][0]
|
|
p['TYPE']=Ring[e]
|
|
Prop.append(deepcopy(p))
|
|
elif type(Ring[e])==float or type(Ring[e])==int:
|
|
|
|
|
|
if Ring[e] not in drir:
|
|
|
|
drir.append(Ring[e])
|
|
drirn.append(ndri)
|
|
ndri=ndri+1
|
|
ndrip=ndri
|
|
else:
|
|
ndrip=drir.index(Ring[e])
|
|
|
|
ele='D'+str(ndri).zfill(4)
|
|
|
|
p={}
|
|
p['L']=Ring[e]
|
|
p['RL']=0
|
|
p['SN']='DRIF'
|
|
p['TYPE']='DRIFT'
|
|
p['DNAME']=ele
|
|
Prop.append(deepcopy(p))
|
|
|
|
|
|
else:
|
|
|
|
if '|' not in ele:
|
|
Prop.append(deepcopy(self.Type[ele]))
|
|
Prop[e]['TYPE']=ele
|
|
else:
|
|
elet=ele.split('|')[0]
|
|
Prop.append(deepcopy(self.Type[elet]))
|
|
Prop[e]['OVERLAP']=ele.split('|')[1:]
|
|
Prop[e]['TYPE']=elet
|
|
|
|
|
|
|
|
if ele=='G0':
|
|
#print (sn,gi,ele)
|
|
GL.append(gl)
|
|
gi=gi+1
|
|
gl=0
|
|
|
|
|
|
|
|
Prop[e]['SECTOR']=None # Not applicable for the beamline/ring in general
|
|
Prop[e]['GIRDER']=gi
|
|
|
|
|
|
#Prop[e]['TL'] causes a key error. I don't understand!!!!!
|
|
if type(Prop[e]['L'])==list:
|
|
for k in Prop[e].keys():
|
|
if k=='TL':
|
|
TL=Prop[e][k]
|
|
Prop[e]['SG']=gl+TL/2
|
|
else:
|
|
Prop[e]['SG']=gl+Prop[e]['L']/2+Prop[e]['RL']
|
|
|
|
Prop[e]['S']=s # Longitudinal position at the entrance of the element (including RL)
|
|
# Integrated bending at the entrance of element
|
|
# Deflection angle of THIS element is not included
|
|
Prop[e]['SANGLE']=ang
|
|
|
|
|
|
'''
|
|
if type(Prop[e]['L'])==list:
|
|
Prop[e]['MS']=s+Prop[e]['TL']/2 # Longitudinal position at the middle of the element
|
|
s=s+Prop[e]['TL']
|
|
gl=gl+Prop[e]['TL']
|
|
Prop[e]['MANGLE']=ang+Prop[e]['TANGLE']/2
|
|
ang=ang+Prop[e]['TANGLE']
|
|
else:
|
|
Prop[e]['MS']=s+Prop[e]['L']/2+Prop[e]['RL'] # Longitudinal position at the middle of the element
|
|
s=s+Prop[e]['L']+Prop[e]['RL']*2
|
|
gl=gl+Prop[e]['L']+Prop[e]['RL']*2
|
|
if 'ANGLE' in Prop[e].keys():
|
|
Prop[e]['MANGLE']=ang+Prop[e]['ANGLE']/2
|
|
ang=ang+Prop[e]['ANGLE']
|
|
else:
|
|
Prop[e]['MANGLE']=ang
|
|
'''
|
|
|
|
if type(Prop[e]['L'])==list and Prop[e]['SN']=='MBSC':
|
|
Prop[e]['MS']=s+Prop[e]['TL']/2 # Longitudinal position at the middle of the element
|
|
s=s+Prop[e]['TL']
|
|
gl=gl+Prop[e]['TL']
|
|
Prop[e]['MANGLE']=ang+Prop[e]['TANGLE']/2
|
|
ang=ang+Prop[e]['TANGLE']
|
|
elif type(Prop[e]['L'])==list:
|
|
Prop[e]['MS']=s+Prop[e]['TL']/2#+Prop[e]['RL'] # Longitudinal position at the middle of the element
|
|
s=s+Prop[e]['TL']#+Prop[e]['RL']*2
|
|
gl=gl+Prop[e]['TL']#+Prop[e]['RL']*2
|
|
if 'ANGLE' in Prop[e].keys():
|
|
Prop[e]['MANGLE']=ang+Prop[e]['ANGLE']/2
|
|
ang=ang+Prop[e]['ANGLE']
|
|
else:
|
|
Prop[e]['MANGLE']=ang
|
|
else:
|
|
Prop[e]['MS']=s+Prop[e]['L']/2+Prop[e]['RL'] # Longitudinal position at the middle of the element
|
|
s=s+Prop[e]['L']+Prop[e]['RL']*2
|
|
gl=gl+Prop[e]['L']+Prop[e]['RL']*2
|
|
if 'ANGLE' in Prop[e].keys():
|
|
Prop[e]['MANGLE']=ang+Prop[e]['ANGLE']/2
|
|
ang=ang+Prop[e]['ANGLE']
|
|
else:
|
|
Prop[e]['MANGLE']=ang
|
|
|
|
|
|
|
|
self.C=s
|
|
Prop.pop(-1)
|
|
|
|
#print (GL)
|
|
#exit()
|
|
|
|
# Second survey to finalize
|
|
#fout=open('temp.dat','w')
|
|
Reserved=[]
|
|
for i in range(0,len(GL)):
|
|
Reserved.append([])
|
|
RingClass=[]
|
|
for i in range(0,len(Prop)):
|
|
p=Prop[i]
|
|
TN=Ring[i]
|
|
#print(p['Sector'],p['Girder'])
|
|
#print (GL)
|
|
gl=GL[p['GIRDER']+1]
|
|
|
|
# Important to add 1e-7 to avoid a flactuation due to round error
|
|
indx=int((p['SG']+1e-7)/gl*100)
|
|
|
|
|
|
if indx==99:
|
|
indx=98
|
|
if p['SN']=='NONE' or p['SN']=='DRIF':
|
|
pass
|
|
else:
|
|
#print ('kiteru?----------',p['SN'],p['TYPE'],100*p['GIRDER']+indx,Reserved[p['GIRDER']],p['GIRDER'],gl)
|
|
if 100*p['GIRDER']+indx in Reserved[p['GIRDER']]:
|
|
print ('Overlap!!!!',p['GIRDER'],indx,p['SN'],p['L'],i)
|
|
if 100*p['GIRDER']+indx+1 not in Reserved[p['GIRDER']]:
|
|
indx=indx+1
|
|
else:
|
|
indx=indx+2
|
|
if p['TYPE']!='DRIFT': # This is always true...
|
|
Reserved[p['GIRDER']].append(100*p['GIRDER']+indx)
|
|
if indx==100:
|
|
indx=99
|
|
|
|
p['INDEX']=indx
|
|
if Kingdom:
|
|
p['NAME']=Kingdom+'-'+p['SN']+'-'+str(p['GIRDER'])+str(indx).zfill(2)
|
|
else:
|
|
p['NAME']='BL-'+p['SN']+'-'+str(p['GIRDER'])+str(indx).zfill(2)
|
|
|
|
|
|
def RL(pin):
|
|
pr1={}
|
|
pr1['L']=pin['RL']
|
|
pr1['RL']=0
|
|
pr1['SN']='DRIF'
|
|
pr1['NAME']=pin['NAME'].split('-')[0]+'-DRIF-'+pin['NAME'].split('-')[2]
|
|
pr1['INDEX']=indx
|
|
pr1['TYPE']='DRIFT'
|
|
pr1['DNAME']='DR'+pin['TYPE'] # Name that appears in OPA file
|
|
|
|
|
|
if type(pin['L'])==list:
|
|
pr1['S']=pin['S']-abs(pin['RL'])
|
|
pr1['MS']=pin['S']-abs(pin['RL'])/2
|
|
else:
|
|
pr1['S']=pin['S']
|
|
pr1['MS']=pin['S']+pin['RL']/2
|
|
|
|
pr1['SANGLE']=pin['SANGLE']
|
|
pr1['MANGLE']=pin['SANGLE']
|
|
pr1['SECTOR']=pin['SECTOR']
|
|
pr1['GIRDER']=pin['GIRDER']
|
|
pr1['RESERVE']=1
|
|
|
|
|
|
pr2=deepcopy(pr1)
|
|
if type(pin['L'])==list:
|
|
pr2['S']=pin['S']+pin['TL']
|
|
else:
|
|
pr2['S']=pin['S']+pin['L']+pin['RL']
|
|
pr2['MS']=pr2['S']+pin['RL']/2
|
|
pr2['RESERVE']=1
|
|
|
|
|
|
|
|
if 'ANGLE' in pin.keys():
|
|
pr2['SANGLE']=pin['SANGLE']+pin['ANGLE']
|
|
else:
|
|
pr2['SANGLE']=pin['SANGLE']
|
|
|
|
return pr1,pr2
|
|
|
|
if p['RL']:
|
|
pr1,pr2=RL(p)
|
|
|
|
if p['SN'] in Gmark:
|
|
RingClass.append(Marker(p))
|
|
elif p['SN'] in Diag:
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Monitor(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Monitor(p))
|
|
elif p['SN'] in Dmag:
|
|
p['K1']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Dipole(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Dipole(p))
|
|
elif p['SN'] in Qmag:
|
|
p['K1']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Quadrupole(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Quadrupole(p))
|
|
elif p['SN'] in Sext:
|
|
p['K2']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Sextupole(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Sextupole(p))
|
|
elif p['SN'] in Oct:
|
|
p['K3L']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Octupole(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Octupole(p))
|
|
elif p['SN'] in HKIK:
|
|
p['KICK']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(HKicker(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(HKicker(p))
|
|
elif p['SN'] in VKIK:
|
|
p['KICK']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(VKicker(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(VKicker(p))
|
|
elif p['SN'] in FM: # Experimental
|
|
if p['RL']>100:
|
|
if self.TracyFM:
|
|
pr1['L']=pr1['L']-100
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(FieldMap(p))
|
|
if self.TracyFM:
|
|
pr2['L']=pr2['L']-100
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
if p['RL']<0 and self.TracyFM:
|
|
pr1['L']=abs(pr1['L'])
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(FieldMap(p))
|
|
if p['RL']>0 and self.TracyFM:
|
|
RingClass.append(Drift(pr2))
|
|
elif p['SN'] in RFcav:
|
|
RingClass.append(Cavity(p))
|
|
elif p['SN'] in Coll:
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Collimator(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Collimator(p))
|
|
elif p['SN'] in CommonLineSN:
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(CommonLine(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(CommonLine(p))
|
|
elif p['SN']=='NONE':
|
|
if p['L']:
|
|
p['DNAME']=p['TYPE']
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Drift(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Drift(p))
|
|
else:
|
|
RingClass.append(Marker(p))
|
|
elif p['SN']=='DRIF':
|
|
RingClass.append(Drift(p))
|
|
elif p['SN']=='GCYC' and cycle:
|
|
RingClass.append('CYCLE')
|
|
|
|
#print (p['TYPE'])
|
|
if 'OVERLAP' in p.keys():
|
|
#if p['SN']==RingClass[-1].SN:
|
|
# Pid=-1
|
|
#else:
|
|
# Pid=-2
|
|
#self.OverlapC[RingClass[Pid].NAME]=[]
|
|
self.OverlapC[p['NAME']]=[]
|
|
for t in p['OVERLAP']:
|
|
po={}
|
|
po['L']=p['L']
|
|
po['RL']=p['RL']
|
|
po['TYPE']=t
|
|
po['SN']=self.Type[t]['SN']
|
|
po['INDEX']=indx
|
|
po['S']=p['S']
|
|
po['SANGLE']=p['SANGLE']
|
|
po['MS']=p['MS']
|
|
po['MANGLE']=p['MANGLE']
|
|
po['SECTOR']=p['SECTOR']
|
|
po['GIRDER']=p['GIRDER']
|
|
po['NAME']=p['NAME'].split('-')[0]+'-'+po['SN']+'-'+p['NAME'].split('-')[2]
|
|
if po['SN']=='MOCT':
|
|
po['K3L']=0
|
|
self.OverlapC[p['NAME']].append(Octupole(po))
|
|
elif po['SN']=='MQSK':
|
|
po['K1']=0
|
|
#if 'SKEW' in self.Type[t].keys():
|
|
# po['SKEW']=self.Type[t]['SKEW']
|
|
po['SKEW']=1
|
|
self.OverlapC[p['NAME']].append(Quadrupole(po))
|
|
|
|
elif po['SN']=='GSRC':
|
|
self.OverlapC[p['NAME']].append(Marker(po))
|
|
elif po['SN']=='NONE':
|
|
self.OverlapC[p['NAME']].append(Marker(po))
|
|
|
|
# Only existing Overlap is implemented...
|
|
|
|
|
|
#exit()
|
|
|
|
if cycle<0: # self.Ring includes 'CYCLE' text
|
|
self.Ring=RingClass
|
|
elif cycle:
|
|
RingClassT=[]
|
|
Nc=len(RingClass)
|
|
CI=[index for index, value in enumerate(RingClass) if value == 'CYCLE']
|
|
Ci=CI[cycle-1]
|
|
Sinit=RingClass[Ci+1].S
|
|
SANGinit=RingClass[Ci+1].SANGLE
|
|
|
|
|
|
for i in range(Ci,len(RingClass)):
|
|
if RingClass[i]!='CYCLE':
|
|
RingClass[i].S=RingClass[i].S-Sinit
|
|
RingClass[i].SANGLE=RingClass[i].SANGLE-SANGinit
|
|
RingClass[i].MS=RingClass[i].MS-Sinit
|
|
RingClass[i].MANGLE=RingClass[i].MANGLE-SANGinit
|
|
RingClassT.append(RingClass[i])
|
|
if RingClass[i].NAME in self.OverlapC.keys():
|
|
for co in self.OverlapC[RingClass[i].NAME]:
|
|
co.S=co.S-Sinit
|
|
co.SANGLE=co.SANGLE-SANGinit
|
|
co.MS=co.MS-Sinit
|
|
co.MANGLE=co.MANGLE-SANGinit
|
|
for i in range(0,Ci):
|
|
if RingClass[i]!='CYCLE':
|
|
RingClass[i].S=self.C-Sinit+RingClass[i].S
|
|
RingClass[i].SANGLE=360-SANGinit+RingClass[i].SANGLE
|
|
RingClass[i].MS=self.C-Sinit+RingClass[i].MS
|
|
RingClass[i].MANGLE=360-SANGinit+RingClass[i].MANGLE
|
|
RingClassT.append(RingClass[i])
|
|
if RingClass[i].NAME in self.OverlapC.keys():
|
|
for co in self.OverlapC[RingClass[i].NAME]:
|
|
co.S=self.C-Sinit+co.S
|
|
co.SANGLE=360-SANGinit+co.SANGLE
|
|
co.MS=self.C-Sinit+co.MS
|
|
co.MANGLE=360-SANGinit+co.MANGLE
|
|
|
|
|
|
self.Ring=RingClassT
|
|
else:
|
|
self.Ring=RingClass
|
|
|
|
|
|
kl=list(self.OverlapC.keys())
|
|
for k in kl:
|
|
self.OverlapC[k+'0']=self.OverlapC.pop(k)
|
|
|
|
|
|
self.ElementDB={}
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
else:
|
|
self.ElementDB[c.NAME]=c
|
|
if c.NAME in self.OverlapC.keys():
|
|
for co in self.OverlapC[c]:
|
|
self.ElementDB[co.NAME]=co
|
|
|
|
|
|
def individuateS2(self,Ring,cycle=0):
|
|
|
|
# This method is strictly for the SLS2 structure
|
|
|
|
del self.Ring
|
|
del self.Ring0
|
|
del self.OverlapC
|
|
self.OverlapC={}
|
|
RingClass=[]
|
|
|
|
#print ('btatt',Ring)
|
|
#exit()
|
|
|
|
# These short name are difined for SLS2 naming convention
|
|
Gmark=['GMRK','GSRC']
|
|
# 'DSCR', screen monitor. Experimental, 08.12.2020
|
|
# DICT added 07.11.2022
|
|
Diag=['DBPM','DSCR','DICT']
|
|
Dmag=['MBEN','MBCF','MBSC']
|
|
Qmag=['MQUA','MQCO']
|
|
Sext=['MSXT']
|
|
Oct=['MOCT']
|
|
HKIK=['MCOX','MKIK','MSEP']
|
|
VKIK=['MCOY']
|
|
ID=['UIND']
|
|
FM=['MMAP'] # Field map, experimental
|
|
RFcav=['RCAV','R3HC']
|
|
Coll=['VCOL'] # Collimator, 21.11.2023
|
|
|
|
CommonLineSN=[]
|
|
for k in self.Common.keys():
|
|
if self.Common[k][0]!='NONE':
|
|
CommonLineSN.append(self.Common[k][0])
|
|
|
|
|
|
|
|
|
|
sn=0 # Sector no.
|
|
s=0.0 # Longitudinal location
|
|
ang= 0 #total angle from the beginning (exclusive of its bending angle)
|
|
GL=[]
|
|
Prop=[]
|
|
# First survey
|
|
ndri=0
|
|
drir=[]
|
|
drirn=[]
|
|
for e in range(0,len(Ring)):
|
|
ele=Ring[e]
|
|
|
|
if Ring[e] in self.Common.keys():
|
|
p={}
|
|
p['L']=self.Common[Ring[e]][2]
|
|
p['ANGLE']=self.Common[Ring[e]][3]
|
|
p['TL']=self.Common[Ring[e]][2]
|
|
p['TANGLE']=self.Common[Ring[e]][3]
|
|
p['DX']=self.Common[Ring[e]][4]
|
|
p['DY']=self.Common[Ring[e]][5]
|
|
p['RL']=0
|
|
p['SN']=self.Common[Ring[e]][0]
|
|
p['TYPE']=Ring[e]
|
|
Prop.append(deepcopy(p))
|
|
elif type(Ring[e])==float or type(Ring[e])==int:
|
|
|
|
|
|
if Ring[e] not in drir:
|
|
|
|
drir.append(Ring[e])
|
|
drirn.append(ndri)
|
|
ndri=ndri+1
|
|
ndrip=ndri
|
|
else:
|
|
ndrip=drir.index(Ring[e])
|
|
|
|
ele='D'+str(ndri).zfill(4)
|
|
|
|
p={}
|
|
p['L']=Ring[e]
|
|
p['RL']=0
|
|
p['SN']='DRIF'
|
|
p['TYPE']='DRIFT'
|
|
p['DNAME']=ele # Name that appears in OPA file. Is it used??
|
|
Prop.append(deepcopy(p))
|
|
|
|
|
|
else: # Need to implement overlap elems here?? maybe not. => In the second survey.
|
|
|
|
if '|' not in ele:
|
|
Prop.append(deepcopy(self.Type[ele]))
|
|
#if ele=='BNVB':
|
|
# print ('cccccc',self.Type[ele])
|
|
# exit()
|
|
|
|
Prop[e]['TYPE']=ele
|
|
else:
|
|
elet=ele.split('|')[0]
|
|
Prop.append(deepcopy(self.Type[elet]))
|
|
Prop[e]['OVERLAP']=ele.split('|')[1:]
|
|
Prop[e]['TYPE']=elet
|
|
|
|
|
|
if ele=='GINI_SEC':
|
|
sn=sn+1
|
|
GL.append([0,0,0,0,0,0])
|
|
gl=0
|
|
gi=0
|
|
|
|
|
|
if ele=='G0A' or ele=='G1A':
|
|
#print (sn,gi,ele)
|
|
GL[sn-1][gi]=gl
|
|
gi=gi+1
|
|
if gi==6:
|
|
gi=5
|
|
else:
|
|
gl=0
|
|
|
|
|
|
|
|
Prop[e]['SECTOR']=sn
|
|
Prop[e]['GIRDER']=gi
|
|
|
|
|
|
#Prop[e]['TL'] causes a key error. I don't understand!!!!!
|
|
if type(Prop[e]['L'])==list:
|
|
for k in Prop[e].keys():
|
|
if k=='TL':
|
|
TL=Prop[e][k]
|
|
Prop[e]['SG']=gl+TL/2
|
|
else:
|
|
Prop[e]['SG']=gl+Prop[e]['L']/2+Prop[e]['RL']
|
|
|
|
|
|
#if Ring[e]=='SOQO':
|
|
# print ('======',Prop[e])
|
|
# print (self.Common[Ring[e]])
|
|
# exit()
|
|
|
|
|
|
Prop[e]['S']=s # Longitudinal position at the entrance of the element (including RL)
|
|
# Integrated bending at the entrance of element
|
|
# Deflection angle of THIS element is not included
|
|
Prop[e]['SANGLE']=ang
|
|
|
|
|
|
|
|
if type(Prop[e]['L'])==list and Prop[e]['SN']=='MBSC':
|
|
Prop[e]['MS']=s+Prop[e]['TL']/2 # Longitudinal position at the middle of the element
|
|
s=s+Prop[e]['TL']
|
|
gl=gl+Prop[e]['TL']
|
|
Prop[e]['MANGLE']=ang+Prop[e]['TANGLE']/2
|
|
ang=ang+Prop[e]['TANGLE']
|
|
elif type(Prop[e]['L'])==list:
|
|
Prop[e]['MS']=s+Prop[e]['TL']/2#+Prop[e]['RL'] # Longitudinal position at the middle of the element
|
|
s=s+Prop[e]['TL']#+Prop[e]['RL']*2
|
|
gl=gl+Prop[e]['TL']#+Prop[e]['RL']*2
|
|
if 'ANGLE' in Prop[e].keys():
|
|
Prop[e]['MANGLE']=ang+Prop[e]['ANGLE']/2
|
|
ang=ang+Prop[e]['ANGLE']
|
|
else:
|
|
Prop[e]['MANGLE']=ang
|
|
else:
|
|
Prop[e]['MS']=s+Prop[e]['L']/2+Prop[e]['RL'] # Longitudinal position at the middle of the element
|
|
s=s+Prop[e]['L']+Prop[e]['RL']*2
|
|
gl=gl+Prop[e]['L']+Prop[e]['RL']*2
|
|
if 'ANGLE' in Prop[e].keys():
|
|
Prop[e]['MANGLE']=ang+Prop[e]['ANGLE']/2
|
|
ang=ang+Prop[e]['ANGLE']
|
|
else:
|
|
Prop[e]['MANGLE']=ang
|
|
|
|
#print (Prop)
|
|
#print (GL)
|
|
self.C=s
|
|
|
|
|
|
# Second survey to finalize
|
|
#fout=open('temp.dat','w')
|
|
Reserved=[[],[],[],[],[],[],[],[],[],[],[],[]]
|
|
RingClass=[]
|
|
for i in range(0,len(Prop)):
|
|
p=Prop[i]
|
|
TN=Ring[i]
|
|
#print(p['Sector'],p['Girder'])
|
|
#print (GL)
|
|
gl=GL[p['SECTOR']-1][p['GIRDER']]
|
|
|
|
# Important to add 1e-7 to avoid a flactuation due to round error
|
|
indx=int((p['SG']+1e-7)/gl*100)
|
|
|
|
#if p['SECTOR']==9 and p['GIRDER']==0:
|
|
# print ('debugging',indx,p['SG'],p['SN'])
|
|
# print (Reserved[p['SECTOR']-1])
|
|
|
|
|
|
if indx==99:
|
|
indx=98
|
|
if p['SN']=='NONE' or p['SN']=='DRIF':
|
|
pass
|
|
else:
|
|
if 100*p['GIRDER']+indx in Reserved[p['SECTOR']-1]:
|
|
#print ('Overlap!!!!!!!!!!!',100*p['GIRDER']+indx+1,p['SECTOR'],p['GIRDER'],indx,p['SN'],p['L'],i)
|
|
if 100*p['GIRDER']+indx+1 not in Reserved[p['SECTOR']-1]:
|
|
indx=indx+1
|
|
else:
|
|
indx=indx+2
|
|
if p['TYPE']!='DRIFT':
|
|
Reserved[p['SECTOR']-1].append(100*p['GIRDER']+indx)
|
|
if indx==100:
|
|
indx=99
|
|
|
|
|
|
p['INDEX']=indx
|
|
p['NAME']='ARS'+str(p['SECTOR']).zfill(2)+'-'+p['SN']+'-'+str(p['GIRDER'])+str(indx).zfill(2)
|
|
#if p['SN'] in Dmag:
|
|
#print (n)
|
|
|
|
|
|
|
|
def RL(pin):
|
|
pr1={}
|
|
pr1['L']=pin['RL']
|
|
pr1['RL']=0
|
|
pr1['SN']='DRIF'
|
|
pr1['NAME']=pin['NAME'].split('-')[0]+'-DRIF-'+pin['NAME'].split('-')[2]
|
|
pr1['INDEX']=indx
|
|
pr1['TYPE']='DRIFT'
|
|
pr1['DNAME']='DR'+pin['TYPE'] # Name that appears in OPA file
|
|
if type(pin['L'])==list:
|
|
pr1['S']=pin['S']-abs(pin['RL'])
|
|
pr1['MS']=pin['S']-abs(pin['RL'])/2
|
|
else:
|
|
pr1['S']=pin['S']
|
|
pr1['MS']=pin['S']+pin['RL']/2
|
|
|
|
pr1['SANGLE']=pin['SANGLE']
|
|
pr1['MANGLE']=pin['SANGLE']
|
|
pr1['SECTOR']=pin['SECTOR']
|
|
pr1['GIRDER']=pin['GIRDER']
|
|
pr1['RESERVE']=1
|
|
|
|
|
|
pr2=deepcopy(pr1)
|
|
if type(pin['L'])==list:
|
|
pr2['S']=pin['S']+pin['TL']
|
|
else:
|
|
pr2['S']=pin['S']+pin['L']+pin['RL']
|
|
pr2['MS']=pr2['S']+pin['RL']/2
|
|
pr2['RESERVE']=1
|
|
|
|
|
|
if 'ANGLE' in pin.keys():
|
|
pr2['SANGLE']=pin['SANGLE']+pin['ANGLE']
|
|
else:
|
|
pr2['SANGLE']=pin['SANGLE']
|
|
|
|
return pr1,pr2
|
|
|
|
if p['RL']:
|
|
pr1,pr2=RL(p)
|
|
|
|
|
|
if p['SN'] in Gmark:
|
|
RingClass.append(Marker(p))
|
|
elif p['SN'] in Diag:
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Monitor(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Monitor(p))
|
|
elif p['SN'] in Dmag:
|
|
p['K1']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Dipole(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Dipole(p))
|
|
elif p['SN'] in Qmag:
|
|
p['K1']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Quadrupole(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Quadrupole(p))
|
|
elif p['SN'] in Sext:
|
|
p['K2']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Sextupole(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Sextupole(p))
|
|
elif p['SN'] in Oct:
|
|
p['K3L']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Octupole(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Octupole(p))
|
|
elif p['SN'] in HKIK:
|
|
p['KICK']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(HKicker(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(HKicker(p))
|
|
elif p['SN'] in VKIK:
|
|
p['KICK']=0.0
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(VKicker(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(VKicker(p))
|
|
elif p['SN'] in ID:
|
|
p['DNAME']=p['TYPE']
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Drift(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Drift(p))
|
|
elif p['SN'] in FM: # Experimental
|
|
if p['RL']>100:
|
|
if self.TracyFM:
|
|
pr1['L']=pr1['L']-100
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(FieldMap(p))
|
|
if self.TracyFM:
|
|
pr2['L']=pr2['L']-100
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
if p['RL']<0 and self.TracyFM:
|
|
pr1['L']=abs(pr1['L'])
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(FieldMap(p))
|
|
if p['RL']>0 and self.TracyFM:
|
|
RingClass.append(Drift(pr2))
|
|
elif p['SN'] in RFcav:
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Cavity(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Cavity(p))
|
|
elif p['SN'] in Coll:
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Collimator(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Collimator(p))
|
|
elif p['SN'] in CommonLineSN:
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(CommonLine(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(CommonLine(p))
|
|
elif p['SN']=='NONE':
|
|
if p['L']:
|
|
p['DNAME']=p['TYPE']
|
|
if p['RL']:
|
|
RingClass.append(Drift(pr1))
|
|
RingClass.append(Drift(p))
|
|
RingClass.append(Drift(pr2))
|
|
else:
|
|
RingClass.append(Drift(p))
|
|
else:
|
|
RingClass.append(Marker(p))
|
|
elif p['SN']=='DRIF':
|
|
RingClass.append(Drift(p))
|
|
elif p['SN']=='GCYC' and cycle:
|
|
RingClass.append('CYCLE')
|
|
|
|
#print (p['TYPE'])
|
|
if 'OVERLAP' in p.keys():
|
|
#if p['SN']==RingClass[-1].SN:
|
|
# Pid=-1
|
|
#else:
|
|
# Pid=-2
|
|
#self.OverlapC[RingClass[Pid].NAME]=[]
|
|
self.OverlapC[p['NAME']]=[]
|
|
for t in p['OVERLAP']:
|
|
po={}
|
|
po['L']=p['L']
|
|
po['RL']=p['RL']
|
|
po['TYPE']=t
|
|
po['SN']=self.Type[t]['SN']
|
|
po['INDEX']=indx
|
|
po['S']=p['S']
|
|
po['SANGLE']=p['SANGLE']
|
|
po['MS']=p['MS']
|
|
po['MANGLE']=p['MANGLE']
|
|
po['SECTOR']=p['SECTOR']
|
|
po['GIRDER']=p['GIRDER']
|
|
po['NAME']=p['NAME'].split('-')[0]+'-'+po['SN']+'-'+p['NAME'].split('-')[2]
|
|
if po['SN']=='MOCT':
|
|
po['K3L']=0
|
|
self.OverlapC[p['NAME']].append(Octupole(po))
|
|
elif po['SN']=='MQSK':
|
|
po['K1']=0
|
|
#if 'SKEW' in self.Type[t].keys():
|
|
# po['SKEW']=self.Type[t]['SKEW']
|
|
po['SKEW']=1
|
|
self.OverlapC[p['NAME']].append(Quadrupole(po))
|
|
|
|
elif po['SN']=='GSRC':
|
|
self.OverlapC[p['NAME']].append(Marker(po))
|
|
elif po['SN']=='NONE':
|
|
self.OverlapC[p['NAME']].append(Marker(po))
|
|
|
|
# Only existing Overlap is implemented...
|
|
|
|
|
|
#exit()
|
|
|
|
if cycle<0: # self.Ring includes 'CYCLE' text
|
|
self.Ring=RingClass
|
|
self.Ring0=copy(self.Ring)
|
|
elif cycle:
|
|
RingClassT=[]
|
|
Nc=len(RingClass)
|
|
CI=[index for index, value in enumerate(RingClass) if value == 'CYCLE']
|
|
Ci=CI[cycle-1]
|
|
Sinit=RingClass[Ci+1].S
|
|
SANGinit=RingClass[Ci+1].SANGLE
|
|
|
|
|
|
for i in range(Ci,len(RingClass)):
|
|
if RingClass[i]!='CYCLE':
|
|
RingClass[i].S=RingClass[i].S-Sinit
|
|
RingClass[i].SANGLE=RingClass[i].SANGLE-SANGinit
|
|
RingClass[i].MS=RingClass[i].MS-Sinit
|
|
RingClass[i].MANGLE=RingClass[i].MANGLE-SANGinit
|
|
RingClassT.append(RingClass[i])
|
|
if RingClass[i].NAME in self.OverlapC.keys():
|
|
for co in self.OverlapC[RingClass[i].NAME]:
|
|
co.S=co.S-Sinit
|
|
co.SANGLE=co.SANGLE-SANGinit
|
|
co.MS=co.MS-Sinit
|
|
co.MANGLE=co.MANGLE-SANGinit
|
|
for i in range(0,Ci):
|
|
if RingClass[i]!='CYCLE':
|
|
RingClass[i].S=self.C-Sinit+RingClass[i].S
|
|
RingClass[i].SANGLE=360-SANGinit+RingClass[i].SANGLE
|
|
RingClass[i].MS=self.C-Sinit+RingClass[i].MS
|
|
RingClass[i].MANGLE=360-SANGinit+RingClass[i].MANGLE
|
|
RingClassT.append(RingClass[i])
|
|
if RingClass[i].NAME in self.OverlapC.keys():
|
|
for co in self.OverlapC[RingClass[i].NAME]:
|
|
co.S=self.C-Sinit+co.S
|
|
co.SANGLE=360-SANGinit+co.SANGLE
|
|
co.MS=self.C-Sinit+co.MS
|
|
co.MANGLE=360-SANGinit+co.MANGLE
|
|
|
|
|
|
self.Ring=RingClassT
|
|
self.Ring0=RingClass
|
|
|
|
else:
|
|
self.Ring=RingClass
|
|
self.Ring0=copy(self.Ring)
|
|
|
|
kl=list(self.OverlapC.keys())
|
|
#print (kl)
|
|
#exit()
|
|
for k in kl:
|
|
self.OverlapC[k+'0']=self.OverlapC.pop(k)
|
|
|
|
self.ElementDB={}
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
else:
|
|
self.ElementDB[c.NAME]=c
|
|
if c.NAME in self.OverlapC.keys():
|
|
for co in self.OverlapC[c.NAME]:
|
|
self.ElementDB[co.NAME]=co
|
|
if c.SN=='MMAP':
|
|
if c.OVERLAP:
|
|
prop={}
|
|
prop['L']=0
|
|
prop['RL']=0
|
|
prop['SN']='DBPM'
|
|
prop['S']=c.S
|
|
prop['SANGLE']=c.SANGLE
|
|
prop['MS']=c.MS
|
|
prop['MANGLE']=c.MANGLE
|
|
prop['SECTOR']=c.SECTOR
|
|
prop['GIRDER']=c.GIRDER
|
|
prop['TYPE']=c.TYPE
|
|
prop['INDEX']=c.INDEX
|
|
prop['NAME']=c.NAME
|
|
|
|
for oe in c.OVERLAP:
|
|
if oe[0]=='DBPM':
|
|
ele=Monitor(prop)
|
|
ele.MAX=c.MAX # Horizontal
|
|
ele.MAY=c.MAY # Vertical
|
|
ele.MAR=c.MAR # Rotation
|
|
ele.TYPE='BPM'
|
|
ele.NAME=c.NAME.replace('MMAP',oe[0])
|
|
self.ElementDB[ele.NAME]=ele
|
|
#print ('kiteru?',ele.NAME)
|
|
#print (self.ElementDB[ele.NAME])
|
|
#exit()
|
|
if oe[0]=='MCOX':
|
|
prop['KICK']=0
|
|
ele=HKicker(prop)
|
|
ele.MAX=c.MAX # Horizontal
|
|
ele.MAY=c.MAY # Vertical
|
|
ele.MAR=c.MAR # Rotation
|
|
ele.TYPE='CH'
|
|
ele.NAME=c.NAME.replace('MMAP',oe[0])
|
|
self.ElementDB[ele.NAME]=ele
|
|
if oe[0]=='MCOY':
|
|
prop['KICK']=0
|
|
ele=VKicker(prop)
|
|
ele.MAX=c.MAX # Horizontal
|
|
ele.MAY=c.MAY # Vertical
|
|
ele.MAR=c.MAR # Rotation
|
|
ele.TYPE='CV'
|
|
ele.NAME=c.NAME.replace('MMAP',oe[0])
|
|
self.ElementDB[ele.NAME]=ele
|
|
if oe[0]=='MQCO':
|
|
prop['K1']=0
|
|
ele=Quadrupole(prop)
|
|
ele.MAX=c.MAX # Horizontal
|
|
ele.MAY=c.MAY # Vertical
|
|
ele.MAR=c.MAR # Rotation
|
|
ele.L=oe[2]*0.001
|
|
ele.NAME=c.NAME.replace('MMAP',oe[0])
|
|
self.ElementDB[ele.NAME]=ele
|
|
|
|
def cycle(self,n):
|
|
# self.Layout method delete the existing ring
|
|
# Therefore, a simple cycle method is necessary...
|
|
# To use this method, self.Layout('full/unit',-1) <- cycle switch should be negative
|
|
|
|
if n:
|
|
RingClassT=[]
|
|
Nc=len(self.Ring)
|
|
CI=[index for index, value in enumerate(self.Ring) if value == 'CYCLE']
|
|
Ci=CI[n-1]
|
|
Sinit=self.Ring[Ci+1].S
|
|
SANGinit=self.Ring[Ci+1].SANGLE
|
|
|
|
for i in range(Ci,len(self.Ring)):
|
|
if self.Ring[i]!='CYCLE':
|
|
self.Ring[i].S=self.Ring[i].S-Sinit
|
|
self.Ring[i].SANGLE=self.Ring[i].SANGLE-SANGinit
|
|
self.Ring[i].MS=self.Ring[i].MS-Sinit
|
|
self.Ring[i].MANGLE=self.Ring[i].MANGLE-SANGinit
|
|
RingClassT.append(self.Ring[i])
|
|
if self.Ring[i].NAME in self.OverlapC.keys():
|
|
for co in self.OverlapC[self.Ring[i].NAME]:
|
|
co.S=co.S-Sinit
|
|
co.SANGLE=co.SANGLE-SANGinit
|
|
co.MS=co.MS-Sinit
|
|
co.MANGLE=co.MANGLE-SANGinit
|
|
|
|
for i in range(0,Ci):
|
|
if self.Ring[i]!='CYCLE':
|
|
self.Ring[i].S=self.C-Sinit+self.Ring[i].S
|
|
self.Ring[i].SANGLE=360-SANGinit+self.Ring[i].SANGLE
|
|
RingClassT.append(self.Ring[i])
|
|
self.Ring[i].MS=self.C-Sinit+self.Ring[i].MS
|
|
self.Ring[i].MANGLE=360-SANGinit+self.Ring[i].MANGLE
|
|
if self.Ring[i].NAME in self.OverlapC.keys():
|
|
for co in self.OverlapC[self.Ring[i].NAME]:
|
|
co.S=self.C-Sinit+co.S
|
|
co.SANGLE=360-SANGinit+co.SANGLE
|
|
co.MS=self.C-Sinit+co.MS
|
|
co.MANGLE=360-SANGinit+co.MANGLE
|
|
|
|
self.Ring=RingClassT
|
|
|
|
|
|
def insertMultipole(self,tn):
|
|
# Method to insert thin multipole after individuation.
|
|
# What is done actually is adding the element to OverlapC
|
|
|
|
# TYPE name tn can be a part of full type name
|
|
# ex. tn='VB' catches VBO, VBI, VBXI, VBXO
|
|
|
|
if not self.Ring:
|
|
return
|
|
|
|
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
else:
|
|
if tn in c.TYPE:
|
|
if c.NAME not in self.OverlapC.keys():
|
|
self.OverlapC[c.NAME]=[]
|
|
|
|
po={}
|
|
po['L']=0
|
|
po['RL']=0
|
|
po['TYPE']='MERR'
|
|
po['TARGET']=c.NAME
|
|
po['SN']='MERR'
|
|
po['INDEX']=c.INDEX
|
|
po['S']=c.S+c.L/2
|
|
po['SANGLE']=0
|
|
po['MS']=c.S+c.L/2
|
|
po['MANGLE']=0
|
|
po['SECTOR']=c.SECTOR
|
|
po['GIRDER']=c.GIRDER
|
|
po['NAME']=c.NAME.split('-')[0]+'-MERR-'+str(c.GIRDER)+str(c.INDEX).zfill(2)
|
|
oe=Multipole(po)
|
|
self.OverlapC[c.NAME].append(oe)
|
|
self.ElementDB[oe.NAME]=oe
|
|
|
|
|
|
def setStrengthAsFile(self,Pattern,Strength,OPA=False):
|
|
|
|
|
|
BDNkey=['MQUA','MSXT','MOCT','MQCO','MQSK']
|
|
|
|
StrPat={}
|
|
Tdone=[]
|
|
for k in Pattern.keys():
|
|
StrPat[k]=[]
|
|
for e in Pattern[k]:
|
|
StrPat[k].append(Strength[e])
|
|
if e not in Tdone:
|
|
Tdone.append(e)
|
|
|
|
for k in Strength.keys():
|
|
if k not in Tdone:
|
|
StrPat[k]=Strength[k]
|
|
|
|
if not OPA:
|
|
try:
|
|
del(StrPat['MKIK'])
|
|
except:
|
|
pass
|
|
|
|
|
|
for k in BDNkey:
|
|
if k in Pattern:
|
|
StrPat[k+'_BDN']=Pattern[k]
|
|
|
|
self.setStrength(StrPat)
|
|
|
|
|
|
def setStrength(self,Pattern):
|
|
# Pattern is a dictionary
|
|
# Pattern['TypeName']=float or possibly a list
|
|
# Pattern['SN'] also works.
|
|
|
|
# This may not work for MMAP with inserted elements...
|
|
|
|
Pat=deepcopy(Pattern)
|
|
if not self.Ring:
|
|
return
|
|
|
|
for c in self.Ring: # Need to elaborate this block?
|
|
if type(c)==str:
|
|
pass
|
|
else:
|
|
if c.SN in Pat.keys():
|
|
if type(Pat[c.SN])==float or type(Pat[c.SN])==int:
|
|
c.setStrength(Pat[c.SN])
|
|
# This may not be the case as MQUA and MSXT strengthes are given by a list normally.
|
|
if (c.SN=='MQUA' or c.SN=='MSXT') and Pat[c.SN]<0.0:
|
|
c.POL=-1
|
|
|
|
if c.SN+'_BDN' in Pat.keys():
|
|
c.BDN=Pat[c.SN+'_BDN']
|
|
|
|
else:
|
|
c.setStrength(Pat[c.SN][0])
|
|
if (c.SN=='MQUA' or c.SN=='MSXT') and Pat[c.SN][0]<0.0:
|
|
c.POL=-1
|
|
Pat[c.SN].pop(0)
|
|
|
|
if c.SN+'_BDN' in Pat.keys():
|
|
c.BDN=Pat[c.SN+'_BDN'][0]
|
|
Pat[c.SN+'_BDN'].pop(0)
|
|
|
|
|
|
elif c.TYPE in Pat.keys():
|
|
c.setStrength(Pat[c.TYPE])
|
|
if (c.SN=='MQUA' or c.SN=='MSXT') and Pat[c.TYPE]<0.0:
|
|
c.POL=-1
|
|
|
|
|
|
if c.NAME in self.OverlapC.keys():
|
|
for t in self.OverlapC[c.NAME]:
|
|
if t.SN in Pat.keys():
|
|
if type(Pat[t.SN])==float:
|
|
t.setStrength(Pat[t.SN])
|
|
else:
|
|
t.setStrength(Pat[t.SN][0])
|
|
Pat[t.SN].pop(0)
|
|
elif t.TYPE in Pat.keys():
|
|
t.setStrength(Pat[t.TYPE])
|
|
|
|
if t.SN+'_BDN' in Pat.keys():
|
|
t.BDN=Pat[t.SN+'_BDN'][0]
|
|
Pat[t.SN+'_BDN'].pop(0)
|
|
|
|
|
|
|
|
def setKL_SN(self,SN,KL,additive=False):
|
|
elem=self.getElement_SN(SN)
|
|
|
|
if type(KL)==list:
|
|
if len(elem)!=len(KL):
|
|
print ('Error: KL input length does not much the number of '+SN+' elements')
|
|
return
|
|
for i in range(0,len(elem)):
|
|
if additive:
|
|
elem.setKL(elem.KL()+KL[i])
|
|
else:
|
|
elem.setKL(KL[i])
|
|
else: # set all elem to KL (float). Mostly used for turning off
|
|
for e in elem:
|
|
if additive:
|
|
e.setKL(e.KL()+KL)
|
|
else:
|
|
e.setKL(KL)
|
|
|
|
|
|
|
|
def setKL_TYPE(self,TYPE,KL,additive=False,bothIO=True):
|
|
# Assumed that the order of KL and the order of elem is the same.
|
|
elem=self.getElement_TYPE(TYPE,bothIO=bothIO)
|
|
if type(KL)==list:
|
|
if len(elem)!=len(KL):
|
|
print ('Error: KL input length does not much the number of '+TYPE+' elements')
|
|
for i in range(0,len(elem)):
|
|
if additive:
|
|
elem[i].setKL(elem.KL()+KL[i])
|
|
else:
|
|
elem[i].setKL(KL[i])
|
|
else:
|
|
for e in elem:
|
|
if additive:
|
|
e.setKL(e.KL()+KL)
|
|
else:
|
|
e.setKL(KL)
|
|
|
|
def setKL_FM_MIX(self,KL,additive=False):
|
|
# Special method to set KL, when some magnets are "incorporated" om Field map
|
|
# KL is a dictionary {Element Name: KL}
|
|
for n in KL.keys():
|
|
elem=getElement(n)
|
|
if elem:
|
|
if additive:
|
|
elem.setKL(elem.KL()+KL[n])
|
|
else:
|
|
elem.setKL(KL[n])
|
|
else:
|
|
name=n.replace('_','-')
|
|
sn=name.split('-')[1]
|
|
efm=getElement(n.replace(sn,'MMAP'))
|
|
for oe in efm.OVERLAP:
|
|
if sn==oe[0]:
|
|
if additive:
|
|
oe[3]=oe[3]+KL[n]
|
|
else:
|
|
oe[3]=KL[n]
|
|
|
|
|
|
def getKL_SN(self,SN):
|
|
|
|
elem=self.getElement_SN(SN)
|
|
|
|
return [c.KL() for c in elem]
|
|
|
|
def getKL_TYPE(self,tn,bothIO=False):
|
|
|
|
elem=self.getElement_TYPE(tn,bothIO=bothIO)
|
|
|
|
return [c.KL() for c in elem]
|
|
|
|
|
|
|
|
def setMultipoleError(self,tn,order,val):
|
|
# val can be list if the error is not constant over individual elements
|
|
# order=2 is sextupole
|
|
|
|
|
|
if not self.Ring:
|
|
return
|
|
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif c.TYPE==tn:
|
|
if c.NAME not in self.OverlapC.keys():
|
|
print ('Insert multipole before assigning errors')
|
|
exit()
|
|
for oe in self.OverlapC[c.NAME]:
|
|
if oe.SN=='MERR':
|
|
oe.setStrength(order,val)
|
|
if type(val)==list:
|
|
val.pop(0)
|
|
|
|
def setAperture(self,Aperture):
|
|
# At this moment, the input is an dictionary
|
|
# defined in ApertureModel.<version>.py
|
|
|
|
|
|
if not self.Ring:
|
|
return
|
|
|
|
if not Aperture:
|
|
return
|
|
|
|
kl=list(Aperture.keys())
|
|
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif c.TYPE in kl:
|
|
c.APERTURE=Aperture[c.TYPE]
|
|
else:
|
|
c.APERTURE=Aperture['Nominal']
|
|
|
|
def setSextFamily(self,Pattern):
|
|
# Input is a list with a length corresponding to the number of sext
|
|
# Set before cycling
|
|
|
|
if not self.Ring:
|
|
return
|
|
|
|
Pat=deepcopy(Pattern)
|
|
|
|
Dad=[]
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif c.SN=='MSXT':
|
|
c.FAMILY=Pattern[0]
|
|
Pattern.pop(0)
|
|
if c.FAMILY not in Dad:
|
|
c.DAD=1
|
|
Dad.append(c.FAMILY)
|
|
|
|
|
|
def getSextFamily(self):
|
|
|
|
|
|
if not self.Ring:
|
|
return
|
|
|
|
SF={}
|
|
Dad=[]
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif c.SN=='MSXT':
|
|
if not c.FAMILY:
|
|
print ('Sextupoles are not yet grouped')
|
|
return SF,Dad
|
|
else:
|
|
if c.FAMILY in SF.keys():
|
|
SF[c.FAMILY].append(c.NAME)
|
|
else:
|
|
SF[c.FAMILY]=[c.NAME]
|
|
if c.DAD:
|
|
Dad.append(c.NAME)
|
|
|
|
return SF,Dad
|
|
|
|
|
|
|
|
def bindSextFamily(self):
|
|
|
|
if not self.Ring:
|
|
return
|
|
|
|
binded={}
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif c.SN=='MSXT':
|
|
if not c.FAMILY:
|
|
print ('Sextupoles are not yet in families')
|
|
return
|
|
else:
|
|
if c.FAMILY in binded.keys():
|
|
c.setKL(binded[c.FAMILY])
|
|
else:
|
|
binded[c.FAMILY]=c.KL()
|
|
|
|
|
|
def SigmaCut(self,Scut=2.0):
|
|
# Cut value in sigma
|
|
while True:
|
|
a=gauss(0,1)
|
|
if abs(a)<Scut:
|
|
return a
|
|
|
|
|
|
def resetMisalignmentS2(self):
|
|
# In MADX, it is too complicate to reset misalignment...
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif hasattr(c,'MAX'):
|
|
if c.SN=='MBSC':
|
|
c.MAX=[0]*len(c.L)
|
|
c.MAY=[0]*len(c.L)
|
|
c.MAR=0
|
|
else:
|
|
c.MAX=0
|
|
c.MAY=0
|
|
c.MAR=0
|
|
|
|
def multiplyMisalignmentS2(self,Factor):
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif hasattr(c,'MAX'):
|
|
if c.SN=='MBSC':
|
|
c.MAX=list(np.array(c.MAX)*Factor)
|
|
c.MAY=list(np.array(c.MAY)*Factor)
|
|
c.MAR=c.MAR*Factor
|
|
else:
|
|
c.MAX=c.MAX*Factor
|
|
c.MAY=c.MAY*Factor
|
|
c.MAR=c.MAR*Factor
|
|
|
|
|
|
|
|
|
|
def CorrelatedMisalignmentS2(self, BPMoffset=0.0,BPMrot=0.0):
|
|
|
|
#
|
|
# Correlation within a unit, such as SOQO, BPMCHV are not included.
|
|
# To be checked with Michael
|
|
# Also, roll errors are not implemented yet. -> Implemented
|
|
|
|
|
|
|
|
if not self.Ring:
|
|
return
|
|
|
|
|
|
GM=60e-6 # Girder absolute
|
|
GGM=20e-6 # Girder to girder
|
|
EM=30e-6 #Element to element
|
|
|
|
# No roll error for the time being.
|
|
# There is something wrong with tilt in Elegant...
|
|
EMR=300e-6 # Magnet rotation error, the value to be discussed.
|
|
if BPMrot:
|
|
BMR=BPMrot
|
|
else:
|
|
BMR=10e-3#*0 # BPM rotation error
|
|
|
|
Sall=[]
|
|
Gall=[]
|
|
SSG=0 # flag for straight section girder
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif 'NONE' in c.NAME:
|
|
if c.TYPE[0]=='G':
|
|
Sall.append(c.S)
|
|
if c.TYPE=='G0S':
|
|
if SSG==0:
|
|
Gall.append(0) # Girder in straight section
|
|
SSG=1
|
|
else:
|
|
SSG=0
|
|
elif c.TYPE=='G0A' and c.GIRDER==1:
|
|
Gall.append(c.GIRDER) # Girder in arc
|
|
elif c.TYPE=='G1A':
|
|
Gall.append(c.GIRDER) # Girder in arc
|
|
Sall.append(c.S)
|
|
|
|
|
|
Girders=[] # Sector No and girder No
|
|
Spair=[] # Longitudinal positions of girder start and end
|
|
for i in range(0,len(Sall),2):
|
|
Spair.append([Sall[i],Sall[i+1]])
|
|
|
|
|
|
#print (Spair)
|
|
#print (len(Sall),len(Spair))
|
|
|
|
GMx=[]
|
|
GMy=[]
|
|
for i in range(0,len(Gall)):
|
|
if Gall[i]==0 or Gall[i]==1:
|
|
GMx.append([GM*self.SigmaCut(),GM*self.SigmaCut()])
|
|
GMy.append([GM*self.SigmaCut(),GM*self.SigmaCut()])
|
|
else: # Girder joint play
|
|
GMx.append([GMx[-1][1]+GGM*self.SigmaCut(),GM*self.SigmaCut()])
|
|
GMy.append([GMy[-1][1]+GGM*self.SigmaCut(),GM*self.SigmaCut()])
|
|
|
|
'''
|
|
fout=open('temp.dat','w')
|
|
for i in range(0,len(Spair)):
|
|
if Gall[i]:
|
|
wline=str(Spair[i][0])+' '+str(GMx[i][0])+' '+str(GMy[i][0])+' '+str(Gall[i])+'\n'
|
|
fout.write(wline)
|
|
wline=str(Spair[i][1])+' '+str(GMx[i][1])+' '+str(GMy[i][1])+' '+str(Gall[i])+'\n'
|
|
fout.write(wline)
|
|
wline='\n'
|
|
fout.write(wline)
|
|
|
|
fout.close()
|
|
'''
|
|
fvb=0 # flag to detect VB mag (excluding VBX)
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
else:
|
|
# It would be clever to use Sector No and Girder index here
|
|
# but it is not straightforward for the girders in straight section
|
|
# since it can be more than one.
|
|
# So, the longitudinal position is used instead - brute force approach...
|
|
gi=-1
|
|
|
|
for i in range(0,len(Spair)):
|
|
if c.S>=Spair[i][0] and c.S<=Spair[i][1]:
|
|
gi=i
|
|
|
|
if gi<0: # Element with no girder?
|
|
c.MAX=EM*self.SigmaCut()
|
|
c.MAY=EM*self.SigmaCut()
|
|
if c.SN=='DBPM':
|
|
c.MAR=BMR*self.SigmaCut()
|
|
else:
|
|
c.MAR=EMR*self.SigmaCut()
|
|
if c.SN=='MMAP':
|
|
if c.NAME.replace('MMAP','DBPM') in ElementDB.keys():
|
|
ele=self.ElementDB[c.NAME.replace('MMAP','DBPM')]
|
|
ele.MAR=BMR*self.SigmaCut()
|
|
elif c.TYPE=='VBO' or c.TYPE=='VBI' or c.TYPE=='VBXO' or c.TYPE=='VBXI' or c.TYPE=='BN':
|
|
# This block is valid even for VB-BS-VB... Need to improve...?
|
|
if fvb==0:
|
|
if c.TYPE=='VBI' or c.TYPE=='VBXI':
|
|
fvb=-1
|
|
elif c.TYPE=='VBO' or c.TYPE=='VBXO':
|
|
fvb=1
|
|
dx=EM*self.SigmaCut()
|
|
dy=EM*self.SigmaCut()
|
|
dr=EMR*self.SigmaCut()
|
|
c.MAX=dx \
|
|
+(c.S+c.RL+c.L/2-Spair[gi][0])/(Spair[gi][1]-Spair[gi][0]) \
|
|
*(GMx[gi][1]-GMx[gi][0]) + GMx[gi][0]
|
|
c.MAY=dy \
|
|
+(c.S+c.RL+c.L/2-Spair[gi][0])/(Spair[gi][1]-Spair[gi][0]) \
|
|
*(GMy[gi][1]-GMy[gi][0]) + GMy[gi][0]
|
|
c.MAR=dr
|
|
|
|
|
|
if fvb==-1 and (c.TYPE=='VBO' or c.TYPE=='VBXO'):
|
|
fvb=0
|
|
elif fvb==1 and (c.TYPE=='VBI' or c.TYPE=='VBXI'):
|
|
fvb=0
|
|
#print ('kiteru?',fvb,c.TYPE)
|
|
|
|
|
|
else:
|
|
#print (c.NAME,c.SN,c.RL)
|
|
# Unfortunately, the misalignment of field map (polykick) in tracy-null is single value...
|
|
if type(c.L)==list and c.SN=='MBSC':
|
|
sj=c.S+c.RL
|
|
mx=[]
|
|
my=[]
|
|
mxf=self.SigmaCut()
|
|
myf=self.SigmaCut()
|
|
for j in range(0,len(c.L)):
|
|
sj=sj+c.L[j]/2
|
|
mx.append(EM*mxf \
|
|
+(sj-Spair[gi][0])/(Spair[gi][1]-Spair[gi][0]) \
|
|
*(GMx[gi][1]-GMx[gi][0]) + GMx[gi][0])
|
|
my.append(EM*myf \
|
|
+(sj-Spair[gi][0])/(Spair[gi][1]-Spair[gi][0]) \
|
|
*(GMy[gi][1]-GMy[gi][0]) + GMy[gi][0])
|
|
sj=sj+c.L[j]/2
|
|
c.MAX=mx
|
|
c.MAY=my
|
|
else:
|
|
if c.SN=='MMAP':
|
|
cL=c.TL
|
|
cRL=0
|
|
else:
|
|
cL=c.L
|
|
cRL=c.RL
|
|
c.MAX=EM*self.SigmaCut() \
|
|
+(c.S+cRL+cL/2-Spair[gi][0])/(Spair[gi][1]-Spair[gi][0]) \
|
|
*(GMx[gi][1]-GMx[gi][0]) + GMx[gi][0]
|
|
c.MAY=EM*self.SigmaCut() \
|
|
+(c.S+cRL+cL/2-Spair[gi][0])/(Spair[gi][1]-Spair[gi][0]) \
|
|
*(GMy[gi][1]-GMy[gi][0]) + GMy[gi][0]
|
|
if c.NAME.replace('MMAP','DBPM') in self.ElementDB.keys():
|
|
ele=self.ElementDB[c.NAME.replace('MMAP','DBPM')]
|
|
ele.MAR=BMR*self.SigmaCut()
|
|
if c.SN=='DBPM':
|
|
c.MAR=BMR*self.SigmaCut()
|
|
else:
|
|
c.MAR=EMR*self.SigmaCut()
|
|
|
|
|
|
if BPMoffset:
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif c.SN=='DBPM':
|
|
c.MAX=c.MAX+BPMoffset*self.SigmaCut()
|
|
c.MAY=c.MAY+BPMoffset*self.SigmaCut()
|
|
elif c.SN=='MMAP':
|
|
if c.NAME.replace('MMAP','DBPM') in self.ElementDB.keys():
|
|
ele=self.ElementDB[c.NAME.replace('MMAP','DBPM')]
|
|
ele.MAX=ele.MAX+BPMoffset*self.SigmaCut()
|
|
ele.MAY=ele.MAY+BPMoffset*self.SigmaCut()
|
|
|
|
ASN=[]
|
|
for k in self.OverlapC.keys():
|
|
sn=k.split('-')[1]
|
|
#if sn=='MBEN':
|
|
# print (self.OverlapC[k])
|
|
if sn not in ASN:
|
|
ASN.append(sn)
|
|
|
|
#print (ASN)
|
|
|
|
|
|
def FieldError(self,SN,RFE):
|
|
|
|
if not self.Ring:
|
|
return
|
|
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
elif c.SN==SN:
|
|
c.RFE=RFE*self.SigmaCut()
|
|
if c.SN=='MBCF' or c.SN=='MMAP':
|
|
c.RGE=RFE*self.SigmaCut()
|
|
|
|
if SN=='MOCT':
|
|
for k in self.OverlapC.keys():
|
|
for c in self.OverlapC[k]:
|
|
if c.SN==SN:
|
|
c.RFE=RFE*self.SigmaCut()
|
|
|
|
|
|
def pushI2KL(self,SM,CrossTalk=False,ZZ=False,Indiv=False):
|
|
|
|
if not self.Ring:
|
|
print ('Layout is not yet configured.')
|
|
return
|
|
|
|
for SN in ['MQUA','MSXT','MOCT','MQCO','MQSK','MCOX','MCOY']:
|
|
EL=self.getElement_SN(SN)
|
|
for c in EL:
|
|
if CrossTalk and SN=='MSXT':
|
|
KL=c.POL*SM.I2KL(c.BDN,c.I)
|
|
elif CrossTalk and SN=='MOCT':
|
|
if c.BDN in ['OXX','OXY','OYY']:
|
|
KL=SM.I2KL(c.TYPE,c.I)
|
|
elif c.BDN in ['OCY1','OCY2']:
|
|
KL=SM.I2KL(c.TYPE,c.I,CrossTalk=c.BDN)
|
|
else:
|
|
KL=SM.I2KL(c.BDN,c.I,CrossTalk=c.BDN)
|
|
else:
|
|
if c.SN=='MQUA' and Indiv:
|
|
KL=SM.I2KL(c.NAME,c.I)
|
|
else:
|
|
KL=SM.I2KL(c.TYPE,c.I)
|
|
if c.SN in ['MQUA','MSXT']:
|
|
KL=c.POL*KL
|
|
if ZZ and c.I==0: # Zero KL if I=0, ignoring b0 constant.
|
|
KL=0
|
|
c.setKL(KL)
|
|
|
|
|
|
|
|
|
|
def pushKL2I(self,SM,CrossTalk=False,ZZ=False,Indiv=False):
|
|
|
|
|
|
if not self.Ring:
|
|
print ('Layout is not yet configured.')
|
|
return
|
|
|
|
for SN in ['MQUA','MSXT','MOCT','MQCO','MQSK','MCOX','MCOY']:
|
|
EL=self.getElement_SN(SN)
|
|
for c in EL:
|
|
if CrossTalk and SN=='MSXT':
|
|
I=SM.KL2I(c.BDN,abs(c.KL()))
|
|
elif CrossTalk and SN=='MOCT':
|
|
if c.BDN in ['OXX','OXY','OYY']:
|
|
I=SM.KL2I(c.TYPE,c.KL())
|
|
elif c.BDN in ['OCY1','OCY2']:
|
|
I=SM.KL2I(c.TYPE,c.KL(),CrossTalk=c.BDN)
|
|
else:
|
|
I=SM.KL2I(c.BDN,c.KL(),CrossTalk=c.BDN)
|
|
else:
|
|
if c.SN=='MQUA' and Indiv:
|
|
I=SM.KL2I(c.NAME,c.KL())
|
|
else:
|
|
I=SM.KL2I(c.TYPE,c.KL())
|
|
if c.SN in ['MQUA','MSXT']:
|
|
I=abs(I)
|
|
if ZZ and c.KL()==0: # Zero A if KL=0, ignoring b0 constant.
|
|
I=0
|
|
c.I=I
|
|
|
|
|
|
def PatternMatch(self,Pattern):
|
|
# Find a series of elements that matches to Pattern in self.Ring
|
|
# Matching is by TYPE
|
|
# Return indices of the first element in Pattern
|
|
|
|
s_idx=[]
|
|
for i in range(0,len(self.Ring)):
|
|
c=self.Ring[i]
|
|
if type(c)!=str:
|
|
if c.TYPE==Pattern[0]:
|
|
Nstr=0
|
|
for j in range(1,len(Pattern)):
|
|
if type(self.Ring[i+j])==str:
|
|
if self.Ring[i+j]==Pattern[j]:
|
|
compatible=1
|
|
else:
|
|
break
|
|
elif self.Ring[i+j].TYPE==Pattern[j]:
|
|
compatible=1
|
|
else:
|
|
compatible=0
|
|
break
|
|
if compatible:
|
|
s_idx.append(i)
|
|
|
|
return s_idx
|
|
|
|
|
|
|
|
|
|
def setRandomSeed(self,rs):
|
|
seed(rs)
|
|
|
|
|
|
|
|
def setBeamEnergy(self,E):
|
|
self.BeamEnergy=E*1e9
|
|
|
|
|
|
def getElement(self,ename):
|
|
|
|
if not self.Ring:
|
|
return None
|
|
|
|
if ename.replace('_','-') in self.ElementDB:
|
|
return self.ElementDB[ename.replace('_','-')]
|
|
else:
|
|
return None
|
|
|
|
def getElement_SN(self,SN):
|
|
|
|
# Returns a list of element classes, corresponding to the given SN
|
|
|
|
EL=self.listElement_SN(SN)
|
|
|
|
if not EL:
|
|
return None
|
|
|
|
CL=[]
|
|
for e in EL:
|
|
CL.append(self.getElement(e))
|
|
|
|
return CL
|
|
|
|
|
|
|
|
def getElement_TYPE(self,tn,bothIO=False):
|
|
|
|
# Returns a list of element classes, corresponding to the given SN
|
|
|
|
EL=self.listElement_TYPE(tn,bothIO=bothIO)
|
|
|
|
if not EL:
|
|
return None
|
|
|
|
CL=[]
|
|
for e in EL:
|
|
CL.append(self.getElement(e))
|
|
|
|
return CL
|
|
|
|
|
|
|
|
def listElement_SN(self,SN):
|
|
|
|
|
|
if not self.Ring:
|
|
return None
|
|
|
|
|
|
fam=[]
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
else:
|
|
if c.SN==SN:
|
|
fam.append(c.NAME)
|
|
if c.NAME in self.OverlapC.keys():
|
|
for oe in self.OverlapC[c.NAME]:
|
|
if oe.SN==SN:
|
|
fam.append(oe.NAME)
|
|
if c.SN=='MMAP':
|
|
if c.OVERLAP:
|
|
for oe in c.OVERLAP:
|
|
if oe[0]==SN:
|
|
fam.append(c.NAME.replace('MMAP',oe[0]))
|
|
|
|
|
|
return fam
|
|
|
|
|
|
def listElement_TYPE(self,tn, bothIO=False, cycled=False):
|
|
|
|
if not self.Ring:
|
|
return None
|
|
|
|
|
|
if cycled:
|
|
|
|
|
|
typ=[]
|
|
for c in self.Ring:
|
|
if type(c)!=str:
|
|
if c.TYPE==tn:
|
|
typ.append(c.NAME)
|
|
if c.NAME in self.OverlapC.keys():
|
|
for oe in self.OverlapC[c.NAME]:
|
|
if oe.TYPE==tn:
|
|
typ.append(oe.NAME)
|
|
|
|
#if bothIO and c.TYPE[0:-1]==tn:
|
|
# The third condition required for 'KIN' to be fine with 'KINJ'
|
|
if bothIO and c.TYPE[0:-1]==tn and c.TYPE[-1] in ['I','O']:
|
|
typ.append(c.NAME)
|
|
|
|
|
|
|
|
else:
|
|
typ=[]
|
|
for c in self.ElementDB.values():
|
|
if c.TYPE==tn:
|
|
typ.append(c.NAME)
|
|
#if bothIO and c.TYPE[0:-1]==tn:
|
|
# The third condition required for 'KIN' to be fine with 'KINJ'
|
|
if bothIO and c.TYPE[0:-1]==tn and c.TYPE[-1] in ['I','O']:
|
|
typ.append(c.NAME)
|
|
|
|
typ.sort()
|
|
|
|
return typ
|
|
|
|
|
|
def changeParameter(self,ename,key,value):
|
|
|
|
if ename.replace('_','-') in self.ElementDB:
|
|
c=self.ElementDB[ename.replace('_','-')]
|
|
exec('c.'+key+'=value')
|
|
|
|
|
|
def Pair(self,SN1,SN2,SN3=None):
|
|
# Find pairs of SN1 and SN2 (or SN3) elements, which are closest, and return a list
|
|
|
|
|
|
if not self.Ring:
|
|
return None
|
|
|
|
G1=self.getElement_SN(SN1)
|
|
G2=self.getElement_SN(SN2)
|
|
if SN3:
|
|
G3=self.getElement_SN(SN3)
|
|
G2=G2+G3
|
|
|
|
p=[]
|
|
for e1 in G1:
|
|
smin=10000
|
|
pc=[]
|
|
for e2 in G2:
|
|
if abs(e1.MS-e2.MS)<smin:
|
|
e2save=e2
|
|
smin=abs(e1.MS-e2.MS)
|
|
pc=[e1.NAME,e2save.NAME,smin]
|
|
p.append(pc)
|
|
|
|
'''
|
|
p=[]
|
|
for c in self.Ring:
|
|
if type(c)==str:
|
|
pass
|
|
else:
|
|
if c.SN==SN1:
|
|
smin=500
|
|
for d in self.Ring:
|
|
if type(d)==str:
|
|
pass
|
|
else:
|
|
if d.SN==SN2 or d.SN==SN3:
|
|
if abs(c.S-d.S)<smin:
|
|
dsave=d
|
|
smin=abs(c.S-d.S)
|
|
|
|
p.append([c.NAME,dsave.NAME,smin])
|
|
'''
|
|
|
|
|
|
|
|
return p
|
|
|
|
|
|
def Pair_TYPE(self,T1,T2,T3=None):
|
|
# Find pairs of TYPE1 and TYPE2 (or TYPE3) elements, which are closest, and return a list
|
|
|
|
if not self.Ring:
|
|
return None
|
|
|
|
G1=self.getElement_TYPE(T1)
|
|
G2=self.getElement_TYPE(T2)
|
|
if T3:
|
|
G3=self.getElement_TYPE(T3)
|
|
G2=G2+G3
|
|
|
|
p=[]
|
|
for e1 in G1:
|
|
smin=10000
|
|
pc=[]
|
|
for e2 in G2:
|
|
if abs(e1.MS-e2.MS)<smin:
|
|
e2save=e2
|
|
smin=abs(e1.MS-e2.MS)
|
|
pc=[e1.NAME,e2save.NAME,smin]
|
|
p.append(pc)
|
|
|
|
|
|
return p
|
|
|
|
|
|
|
|
def BPMplus(self,TYPE='BPM'):
|
|
|
|
# Overwrite TYPE property of the BPM at the end of arc
|
|
|
|
if not self.Ring:
|
|
return None
|
|
|
|
|
|
pa=self.Pair_TYPE('BEHO','BPMA')
|
|
|
|
for p in pa:
|
|
self.getElement(p[1]).TYPE=TYPE
|
|
|
|
|
|
|
|
def UndulatorName(self,InputFile=None):
|
|
|
|
if not InputFile:
|
|
print ('No input file is given')
|
|
return None
|
|
|
|
|
|
if not self.Ring:
|
|
print ('No layout')
|
|
return None
|
|
|
|
exec(open(InputFile).read(),globals())
|
|
print (Ulabel)
|
|
|
|
for c in self.Ring:
|
|
if type(c)!=str:
|
|
if c.SN=='UIND':
|
|
if c.SECTOR in [2,4,6,8,10,12]:
|
|
SS='S'
|
|
elif c.SECTOR in [3,7,11]:
|
|
SS='M'
|
|
else:
|
|
SS='L'
|
|
sector=str(c.SECTOR).zfill(2)
|
|
Nameb=deepcopy(c.NAME)
|
|
c.NAME='X'+sector+SS+Ulabel[c.SECTOR-1][0]+c.NAME[5:]
|
|
Ulabel[c.SECTOR-1].pop(0)
|
|
self.ElementDB[c.NAME]=self.ElementDB[Nameb]
|
|
|
|
class ElementBase:
|
|
def __init__(self,prop):
|
|
self.L=prop['L']
|
|
self.RL=prop['RL']
|
|
self.SN=prop['SN']
|
|
self.S=prop['S']
|
|
self.SANGLE=prop['SANGLE']
|
|
self.MS=prop['MS']
|
|
self.MANGLE=prop['MANGLE']
|
|
self.NAME=prop['NAME']+'0' # 3 digits to 4 digits for vacuum
|
|
self.SECTOR=prop['SECTOR']
|
|
self.GIRDER=prop['GIRDER']
|
|
self.TYPE=prop['TYPE']
|
|
self.INDEX=prop['INDEX']
|
|
self.APERTURE=None # Aperture is implemented if necessary
|
|
|
|
# Misalignment
|
|
if self.SN=='MBSC':
|
|
self.MAX=[0]*len(self.L) # Horizontal
|
|
self.MAY=[0]*len(self.L) # Vertical
|
|
self.MAR=0 # Rotation
|
|
else:
|
|
self.MAX=0 # Horizontal
|
|
self.MAY=0 # Vertical
|
|
self.MAR=0 # Rotation
|
|
|
|
|
|
class CommonLine(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.DX=prop['DX']
|
|
self.DY=prop['DY']
|
|
self.TL=prop['TL']
|
|
self.TANGLE=prop['TANGLE']
|
|
|
|
|
|
class Marker(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
|
|
self.SRC=''
|
|
|
|
class Monitor(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
|
|
|
|
class Drift(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.DNAME=prop['DNAME']
|
|
if 'RESERVE' in prop.keys():
|
|
self.RESERVE=prop['RESERVE']
|
|
|
|
class Dipole(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.ANGLE=prop['ANGLE']
|
|
self.E1=prop['E1']
|
|
self.E2=prop['E2']
|
|
self.K1=prop['K1']
|
|
if type(prop['L'])==list:
|
|
self.TL=prop['TL']
|
|
self.TANGLE=prop['TANGLE']
|
|
self.DX=prop['DX']
|
|
self.DY=prop['DY']
|
|
self.MDX=prop['MDX']
|
|
self.MDY=prop['MDY']
|
|
self.RFE=0.0 # Relative field error
|
|
self.RGE=0.0 # Relative gradient error in case of MBCF
|
|
|
|
|
|
def setStrength(self,k):
|
|
self.K1=k
|
|
|
|
def setKL(self,kl):
|
|
if type(self.L)==list:
|
|
return 0
|
|
self.K1=kl/self.L
|
|
|
|
|
|
def KL(self):
|
|
if type(self.L)==list:
|
|
return 0
|
|
return self.K1*self.L
|
|
|
|
|
|
|
|
class Quadrupole(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.K1=prop['K1']
|
|
if 'SKEW' in prop.keys():
|
|
self.SKEW=prop['SKEW']
|
|
else:
|
|
self.SKEW=0
|
|
self.RFE=0.0 # Relative field error
|
|
|
|
# Polarity of power supply, 1 is either bipolar or unipolar but positive K1
|
|
# -1 is unipolar and negative K1
|
|
# Default is 1. Needed only for MQUA and MSXT
|
|
# Experimental, 10.03.2022
|
|
self.POL=1
|
|
|
|
|
|
self.BDN='' # Name in the original opa file (QP1, QP2, etc.)
|
|
|
|
|
|
self.I=0 # Current attribute to work on the actual machine
|
|
|
|
def setStrength(self,k):
|
|
self.K1=k
|
|
|
|
|
|
def setKL(self,kl):
|
|
#Confusing... but the skew is zero-length and, in the BD pattern file, K1L is given.
|
|
if self.SKEW:
|
|
self.K1=kl
|
|
else:
|
|
self.K1=kl/self.L
|
|
|
|
|
|
def KL(self):
|
|
if self.SKEW:
|
|
return self.K1
|
|
else:
|
|
return self.K1*self.L
|
|
|
|
|
|
class Sextupole(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.K2=prop['K2']
|
|
self.RFE=0.0 # Relative field error
|
|
|
|
# Polarity of power supply, 1 is either bipolar or unipolar but positive K1
|
|
# -1 is unipolar and negative K1
|
|
# Default is 1. Needed only for MQUA and MSXT
|
|
# Experimental, 10.03.2022
|
|
self.POL=1
|
|
|
|
# Sextupole family
|
|
self.FAMILY=None
|
|
self.DAD=0
|
|
|
|
self.BDN='' # Name in the original opa file (SD1, SF1, etc.)
|
|
|
|
self.I=0 # Current attribute to work on the actual machine
|
|
|
|
def setStrength(self,k):
|
|
self.K2=k
|
|
#print ('bffsb',k)
|
|
|
|
def setKL(self,kl):
|
|
self.K2=kl/self.L
|
|
|
|
|
|
def KL(self):
|
|
return self.K2*self.L
|
|
|
|
|
|
class Octupole(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.K3L=prop['K3L']
|
|
self.RFE=0.0 # Relative field error
|
|
|
|
self.BDN='' # Name in the original opa file (OXX, OCY1, etc.)
|
|
|
|
self.I=0 # Current attribute to work on the actual machine
|
|
|
|
def setStrength(self,k):
|
|
self.K3L=k
|
|
|
|
def setKL(self,kl):
|
|
self.K3L=kl
|
|
|
|
def KL(self):
|
|
return self.K3L
|
|
|
|
|
|
class HKicker(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.HKICK=prop['KICK']
|
|
|
|
self.I=0 # Current attribute to work on the actual machine
|
|
|
|
# Polarity property, used only for MKIK
|
|
# Experimental, 28.11.2022
|
|
self.POL=None
|
|
|
|
|
|
def setStrength(self,k):
|
|
self.HKICK=k
|
|
|
|
def setKL(self,kl):
|
|
self.HKICK=kl
|
|
|
|
|
|
def KL(self):
|
|
return self.HKICK
|
|
|
|
|
|
class VKicker(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.VKICK=prop['KICK']
|
|
|
|
self.I=0 # Current attribute to work on the actual machine
|
|
|
|
def setStrength(self,k):
|
|
self.VKICK=k
|
|
|
|
def setKL(self,kl):
|
|
self.VKICK=kl
|
|
|
|
|
|
def KL(self):
|
|
return self.VKICK
|
|
|
|
|
|
class Multipole(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
self.K2L=0
|
|
self.K3L=0
|
|
self.K4L=0
|
|
self.K5L=0
|
|
|
|
self.TARGET=prop['TARGET']
|
|
|
|
def setStrength(self,n,k):
|
|
if n==2:
|
|
self.K2L=k
|
|
if n==3:
|
|
self.K3L=k
|
|
if n==4:
|
|
self.K4L=k
|
|
if n==5:
|
|
self.K5L=k
|
|
|
|
|
|
|
|
class FieldMap:
|
|
# Experimental class for importing field map within the framework of trap by Bernard
|
|
def __init__(self,prop):
|
|
self.FILENAME=prop['FILENAME'].lower()
|
|
self.NAME=prop['NAME']
|
|
|
|
self.SN='MMAP'
|
|
self.APERTURE=None
|
|
self.MAX=0 # Horizontal
|
|
self.MAY=0 # Vertical
|
|
self.MAR=0 # Rotation
|
|
|
|
|
|
self.L=prop['L']
|
|
self.TL=prop['TL']
|
|
self.STRENGTH=prop['STRENGTH']
|
|
self.RL=prop['RL']
|
|
self.S=prop['S']
|
|
self.SANGLE=prop['SANGLE']
|
|
self.MS=prop['MS']
|
|
self.MANGLE=prop['MANGLE']
|
|
self.NAME=prop['NAME']+'0' # 3 digits to 4 digits for vacuum
|
|
self.SECTOR=prop['SECTOR']
|
|
self.GIRDER=prop['GIRDER']
|
|
self.TYPE=prop['TYPE']
|
|
self.INDEX=prop['INDEX']
|
|
|
|
self.ANGLE=prop['ANGLE']
|
|
self.RFE=0.0
|
|
self.RGE=0.0
|
|
|
|
if 'FMOVERLAP' in prop.keys():
|
|
self.OVERLAP=prop['FMOVERLAP']
|
|
else:
|
|
self.OVERLAP=None
|
|
|
|
# 23.06.2022. Experimental to include cavities to Master layout
|
|
class Cavity(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
if 'RESERVE' in prop.keys():
|
|
self.RESERVE=prop['RESERVE']
|
|
|
|
|
|
class Collimator(ElementBase):
|
|
def __init__(self, prop):
|
|
ElementBase.__init__(self,prop)
|
|
# 1-m open gap
|
|
self.HGAP=1.0
|
|
self.VGAP=1.0
|
|
|