Exemplo n.º 1
0
    def track_ghosts_particles(self, ghostBeam):

        induced_energy = self.beam.charge * self.induced_voltage
        libblond.linear_interp_kick(
            ghostBeam.dt.ctypes.data_as(ctypes.c_void_p),
            ghostBeam.dE.ctypes.data_as(ctypes.c_void_p),
            induced_energy.ctypes.data_as(ctypes.c_void_p),
            self.slices.bin_centers.ctypes.data_as(ctypes.c_void_p),
            ctypes.c_uint(self.slices.n_slices),
            ctypes.c_uint(ghostBeam.n_macroparticles))
Exemplo n.º 2
0
    def track(self, Beam):
        '''
        *Track method.*
        '''

        self.induced_voltage_generation(Beam)
        induced_energy = self.beam.charge * self.induced_voltage
        libblond.linear_interp_kick(
            self.beam.dt.ctypes.data_as(ctypes.c_void_p),
            self.beam.dE.ctypes.data_as(ctypes.c_void_p),
            induced_energy.ctypes.data_as(ctypes.c_void_p),
            self.slices.bin_centers.ctypes.data_as(ctypes.c_void_p),
            ctypes.c_uint(self.slices.n_slices),
            ctypes.c_uint(self.beam.n_macroparticles))
Exemplo n.º 3
0
    def track(self):
        '''
        *Track method to apply the induced voltage kick on the beam.*
        '''

        self.induced_voltage_sum(self.beam)

        induced_energy = self.beam.charge * self.induced_voltage
        libblond.linear_interp_kick(
            self.beam.dt.ctypes.data_as(ctypes.c_void_p),
            self.beam.dE.ctypes.data_as(ctypes.c_void_p),
            induced_energy.ctypes.data_as(ctypes.c_void_p),
            self.slices.bin_centers.ctypes.data_as(ctypes.c_void_p),
            ctypes.c_uint(self.slices.n_slices),
            ctypes.c_uint(self.beam.n_macroparticles))
Exemplo n.º 4
0
    def track(self):
        '''
        *Tracking method for the section. Applies first the kick, then the 
        drift. Calls also RF feedbacks if applicable. Updates the counter of the
        corresponding RFSectionParameters class and the energy-related 
        variables of the Beam class.*
        '''

        # Add phase noise directly to the cavity RF phase
        if self.phi_noise != None:
            if self.noiseFB != None:
                self.phi_RF[:,self.counter[0]] += \
                    self.noiseFB.x*self.phi_noise[:,self.counter[0]]
            else:
                self.phi_RF[:,self.counter[0]] += \
                    self.phi_noise[:,self.counter[0]]

        # Determine phase loop correction on RF phase and frequency
        if self.PL != None and self.counter[0] >= self.PL.delay:
            self.PL.track()

        if self.periodicity:

            # Distinguish the particles inside the frame from the particles on the
            # right of the frame.
            self.indices_right_outside = np.where(
                self.beam.dt > self.t_rev[self.counter[0] + 1])[0]
            self.indices_inside_frame = np.where(
                self.beam.dt < self.t_rev[self.counter[0] + 1])[0]

            if len(self.indices_right_outside) > 0:
                # Change reference of all the particles on the right of the current
                # frame; these particles skip one kick and drift
                self.beam.dt[self.indices_right_outside] -= self.t_rev[
                    self.counter[0] + 1]
                # Syncronize the bunch with the particles that are on the right of
                # the current frame applying kick and drift to the bunch; after that
                # all the particles are in the new updated frame
                self.insiders_dt = np.ascontiguousarray(
                    self.beam.dt[self.indices_inside_frame])
                self.insiders_dE = np.ascontiguousarray(
                    self.beam.dE[self.indices_inside_frame])
                self.kick(self.insiders_dt, self.insiders_dE, self.counter[0])
                self.drift(self.insiders_dt, self.insiders_dE,
                           self.counter[0] + 1)
                self.beam.dt[self.indices_inside_frame] = self.insiders_dt
                self.beam.dE[self.indices_inside_frame] = self.insiders_dE
                # Check all the particles on the left of the just updated frame and
                # apply a second kick and drift to them with the previous wave after
                # having changed reference.
                self.indices_left_outside = np.where(self.beam.dt < 0)[0]

            else:
                self.kick(self.beam.dt, self.beam.dE, self.counter[0])
                self.drift(self.beam.dt, self.beam.dE, self.counter[0] + 1)
                # Check all the particles on the left of the just updated frame and
                # apply a second kick and drift to them with the previous wave after
                # having changed reference.
                self.indices_left_outside = np.where(self.beam.dt < 0)[0]

            if len(self.indices_left_outside) > 0:
                left_outsiders_dt = np.ascontiguousarray(
                    self.beam.dt[self.indices_left_outside])
                left_outsiders_dE = np.ascontiguousarray(
                    self.beam.dE[self.indices_left_outside])
                left_outsiders_dt += self.t_rev[self.counter[0] + 1]
                self.kick(left_outsiders_dt, left_outsiders_dE,
                          self.counter[0])
                self.drift(left_outsiders_dt, left_outsiders_dE,
                           self.counter[0] + 1)
                self.beam.dt[self.indices_left_outside] = left_outsiders_dt
                self.beam.dE[self.indices_left_outside] = left_outsiders_dE

            # Orizzontal cut: this method really eliminates particles from the
            # code
            if self.dE_max != None:
                itemindex = np.where(self.beam.dE > -self.dE_max)[0]
                if len(itemindex) < self.beam.n_macroparticles:
                    self.beam.dt = np.ascontiguousarray(
                        self.beam.dt[itemindex])
                    self.beam.dE = np.ascontiguousarray(
                        self.beam.dE[itemindex])
                    self.beam.n_macroparticles = len(self.beam.dt)

        else:

            if self.rf_kick_interp:
                self.rf_voltage_calculation(self.counter[0], self.slices)
                if self.TotalInducedVoltage is not None:
                    self.total_voltage = self.rf_voltage + self.TotalInducedVoltage.induced_voltage
                else:
                    self.total_voltage = self.rf_voltage

                libblond.linear_interp_kick(
                    self.beam.dt.ctypes.data_as(ctypes.c_void_p),
                    self.beam.dE.ctypes.data_as(ctypes.c_void_p),
                    self.total_voltage.ctypes.data_as(ctypes.c_void_p),
                    self.slices.bin_centers.ctypes.data_as(ctypes.c_void_p),
                    ctypes.c_double(self.beam.charge),
                    ctypes.c_int(self.slices.n_slices),
                    ctypes.c_int(self.beam.n_macroparticles),
                    ctypes.c_double(self.acceleration_kick[self.counter[0]]))

            else:
                self.kick(self.beam.dt, self.beam.dE, self.counter[0])

            self.drift(self.beam.dt, self.beam.dE, self.counter[0] + 1)

            # Orizzontal cut: this method really eliminates particles from the
            # code
            if self.dE_max != None:
                itemindex = np.where(self.beam.dE > -self.dE_max)[0]
                if len(itemindex) < self.beam.n_macroparticles:
                    self.beam.dt = np.ascontiguousarray(
                        self.beam.dt[itemindex])
                    self.beam.dE = np.ascontiguousarray(
                        self.beam.dE[itemindex])
                    self.beam.n_macroparticles = len(self.beam.dt)

        # Increment by one the turn counter
        self.counter[0] += 1

        # Updating the beam synchronous momentum etc.
        self.beam.beta = self.rf_params.beta[self.counter[0]]
        self.beam.gamma = self.rf_params.gamma[self.counter[0]]
        self.beam.energy = self.rf_params.energy[self.counter[0]]
        self.beam.momentum = self.rf_params.momentum[self.counter[0]]
