Source code for mbtrack2.tracking.spacecharge

"""
Module for transverse space charge calculations.
"""

from scipy.constants import c

from mbtrack2.tracking.element import Element
from mbtrack2.tracking.emfields import _efieldn_mit, get_displaced_efield
from mbtrack2.tracking.particles import Beam, Bunch
from mbtrack2.utilities.synchrotron import Synchrotron


[docs] class TransverseSpaceCharge(Element): """ Class representing a transverse space charge element. Parameters ---------- ring : Synchrotron The synchrotron object representing the particle accelerator ring. interaction_length : float The interaction length of the space charge effect in meters. n_bins : int, optional The number of bins (longitudinal) used for space charge calculations. Default is 100. Attributes ---------- ratio_threshold : float The ratio numerical threshold for the space charge element to decide if the beam is transversely round. absolute_threshold : float The absolute numerical threshold for the space charge element to decide if the beam is transversely round. ring: Synchrotron Ring object with information about the ring. This class uses ring.E0 and ring.gamma for calculations. efieldn : function The electric field function. Methods ------- track(bunch) Perform the tracking of the bunch through the space charge element. """ ratio_threshold = 1e-3 absolute_threshold = 1e-10
[docs] def __init__(self, ring: Synchrotron, interaction_length: float, n_bins: int = 100): """ Initialize the SpaceCharge object. Parameters ---------- ring : Synchrotron The synchrotron object representing the particle accelerator ring. interaction_length : float The interaction length of the space charge effect in meters. n_bins : int, optional The number of bins (longitudinal) used for space charge calculations. Default is 100. """ self.ring = ring self.n_bins = n_bins self.interaction_length = interaction_length self.efieldn = _efieldn_mit
[docs] @Element.parallel @Element.track_bunch_if_non_empty def track(self, bunch: Bunch | Beam): """ Perform the tracking of the bunch through the space charge element. Parameters ---------- bunch : Bunch The bunch of particles to be tracked. """ prefactor = self.interaction_length / (self.ring.E0 * self.ring.gamma**2) (bins, sorted_index, profile, _) = bunch.binning(n_bin=self.n_bins, return_full_length=True) dz = (bins[1] - bins[0]) * c charge_density = bunch.charge_per_mp * profile / dz for bin_index in range(self.n_bins - 1): particle_ids = bin_index == sorted_index if bunch.track_alive: particle_ids = particle_ids & bunch.alive if len(particle_ids) == 0: continue x = bunch.particles['x'][particle_ids] y = bunch.particles['y'][particle_ids] if len(x) != 0 and len(y) != 0: mean_x, std_x = x.mean(), x.std() mean_y, std_y = y.mean(), y.std() en_x, en_y = get_displaced_efield( self.efieldn, bunch.particles['x'][particle_ids], bunch.particles['y'][particle_ids], std_x, std_y, mean_x, mean_y) kicks_x = prefactor * en_x * charge_density[bin_index] kicks_y = prefactor * en_y * charge_density[bin_index] bunch.particles['xp'][particle_ids] += kicks_x bunch.particles['yp'][particle_ids] += kicks_y