Skip to content

Commit 219237d

Browse files
aeriformepre-commit-ci[bot]lucafedeli88EZoniNeilZaim
authored
Virtual photons (#5595)
This PR adds the option of creating a virtual photon population associated to a given electron or positron species. The virtual photons are generated from scratch at every timestep. They are initialized in the same position as the parent particle. Their momenta is sampled from the theoretical analytical spectrum (see equation 99.16 in Berestetskii, Pitaevskii, Lifshitz. Quantum Electrodynamics: Volume 4.) The virtual photons can be used in linear Breit-Wheeler or linear Compton collisions. This is used to simulate incoherent beam-beam effects at the interaction point of colliders. To do: - [x] create a virtual photon species with the correct number of particles and with attributes same as primary particles - [x] draw the virtual photon energy from the correct probability distribution - [x] add infrastructure - [x] add docs and test Note: As of this PR, the virtual photons are technically not virtual at all, as their virtuality is zero. A more accurate name would be "equivalent quanta". However, follow-up PRs will soon add virtuality calculations. 🧨 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Luca Fedeli <[email protected]> Co-authored-by: Edoardo Zoni <[email protected]> Co-authored-by: Edoardo Zoni <[email protected]> Co-authored-by: Neïl Zaim <[email protected]> Co-authored-by: Andrew Myers <[email protected]> Co-authored-by: Remi Lehe <[email protected]>
1 parent ef6e84c commit 219237d

File tree

13 files changed

+613
-2
lines changed

13 files changed

+613
-2
lines changed

Docs/source/usage/parameters.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,6 +1512,24 @@ Particle initialization
15121512
in each dimension with a matched shape function and filtering used for current deposition.
15131513
This is required when using the electron energy solver with electron-ion temperature relaxation.
15141514

1515+
* ``<species>.do_qed_virtual_photons`` (`boolean`) optional (default `false`)
1516+
Create a population of virtual photons associated with ``<species>``.
1517+
It only works if ``<species>`` is an electron or a positron species.
1518+
The virtual photon species has to be created as a regular photon species in the input file.
1519+
Virtual photons are created from scratch at each timestep at the same position as the parent particle.
1520+
This implies that different primary species must have different virtual photon species.
1521+
The energy of the virtual photons is sampled from their spectrum (see :cite:t:`LandauVol4` section 99 for more details).
1522+
The momentum of the virtual photons is parallel to that of the parent particle.
1523+
This feature also requires the following input parameters:
1524+
* ``<species>.qed_virtual_photon_species_name`` (`string`) name of the virtual photon species associated with the current lepton species.
1525+
* ``<virtual_photon_species>.qed_virtual_photon_min_energy`` (`float`, in Joules) minimum energy of the virtual photons
1526+
* ``<virtual_photon_species>.qed_virtual_photon_multiplier`` (`int`), sampling factor for the virtual photons.
1527+
A sampling factor of ``f`` means that the number of virtual photons is multiplied by ``f``, while their weights are divided by ``f``.
1528+
The virtual photons can undergo collisions via the linear Breit-Wheeler or linear Compton processes.
1529+
This is useful to model incoherent beam-beam effects in colliders (e.g. pair generation, radiative Bhabha scattering).
1530+
This QED feature is separated from the strong-field QED modules (quantum synchrotron and non-linear Breit-Wheeler).
1531+
It requires WarpX to be compiled with ``WarpX_QED=ON`` (CMake) or ``QED=TRUE`` (GNU Make).
1532+
15151533
.. _running-cpp-parameters-fluids:
15161534

15171535
Cold Relativistic Fluid initialization

Examples/Tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,4 @@ add_subdirectory(single_particle)
8484
add_subdirectory(space_charge_initialization)
8585
add_subdirectory(subcycling)
8686
add_subdirectory(vay_deposition)
87+
add_subdirectory(virtual_photons)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Add tests (alphabetical order) ##############################################
2+
#
3+
4+
add_warpx_test(
5+
test_3d_virtual_photons # name
6+
3 # dims
7+
1 # nprocs
8+
inputs_test_3d_virtual_photons # inputs
9+
analysis_virtual_photons.py # analysis
10+
"analysis_default_regression.py --path diags/diag1" # checksum
11+
OFF # dependency
12+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../analysis_default_regression.py
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env python3
2+
3+
# This test generates the population of virtual photons
4+
# of one high-energy electron.
5+
# The total number and spectrum of the virtual photons are
6+
# compared to the theoretical prediction.
7+
# Checks that the photons are in the same position of the electron.
8+
9+
import matplotlib.pyplot as plt
10+
import numpy as np
11+
from numpy import log
12+
from openpmd_viewer import OpenPMDTimeSeries
13+
from scipy.constants import alpha, c, eV, m_e, pi
14+
15+
###########################
16+
### ENERGY AND SPECTRUM ###
17+
###########################
18+
19+
# useful constants
20+
GeV = 1e9 * eV
21+
22+
# electron energy
23+
energy = 125 * GeV
24+
25+
# virtual photons min energy
26+
hw_min = 1e-12 * m_e * c**2
27+
28+
# min fractional energy of the virtual photon wrt electron energy
29+
ymin = hw_min / energy
30+
31+
#############
32+
### WarpX ###
33+
#############
34+
35+
series = OpenPMDTimeSeries("./diags/diag1/")
36+
sampling_factor = 1e7
37+
uz_virtual_photons, w_virtual_photons = series.get_particle(
38+
["uz", "w"], species="virtual_photons", iteration=1
39+
)
40+
w_electrons = series.get_particle(["w"], species="beam", iteration=1)
41+
42+
# fractional photon energy (photon energy / electron energy)
43+
y_warpx = uz_virtual_photons * c / energy
44+
45+
# bins for the fractional photon energy
46+
y = np.geomspace(ymin, 1, 401)
47+
48+
# number of virtual photons per electron obtained with WarpX
49+
N_warpx = np.sum(w_virtual_photons) / np.sum(w_electrons)
50+
51+
# spectrum of the virtual photons per electron
52+
H, b = np.histogram(y_warpx, bins=y, weights=w_virtual_photons)
53+
db = np.diff(b)
54+
b = 0.5 * (b[1:] + b[:-1])
55+
dN_dy_warpx = H / db / np.sum(w_electrons)
56+
57+
##############
58+
### Theory ###
59+
##############
60+
61+
y = b
62+
# spectrum of virtual photons for one electron
63+
dN_dy_theory = alpha / pi / y * (-2 * log(y))
64+
# dN_dy[dN_dy < 0] = 0.0
65+
66+
# number of virtual photons for one electron from theory
67+
N_theory = alpha / pi * log(ymin) ** 2
68+
69+
############
70+
### Plot ###
71+
############
72+
73+
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(5, 4), dpi=200)
74+
ax.plot(y, dN_dy_theory, color="black", lw=6, label="theory")
75+
ax.plot(y, dN_dy_warpx, color="dodgerblue", lw=4, label="WarpX")
76+
ax.legend()
77+
ax.set_yscale("log")
78+
ax.set_xscale("log")
79+
ax.set_xlabel("Fractional photon energy")
80+
ax.set_ylabel("dN/dy")
81+
ax.set_title("Virtual photons spectrum")
82+
fig.savefig("spectrum_virtual_photons.png")
83+
84+
#############
85+
### Error ###
86+
#############
87+
88+
number_rel_error = np.abs(N_warpx - N_theory) / N_theory
89+
spectrum_rel_error = np.abs(dN_dy_warpx - dN_dy_theory) / dN_dy_theory
90+
91+
print("Number of virtual photons per electron:")
92+
print(f"From simulation : {N_warpx}")
93+
print(f"From theory : {N_theory}")
94+
print(f"Relative error : {number_rel_error:.4%}")
95+
96+
print("Spectrum of virtual photons per electron:")
97+
print(f"Max relative error: {spectrum_rel_error.max()}")
98+
99+
assert number_rel_error < 0.02
100+
assert (spectrum_rel_error < 0.04).all()
101+
102+
################
103+
### Position ###
104+
################
105+
106+
x, y, z = series.get_particle(["x", "y", "z"], species="virtual_photons", iteration=1)
107+
x_e, y_e, z_e = series.get_particle(["x", "y", "z"], species="beam", iteration=1)
108+
109+
assert np.unique(x) == x_e
110+
assert np.unique(y) == y_e
111+
assert np.unique(z) == z_e
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#################################
2+
########## MY CONSTANTS #########
3+
#################################
4+
my_constants.mc2_eV = m_e*clight*clight/q_e
5+
6+
# BEAMS
7+
my_constants.beam_energy_eV = 125.e9
8+
my_constants.beam_gamma = beam_energy_eV/(mc2_eV)
9+
my_constants.beam_N = 1.2e10
10+
my_constants.sigmax = 500e-9
11+
my_constants.sigmay = 10e-9
12+
my_constants.sigmaz = 300e-3
13+
my_constants.muz = 4*sigmaz
14+
my_constants.nmacropart = 1
15+
16+
# VIRTUAL PHOTONS
17+
# minimum energy
18+
my_constants.hwmin = 1e-12*m_e*clight*clight
19+
20+
# BOX
21+
my_constants.Lx = 8*sigmax
22+
my_constants.Ly = 8*sigmay
23+
my_constants.Lz = 16*sigmaz
24+
my_constants.nx = 32
25+
my_constants.ny = 32
26+
my_constants.nz = 32
27+
28+
# TIME
29+
my_constants.dt = sigmaz/clight/10.
30+
31+
#################################
32+
####### GENERAL PARAMETERS ######
33+
#################################
34+
max_step = 1
35+
amr.n_cell = nx ny nz
36+
amr.max_level = 0
37+
geometry.dims = 3
38+
geometry.prob_lo = -0.5*Lx -0.5*Ly -0.5*Lz
39+
geometry.prob_hi = 0.5*Lx 0.5*Ly 0.5*Lz
40+
warpx.numprocs = 1 1 1
41+
42+
#################################
43+
######## BOUNDARY CONDITION #####
44+
#################################
45+
boundary.particle_lo = Absorbing Absorbing Absorbing
46+
boundary.particle_hi = Absorbing Absorbing Absorbing
47+
48+
#################################
49+
############ NUMERICS ###########
50+
#################################
51+
algo.maxwell_solver = none
52+
warpx.const_dt = dt
53+
algo.particle_shape = 3
54+
algo.particle_pusher = vay
55+
56+
#################################
57+
########### PARTICLES ###########
58+
#################################
59+
particles.species_names = beam virtual_photons
60+
particles.photon_species = virtual_photons
61+
62+
beam.species_type = electron
63+
beam.injection_style = gaussian_beam
64+
beam.x_rms = sigmax
65+
beam.y_rms = sigmay
66+
beam.z_rms = sigmaz
67+
beam.x_m = 0
68+
beam.y_m = 0
69+
beam.z_m = -muz
70+
beam.npart = nmacropart
71+
beam.q_tot = -beam_N*q_e
72+
beam.z_cut = 4
73+
beam.momentum_distribution_type = gaussian
74+
beam.uz_m = beam_gamma
75+
beam.uy_m = 0.0
76+
beam.ux_m = 0.0
77+
beam.ux_th = 0.0
78+
beam.uy_th = 0.0
79+
beam.uz_th = 0
80+
beam.do_not_deposit = 1
81+
beam.do_not_push = 1
82+
beam.do_qed_virtual_photons = 1
83+
beam.qed_virtual_photon_species_name = virtual_photons
84+
85+
virtual_photons.species_type = photon
86+
virtual_photons.injection_style = none
87+
virtual_photons.do_not_push = 1
88+
virtual_photons.do_not_gather = 1
89+
virtual_photons.do_not_deposit = 1
90+
virtual_photons.qed_virtual_photons_min_energy = hwmin
91+
virtual_photons.qed_virtual_photons_multiplier = 10000000
92+
93+
#################################
94+
######### DIAGNOSTICS ###########
95+
#################################
96+
# FULL
97+
diagnostics.diags_names = diag1
98+
99+
diag1.intervals = -1
100+
diag1.diag_type = Full
101+
diag1.write_species = 1
102+
diag1.species = beam virtual_photons
103+
diag1.format = openpmd
104+
diag1.virtual_photons.variables = uz w x y z
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"lev=0": {
3+
"Bx": 0.0,
4+
"By": 0.0,
5+
"Bz": 0.0,
6+
"Ex": 0.0,
7+
"Ey": 0.0,
8+
"Ez": 0.0,
9+
"jx": 0.0,
10+
"jy": 0.0,
11+
"jz": 0.0
12+
},
13+
"beam": {
14+
"particle_position_x": 2.748730894777248e-07,
15+
"particle_position_y": 1.5827522919751402e-08,
16+
"particle_position_z": 1.122721937612553,
17+
"particle_momentum_x": 0.0,
18+
"particle_momentum_y": 0.0,
19+
"particle_momentum_z": 6.680357490847885e-17,
20+
"particle_weight": 12000000000.0
21+
},
22+
"virtual_photons": {
23+
"particle_position_x": 10.23535247755454,
24+
"particle_position_y": 0.5893638996747153,
25+
"particle_position_z": 41806401.59275659,
26+
"particle_momentum_z": 0.0,
27+
"particle_weight": 44683977600.0
28+
}
29+
}

0 commit comments

Comments
 (0)