Exemplo n.º 5
0
    def track_memory(self):
        '''
        Calculates the induced voltage energy kick to particles taking into
        account multi-turn induced voltage plus inductive impedance contribution.
        '''

        if self.mode_mtw == 'first_method':
            # At each turn the induced voltage is calculated for the current
            # turn and the future, then this voltage is summed to the voltage
            # deriving from the past; the rotation technique is used, that is
            # the voltage from the past is multiplied by a complex
            # exponential after imposing zero values in appropriate cells to
            # avoid overlapping.
            self.fourier_transf_profile = rfft(self.slices.n_macroparticles,
                                               self.n_fft_sampling)
            self.array_memory = rfft(self.induced_voltage_extended,
                                     self.n_fft_sampling)
            self.array_memory *= np.exp(self.omegaj_array_memory *
                                        self.rev_time_array[self.counter_turn])
            self.induced_voltage_extended =  irfft(self.array_memory + self.coefficient * \
                    self.fourier_transf_profile * self.sum_impedances_memory, self.n_fft_sampling)
            self.induced_voltage_extended[-self.buffer:] = 0
            self.induced_voltage = self.induced_voltage_extended[:self.slices.
                                                                 n_slices]

        elif self.mode_mtw == 'second_method':
            # Like the previous one but an interpolation in time domain is performed
            # instead of the rotation to transport the voltage from the past.
            padded_before_profile = np.lib.pad(self.slices.n_macroparticles,
                                               (self.points_before, 0),
                                               'constant',
                                               constant_values=(0, 0))
            self.fourier_transf_profile = rfft(padded_before_profile,
                                               self.n_fft_sampling)
            time_array_shifted = self.time_array_interp + self.rev_time_array[
                self.counter_turn]
            interpolation2 = np.zeros(self.points_ext_ind_volt)
            libblond.linear_interp_time_translation(
                self.time_array_interp.ctypes.data_as(ctypes.c_void_p),
                self.induced_voltage_extended.ctypes.data_as(ctypes.c_void_p),
                time_array_shifted.ctypes.data_as(ctypes.c_void_p),
                interpolation2.ctypes.data_as(ctypes.c_void_p),
                ctypes.c_uint(self.points_ext_ind_volt))
            self.induced_voltage_extended = irfft(self.coefficient * self.fourier_transf_profile * self.sum_impedances_memory, self.n_fft_sampling)[self.points_before:] + \
                                                + interpolation2
            self.induced_voltage = self.induced_voltage_extended[:self.slices.
                                                                 n_slices]

        # Contribution from inductive impedance
        if self.inductive_impedance_on:
            self.induced_voltage_list[
                self.index_inductive_impedance].induced_voltage_generation(
                    self.beam, 'slice_frame')
            self.induced_voltage += self.induced_voltage_list[
                self.index_inductive_impedance].induced_voltage

        # Induced voltage energy kick to particles through linear interpolation
        induced_energy = self.beam.charge * self.induced_voltage
        libblond.linear_interp_kick(
            self.beam.dt.ctypes.data_as(ctypes.c_void_p),
            self.beam.dE.ctypes.data_as(ctypes.c_void_p),
            induced_energy.ctypes.data_as(ctypes.c_void_p),
            self.slices.bin_centers.ctypes.data_as(ctypes.c_void_p),
            ctypes.c_uint(self.slices.n_slices),
            ctypes.c_uint(self.beam.n_macroparticles))

        # Counter update
        self.counter_turn += 1