def build_r(ring, dp, orbit, refpts=None, mxx=None, **kwargs): """""" if ring.radiation: mt, ms = find_m66(ring, refpts=refpts, orbit=orbit, **kwargs) else: mt, ms = find_m44(ring, dp, refpts=refpts, orbit=orbit, **kwargs) a0, vps = a_matrix(mt if mxx is None else mxx) val0, vals = _r_analysis(a0, ms) return ms, vps, val0, vals
def test_find_m66(hmba_lattice, refpts): m66, mstack = physics.find_m66(hmba_lattice, refpts=refpts) expected = numpy.array( [[-0.735654, 4.673766, 0., 0., 2.997161e-3, 0.], [-9.816788e-2, -0.735654, 0., 0., 1.695263e-4, 0.], [0., 0., 0.609804, -2.096051, 0., 0.], [0., 0., 0.299679, 0.609799, 0., 0.], [0., 0., 0., 0., 1., 0.], [1.695128e-4, 2.997255e-3, 0., 0., 2.243281e-3, 1.]]) numpy.testing.assert_allclose(m66, expected, rtol=1e-5, atol=1e-7) stack_size = 0 if refpts is None else len(refpts) assert mstack.shape == (stack_size, 6, 6)
def ohmi_envelope(ring, refpts=None, orbit=None, keep_lattice=False): """ Calculate the equilibrium beam envelope in a circular accelerator using Ohmi's beam envelope formalism [1] emit0, beamdata, emit = ohmi_envelope(ring[, refpts]) PARAMETERS ring Lattice object. refpts=None elements at which data is returned. It can be: 1) an integer in the range [-len(ring), len(ring)-1] selecting the element according to python indexing rules. As a special case, len(ring) is allowed and refers to the end of the last element, 2) an ordered list of such integers without duplicates, 3) a numpy array of booleans of maximum length len(ring)+1, where selected elements are True. KEYWORDS orbit=None Avoids looking for the closed orbit if it is already known ((6,) array) keep_lattice=False Assume no lattice change since the previous tracking OUTPUT emit0 emittance data at the start/end of the ring beamdata beam parameters at the start of the ring emit emittance data at the points refered to by refpts, if refpts is None an empty structure is returned. emit is a record array with fields: r66 (6, 6) equilibrium envelope matrix R r44 (4, 4) betatron emittance matrix (dpp = 0) m66 (6, 6) transfer matrix from the start of the ring orbit6 (6,) closed orbit emitXY (2,) betatron emittance projected on xxp and yyp emitXYZ (3,) 6x6 emittance projected on xxp, yyp, ldp beamdata is a record array with fields: tunes tunes of the 3 normal modes damping_rates damping rates of the 3 normal modes mode_matrices R-matrices of the 3 normal modes mode_emittances equilibrium emittances of the 3 normal modes Field values can be obtained with either emit['r66'] or emit.r66 REFERENCES [1] K.Ohmi et al. Phys.Rev.E. Vol.49. (1994) """ def process(r66): # projections on xx', zz', ldp emit3sq = numpy.array([det(r66[s, s]) for s in _submat]) # Prevent from unrealistic negative values of the determinant emit3 = numpy.sqrt(numpy.maximum(emit3sq, 0.0)) # Emittance cut for dpp=0 if emit3[0] < 1.E-13: # No equilibrium emittance r44 = numpy.nan * numpy.ones((4, 4)) elif emit3[1] < 1.E-13: # Uncoupled machine minv = inv(r66[[0, 1, 4, 5], :][:, [0, 1, 4, 5]]) r44 = numpy.zeros((4, 4)) r44[:2, :2] = inv(minv[:2, :2]) else: # Coupled machine minv = inv(r66) r44 = inv(minv[:4, :4]) # betatron emittances (dpp=0) emit2sq = numpy.array( [det(r44[s, s], check_finite=False) for s in _submat[:2]]) # Prevent from unrealistic negative values of the determinant emit2 = numpy.sqrt(numpy.maximum(emit2sq, 0.0)) return r44, emit2, emit3 def propag(m, cumb, orbit6): """Propagate the beam matrix to refpts""" sigmatrix = m.dot(rr).dot(m.T) + cumb m44, emit2, emit3 = process(sigmatrix) return sigmatrix, m44, m, orbit6, emit2, emit3 nelems = len(ring) uint32refs = uint32_refpts(refpts, nelems) bbcum, orbs = _dmatr(ring, orbit=orbit, keep_lattice=keep_lattice) mring, ms = find_m66(ring, uint32refs, orbit=orbs[0], keep_lattice=True) # ------------------------------------------------------------------------ # Equation for the moment matrix R is # R = MRING*R*MRING' + BCUM; # We rewrite it in the form of Lyapunov-Sylvester equation to use scipy's # solve_sylvester function # A*R + R*B = Q # where # A = inv(MRING) # B = -MRING' # Q = inv(MRING)*BCUM # ------------------------------------------------------------------------ aa = inv(mring) bb = -mring.T qq = numpy.dot(aa, bbcum[-1]) rr = solve_sylvester(aa, bb, qq) rr = 0.5 * (rr + rr.T) rr4, emitxy, emitxyz = process(rr) r66data = get_tunes_damp(mring, rr) data0 = numpy.rec.fromarrays( (rr, rr4, mring, orbs[0], emitxy, emitxyz), dtype=ENVELOPE_DTYPE) if uint32refs.shape == (0,): data = numpy.recarray((0,), dtype=ENVELOPE_DTYPE) else: data = numpy.rec.fromrecords( list(map(propag, ms, bbcum[uint32refs], orbs[uint32refs, :])), dtype=ENVELOPE_DTYPE) return data0, r66data, data
def test_find_m66(hmba_lattice, refpts): hmba_lattice = hmba_lattice.radiation_on(copy=True) m66, mstack = physics.find_m66(hmba_lattice, refpts=refpts) assert_close(m66, M66_MATLAB, rtol=0, atol=1e-8) stack_size = 0 if refpts is None else len(refpts) assert mstack.shape == (stack_size, 6, 6)