Релятивисткая разностная схема для расчета динамики частиц в сложных электрических и магнитных полях
First, we write the main quantities in the difference scheme, then we consider the algorithm.
Basic values
At the initial time \(t\) set Cartesian coordinates of the \(i -\)particles \(\overrightarrow{r_{i}} = (x_i, y_i, z_i)\)nd the initial pulses \(\overrightarrow{p_{i}} = (p_{x_i}, p_{y_i}, p_{z_i})\). Minimum time step is set \(\delta t\).
For convenience, made dimensionless physical quantities (with tilde): \begin{equation} \widetilde{\overrightarrow{r_i}} = \frac{\overrightarrow{r_i}}{c \delta t}, \end{equation} \begin{equation} \widetilde{\overrightarrow{E_i}} = \frac{\overrightarrow{E_i}e}{mc} \delta t, \end{equation} \begin{equation} \widetilde{\overrightarrow{H_i}} = \frac{\overrightarrow{H_i}e}{mc} \delta t, \end{equation} where \(m\) is the speed of light, \(e\) is the particle charge and \(m\) is the particle mass.
Algorithm
Consider the relativistic difference scheme algorithm step by step:
-
Calculation of electric fields \(\overrightarrow{E_i}\) at the points where the particles are.
-
Pulse increment: \begin{equation} \overrightarrow{p_i} = \overrightarrow{p_i} + 2\cdot\overrightarrow{E_i}, \end{equation} where the coefficient means that the increment of the pulse is made for the entire time interval \(2\delta t\).
-
New speeds are calculated by new impulses: \begin{equation} \overrightarrow{v_i} = \frac{\overrightarrow{p_i}}{\gamma_i}, \end{equation} where \(\gamma_i = \sqrt{1 + \overrightarrow{p_i}^2}.\)
-
At new speeds, new coordinates are calculated: \begin{equation} \overrightarrow{r_i} = \overrightarrow{r_i} + 1\cdot\overrightarrow{v_i}, \end{equation} where the coefficient means that the increment of the coordinate is made for the time interval \(\delta t.\)
-
Calculation of magnetic fields \(\overrightarrow{H_i}\) at the new points where the particles are.
-
Calculated velocity values (after rotation in a magnetic field):
\[ b_1 = 1 - \frac{H_i^2}{\gamma_i}, b_2 = 1 + \frac{H_i^2}{\gamma_i}, b_3 = 2\cdot \frac{\overrightarrow{v_i}\cdot\overrightarrow{H_i}}{\gamma_i}, \]
\[ \overrightarrow{f_i} = 2\cdot \frac{\overrightarrow{v_i}\times \overrightarrow{H_i}}{\gamma_i}, \]
\begin{equation} \overrightarrow{v_i} = \frac{\overrightarrow{v_i}b_1 + \overrightarrow{f_i} + \frac{\overrightarrow{H_i}}{\gamma_i}b_3}{b_2}. \end{equation}
-
At new speeds, new coordinates are calculated: \begin{equation} \overrightarrow{r_i} = \overrightarrow{r_i} + 1\cdot\overrightarrow{v_i}, \end{equation} where the coefficient means that the increment of the coordinate is made for the time interval $\delta t.$
-
New impulses are calculated according to the new rates: \begin{equation} \overrightarrow{p_i} = \overrightarrow{v_i}\gamma_i. \end{equation}
One cycle is performed in a time interval \(2\delta t.\)
Python
import redpic as rp
import numpy as np
import holoviews as hv
hv.extension('matplotlib')
import warnings
warnings.filterwarnings('ignore')
rp.__version__
Some plotting options
%output size=100 backend='matplotlib' fig='png' dpi=300
%opts Curve Scatter [aspect=3 show_grid=True]
%opts Curve (linewidth=1 alpha=0.7 color='blue')
%opts Scatter (alpha=0.7 s=0.5)
Define accelerator beamline parameters
acc = rp.accelerator.Accelerator(0.7, 5, 0.01)
# Unique name, z-position [m], Ez [MV/m], Ez(z) profile
acc.add_accel('Acc. 1', 4.096, -1.1, 'Ez.dat')
acc.add_accel('Acc. 2', 5.944, -1.1, 'Ez.dat')
# Unique name, z-position [m], Bz [T], Bz(z) profile
acc.add_solenoid('Sol. 1', 0.450, -0.0580, 'Bz.dat')
acc.add_solenoid('Sol. 2', 0.957, 0.0390, 'Bz.dat')
acc.add_solenoid('Sol. 3', 2.107, 0.0250, 'Bz.dat')
acc.add_solenoid('Sol. 4', 2.907, 0.0440, 'Bz.dat')
acc.add_solenoid('Sol. 5', 3.670, 0.0400, 'Bz.dat')
acc.add_solenoid('Sol. 6', 4.570, 0.0595, 'Bz.dat')
acc.add_solenoid('Sol. 7', 5.470, 0.0590, 'Bz.dat')
acc.compile()
dim_z = hv.Dimension('z', unit='m')
dim_Ez = hv.Dimension('Ez', unit='MV/m', label='$E_z$')
dim_Bz = hv.Dimension('Bz', unit='Gs', label='$B_z$')
z = acc.z
z_Ez = hv.Curve((z, acc.Ez(z)), kdims=dim_z, vdims=dim_Ez)
z_Bz = hv.Curve((z, acc.Bz(z)*1e4), kdims=dim_z, vdims=dim_Bz)
(z_Ez + z_Bz).cols(1)
print(acc)
Accelerator structure.
Solenoids:
[ 0.45 m, -0.058 T, Bz.dat, Sol. 1, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
[ 0.957 m, 0.039 T, Bz.dat, Sol. 2, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
[ 2.107 m, 0.025 T, Bz.dat, Sol. 3, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
[ 2.907 m, 0.044 T, Bz.dat, Sol. 4, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
[ 3.67 m, 0.04 T, Bz.dat, Sol. 5, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
[ 4.57 m, 0.0595 T, Bz.dat, Sol. 6, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
[ 5.47 m, 0.059 T, Bz.dat, Sol. 7, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
Accelerating modules:
[ 4.096 m, -1.1 T, Ez.dat, Acc. 1, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
[ 5.944 m, -1.1 T, Ez.dat, Acc. 2, 0.0 m, 0.0 rad, 0.0 m, 0.0 rad]
Quadrupoles:
Correctors x:
Correctors y:
Define beam parameters
beam = rp.beam.RadialUniformBeam(
type=rp.constants.electron,
energy = 1.32, # MeV
current = 0.5e3, # A
radius_x = 48e-3, # initial r (m)
radius_y = 48e-3, # initial r (m)
radius_z = 3.5,
radius_xp = 2*35.0e-3, # initial r' (rad)
radius_yp = 2*35.0e-3, # initial r' (rad)
x = 0.0e-3, # horizontal centroid position (m)
xp = 0.0e-3, # horizontal centroid angle (rad)
y = 0, # vertical centroid position (m)
normalized_emittance = 200e-6 # m*rad
)
beam.generate(10_000)
2023-08-31 21:35:33,649 - redpic.beam.base - INFO - Generate a radial-uniform beam with 10000 particles
beam.df
x | y | z | px | py | pz | |
---|---|---|---|---|---|---|
0 | 0.034491 | -0.010901 | -1.123685 | 0.100578 | -0.031122 | 1.747093 |
1 | 0.007980 | -0.003833 | 1.251044 | 0.022404 | -0.010670 | 1.749303 |
2 | -0.022694 | -0.010773 | -0.128508 | -0.067049 | -0.031592 | 1.741746 |
3 | 0.017086 | 0.014826 | -2.608725 | 0.048956 | 0.043029 | 1.763242 |
4 | -0.021815 | 0.015455 | 0.520279 | -0.062786 | 0.044937 | 1.759832 |
... | ... | ... | ... | ... | ... | ... |
9995 | 0.018885 | 0.028316 | 1.360050 | 0.054502 | 0.082155 | 1.746065 |
9996 | -0.021948 | 0.040885 | -2.615462 | -0.064131 | 0.119014 | 1.759089 |
9997 | -0.016885 | -0.017578 | 1.473440 | -0.048364 | -0.051265 | 1.740909 |
9998 | 0.027568 | -0.014905 | -0.467425 | 0.080297 | -0.042703 | 1.765850 |
9999 | 0.035333 | 0.010626 | 0.145074 | 0.103711 | 0.031025 | 1.771395 |
10000 rows × 6 columns
dim_x = hv.Dimension('x', unit='m', range=(-0.1, 0.1))
dim_y = hv.Dimension('y', unit='m', range=(-0.1, 0.1))
dim_z = hv.Dimension('z', unit='m', range=(acc.z_start, acc.z_stop))
dim_px = hv.Dimension('px', unit='MeV/c', label='$p_x$')
dim_py = hv.Dimension('py', unit='MeV/c', label='$p_y$')
beam_x_y = hv.Scatter(beam.df, kdims=[dim_x, dim_y])
beam_z_x = hv.Scatter(beam.df, kdims=[dim_z, dim_x])
beam_x_px = hv.Scatter(beam.df, kdims=[dim_x, dim_px])
beam_y_py = hv.Scatter(beam.df, kdims=[dim_y, dim_py])
WARNING:param.Scatter: Chart elements should only be supplied a single kdim
2023-08-31 21:35:33,772 - param.Scatter - WARNING - Chart elements should only be supplied a single kdim
WARNING:param.Scatter: Chart elements should only be supplied a single kdim
2023-08-31 21:35:33,789 - param.Scatter - WARNING - Chart elements should only be supplied a single kdim
WARNING:param.Scatter: Chart elements should only be supplied a single kdim
2023-08-31 21:35:33,791 - param.Scatter - WARNING - Chart elements should only be supplied a single kdim
WARNING:param.Scatter: Chart elements should only be supplied a single kdim
2023-08-31 21:35:33,801 - param.Scatter - WARNING - Chart elements should only be supplied a single kdim
(beam_x_y + beam_z_x + beam_x_px + beam_y_py).cols(2)
print(beam)
Beam parameters:
Type electron
Distribution radial-uniform
Particles 10000
Current 500.0 A
Energy 1.32 MeV
Total momentum 1.7582483378931433 MeV/c
Rel. factor 3.583175582013202
Radius x 48.0 mm
Radius y 48.0 mm
Radius z 3.5 m
Radius x prime 70.0 mrad
Radius y prime 70.0 mrad
Horizontal centroid position 0.0 mm
Vertical centroid position 0.0 mm
Horizontal centroid angle 0.0 mrad
Vertical centroid angle 0.0 mrad
Normalized emittance x 200.0 mm*mrad
Normalized emittance y 200.0 mm*mrad
Run simulation
rp_sim = rp.solver.Simulation(beam, acc)
rp_sim.track()
z = 4.98 m (99.5 %)
Plot the simulation results
def plot(i):
df = rp_sim.result[i]
rp_z_x = hv.Scatter(df, kdims=[dim_z, dim_x], label='redpic')
return rp_z_x
items = [(i, plot(i)) for i in list(rp_sim.result.keys())]
holomap = hv.HoloMap(items, kdims = ['z'])
hv.output(holomap, widget_location='bottom')