''' Classes and functions for TraceWin - Note for clean-up * Old LATTICE and MATCH classes can be deleted once trajectory correction is established with new classes. ''' #---- Lib from numpy import * from numpy.linalg import det from struct import pack from itertools import chain from subprocess import check_output from os import system from os.path import isdir,isfile from sys import exit from lib_tw_elem import * #-------- Classes #---- Lattice and project class LATTICE: ''' 2015.10.14 ''' def __init__(self,file_name_lat,file_name_fmap=[],freq=352.21,gamma=1.0): ''' :param file_name_lat: name of lattice file :type file_name_lat: str :param file_name_fmap: list of file map file(-s) :type file_name_fmap: list or str :param freq: RF frequency :type freq: float :param gamma: relativistic gamma :type gamma: float ''' # In case file_name_fmap is str if isinstance(file_name_fmap,basestring): file_name_fmap=[file_name_fmap] # Elem/comm class dict dic_cls={'DRIFT':DRIFT, 'QUAD':QUAD,'BEND':BEND,'EDGE':EDGE,'THIN_STEERING':THIN_STEERING, 'GAP':GAP,'DTL_CEL':DTL_CEL, 'APERTURE':APERTURE,'DIAG_POSITION':DIAG_POSITION, 'STEERER':STEERER,'CHOPPER':CHOPPER, 'FREQ':FREQ,'MARKER':MARKER} # Field map dict dic_fmap={} for file_name_fmap_i in file_name_fmap: name_fmap='.'.join(file_name_fmap_i.split('/')[-1].split('.')[:-1]) # Remove / and extention dic_fmap[name_fmap]=FIELD_MAP_DATA(file_name_fmap_i) # Go through the lat file with open(file_name_lat) as file: lst=[] for lin in file: lin=lin.partition(';')[0] # Remove comment if lin.split()!=[]: # Remove empty line # Split a line if ':' in lin: name=lin.partition(':')[0].split()[0 ] typ =lin.partition(':')[2].split()[0 ].upper() para=lin.partition(':')[2].split()[1:] else: name='' typ =lin.split()[0 ].upper() para=lin.split()[1:] # Map to a class if typ == 'FIELD_MAP' : lst.append( FIELD_MAP(name,typ,para,dic_fmap)) elif typ in dic_cls.keys() : lst.append(dic_cls[typ](name,typ,para) ) elif 'DIAG' in typ : lst.append( DIAG(name,typ,para) ) else : lst.append( COMM(name,typ,para) ) # in case of field map path, update dictionary with new path if typ == 'FIELD_MAP_PATH' : _update_field_map_dict(dic_fmap,para[0]) # Break the loop if typ=='END': break # Instances self.gamma=gamma self.freq =freq self.lst =lst self.fmap =dic_fmap # Maybe not needed ... # Assign idx, idx_elem, s, freq, apt self.update_idx() def get_correctors_idx(self,i): ''' Get correctors associated to corrector index i ''' import logging found=False correctors=[] for element in self.lst: if found: #WARNING I worry that there could be an inactive comment/element between the ADJUST and actual corrector logging.debug("Found element {} for corrector family {}".format(element.typ,i)) correctors.append(element) found=False if isinstance(element,COMM): if element.typ in ['ADJUST','ADJUST_STEERER']: if int(element.para[0])==i: # next element is the corrector found=True return correctors def get_elem_idx(self,i): ''' Get a TraceWin index number Note: We start counting from 0, TW starts from 1 ''' for element in self.lst: if element.idx_elem==i-1: return element def get_steerer_for(self,idx_elem): ''' Returns the steerer object for an element (e.g. quad) ''' previous=None for element in self.lst: if element.idx_elem+1==idx_elem: if previous.typ=='STEERER': return previous return None previous=element def update_idx(self): # Assign/update idx, idx_elem, s, freq for i in range(len(self.lst)): if i==0: self.lst[0].freq=self.freq if i!=0: self.lst[i].idx =self.lst[i-1].idx self.lst[i].idx_elem=self.lst[i-1].idx_elem self.lst[i].s =self.lst[i-1].s self.lst[i].freq =self.lst[i-1].freq self.lst[i].update_idx() # Assign apt (using apt of the previous elem for diag elem) for i in range(len(self.lst)): try: if self.lst[i].apt==None: if self.lst[i].idx_elem==0: for k in range(1,len(self.lst)): try: if self.lst[k].apt!=None: self.lst[i].apt=self.lst[k].apt; break except: pass else: for k in range(i)[::-1]: try : self.lst[i].apt=self.lst[k].apt; break except: pass except: pass def update_gamma(self): for i in range(len(self.lst)): if i==0: self.lst[0].gamma=self.gamma if i!=0: self.lst[i].gamma=self.lst[i-1].gamma try : self.lst[i].update_gamma() except: pass def update_st(self,file_name): ''' Assign/update steerer values from "Steerer_Values.txt". ''' # Extract BLx and BLy from the file with open(file_name,'r') as file: BLx={}; BLy={} for lin in file: lin=lin.split()[3:] for i in range(len(lin)): if lin[i]==':' : idx_elem =int(lin[i-1])-1 # "-1" since idx=0,1,2,... if lin[i]=='BLx=': BLx[idx_elem]=float(lin[i+1]) if lin[i]=='BLy=': BLy[idx_elem]=float(lin[i+1]) # Assign/update steerers for i in range(len(self.lst)): if self.lst[i].idx_elem in BLx: idx_elem=self.lst[i].idx_elem if self.lst[i].typ=='THIN_STEERING': self.lst[i].BLx=BLx[idx_elem] self.lst[i].BLy=BLy[idx_elem] if self.lst[i].typ!='THIN_STEERING': for k in range(i)[::-1]: if self.lst[k].typ=='STEERER': self.lst[k].Bx=BLx[idx_elem]/self.lst[i].L self.lst[k].By=BLy[idx_elem]/self.lst[i].L break def update_adj(self,file_name="Adjusted_Values.txt"): ''' Assign/update correction values from "Adjusted_Values.txt". WARNING: many corner cases, what happens if multiple adjust commands have corrected same element for example? Use with care! ''' with open(file_name,'r') as file: # First we read in all corrections into dictionaries values={} counts={} for lin in file: lin=lin.split() i=int(lin[1][1:-1]) if i=='ERROR' and lin[0]=='BEAM': continue settings={} for j in xrange(len(lin[2:])/3): k=int(lin[2+3*j]) val=float(lin[4+3*j]) if k in settings: settings[k].append(val) else: settings[k]=[val] values[i]=settings for j in settings: counts[j]=0 # now we will do all the ADJUST_STEERER ones corr_next=False for el in self.lst: if isinstance(el,COMM) and el.typ=='ADJUST_STEERER': i=int(el.para[0]) if i in values: corr_next=values[i] elif corr_next: if isinstance(el,STEERER): # Bx and By are corrected.. vals=corr_next.values()[0] el.Bx=vals[0] el.By=vals[1] corr_next=False # now we will do all the ADJUST ones corr_next=False # The TraceWin index number of the current element: current=-1 for el in self.lst: if el.idx_elem!=-1: current=el.idx_elem+1 if isinstance(el,COMM) and el.typ=='ADJUST': # The index of the corrector scheme i = int(el.para[0]) # the parameter column to vary: j = int(el.para[1])-1 # The TraceWin element index of the element we will vary: k = current+1 # This corrector might not be used: if i in values: # We will correct the next active element in lattice: value = values[i][k][counts[k]] # We have now used one value of the total in the current corrector: counts[k]+=1 # the element to vary: vary=self.get_elem_idx(current+1) vary.para[j]=value vary.update() def get_tw(self,file_name): with open(file_name,'w') as file: for lat_i in self.lst: file.write(lat_i.get_tw()+'\n') def get_madx(self,file_name_elem='elem.madx',file_name_seq='seq.madx'): if self.lst[-1].gamma==1.0: self.update_gamma() # Assign gamma, if not done yet with open(file_name_elem,'w') as file: for lat_i in self.lst: try : print >>file,lat_i.get_madx() except: pass with open(file_name_elem,'r') as file: lst_name=[lin.split(':')[0] for lin in file] with open(file_name_seq ,'w') as file: print >>file,'linac:line=('+','.join(lst_name)+');' def get_fluka(self,file_name='elem.dat'): if self.lst[-1].gamma==1.0: self.update_gamma() # Assign gamma, if not done yet with open(file_name,'w') as file: for lat_i in self.lst: try : print >>file,lat_i.get_fluka() except: pass def get_mars(self,file_name='elem.dat'): if self.lst[-1].gamma==1.0: self.update_gamma() # Assign gamma, if not done yet with open(file_name,'w') as file: for lat_i in self.lst: try : print >>file,lat_i.get_mars() except: pass class PROJECT: ''' - This is for running multiple simulations 1-by-1 under 1 project. - Maybe not very useful... 2015.10.15 ''' def __init__(self,file_name_proj='proj.ini'): # Instances (Add more options as needed.) self.file_name_proj=file_name_proj self.file_name_lat =None self.path_cal =None self.seed =None self.flag_hide =None def exe(self): opt_exe ='TraceWin64_noX11 '+self.file_name_proj if self.file_name_lat!=None: opt_exe+=' dat_file=' +self.file_name_lat if self.path_cal !=None: opt_exe+=' path_cal=' +self.path_cal if self.seed !=None: opt_exe+=' random_seed='+self.seed if self.flag_hide !=None: opt_exe+=' hide' ## if self.path_cal!=None: ## if isdir(self.path_cal)==False: system('mkdir '+self.path_cal) system(opt_exe) #---- Data related class PARTRAN: ''' Note: - The list not complete. Add parameters as needed. History: - 2016.02.17: Changed how to identify the line of indices. - 2016.02.17: Added a logic to avoid #/0 for LEBT. ''' def __init__(self,file_name): # Consts to convert phs to z. mass=938.272029 c =2.99792458 freq=352.21 # Extract indices. with open(file_name) as file: for lin in file.readlines(): lin=lin.split() if '##' in lin[0]: idx_s =lin.index("z(m)" ); idx_gamma=lin.index("gama-1" ) idx_x =lin.index("x0" ); idx_y =lin.index("y0" ); idx_phs =lin.index("p0" ) idx_sigx =lin.index("SizeX" ); idx_sigy =lin.index("SizeY" ); idx_sigz=lin.index("SizeZ"); idx_sigp=lin.index("SizeP") idx_alfx =lin.index("sxx'" ); idx_alfy =lin.index("syy'" ); idx_alfz=lin.index("szdp" ) idx_epsx =lin.index("ex" ); idx_epsy =lin.index("ey" ); idx_epsz=lin.index("ezdp" ); idx_epsp=lin.index("ep" ) idx_halx =lin.index("hx" ); idx_haly =lin.index("hy" ); idx_halp=lin.index("hp" ) idx_Nptcl=lin.index("npart" ); idx_loss =lin.index("Powlost") break # Extract data. with open(file_name) as file: data=[]; flag=0 for lin in file.readlines(): lin=lin.split() if flag ==1 : data.append(map(float,lin)) if '##' in lin[0]: flag=1 data=array(data).transpose() # Instances self.s =data[idx_s ] self.x =data[idx_x ]; self.y =data[idx_y ]; self.phs =data[idx_phs ] self.sigx =data[idx_sigx ]; self.sigy=data[idx_sigy]; self.sigz=data[idx_sigz]; self.sigp=data[idx_sigp] self.epsx =data[idx_epsx ]; self.epsy=data[idx_epsy]; self.epsz=data[idx_epsz]; self.epsp=data[idx_epsp] self.halx =data[idx_halx ]; self.haly=data[idx_haly]; self.halz=data[idx_halp]; self.halp=data[idx_halp] self.Nptcl=data[idx_Nptcl]; self.loss=data[idx_loss] # To avoid #/0 for LEBT for i in range(len(self.s)): if self.epsz[i]==0.0: self.epsz[i]=inf if self.epsp[i]==0.0: self.epsp[i]=inf # Additional instances self.gamma= data[idx_gamma]+1.0 self.beta = sqrt(1.0-1.0/self.gamma**2) self.z =-self.phs*self.beta*(c/freq*1e5)/360.0 self.betx = self.sigx**2/self.epsx*self.beta*self.gamma self.bety = self.sigy**2/self.epsy*self.beta*self.gamma self.betz = self.sigz**2/self.epsz*self.beta*self.gamma**3 self.betp = self.sigp**2/self.epsp self.alfx =-data[idx_alfx]/self.epsx*self.beta*self.gamma self.alfy =-data[idx_alfy]/self.epsy*self.beta*self.gamma self.alfz =-data[idx_alfz]/self.epsz*self.beta*self.gamma**3 self.alfp =-self.alfz # Set epsz/epsp back to 0 for i in range(len(self.s)): if self.epsz[i]==inf: self.epsz[i]=0.0 if self.epsp[i]==inf: self.epsp[i]=0.0 # Convert to list (not necessary?) self.s =self.s.tolist() ; self.gamma=self.gamma.tolist(); self.beta=self.beta.tolist() self.x =self.x.tolist() ; self.y =self.y.tolist() ; self.z =self.z.tolist() ; self.phs =self.phs.tolist() self.sigx =self.sigx.tolist() ; self.sigy =self.sigy.tolist() ; self.sigz=self.sigz.tolist(); self.sigp=self.sigp.tolist() self.betx =self.betx.tolist() ; self.bety =self.bety.tolist() ; self.betz=self.betz.tolist(); self.betp=self.betp.tolist() self.alfx =self.alfx.tolist() ; self.alfy =self.alfy.tolist() ; self.alfz=self.alfz.tolist(); self.alfp=self.alfp.tolist() self.epsx =self.epsx.tolist() ; self.epsy =self.epsy.tolist() ; self.epsz=self.epsz.tolist(); self.epsp=self.epsp.tolist() self.halx =self.halx.tolist() ; self.haly =self.haly.tolist() ; self.halz=self.halz.tolist(); self.halp=self.halp.tolist() self.Nptcl=self.Nptcl.tolist(); self.loss =self.loss.tolist() def loss_den(self,file_name_dt='',dlt_dt=5e-6): return loss_elem2den(self.s,self.loss,file_name_dt,dlt_dt) class DST: ''' Class for a TraceWin's .dst file. - TraceWin seems using beta and gamma for each particle so the conversion to (z,z') is based on this assumption. 2015.10.06 ''' def __init__(self,file_name,unit_x='cm',unit_px='rad',unit_z='rad',unit_pz='MeV'): # Const c=2.99792458 # Read the file with open(file_name) as file: dummy=fromfile(file,dtype= uint8 ,count=2 ) Nptcl=fromfile(file,dtype= uint32,count=1 )[0] Ibeam=fromfile(file,dtype=float64,count=1 )[0] freq =fromfile(file,dtype=float64,count=1 )[0] dummy=fromfile(file,dtype= uint8 ,count=1 ) x =fromfile(file,dtype=float64,count=Nptcl*6).reshape(Nptcl,6).transpose() mass =fromfile(file,dtype=float64,count=1 )[0] # Adjust units gamma=1.0+x[5]/mass; beta=sqrt(1-1/gamma**2) if unit_x =='mm' : x[0]= x[0]*1e1; x[2]=x[2]*1e1 if unit_px=='mrad': x[1]= x[1]*1e3; x[3]=x[3]*1e3 if unit_z =='deg' : x[4]= x[4]*180/pi if unit_z =='mm' : x[4]=-x[4]*c*beta/(2*pi*freq)*1e5 if unit_pz=='mrad': x[5]=(x[5]-mean(x[5]))/(mass*beta**2*gamma**3)*1e3 # Instances self.x =x.transpose() self.mass =mass self.freq =freq self.Ibeam=Ibeam class DENSITY: ''' - Note instances are not identical for Nrun=1 and Nrun>1. - Be careful with # of steps for an envelope file. - When Nrun>1, ave and rms in a file are sum and squared sum. - Double check before a production !!!! - Dim of arrays: Nelem(Nidx): idx_elem, s, Nptcl, Ibeam 2 x Nelem(Nidx): apt # x, y 3 x Nelem(Nidx): accpt # phs+, phs-, ken 7 x Nelem(Nidx): cent_(..), sig, xmax, xmin # x, y, phs, ken, r, z, dpp 3 x Nelem(Nidx): eps # x, y, phs Nrun x Nelem: loss Nelem : loss_num_(..), loss_pow_(..) Nelem x Nstep: den 2015.11.12 ''' def __init__(self,file_name): #-- Empty arrays idx_elem =[]; s =[] apt =[]; accpt =[] Nptcl =[]; Ibeam =[] cent_ave =[]; cent_rms =[] cent_max =[]; cent_min =[] sig_ave =[]; sig_rms =[] eps_ave =[]; eps_rms =[] xmax =[]; xmin =[] loss_num =[]; loss_pow =[] loss_num_ave=[]; loss_pow_ave=[] loss_num_rms=[]; loss_pow_rms=[] loss_num_max=[]; loss_pow_max=[] loss_num_min=[]; loss_pow_min=[] den =[]; den_pow =[] #-- Extract data with open(file_name) as file: while True: try: # Partran and envelope ver,year,flag_long=fromfile(file,dtype=uint16,count=3) Nrun =fromfile(file,dtype=uint32,count=1)[0] idx_elem.append(fromfile(file,dtype= uint32,count=1)[0]) Ibeam.append(fromfile(file,dtype=float32,count=1)[0]) s.append( fromfile(file,dtype=float32,count=1)[0]) apt.append( fromfile(file,dtype=float32,count=2) ) Nstep=fromfile(file,dtype=uint32,count=1)[0] cent_ave.append(fromfile(file,dtype=float32,count=7)) cent_rms.append(fromfile(file,dtype=float32,count=7)) xmax.append( fromfile(file,dtype=float32,count=7)) xmin.append( fromfile(file,dtype=float32,count=7)) if ver> 5: sig_ave.append(fromfile(file,dtype=float32,count=7)) sig_rms.append(fromfile(file,dtype=float32,count=7)) if ver>=6: cent_min.append(fromfile(file,dtype=float32,count=7)) cent_max.append(fromfile(file,dtype=float32,count=7)) if ver>=7: eps_ave.append(fromfile(file,dtype=float32,count=3)) eps_rms.append(fromfile(file,dtype=float32,count=3)) if ver>=8: accpt.append(fromfile(file,dtype=float32,count=3)) Nptcl.append(fromfile(file,dtype=uint64,count=1)[0]) # Partran only if Nptcl[-1]>0: loss_num.append([]); loss_pow.append([]); den.append([]); den_pow.append([]) for n in range(Nrun): loss_num[-1].append(fromfile(file,dtype= uint64,count=1)[0]) loss_pow[-1].append(fromfile(file,dtype=float32,count=1)[0]) loss_num_ave.append(sum(loss_num[-1])) loss_num_rms.append(fromfile(file,dtype= uint64,count=1)[0]) loss_num_min.append(fromfile(file,dtype= uint64,count=1)[0]) loss_num_max.append(fromfile(file,dtype= uint64,count=1)[0]) loss_pow_ave.append(sum(loss_pow[-1])) loss_pow_rms.append(fromfile(file,dtype=float64,count=1)[0]) loss_pow_min.append(fromfile(file,dtype=float32,count=1)[0]) loss_pow_max.append(fromfile(file,dtype=float32,count=1)[0]) for k in range(7): if flag_long==1: den[-1].append(fromfile(file,dtype=uint64,count=Nstep)) else : den[-1].append(fromfile(file,dtype=uint32,count=Nstep)) if Ibeam[-1]>0: for k in range(3): den_pow[-1].append(fromfile(file,dtype=float32,count=Nstep)) #print Nrun,Nptcl[-1],idx_elem[-1] # Diag except: break #-- Reshape arrays apt =swapaxes( apt,1,0); accpt =swapaxes( accpt,1,0) cent_ave=swapaxes(cent_ave,1,0); cent_rms=swapaxes(cent_rms,1,0) cent_max=swapaxes(cent_max,1,0); cent_min=swapaxes(cent_min,1,0) sig_ave =swapaxes( sig_ave,1,0); sig_rms =swapaxes( sig_rms,1,0) eps_ave =swapaxes( eps_ave,1,0); eps_rms =swapaxes( eps_rms,1,0) xmax =swapaxes( xmax,1,0); xmin =swapaxes( xmin,1,0) if Nptcl[0]>0: loss_num=swapaxes(loss_num,1,0); loss_pow=swapaxes(loss_pow,1,0) den =swapaxes( den,1,0); den_pow =swapaxes( den_pow,1,0) #-- Take care ave and rms cent_ave=cent_ave/Nrun; cent_rms=sqrt(cent_rms/Nrun) sig_ave = sig_ave/Nrun; sig_rms =sqrt( sig_rms/Nrun) eps_ave = eps_ave/Nrun; eps_rms =sqrt( eps_rms/Nrun) if Nptcl[0]>0: loss_num_ave=1.0*array(loss_num_ave)/Nrun; loss_num_rms=sqrt(1.0*array(loss_num_rms)/Nrun) loss_pow_ave= array(loss_pow_ave)/Nrun; loss_pow_rms=sqrt( array(loss_pow_rms)/Nrun) #-- Change units, m => mm, pi-m-rad => pi-mm-mrad apt *=1e3 eps_ave*=1e6; eps_rms*=1e6 for k in (0,1,4,5): cent_ave[k]*=1e3; cent_rms[k]*=1e3 cent_max[k]*=1e3; cent_min[k]*=1e3 sig_ave[k] *=1e3; sig_rms[k] *=1e3 xmax[k] *=1e3; xmin[k] *=1e3 #-- Define std (around to avoid sqrt(-eps)) if Nrun>1: cent_std=sqrt(around(cent_rms**2-cent_ave**2,12)) sig_std =sqrt(around( sig_rms**2- sig_ave**2,12)) eps_std =sqrt(around( eps_rms**2- eps_ave**2,12)) cent_std=nan_to_num(cent_std) # Replace nan with 0 sig_std =nan_to_num( sig_std) # Replace nan with 0 eps_std =nan_to_num( eps_std) # Replace nan with 0 if Nptcl[0]>0: loss_num_std=sqrt(around(loss_num_rms**2-loss_num_ave**2,16)) loss_pow_std=sqrt(around(loss_pow_rms**2-loss_pow_ave**2,16)) loss_num_std=nan_to_num(loss_num_std) # Replace nan with 0 loss_pow_std=nan_to_num(loss_pow_std) # Replace nan with 0 #-- Convert to list (just in case...) apt = apt.tolist(); accpt = accpt.tolist(); accpt.append(accpt[0]); del accpt[0] cent_ave=cent_ave.tolist(); cent_rms=cent_rms.tolist() cent_max=cent_max.tolist(); cent_min=cent_min.tolist() sig_ave = sig_ave.tolist(); sig_rms = sig_rms.tolist() eps_ave = eps_ave.tolist(); eps_rms = eps_rms.tolist() xmax = xmax.tolist(); xmin=xmin.tolist() if Nptcl[0]>0: loss_num = loss_num.tolist(); loss_pow = loss_pow.tolist() loss_num_ave=loss_num_ave.tolist(); loss_pow_ave=loss_pow_ave.tolist() loss_num_rms=loss_num_rms.tolist(); loss_pow_rms=loss_pow_rms.tolist() den = den.tolist(); den_pow = den_pow.tolist() if Nrun>1: cent_std=cent_std.tolist() sig_std = sig_std.tolist() eps_std = eps_std.tolist() if Nptcl[0]>0: loss_num_std=loss_num_std.tolist() loss_pow_std=loss_pow_std.tolist() #-- Outputs self.idx_elem=idx_elem self.s =s self.apt =apt self.accpt =accpt self.Nptcl =Nptcl self.Ibeam =Ibeam self.Nrun =Nrun self.Nstep=Nstep if Nrun==1: self.cent=cent_ave self.sig = sig_ave self.eps = eps_ave self.xmax= xmax self.xmin= xmin if Nptcl[0]>0: self.loss_num=loss_num[0]; self.loss_pow=loss_pow[0] self.den = den; self.den_pow = den_pow else: self.cent_ave=cent_ave; self.cent_rms=cent_rms; self.cent_std=cent_std self.cent_max=cent_max; self.cent_min=cent_min self.sig_ave = sig_ave; self.sig_rms = sig_rms; self.sig_std = sig_std self.eps_ave = eps_ave; self.eps_rms = eps_rms; self.eps_std = eps_std self.xmax = xmax; self.xmin = xmin if Nptcl[0]>0: self.loss_num =loss_num ; self.loss_pow =loss_pow self.loss_num_ave=loss_num_ave; self.loss_pow_ave=loss_pow_ave self.loss_num_rms=loss_num_rms; self.loss_pow_rms=loss_pow_rms self.loss_num_std=loss_num_std; self.loss_pow_std=loss_pow_std self.loss_num_max=loss_num_max; self.loss_pow_max=loss_pow_max self.loss_num_min=loss_num_min; self.loss_pow_min=loss_pow_min self.den = den ; self.den_pow = den_pow #-- Option outputs self.idx_4_elem_end=[len(idx_elem)-1-idx_elem[::-1].index(i) for i in list(set(idx_elem))] #-------- Functions #---- Dist related def x2dst(x,mass,freq,Ibeam,path_file='part_dtl1_new.dst'): ''' Output a TraceWin's .dst file from x and etc. Input: x (Nptcl,6) For binary characters see https://docs.python.org/2/library/struct.html 2014.10.03 ''' file=open(path_file,'w') out =pack('b',125) out+=pack('b',100) out+=pack('i',len(x)) out+=pack('d',Ibeam) out+=pack('d',freq) out+=pack('b',125) # Typo in the manual !!!! x=list(chain(*x)) # Flatten x for x_i in x: out+=pack('d',x_i) out+=pack('d',mass) print >>file,out file.close() def plt2x(path_file): ''' Extract x and etc from a TraceWin's binary .plt file. The units are (cm,rad,cm,rad,rad,MeV,loss). Output: x (Nelem,Nptcl,7) For binary characters see https://docs.python.org/2/library/struct.html 2014.10.06 ''' file=open(path_file,'r') # Hetero info file.read(1); file.read(1) # 125,100 Nelem=unpack('i',file.read(4))[0] Nptcl=unpack('i',file.read(4))[0] Ibeam=unpack('d',file.read(8))[0] freq =unpack('d',file.read(8))[0] mass =unpack('d',file.read(8))[0] # Loop for elem x=[]; i_unk=[]; i_elem=[]; s=[]; phs=[]; ken=[]; for i in range(Nelem): try: i_unk.append(unpack('b',file.read(1))[0]) i_elem.append(unpack('i',file.read(4))[0]) s.append(unpack('d',file.read(8))[0]) phs.append(unpack('d',file.read(8))[0]) ken.append(unpack('d',file.read(8))[0]) x.append([[unpack('f',file.read(4))[0] for l in range(7)] for k in range(Nptcl)]) except: break file.close() return x,mass,freq,Ibeam,i_unk,i_elem,s,phs,ken def x2plt(x,mass,freq,Ibeam,i_unk,i_elem,s,phs,ken,path_file='dtl1_new.plt'): ''' Output a TraceWin's .plt file from x and etc. Input: x (Nelem,Nptcl,7) For binary characters see https://docs.python.org/2/library/struct.html 2014.10.07 ''' file=open(path_file,'w') out =pack('b',125) out+=pack('b',100) out+=pack('i',len(x)) out+=pack('i',len(x[0])) out+=pack('d',Ibeam) out+=pack('d',freq) out+=pack('d',mass) for i in range(len(x)): out+=pack('b',i_unk[i]) #out+=pack('i',i_elem[i]) out+=pack('i',i) # To truncate the elem number out+=pack('d',s[i]) out+=pack('d',phs[i]) out+=pack('d',ken[i]) x_i=list(chain(*x[i])) for x_ik in x_i: out+=pack('f',x_ik) print >>file,out file.close() #---- Data related def x2twiss(x): ''' Calculate twiss from x. Note sig = sqrt(bet*eps). Input : x (Nptcl,6) Output: eps,bet,alf,gam 2015.07.30 ''' x =[x_i-mean(x_i) for x_i in array(x).transpose()] sig=[[mean(x_i*x_k) for x_k in x] for x_i in x] eps=[ sqrt(det(array(sig)[i:i+2][:,i:i+2])) for i in (0,2,4)] bet=[ sig[i ][i ]/eps[i/2] for i in (0,2,4)] alf=[-sig[i ][i+1]/eps[i/2] for i in (0,2,4)] gam=[ sig[i+1][i+1]/eps[i/2] for i in (0,2,4)] return eps,bet,alf,gam def x2twiss_halo(x,sig_cut=(None,None,None)): ''' Calculate twiss of halo particles (r > sig_cut). Note halo particles are different for each plane. Input : x (Nptcl,6), sig_cut Output: eps,bet,alf,gam 2015.07.30 ''' eps,bet,alf,gam=x2twiss(x) for k in (0,2,4): if sig_cut[k/2]!=None: x=x.transpose(); r_nom_sq=(x[k]**2+(alf[k/2]*x[k]+bet[k/2]*x[k+1])**2)/(bet[k/2]*eps[k/2]) x=x.transpose(); x_halo=[x[i] for i in range(len(x)) if r_nom_sq[i]>sig_cut[k/2]**2] eps_tmp,bet_tmp,alf_tmp,gam_tmp=x2twiss(x_halo) eps[k/2]=eps_tmp[k/2] bet[k/2]=bet_tmp[k/2] alf[k/2]=alf_tmp[k/2] gam[k/2]=gam_tmp[k/2] return eps,bet,alf,gam def loss_elem2den(s,loss,file_name_dt='',dlt_dt=5e-6): ''' This function calculates loss density [W/m] from s and loss together with the file of the DTL's cell and DT lengths. 2016.01.15 ''' # Define L L=[s[i]-s[i-1] for i in range(1,len(s))]; L.insert(0,0.0) # Take care DTL part if "file_name_dt" is given try: # DTL cell and DT lengths with open(file_name_dt) as file: L_cell,L_dt=array([map(float,lin.split()) for lin in file.readlines()]).transpose()[:2] # Replace cell lengths with DT lengths Ndt=0 for i in range(len(L)): dL=list(abs(L_cell-L[i])); dL_min=min(dL) if dL_min<dlt_dt: L[i]=L_dt[dL.index(dL_min)]; Ndt+=1 # Check if Ndt!=len(L_dt): print 'drift-tube # unmatched, in file: '+str(len(L_dt))+', matched: '+str(Ndt) except: pass # Take care loss in 0 length elem loss_den=loss[::] for i in range(len(loss_den)): if loss_den[i]!=0.0 and L[i]==0.0: print 'Caution: inf loss density at elem # ',i,'!!!!' for k in range(i)[::-1]: if L[k]!=0.0: loss_den[k]+=loss_den[i]; loss_den[i]=0.0; break # Calculate loss den for i in range(len(loss_den)): if loss_den[i]!=0.0: loss_den[i]/=L[i] return loss_den exit() # Define L l=[s[i+1]-s[i] for i in range(len(s)-1)]; l.insert(0,0.0) #L=[s[i+1]-s[i] for i in range(len(s)-1)]; L.insert(0,0.0) # Take care DTL part if "file_name_dt" is given try: # Read DTL cell and DT lengths with open(file_name_dt) as file: l_cell,l_dt=array([map(float,lin.split()) for lin in file.readlines()]).transpose()[:2] # Replace cell lengths with DT lengths Ndt=0 for i in range(len(l)): dl=list(abs(l_cell-l[i])); dl_min=min(dl) if dl_min<dlt_dt: l[i]=l_dt[dl.index(dl_min)]; Ndt+=1 # Check if Ndt!=len(l_cell): print 'drift-tube # unmatched, in file: '+str(len(l_cell))+', matched: '+str(Ndt) except: pass # Take care inf loss den for i in range(len(l)): if l[i]==0.0 and loss[i]!=0.0: if i==1: print 'The 1st elem has 0 length and yet has a loss, exiting...'; exit() else: k=1 while l[i-k]==0.0: k+=1 loss[i-k]+=loss[i]; loss[i]=0.0 print 'Caution: Inf loss density at elem #',i,'!!!!' # Finally, convert to loss density loss_den=[] for i in range(len(l)): if loss[i]==0.0: loss_den.append(0.0) else : loss_den.append(loss[i]/l[i]) return loss_den ## def loss_elem2den(s,loss,path_file_dt,dlt_dt=5e-6): ## ''' ## This function calculates loss density [W/m] from s, loss, ## and the file of the DTL's cell and DT lengths. ## 2015.01.30 ## ''' ## # Define l ## l=[s[i+1]-s[i] for i in range(len(s)-1)]; l.insert(0,0.0) ## # DTL cell and DT lengths. ## file=open(path_file_dt) ## l_cell,l_dt=array([map(float,lin.split()) for lin in file.readlines()]).transpose()[:2] ## file.close() ## # Replace l's in DTL with DT lengths. ## Ndt=0 ## for i in range(len(l)): ## dl=list(abs(l_cell-l[i])); dl_min=min(dl) ## if dl_min<dlt_dt: ## l[i]=l_dt[dl.index(dl_min)]; Ndt+=1 ## # Check the replacement. ## if Ndt!=len(l_cell): ## print 'drift-tube # unmatched, in file: '+str(len(l_cell))+', from matching: '+str(Ndt) ## print 'review the threshold, exiting...'; exit() ## # Treat inf loss den. ## for i in range(len(l)): ## if l[i]==0.0 and loss[i]!=0.0: ## if i==1: ## print 'The 1st elem has 0 length and yet has a loss, exiting...'; exit() ## else: ## k=1 ## while l[i-k]==0.0: k+=1 ## loss[i-k]+=loss[i]; loss[i]=0.0 ## print 'Caution: Inf loss density at elem #',i,'!!!!' ## # Finally, convert to loss density. ## loss_den=[] ## for i in range(len(l)): ## if loss[i]==0.0: loss_den.append(0.0) ## else : loss_den.append(loss[i]/l[i]) ## return loss_den def partran_end_all(file_name_in_all,file_name_out): ''' - Reads multiple partran1.out files and extracts the data at the end. - The same format as partran1.out allows to be used by PARTRAN class. - The elem # is replaced with the file #. 2015.11.25 ''' # Extract header from 1 file. with open(file_name_in_all[0],'r') as file: header='' for lin in file.readlines(): header+=lin if lin.split()[0]=='####': break # Extract output data for each file and write. with open(file_name_out,'w') as file_out: file_out.write(header) for i in range(len(file_name_in_all)): lin=check_output(['tail','-1',file_name_in_all[i]]).split() # Replace elem # with file #. file_out.write('%5s'%str(i)) # Just to maintain the same format as partran1.out. Maybe too much... for i in range(1,len(lin)): if '.' in lin[i]: file_out.write(' %13s'%lin[i]) else : file_out.write(' %10s'%lin[i]) file_out.write('\n') def _update_field_map_dict(dictionary,folder_path): import os,logging for filename in os.listdir(folder_path): if filename.split('.')[-1]=='edz': # only 1D for now.. key=filename.split('.')[0] if key not in dictionary: # do not override user selection dictionary[key]=os.path.join(folder_path,filename) logging.debug(' Found field map {}: {}'.format(key,dictionary[key])) #-------- Obsolete classes and functions #---- Old MATCH and LATTICE classes from the time of IPAC'15 (more complex) ## class MATCH: ## ''' ## Class for matching. Could be revised. ## 2015.04.26 ## ''' ## def __init__(self,typ): ## # Instances ## self.typ =typ # Need typ_knob and etc ?? ## self.i_diag=[] ## self.i_knob=[] ## # Instances for 'TRAJ' ## self.Rx_inv=None ## self.Ry_inv=None ## class LATTICE: ## ''' ## Class to handle a TraceWin lattice file. ## - For now, only for the steerer and BPM. Extend as needed. ## - For now, only for the MEBT. Extend as needed. ## - For now, reading a file for ken. Implement a method for future ?? ## 2015.04.12 ## ''' ## def __init__(self,path_file_lat,path_file_ken): ## # Consts, need to define globally ?? ## mass=938.2723; clight=2.99792458 ## # Some dict and list (MEBT and DTL are supported for now...) ## dic_class={'QUAD' : QUAD , ## 'THIN_STEERING' : THIN_STEERING , ## 'STEERER' : STEERER , ## 'DIAG_POSITION' : DIAG_POSITION , ## 'ADJUST' : ADJUST , ## 'ADJUST_STEERER': ADJUST_STEERER} ## lst_elem =['DRIFT','QUAD','GAP','DTL_CEL', ## 'THIN_STEERING','DIAG_POSITION'] ## lst_comm =['ADJUST','ADJUST_STEERER'] ## lst_diag =['DIAG_POSITION'] ## # Load ken from TW's "Energy(MeV).txt" (vs Nelem, starting from 0) ## with open(path_file_ken,'r') as file: ## ken=[] ## for lin in file: ## try : ken.append(float(lin.split()[2])) ## except: pass ## ken.insert(0,ken[0]) ## # Go through the lat file ## with open(path_file_lat) as file: ## lst=[]; i=0; Nelem=0 ## for lin in file: ## lin=lin.partition(';')[0] # Remove comment ## if lin.split()!=[]: # Remove empty line ## # Convert an elem/comm to a class (maybe too cryptic...) ## try : lst.append(dic_class[ALLTYPE(lin).typ](lin)) ## except: lst.append( ALLTYPE(lin)) ## # Assign index ## lst[-1].indx=i; i+=1 ## # Assign Nelem ## if lst[-1].typ in lst_elem: Nelem+=1 ## lst[-1].Nelem=Nelem ## # Assign gamma, beta, Brho ## gamma=1.0+ken[Nelem]/mass ; lst[-1].gamma=gamma ## beta =sqrt(1.0-1.0/gamma**2) ; lst[-1].beta =beta ## Brho =(10.0/clight)*gamma*beta*mass*1e-3; lst[-1].Brho =Brho ## # End at 'END' ## if lst[-1].typ=='END': break ## # Go through lat again and define matchings, extend/modify as needed ## match={} ## for i in range(len(lst)): ## if lst[i].typ in lst_comm: ## lst,match=lst[i].activate(lst,match) ## # Get index of diagnostics ## for i in range(len(lst)): ## if lst[i].typ in lst_diag: ## try : match[lst[i].fam].i_diag.append(i) ## except: pass ## # Instances ## self.lst =lst ## self.match=match ## def get_tw(self,path_file,flag_no_err=None): ## with open(path_file,'w') as file: ## for lst_i in self.lst: ## if 'ERROR' in lst_i.typ: ## if flag_no_err!=None: pass ## else : file.write(lst_i.get_tw()) ## else: ## file.write(lst_i.get_tw()) #---- Old DENSITY class for the envelope calc only ## class DENSITY_ENV: ## ''' ## This class is to handle Density_Env.dat. ## - For now, this is intended for an individual file and NOT "tot" file. ## (Something not clear between an individual file and "tot" file...) ## - For now, there are instances of only Nelem, s, x_ave, y_ave. ## (Add others when needed.) ## - For now, tested only for the MEBT. ## - Note there are much more data points than the total number of elems ## due to the slicing of the SC calculation. Use i_elem to extract data ## at the ends of elems, e.g., array(x_ave)[array(i_elem)]. ## 2015.03.29 ## ''' ## def __init__(self,path_file): ## # Go through the file ## Nelem=[]; s=[]; x=[] ## with open(path_file) as file: ## while True: ## try: ## ver=fromfile(file,dtype=uint16,count=3)[0] # version, year, vlong ## Nelem.append(fromfile(file,dtype=uint32,count=2)[1]) # Nrun, Nelem ## s.append(fromfile(file,dtype=float32,count=4)[1]) # Ibeam, s, aptx, apty ## fromfile(file,dtype=uint32,count=1) # Nslice ?? ## x.append(list(fromfile(file,dtype=float32,count=7*4)[:2])) # ave & etc ## if ver>=5: fromfile(file,dtype=float32,count=7*2) # ver >= 5 part ## if ver>=6: fromfile(file,dtype=float32,count=7*2) # ver >= 6 part ## if ver>=7: fromfile(file,dtype=float32,count=3*2) # ver >= 7 part ## if ver>=8: fromfile(file,dtype=float32,count=1*3) # ver >= 8 part ## fromfile(file,dtype=uint64,count=1) # Nptcl ## except: ## break ## # Index of n-th elem end, starting from 0 ## i_elem=[0] ## for n in range(1,Nelem[-1]): ## k=1 ## while True: ## try : i_elem.append(Nelem.index(n+k)-1); break ## except: k+=1 ## i_elem.append(len(Nelem)-1) ## # Instances ## self.Nelem=Nelem ## self.s =s ## self.x =list(1e3*array(x).transpose()[0]) ## self.y =list(1e3*array(x).transpose()[1]) ## # Additional instances ## self.i_elem=i_elem #---- Lattice related functions ## def clean_lat(path_file): ## ''' ## Remove comments, names, and etc from a TraceWin file. ## To convert the output to str, use: [' '.join(l)+'\n' for l in lat]. ## The current version not capitalizing. ## Output: Lattice in a list ## 2015.03.18 ## ''' ## with open(path_file) as file: ## lat=[] ## for lin in file: ## lin=lin.partition(';')[0] # Remove comment ## #lin=lin.upper().partition(';')[0] # Remove comment and capitalize ## if ':' in lin: lin=lin.partition(':')[-1].split() # Remove name ## else : lin=lin.split() ## if lin!=[]: # Avoid empty line ## lat.append(lin) ## if lin[0].upper()=='END': break ## return lat ## def get_steerer(path_file): ## ''' ## Extract steerer values from "Adjusted_Values.txt" of TraceWin. ## Note the key is the "lat elem #" where commands are not counted. ## Output is dic of {lat elem #:[val]} or {lat elem #:[val_x,val_y]} ## 2014.10.17 ## ''' ## file=open(path_file) ## i_elem=0; dic_steerer_val={} ## for lin in file.readlines(): ## lin=lin.split() ## for i in range(len(lin)): ## if lin[i]==':': ## if int(lin[i-1])!=i_elem: ## i_elem=int(lin[i-1]) ## dic_steerer_val[i_elem]=[lin[i+1]] ## else: ## dic_steerer_val[i_elem].append(lin[i+1]) ## file.close() ## return dic_steerer_val ## def apply_steerer(lat,dic_steerer_val,lst_typ_elem): ## ''' ## Apply steerer values to a TraceWin lattice. ## Input: lat from "clean_lat, steerer dic from "get_steerer", list of lat elem types ## 2014.10.17 ## ''' ## #-- ## i_elem=0; dic_steerer={} ## for i in range(len(lat)): ## if lat[i][0] in lst_typ_elem: ## i_elem+=1 ## if lat[i][0]=='STEERER': ## if i_elem+1 in dic_steerer_val.keys(): ## if len(dic_steerer_val[i_elem+1])==2: ## dic_steerer[i]=[[1,dic_steerer_val[i_elem+1][0]],[2,dic_steerer_val[i_elem+1][1]]] ## else: ## for k in range(i)[::-1]: ## if lat[k][0]=='ADJUST_STEERER_BX': ## dic_steerer[i]=[[1,dic_steerer_val[i_elem+1][0]]]; break ## if lat[k][0]=='ADJUST_STEERER_BY': ## dic_steerer[i]=[[2,dic_steerer_val[i_elem+1][0]]]; break ## if lat[i][0]=='THIN_STEERING': ## if i_elem in dic_steerer_val.keys(): ## if len(dic_steerer_val[i_elem])==2: ## dic_steerer[i]=[[1,dic_steerer_val[i_elem][0]],[2,dic_steerer_val[i_elem][1]]] ## else: ## for k in range(i)[::-1]: ## if lat[k][0]=='ADJUST' and lat[k][2]=='1': ## dic_steerer[i]=[[1,dic_steerer_val[i_elem][0]]]; break ## if lat[k][0]=='ADJUST' and lat[k][2]=='2': ## dic_steerer[i]=[[2,dic_steerer_val[i_elem][0]]]; break ## for i in sorted(dic_steerer.keys()): ## for k in range(len(dic_steerer[i])): ## lat[i][dic_steerer[i][k][0]]=dic_steerer[i][k][1] ## return lat ## def apply_multipole(lat,typ,r,b3=0.0,b4=0.0,b5=0.0,b6=0.0): ## ''' ## Apply multipole components to quads in a TraceWin lattice file. ## Note all the quads in all the sections are affected in the same way. ## Input : lat from "clean_lat, reference r, b3-b6, and dist type ## ("fix", "uniform", "gauss") ## 2015.01.08 ## ''' ## bn=(b3,b4,b5,b6) ## for i in range(len(lat)): ## if lat[i][0]=='QUAD': ## # Adjust format ## if len(lat[i])<5: ## for k in range(5): lat[i].append('0') ## else: ## lat[i]=lat[i][:5] ## for k in range(4): lat[i].append('0') ## # Fixed value ## if typ=='fix': ## for k in range(4): ## lat[i][k+5]=str( bn[k]/r**(k+1)*float(lat[i][2])) ## # Uniform dist ## if typ=='uniform': ## for k in range(4): ## lat[i][k+5]=str((2.0*rand()-1.0)*bn[k]/r**(k+1)*float(lat[i][2])) ## # Gaussian dist ## if typ=='gauss': ## for k in range(4): ## lat[i][k+5]=str( randn()*bn[k]/r**(k+1)*float(lat[i][2])) ## return lat #---- Dist related ## def partran2twiss(path_file): ## ''' ## MERGE THIS TO PARTRAN CLASS !!!! ## Extract output Twiss and halo from partran1.out ## Longitudinal phase space is z-z'. ## 2015.01.15 ## ''' ## file=open(path_file) ## for lin in file.readlines(): ## lin=lin.split() ## if lin[0]=='####': ## idx_gamma=lin.index('gama-1') ## idx_eps =[lin.index(p) for p in ("ex" ,"ey" ,"ezdp" )] ## idx_bet =[lin.index(p) for p in ("SizeX","SizeY","SizeZ")] ## idx_alf =[lin.index(p) for p in ("sxx'" ,"syy'" ,"szdp" )] ## idx_hal =[lin.index(p) for p in ("hx" ,"hy" ,"hp" )] ## file.close() ## gamma=float(lin[idx_gamma])+1.0 ## eps =array([float(lin[idx]) for idx in idx_eps]) ## bet =array([float(lin[idx])**2 for idx in idx_bet]) # Actually Sig_{i,i} ## alf =array([float(lin[idx]) for idx in idx_alf]) # Actually Sig_{i,i+1} ## hal =array([float(lin[idx]) for idx in idx_hal]) ## bet= bet/eps*sqrt(gamma**2-1.0); bet[2]*=gamma**2 # z-dp => z-z' ## alf=-alf/eps*sqrt(gamma**2-1.0) ## gam= (1.0+alf**2)/bet ## return eps,bet,alf,gam,hal ## class PROJECT_SING_CORE: ## ''' ## - Use this for simultaneous mult 1-core-simulations (w/ tracelx64). ## - Initial parameters are not meant to be changed, unlike "PROJECT". ## (Each run should have its own project.) ## - Make sure the project/lattice file is in the calc dir. ## - Changing the calc dir option not working for tracelx64. ## 2015.10.15 ## ''' ## def __init__(self,path_cal, ## file_name_proj='proj.ini',file_name_lat='lat.dat',seed=None,flag_hide=None): ## # Make sure "path_cal" ends with "/". ## if path_cal[-1]!='/': path_cal+='/' ## # Check the calc dir exists. ## if isdir(path_cal)==False: print 'Calc dir does not exist !!!! Exiting ...'; exit() ## # Check "tracelx64" is in the calc dir. ## if isfile(path_cal+'tracelx64')==False: ## try : system('cp /opt/cea/tracelx64 '+path_cal) ## except: print 'tracelx64 not in calc dir !!!! Exiting ...'; exit() ## # Check "tracewin.key" is in the calc dir. ## if isfile(path_cal+'tracewin.key')==False: ## try : system('cp /opt/cea/tracewin.key '+path_cal) ## except: print 'tracewin.key not in calc dir !!!! Exiting ...'; exit() ## # Check the project/lattice file is in the calc dir. ## if '/' not in file_name_proj: file_name_proj=path_cal+file_name_proj ## if '/' not in file_name_lat : file_name_lat =path_cal+file_name_lat ## if isfile(file_name_proj)==False: print 'project file not in calc dir !!!! Exiting ...'; exit() ## if isfile(file_name_lat) ==False: print 'lattice file not in calc dir !!!! Exiting ...'; exit() ## # Instances (Add more options as needed.) ## self.path_cal =path_cal ## self.file_name_proj=file_name_proj ## self.file_name_lat =file_name_lat ## self.seed =seed ## self.flag_hide =flag_hide ## def exe(self): ## opt_exe =self.path_cal+'tracelx64 '+self.file_name_proj ## if self.file_name_lat!=None: opt_exe+=' dat_file=' +self.file_name_lat ## if self.seed !=None: opt_exe+=' random_seed='+self.seed ## if self.flag_hide !=None: opt_exe+=' hide' ## system(opt_exe)