Skip to content

Commit 842b01a

Browse files
Merge remote-tracking branch 'pkicsiny/pic_lumi' into release/0.25.0
2 parents 7cce7fd + 08c9c9c commit 842b01a

File tree

4 files changed

+590
-10
lines changed

4 files changed

+590
-10
lines changed
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# copyright ################################# #
2+
# This file is part of the Xfields Package. #
3+
# Copyright (c) CERN, 2021. #
4+
# ########################################### #
5+
6+
import numpy as np
7+
from scipy import constants as cst
8+
9+
import xobjects as xo
10+
import xtrack as xt
11+
import xfields as xf
12+
import xpart as xp
13+
from matplotlib import pyplot as plt
14+
15+
context = xo.ContextCpu()
16+
17+
# fcc ttbar 4 IP
18+
# https://indico.cern.ch/event/1202105/contributions/5408583/attachments/2659051/4608141/FCCWeek_Optics_Oide_230606.pdf
19+
bunch_intensity = 1.55e11 # [e]
20+
energy = 182.5 # [GeV]
21+
p0c = 182.5e9 # [eV]
22+
mass0 = 511000 # [eV]
23+
phi = 15e-3 # [rad] half xing
24+
physemit_x = 1.59e-09 # [m]
25+
physemit_y = 9e-13 # [m]
26+
beta_x = 1 # [m]
27+
beta_y = 1.6e-3 # [m]
28+
sigma_x = np.sqrt(physemit_x*beta_x) # [m]
29+
sigma_px = np.sqrt(physemit_x/beta_x) # [1]
30+
sigma_y = np.sqrt(physemit_y*beta_y) # [m]
31+
sigma_py = np.sqrt(physemit_y/beta_y) # [1]
32+
sigma_z_tot = 21.7e-4 # [m] sr+bs
33+
sigma_delta_tot = 19.2e-4 # [1] sr+bs
34+
n_ip = 4 # [1]
35+
36+
n_macroparticles_b1 = int(1e4)
37+
n_macroparticles_b2 = int(1e4)
38+
39+
n_turns = 1
40+
41+
################
42+
# create beams #
43+
################
44+
45+
#e-
46+
particles_b1_pic = xp.Particles(
47+
_context = context,
48+
q0 = -1,
49+
p0c = p0c,
50+
mass0 = mass0,
51+
x = sigma_x *np.random.randn(n_macroparticles_b1),
52+
y = sigma_y *np.random.randn(n_macroparticles_b1),
53+
zeta = sigma_z_tot *np.random.randn(n_macroparticles_b1),
54+
px = sigma_px *np.random.randn(n_macroparticles_b1),
55+
py = sigma_py *np.random.randn(n_macroparticles_b1),
56+
delta = sigma_delta_tot*np.random.randn(n_macroparticles_b1),
57+
weight=bunch_intensity/n_macroparticles_b1
58+
)
59+
60+
# e+
61+
particles_b2_pic = xp.Particles(
62+
_context = context,
63+
q0 = 1,
64+
p0c = p0c,
65+
mass0 = mass0,
66+
x = sigma_x *np.random.randn(n_macroparticles_b2),
67+
y = sigma_y *np.random.randn(n_macroparticles_b2),
68+
zeta = sigma_z_tot *np.random.randn(n_macroparticles_b2),
69+
px = sigma_px *np.random.randn(n_macroparticles_b2),
70+
py = sigma_py *np.random.randn(n_macroparticles_b2),
71+
delta = sigma_delta_tot*np.random.randn(n_macroparticles_b2),
72+
weight=bunch_intensity/n_macroparticles_b2
73+
)
74+
75+
76+
####################
77+
# specify PIC grid #
78+
####################
79+
80+
nx = 64
81+
ny = 64
82+
nz = 64
83+
x_lim = 6
84+
y_lim = 6
85+
z_lim = 6
86+
87+
x_lim_grid = x_lim * sigma_x
88+
y_lim_grid = y_lim * sigma_y
89+
z_lim_grid = z_lim * sigma_z_tot
90+
91+
dx = 2*x_lim_grid/(nx)
92+
dy = 2*y_lim_grid/(ny)
93+
dz = 2*z_lim_grid/(nz)
94+
95+
bbpic_ip1_b1 = xf.BeamBeamPIC3D(
96+
_context=context,
97+
phi=phi, alpha=0,
98+
x_range=(-x_lim_grid, x_lim_grid), dx=dx,
99+
y_range=(-y_lim_grid, y_lim_grid), dy=dy,
100+
z_range=(-z_lim_grid, z_lim_grid), dz=dz,
101+
flag_luminosity=1, flag_lumigrid=1,
102+
)
103+
104+
bbpic_ip1_b2 = xf.BeamBeamPIC3D(
105+
_context=context,
106+
phi=-phi, alpha=0,
107+
x_range=(-x_lim_grid, x_lim_grid), dx=dx,
108+
y_range=(-y_lim_grid, y_lim_grid), dy=dy,
109+
z_range=(-z_lim_grid, z_lim_grid), dz=dz,
110+
flag_luminosity=1, flag_lumigrid=1,
111+
)
112+
113+
#######################
114+
# set up communicator #
115+
#######################
116+
117+
pipeline_manager = xt.PipelineManager()
118+
pipeline_manager.add_particles('p_b1', rank=0)
119+
pipeline_manager.add_particles('p_b2', rank=0)
120+
121+
pipeline_manager.add_element('IP1')
122+
bbpic_ip1_b1.name = 'IP1'
123+
bbpic_ip1_b2.name = 'IP1'
124+
bbpic_ip1_b1.partner_name = 'p_b2'
125+
bbpic_ip1_b2.partner_name = 'p_b1'
126+
particles_b1_pic.init_pipeline('p_b1')
127+
particles_b2_pic.init_pipeline('p_b2')
128+
bbpic_ip1_b1.pipeline_manager = pipeline_manager
129+
bbpic_ip1_b2.pipeline_manager = pipeline_manager
130+
131+
######################
132+
# set up xtrack line #
133+
######################
134+
135+
line_b1 = xt.Line(elements=[bbpic_ip1_b1])
136+
line_b2 = xt.Line(elements=[bbpic_ip1_b2])
137+
138+
line_b1.build_tracker(_context=context)
139+
line_b2.build_tracker(_context=context)
140+
141+
multitracker = xt.PipelineMultiTracker(
142+
branches=[xt.PipelineBranch(line=line_b1, particles=particles_b1_pic),
143+
xt.PipelineBranch(line=line_b2, particles=particles_b2_pic)],
144+
enable_debug_log=True, verbose=True)
145+
146+
#######################
147+
# set up communicator #
148+
#######################
149+
150+
pipeline_manager = xt.PipelineManager()
151+
pipeline_manager.add_particles('p_b1', rank=0)
152+
pipeline_manager.add_particles('p_b2', rank=0)
153+
154+
pipeline_manager.add_element('IP1')
155+
bbpic_ip1_b1.name = 'IP1'
156+
bbpic_ip1_b2.name = 'IP1'
157+
bbpic_ip1_b1.partner_name = 'p_b2'
158+
bbpic_ip1_b2.partner_name = 'p_b1'
159+
particles_b1_pic.init_pipeline('p_b1')
160+
particles_b2_pic.init_pipeline('p_b2')
161+
bbpic_ip1_b1.pipeline_manager = pipeline_manager
162+
bbpic_ip1_b2.pipeline_manager = pipeline_manager
163+
164+
######################
165+
# set up xtrack line #
166+
######################
167+
168+
line_b1 = xt.Line(elements=[bbpic_ip1_b1])
169+
line_b2 = xt.Line(elements=[bbpic_ip1_b2])
170+
171+
line_b1.build_tracker(_context=context)
172+
line_b2.build_tracker(_context=context)
173+
174+
multitracker = xt.PipelineMultiTracker(
175+
branches=[xt.PipelineBranch(line=line_b1, particles=particles_b1_pic),
176+
xt.PipelineBranch(line=line_b2, particles=particles_b2_pic)],
177+
enable_debug_log=True, verbose=True)
178+
179+
##########################
180+
# configure record table #
181+
##########################
182+
183+
record_b1_pic = line_b1.start_internal_logging_for_elements_of_type(
184+
xf.BeamBeamPIC3D, capacity={"beamstrahlungtable": int(0), "lumitable": int(n_turns)})
185+
record_b2_pic = line_b2.start_internal_logging_for_elements_of_type(
186+
xf.BeamBeamPIC3D, capacity={"beamstrahlungtable": int(0), "lumitable": int(n_turns)})
187+
188+
#####################
189+
# track 1 collision #
190+
#####################
191+
192+
multitracker.track(num_turns=1)
193+
194+
line_b1.stop_internal_logging_for_elements_of_type(xf.BeamBeamPIC3D)
195+
line_b2.stop_internal_logging_for_elements_of_type(xf.BeamBeamPIC3D)
196+
197+
record_b1_pic.move(_context=xo.context_default)
198+
record_b2_pic.move(_context=xo.context_default)
199+
200+
###########################
201+
# lumi per bunch crossing #
202+
###########################
203+
204+
# lumi [m^-2]
205+
piwi = sigma_z_tot / sigma_x * phi # [1]
206+
lumi_ip = bunch_intensity**2 / (4*np.pi*sigma_x*np.sqrt(1 + piwi**2)*sigma_y) # [m^-2] lumi per bunch crossing
207+
numlumi_b1 = record_b1_pic.lumitable.luminosity[0]
208+
numlumi_b2 = record_b2_pic.lumitable.luminosity[0]
209+
relabserr_b1 = 100*np.abs(numlumi_b1 - lumi_ip) / lumi_ip
210+
relabserr_b2 = 100*np.abs(numlumi_b2 - lumi_ip) / lumi_ip
211+
print(f"lumi formula: {lumi_ip:.4e}, numlumi beam 1: {numlumi_b1:.4e}, numlumi beam 2: {numlumi_b2:.4e}, error beam 1: {relabserr_b1:.4f} [%], error beam 2: {relabserr_b2:.4f} [%]")
212+
213+
########
214+
# plot #
215+
########
216+
217+
# example of plotting the luminous region (rho1 * rho2)
218+
219+
# get grid params
220+
dx = bbpic_ip1_b1.fieldmap_self.dx
221+
dy = bbpic_ip1_b1.fieldmap_self.dy
222+
dz = bbpic_ip1_b1.fieldmap_self.dz
223+
dt = dz
224+
nx = bbpic_ip1_b1.fieldmap_self.nx
225+
ny = bbpic_ip1_b1.fieldmap_self.ny
226+
nz = bbpic_ip1_b1.fieldmap_self.nz
227+
228+
# make figure
229+
fig, ax = plt.subplots(3,6, figsize=(15,8))
230+
231+
# plot lumigrid at timestep 20, 30 and 40
232+
timestep_dict = {20: 0, 30: 1, 40: 2}
233+
for i_step in timestep_dict.keys():
234+
235+
# reshape lumigrid from 1D to 3D
236+
lumigrid = np.reshape(bbpic_ip1_b2.lumigrid[2*(nx*ny*nz)*i_step: 2*(nx*ny*nz)*(i_step+1)], (2, nx, ny, nz))
237+
l_1 = abs(lumigrid[0])
238+
l_2 = abs(lumigrid[1])
239+
240+
# create projections for 2D plotting
241+
grid_1_x = np.sum(l_1, axis=0)
242+
grid_2_x = np.sum(l_2, axis=0)
243+
grid_1_y = np.sum(l_1, axis=1)
244+
grid_2_y = np.sum(l_2, axis=1)
245+
grid_1_z = np.sum(l_1, axis=2)
246+
grid_2_z = np.sum(l_2, axis=2)
247+
248+
# plot the lumigrid for some specific timesteps
249+
# z-y: y grid limit needs to be large bc of hourglass at CP
250+
ax[timestep_dict[i_step],0].imshow(grid_1_x+grid_2_x, origin='lower')
251+
ax[timestep_dict[i_step],1].imshow(grid_1_x*grid_2_x, origin='lower')
252+
253+
# z-x: x grid limit needs to be large bc of crossing angle boost
254+
ax[timestep_dict[i_step],2].imshow(grid_1_y+grid_2_y, origin='lower')
255+
ax[timestep_dict[i_step],3].imshow(grid_1_y*grid_2_y, origin='lower')
256+
257+
# y-x
258+
ax[timestep_dict[i_step],4].imshow(grid_1_z+grid_2_z, origin='lower')
259+
ax[timestep_dict[i_step],5].imshow(grid_1_z*grid_2_z, origin='lower')
260+
261+
262+
for j in range(6):
263+
ax[timestep_dict[i_step],j].set_xticks([])
264+
ax[timestep_dict[i_step],j].set_yticks([])
265+
266+
fig.tight_layout()
267+
fig.subplots_adjust(hspace=.1, wspace=.1)
268+
plt.show()

0 commit comments

Comments
 (0)