Ejemplo n.º 1
0
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)
# args = parser.parse_args()
# print(args)
if (args['gpu'] == 1):
    import blond.utils.bmath as bm
    bm.use_gpu()
    long_tracker_1.use_gpu()
    long_tracker_2.use_gpu()
    slice_beam.use_gpu()
    long_tracker_tot.use_gpu()


# Tracking --------------------------------------------------------------------
for i in np.arange(1,N_t+1):
    #print(i)
    
    long_tracker_tot.track() 
       
    # Track
    for m in map_:
        m.track()
    
    # Define losses according to separatrix and/or longitudinal position
    # beam.losses_separatrix(general_params, rf_params_tot)
    # beam.losses_longitudinal_cut(0., 2.5e-9)

# if (args.d):
#     print(np.std(beam.dE))
print('dE mean: ', np.mean(beam.dE))
print('dE std: ', np.std(beam.dE))
print('profile mean: ', np.mean(slice_beam.n_macroparticles))
print('profile std: ', np.std(slice_beam.n_macroparticles))
Ejemplo n.º 3
0
for turn in range(n_iterations):

    # Plot has to be done before tracking (at least for cases with separatrix)
    if (turn % dt_plt) == 0:
        mpiprint("Outputting at time step %d..." % turn)
        mpiprint("   Beam momentum %.6e eV" % beam.momentum)
        mpiprint("   Beam gamma %3.3f" % beam.gamma)
        mpiprint("   Beam beta %3.3f" % beam.beta)
        mpiprint("   Beam energy %.6e eV" % beam.energy)
        mpiprint("   Four-times r.m.s. bunch length %.4e s" %
                 (4. * beam.sigma_dt))
        mpiprint("   Gaussian bunch length %.4e s" % profile.bunchLength)
        mpiprint("")

    # Track
    long_tracker.track()

    # Update profile
    if (approx == 0):
        profile.track()
        profile.reduce_histo()
    elif (approx == 1) and (turn % n_turns_reduce == 0):
        profile.track()
        profile.reduce_histo()
    elif (approx == 2):
        profile.track()
        profile.scale_histo()

    worker.DLB(turn, beam)

    if (args['monitor'] > 0) and (turn % args['monitor'] == 0):
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
class TestRfVoltageCalcWCavityFB(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.cavityFB = CavityFB(1.1, 1.2)
        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):
        self.long_tracker.cavityFB = CavityFB(1.1, 1.2)
        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):
        self.long_tracker.cavityFB = CavityFB(1.1, 1.2)
        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 test_rf_voltage_calc_4(self):
        self.long_tracker.cavityFB = CavityFB(
            np.linspace(1, 1.5, self.profile.n_slices),
            np.linspace(0.1, 0.5, self.profile.n_slices))
        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_5(self):
        self.long_tracker.cavityFB = CavityFB(
            np.linspace(1, 1.5, self.profile.n_slices),
            np.linspace(0.1, 0.5, self.profile.n_slices))
        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_6(self):
        self.long_tracker.cavityFB = CavityFB(
            np.linspace(1, 1.5, self.profile.n_slices),
            np.linspace(0.1, 0.5, self.profile.n_slices))
        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 test_phi_modulation(self):

        timebase = np.linspace(0, 0.2, 10000)
        freq = 2E3
        amp = np.pi
        offset = 0
        harmonic = self.h
        phiMod = PMod(timebase, freq, amp, offset, harmonic)

        self.rf = RFStation(
            self.ring, [self.h], self.V * np.linspace(1, 1.1, self.N_t+1), \
            [self.dphi], phi_modulation = phiMod)

        self.long_tracker = RingAndRFTracker(self.rf,
                                             self.beam,
                                             Profile=self.profile)

        for i in range(self.N_t):
            self.long_tracker.track()
            self.assertEqual( \
                self.long_tracker.phi_rf[:, self.long_tracker.counter[0]-1], \
                self.rf.phi_modulation[0][0][i], msg = \
                """Phi modulation not added correctly in tracker""")
