Intra-Beam Scattering

Analytical Growth Rates

The following example illustrates how to obtain Intra-Beam Scattering growth rates in Xsuite. The functionality is exposed directly through xtrack.TwissTable and can make use of two different formalism: Nagaitsev and Bjorken-Mtingwa. The former provides a computationally efficient approach but does not account for vertical dispersion, while the latter correctly accounts for it but is slower.

See also: xtrack.twiss.TwissTable.get_ibs_growth_rates()

import json

import xtrack as xt

##########################
# Load xt.Line from file #
##########################

fname_line_particles = "../../../xtrack/test_data/lhc_no_bb/" \
                       "line_and_particle.json"

with open(fname_line_particles, "r") as fid:
    input_data = json.load(fid)

line = xt.Line.from_json(fname_line_particles)
line.particle_ref = xt.Particles.from_dict(input_data["particle"])
tw = line.twiss(method="4d")

#####################
# Define parameters #
#####################

# Line is for LHC protons at top energy
bunch_intensity: int = int(1.8e11)
nemitt_x: float = 1.8e-6
nemitt_y: float = 1.8e-6
sigma_delta: float = 4.71e-5
bunch_length: float = 3.75e-2

###################################
# Get growth rates with Nagaitsev #
###################################

nag_growth_rates = tw.get_ibs_growth_rates(
    formalism="nagaitsev",
    total_beam_intensity=bunch_intensity,
    nemitt_x=nemitt_x,
    nemitt_y=nemitt_y,
    sigma_delta=sigma_delta,
    bunch_length=bunch_length,
    bunched=True,
)

#########################################
# Get growth rates with Bjorken-Mtingwa #
#########################################

bm_growth_rates = tw.get_ibs_growth_rates(
    formalism="bjorken-mtingwa",  # also accepts "b&m"
    total_beam_intensity=bunch_intensity,
    nemitt_x=nemitt_x,
    nemitt_y=nemitt_y,
    sigma_delta=sigma_delta,
    bunch_length=bunch_length,
    bunched=True,
)

##########################################################
# Compare: we expect Nagaitsev to be wrong in horizontal #
##########################################################

print()
print("Computed from normalized emittances:")
print("------------------------------------")
print(f"Nagaitsev:       {nag_growth_rates}")
print(f"Bjorken-Mtingwa: {bm_growth_rates}")

# Computed from normalized emittances:
# ------------------------------------
# Nagaitsev:       IBSAmplitudeGrowthRates(Kx=3.12e-05, Ky=-1.14e-09, Kz=0.000155)
# Bjorken-Mtingwa: IBSAmplitudeGrowthRates(Kx=3.11e-05, Ky=5.52e-07, Kz=0.000155)

# Complete source: xfields/examples/005_ibs/001_growth_rates_with_vdisp.py

Amplitude and Emittance Conventions

For consistency with the computed Synchrotron Radiation damping times, in Xsuite the IBS amplitude growth rates are computed. The following short example shows how to switch between the amplitude and emittance growth rates should one need to.

import xtrack as xt

##########################
# Load xt.Line from file #
##########################

fname_line_particles = "../../../xtrack/test_data/sps_ions/line_and_particle.json"
line = xt.Line.from_json(fname_line_particles)
tw = line.twiss(method="4d")

#####################
# Define parameters #
#####################

# Line is for SPS ions at injection
bunch_intensity: int = int(3.5e8)
nemitt_x: float = 1.2612e-6
nemitt_y: float = 0.9081e-6
sigma_delta: float = 3.59e-4
bunch_length: float = 19.51e-2

####################
# Get growth rates #
####################

# There is no vertical dispersion so Nagaitsev
# will be correct in vertical
amp_growth_rates = tw.get_ibs_growth_rates(
    formalism="nagaitsev",
    total_beam_intensity=bunch_intensity,
    nemitt_x=nemitt_x,
    nemitt_y=nemitt_y,
    sigma_delta=sigma_delta,
    bunch_length=bunch_length,
    bunched=True,
)

##########################################################
# Converting between amplitude and emittance conventions #
##########################################################

# Notice how, when printing the returned object, it states
# the growth rates are given in amplitude convention
print(amp_growth_rates)
# IBSAmplitudeGrowthRates(Kx=0.000518, Ky=0.00552, Kz=0.00402)

