initial copy of files from /psi.ch/project/SLS2/BD/OnlineModel/ after talking to Masamitsu

This commit is contained in:
2026-07-22 16:28:42 +02:00
parent 4fa30129c5
commit bee6c244e3
9 changed files with 7786 additions and 0 deletions
+532
View File
@@ -0,0 +1,532 @@
"""
import of M.Aiba's OnlineModel to tracy-null via the general tracy-null dictionary statement parser
draft version from July 21 by Bernard Riemann.
This version is only kept as a 'snapshot', as Masamitsu will modify and adapt it as the model develops.
the main function to be used is: onlinemodel_to_statements
Further Notes:
the onlinemodel reader, onlinemodel_to_statements, returns only a list of dictionaries.
The dictionaries are understood by the general tracy-null input parser
(the conversion into the c tracy lattice happens in the function trap/readers.py : push_family,
note that push_family should not be changed too much, as a reinstall/update of tracy in the environment is required for changes to take effect)
if it is problematic to load OMFacility on Merlin or you want to sahre the results with someone who dont uses the OMFacility, you can export the statement list of dictionaries into .json format (see data/sls2/b068/import.ipynb for examples). Another person can then load the dictionaries again from json and import
"""
from OMFacility import *
#exec(open('/afs/psi.ch/project/SLS2/BD/OnlineModel/OMFacility.py').read())
from trap.trapc import LatticeType # from c module, see trap/src/main.cpp or tracy/src/*.{cc,h}
from trap.readers import check_stadict, replace_subsequence # see trap/readers.py
from numpy import deg2rad
from warnings import warn
from copy import copy, deepcopy
def ocell_to_dict(ocell, include_markers=False) -> list:
"""
for a given cell in the OMFacility.Facility, return a list of statements.
if ocell.APERTURE is defined, aperture information is included (aper.. keys)
Typically, there is only one entry in the list.
But sometimes, elements are ignored (no entries) or have more than one statement (like step-wise bends, MBSC)
returned dicts are input for the tracy-null python parser
"""
otype = ocell.SN
# note: not using round(ocell.L, 6) gives only ~2micron total length diff to elegant
# Sign of 'roll' to be checked, i.e., consistency among elegant, MADX and tracy...
if otype=='MMAP':
outdict = {'name': ocell.NAME,
'dx': ocell.MAX, 'dy': ocell.MAY, 'roll': ocell.MAR}
elif otype=='DRIF':
outdict = {'name': ocell.NAME, 'length': ocell.L,
'dx': 0, 'dy': 0, 'roll': 0}
elif otype in ('RCAV','R3HC'):
outdict = {'name': ocell.NAME, 'length': ocell.L,
'dx': 0, 'dy': 0, 'roll': 0}
else:
outdict = {'name': ocell.NAME, 'length': ocell.L,
'dx': ocell.MAX, 'dy': ocell.MAY, 'roll': ocell.MAR}
# note: RFE and RGE are only used internally for parsing the OM file. they are not themselves propagated through tracy, although their effects in multipole strengths are considered
try:
outdict['RFE'] = ocell.RFE
except AttributeError:
pass
try:
outdict['RGE'] = ocell.RGE
except AttributeError:
pass
if ocell.APERTURE is not None:
try:
aperxa, aperya, shp = ocell.APERTURE
# for the moment, shp='E' elliptical is treated like rectangular 'R'
outdict.update({'aperxa': aperxa, 'aperya': aperya})
except ValueError:
# 4 entries instead of 3
aperx, apery, shp, shpa = ocell.APERTURE
if shpa=='+x':
outdict['aperxp'] = aperx
elif shpa=='-x':
outdict['aperxn'] = aperx
elif shpa=='+y':
# if aperyp is defined here, it will be understood by the tracy parser
raise NotImplementedError
elif shpa=='-y':
# if aperyn is defined here, it will be understood by the tracy parser
raise NotImplementedError
else:
raise SyntaxError('aperture specification not understood')
if otype=='DRIF':
outdict['etype'] = 'drift'
elif otype in ('RCAV','R3HC'):
outdict['etype'] = 'drift'
elif otype=='MMAP':
# Only MQCO implemented for the moment. 19.07.2022
# Update to include more
Qrange=None
SQrange=None
Srange=None
Orange=None
dk=0
dks=0
if ocell.OVERLAP:
for oe in ocell.OVERLAP:
if oe[0]=='MQCO':
Qrange=range(oe[1],oe[1]+oe[2])
dk=oe[3]
if oe[0]=='MQSK':
SQrange=range(oe[1],oe[1]+oe[2])
dks=oe[3]
if oe[0]=='MSXT':
Srange=range(oe[1],oe[1]+oe[2])
dk2=oe[3]
if oe[0]=='MOCT':
Orange=range(oe[1],oe[1]+oe[2])
dk3=oe[3]/(oe[2]*0.001)
if ocell.RGE or dk or dks:
fin=open(ocell.FILENAME,'r')
fout=open(ocell.FILENAME+'.'+ocell.NAME,'w')
il=0
for line in fin:
sline=line.split()
if len(sline)>10:
k1p=float(sline[10]) # k1 value without field error
k1n=k1p*(1+ocell.RGE)
k03p=float(sline[6])
k03n=k03p*(1+ocell.RGE) # Sextupole and quadrupole gradient error will be the same... let's accept it
k21p=float(sline[16])
k21n=k21p*(1+ocell.RGE)
k13p=float(sline[12])
k13n=k13p*(1+ocell.RGE) # The same for octupole
k31p=float(sline[22])
k31n=k31p*(1+ocell.RGE)
if Qrange:
if il in Qrange:
k1n=k1n+dk
sline[10]=str(k1n)
if SQrange:
if il in SQrange:
# Factor of 1/2, not clear why needed...
sline[15]=str(dks/2)
if Srange:
if il in Srange:
k21n=k21n+dk2
k03n=k03n-dk2/3.0
sline[6]=str(k03n)
sline[16]=str(k21n)
if Orange:
if il in Orange:
k13n=k13n-dk3
k31n=k31n+dk3
sline[12]=str(k13n)
sline[22]=str(k31n)
wline='len'
for si in range(1,len(sline)):
wline=wline+' '+sline[si]
wline=wline+'\n'
il=il+1
else:
wline=line
fout.write(wline)
fin.close()
fout.close()
tfile=ocell.FILENAME+'.'+ocell.NAME
else:
tfile=ocell.FILENAME
outdict['etype']='magtubefile'
outdict['filename']= tfile
#fgt=open(ocell.FILENAME,'r')
#for line in fgt:
# if 'driftlen' in line:
# sline=line.split()
#fgt.close()
# The following is experimental. 10.11.2021
# enclose in kick
kick_name = outdict['name']+'_E'
kick_elem = {'name': kick_name, 'etype': 'corrector', 'k0l': -deg2rad(ocell.ANGLE)*ocell.RFE/2}
# trick: when only a name(string) like kick_name is passed as a list element,
# it is agreed for onlinemodel_to_statements function,
# that it will just append the name to the sequence, not defining a new element
return [kick_elem, check_stadict(outdict), kick_name]
elif otype=='UIND':
print (ocell.NAME,ocell.L)
#outdict['etype'] = 'drift'
outdict.update({'etype': 'bend', 'angle': 0, 'k1': 0, 'e1': 0, 'e2': 0})
elif otype in ('MBEN', 'MBCF'):
k1 = ocell.K1*(1+ocell.RGE) if otype=='MBCF' else 0
outdict.update({'etype': 'bend', 'angle': deg2rad(ocell.ANGLE), 'k1': k1,
'e1': deg2rad(ocell.E1), 'e2': deg2rad(ocell.E2)})
# enclose in kick
kick_name = outdict['name']+'_E'
kick_elem = {'name': kick_name, 'etype': 'corrector', 'k0l': -outdict['angle']*ocell.RFE/2}
# trick: when only a name(string) like kick_name is passed as a list element,
# it is agreed for onlinemodel_to_statements function,
# that it will just append the name to the sequence, not defining a new element
return [kick_elem, check_stadict(outdict), kick_name]
elif otype=='MBSC':
# interpretation: multiple bends
outdict['etype'] = 'bend'
name = outdict.pop('name')
kick_name = name+'_E'
kick_elem = {'name': kick_name, 'etype': 'corrector', 'k0l': -deg2rad(ocell.TANGLE)*ocell.RFE/2}
# start sequence of elements with kick
li=[kick_elem]
# interior
lengths = outdict.pop('length') # it was a list of lengths
dxs = outdict.pop('dx')
dys = outdict.pop('dy')
for n, (length, angle, e1deg, e2deg, dx, dy) in enumerate(zip(lengths, ocell.ANGLE, ocell.E1, ocell.E2, dxs, dys)):
outdict.update({'name': f'{name}_{n}', 'length': length, 'angle': deg2rad(angle),
'e1': deg2rad(e1deg), 'e2': deg2rad(e2deg), 'dx': dx, 'dy': dy})
li.append(copy(check_stadict(outdict)))
# only kick_name string to end the list, see MBEN/MBCF entry
li.append(kick_name)
return li
elif otype=='MQUA':
outdict.update({'etype': 'quadrupole', 'k1': ocell.K1*(1+ocell.RFE)})
elif otype=='MQCO':
outdict.update({'etype': 'quadrupole', 'k1': ocell.K1*(1+ocell.RFE)})
elif otype=='MSXT':
outdict.update({'etype': 'sextupole', 'k2': ocell.K2*(1+ocell.RFE)})
elif otype=='MOCT':
outdict.update({'etype': 'sextupole', 'k3l': ocell.K3L*(1+ocell.RFE)})
elif otype in ('MCOX', 'MCOY'):
outdict['etype'] = 'corrector'
vertical = otype.endswith('Y')
length = outdict['length']
kick = ocell.VKICK if vertical else -ocell.HKICK
if length==0:
outdict['j0l' if vertical else 'k0l'] = kick
else:
outdict['j0' if vertical else 'k0'] = kick / length
elif otype in ('MKIK', 'MSEP'):
# interpretation: kicker set to zero
#outdict['etype'] = 'corrector'
#outdict['etype'] = 'drift'
#outdict['etype'] = 'corrector'
outdict.update({'etype': 'bend', 'angle': 0, 'k1': 0, 'e1': 0, 'e2': 0})
elif otype=='DBPM':
outdict['etype'] = 'monitor'
elif otype=='VCOL':
outdict['etype'] = 'drift'
elif otype=='NONE':
if outdict['length']==0.0:
return []
# interpretation: just treat it as a drift with length ocell.L (already in outdict)
outdict['etype'] = 'drift'
elif otype in ('GMRK', 'GSRC'):
if include_markers:
return [{'name': outdict['name'], 'etype': 'marker'}] #every other thing (apertures etc.) ignored
else:
return []
elif otype in ('EMALIGN', 'EWATCH'):
return [] #ignored
else:
#outdict.update({'etype': 'NOT IMPL'})
raise NotImplementedError(f'{otype = }, {ocell = }')
return [check_stadict(outdict)] # when you arriive here, list has only one entry
# for aperture settings, see OMFacility.Facility.setAperture()
def onlinemodel_to_statements(omf, cavity: int, undulator_spaces: bool):
"""
convert an instance omf of OMFacility.Facility into a list of statement-dictionaries, that can be read as input to the tracy-null parser
uses aperture information if it was set in onlinemodel by .setApertures
cavity: toggles inclusion of predefined cavity into sequence
undulator_spaces: toggles inclusion of predefined cavity into sequence
"""
statements = list() # a list of statement dictionaries
sequence = list() # names of elements
statements.append( {'name': 'energy', 'variable': '2.7'} ) # in every other place in this example, it can be a number instead of string..
usedDriftNames = dict() # to look up if a drift name has already been used
for ocell in omf.Ring:
if isinstance(ocell, str):
pass
else:
# basic statement parsing (no overlays and special drift treatments, but already step-wise bends):
new_statements = ocell_to_dict(ocell)
for stadict in new_statements:
if isinstance(stadict, str): #if list item is a string, just append it to sequence
sequence.append(stadict)
continue # skip the rest, to next iteration
name = stadict['name']
if stadict['etype']=='drift':
if name in usedDriftNames:
usedDriftNames[name] += 1
name = f'{name}_{usedDriftNames[name]}'
stadict['name'] = name
else:
usedDriftNames[name] = 0
# impose overlaps. Note: applied for any name that occurs in OverlapC, not just MQCO
if name in omf.OverlapC:
for ov_ocell in omf.OverlapC[name]:
# set additional skew quad (j1) or octupole (k3) strength of existing multipole
if ov_ocell.SN=='MQSK':
# assumption: skew quadrupole strength oe.k1*(..) is INTEGRATED strength j1*l like in OMElegant.py,
# is this a typo and should read .K1L similar to octupole?
#stadict['j1'] = ov_ocell.K1 * (1+stadict['RFE']) / stadict['length']
stadict['j1'] = ov_ocell.K1 * (1+ov_ocell.RFE) / stadict['length']
elif ov_ocell.SN=='MOCT':
stadict['k3'] = ov_ocell.K3L* (1+ov_ocell.RFE) / stadict['length']
# remove temporary entries
stadict.pop('RFE', 0.0)
stadict.pop('RGE', 0.0)
sequence.append(stadict['name'])
statements.append(stadict)
# now come some modifiers
if cavity>=0:
# the online model so far has no cavity, so it is appended manually here
#stadict = {'name': 'cav', 'etype': 'cavity',
# 'freq': 480*2.99792458e8/288.0, 'volt': 1.44e6, 'phase': deg2rad(151.8), 'h': 480}
# No phase entry/ Bernard's mail on 1.08.2021
stadict = {'name': 'cav', 'etype': 'cavity',
'freq': 480*2.99792458e8/288.0, 'volt': 1.44e6, 'h': 480}
statements.append(stadict)
sequence.insert(cavity, 'cav') # insert at beginning of list
if undulator_spaces: # use this before exporting to Simona for specific undulator locations
# BR: this is just an example for a single blank unulator space, i don't know the actual lengths
# note that the length of the replaced elements should match those of the new one
stadict = {'name': 'fancy_costly_undulator', 'etype': 'multipole', 'length': 1.23}
statements.append(stadict)
# this will throw a warning, as there is no element 'abcd' present in the sequence:
n = replace_subsequence(sequence, ('ARS08-DRIF-1970', 'abcd'), ('fancy_costly_undulator',))
print(f'{n} replacements for ' + stadict['name'])
# here i added keys for k1 (quadruople), j1 (skew quadrupole) and k3 (octupole)
stadict = {'name': 'cheap_undulator', 'etype': 'multipole', 'length': 4.56,
'k1': 0.2, 'j1': 89.7, 'k3': 42.0}
statements.append(stadict)
# this will show 1 replacement
n = replace_subsequence(sequence, ('ARS01-MKIK-0140', 'ARS01-DRIF-0140_1'), ('cheap_undulator',))
print(f'{n} replacements for ' + stadict['name'])
# sequence is just packed as a statement an appended
statements.append( {'name': 'ring', 'sequence': sequence} )
return statements
def get_onlinemodel(masterfile: str, PF: dict, Aperture: bool):
# its just the things you normally do with onlinemodel
# this needs to be executed in your onlinemodel folder.
# (idea for future: make OMFacility a module that can be installed in environment)
omf=Facility(masterfile)
#if omf.Version!=PF['Pversion'].upper():
# print (omf.Version)
# print (Pversion.upper())
# raise Exception('Version of Master layout and Pattern file does not match.')
omf.TracyFM=True
omf.Layout('full',-1) # StrPat is for the ring with no cycle. CYCLE marker appears with a switch of -1 (or any negtive int)
StrPat={}
Tdone=[]
for k in PF['Pattern'].keys():
StrPat[k]=[]
for e in PF['Pattern'][k]:
print (e)
StrPat[k].append(PF['Strength'][e])
if e not in Tdone:
Tdone.append(e)
for k in PF['Strength'].keys():
if k not in Tdone:
StrPat[k]=PF['Strength'][k]
del(StrPat['MKIK'])
omf.setStrength(StrPat)
if Aperture:
print('using aperture')
omf.setAperture(Aperture)
return omf
def replace_elems(omf, sub_sequence: list, replace_with: list):
# replace routine as in trap.readers but specifically for 'statements' that is generated through this OM2TN module
# defs is the definition of elements that are in replace_with
compatible=0
for i in range(0,len(omf.Ring)):
if type(omf.Ring[i])==str:
# Assumed that the first element of sub_sequence is not CYCLE
pass
elif omf.Ring[i].NAME==sub_sequence[0]:
s_idx=i
for j in range(1,len(sub_sequence)):
if omf.Ring[i+j].NAME==sub_sequence[j]:
compatible=1
else:
compatible=0
break
if not compatible:
raise Exception('Sub-sequence does not match to OMF layout')
omf.Ring=omf.Ring[0:s_idx]+replace_with+omf.Ring[s_idx+len(sub_sequence):]
return omf
def FieldMapLengthCorrection(omf):
# The length of the field map is shorter by a half step size in tracy-null.
# If self.get_onlinemodel is used (or Facility instance is geneerated with omf.TracyFM=True)
# this missing length is adjusted by Facility.individuateS2.
# If not, this routine needs to be called.
if not omf.Ring:
return None
imap=[]
for i in range(0,len(omf.Ring)):
c=omf.Ring[i]
if type(c)==str:
pass
else:
if c.SN=='MMAP':
if c.RL:
imap.append(i)
while imap:
c=omf.Ring[imap[-1]]
pr1={}
pr1['L']=abs(c.RL)
pr1['RL']=0
pr1['SN']='DRIF'
pr1['NAME']=c.NAME.replace('MMAP','DRIF')
pr1['INDEX']=c.INDEX
pr1['TYPE']='DRIFT'
pr1['DNAME']='DR'+c.TYPE # Name that appears in OPA file
pr1['S']=c.S-abs(c.RL) # Is that correct? not c.S? The same is in OMFacility...
pr1['MS']=c.S-abs(c.RL)/2
pr1['SANGLE']=c.SANGLE
pr1['MANGLE']=c.SANGLE
pr1['SECTOR']=c.SECTOR
pr1['GIRDER']=c.GIRDER
pr1['RESERVE']=1
pr2=deepcopy(pr1)
pr2['S']=c.S+c.TL # Is that correct? -c.RL might be missing? The same is in OMFacility...
pr2['MS']=pr2['S']+c.RL/2
pr2['RESERVE']=1
if 'ANGLE' in c.__dict__.keys():
pr2['SANGLE']=c.SANGLE+c.ANGLE
else:
pr2['SANGLE']=c.SANGLE
if c.RL<0:
drif=Drift(pr1)
omf.Ring.insert(imap[-1],drif)
else:
drif=Drift(pr2)
omf.Ring.insert(imap[-1]+1,drif)
imap.pop(-1)
return omf
Executable
+452
View File
@@ -0,0 +1,452 @@
import os
from math import *
import numpy as np
import sys
Energy = 2.7e9
HarmNumber = 480
RFVoltage = 1.44e6
RFVoltage_3HC = 0.375e6
DriftPass = "'DriftPass'"
BendPass = "'BndMPoleSymplectic4Pass'"
QuadPass = "'StrMPoleSymplectic4Pass'"
SextPass = "'StrMPoleSymplectic4Pass'"
# OctPass = "'StrMPoleSymplectic4Pass'"
OctPass = "'ThinMPolePass'"
MultipolePass = "'ThinMPolePass'"
RcavPass = "'RFCavityPass'"
R3HCPass = "'DriftPass'"
class AcceleratorToolbox():
def __init__(self):
pass
def openFile(self,name='SLS2.m'):
self.fout=open(name,'w')
def closeFile(self):
self.fout.close()
def write(self,line):
line=line+'\n'
self.fout.write(line)
def appendMisalignments(self,transErrors,name,dx,dy,tilt):
transErrors['name'].append(name)
transErrors['dx'].append(str(dx))
transErrors['dy'].append(str(dy))
transErrors['tilt'].append(str(tilt))
def defineSequence(self,S2,Radiation=0,Aperture=0,RF=0):
# Input is an instance of OMFacility.Facility
if Aperture:
cnow=Aperture['Nominal']
RingA=[cnow]
for c in S2.Ring:
if type(c)==str:
pass
elif c.SN[0]=='E':
RingA.append(c)
elif cnow!=c.APERTURE:
cnow=c.APERTURE
RingA.append(cnow)
RingA.append(c)
else:
RingA.append(c)
else:
RingA=S2.Ring
d2r=pi/180.0
Drift={}
seq=[]
transErrors = {'name': [], 'dx': [], 'dy': [], 'tilt': []}
cir=0
Iap=1
self.write("function RING = SLS2")
self.write("RING = {...")
for index,c in enumerate(RingA):
if type(c)==str:
pass
elif type(c)==list:
Name='APERTURE'+str(Iap)
seq.append(Name)
Iap=Iap+1
if c[0]==None:
xm=0.05
else:
xm=c[0]
if c[1]==None:
ym=0.05
else:
ym=c[1]
if c[2]=='E' or c[2]=='e':
ell='1'
else:
ell='0'
if len(c)==4:
wline=Name.replace('-','_')+' : MAXAMP, X_MAX= '+str(xm) \
+', Y_MAX= '+str(ym)+', ELLIPTICAL= '+str(ell)+', OPEN_SIDE= '+str(c[3])
else:
wline=Name.replace('-','_')+' : MAXAMP, X_MAX= '+str(xm) \
+', Y_MAX= '+str(ym)+', ELLIPTICAL= '+str(ell)
self.write(wline)
elif c.SN=='EMALIGN':
wline=c.NAME+"atmarker('malign');"
self.write(wline)
seq.append(c.NAME)
elif c.SN=='EWATCH':
wline="atmarker('WATCH');"
self.write(wline)
seq.append(c.NAME)
elif c.SN=='DSCR' or c.SN=='GMRK' or c.SN=='GSRC' or c.SN=='DICT':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline="atmarker('"+elemName+"','Type','"+typeName+"','SN','"+c.SN+"');..."
self.write(wline)
seq.append(elemName)
elif c.SN=='DRIF':
if c.NAME in Drift.keys():
Name=c.NAME+'_'+str(Drift[c.NAME])
Drift[c.NAME]=Drift[c.NAME]+1
else:
Name=c.NAME
Drift[c.NAME]=1
elemName = Name.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline="atdrift('"+elemName+"',"+str(round(c.L,6))+",'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='RCAV':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline="atrfcavity('"+elemName+"',"+str(round(c.L,6))+","+str(RFVoltage)+",500e6,480,"+str(Energy)+",'TimeLag',0,'Type','"+typeName+"','SN','"+c.SN+"'"+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='R3HC':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline="atdrift('"+elemName+"',"+str(round(c.L,6))+",'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='MBEN' or c.SN=='MBCF':
if c.SN=='MBCF':
k1=c.K1*(1+c.RGE)
else:
k1=0
if c.TYPE=='SVBI':
print(c.K1)
print(c.NAME)
print(index)
if c.TYPE=='DCSYIN1' or c.TYPE=='DCSYIN2':
c.NAME = c.NAME.replace('MBEN','MSEP')
elemName_E = c.NAME.replace('-','_')+"_E"
typeName = c.TYPE.replace('-','_')+"_E"
wline = "atcorrector('"+elemName_E+"',0,["+str(d2r*c.ANGLE*c.RFE/2)+" 0],'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName_E)
if c.NAME in S2.OverlapC:
elemName = c.NAME.replace('-','_')+"_1" #name of the element
typeName = c.TYPE.replace('-','_')
wline="atsbend('"+elemName+"',"+str(round(c.L/2,6))+','+str(d2r*c.ANGLE/2)+","+str(k1)+", 'EntranceAngle',"+str(d2r*c.E1)+", 'ExitAngle',0,'PolynomB',[0 "+str(k1)+" 0 0], 'MaxOrder',4,'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
self.appendMisalignments(transErrors,elemName,c.MAX,c.MAY,-c.MAR)
seq.append(elemName)
oe = S2.OverlapC[c.NAME][0]
elemNameOE = oe.NAME.replace('-','_')
typeNameOE = oe.TYPE.replace('-','_')
wline="atmarker('"+elemNameOE+"','Type','"+typeNameOE+"','SN','"+oe.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemNameOE)
elemName = c.NAME.replace('-','_')+"_2" #name of the element
typeName = c.TYPE.replace('-','_')
wline="atsbend('"+elemName+"',"+str(round(c.L/2,6))+','+str(d2r*c.ANGLE/2)+","+str(k1)+", 'EntranceAngle',0, 'ExitAngle',"+str(d2r*c.E2)+",'PolynomB',[0 "+str(k1)+" 0 0], 'MaxOrder',4,'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
self.appendMisalignments(transErrors,elemName,c.MAX,c.MAY,-c.MAR)
seq.append(elemName)
else:
elemName = c.NAME.replace('-','_') #name of the element
typeName = c.TYPE.replace('-','_')
wline="atsbend('"+elemName+"',"+str(c.L)+','+str(d2r*c.ANGLE)+","+str(k1)+",'EntranceAngle',"+str(d2r*c.E1)+", 'ExitAngle',"+str(d2r*c.E2)+",'PolynomB',[0 "+str(k1)+" 0 0], 'MaxOrder',4,'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
self.appendMisalignments(transErrors,elemName,c.MAX,c.MAY,-c.MAR)
seq.append(elemName)
"""
# Minus sign for c.MAR is to be consistent with
elemName = c.NAME.replace('-','_') #name of the element
typeName = c.TYPE.replace('-','_')
wline=elemName+" = atsbend('"+elemName+"','Length',"+str(round(c.L,6))+',... \n' \
+" 'BendingAngle'," +str(d2r*c.ANGLE)+", 'EntranceAngle',"+str(d2r*c.E1)+", 'ExitAngle',"+str(d2r*c.E2)+',... \n' \
+" 'PolynomB',[0,"+str(k1)+",0,0], 'MaxOrder',4,'PassMethod',"+BendPass+",'Type','"+typeName+"','SN','"+c.SN+"');"
self.write(wline)
self.appendMisalignments(transErrors,elemName,c.MAX,c.MAY,-c.MAR)
seq.append(elemName)
"""
seq.append(elemName_E)
cir=cir+c.L
elif c.SN=='MBSC':
if hasattr(c,'k1'):
k1 = c.k1;
else:
k1 = 0
elemName_E = c.NAME.replace('-','_')+"_E"
typeName = c.TYPE.replace('-','_')+"_E"
wline = "atcorrector('"+elemName_E+"',0,["+str(d2r*c.TANGLE*c.RFE/2)+" 0],'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(c.NAME.replace('-','_')+'_E')
for i in range(0,floor(len(c.L)/2)):
elemName = c.NAME.replace('-','_')+'_'+str(i) #name of the element
typeName = c.TYPE.replace('-','_')
wline="atsbend('"+elemName+"',"+str(c.L[i])+"," +str(d2r*c.ANGLE[i])+","+str(k1)+",'EntranceAngle',"+str(d2r*c.E1[i])+", 'ExitAngle',"+str(d2r*c.E2[i])+",'PolynomB',[0 "+str(k1)+" 0 0], 'MaxOrder',4,'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
self.appendMisalignments(transErrors,elemName,c.MAX[i],c.MAY[i],-c.MAR)
seq.append(elemName)
oe = S2.OverlapC[c.NAME][0]
elemNameOE = oe.NAME.replace('-','_')
typeNameOE = oe.TYPE.replace('-','_')
wline="atmarker('"+elemNameOE+"','Type','"+typeNameOE+"','SN','"+oe.SN+"'"+",'Energy',"+str(Energy)+");"
self.write(wline)
seq.append(elemNameOE)
for i in range(floor(len(c.L)/2),len(c.L)):
elemName = c.NAME.replace('-','_')+'_'+str(i) #name of the element
typeName = c.TYPE.replace('-','_')
wline="atsbend('"+elemName+"',"+str(c.L[i])+','+str(d2r*c.ANGLE[i])+","+str(k1)+",'EntranceAngle',"+str(d2r*c.E1[i])+", 'ExitAngle',"+str(d2r*c.E2[i])+",'PolynomB',[0 "+str(k1)+" 0 0], 'MaxOrder',4,'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
self.appendMisalignments(transErrors,elemName,c.MAX[i],c.MAY[i],-c.MAR)
seq.append(elemName)
seq.append(elemName_E)
cir=cir+c.TL
elif c.SN=='UIND':
elemName = c.NAME.replace('-','_').replace('DRIF','UIND')
typeName = c.TYPE.replace('-','_')
if c.NAME in S2.OverlapC:
wline1="atdrift('"+elemName+"',"+str(round(c.L/2,6))+",'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline1)
seq.append(elemName)
oe = S2.OverlapC[c.NAME][0]
elemNameOE = oe.NAME.replace('-','_')
typeNameOE = oe.TYPE.replace('-','_')
wline="atmarker('"+elemNameOE+"','Type','"+typeNameOE+"','SN','"+oe.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
wline="atdrift('"+elemName+"',"+str(round(c.L/2,6))+",'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemNameOE)
seq.append(elemName)
else:
wline="atdrift('"+elemName+"',"+str(round(c.L,6))+",'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='MQUA':
k1 = c.K1*(1+c.RFE)
elemName = c.NAME.replace('-','_') #name of the element
typeName = c.TYPE.replace('-','_')
wline="atquadrupole('"+elemName+"',"+str(round(c.L,6))+","+str(k1)+",'MaxOrder',4,'PolynomB',[0 "+str(k1)+" 0 0],'Type','"+typeName+"','SN','"+c.SN+"','BDN','"+c.BDN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(c.NAME.replace('-','_'))
self.appendMisalignments(transErrors,elemName,c.MAX,c.MAY,-c.MAR)
cir=cir+c.L
elif c.SN=='MQCO':
k1 = c.K1*(1+c.RFE)
elemName = c.NAME.replace('-','_')+'_1'
typeName = c.TYPE.replace('-','_')+'_1'
wline="atquadrupole('"+elemName+"',"+str(round(c.L/2,6))+","+str(k1)+",'MaxOrder',4,'PolynomB',[0 "+str(k1)+" 0 0],'Type','"+typeName+"','SN','"+c.SN+"','BDN','"+c.BDN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
self.appendMisalignments(transErrors,elemName,str(c.MAX),str(c.MAY),str(-c.MAR))
for oe in S2.OverlapC[c.NAME]:
elemName = oe.NAME.replace('-','_')
typeName = oe.TYPE.replace('-','_')
if oe.SN=='MQSK':
tl=-0.78539816339744828-c.MAR
# Need to check the sign of tilt
wline = "atmultipole('"+elemName+"',0,[0 0 0 0 0],[0 "+str(oe.K1*(1+oe.RFE))+" 0 0],'PassMethod',"+MultipolePass+",'Type','"+typeName+"','SN','"+oe.SN+"','BDN','"+oe.BDN+"'"+",'Energy',"+str(Energy)+");..."
elif oe.SN=='MOCT':
wline = "atmultipole('"+elemName+"',0,[0 0 0 0 0],[0 0 0 "+str(oe.K3L*(1+oe.RFE))+"],'PassMethod',"+MultipolePass+",'MaxOrder',5,'Type','"+typeName+"','SN','"+oe.SN+"','BDN','"+oe.BDN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
self.appendMisalignments(transErrors,elemName,str(c.MAX),str(c.MAY),str(-c.MAR))
elemName = c.NAME.replace('-','_')+'_2'
typeName = c.TYPE.replace('-','_')+'_2'
wline="atquadrupole('"+elemName+"',"+str(round(c.L/2,6))+","+str(k1)+",'MaxOrder',4,'PolynomB',[0 "+str(k1)+" 0 0],'Type','"+typeName+"','SN','"+c.SN+"','BDN','"+c.BDN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
self.appendMisalignments(transErrors,elemName,str(c.MAX),str(c.MAY),str(-c.MAR))
cir=cir+c.L
elif c.SN=='MSXT':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline="atsextupole('"+elemName+"',"+str(round(c.L,6))+","+str(c.K2*(1+c.RFE))+",'MaxOrder',4,'PolynomB',[0 0 "+str(c.K2*(1+c.RFE))+" 0],'Type','"+typeName+"','SN','"+c.SN+"','BDN','"+c.BDN+"'"+",'PSFamily','"+c.FAMILY+"','Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
self.appendMisalignments(transErrors,elemName,str(c.MAX),str(c.MAY),str(-c.MAR))
cir=cir+c.L
elif c.SN=='MCOX':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline = "atcorrector('"+elemName+"',"+str(round(c.L,6))+",["+str(c.HKICK)+" 0],'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='MCOY':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline = "atcorrector('"+elemName+"',"+str(round(c.L,6))+",[0 "+str(c.VKICK)+"],'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='MKIK' or c.SN=='MSEP':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline = "atcorrector('"+elemName+"',"+str(round(c.L,6))+",[0 0],'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='DBPM':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline = "atdrift('"+elemName+"',"+str(round(c.L,6))+",'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='VCOL':
elemName = c.NAME.replace('-','_')
typeName = c.TYPE.replace('-','_')
wline = "atdrift('"+elemName+"',"+str(round(c.L,6))+",'EApertures',[1 1],'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
elif c.SN=='NONE':
if c.NAME == 'ARS03-NONE-0380':
print(c.NAME)
print(c.TYPE)
print(c.L)
print(c.SN)
if c.L:
if c.NAME in Drift.keys():
Name=c.NAME+'_'+str(Drift[c.NAME])
typeName = c.TYPE.replace('-','_')+'_'+str(Drift[c.NAME])
Drift[c.NAME]=Drift[c.NAME]+1
else:
Name=c.NAME
Drift[c.NAME]=1
typeName = c.TYPE.replace('-','_')
elemName = Name.replace('-','_')
wline="atdrift('"+elemName+"',"+str(round(c.L,6))+",'Type','"+typeName+"','SN','"+c.SN+"'"+",'Energy',"+str(Energy)+");..."
self.write(wline)
seq.append(elemName)
cir=cir+c.L
else:
print ('Element unknown:',c.NAME,c.SN,c.L)
# wline='MAL: malign, on_pass=0, force_modify_matrix=0\n'
# self.write(wline)
# wline='W1: WATCH,MODE=parameter,FILENAME=monitor.w1\n'
# self.write(wline)
# wline='W2: WATCH,MODE=coordinate,FILENAME=monitor.w2, interval=1\n'
# self.write(wline)
# wline='RF1 : RFCA, L=0.0, FREQ=500e6, VOLT=1.44e6, PHASE=151, T_REFERENCE=0.0\n'
# self.write(wline)
# wline='RF3 : RFCA, L=0.0, FREQ=1500e6, VOLT=0.375e6, PHASE=0.0, T_REFERENCE=0.0\n'
# self.write(wline)
# wline = "RF1 = atrfcavity('RF1','Length',0,'Frequency',500e6,'Voltage',"+str(RFVoltage)+",'TimeLag',0.251492);"
# self.write(wline)
# seq.append('RF1')
# wline = "RF3 = atrfcavity('RF3','Length',0,'Frequency',1500e6,'Voltage',"+str(RFVoltage_3HC)+",'TimeLag',0.0);"
# self.write(wline)
# seq.append('RF3')
# wline = '\n %%%% Setting shifts %%%% \n'
#for i in range(0,len(transErrors['name'])):
#wline=wline+transErrors['name'][i]+'=atshiftelem('+transErrors['name'][i]+","+transErrors['dx'][i]+","+transErrors['dy'][i]+");\n"
#wline = '\n %%%% Setting tilts %%%% \n'
#for i in range(0,len(transErrors['name'])):
# wline=wline+transErrors['name'][i]+'=attiltelem('+transErrors['name'][i]+","+transErrors['tilt'][i]+");\n"
#self.write(wline)
#wline = 'RING = {...\n '
#for i in range(0,len(seq)):
#wline=wline+seq[i]+", "
#if i%5==0 and i!=len(seq)-1:
#wline=wline+'... \n '
#wline=wline[0:len(wline)-1]+"}';\n"
wline = '};\n'
#wline=wline+'RING = atsetenergy(RING,'+str(Energy)+');\n'
wline=wline+'RING = atsetRFCavity(RING,'+str(RFVoltage)+",1,"+str(HarmNumber)+",0);\n"
wline=wline+'RING = atSetRingProperties(RING);'
self.write(wline)
print ('cccccccccccc',cir)
class EMALIGN:
def __init__(self, prop):
self.SN='EMALIGN'
self.NAME=prop['Name']
class EWATCH:
def __init__(self, prop):
self.SN='EWATCH'
self.NAME=prop['Name']
self.MODE=prop['Mode']
self.FILENAME=prop['Filename']
self.INTERVAL=prop['Interval']
+183
View File
@@ -0,0 +1,183 @@
from math import *
from random import gauss, seed, random
from os import system
class BeamDynamics:
def __init__(self):
# SLS2 SR parameters (can be changed for the booster or other ring)
self.Circumference=288.0
self.BeamEnergy=2.7e9
self.Vrf=1.44e6
self.Vrf=1.75e6
self.frf=500e6
self.U0=688e3
self.alpha=1.05e-4
self.EnergySpread=1.16e-3
self.c=2.99792458e8
def BoosterParameter(self):
self.Circumference=270.0
self.BeamEnergy=2.7e9
self.Vrf=0.5e6
self.frf=500e6
self.U0=373e3
self.alpha=5e-3
self.EnergySpread=0.844e-3
def SLSparameter(self):
self.Circumference=288.0
self.BeamEnergy=2.4e9
self.Vrf=2.4e6
self.frf=500e6
self.U0=549e3
self.alpha=6e-4
self.EnergySpread=0.88e-3
def SynchronousPhase(self, Degree=False):
ph=asin(self.U0/self.Vrf)
if Degree:
ph=ph*180/pi
return ph
def SynchrotronTune(self):
phis=self.SynchronousPhase()
T0=self.Circumference/self.c
frev=1/T0
h=self.frf/frev
q2=h*self.alpha*self.Vrf*cos(phis)/2/pi/self.BeamEnergy
q=sqrt(q2)
return q
def BucketHeight(self):
phis=self.SynchronousPhase()
T0=self.Circumference/self.c
frev=1/T0
h=self.frf/frev
F2=cos(phis)-(pi-2*phis)/2*sin(phis)
b2=2*self.Vrf/pi/self.BeamEnergy/h/self.alpha*abs(F2)
b=sqrt(b2)
return b
def BunchLength(self,mm=True):
q=self.SynchrotronTune()
T0=self.Circumference/self.c
w=2*pi*q/T0
if mm:
bl=self.alpha*self.c*self.EnergySpread/w
else:
bl=self.alpha*self.c*self.EnergySpread/w/self.c
return bl
def generateBunch(self,InDic,File=None,Format='plain'):
# InDic keys are
# bx
# by
# ax
# ay
# ex: h emittance (m)
# ey
# l: bunch length (mm)
# d: energy spread(fractional)
# N: number of particle
bx=InDic['bx']
by=InDic['by']
ax=InDic['ax']
ay=InDic['ay']
ex=InDic['ex']
ey=InDic['ey']
d=InDic['d']
s=InDic['l']
Mx11=sqrt(bx)
Mx12=0.0
Mx21=-ax/sqrt(bx)
Mx22=1.0/sqrt(bx)
My11=sqrt(by)
My12=0.0
My21=-ay/sqrt(by)
My22=1.0/sqrt(by)
if File:
fout=open(File,'w')
else:
B=[]
for i in range(0,InDic['N']):
ph=2*pi*random()
amp=2*ex*log(1.0/(1.0-random()))
xt=sqrt(amp)*cos(ph)
xpt=sqrt(amp)*sin(ph)
x=Mx11*xt+Mx12*xpt
xp=Mx21*xt+Mx22*xpt
ph=2*pi*random()
amp=2*ey*log(1.0/(1.0-random()))
yt=sqrt(amp)*cos(ph)
ypt=sqrt(amp)*sin(ph)
y=My11*yt+My12*ypt
yp=My21*yt+My22*ypt
ph=2*pi*random()
amp=2*log(1.0/(1.0-random()))
ss=sqrt(s*1e-12*amp)*cos(ph)
p=sqrt(d*amp)*sin(ph)
if File:
wline=str(x)+' '+str(xp)+' '+str(y)+' '+str(yp)+' '+str(ss)+' '+str(p)+'\n'
fout.write(wline)
else:
B.append([x,xp,y,yp,ss,p])
if File:
fout.close()
else:
return B
return
+297
View File
@@ -0,0 +1,297 @@
import os
from math import *
import numpy as np
import sys
class Elegant():
def __init__(self):
pass
def openFile(self,name='SLS2.lat'):
self.fout=open(name,'w')
def closeFile(self):
self.fout.close()
def write(self,line):
line=line+'\n'
self.fout.write(line)
def defineSequence(self,S2,Radiation=0,Aperture=0,RF=0):
# Input is an instance of OMFacility.Facility
if Aperture:
cnow=Aperture['Nominal']
RingA=[cnow]
for c in S2.Ring:
if type(c)==str:
pass
elif c.SN[0]=='E':
RingA.append(c)
elif cnow!=c.APERTURE:
cnow=c.APERTURE
RingA.append(cnow)
RingA.append(c)
else:
RingA.append(c)
else:
RingA=S2.Ring
d2r=pi/180.0
Drift={}
seq=[]
cir=0
Iap=1
for c in RingA:
if type(c)==str:
pass
elif type(c)==list:
Name='APERTURE'+str(Iap)
seq.append(Name)
Iap=Iap+1
if c[0]==None:
xm=0.05
else:
xm=c[0]
if c[1]==None:
ym=0.05
else:
ym=c[1]
if c[2]=='E' or c[2]=='e':
ell='1'
else:
ell='0'
if len(c)==4:
wline=Name.replace('-','_')+' : MAXAMP, X_MAX= '+str(xm) \
+', Y_MAX= '+str(ym)+', ELLIPTICAL= '+str(ell)+', OPEN_SIDE= '+str(c[3])
else:
wline=Name.replace('-','_')+' : MAXAMP, X_MAX= '+str(xm) \
+', Y_MAX= '+str(ym)+', ELLIPTICAL= '+str(ell)
self.write(wline)
elif c.SN=='EMALIGN':
wline=c.NAME+': malign, on_pass=0, force_modify_matrix=0'
self.write(wline)
seq.append(c.NAME)
elif c.SN=='EWATCH':
wline=c.NAME+': WATCH,MODE='+c.MODE+',FILENAME='+c.FILENAME
self.write(wline)
seq.append(c.NAME)
elif c.SN=='DRIF':
if c.NAME in Drift.keys():
Name=c.NAME+'_'+str(Drift[c.NAME])
Drift[c.NAME]=Drift[c.NAME]+1
else:
Name=c.NAME
Drift[c.NAME]=1
wline=Name.replace('-','_')+' : EDRIFT, L= '+str(round(c.L,6))
self.write(wline)
seq.append(Name.replace('-','_'))
cir=cir+c.L
elif c.SN[0]=='R':
wline=c.NAME.replace('-','_')+' : EDRIFT, L= '+str(round(c.L,6))
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.L
elif c.SN=='MBEN' or c.SN=='MBCF':
if c.SN=='MBCF':
k1=c.K1*(1+c.RGE)
else:
k1=0
wline=c.NAME.replace('-','_')+'_E : EHKICK, L=0, Kick='+str(d2r*c.ANGLE*c.RFE/2)
self.write(wline)
# Minus sign for c.MAR is to be consistent with MADX definition
wline=c.NAME.replace('-','_')+' : CSBEND, L= '+str(c.L)+', &\n' \
+' ANGLE=' +str(d2r*c.ANGLE)+', E1 ='+str(d2r*c.E1)+', E2 ='+str(d2r*c.E2)+', &\n' \
+' K1 ='+str(k1)+', N_KICKS=10, INTEGRATION_ORDER=4, &\n' \
+' USE_RAD_DIST='+str(Radiation)+', ADD_OPENING_ANGLE='+str(Radiation)
#+' DX='+str(c.MAX)+', DY='+str(c.MAY)+', ETILT='+str(-c.MAR)+', &\n' \
self.write(wline)
seq.append(c.NAME.replace('-','_')+'_E')
seq.append(c.NAME.replace('-','_'))
seq.append(c.NAME.replace('-','_')+'_E')
cir=cir+c.L
elif c.SN=='MBSC':
wline=c.NAME.replace('-','_')+'_E : EHKICK, L=0, Kick='+str(d2r*c.TANGLE*c.RFE/2)
self.write(wline)
seq.append(c.NAME.replace('-','_')+'_E')
for i in range(0,len(c.L)):
wline=c.NAME.replace('-','_')+'_'+str(i)+' : CSBEND, L= '+str(c.L[i])+', &\n' \
+' ANGLE=' +str(d2r*c.ANGLE[i])+', E1 ='+str(d2r*c.E1[i])+', E2 ='+str(d2r*c.E2[i])+', &\n' \
+' K1 =0, N_KICKS=2, INTEGRATION_ORDER=4, &\n' \
+' USE_RAD_DIST='+str(Radiation)+', ADD_OPENING_ANGLE='+str(Radiation)
#+' DX='+str(c.MAX[i])+', DY='+str(c.MAY[i])+', ETILT='+str(-c.MAR)+', &\n' \
self.write(wline)
seq.append(c.NAME.replace('-','_')+'_'+str(i))
seq.append(c.NAME.replace('-','_')+'_E')
cir=cir+c.TL
elif c.SN=='UIND':
wline=c.NAME.replace('-','_').replace('DRIF','UIND')+' : EDRIFT, L= '+str(round(c.L,6))
self.write(wline)
seq.append(c.NAME.replace('-','_').replace('DRIF','UIND'))
cir=cir+c.L
elif c.SN=='MQUA':
wline=c.NAME.replace('-','_')+' : KQUAD, L= '+str(round(c.L,6))+',N_KICKS=10 , K1= '+str(c.K1*(1+c.RFE))+'\n' \
# +' DX='+str(c.MAX)+', DY='+str(c.MAY)+', TILT='+str(-c.MAR)
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.L
elif c.SN=='MQCO':
wline=c.NAME.replace('-','_')+'_1'+' : KQUAD, L= '+str(round(c.L/2,6))+',N_KICKS=4 , K1= '+str(c.K1*(1+c.RFE))+'\n'
# +' DX='+str(c.MAX)+', DY='+str(c.MAY)+', TILT='+str(-c.MAR)
self.write(wline)
seq.append(c.NAME.replace('-','_')+'_1')
for oe in S2.OverlapC[c.NAME]:
if oe.SN=='MQSK':
tl=-0.78539816339744828-c.MAR
# Need to check the sign of tilt
wline=oe.NAME.replace('-','_')+' : MULT, ORDER=1, L=0, TILT='+str(tl)+', KNL='+str(oe.K1*(1+c.RFE))+'\n'
#+' DX='+str(c.MAX)+', DY='+str(c.MAY)
self.write(wline)
seq.append(oe.NAME.replace('-','_'))
elif oe.SN=='MOCT':
wline=oe.NAME.replace('-','_')+' : MULT, ORDER=3, L=0, KNL='+str(oe.K3L*6*(1+c.RFE))+'\n'
#+' DX='+str(c.MAX)+', DY='+str(c.MAY)+', TILT='+str(-c.MAR)
self.write(wline)
seq.append(oe.NAME.replace('-','_'))
wline=c.NAME.replace('-','_')+'_2'+' : KQUAD, L= '+str(round(c.L/2,6))+',N_KICKS=4 , K1= '+str(c.K1*(1+c.RFE))+'\n'
#+' DX='+str(c.MAX)+', DY='+str(c.MAY)+', TILT='+str(-c.MAR)
self.write(wline)
seq.append(c.NAME.replace('-','_')+'_2')
cir=cir+c.L
elif c.SN=='MSXT':
wline=c.NAME.replace('-','_')+' : KSEXT, L= '+str(round(c.L,6))+',N_KICKS=8 , K2= '+str(c.K2*2*(1+c.RFE))+'\n'
# +' DX='+str(c.MAX)+', DY='+str(c.MAY)+', TILT='+str(-c.MAR)
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.L
elif c.SN=='MCOX':
wline=c.NAME.replace('-','_')+' : EHKICK, L= '+str(round(c.L,6))+', Kick='+str(c.HKICK)
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.L
elif c.SN=='MCOY':
wline=c.NAME.replace('-','_')+' : EVKICK, L= '+str(round(c.L,6))+', Kick='+str(c.VKICK)
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.L
elif c.SN=='MKIK' or c.SN=='MSEP':
wline=c.NAME.replace('-','_')+' : EHKICK, L= '+str(round(c.L,6))+', Kick=0'
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.L
elif c.SN=='DBPM':
wline=c.NAME.replace('-','_')+' : MONI, L= '+str(round(c.L,6))
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.L
elif c.SN=='VCOL':
wline=c.NAME.replace('-','_')+' : EDRIFT, L= '+str(round(c.L,6))
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.L
elif c.SN=='MMAP':
wline=c.NAME.replace('-','_')+' : BGGEXP'
self.write(wline)
seq.append(c.NAME.replace('-','_'))
cir=cir+c.TL
elif c.SN=='NONE':
if c.L:
if c.NAME in Drift.keys():
Name=c.NAME+'_'+str(Drift[c.NAME])
Drift[c.NAME]=Drift[c.NAME]+1
else:
Name=c.NAME
Drift[c.NAME]=1
wline=Name.replace('-','_')+' : EDRIFT, L= '+str(round(c.L,6))
self.write(wline)
seq.append(Name.replace('-','_'))
cir=cir+c.L
else:
print ('xxxxxxxxxxxxxx',c.NAME,c.SN,c.L)
wline='MAL: malign, on_pass=0, force_modify_matrix=0\n'
self.write(wline)
wline='W1: WATCH,MODE=parameter,FILENAME=monitor.w1\n'
self.write(wline)
wline='W2: WATCH,MODE=coordinate,FILENAME=monitor.w2, interval=1\n'
self.write(wline)
wline='RF1 : RFCA, L=0.0, FREQ=500e6, VOLT=1.44e6, PHASE=151, T_REFERENCE=0.0\n'
self.write(wline)
wline='RF3 : RFCA, L=0.0, FREQ=1500e6, VOLT=0.375e6, PHASE=0.0, T_REFERENCE=0.0\n'
self.write(wline)
if RF:
wline='RING : LINE=(MAL,RF1,RF3,W1,W2,'
else:
wline='RING : LINE=(MAL,W1,W2,'
for i in range(0,len(seq)):
wline=wline+seq[i]+','
if i%5==0 and i!=len(seq)-1:
wline=wline+' &\n'
wline=wline[0:len(wline)-1]+')'
self.write(wline)
print ('cccccccccccc',cir)
class EMALIGN:
def __init__(self, prop):
self.SN='EMALIGN'
self.NAME=prop['Name']
class EWATCH:
def __init__(self, prop):
self.SN='EWATCH'
self.NAME=prop['Name']
self.MODE=prop['Mode']
self.FILENAME=prop['Filename']
self.INTERVAL=prop['Interval']
+715
View File
@@ -0,0 +1,715 @@
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,)
+3081
View File
File diff suppressed because it is too large Load Diff
+1712
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
# To be developed?
class Aperture():
def __init__(self,S2):
self.S2=S2
+808
View File
@@ -0,0 +1,808 @@
import warnings
import math
import numpy as np
from time import sleep
class SLS2Magnet:
def __init__(self):
self.TF={}
# [PhysicalLength,MagneticLength,Imax,Ilin,b0,b1,b2,b3,R] # b1/R is the gradient at Imax.
# If Ilin = Imax, Ilin is not specified (Completely linear magnet)
# TF as in the hard edge model (OPA, MADX): Magnetic length needs to be updated.
# The reference radius R is to be updated as well.
# N.B. The coefficients b0...b3 are the values for the magnetic length self.TF[TYPE][1]
# Quadrupoles
#self.TF['QP'] = [0.1, 0.1, 70.0, 70.0, 0.0, 0.93, 0.0, 0.0, 10e-3] # B' = 93 T/m
#self.TF['QPH'] = [0.14, 0.14, 70.0, 70.0, 0.0, 0.98, 0.0, 0.0, 10e-3]
#self.TF['QA-SLS'] = [0.2, 0.2, 100.0, 100.0, 0.0, 0.232, 0.0, 0.0, 10e-3] # Imax? Assumed 100 A
# Quadrupoles, RC measurement , Average
self.TF['QP']=[0.1, 0.1, 70, 30, 0.0124054210164, 1.17036699272, -0.0365565108681, -0.170883350929, 0.01] # B' = 97.5 T/m
self.TF['QPH']=[0.14, 0.14, 70, 30, 0.0102827462421, 1.17181174371, -0.011395413075, -0.159266318031, 0.01] # B' = 101 T/m
self.TF['QA-SLS']=[0.2, 0.2, 140, 60, 0.00136432203379, 0.27820143007, 0.0176124050321, -0.0382317191743, 0.01]
# Quad TF for individual magnets, RC measurements. The fitting parameters were optimized for the design KL.
# QA-SLS. PS is 200A but it is limited by 140 A because the masurement is up to 140 A.
self.TF['ARS01-MQUA-0550']=[0.2, 0.2, 140, 100, 0.00488, 0.2713445, -0.0049465, -0.012803, 0.01] # QA-SLS, Iop ~100 A
self.TF['ARS01-MQUA-0630']=[0.2, 0.2, 140, 80, 0.002286, 0.2762515, -0.00340875, -0.00876825, 0.01] # QA-SLS, Iop ~90 A
self.TF['ARS01-MQUA-0710']=[0.2, 0.2, 140, 60, 0.001557, 0.27769, 0.00252044992238, -0.0149713056857, 0.01] # QA-SLS, Iop ~70 A
self.TF['ARS01-MQUA-0790']=[0.2, 0.2, 140, 80, 0.00225, 0.275947, -0.002493, -0.0102735, 0.01] # QA-SLS, Iop ~80 A
# QPQPH
self.TF['ARS01-MQUA-1050']=[0.14, 0.14, 70, 20, 0.0079816469117, 1.18426791131, 0.0607856512304, -0.240357941024, 0.01] # QPHI, Iop ~7.7 A
self.TF['ARS01-MQUA-1150']=[0.14, 0.14, 70, 20, 0.00780358419145, 1.18327391369, 0.0592729332282, -0.237078966931, 0.01] # QPHI, Iop ~9.0 A
self.TF['ARS01-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0247799757689, 1.13441076405, -0.12621890086, -0.0593464732633, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS01-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00848221658502, 1.18858462161, 0.053299271752, -0.27387803496, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS01-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00889372897434, 1.18708702888, 0.0468748602597, -0.268231245943, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS01-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0260260881338, 1.13154607743, -0.126546336342, -0.0570747831374, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS01-MQUA-5840']=[0.14, 0.14, 70, 40, 0.0211814862285, 1.13867427654, -0.0758619050232, -0.0727559666234, 0.01] # QPHO, Iop ~38.6 A
self.TF['ARS01-MQUA-5940']=[0.14, 0.14, 70, 40, 0.021218804957, 1.14130843974, -0.0820442421302, -0.0701489583562, 0.01] # QPHO, Iop ~44.6 A
self.TF['ARS02-MQUA-1050']=[0.14, 0.14, 70, 40, 0.0206876279741, 1.14384909713, -0.0868747005732, -0.0670370106246, 0.01] # QPHI, Iop ~44.6 A
self.TF['ARS02-MQUA-1150']=[0.14, 0.14, 70, 40, 0.0210358327099, 1.1408488786, -0.0825655559607, -0.0695451730122, 0.01] # QPHI, Iop ~38.6 A
self.TF['ARS02-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0281344468765, 1.12829322512, -0.11147754187, -0.068230198569, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS02-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00975104251237, 1.18629392371, 0.0432965311437, -0.261556210155, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS02-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00887526988747, 1.18673090298, 0.0550926317902, -0.272720818131, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS02-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0254463436238, 1.13067866503, -0.124119384679, -0.0587013887557, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS02-MQUA-5840']=[0.14, 0.14, 70, 30, 0.0103821620424, 1.17320069866, -0.00993066582094, -0.161935823288, 0.01] # QPHO, Iop ~33.4 A
self.TF['ARS02-MQUA-5940']=[0.14, 0.14, 70, 40, 0.020648451604, 1.1439090513, -0.0823157071707, -0.0702809483788, 0.01] # QPHO, Iop ~36.3 A
self.TF['ARS03-MQUA-0790']=[0.1, 0.1, 70, 40, 0.0272066497068, 1.12841779995, -0.115233383507, -0.0645004640065, 0.01] # QPI, Iop ~53.1 A
self.TF['ARS03-MQUA-0850']=[0.14, 0.14, 70, 40, 0.0209160870773, 1.14211267618, -0.0820081546424, -0.0706922398986, 0.01] # QPHI, Iop ~36.7 A
self.TF['ARS03-MQUA-1050']=[0.14, 0.14, 70, 20, 0.00819675364402, 1.18562474712, 0.0597058598824, -0.23890894014, 0.01] # QPHI, Iop ~22.9 A
self.TF['ARS03-MQUA-1150']=[0.14, 0.14, 70, 20, 0.00858152465222, 1.18197092671, 0.0529375528162, -0.231703365243, 0.01] # QPHI, Iop ~17.5 A
self.TF['ARS03-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0269406186117, 1.12955549412, -0.118907416087, -0.0619703797266, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS03-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00965256963755, 1.18401903318, 0.0467911845914, -0.264203812484, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS03-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00857027952163, 1.18889972891, 0.0505494793685, -0.271872116878, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS03-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0256548352751, 1.13230392888, -0.129341990792, -0.0544080071894, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS03-MQUA-5840']=[0.14, 0.14, 70, 40, 0.0213806820773, 1.13950226217, -0.0782507183232, -0.0721058497186, 0.01] # QPHO, Iop ~38.6 A
self.TF['ARS03-MQUA-5940']=[0.14, 0.14, 70, 40, 0.0206628710298, 1.14212719542, -0.0795591345361, -0.0715860089672, 0.01] # QPHO, Iop ~44.6 A
self.TF['ARS04-MQUA-1050']=[0.14, 0.14, 70, 40, 0.0209345318443, 1.14046892518, -0.0786355600943, -0.071896728547, 0.01] # QPHI, Iop ~44.6 A
self.TF['ARS04-MQUA-1150']=[0.14, 0.14, 70, 40, 0.0216322849976, 1.13818073211, -0.0798716183076, -0.070319861398, 0.01] # QPHI, Iop ~38.6 A
self.TF['ARS04-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0265365959324, 1.13033441086, -0.120305946845, -0.0607396225677, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS04-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00963430309403, 1.18643320353, 0.042977616531, -0.263226334512, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS04-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00861983962921, 1.18624182868, 0.0507152161104, -0.270666875622, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS04-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0251328199829, 1.1332744067, -0.127577980309, -0.056985026738, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS04-MQUA-5840']=[0.14, 0.14, 70, 20, 0.00790583701142, 1.18530354203, 0.0659552290113, -0.245122745463, 0.01] # QPHO, Iop ~16.4 A
self.TF['ARS04-MQUA-5940']=[0.14, 0.14, 70, 20, 0.00804610678733, 1.186385026, 0.0606395931537, -0.241377878168, 0.01] # QPHO, Iop ~15.6 A
self.TF['ARS05-MQUA-0400']=[0.1, 0.1, 70, 30, 0.0125790177572, 1.17281702, -0.0347460504964, -0.172653881113, 0.01] # QPI, Iop ~28.0 A
self.TF['ARS05-MQUA-0440']=[0.14, 0.14, 70, 40, 0.0211634853755, 1.14413196707, -0.0793531303093, -0.0716327579334, 0.01] # QPHI, Iop ~40.4 A
self.TF['ARS05-MQUA-0460']=[0.1, 0.1, 70, 30, 0.0126579317795, 1.16922925137, -0.0375603205641, -0.168705762093, 0.01] # QPI, Iop ~27.0 A
self.TF['ARS05-MQUA-1050']=[0.14, 0.14, 70, 20, 0.00774486989439, 1.18754949481, 0.0620179277666, -0.24114682342, 0.01] # QPHI, Iop ~23.3 A
self.TF['ARS05-MQUA-1150']=[0.14, 0.14, 70, 20, 0.00802871824166, 1.18431759806, 0.0576122341581, -0.236502845788, 0.01] # QPHI, Iop ~22.8 A
self.TF['ARS05-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0271287901891, 1.13414292589, -0.121261721603, -0.0604158205581, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS05-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00960159948821, 1.18333529506, 0.0436891146943, -0.261119481475, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS05-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00876466294849, 1.1853873149, 0.0498332611993, -0.269059748251, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS05-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0255139951502, 1.12924950946, -0.124584766918, -0.0573399883576, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS05-MQUA-5840']=[0.14, 0.14, 70, 40, 0.0213666428504, 1.13999184379, -0.0799300156275, -0.0699959750481, 0.01] # QPHO, Iop ~38.6 A
self.TF['ARS05-MQUA-5940']=[0.14, 0.14, 70, 40, 0.0218895438638, 1.13758969545, -0.0756379705509, -0.0734605282405, 0.01] # QPHO, Iop ~44.6 A
self.TF['ARS06-MQUA-1050']=[0.14, 0.14, 70, 40, 0.0206159749159, 1.14193423012, -0.0806427533998, -0.0711219067748, 0.01] # QPHI, Iop ~44.6 A
self.TF['ARS06-MQUA-1150']=[0.14, 0.14, 70, 40, 0.0208669606643, 1.14211127137, -0.0811107642473, -0.0701542973755, 0.01] # QPHI, Iop ~38.6 A
self.TF['ARS06-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0268325856985, 1.12641137526, -0.122382240161, -0.0577017897957, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS06-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00930736510072, 1.18441021623, 0.048972494037, -0.266253683669, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS06-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00865003188391, 1.18545647308, 0.0434107952861, -0.265108650677, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS06-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0255249681458, 1.13475658895, -0.131813158637, -0.0535355978289, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS06-MQUA-5840']=[0.14, 0.14, 70, 30, 0.010044621805, 1.17515051983, -0.0128135520533, -0.1590811517, 0.01] # QPHO, Iop ~33.4 A
self.TF['ARS06-MQUA-5940']=[0.14, 0.14, 70, 40, 0.0223744436868, 1.13354277752, -0.0722763427687, -0.0745863421613, 0.01] # QPHO, Iop ~36.3 A
self.TF['ARS07-MQUA-0790']=[0.1, 0.1, 70, 40, 0.0268261240229, 1.12850775962, -0.118800652519, -0.0628860550894, 0.01] # QPI, Iop ~53.1 A
self.TF['ARS07-MQUA-0850']=[0.14, 0.14, 70, 40, 0.0208905323449, 1.13952490478, -0.0799232788124, -0.0703853281269, 0.01] # QPHI, Iop ~36.7 A
self.TF['ARS07-MQUA-1050']=[0.14, 0.14, 70, 20, 0.00804233260923, 1.18227651418, 0.0547790934989, -0.233560353823, 0.01] # QPHI, Iop ~22.9 A
self.TF['ARS07-MQUA-1150']=[0.14, 0.14, 70, 20, 0.00802871824166, 1.18431759806, 0.0576122341581, -0.236502845788, 0.01] # QPHI, Iop ~17.5 A
self.TF['ARS07-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0281031810394, 1.12893170363, -0.117669105678, -0.0625133783651, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS07-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00980882672538, 1.18872328962, 0.0374271684138, -0.256366123299, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS07-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00847524785543, 1.18992810605, 0.0544746450998, -0.275611678451, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS07-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0249982564086, 1.13441872059, -0.1267857731, -0.0578763307642, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS07-MQUA-5840']=[0.14, 0.14, 70, 40, 0.0214016570398, 1.13618633301, -0.0772154462687, -0.0715549107099, 0.01] # QPHO, Iop ~38.6 A
self.TF['ARS07-MQUA-5940']=[0.14, 0.14, 70, 40, 0.021270649292, 1.13808807646, -0.0834245165349, -0.0663986333325, 0.01] # QPHO, Iop ~44.6 A
self.TF['ARS08-MQUA-1050']=[0.14, 0.14, 70, 40, 0.021866214922, 1.14100488468, -0.0847840451378, -0.0676795914515, 0.01] # QPHI, Iop ~44.6 A
self.TF['ARS08-MQUA-1150']=[0.14, 0.14, 70, 40, 0.021583400373, 1.1374895233, -0.0780905864371, -0.0709151165956, 0.01] # QPHI, Iop ~38.6 A
self.TF['ARS08-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0262205362497, 1.1325643365, -0.120885991747, -0.0617708042626, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS08-MQUA-1370']=[0.1, 0.1, 70, 20, 0.0100496738163, 1.18381400068, 0.0451620927184, -0.264181428461, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS08-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00847462872389, 1.18869636031, 0.0467484847972, -0.267916853268, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS08-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0253903831111, 1.13613484907, -0.123237046266, -0.060971293687, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS08-MQUA-5840']=[0.14, 0.14, 70, 20, 0.00836745561575, 1.17950303913, 0.0503519252676, -0.227065469804, 0.01] # QPHO, Iop ~22.8 A
self.TF['ARS08-MQUA-5940']=[0.14, 0.14, 70, 20, 0.00810429348709, 1.18288656076, 0.0631416700628, -0.242320436554, 0.01] # QPHO, Iop ~23.3 A
self.TF['ARS09-MQUA-0530']=[0.1, 0.1, 70, 30, 0.0127891751638, 1.16692866622, -0.0409710312471, -0.164789851012, 0.01] # QPI, Iop ~27.0 A
self.TF['ARS09-MQUA-0560']=[0.14, 0.14, 70, 40, 0.0214713744249, 1.14073041109, -0.0856866562901, -0.0665440469885, 0.01] # QPHI, Iop ~40.4 A
self.TF['ARS09-MQUA-0600']=[0.1, 0.1, 70, 30, 0.0127619782193, 1.16828383793, -0.0361652515646, -0.170749694948, 0.01] # QPI, Iop ~28.0 A
self.TF['ARS09-MQUA-1050']=[0.14, 0.14, 70, 20, 0.00779032031895, 1.18265637839, 0.0594775676297, -0.237358884081, 0.01] # QPHI, Iop ~15.6 A
self.TF['ARS09-MQUA-1150']=[0.14, 0.14, 70, 20, 0.0080277997637, 1.18191264557, 0.0597399764031, -0.238021257565, 0.01] # QPHI, Iop ~16.4 A
self.TF['ARS09-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0267706894238, 1.13076827934, -0.12013134413, -0.0609304526397, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS09-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00975022252034, 1.1851528742, 0.0462951187818, -0.264920831307, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS09-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00855153353985, 1.18824348557, 0.0472851933418, -0.26792967913, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS09-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0255240672583, 1.13334352816, -0.124209703075, -0.0597870566735, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS09-MQUA-5840']=[0.14, 0.14, 70, 40, 0.0209767380866, 1.1426776217, -0.0830055429835, -0.0700440208241, 0.01] # QPHO, Iop ~38.6 A
self.TF['ARS09-MQUA-5940']=[0.14, 0.14, 70, 40, 0.0199847664639, 1.1460043739, -0.08413546869, -0.0695934332314, 0.01] # QPHO, Iop ~44.6 A
self.TF['ARS10-MQUA-1050']=[0.14, 0.14, 70, 40, 0.0217641858904, 1.14140891045, -0.0854203959054, -0.0667485107897, 0.01] # QPHI, Iop ~44.6 A
self.TF['ARS10-MQUA-1150']=[0.14, 0.14, 70, 40, 0.0207292846941, 1.14423904487, -0.080135185258, -0.0718125452506, 0.01] # QPHI, Iop ~38.6 A
self.TF['ARS10-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0258090656403, 1.13553947618, -0.130644282989, -0.0533206254614, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS10-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00947055560653, 1.18815632538, 0.0411679839075, -0.260723655328, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS10-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00911052864507, 1.18393663418, 0.0488972528733, -0.266237706673, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS10-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0260113983687, 1.13095518645, -0.132058997795, -0.0522074038276, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS10-MQUA-5840']=[0.14, 0.14, 70, 30, 0.0106285443939, 1.16665730475, -0.0110844546315, -0.157408907481, 0.01] # QPHO, Iop ~33.6 A
self.TF['ARS10-MQUA-5940']=[0.14, 0.14, 70, 40, 0.0218788903308, 1.1376141267, -0.0785207911539, -0.0709542819546, 0.01] # QPHO, Iop ~36.6 A
self.TF['ARS11-MQUA-0830']=[0.1, 0.1, 70, 40, 0.0265181957302, 1.13383540023, -0.127380182735, -0.0547182574518, 0.01] # QPI, Iop ~55.1 A
self.TF['ARS11-MQUA-0890']=[0.14, 0.14, 70, 40, 0.0205970408064, 1.14515548387, -0.083934978866, -0.0695185459798, 0.01] # QPHI, Iop ~37.6 A
self.TF['ARS11-MQUA-1050']=[0.14, 0.14, 70, 20, 0.0079358870871, 1.18061941427, 0.0614609673978, -0.238016106498, 0.01] # QPHI, Iop ~14.5 A
self.TF['ARS11-MQUA-1150']=[0.14, 0.14, 70, 20, 0.00800634347948, 1.18471069605, 0.0603066884021, -0.239723573916, 0.01] # QPHI, Iop ~9.4 A
self.TF['ARS11-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0273752271128, 1.13241152476, -0.125645642304, -0.0566159720971, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS11-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00965935297016, 1.19194142929, 0.0405792648832, -0.261956785075, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS11-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00849380670863, 1.1894190651, 0.0485528210467, -0.26993497585, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS11-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0256314514959, 1.12963122732, -0.126061205037, -0.0573436886644, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS11-MQUA-5840']=[0.14, 0.14, 70, 40, 0.0213763770321, 1.13734894957, -0.0750542249952, -0.0737853659135, 0.01] # QPHO, Iop ~38.6 A
self.TF['ARS11-MQUA-5940']=[0.14, 0.14, 70, 40, 0.0204266463933, 1.14314697383, -0.0813557115322, -0.0701256402485, 0.01] # QPHO, Iop ~44.6 A
self.TF['ARS12-MQUA-1050']=[0.14, 0.14, 70, 40, 0.0205229308439, 1.14304301399, -0.08119174372, -0.070698637475, 0.01] # QPHI, Iop ~44.6 A
self.TF['ARS12-MQUA-1150']=[0.14, 0.14, 70, 40, 0.0202362585845, 1.1468959314, -0.0868251723613, -0.0671963440997, 0.01] # QPHI, Iop ~38.6 A
self.TF['ARS12-MQUA-1260']=[0.1, 0.1, 70, 40, 0.0275665929965, 1.12839886306, -0.117736405417, -0.0623624641848, 0.01] # QPI, Iop ~53.0 A
self.TF['ARS12-MQUA-1370']=[0.1, 0.1, 70, 20, 0.00934141409333, 1.18981443873, 0.0480146676568, -0.267751345363, 0.01] # QPI, Iop ~24.3 A
self.TF['ARS12-MQUA-5620']=[0.1, 0.1, 70, 20, 0.00843531827322, 1.18999128935, 0.0506938763075, -0.273164664944, 0.01] # QPO, Iop ~24.3 A
self.TF['ARS12-MQUA-5730']=[0.1, 0.1, 70, 40, 0.0247221190877, 1.13800703358, -0.132283214609, -0.0554632926452, 0.01] # QPO, Iop ~53.0 A
self.TF['ARS12-MQUA-5840']=[0.14, 0.14, 70, 20, 0.00786389740308, 1.18513390968, 0.0617435132693, -0.24107128681, 0.01] # QPHO, Iop ~23.2 A
self.TF['ARS12-MQUA-5940']=[0.14, 0.14, 70, 20, 0.00828198631199, 1.1825837794, 0.0563437707965, -0.233951363216, 0.01] # QPHO, Iop ~22.4 A
# S extupoles
# Specification from Andreas' note (or TDR BD chapter) # Keep them for history tacking
#self.TF['HS2A'] = [0.09, 0.09, 50.0, 50.0, 0.0, 58.5, 0.0, 0.0, 10e-3] # B''/2 = 5850 T/m**2
#self.TF['HS2B'] = [0.09, 0.09, 50.0, 50.0, 0.0, 58.5, 0.0, 0.0, 10e-3]
#self.TF['HS2G'] = [0.08, 0.08, 50.0, 50.0, 0.0, 58.5, 0.0, 0.0, 10e-3]
#self.TF['HS2H'] = [0.08, 0.08, 50.0, 50.0, 0.0, 58.5, 0.0, 0.0, 10e-3]
#self.TF['HS2K'] = [0.08, 0.08, 50.0, 50.0, 0.0, 58.5, 0.0, 0.0, 10e-3]
#self.TF['HS2L'] = [0.08, 0.08, 50.0, 50.0, 0.0, 58.5, 0.0, 0.0, 10e-3]
#self.TF['HS2M'] = [0.08, 0.08, 50.0, 50.0, 0.0, 58.5, 0.0, 0.0, 10e-3]
#self.TF['SXQ'] = [0.09, 0.09, 70.0, 70.0, 0.0, 58.5, 0.0, 0.0, 10e-3]
# Simulation by Vjeran. No neighboring magnet. 24.08.2022
#self.TF['HS2A'] = [0.09, 0.09, 50.0, 50.0, 0.0, 60.378, 0.0, 0.0, 10e-3] # B''/2 = 5850 T/m**2
#self.TF['HS2B'] = [0.09, 0.09, 50.0, 50.0, 0.0, 67.378, 0.0, 0.0, 10e-3]
#self.TF['HS2G'] = [0.08, 0.08, 50.0, 50.0, 0.0, 59.100, 0.0, 0.0, 10e-3]
#self.TF['HS2H'] = [0.08, 0.08, 50.0, 50.0, 0.0, 59.100, 0.0, 0.0, 10e-3]
#self.TF['HS2K'] = [0.08, 0.08, 50.0, 50.0, 0.0, 59.038, 0.0, 0.0, 10e-3]
#self.TF['HS2L'] = [0.08, 0.08, 50.0, 50.0, 0.0, 59.038, 0.0, 0.0, 10e-3]
#self.TF['HS2M'] = [0.08, 0.08, 50.0, 50.0, 0.0, 58.650, 0.0, 0.0, 10e-3]
#self.TF['SXQ'] = [0.09, 0.09, 70.0, 70.0, 0.0, 64.556, 0.0, 0.0, 10e-3]
# Rotation coil measurement, Average
# /afs/psi.ch/project/SLS2/Magnets/MeasurementData/Data2OM_SX.py
self.TF['HS2A']=[0.09, 0.09, 50.0, 30.0, 0.268672570371, 68.6573024724, 3.63950855666, -10.8627324327, 0.01]
self.TF['HS2B']=[0.09, 0.09, 50.0, 30.0, 0.268672570371, 68.6573024724, 3.63950855666, -10.8627324327, 0.01]
self.TF['HS2G']=[0.08, 0.08, 50.0, 30.0, 0.275523116667, 68.5291754064, 3.76726246385, -11.6558744619, 0.01]
self.TF['HS2H']=[0.08, 0.08, 50.0, 30.0, 0.275523116667, 68.5291754064, 3.76726246385, -11.6558744619, 0.01]
self.TF['HS2K']=[0.08, 0.08, 50.0, 30.0, 0.31366815, 68.4752835626, 3.57602204301, -11.4685644869, 0.01]
self.TF['HS2L']=[0.08, 0.08, 50.0, 30.0, 0.31366815, 68.4752835626, 3.57602204301, -11.4685644869, 0.01]
self.TF['HS2M']=[0.08, 0.08, 50.0, 30.0, 0.312616666667, 68.4330312501, 4.0780833326, -12.5120999994, 0.01]
self.TF['SXQ']=[0.09, 0.09, 70.0, 38.0, 0.356884451852, 86.4520837835, -21.2484787107, 0.669766969922, 0.01]
# Including cross-talk and hysteresis. Documentation: "Transfer function based on RC data and Opera.pptx"
# Note that the dictionary key is BD name (element.BDN), since the cross talk effect depends on the neiboring magnets
self.TF['SXX']=[0.09, 0.09, 50.0, 32.0, 0.268672570371, 68.6573024724, 1.69650336984, -8.91972724591, 0.01] # 32 A with an educated guess
self.TF['SXY']=[0.09, 0.09, 50.0, 32.0, 0.268672570371, 68.6573024724, 1.69650336984, -8.91972724591, 0.01]
self.TF['SYY']=[0.09, 0.09, 50.0, 32.0, 0.268672570371, 68.6573024724, 1.69650336984, -8.91972724591, 0.01]
self.TF['SDM']=[0.09, 0.09, 70.0, 35.2, 0.715160903971, 86.1953605446, -29.1497302221, 6.90040275271, 0.01]
self.TF['SD5']=[0.08, 0.08, 50.0, 32.0, -1.97091476148, 69.1754314874, -4.11968288296, -4.45067935221, 0.01]
self.TF['SD4']=[0.08, 0.08, 50.0, 32.0, -1.97091476148, 69.1754314874, -4.11968288296, -4.45067935221, 0.01] # HS2M (SD4I) is approximated with HS2G (SD4O)
self.TF['SD3']=[0.08, 0.08, 50.0, 32.0, -1.97091476148, 69.1754314874, -4.11968288296, -4.45067935221, 0.01]
self.TF['SD2']=[0.08, 0.08, 50.0, 32.0, -1.97091476148, 69.1754314874, -4.11968288296, -4.45067935221, 0.01]
self.TF['SD1']=[0.08, 0.08, 50.0, 32.0, -1.97091476148, 69.1754314874, -4.11968288296, -4.45067935221, 0.01]
self.TF['SFM']=[0.08, 0.08, 50.0, 32.0, 0.6360058481379699, 68.93581758298821, -9.424073445272223, -0.050151019762392335, 0.01] #
self.TF['SF2']=[0.08, 0.08, 50.0, 32.0, 0.251363431128, 68.9500649825, -5.92252125704, -3.02979404361, 0.01]
self.TF['SF1']=[0.08, 0.08, 50.0, 32.0, 0.251363431128, 68.9500649825, -5.92252125704, -3.02979404361, 0.01]
# Octupoles
# Specification from Andreas' note (or TDR BD chapter)
#self.TF['OS2A'] = [0.0, 0.05, 5.0, 5.0, 0.0, 630.0, 0.0, 0.0, 10e-3] # B'''/6 = 63000 T/m**3
#self.TF['OS2B'] = [0.0, 0.05, 5.0, 5.0, 0.0, 630.0, 0.0, 0.0, 10e-3]
#self.TF['OS2E'] = [0.0, 0.05, 5.0, 5.0, 0.0, 630.0, 0.0, 0.0, 10e-3]
#self.TF['OS2F'] = [0.0, 0.05, 5.0, 5.0, 0.0, 630.0, 0.0, 0.0, 10e-3]
# Simulation by Vjeran. No neighboring magnet. 24.08.2022
# Magnetic length is not defined. Keep 5 cm for now. 31.08.2022
#self.TF['OS2A'] = [0.0, 0.05, 5.0, 5.0, 0.0, 695.8, 0.0, 0.0, 10e-3] # B'''/6 = 69580 T/m**3
#self.TF['OS2B'] = [0.0, 0.05, 5.0, 5.0, 0.0, 695.8, 0.0, 0.0, 10e-3]
#self.TF['OS2E'] = [0.0, 0.05, 5.0, 5.0, 0.0, 695.6, 0.0, 0.0, 10e-3]
#self.TF['OS2F'] = [0.0, 0.05, 5.0, 5.0, 0.0, 695.6, 0.0, 0.0, 10e-3]
# RC measurement
# /afs/psi.ch/project/SLS2/Magnets/MeasurementData/Data2OM_OC.py
# To be verified and on-line
self.TF['OS2A']=[0.0, 0.05, 5.0, 0, 0.0, 669.303622067, 86.1565359977, -49.6460189903, 0.01] # B'''/6 = 74934 T/m**3
self.TF['OS2B']=[0.0, 0.05, 5.0, 0, 0.0, 668.321158671, 86.5072962136, -49.0092030546, 0.01]
self.TF['OS2E']=[0.0, 0.05, 5.0, 0, 0.0, 667.935924897, 88.7205354028, -49.4010112743, 0.01]
self.TF['OS2F']=[0.0, 0.05, 5.0, 0, 0.0, 667.618682856, 87.0688628959, -48.4244780922, 0.01]
# Including cross-talk. Hysteresis is excluded since the PS is bipolar. Documentation: "Transfer function based on RC data and Opera.pptx"
# Note that the dictionary key is BD name (element.BDN), since the cross talk effect depends on the neiboring magnets
# Three cases considered, 1) with no cross talk anticipated, 2) with no direct cross talk anticipated but there is an octupole component nearby, and 3) with cross talk
# For OXX, OXY, OYY (Case 1), use the above TFs from RC data, SM.I2KL(element.TYPE, I), provided the cross talk between electromagnets is not signigficant.
# For OCY1/OCY2 (Case 2), set option in SM.I2KL(element.TYPE, I, CrossTalk=element.BDN) -> The follwing offset is then included.
# For OCX1, OCX2 and OCXM (Case3), use the TFs below. SM.I2KL(element.BDN, I, CrossTalk=element.BDN): Note that both TYPE and CrossTalk = element.BDN
self.TF0={}
self.TF0['OCY2']=70.070791927 # K3L offset in SDn. Its current dependency is not included here since it is not significant as for OCX
self.TF0['OCY1']=70.070791927
self.TF0['OCXM']=56.1877821522+10.7526313278 # C13(ANM) + C10 (Oct off)
self.TF0['OCX2']=55.2440968811+10.7526313278 # C11 + C10 (Oct off)
self.TF0['OCX1']=28.8497357133+10.7526313278 # C9 + C10 (Oct off)
self.TF['OCXM']=[0.05, 0.05, 5.0, 1.0, 0.0, 727.309735329, -54.0658393851, 35.9640331277, 0.01] # OS2A RC + Opera cross talk + Opera single mag
self.TF['OCX2']=[0.05, 0.05, 5.0, 1.0, 0.0, 727.309735329, -54.0658393851, 35.9640331277, 0.01]
self.TF['OCX1']=[0.05, 0.05, 5.0, 1.0, 0.0, 727.309735329, -54.0658393851, 35.9640331277, 0.01]
# Corrector quad, spec requested
# Specification from Andreas' note (or TDR BD chapter)
#self.TF['QAOS2A'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.056, 0.0, 0.0, 10e-3] # B' = 5.6 T/m
#self.TF['QAOS2B'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.056, 0.0, 0.0, 10e-3]
#self.TF['QAOS2E'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.056, 0.0, 0.0, 10e-3]
#self.TF['QAOS2F'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.056, 0.0, 0.0, 10e-3]
# Simulation by Vjeran. No neighboring magnet. 24.08.2022
#self.TF['QAOS2A'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.06764, 0.0, 0.0, 10e-3] # B' = 6.7 T/m :)
#self.TF['QAOS2B'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.06764, 0.0, 0.0, 10e-3]
#self.TF['QAOS2E'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.06754, 0.0, 0.0, 10e-3]
#self.TF['QAOS2F'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.06754, 0.0, 0.0, 10e-3]
# RC measurement, average
self.TF['QAOS2A']=[0.05, 0.05, 5.0, 0, 0.0, 0.063439478074, 0.00894565593072, -0.0047472221448, 0.01] # B' = 6.76 T/m :)
self.TF['QAOS2B']=[0.05, 0.05, 5.0, 0, 0.0, 0.0632856330626, 0.00912884806541, -0.00482820798325, 0.01]
self.TF['QAOS2E']=[0.05, 0.05, 5.0, 0, 0.0, 0.0628063944775, 0.00978968479097, -0.00512004704693, 0.01]
self.TF['QAOS2F']=[0.05, 0.05, 5.0, 0, 0.0, 0.0628383904087, 0.00965142365802, -0.00505041790927, 0.01]
# Corrector skew, spec requested
#self.TF['QSOS2A'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.056, 0.0, 0.0, 10e-3] # B' = 5.6 T/m
#self.TF['QSOS2B'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.056, 0.0, 0.0, 10e-3]
#self.TF['QSOS2E'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.056, 0.0, 0.0, 10e-3]
#self.TF['QSOS2F'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.056, 0.0, 0.0, 10e-3]
# Simulation by Vjeran. No neighboring magnet. 24.08.2022
#self.TF['QSOS2A'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.06314, 0.0, 0.0, 10e-3] # B' = 6.3 T/m
#self.TF['QSOS2B'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.06314, 0.0, 0.0, 10e-3]
#self.TF['QSOS2E'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.06312, 0.0, 0.0, 10e-3]
#self.TF['QSOS2F'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.06312, 0.0, 0.0, 10e-3]
# RC measurement, average
self.TF['QSOS2A']=[0.05, 0.05, 5.0, 0, 0.0, 0.0590039543127, 0.00881466567091, -0.00463485306762, 0.01] # B' = 6.32 T/m
self.TF['QSOS2B']=[0.05, 0.05, 5.0, 0, 0.0, 0.0588472565198, 0.00900380966447, -0.00471795253389, 0.01]
self.TF['QSOS2E']=[0.05, 0.05, 5.0, 0, 0.0, 0.0588507592533, 0.0090524480532, -0.00471766261077, 0.01]
self.TF['QSOS2F']=[0.05, 0.05, 5.0, 0, 0.0, 0.0589230620203, 0.00884305456705, -0.00460527483071, 0.01]
# Corrector. Magnetic/Physical length?
#self.TF['CH'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.00072*1.5, 0.0, 0.0, 10e-3] # B = 0.072+0.036 T
#self.TF['CHS'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.00072*1.5, 0.0, 0.0, 10e-3] # B = 0.072+0.036 T
#self.TF['CV'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.00072, 0.0, 0.0, 10e-3] # B = 0.072 T
self.TF['CHY'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.00072*1.5, 0.0, 0.0, 10e-3] # B = 0.072+0.036 T
self.TF['CVY'] = [0.0, 0.05, 5.0, 5.0, 0.0, 0.00072, 0.0, 0.0, 10e-3] # B = 0.072 T
# Measurement, average
self.TF['CHS']=[0.05, 0.05, 5.0, 0, 0.0, 0.00143101755247, 0.000512080877263, -0.000519022672712, 0.01] # 820 urad!
self.TF['CV']=[0.05, 0.05, 5.0, 0, 0.0, 0.00103560521719, 0.000121693453739, -7.77922718062e-05, 0.01] # 600 urad!
# Measurement, id3 : Factor 0.92 from LOCO, 2025 02 13
self.TF['CH']=[0.05, 0.05, 5.0, 0, 0.0, 0.00157085011963*0.92, 0.000195329502438*0.92, -0.000160199545181*0.92, 0.01]
# Experimental. Correction from LOCO calibration
self.TF['CH1470']=[0.05, 0.05, 5.0, 0, 0.0, 0.00157085011963*0.84, 0.000195329502438*0.84, -0.000160199545181*0.84, 0.01]
# kicker bump
self.TF['KIN'] = [0.6, 0.6, 2500.0, 2500.0, 0.0, 0.0007125, 0.0, 0.0, 10e-3] # 4.75 mrad @ 2500 A @ peak, Mail from Martin on 11.07.2024
# BTR magnets
self.TF['QFA'] =[0.15, 0.173, 150.0, 91.1, 0.0, 0.74521, -0.00813, -0.03542, 22.5e-3] # From MEASUREMENT. Documentation: https://intranet.psi.ch/pub/Swiss_FEL/FinQuadrupoles/QFA.pdf (Link is now invalid...)
self.TF['CVTO'] = [0.05, 0.05, 5.0, 5.0, 0.0, 0.0036, 0.0, 0.0, 10e-3] # 2 mrad at 5A. The length is arbitrarily set to 0.05 m.
self.TF['CVTN'] = [0.171, 0.171, 5.0, 5.0, 0.0, 0.0009984310369419486, 0.0, 0.0, 10e-3] # BL= 0.014 Tm at 4.1 A. If it is at 5A, b1=0.0008187134502923977
self.TF['CHTN'] = [0.171, 0.171, 5.0, 5.0, 0.0, 0.0009984310369419486, 0.0, 0.0, 10e-3] # BL= 0.014 Tm at 4.1 A. If it is at 5A, b1=0.0008187134502923977
self.TF['SYINCH'] = [0.171, 0.171, 5.0, 5.0, 0.0, 0.0019883040935672514, 0.0, 0.0, 10e-3] # BL= 0.034 Tm at 5.0 A. If it is at 5A, b1=0.0008187134502923977
# brho for 2.7 GeV beam
gamma=(2.7e9+511e3)/511e3
beta=math.sqrt(1-1/gamma**2)
p=511e3*beta*gamma/1e9 # momentum in GeV/c
self.brho=p/0.299792 # P[GeV/c]=0.3*Brho[T.m]
# Multipole errors based on Vjeran's simulation. Experimental 29.08.2022
self.ME={}
# 20 poles is upper limit in tracy-null?
#self.ME['OS2A'] = [['k11',-232.9E+15/self.brho]]
#self.ME['OS2B'] = [['k11',-232.9E+15/self.brho]]
#self.ME['OS2E'] = [['k11',-232.5E+15/self.brho]]
#self.ME['OS2F'] = [['k11',-232.5E+15/self.brho]]
self.ME['QAOS2A'] = [['k5',4.969e6/self.brho/0.05],['k9',-4.993e12/self.brho/0.05]]
self.ME['QAOS2B'] = [['k5',4.969e6/self.brho/0.05],['k9',-4.993e12/self.brho/0.05]]
self.ME['QAOS2E'] = [['k5',4.966e6/self.brho/0.05],['k9',-4.521e12/self.brho/0.05]]
self.ME['QAOS2F'] = [['k5',4.966e6/self.brho/0.05],['k9',-4.521e12/self.brho/0.05]]
self.ME['QSOS2A'] = [['j5',-4.612e6/self.brho/0.05],['j9',-4.103e12/self.brho/0.05]]
self.ME['QSOS2B'] = [['j5',-4.612e6/self.brho/0.05],['j9',-4.103e12/self.brho/0.05]]
self.ME['QSOS2E'] = [['j5',-4.617e6/self.brho/0.05],['j9',-4.182e12/self.brho/0.05]]
self.ME['QSOS2F'] = [['j5',-4.617e6/self.brho/0.05],['j9',-4.182e12/self.brho/0.05]]
# k3 is static
self.ME['HS2A'] = [['k8',-1.189e12/self.brho/0.09]]
self.ME['HS2B'] = [['k8',-1.189e12/self.brho/0.09]]
#self.ME['HS2G'] = [['k8',-1.126e12/self.brho/S2.Type['HS2G']['L']]]
#self.ME['HS2H'] = [['k8',-1.126e12/self.brho/S2.Type['HS2H']['L']]]
#self.ME['HS2K'] = [['k8',-1.063e12/self.brho/S2.Type['HS2K']['L']]]
#self.ME['HS2L'] = [['k8',-1.063e12/self.brho/S2.Type['HS2L']['L']]]
#self.ME['HS2M'] = [['k8', -870.5e9/self.brho/S2.Type['HS2M']['L']]]
self.ME['HS2G'] = [['k3',540.0],['k8',-1.126e12/self.brho/0.08]]
self.ME['HS2H'] = [['k3',315.0],['k8',-1.126e12/self.brho/0.08]]
self.ME['HS2K'] = [['k3',315.0],['k8',-1.063e12/self.brho/0.08]]
self.ME['HS2L'] = [['k3',315.0],['k8',-1.063e12/self.brho/0.08]]
self.ME['HS2M'] = [['k3',315.0],['k8',-870.5e9/self.brho/0.08]]
self.ME['SXQ'] = [['k8',-712.9e9/self.brho/0.09]]
# Permanent magnets, experimental. 30.08.2022
self.ME['ANI'] = [['k2',0.3714/0.14],
['k3',13.884/0.14],
['k4',939.21/0.14],
['k5',-44425/0.14]]
self.ME['ANO'] = self.ME['ANI']
self.ME['ANMI'] = [['k2',0.072/0.15],
['k3',-28.72/0.15],
['k4',5563.4/0.15],
['k5',-341404/0.15]]
self.ME['ANMO'] = self.ME['ANMI']
self.ME['BEHI'] = [['k2',-0.3909/0.2287216],
['k3',5.5647/0.2287216],
['k4',-1273.8/0.2287216],
['k5',7580.6/0.2287216]]
self.ME['BEHO'] = self.ME['BEHI']
self.ME['BN'] = [['k2',-0.3010*2/0.405],
['k3',3.4507*2/0.405],
['k4',-484.29*2/0.405],
['k5',-8805.5*2/0.405]]
self.ME['VBI'] = [['k2',2.3935/0.185],
['k3',71.468/0.185],
['k4',183.93/0.185],
['k5',66049.5/0.185]]
self.ME['VBO'] = self.ME['VBI']
self.ME['VBXI'] = self.ME['VBI'] # No simulation available at the moment. 30.08.2022
self.ME['VBXO'] = self.ME['VBI']
self.ME['VEI'] = [['k2',-0.13577/0.24],
['k3',20.263/0.24],
['k4',-2990.5/0.24],
['k5',470512.2/0.24]]
self.ME['VEO'] = self.ME['VEI']
# Quad and Skew quad axeis shifts with respect to the paired sextupole axis
# [qx, qy, sqx, sqy] (mm)
self.OctShift={}
self.OctShift['ARS01-MOCT-1230']=[0.003, -0.008, 0.02, 0.009]
self.OctShift['ARS01-MOCT-1330']=[-0.004, 0.021, -0.002, 0.024]
self.OctShift['ARS01-MOCT-1440']=[-0.012, 0.004, -0.007, -0.001]
self.OctShift['ARS01-MOCT-1840']=[-0.005, 0.025, 0.007, 0.035]
self.OctShift['ARS01-MOCT-1950']=[-0.011, -0.001, -0.005, -0.002]
self.OctShift['ARS01-MOCT-2230']=[0.013, 0.037, 0.059, 0.038]
self.OctShift['ARS01-MOCT-2360']=[0.004, 0.011, 0.012, 0.018]
self.OctShift['ARS01-MOCT-2450']=[0.002, 0.02, 0.009, 0.019]
self.OctShift['ARS01-MOCT-2730']=[-0.001, 0.034, 0.015, 0.041]
self.OctShift['ARS01-MOCT-2860']=[-0.002, 0.034, 0.005, 0.032]
self.OctShift['ARS01-MOCT-2950']=[0.006, 0.017, 0.016, 0.014]
self.OctShift['ARS01-MOCT-4040']=[-0.015, -0.005, -0.005, 0.014]
self.OctShift['ARS01-MOCT-4130']=[-0.007, 0.043, -0.004, 0.033]
self.OctShift['ARS01-MOCT-4260']=[0.009, 0.022, 0.002, 0.026]
self.OctShift['ARS01-MOCT-4540']=[0.005, 0.002, 0.027, 0.009]
self.OctShift['ARS01-MOCT-4630']=[0.004, -0.003, 0.007, -0.002]
self.OctShift['ARS01-MOCT-4760']=[0.008, 0.006, 0.008, 0.0]
self.OctShift['ARS01-MOCT-5040']=[0.006, 0.039, 0.014, 0.045]
self.OctShift['ARS01-MOCT-5150']=[0.01, 0.015, 0.012, 0.015]
self.OctShift['ARS01-MOCT-5550']=[-0.006, 0.011, 0.001, 0.006]
self.OctShift['ARS01-MOCT-5660']=[0.012, -0.001, 0.028, -0.015]
self.OctShift['ARS01-MOCT-5760']=[0.007, 0.019, 0.014, 0.009]
self.OctShift['ARS02-MOCT-1230']=[-0.012, -0.001, 0.011, 0.018]
self.OctShift['ARS02-MOCT-1330']=[0.004, 0.023, -0.007, 0.018]
self.OctShift['ARS02-MOCT-1440']=[-0.005, 0.018, -0.002, 0.03]
self.OctShift['ARS02-MOCT-1840']=[0.006, 0.018, 0.001, 0.046]
self.OctShift['ARS02-MOCT-1950']=[-0.005, 0.03, -0.006, 0.033]
self.OctShift['ARS02-MOCT-2230']=[-0.012, -0.003, -0.019, -0.006]
self.OctShift['ARS02-MOCT-2360']=[-0.002, 0.025, 0.005, 0.026]
self.OctShift['ARS02-MOCT-2450']=[0.011, 0.013, -0.001, 0.001]
self.OctShift['ARS02-MOCT-2730']=[-0.007, 0.01, -0.016, 0.027]
self.OctShift['ARS02-MOCT-2860']=[0.013, -0.004, 0.007, 0.006]
self.OctShift['ARS02-MOCT-2950']=[-0.012, 0.022, -0.024, 0.029]
self.OctShift['ARS02-MOCT-4040']=[-0.01, 0.001, 0.002, -0.003]
self.OctShift['ARS02-MOCT-4130']=[-0.008, 0.014, -0.012, -0.009]
self.OctShift['ARS02-MOCT-4260']=[-0.007, 0.015, -0.024, 0.027]
self.OctShift['ARS02-MOCT-4540']=[-0.004, 0.003, -0.014, -0.003]
self.OctShift['ARS02-MOCT-4630']=[0.007, 0.029, 0.03, 0.03]
self.OctShift['ARS02-MOCT-4760']=[-0.006, 0.015, 0.011, 0.0]
self.OctShift['ARS02-MOCT-5040']=[-0.001, 0.012, 0.0, 0.015]
self.OctShift['ARS02-MOCT-5150']=[-0.002, 0.009, -0.019, 0.004]
self.OctShift['ARS02-MOCT-5550']=[0.005, -0.007, -0.01, 0.012]
self.OctShift['ARS02-MOCT-5660']=[-0.012, -0.013, -0.017, -0.012]
self.OctShift['ARS02-MOCT-5760']=[0.014, 0.001, 0.007, 0.006]
self.OctShift['ARS03-MOCT-1230']=[0.013, -0.026, 0.004, -0.027]
self.OctShift['ARS03-MOCT-1330']=[-0.004, 0.01, -0.006, 0.019]
self.OctShift['ARS03-MOCT-1440']=[-0.012, 0.004, -0.01, 0.019]
self.OctShift['ARS03-MOCT-1840']=[-0.002, 0.023, 0.004, 0.03]
self.OctShift['ARS03-MOCT-1950']=[-0.002, 0.026, -0.012, 0.018]
self.OctShift['ARS03-MOCT-2230']=[-0.001, -0.001, 0.012, -0.0]
self.OctShift['ARS03-MOCT-2360']=[0.007, -0.001, -0.003, -0.011]
self.OctShift['ARS03-MOCT-2450']=[0.004, 0.016, 0.003, 0.016]
self.OctShift['ARS03-MOCT-2730']=[-0.01, 0.009, 0.002, 0.028]
self.OctShift['ARS03-MOCT-2860']=[-0.003, -0.009, -0.004, -0.009]
self.OctShift['ARS03-MOCT-2950']=[-0.013, 0.014, -0.015, 0.031]
self.OctShift['ARS03-MOCT-4040']=[0.007, 0.015, 0.0, 0.028]
self.OctShift['ARS03-MOCT-4130']=[0.011, -0.019, 0.013, -0.002]
self.OctShift['ARS03-MOCT-4260']=[0.001, 0.041, 0.016, 0.078]
self.OctShift['ARS03-MOCT-4540']=[-0.014, 0.04, -0.028, 0.049]
self.OctShift['ARS03-MOCT-4630']=[0.009, 0.006, 0.02, 0.011]
self.OctShift['ARS03-MOCT-4760']=[0.009, 0.022, -0.002, 0.02]
self.OctShift['ARS03-MOCT-5040']=[0.002, -0.013, 0.013, -0.026]
self.OctShift['ARS03-MOCT-5150']=[0.001, 0.023, -0.005, 0.018]
self.OctShift['ARS03-MOCT-5550']=[0.011, 0.011, 0.008, 0.017]
self.OctShift['ARS03-MOCT-5660']=[0.003, 0.038, 0.017, 0.052]
self.OctShift['ARS03-MOCT-5760']=[0.002, -0.007, -0.006, -0.015]
self.OctShift['ARS04-MOCT-1230']=[0.005, 0.01, 0.012, 0.0]
self.OctShift['ARS04-MOCT-1330']=[0.006, -0.007, 0.005, 0.001]
self.OctShift['ARS04-MOCT-1440']=[-0.005, -0.019, 0.007, -0.03]
self.OctShift['ARS04-MOCT-1840']=[-0.007, 0.003, 0.014, 0.019]
self.OctShift['ARS04-MOCT-1950']=[0.011, 0.021, 0.007, 0.027]
self.OctShift['ARS04-MOCT-2230']=[-0.004, 0.024, -0.026, 0.037]
self.OctShift['ARS04-MOCT-2360']=[-0.011, -0.016, -0.016, -0.026]
self.OctShift['ARS04-MOCT-2450']=[-0.006, -0.008, -0.008, 0.0]
self.OctShift['ARS04-MOCT-2730']=[0.011, 0.041, 0.012, 0.038]
self.OctShift['ARS04-MOCT-2860']=[-0.001, 0.016, 0.005, 0.017]
self.OctShift['ARS04-MOCT-2950']=[0.008, 0.02, 0.008, 0.009]
self.OctShift['ARS04-MOCT-4040']=[0.015, 0.02, 0.006, 0.021]
self.OctShift['ARS04-MOCT-4130']=[-0.013, 0.015, -0.023, 0.008]
self.OctShift['ARS04-MOCT-4260']=[0.01, 0.026, 0.011, 0.044]
self.OctShift['ARS04-MOCT-4540']=[-0.006, 0.012, 0.012, 0.014]
self.OctShift['ARS04-MOCT-4630']=[0.008, 0.014, 0.019, 0.034]
self.OctShift['ARS04-MOCT-4760']=[0.002, 0.035, 0.004, 0.038]
self.OctShift['ARS04-MOCT-5040']=[0.003, -0.009, 0.017, -0.01]
self.OctShift['ARS04-MOCT-5150']=[0.004, 0.014, -0.005, 0.008]
self.OctShift['ARS04-MOCT-5550']=[-0.009, 0.029, -0.01, 0.037]
self.OctShift['ARS04-MOCT-5660']=[-0.012, 0.029, -0.003, 0.023]
self.OctShift['ARS04-MOCT-5760']=[0.006, 0.008, 0.005, 0.011]
self.OctShift['ARS05-MOCT-1230']=[-0.013, 0.001, -0.013, -0.006]
self.OctShift['ARS05-MOCT-1330']=[-0.002, 0.011, -0.018, 0.001]
self.OctShift['ARS05-MOCT-1440']=[-0.01, 0.034, -0.013, 0.048]
self.OctShift['ARS05-MOCT-1840']=[0.004, 0.028, -0.002, 0.038]
self.OctShift['ARS05-MOCT-1950']=[-0.0, 0.02, 0.015, 0.041]
self.OctShift['ARS05-MOCT-2230']=[-0.013, -0.006, -0.014, -0.002]
self.OctShift['ARS05-MOCT-2360']=[0.011, 0.021, 0.013, 0.021]
self.OctShift['ARS05-MOCT-2450']=[-0.004, 0.037, 0.003, 0.035]
self.OctShift['ARS05-MOCT-2730']=[0.003, -0.0, 0.014, 0.013]
self.OctShift['ARS05-MOCT-2860']=[0.01, 0.029, 0.014, 0.028]
self.OctShift['ARS05-MOCT-2950']=[0.01, 0.024, 0.006, 0.023]
self.OctShift['ARS05-MOCT-4040']=[-0.001, -0.019, -0.015, -0.009]
self.OctShift['ARS05-MOCT-4130']=[0.012, 0.002, 0.026, 0.003]
self.OctShift['ARS05-MOCT-4260']=[0.0, 0.018, 0.011, 0.02]
self.OctShift['ARS05-MOCT-4540']=[-0.001, 0.029, -0.009, 0.027]
self.OctShift['ARS05-MOCT-4630']=[-0.005, 0.014, 0.009, 0.006]
self.OctShift['ARS05-MOCT-4760']=[0.003, 0.004, -0.008, 0.027]
self.OctShift['ARS05-MOCT-5040']=[-0.0, 0.012, 0.002, 0.021]
self.OctShift['ARS05-MOCT-5150']=[-0.006, 0.005, 0.003, 0.006]
self.OctShift['ARS05-MOCT-5550']=[0.008, 0.001, 0.008, -0.002]
self.OctShift['ARS05-MOCT-5660']=[0.002, 0.002, 0.001, 0.016]
self.OctShift['ARS05-MOCT-5760']=[0.006, 0.019, 0.017, 0.033]
self.OctShift['ARS06-MOCT-1230']=[0.006, -0.007, 0.001, 0.001]
self.OctShift['ARS06-MOCT-1330']=[0.005, 0.027, 0.0, 0.018]
self.OctShift['ARS06-MOCT-1440']=[0.0, 0.016, -0.013, 0.018]
self.OctShift['ARS06-MOCT-1840']=[0.008, 0.007, 0.011, 0.016]
self.OctShift['ARS06-MOCT-1950']=[0.004, 0.014, -0.009, 0.033]
self.OctShift['ARS06-MOCT-2230']=[0.004, 0.008, -0.011, -0.0]
self.OctShift['ARS06-MOCT-2360']=[0.004, 0.001, 0.02, 0.007]
self.OctShift['ARS06-MOCT-2450']=[0.005, 0.041, 0.002, 0.04]
self.OctShift['ARS06-MOCT-2730']=[-0.008, 0.024, 0.009, 0.041]
self.OctShift['ARS06-MOCT-2860']=[-0.01, 0.024, -0.019, 0.028]
self.OctShift['ARS06-MOCT-2950']=[-0.006, 0.022, 0.005, 0.024]
self.OctShift['ARS06-MOCT-4040']=[0.003, -0.008, -0.001, 0.002]
self.OctShift['ARS06-MOCT-4130']=[0.003, 0.028, -0.018, 0.055]
self.OctShift['ARS06-MOCT-4260']=[-0.013, 0.007, -0.026, -0.0]
self.OctShift['ARS06-MOCT-4540']=[-0.005, 0.004, -0.007, 0.006]
self.OctShift['ARS06-MOCT-4630']=[0.004, 0.037, 0.004, 0.063]
self.OctShift['ARS06-MOCT-4760']=[-0.0, 0.044, -0.006, 0.043]
self.OctShift['ARS06-MOCT-5040']=[0.012, 0.019, 0.008, 0.032]
self.OctShift['ARS06-MOCT-5150']=[0.002, 0.011, 0.002, 0.009]
self.OctShift['ARS06-MOCT-5550']=[0.013, 0.022, -0.0, 0.03]
self.OctShift['ARS06-MOCT-5660']=[0.008, 0.019, 0.014, 0.037]
self.OctShift['ARS06-MOCT-5760']=[0.013, 0.028, -0.0, 0.035]
self.OctShift['ARS07-MOCT-1230']=[0.003, 0.012, 0.009, 0.013]
self.OctShift['ARS07-MOCT-1330']=[-0.007, 0.001, 0.003, 0.003]
self.OctShift['ARS07-MOCT-1440']=[0.009, 0.01, 0.014, 0.015]
self.OctShift['ARS07-MOCT-1840']=[-0.001, 0.009, -0.004, 0.017]
self.OctShift['ARS07-MOCT-1950']=[-0.005, 0.032, 0.004, 0.026]
self.OctShift['ARS07-MOCT-2230']=[0.013, -0.004, 0.01, 0.004]
self.OctShift['ARS07-MOCT-2360']=[-0.009, 0.023, -0.019, 0.023]
self.OctShift['ARS07-MOCT-2450']=[-0.011, 0.016, -0.013, 0.019]
self.OctShift['ARS07-MOCT-2730']=[0.003, 0.034, 0.0, 0.035]
self.OctShift['ARS07-MOCT-2860']=[0.003, 0.024, 0.003, 0.022]
self.OctShift['ARS07-MOCT-2950']=[-0.012, 0.031, -0.003, 0.106]
self.OctShift['ARS07-MOCT-4040']=[0.0, 0.01, -0.002, 0.013]
self.OctShift['ARS07-MOCT-4130']=[0.0, 0.005, -0.013, 0.009]
self.OctShift['ARS07-MOCT-4260']=[-0.002, 0.04, 0.004, 0.052]
self.OctShift['ARS07-MOCT-4540']=[0.011, -0.009, -0.004, 0.009]
self.OctShift['ARS07-MOCT-4630']=[-0.004, 0.012, -0.009, 0.019]
self.OctShift['ARS07-MOCT-4760']=[-0.001, 0.016, -0.011, 0.021]
self.OctShift['ARS07-MOCT-5040']=[0.008, 0.01, -0.003, 0.003]
self.OctShift['ARS07-MOCT-5150']=[-0.011, 0.02, -0.002, 0.023]
self.OctShift['ARS07-MOCT-5550']=[-0.007, 0.023, 0.001, 0.024]
self.OctShift['ARS07-MOCT-5660']=[-0.014, 0.021, -0.02, 0.023]
self.OctShift['ARS07-MOCT-5760']=[-0.007, 0.013, -0.006, 0.012]
self.OctShift['ARS08-MOCT-1230']=[0.011, 0.012, 0.008, 0.049]
self.OctShift['ARS08-MOCT-1330']=[-0.001, -0.007, -0.007, -0.009]
self.OctShift['ARS08-MOCT-1440']=[-0.008, 0.001, 0.005, -0.006]
self.OctShift['ARS08-MOCT-1840']=[-0.005, -0.003, -0.007, 0.013]
self.OctShift['ARS08-MOCT-1950']=[0.007, 0.011, 0.011, 0.001]
self.OctShift['ARS08-MOCT-2230']=[-0.007, -0.005, 0.002, -0.011]
self.OctShift['ARS08-MOCT-2360']=[0.0, -0.007, -0.009, -0.007]
self.OctShift['ARS08-MOCT-2450']=[-0.004, 0.012, -0.007, 0.03]
self.OctShift['ARS08-MOCT-2730']=[0.011, 0.022, 0.015, 0.036]
self.OctShift['ARS08-MOCT-2860']=[-0.006, 0.012, -0.006, 0.013]
self.OctShift['ARS08-MOCT-2950']=[0.002, 0.006, 0.001, 0.017]
self.OctShift['ARS08-MOCT-4040']=[-0.002, 0.018, -0.008, 0.039]
self.OctShift['ARS08-MOCT-4130']=[-0.002, 0.041, -0.012, 0.041]
self.OctShift['ARS08-MOCT-4260']=[-0.011, 0.013, -0.022, 0.013]
self.OctShift['ARS08-MOCT-4540']=[-0.008, -0.002, -0.016, -0.004]
self.OctShift['ARS08-MOCT-4630']=[-0.01, -0.01, -0.006, -0.014]
self.OctShift['ARS08-MOCT-4760']=[0.012, 0.021, 0.01, 0.018]
self.OctShift['ARS08-MOCT-5040']=[0.01, 0.018, 0.02, 0.008]
self.OctShift['ARS08-MOCT-5150']=[-0.002, 0.003, -0.005, 0.014]
self.OctShift['ARS08-MOCT-5550']=[0.011, 0.001, 0.007, 0.005]
self.OctShift['ARS08-MOCT-5660']=[-0.0, 0.037, 0.004, 0.036]
self.OctShift['ARS08-MOCT-5760']=[-0.008, 0.007, -0.02, 0.017]
self.OctShift['ARS09-MOCT-1230']=[-0.005, -0.01, 0.0, -0.002]
self.OctShift['ARS09-MOCT-1330']=[-0.008, -0.028, 0.011, -0.01]
self.OctShift['ARS09-MOCT-1440']=[-0.007, 0.001, -0.015, 0.007]
self.OctShift['ARS09-MOCT-1840']=[-0.003, 0.04, -0.01, 0.039]
self.OctShift['ARS09-MOCT-1950']=[0.006, 0.007, -0.002, 0.025]
self.OctShift['ARS09-MOCT-2230']=[-0.003, -0.005, -0.008, 0.001]
self.OctShift['ARS09-MOCT-2360']=[0.01, 0.03, 0.016, 0.043]
self.OctShift['ARS09-MOCT-2450']=[-0.002, 0.018, 0.001, 0.005]
self.OctShift['ARS09-MOCT-2730']=[0.01, -0.008, 0.009, -0.004]
self.OctShift['ARS09-MOCT-2860']=[-0.005, 0.024, -0.008, 0.022]
self.OctShift['ARS09-MOCT-2950']=[-0.002, 0.004, 0.0, 0.008]
self.OctShift['ARS09-MOCT-4040']=[0.002, -0.0, 0.019, -0.011]
self.OctShift['ARS09-MOCT-4130']=[0.001, 0.006, 0.011, 0.003]
self.OctShift['ARS09-MOCT-4260']=[0.004, -0.015, -0.003, -0.009]
self.OctShift['ARS09-MOCT-4540']=[-0.007, 0.008, 0.001, 0.022]
self.OctShift['ARS09-MOCT-4630']=[0.015, -0.023, 0.015, -0.013]
self.OctShift['ARS09-MOCT-4760']=[-0.003, -0.002, 0.013, 0.004]
self.OctShift['ARS09-MOCT-5040']=[-0.002, 0.005, -0.007, 0.009]
self.OctShift['ARS09-MOCT-5150']=[0.005, 0.03, -0.004, 0.036]
self.OctShift['ARS09-MOCT-5550']=[0.002, -0.003, 0.0, -0.006]
self.OctShift['ARS09-MOCT-5660']=[0.012, 0.002, 0.007, -0.016]
self.OctShift['ARS09-MOCT-5760']=[-0.009, 0.029, -0.022, 0.051]
self.OctShift['ARS10-MOCT-1230']=[0.0, 0.039, 0.005, 0.033]
self.OctShift['ARS10-MOCT-1330']=[0.002, 0.015, 0.002, 0.009]
self.OctShift['ARS10-MOCT-1440']=[0.005, 0.021, -0.006, 0.037]
self.OctShift['ARS10-MOCT-1840']=[-0.009, 0.001, -0.017, 0.015]
self.OctShift['ARS10-MOCT-1950']=[0.01, 0.018, -0.007, 0.033]
self.OctShift['ARS10-MOCT-2230']=[0.001, -0.005, 0.002, -0.007]
self.OctShift['ARS10-MOCT-2360']=[0.002, 0.013, 0.003, 0.02]
self.OctShift['ARS10-MOCT-2450']=[-0.001, 0.027, 0.001, 0.028]
self.OctShift['ARS10-MOCT-2730']=[0.011, -0.005, 0.009, -0.0]
self.OctShift['ARS10-MOCT-2860']=[0.005, 0.018, 0.005, 0.019]
self.OctShift['ARS10-MOCT-2950']=[-0.011, -0.001, -0.023, 0.003]
self.OctShift['ARS10-MOCT-4040']=[-0.011, 0.03, 0.004, 0.035]
self.OctShift['ARS10-MOCT-4130']=[-0.002, -0.002, 0.003, 0.007]
self.OctShift['ARS10-MOCT-4260']=[0.001, 0.011, 0.004, 0.01]
self.OctShift['ARS10-MOCT-4540']=[0.003, 0.027, 0.004, 0.041]
self.OctShift['ARS10-MOCT-4630']=[0.015, 0.007, 0.013, 0.01]
self.OctShift['ARS10-MOCT-4760']=[0.002, 0.02, 0.006, 0.031]
self.OctShift['ARS10-MOCT-5040']=[0.014, 0.005, 0.009, -0.002]
self.OctShift['ARS10-MOCT-5150']=[-0.008, 0.025, -0.004, 0.023]
self.OctShift['ARS10-MOCT-5550']=[-0.014, 0.016, -0.016, 0.025]
self.OctShift['ARS10-MOCT-5660']=[0.007, 0.025, 0.006, 0.024]
self.OctShift['ARS10-MOCT-5760']=[-0.011, 0.003, -0.028, -0.007]
self.OctShift['ARS11-MOCT-1230']=[-0.002, 0.022, -0.003, 0.021]
self.OctShift['ARS11-MOCT-1330']=[0.001, 0.024, 0.007, 0.017]
self.OctShift['ARS11-MOCT-1440']=[-0.006, 0.006, -0.011, 0.0]
self.OctShift['ARS11-MOCT-1840']=[-0.007, 0.002, 0.014, 0.018]
self.OctShift['ARS11-MOCT-1950']=[-0.01, 0.031, 0.011, 0.037]
self.OctShift['ARS11-MOCT-2230']=[0.004, 0.028, 0.004, 0.033]
self.OctShift['ARS11-MOCT-2360']=[-0.003, 0.01, 0.002, 0.018]
self.OctShift['ARS11-MOCT-2450']=[0.002, 0.02, -0.008, 0.04]
self.OctShift['ARS11-MOCT-2730']=[-0.009, 0.013, -0.008, 0.036]
self.OctShift['ARS11-MOCT-2860']=[0.002, 0.01, -0.004, 0.001]
self.OctShift['ARS11-MOCT-2950']=[0.002, -0.007, -0.006, -0.008]
self.OctShift['ARS11-MOCT-4040']=[0.004, 0.01, -0.003, 0.007]
self.OctShift['ARS11-MOCT-4130']=[0.001, 0.012, 0.012, 0.011]
self.OctShift['ARS11-MOCT-4260']=[0.01, 0.022, 0.008, 0.03]
self.OctShift['ARS11-MOCT-4540']=[0.007, 0.011, 0.007, -0.0]
self.OctShift['ARS11-MOCT-4630']=[-0.005, 0.03, -0.003, 0.026]
self.OctShift['ARS11-MOCT-4760']=[0.003, 0.032, 0.003, 0.025]
self.OctShift['ARS11-MOCT-5040']=[0.004, -0.01, 0.011, -0.01]
self.OctShift['ARS11-MOCT-5150']=[-0.011, 0.01, -0.003, 0.004]
self.OctShift['ARS11-MOCT-5550']=[0.002, 0.02, -0.004, 0.015]
self.OctShift['ARS11-MOCT-5660']=[0.002, 0.01, 0.018, 0.004]
self.OctShift['ARS11-MOCT-5760']=[-0.006, 0.001, -0.01, 0.005]
self.OctShift['ARS12-MOCT-1230']=[-0.013, 0.033, 0.0, 0.041]
self.OctShift['ARS12-MOCT-1330']=[0.006, 0.023, -0.0, 0.023]
self.OctShift['ARS12-MOCT-1440']=[0.015, 0.026, 0.021, 0.032]
self.OctShift['ARS12-MOCT-1840']=[-0.008, 0.001, -0.014, -0.012]
self.OctShift['ARS12-MOCT-1950']=[-0.003, 0.04, 0.003, 0.042]
self.OctShift['ARS12-MOCT-2230']=[0.008, -0.008, 0.033, 0.009]
self.OctShift['ARS12-MOCT-2360']=[0.001, -0.014, -0.009, -0.002]
self.OctShift['ARS12-MOCT-2450']=[-0.01, 0.032, -0.005, 0.043]
self.OctShift['ARS12-MOCT-2730']=[-0.009, 0.016, 0.007, 0.023]
self.OctShift['ARS12-MOCT-2860']=[0.004, 0.02, 0.0, 0.009]
self.OctShift['ARS12-MOCT-2950']=[0.002, 0.009, 0.001, 0.014]
self.OctShift['ARS12-MOCT-4040']=[0.013, -0.01, 0.02, 0.005]
self.OctShift['ARS12-MOCT-4130']=[0.006, 0.028, -0.009, 0.022]
self.OctShift['ARS12-MOCT-4260']=[0.002, 0.033, -0.005, 0.033]
self.OctShift['ARS12-MOCT-4540']=[-0.005, 0.028, -0.015, 0.028]
self.OctShift['ARS12-MOCT-4630']=[0.007, 0.03, 0.011, 0.025]
self.OctShift['ARS12-MOCT-4760']=[-0.012, 0.01, 0.002, 0.013]
self.OctShift['ARS12-MOCT-5040']=[0.003, -0.005, -0.005, 0.008]
self.OctShift['ARS12-MOCT-5150']=[-0.003, 0.035, -0.005, 0.034]
self.OctShift['ARS12-MOCT-5550']=[-0.004, 0.024, -0.005, 0.027]
self.OctShift['ARS12-MOCT-5660']=[0.006, 0.012, 0.017, 0.021]
self.OctShift['ARS12-MOCT-5760']=[0.008, 0.017, 0.022, 0.027]
def KL2I(self, TYPE, KL, CrossTalk=None):
def Single(TYPE,KL):
# TYPE can be NAME of the magnet, for example, 'ARSnn-MQUA-iiii'
# KL is integrated field in European notation (OPA, tracy)
if TYPE[-1]=='I' or TYPE[-1]=='O':
TYPE=TYPE.replace('I','').replace('O','')
if TYPE not in self.TF.keys():
warnings.warn('Transfer function for '+TYPE+' is not found...')
return None
[HEL,ML,Imax,Ilin,b0,b1,b2,b3,R]=self.TF[TYPE]
# Copied from SwissFEL OM. Need to check
G = self.brho*KL/ML
I=Imax*(abs(G)*R -b0)/b1
if abs(I)>Imax:
warnings.warn('Warning: In OMSLS2Magnet.KL2I, the given KL resulted in I>Imax, and thus Imax is returned.')
return np.sign(KL)*Imax
if abs(I)>Ilin:
#coeff=[b3/(Imax-Ilin)**3,b2/(Imax-Ilin)**2,b1/Imax,b0-G*R+b1*Ilin/Imax]
#I=KL/abs(KL)*(np.roots(coeff)[0]+Ilin)
coeff=[b3/(Imax-Ilin)**3,b2/(Imax-Ilin)**2,b1/Imax,b0-(abs(G)*R-b1*Ilin/Imax)]
rt=np.roots(coeff)
if len(rt)==1:
rt=rt[0]
else:
rtind=np.argmin(np.abs(np.abs(rt)-(abs(I)-Ilin)))
rt=abs(rt[rtind])
I=(rt+Ilin)
if not b0:
I=np.sign(KL)*I
if CrossTalk:
Gct = self.brho*self.TF0[CrossTalk]/ML
Ict=Imax*(Gct*R -b0)/b1
I=I-Ict
return I
if type(KL)==list or type(KL)==np.ndarray:
return [Single(TYPE,kl) for kl in KL]
else:
return Single(TYPE,KL)
def I2KL(self, TYPE, I, CrossTalk=None):
def Single(TYPE,I):
if TYPE[-1]=='I' or TYPE[-1]=='O':
TYPE=TYPE.replace('I','').replace('O','')
if TYPE not in self.TF.keys():
warnings.warn('Transfer function for '+TYPE+' is not found...')
return None
[HEL,ML,Imax,Ilin,b0,b1,b2,b3,R]=self.TF[TYPE]
if CrossTalk:
#KL=KL+self.TF0[CrossTalk]
Gct = self.brho*self.TF0[CrossTalk]/ML
Ict=Imax*(Gct*R -b0)/b1
I=I+Ict
if abs(I)>Imax:
warnings.warn('Warning: In OMSLS2Magnet.I2KL, the given I is >Imax, and thus KL at Imax is returned.')
I=np.sign(I)*Imax
if abs(I)<=Ilin:
G = (b0 + b1*abs(I)/Imax)/R
else:
G = (b0 + b1*abs(I)/Imax + b2*((abs(I)-Ilin)**2/(Imax-Ilin)**2) + b3*((abs(I)-Ilin)**3/(Imax-Ilin)**3))/R
if I==0:
K = G/self.brho
else:
K = np.sign(I)*G/self.brho
KL = K*ML
return KL
if type(I)==list or type(I)==np.ndarray:
return [Single(TYPE,i) for i in I]
else:
return Single(TYPE,I)