Skip to content

Commit e982ccc

Browse files
committed
Test fake multibunch with single pass through tracker
1 parent b9dd995 commit e982ccc

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed

tests/test_fakemultibunch.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import numpy as np
2+
from matplotlib import pyplot as plt
3+
from scipy import constants as cst
4+
5+
import xobjects as xo
6+
import xtrack as xt
7+
import xfields as xf
8+
import xwakes as xw
9+
10+
context = xo.ContextCpu()
11+
12+
energy = 7E3
13+
qx = 62.31
14+
qy = 60.32
15+
momentumCompaction = 3.48e-04
16+
basic_slot_time = 25E-9
17+
n_bunch_max = 3000
18+
n_bunch = 100
19+
bunch_intensity = 5E12
20+
emit_norm = 2.5E-6
21+
sigma_z = 0.08
22+
selected_bunch = n_bunch-1
23+
r_over_q = 1806
24+
q = 5E3
25+
coupled_bunch_number_x = 16
26+
coupled_bunch_number_y = 73
27+
n_turns_wake = 1
28+
num_slices = 11
29+
30+
assert n_bunch_max%n_bunch == 0
31+
circumference = n_bunch_max * basic_slot_time * cst.c
32+
bunch_spacing_zeta = circumference/n_bunch
33+
beta_x = circumference/(2.0*np.pi*qx)
34+
beta_y = circumference/(2.0*np.pi*qy)
35+
mass0 = cst.value('proton mass energy equivalent in MeV')*1E-3
36+
gamma = energy/mass0
37+
RF_freq = 10.0/basic_slot_time
38+
sigma_x = np.sqrt(emit_norm*beta_x/gamma)
39+
sigma_y = np.sqrt(emit_norm*beta_y/gamma)
40+
betar = np.sqrt(1 - 1 / gamma ** 2)
41+
zeta_range=(-3*sigma_z, 3*sigma_z)
42+
filling_scheme = np.ones(n_bunch,dtype=int)
43+
44+
n_part = num_slices
45+
slice_intensity = bunch_intensity/num_slices
46+
x0 = np.ones(n_part)
47+
z_edges = np.linspace(zeta_range[0],zeta_range[1],num_slices+1)
48+
z0 = z_edges[:-1]+(z_edges[1]-z_edges[0])/2
49+
zeta0 = z0-1*(n_bunch-1)*bunch_spacing_zeta
50+
particles = xt.Particles(
51+
_context = context,
52+
q0 = 1,
53+
p0c = energy*1E9,
54+
mass0 = mass0*1E9,
55+
x = sigma_x*x0,
56+
y = sigma_y*x0,
57+
zeta = zeta0,
58+
weight = bunch_intensity / n_part
59+
)
60+
61+
wfx = xw.wit.ComponentResonator(kind = 'dipole_x',
62+
r=r_over_q*q, q=q, f_r=RF_freq+3E5)
63+
wfy = xw.wit.ComponentResonator(kind = 'dipole_y',
64+
r=r_over_q*q, q=q, f_r=RF_freq-3E5)
65+
66+
67+
coupled_bunch_phase_x = 2*np.pi*coupled_bunch_number_x/n_bunch
68+
wfx.configure_for_tracking(zeta_range=zeta_range,
69+
num_slices=num_slices,
70+
bunch_spacing_zeta=bunch_spacing_zeta,
71+
num_turns=n_turns_wake,
72+
circumference=circumference,
73+
filling_scheme = np.ones(n_bunch,dtype=int),
74+
bunch_selection = [selected_bunch],
75+
fake_coupled_bunch_phase_x = coupled_bunch_phase_x,
76+
beta_x = beta_x,
77+
)
78+
coupled_bunch_phase_y = 2*np.pi*coupled_bunch_number_y/n_bunch
79+
wfy.configure_for_tracking(zeta_range=zeta_range,
80+
num_slices=num_slices,
81+
bunch_spacing_zeta=bunch_spacing_zeta,
82+
num_turns=n_turns_wake,
83+
circumference=circumference,
84+
filling_scheme = np.ones(n_bunch,dtype=int),
85+
bunch_selection = [selected_bunch],
86+
fake_coupled_bunch_phase_y = coupled_bunch_phase_y,
87+
beta_y = beta_y,
88+
)
89+
90+
91+
for turn in range(n_turns_wake):
92+
px0 = np.copy(particles.px)
93+
wfx.track(particles)
94+
py0 = np.copy(particles.py)
95+
wfy.track(particles)
96+
97+
moments_data = wfx._xfields_wf.moments_data
98+
z,x = moments_data.get_moment_profile('x',0)
99+
moments_data = wfy._xfields_wf.moments_data
100+
z,y = moments_data.get_moment_profile('y',0)
101+
zetas = np.array([])
102+
positions_x = np.array([])
103+
positions_y = np.array([])
104+
for slot in np.arange(n_bunch):
105+
zetas = np.hstack([zetas,z0-bunch_spacing_zeta*slot])
106+
positions_x = np.hstack([positions_x,x0*np.cos(coupled_bunch_phase_x*(selected_bunch-slot))])
107+
positions_y = np.hstack([positions_y,x0*np.cos(coupled_bunch_phase_y*(selected_bunch-slot))])
108+
indices = np.argsort(zetas)
109+
zetas = zetas[indices]
110+
positions_x = positions_x[indices]
111+
positions_y = positions_y[indices]
112+
113+
assert np.allclose(z,zetas)
114+
assert np.allclose(x/sigma_x,positions_x)
115+
assert np.allclose(y/sigma_y,positions_y)
116+
117+
118+
for i_slice in range(num_slices):
119+
zetas_slice = zeta0[i_slice]-zetas
120+
121+
scaling_constant = particles.q0**2 * cst.e**2 / (particles.p0c[0] * particles.beta0[0] * cst.e)
122+
kicks = positions_x*sigma_x*scaling_constant*slice_intensity*wfx.function_vs_zeta(zetas_slice,beta0=betar,dzeta=moments_data.dz)
123+
kick_from_track = particles.px[i_slice]-px0[i_slice]
124+
assert np.isclose(np.sum(kicks),kick_from_track)
125+
kicks = positions_x*sigma_x*scaling_constant*slice_intensity*wfy.function_vs_zeta(zetas_slice,beta0=betar,dzeta=moments_data.dz)
126+
kick_from_track = particles.py[i_slice]-py0[i_slice]
127+
assert np.isclose(np.sum(kicks),kick_from_track)
128+
129+

0 commit comments

Comments
 (0)