# Methods are implemented to convert to the emittance convention
emit_growth_rates = amp_growth_rates.to_emittance_growth_rates()
print(emit_growth_rates)
# IBSEmittanceGrowthRates(Kx=0.00104, Ky=0.011, Kz=0.00803)

# It is also possible to convert back to the amplitude convention
print(f"Initial:         {amp_growth_rates}")
print(f"Converted twice: {emit_growth_rates.to_amplitude_growth_rates()}")
# Initial:         IBSAmplitudeGrowthRates(Kx=0.000518, Ky=0.00552, Kz=0.00402)
# Converted twice: IBSAmplitudeGrowthRates(Kx=0.000518, Ky=0.00552, Kz=0.00402)

####################################################
# Converting between growth rates and growth times #
####################################################

# Should one want the growth times, a method is available in both
# conventions to perform this conversion, although it returns a tuple
print(f"Amp times from amp rates:  {amp_growth_rates.to_amplitude_growth_times()}")
print(f"Amp times from emit rates: {emit_growth_rates.to_amplitude_growth_times()}")
# Amp times from amp rates:  (1930.7146824847905, 181.11747760500302, 248.968512633387)
# Amp times from emit rates: (1930.7146824847905, 181.11747760500302, 248.968512633387)

# And it is of course possible to get the emittance
# growth times from any of the two conventions
print(f"Emit times from amp rates:  {amp_growth_rates.to_emittance_growth_times()}")
print(f"Emit times from emit rates: {emit_growth_rates.to_emittance_growth_times()}")
# Emit times from amp rates:  (965.3573412423953, 90.55873880250151, 124.4842563166935)
# Emit times from emit rates: (965.3573412423953, 90.55873880250151, 124.4842563166935)

# Complete source: xfields/examples/005_ibs/002_growth_rates_conventions.py

IBS Kicks for Tracking

When trying to study the interplay of IBS effects with others such as space charge, e-cloud, beamb-beam etc. analytical growth rates are not enough and tracking becomes necessary. In Xfields beam elements are provided to model IBS tracking, which apply momenta kicks to particles. Two kick elements are available:

  • IBSAnalyticalKick (based on R. Bruce) for kicks based on analytical growth rates;

  • IBSKineticKick (based on P. Zenkevich, adapted by M. Zampetakis) for kicks based on diffusion and friction terms from the kinetic theory of gases.

The following example illustrates how to create a kick element, inserting and configuring it for tracking. Refer to the Reference manual for the full list of parameters and their explanation, and to the Physics guide for full information.

See also: xtrack.Line.configure_intrabeam_scattering()

import xfields as xf
import xobjects as xo
import xpart as xp
import xtrack as xt

context = xo.ContextCpu(omp_num_threads="auto")

##########################
# Load xt.Line from file #
##########################

# This is SPS line with proton as particle ref
fname_line_particles = "../../../xtrack/test_data/sps_w_spacecharge/"\
                       "line_no_spacecharge_and_particle.json"
line: xt.Line = xt.Line.from_json(fname_line_particles)
line.build_tracker(_context=context)

#######################################
# Create and Install IBS Kick Element #
#######################################

# For the analytical kick formalism: kicks are computed based
# on the analytical growth rates (so it needs a formalism)
# ibs_kick = xf.IBSAnalyticalKick(formalism="nagaitsev", num_slices=50)

# For the kinetic formalism: kicks are computed based on the
# friction and diffusion terms of the kinetic theory of gases
ibs_kick = xf.IBSKineticKick(num_slices=50)

# By default the element is off until configuration. Let's install
# the kick at the end of the line and configure it. This internally
# provides the necessary information to the element
line.configure_intrabeam_scattering(
    element=ibs_kick, name="ibskick", index=-1, update_every=50
)

############################################
# Define parameters and Generate Particles #
############################################

# Line is for SPS protons at injection
bunch_intensity: int = int(3.5e8)
nemitt_x: float = 2.5e-6
nemitt_y: float = 2.5e-6
sigma_delta: float = 9.56e-4
bunch_length: float = 8.98e-2

particles = xp.generate_matched_gaussian_bunch(
    num_particles=10_000,
    total_intensity_particles=bunch_intensity,
    nemitt_x=nemitt_x,
    nemitt_y=nemitt_y,
    sigma_z=bunch_length,
    line=line,
    _context=context,
)

##############################################
# Track now applies an IBS kick at each turn #
##############################################

line.track(particles, num_turns=100, with_progress=5)

# Complete source: xfields/examples/005_ibs/003_tracking_with_kicks.py