def tapering(ring, multipoles=True, niter=1, **kwargs): """ Scales magnet strength with local energy to cancel the closed orbit and optics errors due to synchrotron radiations. PolynomB is used for dipoles such that the machine geometry is maintained. This is the ideal tapering scheme where magnets and multipoles components (PolynomB and PolynomA) are scaled individually. !!! WARNING: This method works only for lattices without errors and corrections: if not all corrections and field errors will also be scaled !!! tapering(ring) or ring.tapering() PARAMETERS ring lattice description. KEYWORDS multipoles=True scale all multipoles niter=1 number of iteration XYStep=1.0e-8 transverse step for numerical computation DPStep=1.0E-6 momentum deviation used for computation of orbit6 """ xy_step = kwargs.pop('XYStep', DConstant.XYStep) dp_step = kwargs.pop('DPStep', DConstant.DPStep) dipoles = get_refpts(ring, Dipole) b0 = get_value_refpts(ring, dipoles, 'BendingAngle') k0 = get_value_refpts(ring, dipoles, 'PolynomB', index=0) ld = get_value_refpts(ring, dipoles, 'Length') for i in range(niter): _, o6 = find_orbit6(ring, refpts=range(len(ring) + 1), XYStep=xy_step, DPStep=dp_step) dpps = (o6[dipoles, 4] + o6[dipoles + 1, 4]) / 2 set_value_refpts(ring, dipoles, 'PolynomB', b0 / ld * dpps + k0 * (1 + dpps), index=0) if multipoles: mults = get_refpts(ring, Multipole) k0 = get_value_refpts(ring, dipoles, 'PolynomB', index=0) _, o6 = find_orbit6(ring, refpts=range(len(ring) + 1), XYStep=xy_step, DPStep=dp_step) dpps = (o6[mults, 4] + o6[mults + 1, 4]) / 2 for dpp, el in zip(dpps, ring[mults]): el.PolynomB *= 1 + dpp el.PolynomA *= 1 + dpp set_value_refpts(ring, dipoles, 'PolynomB', k0, index=0)
def fast_ring(ring, split_inds=[]): all_rings = rearrange(ring, split_inds=split_inds) ringnorad, ringrad = merge_rings(all_rings) ibegs = get_refpts(ringnorad, 'xbeg') iends = get_refpts(ringnorad, 'xend') markers = numpy.sort(numpy.concatenate((ibegs, iends))) _, orbit4 = ringnorad.find_sync_orbit(dct=0.0, refpts=markers) _, orbit6 = ringrad.find_orbit6(refpts=markers) detuning_elem = gen_detuning_elem(ringnorad, orbit4[-1]) detuning_elem_rad = detuning_elem.deepcopy() detuning_elem_rad.T1 = -orbit6[-1] detuning_elem_rad.T2 = orbit6[-1] for counter, ring_slice in enumerate(all_rings): ibeg = get_refpts(ring_slice, 'xbeg')[0] iend = get_refpts(ring_slice, 'xend')[0] cavs = ring_slice[:ibeg] ring_slice = ring_slice[ibeg:iend] ring_slice_rad = ring_slice.deepcopy() if ring_slice.radiation: ring_slice.radiation_off(quadrupole_pass='******') else: ring_slice_rad.radiation_on(quadrupole_pass='******') lin_elem = gen_m66_elem(ring_slice, orbit4[2 * counter], orbit4[2 * counter + 1]) lin_elem.FamName = lin_elem.FamName + '_' + str(counter) qd_elem = gen_quantdiff_elem(ring_slice_rad, orbit=orbit6[2 * counter]) qd_elem.FamName = qd_elem.FamName + '_' + str(counter) lin_elem_rad = gen_m66_elem(ring_slice_rad, orbit6[2 * counter], orbit6[2 * counter + 1]) lin_elem_rad.FamName = lin_elem_rad.FamName + '_' + str(counter) [ringnorad.append(cav) for cav in cavs] ringnorad.append(lin_elem) [ringrad.append(cav) for cav in cavs] ringrad.append(lin_elem_rad) ringrad.append(qd_elem) ringnorad.append(detuning_elem) ringrad.append(detuning_elem_rad) del ringnorad[:markers[-1] + 1] del ringrad[:markers[-1] + 1] return ringnorad, ringrad
def rearrange(ring, split_inds=[]): iends = numpy.concatenate((split_inds, [len(ring) + 1])) ibegs = numpy.concatenate(([0], iends[:-1])) iends = iends[iends != 0] ibegs = ibegs[ibegs != len(ring) + 1] all_rings = [ring[int(ibeg):int(iend)] for ibeg, iend in zip(ibegs, iends)] for ring_slice in all_rings: # replace cavity with length > 0 with drift # set cavity length to 0 and move to start icav = get_refpts(ring_slice, RFCavity) for i in numpy.arange(len(icav)): cav_elem = ring_slice.pop(int(icav[i])) if cav_elem.Length != 0: cavdrift = Drift('CavDrift', cav_elem.Length) ring_slice.insert(icav[i], cavdrift) icav = icav + 1 cav_elem.Length = 0.0 ring_slice.insert(0, cav_elem) # merge all cavities with the same frequency icav = get_refpts(ring_slice, RFCavity) all_freq = numpy.array([ring_slice[ic].Frequency for ic in icav]) all_volt = numpy.array([ring_slice[ic].Voltage for ic in icav]) uni_freq = numpy.unique(all_freq) for ii in numpy.arange(len(uni_freq)): fr = uni_freq[ii] cavmsk = all_freq == fr vol = numpy.sum(all_volt[cavmsk]) ring_slice[ii].Frequency = fr ring_slice[ii].Voltage = vol for pp in numpy.arange(len(icav) - len(uni_freq)): ring_slice.pop(len(uni_freq)) ring_slice.insert(len(uni_freq), Marker('xbeg')) ring_slice.append(Marker('xend')) return all_rings
def gen_m66_elem(ring, o4b, o4e): """ converts a ring to a linear 6x6 matrix tracking elemtn """ dip_inds = get_refpts(ring, Bend) theta = numpy.array([ring[ind].BendingAngle for ind in dip_inds]) lendp = numpy.array([ring[ind].Length for ind in dip_inds]) allS = ring.get_s_pos() s = numpy.diff(numpy.array([allS[0], allS[-1]]))[0] I2 = numpy.sum(numpy.abs(theta * theta / lendp)) m66_mat, _ = find_m66(ring, [], o4b) if ring.radiation is False: m66_mat = symplectify(m66_mat) # remove for damping lin_elem = M66('Linear', m66_mat, T1=-o4b, T2=o4e, Length=s, I2=I2) return lin_elem