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))
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))
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))
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]]
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