S. Albright, H. Damerau, A. Lasheen, F. Tecker
In this hands-on session we will experiment with particle tracking simulations.
The goal of the session is to write a tracking code to observe the evolution of the particles in the longitudinal phase space ($\phi$, $\Delta E$), for each turn in the machine.
The notebook is constructed with the following purpose in mind:
Along the exercises, you will be encouraged to use support_functions
. These were designed to help you during the hands-on session by reducing the coding overhead. You can check the documentation of each function by calling function?
in a new cell.
The available support functions are
| support_functions.py
|
| ----------------------------- |
| plot_phase_space_trajectory |
| plot_phase_space_distribution |
| synchrotron_tune |
| separatrix |
| run_animation |
| oscillation_spectrum |
| synchrotron_tune |
# In this cell we import all modules that will be required for the computation
# You can add extra imports as you progress in the exercises
# Hint: use scipy.constants for elementary charge, speed of light, mass of a proton...
import matplotlib.pyplot as plt
import numpy as np
from scipy.constants import e, c, m_p
| Parameter | | | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | Energy range | $E_\mathrm{kin} = 26\,\mathrm{GeV}...1300\,\mathrm{GeV}$ | | Circumference | $2 \pi R = 6911.5\,\mathrm{m}$ | | Bending radius | $\rho = 741.3\,\mathrm{m}$ | | Transition gamma | $\gamma_\mathrm{tr} = 18.$ | | Acceleration time | $4\,\mathrm{s}$ | | Harmonic number | $4620$ | | Maximum RF voltage | $V_{\mathrm{rf}} = 15\,\mathrm{MV}$ | | Longitudinal emittance per bunch | $\varepsilon_\mathrm{l} = 0.6\,\mathrm{eVs}$ | | Maximum bucket filling factor | $\varepsilon_\mathrm{l}/A_\mathrm{bucket} = 0.8$ | | Total beam intensity | $N = 1.6 \cdot 10^{14} \,\mathrm{protons}$ $(2 \times 320\mathrm{b} \times 2.5 \cdot 10^{11} \mathrm{protons}/\mathrm{bunch})$ |
Ekin = 26e9 # 1.3e12
charge = 1
E0 = m_p*c**2./e
circumference = 6911.5
energy = Ekin + E0
momentum = np.sqrt(energy**2. - E0**2.)
beta = momentum/energy
gamma = energy/E0
t_rev = circumference/(beta*c)
f_rev = 1/t_rev
harmonic = 4620
voltage = 4.5e6
f_rf = harmonic*f_rev
t_rf = 1/f_rf
gamma_t = 18
alpha_c = 1/gamma_t**2.
eta = alpha_c - 1/gamma**2.
print("Beta: " +str(beta))
print("Gamma: " +str(gamma))
print("Revolution period: " +str(t_rev*1e6) + " mus")
print("RF frequency: " +str(f_rf/1e6) + " MHz")
print("RF period: " +str(t_rf*1e9) + " ns")
print("Momentum compaction factor: " +str(alpha_c))
print("Phase slippage factor: " +str(eta))
Beta: 0.9993932358608412 Gamma: 28.710512044511262 Revolution period: 23.0682794443392 mus RF frequency: 200.27501449110963 MHz RF period: 4.993134078861298 ns Momentum compaction factor: 0.0030864197530864196 Phase slippage factor: 0.0018732596374893458
np.zeros(n_turns)
and fill the particle coordinates each turnplot_phase_space_trajectory
can be used# Tracking functions
def drift(phaseInitial, energyInitial, harmonic, eta, beta, energy):
newPhase = phaseInitial + 2*np.pi*harmonic*eta*energyInitial/(beta**2*energy)
return newPhase
def kick(energyInitial, phaseInitial, charge, voltage):
newEnergy = energyInitial + charge*voltage*np.sin(phaseInitial)
return newEnergy
# Initial coordinates
particlePhase = 0.99*np.pi
particleEnergy = 0
# Storing with list
n_turns = 1000
particleEnergyList = []
particlePhaseList = []
for i in range(n_turns):
particleEnergyList.append(particleEnergy)
particlePhaseList.append(particlePhase)
particlePhase = drift(particlePhase, particleEnergy, harmonic, eta, beta, energy)
particleEnergy = kick(particleEnergy, particlePhase, charge, voltage)
# Storing with np array
n_turns = 1000
particleEnergyArray = np.zeros(n_turns)
particlePhaseArray = np.zeros(n_turns)
for i in range(n_turns):
particleEnergyArray[i] = np.array(particleEnergy)
particlePhaseArray[i] = np.array(particlePhase)
particlePhase = drift(particlePhase, particleEnergy, harmonic, eta, beta, energy)
particleEnergy = kick(particleEnergy, particlePhase, charge, voltage)
plt.figure()
plt.plot(particlePhaseList)
plt.figure()
plt.plot(particleEnergyList)
plt.figure()
plt.plot(particlePhaseList, particleEnergyList)
[<matplotlib.lines.Line2D at 0x215664593a0>]
from support_functions import plot_phase_space_trajectory
plot_phase_space_trajectory?
Signature: plot_phase_space_trajectory( phase_trajectory, energy_trajectory, phase_sep=None, separatrix_array=None, figname=None, draw_line=True, xlim=None, ylim=None, ) Docstring: This support function can be used to plot the trajectory of a particle in the longitudinal phase space. The o marker is the starting coordinate, the * marker is the end coordinate. Parameters ---------- phase_trajectory : np.array or list The phase coordinates of a distribution of particles in [rad] energy_trajectory : np.array or list The energy coordinates of a distribution of particles in [eV] phase_sep : np.array The phase of the separatrix array in [rad], as output by the separatrix function separatrix_array : np.array The separatrix array in [eV], as output by the separatrix function figname : str, optional The name of your nice figure, by default None draw_line : bool, optional Hide the trajectory to plot only the start/end coordinates, by default True xlim : tuple, optional The limits in phase for your nice plot in [rad], e.g. (-np.pi, np.pi), by default None ylim : tuple, optional The limits in energy for your nice plot [eV], e.g. (-1e6, 1e6), by default None File: c:\users\alasheen\cernbox\storage\redaction\events\2022\cas\git\hands-on\tracking\support_functions.py Type: function
plot_phase_space_trajectory(particlePhaseList, particleEnergyList)
plot_phase_space_trajectory(particlePhaseArray, particleEnergyArray)
figname_traj_1 = 'trajectories 1'
plot_phase_space_trajectory(particlePhaseList, particleEnergyList, figname=figname_traj_1)
plot_phase_space_trajectory(particlePhaseArray, particleEnergyArray, figname=figname_traj_1)
np.array([phase_1, phase_2, phase_3])
np.zeros((n_turns, n_particles))
np.linspace(phase_start, phase_end, n_particles)
to linearly space particles in phaseseparatrix
support_function to generate the separatrix.plot_phase_space_trajectory
to combine plots# Initial coordinates
particle1Phase = 0.9*np.pi
particle1Energy = 0
particle2Phase = np.pi/2
particle2Energy = 0
particle3Phase = np.pi/8
particle3Energy = 0
# Each particle treated separately
particle1EnergyList = []
particle2EnergyList = []
particle3EnergyList = []
particle1PhaseList = []
particle2PhaseList = []
particle3PhaseList = []
for i in range(n_turns):
particle1EnergyList.append(particle1Energy)
particle2EnergyList.append(particle2Energy)
particle3EnergyList.append(particle3Energy)
particle1PhaseList.append(particle1Phase)
particle2PhaseList.append(particle2Phase)
particle3PhaseList.append(particle3Phase)
particle1Phase = drift(particle1Phase, particle1Energy, harmonic, eta, beta, energy)
particle2Phase = drift(particle2Phase, particle2Energy, harmonic, eta, beta, energy)
particle3Phase = drift(particle3Phase, particle3Energy, harmonic, eta, beta, energy)
particle1Energy = kick(particle1Energy, particle1Phase, charge, voltage)
particle2Energy = kick(particle2Energy, particle2Phase, charge, voltage)
particle3Energy = kick(particle3Energy, particle3Phase, charge, voltage)
plt.figure('energy evolution several')
plt.plot(particle1PhaseList)
plt.plot(particle2PhaseList)
plt.plot(particle3PhaseList)
plt.figure('phase evolution several')
plt.plot(particle1EnergyList)
plt.plot(particle2EnergyList)
plt.plot(particle3EnergyList)
plt.figure('phase space several')
plt.plot(particle1PhaseList, particle1EnergyList)
plt.plot(particle2PhaseList, particle2EnergyList)
plt.plot(particle3PhaseList, particle3EnergyList)
[<matplotlib.lines.Line2D at 0x21566912cd0>]
# Using numpy arrays
n_particles = 3
particlePhase = np.array([particle1Phase, particle2Phase, particle3Phase])
particleEnergy = np.array([particle1Energy, particle2Energy, particle3Energy])
particleEnergyArray = np.zeros((n_turns, n_particles))
particlePhaseArray = np.zeros((n_turns, n_particles))
for i in range(n_turns):
particlePhaseArray[i] = np.array(particlePhase)
particleEnergyArray[i] = np.array(particleEnergy)
particlePhase = drift(particlePhase, particleEnergy, harmonic, eta, beta, energy)
particleEnergy = kick(particleEnergy, particlePhase, charge, voltage)
plot_phase_space_trajectory(particlePhaseArray, particleEnergyArray)
n_particles = 10
n_turns = 200
particlePhase = np.linspace(0, np.pi, n_particles)
particleEnergy = np.zeros(n_particles)
particleEnergyArray = np.zeros((n_turns, n_particles))
particlePhaseArray = np.zeros((n_turns, n_particles))
for i in range(n_turns):
particlePhaseArray[i] = np.array(particlePhase)
particleEnergyArray[i] = np.array(particleEnergy)
particlePhase = drift(particlePhase, particleEnergy, harmonic, eta, beta, energy)
particleEnergy = kick(particleEnergy, particlePhase, charge, voltage)
from support_functions import separatrix
phase_array = np.linspace(0, 2*np.pi, 1000)
phase_sep, separatrix_array = separatrix(phase_array, f_rev, eta, beta, energy, charge, voltage, harmonic)
plot_phase_space_trajectory(particlePhaseArray, particleEnergyArray,
phase_sep=phase_sep, separatrix_array=separatrix_array)
c:\Users\alasheen\cernbox\Software\win\python-3.9.12\lib\site-packages\ipywidgets\widgets\widget.py:443: DeprecationWarning: Passing unrecognized arguments to super(Toolbar).__init__(). __init__() missing 1 required positional argument: 'canvas' This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets. super().__init__(**kwargs)
n_particles = 10
n_turns = 200
particlePhase = np.ones(n_particles) * np.pi
particleEnergy = np.linspace(0, 2e8, n_particles)
particleEnergyArray = np.zeros((n_turns, n_particles))
particlePhaseArray = np.zeros((n_turns, n_particles))
for i in range(n_turns):
particlePhaseArray[i] = np.array(particlePhase)
particleEnergyArray[i] = np.array(particleEnergy)
particlePhase = drift(particlePhase, particleEnergy,
harmonic, eta, beta, energy)
particleEnergy = kick(particleEnergy, particlePhase, charge, voltage)
plot_phase_space_trajectory(particlePhaseArray, particleEnergyArray,
phase_sep=phase_sep, separatrix_array=separatrix_array)
n_particles = 10
n_turns = 2000
particlePhase = np.linspace(0, 15, n_particles)
particleEnergy = np.zeros(n_particles)
particleEnergyArray = np.zeros((n_turns, n_particles))
particlePhaseArray = np.zeros((n_turns, n_particles))
for i in range(n_turns):
particlePhaseArray[i] = np.array(particlePhase)
particleEnergyArray[i] = np.array(particleEnergy)
particlePhase = drift(particlePhase, particleEnergy,
harmonic, eta, beta, energy)
particleEnergy = kick(particleEnergy, particlePhase, charge, voltage)
phase_array = np.linspace(0, 20, 10000)
phase_sep, separatrix_array = separatrix(
phase_array, f_rev, eta, beta, energy, charge, voltage, harmonic)
plot_phase_space_trajectory(particlePhaseArray, particleEnergyArray,
phase_sep=phase_sep, separatrix_array=separatrix_array)
c:\Users\alasheen\cernbox\Software\win\python-3.9.12\lib\site-packages\ipywidgets\widgets\widget.py:443: DeprecationWarning: Passing unrecognized arguments to super(Toolbar).__init__(). __init__() missing 1 required positional argument: 'canvas' This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets. super().__init__(**kwargs)
def kick(energyInitial, phaseInitial, charge, voltage, acceleration=0):
newEnergy = energyInitial + charge * voltage * \
np.sin(phaseInitial) - acceleration
return newEnergy
Ekin_top = 1.3e12
Ekin_bottom = 26e9
t_ramp = 4
U0 = (Ekin_top-Ekin_bottom)/t_ramp / (t_ramp/t_rev)
n_particles = 10
n_turns = 1000
particlePhase = np.linspace(0, np.pi, n_particles)
particleEnergy = np.zeros(n_particles)
particleEnergyArray = np.zeros((n_turns, n_particles))
particlePhaseArray = np.zeros((n_turns, n_particles))
for i in range(n_turns):
particlePhaseArray[i] = np.array(particlePhase)
particleEnergyArray[i] = np.array(particleEnergy)
particlePhase = drift(particlePhase, particleEnergy, harmonic, eta, beta, energy)
particleEnergy = kick(particleEnergy, particlePhase, charge, voltage, U0)
phase_array = np.linspace(0, 2*np.pi, 1000)
phase_sep, separatrix_array = separatrix(
phase_array, f_rev, eta, beta, energy, charge, voltage, harmonic,
acceleration=U0)
plot_phase_space_trajectory(particlePhaseArray, particleEnergyArray,
phase_sep=phase_sep, separatrix_array=separatrix_array,
xlim=(-np.pi, 2*np.pi),
ylim=(-100, 100))
c:\Users\alasheen\cernbox\Storage\Redaction\Events\2022\CAS\git\hands-on\tracking\support_functions.py:236: RuntimeWarning: invalid value encountered in sqrt separatrix_array = np.sqrt( c:\Users\alasheen\cernbox\Software\win\python-3.9.12\lib\site-packages\ipywidgets\widgets\widget.py:443: DeprecationWarning: Passing unrecognized arguments to super(Toolbar).__init__(). __init__() missing 1 required positional argument: 'canvas' This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets. super().__init__(**kwargs)
Ekin = 14e9
charge = 1
E0 = m_p*c**2./e
circumference = 6911.5
energy = Ekin + E0
momentum = np.sqrt(energy**2. - E0**2.)
beta = momentum/energy
gamma = energy/E0
t_rev = circumference/(beta*c)
f_rev = 1/t_rev
harmonic = 4620
voltage = 15e6
f_rf = harmonic*f_rev
t_rf = 1/f_rf
gamma_t = 18
alpha_c = 1/gamma_t**2.
eta = alpha_c - 1/gamma**2.
print("Beta: " +str(beta))
print("Gamma: " +str(gamma))
print("Revolution period: " +str(t_rev*1e6) + " mus")
print("RF frequency: " +str(f_rf/1e6) + " MHz")
print("RF period: " +str(t_rf*1e9) + " ns")
print("Momentum compaction factor: " +str(alpha_c))
print("Phase slippage factor: " +str(eta))
Beta: 0.9980255059233202 Gamma: 15.921044947044525 Revolution period: 23.099893041602865 mus RF frequency: 200.00092605101628 MHz RF period: 4.999976848831789 ns Momentum compaction factor: 0.0030864197530864196 Phase slippage factor: -0.0008586697734143615
n_particles = 10
n_turns = 1000
particlePhase = np.linspace(0, np.pi, n_particles)
particleEnergy = np.zeros(n_particles)
particleEnergyArray = np.zeros((n_turns, n_particles))
particlePhaseArray = np.zeros((n_turns, n_particles))
for i in range(n_turns):
particlePhaseArray[i] = np.array(particlePhase)
particleEnergyArray[i] = np.array(particleEnergy)
particlePhase = drift(particlePhase, particleEnergy, harmonic, eta, beta, energy)
particleEnergy = kick(particleEnergy, particlePhase, charge, voltage)
phase_array = np.linspace(-np.pi, np.pi, 1000)
phase_sep, separatrix_array = separatrix(
phase_array, f_rev, eta, beta, energy, charge, voltage, harmonic)
plot_phase_space_trajectory(particlePhaseArray, particleEnergyArray,
phase_sep=phase_sep, separatrix_array=separatrix_array)
c:\Users\alasheen\cernbox\Software\win\python-3.9.12\lib\site-packages\ipywidgets\widgets\widget.py:443: DeprecationWarning: Passing unrecognized arguments to super(Toolbar).__init__(). __init__() missing 1 required positional argument: 'canvas' This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets. super().__init__(**kwargs)
Ekin = 26e9
charge = 1
E0 = m_p * c**2. / e
circumference = 6911.5
energy = Ekin + E0
momentum = np.sqrt(energy**2. - E0**2.)
beta = momentum / energy
gamma = energy / E0
t_rev = circumference / (beta * c)
f_rev = 1 / t_rev
omega_rev = 2 * np.pi * f_rev
harmonic = 4620
voltage = 4.5e6
f_rf = harmonic * f_rev
t_rf = 1 / f_rf
omega_rf = 2 * np.pi * f_rf
gamma_t = 18
alpha_c = 1 / gamma_t**2.
eta = alpha_c - 1 / gamma**2.
phi_s = np.arcsin(U0 / voltage)
stationaryBucketHeight = beta * \
np.sqrt(2 * charge * voltage * energy / (np.pi * harmonic * np.abs(eta)))
print("Bucket height: " +
str(stationaryBucketHeight / 1e6) + " MeV")
bucketHeightRed = np.abs(
np.cos(phi_s) - (np.pi - 2 * phi_s) / 2 * np.sin(phi_s))**(1 / 2.)
print("Accelerating bucket height: " +
str(stationaryBucketHeight / 1e6 * bucketHeightRed) + " MeV")
stationaryBucketArea = 16 * beta / omega_rf * \
np.sqrt(charge * voltage * energy / (2 * np.pi * harmonic * np.abs(eta)))
print("Bucket area: " +
str(stationaryBucketArea) + " eVs")
bucketAreaRed = (1 - np.sin(phi_s)) / (1 + np.sin(phi_s))
print("Accelerating bucket area: " +
str(stationaryBucketArea * bucketAreaRed) + " eVs")
stationaryBucketCentralSynchrotronFrequency = np.sqrt(-omega_rev**2 * harmonic *
eta * charge * voltage * np.cos(np.pi) / (2 * np.pi * beta**2 * energy)) / (2 * np.pi)
stationaryBucketCentralSynchrotronTune = stationaryBucketCentralSynchrotronFrequency / f_rev
print("Synchtron frequency: " +
str(stationaryBucketCentralSynchrotronFrequency) + " Hz")
print("Synchtron period: " +
str(1 / stationaryBucketCentralSynchrotronFrequency * 1e3) + " ms")
print("Inverse tune: " +
str(1 / stationaryBucketCentralSynchrotronTune) + " turns")
Bucket height: 94.37296851790389 MeV Accelerating bucket height: 62.83826390584678 MeV Bucket area: 0.5999719724218308 eVs Accelerating bucket area: 0.25215177121828763 eVs Synchtron frequency: 657.9604989768133 Hz Synchtron period: 1.5198480783498225 ms Inverse tune: 65.88476102073503 turns
generate_bunch
function.plot_phase_space_distribution
to plot the distribution in phase spacerun_animation
function to monitor the evolution of the distribution while trackingrun_animation
please call if you have trouble with the function syntaxfrom support_functions import generate_bunch
bunch_position = np.pi
bunch_length = np.pi/2
energy_position = 0
energy_spread = 100e6
n_macroparticles = 10000
phase_coordinates, energy_coordinates = generate_bunch(
bunch_position, bunch_length,
energy_position, energy_spread,
n_macroparticles)
from support_functions import plot_phase_space_distribution
phase_array = np.linspace(0, 2 * np.pi, 1000)
phase_sep, separatrix_array = separatrix(
phase_array, f_rev, eta, beta, energy, charge, voltage, harmonic)
plot_phase_space_distribution(
phase_coordinates,
energy_coordinates,
phase_sep=phase_sep,
separatrix_array=separatrix_array,)
c:\Users\alasheen\cernbox\Software\win\python-3.9.12\lib\site-packages\ipywidgets\widgets\widget.py:443: DeprecationWarning: Passing unrecognized arguments to super(Toolbar).__init__(). __init__() missing 1 required positional argument: 'canvas' This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets. super().__init__(**kwargs)
n_turns = 1000
for i in range(n_turns):
phase_coordinates = drift(phase_coordinates, energy_coordinates, harmonic, eta, beta, energy)
energy_coordinates = kick(energy_coordinates, phase_coordinates, charge, voltage)
plot_phase_space_distribution(
phase_coordinates,
energy_coordinates,
phase_sep=phase_sep,
separatrix_array=separatrix_array,)
from support_functions import run_animation
figname = 'Animate'
iterations = 100
framerate = 30
plt.rcParams['animation.embed_limit'] = 2**32
run_animation(phase_coordinates, energy_coordinates,
drift, kick,
[harmonic, eta, beta, energy],
[charge, voltage],
figname, iterations, framerate,
phase_sep=phase_sep,
separatrix_array=separatrix_array)
bunch_position = np.pi/2
bunch_length = np.pi/4
energy_position = 0
energy_spread = 100e6
phase_coordinates, energy_coordinates = generate_bunch(
bunch_position, bunch_length,
energy_position, energy_spread,
n_macroparticles)
figname = 'Dip'
run_animation(phase_coordinates, energy_coordinates,
drift, kick,
[harmonic, eta, beta, energy],
[charge, voltage],
figname, 4*iterations, framerate,
phase_sep=phase_sep,
separatrix_array=separatrix_array)
c:\Users\alasheen\cernbox\Software\win\python-3.9.12\lib\site-packages\ipywidgets\widgets\widget.py:443: DeprecationWarning: Passing unrecognized arguments to super(Toolbar).__init__(). __init__() missing 1 required positional argument: 'canvas' This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets. super().__init__(**kwargs)
bunch_position = np.pi
bunch_length = np.pi
energy_position = 0
energy_spread = 25e6
phase_coordinates, energy_coordinates = generate_bunch(
bunch_position, bunch_length,
energy_position, energy_spread,
n_macroparticles)
figname = 'Quad'
run_animation(phase_coordinates, energy_coordinates,
drift, kick,
[harmonic, eta, beta, energy],
[charge, voltage],
figname, 4*iterations, framerate,
phase_sep=phase_sep,
separatrix_array=separatrix_array)
c:\Users\alasheen\cernbox\Software\win\python-3.9.12\lib\site-packages\ipywidgets\widgets\widget.py:443: DeprecationWarning: Passing unrecognized arguments to super(Toolbar).__init__(). __init__() missing 1 required positional argument: 'canvas' This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets. super().__init__(**kwargs)