Ejemplo n.º 6
0
class CompareDrift(object):

    # Using PSB as base for 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 = 2*np.pi*25.                     # Machine circumference [m]
    Ek = 160e6                          # Kinetic energy [eV]
    gamma_t = 4.1                       # Transition gamma
    alpha_0 = 1./gamma_t/gamma_t        # First order mom. comp. factor
    alpha_1 = 10*alpha_0
    alpha_2 = 100*alpha_0

    # Tracking details
    N_t = 2000                          # Number of turns to track

    def run_simple(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=None, alpha_2=None)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='simple')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * linear_drift(
            original_distribution_dE, self.ring.eta_0[0, 0],
            self.ring.beta[0, 0], self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_legacy_order0(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=None, alpha_2=None)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='legacy')

        # Forcing usage of legacy
        self.long_tracker.solver = 'legacy'
        self.long_tracker.solver = self.long_tracker.solver.encode(
            encoding='utf_8')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * legacy_drift(
            original_distribution_dE, self.ring.eta_0[0, 0],
            self.ring.eta_1[0, 0], self.ring.eta_2[0, 0], self.ring.beta[0, 0],
            self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_legacy_order1(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=self.alpha_1, alpha_2=None)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='legacy')

        # Forcing usage of legacy
        self.long_tracker.solver = 'legacy'
        self.long_tracker.solver = self.long_tracker.solver.encode(
            encoding='utf_8')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * legacy_drift(
            original_distribution_dE, self.ring.eta_0[0, 0],
            self.ring.eta_1[0, 0], self.ring.eta_2[0, 0], self.ring.beta[0, 0],
            self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_legacy_order2(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=None, alpha_2=self.alpha_2)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='legacy')

        # Forcing usage of legacy
        self.long_tracker.solver = 'legacy'
        self.long_tracker.solver = self.long_tracker.solver.encode(
            encoding='utf_8')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * legacy_drift(
            original_distribution_dE, self.ring.eta_0[0, 0],
            self.ring.eta_1[0, 0], self.ring.eta_2[0, 0], self.ring.beta[0, 0],
            self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_legacy_order1and2(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=self.alpha_1, alpha_2=self.alpha_2)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='legacy')

        # Forcing usage of legacy
        self.long_tracker.solver = 'legacy'
        self.long_tracker.solver = self.long_tracker.solver.encode(
            encoding='utf_8')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * legacy_drift(
            original_distribution_dE, self.ring.eta_0[0, 0],
            self.ring.eta_1[0, 0], self.ring.eta_2[0, 0], self.ring.beta[0, 0],
            self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_exact_order0(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=None, alpha_2=None)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='exact')

        # Forcing usage of legacy
        self.long_tracker.solver = 'exact'
        self.long_tracker.solver = self.long_tracker.solver.encode(
            encoding='utf_8')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * exact_drift(
            original_distribution_dE, self.ring.alpha_0[0, 0],
            self.ring.alpha_1[0, 0], self.ring.alpha_2[0, 0],
            self.ring.beta[0, 0], self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_exact_order1(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=self.alpha_1, alpha_2=None)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='exact')

        # Forcing usage of legacy
        self.long_tracker.solver = 'exact'
        self.long_tracker.solver = self.long_tracker.solver.encode(
            encoding='utf_8')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * exact_drift(
            original_distribution_dE, self.ring.alpha_0[0, 0],
            self.ring.alpha_1[0, 0], self.ring.alpha_2[0, 0],
            self.ring.beta[0, 0], self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_exact_order2(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=None, alpha_2=self.alpha_2)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='exact')

        # Forcing usage of legacy
        self.long_tracker.solver = 'exact'
        self.long_tracker.solver = self.long_tracker.solver.encode(
            encoding='utf_8')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * exact_drift(
            original_distribution_dE, self.ring.alpha_0[0, 0],
            self.ring.alpha_1[0, 0], self.ring.alpha_2[0, 0],
            self.ring.beta[0, 0], self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_exact_order1and2(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=self.alpha_1, alpha_2=self.alpha_2)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        self.beam.dt[:] = np.array(original_distribution_dt)
        self.beam.dE[:] = np.array(original_distribution_dE)

        self.long_tracker = RingAndRFTracker(
            self.rf, self.beam, solver='exact')

        # Forcing usage of legacy
        self.long_tracker.solver = 'exact'
        self.long_tracker.solver = self.long_tracker.solver.encode(
            encoding='utf_8')

        for i in range(self.ring.n_turns):
            self.long_tracker.track()

        original_distribution_dt += self.ring.n_turns * exact_drift(
            original_distribution_dE, self.ring.alpha_0[0, 0],
            self.ring.alpha_1[0, 0], self.ring.alpha_2[0, 0],
            self.ring.beta[0, 0], self.ring.energy[0, 0], self.ring.t_rev[0])

        return self.beam.dt, original_distribution_dt, original_distribution_dE

    def run_expected_drift(self):

        self.ring = Ring(self.C, self.alpha_0, self.Ek, Proton(), self.N_t,
                         synchronous_data_type='kinetic energy',
                         alpha_1=self.alpha_1, alpha_2=self.alpha_2)

        self.beam = Beam(self.ring, self.N_p, self.N_b)

        self.rf = RFStation(self.ring, 1, 0, np.pi)

        original_distribution_dt = np.zeros(self.beam.n_macroparticles)
        original_distribution_dE = np.linspace(
            -0.1*self.beam.energy,
            0.1*self.beam.energy,
            self.beam.n_macroparticles)

        original_distribution_dt += self.ring.n_turns * expected_drift(
            original_distribution_dE, self.ring.alpha_0[0, 0],
            self.ring.alpha_1[0, 0], self.ring.alpha_2[0, 0],
            self.ring.energy[0, 0], self.ring.t_rev[0],
            self.ring.ring_circumference, self.ring.Particle.mass)

        return original_distribution_dt, original_distribution_dE
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)


# Accelerator map
map_ = [long_tracker_1] + [long_tracker_2] + [slice_beam] + [bunchmonitor] + \
       [plots]
print("Map set")
print("")

# Tracking --------------------------------------------------------------------
for i in np.arange(1,N_t+1):
    print(i)
    
    long_tracker_tot.track() 
       
    # Track
    for m in map_:
        m.track()
    
    # Define losses according to separatrix and/or longitudinal position
    beam.losses_separatrix(general_params, rf_params_tot)
    beam.losses_longitudinal_cut(0., 2.5e-9)


print("Done!")