def calc_emittance_coupling(accelerator): # I copied the code below from: # http://nicky.vanforeest.com/misc/fitEllipse/fitEllipse.html def fitEllipse(x,y): x = x[:,_np.newaxis] y = y[:,_np.newaxis] D = _np.hstack((x*x, x*y, y*y, x, y, _np.ones_like(x))) S = _np.dot(D.T,D) C = _np.zeros([6,6]) C[0,2] = C[2,0] = 2; C[1,1] = -1 E, V = _np.linalg.eig(_np.linalg.solve(S, C)) n = _np.argmax(_np.abs(E)) a = V[:,n] b,c,d,f,g,a = a[1]/2, a[2], a[3]/2, a[4]/2, a[5], a[0] up = 2*(a*f*f+c*d*d+g*b*b-2*b*d*f-a*c*g) down1 = (b*b-a*c)*( (c-a)*_np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a)) down2 = (b*b-a*c)*( (a-c)*_np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a)) res1 = _np.sqrt(up/down1) res2 = _np.sqrt(up/down2) return _np.array([res1, res2]) #returns the axes of the ellipse acc = accelerator[:] acc.cavity_on = False acc.radiation_on = False orb = _tracking.findorbit4(acc) rin = _np.array([2e-5+orb[0],0+orb[1],1e-8+orb[2],0+orb[3],0,0],dtype=float) rout, *_ = _tracking.ringpass(acc, rin, nr_turns=100, turn_by_turn='closed',element_offset = 0) r = _np.dstack([rin[None,:,None],rout]) ax,bx = fitEllipse(r[0][0],r[0][1]) ay,by = fitEllipse(r[0][2],r[0][3]) return (ay*by) / (ax*bx) # ey/ex
def get_mcf(accelerator, order=1, energy_offset=None): """Return momentum compaction factor of the accelerator""" if energy_offset is None: energy_offset = _np.linspace(-1e-3,1e-3,11) accel=accelerator[:] _tracking.set4dtracking(accel) ring_length = _lattice.length(accel) dl = _np.zeros(_np.size(energy_offset)) for i in range(len(energy_offset)): fp = _tracking.findorbit4(accel,energy_offset[i]) X0 = _np.concatenate([fp,[energy_offset[i],0]]).tolist() T = _tracking.ringpass(accel,X0) dl[i] = T[0][5]/ring_length polynom = _np.polyfit(energy_offset,dl,order) a = _np.fliplr([polynom])[0].tolist() a = a[1:] if len(a) == 1: a=a[0] return a
def old_calc_twiss(accelerator=None, init_twiss=None, fixed_point=None, indices = 'open'): """Return Twiss parameters of uncoupled dynamics. Keyword arguments: accelerator -- Accelerator object init_twiss -- Twiss parameters at the start of first element fixed_point -- 6D position at the start of first element indices -- Open or closed Returns: tw -- list of Twiss objects m66 transfer_matrices closed_orbit """ if indices == 'open': length = len(accelerator) elif indices == 'closed': length = len(accelerator)+1 else: raise OpticsException("invalid value for 'indices' in calc_twiss") if init_twiss is not None: ''' as a transport line: uses init_twiss ''' if fixed_point is None: fixed_point = init_twiss.fixed_point else: raise OpticsException('arguments init_twiss and fixed_orbit are mutually exclusive') closed_orbit, *_ = _tracking.linepass(accelerator, particles=list(fixed_point), indices='open') m66, cumul_trans_matrices = _tracking.findm66(accelerator, closed_orbit=closed_orbit) if indices == 'closed': orb, *_ = _tracking.linepass(accelerator[-1:], particles=closed_orbit[:,-1]) closed_orbit = _np.append(closed_orbit,orb.transpose(),axis=1) mx, my = m66[0:2, 0:2], m66[2:4, 2:4] t = init_twiss t.etax = _np.array([[t.etax], [t.etapx]]) t.etay = _np.array([[t.etay], [t.etapy]]) else: ''' as a periodic system: try to find periodic solution ''' if accelerator.harmonic_number == 0: raise OpticsException('Either harmonic number was not set or calc_twiss was' 'invoked for transport line without initial twiss') if fixed_point is None: if not accelerator.cavity_on and not accelerator.radiation_on: closed_orbit = _np.zeros((6,length)) closed_orbit[:4,:] = _tracking.findorbit4(accelerator, indices=indices) elif not accelerator.cavity_on and accelerator.radiation_on: raise OpticsException('The radiation is on but the cavity is off') else: closed_orbit = _tracking.findorbit6(accelerator, indices=indices) else: closed_orbit, *_ = _tracking.linepass(accelerator, particles=list(fixed_point), indices=indices) ''' calcs twiss at first element ''' orbit = closed_orbit[:,:-1] if indices == 'closed' else closed_orbit m66, cumul_trans_matrices, *_ = _tracking.findm66(accelerator, closed_orbit=orbit) mx, my = m66[0:2,0:2], m66[2:4,2:4] # decoupled transfer matrices trace_x, trace_y, *_ = get_traces(accelerator, m66 = m66, closed_orbit=closed_orbit) if not (-2.0 < trace_x < 2.0): raise OpticsException('horizontal dynamics is unstable') if not (-2.0 < trace_y < 2.0): raise OpticsException('vertical dynamics is unstable') sin_nux = _math.copysign(1,mx[0,1]) * _math.sqrt(-mx[0,1] * mx[1,0] - ((mx[0,0] - mx[1,1])**2)/4); sin_nuy = _math.copysign(1,my[0,1]) * _math.sqrt(-my[0,1] * my[1,0] - ((my[0,0] - my[1,1])**2)/4); fp = closed_orbit[:,0] t = Twiss() t.spos = 0 t.rx, t.px = fixed_point[0], fixed_point[1] t.ry, t.py = fixed_point[2], fixed_point[3] t.de, t.dl = fixed_point[4], fixed_point[5] t.alphax = (mx[0,0] - mx[1,1]) / 2 / sin_nux t.betax = mx[0,1] / sin_nux t.alphay = (my[0,0] - my[1,1]) / 2 / sin_nuy t.betay = my[0,1] / sin_nuy ''' dispersion function based on eta = (1 - M)^(-1) D ''' Dx = _np.array([[m66[0,4]],[m66[1,4]]]) Dy = _np.array([[m66[2,4]],[m66[3,4]]]) t.etax = _np.linalg.solve(_np.eye(2,2) - mx, Dx) t.etay = _np.linalg.solve(_np.eye(2,2) - my, Dy) ''' get transfer matrices from cumulative transfer matrices ''' transfer_matrices = [] m66_prev = _np.eye(6,6) cumul_trans_matrices.append(m66) for m66_this in cumul_trans_matrices[1:]: # Matrices at start of elements inv_m66_prev = _np.linalg.inv(m66_prev) tm = _np.dot(m66_this, inv_m66_prev) #tm = _np.linalg.solve(m66_prev.T, m66_this.T).T # Fernando, you may uncomment this line when running YOUR code! aushuashuahs m66_prev = m66_this transfer_matrices.append(tm) ''' propagates twiss through line ''' tw = [t] m_previous = _np.eye(6,6) for i in range(1, length): m = transfer_matrices[i-1] mx, my = m[0:2,0:2], m[2:4,2:4] # decoupled transfer matrices Dx = _np.array([[m[0,4]],[m[1,4]]]) Dy = _np.array([[m[2,4]],[m[3,4]]]) n = Twiss() n.spos = t.spos + accelerator[i-1].length fp = closed_orbit[:,i] n.rx, n.px = fixed_point[0], fixed_point[1] n.ry, n.py = fixed_point[2], fixed_point[3] n.de, n.dl = fixed_point[4], fixed_point[5] n.betax = ((mx[0,0] * t.betax - mx[0,1] * t.alphax)**2 + mx[0,1]**2) / t.betax n.alphax = -((mx[0,0] * t.betax - mx[0,1] * t.alphax) * (mx[1,0] * t.betax - mx[1,1] * t.alphax) + mx[0,1] * mx[1,1]) / t.betax n.betay = ((my[0,0] * t.betay - my[0,1] * t.alphay)**2 + my[0,1]**2) / t.betay n.alphay = -((my[0,0] * t.betay - my[0,1] * t.alphay) * (my[1,0] * t.betay - my[1,1] * t.alphay) + my[0,1] * my[1,1]) / t.betay ''' calcs phase advance based on R(mu) = U(2) M(2|1) U^-1(1) ''' sint = mx[0,1]/_math.sqrt(n.betax * t.betax) cost = (mx[0,0] * t.betax - mx[0,1] * t.alphax)/_math.sqrt(n.betax * t.betax) dmux = _math.atan2(sint, cost) n.mux = t.mux + dmux sint = my[0,1]/_math.sqrt(n.betay * t.betay) cost = (my[0,0] * t.betay - my[0,1] * t.alphay)/_math.sqrt(n.betay * t.betay) dmuy = _math.atan2(sint, cost) n.muy = t.muy + dmuy ''' when phase advance in an element is over PI atan2 returns a negative value that has to be corrected by adding 2*PI''' if dmux < 0 and dmux < -10*_sys.float_info.epsilon: n.mux += 2*_math.pi if dmuy < 0 and dmuy < -10*_sys.float_info.epsilon: n.muy += 2*_math.pi ''' dispersion function''' n.etax = Dx + _np.dot(mx, t.etax) n.etay = Dy + _np.dot(my, t.etay) tw.append(n) t = n.make_copy() ''' converts eta format ''' for t in tw: t.etapx, t.etapy = (t.etax[1,0], t.etay[1,0]) t.etax, t.etay = (t.etax[0,0], t.etay[0,0]) return tw, m66, transfer_matrices, closed_orbit