|
| 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