def setUp(self): self.general_params = Ring(np.ones(self.n_sections) * self.C/self.n_sections, np.tile(self.momentum_compaction, (1, self.n_sections)).T, np.tile(self.sync_momentum, (self.n_sections, self.n_turns+1)), self.particle_type, self.n_turns, n_sections=self.n_sections) self.RF_sct_par = [] self.RF_sct_par_cpp = [] for i in np.arange(self.n_sections)+1: self.RF_sct_par.append(RFStation(self.general_params, [self.harmonic_numbers], [ self.voltage_program/self.n_sections], [self.phi_offset], self.n_rf_systems, section_index=i)) self.RF_sct_par_cpp.append(RFStation(self.general_params, [self.harmonic_numbers], [ self.voltage_program/self.n_sections], [self.phi_offset], self.n_rf_systems, section_index=i)) # DEFINE BEAM------------------------------------------------------------------ self.beam = Beam(self.general_params, self.n_macroparticles, self.n_particles) self.beam_cpp = Beam(self.general_params, self.n_macroparticles, self.n_particles) # DEFINE SLICES---------------------------------------------------------------- number_slices = 500 cut_options = CutOptions( cut_left=0., cut_right=self.bucket_length, n_slices=number_slices) self.slice_beam = Profile(self.beam, CutOptions=cut_options) self.slice_beam_cpp = Profile(self.beam_cpp, CutOptions=cut_options) # DEFINE TRACKER--------------------------------------------------------------- self.longitudinal_tracker = [] self.longitudinal_tracker_cpp = [] for i in range(self.n_sections): self.longitudinal_tracker.append(RingAndRFTracker( self.RF_sct_par[i], self.beam, Profile=self.slice_beam)) self.longitudinal_tracker_cpp.append(RingAndRFTracker( self.RF_sct_par_cpp[i], self.beam_cpp, Profile=self.slice_beam_cpp)) full_tracker = FullRingAndRF(self.longitudinal_tracker) full_tracker_cpp = FullRingAndRF(self.longitudinal_tracker_cpp) # BEAM GENERATION-------------------------------------------------------------- matched_from_distribution_function(self.beam, full_tracker, emittance=self.emittance, distribution_type=self.distribution_type, distribution_variable=self.distribution_variable, seed=1000) matched_from_distribution_function(self.beam_cpp, full_tracker_cpp, emittance=self.emittance, distribution_type=self.distribution_type, distribution_variable=self.distribution_variable, seed=1000) self.slice_beam.track() self.slice_beam_cpp.track()
class TestRfVoltageCalc(unittest.TestCase): # Simulation parameters ------------------------------------------------------- # Bunch parameters N_b = 1e9 # Intensity N_p = 50000 # Macro-particles tau_0 = 0.4e-9 # Initial bunch length, 4 sigma [s] # Machine and RF parameters C = 26658.883 # Machine circumference [m] p_i = 450e9 # Synchronous momentum [eV/c] p_f = 460.005e9 # Synchronous momentum, final h = 35640 # Harmonic number V = 6e6 # RF voltage [V] dphi = 0 # Phase modulation/offset gamma_t = 55.759505 # Transition gamma alpha = 1./gamma_t/gamma_t # First order mom. comp. factor # Tracking details N_t = 2000 # Number of turns to track # Run before every test def setUp(self): self.ring = Ring(self.C, self.alpha, np.linspace( self.p_i, self.p_f, self.N_t + 1), Proton(), self.N_t) self.beam = Beam(self.ring, self.N_p, self.N_b) self.rf = RFStation( self.ring, [self.h], self.V * np.linspace(1, 1.1, self.N_t+1), [self.dphi]) bigaussian(self.ring, self.rf, self.beam, self.tau_0/4, reinsertion=True, seed=1) self.profile = Profile(self.beam, CutOptions(n_slices=100, cut_left=0, cut_right=self.rf.t_rf[0, 0]), FitOptions(fit_option='gaussian')) self.long_tracker = RingAndRFTracker( self.rf, self.beam, Profile=self.profile) # Run after every test def tearDown(self): pass def test_rf_voltage_calc_1(self): self.long_tracker.rf_voltage_calculation() orig_rf_voltage = orig_rf_volt_comp(self.long_tracker) np.testing.assert_almost_equal( self.long_tracker.rf_voltage, orig_rf_voltage, decimal=8) def test_rf_voltage_calc_2(self): for i in range(100): self.long_tracker.rf_voltage_calculation() orig_rf_voltage = orig_rf_volt_comp(self.long_tracker) np.testing.assert_almost_equal( self.long_tracker.rf_voltage, orig_rf_voltage, decimal=8) def test_rf_voltage_calc_3(self): for i in range(100): self.profile.track() self.long_tracker.track() self.long_tracker.rf_voltage_calculation() orig_rf_voltage = orig_rf_volt_comp(self.long_tracker) np.testing.assert_almost_equal( self.long_tracker.rf_voltage, orig_rf_voltage, decimal=8)
def setUp(self): initial_time = 0 final_time = 1E-3 # Machine and RF parameters radius = 25 gamma_transition = 4.4 # [1] C = 2 * np.pi * radius # [m] momentum_compaction = 1 / gamma_transition**2 # [1] particle_type = 'proton' self.ring = Ring(C, momentum_compaction, \ ([0, 1E-3], [3.13E8, 3.13E8]), Proton()) self.rf_params = RFStation(self.ring, [1], [1E3], [np.pi], 1) self.beam = Beam(self.ring, 1, 0) self.profile = Profile(self.beam) self.long_tracker = RingAndRFTracker(self.rf_params, self.beam) self.full_ring = FullRingAndRF([self.long_tracker]) self.n_turns = self.ring.n_turns self.map_ = [self.full_ring.track, self.profile.track] self.trackIt = TrackIteration(self.map_)
def test_4(self): # Create a batch of 100 equal, short bunches bunches = 100 T_s = 5 * self.rf.t_rev[0] / self.rf.harmonic[0, 0] N_m = int(1e5) N_b = 2.3e11 bigaussian(self.ring, self.rf, self.beam, 0.1e-9, seed=1234, reinsertion=True) beam2 = Beam(self.ring, bunches * N_m, bunches * N_b) bunch_spacing = 5 * self.rf.t_rf[0, 0] buckets = 5 * bunches for i in range(bunches): beam2.dt[i * N_m:(i + 1) * N_m] = self.beam.dt + i * bunch_spacing beam2.dE[i * N_m:(i + 1) * N_m] = self.beam.dE profile2 = Profile(beam2, CutOptions=CutOptions(cut_left=0, cut_right=bunches * bunch_spacing, n_slices=1000 * buckets)) profile2.track() tot_charges = np.sum(profile2.n_macroparticles)/\ beam2.n_macroparticles*beam2.intensity self.assertAlmostEqual(tot_charges, 2.3000000000e+13, 9) # Calculate fine- and coarse-grid RF current rf_current_fine, rf_current_coarse = rf_beam_current( profile2, self.rf.omega_rf[0, 0], self.ring.t_rev[0], lpf=False, downsample={ 'Ts': T_s, 'points': self.rf.harmonic[0, 0] / 5 }) rf_current_coarse /= T_s # Peak RF current on coarse grid peak_rf_current = np.max(np.absolute(rf_current_coarse)) self.assertAlmostEqual(peak_rf_current, 2.9285808008, 7)
def setUp(self): self.ring = Ring(self.C, self.alpha, np.linspace( self.p_i, self.p_f, self.N_t + 1), Proton(), self.N_t) self.beam = Beam(self.ring, self.N_p, self.N_b) self.rf = RFStation( self.ring, [self.h], self.V * np.linspace(1, 1.1, self.N_t+1), [self.dphi]) bigaussian(self.ring, self.rf, self.beam, self.tau_0/4, reinsertion=True, seed=1) self.profile = Profile(self.beam, CutOptions(n_slices=100, cut_left=0, cut_right=self.rf.t_rf[0, 0]), FitOptions(fit_option='gaussian')) self.long_tracker = RingAndRFTracker( self.rf, self.beam, Profile=self.profile)
def setUp(self): self.ring = Ring(self.C, self.alpha, np.linspace(self.p_i, self.p_f, self.N_t + 1), Proton(), self.N_t) self.beam = Beam(self.ring, self.N_p, self.N_b) self.rf = RFStation(self.ring, [self.h], self.V * np.linspace(1, 1.1, self.N_t + 1), [self.dphi]) bigaussian(self.ring, self.rf, self.beam, self.tau_0 / 4, reinsertion=True, seed=1) self.profile = Profile( self.beam, CutOptions(n_slices=100, cut_left=0, cut_right=self.rf.t_rf[0, 0]), FitOptions(fit_option='gaussian')) self.long_tracker = RingAndRFTracker(self.rf, self.beam, Profile=self.profile)
def setUp(self): C = 2 * np.pi * 1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1 / gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] N_m = 1e5 # Number of macro-particles for tracking N_b = 1.0e11 # Bunch intensity [ppb] # Set up machine parameters self.ring = Ring(C, alpha, p_s, Proton(), n_turns=1) # RF-frequency at which to compute beam current self.omega = 2 * np.pi * 200.222e6 # Create Gaussian beam self.beam = Beam(self.ring, N_m, N_b) self.profile = Profile(self.beam, CutOptions=CutOptions(cut_left=-1.e-9, n_slices=100, cut_right=6.e-9))
def setUp(self): n_turns = 200 intensity_pb = 1.2e6 # protons per bunch n_macroparticles = int(1e6) # macropartilces per bunch sigma = 0.05e-9 # sigma for gaussian bunch [s] self.time_offset = 0.1e-9 # time by which to offset the bunch # Ring parameters SPS C = 6911.5038 # Machine circumference [m] sync_momentum = 25.92e9 # SPS momentum at injection [eV/c] gamma_transition = 17.95142852 # Q20 Transition gamma momentum_compaction = 1./gamma_transition**2 # Momentum compaction array self.ring = Ring(C, momentum_compaction, sync_momentum, Proton(), n_turns=n_turns) # RF parameters SPS harmonic = 4620 # Harmonic numbers voltage = 4.5e6 # [V] phi_offsets = 0 self.rf_station = RFStation(self.ring, harmonic, voltage, phi_offsets) t_rf = self.rf_station.t_rf[0, 0] # Beam setup self.beam = Beam(self.ring, n_macroparticles, intensity_pb) bigaussian(self.ring, self.rf_station, self.beam, sigma, seed=1234, reinsertion=True) # displace beam to see effect of phase error and phase loop self.beam.dt += self.time_offset # Profile setup self.profile = Profile(self.beam, CutOptions=CutOptions(cut_left=0, cut_right=t_rf, n_slices=1024))
def setUp(self): C = 2*np.pi*1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1/gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] N_m = 1e5 # Number of macro-particles for tracking N_b = 1.0e11 # Bunch intensity [ppb] # Set up machine parameters self.ring = Ring(C, alpha, p_s, Proton(), n_turns=1) # RF-frequency at which to compute beam current self.omega = 2*np.pi*200.222e6 # Create Gaussian beam self.beam = Beam(self.ring, N_m, N_b) self.profile = Profile( self.beam, CutOptions=CutOptions(cut_left=-1.e-9, n_slices=100, cut_right=6.e-9))
def setUp(self): # Bunch parameters (dummy) N_b = 1e9 # Intensity N_p = 50000 # Macro-particles # Machine and RF parameters C = 26658.883 # Machine circumference [m] p_s = 450e9 # Synchronous momentum [eV/c] h = 35640 # Harmonic number V = 4e6 # RF voltage [V] dphi = 0 # Phase modulation/offset gamma_t = 53.8 # Transition gamma alpha = 1 / gamma_t**2 # First order mom. comp. factor # Initialise necessary classes ring = Ring(C, alpha, p_s, Particle=Proton(), n_turns=1) self.rf = RFStation(ring, [h], [V], [dphi]) beam = Beam(ring, N_p, N_b) self.profile = Profile(beam) # Test in open loop, on tune self.RFFB = LHCRFFeedback(open_drive=True) self.f_c = self.rf.omega_rf[0, 0] / (2 * np.pi)
def setUp(self): n_turns = 200 intensity_pb = 1.2e6 # protons per bunch n_macroparticles = int(1e6) # macropartilces per bunch sigma = 0.05e-9 # sigma for gaussian bunch [s] self.time_offset = 0.1e-9 # time by which to offset the bunch # Ring parameters SPS C = 6911.5038 # Machine circumference [m] sync_momentum = 25.92e9 # SPS momentum at injection [eV/c] gamma_transition = 17.95142852 # Q20 Transition gamma momentum_compaction = 1./gamma_transition**2 # Momentum compaction array self.ring = Ring(C, momentum_compaction, sync_momentum, Proton(), n_turns=n_turns) # RF parameters SPS harmonic = 4620 # Harmonic numbers voltage = 4.5e6 # [V] phi_offsets = 0 self.rf_station = RFStation(self.ring, harmonic, voltage, phi_offsets) t_rf = self.rf_station.t_rf[0,0] # Beam setup self.beam = Beam(self.ring, n_macroparticles, intensity_pb) bigaussian(self.ring, self.rf_station, self.beam, sigma, seed = 1234, reinsertion = True) ### displace beam to see effect of phase error and phase loop self.beam.dt += self.time_offset # Profile setup self.profile = Profile(self.beam, CutOptions = CutOptions(cut_left=0, cut_right=t_rf, n_slices=1024))
bunch = Beam(ring, n_particles, N_b) beam = Beam(ring, n_particles*n_bunches, N_b) bigaussian(ring, rf, bunch, 0.3e-9, reinsertion=True, seed=seed) bunch_spacing_buckets = 10 for i in np.arange(n_bunches): beam.dt[i*n_particles:(i+1) * n_particles] = bunch.dt[0:n_particles] + i*rf.t_rf[0, 0]*10 beam.dE[i*n_particles:(i+1)*n_particles] = bunch.dE[0:n_particles] # Profile required for PL cutRange = (n_bunches-1)*25.e-9+3.5e-9 n_slices = np.int(cutRange/0.025e-9 + 1) n_slices = next_regular(n_slices) profile = Profile(beam, CutOptions(n_slices=n_slices, cut_left=-0.5e-9, cut_right=(cutRange-0.5e-9))) mpiprint("Beam generated, profile set...") mpiprint("Using %d slices" % n_slices) # Define emittance BUP feedback noiseFB = LHCNoiseFB(rf, profile, bl_target) mpiprint("Phase noise feedback set...") # Define phase loop and frequency loop gain PL_gain = 1./(5.*ring.t_rev[0]) SL_gain = PL_gain/10. # Noise injected in the PL delayed by one turn and opposite sign config = {'machine': 'LHC', 'PL_gain': PL_gain, 'SL_gain': SL_gain} PL = BeamFeedback(ring, rf, profile, config, PhaseNoise=LHCnoise, LHCNoiseFB=noiseFB)
long_tracker = RingAndRFTracker(rf_params, beam) eta_0_test = rf_params.eta_0 #: *Slippage factor (0th order) for the given RF section* eta_1_test = rf_params.eta_1 #: *Slippage factor (1st order) for the given RF section* eta_2_test = rf_params.eta_2 #: *Slippage factor (2nd order) for the given RF section* alpha_order_test = rf_params.alpha_order bigaussian(general_params, rf_params, beam, tau_0 / 4, reinsertion='on', seed=1) # Need slices for the Gaussian fit slice_beam = Profile(beam, CutOptions(n_slices=100)) # Define what to save in file bunchmonitor = BunchMonitor(general_params, rf_params, beam, this_directory + '../output_files/EX_07_output_data', Profile=slice_beam) format_options = {'dirname': this_directory + '../output_files/EX_07_fig'} plots = Plot(general_params, rf_params, beam, dt_plt, N_t,
beam_dummy = Beam(general_params, 1, N_b) long_tracker_tot = RingAndRFTracker(rf_params_tot, beam_dummy) print("General and RF parameters set...") # Define beam and distribution bigaussian(general_params, rf_params_tot, beam, tau_0/4, reinsertion = 'on', seed=1) print("Beam set and distribution generated...") # Need slices for the Gaussian fit; slice for the first plot slice_beam = Profile(beam, CutOptions(n_slices=100), FitOptions(fit_option='gaussian')) # Define what to save in file bunchmonitor = BunchMonitor(general_params, rf_params_tot, beam, this_directory + '../output_files/EX_04_output_data', Profile=slice_beam, buffer_time=1) # PLOTS format_options = {'dirname': this_directory + '../output_files/EX_04_fig', 'linestyle': '.'} plots = Plot(general_params, rf_params_tot, beam, dt_plt, dt_plt, 0, 0.0001763*h, -450e6, 450e6, xunit='rad', separatrix_plot=True, Profile=slice_beam, h5file=this_directory + '../output_files/EX_04_output_data', histograms_plot=True, format_options=format_options) # For testing purposes test_string = ''
h = 35640 # Harmonic number V = 6e6 # RF voltage [V] dphi = 0 # Phase modulation/offset gamma_t = 55.759505 # Transition gamma alpha = 1. / gamma_t / gamma_t # First order mom. comp. factor # Tracking details N_t = 2000 # Number of turns to track # Simulation setup ------------------------------------------------------------ ring = Ring(C, alpha, p, Proton(), N_t) rf = RFStation(ring, [h], [V], [dphi]) beam = Beam(ring, N_p, N_b) bigaussian(ring, rf, beam, tau_0 / 4, reinsertion=True, seed=1) profile = Profile(beam, CutOptions=CutOptions(n_slices=100, cut_left=0, cut_right=2.5e-9)) profile.track() # Calculate oscillation amplitude from coordinates dtmax, bin_centres, histogram = oscillation_amplitude_from_coordinates( ring, rf, beam.dt, beam.dE, Np_histogram=100) # Normalise profiles profile.n_macroparticles /= np.sum(profile.n_macroparticles) histogram /= np.sum(histogram) # Plot plt.plot(profile.bin_centers, profile.n_macroparticles, 'b',
# ----------------------------------------------------------------------------- # Plot settings plt.rc('axes', labelsize=12, labelweight='normal') plt.rc('lines', linewidth=1.5, markersize=6) plt.rc('font', family='sans-serif') plt.rc('legend', fontsize=12) # Logger for messages on console & in file Logger(debug=True) ring = Ring(C, alpha, p_s, Particle=Proton(), n_turns=1) rf = RFStation(ring, [h], [V], [dphi]) beam = Beam(ring, N_p, N_b) profile = Profile(beam, CutOptions(n_slices=100), FitOptions(fit_option='gaussian')) logging.info( 'Initialising LHCCavityLoop, tuned to injection (with no beam current)') logging.info('CLOSED LOOP, no excitation, 1 turn tracking') CL = LHCCavityLoop( rf, profile, f_c=rf.omega_rf[0, 0] / (2 * np.pi), G_gen=1, I_gen_offset=0, n_cav=8, n_pretrack=1, Q_L=20000, R_over_Q=45, tau_loop=650e-9, #T_s=25e-9,
ring_RF_section_freq = RingAndRFTracker(RF_sct_par_freq, my_beam_freq) ring_RF_section_res = RingAndRFTracker(RF_sct_par_res, my_beam_res) # DEFINE BEAM------------------------------------------------------------------ bigaussian(general_params, RF_sct_par, my_beam, tau_0/4, seed=1) bigaussian(general_params_freq, RF_sct_par_freq, my_beam_freq, tau_0/4, seed=1) bigaussian(general_params_res, RF_sct_par_res, my_beam_res, tau_0/4, seed=1) number_slices = 2**8 cut_options = CutOptions(cut_left= 0, cut_right=2*np.pi, n_slices=number_slices, RFSectionParameters=RF_sct_par, cuts_unit = 'rad') slice_beam = Profile(my_beam, cut_options, FitOptions(fit_option='gaussian')) cut_options_freq = CutOptions(cut_left= 0, cut_right=2*np.pi, n_slices=number_slices, RFSectionParameters=RF_sct_par_freq, cuts_unit = 'rad') slice_beam_freq = Profile(my_beam_freq, cut_options_freq, FitOptions(fit_option='gaussian')) cut_options_res = CutOptions(cut_left= 0, cut_right=2*np.pi, n_slices=number_slices, RFSectionParameters=ring_RF_section_res, cuts_unit = 'rad') slice_beam_res = Profile(my_beam_res, cut_options_res, FitOptions(fit_option='gaussian')) slice_beam.track() slice_beam_freq.track() slice_beam_res.track() # MONITOR---------------------------------------------------------------------- bunchmonitor = BunchMonitor(general_params, ring_RF_section, my_beam, this_directory + '../output_files/EX_05_output_data',
def test_vind(self): # randomly chose omega_c from allowed range np.random.seed(1980) factor = np.random.uniform(0.9, 1.1) # round results to this digits digit_round = 8 # SPS parameters C = 2 * np.pi * 1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1 / gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] h = 4620 # 200 MHz system harmonic V = 4.5e6 # 200 MHz RF voltage phi = 0. # 200 MHz RF phase # Beam and tracking parameters N_m = 1e5 # Number of macro-particles for tracking N_b = 1.0e11 # Bunch intensity [ppb] N_t = 1 # Number of turns to track ring = Ring(C, alpha, p_s, Proton(), n_turns=N_t) rf = RFStation(ring, h, V, phi) beam = Beam(ring, N_m, N_b) bigaussian(ring, rf, beam, 3.2e-9 / 4, seed=1234, reinsertion=True) n_shift = 5 # how many rf-buckets to shift beam beam.dt += n_shift * rf.t_rf[0, 0] profile = Profile(beam, CutOptions=CutOptions( cut_left=(n_shift - 1.5) * rf.t_rf[0, 0], cut_right=(n_shift + 1.5) * rf.t_rf[0, 0], n_slices=140)) profile.track() l_cav = 16.082 v_g = 0.0946 tau = l_cav / (v_g * c) * (1 + v_g) TWC_impedance_source = TravelingWaveCavity(l_cav**2 * 27.1e3 / 8, 200.222e6, 2 * np.pi * tau) # Beam loading by convolution of beam and wake from cavity inducedVoltageTWC = InducedVoltageTime(beam, profile, [TWC_impedance_source]) induced_voltage = TotalInducedVoltage(beam, profile, [inducedVoltageTWC]) induced_voltage.induced_voltage_sum() V_ind_impSource = np.around(induced_voltage.induced_voltage, digit_round) # Beam loading via feed-back system OTFB_4 = SPSOneTurnFeedback(rf, beam, profile, 4, n_cavities=1) OTFB_4.counter = 0 # First turn OTFB_4.omega_c = factor * OTFB_4.TWC.omega_r # Compute impulse response OTFB_4.TWC.impulse_response_beam(OTFB_4.omega_c, profile.bin_centers) # Compute induced voltage in (I,Q) coordinates OTFB_4.beam_induced_voltage(lpf=False) # convert back to time V_ind_OTFB \ = OTFB_4.V_fine_ind_beam.real \ * np.cos(OTFB_4.omega_c*profile.bin_centers) \ + OTFB_4.V_fine_ind_beam.imag \ * np.sin(OTFB_4.omega_c*profile.bin_centers) V_ind_OTFB = np.around(V_ind_OTFB, digit_round) self.assertListEqual( V_ind_impSource.tolist(), V_ind_OTFB.tolist(), msg="In TravelingWaveCavity test_vind: induced voltages differ")
def setUp(self): C = 2*np.pi*1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1/gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] h = 4620 # 200 MHz system harmonic phi = 0. # 200 MHz RF phase # With this setting, amplitude in the two four-section, five-section # cavities must converge, respectively, to # 2.0 MV = 4.5 MV * 4/18 * 2 # 2.5 MV = 4.5 MV * 5/18 * 2 V = 4.5e6 # 200 MHz RF voltage N_t = 1 # Number of turns to track self.ring = Ring(C, alpha, p_s, Particle=Proton(), n_turns=N_t) self.rf = RFStation(self.ring, h, V, phi) N_m = 1e6 # Number of macro-particles for tracking N_b = 72*1.0e11 # Bunch intensity [ppb] # Gaussian beam profile self.beam = Beam(self.ring, N_m, N_b) sigma = 1.0e-9 bigaussian(self.ring, self.rf, self.beam, sigma, seed=1234, reinsertion=False) n_shift = 1550 # how many rf-buckets to shift beam self.beam.dt += n_shift * self.rf.t_rf[0,0] self.profile = Profile( self.beam, CutOptions=CutOptions( cut_left=(n_shift-1.5)*self.rf.t_rf[0,0], cut_right=(n_shift+2.5)*self.rf.t_rf[0,0], n_slices=4*64)) self.profile.track() # Cavities l_cav = 43*0.374 v_g = 0.0946 tau = l_cav/(v_g*c)*(1 + v_g) f_cav = 200.222e6 n_cav = 2 # factor 2 because of two four/five-sections cavities short_cavity = TravelingWaveCavity(l_cav**2 * n_cav * 27.1e3 / 8, f_cav, 2*np.pi*tau) shortInducedVoltage = InducedVoltageTime(self.beam, self.profile, [short_cavity]) l_cav = 54*0.374 tau = l_cav/(v_g*c)*(1 + v_g) long_cavity = TravelingWaveCavity(l_cav**2 * n_cav * 27.1e3 / 8, f_cav, 2*np.pi*tau) longInducedVoltage = InducedVoltageTime(self.beam, self.profile, [long_cavity]) self.induced_voltage = TotalInducedVoltage( self.beam, self.profile, [shortInducedVoltage, longInducedVoltage]) self.induced_voltage.induced_voltage_sum() self.cavity_tracker = RingAndRFTracker( self.rf, self.beam, Profile=self.profile, interpolation=True, TotalInducedVoltage=self.induced_voltage) self.OTFB = SPSCavityFeedback( self.rf, self.beam, self.profile, G_llrf=5, G_tx=0.5, a_comb=15/16, turns=50, Commissioning=CavityFeedbackCommissioning()) self.OTFB_tracker = RingAndRFTracker(self.rf, self.beam, Profile=self.profile, TotalInducedVoltage=None, CavityFeedback=self.OTFB, interpolation=True)
class TestCavityFeedback(unittest.TestCase): def setUp(self): C = 2*np.pi*1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1/gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] h = 4620 # 200 MHz system harmonic phi = 0. # 200 MHz RF phase # With this setting, amplitude in the two four-section, five-section # cavities must converge, respectively, to # 2.0 MV = 4.5 MV * 4/18 * 2 # 2.5 MV = 4.5 MV * 5/18 * 2 V = 4.5e6 # 200 MHz RF voltage N_t = 1 # Number of turns to track self.ring = Ring(C, alpha, p_s, Particle=Proton(), n_turns=N_t) self.rf = RFStation(self.ring, h, V, phi) N_m = 1e6 # Number of macro-particles for tracking N_b = 72*1.0e11 # Bunch intensity [ppb] # Gaussian beam profile self.beam = Beam(self.ring, N_m, N_b) sigma = 1.0e-9 bigaussian(self.ring, self.rf, self.beam, sigma, seed=1234, reinsertion=False) n_shift = 1550 # how many rf-buckets to shift beam self.beam.dt += n_shift * self.rf.t_rf[0,0] self.profile = Profile( self.beam, CutOptions=CutOptions( cut_left=(n_shift-1.5)*self.rf.t_rf[0,0], cut_right=(n_shift+2.5)*self.rf.t_rf[0,0], n_slices=4*64)) self.profile.track() # Cavities l_cav = 43*0.374 v_g = 0.0946 tau = l_cav/(v_g*c)*(1 + v_g) f_cav = 200.222e6 n_cav = 2 # factor 2 because of two four/five-sections cavities short_cavity = TravelingWaveCavity(l_cav**2 * n_cav * 27.1e3 / 8, f_cav, 2*np.pi*tau) shortInducedVoltage = InducedVoltageTime(self.beam, self.profile, [short_cavity]) l_cav = 54*0.374 tau = l_cav/(v_g*c)*(1 + v_g) long_cavity = TravelingWaveCavity(l_cav**2 * n_cav * 27.1e3 / 8, f_cav, 2*np.pi*tau) longInducedVoltage = InducedVoltageTime(self.beam, self.profile, [long_cavity]) self.induced_voltage = TotalInducedVoltage( self.beam, self.profile, [shortInducedVoltage, longInducedVoltage]) self.induced_voltage.induced_voltage_sum() self.cavity_tracker = RingAndRFTracker( self.rf, self.beam, Profile=self.profile, interpolation=True, TotalInducedVoltage=self.induced_voltage) self.OTFB = SPSCavityFeedback( self.rf, self.beam, self.profile, G_llrf=5, G_tx=0.5, a_comb=15/16, turns=50, Commissioning=CavityFeedbackCommissioning()) self.OTFB_tracker = RingAndRFTracker(self.rf, self.beam, Profile=self.profile, TotalInducedVoltage=None, CavityFeedback=self.OTFB, interpolation=True) def test_FB_pre_tracking(self): digit_round = 3 Vind4_mean = np.around( np.mean(np.absolute(self.OTFB.OTFB_4.V_coarse_tot))/1e6, digit_round) Vind4_std = np.around( np.std(np.absolute(self.OTFB.OTFB_4.V_coarse_tot))/1e6, digit_round) Vind4_mean_exp = np.around(1.99886351363, digit_round) Vind4_std_exp = np.around(2.148426e-6, digit_round) Vind5_mean = np.around( np.mean(np.absolute(self.OTFB.OTFB_5.V_coarse_tot))/1e6, digit_round) Vind5_std = np.around( np.std(np.absolute(self.OTFB.OTFB_5.V_coarse_tot))/1e6, digit_round) Vind5_mean_exp = np.around(2.49906605189, digit_round) Vind5_std_exp = np.around(2.221665e-6, digit_round) self.assertEqual(Vind4_mean, Vind4_mean_exp, msg='In TestCavityFeedback test_FB_pretracking: ' +'mean value of four-section cavity differs') self.assertEqual(Vind4_std, Vind4_std_exp, msg='In TestCavityFeedback test_FB_pretracking: standard ' +'deviation of four-section cavity differs') self.assertEqual(Vind5_mean, Vind5_mean_exp, msg='In TestCavityFeedback test_FB_pretracking: ' +'mean value of five-section cavity differs') self.assertEqual(Vind5_std, Vind5_std_exp, msg='In TestCavityFeedback test_FB_pretracking: standard '+ 'deviation of five-section cavity differs') def test_FB_pre_tracking_IQ_v1(self): digit_round = 2 # interpolate from coarse mesh to fine mesh V_fine_tot_4 = np.interp( self.profile.bin_centers, self.OTFB.OTFB_4.rf_centers, self.OTFB.OTFB_4.V_coarse_ind_gen) V_fine_tot_5 = np.interp( self.profile.bin_centers, self.OTFB.OTFB_5.rf_centers, self.OTFB.OTFB_5.V_coarse_ind_gen) V_tot_4 = np.around(V_fine_tot_4/1e6, digit_round) V_tot_5 = np.around(V_fine_tot_5/1e6, digit_round) V_sum = np.around(self.OTFB.V_sum/1e6, digit_round) # expected generator voltage is only in Q V_tot_4_exp = 2.0j*np.ones(256) V_tot_5_exp = 2.5j*np.ones(256) V_sum_exp = 4.5j*np.ones(256) self.assertListEqual(V_tot_4.tolist(), V_tot_4_exp.tolist(), msg='In TestCavityFeedback test_FB_pretracking_IQ: total voltage ' +'in four-section cavity differs') self.assertListEqual(V_tot_5.tolist(), V_tot_5_exp.tolist(), msg='In TestCavityFeedback test_FB_pretracking_IQ: total voltage ' +'in five-section cavity differs') self.assertListEqual(V_sum.tolist(), V_sum_exp.tolist(), msg='In TestCavityFeedback test_FB_pretracking_IQ: voltage sum ' +' differs') def test_rf_voltage(self): digit_round = 8 # compute voltage self.cavity_tracker.rf_voltage_calculation() # compute voltage after OTFB pre-tracking self.OTFB_tracker.rf_voltage_calculation() # Since there is a systematic offset between the voltages, # compare the maxium of the ratio max_ratio = np.max(self.cavity_tracker.rf_voltage / self.OTFB_tracker.rf_voltage) max_ratio = np.around(max_ratio, digit_round) max_ratio_exp = np.around(1.0008217052569774, digit_round) self.assertAlmostEqual(max_ratio, max_ratio_exp, places=digit_round, msg='In TestCavityFeedback test_rf_voltage: ' + 'RF-voltages differ') def test_beam_loading(self): digit_round = 10 # Compute voltage with beam loading self.cavity_tracker.rf_voltage_calculation() cavity_tracker_total_voltage = self.cavity_tracker.rf_voltage \ + self.cavity_tracker.totalInducedVoltage.induced_voltage self.OTFB.track() self.OTFB_tracker.rf_voltage_calculation() OTFB_tracker_total_voltage = self.OTFB_tracker.rf_voltage max_ratio = np.around(np.max(cavity_tracker_total_voltage / OTFB_tracker_total_voltage), digit_round) max_ration_exp = np.around(1.0051759770680779, digit_round) self.assertEqual(max_ratio, max_ration_exp, msg='In TestCavityFeedback test_beam_loading: ' + 'total voltages differ') def test_Vsum_IQ(self): digit_round = 4 self.OTFB.track() V_sum = np.around(self.OTFB.V_sum/1e6, digit_round) V_sum_exp = np.around(np.array([-7.40650823e+01+4497812.99202967j, -7.40650823e+01+4497812.99202967j, -7.40650823e+01+4497812.99202967j, -7.40650823e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650823e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j,-7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j,-7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j,-7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j,-7.40650822e+01+4497812.99202968j, -6.02318851e+01+4497817.94162674j,-1.98390915e+01+4497835.4539936j , 1.93158486e+01+4497855.56826354j,4.37055412e+01+4497871.87009121j, 7.72626261e+01+4497900.35036866j,1.08879867e+02+4497930.96118169j, 1.36226374e+02+4497965.43834138j,1.83914308e+02+4498039.43198652j, 2.58060957e+02+4498182.7842137j ,3.46527521e+02+4498400.20917783j, 4.26706222e+02+4498667.15544146j,4.94661306e+02+4499027.56784064j, 5.43482338e+02+4499582.92538958j,5.37601327e+02+4500375.11759629j, 4.18116316e+02+4501483.68340875j,1.06781854e+02+4502992.29896325j, -5.18346745e+02+4504994.88486696j,-1.49458714e+03+4507337.42385509j, -3.01163886e+03+4510119.3419273j ,-5.32851179e+03+4513546.45481774j, -8.74569640e+03+4517649.58201841j,-1.36711235e+04+4522515.97696859j, -2.06268308e+04+4528145.57335092j,-3.07188747e+04+4534772.43779405j, -4.42705242e+04+4541938.02912512j,-6.14651616e+04+4548954.45228089j, -8.23300421e+04+4555211.22162217j,-1.09421551e+05+4560368.34346543j, -1.43885886e+05+4563628.1865127j ,-1.85808399e+05+4563383.852869j , -2.36208282e+05+4558209.23829535j,-2.94836934e+05+4546270.53281669j, -3.63317854e+05+4525133.07455768j,-4.41779074e+05+4492246.31582297j, -5.28977031e+05+4445197.26263046j,-6.24427353e+05+4380854.18329653j, -7.28570463e+05+4294604.34393273j,-8.41413067e+05+4180725.12037253j, -9.58666802e+05+4036850.21934613j,-1.07489637e+06+3861588.24443417j, -1.18692079e+06+3650150.96222293j,-1.28868132e+06+3402561.33925834j, -1.37503355e+06+3113868.12951949j,-1.44047679e+06+2779413.13521708j, -1.47644078e+06+2402815.35953829j,-1.47522678e+06+1985042.23744602j, -1.42897968e+06+1528424.34271266j,-1.32931255e+06+1034805.30411738j, -1.16912937e+06 +511261.80102318j,-9.43345126e+05 -30406.39494472j, -6.44543913e+05 -585971.64269612j,-2.67898382e+05-1147041.0353738j , 1.87647422e+05-1699739.23544117j,7.19585769e+05-2229855.79356738j, 1.32653137e+06-2725965.80099238j,2.00691053e+06-3178849.17084715j, 2.75728744e+06-3578075.86057957j,3.56230981e+06-3910440.14562456j, 4.40408617e+06-4164575.91355405j,5.28572695e+06-4338227.19020188j, 6.19719564e+06-4426787.10912655j,7.11277008e+06-4425807.66220696j, 8.01692653e+06-4335730.38899002j,8.89765817e+06-4159572.80505286j, 9.74683705e+06-3900763.99853979j,1.05559999e+07-3564480.67012727j, 1.13018718e+07-3165395.29765105j,1.19781005e+07-2712267.95526922j, 1.25833208e+07-2214895.26359232j,1.31112101e+07-1685734.89623327j, 1.35640429e+07-1132761.26804116j,1.39371556e+07 -573495.98893318j, 1.42323033e+07 -19883.35687916j,1.44559502e+07 +521811.95451886j, 1.46134106e+07+1043190.45283868j,1.47105373e+07+1534116.02749795j, 1.47549265e+07+1994083.71851812j,1.47545428e+07+2416602.70892133j, 1.47166958e+07+2794242.30539414j,1.46493955e+07+3129779.93382244j, 1.45593030e+07+3424466.23125072j,1.44539743e+07+3677716.51226699j, 1.43401341e+07+3889644.33404043j,1.42224899e+07+4064982.31004726j, 1.41063737e+07+4205965.72167177j,1.39946111e+07+4317244.42689922j, 1.38886184e+07+4403883.23649077j,1.37894739e+07+4469861.27187975j, 1.36989283e+07+4518194.75268176j,1.36191316e+07+4551305.81768837j, 1.35495619e+07+4572524.22309931j,1.34903101e+07+4584597.89085099j, 1.34406305e+07+4589814.4489974j ,1.33976876e+07+4590220.82697034j, 1.33615022e+07+4587255.76269093j,1.33327026e+07+4582254.09185628j, 1.33096130e+07+4576070.77968165j,1.32911752e+07+4569436.1321998j , 1.32768524e+07+4562928.08977976j,1.32656893e+07+4556810.85976046j, 1.32570926e+07+4551309.42853408j,1.32504722e+07+4546502.73564931j, 1.32453253e+07+4542354.45990368j,1.32414716e+07+4539159.11692844j, 1.32386032e+07+4536873.63706821j,1.32362022e+07+4534949.63932622j, 1.32341515e+07+4533397.43716764j,1.32323621e+07+4532141.64712087j, 1.32307439e+07+4531156.20064611j,1.32292493e+07+4530633.17835778j, 1.32277994e+07+4530492.96280951j,1.32263821e+07+4530446.25647796j, 1.32249901e+07+4530405.83108728j,1.32236081e+07+4530431.11420123j, 1.32222495e+07+4530467.44843446j,1.32208432e+07+4530611.48233323j, 1.32193886e+07+4530847.10244979j,1.32179361e+07+4531084.60180009j, 1.32164993e+07+4531317.55923836j,1.32150516e+07+4531560.32993118j, 1.32135685e+07+4531829.29611484j,1.32120853e+07+4532098.20168656j, 1.32106022e+07+4532367.04664624j,1.32091191e+07+4532635.83099376j, 1.32076359e+07+4532904.55472902j,1.32061675e+07+4533173.93875581j, 1.32046990e+07+4533443.26260922j,1.32032158e+07+4533711.80494598j, 1.32017326e+07+4533980.28666989j,1.32002495e+07+4534248.70778084j, 1.31987663e+07+4534517.06827872j,1.31972831e+07+4534785.36816343j, 1.31957999e+07+4535053.60743485j,1.31943167e+07+4535321.78609287j, 1.31928335e+07+4535589.90413737j,1.31913503e+07+4535857.96156826j, 1.31898671e+07+4536125.95838542j,1.31883839e+07+4536393.89458873j, 1.31869007e+07+4536661.77017809j,1.31854174e+07+4536929.58515338j, 1.31839342e+07+4537197.33951451j,1.31824510e+07+4537465.03326134j, 1.31809677e+07+4537732.66639378j,1.31794845e+07+4538000.23891172j, 1.31780012e+07+4538267.75081504j,1.31765179e+07+4538535.20210364j, 1.31750347e+07+4538802.5927774j ,1.31735514e+07+4539069.92283622j, 1.31720681e+07+4539337.19227997j,1.31705848e+07+4539604.40110857j, 1.31691016e+07+4539871.54932188j,1.31676183e+07+4540138.63691982j, 1.31661350e+07+4540405.66390225j,1.31646517e+07+4540672.63026908j, 1.31631684e+07+4540939.53602019j,1.31616850e+07+4541206.38115549j, 1.31602017e+07+4541473.16567484j,1.31587184e+07+4541739.88957815j, 1.31572351e+07+4542006.55286531j,1.31557517e+07+4542273.1555362j , 1.31542684e+07+4542539.69759073j,1.31527850e+07+4542806.17902876j, 1.31513017e+07+4543072.59985021j,1.31498183e+07+4543338.96005496j, 1.31483350e+07+4543605.2596429j ,1.31468516e+07+4543871.49861392j, 1.31453682e+07+4544137.6769679j ,1.31438848e+07+4544403.79470476j, 1.31424014e+07+4544669.85182436j,1.31409181e+07+4544935.84832662j, 1.31394347e+07+4545201.7842114j ,1.31379513e+07+4545467.65947862j, 1.31364679e+07+4545733.47412815j,1.31349844e+07+4545999.22815989j, 1.31335010e+07+4546264.92157373j,1.31320176e+07+4546530.55436956j, 1.31305342e+07+4546796.12654728j,1.31290507e+07+4547061.63810677j, 1.31275673e+07+4547327.08904792j,1.31260839e+07+4547592.47937064j, 1.31246004e+07+4547857.8090748j ,1.31231170e+07+4548123.0781603j , 1.31216335e+07+4548388.28662704j,1.31201500e+07+4548653.4344749j , 1.31186666e+07+4548918.52170378j,1.31171831e+07+4549183.54831356j, 1.31156996e+07+4549448.51430414j,1.31142161e+07+4549713.41967541j, 1.31127326e+07+4549978.26442727j])/1e6, digit_round) self.assertListEqual(V_sum.tolist(), V_sum_exp.tolist(), msg='In TestCavityFeedback test_Vsum_IQ: total voltage ' +'is different from expected values!')
[phi_offset], n_rf_systems) beam = Beam(general_params, n_macroparticles, n_particles) ring_RF_section = RingAndRFTracker(RF_sct_par, beam) bucket_length = 2.0 * np.pi / RF_sct_par.omega_rf[0,0] # DEFINE BEAM------------------------------------------------------------------ bigaussian(general_params, RF_sct_par, beam, sigma_dt, seed=1) # DEFINE SLICES---------------------------------------------------------------- number_slices = 200 slice_beam = Profile(beam, CutOptions(cut_left=0, cut_right=bucket_length, n_slices=number_slices)) # Overwriting the slices by a Gaussian profile (no slicing noise) slice_beam.n_macroparticles = (n_macroparticles * slice_beam.bin_size / (sigma_dt * np.sqrt(2.0 * np.pi)) * np.exp(-0.5 * (slice_beam.bin_centers - bucket_length/2.0)**2.0 / sigma_dt**2.0)) # LOAD IMPEDANCE TABLES-------------------------------------------------------- R_S = 5e3 frequency_R = 10e6 Q = 10 resonator = Resonators(R_S, frequency_R, Q)
class TestRFCurrent(unittest.TestCase): def setUp(self): C = 2*np.pi*1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1/gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] N_m = 1e5 # Number of macro-particles for tracking N_b = 1.0e11 # Bunch intensity [ppb] # Set up machine parameters self.ring = Ring(C, alpha, p_s, Proton(), n_turns=1) # RF-frequency at which to compute beam current self.omega = 2*np.pi*200.222e6 # Create Gaussian beam self.beam = Beam(self.ring, N_m, N_b) self.profile = Profile( self.beam, CutOptions=CutOptions(cut_left=-1.e-9, n_slices=100, cut_right=6.e-9)) def test_1(self): t = self.profile.bin_centers self.profile.n_macroparticles \ = 2600*np.exp(-(t-2.5e-9)**2 / (2*0.5e-9)**2) rf_current = rf_beam_current(self.profile, self.omega, self.ring.t_rev[0], lpf=False) rf_current_real = np.around(rf_current.real, 12) rf_current_imag = np.around(rf_current.imag, 12) rf_theo_real = 2*self.beam.ratio*self.profile.Beam.Particle.charge*e\ * 2600*np.exp(-(t-2.5e-9)**2/(2*0.5*1e-9)**2)\ * np.cos(self.omega*t) rf_theo_real = np.around(rf_theo_real, 12) rf_theo_imag = 2*self.beam.ratio*self.profile.Beam.Particle.charge*e\ * 2600*np.exp(-(t-2.5e-9)**2/(2*0.5*1e-9)**2)\ * np.sin(self.omega*t) rf_theo_imag = np.around(rf_theo_imag, 12) self.assertListEqual(rf_current_real.tolist(), rf_theo_real.tolist(), msg="In TestRfCurrent test_1, mismatch in real part of RF current") self.assertListEqual(rf_current_imag.tolist(), rf_theo_imag.tolist(), msg="In TestRfCurrent test_1, mismatch in real part of RF current") def test_2(self): RF = RFStation(self.ring, 4620, 4.5e6, 0) bigaussian(self.ring, RF, self.beam, 3.2e-9/4, seed = 1234, reinsertion = True) self.profile.track() rf_current = rf_beam_current(self.profile, self.omega, self.ring.t_rev[0], lpf=False) Iref_real = np.array( [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 4.17276535e-13, 4.58438681e-13, 2.48023976e-13, 5.29812878e-13, 2.79735891e-13, 0.00000000e+00, 1.21117141e-12, 9.32525023e-13, 3.16481489e-13, 6.39337176e-13, 0.00000000e+00, 0.00000000e+00, 4.08671434e-12, 4.92294314e-12, 6.56965575e-12, 1.06279981e-11, 1.36819774e-11, 2.16648778e-11, 3.09847740e-11, 3.52971849e-11, 4.70378842e-11, 4.53538351e-11, 4.87255679e-11, 5.36705228e-11, 5.13609263e-11, 4.32833543e-11, 3.41417624e-11, 1.57452091e-11, -1.09005668e-11, -4.60465929e-11, -9.12872553e-11, -1.48257171e-10, -2.08540597e-10, -2.77630608e-10, -3.72157667e-10, -4.56272786e-10, -5.57978710e-10, -6.46554672e-10, -7.48006839e-10, -8.21493943e-10, -9.37522966e-10, -1.03729659e-09, -1.06159943e-09, -1.08434837e-09, -1.15738771e-09, -1.17887328e-09, -1.17146946e-09, -1.10964397e-09, -1.10234198e-09, -1.08852433e-09, -9.85866185e-10, -9.11727492e-10, -8.25604179e-10, -7.34122902e-10, -6.47294094e-10, -5.30372699e-10, -4.40357820e-10, -3.61273445e-10, -2.76871612e-10, -2.02227691e-10, -1.45430219e-10, -8.88675652e-11, -4.28984525e-11, -8.85451321e-12, 1.79026289e-11, 3.48384211e-11, 4.50190278e-11, 5.62413467e-11, 5.27322593e-11, 4.98163111e-11, 4.83288193e-11, 4.18200848e-11, 3.13334266e-11, 2.44082106e-11, 2.12572803e-11, 1.37397871e-11, 1.00879346e-11, 7.78502206e-12, 4.00790815e-12, 2.51830412e-12, 1.91301488e-12, 0.00000000e+00, 9.58518921e-13, 3.16123806e-13, 1.24116545e-12, 1.20821671e-12, 5.82952178e-13, 8.35917228e-13, 5.27285250e-13, 4.93205915e-13, 0.00000000e+00, 2.06937011e-13, 1.84618141e-13, 1.60868490e-13, 0.00000000e+00, 1.09822742e-13]) I_real = np.around(rf_current.real, 14) # round Iref_real = np.around(Iref_real, 14) self.assertSequenceEqual(I_real.tolist(), Iref_real.tolist(), msg="In TestRFCurrent test_2, mismatch in real part of RF current") Iref_imag = np.array([ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -4.86410815e-13, -4.47827158e-13, -2.02886432e-13, -3.60573852e-13, -1.56290206e-13, 0.00000000e+00, -4.19433613e-13, -2.33465744e-13, -5.01823105e-14, -4.43075921e-14, 0.00000000e+00, 0.00000000e+00, 8.07144709e-13, 1.43192280e-12, 2.55659168e-12, 5.25480064e-12, 8.33669524e-12, 1.59729353e-11, 2.73609511e-11, 3.71844853e-11, 5.92134758e-11, 6.87376280e-11, 9.02226570e-11, 1.24465616e-10, 1.55478762e-10, 1.84035433e-10, 2.37241518e-10, 2.86677989e-10, 3.28265272e-10, 3.77882012e-10, 4.29727720e-10, 4.83759029e-10, 5.13978173e-10, 5.41841031e-10, 5.91537968e-10, 6.00658643e-10, 6.13928028e-10, 5.96367636e-10, 5.76920099e-10, 5.25297875e-10, 4.89104065e-10, 4.29776324e-10, 3.33901906e-10, 2.38690921e-10, 1.49673305e-10, 4.78223853e-11, -5.57081558e-11, -1.51374774e-10, -2.50724894e-10, -3.50731761e-10, -4.16547058e-10, -4.83765618e-10, -5.36075032e-10, -5.74421794e-10, -6.05459147e-10, -5.91794283e-10, -5.88179055e-10, -5.83222843e-10, -5.49774151e-10, -5.08571646e-10, -4.86623358e-10, -4.33179012e-10, -3.73737133e-10, -3.37622742e-10, -2.89119788e-10, -2.30660798e-10, -1.85597518e-10, -1.66348322e-10, -1.19981335e-10, -9.07232680e-11, -7.21467862e-11, -5.18977454e-11, -3.25510912e-11, -2.12524272e-11, -1.54447488e-11, -8.24107056e-12, -4.90052047e-12, -2.96720377e-12, -1.13551262e-12, -4.79152734e-13, -1.91861296e-13, 0.00000000e+00, 7.31481456e-14, 5.23883203e-14, 3.19951675e-13, 4.27870459e-13, 2.66236636e-13, 4.74712082e-13, 3.64260145e-13, 4.09222572e-13, 0.00000000e+00, 2.44654594e-13, 2.61906356e-13, 2.77128356e-13, 0.00000000e+00, 3.01027843e-13]) I_imag = np.around(rf_current.imag, 14) # round Iref_imag = np.around(Iref_imag, 14) self.assertSequenceEqual(I_imag.tolist(), Iref_imag.tolist(), msg="In TestRFCurrent test_2, mismatch in imaginary part of" + " RF current") # Skip this unit test, since its reference values are obsolete; # This test used to be in /unittests/general/test_cavity_feedback.py @unittest.skip('Skipping because of obsolete reference values!') def test_3(self): # Set up SPS conditions ring = Ring(2*np.pi*1100.009, 1/18**2, 25.92e9, Proton(), 1000) RF = RFStation(ring, 4620, 4.5e6, 0) beam = Beam(ring, 1e5, 1e11) bigaussian(ring, RF, beam, 3.2e-9/4, seed = 1234, reinsertion = True) profile = Profile(beam, CutOptions(cut_left=-1.e-9, cut_right=6.e-9, n_slices=100)) profile.track() self.assertEqual(len(beam.dt), np.sum(profile.n_macroparticles), "In" + " TestBeamCurrent: particle number mismatch in Beam vs Profile") # RF current calculation with low-pass filter rf_current = rf_beam_current(profile, 2*np.pi*200.222e6, ring.t_rev[0]) Iref_real = np.array([ -9.4646042539e-12, -7.9596801534e-10, -2.6993572787e-10, 2.3790828610e-09, 6.4007063190e-09, 9.5444302650e-09, 9.6957462918e-09, 6.9944771120e-09, 5.0040512366e-09, 8.2427583408e-09, 1.6487066238e-08, 2.2178930587e-08, 1.6497620890e-08, 1.9878201568e-09, -2.4862807497e-09, 2.0862096916e-08, 6.6115473293e-08, 1.1218114710e-07, 1.5428441607e-07, 2.1264254596e-07, 3.1213935713e-07, 4.6339212948e-07, 6.5039440158e-07, 8.2602190806e-07, 9.4532001396e-07, 1.0161170159e-06, 1.0795840334e-06, 1.1306004256e-06, 1.1081141333e-06, 9.7040873320e-07, 7.1863437325e-07, 3.3833950889e-07, -2.2273124358e-07, -1.0035204008e-06, -1.9962696992e-06, -3.1751183137e-06, -4.5326227784e-06, -6.0940850385e-06, -7.9138578879e-06, -9.9867317826e-06, -1.2114906338e-05, -1.4055138779e-05, -1.5925650405e-05, -1.8096693885e-05, -2.0418813156e-05, -2.2142865862e-05, -2.3038234657e-05, -2.3822481250e-05, -2.4891969829e-05, -2.5543384520e-05, -2.5196086909e-05, -2.4415522211e-05, -2.3869116251e-05, -2.3182951665e-05, -2.1723128723e-05, -1.9724625363e-05, -1.7805112266e-05, -1.5981218737e-05, -1.3906226012e-05, -1.1635865568e-05, -9.5381189596e-06, -7.7236624815e-06, -6.0416822483e-06, -4.4575806261e-06, -3.0779237834e-06, -1.9274519396e-06, -9.5699993457e-07, -1.7840768971e-07, 3.7780452612e-07, 7.5625231388e-07, 1.0158886027e-06, 1.1538975409e-06, 1.1677937652e-06, 1.1105424636e-06, 1.0216131672e-06, 8.8605026541e-07, 7.0783694846e-07, 5.4147914020e-07, 4.1956457226e-07, 3.2130062098e-07, 2.2762751268e-07, 1.4923020411e-07, 9.5683463322e-08, 5.8942895620e-08, 3.0515695233e-08, 1.2444834300e-08, 8.9413517889e-09, 1.6154761941e-08, 2.3261993674e-08, 2.3057968490e-08, 1.8354179928e-08, 1.4938991667e-08, 1.2506841004e-08, 8.1230022648e-09, 3.7428821201e-09, 2.8368110506e-09, 3.6536247240e-09, 2.8429736524e-09, 1.6640835314e-09, 2.3960087967e-09]) I_real = np.around(rf_current.real, 9) # round Iref_real = np.around(Iref_real, 9) self.assertSequenceEqual(I_real.tolist(), Iref_real.tolist(), msg="In TestRFCurrent test_3, mismatch in real part of RF current") Iref_imag = np.array([ -1.3134886055e-11, 1.0898262206e-09, 3.9806900984e-10, -3.0007980073e-09, -7.4404909183e-09, -9.5619658077e-09, -7.9029982105e-09, -4.5153699012e-09, -2.8337010673e-09, -4.0605999910e-09, -5.7035811935e-09, -4.9421561822e-09, -2.6226262365e-09, -1.0904425703e-09, 1.5886725829e-10, 3.6061564044e-09, 1.2213233410e-08, 3.0717134774e-08, 6.2263860975e-08, 1.0789908935e-07, 1.8547368321e-07, 3.3758410599e-07, 5.8319210090e-07, 8.7586115583e-07, 1.1744525681e-06, 1.5330067491e-06, 2.0257108185e-06, 2.6290348930e-06, 3.3065045701e-06, 4.1218136471e-06, 5.1059358251e-06, 6.1421308306e-06, 7.1521192647e-06, 8.2164613957e-06, 9.3474086978e-06, 1.0368027059e-05, 1.1176114701e-05, 1.1892303251e-05, 1.2600522466e-05, 1.3142991032e-05, 1.3286611961e-05, 1.2972067098e-05, 1.2344251145e-05, 1.1561930031e-05, 1.0577353622e-05, 9.1838382917e-06, 7.3302333455e-06, 5.2367297732e-06, 3.1309520147e-06, 1.0396785645e-06, -1.1104442284e-06, -3.3300486963e-06, -5.5129705406e-06, -7.4742790081e-06, -9.1003715719e-06, -1.0458342224e-05, -1.1632423668e-05, -1.2513736332e-05, -1.2942309414e-05, -1.2975831165e-05, -1.2799952495e-05, -1.2469945465e-05, -1.1941176358e-05, -1.1222986380e-05, -1.0349594257e-05, -9.3491445482e-06, -8.2956327726e-06, -7.2394219079e-06, -6.1539590898e-06, -5.0802321519e-06, -4.1512021086e-06, -3.3868884793e-06, -2.6850344653e-06, -2.0327038471e-06, -1.5048854341e-06, -1.0965986189e-06, -7.4914749272e-07, -4.7128817088e-07, -2.9595396024e-07, -1.9387567373e-07, -1.1597751838e-07, -5.5766761837e-08, -2.3991059778e-08, -1.1910924971e-08, -4.7797889603e-09, 9.0715301612e-11, 1.5744084129e-09, 2.8217939283e-09, 5.5919203984e-09, 7.7259433940e-09, 8.5033504655e-09, 9.1509256107e-09, 8.6746085156e-09, 5.8909590412e-09, 3.5957212556e-09, 4.3347189168e-09, 5.3331969589e-09, 3.9322184713e-09, 3.3616434953e-09, 6.5154351819e-09]) I_imag = np.around(rf_current.imag, 9) # round Iref_imag = np.around(Iref_imag, 9) self.assertSequenceEqual(I_imag.tolist(), Iref_imag.tolist(), msg="In TestRFCurrent test_3, mismatch in imaginary part of RF current")
Proton(), n_turns) # Cavities parameters n_rf_systems = 1 harmonic_numbers_1 = 1 # [1] voltage_1 = 8000 # [V] phi_offset_1 = np.pi # [rad] rf_params = RFStation( general_params, [harmonic_numbers_1], [voltage_1], [phi_offset_1], n_rf_systems, omega_rf=[1.00001*2.*np.pi/general_params.t_rev[0]]) my_beam = Beam(general_params, n_macroparticles, n_particles) cut_options = CutOptions(cut_left= 0, cut_right=2.0*0.9e-6, n_slices=200) slices_ring = Profile(my_beam, cut_options) #Phase loop configuration = {'machine': 'PSB', 'PL_gain': 0., 'RL_gain': [0.,0.], 'period': 10.0e-6} phase_loop = BeamFeedback(general_params, rf_params, slices_ring, configuration) #Long tracker long_tracker = RingAndRFTracker(rf_params, my_beam, BeamFeedback=phase_loop) full_ring = FullRingAndRF([long_tracker])
[phi_offset], n_rf_systems) beam = Beam(general_params, n_macroparticles, n_particles) ring_RF_section = RingAndRFTracker(RF_sct_par, beam) bucket_length = 2.0 * np.pi / RF_sct_par.omega_rf[0, 0] # DEFINE BEAM------------------------------------------------------------------ bigaussian(general_params, RF_sct_par, beam, sigma_dt, seed=1) # DEFINE SLICES---------------------------------------------------------------- number_slices = 200 slice_beam = Profile( beam, CutOptions(cut_left=0, cut_right=bucket_length, n_slices=number_slices)) # Overwriting the slices by a Gaussian profile (no slicing noise) slice_beam.n_macroparticles = ( n_macroparticles * slice_beam.bin_size / (sigma_dt * np.sqrt(2.0 * np.pi)) * np.exp( -0.5 * (slice_beam.bin_centers - bucket_length / 2.0)**2.0 / sigma_dt**2.0)) # LOAD IMPEDANCE TABLES-------------------------------------------------------- R_S = 5e3 frequency_R = 10e6 Q = 10
mpiprint("Setting up the simulation...") # Define general parameters ring = Ring(C, alpha, np.linspace(p_i, p_f, n_turns + 1), Proton(), n_turns) # Define beam and distribution beam = Beam(ring, n_particles, N_b) # Define RF station parameters and corresponding tracker rf = RFStation(ring, [h], [V], [dphi]) bigaussian(ring, rf, beam, tau_0 / 4, reinsertion=True, seed=seed) # Need slices for the Gaussian fit # TODO add the gaussian fit profile = Profile(beam, CutOptions(n_slices=n_slices)) # FitOptions(fit_option='gaussian')) long_tracker = RingAndRFTracker(rf, beam) # beam.split_random() beam.split() if args['monitor'] > 0 and worker.isMaster: if args.get('monitorfile', None): filename = args['monitorfile'] else: filename = 'monitorfiles/ex01-t{}-p{}-b{}-sl{}-approx{}-prec{}-r{}-m{}-se{}-w{}'.format( n_iterations, n_particles, n_bunches, n_slices, approx, args['precision'], n_turns_reduce, args['monitor'], seed, worker.workers)
for bucket in rf_LoCa.buckets: turns_SC.append(bucket[0]) momentum_SC.append(rf_LoCa.buckets[bucket].momentum) momentum_spread_SC.append(rf_LoCa.buckets[bucket].bunch_dp_over_p * 2 / 4.) # Beam beam = Beam(ring, n_macroparticles, intensity) # Profile cut_options = CutOptions(cut_left, cut_right, n_slices_total, cuts_unit='rad', RFSectionParameters=rf_params) profile = Profile(beam, cut_options) # 10 MHz cavities are treated separately impedance10MHzCavities = scenario( MODEL=model, method_10MHz='/rf_cavities/10MHz/All/Resonators/multi_resonators_h21.txt') impedance10MHzCavities.importCavities10MHz( impedance10MHzCavities.freq_10MHz, method=impedance10MHzCavities.method_10MHz, RshFactor=impedance10MHzCavities.RshFactor_10MHz, QFactor=impedance10MHzCavities.QFactor_10MHz) # The rest of the impedance model impedanceRestOfMachine = scenario( MODEL=model, method_10MHz='/rf_cavities/10MHz/All/Resonators/multi_resonators_h21.txt')
Proton(), n_turns) # Cavities parameters n_rf_systems = 1 harmonic_numbers_1 = 1 voltage_1 = 8000 # [V] phi_offset_1 = np.pi # [rad] rf_params = RFStation(general_params, [harmonic_numbers_1], [voltage_1], [phi_offset_1], n_rf_systems) my_beam = Beam(general_params, n_macroparticles, n_particles) cut_options = CutOptions(cut_left= 0, cut_right=2*np.pi, n_slices=200, RFSectionParameters=rf_params, cuts_unit = 'rad') slices_ring = Profile(my_beam, cut_options) #Phase loop configuration = {'machine': 'PSB', 'PL_gain': 1./25.e-6, 'period': 10.e-6} phase_loop = BeamFeedback(general_params, rf_params, slices_ring, configuration) #Long tracker long_tracker = RingAndRFTracker(rf_params, my_beam, periodicity='Off', BeamFeedback=phase_loop) full_ring = FullRingAndRF([long_tracker]) distribution_type = 'gaussian' bunch_length = 200.0e-9
V = 6e6 # RF voltage [V] dphi = 0 # Phase modulation/offset gamma_t = 55.759505 # Transition gamma alpha = 1./gamma_t/gamma_t # First order mom. comp. factor # Tracking details N_t = 2000 # Number of turns to track # Simulation setup ------------------------------------------------------------ ring = Ring(C, alpha, p, Proton(), N_t) rf = RFStation(ring, [h], [V], [dphi]) beam = Beam(ring, N_p, N_b) bigaussian(ring, rf, beam, tau_0/4, reinsertion = True, seed=1) profile = Profile(beam, CutOptions=CutOptions(n_slices=100, cut_left=0, cut_right=2.5e-9)) profile.track() # Calculate oscillation amplitude from coordinates dtmax, bin_centres, histogram = oscillation_amplitude_from_coordinates(ring, rf, beam.dt, beam.dE, Np_histogram = 100) # Normalise profiles profile.n_macroparticles /= np.sum(profile.n_macroparticles) histogram /= np.sum(histogram) # Plot plt.plot(profile.bin_centers, profile.n_macroparticles, 'b', label=r'$\lambda(t)$') plt.plot(bin_centres + 1.25e-9, histogram, 'r', label='$\lambda(t_{\mathsf{max}})$')
bucket_length = 2.0 * np.pi / RF_sct_par.omega_rf[0,0] # DEFINE BEAM------------------------------------------------------------------ beam = Beam(general_params, n_macroparticles, n_particles) # DEFINE TRACKER--------------------------------------------------------------- longitudinal_tracker = RingAndRFTracker(RF_sct_par,beam) full_tracker = FullRingAndRF([longitudinal_tracker]) # DEFINE SLICES---------------------------------------------------------------- number_slices = 500 cut_options = CutOptions(cut_left= 0, cut_right=bucket_length, n_slices=number_slices) slice_beam = Profile(beam, cut_options) # Single RF ------------------------------------------------------------------- matched_from_distribution_function(beam, full_tracker, emittance=emittance, distribution_type=distribution_type, distribution_variable=distribution_variable, main_harmonic_option='lowest_freq', seed=1256) slice_beam.track() [sync_freq_distribution_left, sync_freq_distribution_right], \ [emittance_array_left, emittance_array_right], \ [delta_time_left, delta_time_right], \ particleDistributionFreq, synchronous_time = \ synchrotron_frequency_distribution(beam, full_tracker)
general_params = Ring(C, momentum_compaction, sync_momentum, Proton(), n_turns) RF_sct_par = RFStation(general_params, [harmonic_numbers], [voltage_program], [phi_offset], n_rf_systems) my_beam = Beam(general_params, n_macroparticles, n_particles) ring_RF_section = RingAndRFTracker(RF_sct_par, my_beam) # DEFINE BEAM------------------------------------------------------------------ bigaussian(general_params, RF_sct_par, my_beam, sigma_dt, seed=1) # DEFINE SLICES---------------------------------------------------------------- slice_beam = Profile( my_beam, CutOptions(cut_left=-5.72984173562e-7, cut_right=5.72984173562e-7, n_slices=100)) # MONITOR---------------------------------------------------------------------- bunchmonitor = BunchMonitor(general_params, RF_sct_par, my_beam, this_directory + '../output_files/EX_02_output_data', buffer_time=1) # LOAD IMPEDANCE TABLES-------------------------------------------------------- var = str(kin_beam_energy / 1e9)
profile_margin = 20 * t_rf t_batch_begin = n_shift * t_rf t_batch_end = t_rf * (bunch_spacing * (n_bunches - 1) + 1 + n_shift) cut_left = t_batch_begin - profile_margin cut_right = t_batch_end + profile_margin # number of rf-buckets of the beam # + rf-buckets before the beam + rf-buckets after the beam n_slices = n_bins_rf * (bunch_spacing * (n_bunches - 1) + 1 + int(np.round((t_batch_begin - cut_left) / t_rf)) + int(np.round((cut_right - t_batch_end) / t_rf))) profile = Profile(beam, CutOptions=CutOptions(cut_left=cut_left, cut_right=cut_right, n_slices=n_slices)) mpiprint('Profile set!') # SPS --- Impedance and induced voltage ------------------------------ mpiprint('Setting up impedance') frequency_step = nFrev * ring.f_rev[0] if SPS_IMPEDANCE == True: if impedance_model_str == 'present': number_vvsa = 28 number_vvsb = 36 shield_vvsa = False
def setUp(self): C = 2*np.pi*1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1/gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] h = 4620 # 200 MHz system harmonic phi = 0. # 200 MHz RF phase # With this setting, amplitude in the two four-section, five-section # cavities must converge, respectively, to # 2.0 MV = 4.5 MV * 4/18 * 2 # 2.5 MV = 4.5 MV * 5/18 * 2 V = 4.5e6 # 200 MHz RF voltage N_t = 1 # Number of turns to track self.ring = Ring(C, alpha, p_s, Particle=Proton(), n_turns=N_t) self.rf = RFStation(self.ring, h, V, phi) N_m = 1e6 # Number of macro-particles for tracking N_b = 72*1.0e11 # Bunch intensity [ppb] # Gaussian beam profile self.beam = Beam(self.ring, N_m, N_b) sigma = 1.0e-9 bigaussian(self.ring, self.rf, self.beam, sigma, seed=1234, reinsertion=False) n_shift = 1550 # how many rf-buckets to shift beam self.beam.dt += n_shift * self.rf.t_rf[0, 0] self.profile = Profile( self.beam, CutOptions=CutOptions( cut_left=(n_shift-1.5)*self.rf.t_rf[0, 0], cut_right=(n_shift+2.5)*self.rf.t_rf[0, 0], n_slices=4*64)) self.profile.track() # Cavities l_cav = 43*0.374 v_g = 0.0946 tau = l_cav/(v_g*c)*(1 + v_g) f_cav = 200.222e6 n_cav = 2 # factor 2 because of two four/five-sections cavities short_cavity = TravelingWaveCavity(l_cav**2 * n_cav * 27.1e3 / 8, f_cav, 2*np.pi*tau) shortInducedVoltage = InducedVoltageTime(self.beam, self.profile, [short_cavity]) l_cav = 54*0.374 tau = l_cav/(v_g*c)*(1 + v_g) long_cavity = TravelingWaveCavity(l_cav**2 * n_cav * 27.1e3 / 8, f_cav, 2*np.pi*tau) longInducedVoltage = InducedVoltageTime(self.beam, self.profile, [long_cavity]) self.induced_voltage = TotalInducedVoltage( self.beam, self.profile, [shortInducedVoltage, longInducedVoltage]) self.induced_voltage.induced_voltage_sum() self.cavity_tracker = RingAndRFTracker( self.rf, self.beam, Profile=self.profile, interpolation=True, TotalInducedVoltage=self.induced_voltage) self.OTFB = SPSCavityFeedback( self.rf, self.beam, self.profile, G_llrf=5, G_tx=0.5, a_comb=15/16, turns=50, Commissioning=CavityFeedbackCommissioning()) self.OTFB_tracker = RingAndRFTracker(self.rf, self.beam, Profile=self.profile, TotalInducedVoltage=None, CavityFeedback=self.OTFB, interpolation=True)
n_turns = 2000 general_params = Ring(C, alpha, 310891054.809, Proton(), n_turns) # Cavities parameters n_rf_systems = 1 harmonic_numbers_1 = 1 voltage_1 = 8000 # [V] phi_offset_1 = np.pi # [rad] rf_params = RFStation(general_params, [harmonic_numbers_1], [voltage_1], [phi_offset_1], n_rf_systems) my_beam = Beam(general_params, n_macroparticles, n_particles) cut_options = CutOptions(cut_left=0, cut_right=2.0 * 0.9e-6, n_slices=200) slices_ring = Profile(my_beam, cut_options) #Phase loop #configuration = {'machine': 'PSB', 'PL_gain': 0., 'RL_gain': [34.8,16391], # 'PL_period': 10.e-6, 'RL_period': 7} configuration = { 'machine': 'PSB', 'PL_gain': 0, 'RL_gain': [1.e7, 1.e11], 'period': 10.e-6 } phase_loop = BeamFeedback(general_params, rf_params, slices_ring, configuration) #Long tracker long_tracker = RingAndRFTracker(rf_params, my_beam, BeamFeedback=phase_loop)
class TestBeamFeedback(unittest.TestCase): def setUp(self): n_turns = 200 intensity_pb = 1.2e6 # protons per bunch n_macroparticles = int(1e6) # macropartilces per bunch sigma = 0.05e-9 # sigma for gaussian bunch [s] self.time_offset = 0.1e-9 # time by which to offset the bunch # Ring parameters SPS C = 6911.5038 # Machine circumference [m] sync_momentum = 25.92e9 # SPS momentum at injection [eV/c] gamma_transition = 17.95142852 # Q20 Transition gamma momentum_compaction = 1./gamma_transition**2 # Momentum compaction array self.ring = Ring(C, momentum_compaction, sync_momentum, Proton(), n_turns=n_turns) # RF parameters SPS harmonic = 4620 # Harmonic numbers voltage = 4.5e6 # [V] phi_offsets = 0 self.rf_station = RFStation(self.ring, harmonic, voltage, phi_offsets) t_rf = self.rf_station.t_rf[0, 0] # Beam setup self.beam = Beam(self.ring, n_macroparticles, intensity_pb) bigaussian(self.ring, self.rf_station, self.beam, sigma, seed=1234, reinsertion=True) # displace beam to see effect of phase error and phase loop self.beam.dt += self.time_offset # Profile setup self.profile = Profile(self.beam, CutOptions=CutOptions(cut_left=0, cut_right=t_rf, n_slices=1024)) def test_SPS_RL(self): PL_gain = 1000 # gain of phase loop rtol = 1e-4 # relative tolerance atol = 0 # absolute tolerance # Phase loop setup phase_loop = BeamFeedback(self.ring, self.rf_station, self.profile, {'machine': 'SPS_RL', 'PL_gain': PL_gain}) # Tracker setup section_tracker = RingAndRFTracker( self.rf_station, self.beam, Profile=self.profile, BeamFeedback=phase_loop, interpolation=False) tracker = FullRingAndRF([section_tracker]) # average beam position beamAvgPos = np.zeros(self.ring.n_turns) n_turns = self.ring.n_turns for turn in range(n_turns): beamAvgPos[turn] = np.mean(self.beam.dt) self.profile.track() tracker.track() # difference between beam position and synchronuous position # (assuming no beam loading) delta_tau = beamAvgPos - (np.pi - self.rf_station.phi_rf[0, :-1])\ / self.rf_station.omega_rf[0, :-1] # initial position for analytic solution init_pos = self.time_offset omega_eff = cmath.sqrt(-PL_gain**2 + 4*self.rf_station.omega_s0[0]**2) time = np.arange(n_turns) * self.ring.t_rev[0] # initial derivative for analytic solution; # defined such that analytical solution at turn 1 agrees with numerical # solution init_slope = 0.5 * (delta_tau[1] * omega_eff * np.exp(0.5*PL_gain*time[1]) / np.sin(0.5*omega_eff*time[1]) - delta_tau[0] * (PL_gain+omega_eff/np.tan(0.5*omega_eff*time[1]))).real delta_tau_analytic = init_pos * np.exp(-0.5*PL_gain*time) delta_tau_analytic *= np.cos(0.5*time*omega_eff).real\ + (PL_gain+2*init_slope/init_pos)\ * (np.sin(0.5*time*omega_eff)/omega_eff).real difference = delta_tau - delta_tau_analytic # normalize result difference = difference / np.max(difference) # expected difference difference_exp = np.array([ -1.56306635e-05, -1.55605315e-05, -2.10224435e-05, -3.18525050e-05, -4.74014489e-05, -6.70584402e-05, -9.01307422e-05, -1.15823959e-04, -1.43290487e-04, -1.71572162e-04, -1.99820151e-04, -2.27071730e-04, -2.52331681e-04, -2.74668126e-04, -2.93165304e-04, -3.06972913e-04, -3.15442474e-04, -3.17857324e-04, -3.13794970e-04, -3.02786089e-04, -2.84680298e-04, -2.59322215e-04, -2.26874004e-04, -1.87452375e-04, -1.41293604e-04, -8.89863575e-05, -3.08865701e-05, 3.22411495e-05, 9.97408029e-05, 1.70914181e-04, 2.44766912e-04, 3.20596833e-04, 3.97403451e-04, 4.74233283e-04, 5.50189125e-04, 6.24368453e-04, 6.95836553e-04, 7.63737143e-04, 8.27069057e-04, 8.84995559e-04, 9.36770723e-04, 9.81561780e-04, 1.01869959e-03, 1.04738842e-03, 1.06711062e-03, 1.07736961e-03, 1.07778386e-03, 1.06805613e-03, 1.04797776e-03, 1.01747638e-03, 9.76519221e-04, 9.25420191e-04, 8.64415092e-04, 7.93844624e-04, 7.14396030e-04, 6.26549187e-04, 5.31154439e-04, 4.28985322e-04, 3.21198916e-04, 2.08550190e-04, 9.21607082e-05, -2.68249728e-05, -1.47278123e-04, -2.67890543e-04, -3.87642210e-04, -5.05244473e-04, -6.19660328e-04, -7.29670300e-04, -8.34272846e-04, -9.32388033e-04, -1.02301036e-03, -1.10520861e-03, -1.17824066e-03, -1.24119243e-03, -1.29350096e-03, -1.33458128e-03, -1.36388379e-03, -1.38105465e-03, -1.38595634e-03, -1.37832214e-03, -1.35829791e-03, -1.32588558e-03, -1.28146000e-03, -1.22518721e-03, -1.15769141e-03, -1.07943574e-03, -9.91143310e-04, -8.93671637e-04, -7.87961546e-04, -6.74866999e-04, -5.55444011e-04, -4.30919368e-04, -3.02270469e-04, -1.70824836e-04, -3.77396109e-05, 9.56816273e-05, 2.28299979e-04, 3.58842001e-04, 4.86074690e-04, 6.08875045e-04, 7.26090501e-04, 8.36677390e-04, 9.39639556e-04, 1.03407702e-03, 1.11906014e-03, 1.19386315e-03, 1.25779004e-03, 1.31037519e-03, 1.35108872e-03, 1.37958003e-03, 1.39570542e-03, 1.39927441e-03, 1.39033118e-03, 1.36892681e-03, 1.33533475e-03, 1.28987173e-03, 1.23311389e-03, 1.16551418e-03, 1.08773037e-03, 1.00059786e-03, 9.04879918e-04, 8.01551710e-04, 6.91575582e-04, 5.75952750e-04, 4.55756793e-04, 3.32302985e-04, 2.06487043e-04, 7.95882588e-05, -4.72208138e-05, -1.72823958e-04, -2.96101535e-04, -4.15925168e-04, -5.31250383e-04, -6.41017819e-04, -7.44349685e-04, -8.40276057e-04, -9.28032591e-04, -1.00688055e-03, -1.07610640e-03, -1.13518206e-03, -1.18370702e-03, -1.22129557e-03, -1.24764964e-03, -1.26264035e-03, -1.26627364e-03, -1.25857717e-03, -1.23964021e-03, -1.20980891e-03, -1.16944284e-03, -1.11887385e-03, -1.05870668e-03, -9.89617769e-04, -9.12311681e-04, -8.27560752e-04, -7.36170045e-04, -6.39042153e-04, -5.37114997e-04, -4.31247869e-04, -3.22637131e-04, -2.12194968e-04, -1.00869243e-04, 1.03136916e-05, 1.20241207e-04, 2.27979265e-04, 3.32675130e-04, 4.33323979e-04, 5.29105666e-04, 6.19142445e-04, 7.02728753e-04, 7.79114404e-04, 8.47787258e-04, 9.08216047e-04, 9.59821724e-04, 1.00228122e-03, 1.03538392e-03, 1.05880009e-03, 1.07260841e-03, 1.07662550e-03, 1.07093155e-03, 1.05577003e-03, 1.03129797e-03, 9.97904596e-04, 9.55975595e-04, 9.05955028e-04, 8.48396342e-04, 7.83925297e-04, 7.13242537e-04, 6.36896396e-04, 5.55809454e-04, 4.70697276e-04, 3.82464668e-04, 2.91766220e-04, 1.99564879e-04, 1.06707654e-04, 1.40463177e-05, -7.76333806e-05, -1.67470574e-04, -2.54708122e-04, -3.38623857e-04, -4.18484684e-04]) difference_exp = difference_exp/np.max(difference_exp) np.testing.assert_allclose(difference_exp, difference, rtol=rtol, atol=atol, err_msg='In TestBeamFeedback test_SPS_RL: difference between simulated and analytic result different than expected')
class testProfileClass(unittest.TestCase): # Run before every test def setUp(self): """ Slicing of the same Gaussian profile using four distinct settings to test different features. """ np.random.seed(1984) intensity_pb = 1.0e11 sigma = 0.2e-9 # Gauss sigma, [s] n_macroparticles_pb = int(1e4) n_bunches = 2 # --- Ring and RF ---------------------------------------------- intensity = n_bunches * intensity_pb # total intensity SPS n_turns = 1 # Ring parameters SPS circumference = 6911.5038 # Machine circumference [m] sync_momentum = 25.92e9 # SPS momentum at injection [eV/c] gamma_transition = 17.95142852 # Q20 Transition gamma momentum_compaction = 1. / gamma_transition**2 # Momentum compaction array ring = Ring(circumference, momentum_compaction, sync_momentum, Proton(), n_turns=n_turns) # RF parameters SPS harmonic_number = 4620 # harmonic number voltage = 3.5e6 # [V] phi_offsets = 0 self.rf_station = RFStation(ring, harmonic_number, voltage, phi_offsets, n_rf=1) t_rf = self.rf_station.t_rf[0, 0] bunch_spacing = 5 # RF buckets n_macroparticles = n_bunches * n_macroparticles_pb self.beam = Beam(ring, n_macroparticles, intensity) for bunch in range(n_bunches): bunchBeam = Beam(ring, n_macroparticles_pb, intensity_pb) bigaussian(ring, self.rf_station, bunchBeam, sigma, reinsertion=True, seed=1984 + bunch) self.beam.dt[bunch*n_macroparticles_pb : (bunch+1)*n_macroparticles_pb] \ = bunchBeam.dt + bunch*bunch_spacing * t_rf self.beam.dE[bunch * n_macroparticles_pb:(bunch + 1) * n_macroparticles_pb] = bunchBeam.dE self.filling_pattern = np.zeros(bunch_spacing * (n_bunches - 1) + 1) self.filling_pattern[::bunch_spacing] = 1 # uniform profile profile_margin = 0 * t_rf t_batch_begin = 0 * t_rf t_batch_end = (bunch_spacing * (n_bunches - 1) + 1) * t_rf self.n_slices_rf = 32 # number of slices per RF-bucket cut_left = t_batch_begin - profile_margin cut_right = t_batch_end + profile_margin # number of rf-buckets of the self.beam # + rf-buckets before the self.beam + rf-buckets after the self.beam n_slices = self.n_slices_rf * ( bunch_spacing * (n_bunches - 1) + 1 + int(np.round((t_batch_begin - cut_left) / t_rf)) + int(np.round((cut_right - t_batch_end) / t_rf))) self.uniform_profile = Profile(self.beam, CutOptions=CutOptions( cut_left=cut_left, n_slices=n_slices, cut_right=cut_right)) self.uniform_profile.track() def test_WrongTrackingFunction(self): with self.assertRaises(RuntimeError): SparseSlices(self.rf_station, self.beam, self.n_slices_rf, self.filling_pattern, tracker='something horribly wrong') nonuniform_profile = SparseSlices(self.rf_station, self.beam, self.n_slices_rf, self.filling_pattern) self.assertEqual(nonuniform_profile.bin_centers_array.shape, (2, self.n_slices_rf), msg='Wrong shape of bin_centers_array!') def test_onebyone(self): rtol = 1e-6 # relative tolerance atol = 0 # absolute tolerance nonuniform_profile = SparseSlices(self.rf_station, self.beam, self.n_slices_rf, self.filling_pattern, tracker='onebyone', direct_slicing=True) for bunch in range(2): indexes = (self.uniform_profile.bin_centers>nonuniform_profile.cut_left_array[bunch])\ * (self.uniform_profile.bin_centers<nonuniform_profile.cut_right_array[bunch]) np.testing.assert_allclose( self.uniform_profile.bin_centers[indexes], nonuniform_profile.bin_centers_array[bunch], rtol=rtol, atol=atol, err_msg=f'Bins for bunch {bunch} do not agree ' + 'for tracker="onebyone"') np.testing.assert_allclose( self.uniform_profile.n_macroparticles[indexes], nonuniform_profile.n_macroparticles_array[bunch], rtol=rtol, atol=atol, err_msg=f'Profiles for bunch {bunch} do not agree ' + 'for tracker="onebyone"') def test_Ctracker(self): rtol = 1e-6 # relative tolerance atol = 0 # absolute tolerance nonuniform_profile = SparseSlices(self.rf_station, self.beam, self.n_slices_rf, self.filling_pattern, tracker='C', direct_slicing=True) for bunch in range(2): indexes = (self.uniform_profile.bin_centers>nonuniform_profile.cut_left_array[bunch])\ * (self.uniform_profile.bin_centers<nonuniform_profile.cut_right_array[bunch]) np.testing.assert_allclose( self.uniform_profile.bin_centers[indexes], nonuniform_profile.bin_centers_array[bunch], rtol=rtol, atol=atol, err_msg=f'Bins for bunch {bunch} do not agree ' + 'for tracker="C"') np.testing.assert_allclose( self.uniform_profile.n_macroparticles[indexes], nonuniform_profile.n_macroparticles_array[bunch], rtol=rtol, atol=atol, err_msg=f'Profiles for bunch {bunch} do not agree ' + 'for tracker="C"')
def test_3(self): # Set up SPS conditions ring = Ring(2*np.pi*1100.009, 1/18**2, 25.92e9, Proton(), 1000) RF = RFStation(ring, 4620, 4.5e6, 0) beam = Beam(ring, 1e5, 1e11) bigaussian(ring, RF, beam, 3.2e-9/4, seed = 1234, reinsertion = True) profile = Profile(beam, CutOptions(cut_left=-1.e-9, cut_right=6.e-9, n_slices=100)) profile.track() self.assertEqual(len(beam.dt), np.sum(profile.n_macroparticles), "In" + " TestBeamCurrent: particle number mismatch in Beam vs Profile") # RF current calculation with low-pass filter rf_current = rf_beam_current(profile, 2*np.pi*200.222e6, ring.t_rev[0]) Iref_real = np.array([ -9.4646042539e-12, -7.9596801534e-10, -2.6993572787e-10, 2.3790828610e-09, 6.4007063190e-09, 9.5444302650e-09, 9.6957462918e-09, 6.9944771120e-09, 5.0040512366e-09, 8.2427583408e-09, 1.6487066238e-08, 2.2178930587e-08, 1.6497620890e-08, 1.9878201568e-09, -2.4862807497e-09, 2.0862096916e-08, 6.6115473293e-08, 1.1218114710e-07, 1.5428441607e-07, 2.1264254596e-07, 3.1213935713e-07, 4.6339212948e-07, 6.5039440158e-07, 8.2602190806e-07, 9.4532001396e-07, 1.0161170159e-06, 1.0795840334e-06, 1.1306004256e-06, 1.1081141333e-06, 9.7040873320e-07, 7.1863437325e-07, 3.3833950889e-07, -2.2273124358e-07, -1.0035204008e-06, -1.9962696992e-06, -3.1751183137e-06, -4.5326227784e-06, -6.0940850385e-06, -7.9138578879e-06, -9.9867317826e-06, -1.2114906338e-05, -1.4055138779e-05, -1.5925650405e-05, -1.8096693885e-05, -2.0418813156e-05, -2.2142865862e-05, -2.3038234657e-05, -2.3822481250e-05, -2.4891969829e-05, -2.5543384520e-05, -2.5196086909e-05, -2.4415522211e-05, -2.3869116251e-05, -2.3182951665e-05, -2.1723128723e-05, -1.9724625363e-05, -1.7805112266e-05, -1.5981218737e-05, -1.3906226012e-05, -1.1635865568e-05, -9.5381189596e-06, -7.7236624815e-06, -6.0416822483e-06, -4.4575806261e-06, -3.0779237834e-06, -1.9274519396e-06, -9.5699993457e-07, -1.7840768971e-07, 3.7780452612e-07, 7.5625231388e-07, 1.0158886027e-06, 1.1538975409e-06, 1.1677937652e-06, 1.1105424636e-06, 1.0216131672e-06, 8.8605026541e-07, 7.0783694846e-07, 5.4147914020e-07, 4.1956457226e-07, 3.2130062098e-07, 2.2762751268e-07, 1.4923020411e-07, 9.5683463322e-08, 5.8942895620e-08, 3.0515695233e-08, 1.2444834300e-08, 8.9413517889e-09, 1.6154761941e-08, 2.3261993674e-08, 2.3057968490e-08, 1.8354179928e-08, 1.4938991667e-08, 1.2506841004e-08, 8.1230022648e-09, 3.7428821201e-09, 2.8368110506e-09, 3.6536247240e-09, 2.8429736524e-09, 1.6640835314e-09, 2.3960087967e-09]) I_real = np.around(rf_current.real, 9) # round Iref_real = np.around(Iref_real, 9) self.assertSequenceEqual(I_real.tolist(), Iref_real.tolist(), msg="In TestRFCurrent test_3, mismatch in real part of RF current") Iref_imag = np.array([ -1.3134886055e-11, 1.0898262206e-09, 3.9806900984e-10, -3.0007980073e-09, -7.4404909183e-09, -9.5619658077e-09, -7.9029982105e-09, -4.5153699012e-09, -2.8337010673e-09, -4.0605999910e-09, -5.7035811935e-09, -4.9421561822e-09, -2.6226262365e-09, -1.0904425703e-09, 1.5886725829e-10, 3.6061564044e-09, 1.2213233410e-08, 3.0717134774e-08, 6.2263860975e-08, 1.0789908935e-07, 1.8547368321e-07, 3.3758410599e-07, 5.8319210090e-07, 8.7586115583e-07, 1.1744525681e-06, 1.5330067491e-06, 2.0257108185e-06, 2.6290348930e-06, 3.3065045701e-06, 4.1218136471e-06, 5.1059358251e-06, 6.1421308306e-06, 7.1521192647e-06, 8.2164613957e-06, 9.3474086978e-06, 1.0368027059e-05, 1.1176114701e-05, 1.1892303251e-05, 1.2600522466e-05, 1.3142991032e-05, 1.3286611961e-05, 1.2972067098e-05, 1.2344251145e-05, 1.1561930031e-05, 1.0577353622e-05, 9.1838382917e-06, 7.3302333455e-06, 5.2367297732e-06, 3.1309520147e-06, 1.0396785645e-06, -1.1104442284e-06, -3.3300486963e-06, -5.5129705406e-06, -7.4742790081e-06, -9.1003715719e-06, -1.0458342224e-05, -1.1632423668e-05, -1.2513736332e-05, -1.2942309414e-05, -1.2975831165e-05, -1.2799952495e-05, -1.2469945465e-05, -1.1941176358e-05, -1.1222986380e-05, -1.0349594257e-05, -9.3491445482e-06, -8.2956327726e-06, -7.2394219079e-06, -6.1539590898e-06, -5.0802321519e-06, -4.1512021086e-06, -3.3868884793e-06, -2.6850344653e-06, -2.0327038471e-06, -1.5048854341e-06, -1.0965986189e-06, -7.4914749272e-07, -4.7128817088e-07, -2.9595396024e-07, -1.9387567373e-07, -1.1597751838e-07, -5.5766761837e-08, -2.3991059778e-08, -1.1910924971e-08, -4.7797889603e-09, 9.0715301612e-11, 1.5744084129e-09, 2.8217939283e-09, 5.5919203984e-09, 7.7259433940e-09, 8.5033504655e-09, 9.1509256107e-09, 8.6746085156e-09, 5.8909590412e-09, 3.5957212556e-09, 4.3347189168e-09, 5.3331969589e-09, 3.9322184713e-09, 3.3616434953e-09, 6.5154351819e-09]) I_imag = np.around(rf_current.imag, 9) # round Iref_imag = np.around(Iref_imag, 9) self.assertSequenceEqual(I_imag.tolist(), Iref_imag.tolist(), msg="In TestRFCurrent test_3, mismatch in imaginary part of RF current")
RF_sct_par = RFStation(general_params, [harmonic_numbers], [voltage_program], [phi_offset], n_rf_systems) beam = Beam(general_params, n_macroparticles, n_particles) ring_RF_section = RingAndRFTracker(RF_sct_par, beam) full_tracker = FullRingAndRF([ring_RF_section]) fs = RF_sct_par.omega_s0[0]/2/np.pi bucket_length = 2.0 * np.pi / RF_sct_par.omega_rf[0,0] # DEFINE SLICES --------------------------------------------------------------- number_slices = 3000 slice_beam = Profile(beam, CutOptions(cut_left=0, cut_right=21*bucket_length, n_slices=number_slices)) # LOAD IMPEDANCE TABLES ------------------------------------------------------- R_S = 5e8 frequency_R = 2*RF_sct_par.omega_rf[0,0] / 2.0 / np.pi Q = 10000 print('Im Z/n = '+str(R_S / (RF_sct_par.t_rev[0] * frequency_R * Q))) resonator = Resonators(R_S, frequency_R, Q) # INDUCED VOLTAGE FROM IMPEDANCE ---------------------------------------------- imp_list = [resonator]
def setUp(self): """ Slicing of the same Gaussian profile using four distinct settings to test different features. """ np.random.seed(1984) intensity_pb = 1.0e11 sigma = 0.2e-9 # Gauss sigma, [s] n_macroparticles_pb = int(1e4) n_bunches = 2 # --- Ring and RF ---------------------------------------------- intensity = n_bunches * intensity_pb # total intensity SPS n_turns = 1 # Ring parameters SPS circumference = 6911.5038 # Machine circumference [m] sync_momentum = 25.92e9 # SPS momentum at injection [eV/c] gamma_transition = 17.95142852 # Q20 Transition gamma momentum_compaction = 1. / gamma_transition**2 # Momentum compaction array ring = Ring(circumference, momentum_compaction, sync_momentum, Proton(), n_turns=n_turns) # RF parameters SPS harmonic_number = 4620 # harmonic number voltage = 3.5e6 # [V] phi_offsets = 0 self.rf_station = RFStation(ring, harmonic_number, voltage, phi_offsets, n_rf=1) t_rf = self.rf_station.t_rf[0, 0] bunch_spacing = 5 # RF buckets n_macroparticles = n_bunches * n_macroparticles_pb self.beam = Beam(ring, n_macroparticles, intensity) for bunch in range(n_bunches): bunchBeam = Beam(ring, n_macroparticles_pb, intensity_pb) bigaussian(ring, self.rf_station, bunchBeam, sigma, reinsertion=True, seed=1984 + bunch) self.beam.dt[bunch*n_macroparticles_pb : (bunch+1)*n_macroparticles_pb] \ = bunchBeam.dt + bunch*bunch_spacing * t_rf self.beam.dE[bunch * n_macroparticles_pb:(bunch + 1) * n_macroparticles_pb] = bunchBeam.dE self.filling_pattern = np.zeros(bunch_spacing * (n_bunches - 1) + 1) self.filling_pattern[::bunch_spacing] = 1 # uniform profile profile_margin = 0 * t_rf t_batch_begin = 0 * t_rf t_batch_end = (bunch_spacing * (n_bunches - 1) + 1) * t_rf self.n_slices_rf = 32 # number of slices per RF-bucket cut_left = t_batch_begin - profile_margin cut_right = t_batch_end + profile_margin # number of rf-buckets of the self.beam # + rf-buckets before the self.beam + rf-buckets after the self.beam n_slices = self.n_slices_rf * ( bunch_spacing * (n_bunches - 1) + 1 + int(np.round((t_batch_begin - cut_left) / t_rf)) + int(np.round((cut_right - t_batch_end) / t_rf))) self.uniform_profile = Profile(self.beam, CutOptions=CutOptions( cut_left=cut_left, n_slices=n_slices, cut_right=cut_right)) self.uniform_profile.track()
class TestCavityFeedback(unittest.TestCase): def setUp(self): C = 2*np.pi*1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1/gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] h = 4620 # 200 MHz system harmonic phi = 0. # 200 MHz RF phase # With this setting, amplitude in the two four-section, five-section # cavities must converge, respectively, to # 2.0 MV = 4.5 MV * 4/18 * 2 # 2.5 MV = 4.5 MV * 5/18 * 2 V = 4.5e6 # 200 MHz RF voltage N_t = 1 # Number of turns to track self.ring = Ring(C, alpha, p_s, Particle=Proton(), n_turns=N_t) self.rf = RFStation(self.ring, h, V, phi) N_m = 1e6 # Number of macro-particles for tracking N_b = 72*1.0e11 # Bunch intensity [ppb] # Gaussian beam profile self.beam = Beam(self.ring, N_m, N_b) sigma = 1.0e-9 bigaussian(self.ring, self.rf, self.beam, sigma, seed=1234, reinsertion=False) n_shift = 1550 # how many rf-buckets to shift beam self.beam.dt += n_shift * self.rf.t_rf[0, 0] self.profile = Profile( self.beam, CutOptions=CutOptions( cut_left=(n_shift-1.5)*self.rf.t_rf[0, 0], cut_right=(n_shift+2.5)*self.rf.t_rf[0, 0], n_slices=4*64)) self.profile.track() # Cavities l_cav = 43*0.374 v_g = 0.0946 tau = l_cav/(v_g*c)*(1 + v_g) f_cav = 200.222e6 n_cav = 2 # factor 2 because of two four/five-sections cavities short_cavity = TravelingWaveCavity(l_cav**2 * n_cav * 27.1e3 / 8, f_cav, 2*np.pi*tau) shortInducedVoltage = InducedVoltageTime(self.beam, self.profile, [short_cavity]) l_cav = 54*0.374 tau = l_cav/(v_g*c)*(1 + v_g) long_cavity = TravelingWaveCavity(l_cav**2 * n_cav * 27.1e3 / 8, f_cav, 2*np.pi*tau) longInducedVoltage = InducedVoltageTime(self.beam, self.profile, [long_cavity]) self.induced_voltage = TotalInducedVoltage( self.beam, self.profile, [shortInducedVoltage, longInducedVoltage]) self.induced_voltage.induced_voltage_sum() self.cavity_tracker = RingAndRFTracker( self.rf, self.beam, Profile=self.profile, interpolation=True, TotalInducedVoltage=self.induced_voltage) self.OTFB = SPSCavityFeedback( self.rf, self.beam, self.profile, G_llrf=5, G_tx=0.5, a_comb=15/16, turns=50, Commissioning=CavityFeedbackCommissioning()) self.OTFB_tracker = RingAndRFTracker(self.rf, self.beam, Profile=self.profile, TotalInducedVoltage=None, CavityFeedback=self.OTFB, interpolation=True) def test_FB_pre_tracking(self): digit_round = 3 Vind4_mean = np.mean(np.absolute(self.OTFB.OTFB_4.V_coarse_tot))/1e6 Vind4_std = np.std(np.absolute(self.OTFB.OTFB_4.V_coarse_tot))/1e6 Vind4_mean_exp = 1.99886351363 Vind4_std_exp = 2.148426e-6 Vind5_mean = np.mean(np.absolute(self.OTFB.OTFB_5.V_coarse_tot))/1e6 Vind5_std = np.std(np.absolute(self.OTFB.OTFB_5.V_coarse_tot))/1e6 Vind5_mean_exp = 2.49906605189 Vind5_std_exp = 2.221665e-6 self.assertAlmostEqual(Vind4_mean, Vind4_mean_exp, places=digit_round, msg='In TestCavityFeedback test_FB_pretracking: ' + 'mean value of four-section cavity differs') self.assertAlmostEqual(Vind4_std, Vind4_std_exp, places=digit_round, msg='In TestCavityFeedback test_FB_pretracking: standard ' + 'deviation of four-section cavity differs') self.assertAlmostEqual(Vind5_mean, Vind5_mean_exp, places=digit_round, msg='In TestCavityFeedback test_FB_pretracking: ' + 'mean value of five-section cavity differs') self.assertAlmostEqual(Vind5_std, Vind5_std_exp, places=digit_round, msg='In TestCavityFeedback test_FB_pretracking: standard ' + 'deviation of five-section cavity differs') def test_FB_pre_tracking_IQ_v1(self): rtol = 1e-3 # relative tolerance atol = 0 # absolute tolerance # interpolate from coarse mesh to fine mesh V_fine_tot_4 = np.interp( self.profile.bin_centers, self.OTFB.OTFB_4.rf_centers, self.OTFB.OTFB_4.V_coarse_ind_gen) V_fine_tot_5 = np.interp( self.profile.bin_centers, self.OTFB.OTFB_5.rf_centers, self.OTFB.OTFB_5.V_coarse_ind_gen) V_tot_4 = V_fine_tot_4/1e6 V_tot_5 = V_fine_tot_5/1e6 V_sum = self.OTFB.V_sum/1e6 # expected generator voltage is only in Q V_tot_4_exp = 2.0j*np.ones(256) V_tot_5_exp = 2.5j*np.ones(256) V_sum_exp = 4.5j*np.ones(256) np.testing.assert_allclose(V_tot_4, V_tot_4_exp, rtol=rtol, atol=atol, err_msg='In TestCavityFeedback test_FB_pretracking_IQ: total voltage ' + 'in four-section cavity differs') np.testing.assert_allclose(V_tot_5, V_tot_5_exp, rtol=rtol, atol=atol, err_msg='In TestCavityFeedback test_FB_pretracking_IQ: total voltage ' + 'in five-section cavity differs') np.testing.assert_allclose(V_sum, V_sum_exp, rtol=rtol, atol=atol, err_msg='In TestCavityFeedback test_FB_pretracking_IQ: voltage sum ' + ' differs') def test_rf_voltage(self): digit_round = 9 # compute voltage self.cavity_tracker.rf_voltage_calculation() # compute voltage after OTFB pre-tracking self.OTFB_tracker.rf_voltage_calculation() # Since there is a systematic offset between the voltages, # compare the maxium of the ratio max_ratio = np.max(self.cavity_tracker.rf_voltage / self.OTFB_tracker.rf_voltage) max_ratio = max_ratio max_ratio_exp = 1.0008217052569774 self.assertAlmostEqual(max_ratio, max_ratio_exp, places=digit_round, msg='In TestCavityFeedback test_rf_voltage: ' + 'RF-voltages differ') def test_beam_loading(self): digit_round = 9 # Compute voltage with beam loading self.cavity_tracker.rf_voltage_calculation() cavity_tracker_total_voltage = self.cavity_tracker.rf_voltage \ + self.cavity_tracker.totalInducedVoltage.induced_voltage self.OTFB.track() self.OTFB_tracker.rf_voltage_calculation() OTFB_tracker_total_voltage = self.OTFB_tracker.rf_voltage max_ratio = np.max(cavity_tracker_total_voltage / OTFB_tracker_total_voltage) max_ration_exp = 1.0051759770680779 self.assertAlmostEqual(max_ratio, max_ration_exp, places=digit_round, msg='In TestCavityFeedback test_beam_loading: ' + 'total voltages differ') def test_Vsum_IQ(self): rtol = 1e-7 # relative tolerance atol = 0 # absolute tolerance self.OTFB.track() V_sum = self.OTFB.V_sum/1e6 V_sum_exp = np.array([-7.40650823e+01+4497812.99202967j, -7.40650823e+01+4497812.99202967j, -7.40650823e+01+4497812.99202967j, -7.40650823e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650823e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202967j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -7.40650822e+01+4497812.99202968j, -6.02318851e+01+4497817.94162674j, -1.98390915e+01+4497835.4539936j, 1.93158486e+01+4497855.56826354j, 4.37055412e+01+4497871.87009121j, 7.72626261e+01+4497900.35036866j, 1.08879867e+02+4497930.96118169j, 1.36226374e+02+4497965.43834138j, 1.83914308e+02+4498039.43198652j, 2.58060957e+02+4498182.7842137j, 3.46527521e+02+4498400.20917783j, 4.26706222e+02+4498667.15544146j, 4.94661306e+02+4499027.56784064j, 5.43482338e+02+4499582.92538958j, 5.37601327e+02+4500375.11759629j, 4.18116316e+02+4501483.68340875j, 1.06781854e+02+4502992.29896325j, -5.18346745e+02+4504994.88486696j, -1.49458714e+03+4507337.42385509j, -3.01163886e+03+4510119.3419273j, -5.32851179e+03+4513546.45481774j, -8.74569640e+03+4517649.58201841j, -1.36711235e+04+4522515.97696859j, -2.06268308e+04+4528145.57335092j, -3.07188747e+04+4534772.43779405j, -4.42705242e+04+4541938.02912512j, -6.14651616e+04+4548954.45228089j, -8.23300421e+04+4555211.22162217j, -1.09421551e+05+4560368.34346543j, -1.43885886e+05+4563628.1865127j, -1.85808399e+05+4563383.852869j, -2.36208282e+05+4558209.23829535j, -2.94836934e+05+4546270.53281669j, -3.63317854e+05+4525133.07455768j, -4.41779074e+05+4492246.31582297j, -5.28977031e+05+4445197.26263046j, -6.24427353e+05+4380854.18329653j, -7.28570463e+05+4294604.34393273j, -8.41413067e+05+4180725.12037253j, -9.58666802e+05+4036850.21934613j, -1.07489637e+06+3861588.24443417j, -1.18692079e+06+3650150.96222293j, -1.28868132e+06+3402561.33925834j, -1.37503355e+06+3113868.12951949j, -1.44047679e+06+2779413.13521708j, -1.47644078e+06+2402815.35953829j, -1.47522678e+06+1985042.23744602j, -1.42897968e+06+1528424.34271266j, -1.32931255e+06+1034805.30411738j, -1.16912937e+06 + 511261.80102318j, -9.43345126e+05 - 30406.39494472j, -6.44543913e+05 - 585971.64269612j, -2.67898382e+05-1147041.0353738j, 1.87647422e+05-1699739.23544117j, 7.19585769e+05-2229855.79356738j, 1.32653137e+06-2725965.80099238j, 2.00691053e+06-3178849.17084715j, 2.75728744e+06-3578075.86057957j, 3.56230981e+06-3910440.14562456j, 4.40408617e+06-4164575.91355405j, 5.28572695e+06-4338227.19020188j, 6.19719564e+06-4426787.10912655j, 7.11277008e+06-4425807.66220696j, 8.01692653e+06-4335730.38899002j, 8.89765817e+06-4159572.80505286j, 9.74683705e+06-3900763.99853979j, 1.05559999e+07-3564480.67012727j, 1.13018718e+07-3165395.29765105j, 1.19781005e+07-2712267.95526922j, 1.25833208e+07-2214895.26359232j, 1.31112101e+07-1685734.89623327j, 1.35640429e+07-1132761.26804116j, 1.39371556e+07 - 573495.98893318j, 1.42323033e+07 - 19883.35687916j, 1.44559502e+07 + 521811.95451886j, 1.46134106e+07+1043190.45283868j, 1.47105373e+07+1534116.02749795j, 1.47549265e+07+1994083.71851812j, 1.47545428e+07+2416602.70892133j, 1.47166958e+07+2794242.30539414j, 1.46493955e+07+3129779.93382244j, 1.45593030e+07+3424466.23125072j, 1.44539743e+07+3677716.51226699j, 1.43401341e+07+3889644.33404043j, 1.42224899e+07+4064982.31004726j, 1.41063737e+07+4205965.72167177j, 1.39946111e+07+4317244.42689922j, 1.38886184e+07+4403883.23649077j, 1.37894739e+07+4469861.27187975j, 1.36989283e+07+4518194.75268176j, 1.36191316e+07+4551305.81768837j, 1.35495619e+07+4572524.22309931j, 1.34903101e+07+4584597.89085099j, 1.34406305e+07+4589814.4489974j, 1.33976876e+07+4590220.82697034j, 1.33615022e+07+4587255.76269093j, 1.33327026e+07+4582254.09185628j, 1.33096130e+07+4576070.77968165j, 1.32911752e+07+4569436.1321998j, 1.32768524e+07+4562928.08977976j, 1.32656893e+07+4556810.85976046j, 1.32570926e+07+4551309.42853408j, 1.32504722e+07+4546502.73564931j, 1.32453253e+07+4542354.45990368j, 1.32414716e+07+4539159.11692844j, 1.32386032e+07+4536873.63706821j, 1.32362022e+07+4534949.63932622j, 1.32341515e+07+4533397.43716764j, 1.32323621e+07+4532141.64712087j, 1.32307439e+07+4531156.20064611j, 1.32292493e+07+4530633.17835778j, 1.32277994e+07+4530492.96280951j, 1.32263821e+07+4530446.25647796j, 1.32249901e+07+4530405.83108728j, 1.32236081e+07+4530431.11420123j, 1.32222495e+07+4530467.44843446j, 1.32208432e+07+4530611.48233323j, 1.32193886e+07+4530847.10244979j, 1.32179361e+07+4531084.60180009j, 1.32164993e+07+4531317.55923836j, 1.32150516e+07+4531560.32993118j, 1.32135685e+07+4531829.29611484j, 1.32120853e+07+4532098.20168656j, 1.32106022e+07+4532367.04664624j, 1.32091191e+07+4532635.83099376j, 1.32076359e+07+4532904.55472902j, 1.32061675e+07+4533173.93875581j, 1.32046990e+07+4533443.26260922j, 1.32032158e+07+4533711.80494598j, 1.32017326e+07+4533980.28666989j, 1.32002495e+07+4534248.70778084j, 1.31987663e+07+4534517.06827872j, 1.31972831e+07+4534785.36816343j, 1.31957999e+07+4535053.60743485j, 1.31943167e+07+4535321.78609287j, 1.31928335e+07+4535589.90413737j, 1.31913503e+07+4535857.96156826j, 1.31898671e+07+4536125.95838542j, 1.31883839e+07+4536393.89458873j, 1.31869007e+07+4536661.77017809j, 1.31854174e+07+4536929.58515338j, 1.31839342e+07+4537197.33951451j, 1.31824510e+07+4537465.03326134j, 1.31809677e+07+4537732.66639378j, 1.31794845e+07+4538000.23891172j, 1.31780012e+07+4538267.75081504j, 1.31765179e+07+4538535.20210364j, 1.31750347e+07+4538802.5927774j, 1.31735514e+07+4539069.92283622j, 1.31720681e+07+4539337.19227997j, 1.31705848e+07+4539604.40110857j, 1.31691016e+07+4539871.54932188j, 1.31676183e+07+4540138.63691982j, 1.31661350e+07+4540405.66390225j, 1.31646517e+07+4540672.63026908j, 1.31631684e+07+4540939.53602019j, 1.31616850e+07+4541206.38115549j, 1.31602017e+07+4541473.16567484j, 1.31587184e+07+4541739.88957815j, 1.31572351e+07+4542006.55286531j, 1.31557517e+07+4542273.1555362j, 1.31542684e+07+4542539.69759073j, 1.31527850e+07+4542806.17902876j, 1.31513017e+07+4543072.59985021j, 1.31498183e+07+4543338.96005496j, 1.31483350e+07+4543605.2596429j, 1.31468516e+07+4543871.49861392j, 1.31453682e+07+4544137.6769679j, 1.31438848e+07+4544403.79470476j, 1.31424014e+07+4544669.85182436j, 1.31409181e+07+4544935.84832662j, 1.31394347e+07+4545201.7842114j, 1.31379513e+07+4545467.65947862j, 1.31364679e+07+4545733.47412815j, 1.31349844e+07+4545999.22815989j, 1.31335010e+07+4546264.92157373j, 1.31320176e+07+4546530.55436956j, 1.31305342e+07+4546796.12654728j, 1.31290507e+07+4547061.63810677j, 1.31275673e+07+4547327.08904792j, 1.31260839e+07+4547592.47937064j, 1.31246004e+07+4547857.8090748j, 1.31231170e+07+4548123.0781603j, 1.31216335e+07+4548388.28662704j, 1.31201500e+07+4548653.4344749j, 1.31186666e+07+4548918.52170378j, 1.31171831e+07+4549183.54831356j, 1.31156996e+07+4549448.51430414j, 1.31142161e+07+4549713.41967541j, 1.31127326e+07+4549978.26442727j])/1e6 np.testing.assert_allclose(V_sum_exp, V_sum, rtol=rtol, atol=atol, err_msg='In TestCavityFeedback test_Vsum_IQ: total voltage ' + 'is different from expected values!')
# Single bunch bunch = Beam(ring, N_m, N_b) bigaussian(ring, rf, bunch, 3.2e-9 / 4, seed=1234, reinsertion=True) logging.info("Bunch spacing %.3e s", rf.t_rf[0, 0] * bunch_spacing) # Create beam beam = Beam(ring, n_bunches * N_m, n_bunches * N_b) for i in range(n_bunches): beam.dt[int(i * N_m):int((i + 1) * N_m)] = bunch.dt + i * rf.t_rf[0, 0] * bunch_spacing beam.dE[int(i * N_m):int((i + 1) * N_m)] = bunch.dE profile = Profile(beam, CutOptions=CutOptions(cut_left=0.e-9, cut_right=rf.t_rev[0], n_slices=46200)) profile.track() logging.debug("Beam q/m ratio %.3e", profile.Beam.ratio) OTFB = SPSCavityFeedback(rf, beam, profile, G_llrf=5, G_tx=0.5, a_comb=15 / 16, turns=N_pretrack, post_LS2=False, Commissioning=CavityFeedbackCommissioning( debug=True, open_FF=True))
for i in range(108, 156): beam.dt[i * N_m:(i + 1) * N_m] = bunch.dt[0:N_m] + i * buckets + 48 * buckets beam.dE[i * N_m:(i + 1) * N_m] = bunch.dE[0:N_m] for i in range(156, 500): beam.dt[i * N_m:(i + 1) * N_m] = bunch.dt[0:N_m] + i * buckets + 200 * buckets beam.dE[i * N_m:(i + 1) * N_m] = bunch.dE[0:N_m] tot_buckets = (NB + 32 + 40 + 48 + 200) * 10 logging.debug('Maximum of beam coordinates %.4e s', np.max(beam.dt)) logging.info('Number of buckets considered %d', tot_buckets) logging.debug('Profile cut set at %.4e s', tot_buckets * rf.t_rf[0, 0]) profile = Profile( beam, CutOptions(n_slices=int(100 * tot_buckets), cut_left=0, cut_right=tot_buckets * rf.t_rf[0, 0])) profile.track() plt.figure('Bunch profile') plt.plot(profile.bin_centers * 1e9, profile.n_macroparticles) plt.xlabel('Bin centers [ns]') plt.ylabel('Macroparticles [1]') plt.show() logging.info( 'Initialising LHCCavityLoop, tuned to injection (with no beam current)') logging.info('CLOSED LOOP, no excitation, 1 turn tracking') # DUMMY TO CALCULATE PEAK BEAM CURRENT CL = LHCCavityLoop(rf,
def test_vind(self): # randomly chose omega_c from allowed range np.random.seed(1980) factor = np.random.uniform(0.9, 1.1) # round results to this digits digit_round = 8 # SPS parameters C = 2*np.pi*1100.009 # Ring circumference [m] gamma_t = 18.0 # Gamma at transition alpha = 1/gamma_t**2 # Momentum compaction factor p_s = 25.92e9 # Synchronous momentum at injection [eV] h = 4620 # 200 MHz system harmonic V = 4.5e6 # 200 MHz RF voltage phi = 0. # 200 MHz RF phase # Beam and tracking parameters N_m = 1e5 # Number of macro-particles for tracking N_b = 1.0e11 # Bunch intensity [ppb] N_t = 1 # Number of turns to track ring = Ring(C, alpha, p_s, Proton(), n_turns=N_t) rf = RFStation(ring, h, V, phi) beam = Beam(ring, N_m, N_b) bigaussian(ring, rf, beam, 3.2e-9/4, seed=1234, reinsertion=True) n_shift = 5 # how many rf-buckets to shift beam beam.dt += n_shift * rf.t_rf[0,0] profile = Profile(beam, CutOptions= CutOptions(cut_left=(n_shift-1.5)*rf.t_rf[0,0], cut_right=(n_shift+1.5)*rf.t_rf[0,0], n_slices=140)) profile.track() l_cav = 16.082 v_g = 0.0946 tau = l_cav/(v_g*c)*(1 + v_g) TWC_impedance_source = TravelingWaveCavity(l_cav**2 * 27.1e3 / 8, 200.222e6, 2*np.pi*tau) # Beam loading by convolution of beam and wake from cavity inducedVoltageTWC = InducedVoltageTime(beam, profile, [TWC_impedance_source]) induced_voltage = TotalInducedVoltage(beam, profile, [inducedVoltageTWC]) induced_voltage.induced_voltage_sum() V_ind_impSource = np.around(induced_voltage.induced_voltage, digit_round) # Beam loading via feed-back system OTFB_4 = SPSOneTurnFeedback(rf, beam, profile, 4, n_cavities=1) OTFB_4.counter = 0 # First turn OTFB_4.omega_c = factor * OTFB_4.TWC.omega_r # Compute impulse response OTFB_4.TWC.impulse_response_beam(OTFB_4.omega_c, profile.bin_centers) # Compute induced voltage in (I,Q) coordinates OTFB_4.beam_induced_voltage(lpf=False) # convert back to time V_ind_OTFB \ = OTFB_4.V_fine_ind_beam.real \ * np.cos(OTFB_4.omega_c*profile.bin_centers) \ + OTFB_4.V_fine_ind_beam.imag \ * np.sin(OTFB_4.omega_c*profile.bin_centers) V_ind_OTFB = np.around(V_ind_OTFB, digit_round) self.assertListEqual(V_ind_impSource.tolist(), V_ind_OTFB.tolist(), msg="In TravelingWaveCavity test_vind: induced voltages differ")
bigaussian(general_params, RF_sct_par, my_beam, tau_0 / 4, seed=1) bigaussian(general_params_freq, RF_sct_par_freq, my_beam_freq, tau_0 / 4, seed=1) bigaussian(general_params_res, RF_sct_par_res, my_beam_res, tau_0 / 4, seed=1) number_slices = 2**8 cut_options = CutOptions(cut_left=0, cut_right=2 * np.pi, n_slices=number_slices, RFSectionParameters=RF_sct_par, cuts_unit='rad') slice_beam = Profile(my_beam, cut_options, FitOptions(fit_option='gaussian')) cut_options_freq = CutOptions(cut_left=0, cut_right=2 * np.pi, n_slices=number_slices, RFSectionParameters=RF_sct_par_freq, cuts_unit='rad') slice_beam_freq = Profile(my_beam_freq, cut_options_freq, FitOptions(fit_option='gaussian')) cut_options_res = CutOptions(cut_left=0, cut_right=2 * np.pi, n_slices=number_slices, RFSectionParameters=ring_RF_section_res, cuts_unit='rad') slice_beam_res = Profile(my_beam_res, cut_options_res, FitOptions(fit_option='gaussian'))
class TestBeamFeedback(unittest.TestCase): def setUp(self): n_turns = 200 intensity_pb = 1.2e6 # protons per bunch n_macroparticles = int(1e6) # macropartilces per bunch sigma = 0.05e-9 # sigma for gaussian bunch [s] self.time_offset = 0.1e-9 # time by which to offset the bunch # Ring parameters SPS C = 6911.5038 # Machine circumference [m] sync_momentum = 25.92e9 # SPS momentum at injection [eV/c] gamma_transition = 17.95142852 # Q20 Transition gamma momentum_compaction = 1./gamma_transition**2 # Momentum compaction array self.ring = Ring(C, momentum_compaction, sync_momentum, Proton(), n_turns=n_turns) # RF parameters SPS harmonic = 4620 # Harmonic numbers voltage = 4.5e6 # [V] phi_offsets = 0 self.rf_station = RFStation(self.ring, harmonic, voltage, phi_offsets) t_rf = self.rf_station.t_rf[0,0] # Beam setup self.beam = Beam(self.ring, n_macroparticles, intensity_pb) bigaussian(self.ring, self.rf_station, self.beam, sigma, seed = 1234, reinsertion = True) ### displace beam to see effect of phase error and phase loop self.beam.dt += self.time_offset # Profile setup self.profile = Profile(self.beam, CutOptions = CutOptions(cut_left=0, cut_right=t_rf, n_slices=1024)) def test_SPS_RL(self): PL_gain = 1000 # gain of phase loop round_digit = 5 # to how many digits round the result # Phase loop setup phase_loop = BeamFeedback(self.ring, self.rf_station, self.profile, {'machine':'SPS_RL', 'PL_gain':PL_gain}) # Tracker setup section_tracker = RingAndRFTracker( self.rf_station, self.beam, Profile=self.profile, BeamFeedback=phase_loop, interpolation=False) tracker = FullRingAndRF([section_tracker]) # average beam position beamAvgPos = np.zeros(self.ring.n_turns) n_turns = self.ring.n_turns for turn in range(n_turns): beamAvgPos[turn] = np.mean(self.beam.dt) self.profile.track() tracker.track() # difference between beam position and synchronuous position # (assuming no beam loading) delta_tau = beamAvgPos - (np.pi - self.rf_station.phi_rf[0,:-1])\ / self.rf_station.omega_rf[0,:-1] # initial position for analytic solution init_pos = self.time_offset omega_eff = cmath.sqrt(-PL_gain**2 + 4*self.rf_station.omega_s0[0]**2) time = np.arange(n_turns) * self.ring.t_rev[0] # initial derivative for analytic solution; # defined such that analytical solution at turn 1 agrees with numerical # solution init_slope = 0.5 * (delta_tau[1] * omega_eff * np.exp(0.5*PL_gain*time[1])\ / np.sin(0.5*omega_eff*time[1]) - delta_tau[0]\ *(PL_gain+omega_eff/np.tan(0.5*omega_eff*time[1])) ).real delta_tau_analytic = init_pos * np.exp(-0.5*PL_gain*time) delta_tau_analytic *= np.cos(0.5*time*omega_eff).real\ + (PL_gain+2*init_slope/init_pos)\ * (np.sin(0.5*time*omega_eff)/omega_eff).real difference = delta_tau - delta_tau_analytic # normalize result difference = np.around(difference/np.max(difference), round_digit) # expected difference difference_exp = np.array([ -1.56306635e-05, -1.55605315e-05, -2.10224435e-05, -3.18525050e-05, -4.74014489e-05, -6.70584402e-05, -9.01307422e-05, -1.15823959e-04, -1.43290487e-04, -1.71572162e-04, -1.99820151e-04, -2.27071730e-04, -2.52331681e-04, -2.74668126e-04, -2.93165304e-04, -3.06972913e-04, -3.15442474e-04, -3.17857324e-04, -3.13794970e-04, -3.02786089e-04, -2.84680298e-04, -2.59322215e-04, -2.26874004e-04, -1.87452375e-04, -1.41293604e-04, -8.89863575e-05, -3.08865701e-05, 3.22411495e-05, 9.97408029e-05, 1.70914181e-04, 2.44766912e-04, 3.20596833e-04, 3.97403451e-04, 4.74233283e-04, 5.50189125e-04, 6.24368453e-04, 6.95836553e-04, 7.63737143e-04, 8.27069057e-04, 8.84995559e-04, 9.36770723e-04, 9.81561780e-04, 1.01869959e-03, 1.04738842e-03, 1.06711062e-03, 1.07736961e-03, 1.07778386e-03, 1.06805613e-03, 1.04797776e-03, 1.01747638e-03, 9.76519221e-04, 9.25420191e-04, 8.64415092e-04, 7.93844624e-04, 7.14396030e-04, 6.26549187e-04, 5.31154439e-04, 4.28985322e-04, 3.21198916e-04, 2.08550190e-04, 9.21607082e-05, -2.68249728e-05, -1.47278123e-04, -2.67890543e-04, -3.87642210e-04, -5.05244473e-04, -6.19660328e-04, -7.29670300e-04, -8.34272846e-04, -9.32388033e-04, -1.02301036e-03, -1.10520861e-03, -1.17824066e-03, -1.24119243e-03, -1.29350096e-03, -1.33458128e-03, -1.36388379e-03, -1.38105465e-03, -1.38595634e-03, -1.37832214e-03, -1.35829791e-03, -1.32588558e-03, -1.28146000e-03, -1.22518721e-03, -1.15769141e-03, -1.07943574e-03, -9.91143310e-04, -8.93671637e-04, -7.87961546e-04, -6.74866999e-04, -5.55444011e-04, -4.30919368e-04, -3.02270469e-04, -1.70824836e-04, -3.77396109e-05, 9.56816273e-05, 2.28299979e-04, 3.58842001e-04, 4.86074690e-04, 6.08875045e-04, 7.26090501e-04, 8.36677390e-04, 9.39639556e-04, 1.03407702e-03, 1.11906014e-03, 1.19386315e-03, 1.25779004e-03, 1.31037519e-03, 1.35108872e-03, 1.37958003e-03, 1.39570542e-03, 1.39927441e-03, 1.39033118e-03, 1.36892681e-03, 1.33533475e-03, 1.28987173e-03, 1.23311389e-03, 1.16551418e-03, 1.08773037e-03, 1.00059786e-03, 9.04879918e-04, 8.01551710e-04, 6.91575582e-04, 5.75952750e-04, 4.55756793e-04, 3.32302985e-04, 2.06487043e-04, 7.95882588e-05, -4.72208138e-05, -1.72823958e-04, -2.96101535e-04, -4.15925168e-04, -5.31250383e-04, -6.41017819e-04, -7.44349685e-04, -8.40276057e-04, -9.28032591e-04, -1.00688055e-03, -1.07610640e-03, -1.13518206e-03, -1.18370702e-03, -1.22129557e-03, -1.24764964e-03, -1.26264035e-03, -1.26627364e-03, -1.25857717e-03, -1.23964021e-03, -1.20980891e-03, -1.16944284e-03, -1.11887385e-03, -1.05870668e-03, -9.89617769e-04, -9.12311681e-04, -8.27560752e-04, -7.36170045e-04, -6.39042153e-04, -5.37114997e-04, -4.31247869e-04, -3.22637131e-04, -2.12194968e-04, -1.00869243e-04, 1.03136916e-05, 1.20241207e-04, 2.27979265e-04, 3.32675130e-04, 4.33323979e-04, 5.29105666e-04, 6.19142445e-04, 7.02728753e-04, 7.79114404e-04, 8.47787258e-04, 9.08216047e-04, 9.59821724e-04, 1.00228122e-03, 1.03538392e-03, 1.05880009e-03, 1.07260841e-03, 1.07662550e-03, 1.07093155e-03, 1.05577003e-03, 1.03129797e-03, 9.97904596e-04, 9.55975595e-04, 9.05955028e-04, 8.48396342e-04, 7.83925297e-04, 7.13242537e-04, 6.36896396e-04, 5.55809454e-04, 4.70697276e-04, 3.82464668e-04, 2.91766220e-04, 1.99564879e-04, 1.06707654e-04, 1.40463177e-05, -7.76333806e-05, -1.67470574e-04, -2.54708122e-04, -3.38623857e-04, -4.18484684e-04]) difference_exp = np.around(difference_exp/np.max(difference_exp), round_digit) self.assertListEqual(difference.tolist(), difference_exp.tolist(), msg='In TestBeamFeedback test_SPS_RL: ' +'difference between simulated and analytic result different than' +'expected')