diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 000000000..78835a641 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 533474bd7d88e5b538ee6bee023fde1a +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/Overview/highlights.html b/Overview/highlights.html new file mode 100644 index 000000000..2a7d73e58 --- /dev/null +++ b/Overview/highlights.html @@ -0,0 +1,856 @@ + + + + + + + + + Highlights — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Highlights

+
+

Improved performance using GPU offloading

+

Smilei computational performance has been recently enhanced with GPU offloading support, +in particular the projection of current has been accelerated with a CUDA kernel while other features +have been accelerated with the use of either OpenAcc Pragmas or OpenMP pragmas.

+

SMILEI can bes tested on recent supercomputers such as Adastra where it shows great weak scaling efficiency even while using diagnostics as shown in figure below:

+../_images/weak_scaling_efficiency.png +
+
+
+

Mitigation of numerical artifacts with relativistic particles

+

The staggering in space and time of the electromagnetic fields and the numerical dispersion of electromagnetic solvers +using finite differences in the time domain, typically used in electromagnetic Particle in Cell codes, create +numerical artifacts that become increasingly detrimental in presence of relativisitc macro-particles.

+

A typical example of simulation where the effects of these artifacts can become relevant and alter the numerical results +is Laser Wakefield Acceleration. In this kind of simulation, a numerical artifact called Numerical Cherenkov Radiation is +generated by the spurious interaction between relativistic macro-particles and electromagnetic fields that are numerically +slower due to the dispersion of the Finite Difference Time Domain solver for Maxwell’s equations. +This artifact can significantly alter the dynamics of relativistic electron beams accelerated in plasma waves, quickly increasing +their divergence along their propagation in the plasma.

+

Recently an interpolation scheme called B-TIS3 has been implemented in the code CALDER and published in P.-L. Bourgeois, X. Davoine (2023) +This scheme can significantly reduce the effects of Numerical Cherenkov Radiation and of the staggering of the electromagnetic fields, +as shown in this Figure:

+../_images/BTIS3_effect.png +

Both panels show a field proportional to the y component of the Lorentz force acting on the electron macro-particles in a Smilei simulation of Laser Wakefield Acceleration. +Top panel: simulation not using the B-TIS3 interpolation. +Bottom panel: simulation using the B-TIS3 interpolation. +The high frequency modulations, due to the Numerical Cherenkov Radiation are evident in the top panel, while they are +considerably reduced in the bottom panel. +These two simulations were obtained using the AMcylindrical geometry (1 azimuthal mode) and the Laser Envelope model.

+
+
+
+

Laser Envelope model and averaged tunnel ionization

+

Laser-plasma interaction in underdense plasmas can be accurately simulated under certain conditions through a +laser envelope model, where the high frequency oscillations of the laser pulse do not need to be resolved. +In this model the laser effect on the plasma is described through the ponderomotive force and the effect of the precence of the +plasma on the laser pulse is described through the plasma susceptibility. These terms in the laser plasma interaction +can be expressed only as function of the laser complex envelope.

+

This technique relaxes the constraint on the minimum spatial and temporal scales to be resolved and can yield +speed-ups of some orders of magnitude, expecially if coupled with a purely cylindrical geometry +(where only one azimuthal mode is taken into account).

+

The envelope model is particularly used for Laser Wakefield Acceleration, where often the laser pulse envelope is at least ten +times longer than the laser carrier wavelength. Recently an new averaged tunnel ionization model has been developed for the envelope model, +allowing the simulation of Laser Wakefield Acceleration with ionization injection with this efficient technique.

+

Following is the comparison of the electron density from two LWFA simulations, one using the laser envelope model and the averaged +tunnel ionization module (a) and one without the envelope model (b).

+../_images/Rho_2D_IonizationEnvelope_PRE.jpg +

In these simulations an intense laser pulse is propagating in a plasma composed of helium and partially ionized nitrogen. +The laser field near the pulse’s center is intense enough to further ionize the nitrogen ions, releasing electrons that can be trapped and +accelerated in the relativistic plasma wave behind the laser pulse.

+

Previous averaged tunnel ionization models did not allow to accurately describe this LWFA scheme at relativistic regimes. +In this new model also the longitudinal momentum of the electrons obtained through ionization is initialized following analytical derivations. +Including this longitudinal momentum initialization allows to accurately describe the dynamics of these electrons.

+

Following is a comparison of the accelerated electron spectra at the end of these simulations.

+../_images/Energy_spectrum_laser_vs_envelope.png +

In the green line it is shown the result of the previously known averaged ionization model. Without the longitudinal +momentum initialization, few electrons obtained through ionization are trapped and accelerated in the plasma wave. +The red line shows the result with the new averaged ionization model implemented in Smilei, which accurately reproduces +the spectrum obtained with the simulation without an envelope model (blue line).

+

The envelope simulation required an amount of computing resources orders of magnitude smaller than those required by the simulation without a +laser envelope model.

+

More details on the envelope model and the averaged tunnel ionization model in Smilei can be found here

+
+
+
+

Field initialization of a relativistic particle beam

+

In Plasma Wakefield Acceleration (PWFA) a plasma wave is generated behind a relativistic particle +beam propagating in a plasma.

+

To simulate this phenomenon, it is necessary to self-consistently initialize the electromagnetic fields +of a relativistic particle beam in vacuum, before its entrance into the plasma.

+

Following is the image of a PWFA simulation which used this technique at its start.

+../_images/PWFA.jpg +

The “driver” relativistic electron beam (in yellow) propagates through a plasma and drives a nonlinear Langmuir wave (in blue) that +propagates at a velocity close to that of light in its wake. A “witness” relativistic electron bunch injected in this wave +can be accelerated with electric fields orders of magnitude higher than those sustainable by metallic radio-frequency +accelerating cavities.

+
+
+
+

Azimuthal Fourier decomposition

+

In Laser Wakefield Acceleration (LWFA) a plasma wave is generated behind an intense laser pulse +propagating in an underdense plasma. +The physics in this phenomenon cannot be accurately simulated through 2D Cartesian +simulations. Nonetheless, 3D Cartesian simulations can be computationally demanding, +hence preliminary studies for LWFA experiments, typically consisting of many PIC simulations, +cannot be realissically be carried with 3D Cartesian simulations.

+

The azimuthal Fourier decomposition addresses this issue by using a cylindrical grid, hence +a 2D grid, decomposing the fields in azimuthal harmonics to take into account a third dimension in space +and treating macro-particles in the 6D phase space.

+

This technique can yield thus simulations with a computational cost comparable to that of 2D simulations, but +at the same time with an accuracy comparable to that of a full 3D Cartesian simulation.

+

Following is the image of a LWFA simulation using azimuthal Fourier decomposition, which has made it +feasible in a medium-scale laboratory cluster. An equivalent 3D Cartesian simulation would have required +an amount of resources greater by at least an order of magnitude.

+../_images/LWFA_Plas@Par.jpg +

The laser (in red) propagates through a low density plasma and drives a nonlinear Langmuir wave (in blue) that +propagates at a velocity close to that of light in its wake. In this simulation, a moving window is used +so we can follow the laser as it propagates through the plasma. We see electrons (in white) being self-injected +in this wakefield where they see a strong electric field that accelerates them up to ultra-relativistic (GeV) energy level.

+

An animation generated from the simulation data can be found here

+
+
+
+

Improved performance using vectorization

+

Smilei computational performance has been recently enhanced with +vectorized operations, +in particular the projection of currents and the interpolation of fields. +Typically, the new algorithms are more efficient than the old ones above +10 particles per cell, up to 3 times faster. An adaptive switching technique +ensures that the best version is used, dynamically and locally.

+

This has been validated on large-scale simulations. +An example of a mildly-relativistic collisionless shock simulation is provided +in Fig. 1 (watch the video).

+
+../_images/Weibel_3d_ne_vecto_it510.jpg +
+

Fig. 1 Mildly-relativistic collisionless shock simulation, with two drifting +plasmas colliding in the middle of the box. +Top panel: electron density. +Bottom panel: regions switched to vectorized operators are highlighted.

+
+
+

High-density regions are switched to vectorized operators while low-density +regions remain scalar (they have only 8 particles per cell). +In this particular case, the treatment of particles can be sped-up by 2.

+

For more details, checkout the doc and this +ArXiV paper.

+
+
+
+

Scalability in a wakefield acceleration simulation

+

Wakefield-acceleration of electrons in an underdense plasma creates a +hotspot of electrons, which makes the simulation strongly imbalanced. +This spot represent a large part of the total calculations, so that +more computing power should be allocated on it.

+

Please refer to the doc Parallelization basics to learn the basics of the +parallelization techniques employed in this section.

+

1. OpenMP

+

In a local area around this hotspot, OpenMP is able to manage the computing +resources to make the overall simulation faster. The following figure shows +the evolution of the time to calculate 100 iterations, as a function of time. +Each line corresponds to a different partition of the box in terms of +MPI processes and OpenMP threads: \(N\times M\), where \(N\) is +the total number of MPI processes, and \(M\) is the number of threads +in each MPI process.

+../_images/openMP_balancing.png +

Using more OpenMP threads per MPI process (while keeping the total number +of threads constant) clearly reduces the simulation time, because the +computing power is balanced within each MPI patch collection.

+

2. Dynamic load balancing between MPI processes

+

At the global simulation scale, OpenMP cannot be used to smoothen the balance. +Instead, a dynamic load balancing (DLB) algorithm periodically exchanges pieces of +the simulation box (patches) between MPI processes, so that each MPI +process owns a fair amount of the simulation load. The following figure +shows how this balancing reduces the time of the simulation.

+../_images/DLB_balancing.png +

The red curve is the best situation obtained in the previous section, while +the black curve corresponds to the DLB algorithm enabled.

+

The portion of the box belonging to each MPI process varies when the load balancing +occurs. The following figure shows how each of these portions evolve with time.

+../_images/Patch_loadcomparision.jpg +

The four panels correspond to four timesteps during the simulation. +The colorscale represents the log-scaled load of each patch. +The black lines show the borders of each MPI process’ portion of the box. +The MPI processes that are close to the hotspot tend to handle a smaller portion +of the box.

+
+
+
+

High-harmonic generation

+

The interaction between an ultra-intense (\(I>10^{18}~{\rm W/cm^2}\)) femtosecond laser pulse +with a solid target generates a dense “plasma mirror” at its surface that reflects the laser +in a strongly non-linear manner. The temporal distortion of the reflected wave creates +a train of ultra-short attosecond pulses, associated, in the frequency domain, +to a comb of high-order harmonics.

+

We present a 2-dimensional Smilei simulation of laser-solid interaction +with wavelength \(\lambda_0 = 0.8\) µm, peak intensity +\(2\times10^{19}~{\rm W/cm^2}\), at 45° incidence with p-polarization on an overdense plasma slab +of constant electron density \(n_0=200\,n_c\) (\(n_c\) being the critical density), +\(5\lambda_0\)-thick, with an exponential pre-plasma of gradient length \(0.1\,\lambda_0\) +down to a cut-off density \(0.05\,n_c\). The full box size is +\(80\,\lambda_0 \times 60\lambda_0\) and the simulation time \(150\,\lambda_0/c\) +with a total of \(\sim 1.4\) billion quasi-particles in the box.

+

The following figure (top panel) shows half of the simulation box in the +y-direction, and the laser field is reported at three different times. +The reflected laser pulse (at time \(t_2\)) shows a different spectral content than +the incident pulse (at time \(t_0\)). The plasma electron density is shown in black. +A close-up view of the interaction region is given in the bottom panel, illustrating +the electron bunches being pulled out from the plasma surface.

+../_images/hhg1.jpg +

Fourier analysis of the reflected laser field, in space and time, provides the +angular distribution of the frequency spectrum of the reflected light, shown in the +following figure (top panel). High harmonics appear up to order 16.

+../_images/hhg2.jpg +

The bottom panel shows trajectories of accelerated electrons ejected from the target. +The angular histogram shows that the momenta of the escaping energetic electrons +(1 to 10 MeV) are mostly directed along two directions which are close to the reflected +laser direction.

+

This simulation was run on the CINES/Occigen (Bullx) machine using 256 MPI x 14 OpenMP +threads for about 10700 CPU-hours. The characteristic computing time per particle +(average PIC iteration divided by the number of particles) is of the order of +0.7 µs, including 25% for diagnostics.

+
+
+
+

Brillouin amplification

+

Coupling, in a plasma, a long energetic “pump” pulse of moderate intensity to +a short counter-propagating “seed” pulse of initially low intensity can transfer energy +from the pump to the seed thanks to the excitation of a plasma or ion-acoustic wave.

+

Here, we look specifically at +the stimulated Brillouin scattering +(SBS) amplification, where the excited waves are ion-acoustic waves.

+

A pump with intensity \(10^{15}\) W/cm² (wavelength 1 µm) +correspond to the “strong-coupling” regime, particularly robust with respect to +plasma inhomogeneities and seed frequency [Chiaramello2016].

+

A 2-dimensional simulation, in conditions close to actual experiments, ran +on a box size of 1024 µm x 512 µm for 10 ps +with 25 billion quasi-particles. The following figure shows the evolution +of the pump and seed intensities in the head-on collision at three different times. +The blue-yellow maps correspond to the plasma density while the white-red maps +correspond to the lasers intensity.

+../_images/pump_seed.jpg +

The final seed intensity is nearly 5 times its initial intensity +while the spot size and phase front are well conserved, +suggesting that such a beam could be further focused using plasma mirrors.

+

This simulation used the IDRIS/Turing (BlueGene/Q) super-computer using 1.8 million +CPU-hours on 32768 MPI processes, and 4 OpenMP threads per core. +The average time to push a particle was 1.9 µs, including 5% +for diagnostics. On the CINES/Occigen (Bullx) machine, we obtained an average time +of 0.43 µs to push one particle (without diagnostics).

+
+
+
+

Magnetic reconnection at the Earth magnetopause

+

Magnetic reconnection at the Earth magnetopause regulates the transport of matter, +momentum and energy from the solar wind to the internal magnetosphere. +The solar wind plasma temperature is typically one tenth that of the magnetospheric plasma, +but its density is about ten times larger, and its magnetic field 2-3 times smaller. +This asymmetry makes the reconnection dynamics vastly more complex than in symmetric +environments, and has only been studied for a decade +via numerical simulations +and spacecraft observations.

+

Studying the impact of a plasmaspheric plume on magnetopause reconnection +via kinetic numerical simulation is difficult. The simulation first needs +to reach a quasi-steady state reconnection with a typical magnetopause asymmetry, +see the arrival of the plume and then last longer for a quasi-steady state plume +reconnection regime to settle. Due to the large particle density of plumes, +the transition and last phases have substantially longer time scales than the early phase, +which makes the simulation heavy. The domain must be long enough in the downstream direction +for the plasma, expelled during the early and transition phases, to be evacuated from +the reconnection region. Otherwise, upstream plasma would not inflow, +thereby stopping reconnection.

+

Three ion populations are present. +The solar wind and magnetospheric populations have densities equal to \(n_0\) and \(n_0/10\), +respectively, on their side of the current sheet, and fall to zero on the other side. +The plume population increases from 0 to \(2\,n_0\) at \(20\,c/\omega_{pi}\) from the initial +current sheet on the magnetospheric side. The magnetic field amplitude goes from \(2\,B_0\) +in the magnetosphere to \(B_0=m_e\omega_{pe}/e\) in the solar wind and is totally in the +simulation plane. The temperature is initially isotropic and its profile is calculated +to balance the total pressure.

+

The domain size is 1280 \(c/\omega_{pi} \times\) 256 \(c/\omega_{pi}\). +The total simulation time is \(800\times\) the ion gyration time. +We used a reduced ion to electron mass ratio \(m_i/m_e = 25\), and a ratio +50 of the speed of light by the Alfvén velocity. +There are initially 8.6 billion quasi-protons for the three populations, and 13 billion electrons.

+../_images/reconnection.jpg +

This figure presents some of the simulation results: +the electron density at three different times. +In the top panel, reconnection is in steady state between the solar wind plasma of +density \(\simeq n_0\) and the magnetosphere plasma of density \(\simeq 0.1~n_0\). +At this time, the exhaust is filled with mixed solar wind/hot magnetospheric plasma as +the plume (of density \(\simeq 2~n_0\)) is still located at \(\simeq 10~c/\omega_{pi}\) +from the magnetospheric separatrix. The reconnection rate during this period has a +typical value around \(0.1~\Omega_{ci}^{-1}\), with important fluctuations caused +by plasmoid formation. The plume, originally at \(20~c/\omega_{pi}\) from the magnetopause, +is slowly advected towards the magnetosphere separatrix and finally touches the +reconnection site at about \(t=300~\Omega_{ci}^{-1}\). The second panel at +\(t=370~\Omega_{ci}^{-1}\) shows the plume starting to fill the exhaust after +reaching the reconnection site and mixing with solar wind plasma. +At this time, the reconnection rate collapses to about half its previous value. +The transition phase lasts for about \(100~\Omega_{ci}^{-1}\) before a plume +reconnection regime reaches a quasi-steady state. +The third panel shows the electron density at the end of the simulation, +where the exhaust is filled with plume and solar wind plasma.

+

This large-scale simulation has run for a total of 14 million CPU-hours on 16384 cores +of the CINES/Occigen (Bullx) supercomputer within a GENCI-CINES special call. +Overall, the characteristic (full) push-time for a single particle was of the order +of 1.6 µs (including 31% for diagnostics). +No dynamic load balancing was used for this simulation.

+
+
+
+

Collisionless shock in pair plasmas

+

Relativistic collisionless shocks play a fundamental role in various astrophysical scenarios +(active galactic nuclei, micro-quasars, pulsar wind nebulae and gamma-ray bursts) +where they cause high-energy radiation and particle acceleration related to the +cosmic-ray spectrum. In the absence of particle collisions, the shock is mediated +by collective plasma processes, produced by electromagnetic plasma instabilities +at the shock front.

+

Specifically, the Weibel (or current filamentation) instability +is observed in most of the astrophysical relativistic outflows interacting with +the interstellar medium. It can be excited by counter-streaming unmagnetized relativistic +flows, and dominates the instability spectrum for a wide range of parameters. +The resulting strong magnetic turbulence can isotropize the incoming flow, +hence stopping it and leading to compression of the downstream (shocked plasma) and shock formation.

+

We present a 2-dimensional PIC simulation of such shock, +driven in an initially unmagnetized electron-positron plasma. +The simulation relies on the “piston” method that consists in initializing the +simulation with a single cold electron-positron plasma drifting +at a relativistic velocity \(v_0 \simeq 0.995\,c\). +Reflecting boundary conditions at the right border creates a counter-penetrating flow.

+

The simulation box size is 2048 \(\delta_e \times\) 128 \(\delta_e\) +(\(\delta_e = c/\omega_p\) being the electron skin-depth of the initial flow), +with a total of 2.15 billion quasi-particles. +The following figure show an unstable overlapping region of incoming and +reflected flows, resulting in the creation, before the shock +of filamentary structures in both the magnetic field (panel a) and +the total plasma density (panel b).

+../_images/shock1.jpg +

The magnetic field at the shock front becomes turbulent and it is strong +enough to stop the incoming particles leading to a pile-up of the plasma +density (panel c).

+

The following figure demonstrates the build-up, at late times, of a supra-thermal tail +in the downstream particle energy distribution. +It is characteristic of first-order Fermi acceleration at the shock front, +and appears to follow a \(\gamma^{-2.5}\) power law.

+../_images/shock3.jpg +

This simulation run on the TGCC/Curie machine using 128 MPI x 8 OpenMP threads +for a total of 18800 CPU-hours for 49780 timesteps. +The average push time for one quasi-particle was of 0.63 µs (including 20% for diagnostics).

+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Overview/licence.html b/Overview/licence.html new file mode 100644 index 000000000..f879aa07c --- /dev/null +++ b/Overview/licence.html @@ -0,0 +1,530 @@ + + + + + + + + + Licence — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Licence

+

Smilei is protected by a licence CeCILL, the french equivalent to +the open-source Gnu GPL license.

+

Extract:

+
+

This software is governed by the CeCILL-B license under French law and +abiding by the rules of distribution of free software. You can use, +modify and/ or redistribute the software under the terms of the CeCILL-B +license as circulated by CEA, CNRS and INRIA at the following URL +http://www.cecill.info.

+
+

More information here.

+
+
+

How to cite Smilei

+

Smilei’s development depends on its visibility from publications or presentations +featuring its results. When publishing simulation results involving Smilei, +please cite the following article:

+
+

J. Derouillat, A. Beck, F. Pérez, T. Vinci, M. Chiaramello, A. Grassi, M. Flé, G. Bouchard, I. Plotnikov, N. Aunai, J. Dargent, C. Riconda, M. Grech, +SMILEI: a collaborative, open-source, multi-purpose particle-in-cell code for plasma simulation, +Comput. Phys. Commun. 222, 351-373 (2018),

+
+

If help or changes in the code were obtained from Smilei developers, +please acknowledge their participation in any subsequent publication or presentation.

+

If your publication makes significant use of Smilei, we will gladly list it +in the Publications.

+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Overview/material.html b/Overview/material.html new file mode 100644 index 000000000..42c1f4769 --- /dev/null +++ b/Overview/material.html @@ -0,0 +1,1246 @@ + + + + + + + + + Publications — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Publications

+ + +
+
+

Reference article

+
+
Derouillat2018
+

J. Derouillat, A. Beck, F. Pérez, T. Vinci, M. Chiaramello, A. Grassi, M. Flé, G. Bouchard, I. Plotnikov, N. Aunai, J. Dargent, C. Riconda and M. Grech, +SMILEI: a collaborative, open-source, multi-purpose particle-in-cell code for plasma simulation, +Comput. Phys. Commun. 222, 351-373 (2018), +arXiv:1702.05128

+
+
+
+
+
+

Papers involving Smilei

+

Only papers published in peer-reviewed journals are listed (for the complete list of citing papers see Google Scholar). +As of November 2021, 90 papers have been published covering a broad range of topics:

+
    +
  • laser-plasma interaction (LPI) / inertial fusion (FCI)

  • +
  • ultra-high intensity (UHI) applications

  • +
  • quantum electrodynamics (QED) processes in plasmas

  • +
  • astrophysical and space plasmas

  • +
  • high-performance computing (HPC)

  • +
+
+../_images/paper_topics.png +
+
+
Drobniak2023
+

P. Drobniak, E. Baynard, C. Bruni, K. Cassou, C. Guyot, G. Kane, S. Kazamias, V. Kubytskyi, N. Lericheux, B. Lucas, M. Pittman, F. Massimo, A. Beck, A. Specka, P. Nghiem, and D. Minenna, +Random scan optimization of a laser-plasma electron injector based on fast particle-in-cell simulations, +Phys. Rev. Accel. Beams 26, 091302 (2023)

+
+
Bukharskii2023
+

N. Bukharskii and Ph. Korneev, +Intense widely controlled terahertz radiation from laser-driven wires, +Matter Radiat. Extremes 8, 044401 (2023)

+
+
Schmitz2023
+

B. Schmitz, D. Kreuter, and O. Boine-Frankenheim, +Modeling of a Liquid Leaf Target TNSA Experiment Using Particle-In-Cell Simulations and Deep Learning, +Laser and Particle Beams, 2868112 (2023)

+
+
Paschke_Bruehl2023
+

F. Paschke-Bruehl, M. Banjafar, M. Garten, L. G. Huang, B. E. Marré, M. Nakatsutsumi, L. Randolph, T. E. Cowan, U. Schramm and T. Kluge, +Heating in multi-layer targets at ultra-high intensity laser irradiation and the impact of density oscillation, +New Journal of Physics 25 (2023)

+
+
Vladisavlevici2023
+

I. M. Vladisavlevici, D. Vizman and E. d’Humières, +Theoretical investigation of the interaction of ultra-high intensity laser pulses with near critical density plasmas, +Plasma Physics and Controlled Fusion 65, 4 (2023)

+
+
Gao2023
+

Xiaohui Gao, +Ionization dynamics of sub-micrometer-sized clusters in intense ultrafast laser pulses, +Phys. Plasmas 30, 052102 (2023)

+
+
Krafft2023
+

C. Krafft and P. Savoini, +Dynamics of Two-dimensional Type III Electron Beams in Randomly Inhomogeneous Solar Wind Plasmas, +The Astrophysical Journal 949, 1 (2023)

+
+
Hadjikyriacou2023
+

A. Hadjikyriacou, J. Psikal, L. Giuffrida and M. Kucharik, +Novel approach to TNSA enhancement using multi-layered targets—a numerical study, +Plasma Physics and Controlled Fusion 65, 8 (2023)

+
+
Ghizzo2023
+

Alain Ghizzo, Daniele Del Sarto, and Homam Betar, +Collisionless Heating Driven by Vlasov Filamentation in a Counterstreaming Beams Configuration, +Phys. Rev. Lett. 131, 035101 (2023)

+
+
Yang2023
+

Tong Yang, Zhen Guo, Yang Yan, Minjian Wu, Yadong Xia, Qiangyou He, Hao Cheng, Yuze Li, Yanlv Fang, Yanying Zhao, Xueqing Yan and Chen Lin, +Measurements of Plasma Density Profile Evolutions with Channel-guided Laser, +High Power Laser Science and Engineering pp. 1-15 (2023)

+
+
Yao2023
+

W. Yao, A. Fazzini, S.N. Chen, K. Burdonov, J. Béard, M. Borghesi, A. Ciardi, M. Miceli, S. Orlando, X. Ribeyre, E. d’Humières and J. Fuchs, +Investigating particle acceleration dynamics in interpenetrating magnetized collisionless super-critical shocks, +J. Plasma Phys. 89, 915890101 (2023)

+
+
Pak2023
+

Taegyu Pak, Mohammad Rezaei-Pandari, Sang Beom Kim, Geonwoo Lee, Dae Hee Wi, Calin Ioan Hojbota, Mohammad Mirzaie, Hyeongmun Kim, Jae Hee Sung, Seong Ku Lee, Chul Kang and Ki-Yong Kim, +Multi-millijoule terahertz emission from laser-wakefield-accelerated electrons, +Light Sci Appl 12, 37 (2023)

+
+
Istokskaia2023
+

Valeriia Istokskaia, Marco Tosca, Lorenzo Giuffrida, Jan Psikal, Filip Grepl, Vasiliki Kantarelou, Stanislav Stancek, Sabrina Di Siena, Arsenios Hadjikyriacou, Aodhan McIlvenny, Yoann Levy, Jaroslav Huynh, Martin Cimrman, Pavel Pleskunov, Daniil Nikitin, Andrei Choukourov, Fabio Belloni, Antonino Picciotto, Satyabrata Kar, Marco Borghesi, Antonio Lucianetti, Tomas Mocek and Daniele Margarone, +A multi-MeV alpha particle source via proton-boron fusion driven by a 10-GW tabletop laser, +Commun Phys 6, 27 (2023)

+
+
Yoon2023
+

Young Dae Yoon, Deirdre E. Wendel and Gunsu S. Yun, +Equilibrium selection via current sheet relaxation and guide field amplification, +Nat Commun 14, 139 (2023)

+
+
Galbiati2023
+

Marta Galbiati, Arianna Formenti, Mickael Grech and Matteo Passoni, +Numerical investigation of non-linear inverse Compton scattering in double-layer targets, +Front. Phys. 11, fphy.2023.1117543 (2023)

+
+
Sakai2023
+

K. Sakai, T. Nishimoto, S. Isayama, S. Matsukiyo and Y. Kuramitsu, +Ion-acoustic feature of collective Thomson scattering in non-equilibrium two-stream plasmas, +Physics of Plasmas 30, 012105 (2023)

+
+
Golovanov2023
+

A. Golovanov, I. Yu. Kostyukov, A. Pukhov and V. Malka, +Energy-Conserving Theory of the Blowout Regime of Plasma Wakefield, +Phys. Rev. Lett. 130, 105001 (2023)

+
+
Miethlinger2023
+

Thomas Miethlinger, Nico Hoffmann and Thomas Kluge, +Acceptance Rates of Invertible Neural Networks on Electron Spectra from Near-Critical Laser-Plasmas: A Comparison, +Parallel Processing and Applied Mathematics, 273-284 (2023)

+
+
Zepter2023
+

C. Zepter, A. Seidel, M. Zepf, M. C. Kaluza and A. Sävert, +Role of spatiotemporal couplings in stimulated Raman side scattering, +Phys. Rev. Research 5, L012023 (2023)

+
+
Marini2023
+

S. Marini, M. Grech, P. S. Kleij, M. Raynaud and C. Riconda, +Electron acceleration by laser plasma wedge interaction, +Phys. Rev. Research 5, 013115 (2023)

+
+
Glek2022b
+

P. B. Glek and A. M. Zheltikov, +Enhanced coherent transition radiation from midinfrared‐laser‐driven microplasmas, +Scientific Reports 12, 7660 (2022)

+
+
Margarone2022
+

D. Margarone, J. Bonvalet, L. Giuffrida, A. Morace, V. Kantarelou, M. Tosca, D. Raffestin, P. Nicolai, A. Picciotto, Y. Abe, Y. Arikawa, S. Fujioka, Y. Fukuda, Y. Kuramitsu, H. Habara and D. Batani, +In-Target Proton–Boron Nuclear Fusion Using a PW-Class Laser, +Appl. Sci. 12(3), 1444 (2022)

+
+
Kochetkov2022
+

Iu. V. Kochetkov, N. D. Bukharskii, M. Ehret, Y. Abe, K. F. F. Law,V. Ospina‐Bohorquez, J. J. Santos, S. Fujioka, G. Schaumann, B. Zielbauer, A. Kuznetsov and Ph. Korneev, +Neural network analysis of quasistationary magnetic fields in microcoils driven by short laser pulses, +Scientific Reports 12, 13734 (2022)

+
+
Oudin2022
+

A. Oudin, A. Debayle, C. Ruyer, D. Benisti, +Cross-beam energy transfer between spatially smoothed laser beams, +Phys. Plasmas 29, 112112 (2022)

+
+
Chen2022
+

Q. Chen, Dominika Maslarova, J. Wang, S. Li, and D. Umstadter, +Injection of electron beams into two laser wakefields and generation of electron rings, +Phys. Rev. E 106, 055202 (2022)

+
+
Kumar2022b
+

Sonu Kumar, Rajat Dhawan, D.K. Singh and Hitendra K. Malik, +Diagnostic of laser wakefield acceleration with ultra – Short laser pulse by using SMILEI PIC code, +Materials Today: Proceedings 62, 3203-3207 (2022)

+
+
Kumar2022a
+

Sonu Kumar, Dhananjay K Singh and Hitendra K Malik, +Comparative study of ultrashort single-pulse and multi-pulse driven laser wakefield acceleration, +Laser Phys. Lett. 20, 026001 (2022)

+
+
Miloshevsky2022
+

G. Miloshevsky, +Pic Modeling of Omega Experiments on Ablation of Plasmas, +2022 IEEE International Conference on Plasma Science (ICOPS), ICOPS45751.2022.9813047 (2022)

+
+
Zhang2022b
+

Yue Zhang, Feng Wang, Jianyong Liu and Jizhong Sun, +Simulation of the inverse bremsstrahlung absorption by plasma plume in laser penetration welding, +Chemical Physics Letters 793, 139434 (2022)

+
+
Vladisavlevici2022
+

Iuliana-Mariana Vladisavlevici, Daniel Vizman and Emmanuel d’Humières, +Laser Driven Electron Acceleration from Near-Critical Density Targets towards the Generation of High Energy γ-Photons, +Photonics 9, 953 (2022)

+
+
Ouatu2022
+

I. Ouatu, B. T. Spiers, R. Aboushelbaya, Q. Feng, M. W. von der Leyen, R. W. Paddock, R. Timmis, C. Ticos, K. M. Krushelnick and P. A. Norreys, +Ionization states for the multipetawatt laser-QED regime, +Phys. Rev. E 106, 015205 (2022)

+
+
Beth2022
+

A. Beth, H. Gunell, C. Simon Wedlund, C. Goetz, H. Nilsson and M. Hamrin, +First investigation of the diamagnetic cavity boundary layer with a 1D3V PIC simulation, +A&A 667, A143 (2022)

+
+
Guo2022
+

Yinlong Guo, Xuesong Geng, Liangliang Ji, Baifei Shen and Ruxin Li, +Improving the accuracy of hard photon emission by sigmoid sampling of the quantum-electrodynamic table in particle-in-cell Monte Carlo simulations, +Phys. Rev. E 105, 025309 (2022)

+
+
Pae2022
+

Ki Hong Pae, Chul Min Kim, Vishwa Bandhu Pathak, Chang-Mo Ryu and Chang Hee Nam, +Direct laser acceleration of electrons from a plasma mirror by an intense few-cycle Laguerre–Gaussian laser and its dependence on the carrier-envelope phase, +Plasma Phys. Control. Fusion 64, 055013 (2022)

+
+
Zhang2022a
+

Cui-Wen Zhang, Yi-Xuan Zhu, Jian-Feng Lv and Bai-Song Xie, +Simulation Study of a Bright Attosecond γ-ray Source Generation by Irradiating an Intense Laser on a Cone Target, +Applied Sciences 12, 4361 (2022)

+
+
Han2022
+

Qianqian Han, Xuesong Geng, Baifei Shen, Zhizhan Xu and Liangliang Ji, +Ultra-fast polarization of a thin electron layer in the rotational standing-wave field driven by double ultra-intense laser pulses, +New J. Phys. 24, 063013 (2022)

+
+
Gothel2022
+

Ilja Göthel, Constantin Bernert, Michael Bussmann, Marco Garten, Thomas Miethlinger, Martin Rehwald, Karl Zeil, Tim Ziegler, Thomas E Cowan, Ulrich Schramm and Thomas Kluge, +Optimized laser ion acceleration at the relativistic critical density surface, +Plasma Phys. Control. Fusion 64, 044010 (2022)

+
+
Fazzini2022
+

A. Fazzini, W. Yao, K. Burdonov, J. Béard, S. N. Chen, A. Ciardi, E. d’Humières, R. Diab, E. D. Filippov, S. Kisyov, V. Lelasseux, M. Miceli, Q. Moreno, S. Orlando, S. Pikuz, X. Ribeyre, M. Starodubtsev, R. Zemskov and J. Fuchs, +Particle energization in colliding subcritical collisionless shocks investigated in the laboratory, +A&A 665, A87 (2022)

+
+
Bykov2022
+

A. M. Bykov, S. M. Osipov and V. I. Romanskii, +Acceleration of Cosmic Rays to Energies above 1015 eV by Transrelativistic Shocks, +J. Exp. Theor. Phys. 134, 487-497 (2022)

+
+
Sundstrom2022
+

Andréas Sundström, Mickael Grech, István Pusztai and Caterina Riconda, +Stimulated-Raman-scattering amplification of attosecond XUV pulses with pulse-train pumps and application to local in-depth plasma-density measurement, +Phys. Rev. E 106, 045208 (2022)

+
+
Krafft2022b
+

C. Krafft and P. Savoini, +Third and Fourth Harmonics of Electromagnetic Emissions by a Weak Beam in a Solar Wind Plasma with Random Density Fluctuations, +ApJL 934, L28 (2022)

+
+
Krafft2022a
+

C. Krafft and P. Savoini, +Fundamental Electromagnetic Emissions by a Weak Electron Beam in Solar Wind Plasmas with Density Fluctuations, +ApJL 924, L24 (2022)

+
+
Kong2022
+

Defeng Kong, Guoqiang Zhang, Yinren Shou, Shirui Xu, Zhusong Mei, Zhengxuan Cao, Zhuo Pan, Pengjie Wang, Guijun Qi, Yao Lou, Zhiguo Ma, Haoyang Lan, Wenzhao Wang, Yunhui Li, Peter Rubovic, Martin Veselsky, Aldo Bonasera, Jiarui Zhao, Yixing Geng, Yanying Zhao, Changbo Fu, Wen Luo, Yugang Ma, Xueqing Yan and Wenjun Ma, +High-energy-density plasma in femtosecond-laser-irradiated nanowire-array targets for nuclear reactions, +Matter and Radiation at Extremes 7, 064403 (2022)

+
+
Davidson2022
+

Conor Davidson, Zheng-Ming Sheng, Thomas Wilson and Paul McKenna, +Theoretical and computational studies of the Weibel instability in several beam–plasma interaction configurations, +J. Plasma Phys. 88, 905880206 (2022)

+
+
Glek2022
+

P. B. Glek and A. M. Zheltikov, +Subcycle terahertz field waveforms clocked by attosecond high-harmonic pulses from relativistic laser plasmas, +Journal of Applied Physics 131, 103104 (2022)

+
+
Umstadter2022
+

D. Umstadter +Controlled Injection of Electrons for Improved Performance of Laser-Wakefield Acceleration, +United States: N. p., (2022)

+
+
Massimo2022
+

Francesco Massimo, Mathieu Lobet, Julien Derouillat, Arnaud Beck, Guillaume Bouchard, Mickael Grech, Frédéric Pérez, Tommaso Vinci, +A Task Programming Implementation for the Particle in Cell Code Smilei, +PASC ‘22: Proceedings of the Platform for Advanced Scientific Computing Conference 5, 1 (2022), +arXiv:2204.12837

+
+
Yao2022
+

W. Yao, A. Fazzini, S. N. Chen, K. Burdonov, P. Antici, J. Béard, S. Bolaños, A. Ciardi, R. Diab, E. D. Filippov, S. Kisyov, V. Lelasseux, M. Miceli, Q. Moreno, V. Nastasa, S. Orlando, S. Pikuz, D. C. Popescu, G. Revet, X. Ribeyre, E. d’Humières and J. Fuchs, +Detailed characterization of a laboratory magnetized supercritical collisionless shock and of the associated proton energization, +Matter and Radiation at Extremes 7, 014402 (2022)

+
+
Singh2022
+

P. K. Singh, F.-Y. Li, C.-K. Huang, A. Moreau, R. Hollinger, A. Junghans, A. Favalli, C. Calvi, S. Wang, Y. Wang, H. Song, J. J. Rocca, R. E. Reinovsky and S. Palaniyappan, +Vacuum laser acceleration of super-ponderomotive electrons using relativistic transparency injection, +Nat Commun 13, 54 (2022)

+
+
Lobet2022
+

M. Lobet, F. Massimo, A. Beck, G. Bouchard, F. Perez, T. Vinci, and M. Grech. +Simple adaptations to speed-up the Particle-In-Cell code Smilei on the ARM-based Fujitsu A64FX processor., +In International Conference on High Performance Computing in Asia-Pacific Region Workshops (HPCAsia 2022 Workshop). +Association for Computing Machinery, New York, NY, USA, 40–48. (2022)

+
Tomassini2021
+

Paolo Tomassini, Francesco Massimo, Luca Labate and Leonida A. Gizzi, +Accurate electron beam phase-space theory for ionization-injection schemes driven by laser pulses, +High Pow Laser Sci Eng 10, e15 (2021)

+
+
+ +
+
Meinhold2021
+

Tim Arniko Meinhold and Naveen Kumar, +Radiation pressure acceleration of protons from structured thin-foil targets, +J. Plasma Phys. 87, 905870607 (2021)

+
+
Bonvalet2021b
+

J. Bonvalet, P. Loiseau, J.-R. Marquès, E. Atukpor, E. d’Humières, J. Domange, P. Forestier-Colleoni, F. Hannachi, L. Lancia, D. Raffestin, M. Tarisien, V. Tikhonchuk and Ph. Nicolaï, +Laser-driven collisionless shock acceleration of protons from gas jets tailored by one or two nanosecond beams, +Physics of Plasmas 28, 113102 (2021)

+
+
Shi2021b
+

Yin Shi, David R Blackman and Alexey Arefiev, +Electron acceleration using twisted laser wavefronts, +Plasma Phys. Control. Fusion 63, 125032 (2021)

+
+
Kumar2021
+

Naveen Kumar and Brian Reville, +Nonthermal Particle Acceleration at Highly Oblique Nonrelativistic Shocks, +ApJL 921, L14 (2021)

+
+
Ghaith2021
+

A. Ghaith, M.-E. Couprie, D. Oumbarek-Espinos, I.A. Andriyash, F. Massimo, J.A. Clarke, M. Courthold, V. Bayliss, A. Bernhard, M. Trunk, M. Valléau, O. Marcouillé, A. Chancé, S. Licciardi, V. Malka, F. Nguyen and G. Dattoli, +Undulator design for a laser-plasma-based free-electron-laser, +Physics Reports 937, 1-73 (2021)

+
+
Horny2021
+

Vojtěch Horný and László Veisz, +Generation of single attosecond relativistic electron bunch from intense laser interaction with a nanosphere, +Plasma Phys. Control. Fusion 63, 125025 (2021)

+
+
Krafft2021
+

C. Krafft and P. Savoini, +Second Harmonic Electromagnetic Emissions by an Electron Beam in Solar Wind Plasmas with Density Fluctuations, +ApJL 917, L23 (2021)

+
+
Khalilzadeh2021c
+

E. Khalilzadeh, M. J. Jafari and A. Chakhmachi, +Stochastic heating of electrons due to Raman backscatter radiations in interaction of intense laser pulse with nitrogen atoms, +Physics of Plasmas 28, 072304 (2021)

+
+
Marini2021b
+

S. Marini, P. S. Kleij, F. Amiranoff, M. Grech, C. Riconda and M. Raynaud, +Key parameters for surface plasma wave excitation in the ultra-high intensity regime, +Physics of Plasmas 28, 073104 (2021)

+
+
Sladkov2021
+

A. Sladkov, R. Smets, N. Aunai and A. Korzhimanov, +Numerical study of non-gyrotropic electron pressure effects in collisionless magnetic reconnection, +Physics of Plasmas 28, 072108 (2021)

+
+
Shou2021
+

Yinren Shou, Dahui Wang, Pengjie Wang, Jianbo Liu, Zhengxuan Cao, Zhusong Mei, Shirui Xu, Zhuo Pan, Defeng Kong, Guijun Qi, Zhipeng Liu, Yulan Liang, Ziyang Peng, Ying Gao, Shiyou Chen, Jiarui Zhao, Yanying Zhao, Han Xu, Jun Zhao, Yanqing Wu, Xueqing Yan and Wenjun Ma, +High-efficiency generation of narrowband soft x rays from carbon nanotube foams irradiated by relativistic femtosecond lasers, +Opt. Lett. 46, 3969 (2021)

+
+
Khalilzadeh2021b
+

E. Khalilzadeh, A. Chakhmachi, Z. Dehghani, S. Rezaei and M. J. Jafari, +Electron energy spectrum in the field‐ionized plasma, +Contributions to Plasma Physics 61, ctpp.202000219 (2021)

+
+
Hosseinkhani2021
+

H. Hosseinkhani, M. Pishdast, J. Yazdanpanah and S.A. Ghasemi, +Investigation of the classical and quantum radiation reaction effect on interaction of ultra high power laser with near critical plasma, +J. Nuclear Sci. Technol. 42, 27-35 (2021)

+
+
MercuriBaron2021
+

A Mercuri-Baron, M Grech, F Niel, A Grassi, M Lobet, A Di Piazza and C Riconda, +Impact of the laser spatio-temporal shape on Breit–Wheeler pair production, +New J. Phys. 23, 085006 (2021)

+
+
Peng2021
+

H. Peng, C. Riconda, S. Weber, C.T. Zhou and S.C. Ruan, +Frequency Conversion of Lasers in a Dynamic Plasma Grating, +Phys. Rev. Applied 15, 054053 (2021)

+
+
Shi2021a
+

Yin Shi, David Blackman, Dan Stutman and Alexey Arefiev, +Generation of Ultrarelativistic Monoenergetic Electron Bunches via a Synergistic Interaction of Longitudinal Electric and Magnetic Fields of a Twisted Laser, +Phys. Rev. Lett. 126, 234801 (2021)

+
+
Bonvalet2021a
+

J. Bonvalet, Ph. Nicolaï, D. Raffestin, E. D’humieres, D. Batani, V. Tikhonchuk, V. Kantarelou, L. Giuffrida, M. Tosca, G. Korn, A. Picciotto, A. Morace, Y. Abe, Y. Arikawa, S. Fujioka, Y. Fukuda, Y. Kuramitsu, H. Habara and D. Margarone, +Energetic α-particle sources produced through proton-boron reactions by high-energy high-intensity laser beams, +Phys. Rev. E 103, 053202 (2021)

+
+
Shekhanov2021
+

S A Shekhanov and V T Tikhonchuk, +SRS-SBS competition and nonlinear laser energy absorption in a high temperature plasma, +Plasma Phys. Control. Fusion 63, 115016 (2021)

+
+
Psikal2021
+

J Psikal, +Laser-driven ion acceleration from near-critical Gaussian plasma density profile, +Plasma Phys. Control. Fusion 63, 064002 (2021)

+
+
Yoon2021b
+

Young Dae Yoon, Gunsu S. Yun, Deirdre E. Wendel and James L. Burch, +Collisionless relaxation of a disequilibrated current sheet and implications for bifurcated structures, +Nat Commun 12, 3774 (2021)

+
+
Lavorenti2021
+

F. Lavorenti, P. Henri, F. Califano, S. Aizawa and N. André, +Electron acceleration driven by the lower-hybrid-drift instability. An extended quasilinear model, +A&A 652, 202141049 (2021)

+
+
Golovanov2021
+

A A Golovanov, I Yu Kostyukov, L Reichwein, J Thomas and A Pukhov, +Excitation of strongly nonlinear plasma wakefield by electron bunches, +Plasma Phys. Control. Fusion 63, 085004 (2021)

+
+
Jirka2021
+

M. Jirka, P. Sasorov, S. S. Bulanov, G. Korn, B. Rus and S. V. Bulanov, +Reaching high laser intensity by a radiating electron, +Phys. Rev. A 103, 053114 (2021)

+
+
Marques2021
+

J.-R. Marquès, P. Loiseau, J. Bonvalet, M. Tarisien, E. d’Humières, J. Domange, F. Hannachi, L. Lancia, O. Larroche, P. Nicolaï, P. Puyuelo-Valdes, L. Romagnani, J. J. Santos and V. Tikhonchuk, +Over-critical sharp-gradient plasma slab produced by the collision of laser-induced blast-waves in a gas jet: Application to high-energy proton acceleration, +Physics of Plasmas 28, 023103 (2021)

+
+
Do2021
+

Hue Thi Bich Do, Ding Wen Jun, Zackaria Mahfoud, Wu Lin and Michel Bosman, +Electron dynamics in plasmons, +Nanoscale 13, 2801-2810 (2021)

+
+
Khalilzadeh2021a
+

E. Khalilzadeh, M.J. Jafari, S. Rezaei and Z. Dehghani, +The effect of the laser pulse shape on the wakefield generation in field-ionized plasma, +Chinese Journal of Physics 71, 212-223 (2021)

+
+
Babjak2021
+

R. Babjak and J. Psikal, +The role of standing wave in the generation of hot electrons by femtosecond laser beams incident on dense ionized target, +Physics of Plasmas 28, 023107 (2021)

+
+
Cantono2021
+

Giada Cantono, Alexander Permogorov, Julien Ferri, Evgeniya Smetanina, Alexandre Dmitriev, Anders Persson, Tünde Fülöp and Claes-Göran Wahlström, +Laser-driven proton acceleration from ultrathin foils with nanoholes, +Sci Rep 11, 5006 (2021)

+
+
Perez2021
+

F. Pérez, F. Amiranoff, C. Briand, S. Depierreux, M. Grech, L. Lancia, P. Loiseau, J.-R. Marquès, C. Riconda and T. Vinci, +Numerical study of Langmuir wave coalescence in laser-plasma interaction, +Physics of Plasmas 28, 043102 (2021)

+
+
Yoon2021a
+

Young Dae Yoon and Paul M. Bellan, +How Hall electric fields intrinsically chaotize and heat ions during collisionless magnetic reconnection, +Physics of Plasmas 28, 022113 (2021)

+
+
Sampath2021
+

Archana Sampath, Xavier Davoine, Sébastien Corde, Laurent Gremillet, Max Gilljohann, Maitreyi Sangal, Christoph H. Keitel, Robert Ariniello, John Cary, Henrik Ekerfelt, Claudio Emma, Frederico Fiuza, Hiroki Fujii, Mark Hogan, Chan Joshi, Alexander Knetsch, Olena Kononenko, Valentina Lee, Mike Litos, Kenneth Marsh, Zan Nie, Brendan O’Shea, J. Ryan Peterson, Pablo San Miguel Claveria, Doug Storey, Yipeng Wu, Xinlu Xu, Chaojie Zhang and Matteo Tamburini, +Extremely Dense Gamma-Ray Pulses in Electron Beam-Multifoil Collisions, +Phys. Rev. Lett. 126, 064801 (2021)

+
+
Marini2021a
+

S. Marini, P. S. Kleij, F. Pisani, F. Amiranoff, M. Grech, A. Macchi, M. Raynaud and C. Riconda, +Ultrashort high energy electron bunches from tunable surface plasma waves driven with laser wavefront rotation, +Phys. Rev. E 103, L021201 (2021)

+
+
Yao2021
+

W. Yao, A. Fazzini, S. N. Chen, K. Burdonov, P. Antici, J. Béard, S. Bolaños, A. Ciardi, R. Diab, E. D. Filippov, S. Kisyov, V. Lelasseux, M. Miceli, Q. Moreno, V. Nastasa, S. Orlando, S. Pikuz, D. C. Popescu, G. Revet, X. Ribeyre, E. d’Humières and J. Fuchs, +Laboratory evidence for proton energization by collisionless shock surfing, +Nat. Phys. 17, 1177-1182 (2021)

+
+
Gelfer2021
+

E G Gelfer, A M Fedotov and S Weber, +Radiation induced acceleration of ions in a laser irradiated transparent foil, +New J. Phys. 23, 095002 (2021) +arXiv:1907.02621

+
+
Siminos2021
+

E. Siminos, I. Thiele and C. Olofsson, +Laser Wakefield Driven Generation of Isolated Carrier-Envelope-Phase Tunable Intense Subcycle Pulses, +Phys. Rev. Lett. 126, 044801 (2021) +arXiv:1902.05014

+
+
Budriga2020
+

O. Budriga, L. E. Ionel, D. Tatomirescu and K. A. Tanaka, +Enhancement of laser-focused intensity greater than 10 times through a re-entrant cone in the petawatt regime, +Optics Letters 45, 3454 (2020)

+
+
Nghiem2020
+

P. A. P. Nghiem, R. Assmann, A. Beck et al., +Toward a plasma-based accelerator at high beam energy with high beam charge and high beam quality, +Phys. Rev. Accel. Beams 23, 031301 (2020)

+
+
Pisarczyk2020
+

T. Pisarczyk, M. Kalal, S. Yu. Gus’kov et al., +Hot electron retention in laser plasma created under terawatt subnanosecond irradiation of Cu targets, +Plasma Phys. Control. Fusion 62, 115020 (2020)

+
+
Pagano2020
+

I. Pagano, J. Brooks, A. Bernstein, R. Zgadzaj, J. Leddy, J. Cary and M. C. Downer, +Low Density Plasma Waveguides Driven by Ultrashort (30 fs) and Long (300 ps) Pulses for Laser Wakefield Acceleration, +2018 IEEE Advanced Accelerator Concepts Workshop (AAC), 1

+
+
Ruyer2020
+

C. Ruyer, A. Debayle, P. Loiseau, M. Casanova and P. E. Masson-Laborde, +Kinetic analytical modeling of Gaussian pulse beam-bending including the transient regime, +Physics of Plasmas 27, 102105 (2020)

+
+
Peng2020
+

H. Peng, C. Riconda, M. Grech, C.-T. Zhou and S. Weber, +Dynamical aspects of plasma gratings driven by a static ponderomotive potential, +Plasma Phys. Control. Fusion 62, 115015 (2020)

+
+
Glek2020
+

P. B. Glek, A. A. Voronin, V. Ya. Panchenko and A. M. Zheltikov, +Relativistic electron bunches locked to attosecond optical field waveforms: an attosecond light–matter bound state, +Laser Phys. Lett. 17 055401 (2020)

+
+
Margarone2020
+

D. Margarone, A. Morace, J. Bonvalet et al., +Generation of α-Particle Beams With a Multi-kJ, Peta-Watt Class Laser System, +Front. Phys. 8, 343 (2020)

+
+
Sinha2020
+

U. Sinha and N. Kumar, +Pair-beam propagation in a magnetized plasma for modeling the polarized radiation emission from gamma-ray bursts in laboratory astrophysics experiments, +Phys. Rev. E 101, 063204 (2020)

+
+
Mitrofanov2020
+

A. V. Mitrofanov, D. A. Sidorov-Biryukov, P. B. Glek, M. V. Rozhko, E. A. Stepanov, A. D. Shutov, S. V. Ryabchuk, A. A. Voronin, A. B. Fedotov, and A. M. Zheltikov, +Chirp-controlled high-harmonic and attosecond-pulse generation via coherent-wake plasma emission driven by mid-infrared laser pulses, +Optics Letters 45, 750 (2020)

+
+
Spiers2020
+

B. T. Spiers, M. P. Hill, C. Brown, L. Ceurvorst, N. Ratan, A. F. Savin, P. Allan, E. Floyd, J. Fyrth, L. Hobbs, S. James, J. Luis, M. Ramsay, N. Sircombe, J. Skidmore, R. Aboushelbaya, M. W. Mayr, R. Paddock, R. H. W. Wang and P. A. Norreys, +Whole-beam self-focusing in fusion-relevant plasma, +Phil. Trans. R. Soc. A379, 20200159

+
+
Derouillat2020
+

J. Derouillat and A. Beck, +Single Domain Multiple Decompositions for Particle-in-Cell simulations, +J. Phys.: Conf. Ser. 1596, 012052 (2020) +arXiv:1912.04064

+
+
Zemzemi2020
+

I. Zemzemi, F. Massimo and A. Beck, +Azimuthal decomposition study of a realistic laser profile for efficient modeling of Laser WakeField Acceleration, +J. Phys.: Conf. Ser. 1596, 012055 (2020)

+
+
Massimo2020b
+

F. Massimo, I. Zemzemi, A. Beck, J. Derouillat and A. Specka, +Efficient cylindrical envelope modeling for laser wakefield acceleration, +J. Phys.: Conf. Ser. 1596, 012054 (2020) +arXiv:1912.04674

+
+
Massimo2020a
+

F. Massimo, A. Beck, J. Derouillat, I. Zemzemi and A. Specka, +Numerical modeling of laser tunneling ionization in particle-in-cell codes with a laser envelope model, +Phys. Rev. E 102, 033204 (2020) +arXiv:2006.04433

+
+
Marcowith2020
+

Alexandre Marcowith, Gilles Ferrand, Mickael Grech, Zakaria Meliani, Illya Plotnikov and Rolf Walder, +Multi-scale simulations of particle acceleration in astrophysical systems, +Living Rev Comput Astrophys 6, 1 (2020) +arXiv:2002.09411

+
+
Dargent2020
+

J. Dargent, N. Aunai, B. Lavraud, S. Toledo‐Redondo and F. Califano, +Simulation of Plasmaspheric Plume Impact on Dayside Magnetic Reconnection, +Geophys. Res. Lett. 47, 2019GL086546 (2020) +arXiv:2002.02243

+
+
Sundström2020b
+

A. Sundström, L. Gremillet, E. Siminos and I. Pusztai, +Collisional effects on the electrostatic shock dynamics in thin-foil targets driven by an ultraintense short pulse laser, +Plasma Phys. Control. Fusion 62, 085015 (2020)

+
+
Sundström2020a
+

A. Sundström, L. Gremillet, E. Siminos and I. Pusztai, +Fast collisional electron heating and relaxation in thin foils driven by a circularly polarized ultraintense short-pulse laser, +J. Plasma Phys. 86, 755860201 (2020) +arXiv:1911.09562

+
+
Gelfer2020
+

E. G. Gelfer, A. M. Fedotov, O. Klimo and S. Weber, +Absorption and opacity threshold for a thin foil in a strong circularly polarized laser field, +Phys. Rev. E 101, 033204 (2020) +arXiv:1906.05902

+
+
Ferri2020
+

J. Ferri, I. Thiele, E. Siminos, L. Gremillet, E. Smetanina, A. Dmitriev, G. Cantono, C.-G. Wahlström and T. Fülöp, +Enhancement of laser-driven ion acceleration in non-periodic nanostructured targets, +J. Plasma Phys. 86, 905860101 (2020) +arXiv:1905.11131

+
+
Marques2019
+

J.-R. Marquès, L. Lancia, T. Gangolf, M. Blecher, S. Bolaños, J. Fuchs, O. Willi, F. Amiranoff, R. L. Berger, M. Chiaramello, S. Weber, and C. Riconda, +Joule-Level High-Efficiency Energy Transfer to Subpicosecond Laser Pulses by a Plasma-Based Amplifier, +Phys. Rev. X 9, 021008 (2019)

+
+
Plotnikov2019
+

I. Plotnikov and L. Sironi, +The synchrotron maser emission from relativistic shocks in Fast Radio Bursts: 1D PIC simulations of cold pair plasmas, +Monthly Notices of the Royal Astronomical Society 485, 3816 (2019)

+
+
Dargent2019b
+

J. Dargent, N. Aunai, B. Lavraud, S. Toledo-Redondo and F. Califano, +Signatures of Cold Ions in a Kinetic Simulation of the Reconnecting Magnetopause, +Journal of Geophysical Research: Space Physics, 124, 2497 (2019)

+
+
Dargent2019a
+

J. Dargent, F. Lavorenti, F. Califano, P. Henri, F. Pucci and S. S. Cerri, +Interplay between Kelvin–Helmholtz and lower-hybrid drift instabilities, +Journal of Plasma Physics 85, 805850601

+
+
Geng2019
+

X. S. Geng, L. L. Ji, B. F. Shen et al., +Quantum reflection above the classical radiation-reaction barrier in the quantum electro-dynamics regime, +Commun. Phys. 2, 66 (2019)

+
+
Sinha2019
+

U. Sinha, C. H. Keitel, and N. Kumar, +Polarized Light from the Transportation of a Matter-Antimatter Beam in a Plasma, +Phys. Rev. Lett. 122, 204801 (2019)

+
+
Malko2019
+

S. Malko, X. Vaisseau, F. Perez, D. Batani, A. Curcio, M. Ehret, J. Honrubia, K. Jakubowska, A. Morace, J. J. Santos and L. Volpe, +Enhanced relativistic-electron beam collimation using two consecutive laser pulses, +Sci Rep 9, 14061 (2019)

+
+
Peng2019
+

H. Peng, C. Riconda, M. Grech, J.-Q. Su and S. Weber, +Nonlinear dynamics of laser-generated ion-plasma gratings: A unified description, +Phys. Rev. E 100, 061201 (2019) +arXiv:1911.03440

+
+
Fang2019
+

Jun Fang, Chun-Yan Lu, Jing-Wen Yan and Huan Yu, +Early acceleration of electrons and protons at the nonrelativistic quasiparallel shocks with different obliquity angles, +Res. Astron. Astrophys. 19, 182 (2019) +arXiv:1908.08170

+
+
Yoon2019b
+

Young Dae Yoon and Paul M. Bellan, +Kinetic Verification of the Stochastic Ion Heating Mechanism in Collisionless Magnetic Reconnection, +ApJ 887, L29 (2019)

+
+
Yoon2019a
+

Young Dae Yoon and Paul M. Bellan, +The electron canonical battery effect in magnetic reconnection: Completion of the electron canonical vorticity framework, +Physics of Plasmas 26, 100702 (2019)

+
+
Massimo2019
+

F Massimo, A Beck, J Derouillat, M Grech, M Lobet, F Pérez, I Zemzemi and A Specka, +Efficient start-to-end 3D envelope modeling for two-stage laser wakefield acceleration experiments, +Plasma Phys. Control. Fusion 61, 124001 (2019) +arXiv:1912.04127

+
+
Beck2019
+

A. Beck, J. Derouillat, M. Lobet, A. Farjallah, F. Massimo, I. Zemzemi, F. Perez, T. Vinci and M. Grech, +Adaptive SIMD optimizations in particle-in-cell codes with fine-grain particle sorting, +Computer Physics Communications 244, 246-263 (2019) +arXiv:1810.03949

+
+
Pérez2019
+

F. Pérez and M. Grech, +Oblique-incidence, arbitrary-profile wave injection for electromagnetic simulations, +Phys. Rev. E 99, 033307 (2019) +arXiv:1809.04435

+
+
Thiele2019
+

I. Thiele, E. Siminos and T. Fülöp, +Electron Beam Driven Generation of Frequency-Tunable Isolated Relativistic Subcycle Pulses, +Phys. Rev. Lett. 122, 104803 (2019) +arXiv:1806.04976

+
+
Massimo2018
+

F. Massimo, A. Beck, A. Specka, I. Zemzemi, J. Derouillat, M. Grech and F. Pérez, +Efficient Modeling of Laser Wakefield Acceleration Through the PIC Code Smilei in CILEX Project, +Proc. 13th International Computational Accelerator Physics Conference (ICAP’18), Key West, FL, USA, 20-24 October 2018

+
+
ToledoRedondo2018
+

S. Toledo-Redondo, J. Dargent, N. Aunai, B. Lavraud, M. André, W. Li, B. Giles, P.-A. Lindvist, R. E. Ergun, C. T. Russel and J. L. Burch, +Perpendicular Current Reduction Caused by Cold Ions of Ionospheric Origin in Magnetic Reconnection at the Magnetopause: Particle-in-Cell Simulations and Spacecraft Observations, +Geophys. Res. Lett. 45, 10,033 (2018)

+
+
Gelfer2018
+

E. Gelfer, N. Elkina and A. Fedotov, +Unexpected impact of radiation friction: enhancing production of longitudinal plasma waves, +Sci. Rep. 8, 6478 (2018)

+
+
Niel2018b
+

F Niel, C Riconda, F Amiranoff, M Lobet, J Derouillat, F Pérez, T Vinci and M Grech, +From quantum to classical modeling of radiation reaction: a focus on the radiation spectrum, +Plasma Phys. Control. Fusion 60, 094002 (2018) +arXiv:1802.02927

+
+
Plotnikov2018
+

Illya Plotnikov, Anna Grassi and Mickael Grech, +Perpendicular relativistic shocks in magnetized pair plasma, +Monthly Notices of the Royal Astronomical Society 477, 5238-5260 (2018) +arXiv:1712.02883

+
+
Niel2018a
+

F. Niel, C. Riconda, F. Amiranoff, R. Duclous and M. Grech, +From quantum to classical modeling of radiation reaction: A focus on stochasticity effects, +Phys. Rev. E 97, 043209 (2018) +arXiv:1707.02618

+
+
Grassi2017b
+

A. Grassi, M. Grech, F. Amiranoff, A. Macchi and C. Riconda, +Radiation-pressure-driven ion Weibel instability and collisionless shocks, +Phys. Rev. E 96, 033204 (2017) +arXiv:1705.05402

+
+
Fedeli2017
+

L Fedeli, A Formenti, L Cialfi, A Sgattoni, G Cantono and M Passoni, +Structured targets for advanced laser-driven sources, +Plasma Phys. Control. Fusion 60, 014013 (2017)

+
+
Golovanov2017
+

A. A. Golovanov, I. Yu. Kostyukov, J. Thomas and A. Pukhov, +Analytic model for electromagnetic fields in the bubble regime of plasma wakefield in non-uniform plasmas, +Physics of Plasmas 24, 103104 (2017)

+
+
Dargent2017
+

J. Dargent, N. Aunai, B. Lavraud, S. Toledo-Redondo, M. A. Shay, P. A. Cassak and K. Malakit, +Kinetic simulation of asymmetric magnetic reconnection with cold ions, +J. Geophys. Res. Space Physics 122, 5290-5306 (2017)

+
+
Grassi2017a
+

A. Grassi, M. Grech, F. Amiranoff, F. Pegoraro, A. Macchi and C. Riconda, +Electron Weibel instability in relativistic counterstreaming plasmas with flow-aligned external magnetic fields, +Phys. Rev. E 95, 023203 (2017)

+
+
Dargent2016
+

J. Dargent, N. Aunai, G. Belmont, N. Dorville, B. Lavraud and M. Hesse, +Full particle-in-cell simulations of kinetic equilibria and the role of the initial current sheet on steady asymmetric magnetic reconnection, +J. Plasma Phys. 82, 905820305 (2016)

+
+
Chiaramello2016
+

M. Chiaramello, C. Riconda, F. Amiranoff, J. Fuchs, M. Grech, L. Lancia, J.-R. Marquès, T. Vinci and S. Weber, +Optimization of interaction conditions for efficient short laser pulse amplification by stimulated Brillouin scattering in the strongly coupled regime, +Physics of Plasmas 23, 072103 (2016)

+
+
Beck2016
+

A. Beck, J.T. Frederiksen and J. Dérouillat, +Load management strategy for Particle-In-Cell simulations in high energy particle acceleration, +Nucl. Inst. Meth. in Phys. Res. A 829, 418-421 (2016)

+
+
Lancia2016
+

L. Lancia, A. Giribono, L. Vassura, M. Chiaramello, C. Riconda, S. Weber, A. Castan, A. Chatelain, A. Frank, T. Gangolf, M. N. Quinn, J. Fuchs and J.-R. Marquès, +Signatures of the Self-Similar Regime of Strongly Coupled Stimulated Brillouin Scattering for Efficient Short Laser Pulse Amplification, +Phys. Rev. Lett. 116, 075001 (2016)

+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Overview/partners.html b/Overview/partners.html new file mode 100644 index 000000000..3a9e3f665 --- /dev/null +++ b/Overview/partners.html @@ -0,0 +1,759 @@ + + + + + + + + + Partners — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Partners

+ ++++ + + + + + + + +

mdls

Maison de la Simulation (MdlS), USR 3441

+
+ ++++ + + + + + + + +

luli

Laboratoire pour l’Utilisation des Lasers Intenses (LULI), UMR 7605

+
+ ++++ + + + + + + + +

llr

Laboratoire Leprince-Ringuet (LLR), UMR 7638

+
+ ++++ + + + + + + + +

lpgp

Laboratoire de Physique des Gaz et des Plasmas (LPGP), UMR 8578

+
+ ++++ + + + + + + + +

idris

Institut du developpement et des ressources en informatique scientifique (IDRIS), UPS 851

+
+ ++++ + + + + + + + +

lpp

Laboratoire de Physique des Plasmas (LPP), UMR 7648

+
+ ++++ + + + + + + + +

IRAMIS

Institut Rayonnement Matière de Saclay (Iramis)

+ ++++ + + + + + + + +

IRAP

Institut de Recherche en Astrophysique et Planétologie (IRAP)

+
+ ++++ + + + + + + + +

intel

Intel

+
+ ++++ + + + + + + + +

IAPRAS

Institute of Applied Physics, Russian Academy of Science

+
+ ++++ + + + + + + + +

GOTHB

University of Gothenburg

+
+
+ +
+
+

Acknowledgments

+

Financial support from the Laboratoires d’Excellence:

+ ++++ + + + + + +

plasapar

+
Plas@Par provided grants for 2 PhD thesis.
+
and 1 post-doc.
+
+
+ ++++ + + + + + +

palm

+
Smilei was initiated thanks to the SimPLE junior chair
+
granted by the labex PALM.
+
+
+ ++++ + + + + + +

P2IO

+
Francesco Massimo’s 2 years post-doc was funded by the
+
labex P2IO.
+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Overview/releases.html b/Overview/releases.html new file mode 100644 index 000000000..cfdd8ea91 --- /dev/null +++ b/Overview/releases.html @@ -0,0 +1,1006 @@ + + + + + + + + + Releases — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Releases

+
+

Get Smilei

+

Clone the latest version of Smilei from GitHub:

+
git clone https://github.com/SmileiPIC/Smilei.git
+
+
+

Learn about Git here.

+

You can find older, unsupported versions here

+
+
+
+

Changes made in the repository (not released)

+

+
+
+
+

Projects

+
    +
  • Already available, but experimental:

    +
      +
    • Particle merging

    • +
    • Nuclear reactions

    • +
    • Perfectly Matched Layers

    • +
    • NewParticles diagnostic

    • +
    +
  • +
  • In preparation:

    +
      +
    • Spectral solvers

    • +
    +
  • +
+
+
+
+

Release 5.0

+
    +
  • GPU support (not all features are supported at the moment)

    +
      +
    • Both AMD and Nvidia GPUs

    • +
    • Cartesian geometry in 2D and in 3D

    • +
    • Moving Window

    • +
    • Diagnostics: Field, Probes, Scalar, ParticleBinning, TrackParticles

    • +
    +
  • +
+
+
+
+

Release 4.8

+
    +
  • LaserEnvelope model:

    +
      +
    • Now compatible with PML boundaries

    • +
    • In AMcylindrical geometry, the number of modes can be greater than 1 (only affects electromagnetic +fields and the densities, not envelope or susceptibility)

    • +
    • multi-level tunnel ionization creates multiple electrons, improving the sampling

    • +
    +
  • +
  • Diagnostics

    +
      +
    • Much faster DiagFields (speedup ~ x3)

    • +
    • DiagFields and DiagProbe: new parameter datatype

    • +
    • DiagPerformances: new parameter cumulative

    • +
    +
  • +
  • Collisions: new parameter time_frozen

  • +
  • Species: in AMcylindrical geometry, the initial drift velocity profiles may be defined +either in the x,r,θ directions with mean_velocity_AM or in the x,y,z directions with mean_velocity.

  • +
  • Lasers: changed the delay and phase of gaussian lasers at high incidence to make them consistent between boundaries.

  • +
  • Happi:

    +
      +
    • Operations in Fields, Probe, and ParticleBinning may now accept physical constants, units, +or basic functions such as exp() or sin()

    • +
    • Probe has a new method changeField

    • +
    • Open has a new argument pint to disable the Pint package

    • +
    • multiPlot and multiSlide have a new argument legend_font

    • +
    • The title can be formatted with a placeholder for the current time in an animation

    • +
    • Various performance improvements

    • +
    +
  • +
  • Friedman filter: now available in geometries 1Dcartesian and AMcylindrical (previously available only in 2Dcartesian)

  • +
  • Lehe solver for Maxwell equations now available in AMcylindrical geometry

  • +
  • Bugfixes:

    +
      +
    • Compilation fixed for the newest version of GNU make

    • +
    • Poisson Solver correction was not properly accounted for with SDMD

    • +
    • Bug correction using Monte-Carlo radiation and multiphoton Breit-Wheeler processes with checkpoints

    • +
    • C++11 compilation issue

    • +
    • Reading particle weights and momenta from hdf5 file

    • +
    • PML are now compatible with dynamic load balancing.

    • +
    • solved segfault with Multiphoton Breit-Wheeler process in AMcylindrical geometry

    • +
    • Collisional ionization incorrect for \(Z^\star = Z-1\)

    • +
    • Field.getAxis was not accounting for the timestep

    • +
    • Bug correction in 1D relativistic Poisson solver

    • +
    +
  • +
  • Experimental

    +
      +
    • B-TIS3 interpolation scheme to reduce the effects of numerical Cherenkov radiation is implemented up to interpolation order 2

    • +
    • New diagnostic: DiagNewParticles records particle information when they are created by ionization or other mechanisms

    • +
    +
  • +
+
    +
  • For developers: new table management for Monte-Carlo physical processes (transparent to users)

  • +
+
+
+
+

Release 4.7

+
    +
  • Perfectly Matched Layers boundary conditions for EM fields (+2D Cartesian benchmark).

  • +
  • Improved performance for ARM-based processors including the Fujitsu A64FX

  • +
  • Improved performance for GNU, LLVM, arm-clang and Fujitsu compilers on all types of architectures

  • +
  • Lasers can be injected from all boundaries

  • +
  • Flag ponderomotive_dynamics removed from Species block. All Species interact with LaserEnvelope if present

  • +
  • Option to create neutrons for D-D fusion

  • +
  • Collisions can be done less often

  • +
  • Lasers can be injected from all boundaries

  • +
  • New 4th-order non-standard FDTD solver M4

  • +
  • Timestep dependent field interpolation scheme

  • +
  • LaserOffset:

    +
      +
    • may be re-used from a previous simulation

    • +
    • available from ymin, ymax, zmin and zmax

    • +
    • has new arguments fft_time_window and fft_time_step

    • +
    +
  • +
  • Diagnostics:

    +
      +
    • Probes can include components of the Poynting vector PoyX, PoyY, PoyZ

    • +
    • Probes can be time-integrated

    • +
    • ParticleBinning diagnostics may accept "auto" as axis limits

    • +
    • Particle IDs may be modified in the DiagTrackParticles.filter (8 available bits)

    • +
    • Screens may have a cylinder shape

    • +
    • Scalar diagnostics for AM geometry now available

    • +
    • happi ParticleBinning now uses the keyword average instead of sum

    • +
    +
  • +
  • Bugfixes:

    +
      +
    • Poynting scalars behaviour with several patches, or with checkpoints

    • +
    • Densities too low are put to 0 to avoid underflow

    • +
    • Prescribed fields in 2D

    • +
    • ellipticity = -1. was doing +1.

    • +
    • Setting units in happi’s TrackParticles was wrong (for plotting only)

    • +
    • Current communication correction for FIR filters

    • +
    • Fix for particle merging segmentation fault in spherical and Cartesian modes

    • +
    • Tracked particles with the vectorized mode

    • +
    • momentum_initialization from a file did not take the proper file

    • +
    +
  • +
+
+
+
+

Release 4.6

+
    +
  • Single-domain multiple decompositions

  • +
  • New 4th-order non-standard FDTD solver Bouchard for 2D and 3D geometries

  • +
  • New method for current filtering with a user-provided FIR kernel for 1D, 2D and 3D geometries

  • +
  • Diagnostics may now have a name (useful during post-processing)

  • +
  • Laser Envelope:

    +
      +
    • linear and circular polarization

    • +
    • ionization model

    • +
    • normalized laser frequency can be different from 1

    • +
    +
  • +
  • Particles can be imported from a file

  • +
  • Some Profiles can be imported from a file

  • +
  • Coulomb logarithm may be multiplied by a constant factor

  • +
  • Happi:

    +
      +
    • handles fonts

    • +
    • time slider available with multiple plotting

    • +
    • vsym option for symmetric graph

    • +
    • getXmoved now accounts for requested units

    • +
    • Tracked particles can be selected before sorting

    • +
    +
  • +
  • Bugfixes:

    +
      +
    • Fix in the vectorized projection at order 4

    • +
    • Photons could not be read from numpy array

    • +
    • DiagFields with time_average did not work for densities

    • +
    • Prescribed fields caused unstable real fields

    • +
    • Initialisation from numpy or hdf5 caused wrong weights in AM geometry

    • +
    • Better positionning of collisionally-ionised electrons

    • +
    • Fix segfault from thermalizing boundary

    • +
    • Running a simulation displayed the wrong version v4.4

    • +
    +
  • +
+
+
+
+

Release 4.5

+
    +
  • Changes:

    +
      +
    • Current filtering with adjustable number of passes per dimension

    • +
    • Improved axial boundary conditions for AMcylindrical geometry

    • +
    • Units in RadiationSpectrum diagnostic are more consistent with that +of ParticleBinning

    • +
    • Ionisation current at fourth order of interpolation

    • +
    • Correction for Binary collisions & reactions as suggested in [Higginson2020]

    • +
    +
  • +
  • Bugfixes:

    +
      +
    • PrescribedField was sometimes not applied by some OpenMP threads

    • +
    • Scalar Ukin_bnd was sometimes wrong with load balancing

    • +
    • Scalar Urad was sometimes wrong with moving window

    • +
    • On some systems, particles IDs were incorrect with ionization

    • +
    +
  • +
+
+
+
+

Release 4.4

+
    +
  • Changed radiation tables: see the doc.

    +
      +
    • Old tables are not valid anymore, input files must be updated.

    • +
    • Default tables are now embebded in the code

    • +
    • Possibility to read external generated by an external tool (more efficient and stable)

    • +
    +
  • +
  • New RadiationSpectrum diagnostics available (see the doc)

  • +
  • AMcylindrical: sorting, documentation, subgrid in DiagFields, +species-related currents and density in probes (not per mode anymore)

  • +
  • LaserOffset is not recomputed after restart

  • +
  • Prescribed fields that only contribute to pushing particles

  • +
  • Laser Envelope: added envelope equation solver with reduced numerical dispersion

  • +
  • Bugfixes:

    +
      +
    • Weight-initialization bug in AM geometry when a species was initialized +on top of a regularly-initialized species

    • +
    • LaserOffset was off sideways and temporally by a couple of cells

    • +
    • Do not project twice a frozen species

    • +
    • Probes for species faulty when 4th order of interpolation

    • +
    • Checkpoints restart_number=0 was not used

    • +
    • Checkpointing with dump_minutes could be out of sync between MPI process

    • +
    • Prevent deadlock when restart files are corrupted

    • +
    • Checkpoints file_grouping had typo with python3

    • +
    • Scalar Ukin for ions was incorrect, thus Ubal was also wrong

    • +
    • happi had incorrect unit conversion with a sum of two fields

    • +
    • fix error occurring when envelope Probes on axis are used in AM geometry

    • +
    +
  • +
+
+
+
+

Release 4.3

+
    +
  • AMcylindrical : envelope, ionization, additional diagnotics, +number of ppc per direction, binomial current filter, poisson solver, +non-separable laser initialization per mode, improved diag field nomenclature

  • +
  • Particle injector

  • +
  • More control over the moving window movement

  • +
  • More control over the regular position initialization in Cartesian geometries

  • +
  • Bugfixes:

    +
      +
    • ionization of frozen species

    • +
    • particle binning was not following the moving window

    • +
    • gaussian profile with order 0 was incorrect

    • +
    • tracked particles post-processing was incorrect above 20M particles

    • +
    • better management of particle binning in collisions

    • +
    • Intel 19 optimizations

    • +
    +
  • +
+
+
+
+

Release 4.2

+
    +
  • AMcylindrical geometry with azimuthal Fourier decomposition (beta version)

  • +
  • Different convention for circular polarization amplitude

  • +
  • 1D and 2D laser envelope model

  • +
  • Compatibility between various ionization and QED models

  • +
  • Bugfixes:

    +
      +
    • Binomial filter in Cartesian 3D parallel implementation

    • +
    • Various crashes linked to vectorization

    • +
    • LaserGaussian2D when focused far from boundary

    • +
    • Laser a0 normalization to omega

    • +
    • Frozen particles are now properly ionized

    • +
    • Position initialization over another species with moving window

    • +
    • Tracked particles output was missing the mass factor for momenta

    • +
    • Breit-Wheeler pair production with fine grain sorted particles

    • +
    +
  • +
+
+
+
+

Release 4.1

+
    +
  • Probe diagnostics of currents and density per species

  • +
  • Field diagnostics with more than 2^32 points

  • +
  • Bugfixes:

    +
      +
    • collisions (badly affected by vectorization)

    • +
    • adaptive vectorization with dynamic load balancing

    • +
    • memory leak in the laser envelope model

    • +
    +
  • +
  • Disable usage of -ipo to compile on supercomputers +despite of saving time simulation

    +
      +
    • it needs too many resources (time and memory) to link

    • +
    • it is recommended to do some tests on a new supercomputer +without and then to re-establish it

    • +
    +
  • +
+
+

Warning

+

Since version 4.1, the definition of macro-particle weights +has changed to ensure they do not depend on the cell volume. This impacts +only the users working directly with values of weights. Other simulation +results should be unchanged.

+
+
+
+
+

Release 4.0

+
    +
  • Vectorization

  • +
  • Laser envelope model

  • +
  • MPI option MPI_THREAD_MULTIPLE is now optional (but recommended)

  • +
  • Faster collisions

  • +
  • Bugfixes: handling sum for happi’s ParticleBinning

  • +
+
+
+
+

Release 3.5

+ +
+
+
+

Release 3.4.1

+
    +
  • Ionization considering a user-defined rate

  • +
+
+
+
+

Release 3.4

+
    +
  • Compatibility with Python 3

  • +
  • New ‘Performances’ diagnostic

  • +
  • Tracked particles may output the fields at their location

  • +
  • ‘subgrid’ option in Fields diagnostics

  • +
  • Printout of the expected disk usage

  • +
  • Laser propagation pre-processing

  • +
  • More flexible domain decomposition

  • +
  • Relativistic initialization

  • +
  • Particles injection using Numpy arrays

  • +
  • Possibility to use user-defined ionization rates

  • +
  • Bugfixes: circular polarization, collisional ionization

  • +
+
+
+
+

Release 3.3

+
    +
  • Major syntax changes in the namelist

  • +
  • QED radiation reaction

  • +
  • Monte-Carlo QED photon emission

  • +
  • Test mode to quickly check the namelist consistency

  • +
  • ParticleBinning and Screen diagnostics accept a python function as their +deposited_quantity and axis.

  • +
  • Bugfixes: 4th order, field ionization

  • +
+
+
+
+

Release 3.2

+
    +
  • New pushers (Vay’s and Higuera-Cary’s)

  • +
  • Numpy used for filtering track particles

  • +
  • Fourth order in 3D

  • +
  • Add some missing 3D features: external fields management, boundary conditions +and non-neutral plasma initialization

  • +
  • OpenMP support in moving window

  • +
  • Tracked particles post-processing improved for large files

  • +
  • Bugfixes: energy computation in 3D or with moving window, random number seed

  • +
+
+
+
+

Release 3.1

+
    +
  • Screen diagnostics

  • +
  • Exporting 3D diagnostics to VTK for reading in ParaView or VisIt

  • +
  • Partial support of the OpenPMD standard

  • +
  • Improvements: moving window (OpenMP), 3D projection

  • +
  • Bugfixes: tracked particles, walls, collisional ionization, etc.

  • +
+

Notes:

+
    +
  • Outputs of Fields and Tracks are incompatible with 3.0

  • +
  • The input “output_dir” is not supported anymore

  • +
+
+
+
+

Release 3.0

+
    +
  • 3D geometry

  • +
  • Field and scalar diagnostics improved for more flexibility and memory saving

  • +
  • Faster initialization (including Maxwell-Jüttner sampling)

  • +
  • Post-processing handles restarts

  • +
  • Bugfixes in checkpoints, timers, memory profile

  • +
+
+
+
+

Release 2.3

+
    +
  • Post-processing scripts have been turned into a python module

  • +
  • Many bugfixes, such as addressing diagnostics efficiency

  • +
+
+
+
+

Release 2.2

+
    +
  • state-of-the-art dynamic load balancing

  • +
  • full python namelist, allowing for complex, user-friendly input

  • +
  • external fields and antennas

  • +
  • binary Coulomb collisions

  • +
  • new diagnostics

  • +
  • python scripts for post-processing

  • +
+
+
+
+

Release 1.0

+
    +
  • 1D & 2D cartesian geometries

  • +
  • Moving window

  • +
  • Hybrid MPI-OpenMP parallelization

  • +
  • Field ionization

  • +
  • Some python diagnostics

  • +
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Overview/synopsis.html b/Overview/synopsis.html new file mode 100644 index 000000000..d6ad7db7a --- /dev/null +++ b/Overview/synopsis.html @@ -0,0 +1,536 @@ + + + + + + + + + Synopsis — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Synopsis

+

Smilei is a collaborative project providing physicists with an open-source, +user-friendly, high-performance and multi-purpose +electromagnetic Particle-In-Cell (PIC) code for plasma simulation.

+

The code is developed in C++ based on an object-oriented architecture. +To face the diverse needs of the Smilei community, it offers modularity:

+
    +
  • various geometries (Cartesian 1D, 2D, 3D or cylindrical with decomposition into azimuthal modes),

  • +
  • arbitrary laser or plasma profiles (any Python function),

  • +
  • various Maxwell solvers, particle pushers, interpolators, projectors

  • +
  • an envelope solver, including in the cylindrical geometry

  • +
  • advanced boundary conditions (e.g. Perfectly-Matched Layers)

  • +
  • etc.

  • +
+

The user-friendly interface consists in input files written in the Python language, +and a whole set of run-time diagnostics (outputs in HDF5) and user-friendly (Python) +post-processing tools complement the code.

+

Co-developed by HPC specialists and physicists, Smilei is designed for high performances +on massively-parallel super-computers. It benefits from a state-of-the-art hybrid +MPI/OpenMP parallelization, dynamic load balancing and SIMD vectorization. +It has been successfully tested on various architectures, among which the most recent +Intel Cascadelake (CSL) & Fujitsu A64FX (ARM).

+

Recently, GPU acceleration has been implemented in SMILEI and allows offloading on Nvidia or AMD GPUs, such as V100, A100 or MI250. +As of yet, not all features are supported.

+

In Smilei, Maxwell’s equations are solved using a Yee mesh, where the +electric and magnetic fields are centered following the finite-difference time-domain (FDTD) +method or related methods. A pseudo-spectral analytical time domain method is +also available as an experimental feature. +Charge deposition follows a charge-conservation scheme.

+

As a multi-purpose code, Smilei is applied to a wide range of physics-related studies: +from relativistic laser-plasma interaction to astrophysics. Smilei thus benefits from +various additional physics modules, among which field ionization, +binary collisions and impact ionization. QED processes, such as +high-energy photon emission and its back-reaction +on the electron dynamics, as well as +pair production through the Breit-Wheeler +process, are also included.

+

An initial detailed account (as of 2018) of Smilei’s capabilities is given in +this article. +For publications on more advanced features, please refer to the Publications section of this documentation.

+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/GPU_offloading.html b/Understand/GPU_offloading.html new file mode 100644 index 000000000..03497d07b --- /dev/null +++ b/Understand/GPU_offloading.html @@ -0,0 +1,516 @@ + + + + + + + + + GPU offloading — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

GPU offloading

+

To support recent supercomputers, Smilei has been ported on GPU (graphical processing units). +Initially built to handle complex graphical output and related to rendering and video games, +GPUs appeared only relatively recently in the HPC ecosystem. +Unlike CPUs, GPUs can do much smaller sets of tasks with massive data throughput.

+

Currently 7 of the 10 most powerful supercomputers are based on GPU acceleration and +the trend seems confirmed at least in the near future: +the announced exaflopic supercomputers will include GPUs.

+
    +
  • Guideline: in general it is recommended to use one patch per GPU +to obtain the best performance. However, for better memory management, +testing a few patches per GPU is encouraged.

  • +
  • Currently supported features:

    +
      +
    • Both AMD’s GPUs and Nvidia’s GPUs are supported

    • +
    • Cartesian geometry in 2D and in 3D

    • +
    • Diagnostics: Field, Probes, Scalar, ParticleBinning, TrackParticles

    • +
    • Moving Window.

    • +
    +
  • +
  • A few key features remain to be implemented (AM geometry, ionization, PML, envelope, +additional physics), but the fundamentals of the code are ported.

  • +
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/PML.html b/Understand/PML.html new file mode 100644 index 000000000..05c1f31c1 --- /dev/null +++ b/Understand/PML.html @@ -0,0 +1,561 @@ + + + + + + + + + Perfectly Matched Layers — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ + + + +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Perfectly Matched Layers

+

Perfectly Matched Layers (PML) are open boundary conditions for electromagnetic and laser envelope fields. +This means that a wave propagating through the boundary will be absorbed and not reintroduced into the simulation. +In that regard, it plays the same role as the “Silver-Muller” boundary conditions which is supported for electromagnetic fields only (not envelope).

+

At the cost of having a slightly higher computing cost than Silver-Muller, PML have several very interesting advantages:

+
    +
  • All resolved frequencies are equally absorbed.

  • +
  • Absorption is efficient for any incident angle.

  • +
  • The overall absorption of exiting waves is, in most cases, much better than Silver-Muller.

  • +
+

This leads to a more accurate result of course but can also relaxes constraints on the size of the simulation domain. +Very large transverse sizes to let the laser diffract more before it hits the boundary is no longer necessary for instance.

+

Basic use

+

A PML is in fact several layers of absorbing media which are contiguous to the simulation domain and through which exiting waves are going. +The waves are progressively absorbed as they travel across this absorbing media. +The thickness of this media can be tuned with the parameter number_of_pml_cells and is in fact equal to

+
+(70)\[PML_{\rm thickness} = {\rm number\_of\_pml\_cells[0]}\times {\rm dx},\]
+

in the x direction.

+

Keep in mind that the absorbing power of a PML increases with its physical thickness.

+

This means that the more layers are set, the more absorbing the PML is. +But adding layers also increases computing time of course because it is similar to increasing the simulation domain size.

+

It also means that the absorption of the PML depends on the resolution dx. +Higher resolution simulations will need more cells in order to keep the same thickness and therefore the same absorption as a less resolved one.

+

The default number of pml cells is 6.

+

Rules of thumb for a good use of the PML

+

First of all, it is important to realize that open boundary conditions are only good at letting waves out of the domain. +It does not relax any constraint on the quality of the initial conditions and will not prevent reflections if these are physical.

+

The typical case is a vacuum/plasma interface at the boundary of the simulation box when a remove boundary condition is chosen for particles. +In that configuration, if the plasma density is high enough at the interface, there can be perfectly physical reflections that PML are not designed to mitigate. +We therefore advise to use plasma profiles whith decreasing densities close to the boundaries.

+

Advanced settings for Cartesian Geometry

+

In the PML medium, the complex susceptibility is given by

+
+(71)\[s = \kappa + \frac{\sigma}{i\omega\epsilon_0},\]
+

where \(\kappa\) and \(\sigma\) can be chosen by the user. +They are functions of a single space variable which describes the normal position in the PML. +This variable ranges from 0 (the inner bound of the PML) to 1, the outer bound of the PML.

+

One profile per simulation dimension is required and the same profile is applied to both sides of a given dimension.

+

Expert settings for AM geometry

+

In the specific case of the AM geometry, using arbitrary susceptibility profiles is trickier because an integration along the radial direction is necessary. +Therefore it is important that Smilei knows not only the profiles of sigma and kappa but also a primitive of these profiles along the radial dimension.

+

It is up to the user to provide such primitives in the namelist using the following syntax (here is an example for sigma):

+
+
+
Syntax 1: [sigma, integrate_sigma], identical for all dimensions.
+
Syntax 2: [sigma_x, sigma_r, integrate_sigma_r], different on each dimension.
+
+
+

The default profiles identical for all dimensions and are given by:

+
def sigma(u):
+    return 20. * u**2
+def integrate_sigma(u):
+    return 20./3. * u**3
+def kappa(u):
+    return 1 + 79. * u**4
+def integrate_kappa(u):
+    return u + 79./5. * u**5
+
+
+

PML for the envelope model

+

For stability purposes, the PML boundaries for the envelope use frequency shifting which prevents from using arbitrary profiles for the susceptibility. +Therefore it is not possible to tune its profile.

+

Details of the method will be published soon.

+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/SDMD.html b/Understand/SDMD.html new file mode 100644 index 000000000..82ebf966d --- /dev/null +++ b/Understand/SDMD.html @@ -0,0 +1,522 @@ + + + + + + + + + Single-domain multiple decompositions — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Single-domain multiple decompositions

+

The standard decomposition of the simulated domain consists in splitting +the grid in rectangular “patches” that contain both fields and particles +(see Parallelization basics). A new technique has been developed for Smilei, +“Single-Domain Multiple Decompositions” (SDMD), where two decompositions are +made:

+
    +
  • Particles are still contained in the same small, rectangular patches.

  • +
  • Fields are contained in large, rectangular “regions”.

  • +
+

Each MPI process owns many patches but only (and exactly) one region. +A single region extent therefore covers the equivalent of many patches allowing +communication-less operations over a larger area.

+

Fields are simply communicated from regions to patches in order to interpolate their +values at the particles locations. Inversely, currents and densities are communicated +from patches to regions in order to solve Maxwell’s equations.

+

The region extents are always Cartesian and their size is as homogeneous as possible. +The association between MPI processes and regions is dynamically reconsidered +during the simulation if dynamic load balancing is used. +The goal is to maximize the overlap between the region and the collection of +patches owned by the MPI process at all times in order to reduce communication overhead.

+

Advantages

+
    +
  • The synchronization overhead induced by the use of very small patches is reduced.

  • +
  • Operations requiring many ghost cells (like large-stencil filters or spectral solvers) +can be executed much more efficiently.

  • +
+

The benefits of SDMD are illustrated +in this paper.

+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/algorithms.html b/Understand/algorithms.html new file mode 100644 index 000000000..dc73271b6 --- /dev/null +++ b/Understand/algorithms.html @@ -0,0 +1,878 @@ + + + + + + + + + PIC algorithms — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ + + + +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

PIC algorithms

+

This document describes the theoretical basis with which Smilei simulates +the behaviour of plasmas. Note that all quantities are expressed in terms of the +reference units.

+
+
+

The Maxwell-Vlasov model

+

The kinetic description of a collisionless plasma relies on the so-called Vlasov-Maxwell +system of equations. In this description, the different species of particles constituting +the plasma are described by their respective distribution functions +\(f_s(t,\mathbf{x},\mathbf{p})\), where \(s\) denotes a given species consisting +of particles of charge \(q_s\), mass \(m_s\), and \(\mathbf{x}\) and +\(\mathbf{p}\) denote the position and momentum of a phase-space element. +The distribution \(f_s\) satisfies Vlasov’s equation:

+
+(1)\[\left(\partial_t + \frac{\mathbf{p}}{m_s \gamma} \cdot \nabla + \mathbf{F}_L \cdot \nabla_{\mathbf{p}} \right) f_s = 0\,,\]
+

where \(\gamma = \sqrt{1+\mathbf{p}^2/m_s^2}\) is the (relativistic) Lorentz factor,

+
+(2)\[\mathbf{F}_L = q_s\,(\mathbf{E} + \mathbf{v} \times \mathbf{B})\]
+

is the Lorentz force acting on the particles. +This force follows from the existence, in the plasma, of collective (macroscopic) +electric [\(\mathbf{E}(t,\mathbf{x})\)] and magnetic [\(\mathbf{B}(t,\mathbf{x})\)] +fields satisfying Maxwell’s equations:

+
+(3)\[\begin{split}\begin{eqnarray} +\nabla \cdot \mathbf{B} &=& 0 \,,\\ +\nabla \cdot \mathbf{E} &=& \rho \,,\\ +\nabla \times \mathbf{B} &=& \mathbf{J} + \partial_t \mathbf{E} \,,\\ +\nabla \times \mathbf{E} &=& -\partial_t \mathbf{B} \,. +\end{eqnarray}\end{split}\]
+

The Vlasov-Maxwell system of equations (1)(3) describes the +self-consistent dynamics of the plasma which consistuents are subject to the Lorentz force, +and in turn modify the collective electric and magnetic fields through their charge and +current densities:

+
+(4)\[\begin{split}\begin{eqnarray} +\rho(t,\mathbf{x}) &=& \sum_s q_s\int\!d^3\!p f_s(t,\mathbf{x},\mathbf{p})\,,\\ +\mathbf{J}(t,\mathbf{x}) &=& \sum_s q_s\int\! d^3\!p\,\mathbf{v} f_s(t,\mathbf{x},\mathbf{p})\,, +\end{eqnarray}\end{split}\]
+

where we have introduced the velocity \(\mathbf{v} = \mathbf{p}/(m_s\,\gamma)\).

+
+
+
+

Quasi-particles

+

The Particle-In-Cell method owes its name to the discretization of the distribution +function \(f_s\) as a sum of \(N_s\) quasi-particles (also referred to as +super-particles or macro-particles):

+
+(5)\[f_s(t,\mathbf{x},\mathbf{p}) = + \sum_{p=1}^{N_s}\,\frac{w_p}{V_c}\,\,S\big(\mathbf{x}-\mathbf{x}_p(t)\big)\,\delta\big(\mathbf{p}-\mathbf{p}_p(t)\big)\,,\]
+

where \(w_p\) is a quasi-particle weight, \(\mathbf{x}_p\) is its position, +\(\mathbf{p}_p\) is its momentum, \(V_c\) is the hypervolume of the cell, +\(S\) is the shape-function of all quasi-particles, +and \(\delta\) is the Dirac distribution.

+

In PIC codes, Vlasov’s equation (1) is integrated along the continuous trajectories +of these quasi-particles, while Maxwell’s equations (3) are solved on a +discrete spatial grid, the spaces between consecutive grid points being referred to as +cells. Injecting the discrete distribution function of +Eq. (5) in Vlasov’s equation (1), multiplying the result by +\(\mathbf{p}\) and integrating over all \(\mathbf{p}\) and over the volume of +the quasi-particles, leads to the relativistic equations of motion of individual +quasi-particles:

+
+\[\begin{split}\begin{eqnarray} +\frac{d\mathbf{x}_p}{dt} &=& \frac{\mathbf{u}_p}{\gamma_p}\,\\ +\frac{d\mathbf{u}_p}{dt} &=& r_s \, \left( \mathbf{E}_p + \frac{\mathbf{u}_p}{\gamma_p} \times \mathbf{B}_p \right), +\end{eqnarray}\end{split}\]
+

where \(r_s = q_s/m_s\) is the charge-over-mass ratio (for species \(s\)), +\(\mathbf{u}_p = \mathbf{p}_p/m_s\) is the reduced momentum and +\(\gamma_p=\sqrt{1+\mathbf{u}_p^2}\) is the Lorentz factor.

+
+
+
+

Time and space discretization

+

Maxwell’s equations are solved here using +the Finite Difference Time Domain (FDTD) approach +as well as refined methods based on this algorithm. +In these methods, the electromagnetic +fields are discretized onto a staggered grid, the so-called Yee-grid that allows for +spatial-centering of the discretized curl operators in Maxwell’s equations. +The following figure summarizes at which points of the Yee-grid are defined the +electromagnetic fields as well as charge and density currents.

+../_images/figYee.png +

Similarly, the time-centering +of the time-derivative in Maxwell’s equations is ensured by considering the electric fields +as defined at integer time-steps \((n)\) and magnetic fields at half-integer +time-steps \((n+\tfrac{1}{2})\). Time-centering of the magnetic fields is however +necessary for diagnostic purposes, and most importantly when computing the Lorentz force +acting on the quasi-particles.

+

A leap-frog scheme is used to advance the particles in time, so that the particle positions +and velocities are defined at integer \((n)\) and half-integer \((n-\tfrac{1}{2})\) +time-steps, respectively.

+
+
+
+

Initialization of the simulation

+

The initialization of a PIC simulation is a three-step process consisting in

+
    +
  1. loading particles,

  2. +
  3. computing the initial total charge and current densities on the grid,

  4. +
  5. computing the initial electric and magnetic field at the grid points.

  6. +
+

In Smilei, all three steps can be done either as a restart of a previous simulation +(in which case the particles, charge and current densities and electromagnetic fields are +directly copied from a file generated at the end of a previous simulation), or from a +user-defined input file. In that case, the user defines the initial conditions of the +particle, charge and current densities as well as the initial electromagnetic fields +over the whole simulation domain.

+

In particular, the number density \(n_s(\mathbf{x})\), mean velocity +\(\mathbf{v}_s(\mathbf{x})\) and temperature \(T_s(\mathbf{x})\) of all species +\(s\) in a given cell (located at position \(\mathbf{x}\)) at time \(t=0\) +have to be prescribed. The particle loading then consists in creating, in each cell, +\(N_s\) particles with positions \(\mathbf{x}_p\) (either randomly chosen or +regularly spaced) such that particles are uniformly distributed within the cell, +and momentum \(\mathbf{p}_p\) randomly chosen such that the particle distribution +follows a Maxwell-Jüttner distribution with mean-velocity \(\mathbf{v}_s(\mathbf{x})\) +and temperature \(T_s(\mathbf{x})\).

+

In Smilei, a weight is assigned to each particle depending on the density associated +to the cell it originates from:

+
+\[w_p = \frac{n_s\big(\mathbf{x}_p(t=0)\big)}{N_s} V_c\,.\]
+

This variable weighting is particularly beneficial when considering initially +highly-inhomogeneous density distributions.

+

Once all particles in the simulation domain have been created, the total charge and +current densities \(\rho(t=0,\mathbf{x})\) and \(\mathbf{J}(t=0,\mathbf{x})\) +are computed on the grid using a simple projection technique:

+
+\[\rho(t=0,\mathbf{x}) = \sum_s\,\sum_p\,W_p\,S\big(\mathbf{x}-\mathbf{x}_p(t=0)\big)\,,\]
+

where \(W_p = q_s w_p / V_c\).

+

Then, the initial electric fields are computed from \(\rho(t=0,\mathbf{x})\) +by solving Poisson’s equation. In Smilei, this is done using the conjugate gradient +method. This iterative method is particularly interesting +as it is easily implemented on massively parallel computers and requires mainly +local information exchange between adjacent processes.

+

External (divergence-free) electric and/or magnetic fields can then be added to the +resulting electrostatic fields, provided they fullfill Maxwell’s equations (3), +and in particular Gauss’ and Poisson’s.

+

Note that a relativistically drifting plasma needs special treatment.

+
+
+
+

The PIC loop

+

At the end of the initialization stage [time-step \((n=0)\)], all quasi-particles +in the simulation have been loaded and the electromagnetic fields have been computed +over the whole simulation grid. The PIC loop is then started over \(N\) time-steps +each consisting in

+
    +
  1. interpolating the electromagnetic fields at the particle positions,

  2. +
  3. computing the new particle velocities and positions,

  4. +
  5. projecting the new charge and current densities on the grid,

  6. +
  7. computing the new electromagnetic fields on the grid.

  8. +
+

In this section, we describe these four steps which advance the time from +time-step \((n)\) to time-step \((n+1)\).

+
+

Field interpolation

+

At the beginning of time-step \((n)\), the particles velocity and position are known +at time-step \((n-\tfrac{1}{2})\) and \((n)\), respectively. For each particle +\(p\), the electromagnetic fields [at time-step \((n)\)] are computed at the +particle position using a simple interpolation technique:

+
+\[\begin{split}\begin{eqnarray} +\mathbf{E}_p^{(n)} = V_c^{-1} \int d^3\mathbf{x}\, S\left(\mathbf{x}-\mathbf{x}_p^{(n)}\right) \mathbf{E}^{(n)}(\mathbf{x})\,,\\ +\mathbf{B}_p^{(n)} = V_c^{-1} \int d^3\mathbf{x}\, S\left(\mathbf{x}-\mathbf{x}_p^{(n)}\right) \mathbf{B}^{(n)}(\mathbf{x})\,, +\end{eqnarray}\end{split}\]
+

where we have used the time-centered magnetic fields +\(\mathbf{B}^{(n)}=\tfrac{1}{2}[\mathbf{B}^{(n+1/2) } + \mathbf{B}^{(n-1/2)}]\).

+
+
+

Particle push

+

Knowing, for each quasi-particle, the electromagnetic fields at its position, the new +particle momentum and position are computed using a (second order) leap-frog integrator.

+

In Smilei, different schemes have been implemented: +the well-known Boris pusher +both in the classical and relativistic form, +the pusher developed by J.-L. Vay, +and the pusher of Higuera and Cary.

+

All schemes compute the new particle momentum and position according to

+
+\[\mathbf{u}_p^{n+\tfrac{1}{2}}=\mathbf{v}_p^{n-\tfrac{1}{2}} + r_s \Delta t \, \left[ E_p^{(n)} + \frac{\mathbf{v}_p^{(n+\tfrac{1}{2})}+\mathbf{v}_p^{(n-\tfrac{1}{2})}}{2} \times B_p^{(n)}\right],\]
+
+\[\mathbf{x}_p^{n+1}=\mathbf{x}_p^{n} + \Delta t \, \frac{\mathbf{u}_p^{n+\tfrac{1}{2}}}{\gamma_p},\]
+

where \(\Delta t\) denotes the duration of a time-step.

+
+
+

Current deposition

+

Charge deposition (i.e. charge and current density projection onto the grid) is then +performed using the charge-conserving algorithm +proposed by Esirkepov. +The current densities along the dimensions of the grid +(i.e., the \(x\)-direction for 1D3V simulations, +both \(x\)- and \(y\)-directions for 2D3V simulations, +and all three \(x\)-, \(y\)- and \(z\)-directions for 3D3V simulations) +are computed from the charge flux through the cell borders +(hence ensuring charge conservation) while the current densities along the other +dimensions are performed using a simple projection.

+

To illustrate this point, we take the example of current deposition in a 2D3V simulation. +The current densities in the \(x\)- and \(y\)-directions associated to a particle +with charge \(q\) are computed as:

+
+\[\begin{split}\begin{eqnarray} +(J_x)_{i+\tfrac{1}{2},j}^{(n+\tfrac{1}{2})} = (J_x)_{i-\tfrac{1}{2},j}^{(n+\tfrac{1}{2})} + W_p\,\frac{\Delta x}{\Delta t}\,(W_x)_{i+\tfrac{1}{2},j}^{(n+\tfrac{1}{2})}\,\\ +(J_y)_{i,j+\tfrac{1}{2}}^{(n+\tfrac{1}{2})} = (J_y)_{i,j-\tfrac{1}{2}}^{(n+\tfrac{1}{2})} + W_p\,\frac{\Delta y}{\Delta t}\,(W_y)_{j,i+\tfrac{1}{2}}^{(n+\tfrac{1}{2})}\, +\end{eqnarray}\end{split}\]
+

where \((W_x)^{(n+\tfrac{1}{2})}\) and \((W_y)^{(n+\tfrac{1}{2})}\) are quantities computed +from the particle current and former positions \(x_p^{(n+1)}\) and \(x_p^{(n)}\), +respectively, using the method developed by Esirkepov. +The particle current in the \(z\)-direction (not a dimension of the grid) is, +in this geometry, computed using a simple projection:

+
+\[(J_z)_{i,j} = W_r \mathbf{v}_p\,S(\mathbf{x}_{i,j}-\mathbf{x}_p)\,.\]
+

In all cases, the charge density deposited by the particle is obtained using the simple +projection:

+
+\[(\rho)_{i,j}^{(n+1)} = W_p\,S(\mathbf{x}_{i,j}-\mathbf{x}_p^{(n+1)})\,.\]
+

The total charge and current densities henceforth gather the contributions of all +quasi-particles of all species. It is worth noting that, within a charge-conserving +framework, charge densities are only projected on the grid for diagnostics purposes +(as we will see in the next paragraph, it is not used to advance the electromagnetic fields).

+
+
+

Maxwell solvers

+

Now that the currents are known at time-step \(n+\tfrac{1}{2}\), the electromagnetic +fields can be advanced solving Maxwell’s equations (3).

+

First, Maxwell-Ampère is solved, giving the advanced electric fields

+
+\[\mathbf{E}^{(n+1)} = \mathbf{E}^{(n)} + \Delta t\, \left[\left(\nabla \times \mathbf{B}\right)^{(n+\tfrac{1}{2})} - \mathbf{J}^{(n+\tfrac{1}{2})} \right]\,.\]
+

Then, Maxwell-Faraday is computed, leading to the advanced magnetic fields

+
+\[\mathbf{B}^{(n+\tfrac{3}{2})} = \mathbf{B}^{(n+\tfrac{1}{2})} - \Delta t\, \left(\nabla \times \mathbf{E}\right)^{(n+1)}\,.\]
+

The discretization of the curl-operator is not detailed here.

+

It is worth +noting that computing the two previous equations is sufficient to get a complete description +of the new electromagnetic fields. Indeed, it can be shown that this conserves a +divergence-free magnetic field if Gauss’ equation is satisfied at time \(t=0\). +Similarly, Poisson’s equation is verified as long as it is satisfied +at time \(t=0\), if the charge deposition algorithm fulfills the charge conservation +equation:

+
+\[\partial_t \rho + \nabla \cdot \mathbf{J} = 0\]
+

(this motivated the use of Esirkepov’s projection scheme discussed in the previous paragraph).

+
+
+
+
+

Boundary conditions

+

After new quasi-particle positions and velocities have been computed, boundary conditions (BCs) +are applied to each quasi-particle that may be located in a ghost cell, +i.e. outside of the ‘real’ grid. +Quasi-particle species may have a different BC for each boundary of the simulation box: +the quasi-particles can either loop around the box (periodic), +be stopped (momentum set to zero), +suppressed (removed from memory), +reflected (momentum and position follow specular reflection rules) +or thermalized. +In the latter case, the quasi-particle is set back inside the simulation box, +and its new momentum is randomly sampled in a Maxwellian distribution +with a given temperature and drift velocity, both specified by the user.

+

BCs are applied to the electromagnetic fields after Maxwell’s equations have been solved. +Each boundary of the simulation box can feature a different BC. +First, injecting/absorbing BCs inspired from the Silver-Müller BC +are able to inject an electromagnetic wave (e.g. a laser) and/or +to absorb outgoing electromagnetic waves. +In contrast, the reflective electromagnetic BC will reflect any outgoing +electromagnetic wave reaching the simulation boundary. +Lastly, periodic BCs correspond to applying the fields from the opposite boundary.

+
+
+
+

Multi-pass filtering of the current densities

+

A multi-pass filter on the current densities is available in Smilei. +The user can choose a simple 3-points FIR binomial filter, +which implementation follows that presented by +Vay et al. (2011), +or a N-point kernel FIR filter. +Each pass consists in a N-point spatial averaging (in one or all spatial dimensions) +of the current densities, so that the filtered current density (here defined +at location i on a one-dimensional grid) is recomputed as:

+
+\[J_{f,i} = \sum_{n=-(N-1)/2}^{+(N-1)/2} K_{(N-1)/2+n}J_{i+n}\]
+

In particular, the binomial filter uses a kernel K = [0.25,0.5,0.25] resulting in

+
+\[J_{f,i} = \frac{1}{2} J_i + \frac{J_{i+1}+J_{i-1}}{4}\]
+

A user-provided FIR kernel must be of length N with an odd number of coefficients +(symmetrical to avoid phase effects). +The number of ghost cells must be greater than (N-1)/2. +Moreover, the sum of the kernel’s coefficients must be equal to one. +This online tool is handy to design a custom filter.

+

Current filtering, if requested by the user, is applied before solving +Maxwell’s equation, and the number of passes is an input parameter +defined by the user.

+
+
+
+

Friedman filter on the electric field

+

A method for temporal filtering of the electric field is also available in Smilei. +It is the so-called Friedman filter detailed in Greenwood et al. (2004). +This method consists in computing the filtered electric field at time-step \(n\):

+
+\[{\bf E}_f^{(n)} = \left(1+\frac{\theta}{2}\right) {\bf E}^{(n)} - \theta \left(1-\frac{\theta}{2}\right) {\bf E}^{(n-1)} + \frac{1}{2} \theta \big(1-\theta\big)^2 \bar{\bf E}^{(n-2)},\]
+

where:

+
+\[\bar{\bf E}^{(n-2)} = {\bf E}^{(n-2)} + \theta \bar{\bf E}^{(n-3)},\]
+

and \(\theta \in [0,1[\) is an input parameter defined by the user. +Note that the filtered field \(E_f\) is not used to push particles, but is used when solving the Maxwell-Faraday equation. +Also note that, as underlined in Greenwood et al. (2004), +using this particular filter modifies the CFL condition of the Maxwell solver. +A simple trick to ensure that this condition is still verified is to use (for \(\Delta x = \Delta y = \Delta z\)) the +magic time-step \(\Delta t = \Delta x/2\) whenever the Friedman filter is employed.

+

Both filters on the currents and electric fields can be used together or +separately. They can be used, e.g., to mitigate the numerical Cherenkov instability that plagues PIC simulations dealing with +relativistically drifting flows. +An exemple of their use to mitigate this effect is highlighted in the work by Plotnikov et al. (2017).

+
+
+
+

B-translated interpolation scheme version 3

+

This interpolation scheme, called B-TIS3 and described in detail in P.-L. Bourgeois, X. Davoine (2023), mitigates some numerical artifacts +that arise when macro-particles at relativistic velocities are present in the simulation:

+
    +
  • inaccurate \(\mathbf{B}\) interpolation due to the time and space staggering of \(\mathbf{E}\) and \(\mathbf{B}\) in the Yee grid. The associated errors are particularly detrimental for the accuracy of simulations with relativistic particles;

  • +
  • Numerical Cherenkov radiation (see e.g. R. Lehe et al. (2013)) that arises with the interaction of relativistic particles and the numerical dispersion of Finite Difference methods used to solve Maxwell’s Equations. As explained in the same reference, this numerical artefact can increase the divergence and emittance of relativistic particle beams.

  • +
+

The B-TIS3 interpolation scheme can give a more accurate computation of the force acting on particles in presence of +fields that move at speed close to the speed of light in the x direction, which is the underlying hypothesis where this scheme can be used safely. +This hypothesis is also partially satisfied by Numerical Cherenkov radiation, as shown in P.-L. Bourgeois, X. Davoine (2020). +Please note that this scheme does not remove this numerical artifact (which will remain visible e.g. in Field diagnostics), but it mitigates its effects on the macro-particles. Instead, the effects of this interpolation scheme on the force acting on the macro-particles can be seen also through Probes showing the associated B-TIS3 fields. This because Probes act as macro-particles interpolating the fields from the grid as if they were plasma macro-particles.

+

As described in P.-L. Bourgeois, X. Davoine (2023), the correction given by the B-TIS3 scheme on force interpolation (compared to the usual +interpolation of the magnetic field) is effective only when the normalized integration timestep \(\Delta t\) is near to the value \(\Delta x\) of the +grid cell size along the x direction.

+

As explained before, in a typical PIC code using a Yee scheme to solve Maxwell’s equations, the magnetic field interpolated on the macro-particles’ +positions is often linearly interpolated in time. For example, for the \(B_z\) component of the magnetic field:

+
+\[B_{z,i-1/2}^{(n)}=\tfrac{1}{2}[B_{z,i-1/2}^{(n+1/2) } + B_{z,i-1/2}^{(n-1/2)}].\]
+

The B-TIS3 scheme tries to reduce the errors associated to this temporal interpolation and to the staggering of the electric and magnetic fields in the Yee cell, +interpolating a magnetic field defined at the same x spatial indices of the electric field when necessary.

+

For example, in the y component of the Lorentz force, the electric field component \(E_y\) is defined on the primal grid in the x direction, +but \(B_z\) is defined on the dual grid in the x direction.

+

Thus, in the B-TIS3 scheme a translated interpolation scheme is used for \(B_z\) in the Lorentz force:

+
+\[B_{z,i}^{(n), B-TIS3}=\tfrac{1}{2}[B_{z,i-1/2}^{(n-1/2) } + B_{z,i+1/2}^{(n+1/2)}].\]
+

As explained in the B-TIS3 reference, for \(\mathbf{B}\) fields moving near to the speed of light in the x direction and for \(c\Delta t\) near to the value \(\Delta x\), +this choice is more accurate than the usual linear temporal intepolation of the magnetic fields.

+

Note that in the x component of the Lorentz force the electric field \(E_x\) is defined on the +dual grid in the x direction, thus the usual Yee-centered and linearly interpolated \(B_z\) (also defined on the +dual grid in the x direction) is maintained.

+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/azimuthal_modes_decomposition.html b/Understand/azimuthal_modes_decomposition.html new file mode 100644 index 000000000..a9d4c7dea --- /dev/null +++ b/Understand/azimuthal_modes_decomposition.html @@ -0,0 +1,892 @@ + + + + + + + + + Azimuthal modes decomposition — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Azimuthal modes decomposition

+

Smilei can run in cyclindrical geometry with +a decomposition in azimuthal modes (AM), as described in +this article. +This requires a system with cylindrical symmetry or close to cylindrical symmetry +(around the x axis in Smilei).

+
+
+

Mathematical definition

+
+../_images/Coordinate_Reference_AMcylindrical.png +
+

Fig. 41 Coordinates in azimuthal geometry.

+
+
+

Any scalar field \(F(x,r,\theta)\) can be decomposed into a basis of +azimuthal modes, or harmonics, defined as \(\exp(-im\theta)\), +where \(m\) is the number of the mode. Writing each Fourier coefficient +as \(\tilde{F}^{m}\) leads to:

+
+(41)\[F\left(x,r,\theta\right) = \textrm{Re}\left[ + \sum_{m=0}^{+\infty}\tilde{F}^{m}\left(x,r\right)\exp{\left(-im\theta\right)} +\right],\]
+

The mode \(m=0\) has cylindrical symmetry (no dependence +on \(\theta\)). The following figure shows the real part +of the first four azimuthal modes.

+
+../_images/AM_modes.png +
+

Fig. 42 Real part of the first four pure azimuthal modes \(exp(-im\theta)\) +on the yz plane.

+
+
+

Eq. (41) can be expanded as:

+
+(42)\[F\left(x,r,\theta\right) = + \tilde{F}^{0}_{real} + + \tilde{F}^{1}_{real}\cos(\theta) + + \tilde{F}^{1}_{imag}\sin(\theta) + + \tilde{F}^{2}_{real}\cos(2\theta) + + \tilde{F}^{2}_{imag}\sin(2\theta) + ...\]
+

The complex coefficients \(\tilde{F}^{m}\) can be calculated from \(F\) +according to:

+
+\[\begin{split}\tilde{F}^{m} &=& \frac{1}{\pi}\int_0^{2\pi} F\left(x,r,\theta\right)\exp{\left(-im\theta\right)}d\theta +& \quad\textrm{ for } m>0 \\ +\tilde{F}^{0} &=& \frac{1}{2\pi}\int_0^{2\pi}F\left(x,r,\theta\right)d\theta. +& \textrm{ for } m=0\end{split}\]
+
+
+
+

Decomposition of vector fields

+

Vector fields can also be decomposed in azimuthal modes through a +decomposition of each of their components along the cylindrical +coordinates \((\mathbf{e_x},\mathbf{e_r},\mathbf{e_\theta})\). +For example, the transverse field \(\mathbf{E}_\perp\) of a laser pulse +polarized in the \(y\) direction with cylindrically symmetric envelope +can be written as

+
+\[\begin{split}\mathbf{E}_\perp(x,r,\theta, t) &= E_y(x,r,\theta, t) \mathbf{e_y} \\ + &= E_r (x,r,\theta, t) \mathbf{e_r} + E_{\theta}(x,r,\theta, t) \mathbf{e_{\theta}}\\ + &= E_y(x,r,t) [\cos(\theta) \mathbf{e_r} - \sin(\theta) \mathbf{e_{\theta}}].\end{split}\]
+

Thus, comparing to Eq (42), we recognize +a pure azimuthal mode of order \(m=1\) for both \(E_r\) +and \(E_\theta\), with the Fourier coefficients:

+
+\[ \begin{align}\begin{aligned}\begin{split}\tilde{E}^1_r (x,r,t) = E_y(x,r,t),\\\end{split}\\\tilde{E}^1_{\theta} (x,r,t) = -iE_y(x,r,t).\end{aligned}\end{align} \]
+

Similarly, an elliptically (or cylindrically) polarized laser +is described by a pure mode \(m=1\), as it can be seen as the linear +superposition of two linearly polarized lasers. A difference in phase or in the polarization direction simply +corresponds to a multiplication of the Fourier coefficients by a complex exponential.

+

The AM decomposition is most suited for +physical phenomena close to cylindrical symmetry as a low number +of modes is sufficient. +For example, in a basic Laser Wakefield Acceleration setup, +a linearly-polarized laser pulse with cylindrically symmetric envelope may be +described only by the mode \(m=1\). +As the wakefield wave is mainly determined by the cylindrically symmetric +ponderomotive force, it can be described by the mode \(m=0\). +Thus, such a simulation only needs, in principle, two azimuthal modes.

+
+
+
+

Maxwell’s equations in cylindrical geometry

+

In an AM simulation, the \(\tilde{F}^{m}(x,r)\) are stored and computed +for each scalar field and for each component of the vector fields. +Each of them is a \((x,r)\) grid of complex values.

+

From the linearity of Maxwell’s Equations, and assuming that the densities +and currents can also be decomposed in modes, we obtain the following +evolution of the mode \(m\):

+
+(43)\[\begin{split}\partial_t \tilde{B}^m_{x} &=-\frac{1}{r}\partial_r(r\tilde{E}^m_{\theta})-\frac{im}{r}\tilde{E}^m_r,\\ +\partial_t \tilde{B}^m_r &= \frac{im}{r}\tilde{E}^m_x+\partial_x \tilde{E}^m_{\theta},\\ +\partial_t \tilde{B}^m_{\theta} &=-\partial_x \tilde{E}^m_{r} + \partial_r \tilde{E}^m_{x},\\ +\partial_t \tilde{E}^m_{x} &=\frac{1}{r}\partial_r(r\tilde{B}^m_{\theta})+\frac{im}{r}\tilde{B}^m_r-\tilde{J}^m_{x},\\ +\partial_t \tilde{E}^m_r &= -\frac{im}{r}\tilde{B}^m_x-\partial_x \tilde{B}^m_{\theta}-\tilde{J}^m_{r},\\ +\partial_t \tilde{E}^m_{\theta} &=\partial_x \tilde{B}^m_{r} - \partial_r \tilde{B}^m_{x}-\tilde{J}^m_{\theta}.\end{split}\]
+

Thus, even in presence of a plasma, at each timestep, +these equations are solved independently. +The coupling between the modes occurs when the total electromagnetic fields +push the macro-particles, creating, in turn, the currents \(\tilde{J}^m\) +of their current density.

+
+
+
+

Interaction with the macro-particles

+

The azimuthal decomposition concerns only the grid quantities +(EM fields and current densities), which are thus defined on a 2D grid, +but macro-particles evolve in a full three-dimensional +space with cartesian coordinates.

+
+../_images/AM_grid_particles.jpg +
+

Fig. 43 Blue arrows: the x and r axes of the 2D grid (red) +where the electromagnetic fields are defined. +Macro-particle positions and momenta are defined in 3D.

+
+
+

During each iteration, the macro-particles are pushed in phase space +using reconstructed 3D cartesian electromagnetic fields +at their position \((x,r,\theta)\) (see Eq. (41)). +Then, their contribution to the current densities \((J_x,J_r,J_{\theta})\) +is computed to update the electromagnetic fields at the next iteration +(see Eqs (43)).

+
+
+
+

Tips

+

Note that each mode \(\tilde{F}^{m}\) is a function of \(x\), +the longitudinal coordinate and \(r\), the radial coordinate. +Therefore, each of them is only two dimensional. Thus, the computational cost +of AM simulations scales approximately as 2D simulations multiplied by the +number of modes. However, a higher number of macro-particles might be necessary +to obtain convergence of the results (always check the convergence of your +results by increasing the number of macro-particles and modes). +A rule of thumb is to use at least 4 times the number of modes as +macro-particles along \(\theta\).

+
+
+
+

Conventions for the namelist

+

Several differences appear in the notations and definitions between +the AM and 3D geometries:

+
    +
  • The origin of the coordinates is on the axis of the cylinder +(see figure below).

  • +
+
+../_images/AMcylindrical_vs_cartesian.png +
+

Fig. 44 Origin of coordinates in AM cylindrical and 3D cartesian.

+
+
+
    +
  • The AM radial grid size (grid_length[1]) represents the radius +of the cylinder; not its diameter. Thus, it is half the size of +the 3D transverse grid.

  • +
  • Particles are defined 3D space, so their coordinates should be +provided in terms of x, y, z if needed (e.g. a Species +initialized with a numpy array). +However, the density profiles of particles are assimilated to +scalar fields defined on the \((x,r)\) grid.

  • +
  • Field diagnostics really correspond to the complex fields +of each mode on \((x,r)\) grids. However, Probes +diagnostics are defined in 3D space just like the particles: +all fields are interpolated at their 3D positions, and reconstructed +by summing over the modes.

  • +
  • ExternalFields are grid quantities in \((x,r)\) coordinates. +One must be defined for each mode.

  • +
+
+
+
+

Classical and relativistic Poisson’s equation

+

Given the linearity of the relativistic Poisson’s equation +described in Field initialization for relativistic species, +it can be decomposed in azimuthal modes +with the corresponding mode of the charge density +\(-\tilde{\rho}^m\) as source term. +For the mode m of the potential \(\Phi\), +it writes:

+
+(44)\[\left[ + \frac{1}{\gamma^2_0}\partial^2_x\tilde{\Phi}^m + +\frac{1}{r}\partial_r\left(r\partial_r\tilde{\Phi}^m\right) + -\frac{m^2}{r^2}\tilde{\Phi}^m +\right] = -\tilde{\rho}^m.\]
+

By solving each of these relativistic Poisson’s equations +we initialize the azimuthal components of the electromagnetic fields:

+
+\[\begin{split}\begin{eqnarray} +\tilde{E}^m_x &=& -\frac{1}{\gamma_0^2}\partial_x \tilde{\Phi}^m,\\ +\tilde{E}^m_r &=& -\partial_r \tilde{\Phi}^m, \\ +\tilde{E}^m_{\theta} &=& \frac{im}{r} \tilde{\Phi}^m, \\ +\tilde{\mathbf{B}}^m &=& \beta_0\mathbf{\hat{x}}\times\tilde{\mathbf{E}}^m. +\end{eqnarray}\end{split}\]
+

The initialization of the electric field with the non-relativistic +Poisson’s equation is performed similarly, and the underlying equations simply +reduce to the previous equations, with \(\gamma_0 = 1\) and +\(\beta_0 = 0\) (i.e. an immobile Species).

+
+
+
+

The envelope model in cylindrical coordinates

+

The Laser envelope model for cartesian geometries has been +implemented also in cylindrical geometry, as described in [Massimo2020b].

+

Only the mode \(m=0\) is available for the envelope +in the present implementation, i.e. the electromagnetic and +envelope fields have perfect cylindrical symmetry with respect +to the envelope propagation axis \(x\).

+

The main difference compared to the cartesian geometry lies in the envelope +equation (see Eq. (50)). The assumption of cylindrical +symmetry removes derivatives with respect \(\theta\), leading to:

+
+(45)\[\partial^2_x\tilde{A} ++\frac{1}{r}\partial_r(r\partial_r\tilde{A}) ++2i\left(\partial_x \tilde{A} + \partial_t \tilde{A}\right) +-\partial^2_t\tilde{A} += \chi \tilde{A}.\]
+

The envelope approximation coupled to the cylindrical symmetry +can greatly speed-up the simulation: compared to a 3D envelope simulation +with the same number of particles, it has a speed-up which scales linearly +as twice the transverse number of cells. +This speed-up can reach 100 for lasers with transverse sizes of the order +of tens of microns. Compared to a standard 3D laser simulation with the +same number of particles, the speed-up of a cylindrical envelope simulation +can reach 1000 for lasers of durations of the order of tens of femtoseconds. +These comparisons assume the same longitudinal window size and the same +transverse size for the simulated physical space.

+
+
+
+

On-Axis boundary conditions in FDTD

+

In the AM geometry, specific boundary conditions are derived on-axis for the FDTD solver using a Yee lattice. +This section presents the actual implementation in Smilei. +It is mostly based on the original paper but also includes +original contributions from X. Davoine and the Smilei team.

+
+

Primal and Dual grids

+

In Smilei, ghost cells in the radial direction are located “before” the axis. +So if you have \(N_{ghost}\) ghost cells, you have as many primal points on the radial axis before +reaching the actual geometric axis \(r=0\). +If \(dr\) is a radial cell size, the dual radial axis is shifted by \(-dr/2\). +Below is an example for \(N_{ghost}=2\). +All equations in this section are given for this specific case. +For different numbers of ghost cells, simply add the difference in all indices. +\(jp\) and \(jd\) stand for the primal and dual indices.

+
+../_images/transverse_axis.png +
+
+
+

Cancellation on axis

+

The first basic principle is that a mode 0 field defined on axis can only be longitudinal otherwise it would be ill defined. +On the opposite, longitudinal fields on axis can only be of mode 0 since they do not depend on \(theta\). +From this we can already state that \(E_r^{m=0},\ E_t^{m=0},\ B_r^{m=0},\ B_t^{m=0},\ E_l^{m>0},\ B_l^{m>0}\) are zero on axis.

+

This condition is straight forward for primal fields in R which take a value on axis exactly. +We simply set this value to zero.

+
+\[ \begin{align}\begin{aligned}E_{\theta}^{m=0}[2] = 0\\B_r^{m=0}[2] = 0\\E_l^{m>0}[2] = 0\end{aligned}\end{align} \]
+

For dual fields in R, we set a value such as a linear interpolation between nearest grid points gives a zero on axis.

+
+\[ \begin{align}\begin{aligned}E_r^{m=0}[2] = -E_r^{m=0}[3]\\B_{\theta}^{m=0}[2] = -B_{\theta}^{m=0}[3]\\B_l^{m>0}[2] = -B_l^{m>0}[3]\end{aligned}\end{align} \]
+
+
+

Transverse field on axis

+

The transverse electric field can be written as follows

+
+\[\mathbf{E_\perp} = \mathbf{E_y} + \mathbf{E_z} = (E_r\cos{\theta}-E_{\theta}\sin{\theta})\mathbf{e_y} + (E_r\sin{\theta}+E_{\theta}\cos{\theta})\mathbf{e_z}\]
+

The transverse field on axis can not depend on \(\theta\) otherwise it would be ill defined. +Therefore we have the following condition on axis:

+
+\[\frac{\partial\mathbf{E_\perp}}{\partial\theta} = 0\ \forall\theta\]
+

which leads to the following relation:

+
+\[\cos{\theta}\left(\frac{\partial E_r}{\partial\theta}-E_{\theta}\right) + \sin{\theta}\left(\frac{\partial E_{\theta}}{\partial\theta}+E_r\right)=0\ \forall\theta\]
+

Being true for all \(\theta\), this leads to

+
+\[ \begin{align}\begin{aligned}\frac{\partial E_r}{\partial\theta}-E_{\theta}=0\ \forall\theta\\\frac{\partial E_{\theta}}{\partial\theta}+E_r=0\ \forall\theta\end{aligned}\end{align} \]
+

Remembering that for a given mode \(m\) and a given field \(F\), we have \(F=Re\left(\tilde{F}^m\exp{(-im\theta)}\right)\), +we can write the previous equations for all modes \(m\) as follows:

+
+(46)\[ \begin{align}\begin{aligned} \tilde{E_r}^m=\frac{i\tilde{E_{\theta}}^m}{m}\\ \tilde{E_r}^m=mi\tilde{E_{\theta}}^m\end{aligned}\end{align} \]
+

We have already established in the previuos section that the modes \(m=0\) must cancel on axis and we are concerned only about \(m>0\). +Equations (46) can have a non zero solution only for \(m=1\) and is also valid for the magnetic field. +We therefore conclude that all modes must cancel on axis except for \(m=1\).

+
+\[ \begin{align}\begin{aligned}E_{\theta}^{m>1}[2] = 0\\B_r^{m>1}[2] = 0\\E_r^{m>1}[2] = -E_r^{m>1}[3]\\B_{\theta}^{m>1}[2] = -B_{\theta}^{m>1}[3]\end{aligned}\end{align} \]
+

Let’s now write the Gauss law for mode \(m=1\):

+
+\[div(\mathbf{\tilde{E}^{m=1}})=\tilde{\rho}^{m=1}\]
+

where \(\rho\) is the charge density. +We have already established that on axis the longitudinal field are zero for all modes \(m>0\). +The charge density being a scalar field, it follows the same rule and is zero as well on axis. +The continuity equation on axis and written in cylindrical coordinates becomes:

+
+\[\frac{\tilde{E_r}^{m=1}-im\tilde{E_{\theta}}^{m=1}}{r} + \frac{\partial \tilde{E_r}^{m=1}}{\partial r} = 0\]
+

Eq. (46) already establishes that the first term is zero. +It is only necessary to cancel the second term.

+

In order to do so, let’s build an uncentered finite dfference scheme of the second order. +Simple Taylor developments give for any quantity \(u\):

+
+\[ \begin{align}\begin{aligned}u(x+\frac{dx}{2})=u(x)+\frac{dx}{2}u'(x)+\frac{dx^2}{8}u''(x)+O(dx3)\\u(x+\frac{3dx}{2})=u(x)+\frac{3dx}{2}u'(x)+\frac{9dx^2}{8}u''(x)+O(dx3)\end{aligned}\end{align} \]
+

By combination we obtain the scheme we are looking for:

+
+\[u'(x) = \frac{9u(x+\frac{dx}{2})-u(x+\frac{3dx}{2})-8u(x)}{3dx}\]
+

We can therefore write:

+
+\[\frac{\partial \tilde{E_r}^{m=1}}{\partial r}(r=0)= 9\tilde{E_r}^{m=1}(r=\frac{dr}{2})-\tilde{E_r}^{m=1}(r=\frac{3dr}{2})-8\tilde{E_r}^{m=1}(r=0) = 0\]
+

which gives:

+
+\[\tilde{E_r}^{m=1}(r=0)=\frac{1}{8}\left(9\tilde{E_r}^{m=1}(r=\frac{dr}{2})-\tilde{E_r}^{m=1}(r=\frac{3dr}{2})\right)\]
+

And from (46) this turns into:

+
+\[\tilde{E_{\theta}}^{m=1}(r=0)=\frac{-i}{8}\left(9\tilde{E_r}^{m=1}(r=\frac{dr}{2})-\tilde{E_r}^{m=1}(r=\frac{3dr}{2})\right)\]
+

giving the corresponding boundary condition for \(E_{\theta}^{m=1}\):

+
+\[E_{\theta}^{m=1}[2] = \frac{-i}{8}\left(9E_r^{m=1}[3]-E_r^{m=1}[4]\right)\]
+

Once \(E_{\theta}^{m=1}\) is defined on axis, we need to pick \(E_r^{m=1}\) so that (46) is matched. +With a linear interpolation we obtain:

+
+\[E_r^{m=1}[2] = 2iE_{\theta}^{m=1}[2]-E_r^{m=1}[3]\]
+

All the equation derived here are also valid for the magnetic field. +But because of a different duality, it is more convenient to use a different approach. +The equations (43) has a \(\frac{E_l}{r}\) term in the expression of \(B_r\) which makes it undefined on axis. +Nevertheless, we need to evaluate this term for the mode \(m=1\) and it can be done as follows.

+
+\[\lim_{r\to 0}\frac{E_l^{m=1}(r)}{r} = \lim_{r\to 0}\frac{E_l^{m=1}(r)-E_l^{m=1}(0)}{r}\]
+

since we established in the previous section that \(E_l^{m=1}(r=0)=0\). +And by definition of a derivative we have:

+
+\[\lim_{r\to 0}\frac{E_l^{m=1}(r)-E_l^{m=1}(0)}{r}=\frac{\partial E_l^{m=1} }{\partial r}(r=0)\]
+

This derivative can be evaluated by a simple finite difference scheme and using again that \(E_l^{m=1}\) is zero on axis we get:

+
+(47)\[\lim_{r\to 0}\frac{E_l^{m=1}(r)}{r} = \frac{E_l^{m=1}(dr)}{dr}\]
+

Introducing this result in the standard FDTD scheme for \(B_r\) we get the axis bounday condition:

+
+\[B_{r}^{m=1,n+1}[i,2] = B_{r}^{m=1,n}[i,2] + dt\left(\frac{i}{dr}E_l^{m=1}[i,3]+\frac{E_{\theta}^{m=1}[i+1,2]-E_{\theta}^{m=1}[i,2]}{dl}\right)\]
+

where the \(n\) indice indicates the time step and \(i\) the longitudinal indice. +Exactly as for the electric field, we need to have \(B_{r}^{m=1}=iB_{\theta}^{m=1}\). +With a similar interpolation we obtain the boundary condition on axis for \(B_{\theta}^{m=1}\):

+
+\[B_{\theta}^{m=1}[2]=-2iB_{r}^{m=1}[2]-B_{\theta}^{m=1}[3]\]
+
+
+

Longitudinal fields on axis

+

We have alreayd established that only modes \(m=0\) of longitudinal fields are non zero on axis. +In order to get an evaluation of \(E_l^{m=0}\) on axis one can use the same approach as for \(B_r^{m=1}\). +Since we have already shown that \(E_{\theta}^{m=0}\) is zero on axis, we have the following relation which is demonstrated using +similar arguments as Eq. (47):

+
+\[\lim_{r\to 0}\frac{1}{r}\frac{\partial rB_{\theta}^{m=0}}{\partial r} = \frac{4B_{\theta}^{m=0}(dr/2)}{dr}\]
+

Introducing this result in the standard FDTD expression of \(E_l\) we get:

+
+\[E_{l}^{m=0,n+1}[i,2] = E_{l}^{m=0,n}[i,2] + dt\left(\frac{4}{dr}B_{\theta}^{m=0}[i,3]-J_{l}^{m=0}[i,2]\right)\]
+

Again, the \(n\) indice indicates the time step here.

+

\(B_l^{m=0}\) is independant of \(\theta\). If we assume it is differentiable at \(r=0\) then its derivative along \(r\) is zero +on axis (derivative of a pair function is zero at \(x=0\) ). From this we get:

+
+\[B_{l}^{m=0}[2]=B_{l}^{m=0}[3]\]
+
+
+

Below axis

+

Fields “below” axis are primal fields data with indice \(j<2\) and dual fields with indice \(j<3\). +These fields are not physical in the sense that they do not contribute to the reconstruction of any physical field in real space and are not obtained by solving Maxwell’s equations. +Nevertheless, it is numerically convenient to give them a value in order to facilitate field interpolation for macro-particles near axis. +This is already what is done for dual fields in \(r\) which cancel on axis for instance. +We extend this logic to primal fields in \(r\):

+
+\[ \begin{align}\begin{aligned}E_{l}^{m=0}[1] = E_{l}^{m=0}[3]\\E_{l}^{m>0}[1] = -E_{l}^{m>0}[3]\\E_{\theta}^{m\neq1}[1] = -E_{\theta}^{m\neq1}[3]\\E_{\theta}^{m=1}[1] = E_{\theta}^{m=1}[3]\\B_{r}^{m\neq1}[1] = -B_{r}^{m\neq1}[3]\\B_{r}^{m=1}[1] = B_{r}^{m=1}[3]\end{aligned}\end{align} \]
+
+
+

Currents near axis

+

A specific treatment must be applied to charge and current densities near axis because the projector deposits charge and current “below” axis. +Quantities below axis must be brought back in the “physical” terms on and above axis.

+

Using the continuity equation instead of Gauss law for transverse current of mode \(m=1\) on axis, we can derive the exact same boundary conditions +on axis for current density as for the electric field.

+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/collisions.html b/Understand/collisions.html new file mode 100644 index 000000000..dee71ef3f --- /dev/null +++ b/Understand/collisions.html @@ -0,0 +1,971 @@ + + + + + + + + + Binary collisions & reactions — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Binary collisions & reactions

+

Relativistic binary collisions between particles have been implemented in +Smilei following these references:

+ +

This collision scheme can host reactions between the colliding +macro-particles, when requested:

+
    +
  • Ionization of an atom by collision with an electron.

  • +
  • Nuclear reaction between two atoms.

  • +
+

Please refer to that doc for an explanation of how to add +collisions in the namelist file.

+
+
+

The binary collision scheme

+

Collisions are calculated at each timestep and for each collision block +given in the input file:

+
    +
  • Macro-particles that should collide are randomly paired.

  • +
  • Average parameters are calculated (densities, etc.).

  • +
  • For each pair:

    +
      +
    • Calculate the momenta in the center-of-mass (COM) frame.

    • +
    • Calculate the coulomb log if requested (see [Perez2012]).

    • +
    • If the collision corresponds to a nuclear reaction (optional), +the reaction probability is computed and new particles are created +if successful.

    • +
    • Calculate the collision rate.

    • +
    • Randomly pick the deflection angle.

    • +
    • Deflect particles in the COM frame and switch back to the laboratory frame.

    • +
    • If the collision corresponds to ionization (optional), +its probability is computed and new electrons are created +if successful.

    • +
    +
  • +
+

Modifications in Smilei

+
    +
  • A typo from [Perez2012] is corrected: in Eq. (22), corresponding to +the calculation of the Coulomb Logarithm, the last parenthesis is +written as a squared expression, but should not.

  • +
  • The deflection angle distribution given by [Nanbu1997] +(which is basically a fit from Monte-Carlo simulations) +is modified for better accuracy and performance. +Given Nanbu’s \(s\) parameter and a random number \(U\in [0,1]\), +the deflection angle \(\chi\) is:

    +
    +\[\begin{split}\sin^2\frac\chi 2 = \begin{cases} +\alpha U/\sqrt{1-U + \alpha^2 U} &, s < 4\\ +1-U &, \textrm{otherwise} +\end{cases}\end{split}\]
    +

    where \(\alpha = 0.37 s-0.005 s^2-0.0064 s^3\).

    +
  • +
+
+
+
+

Test cases for collisions

+

1. Beam relaxation

+

An electron beam with narrow energy spread enters an ion background with \(T_i=10\) eV. +The ions are of very small mass \(m_i=10 m_e\) to speed-up the calculation. +Only e-i collisions are calculated. +The beam gets strong isotropization => the average velocity relaxes to zero.

+

Three figures show the time-evolution of the longitudinal \(\left<v_\|\right>\) +and transverse velocity \(\sqrt{\left<v_\perp^2\right>}\)

+
    +
  • Fig. 14 : initial velocity = 0.05, ion charge = 1

  • +
  • Fig. 15 : initial velocity = 0.01, ion charge = 1

  • +
  • Fig. 16 : initial velocity = 0.01, ion charge = 3

  • +
+

Each of these figures show 3 different blue and red curves which correspond to different +ratios of particle weights: 0.1, 1, and 10.

+
+../_images/beam_relaxation123.png +
+

Fig. 14 Relaxation of an electron beam. Initial velocity = 0.05, ion charge = 1.

+
+
+
+../_images/beam_relaxation456.png +
+

Fig. 15 Relaxation of an electron beam. Initial velocity = 0.01, ion charge = 1.

+
+
+
+../_images/beam_relaxation789.png +
+

Fig. 16 Relaxation of an electron beam. Initial velocity = 0.01, ion charge = 3.

+
+
+

The black lines correspond to the theoretical rates taken from the NRL formulary:

+
+\[\nu_\| = -\left(1+\frac{m_e}{m_i}\right)\nu_0 +\quad\textrm{and}\quad +\nu_\perp = 2\;\nu_0 +\quad\textrm{where}\quad +\nu_0=\frac{e^4\,Z^{\star 2}\,n_i\,\ln\Lambda } { 4 \pi \epsilon_0^2 \,m_e^2\,v_e^3 }\]
+

The distribution is quickly non-Maxwellian so that theory is valid only at the beginning.

+

2. Thermalization

+

A population of electrons has a different temperature from that of the ion population. +Through e-i collisions, the two temperatures become equal. +The ions are of very small mass \(m_i=10 m_e\) to speed-up the calculation. +Three cases are simulated, corresponding to different ratios of weights: 0.2, 1 and 5. +They are plotted in Fig. 17.

+
+../_images/thermalisation_ei123.png +
+

Fig. 17 Thermalization between two species.

+
+
+

The black lines correspond to the theoretical rates taken from the NRL formulary:

+
+\[\nu_\epsilon = \frac{2}{3}\sqrt\frac{2}{\pi} +\frac{e^4\,Z^{\star 2} \sqrt{m_em_i}\,n_i\,\ln\Lambda } +{ 4 \pi\epsilon_0^2 \,\left(m_eT_e+m_iT_i\right)^{3/2} }\]
+

3. Temperature isotropization

+

Electrons have a longitudinal temperature different from their transverse temperature. +They collide only with themselves (intra-collisions) and the anisotropy disappears +as shown in Fig. 18.

+
+../_images/temperature_isotropization1.png +
+

Fig. 18 Temperature isotropization of an electron population.

+
+
+

The black lines correspond to the theoretical rates taken from the NRL formulary:

+
+\[\nu_T=\frac{e^4 \,n_e\,\ln\Lambda } { 8\pi^{3/2} \epsilon_0^2 \,m_e^{1/2}T_\|^{3/2} } +A^{-2} \left[-3+(3-A)\frac{\rm{arctanh}(\sqrt{A})}{\sqrt{A}}\right] +\quad \rm{where}\quad A=1-\frac{T_\perp}{T_\|}\]
+

4. Maxwellianization

+

Electrons start with zero temperature along \(y\) and \(z\). +Their velocity distribution along \(x\) is rectangular. +They collide only with themselves and the rectangle becomes a maxwellian +as shown in Fig. 19.

+
+../_images/Maxwellianization1.png +
+

Fig. 19 Maxwellianization of an electron population. +Each blue curve is the distribution at a given time. +The red curve is an example of a gaussian function.

+
+
+

5. Stopping power

+

Test electrons (very low density) collide with background electrons of density +\(10\,n_c\) and \(T_e=5\) keV. +Depending on their initial velocity, they are slowed down at different rates, +as shown in Fig. 20.

+
+../_images/Stopping_power123.png +
+

Fig. 20 Stopping power of test electrons into a background electron population. +Each point is one simulation. The black line is Frankel’s theory [Frankel1979].

+
+
+

6. Conductivity

+

Solid-density Cu is simulated at different temperatures (e-i equilibrium) with only +e-i collisions. An electric field of \(E=3.2\) GV/m (0.001 in code units) is +applied using two charged layers on each side of the solid Cu. +The electron velocity increases until a limit value \(v_f\). +The resulting conductivity \(\sigma=en_ev_f/E\) is compared in +Fig. 21 to the models in [Lee1984] and [Perez2012].

+
+../_images/conductivity.png +
+

Fig. 21 Conductivity of solid-density copper. Each point is one simulation.

+
+
+
+
+
+

Collisional ionization

+

The binary collisions can also be ionizing if they are electron-ion collisions. +The approach is almost the same as that provided in [Perez2012].

+

When ionization is requested by setting ionizing=True, a few additional operations +are executed:

+
    +
  • At the beginning of the run, cross-sections are calculated from tabulated binding +energies (available for ions up to atomic number 100). These cross-sections are then +tabulated for each requested ion species.

  • +
  • Each timestep, the particle density \(n = n_e n_i/n_{ei}\) +(similar to the densities above for collisions) is calculated.

  • +
  • During each collision, a probability for ionization is computed. If successful, +the ion charge is increased, the incident electron is slowed down, and a new electron +is created.

  • +
+

Warnings

+
    +
  • This scheme does not account for recombination, which would balance ionization +over long time scales.

  • +
+

Relativistic change of frame

+

A modification has been added to the theory of [Perez2012] in order to account for the +laboratory frame being different from the ion frame. Considering \(\overrightarrow{p_e}\) +and \(\overrightarrow{p_i}\) the electron and ion momenta in the laboratory frame, +and their associated Lorentz factors \(\gamma_e\) and \(\gamma_i\), we define +\(\overrightarrow{q_e}=\overrightarrow{p_e}/(m_e c)\) and +\(\overrightarrow{q_i}=\overrightarrow{p_i}/(m_i c)\). +The Lorentz factor of the electron in the ion frame is +\(\gamma_e^\star=\gamma_e\gamma_i-\overrightarrow{q_e}\cdot\overrightarrow{q_i}\). +The probability for ionization reads:

+
+\[P = 1-\exp\left( - v_e \sigma n \Delta t \right) = 1-\exp\left( -V^\star \sigma^\star n \Delta t \right)\]
+

where \(v_e\) is the electron velocity in the laboratory frame, +\(\sigma\) is the cross-section in the laboratory frame, \(\sigma^\star\) +is the cross-section in the ion frame, and +\(V^\star=c\sqrt{\gamma_e^{\star\,2}-1}/(\gamma_e\gamma_i)\).

+

The loss of energy \(m_ec^2 \delta\gamma\) of the incident electron translates into a change in momentum +\({q_e^\star}' = \alpha_e q_e^\star\) in the ion frame, with +\(\alpha_e=\sqrt{(\gamma_e^\star-\delta\gamma)^2-1}/\sqrt{\gamma_e^{\star2}-1}\). +In the laboratory frame, it becomes +\(\overrightarrow{q_e'}=\alpha_e\overrightarrow{q_e}+((1-\alpha_e)\gamma_e^\star-\delta\gamma)\overrightarrow{q_i}\).

+

A similar operation is done for defining the momentum of the new electron in the lab frame. +It is created with energy \(m_ec^2 (\gamma_w-1)\) and its momentum is +\(q_w^\star = \alpha_w q_e^\star\) in the ion frame, with +\(\alpha_w=\sqrt{\gamma_w^2-1}/\sqrt{\gamma_e^{\star 2}-1}\). +In the laboratory frame, it becomes +\(\overrightarrow{q_w}=\alpha_w\overrightarrow{q_e}+(\gamma_w-\alpha_w\gamma_e^\star)\overrightarrow{q_i}\).

+

Multiple ionization

+

A modification has been added to the theory of [Perez2012] in order to account for +multiple ionization in a single timestep. The approach for field ionization +by Nuter et al +has been adapted to calculate the successive impact ionization probabilities +when an ion is ionized several times in a row.

+

Writing the probability to not ionize an ion already ionized \(i\) times as +\(\bar{P}^i = \exp\left( -W_i\Delta t\right)\), and defining +\(R^m_n = (1-W_m/W_n)^{-1}\), we can calculate the probability to ionize \(k\) times +the ion:

+
+\[\begin{split}P^i_k = \left\{ +\begin{array}{ll} +\bar{P}^i +& +\quad\mathrm{if}\quad k=0 +\\ +\sum\limits_{p=0}^{k-1} R^{i+k}_{i+p} \left(\bar{P}^{i+k} - \bar{P}^{i+p}\right) +\prod\limits_{j=0,j\ne p}^{k-1} R^{i+p}_{i+j} +& +\quad\mathrm{if}\quad 0<k<k_\mathrm{max} +\\ +\sum\limits_{p=0}^{k-1} \left[ 1+R^{i+k}_{i+p}\left(\frac{W_{i+k}}{W_{i+p}}\bar{P}^{i+p} - \bar{P}^{i+k}\right) \right] +\prod\limits_{j=0,j\ne p}^{k-1} R^{i+p}_{i+j} +& +\quad\mathrm{if}\quad k=k_\mathrm{max} +\end{array} +\right.\end{split}\]
+

where \(k_\mathrm{max} = Z-Z^\star\).

+

The cumulative probability \(F^i_k = \sum_{j=0}^{k} P^i_j\) provides an efficient +way to pick when the ionization stops: we pick a random number \(U\in [0,1]\) and +loop from \(k=0\) to \(k_\mathrm{max}\). We stop ionizing when \(F^i_k>U\).

+
+
+
+

Test cases for ionization

+

1. Ionization rate

+

A cold plasma of \(\mathrm{Al}^{3+}\) is set with density \(n_e=10^{21} \mathrm{cm}^{-3}\) +and with all electrons drifting at a velocity \(v_e=0.03\,c\). The charge state of ions +versus time is shown in Fig. 22 where the three dotted curves correspond +to three different weight ratios between electrons and ions.

+
+../_images/ionization_rate.png +
+

Fig. 22 Ionization of an aluminium plasma by drifting electrons.

+
+
+

The theoretical curve (in black) corresponds to \(1-\exp\left(v_en_e\sigma t\right)\) +where \(\sigma\) is the ionization cross section of \(\mathrm{Al}^{3+}\) at the +right electron energy. The discrepancy at late time is due to the changing velocity +distributions and to the next level starting to ionize.

+

2. Inelastic stopping power

+

A cold, non-ionized Al plasma is set with density \(n_e=10^{21} \mathrm{cm}^{-3}\). +Electrons of various initial velocities are slowed down by ionizing collisions and their +energy loss is recorded as a function of time.

+

A few examples are given in the left graph of Fig. 23. +The theoretical curve is obtained from [Rohrlich1954]. Note that this theory does not +work below a certain average ionization energy, in our case \(\sim 200\) eV.

+
+../_images/ionization_stopping_power.png +
+

Fig. 23 Left: ionization slowing down versus time, for electrons injected at various +initial energies into cold Al. Right: corresponding stopping power versus initial +electron energy.

+
+
+

In the same figure, the graph on the right-hand-side provides the stopping power value +in the same context, at different electron energies. It is compared to the same theory.

+

3. Multiple ionization

+

If the timestep is large, multiple ionization can occur, especially with cold high-Z +material and high-energy electrons. The multiple ionization algorithm is not perfect, +as it does not shuffle the particles for each ionization. Thus, good statistical +sampling is reached after several timesteps. To test the potential error, +we ran simulations of electrons at 1 MeV incident on cold atoms. The evolution of the +secondary electron density is monitored versus time in Fig. 24.

+
+../_images/ionization_multiple.png +
+

Fig. 24 Secondary electron density vs time, for cold plasmas traversed by a 1 MeV electron beam.

+
+
+

The solid lines correspond to a very-well resolved ionization, whereas the dashed lines +correspond to a large timestep. A difference is visible initially, but decreases +quickly as the statistical sampling increases and as the subsequent ionization +cross-sections decrease.

+

3. Effect of neglecting recombination

+

As recombination is not accounted for, we can expect excess ionization to occur indefinitely +without being balanced to equilibrium. However, in many cases, the recombination rate +is small and can be neglected over the duration of the simulation. We provide an example +that is relevant to picosecond-scale laser-plasma interaction. Plasmas initially at +a density of 10 times the critical density are given various initial temperatures. +Ionization initially increases while the temperature decreases, until, after a while, +their charge state stagnates (it still increases, but very slowly). +In Fig. 25, these results are compared to a Thomas-Fermi model +from [Desjarlais2001].

+
+../_images/ionization_recombination.png +
+

Fig. 25 Final charge state of various plasmas at various temperatures.

+
+
+

The model does not account for detailed ionization potentials. It provides a rough +approximation, and is particularly questionable for low temperatures or high Z. +We observe that Smilei’s approach for impact ionization provides decent estimates +of the ionization state. Detailed comparison to atomic codes has not been done yet.

+
+
+
+

Nuclear reactions

+

Nuclear reactions may occur during collisions when requested. The reaction +scheme is largely inspired from [Higginson2019].

+

1. Outline of the nuclear reaction process

+

We take advantage of the +relativistic kinematics calculations of the binary collision scheme +to introduce the nuclear reactions in the COM frame:

+
    +
  • The cross-section \(\sigma\) (tabulated for some reactions) +is interpolated, given the kinetic energies.

  • +
  • The probability for the reaction to occur is calculated.

  • +
  • This probability is randomly sampled and, if successful:

    +
      +
    • New macro-particles (the reaction products) are created.

    • +
    • Their angle is sampled from a tabulated distribution.

    • +
    • Their mpmenta are calculated from the conservation of total energy and momentum.

    • +
    • Their momenta are boosted back to the simulation frame.

    • +
    +
  • +
  • Otherwise: the collision process proceeds as usual.

  • +
+

2. Nuclear reaction probability

+

The probability for the reaction to occur is calculated as +\(P=1-\exp(R\, v\, n\, \sigma\, \Delta t)\) where v is the relative +velocity, n is a corrected density (see [Higginson2020]), and R is +a rate multiplier (see [Higginson2019]).

+

This factor R is of great importance for most applications, because +almost no reactions would occur when \(R=1\). This factor artificially +increases the number of reactions to ensure enough statistics. The weights +of the products are adjusted accordingly, and the reactants are not destroyed +in the process: we simply decrease their weight by the same amount.

+

In Smilei, this factor R can be forced by the user to some value, but by +default, it is automatically adjusted so that the final number of created particles +approches the initial number of pairs.

+

3. Creation of the reaction products

+

Special care must be taken when creating new charged particles while +conserving Poisson’s equation. Following Ref. [Higginson2019], we choose to +create two macro-particles of each type. To explain in detail, let us write +the following reaction:

+
+\[1 + 2 \rightarrow 3 + 4\]
+

Two particles of species 3 are created: one at the position of particle 1, +the other at the position of particle 2. Two particles of species 4 are also +created. To conserve the charge at each position, the weights of the new +particles must be:

+
+\[\begin{split}W_3^{@1} = w \frac{q_1}{q_1+q_2} q_3\\ +W_3^{@2} = w \frac{q_2}{q_1+q_2} q_3\\ +W_4^{@1} = w \frac{q_1}{q_1+q_2} q_4\\ +W_4^{@2} = w \frac{q_2}{q_1+q_2} q_4\end{split}\]
+

where \(w\) is the products’ weight, and the \(q_i\) are the charges.

+

4. Calculation of the resulting momenta

+

The conservation of energy reads:

+
+\[K_1 + K_2 + Q = K_3 + K_4\]
+

where the \(K_i\) are kinetic energies, and \(Q\) is the reaction’s +Q-value. In the COM frame, we have, by definition, equal momenta: \(p_3 = p_4\). +Using the relativistic expression \((K_k+m_k)^2=p_k^2+m_k^2\), we can +calculate that

+
+\[0=p_4^2-p_3^2=K_4 (K_4 + 2m_4) - K_3(K_3+2m_3)\]
+

Substituting for \(K_4\) using the conservation of energy, this translates into

+
+\[0=A_{00} A_{02} - (A_{20}+A_{02})K_3\]
+

where we have defined \(A_{ij}=K_1 + K_2 +Q+i\,m_3+j\,m_4\). We thus obtain

+
+\[\begin{split}K_3 = \frac{A_{00}A_{02}}{A_{20}+A_{02}}\\ +K_3+2m_3 = ... = \frac{A_{20}A_{22}}{A_{20}+A_{02}}\end{split}\]
+

Finally,

+
+\[p_3^2 = K_3(K_3+2m_3) = ... = \frac{A_{00}A_{02}A_{20}A_{22}}{(2A_{11})^2}\]
+

which expresses the resulting momentum as a function of the initial energies.

+
+
+
+

Collisions debugging

+

Using the parameter debug_every in a Collisions() group (see Collisions & reactions) +will create a file with info about these collisions. +These information are stored in the files “Collisions0.h5”, “Collisions1.h5”, etc.

+
+
The hdf5 files are structured as follows:

One HDF5 file contains several groups called "t********" where "********" +is the timestep. Each of these groups contains several arrays, which represent +quantities vs. space.

+
+
+

The available arrays are:

+
+
    +
  • s: defined in [Perez2012]: \(s=N\left<\theta^2\right>\), where \(N\) is +the typical number of real collisions during a timestep, and +\(\left<\theta^2\right>\) is the average square deviation of individual +real collisions. This quantity somewhat represents the typical amount of angular +deflection accumulated during one timestep. +It is recommended that \(s<1\) in order to have realistic collisions.

  • +
  • coulomb_log: average Coulomb logarithm.

  • +
  • debyelength: Debye length (not provided if all Coulomb logs are manually defined).

  • +
+
+

The arrays have the same dimension as the plasma, but each element of these arrays +is an average over all the collisions occurring in a single patch.

+
+
+
+

References

+
+
Desjarlais2001
+

M. Desjarlais, Contrib. Plasma Phys. 41, 267 (2001)

+
+
Frankel1979(1,2)
+

N. E. Frankel, K. C. Hines, and R. L. Dewar, Phys. Rev. A 20, 2120 (1979)

+
+
Higginson2019(1,2)
+

D. P. Higginson, A. Link, A. Schmidt, J. Comput. Phys. 388, 439 (2019)

+
+
Higginson2020(1,2)
+

D. P. Higginson, I. Holod and A. Link, J. Comput. Phys. 413, 109450 (2020)

+
+
Lee1984(1,2)
+

Y. T. Lee and R. M. More, Phys. Fluids 27, 1273 (1984)

+
+
Nanbu1997(1,2)
+

K. Nanbu, Phys. Rev. E 55, 4642 (1997)

+
+
Nanbu1998
+

K. Nanbu and S. Yonemura, J. Comput. Phys. 145, 639 (1998)

+
+
Perez2012(1,2,3,4,5,6,7,8)
+

F. Pérez et al., Phys. Plasmas 19, 083104 (2012)

+
+
Rohrlich1954
+

F. Rohrlich and B. C. Carlson, Phys. Rev. 93, 38 (1954)

+
+
Sentoku2008
+

Y. Sentoku and A. J. Kemp, J. Comput. Phys. 227, 6846 (2008)

+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/ionization.html b/Understand/ionization.html new file mode 100644 index 000000000..075b18c2c --- /dev/null +++ b/Understand/ionization.html @@ -0,0 +1,789 @@ + + + + + + + + + Ionization — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Ionization

+

Three types of ionization have been introduced in Smilei (4 if you count field ionization with a laser envelope as a separate type).

+
+
+

Collisional ionization

+

Ionization may occur during collisions. +A detailed description is given on the corresponding page.

+
+
+
+

Field ionization

+

Field ionization is a process of particular importance for laser-plasma interaction +in the ultra-high intensity regime. +It can affect ion acceleration driven by irradiating a solid target with +an ultra-intense laser, or can be used to inject electrons through +the accelerating field in laser wakefield acceleration. +This process is not described in the standard PIC (Vlasov-Maxwell) formulation, +and an ad hoc description needs to be implemented. +A Monte-Carlo module for field ionization has thus been developed in Smilei, +closely following the method proposed in [Nuter2011].

+
+

Physical model for field ionization

+

This scheme relies on the quasi-static rate for tunnel ionization derived in +[Perelomov1966], [Perelomov1967] and [Ammosov1986]. +Considering an ion with atomic number \(Z\) being ionized from charge state +\(Z^\star-1\) to \(Z^\star \le Z\) in a constant electric field \(\mathbf{E}\) +of magnitude \(\vert E\vert\), the ionization rate reads:

+
+(9)\[\Gamma_{\rm ADK, DC} = A_{n^\star,l^\star}\,B_{l,\vert m\vert}\, +I_p\,\left( \frac{2 (2 I_p)^{3/2}}{\vert E\vert} \right)^{2n^\star-\vert m \vert -1}\, +\exp\!\left( -\frac{2 (2 I_p)^{3/2}}{3 \vert E\vert} \right)\,,\]
+

where \(I_p\) is the \(Z^{\star}-1\) ionization potential of the ion, +\(n^\star=Z^\star/\sqrt{2 I_p}\) and \(l^\star=n^\star-1\) denote +the effective principal quantum number and angular momentum, +and \(l\) and \(m\) denote the angular momentum and its projection on +the laser polarization direction, respectively. +\(\Gamma_{\rm ADK, DC}\), \(I_p\) and \(E\) are here expressed in atomic units +The coefficients \(A_{n^\star,l^\star}\) and \(B_{l,\vert m\vert}\) are given by:

+
+\[\begin{split}\begin{array}{lll} +A_{n^\star,l^\star}&=& \frac{2^{2n^\star}}{n^\star\,\Gamma(n^\star+l^\star+1)\,\Gamma(n^\star-l^\star)},\\ +B_{l,\vert m\vert} &=& \frac{(2l+1)(l+\vert m\vert)!}{2^{\vert m\vert} \vert m\vert! (l-\vert m\vert)!}\,, +\end{array}\end{split}\]
+

where \(\Gamma(x)\) is the gamma function. +Note that considering an electric field \(E=\vert E\vert\,\cos(\omega t)\) +oscillating in time at the frequency \(\omega\), averaging Eq. (9) +over a period \(2\pi/\omega\) leads to the well-known cycle-averaged ionization rate:

+
+(10)\[\Gamma_{\rm ADK, AC} = \sqrt{\frac{3}{\pi}}A_{n^\star,l^\star}\,B_{l,\vert m\vert} +\,I_p\,\left( \frac{2 (2 I_p)^{3/2}}{\vert E\vert} \right)^{2n^\star-\vert m \vert -3/2}\, +\exp\!\left( -\frac{2 (2 I_p)^{3/2}}{3 \vert E\vert} \right)\,.\]
+

In Smilei, following [Nuter2011], the ionization rate of (9) +is computed for \(\vert m \vert=0\) only. +Indeed, as shown in [Ammosov1986], the ratio \(R\) of the ionization rate +computed for \(\vert m\vert=0\) by the rate computed for \(\vert m\vert=1\) is:

+
+\[R = \frac{\Gamma_{{\rm qs},\vert m \vert = 0}}{\Gamma_{{\rm qs},\vert m \vert = 1}} += 2\frac{(2\,I_p)^{3/2}}{\vert E\vert} +\simeq 7.91\,10^{-3} \,\,\frac{(I_p[\rm eV])^{3/2}}{a_0\,\hbar\omega_0[\rm eV]}\,,\]
+

where, in the practical units formulation, we have considered ionization +by a laser with normalized vector potential \(a_0=e\vert E\vert /(m_e c \omega_0)\), +and photon energy \(\hbar\omega_0\) in eV. +Typically, ionization by a laser with wavelength \(1~{\rm \mu m}\) +(correspondingly \(\hbar \omega_0 \sim 1~{\rm eV}\)) occurs for values +of \(a_0\ll 1\) (even for large laser intensities for which ionization +would occur during the rising time of the pulse) while the ionization potential +ranges from a couple of eV (for electrons on the most external shells) +up to a few tens of thousands of eV (for electrons on the internal shell +of high-Z atoms). As a consequence, \(R\gg1\), and the probability +of ionization of an electron with magnetic quantum number \(\vert m \vert=0\) +greatly exceeds that of an electron with \(\vert m \vert = 1\).

+

The initial velocity of the electrons newly created by ionization is chosen as equal to the ion velocity. +This constitutes a minor violation of momentum conservation, as the ion mass is not decreased after ionization.

+
+
+

Monte-Carlo scheme

+

In Smilei, tunnel ionization is treated for each species +(defined by the user as subject to field ionization) right after field interpolation +and before applying the pusher. +For all quasi-particles (henceforth referred to as quasi-ion) of the considered species, +a Monte-Carlo procedure has been implemented that allows to treat multiple ionization +events in a single timestep. It relies on the cumulative probability derived +in Ref. [Nuter2011]:

+
+\[F_k^{Z^{\star}-1} = \sum_{j=0}^k p_j^{Z^{\star}-1}\,,\]
+

to ionize from 0 to \(k\) times a quasi-ion with initial charge state +\(Z^{\star}-1\) during a simulation timestep \(\Delta t\), +\(p_j^{Z^{\star}-1}\) being the probability to ionize exactly \(j\) times this ion.

+

The Monte-Carlo procedure proceeds as follows. +A random number \(r\) with uniform distribution between 0 and 1 is picked. +If \(r\) is smaller than the probability \(p_0^{Z^{\star}-1}\) +to not ionize the quasi-ion, then the quasi-ion is not ionized during this time step. +Otherwise, we loop over the number of ionization events \(k\), +from \(k=1\) to \(k_{\rm max}=Z-Z^{\star}+1\) +(for which \(F_{k_{\rm max}}^{Z^{\star}-1}=1\) by construction), +until \(r<F_k^{Z^{\star}-1}\). At that point, \(k\) is the number of +ionization events for the quasi-ion. A quasi-electron is created with +the numerical weight equal to \(k\) times that of the quasi-ion, +and with the same velocity as this quasi-ion. +The quasi-ion charge is also increased by \(k\).

+

Finally, to ensure energy conservation, an ionization current +\({\bf J}_{\rm ion}\) is projected onto the simulation grid such that

+
+(11)\[{\bf J}_{\rm ion} \cdot {\bf E} = \Delta t^{-1}\,\sum_{j=1}^k I_p(Z^{\star}-1+k)\,.\]
+
+
+

Benchmarks

+

In what follows, we present two benchmarks of the field ionization model. +Both benchmarks consist in irradiating a thin (one cell long) neutral material (hydrogen or carbon) +with a short (few optical-cycle long) laser with wavelength \(\lambda_0 = 0.8~{\mu m}\).

+
+../_images/FieldIonization.png +
+

Fig. 26 Results of two benchmarks for the field ionization Model. +Top: Average charge state of hydrogen ions as a function of time when irradiated by a laser. +The red solid line corresponds to PIC results, the dashed line corresponds to +theoretical predictions using the cycle-averaged ADK growth rate of (10). +Bottom: Relative distribution of carbon ions for different charge states as a function +of time. Dashed lines correspond to PIC results, thin gray lines correspond to +theoretical predictions obtained from (12). The Gaussian gray shape +indicates the laser electric field envelope.

+
+
+

In the first benchmark, featuring hydrogen, the laser intensity is kept constant +at \(I_L = 10^{14}~{\rm W/cm^2}\), corresponding to a normalized vector +potential \(a_0 \simeq 6.81 \times 10^{-3}\), over 10 optical cycles. +The resulting averaged ion charge in the simulation is presented as a function of +time in Fig. 26 (left). It is found to be in excellent agreement +with the theoretical prediction considering the cycle averaged ionization rate +\(\Gamma_{\rm ADK} \simeq 2.55\times10^{12}~{\rm s^{-1}}\) computed +from (10).

+

The second benchmark features carbon ions. The laser has a peak intensity +\(I_L = 5 \times 10^{16}~{\rm W/cm^2}\), corresponding to a normalized +vector potential \(a_0 \simeq 1.52 \times 10^{-1}\), and a gaussian time profile +with FWHM \(\tau_L=5~\lambda_0/c\) (in terms of +electric field). Fig. 26 (right) shows, as function of time, +the relative distribution of carbon ions for different charge states +(from 0 to \(+4\)). These numerical results are shown to be in excellent +agreement with theoretical predictions obtained by numerically solving the coupled +rate equations on the population \(N_i\) of each level \(i\):

+
+(12)\[\frac{d}{dt}N_i = +(1-\delta_{i,0}) \, \Gamma_{i-1}\,N_{i-1} - (1-\delta_{i,Z})\, \Gamma_{i}\,N_{i}\,,\]
+

with \(\delta_{i,j}\) the Kroenecker delta, and \(\Gamma_i\) the ionization +rate of level \(i\). Note also that, for this configuration, +\(\Delta t \simeq 0.04~{\rm fs}\) is about ten times larger than +the characteristic time \(\Gamma_{\rm ADK}^{-1} \simeq 0.006~{\rm fs}\) +to ionize \({\rm C}^{2+}\) and \({\rm C}^{3+}\) +so that multiple ionization from \({\rm C}^{2+}\) to \({\rm C}^{4+}\) +during a single timestep does occur and is found to be correctly accounted for +in our simulations.

+
+
+
+
+

Field ionization with a laser envelope

+

In a typical PIC simulation, the laser oscillation is sampled frequently in time, +thus the electric field can be considered static within a single timestep where ionization takes place, +and the ionization rate in +DC, i.e. \(\Gamma_{\rm ADK, DC}\) from Eq. (9) can be used at +each timestep. +Furthermore, if the atom/ion from which the electrons are stripped through ionization is at rest, +for momentum conservation the new electrons can be initialized with zero momentum. +If a laser ionized the atom/ion, the new electrons momenta will quickly change due to the Lorentz force.

+

Instead, in presence of a laser envelope (see Laser envelope model) an ad hoc treatment of the +ionization process averaged over the scales of the optical cycle is necessary, since the +integration timestep is much greater than the one used in those typical PIC simulations [Chen2013]. +Thus, in this case a ionization rate \(\Gamma_{\rm ADK, AC}\) obtained averaging \(\Gamma_{\rm ADK, DC}\) over the laser oscillations +should be used at each timestep to have a better agreement with a correspondent standard laser simulation. +Afterwards, the momentum of the newly created electrons must be properly initialized taking into account of the +averaging process in the definition of the particle-envelope interaction.

+

For circular polarization, i.e. ellipticity = 1, +\(\Gamma_{\rm ADK, AC}=\Gamma_{\rm ADK, DC}\), since the field does not change +its magnitude over the laser oscillations. +For linear polarization, i.e. ellipticity = 0 :

+
+(13)\[\Gamma_{\rm ADK, AC} = \left(\frac{3}{\pi}\frac{\vert E\vert}{(2I_p)^{3/2}}\right)^{1/2}\Gamma_{\rm ADK, DC} .\]
+

Normally the laser is intense enough to be the main cause of ionization, +but to take into account possible high total fields \(E\) not described only by an envelope, +in Smilei a combination \(E=\sqrt{\vert E_{plasma}\vert^{2}+\vert\tilde{E}_{envelope}\vert^{2}}\) +is used instead of \(E\) in the above formulas. The field \(\tilde{E}_{plasma}\) represents +the (low frequency) electric field of the plasma, while \(\vert\tilde{E}_{envelope} \vert=\sqrt{\vert\tilde{E}\vert^2+\vert\tilde{E}_x\vert^2}\) +takes into account the envelopes of both the transverse and longitudinal components of the laser electric field +(see Laser envelope model for details on their calculation).

+

After an electron is created through envelope tunnel ionization, its initial transverse momentum \(p_{\perp}\) is assigned as described in [Tomassini2017]. +For circular polarization, in the case of an electron subject to a laser transverse envelope vector potential \(\tilde{A}\), the magnitude of its initial transverse momentum is set as +\(\vert p_{\perp}\vert = \vert\tilde{A}\vert\) and its transverse direction is chosen randomly between \(0\) and \(2\pi\). +For linear polarization, the initial transverse momentum along the polarization direction is drawn from a gaussian distribution with +rms width \(\sigma_{p_{\perp}} = \Delta\vert\tilde{A}\vert\), to reproduce the residual rms transverse momentum spread of electrons stripped from +atoms by a linearly polarized laser [Schroeder2014]. The parameter \(\Delta\) is defined as [Schroeder2014]:

+
+(14)\[\Delta = \left(\frac{3}{2} \vert E \vert \right)^{1/2}\left(2I_p\right)^{-3/4}.\]
+

This approximation is valid for regimes where \(\Delta\ll 1\). +Additionally, in Smilei the initial longitudinal momentum of the new electrons is initialized, to recreate the statistical features of the momentum distribution of the +electrons created through ionization. An electron initially at rest in a plane wave +with vector potential of amplitude \(\vert\tilde{A}\vert\) propagating along the positive \(x\) direction is subject to a drift in the wave propagation direction [Gibbon]. +An electron stripped from an atom/ion through envelope ionization by a laser can be approximated locally as in a plane wave, thus averaging over the laser oscillations +yields a positive momentum in the \(x\) direction. +Thus, each electron created from envelope tunnel ionization is initialized with \(p_x = \vert\tilde{A}\vert^2/4+\vert p_{\perp}\vert^2/2\) for linear polarization, +where \(p_{\perp}\) is drawn as described above. For circular polarization, each of these electron is initalized with \(p_x = \vert\tilde{A}\vert^2/2\). +This technique allows to take into account the longitudinal effects of the wave on the initial momentum, that start to be significant +when \(\vert\tilde{A}\vert>1\), effects which manifest mainly as an initial average longitudinal momentum. +For relativistic regimes, the longitudinal momentum effects significantly change the relativistic Lorentz factor +and thus start to significantly influence also the evolution of the transverse momenta.

+

If the envelope approximation hypotheses are satisfied, the charge created with ionization and the momentum distribution +of the newly created electrons computed with this procedure should agree with those obtained with a standard laser simulation, +provided that the comparison is made after the end of the interaction with the laser. +Examples of these comparisons and the derivation of the described electron momentum initialization can be found in [Massimo2020a]. +A comparison made in a timestep where the interaction with the laser is still taking place would show the effects of the quiver motion in the electron momenta +in the standard laser simulation (e.g. peaks in the transverse momentum spectrum). These effects would be absent in the envelope simulation.

+

Apart from the different ionization rate and the ad hoc momentum initialization of the new electrons, +the implementation of the field ionization with a laser envelope follows the same procedure +described in the above section treating the usual field ionization.

+

In presence of a laser envelope, an energy conservation equation analogous to (11) +cannot be written, since the information about the direction of the ionizing field is lost with the envelope +description. However, in many situations where the envelope approximation is valid the ion current can be +neglected and the error on energy conservation is negligible.

+
+
+
+

User-defined ionization rate

+

Smilei can treat ionization considering a fixed rate prescribed by the user. +The ionization rates are defined, for a given Species, as described here. +The Monte-Carlo procedure behind the treatment of ionization in this case closely follows +that developed for field ionization.

+
+

Warning

+

Note that, in the case of a user-defined ionization rate, only single ionization event per timestep are possible.

+
+

Let us introduce two benchmarks for which the rate of ionization is defined by the user. +The first benchmark considers an initially neutral species that can be potentially ionized twice. +To run this case, a constant and uniform ionization rate is considered that depends only on the particle current charge +state. For this particular case, we have considered a rate \(r_0 = 0.1\) (in code units) for ionization from +charge state 0 to 1, and a rate \(r_1 = 0.05\) (in code units) for ionization from charge state 1 to 2. +The simulation results presented in Fig. Fig. 27 (top panel) shows the time evolution of the +fraction in each possible charge states (\(Z=0\), \(Z=1\) and \(Z=2\)). +Super-imposed (dashed lines) are the corresponding theoretical predictions.

+

The second benchmark features an initially neutral species homogeneously distributed in the simulation box. +The ionization rate is here chosen as a function of the spatial coordinate \(x\), +and reads \(r(x) = r_0 \exp(-(x-x_c)^2/2)\) with \(r_0 = 0.02\) the maximum ionization rate and +\(x_c=5\) the center of the simulation box. +The simulation results presented in Fig. Fig. 27 (bottom panel) shows, +at the end of the simulation \(t=20\), the electron number density as a function of space. +Super-imposed (in red) is the corresponding theoretical prediction.

+
+../_images/userDefinedRate.png +
+

Fig. 27 Results of the two benchmarks for the ionization model using user-defined rates as described above.

+
+
+
+
+
+

References

+
+
Ammosov1986(1,2)
+

M. V. Ammosov, N. B. Delone, and V. P. Krainov, Sov. Phys. JETP 64, 1191 (1986)

+
+
Nuter2011(1,2,3)
+

R. Nuter et al., Phys. of Plasmas 19, 033107 (2011)

+
+
Perelomov1966
+

A. M. Perelomov, V. S. Popov, and M. V. Terent’ev, Sov. Phys. JETP 23, 924 (1966)

+
+
Perelomov1967
+

A. M. Perelomov, V. S. Popov, and M. V. Terent’ev, Sov. Phys. JETP 24, 207 (1967)

+
+
Chen2013
+

M. Chen, E. Cormier-Michel, C. G. R. Geddes, D. L. Bruwhiler, L. L. Yu, E. Esarey, C. B. Schroeder, W. P. Leemans, Journ. Comput. Phys. 236, 220 (2013)

+
+
Tomassini2017
+

P. Tomassini, S. De Nicola, L. Labate, P. Londrillo, R. Fedele, D. Terzani, and L. A. Gizzi, Physics of Plasmas 24, 103120 (2017)

+
+
Schroeder2014
+

C. B. Schroeder, J.-L. Vay, E. Esarey, S. S. Bulanov, C. Benedetti, L.-L. Yu, M. Chen, C. G. R. Geddes, and W. P. Leemans, Phys. Rev. ST Accel. Beams 17, 101301

+
+
Gibbon
+
    +
  1. Gibbon, Short Pulse Laser Interactions with Matter - An Introduction, Imperial College Press (2005)

  2. +
+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/laser_envelope.html b/Understand/laser_envelope.html new file mode 100644 index 000000000..ac281648e --- /dev/null +++ b/Understand/laser_envelope.html @@ -0,0 +1,775 @@ + + + + + + + + + Laser envelope model — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Laser envelope model

+

In many physical situations, the spatial and temporal scales of interest (e.g. the plasma wavelength \(\lambda_p\)) are much larger than the scales related to the laser central wavelength \(\lambda_0\). +In these cases, if the laser pulse is much longer than \(\lambda_0\), the computation time can be substantially reduced: one only needs to sample the laser envelope instead of \(\lambda_0\), as depicted in the following figure.

+
+../_images/Envelope_Figure.png +
+

Fig. 45 Blue: laser vector potential component \(\hat{A}\) along the transverse direction. Red: the module of its complex envelope \(|\tilde{A}|\). Both the lines display a suitable number of points for a proper sampling. In this case, the envelope is sampled by a number of points smaller by a factor ten.

+
+
+

The description of the physical system in terms of the complex envelope of the laser vector potential, neglecting its fast oscillations, is the essence of the envelope approximation. +However, a main limit of this technique is the impossibility to model phenomena at the scale of \(\lambda_0\).

+

In the following, the equations of the envelope model are presented, following mainly [Cowan2011], [Terzani], [MassimoPPCF2019] . Their numerical solution is briefly described as well.

+
+
+

The envelope approximation

+

The use of envelope models to describe a laser pulse is well known in PIC codes [Mora1997], [Quesnel1998], [Gordon2000], [Huang2006], [Cowan2011], [Benedetti2012]. The basic blocks of a PIC code using an envelope description for the laser are an envelope equation, to describe the evolution of the laser, and equations of motion for the macro-particles, to take into account their interactions with the laser. +The effect of the plasma on laser propagation is taken into account in the envelope equation through the plasma susceptibility, as described in the following section. +The various PIC codes using an envelope model for the laser solve different versions of the envelope equation, depending mostly on which terms are retained and which ones are neglected, or the set of coordinates used to derive the envelope equation. Also the numerical schemes used to solve the envelope equation and the equations of motion of the macro-particles vary accordingly. +In Smilei, the version of the envelope model written in laboratory frame coordinates, first demonstrated in the PIC code ALaDyn [Benedetti2008], [Terzani] is implemented, including the same numerical scheme to solve the lab frame coordinates envelope equation.

+

The basic assumption of the model is the description of the laser pulse vector potential in the transverse direction \(\mathbf{\hat{A}}(\mathbf{x},t)\) as a slowly varying envelope \(\mathbf{\tilde{A}}(\mathbf{x},t)\) modulated by fast oscillations at wavelength \(\lambda_0\), moving at the speed of light \(c\):

+
+(48)\[\mathbf{\hat{A}}(\mathbf{x},t)=\textrm{Re}\left[\mathbf{\tilde{A}}(\mathbf{x},t)e^{ik_0(x-ct)}\right],\]
+

where \(k_0=2\pi/\lambda_0\). In the language of signal processing, \(\mathbf{\tilde{A}}\) is the complex envelope of \(\mathbf{\hat{A}}\). In other words, the spectral content of \(\mathbf{\tilde{A}}\) is given by the positive frequency components of \(\mathbf{\hat{A}}\) around \(k_0\), but centered around the origin of the frequency \(k\) axis. +As the laser is the source term of the phenomena of interest, in general any vector \(\mathbf{A}\) will be therefore given by the summation of a slowly varying part \(\mathbf{\bar{A}}\) and a fast oscillating part \(\mathbf{\hat{A}}\) with the same form of Eq. (48):

+
+\[\mathbf{A}=\mathbf{\bar{A}} + \mathbf{\hat{A}}.\]
+

In the envelope model context, “slowly varying” means that the spatial and temporal variations of \(\mathbf{\bar{A}}\) and \(\mathbf{\tilde{A}}\) are small enough to be treated perturbatively with respect to the ratio \(\epsilon=\lambda_0/\lambda_p\), as described in detail in [Mora1997], [Quesnel1998], [Cowan2011]. The laser envelope transverse size \(R\) and longitudinal size \(L\) are thus assumed to scale as \(R \approx L \approx \lambda_0 / \epsilon\) [Mora1997], [Quesnel1998]. +As described thoroughly in the same references, the coupling between the laser envelope and the plasma macro-particles can be modeled through the addiction of a ponderomotive force term in the macro-particles equations of motion. This term, not representing a real force, is a term rising from an averaging process in the perturbative treatment of the macro-particles motion over the laser optical cycles.

+

Modeling the laser through a complex envelope and its coupling with the plasma through the ponderomotive force will yield physically meaningful results only if the variation scales in space and time are greater than \(\lambda_0\), \(1/\omega_0\). Examples violating these hypotheses include, but are not limited to, tightly focused lasers, few optical cycles lasers, sharp gradients in the plasma density.

+
+
+
+

The envelope equation

+

The evolution of the laser pulse is described by d’Alembert’s equation, which in normalized units reads:

+
+(49)\[\nabla^2 \mathbf{\hat{A}}-\partial^2_t\mathbf{\hat{A}}=-\mathbf{\hat{J}},\]
+

where \(\mathbf{\hat{J}}\) is the fast oscillating part of the current density in the laser polarization direction. Through the assumption given by Eq. (48), Eq. (49) can be reduced to an envelope equation:

+
+(50)\[\nabla^2 \mathbf{\tilde{A}}+2i\left(\partial_x \mathbf{\tilde{A}} + \partial_t \mathbf{\tilde{A}}\right)-\partial^2_t\mathbf{\tilde{A}}=\chi \mathbf{\tilde{A}},\]
+

which describes the evolution of the laser pulse only in terms of the laser envelope \(\mathbf{\tilde{A}}\). The function \(\chi\) represents the plasma susceptibility, which is computed similarly to the charge density (see PIC algorithms) as

+
+(51)\[\chi(\mathbf{x}) = \sum_s\,\frac{q^2_s}{m_s}\,\sum_p\,\frac{w_p}{\bar{\gamma}_p}\,S\big(\mathbf{x}-\mathbf{\bar{x}}_p\big)\,\]
+

where \(\bar{\gamma}_p\) is the averaged Lorentz factor of the macro-particle \(p\). This averaged quantity is computed from the averaged macro-particle momentum \(\mathbf{\bar{u}}_p=\mathbf{\bar{p}}_p/m_s\) and the envelope \(\mathbf{\tilde{A}}\):

+
+(52)\[\bar{\gamma}_p = \sqrt{1+\mathbf{\bar{u}}^2_p+\frac{|\mathbf{\tilde{A}}(\mathbf{\bar{x}}_p)|^2}{2}}.\]
+

The term at the right hand side of Eq. (48), where the plasma susceptibility \(\chi\) appears, allows to describe phenomena where the plasma alters the propagation of the laser pulse, as relativistic self-focusing.

+

Note that if in Eq. (48) the temporal variation of the envelope \(\mathbf{\tilde{A}}\) is neglected, and \(\partial^2_x \mathbf{\tilde{A}} \ll 2i\partial_x \mathbf{\tilde{A}}\) is assumed, the well-known paraxial wave equation is retrieved in vacuum (\(\chi=0\)):

+
+(53)\[\nabla_{\perp}^2 \mathbf{\tilde{A}}+2i\partial_x \mathbf{\tilde{A}}=0.\]
+

In Smilei, no assumptions on the derivatives are made and the scalar versions of Eq. (50) is solved (see next sections).

+
+
+
+

The ponderomotive equations of motion

+

The process of averaging over the time scale of a laser oscillation period yields a simple result for the macro-particles equations of motion. +The averaged position \(\mathbf{\bar{x}}_p\) and momentum \(\mathbf{\bar{u}}_p\) of the macro-particle \(p\) are related to the averaged electromagnetic fields \(\mathbf{\bar{E}}_p=\mathbf{\bar{E}}(\mathbf{\bar{x}}_p)\), \(\mathbf{\bar{B}}_p=\mathbf{\bar{B}}(\mathbf{\bar{x}}_p)\) through the usual equations of motion, with the addition of a ponderomotive force term which models the interaction with the laser:

+
+(54)\[\begin{split}\begin{eqnarray} +\frac{d\mathbf{\bar{x}}_p}{dt} &=& \frac{\mathbf{\bar{u}_p}}{\bar{\gamma}_p}, \,\\ +\frac{d\mathbf{\bar{u}}_p}{dt} &=& r_s \, \left( \mathbf{\bar{E}}_p + \frac{\mathbf{\bar{u}}_p}{\bar{\gamma}_p} \times \mathbf{\bar{B}}_p \right)-r^2_s\thinspace\frac{1}{4\bar{\gamma}_p}\nabla\left(|\mathbf{\tilde{A}}_p|^2\right), +\end{eqnarray}\end{split}\]
+

where \(r_s = q_s/m_s\) is the charge-over-mass ratio (for species \(s\)). +The presence of the ponderomotive force \(\mathbf{F}_{pond}=-r^2_s\thinspace\frac{1}{4\bar{\gamma}_p}\nabla\left(|\mathbf{\tilde{A}}|^2\right)\) and of the ponderomotive potential \(\Phi_{pond}=\frac{|\mathbf{\tilde{A}}|^2}{2}\) +in the envelope and particle equations is the reason why the envelope model is also called ponderomotive guiding center model [Gordon2000].

+
+
+
+

The averaged electromagnetic fields

+

In the envelope model, Maxwell’s equations remain unaltered, except for the fact that they describe the evolution of the averaged electromagnetic fields \(\mathbf{\bar{E}}(\mathbf{x},t)\), \(\mathbf{\bar{B}}(\mathbf{x},t)\) in terms of the averaged charge density \(\bar{\rho}(\mathbf{x},t)\) and averaged current density \(\mathbf{\bar{J}}(\mathbf{x},t)\):

+
+(55)\[\begin{split}\begin{eqnarray} +\nabla \cdot \mathbf{\bar{B}} &=& 0 \,,\\ +\nabla \cdot \mathbf{\bar{E}} &=& \bar{\rho} \,,\\ +\nabla \times \mathbf{\bar{B}} &=& \mathbf{\bar{J}} + \partial_t \mathbf{\bar{E}} \,,\\ +\nabla \times \mathbf{\bar{E}} &=& -\partial_t \mathbf{\bar{B}} \,. +\end{eqnarray}\end{split}\]
+

Note that the averaged electromagnetic fields do not include the laser fields. Thus, also in the diagnostics of Smilei, the fields will include only the averaged fields.

+
+
+
+

The ponderomotive PIC loop

+

Since Maxwell’s equations (55) remain unaltered, their solution can employ the same techniques used in a standard PIC code. The main difficulty in the solution of the other equations, namely the envelope equation Eq. (50) and the macroparticles equations of motion Eqs. (54), is that the source terms contain the unknown terms. +For example, in the envelope equations, the source term involves the unknown envelope itself and the susceptibility, which depends on the envelope. Also, the equations of motion contain the term \(\bar{\gamma}\), which depends on the envelope. +The PIC loop described in PIC algorithms is thus modified to self-consistently solve the envelope model equations. At each timestep, the code performs the following operations

+
    +
  1. interpolating the electromagnetic fields and the ponderomotive potential at the macro-particle positions,

  2. +
  3. projecting the new plasma susceptibility on the grid,

  4. +
  5. computing the new macro-particle velocities,

  6. +
  7. computing the new envelope values on the grid,

  8. +
  9. computing the new macro-particle positions,

  10. +
  11. projecting the new charge and current densities on the grid,

  12. +
  13. computing the new electromagnetic fields on the grid.

  14. +
+

Note that the momentum advance and position advance are separated by the envelope equation solution in this modified PIC loop. +In this section, we describe these steps which advance the time from time-step \((n)\) to time-step \((n+1)\).

+
+

Field interpolation

+

The electromagnetic fields and ponderomotive potential interpolation at the macro-particle position at time-step \((n)\) follow the same technique described in PIC algorithms:

+
+\[\begin{split}\begin{eqnarray} +\mathbf{\bar{E}}_p^{(n)} = V_c^{-1} \int d\mathbf{x}\, S\left(\mathbf{x}-\mathbf{\bar{x}}_p^{(n)}\right) \mathbf{\bar{E}}^{(n)}(\mathbf{x})\,,\\ +\mathbf{\bar{B}}_p^{(n)} = V_c^{-1} \int d\mathbf{x}\, S\left(\mathbf{x}-\mathbf{\bar{x}}_p^{(n)}\right) \mathbf{\bar{B}}^{(n)}(\mathbf{x})\,,\\ +\mathbf{\Phi}_p^{(n)} = V_c^{-1} \int d\mathbf{x}\, S\left(\mathbf{x}-\mathbf{\bar{x}}_p^{(n)}\right) \mathbf{\Phi}^{(n)}(\mathbf{x})\,, +\end{eqnarray}\end{split}\]
+

where we have used the time-centered magnetic fields +\(\mathbf{\bar{B}}^{(n)}=\tfrac{1}{2}[\mathbf{\bar{B}}^{(n+1/2) } + \mathbf{\bar{B}}^{(n-1/2)}]\), +and \(V_c\) denotes the volume of a cell.

+
+
+

Susceptibility deposition

+

The macro-particle averaged positions \(\mathbf{\bar{x}}_p^{(n)}\) and averaged momenta \(\mathbf{\bar{p}}_p^{(n)}\) +and the ponderomotive potential \(\mathbf{\Phi}_p^{(n)}\) are used to compute the ponderomotive Lorentz factor \(\bar{\gamma}_p\) (52) +and deposit the susceptibility on the grid through Eq. (51).

+
+
+

Ponderomotive momentum push

+

The momentum push is performed through a modified version of the well-known Boris Pusher, derived +and proposed in [Terzani]. +The plasma electric, magnetic and ponderomotive potential fields at the macro-particle position \(\mathbf{\bar{E}}_p^{(n)}\), +\(\mathbf{\bar{B}}_p^{(n)}\), \(\mathbf{\Phi}_p^{(n)}\) are used to advance the momentum \(\mathbf{\bar{p}}_p^{(n-1/2)}\) +from time-step \(n−1/2\) to time-step \(n + 1/2\), solving the momentum equation in Eqs. (54)

+
+
+

Envelope equation solution

+

Now that the averaged susceptibility is known at time-step \(n\), the envelope can be advanced solving the envelope equation (50). +In the two solver schemes available in the code (see below), the envelope \(\mathbf{\tilde{A}}\) at time-step \(n+1\) is computed from its value +at timesteps \(n\), \(n-1\) and the suceptibility \(\chi\) at time-step \(n\). The value of the envelope at timestep \(n\) is conserved for the next iteration of the time loop. +A main advantage of these explicit numerical schemes is their straightforward parallelization in 3D, due to the locality of the operations involved.

+
+
+

Ponderomotive position push

+

The updated ponderomotive potential is interpolated at macro-particle positions to obtain \(\mathbf{\Phi}_p^{(n+1)}\). +Afterwards, the temporal interpolation \(\mathbf{\Phi}_p^{(n+1/2)}=\left(\mathbf{\Phi}_p^{(n)}+\mathbf{\Phi}_p^{(n+1)}\right)/2\) is performed. +The updated ponderomotive Lorentz factor \(\bar{\gamma}_p^{(n+1/2)}\) can be computed and the averaged position of each macro-particle +can be advanced solving the last of Eqs. (54):

+
+\[\mathbf{\bar{x}}_p^{n+1}=\mathbf{\bar{x}}_p^{n} + \Delta t \, \frac{\mathbf{\bar{p}}_p^{n+\tfrac{1}{2}}}{m_s\bar{\gamma}_p^{(n+1/2)}},\]
+
+
+

Current deposition

+

The averaged charge deposition (i.e. charge and current density projection onto the grid) is then +performed exactly as in the standard PIC loop for the non averaged quantities (see PIC algorithms), using the charge-conserving algorithm +proposed by Esirkepov.

+
+
+

Maxwell solvers

+

Now that the averaged currents are known at time-step \(n+\tfrac{1}{2}\), the averaged electromagnetic +fields can be advanced solving Maxwell’s equations (55). Their solution is identical to the one described in PIC algorithms for the corresponding non-averaged quantities.

+
+
+
+
+

Laser polarization in the envelope model

+

In Smilei, the envelope model is implemented to take into account either linear or circular polarization +(ellipticity = 0 and ellipticity = 1 in the input namelist respectively). The default polarization is linear along the y direction. +The envelope of a laser pulse propagating in the positive x direction can be written as

+
+\[\mathbf{\tilde{A}} (\mathbf{x},t)= \tilde{A}(\mathbf{x},t) \left[ \eta\thinspace\hat{y} + i(1-\eta^2)^{1/2}\hat{z} \right] ,\]
+

where \(\eta=1\) or \(\eta=0\) for linear polarization along y or z, and \(\eta\pm1/\sqrt{2}\) for circular polarization. +Although Eq. (50) is a vector equation nonlinear, these two polarizations allow to solve only one scalar equation +at each timestep, because once the susceptibility at a given timestep is known, the envelope equation can be considered linear. +Thus, after calculating the susceptibility we can solve the equation:

+
+(56)\[\nabla^2 \tilde{A}+2i\left(\partial_x \tilde{A} + \partial_t \tilde{A}\right)-\partial^2_t\tilde{A}=\chi \tilde{A},\]
+

where \(\tilde{A}\) is the nonzero component of \(\mathbf{\tilde{A}}\) for linear polarization and \(\tilde{A}/\sqrt{2}\) for circular polarization. +This approach gives accurate results only if the ponderomotive potential \(\Phi_{pond}=\frac{|\mathbf{\tilde{A}}|^2}{2}\) is computed +accordingly to the vector definition of \(\mathbf{\tilde{A}}\). This means that \(\Phi_{pond}=\frac{|\tilde{A}|^2}{2}\) for both linear and +circular polarization. +Besides, with this approach the absolute value of \(\tilde{A}\) and the derived electric field \(\tilde{E}\) (see next section) are directly comparable with +standard laser simulations with the same polarization and \(a_0\).

+
+
+
+

Computing the laser electric field from the laser envelope

+

It is always useful (and recommendable) to compare the results of an envelope simulation and of a standard laser simulation, +to check if the envelope approximation is suitable for the physical case that is simulated. +For this purpose, the plasma electromagnetic fields and the charge densities are easily comparable. +However, in an envelope simulation all the plasma dynamics is written as function of the envelope of the transverse component +of the vector potential \(\tilde{A}\), as explained in the previous sections, and not as function of the laser electric field.

+

Furthermore, in case of envelope simulations with ionization, the ionization rate formula is computed using the electric field +(longitudinal and transverse components) of the laser.

+

For these two reasons (diagnostic and ionization), in an envelope simulation two additional fields are computed, +\(\tilde{E}\) and \(\tilde{E_x}\), which represent respectively the envelope of the transverse component +and of the longitudinal component of the laser electric field.

+

From Eq. (48), the laser transverse electric field’s complex envelope \(\tilde{E}\) can be derived. +In the context of the perturbative treatment, the laser scalar potential can be neglected [Cowan2011], yielding:

+
+\[\hat{E} = -\partial_t \hat{A} = -\partial_t \Big\{\textrm{Re}\left[\tilde{A}(\mathbf{x},t)e^{ik_0(x-ct)}\right]\Big\} = \textrm{Re}\left[-\left(\partial_t-ik_0c\right)\tilde{A}(\mathbf{x},t)e^{ik_0(x-ct)}\right],\]
+

which can be expressed, following the definition in Eq. (48), also as

+
+\[\hat{E} = \textrm{Re}\left[\tilde{E}(\mathbf{x},t)e^{ik_0(x-ct)}\right].\]
+

The laser transverse electric field’s complex envelope \(\tilde{E}\) can thus be defined:

+
+\[\tilde{E} = -\left(\partial_t-ik_0c\right)\tilde{A}(\mathbf{x},t).\]
+

In the same theoretical framework, it can be shown that the laser longitudinal electric field’s envelope can be computed through +a partial derivative along the direction perpendicular to the laser propagation direction:

+
+\[\tilde{E_x} = -\partial_{\perp}\tilde{A}(\mathbf{x},t).\]
+

In the diagnostics, the absolute value of the fields \(\tilde{E}\), \(\tilde{E_x}\) are available, under the names Env_E_abs and Env_Ex_abs.

+
+
+
+

The numerical solution of the envelope equation

+

To solve Eq. (56), two explicit numerical schemes are implemented in the code, first implemented in the PIC code ALaDyn [Benedetti2008] and described in [Terzani].

+

In the first scheme, denoted as "explicit" in the input namelist, the well known central finite differences are used to discretize the envelope equation. +In 1D for example, the spatial and time derivatives of the envelope \(\tilde{A}\) at time-step \(n\) and spatial index \(i\) are thus approximated by:

+
+\[\begin{split}D_x\tilde{A}\bigg\rvert^{n}_{i}&=&\frac{\tilde{A}^n_{i+1}-\tilde{A}^n_{i-1}}{2\Delta x},\\ +D_t\tilde{A}\bigg\rvert^{n}_{i}&=&\frac{\tilde{A}^{n+1}_{i}-\tilde{A}^{n-1}_{i}}{2\Delta t},\\ +D_{xx}\tilde{A}\bigg\rvert^{n}_{i}&=&\frac{\tilde{A}^n_{i+1}-2\tilde{A}^n_{i}+\tilde{A}^n_{i-1}}{\Delta x^2},\\ +D_{tt}\tilde{A}\bigg\rvert^{n}_{i}&=&\frac{\tilde{A}^{n+1}_{i}-2\tilde{A}^n_{i}+\tilde{A}^{n-1}_{i}}{\Delta t^2},\end{split}\]
+

where \(\Delta x, \Delta t\) are the cell size in the x direction and the integration time-step respectively.

+

In the second scheme, denoted as "explicit_reduced_dispersion" in the input namelist, the finite difference approximations for the derivatives along +the propagation direction x are substituted by optimized finite differences that reduce the numerical dispersion in that direction (see [Terzani] for the derivation). +Namely, defining \(\nu=\Delta t/\Delta x\), \(\delta=(1-\nu^2)/3\), these optimized derivatives can be written as:

+
+\[\begin{split}D_{x,opt}\tilde{A}\bigg\rvert^{n}_{i}&=& (1+\delta)D_x\tilde{A}\bigg\rvert^{n}_{i}-\delta\left(\frac{\tilde{A}^n_{i+2}-\tilde{A}^n_{i-2}}{4\Delta x}\right),\\ +D_{xx,opt}\tilde{A}\bigg\rvert^{n}_{i}&=& (1+\delta)D_{xx}\tilde{A}\bigg\rvert^{n}_{i}-\delta\left(\frac{\tilde{A}^n_{i+2}-2\tilde{A}^n_{i}+\tilde{A}^n_{i-2}}{4\Delta x^2}\right).\\\end{split}\]
+

In both schemes, after substituting the spatial and temporal derivative with the chosen finite differences forms, +an explicit update of \(\tilde{A}^{n+1}_i\), function of \(\tilde{A}^{n}_i\), \(\tilde{A}^{n}_{i-1}\), \(\tilde{A}^{n}_{i+1}\), \(\tilde{A}^{n-1}_i\) and \(\chi^{n}_i\) can be easily found. +In the reduced dispersion scheme, also the values \(\tilde{A}^{n}_{i-2}\), \(\tilde{A}^{n}_{i+2}\) are necessary for the update. +The locality of the abovementioned finite difference stencils allows a parallelization with well known techniques and the extension to the other geometries is straightforward. +The discretization of the transverse components of the Laplacian in Eq. (50) in Cartesian geometry uses the central finite differences defined above, applied to the y and z axes. +In cylindrical geometry (see Azimuthal modes decomposition), the transverse part of the Laplacian is discretized as:

+
+\[D^2_{\perp, cyl}\tilde{A}\rvert^{n}_{i,j} = \frac{\tilde{A}^n_{i,j+1}-2\tilde{A}^n_{i,j}+\tilde{A}^n_{i,j-1}}{\Delta r^2} + \frac{1}{r_j}\frac{\tilde{A}^n_{i,j+1}-\tilde{A}^n_{i,j-1}}{2\Delta r},\]
+

where \(j, r, \Delta r\) are the transverse index, the distance from the propagation axis and the radial cell size respectively.

+
+
+
+

References

+
+
Mora1997(1,2,3)
+

P. Mora and T. M. Antonsen Jr, Physics of Plasmas 4, 217 (1997)

+
+
Quesnel1998(1,2,3)
+

B. Quesnel and P. Mora, Physics Review E 58, 3719 (1998)

+
+
Gordon2000(1,2)
+

D. F. Gordon et al.,IEEE Transactions on Plasma Science 28, 4 (2000)

+
+
Huang2006
+

C. Huang et al., Journal of Physics: Conference Series 46, 190 (2006)

+
+
Cowan2011(1,2,3,4)
+

B. M. Cowan et al., Journal of Computational Physics 230, 61 (2011)

+
+
Benedetti2012
+

C. Benedetti et al., Proceedings of the 11th International Computational Accelerator Physics Conference (ICAP 2012)

+
+
Benedetti2008(1,2)
+

C. Benedetti et al., IEEE Transactions on Plasma Science 36, 1790 (2008)

+
+
Terzani(1,2,3,4,5)
+

D. Terzani and P. Londrillo, Computer Physics Communications 242, 49 (2019)

+
+
MassimoPPCF2019
+

F. Massimo et al., Plasma Phys. Control. Fusion (2019)

+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/multiphoton_Breit_Wheeler.html b/Understand/multiphoton_Breit_Wheeler.html new file mode 100644 index 000000000..2c6aab1d6 --- /dev/null +++ b/Understand/multiphoton_Breit_Wheeler.html @@ -0,0 +1,810 @@ + + + + + + + + + Multiphoton Breit-Wheeler pair creation — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Multiphoton Breit-Wheeler pair creation

+

The multiphoton Breit-Wheeler (\(\gamma + n\omega \rightarrow e^- + e^+\)), +also referred to as +the nonlinear Breit-Wheeler, corresponds to the decay of a +high-energy photon into a pair of electron-positron +when interacting with a strong electromagnetic field.

+

In the vacuum, the electromagnetic field becomes nonlinear from the Schwinger +electric field \(E_s = 1.3 \times 10^{18}\ \mathrm{V/m}\) corresponding +to an intensity of \(10^{29}\ \mathrm{Wcm^{-2}}\) for +\(\lambda = 1\ \mu m\). In such a field, spontaneous apparitions of electron-positron pairs from +the nonlinear vacuum are possible. If this field is not reachable in the laboratory +frame, it will be very close in the boosted frame of highly-accelerated electrons. At +\(10^{24}\ \mathrm{Wcm^{-2}}\), a Lorentz factor of \(\gamma \sim 10^5\) +is required to reach the Schwinger limit. +This is the reason why quantum electrodynamics effects and in particular strong- +field pair generation is accessible with the extreme-intensity lasers (multipetawatt lasers).

+

As for electrons or positrons, the strength of QED effects depends +on the photon quantum parameter:

+
+(35)\[\chi_\gamma = \frac{\gamma_\gamma}{E_s} \sqrt{ \left( \mathbf{E}_\perp ++ \mathbf{c} \times \mathbf{B} \right)^2 }\]
+

where +\(\gamma_\gamma = \varepsilon_\gamma / m_e c^2\) is the photon normalized energy, +\(m_e\) the electron mass, +\(c\) the speed of light in vacuum, +\(\mathbf{E}_\perp\) is the electric field orthogonal to +the propagation direction of the photon, +\(\mathbf{B}\) the magnetic field.

+
+
+

Physical model

+

The energy distribution of the production rate of pairs by a hard photon +is given by the Ritus formulae

+
+(36)\[\frac{d^2N_{BW}}{d \chi_{\pm} dt} = \frac{\alpha_f m_e^2 c^4}{\pi \sqrt{3} \hbar \varepsilon_\gamma \chi_\gamma} +\int_{x}^{+\infty}{\sqrt{s} K_{1/3} \left( \frac{2}{3} s^{3/2} \right) ds - \left( 2 - \chi_\gamma x^{3/2} \right) K_{2/3} \left( \frac{2}{3} x^{3/2} \right) }\]
+

where \(x = \left( \chi_\gamma / (\chi_{-} \chi_{+}) \right)^{2/3}\). +The parameters \(\chi_{-}\) and \(\chi_{+}\) are the respective Lorentz +invariant of the electron and the positron after pair creation. +Furthermore, one has \(\chi_- = \chi_\gamma - \chi_+\) meaning that \(\chi_-\) +and \(\chi_+\) can be interchanged.

+

The total production rate of pairs can be written

+
+(37)\[\frac{dN_{BW}}{dt} = \frac{\alpha_f m_e^2 c^4}{ \hbar \varepsilon_\gamma} \chi_\gamma T \left( \chi_\gamma \right)\]
+

where

+
+(38)\[T \left( \chi_\gamma \right) = \frac{1}{\pi \sqrt{3} \chi_\gamma^2 } +\int_{0}^{+\infty}{\int_{x}^{+\infty}{\sqrt{s} K_{1/3} \left( \frac{2}{3} s^{3/2} +\right) ds - \left( 2 - \chi_\gamma x^{3/2} \right) K_{2/3} \left( \frac{2}{3} x^{3/2} \right) }} d\chi_-\]
+

A photon of energy \(\varepsilon_\gamma\) traveling in a constant electric field \(E\) has a Lorentz +parameter equal to \(\chi_\gamma = \varepsilon_\gamma E / (E_s m_e c^2)\).

+

We consider the case where photon interact in a constant uniform electric field. +For a field of amplitude \(E = 500 m_e \omega c / e\), the energy +distribution and the production rate of pair creation as a function of \(\chi_\gamma\) are +plotted in Fig. 37. It shows that the total production +rate of electron-positron pairs rises rapidly to reach a peak around +\(\chi_\gamma = 10\) with almost a pair generated per femtosecond. +Under \(\chi_\gamma = 0.1\), the production rate is very weak with +less than a pair after 100 picoseconds of interaction. +Above \(\chi_\gamma = 10\), the production decreases slowly with +\(\chi_\gamma\).

+

The right subplot in Fig. 37 gives the probability +for a photon to decay into a pair as a function of the energy given to the electron +(using approximation \(\chi_\gamma / \chi_- = \gamma_\gamma / \gamma_-\)) +for a field of amplitude \(E = 500 m_e \omega c / e\). +It can also be seen as the pair creation energy distribution. +The distribution is symmetric with respect to \(\chi_- / \chi_\gamma = 1/2\). +Below \(\chi_\gamma = 10\), The maximum probability corresponds to +equal electron-positron energies \(\chi_- = \chi_+ = \chi_\gamma / 2\). +Above this threshold, the energy dispersion increases with \(\chi_\gamma\).

+
+../_images/synchrotron_pairs_dNdt.png +
+

Fig. 37 (left) - Normalized total pair production distribution given by Eq. (37). +(right) - Normalized pair creation \(\chi\) distribution given by Eq. (36).

+
+
+
+
+
+

Stochastic scheme

+

The Multiphoton Breit-Wheeler is treated with a Monte-Carlo process similar +to the nonlinear inverse Compton Scattering +(see the radiation reaction page). +It is close to what has been done in +[Duclous2011], [Lobet2013], [Lobet2015].

+

The first preliminary step consists +on introducing the notion of macro-photon. Macro-photons are simply the equivalent of +macro-particles (see the macro-particle section) +extended to photons. +There are defined by a charge and a mass equal to 0. The momentum is substituted +by the photon momentum \(\mathbf{p}_\gamma = \hbar \mathbf{k}\) where +\(\mathbf{k}\) is the wave vector. +The momentum contains the photon energy so that +\(\mathbf{p}_\gamma = \gamma_\gamma m_e \mathbf{c}\). +The definition of the photon Lorentz factor is therefore also slightly different +than particles.

+

1. An incremental optical depth \(\tau\), initially set to 0, is assigned to the macro-photon. +Decay into pairs occurs when it reaches the final optical depth \(\tau_f\) +sampled from \(\tau_f = -\log{(\xi)}\) where \(\xi\) is a random number in \(\left]0,1\right]\).

+

2. The optical depth \(\tau\) evolves according to the photon quantum parameter +following:

+
+(39)\[\frac{d\tau}{dt} = \frac{dN_{BW}}{dt}\left( \chi_\gamma \right)\]
+

that is also the production rate of pairs +(integration of Eq. (36)).

+

3. The emitted electron’s quantum parameter \(\chi_-\) is computed by +inverting the cumulative distribution function:

+
+(40)\[P(\chi_-,\chi_\gamma) = \frac{\displaystyle{\int_0^{\chi_-}{ +\frac{d^2N_{BW}}{d \chi dt} d\chi}}}{\displaystyle{\int_0^{\chi_\gamma}{\frac{d^2N_{BW}}{d \chi dt} d\chi}}}\]
+

The inversion of \(P(\chi_-,\chi_\gamma)=\xi'\) is done after drawing +a second random number +\(\xi' \in \left[ 0,1\right]\) to find \(\chi_-\). +The positron quantum parameter is \(\chi_+ = \chi_\gamma - \chi_-\).

+

4. The energy of the emitted electron is then computed: +\(\varepsilon_- = mc^2 \gamma_- = mc^2 \left[ 1 + \left(\gamma_\gamma - 2\right) \chi_- / \chi_\gamma \right]\). +If \(\gamma_\gamma < 2\), the pair creation is not possible since the photon +energy is below the rest mass of the particles.

+

5. The photon momentum is then updated. +Propagation direction is the same as for the photon. Pairs are created at the +same position as for the photon. The weight is conserved. It is possible to +create more than a macro-electron or a macro-positron in order to improve +the phenomenon statistics. In this case, the weight of each macro-particle is +the photon weight divided by the number of emissions.

+
+
+
+

Implementation

+

C++ classes for the multiphoton Breit-Wheeler process are located +in the directory src/MultiphotonBreitWheeler. +In Smilei, the multiphoton Breit-Wheeler process is not incorporated +in the photon pusher in order to preserve vector performance of the latter one.

+

Description of the files:

+
    +
  • Class MultiphotonBreitWheelerTables: This class initializes and manages the +multiphoton Breit-Wheeler parameters. +It contains the methods to read the tables and data structures to store them. +It also contains default embebded tables. +Then, it provides several methods to look for values in the tables for the Monte-Carlo process +and compute different parameters used by this physical mechanism.

  • +
  • Class MultiphotonBreitWheeler: this class contains the methods to +perform the Breit-Wheeler Monte-Carlo process described in the previous section).

  • +
  • Class MultiphotonBreitWheelerFactory: this class is supposed to +manage the different Breit-Wheeler algorithms. +For the moment, only one model is implemented.

  • +
+

If the multiphoton Breit-Wheeler is activated for a photon species, the factory +will initialize the instance Multiphoton_Breit_Wheeler_process of +the class MultiphotonBreitWheeler +declared in the corresponding species (see species.cpp).

+

The multiphoton Breit-Wheeler Monte-Carlo process is performed in the method dynamics of species. +It is called after the particle field interpolation (field gathering), +after ionization and radiation reaction and before the particle pusher. +At this stage, the new particles are stored in a temporary buffer called new_pair. +This is an array of two instances of Particles. +It is declared in Multiphoton_Breit_Wheeler_process. +Particles are imported in the main species particle arrays +(particles object in species) only after the current deposition +and before the boundary conditions using the method importParticles +of the class Particles.

+
+
+
+

Tables

+

External tables can be generated using an external tools called smilei_tables. +More information can be found in Generation of the external tables.

+
+
+
+

Benchmarks

+
+

Synchrotron, 2D

+

In this configuration, a mono-energetic bunch of photons is initialized +in a constant uniform strong magnetic field. +The photons decay into pairs via the multiphoton Breit-Wheeler progressively. +In this particular case, the generated electrons and positrons do not radiate +in order to capture the emission energy spectrum. +Two cases are simulated with different +initial quantum parameters:

+
    +
  • Case 1: \(\chi_{\gamma,0} = 1\), \(B = 270\), \(\gamma_{\gamma,0} = 1500\)

  • +
  • Case 2: \(\chi_{\gamma,0} = 20\), \(B = 1000\), \(\gamma_{\gamma,0} = 8125\)

  • +
+

The results of the first case are shown in +Fig. 38. The two first figures +represent respectively the electron (left) and the positron energy (center) spectrum at the end +of the simulation when all photons have been converted into pairs. +The last one on the right is the time evolution of the photon (green), electron (blue), +positron (orange) and total (black) kinetic energy. +The quantum parameter of all photons is initially equal to +\(\chi_{\gamma,0} = 1\). According to Fig. 37, +we are located in an area of the energy distribution where electrons and +positrons are more likely to be created with almost the same energy +(\(\chi_{+} = \chi_{-} =\chi_{\gamma,0} /2\)). +This is confirmed in Fig. 38. +Electron and positron energy spectra are well similar, symmetric and centered +at half the initial photon energy equal to \(\gamma = 750\). +The energy balance (right figure) shows that positron and electron kinetic energies +have the same behaviors and converge to half the initial photon energy +at the end of the simulation. +The total energy is well constant and conserved in time.

+
+../_images/synchrotron_pairs_energy_spectra_chi1.png +
+

Fig. 38 (left) - Electron energy spectrum at the end of the run. +(middle) - Positron energy spectrum at the end of the run. +(right) - Time evolution of the photon (green), electron (blue), positron +(orange) and total (black) normalized energy \(U / U_{tot}\).

+
+
+

The results of the second case are shown in +Fig. 39 as for the first case. +Here, the quantum parameter of all photons is initially equal to +\(\chi_{\gamma,0} = 20\). This means that contrary to the previous case, +the probability to generate electrons and positrons of similar energy +is not the most significant. +As in Fig. 37, the energy spectra exhibit two maximums. +This maximums are located approximately at 10% and 90% of the initial photon +energy of \(\gamma_{\gamma,0} = 8125\). +Electron and positron spectra are nonetheless similar and symmetric in respect +to half the initial photon energy. +Again, the energy balance (right figure) shows that positron and electron kinetic energies +have the same behaviors and converge to half the initial photon energy +at the end of the simulation. +The total energy is well constant and conserved in time.

+
+../_images/synchrotron_pairs_energy_spectra_chi20.png +
+

Fig. 39 (left) - Electron energy spectrum at the end of the run. +(middle) - Positron energy spectrum at the end of the run. +(right) - Time evolution of the photon (green), electron (blue) +and positron (orange) +normalized energy \(U / U_{tot}\).

+
+
+

The benchmark tst2d_10_multiphoton_Breit_Wheeler is very close to +the second case presented here.

+
+
+

Counter-propagating plane wave, 1D

+

In this test case, a bunch of electrons is initialized at the right side +of the domain with an initial energy of 4 GeV. The bunch is made to collide head-on +with a laser plane wave injected from the left side of the domain. +The laser has a maximal intensity of \(10^{23}\ \mathrm{Wcm^{-2}}\). +It is circularly polarized and has a temporal Gaussian profile with a +FWHM (full width at half maximum) of 10 periods +(approximately corresponding to 33 fs). +A wavelength of \(1\ \mathrm{\mu m}\) is considered.

+

This configuration is one of the most efficient to trigger QED effects +since it maximizes the particle and photon quantum parameters.

+

By interacting with the laser pulse, the high-energy electron will first +radiate high-energy gamma photons that will be generated as macro-photons by the code +via the nonlinear Compton scattering. +These photons are generated in the same direction of the electrons with an energy up +to almost the electron kinetic energy. +Then, the macro-photons interact in turn with the laser field and can decay +into electron-positron pairs via the multiphoton Breit-Wheeler process.

+

The first plot on left of Fig. 40 shows the energy +balance of the simulation. +The second plot on the center of Fig. 40 shows the +time evolution of the number of macro-electrons, macro-positrons and macro-photons. +The electron bunch energy rapidly drops +after entering the laser field around \(t = 240 \omega_r^{-1}\). +At the same time, many macro-photons are generated by the particle number evolution +as shown in Fig. 40. The photon energy therefore rapidly rises +as the electron energy decreases.

+
+../_images/counter_pair_smilei.png +
+

Fig. 40 (left) - Energy balance of the simulation. In the legend, Photon represents the macro-photon +energy and Radiation represents the radiated energy excluding the macro-photons. +(center) - Time evolution of the number of macro-electrons (blue), +macro-positrons (orange) and macro-photons (green) in the simulation. +(right) - Final energy spectrum of the electrons (blue), positrons (orange), +and photons (green).

+
+
+

The multiphoton Breit-Wheeler generation of electron-positron starts latter +when emitted macro-photons enters the high-intensity region of the laser. +This is revealed by the yield of macro-positron. +When electrons and positrons have lost sufficient energy, they can not produce +macro-photons anymore and radiated energy is therefore added directly +in the energy balance. +This is shown by the red curve of the energy balance of Fig. 40. +The radiated energy rises after the main phase of the macro-photon generation after +\(t = 250 \omega_r^{-1}\). The radiated energy contains the energy from +the continuous radiation reaction model and from the discontinuous Monte-Carlo +if the energy of the emitted photon is below \(\gamma = 2\). +Under this threshold, the photon can not decay into electron-positron pair. +It is therefore useless and costly to generated a macro-photon.

+

The final electron, positron and photon energy spectra are shown in +the right plot of Fig. 40. At the end of the simulation, +the photon spectrum is a broad decreasing profile ranging from 1 MeV to 1 GeV. +This is the consequence of two main facts:

+
    +
  • The highest is the photon energy, more important is the probability to decay into pairs.

  • +
  • As electron and positron lose energy, they continue to radiate smaller ans smaller photon energy.

  • +
+

Electron and positron spectra are very similar ranging from 20 MeV +to mainly 200 MeV. +Few particles have an energy above this threshold up to 1 GeV.

+

This corresponds to the benchmark benchmark/tst1d_10_pair_electron_laser_collision.py.

+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/numerical_techniques.html b/Understand/numerical_techniques.html new file mode 100644 index 000000000..f6bce7fe8 --- /dev/null +++ b/Understand/numerical_techniques.html @@ -0,0 +1,508 @@ + + + + + + + + + Advanced numerical techniques — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ + + + +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Advanced numerical techniques

+

In specific situations, advanced techniques may help reduce the simulation +run time.

+ +
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/parallelization.html b/Understand/parallelization.html new file mode 100644 index 000000000..a7701304d --- /dev/null +++ b/Understand/parallelization.html @@ -0,0 +1,718 @@ + + + + + + + + + Parallelization basics — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Parallelization basics

+

For high performances, Smilei uses parallel computing, +and it is important to understand the basics of this technology. Parallel simply +means that many processors can run the simulation at the same time, but there is +much more than that.

+
+
+

Nodes, cores, processes and threads

+
+

Warning

+

The terminology of nodes, cores, processes and threads is not universal. +Depending on the computer, software (etc.), they can have various meanings. +Typical examples: socket instead of node; cpu instead of core; +task instead of process.

+
+

Supercomputers have complex architectures, mainly due to their processors +capability to work together on the same memory space. More precisely, +the smallest computing units, called cores, +are grouped in nodes. All the cores in one node share the same memory space. +In other terms, the cores of the same node can operate on the same data, at the +same time; no need for sending the data back and forth. +This hardware architecture is summarized in Fig. 2.

+
+../_images/NodesCoresThreads.png +
+

Fig. 2 Simplified super-computer architecture.

+
+
+

This same figure shows how the software is structured. +A thread is essentially the sequence of instructions from the program. +It is executed by one core, and a given core can operate only one thread at a time +(if two threads are associated with one core, they are handled one after the other). +A process refers to a group of threads which are assigned to a single (shared) +memory space: one process will not handle the memory of another process. The +process provides the communication between its threads so that they can work +on their memory space without conflicts.

+

The association between the software threads and the hardware cores can be more +complicated. Fig. 3 shows an example where two processes share the +same node. In this case, we illustrate the memory of this node as split in two parts because +the two processes cannot access to the same memory.

+
+../_images/NodeWith2Processes.png +
+

Fig. 3 An example where two processes share the same node.

+
+
+

Note that many computer architectures have a different meaning for nodes. +Indeed, their nodes have a memory space that is already split into several +sockets. In this situation, one process is associated with one socket.

+
+
+
+

Managing processes and threads

+

Although two processes do not share their memory, they must sometimes synchronize their +advance in the execution of the program, or communicate data between each other. +For instance, to calculate the total energy in the simulation, they must communicate +their contribution to the others and compute the sum. +In Smilei, these tasks are accomplished by the Message Passing Interface (MPI) protocol.

+

At the thread level, the communications do not work in the same manner because threads +already share their data. However, they need synchronization and management to decide +which core handles which thread. In Smilei, this is accomplished by the OpenMP protocol.

+

An illustration of the roles of MPI and OpenMP is provided in Fig. 4

+
+../_images/MPIandOpenMP.png +
+

Fig. 4 MPI handles process-to-process communications, while OpenMP manages threads in a given process.

+
+
+
+
+
+

Decomposition of the whole domain

+

Traditionally, PIC codes would +split the spatial grid into \(N\) portions, where \(N\) is the number +of cores. Each core would manage its own portion on a separate memory space, +and information is communicated between cores using the MPI protocol. +Smilei proposes a different approach: +portions are much smaller so that each core handle many portions.

+

Let us explain this difference in details. +Fig. 5 gives an example of a grid containing 960 cells. +It is decomposed in \(4\times8 = 32\) portions, called patches. +Each patch has \(5\times6\) cells. +This patch size is actually reasonable for Smilei, whereas +traditional PIC codes would have much larger portions.

+

The issue is now to decide where these patches will be stored in the memory, +and to choose which cores should handle which patches. +Recall that all the cores handled by one process share the same memory: +we will refer to this memory as an MPI patch collection. +This means that one process manages one exclusive MPI patch collection. +Fig. 5 shows an example with the 32 patches split +in 5 collections recognized by their different colors. +Note that these collections are connex, but not necessarily rectangular.

+
+../_images/PatchDecomposition.svg +
+

Fig. 5 Decomposition of a grid in patches and MPI patch collections.

+
+
+

Each MPI patch collection is handled by all the threads of the process. For example, if there are +4 threads in the process that handles the patch collection colored in green, this means the +4 threads will handle 10 patches. The 4 threads will work in parallel, patch by patch, +until all patches are done.

+
+../_images/PatchDecompositionNodes.svg +
+

Fig. 6 Each process handles one collection of patches. Patches are treated one by one by +the available threads.

+
+
+

The great advantage of this scheme is that, inside one MPI patch collection, the threads do not +need to wait for their colleagues to go to the next patch; they can continue working on +the available patches, thus avoiding long waiting times. +This is a form of local dynamic load balancing.

+
+
+
+

Load balancing between MPI patch collections

+

As we just explained, threads treat patches asynchronously, thus balancing their computational loads. +Indeed, some patches may have more particles than others and therefore represent a heavier load. +In the meantime, other threads can take care of several lighter patches. +Unfortunately, it may not be sufficient. +When one MPI patch collection holds more total load than the others, it will take a long +time to compute, while the other processes have already finished and wait for this one. +This can cause large delays.

+

Smilei has an algorithm able to reduce this imbalance by exchanging patches +from one MPI patch collection to another. A process that has too much load will give patches to +other processes in order to reduce the size of its MPI patch collection. This algorithm is based +on an ordering of the patches by a Hilbert curve, as drawn in +Fig. 7. One MPI patch collection contains only patches that contiguously +follow this curve. If this “portion” of the curve has too much load, it will send +some patches to the portions ahead or after, along the same curve. By repeating this +operation every now and then, we ensure that all regions manage an equitable computational load.

+
+../_images/PatchDecompositionHilbert.svg +
+

Fig. 7 The shape of the Hilbert curve which determines the patch order.

+
+
+
+
+
+

Practical setup

+

The user must choose the number of processes and threads (see Run). +Furthermore, they must define how the whole domain is split into patches +(see number_of_patches). Here are a few rules and recommendations +to help deciding this splitting.

+
    +
  • In each direction \(x\), \(y\), \(z\), +the number of patches must be a power of 2.

  • +
  • The minimum patch size depends on the order of the interpolation_order. +For the default order 2, the minimum size is 6 cells in each direction.

  • +
  • Have reasonably small patches. +Small patches are beneficial to efficient load balancing and cache use, +but they increase the synchronization costs. +The optimal patch size depends strongly on the type of simulation. +Use small patches (down to 6x6x6 cells) if your simulation has small regions with many particles. +Use larger patches (typically 100x100 or 25x25x25 cells) otherwise.

  • +
  • For high performances, each process should own more patches than threads. +And even many more if possible. This means that the total number of patches +should be larger than the total number of threads, at the very least.

  • +
  • Have only as many MPI processes as sockets in order to optimize the memory distribution. +Less MPI processes is not possible because they cannot be split among separate memory spaces. +More MPI processes is not recommended because they are not as efficient as OpenMP threads.

  • +
  • Have as many threads per process as cores per socket. +If you have less threads than cores, you will not be using all your cores. +Use more threads than cores only if your architecture supports it well.

  • +
  • Use dynamic scheduling for the OpenMP protocol, by setting the environment variable:

    +
    export OMP_SCHEDULE=dynamic
    +
    +
    +

    This affects only the particles treatment, which will be assigned to threads dynamically +(fields are always assigned statically).

    +
  • +
  • Take these recommendations with a pinch of salt. Do your own tests and send us feedback!

  • +
+
+
+
+

MPI patch collections forming rectangular areas

+

For some plasma shapes, following the hilbert +curve (as described above) may not be efficient. +In Smilei, it is possible to use a classical grouping of patches in rectangles +or cubes.

+

In the namelist:

+
Main(
+    ...
+    patch_arrangement = "linearized_XY",  # 2D
+    patch_arrangement = "linearized_XYZ", # 3D
+    ...
+)
+
+
+

Those linearized decompositions are oriented to contiguously store patches +along the innermost direction (Z, then Y, then X). +The storage order can be modified through following options

+
Main(
+    ...
+    patch_arrangement = "linearized_YX",  # 2D
+    patch_arrangement = "linearized_ZYX", # 3D
+    ...
+)
+
+
+

These options has several consequences:

+
    +
  • No more restrictions on the number of patches per direction.

  • +
  • Load balancing is not available.

  • +
  • To use the Fields diagnostics, the number of patches per process must allow +a rectangular tessellation of the simulation box. For instance:

    +
      +
    • 8 x 8 patches on 4 MPI process : ok, each process own 2 x 8 patches slice.

    • +
    • 6 x 8 patches on 4 MPI process : not ok, each process owns 12 patches which overlap 2 tiles.

    • +
    +
  • +
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/particle_injector.html b/Understand/particle_injector.html new file mode 100644 index 000000000..5e815ddda --- /dev/null +++ b/Understand/particle_injector.html @@ -0,0 +1,539 @@ + + + + + + + + + Particle Injector — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Particle Injector

+

Particle injectors provide a continuous flow of fresh +macro-particles from the boundaries into the simulation domain.

+
+
+

The method implemented in Smilei

+

In the PIC loop structure, the particle injection occurs +after current projection on the grid, particle sorting and synchronizations. +Injected macro-particles therefore do not contribute to the current and fields +of the current iteration but they are taken into account in the diagnostics.

+
+../_images/particle_injector.png +
+
+
+
+

Recommendation

+
    +
  • Although a single species may be injected, we recommend to inject both +positively and negatively charged species at the same time to ensure +a neutral plasma. To strengthen neutrality, species may be created at +the same positions.

  • +
  • If the particle momentum is drawn from a Maxwellian, we recommend to use a random +positionning instead of the regular one. +Regular positionning may induce numerical effects such as loss of charge and spurious field near the boundary. +The reason is explained in the following figure. +The regular positionning works when injecting a drifting cold plasma with a drift velocity +sufficiently high to let the particles entering the simulation domain.

  • +
+
+../_images/particle_injector_regular_random.png +
+
+
+
+

Implementation

+

The particle injector algorithm is coded in the file +Patch/VectorPatch.cpp in the function injectParticlesFromBoundaries.

+

The class ParticleInjector manages the injector’s parameters and properties, +while new macro-particles are initialized using the class ParticleCreator.

+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/particle_merging.html b/Understand/particle_merging.html new file mode 100644 index 000000000..4403dc7e7 --- /dev/null +++ b/Understand/particle_merging.html @@ -0,0 +1,977 @@ + + + + + + + + + Particle Merging — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Particle Merging

+
+

Be careful when using this module and read +carefully the documentation.

+

Note that the nomenclature might change

+
+

The ability to merge macro-particles can speed-up the code efficiency +and reduce the memory footprint in some specific simulation scenarii:

+
    +
  • When macro-particles accumulate in a fraction of the simulation domain +hence strongly worsening the load imbalance (ex: Weibel collision shocks, +laser wakefield electron acceleration).

  • +
  • When macro-particles are generated in a large quantity due to some +additional physical mechanisms (ionization, macro-photon emission, +QED pair production…)

  • +
  • When macro-particles travel in large quantities outside interesting +physical regions.

  • +
+

Smilei’s merging method is inspired from that of M. Vranic +[Vranic2005] with some additions.

+

Please refer to that doc for +the definitions in the namelist file.

+
+
+

Understand the method

+

The method of M. Vranic, illustrated (in 2D) in +Fig. Fig. 46, consists in 3 main steps:

+
    +
  1. Decompose macro-particles into groups according to their location so that +they have nearby positions. +In Smilei, macro-particles are sorted by field cells, +even though, in Vranic et al., the decomposition can be larger +than just one cell.

  2. +
  3. Subdivide groups into sub-groups in momentum space so that macro-particles +share close kinetic properties.

  4. +
  5. Merge macro-particles located in the same sub-group into 2 new +macro-particles, while conserving charge, energy and momentum.

  6. +
+
+../_images/vranic_particle_merging.png +
+

Fig. 46 Basic description of M. Vranic merging method in 2D geometry.

+
+
+

This method has several advantages:

+
    +
  • it is relatively easy to understand and implement,

  • +
  • it has a relatively low computational cost,

  • +
  • it is efficient without impacting significantly the physical results.

  • +
+
+

Warning

+

This assumes that the parameters are adequately tuned. +Otherwise, the macro-particle merging can affect the final simulation results.

+
+
+

1. Momentum sub-groups

+

The momentum (\(\mathbf p\)) space may be decomposed either in +cartesian (\(p_x\), \(p_y\), \(p_z\)) +or spherical (\(p\), \(\theta\), \(\phi\)) coordinates.

+

In each cell, for each coordinate \(\alpha\):

+
    +
  • we compute the overall limits in momentum space.

  • +
  • This space is divided in \(N_{\alpha}\) sub-groups (as prescribed by the +user) of length \(\Delta_{\alpha}\).

  • +
+
+../_images/vranic_momentum_discretization.png +
+

Fig. 47 Cartesian and spherical momentum discretizations, in 2D.

+
+
+

The spherical components are related to the Cartesian momentum components by:

+
+(57)\[\begin{split}p = \sqrt{ p_x^2 + p_y^2 + p_z^2 }\\ +\theta = \arctan{ \left( p_y / p_x \right)}\\ +\phi = \arcsin{\left( p_z / p \right)}\end{split}\]
+
+../_images/spherical_coordinates.png +
+

Fig. 48 Spherical coordinates used for the momentum cell discretization.

+
+
+

Since macro-particle momentum components are defined in Cartesian geometry +by default, the spherical discretization induces small additional computation. +However, it makes the merging process more accurate. +Indeed, in the Cartesian discretization, the maximum angle between the momentum +directions of two macro-particles located in the same sub-group +depends on the sub-group. +For instance, in the cell adjacent to the origin \(p_x = p_y = p_z = 0\), +this angle equal up to \(\pi / 2\) whatever the discretization. +The spherical geometry ensures that the merging accuracy depends +on the discretization and is similar for all momentum cells. +The overhead induced by the change of geometry is +a small fraction of the entire process.

+
+
+

2. Merging algorithm for massive macro-particles

+

In step 3, for each sub-group containing more than 4 macro-particles, +the algorithm merges them into 2 macro-particles. +Let us denote by \(k\) the macro-particles in a given sub-group +\(\mathrm{M}\), their weights by \(w_k\), their energies +by \(\varepsilon_k\) and their momenta by \(\mathbf{p}_k\). +We start by computing total quantities:

+
+(58)\[\begin{split}w_t = \sum_{k \in \mathrm{M}}{w_k}\\ +\varepsilon_t = \sum_{k \in \mathrm{M}}{w_k \varepsilon_k}\\ +\mathbf{p}_t = \sum_{k \in \mathrm{M}}{w_k \mathbf{p}_k}\\\end{split}\]
+

In spherical geometry, the total angles are also defined:

+
+(59)\[\begin{split}\theta_t = \sum_{k \in \mathrm{M}}{w_k \theta_k}\\ +\phi_t = \sum_{k \in \mathrm{M}}{w_k \phi_k}\end{split}\]
+

Merging all the macro-particles into one cannot always conserve weight, +energy and momentum. Vranic et al. propose to merge into 2 macro-particles:

+
+(60)\[\begin{split}w_t = w_a + w_b \\ +\mathbf{p}_t = w_a \mathbf{p}_a + w_b \mathbf{p}_b \\ +\varepsilon_t = w_a \varepsilon_a + w_b \varepsilon_b\end{split}\]
+

The following energy-momentum relation has to be satisfied +for both macro-particles a and b:

+
+(61)\[\varepsilon^2 = p^2 + 1\]
+

To simplify the problem, Vranic et al assume that merged macro-particles +have the same weight \(w_a = w_b = w_t / 2\) +and same energy \(\varepsilon_a = \varepsilon_b = \varepsilon_t / w_t\).

+
+../_images/vranic_planar_merging.png +
+

Fig. 49 View of the plane made by vector \(\mathbf{d}\) and \(\mathbf{p_t}\). +The corresponding Cartesian frame is given by \((\mathbf{e_1}, \mathbf{e_2}, \mathbf{e_3})\).

+
+
+

As illustrated in Fig. 49, it follows that:

+
+(62)\[\begin{split}\mathbf{p}_a + \mathbf{p}_b = \frac{2 \mathbf{p}_t}{w_t} \\ +\mathbf{p}_{a,\perp} = - \mathbf{p}_{b,\perp} \\ +\mathbf{p}_{a,\parallel} = \mathbf{p}_{b,\parallel} = \mathbf{p_t} / w_t\end{split}\]
+

We denote by \(\omega\) the angle between +\(\mathbf{p_a}\) and \(\mathbf{p_t}\) so that:

+
+(63)\[\cos{\omega} = \frac{\mathbf{p_t}}{w_t \mathbf{p_a}}\]
+

We denote by \(\mathbf{d}\) the coordinate vector of the sub-group +where the macro-particles are located.

+
+../_images/vranic_momentum_cell_vector.png +
+

Fig. 50 Sub-group coordinate vector in Cartesian and spherical geometries.

+
+
+

The plane \((\mathbf{e_1},\mathbf{e_2})\) is the plane made by +the vectors \(\mathbf{p_t}\) and \(\mathbf{d}\). +We choose that it contains \(\mathbf{p_a}\) and \(\mathbf{p_b}\) +so that we have only one possible solution.

+

The vectors \(\mathbf{e_1}\) and \(\mathbf{e_2}\) are given by the +following formula in the PIC code’s momentum frame:

+
+(64)\[\mathbf{e_1} = \mathbf{p_t} / p_t\]
+
+(65)\[\mathbf{e_3} = \frac{ \mathbf{d} \times \mathbf{e_1} }{d}\]
+
+(66)\[\mathbf{e_2} = \mathbf{e_1} \times \mathbf{e_3}\]
+

Finally, the new macro-particle momentums are:

+
+(67)\[\begin{split}\mathbf{p_a} = p_a \left( \cos{\left( \omega \right)} \mathbf{e_1} + \sin{\left(\omega\right)} \mathbf{e_2} \right) \\ +\mathbf{p_b} = p_b \left( \cos{\left( \omega \right)} \mathbf{e_1} - \sin{\left(\omega\right)} \mathbf{e_2} \right)\end{split}\]
+
+../_images/vranic_3d_schematics.png +
+

Fig. 51 3D view of the different vectors involved in the merging method. +Generated by this python script.

+
+
+

The new macro-particle positions are assigned the position of one of +the merged macro-particles. +We have tested to assign them randomly +or to the first macro-particles of the merged list and we did +not observe any difference.

+

This algorithm does not work when the total momentum \(\mathbf{p}_t\) +of the macro-particles to be merged is in the direction of \(\mathbf{d}\). +In this case \(|| \mathbf{e_3} || = 0\) and the system cannot be solved. +In this specific case, the merging is not performed.

+
+
+

3. Merging algorithm for macro-photons

+

Macro-photons can be merged with the same algorithm, the only difference +being that the momentum norm is equal to the energy \(\varepsilon = p\).

+

When the total momentum \(\mathbf{p}_t\) is in the direction +of \(\mathbf{d}\), macro-photons can be merged into a single one, +contrary to the massive macro-particles case, +since \(\varepsilon_t = || \mathbf{p}_t ||\). +This specific situation is implemented in the code.

+
+
+
+
+

Implementation details

+

The Vranic merging method is implemented with both Cartesian +and the spherical discretizations in the directory src/Merging. +It is considered as a particle operator and the merging algorithm is +managed with a factory (MergingFactory.h) as +any operator with multiple implementations. +The Cartesian implementation is done in the class MergingVranicCartesian +and the spherical one in MergingVranicSpherical.

+

For both methods, the implemented algorithm is very similar.

+
+

For each cell:

+
    +
  1. Initialization of the sub-group discretization

  2. +
  3. Computation of the direction vectors (\(\mathbf{d}\)): +this step depends on the discretization and +can be efficiently vectorized.

  4. +
  5. Computation of the sub-group indexes for each macro-particle. +Efficiently Vectorizable.

  6. +
  7. Computation of the number of particles per sub-group. +Not vectorizable because of random memory accesses.

  8. +
  9. Computation of the index of each sub-group in the +sorted array of particles (only the particle indexes are sorted). +Not vectorizable.

  10. +
  11. Sorting of the macro-particles per sub-groups, the index +previously computed determines where +each sub-group starts. Not vectorizable.

  12. +
+

Then, for each sub-group:

+
    +
  1. Division of the macro-particles of the sub-groupinto +packets (size depends on the user parameters merge_min_packet_size +and merge_max_packet_size)

  2. +
  3. Merge of the packs using the previously described Vranic algorithm. +Partly vectorized.

  4. +
  5. Creation of the merged macro-particles at the position +of the previous ones

  6. +
  7. Tag of the macro-particles to be removed

  8. +
+

Then, once the merging finished for a given patch:

+
    +
  1. Compression of the macro-particle list (remove hole in arrays let +by removed and tagged particles). +By cleaning the particle vector at the end, we limit the computational +impact of this step.

  2. +
+
+
+

1. Cartesian sub-group discretization

+

How to discretize momentum space is in fact one of the most important points. +The user provides \(N_x\), \(N_y\) and \(N_z\) via the namelist, +but it may be slightly adjusted for algorithmic reasons:

+
    +
  • If the momentum space is very narrow in one direction, only one +sub-group may be used.

  • +
  • We force the origin (\(p = 0\)) to delimit two sub-groups +so that a sub-group cannot contain two opposite momenta. +This may require an extra sub-group to fit the whole momentum space.

  • +
+
+
+

2. Spherical sub-group discretization

+

The user provides \(N_p\), \(N_\theta\) and \(N_\phi\) +via the namelist, but adjustments may occur:

+
    +
  • If the momentum space is very narrow in one direction, only one +sub-group may be used.

  • +
  • The \(\Delta_{\alpha}\) are modified by a factor 1.01 to +include the maximum boundary.

  • +
+
+
+

3. Solid-angle correction in 3D

+

A rudimentary spherical discretization does not ensure that all sub-groups +span similar solid-angles, as they becomes arbitrarily small at the poles.

+
+../_images/spherical_discretization.png +
+

Fig. 52 Rudimentary spherical discretization (a) and the spherical discretization +with solid angle correction (b). This figure was generated with the +following Python script.

+
+
+

To obtain a solid angle approximately constant, the discretization in +\(\theta\) is adjusted depending on the value of \(\phi\). +Denoting by \(\Omega_{0}\) the solid angle at the smallest \(|\phi|\), +the sub-groups length \(\Delta_\theta\) along \(\theta\) varies to +satisfy \(\Omega = \sin{(\phi)}\Delta \theta \Delta \phi = \Omega_{0}\).

+
+
+

4. Accumulation effect

+

In one merging event, the strongest contribution comes from weightiest +macro-particles, which mostly come from a previous merging event instead +of the smaller macro-particles. +Some macro-particles may thus become uncontrollably heavy and dominate +others with little changes in their kinetic properties. +This effect may be particularly strong with large sub-groups and broad +momentum distributions, which are not well conserved.

+

To illustrate this phenomenon, let us consider a 3D magnetic shower benchmark: +the domain is filled with an electron-positron plasma with all macro-particles +initialized using the same Lorentz factor \(\gamma = 8125\) +in the same direction. +They propagate orthogonally to a constant and uniform magnetic field of +amplitude \(B = 1000 e/(m\omega)\), corresponding to a quantum parameter +of \(\chi = 20\) for both electrons and positrons. +The input script of this simulation is available +here.

+

This accumulation effect creates peaks in the photon energy distribution +as shown in Fig. 53 a).

+
+

Need to explain the correction.

+
+
+../_images/magnetic_shower_photon_energy_distribution.png +
+

Fig. 53 Photon energy distribution at the end of the simulation.

+
+
+
+../_images/magnetic_shower_photon_pxpy_distribution.png +
+

Fig. 54 Photon px-py momentum distribution at the end of the simulation.

+
+
+

Warning: the accumulation correction is not working with the logarithmic discretization.

+
+
+

5. Logarithmic scale

+

For the spherical discretization only, the momentum norm \(p\) +discretization may be chosen logarithmically scaled. +Due to the logarithm computation, this option is slightly slower than the +linear version. +Nonetheless, it can handle more appropriately broad momentum distributions.

+

On the magnetic shower case presented in the previous section, +the logarithmic discretization reproduces nicely +the distribution obtained without merging.

+
+../_images/magnetic_shower_gamma_distribution_log.png +
+

Fig. 55 Photon energy distribution for the 3D magnetic shower benchmark +at the end of the simulation.

+
+
+

Warning: the logarithmic discretization is subject to accumulation +oscillations but is not compatible with the accumulation correction.

+
+
+
+
+

Simulation results

+
+

1. 3D QED cascade

+

In this section, the particle merging is tested with a 3D scenario +of electron-positron pair cascading. +Like the magnetic shower, a seed of electrons or positrons in a strong +electromagnetic field generates high-energy photons that, in turn, decay +into electron-positron pairs. +The difference is that the seed particles and the newly created ones may +gain some energy from the fields and participate to the generation of pairs. +The production of electron-positron pairs can therefore be maintained +(the cascade) as long as there is a source of energy. +In such a scenario, we can expect an exponential growth of the number of +particles leading to the creation of an electron-positron plasma.

+

A plasma of electrons and positrons (the seed) is initially irradiated +by two counter-propagating lasers (strong field and source of energy), +chosen as circularly-polarized plane waves.

+
+../_images/qed_pair_cascade.png +
+

Fig. 56 QED pair cascade configuration with two counter-propagating lasers.

+
+
+

When they collide, the two waves form a steady plane wave of very strong +amplitude able to trigger strong QED effects. +Detailed simulation parameters are available +in this namelist.

+

An aggressive merging process is performed at every timestep +with a relatively sparse momentum-space discretization. +Note that, in 1D and 2D, it could use smaller sub-groups and +be performed more often as there would be more particles per cell. +The merging is applied on all species. +All cases are run during a maximum of 1000 seconds.

+

As presented in Fig. 57, the merging process +starts when the number of macro-particles is high enough: +\(\sim 10^5\) macro-photons. +Between 10% and 20% more iterations are achieved, compared to the no +merging case.

+

Each merging method does not exactly gives the same kinetic +energy and weight evolution. As we will see, the merging processes modify +the momentum distribution and influence the physical processes.

+
+../_images/QED_cascade_scalar.png +
+

Fig. 57 Effect of various merging configurations on the +number of macro-particles, their total weight, and their total +kinetic energy.

+
+
+

We now compare energy spectra at time \(t = 39 \omega^{-1}\) +(nearly when the no merging case saturates) +in Fig. 58. +All merging methods significantly affect the energy distributions, +and oscillations are most visible in the photon distribution +due to the accumulation effect.

+
+../_images/QED_cascade_gamma_spectrum.png +
+

Fig. 58 Effect of various merging configurations on energy spectra.

+
+
+

Fig. 59 shows the +\(k_x-k_y\) momentum distribution of the photons. +It clearly shows that, with their level of discretization, +none of the merging processes can adequately reproduce the +reference distribution.

+
+../_images/QED_cascade_photon_px_py_distribution.png +
+

Fig. 59 \(k_x-k_y\) photon momentum distributions at simulation +time \(t = 39.5 \omega^{-1}\) +for the various merging configurations.

+
+
+

Fig. 60 shows the +\(p_x-p_y\) momentum distribution of the electrons.

+
+../_images/QED_cascade_electron_px_py_distribution.png +
+

Fig. 60 \(p_x-p_y\) electron momentum distributions at simulation +time \(t = 39.5 \omega^{-1}\) +for the various merging configurations.

+
+
+

To compare the merging methods in term of performance, +Fig. 61 shows the CPU time necessary +to compute a numerical timestep as a function of time. +The linear spherical discretization is the fastest method because +the solid angle correction reduces the number of sub-groups. +The logarithmic spherical discretization has the same advantage +but it is slowed down by the computation of logarithms, and, in the end, +similar to the original cartesian method described in [Vranic2005].

+
+../_images/QED_cascade_iteration_time.png +
+

Fig. 61 Computation time per iteration as a function of time.

+
+
+

The following video illustrates the simulation benchmark +in the case of a logarithmic spherical discretization. +Specifically, it shows the time evolution of the electron, the positron +and the photon densities in the plane x-y, integrating over z. +It shows and exponential growth of photons and massive particles +happening first in the y-z plane near the center of the domain +then expanding longitudinally.

+
+
+
+
+

References

+
+
Vranic2005(1,2)
+

M. Vranic et al., CPC, 191 65-73 (2015)

+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/performances.html b/Understand/performances.html new file mode 100644 index 000000000..3c835d914 --- /dev/null +++ b/Understand/performances.html @@ -0,0 +1,508 @@ + + + + + + + + + Parallelization & optimization — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Parallelization & optimization

+

To reach high performances on supercomputers, several techniques have +been developed in Smilei. +While a good understanding of parallelization is mandatory +to run a meaningful PIC simulation for any supercomputer user, other advanced +techniques, such as Vectorization, are optional even though they can +provide important advantages.

+ +
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/physics_modules.html b/Understand/physics_modules.html new file mode 100644 index 000000000..595b6a6ec --- /dev/null +++ b/Understand/physics_modules.html @@ -0,0 +1,510 @@ + + + + + + + + + Physics modules — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ + + + +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Physics modules

+

The basic PIC algorithms do not reproduce all the physics of a plasma. +For instance, the typical cell size is too coarse to model collisions +so that a specific module is necessary. Similarly, atomic physics and +quantum processes require physics modules such as Ionization and +High-energy photon emission & radiation reaction.

+ +
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/radiation_loss.html b/Understand/radiation_loss.html new file mode 100644 index 000000000..d03c23db2 --- /dev/null +++ b/Understand/radiation_loss.html @@ -0,0 +1,1304 @@ + + + + + + + + + High-energy photon emission & radiation reaction — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

High-energy photon emission & radiation reaction

+

Accelerated charges emit electromagnetic radiation, and by doing so, lose some of their energy and momentum. +This process is particularly important for high-energy particles traveling in strong electromagnetic fields +where it can strongly influence the dynamics of the radiating charges, a process known as radiation reaction.

+

In Smilei, different modules treating high-energy photon emission & its back-reaction have been implemented. +We first give a short overview of the physics (and assumptions) underlying these modules, before giving more pratical +information on what each module does. We then give examples & benchmarks, while the last two sections give additional +information on the implementation of the various modules and their performances.

+
+

Warning

+

The processes discussed in this section bring into play a characteristic length +[the classical radius of the electron \(r_e = e^2/(4\pi \epsilon_0 m_e c^2)\) in classical electrodynamics (CED) +or the standard Compton wavelength \(\lambda_C=\hbar/(m_e c)\) in quantum electrodynamics (QED)]. +As a result, a simulation will require the user to define the absolute scale of the system by defining +the reference_angular_frequency_SI parameter (see Units for more details).

+

Also note that, unless specified otherwise, SI units are used throughout this section, and we use standard notations +with \(m_e\), \(e\), \(c\) and \(\hbar\) the electron mass, elementary charge, speed of light +and reduced Planck constant, respectively, and \(\epsilon_0\) the permittivity of vacuum.

+
+
+
+

Inverse Compton scattering

+

This paragraph describes the physical model and assumptions behind the different modules +for high-energy photon emission & radiation reaction that have been implemented in Smilei. +The presentation is based on the work [Niel2018a].

+
+

Assumptions

+

All the modules developed so far in Smilei assume that:

+
    +
  • the radiating particles (either electrons or positrons) are ultra-relativistic (their Lorentz factor \(\gamma \gg 1\)), +hence radiation is emitted in the direction given by the radiating particle velocity,

  • +
  • the electromagnetic field varies slowly over the formation time of the emitted photon, which requires +relativistic field strengths [i.e., the field vector potential is \(e\vert A^{\mu}\vert/(mc^2) \gg 1\)], +and allows to use quasi-static models for high-energy photon emission (locally-constant cross-field approximation),

  • +
  • the electromagnetic fields are small with respect to the critical field of Quantum Electrodynamics (QED), +more precisely both field invariants \(\sqrt{c^2{\bf B}^2-{\bf E}^2}\) and \(\sqrt{c{\bf B}\cdot{\bf E}}\) are small with +respect to the Schwinger field \(E_s = m^2 c^3 / (\hbar e) \simeq 1.3 \times 10^{18}\ \mathrm{V/m}\),

  • +
  • all (real) particles radiate independently of their neighbors (incoherent emission), which requires the emitted radiation +wavelength to be much shorter than the typical distance between (real) particles \(\propto n_e^{-1/3}\).

  • +
+
+
+

Rate of photon emission and associated quantities

+

Under these assumptions, high-energy photon emission reduces to the incoherent process of +nonlinear inverse Compton scattering. +The corresponding rate of high-energy photon emission is given by [Ritus1985]:

+
+(15)\[\frac{d^2 N_{\gamma}}{d\tau d\chi_{\gamma}} = \frac{2}{3}\frac{\alpha^2}{\tau_e}\,\frac{S(\chi,\chi_{\gamma}/\chi)}{\chi_{\gamma}}\]
+

with \(\tau_e = r_e/c\) the time for light to cross the classical radius of the electron, +and \(\alpha\) the fine-structure constant. +This rate depends on two Lorentz invariants, the electron quantum parameter:

+
+(16)\[\chi = \frac{\gamma}{E_s} \sqrt{ \left({\bf E} + {\bf v} \times {\bf B}\right)^2 - ({\bf v }\cdot{\bf E})^2/c^2 }\]
+

and the photon quantum parameter (at the time of photon emission):

+
+(17)\[\chi_{\gamma} = \frac{\gamma_{\gamma}}{E_s} \sqrt{ \left({\bf E} + {\bf c} \times {\bf B}\right)^2 - ({\bf c }\cdot{\bf E})^2/c^2 }\]
+

where \(\gamma = \varepsilon / (m_e c^2)\) and \(\gamma_{\gamma} = \varepsilon_{\gamma} / (m_e c^2)\) are +the normalized energies of the radiating particle and emitted photon, respectively, and \({\bf v}\) and +\({\bf c}\) their respective velocities.

+

Note that considering ultra-relativistic (radiating) particles, both parameters are related by:

+
+(18)\[\xi = \frac{\chi_{\gamma}}{\chi} = \frac{\gamma_{\gamma}}{\gamma}\,.\]
+

In the photon production rate Eq. (15) appears the quantum emissivity:

+
+(19)\[S(\chi,\xi) = \frac{\sqrt{3}}{2\pi}\,\xi\,\left[\int_{\nu}^{+\infty} {\rm K}_{5/3}(y) dy ++ \frac{\xi^2}{1-\xi}\,{\rm K}_{2/3}(\nu)\right]\,,\]
+

with \(\nu = 2\xi/[3\chi(1-\xi)]\).

+

Finally, the instantaneous radiated power energy-spectrum reads:

+
+(20)\[\frac{dP_{\rm inst}}{d\gamma_{\gamma}} = P_{\alpha}\,\gamma^{-1}\,S(\chi,\chi_{\gamma}/\chi)\,,\]
+

with \(P_{\alpha}=2\alpha^2 m_e c^2/(3\tau_e)\), and the instantaneous radiated power:

+
+(21)\[P_{\rm inst} = P_{\alpha}\,\chi^2\,g(\chi)\,,\]
+

with \(g(\chi)\) the so-called quantum correction:

+
+(22)\[g(\chi) = \frac{9 \sqrt{3} }{8 \pi} \int_0^{+\infty}{d\nu +\left[ \frac{2\nu^2 }{\left( 2 + 3 \nu \chi \right) ^2}K_{5/3}(\nu) + +\frac{4 \nu \left( 3 \nu \chi\right)^2 }{\left( 2 + 3 \nu \chi \right)^4}K_{2/3}(\nu) \right]}\,.\]
+
+
+

Regimes of radiation reaction

+

Knowing exactly which model of radiation reaction is best to describe a given situation is not always easy, and the domain of application +of each model is still discussed in the recent literature (again see [Niel2018a] for more details). +However, the typical value of the electron quantum parameter \(\chi\) in a simulation can be used as a way to +assess which model is most suitable. +We adopt this simple (yet sometimes not completely satisfactory) point of view below to describe the three main approaches +used in Smilei to account for high-energy photon emission and its back-reaction on the electron dynamics.

+
+

For arbitrary values of the electron quantum parameter \(\chi\) (but mandatory in the quantum regime \(\chi \gtrsim 1\))

+

The model of high-energy photon emission described above is generic, and applies for any value of +the electron quantum parameter \(\chi\) (of course as long as the assumptions listed above hold!). +In particular, it gives a correct description of high-energy photon emission and its back-reaction on +the particle (electron or positron) dynamics in the quantum regime \(\chi \gtrsim 1\). +In this regime, photons with energies of the order of the energy of the emitting particle can be produced. +As a result, the particle energy/velocity can exhibit abrupt jumps, and the stochastic nature of high-energy +photon emission is important. +Under such conditions, a Monte-Carlo description of discrete high-energy photon emission (and their feedback +on the radiating particle dynamics) is usually used (see [Timokhin2010], [Elkina2011], [Duclous2011], and [Lobet2013]). +More details on the implementation are given below.

+

In Smilei the corresponding description is accessible for an electron species by defining +radiation_model = "Monte-Carlo" or "MC" in the Species() block (see Write a namelist for details).

+
+
+

Intermediate, moderately quantum regime \(\chi \lesssim 1\)

+

In the intermediate regime (\(\chi \lesssim 1\)), the energy of the emitted photons remains +small with respect to that of the emitting electrons. Yet, the stochastic nature of photon emission cannot be neglected. +The electron dynamics can then be described by a stochastic differential equation derived from a Fokker-Planck +expansion of the full quantum (Monte-Carlo) model described above [Niel2018a].

+

In particular, the change in electron momentum during a time interval \(dt\) reads:

+
+(23)\[d{\bf p} = {\bf F}_{\rm L} dt + {\bf F}_{\rm rad} dt + mc^2 \sqrt{R\left( \chi, \gamma \right)} dW +\mathbf{u} / \left( \mathbf{u}^2 c\right)\]
+

where we recognize 3 terms:

+
    +
  • the Lorentz force \({\bf F}_{\rm L} = \pm e ({\bf E} + {\bf v}\times{\bf B})\) (with \(\pm e\) the particle’s charge),

  • +
  • a deterministic force term \({\bf F}_{\rm rad}\) (see below for its expression), so-called drift term, which is nothing but the leading term +of the Landau-Lifshitz radiation reaction force with the quantum correction \(g(\chi)\),

  • +
  • a stochastic force term, so-called diffusion term, proportional to \(dW\), a Wiener process of variance \(dt\). +This last term allows to account for the stochastic nature of high-energy photon emission, and it depends on functions +which are derived from the stochastic model of radiation emission presented above:

    +
    +(24)\[ R\left( \chi, \gamma \right) = \frac{2}{3} \frac{\alpha^2}{\tau_e} \gamma + h \left( \chi \right)\]
    +

    and

    +
    +(25)\[ h \left( \chi \right) = \frac{9 \sqrt{3}}{4 \pi} \int_0^{+\infty}{d\nu + \left[ \frac{2\chi^3 \nu^3}{\left( 2 + 3\nu\chi \right)^3} K_{5/3}(\nu) + + \frac{54 \chi^5 \nu^4}{\left( 2 + 3 \nu \chi \right)^5} K_{2/3}(\nu) \right]}\]
    +
  • +
+

In Smilei the corresponding description is accessible for an electron species by defining +radiation_model = "Niel" in the Species() block (see Write a namelist for details).

+
+
+

The classical regime \(\chi \ll 1\)

+

Quantum electrodynamics (QED) effects are negligible (classical regime) when \(\chi \ll 1\). +Radiation reaction follows from the cummulative effect of incoherent photon emission. +It can be treated as a continuous friction force acting on the particles. +Several models for the radiation friction force have been proposed (see [DiPiazza2012]). +The ones used in Smilei are based on the Landau-Lifshitz (LL) model [Landau1947] +approximated for high Lorentz factors (\(\gamma \gg 1\)). +Indeed, as shown in [Niel2018a], the LL force with the quantum correction \(g(\chi)\) +naturaly emerges from the full quantum description given above. +This can easily be seen from Eq. (23), in which the diffusion term vanishes +in the limit \(\chi \ll 1\) so that one obtains for the deterministic equation of motion for the electron:

+
+\[\frac{d{\bf p}}{dt} = {\bf F}_{\rm L} + {\bf F}_{\rm rad}\]
+

with

+
+(26)\[{\bf F}_{\rm rad} = -P_{\alpha} \chi^2 g(\chi)\,\mathbf{u} / \left( \mathbf{u}^2 c\right)\]
+

In Smilei the corresponding description is accessible for an electron species by defining +radiation_model = "corrected-Landau-Lifshitz" or "cLL" in the Species() block (see Write a namelist for details).

+
+

Note

+
    +
  • for \(\chi \rightarrow 0\), the quantum correction \(g(\chi) \rightarrow 1\), +\(P_{\rm inst} \rightarrow P_{\alpha}\,\chi^2\) (which is the Larmor power) +and \(dP_{\rm inst}/d\gamma_{\gamma}\) [Eq. (20)] reduces to the classical +spectrum of synchrotron radiation.

  • +
  • the purely classical (not quantum-corrected) LL radiation friction is also accessible in Smilei, +using radiation_model = "Landau-Lifshitz" or "LL" in the Species().

  • +
+
+
+
+

Choosing the good model for your simulation

+

The next sections describe in more details the different models implemented in Smilei. +For the user convenience, Table 3 briefly summarises the models and how to choose +the most appropriate radiation reaction model for your simulation.

+
+

Note

+

In [Niel2018a], an extensive study of the links between the different models for radiation reaction and their domain +of applicability is presented. The following table is mainly informative.

+
+ + ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 3 Radiation model regimes

Regime

\(\chi\) value

Description

Models

Classical radiation emission

\(\chi \sim 10^{-3}\)

\(\gamma_\gamma \ll \gamma\), +radiated energy overestimated for +\(\chi > 10^{-2}\)

Landau-Lifshitz

Semi-classical radiation emission

\(\chi \sim 10^{-2}\)

\(\gamma_\gamma \ll \gamma\), +no stochastic effects

Corrected Landau-Lifshitz

Weak quantum regime

\(\chi \sim 10^{-1}\)

\(\gamma_\gamma < \gamma\), +\(\gamma_\gamma \gg mc^2\)

Stochastic model of +Niel et al / Monte-Carlo

Quantum regime

\(\chi \sim 1\)

\(\gamma_\gamma \gtrsim \gamma\)

Monte-Carlo

+
+
+
+
+
+

Implementation

+

C++ classes for the radiation processes are located in the directory src/Radiation. +In Smilei, the radiative processes are not incorporated in the pusher in +order to preserve the vector performance of the pusher when using non-vectorizable +radiation models such as the Monte-Carlo process.

+

Description of the files:

+
    +
  • Class RadiationTable: useful tools, parameters and the tables.

  • +
  • Class Radiation: the generic class from which will inherit specific +classes for each model.

  • +
  • Class RadiationFactory: manages the choice of the radiation model among the following.

  • +
  • Class RadiationLandauLifshitz: classical Landau-Lifshitz radiation process.

  • +
  • Class RadiationCorrLandauLifshitz: corrected Landau-Lifshitz radiation process.

  • +
  • Class RadiationNiel: stochastic diffusive model of [Niel2018a].

  • +
  • Class RadiationMonteCarlo: Monte-Carlo model.

  • +
+

As explained below, many functions have been tabulated because of +the cost of their computation for each particle. +Tables can be generated by the external tool +smilei_tables. +More information can be found in Generation of the external tables.

+
+

Continuous, Landau-Lifshitz-like models

+

Two models of continuous radiation friction force are available in Smilei: +(i) the approximation for high-math:gamma of the Landau-Lifshitz equation (taking \(g(\chi)=1\) in Eq. (26)), +and (ii) the corrected Landau-Lifshitz equation Eq. (26). +The modelS are accessible in the species configuration under the name +Landau-Lifshitz (equiv. LL) and corrected-Landau-Lifshitz (equiv. ‘cLL’).

+

The implementation of these continuous radiation friction forces consists in a modification of the particle pusher, +and follows the simple splitting technique proposed in [Tamburini2010]. +Note that for the quantum correction, we use a fit of the function +\(g(\chi)\) given by

+
+(27)\[g \left( \chi_{\pm} \right) = \left[ 1 + 4.8 \left( 1 + \chi_{\pm} \right) +\log \left( 1 + 1.7 \chi_{\pm} \right) + 2.44 \chi_{\pm}^2 \right]^{-2/3}\]
+

This fit enables to keep the vectorization of the particle loop.

+
+
+

Fokker-Planck stochastic model of Niel et al.

+

Equation (23) is implemented in Smilei using +a simple explicit scheme, see [Niel2018a] Sec. VI.B for more details. +This stochastic diffusive model is accessible in the species configuration +under the name Niel.

+

The direct computation of Eq. (25) during the emission process is too expensive. +For performance issues, Smilei uses tabulated values or fit functions.

+

Concerning the tabulation, Smilei first checks the presence of +an external table at the specified path. +If the latter does not exist at the specified path, the table is computed at initialization. +The new table is outputed on disk in the current simulation directory. +It is recommended to use existing external tables to save simulation time. +The computation of h during the simulation can slow down the initialization +and represents an important part of the total simulation. +The parameters such as the \(\chi\) range and the discretization can be +given in RadiationReaction.

+

Polynomial fits of this integral can be obtained in log-log +or log10-log10 domain. However, high accuracy requires high-order polynomials +(order 20 for an accuracy around \(10^{-10}\) for instance). +In Smilei, an order 5 (see Eq. (28)) and 10 polynomial fits are implemented. +They are valid for quantum parameters \(\chi\) between \(10^{-3}\) and 10.

+
+(28)\[\begin{split}h_{o5}(\chi) = \exp{ \left(1.399937206900322 \times 10^{-4} \log(\chi)^5 \\ ++ 3.123718241260330 \times 10^{-3} \log{(\chi)}^4 \\ ++ 1.096559086628964 \times 10^{-2} \log(\chi)^3 \\ +-1.733977278199592 \times 10^{-1} \log(\chi)^2 \\ ++ 1.492675770100125 \log(\chi) \\ +-2.748991631516466 \right) }\end{split}\]
+

An additional fit from [Ridgers2017] has been implemented and the formula +is given in Eq. (29).

+
+(29)\[h_{Ridgers}(\chi) = \chi^3 \frac{165}{48 \sqrt{3}} \left(1. + (1. + 4.528 \chi) \log(1.+12.29 \chi) + 4.632 \chi^2 \right)^{-7/6}\]
+
+
+

Monte-Carlo full-quantum model

+

The Monte-Carlo treatment of the emission is more complex process than +the previous ones and can be divided into several steps ([Duclous2011], +[Lobet2013], [Lobet2015]):

+
    +
  1. An incremental optical depth \(\tau\), initially set to 0, is assigned to the particle. +Emission occurs when it reaches the final optical depth \(\tau_f\) +sampled from \(\tau_f = -\log{\xi}\) where \(\xi\) is a random number in \(\left]0,1\right]\).

  2. +
  3. The optical depth \(\tau\) evolves according to the field and particle +energy variations following this integral:

    +
    +(30)\[ \frac{d\tau}{dt} = \int_0^{\chi_{\pm}}{ \frac{d^2N}{d\chi dt} d\chi } + = \frac{2}{3} \frac{\alpha^2}{\tau_e} \int_0^{\chi_{\pm}}{ \frac{S(\chi_\pm, \chi/\chi_{\pm})}{\chi} d\chi } + \equiv \frac{2}{3} \frac{\alpha^2}{\tau_e} K (\chi_\pm)\]
    +

    that simply is the production rate of photons +(computed from Eq. (15)). +Here, \(\chi_{\pm}\) is the emitting electron (or positron) quantum parameter and +\(\chi\) the integration variable.

    +
  4. +
  5. The emitted photon’s quantum parameter \(\chi_{\gamma}\) is computed by +inverting the cumulative distribution function:

    +
    +(31)\[ \xi = P(\chi_\pm,\chi_{\gamma}) = \frac{\displaystyle{\int_0^{\chi_\gamma}{ d\chi S(\chi_\pm, \chi/\chi_{\pm}) / \chi + }}}{\displaystyle{\int_0^{\chi_\pm}{d\chi S(\chi_\pm, \chi/\chi_{\pm}) / \chi }}}.\]
    +

    The inversion of \(\xi = P(\chi_\pm,\chi_{\gamma})\) is done after drawing +a second random number +\(\phi \in \left[ 0,1\right]\) to find \(\chi_{\gamma}\) by solving :

    +
    +(32)\[\xi^{-1} = P^{-1}(\chi_\pm, \chi_{\gamma}) = \phi\]
    +
  6. +
  7. The energy of the emitted photon is then computed: +\(\varepsilon_\gamma = mc^2 \gamma_\gamma = +mc^2 \gamma_\pm \chi_\gamma / \chi_\pm\).

  8. +
  9. The particle momentum is then updated using momentum conservation and +considering forward emission (valid when \(\gamma_\pm \gg 1\)).

    +
    +(33)\[ d{\bf p} = - \frac{\varepsilon_\gamma}{c} \frac{\mathbf{p_\pm}}{\| \mathbf{p_\pm} \|}\]
    +

    The resulting force follows from the recoil induced by the photon emission. +Radiation reaction is therefore a discrete process. +Note that momentum conservation does not exactly conserve energy. +It can be shown that the error \(\epsilon\) tends to 0 when the particle +energy tends to infinity [Lobet2015] and that the error is small when +\(\varepsilon_\pm \gg 1\) and \(\varepsilon_\gamma \ll \varepsilon_\pm\). +Between emission events, the electron dynamics is still governed by the +Lorentz force.

    +

    If the photon is emitted as a macro-photon, its initial position is the same as +for the emitting particle. The (numerical) weight is also conserved.

    +
  10. +
+

The computation of Eq. (30) would be too expensive for every single +particles. +Instead, the integral of the function \(S(\chi_\pm, \chi/\chi_{\pm}) / \chi\) +also referred to as \(K(\chi_\pm)\) is tabulated.

+

This table is named integfochi +Related parameters are stored in the structure integfochi in the code.

+

Similarly, Eq. (31) is tabulated (named xi in the code). +The only difference is that a minimum photon quantum parameter +\(\chi_{\gamma,\min}\) is computed before for the integration so that:

+
+(34)\[ \frac{\displaystyle{\int_{0}^{\chi_{\gamma,\min}}{d\chi S(\chi_\pm, \chi/\chi_{\pm}) / \chi}}} + {\displaystyle{\int_0^{\chi_\pm}{d\chi S(\chi_\pm, \chi/\chi_{\pm}) / \chi}}} < \epsilon\]
+

This enables to find a lower bound to the \(\chi_\gamma\) range +(discretization in the log domain) so that the +remaining part is negligible in term of radiated energy. +The parameter \(\epsilon\) is called xi_threshold in +RadiationReaction and the tool smilei_tables (Generation of the external tables.).

+

The Monte-Carlo model is accessible in the species configuration +under the name Monte-Carlo or mc.

+
+
+
+
+

Benchmarks

+
+

Radiation emission by ultra-relativistic electrons in a constant magnetic field

+

This benchmark closely follows benchmark/tst1d_18_radiation_spectrum_chi0.1.py. +It considers a bunch of electrons with initial Lorentz factor \(\gamma=10^3\) radiating in a constant magnetic field. +The magnetic field is perpendicular to the initial electrons’ velocity, +and its strength is adjusted so that the electron quantum parameter is either \(\chi=0.1\) or \(\chi=1\). +In both cases, the simulation is run over a single gyration time of the electron (computed neglecting radiation losses), +and 5 electron species are considered (one neglecting all radiation losses, the other four each corresponding +to a different radiation model: LL, cLL, FP and MC).

+

In this benchmark, we focus on the differences obtained on the energy spectrum of the emitted radiation +considering different models of radiation reaction. +When the Monte-Carlo model is used, the emitted radiation spectrum is obtained by applying a ParticleBinning diagnostic +on the photon species. +When other models are considered, the emitted radiation spectrum is reconstructed using a RadiationSpectrum diagnostic, +as discussed in RadiationSpectrum diagnostics, and given by Eq. (20) (see also [Niel2018b]). +Fig. 28 presents for both values of the initial quantum parameter \(\chi=0.1\) and \(\chi=1\) +the resulting power spectra obtained from the different models, focusing of the (continuous) corrected-Landau-Lifshitz (cLL), +(stochastic) Fokker-Planck (Niel) and Monte-Carlo (MC) models. +At \(\chi=0.1\), all three descriptions give the same results, which is consistent with the idea that at small quantum parameters, +the three descriptions are equivalent. +In contrast, for \(\chi=1\), the stochastic nature of high-energy photon emission (not accounted for in the continuous cLL model) +plays an important role on the electron dynamics, and in turns on the photon emission. Hence only the two stochastic model give a +satisfactory description of the photon emitted spectra. +More details on the impact of the model on both the electron and photon distribution are given in [Niel2018b].

+
+../_images/figSpectra_LR.png +
+

Fig. 28 Energy distribution (power spectrum) of the photon emitted by an ultra-relativistic electron bunch in a constant magnetic field. +(left) for \(\chi=0.1\), (right) for \(\chi=1\).

+
+
+
+
+

Counter-propagating plane wave, 1D

+

In the benchmark benchmark/tst1d_09_rad_electron_laser_collision.py, +a GeV electron bunch is initialized near the right +domain boundary and propagates towards the left boundary from which a plane +wave is injected. The laser has an amplitude of \(a_0 = 270\) +corresponding to an intensity of \(10^{23}\ \mathrm{Wcm^{-2}}\) at +\(\lambda = 1\ \mathrm{\mu m}\). +The laser has a Gaussian profile of full-with at half maxium of +\(20 \pi \omega_r^{-1}\) (10 laser periods). +The maximal quantum parameter \(\chi\) +value reached during the simulation is around 0.5.

+
+../_images/rad_counter_prop_scalar.png +
+

Fig. 29 Kinetic, radiated and total energy plotted respectively with solid, dashed and dotted lines for +the Monte-Carlo (MC), Niel (Niel), +corrected Landau-Lifshitz (CLL) and the Landau-Lifshitz (LL) models.

+
+
+

Fig. 29 shows that the Monte-Carlo, the Niel and +the corrected Landau-Lifshitz models exhibit very similar +results in term of the total radiated and kinetic energy evolution with a final +radiation rate of 80% the initial kinetic energy. The relative error on the +total energy is small (\(\sim 3\times10^{-3}\)). +As expected, the Landau-Lifshitz model overestimates the radiated energy +because the interaction happens mainly in the quantum regime.

+
+../_images/rad_counter_prop_track.png +
+

Fig. 30 Evolution of the normalized kinetic energy +\(\gamma - 1\) of some selected electrons as a function of their position.

+
+
+

Fig. 30 shows that the Monte-Carlo and the Niel models +reproduce the stochastic nature of the trajectories as opposed to the +continuous approaches (corrected Landau-Lifshitz and Landau-Lifshitz). +In the latter, every particles initially located at the same position will +follow the same trajectories. +The stochastic nature of the emission for high \(\chi\) values can +have consequences in term of final spatial and energy distributions. +Not shown here, the Niel stochastic model does not reproduce correctly the +moment of order 3 as explained in [Niel2018a].

+
+
+

Synchrotron, 2D

+

A bunch of electrons of initial momentum \(p_{-,0}\) +evolves in a constant magnetic field \(B\) orthogonal +to their initial propagation direction. +In such a configuration, the electron bunch is supposed to rotate endlessly +with the same radius \(R = p_{-,0} /e B\) without radiation energy loss. +Here, the magnetic field is so strong that the electrons +radiate their energy as in a synchrotron facility. +In this setup, each electron quantum parameter depends on their Lorentz +factors \(\gamma_{-}\) according to +\(\chi_{-} = \gamma_{-} B /m_e E_s\). +The quantum parameter is maximum at the beginning of the interaction. +The strongest radiation loss are therefore observed at the beginning too. +As energy decreases, radiation loss becomes less and less important so that +the emission regime progressively move from the quantum to the classical regime.

+

Similar simulation configuration can be found in the benchmarks. +It corresponds to two different input files in the benchmark folder:

+
    +
  • tst2d_08_synchrotron_chi1.py: tests and compares the corrected +Landau-Lifshitz and the Monte-Carlo model for an initial \(\chi = 1\).

  • +
  • tst2d_09_synchrotron_chi0.1.py: tests and compares the corrected +Landau-Lifshitz and the Niel model for an initial \(\chi = 0.1\).

  • +
+

In this section, we focus on the case with initial quantum parameter +\(\chi = 0.1\). +The magnetic field amplitude is \(B = 90 m \omega_r / e\). +The initial electron Lorentz factor is +\(\gamma_{-,0} = \varepsilon_{-,0}/mc^2 = 450\). +Electrons are initialized with a Maxwell-Juttner distribution of temperature +\(0.1 m_e c^2\).

+

Fig. 31 shows the time evolution of the particle kinetic energy, +the radiated energy and the total energy. All radiation models provide +similar evolution of these integrated quantities. The relative error on the +total energy is between \(2 \times 10^{-9}\) and \(3 \times 10^{-9}\).

+
+../_images/synchrotron_scalar.png +
+

Fig. 31 Kinetic, radiated and total energies plotted respectively with solid, dashed and dotted +lines for various models.

+
+
+

The main difference between models can be understood by studying the +particle trajectories and phase spaces. For this purpose, the local kinetic energy spatial-distribution +at \(25 \omega_r^{-1}\) is shown in +Fig. 32 for the different models. +With continuous radiation energy loss +(corrected Landau-Lifshitz case), each electron of the bunch rotates with a decreasing +radius but the bunch. +Each electron of similar initial energies have the same trajectories. +In the case of a cold bunch (null initial temperature), +the bunch would have kept its original shape. +The radiation with this model only acts as a cooling mechanism. +In the cases of the Niel and the Monte-Carlo radiation models, +stochastic effects come into play and lead the bunch to spread spatially. +Each individual electron of the bunch, even with similar initial energies, +have different trajectories depending on their emission history. +Stochastic effects are particularly strong at the beginning with the highest +\(\chi\) values when the radiation +recoil is the most important.

+
+../_images/synchrotron_x_y_gamma.png +
+

Fig. 32 Average normalized kinetic energy at time \(25 \omega_r^{-1}\) +for the simulations with the Monte-Carlo, the Niel +and the corrected Landau-Lifshitz (CLL) models.

+
+
+

Fig. 33 shows the time evolution of +the electron Lorentz factor distribution (normalized energy) for different +radiation models. +At the beginning, the distribution is extremely broad due to the Maxwell-Juttner parameters. +The average energy is well around \(\gamma_{-,0} = \varepsilon_{-,0}/mc^2 = 450\) +with maximal energies above \(\gamma_{-} = 450\).

+

In the case of a initially-cold electron beam, +stochastic effects would have lead the bunch to spread energetically +with the Monte-Carlo and the Niel stochastic models at the beginning of the simulation. +This effect is hidden since electron energy is already highly spread at the +beginning of the interaction. +This effect is the strongest when the quantum parameter is high in the quantum regime.

+

In the Monte-Carlo case, some electrons have lost all their energy almost immediately +as shown by the lower part of the distribution below \(\gamma_{-} = 50\) +after comparison with the Niel model.

+

Then, as the particles cool down, the interaction enters the semi-classical +regime where energy jumps are smaller. +In the classical regime, radiation loss acts oppositely to the quantum regime. +It reduces the spread in energy and space. +In the Landau-Lifshitz case, this effect starts at the beginning even +in the quantum regime due to the nature of the model. +For a initially-cold electron bunch, there would not have been +energy spread at the beginning of the simulation. All electron would have lost +their energy in a similar fashion (superimposed behavior). +This model can be seen as the average behavior of the stochastic ones of +electron groups having the same initial energy.

+
+../_images/synchrotron_t_gamma_ne.png +
+

Fig. 33 Time evolution of the electron energy distribution for the Monte-Carlo, the Niel +and the corrected Landau-Lifshitz (CLL) models.

+
+
+
+
+

Thin foil, 2D

+

This case is not in the list of available benchmarks but we decided to present +these results here as an example of simulation study. +An extremely intense plane wave in 2D interacts with a thin, fully-ionized carbon foil. +The foil is located 4 µm from the left border (\(x_{min}\)). +It starts with 1 µm of linear pre-plasma density, followed by +3 µm of uniform plasma of density 492 times critical. +The target is irradiated by a gaussian plane wave of peak intensity +\(a_0 = 270\) (corresponding to \(10^{23}\ \mathrm{Wcm^{-2}}\)) +and of FWHM duration 50 fs. +The domain has a discretization of 64 cells per µm in +both directions x and y, with 64 particles per cell. +The same simulation has been performed with the different radiation models.

+

Electrons can be accelerated and injected in +the target along the density gradient through the combined action of +the transverse electric and the magnetic fields (ponderomotive effects). +In the relativistic regime and linear polarization, +this leads to the injection of bunches of hot electrons +every half laser period that contribute to heat the bulk. +When these electrons reach the rear surface, they start to expand in the vacuum, +and, being separated from the slow ion, create a longitudinal charge-separation field. +This field, along the surface normal, has two main effects:

+
    +
  • It acts as a reflecting barrier for electrons of moderate energy (refluxing electrons).

  • +
  • It accelerates ions located at the surface (target normal sheath acceleration, TNSA).

  • +
+

At the front side, a charge separation cavity appears +between the electron layer pushed forward by the ponderomotive force and ions +left-behind that causes ions to be consequently accelerated. This +strong ion-acceleration mechanism +is known as the radiation pressure acceleration (RPA) or laser piston.

+

Under the action of an extremely intense laser pulse, electrons accelerated at +the target front radiate. It is confirmed in Fig. 34 +showing the distribution of the quantum parameter \(\chi\) along the x axis +for the Monte-Carlo, the Niel and the corrected Landau-Lifshitz (CLL) radiation models. +The maximum values can be seen at the front where the electrons +interact with the laser. Radiation occurs in the quantum regime +\(\chi > 0.1\). Note that there is a second peak for \(\chi\) at the +rear where electrons interact with the target normal sheath field. +The radiation reaction can affect electron energy absorption and therefore the ion +acceleration mechanisms.

+
+../_images/thin_foil_x_chi_ne.png +
+

Fig. 34 \(x - \chi\) electron distribution at time 47 fs for the Monte-Carlo, +the Niel and the corrected Landau-Lifshitz (CLL) model.

+
+
+

The time evolutions of the electron kinetic energy, the carbon ion +kinetic energy, the radiated energy and the total +absorbed energy are shown in Fig. 35. +The corrected-Landau-Lifshitz, the Niel +and the Monte-Carlo models present very +similar behaviors. +The absorbed electron energy is only slightly lower in the Niel model. +This difference depends on the random seeds and the +simulation parameters. +The radiated energy represents around 14% of the total laser energy. +The classical Landau-Lifshitz model overestimates the radiated energy; +the energy absorbed by electrons and ions is therefore slightly lower. +In all cases, radiation reaction strongly impacts the overall particle energy absorption +showing a difference close to 20% with the non-radiative run.

+
+../_images/thin_foil_scalar.png +
+

Fig. 35 Time evolution of the electron kinetic energy (solid lines), the carbon ion +kinetic energy (dashed line), the radiated energy (dotted line) and the total +absorbed energy by particle and radiation (dotted-dashed lines), for various models.

+
+
+

The differences between electron \(p_x\) distributions are shown +in Fig. 36. Without radiation reaction, electrons refluxing +at the target front can travel farther in vacuum (negative \(p_x\)) +before being injected back to the target. +With radiation reaction, these electrons are rapidly slowed down +and newly accelerated by the ponderotive force. +Inside the target, accelerated bunches of hot electrons correspond to +the regular positive spikes in \(p_x\) (oscillation at \(\lambda /2\)). +The maximum electron energy is almost twice lower with radiation reaction.

+
+../_images/thin_foil_x_px_ne.png +
+

Fig. 36 \(x - p_x\) electron distribution at time 47 fs for the Monte-Carlo, +the Niel, the corrected Landau-Lifshitz (CLL) model and +without radiation loss (none).

+
+
+
+
+
+
+

Performances

+

The cost of the different models is summarized in Table 4. +Reported times are for the field projection, the particle pusher and +the radiation reaction together. Percentages correspond to the overhead induced by +the radiation module in comparison to the standard PIC pusher.

+

All presented numbers are not generalizable and are only indicated to give +an idea of the model costs. The creation of macro-photons is not enabled for +the Monte-Carlo radiation process.

+ + ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 4 Radiation model performances

Radiation model

None

LL

CLL

Niel

MC

Counter-propagating Plane Wave 1D +Haswell (Jureca)

0.2s

0.23s

0.24s

0.26s

0.3s

Synchrotron 2D Haswell (Jureca) +\(\chi=0.05\), \(B=100\)

10s

11s

12s

14s

15s

Synchrotron 2D Haswell (Jureca) +\(\chi=0.5\), \(B=100\)

10s

11s

12s

14s

22s

Synchrotron 2D KNL (Frioul) +\(\chi=0.5\), \(B=100\)

21s

23s

23s

73s

47s

Interaction with a carbon thin foil +2D Sandy Bridge (Poincare)

6.5s

6.5s

6.6s

6.8s

6.8s

+

Descriptions of the cases:

+
    +
  • Counter-propagating Plane Wave 1D: run on a single node of Jureca with 2 MPI ranks and 12 OpenMP +threads per rank.

  • +
  • Synchrotron 2D: The domain has a dimension of 496x496 cells with +16 particles per cell and 8x8 patches. +A 4th order B-spline shape factor is used for the projection. +The first case has been run on a single Haswell node of Jureca with 2 MPI ranks and +12 OpenMP threads per rank. the second one has been run on a single KNL node of Frioul +configured in quadrant cache using 1 MPI rank and 64 OpenMP threads. +On KNL, the KMP_AFFINITY is set to fine and scatter.

  • +
+
+

Only the Niel model provides better performance with a compact affinity.

+
+
    +
  • Thin foil 2D: +The domain has a discretization of 64 cells per \(\mu\mathrm{m}\) in +both directions, with 64 particles per cell. +The case is run on 16 nodes of Poincare with 2 MPI ranks and 8 OpenMP +threads per rank.

  • +
+

The LL and CLL models are vectorized efficiently. +These radiation reaction models represent a small overhead +to the particle pusher.

+

The Niel model implementation is split into several loops to +be partially vectorized. The table lookup is the only phase that +can not be vectorized. Using a fit function enables to have a fully +vectorized process. The gain depends on the order of the fit. +The radiation process with the Niel model is dominated +by the normal distribution random draw.

+

The Monte-Carlo pusher is not vectorized because the Monte-Carlo loop has +not predictable end and contains many if-statements. +When using the Monte-Carlo radiation model, code performance is likely to be +more impacted running on SIMD architecture with large vector registers +such as Intel Xeon Phi processors. This can be seen in Table 4 +in the synchrotron case run on KNL.

+
+
+
+

References

+
+
DiPiazza2012
+

Di Piazza et al. (2012), Rev. Mod. Phys. 84, 1177

+
+
Duclous2011(1,2)
+

Duclous, Kirk and Bell (2011), Plasma Physics and Controlled Fusion, 53 (1), 015009

+
+
Elkina2011
+

Elkina et al. (2011), Physical Review Accelerators and Beam, 14, 054401

+
+
Landau1947
+

Landau and Lifshitz (1947), The classical theory of fields. Butterworth-Heinemann

+
+
Lobet2013(1,2)
+

Lobet et al. (2016), J. Phys.: Conf. Ser. 688, 012058

+
+
Lobet2015(1,2)
+

Lobet (2015), Effets radiatifs et d’électrodynamique quantique dans l’interaction laser-matière ultra-relativiste (2015)

+
+
Ridgers2017
+

Ridgers et al. (2017), Journal of Plasma Physics, 83(5)

+
+
Ritus1985
+

Ritus (1985), Journal of Soviet Laser Research, 6, 497, ISSN 0270-2010

+
+
Tamburini2010
+

Tamburini et al. (2010), New J. Phys. 12, 123005

+
+
Timokhin2010
+

Timokhin (2010), Monthly Notices of the Royal Astronomical Society, 408 (4), 2092, ISSN 1365-2966

+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/relativistic_fields_initialization.html b/Understand/relativistic_fields_initialization.html new file mode 100644 index 000000000..d2ee68bc5 --- /dev/null +++ b/Understand/relativistic_fields_initialization.html @@ -0,0 +1,594 @@ + + + + + + + + + Field initialization for relativistic species — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Field initialization for relativistic species

+

As explained in PIC algorithms, if a net charge is present at the beginning of the simulation, the initial electromagnetic fields are computed. +For static charge distributions, the solution of Poisson’s equation will be necessary to find the initial electrostatic field. +If the initial charge has a non-zero initial speed, in general the electric and magnetic field should be computed solving the full set of Maxwell’s equations or equivalently the potentials equations. +In some physical setups of interest, one or more relativistic species are injected in a plasma. In these cases, the computation of the initial electromagnetic fields can be reduced to the solution of a modified version of Poisson’s equation.

+
+
+

The relativistic Poisson’s equation

+

From the continuity equation \(\partial_t \rho + \nabla \cdot \mathbf{J} = 0\) +and Maxwell’s equations, it can be shown that the quantities \(\nabla\cdot\mathbf{B}\) and \(\nabla\cdot\mathbf{E}-\rho\) do not change over time:

+
+\[\begin{split}\begin{eqnarray} +\partial_t \left( \nabla\cdot\mathbf{B} \right ) &=& 0, \\ +\partial_t \left( \nabla\cdot\mathbf{E}-\rho \right ) &=& \nabla\cdot\partial_t\mathbf{E}-\partial_t\rho = \nabla\cdot\left(\nabla\times\mathbf{B}-\mathbf{J}\right)-\partial_t\rho = - \left(\nabla\cdot\mathbf{J}+\partial_t \rho\right). +\end{eqnarray}\end{split}\]
+

Thus, if a simulation starts with \(\rho\neq0\), the electromagnetic fields must be properly initialized.

+

In the case of a static charge distribution, i.e. \(\rho\neq0\), \(\mathbf{J}=0\), the initial electrostatic potential \(\Phi\) can be computed solving Poisson’s equation:

+
+\[\nabla^2 \Phi = -\rho,\]
+

and then be integrated to find the initial electric field: \(\mathbf{E}=-\nabla\Phi\). The initial magnetic field \(\mathbf{B}\) will be zero.

+

In general when the initial current \(\mathbf{J}\) is not zero, the full set of fields equations should be solved to correctly initialize the electromagnetic fields.

+

However, if a species is already relativistic when the simulation starts, e.g. a relativistic electron bunch, its initial electromagnetic fields can be computed through a simplified procedure, described in [Vay2008], [Londrillo2014], [Massimo2016] and [Marocchino2018].

+

An important assumption of this calculation is that the species is highly relativistic, moving in the positive \(x\) direction, with negligible momentum spread. Under this hypothesis, the transverse components of the species current density are neglected and the four-current quadrivector can be written as:

+
+\[\left(\mathbf{J},\rho\right) = \left(\rho \beta_0 , 0, 0, \rho \right),\]
+

where \(\beta_0\) is the initial mean velocity of the relativistic species. At least locally, the potentials \(\mathbf{A}\), \(\Phi\) in the laboratory frame will be only function of \(x-\beta_0 t\), as they are propagating with the species at uniform relativistic velocity.

+

In the relativistic species rest frame \(S'\), the charge distribution is static and the electrostatic potential in that reference frame \(\Phi'\) is related to the charge density in that reference frame \(\rho'\) through Poisson’s equation:

+
+(68)\[\nabla'^2 \Phi' = -\rho',\]
+

where the Laplacian operator is computed in the reference frame \(S'\):

+
+\[\nabla'^2=\partial^2_{x'}+\partial^2_{y'}+\partial^2_{z'}.\]
+

The vector potential in the species rest frame can be set to zero: \(\mathbf{A'}=0\). Through the above mentioned assumptions, it is possible to rewrite Eq. (68) only in terms of laboratory frame quantities.

+

Lorentz transformation of the four-vector \(\left(\mathbf{J},\rho \right)\) yields \(\rho'=\rho/\gamma_0\), where \(\gamma_0=1/\sqrt{1-\beta^2_0}\) is the average Lorentz factor of the relativistic species. +Similarly, the potential \(\Phi'\) can be rewritten in terms of the potential in the laboratory frame: \(\Phi'=\Phi/\gamma_0\). The Lorentz back-transformation of coordinates

+
+\[x=\gamma_0(x'+\beta_0 t'),\quad t = \gamma_0(t'+\beta_0 x'), \quad y=y', \quad z=z'\]
+

allows to transform the derivatives in Eq. (68) as

+
+\[\partial_{x'}=\gamma_0\left(\partial_x+\beta_0\partial_t\right), \quad \partial_{y'}=\partial_y, \quad \partial_{z'}=\partial_z.\]
+

The partial derivative along the \(x'\) direction can be further simplified, through the hypothesis of temporary dependence of all quantities on \(x-\beta_0 t\), implying \(\partial_t=-\beta_0\partial_x\):

+
+\[\partial_{x'}=\frac{1}{\gamma_0}\partial_x.\]
+

Equation (68) can thus be rewritten as

+
+(69)\[\left( \frac{1}{\gamma^2_0}\partial^2_x+\nabla_{\perp}^2\right) \Phi = -\rho,\]
+

here informally referred to as the relativistic Poisson’s equation. In Smilei, as for Eq. (68), the solution of the relativistic Poisson’s equation is performed through the conjugate gradient method.

+

Once the potential \(\Phi\) is found, we can compute all the components of the electromagnetic field, using again the relations \(\partial_t=-\beta_0\partial_x\), \(\Phi'=-\Phi/\gamma_0\) and the Lorentz back-transformation of the vector potential \(\mathbf{A}\):

+
+\[A_x = \gamma_0(A_x'+\beta_0 \Phi')=\gamma_0\beta_0 \Phi'=\beta_0\Phi,\quad A_y = A_y'=0, \quad A_z = A_z'=0.\]
+

From all these relations, the electromagnetic field can be computed as usual, through the definitions of potentials \(\mathbf{E}=-\nabla\Phi-\partial_t\mathbf{A}\), \(\mathbf{B}=-\nabla\times\mathbf{A}\):

+
+\[\begin{split}\begin{eqnarray} +E_x &=& -\partial_x \Phi - \partial_t A_x = -\partial_x \Phi + \beta_0^2 \partial_x \Phi = -\frac{1}{\gamma_0^2}\partial_x \Phi,\\ +E_y &=& -\partial_y \Phi - \partial_t A_y = -\partial_y \Phi,\\ +E_z &=& -\partial_z \Phi - \partial_t A_z = -\partial_z \Phi,\newline\\ +B_x &=& \partial_y A_z - \partial_z A_y = 0 ,\\ +B_y &=& \partial_z A_x - \partial_x A_z = \partial_z A_x = \beta_0 \partial_z \Phi = - \beta_0 E_z,\\ +B_z &=& \partial_x A_y - \partial_y A_x = - \partial_y A_x = - \beta_0 \partial_y \Phi = \beta_0 E_y, +\end{eqnarray}\end{split}\]
+

or in more compact form: \(\mathbf{E}=\left( -\frac{1}{\gamma_0^2}\partial_x \Phi, -\partial_y \Phi,-\partial_z \Phi \right)\), \(\mathbf{B}=\beta_0\mathbf{\hat{x}}\times\mathbf{E}\).

+

From the previous equations, it can be inferred that, in a 1D cartesian geometry, the fields computed through this procedure equal those obtained through the standard Poisson’s problem. +This can also be inferred from the relativistic transformations of fields, which conserve the \(x\) components of the electromagnetic fields for boosts in the \(x\) direction.

+
+
+
+

Recommendations for relativistic species field initialization

+

In Smilei, each species can independently benefit from this field initialization procedure. Its field will be initialized when the species will start to move, in order not to interfere with the other species’ dynamics. +The initialized fields will be superimposed to the electromagnetic fields already present in the simulation. To have physically meaningful results, we recommend to place a species which requires this method of field initialization far from other species, otherwise the latter could experience instantaneous unphysical forces by the relativistic species’ fields.

+

Remember that the transverse field of a moving charge with relativistic factor \(\gamma\) is greater than the electrostatic transverse field of that charge, by a factor \(\gamma\). +This means that for highly relativistic particles, you will need to use a transversely large simulation window to let the field decrease enough to reduce border effects during its propagation. +A complete absence of boundary effects in this case would be provided by perfectly absorbing boundary conditions, which are not implemented yet in the code. +If the relativistic species propagates in a plasma, these border effects could be partially screened by the plasma.

+

A relativistic mean velocity in the \(x\) direction and a negligible energy spread are assumed in the hypotheses of this procedure, so the user must ensure these conditions when defining the species requiring field initialization in the namelist. +The procedure could be extended to non-monoenergetic species, dividing the species macro-particles in monoenergetic energy bins and then superimposing the fields by each of the monoenergetic bins, computed with the same procedure. +At the moment, this energy binning technique is not available in Smilei.

+
+
+
+

References

+
+
Vay2008
+

J.-L. Vay, Physics of Plasmas 15, 056701 (2008)

+
+
Londrillo2014
+

P. Londrillo, C. Gatti and M. Ferrario, Nucl. Instr. and Meth. A 740, 236-241 (2014)

+
+
Massimo2016
+

F. Massimo, A. Marocchino and A. R. Rossi, Nucl. Instr. and Meth. A 829, 378-382 (2016)

+
+
Marocchino2018
+

A. Marocchino, E. Chiadroni, M. Ferrario, F. Mira and A.R. Rossi, Nucl. Instr. and Meth. A (2018)

+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/task_parallelization.html b/Understand/task_parallelization.html new file mode 100644 index 000000000..50be9ad38 --- /dev/null +++ b/Understand/task_parallelization.html @@ -0,0 +1,627 @@ + + + + + + + + + Task Parallelization — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Task Parallelization

+

Task parallelization is a method to spread the computing workload on the many cores +of a computer. Instead of splitting the data accross cores and apply the same task +to all these pieces, different tasks are split accross the cores with the +data necessary to complete them. This approach can often make the computation faster, +especially with non-uniform plasma distributions.

+

Task parallelization of macro-particle operations in Smilei (using OpenMP) is +published in [Massimo2022].

+
+
+

Motivation

+

Usually, most of the computing time is spent on macro-particle operations. +Consequently, a non-uniform plasma distribution results in load imbalance: +some cpu cores are loaded with less macro-particles, and idly wait for the +other cores to finish their work.

+

Worse: adding more cpu cores will not result in significant speedup, as only +a few of them are performing most of the work. This “strong scaling” curve +(speed-up vs number of cpu-cores) starts to saturate. Several methods for +parallelism can increase the number of computing units where +the saturation occurs.

+

In Smilei, by default, the data is split in patches (see +Parallelization basics) and, when the environment variable OMP_SCHEDULE +is set to dynamic, the OpenMP scheduler dynamically assigns each patch +to each core. This provides for some load balancing inside each MPI process, as +cores can work asynchronously on different patches.

+

This strategy implies that only 1 OpenMP thread can work on a given patch, +which includes potentially several Species and all the PIC operators +(interpolation, push, etc). These constraints can considerably slow down the +simulation in some situations (many species with non-uniform distribution, +and/or low number of patches per core).

+

A first solution is to split the data to a finer level: separate the +treatment of species, and split the patch in smaller structures (in Smilei, +patches are divided in clusters along the dimension x). This +can improve the strong scaling results, but some constructs cannot be +parallelized with this data splitting (e.g. irregularly nested loops, recursion, +etc). The task parallelism has been introduced to answer these issues.

+
+
+
+

Task approach

+

Smilei exploits the task parallelization (including task dependencies) +available with OpenMP 4.5. +The main idea is to split the work in smaller units that can be run asynchronously, +respecting the logical order in which these units of work must be completed.

+

In addition to separated species treatment and patches split in clusters +(see cluster_width and the following Figure), the macro-particle +operators (interpolation, push, etc) are defined as tasks. +All the combinations of [operator-cluster-species-patch] +correspond to different tasks that can be run in parallel.

+
+../_images/Cluster_definition_doc.png +
+

Fig. 70 Definition of clusters in a patch. The depicted 2D patch’s size is 16 × 6 cells +in the x and y directions respectively. In the Figure each cluster has an x +extension equal to cluster_width = 4 cells in the x direction.

+
+
+
+
+
+

Task dependency graph

+

Some tasks logically depend on other tasks, e.g. the position and momenta of the +macro-particles of a certain [cluster-species-patch] combination can be +advanced in a given iteration only after that the electromagnetic force acting +on them in that iteration has been interpolated from the grid.

+

The combinations [operator-cluster-species-patch] are defined as tasks, with +dependencies respecting the PIC macro-particle operator sequence +(Interpolation, Push, Projection) on the respective [cluster-species-patch] +combinations.

+

In task programming, the task dependencies of an algorithm are represented by +a task dependency graph, where each task is a node of the graph and the directed +edges between nodes are the task dependencies. If in this graph an arrow spawns +from task A to task B, then task B logically depends on task A.

+

In the code, the dependency graph is provided to OpenMP in form of depend +clauses in the omp task directives. This way, the tasks are dynamically assigned +to OpenMP threads, in the correct order (preventing data race conditions). +The user does not have to worry about the assignment of tasks to +the available threads, as this operation is done dynamically by the OpenMP scheduler.

+

This is described in [Massimo2022].

+
+
+
+

Performance Results

+

Some results from [Massimo2022] are shown in the following.

+

In the following Figure, a 2D uniform thermal plasma case shows that with +uniform macro-particle distributions the task-parallelization in Smilei +does not have a performance advantage. +In the same Figure, a 2D radiation pressure acceleration case shows that task +parallelization can have a performance advantage with non-uniform macro-particle +distributions.

+
+../_images/Cluster_width_scan_doc.png +
+

Fig. 71 Performances with and without task parallelization in a 2D uniform plasma case +(left) and in a 2D radiation pressure acceleration case (right).

+
+
+

Note in the following Figure the non-uniformity of the electrons distribution +in the radiation pressure acceleration case. The non-uniformity is present since +the start of the simulation. A namelist for a similar case can be found in the +benchmarks/tst2d_02_radiation_pressure_acc.

+
+../_images/Radiation_Pressure_Rho.png +
+

Fig. 72 Electron density divided by the critical density in a 2D radiation pressure +benchmark at 0 (left) and 1500 iterations (right). The non-uniformity of the +macro-particle distribution is present since the start of the simulation.

+
+
+

The scheduling of macro-particle operations without and with task parallelization +can be seen in the following figures. +Note how in the first Figure (without task parallelization), the end of the +treatment of macro-particle operators (around 0.1 s) is determined by the +OpenMP thread 0 of the MPI process 0. In the second Figure (with task parallelization), +the OpemMP thread 2 of MPI process 0 determines the end of the +treatment of macro-particle operators (around 0.07 s). In this case, the finer +decomposition given by the clusters and the relaxation of the constraints involved +in the assignment of macro-particle operations to threads yields a shorter time +to the result.

+
+../_images/Task_tracing_doc.png +
+

Fig. 73 Scheduling of macro-particle operations for the 2D radiation pressure benchmark, +4 MPI processes and 4 OpenMP threads, during iteration 1200, +without (left panel) and with task parallelization, 4 clusters per patch (right panel).

+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/units.html b/Understand/units.html new file mode 100644 index 000000000..9bfbebb54 --- /dev/null +++ b/Understand/units.html @@ -0,0 +1,660 @@ + + + + + + + + + Units — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ + + + +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Units

+

Like many PIC codes, Smilei handles only dimension-less variables, +normalized to reference quantities.

+
+
+

Basic reference quantities

+

The speed of light, the elementary charge and the electron mass provide the basis +of the normalizations in Smilei:

+
    +
  • Reference electric charge \(Q_r = e\) (the elementary charge)

  • +
  • Reference mass \(M_r = m_e\) (the electron mass)

  • +
  • Reference velocity \(V_r = c\) (the speed of light)

  • +
+

We can derive from these:

+
    +
  • a reference energy \(K_r = m_e c^2\)

  • +
  • a reference momentum \(P_r = m_e c\)

  • +
+

Even with these normalizations, Smilei does not know the scale of the problem: +it lacks a reference distance, or equivalently, a reference time.

+
+
+
+

Arbitrary reference quantities

+

Instead of choosing a physical constant (for example, the electron radius) as a reference, +the scale of the problem is not decided a priori, and the user is free to scale the result +of the simulation to any value. +In fact, quantities are proportional an unknown reference frequency +\(\omega_r\), which can be scaled by the user a posteriori.

+

Usually, \(\omega_r\) will be an important frequency of the problem. +For example, if there is a laser, it could be the laser frequency. +Or it could be the electron plasma frequency.

+

From this reference frequency \(\omega_r\), we define:

+
    +
  • a reference time \(T_r = 1/\omega_r\)

  • +
  • a reference length \(L_r = c/\omega_r\)

  • +
  • a reference electric field \(E_r = m_e c \omega_r / e\)

  • +
  • a reference magnetic field \(B_r = m_e \omega_r / e\)

  • +
  • a reference particle density \(N_r = \varepsilon_0 m_e \omega_r^2 /e^2\)

  • +
  • a reference current \(J_r = c\, e\, N_r\)

  • +
+
+

Warning

+

\(1/N_r\) is a volume, but counter-intuitively, it is not equal to \(L_r^{3}\).

+
+

Normalizing all quantities to these references is convenient for resolving Maxwell’s equations, +and the charges equation of motion, as it converts them into a dimension-less set of equations:

+
+\[ \begin{align}\begin{aligned}\begin{split}\mathbf{\nabla}\cdot\mathbf{E} = \rho +\quad\quad +\nabla\cdot\mathbf{B} & = 0 \\\end{split}\\\nabla\times\mathbf{E} = - \partial_t \mathbf{B} +\quad\quad +\nabla\times\mathbf{B} = & \; \mathbf{j} + \partial_t \mathbf{E}\end{aligned}\end{align} \]
+
+\[\partial_t \mathbf{p} = Z \mathbf{E} + Z \mathbf{v}\times\mathbf{B}\]
+

where \(\mathbf{E}\), \(\mathbf{B}\), \(\mathbf{j}\) and \(\mathbf{\rho}\) +are the electric field, magnetic field, current density and charge density, normalized to +\(E_r\), \(B_r\), \(J_r\) and \(Q_r N_r\), respectively. \(Z\) and +\(\mathbf p\) are a particle’s charge and momentum, normalized to \(Q_r\) and +\(P_r\), respectively. Note that the temporal and spatial derivatives are also +normalized to \(T_r\) and \(L_r\), respectively.

+
+
+
+

Tips for the namelist

+

In the namelist, the user must provide all parameters in units of \(Q_r\), +\(M_r\), \(V_r\), \(K_r\), \(P_r\), \(T_r\), \(L_r\), \(E_r\), +\(B_r\), \(N_r\) or \(J_r\).

+

This may be cumbersome if you know your input data in other units. +However, the namelist is actually a python code that can compute conversions easily.

+

For example, let us assume that you know your problem size in units of the wavelength. +Knowing that the reference wavelength is \(2\pi L_r\), you can multiply all your +lengths by \(2\pi\):

+
from math import pi
+wavelength = 2. * pi
+cell_length = [0.05 * wavelength]
+grid_length  = [100. * wavelength]
+
+
+
+
+
+

Problems requiring explicit units

+

Sometimes, Smilei may be requested to compute other things than Maxwell’s +equations. That is the case, for example, for computing collisions or ionization. +In these situations, equations cannot be normalized to dimension-less terms, and +the code must know the value of \(\omega_r\) in physical units. This requires +defining an extra parameter in the namelist.

+

For instance, reference_angular_frequency_SI = 2.*pi*3e8/1e-6 means that +\(L_r = 1\,\mathrm{\mu m} /(2\pi)\). +This information will be used only in some specific parts of the code (collisions, ionization, …) +but not in the main PIC algorithms.

+
+

Warning

+

The outputs of the code are not converted to SI. +They are all kept in the reference units listed above.

+
+
+
+
+

Quantities integrated over the grid

+

Special care must be taken when considering local quantities that are spatially +integrated.

+

1. The spatially-integrated kinetic energy density

+

The particle kinetic energy density is naturally in units of \(K_r N_r\). +Integrating over space give different results depending on the simulation dimension. +In 1D, this space is a length, with units \(L_r\); in 2D, it is a surface, with units +\(L_r^2\); and in 3D, it is a volume, with units \(L_r^3\). +Overall, the integrated energy has the units \(K_r N_r L_r^D\) +where \(D\) is the simulation dimension. Note that we could expect +to obtain, in 3D, an energy with units \(K_r\), but counter-intuitively +it has the units \(K_r N_r L_r^3\).

+

These kinetic energies appear, for instance, in the Scalar diagnostics as +Ukin (and associated quantities).

+

2. The spatially-integrated electromagnetic energy density

+

The electromagnetic energy density has the units \(E_r^2/\varepsilon_0 = K_r N_r\). +Consequently, the spatially-integrated electromagnetic energy density has +the units \(K_r N_r L_r^D\); the same as the integrated kinetic energy density above.

+

These electromagnetic energies appear, for instance, in the Scalar diagnostics as +Uelm (and associated quantities).

+

3. The space- & time-integrated Poynting flux

+

The Poynting flux has the units \(E_r B_r / \mu_0 = V_r K_r N_r\). +Consequently, the flux integrated over a boundary, and over time, has the units +\(V_r K_r N_r L_r^{D-1} T_r = K_r N_r L_r^D\), which is the same as the +integrated energy densities above.

+

This integrated Poynting flux appears, for instance, in the Scalar diagnostics as +Uelm_bnd, PoyXmin, PoyXminInst (and associated quantities).

+
+
+
+

Macro-particle weights

+

Macro-particles are assigned a statistical weight which measures +their contribution to the plasma distribution function. +In Smilei, this weight is defined for each particle at the moment of its creation +(usually at the beginning of the simulation), +and is never modified afterwards. Its definition reads:

+
+\[\textrm{macro-particle weight} = \frac + {\textrm{species density} \times \textrm{cell hypervolume}} + {\textrm{number of macro-particles in cell}}\]
+

As the density is in units of \(N_r\) and the cell hypervolume in +units of \(L_r^D\) (where \(D\) is the simulation dimension), +then the units of weights is \(N_r L_r^D\).

+

This definition of weights ensures that they do not depend on the +cell hypervolume, i.e. they can be reused in another simulation, as long as +\(D\), \(L_r\) and \(N_r\) are unchanged.

+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Understand/vectorization.html b/Understand/vectorization.html new file mode 100644 index 000000000..91e7b9226 --- /dev/null +++ b/Understand/vectorization.html @@ -0,0 +1,767 @@ + + + + + + + + + Vectorization — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Vectorization

+

For enhanced performances on most recent CPUs, Smilei exploits +efficiently vectorization using refactored and optimized operators.

+

Vectorization optimizations are published in [Beck2019].

+
+
+

Notion of Single Instruction Multiple Data (SIMD) Vectorization

+

Single Instruction Multiple Data (SIMD) vectorization consists on performing on +a contiguous set of data, usually called vector, the same operation(s) +in a single instruction. +On modern Computational Processing Units (CPU), vector registers have a length 512 kb +that corresponds to 8 double precision floats (on Intel Skylake processors for +instance and future ARM architecture). +Each processing unit can perform a Fused Multiply Add instruction (FMA) that +combines an addition and a multiplication. +If-conditions can be handled using mask registers. +Modern SIMD vectorization is described in Fig. 8.

+
+../_images/SIMD.png +
+

Fig. 8 Single Instruction Multiple Data (SIMD) vectorization

+
+
+

On SIMD CPUs, an application has to use SIMD vectorization to reach the maximum +of the core computational peak performance. A scalar code without FMA +uses less than 7% of the core computational power. +This affirmation can nonetheless be mitigated on Intel Skylake processors that +adapt their frequency on the used vectorization instruction set.

+
+
+
+

SIMD vectorization of the particle operators

+

Optimization efforts have been recently done to vectorize efficiently the +particle operators of Smilei.

+

A new sorting method has been first implemented in order to then make +the particle operator vectorization easier. +This method, referred to as cycle sort, minimizes the number of data movements +by performing successive permutation.

+

The most expensive operators and most difficult to vectorize are the current projection +(deposition) and the field interpolation (gathering) steps where +there is an interpolation between the grids and the macro-particles. +These two steps have been vectorized taking advantage of the cycle sort.

+
+
+
+

Vectorization Performance

+

Vectorization is not always the most efficient choice. +It depends on the number of macro-particles per cell. +To demonstrate this, we have evaluated in [Beck2019] the performance with a series of tests on different architectures: Intel Cascade +Lake, Intel Skylake, Intel Knights Landing, Intel Haswell, Intel Broadwell. +The Cascade Lake processor is not in the original study and has been added after. +We have used the 3D homogeneous Maxwellian benchmark available here. +The number of macro-particles per cell is varied from 1 to 512. +This study has been focused on the particle operators (interpolator, pusher, projector, sorting) and discards the +computational costs of the Maxwell solver and of the communications between processes. +Each run has been performed on a single node with both the scalar and the vectorized operators.. +Since the number of cores varies from an architecture +to another, the runs were conducted so that the load per core +(i.e. OpenMP thread) is constant. +The number of patches per core also remains the same for all cores throughout the whole simulation since the imbalance +in this configuration is never high enough to trigger patch exchanges. +The patch size is kept constant at 8 × 8 × 8 cells. +The total number of patches for each architecture is determined so that each core has 8 patches to handle. +The numerical parameters are given in Table 1.

+ + ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1 Numerical parameters for vectorization

Cluster

Architecture

Number of patches

Configuration

Jean Zay, IDRIS, France

2 x Cascade Lake (Intel® Xeon® Gold 6248, 20 cores)

5 x 8 x 8

Intel 19, IntelMPI 19

Irene Joliot-Curie, TGCC, France

2 x skylake (Intel® Skylake 8168, 24 cores)

6 x 8 x 8

Intel 18, IntelMPI 18

Frioul, Cines, France

2 x Knights Landing (Intel® Xeon® Phi 7250, 68 cores)

8 x 8 x 8

Intel 18, IntelMPI 18

Tornado, LPP, France

2 x Broadwell (Intel® Xeon® E5-2697 v4, 16 cores)

4 x 8 x 8

Intel 17, openMPI 1.6.5

Jureca, Juelich, Germany

2 x Haswell (Intel® Xeon® E5-2680 v3, 12 cores)

3 x 8 x 8

Intel 18, IntelMPI 18

+

The results of the simulation tests (shape factor of order 2) for both scalar and vectorized versions are +shown in Fig. 9. +Contrary to the scalar mode, the vectorized operators efficiency depends strongly on the number of particles per cell. +It shows improved efficiency, compared to the scalar mode, above a certain number of particles per cell denoted inversion point.

+
+../_images/vecto_particle_times_o2_all.png +
+

Fig. 9 Particle computational cost as a function of the number of particles per cell. Vectorized +operators are compared to their scalar versions on various cluster +architectures. Note that the Skylake compilations accepts both AVX512 and AVX2 +instruction sets.

+
+
+

The lower performances of the vectorized operators at low particles per cell can be easily understood:

+
    +
  1. The complexity of vectorized algorithms is higher than their scalar counter-parts.

  2. +
  3. New schemes with additional loops and local buffers induced an overhead that is onmy compensated when the number of particles is large enough.

  4. +
  5. SIMD instructions are not efficient if not fulfilled

  6. +
  7. SIMD instructions operate at a lower clock frequency than scalar ones on recent architectures

  8. +
+

The location of the inversion point of the speed-ups brought by vectorization depends on the architecture. +The performance results are summarized in Table 2.

+ + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 2 Vectorization performance

Architecture (Cluster)

Inversion point (particles per cell)

Vectorization speed-up

Cascade lake (Jean Zay)

8 particles per cell

x2

Skylake (Irene Joliot-Curie)

10 particles per cell (most advanced instruction set)

x2.1

KNL (Frioul)

12 particles per cell

x2.8

Broadwell (LLR)

10 particles per cell

x1.9

Haswell (Jureca)

10 particles per cell

x1.9

+

Vectorization efficiency increases with the number of particles per cell above the inversion point. +It tends to stabilize far from the inversion point above 256 particles per cell.

+
+
+
+

Adaptive vectorization

+

Adaptive vectorization consists on switching localy between scalar and +vectorized operators during the simulation, choosing the most efficient one +in the region of interest. +The concept has been successfully implemented at the lower granularity of the code. +Every given number of time steps, for each +patch, and for each species, the most efficient set of operator is determined +from the number of particles per cell. +The concept is schematically described in Fig. 10.

+
+../_images/vecto_domain_decomposition.png +
+

Fig. 10 Description of the adaptive vectorization withn the multi-stage domain decomposition. +Patches with many macro-particles per cell are faster in with vectorized operators whereas with few macro-particles per cell, scalar operators are more efficient.

+
+
+

An advanced empirical criterion has been developed. +It is computed from the parametric studies presented in Fig. 9 +summarizes their results and indicates, for a given species in a given patch, the approximate time to compute the particle +operators using both the scalar and the vectorized operator. +The computation times have been normalized to that of the scalar operator for a single particle. +The comparision of all normalized curves is presented in Fig. 11.

+
+../_images/vecto_efficiency_o2_all_mc.png +
+

Fig. 11 Normalized time per particle spent for all particle operators in +the scalar and vectorized modes with various architectures, and 2nd-order +interpolation shape functions.

+
+
+

The outcomes from different architectures appear sufficiently similar to consider an average between their results. +A linear regression of the average between all is applied on the scalar results to have a fit function to implement in the code. +It writes:

+
+(6)\[S(N) = -1.11 \times 10^{-2} \log{\left( N \right)} + 9.56 \times 10^{-1}\]
+

S is the computation time per particle normalized to that with 1 PPC, and N is the number of PPC. +For the average between vectorized results, a fourth-order polynomial regression writes:

+
+(7)\[\begin{split}V(N) = 1.76 \times 10^{ -3 } \log{ \left( N \right)}^4 \\ \nonumber ++ 8.41 \times 10^{ -2 } \log{ \left( N \right)}^3 \\ \nonumber ++ 1.45 \times 10^{ -2 } \log{ \left( N \right)}^2 \\ \nonumber +-1.19 \log{ \left( N \right) } \\ \nonumber ++ 2.86\end{split}\]
+

The polynomial regressions are shown in Fig. 12.

+
+../_images/vecto_efficiency_o2_all_fit.png +
+

Fig. 12 Averages of the curves of Fig. 11 , and polynomial regressions.

+
+
+

These functions are implemented in the code to determine approximately the normalized single-particle cost. +Assuming every particle takes the same amount of time, the total time to advance a species in a given patch can then be simply evaluated with a +sum on all cells within the patch as:

+
+(8)\[T_{\rm s,v} = \sum_{c \ \in\ patch\ cells} N(c) \times F\!\left(N(c)\right)\]
+

where F is either S or V. +Comparing \(T_s\) and \(T_v\) determines which of the scalar or vectorized operators should be locally selected. +This operation is repeated every given number of time steps to adapt to the evolving plasma distribution. Note that similar +approximations may be computed for specific processors instead of using a general rule. +In Smilei, other typical processors have been included, requiring an additional compilation flag automatically included in the machine files for make.

+

The process of computing the faster mode and changing operators accordingly is called reconfiguration

+
+
+

Large-scale simulations

+

Adaptive vectorization has been validated on large-scale simulations with +different benchmarks. +The following video enables to visualize on different scenarii the behavior of the adaptive vectorization.

+
+

Mildly-relativistic collisionless shock

+

One of the case was the simulation of Mildly-relativistic collisionless shock. +The effect of the adaptive vectorization mode is illustrated by Fig. 13. +The electron density is shown in the volume rendering of the top. +The volume rendering at the bottom shows and patch computational state for the electron species.

+
+../_images/Weibel_3d_ne_vecto_it510.jpg +
+

Fig. 13 Mildly-relativistic collisionless shock: On the top, volume rendering of the normalized +electron density \(n_e /n_c\) (\(n_c\) the critical density) at +time \(t = 34 \omega^{-1}\) (\(\omega\) the laser frequency) after the beginning of the collision. +On the bottom, patches in vectorized +mode for the electron species at the same time. +An animated version of these can be viewed by clicking on this image.

+
+
+

Thanks to the adaptive vectorization, high-density regions that contains many macro-particles per cell corresponds to the patches in vectorized mode. +Incoming plasma flows, with 8 particles per cell in average, are in scalar mode. +The following video shows how the patches are dynamically switched in vectorized or scalar mode.

+

For this specific benchmark, the speed-up obtained with vectorization is of x2. +Adaptive vectorization brinds a small additional speed-up in some cases.

+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/contribute.html b/Use/contribute.html new file mode 100644 index 000000000..010ddec0c --- /dev/null +++ b/Use/contribute.html @@ -0,0 +1,700 @@ + + + + + + + + + Contribute — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ + + + +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Contribute

+

Contributions to the development of Smilei are welcome.

+
    +
  • Chatroom for discussion and sharing.

  • +
  • GitHub issues for bugs and requests.

  • +
  • Develop new features (clone the repository clicking the “fork” button the GitHub page so you can then make a pull request to integrate them in the main repository).

  • +
+

Guidelines for new developments are:

+
    +
  • Write clear, commented code, or self-explanatory.

  • +
  • Write the documentation corresponding to the new features, if any.

  • +
  • Make validation cases, and reference data, corresponding to the added features.

  • +
+
+
+

Add my publication to the list on Smilei’s website

+

You can easily add your paper to the Publications.

+
    +
  • On GitHub, edit the file +material.rst. +and add a few lines such as:

    +
    .. [MyNameYEAR]
    +
    +    M. Name, A. Collaborator and B. Collaborator,
    +    `Title of my paper`,
    +    `Reference of the Paper <https://link/to/the/paper>`_,
    +    `arXiv:xxxx.xxxx <https://arxiv.org/abs/xxxx.xxxx>`_
    +
    +
    +
  • +
  • Make a pull request to share your update.

  • +
+
+
+
+

Write documentation

+

The documentation you are currently reading is written in the +reStructuredText (rST) language, and included +in the main Smilei repository. This is a fairly simple markup language. You +can see examples from the source files, which are located in the +doc/Sphinx folder and have the extension .rst.

+

To transform it into an html website, it is +processed using the sphinx python package that you may have to +install. +If you have sphinx installed, you may simply go to the +main Smilei folder from a command line terminal, then run the command

+
make doc
+
+
+

This creates a local html website accessible in the build/html/ folder. Simply +open the build/html/index.html file in your favorite web browser.

+

To document a new feature, please modify the file namelist.rst to indicate the +syntax changes in the input file. If the feature requires detailed physical or numerical +background, you may add a new page in the “Understand” section of the website. +To do that, create a new .rst file, then reference it in the table of contents +located in index.rst.

+
+
+
+

Validate your changes

+

Smilei has a system of test cases combined with reference results that must be +validated, ideally, for every push submitted to the git repository. +These test cases are located in the benchmarks/ folder.

+

Each benchmark has an associated validation file, written in python, which contains +instructions on how to produce an analysis of the results that can validate that particular +benchmark. The validation files are located in the validation/analyses/ folder. +They have the same name as the benchmarks, with the prefix validate_.

+

Once a benchmark has been run, the corresponding validate_* file is run in python +to compare the analysis results with a reference file located in the folder +validation/references/. Note that the analysis produced by the validate_* file +can also be used to generate the reference file the first time.

+

When you code a new feature, you must provide a new benchmark, the corresponding +analysis and reference file

+

To make this process easier, a python script is available.

+

How do I use the validation.py script?

+

The script validation/validation.py can do three things:

+
    +
  • generate validation reference(s) for given benchmark(s)

  • +
  • compare benchmark(s) to their reference(s)

  • +
  • show visually differences between benchmark(s) and their reference(s)

  • +
+

Usage:

+
+
python validation.py [-c] [-h] [-v] [-o <nOMP>] [-m <nMPI>] [-b <bench> [-g | -s]] [-r <nRestarts>] [-t <max_time>]
+
+
+
    +
  • +
    Option -b <bench>:
    +
    <bench> : benchmark(s) to validate. Accepts wildcards.
    +
    <bench>=? : ask input for a benchmark
    +
    DEFAULT : All benchmarks are validated.
    +
    +
  • +
  • +
    Option -o <nOMP>:
    +
    <nOMP> : number of OpenMP threads used for the execution
    +
    DEFAULT : 4
    +
    +
  • +
  • +
    Option -m <nMPI>:
    +
    <nMPI> : number of MPI processes used for the execution
    +
    DEFAULT : 4
    +
    +
  • +
  • Option -g: Generation of references only (no validation)

  • +
  • Option -s: Plot differences with references only (no validation)

  • +
  • Option -c: Compilation only (no run, no validation)

  • +
  • Option -r <nRrestarts>: Force the simulation to be broken in several restarts

  • +
  • Option -v: Verbose

  • +
  • Option -h: Help

  • +
  • Option -t <max_time>: maximum wall time (format "hh:mm:ss")

  • +
+
+

Exit status of the script:

+
+
    +
  • 0 validated

  • +
  • 1 validation fails

  • +
  • 2 execution fails

  • +
  • 3 compilation fails

  • +
  • 4 bad option

  • +
+
+

Examples:

+
+
./validation.py -v
+
+
+

Compiles and validates all cases in verbose mode.

+
./validation.py -v -b tst1d_00_em_propagation.py
+
+
+

Validates only the benchmark tst1d_00_em_propagation.py.

+
./validation.py -v -b tst1d_00_em_propagation.py -g
+
+
+

Generates the reference file for the benchmark tst1d_00_em_propagation.py.

+
./validation.py -v -b tst1d_00_em_propagation.py -s
+
+
+

Runs the benchmark tst1d_00_em_propagation.py, and plots the differences with the reference file.

+
+

What does validation.py actually do?

+

It creates a new validation/workdirs directory (that may be freely deleted later).

+

It compiles the code:

+
+

If the “workdirs” directory lacks a smilei binary, or it is too old, +then the “workdirs” is backed up, and a new compilation occurs. +The compilation output is logged in compilation_output. +If compiling errors occur, compilation_errors is created and the script exits with status 3.

+
+

It runs each benchmark:

+
+

If the directory wd_<benchmark>/<o>/<m> does not exist then:

+
    +
  • it is created.

  • +
  • smilei is executed in that directory for the requested benchmark.

  • +
  • if execution fails, the script exits with status 2.

  • +
+
+

It analyses the results (for each requested benchmark) using the validate_* script:

+
+
    +
  • If requested to compare to previous references (default option), the analysis +is compared to the reference data.

  • +
  • If requested to generate references (option -g), the analysis is stored +as reference data.

  • +
  • If requested to show differences to previous references (option -s), +the analysis is plotted vs. the reference data.

  • +
+
+

How should I make the validate_* script?

+

The validate_* script should load the simulation results using whatever means suits +the benchmark the best. In many cases, the happi module is +employed to extract diagnostics results.

+

Any python instructions may be used to process the simulation results. Once the data +has been crunched into a meaningful value, string, or array, then it must be passed to the +following predefined function:

+
+
+Validate(description, data, epsilon)
+
    +
  • description: a string describing the data

  • +
  • data: a float, a numpy float array, or any other python data

  • +
  • epsilon (optional): acceptable difference between data and reference

  • +
+
+ +

The data passed to this function constitutes the analysis that is compared to previous +reference files. It is the same analysis that is used to generate those reference files +in the first place.

+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/ids.html b/Use/ids.html new file mode 100644 index 000000000..329a4beba --- /dev/null +++ b/Use/ids.html @@ -0,0 +1,524 @@ + + + + + + + + + Identification of tracked particles — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Identification of tracked particles

+

Tracked particles require an identification number (ID) in +order to be recognized after they move around. In Smilei, the particles ID are not simply +the integers from 0 to N-1, where N is the total number of particles in the +simulation. Instead, a more subtle approach is taken.

+

If all numbers from 0 to N-1 were used, then processors would have to communicate +together each time a new particle is created to avoid duplicates. That would be too +costly. We choose to avoid unnecessary communications, meaning that processors manage +particle IDs independently from each other. This is reflected in the structure of the +output files for the tracked particles diagnostic. These +files, named TrackParticlesDisordered_***.h5, contain arrays where each proc owns +a contiguous block, corresponding to the amount of particles it needs to write:

+
|------- Proc 0 ------|----------- Proc 1 ------------|--- Proc 2 ---|-- .......
+
+
+

These blocs have distinct sizes in general, and contain particles that are not sorted by +ID, as they move sometimes from one processor to another.

+

However, particles keep, in their ID, the number of the processor in which they were +created. More precisely, the ID of a particle is a uint64, a positive integer whose +binary representation has 64 bits. To illustrate the content of these 64 bits let us +replace zeros and ones by X, Y or Z:

+
XXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+
+

There are 64 bits available. The first 8 (X) are not parsed by the code, but may be set +by users for custom purposes. The next 24 (Y) represent the processor number. For instance, +for processor 0, all Y will equal 0; for processor 1, only the last Y will be 1. The last +32 bits (Z) indicate the particle number. This number is not unique among processors: for +example, the first particle of each proc always has number 0. The combination of these +last two numbers (YYYYY… and ZZZZZZ….) ensures a unique ID across the whole simulation. +Clearly, the IDs are not represented by a contiguous list of integers from 0 to N-1.

+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/install_linux.html b/Use/install_linux.html new file mode 100644 index 000000000..b183a909e --- /dev/null +++ b/Use/install_linux.html @@ -0,0 +1,575 @@ + + + + + + + + + Install dependencies on Linux — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Install dependencies on Linux

+

Here we present the packages you need to install in order to be able to compile Smilei. Please be aware that distribution change quite often the package names. As +result this guide could partially or totally outdated. In case you find some error, please fill a github issue .

+
+

ArchLinux

+
sudo pacman -S git hdf5-openmpi python-numpy python-sphinx python-h5py-openmpi python-matplotlib python-pint make gcc
+
+
+
+
+

Fedora

+
sudo dnf install gcc-c++ git hdf5-openmpi hdf5-openmpi-devel openmpi-devel python python-devel python3-h5py ipython python3-pint python3-sphinx python3-matplotlib
+
+
+

Add the following lines to your ~/.bashrc or ~/.bash_profile file

+
module load mpi
+
+
+
+
+

Debian or Ubuntu

+
sudo apt-get install git python3-h5py python3-ipython python3-pint python3-sphinx python3-matplotlib python3-dev python3-numpy build-essential gcc libhdf5-openmpi-dev
+
+
+

Add the following lines to your ~/.bashrc or ~/.bash_profile file

+
export PYTHONEXE=python3
+export HDF5_ROOT_DIR=/usr/lib/x86_64-linux-gnu/hdf5/openmpi
+
+
+
+
+

Troubleshooting:

+

Besides Python Smilei need a quite recent mpi (with mpi-thread-multiple enabled) and a parallel hdf5 library. +In case you system doe not provide them, here is a (non exhaustive) help to instlal them:

+
    +
  1. If your system openmpi is not compiled with --enable-mpi-thread-multiple, a manual installation is required. +Add the following lines to your ~/.bashrc or ~/.bash_profile file +(You may choose any ${INSTALL_DIR})

  2. +
+
+
export INSTALL_DIR=/usr/local
+export PATH=${INSTALL_DIR}/openmpi/bin:${PATH}
+export LD_LIBRARY_PATH=${INSTALL_DIR}/openmpi/lib:${LD_LIBRARY_PATH}
+export PATH=${INSTALL_DIR}/hdf5/bin:${PATH}
+export LD_LIBRARY_PATH=${INSTALL_DIR}/hdf5/lib:${LD_LIBRARY_PATH}
+export HDF5_ROOT_DIR=${INSTALL_DIR}/hdf5
+
+
+
+
    +
  1. Restart your terminal

  2. +
  3. Download OpenMPI and install.

  4. +
+
+
tar zxvf openmpi-*.*.*.tar.gz
+cd openmpi-*.*.*
+./configure --prefix=${INSTALL_DIR}/openmpi --enable-mpi-thread-multiple --enable-mpirun-prefix-by-default
+make
+sudo make install
+
+
+
+
    +
  1. Restart your terminal

  2. +
  3. Download HDF5 and install

  4. +
+
+
tar zxvf hdf5-*.*.*.tar.gz
+cd hdf5-*.*.*
+./configure --prefix=${INSTALL_DIR}/hdf5 --enable-parallel --with-pic --enable-linux-lfs --enable-shared --enable-build-mode=production --disable-sharedlib-rpath --enable-static CC=mpicc FC=mpif90
+make
+sudo make install
+
+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/install_macos.html b/Use/install_macos.html new file mode 100644 index 000000000..9af730a8d --- /dev/null +++ b/Use/install_macos.html @@ -0,0 +1,612 @@ + + + + + + + + + Install dependencies on MacOS — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Install dependencies on MacOS

+

First, you will need to install Xcode and the Command Line Tools in order to be able to compile Smilei

+
+
xcode-select --install
+
+
+
+

and follow the instructions.

+

Here we show how to install all dependendencies needed by Smilei using Brew or Macports. Please note that you need to install one and only one package manager.

+
+
+

Brew : install Smilei

+

This installation procedure has been tested on macOS 10.14.4

+
    +
  1. Install HomeBrew via:

    +
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    +
    +
    +
  2. +
  3. Install Smilei

    +
    brew install --HEAD iltommi/brews/smilei
    +
    +
    +

    Smilei executables (smilei and smilei_test) and the python module are now accessible from everywhere.

    +
  4. +
  5. Install python packages needed for the happi python module:

    +
    pip3 install ipython h5py pint sphinx matplotlib scipy
    +
    +
    +
  6. +
+

Documentation can be opened with

+
+
open /usr/local/opt/smilei/share/html/index.html
+
+
+
+

To update Smilei with just type

+
+
brew upgrade --fetch-HEAD smilei
+
+
+
+
+
+
+

Brew : install dependencies

+

In case you want ot keep a private version of Smilei where you can make changes to the core code, +you might want to just install the Smilei dependencies to be able to compile Smilei from you directory:

+
    +
  1. install Smilei dependencies

    +
    brew install iltommi/brews/smilei --HEAD --only-dependencies
    +
    +
    +
  2. +
  3. Edit your .bash_profile (or .zprofile on Catalina) hidden file located in your home folder:

    +
    open ~/.bash_profile
    +
    +
    +

    and add the following lines at the end:

    +
    export OMPI_CXX=g++-11
    +export HDF5_ROOT_DIR=`brew --prefix`/opt/hdf5-parallel
    +export PYTHONEXE=python3
    +
    +
    +
  4. +
  5. In a new terminal window, you can now compile smilei (see Download and compile for other options)

  6. +
+
+
+
+

Macports : install dependencies

+

Please note that these guidelines might be slightly outdated. Tested on Mojave in january 2021

+

If you find any error, please fill an issue on GitHub: https://github.com/SmileiPIC/Smilei/issues

+

This installation procedure relies on the software MacPorts +that you can install following these instructions.

+
    +
  1. In a terminal, run the following command to install the C++ compiler with MPI and HDF5:

    +
    sudo port -N install openmpi-gcc10 +threads
    +sudo port select --set mpi openmpi-gcc10-fortran
    +sudo port -N install hdf5 +openmpi+gcc10
    +
    +
    +
  2. +
  3. Edit your .bash_profile hidden file located in your home folder:

    +
    open ~/.bash_profile
    +
    +
    +

    and add the following lines at the end:

    +
    export HDF5_ROOT_DIR=/opt/local
    +export PYTHONEXE=python3
    +
    +
    +
  4. +
  5. Python should be already installed by default, but in case you need +a specific version, run:

    +
    sudo port -N install python38
    +sudo port select --set python3 python38
    +
    +
    +
  6. +
  7. If you wish to run the Python post-processing scripts provided in Smilei, +you need several modules (h5py, numpy, matplotlib, sphinx, pint). +We recommend to install IPython which includes some of these.

    +
    sudo port -N install py38-h5py         # mandatory for opening any HDF5 file
    +sudo port -N install py38-matplotlib   # plottting
    +sudo port -N install py38-pint         # only for auto unit conversion
    +sudo port -N install py38-ipython      # nicer python console
    +sudo port -N install py38-sphinx       # only for building the doc
    +
    +
    +
  8. +
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/install_supercomputer.html b/Use/install_supercomputer.html new file mode 100644 index 000000000..fb8bf600b --- /dev/null +++ b/Use/install_supercomputer.html @@ -0,0 +1,612 @@ + + + + + + + + + Installation on supercomputers — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Installation on supercomputers

+

On a large cluster, refer to the administrator to install the requirements +and to choose the compilation options.

+

For a few existing machines, we provide instructions in the folder +scripts/compile_tools/machine. Each file contains compiler flags +and environment setup to optimize Smilei’s performance.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Archer2

+
Archer2 (GNU compiler): archer2
+
+

Cori

+
Haswell: cori_hsw
+
KNL: cori_knl
+
+

Frioul

+
frioul
+
+

FUGAKU

+
Fujitsu compiler in trad mode : fugaku_fujitsu_tm
+
Fujitsu compiler in clang mode : fugaku_fujitsu_cm
+
+

Joliot-Curie

+
KNL (Intel compiler): joliot_curie_knl
+
Skylake (Intel compiler): joliot_curie_skl
+
Rome (Intel compiler): joliot_curie_rome
+
A64FX with the GNU compiler: joliot_curie_gnu_a64fx
+
A64FX with the ARM compiler: joliot_curie_arm_a64fx
+
A64FX with the Fujitsu compiler: joliot_curie_fujitsu_a64fx
+
+

Jean Zay

+
Cascadelake: jean_zay
+
+

Jureca

+
Haswell: jureca
+
+

Marconi

+
Broadwell: marconi_bdw
+
KNL: marconi_knl
+
+

Occigen

+
Haswell: occigen
+
+

Ruche

+
Cascadelake (Intel): ruche
+
+

Stampede

+
KNL: stampede2_knl
+
skylake: stampede2_skylake
+
+
+

We also provide instructions for some common architectures:

+
    +
  • Intel Cascadelake processors: cascadelake

  • +
  • Intel Skylake processors: skylake

  • +
  • Intel Knights Landing processors: knl

  • +
  • Intel Broadwell processors: broadwell

  • +
  • Intel Haswell processors: haswell

  • +
+

All these files contain:

+
    +
  • Commented commands that must be executed manually by the user

  • +
  • Compiler options automatically accounted for during compilation

  • +
+

To print out the commands to be executed, type make machine=target help. +See, for instance:

+
$ make machine=occigen help
+...
+Machine comments for occigen:
+# module purge
+# module load intel intelmpi hdf5/1.8.18 qt/4.8.6 python/2.7.12 mesa/17.2.4 VTK/7.0.0
+
+
+

After copying and pasting those commands to the terminal, you can use the +command make machine=target to compile Smilei. For instance:

+
$ make machine=occigen
+
+
+

If your machine is not in this list, please contact your administrator +for help on the installation. You may submit your installation instructions +to the Smilei repository so that we can add your machine to the list.

+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/installation.html b/Use/installation.html new file mode 100644 index 000000000..75e94c671 --- /dev/null +++ b/Use/installation.html @@ -0,0 +1,689 @@ + + + + + + + + + Install — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ + + + +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Install

+

Before installing Smilei, you need to install a few dependencies:

+
    +
  • A C++11 compiler, optionally implementing openMP version > 4.5 +(gcc users: v6.0 or newer recommended)

  • +
  • an MPI library (by default a version supporting MPI_THREAD_MULTIPLE +is required: v4.0 or newer recommended)

  • +
  • an HDF5 library compatible with your versions of C++ and MPI

  • +
  • Python 2.7 or Python 3+ (with header files)

  • +
+

Optional dependencies are:

+
    +
  • Git

  • +
  • Python modules: sphinx, h5py, numpy, matplotlib, pint

  • +
  • ffmpeg

  • +
  • CUDA for NVIDIA GPUs or HIP-SYCL for AMD GPUs (it is recommended to use the already installed software stack and the support team of a supercomputer you have access to).

  • +
+
+
+

Install the dependencies

+

There are various ways to install all dependencies, depending on the platform:

+ +

The command make help can give you some information about your environment.

+

If you have successfully installed these dependencies on other platforms, +please contact us and share!

+
+
+
+

Setup environment variables for compilation

+

Several environment variables may be required, depending on your setup.

+
    +
  • SMILEICXX: the MPI-C++ compiler. +Defaults to mpicxx.

  • +
  • HDF5_ROOT_DIR: the folder for the HDF5 library. +Defaults to $HDF5_ROOT.

  • +
  • BUILD_DIR: the folder where the compilation should occur. +Defaults to ./build.

  • +
  • PYTHONEXE: the python executable to use in smilei. +Defaults to python.

  • +
+

The usual CXXFLAGS and LDFLAGS can also be used to pass other +arguments to the compiler and linker.

+
+
+
+

Download and compile

+
    +
  1. Clone the latest Smilei version from Github:

    +
    cd /path/of/your/choice/
    +git clone https://github.com/SmileiPIC/Smilei.git
    +
    +
    +

    If you do not have git, you can dowload a tarball here +and extract it in a new folder.

    +
  2. +
  3. In a terminal, go to that location and compile:

    +
    cd Smilei
    +make
    +
    +
    +

    If the compilation is successful, you should now have a new smilei executable.

    +
  4. +
  5. The next step is to write a namelist.

  6. +
+
+
+
+

Advanced compilation options

+

Compile with several processors (fast compilation)

+
make -j 4
+
+
+

Compilation configuration with keyword “config”

+
make config=debug                        # With debugging output (slow execution)
+make config=noopenmp                     # Without OpenMP support
+make config=no_mpi_tm                    # Without a MPI library which supports MPI_THREAD_MULTIPLE
+make config=scalasca                     # For the Scalasca profiler
+make config=advisor                      # For Intel Advisor
+make config=vtune                        # For Intel Vtune
+make config=inspector                    # For Intel Inspector
+make config=detailed_timers              # More detailed timers, but somewhat slower execution
+make config=omptasks                     # use OpenMP task parallelization, not supported by old compilers
+make config=part_event_tracing_tasks_off # trace the use particle operators, without task parallelization
+make config=part_event_tracing_tasks_on  # trace the use particle operators, with OpenMP task parallelization
+make config="gpu_nvidia noopenmp"        # For Nvidia GPU acceleration
+make config="gpu_amd"                    # For AMD GPU acceleration
+
+
+

It is possible to combine arguments above within quotes, for instance:

+
make config="debug noopenmp" # With debugging output, without OpenMP
+
+
+

However, some arguments may not be compatible, e.g. noopenmp and omptasks.

+

Obtain some information about the compilation

+
make print-XXX               # Prints the value of makefile variable XXX
+make env                     # Prints the values of all makefile variables
+make help                    # Gets some help on compilation
+
+
+

Machine-specific compilation

+

Each machine may require a specific configuration (environment variables, +modules, etc.). These instructions may be included in a file of your choice, +via the machine argument:

+
make machine=my_machine_file
+
+
+

where my_machine_file is a file, located in +scripts/compile_tools/machine, containing the lines of command to be +executed before compilation. If you successfully write such a file for +a common supercomputer, please share it with developpers so that it can +be included in the next release of Smilei.

+
+
+
+

Optimization and vectorization options explained

+

To tune optimization and vectorization options, Smilei uses the machine files described above. They contain compiler options for specific hardware architectures or processor families.

+

This page explains in detail optimization flags used in machine files and therefore how to generate your own machine file.

+
+
+
+

Create the documentation

+

If you have installed the python module sphinx, you can create the +documentation (which you are currently reading) with:

+
make doc
+
+
+

This creates a local html website accessible in your build/html/ folder.

+
+
+
+

Install the happi module

+

A python module, happi, is provided to view, extract and post-process +data from all the diagnostics. +There are several ways to load this module in python.

+
    +
  1. Recommended:

  2. +
+
+
make happi
+
+
+

This has to be done only once, unless you move the smilei directory elsewhere. +This command creates a small file in the Python user-site directory that tells python +where to find the module. +To remove it use the command make uninstall_happi.

+

The module will directly be accessible from python:

+
>>> import happi
+
+
+
+
    +
  1. Alternative: Execute the Diagnostics.py script from python

  2. +
+
+

Adding a new python module is not always possible. +Instead, we provide the script Diagnostics.py which is able to find the +happi module and import it into python.

+

You may add the following command in your own python script:

+
>>> execfile("/path/to/Smilei/scripts/Diagnostics.py")
+
+
+
+
+
+
+

Install the smilei_tables tool

+

Generation of the tables is handled by an external tools. +A full documentation is available on the dedicated page.

+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/laser_offset.html b/Use/laser_offset.html new file mode 100644 index 000000000..1cf3d9205 --- /dev/null +++ b/Use/laser_offset.html @@ -0,0 +1,652 @@ + + + + + + + + + Laser propagation preprocessing — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Laser propagation preprocessing

+

In Smilei, Lasers are provided as oscillating fields at the box boundaries. +For instance, at the xmin boundary of a 3D cartesian box, the user may define the +\(B_y(y,z,t)\) and \(B_z(y,z,t)\) profiles. But in some cases, the laser field +only known analytically at some arbitrary plane that does not coincide with the box +boundary. This appears typically in the case of tightly-focused beams that cannot be +described with a paraxial approximation.

+

At the beginning of the simulation (during the initialization), Smilei is able to perform +a laser backwards propagation from an arbitrary plane to the box boundary. The +calculated field is then injected from then boundary like a normal laser. From the user’s +perspective, this simply requires the definition of the laser profile at some arbitrary +plane.

+

The general technique is taken from [Thiele2016] but it has been improved for parallel +computation in both 2D and 3D geometries. Further below, another improvement is presented: +the propagation towards a tilted plane.

+
+
+

Theoretical background

+

The method employed for the propagation preprocessing is similar to the angular spectrum +method. We illustrate this method on an arbitrary scalar field \(A\), but it is +valid for all components of a field satisfying a wave equation:

+
+
+\[c^2 \Delta A(x,y,z,t) = \partial_t^2 A(x,y,z,t)\]
+
+

The 3D Fourier transform of this equation for the variables \(y\), \(z\) and +\(t\) gives:

+
+
+\[(\partial_x^2 + k_x^2) \hat A(x,k_y,k_z,\omega) = 0\]
+
+

where \(k_y\), \(k_z\) and \(\omega\) are the conjugate variables in the +frequency domain, and \(k_x(k_y,k_z,\omega) \equiv \sqrt{\omega^2/c^2-k_y^2-k_z^2}\). +This equation has general solutions proportional to \(\exp(-i k_x x)\) for waves +propagating towards positive \(x\). This means that, if the profile is known at some +plane \(x=x_0+\delta\), the profile at \(x=x_0\) is obtained after multiplying +\(\hat A\) by \(\exp(i k_x \delta)\):

+
+
+\[\hat A(x_0,k_y,k_z,\omega) = \exp(i k_x \delta) \hat A(x_0+\delta,k_y,k_z,\omega)\]
+
+

To recover the field profile in real space, a 3D inverse Fourier transform would be +sufficient. However, storing all values of the \((y,z,t)\) profile would consume too +much time and disk space. +Instead, Smilei does only a 2D inverse Fourier transform on \(k_y\) and +\(k_z\). This results in a \(\tilde A(y,z,\omega)\) profile, where \(\omega\) are +the temporal Fourier modes. Keeping only a few of these modes (the most intense ones) +ensures a reasonable disk space usage.

+

The full \(A(y,z,t)\) profile is calculated during the actual PIC simulation, summing +over the different \(\omega\).

+
+
+
+

Numerical process

+

Let us summarize how the calculation above is realized numerically. We suppose that the +grid is 3D cartesian with the number of cells \((N_x, N_y, N_z)\) in the three +directions, but the same process works in 2D. We write \(N_t\) the total number of +timesteps.

+

The points 1 to 7 are realized during initialization.

+

1. The user profile \(B(y, z, t)\) is sampled

+
+

This profile corresponds to the magnetic field at the plane \(x=x_0+\delta\). +Smilei calculates an array of size \((N_y, N_z, N_t)\) sampling +this profile for all points of this plane, and all times of the simulation.

+
+

2. Smilei calculates the 3D Fourier transform along y, z and t

+
+

Using the FFT capabilities of the numpy python package, a parallel Fourier transform +is achieved, giving a transformed array of the same size \((N_y, N_z, N_t)\). +This array represents \(\hat B(k_y,k_z,\omega)\)

+
+

3. Frequencies with the most intense values are selected

+
+

Summing for all \(k_y\) and \(k_z\) provides a (temporal) spectrum of the wave. +By default, the 100 frequencies giving the strongest values of this spectrum are kept, +but this can be changed in the namelist (see keep_n_strongest_modes). +The resulting array is of size \((N_y, N_z, 100)\).

+
+

4. The array is multiplied by the propagation term

+
+

This term \(\exp(i k_x \delta)\) depends on the coordinates of the array because +\(k_x\) is a function of \(k_y\), \(k_z\) and \(\omega\). +Note that the \(\delta\) corresponds to the attribute offset.

+
+

5. The inverse 2D Fourier transform is computed

+
+

This provides an array representing \(\tilde B(y,z,\omega)\)

+
+

6. The array is stored in an HDF5 file

+
+

This file is named LaserOffset0.h5, LaserOffset1.h5, etc. if there are several +lasers.

+
+

7. Each patch reads the part of the array that it owns

+
+

This means that each patch of the PIC mesh will own a distinct portion of the overall +array.

+
+

The point 8 is realized at runtime, for each iteration.

+

8. For each timestep, the laser profile is calculated

+
+

The 100 selected modes are summed according to

+
+\[B(y,z,t) = f(y,z,t) \sum_\omega \left| \tilde B(y,z,\omega) \right| \sin\left(\omega t + \phi(y,z,\omega)\right)\]
+

where \(\phi\) is the complex argument of \(\tilde B\) and \(f(y,z,t)\) is +an additional extra_envelope, defined by the user. +This envelope helps removing spurious repetitions of the laser pulse that can +occur due to the limited number of frequencies that are kept.

+
+
+
+
+

Tilted plane

+

The method above describes a wave propagation between two parallel planes. In Smilei, a +technique inspired from [Matsushima2003] allows for the propagation from a title plane.

+

This rotation happens in the Fourier space: wave vectors \(k_x\) and \(k_y\) are +rotated around \(k_z\) by an angle \(\theta\), according to

+
+\[\begin{split}\begin{array}{rcl} + k_x & = & k_x^\prime \cos\theta - k_y^\prime \sin\theta \\ + k_y & = & k_x^\prime \sin\theta + k_y^\prime \cos\theta \\ + k_z & = & k_z^\prime +\end{array}\end{split}\]
+

This transforms \(\hat A(x,k_y,k_z,\omega)\) into +\(\hat A^\prime(x,k_y^\prime,k_z,\omega)\), thus the operation is merely a change of one +variable (\(k_y\)).

+

Numerically, the process is not that straightforward because \(\hat A^\prime\) is an +array in which the axis \(k_y^\prime\) is linearly sampled, but the corresponding +values \(k_y\) do not match this linear sampling. We developed an interpolation method +to obtain the transformed values at any point.

+

In the end, the prescribed laser profile lies in a plane located at a distance +\(\delta\) and rotated around \(z\) by an angle \(\theta\), according to the +following figure.

+
+../_images/LaserOffsetAngle.png +
+

Fig. 62 The position of the plane where the laser profile is defined, with respect to the box.

+
+
+
+
+
+

References

+
+
Matsushima2003
+

K. Matsushima et al., J. Opt. Soc. Am. A 20, 1755 (2003)

+
+
Thiele2016
+

I. Thiele et al., J. Comput. Phys. 321, 1110 (2016)

+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/maxwell-juttner.html b/Use/maxwell-juttner.html new file mode 100644 index 000000000..d81f15a9b --- /dev/null +++ b/Use/maxwell-juttner.html @@ -0,0 +1,535 @@ + + + + + + + + + Sampling a Maxwell-Jüttner distribution — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Sampling a Maxwell-Jüttner distribution

+

We base our method on that described in the Appendix B of +an article by Schnittman and Krolik.

+

The Maxwell-Jüttner distribution, as a function of the Lorentz factor \(\gamma\), reads

+
+\[f(\gamma) = \gamma^2 \beta +\exp\left(- \frac {\gamma}{\theta} \right)\]
+

where \(\theta\) is the temperature divided by \(mc^2\). +It is problematic that the change of variable \(\gamma/\theta\) is impossible, because +it requires the cumulative distribution function to be computed for every different temperature.

+

Instead, the “rejection method” makes it possible to choose another function \(g(\gamma)\) +such that \(g(\gamma)>f(\gamma)\) everywhere. It can be chosen so that the cumulative +distribution function \(G(\gamma)\) is easy to inverse. First, we take a random +number \(U_1\) between 0 and 1, and sample the value \(\gamma_1=G^{-1}(U_1)\). +Second, we pick another random number \(U_2\), and if \(U_2<f(\gamma_1)/g(\gamma_1)\), +we keep the value \(\gamma_1\). Otherwise, we start over to choose another \(U_1\), +and so on until a good value is found.

+

In this particular case, we choose

+
+\[g(\gamma) = \gamma^2 +\exp\left(- \frac {\gamma}{\theta} \right)\]
+

which verifies \(g(\gamma)>f(\gamma)\) and which has the cumulative distribution function

+
+\[G(\gamma) = \int_1^\gamma g(x) dx = 1 - \exp\left[H(\gamma/\theta)-H(1/\theta)\right]\]
+

where \(H(u) = -u +\ln(1+u+u^2/2)\).

+

The rejection methods proceeds as

+
    +
  1. pick a random \(U_1\)

  2. +
  3. calculate \(\gamma_1=G^{-1}(U_1)=\theta\; H^{-1}[\ln(1-U_1)+H(1/\theta)]\)

  4. +
  5. pick a random \(U_2\)

  6. +
  7. select \(\gamma_1\) if \(U_2<\sqrt{1-\gamma_1^{-2}}\), otherwise restart from point 1

  8. +
+

Now, to do this, we need to know \(H^{-1}\), which is not easy. We choose to tabulate it +in Smilei. For \(X>-\exp(-26)\), we use the series development \(H^{-1}(X) = (-6X)^{1/3}\). +For \(X<-\exp(12)\), we use the fit \(H^{-1}(X) = -X + 11.35(-X)^{0.06}\). +For all points in between, the function is linearly interpolated in log-log scale over 1000 +tabulated values.

+

Note that the rejection method requires to pick several random numbers if the functions +\(f\) and \(g\) differ significantly. This strongly slows the calculation down +when the temperature is non-relativistic. For this reason, we fall back to the +Maxwell-Boltzmann distribution when \(\theta<0.1\).

+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/namelist.html b/Use/namelist.html new file mode 100644 index 000000000..0ae5ec3d5 --- /dev/null +++ b/Use/namelist.html @@ -0,0 +1,5087 @@ + + + + + + + + + Write a namelist — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ + + + +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Write a namelist

+

Before you run Smilei, you need a namelist (an input file). The namelist +is written in the python language. It is thus recommended to know the basics of python.

+

We suggest you copy one existing namelist from the folder benchmarks. +All namelists have the extension .py.

+
+
+

General rules

+
    +
  • Smilei requires a few blocks to be defined, such as:

    +
    Main(
    +    # ...
    +    timestep = 0.01,         # defines the timestep value
    +    grid_length = [10., 20.], # defines the 2D box dimensions
    +    # ...
    +)
    +
    +
    +

    Outside blocks, you can calculate anything you require. +Inside a block, you must only define variables for Smilei.

    +
  • +
  • The python syntax requires special indentation of each line. +You begin with no indentation, but you have to add four spaces at the +beginning of lines inside a group, and so on. +For instance:

    +
    if a == 0:
    +    timestep = 0.1
    +    if b == 1:
    +        timestep = 0.2
    +else:
    +    timestep = 0.3
    +
    +
    +
  • +
  • You will need to use lists, +which are series of things in python, +defined between brackets [] and separated by commas. +For example, mean_velocity = [0., 1.1, 3.].

  • +
  • You are free to import any installed python package into the namelist. +For instance, you may obtain \(\pi\) using from math import pi.

  • +
  • All quantities are normalized to arbitrary values: see Units.

  • +
+
+
+
+

Python workflow

+

Python is started at the beginning of the simulation (one python interpreter +for each MPI process). The following steps are executed:

+
    +
  1. A few variables from Smilei are passed to python so that they are +available to the user:

    +
      +
    • The rank of the current MPI process as smilei_mpi_rank.

    • +
    • The total number of MPI processes as smilei_mpi_size.

    • +
    • The maximum random integer as smilei_rand_max.

    • +
    +
  2. +
  3. The namelist(s) is executed.

  4. +
  5. Python runs preprocess() if the user has defined it. +This is a good place to calculate things that are not needed for +post-processing with happi.

  6. +
  7. The simulation is initialized (including field and particle arrays).

  8. +
  9. Python runs cleanup() if the user has defined it. +This is a good place to delete unused heavy variables.

  10. +
  11. Python checks whether the python interpreter is needed during the simulation +(e.g. the user has defined a temporal profile which requires python +to calculate it every timestep). Otherwise, python is stopped.

  12. +
+

All these instructions are summarized in a file smilei.py, +so that the user can directly run python -i smilei.py for post-processing purposes.

+
+
+
+

Main variables

+

The block Main is mandatory and has the following syntax:

+
Main(
+    geometry = "1Dcartesian",
+    interpolation_order = 2,
+    interpolator = "momentum-conserving",
+    grid_length  = [16. ],
+    cell_length = [0.01],
+    simulation_time    = 15.,
+    timestep    = 0.005,
+    number_of_patches = [64],
+    cluster_width = 5,
+    maxwell_solver = 'Yee',
+    EM_boundary_conditions = [
+        ["silver-muller", "silver-muller"],
+#        ["silver-muller", "silver-muller"],
+#        ["silver-muller", "silver-muller"],
+    ],
+    time_fields_frozen = 0.,
+    reference_angular_frequency_SI = 0.,
+    print_every = 100,
+    random_seed = 0,
+)
+
+
+
+
+geometry
+

The geometry of the simulation:

+ +

In the following documentation, all references to dimensions or coordinates +depend on the geometry. +1D, 2D and 3D stand for 1-dimensional, 2-dimensional and 3-dimensional cartesian +geometries, respectively. All coordinates are ordered as \((x)\), \((x,y)\) or \((x,y,z)\). +In the "AMcylindrical" case, all grid coordinates are 2-dimensional +\((x,r)\), while particle coordinates (in Species) +are expressed in the 3-dimensional Cartesian frame \((x,y,z)\).

+
+

Warning

+

The "AMcylindrical" geometry has some restrictions. +Boundary conditions must be set to "remove" for particles, +"silver-muller" for longitudinal EM boundaries and +"buneman" for transverse EM boundaries. +You can alternatively use "PML" for any EM boundary. +Collisions and +order-4 interpolation are not supported yet.

+
+
+ +
+
+interpolation_order
+
+
Default
+

2

+
+
+

Interpolation order, defines particle shape function:

+
    +
  • 2 : 3 points stencil, supported in all configurations.

  • +
  • 4 : 5 points stencil, not supported in vectorized 2D geometry.

  • +
+
+ +
+
+interpolator
+
+
Default
+

"momentum-conserving"

+
+
+
    +
  • "momentum-conserving"

  • +
  • "wt"

  • +
+

The interpolation scheme to be used in the simulation. +"wt" is for the timestep dependent field interpolation scheme described in +this paper .

+
+ +
+
+grid_length
+
+number_of_cells
+
+
A list of numbers: size of the simulation box for each dimension of the simulation.
    +
  • Either grid_length, the simulation length in each direction in units of \(L_r\),

  • +
  • or number_of_cells, the number of cells in each direction.

  • +
+
+
+
+ +
+
+cell_length
+

A list of floats: sizes of one cell in each direction in units of \(L_r\).

+
+ +
+
+simulation_time
+
+number_of_timesteps
+
+
Duration of the simulation.
    +
  • Either simulation_time, the simulation duration in units of \(T_r\),

  • +
  • or number_of_timesteps, the total number of timesteps.

  • +
+
+
+
+ +
+
+timestep
+
+timestep_over_CFL
+
+
Duration of one timestep.
    +
  • Either timestep, in units of \(T_r\),

  • +
  • or timestep_over_CFL, in units of the Courant–Friedrichs–Lewy (CFL) time.

  • +
+
+
+
+ +
+
+gpu_computing
+
+
Default
+

False

+
+
+

Activates GPU acceleration if set to True

+
+ +
+
+number_of_patches
+

A list of integers: the number of patches in each direction. +Each integer must be a power of 2, and the total number of patches must be +greater or equal than the number of MPI processes. +It is also strongly advised to have more patches than the total number of openMP threads. +See Parallelization basics.On the other hand, in case of GPU-acceleration it is recommended to use one patch per MPI-rank +(with one MPI-rank per GPU)

+
+ +
+
+patch_arrangement
+
+
Default
+

"hilbertian"

+
+
+

Determines the ordering of patches and the way they are separated into the +various MPI processes. Options are:

+
    +
  • "hilbertian": following the Hilbert curve (see this explanation).

  • +
  • "linearized_XY" in 2D or "linearized_XYZ" in 3D: following the +row-major (C-style) ordering.

  • +
  • "linearized_YX" in 2D or "linearized_ZYX" in 3D: following the +column-major (fortran-style) ordering. This prevents the usage of +Fields diagnostics (see Parallelization basics).

  • +
+
+ +
+
+cluster_width
+
+
Default
+

set to minimize the memory footprint of the particles pusher, especially interpolation and projection processes

+
+
+

For advanced users. Integer specifying the cluster width along X direction in number of cells. +The “cluster” is a sub-patch structure in which particles are sorted for cache improvement. +cluster_width must divide the number of cells in one patch (in dimension X). +The finest sorting is achieved with cluster_width=1 and no sorting with cluster_width equal to the full size of a patch along dimension X. +The cluster size in dimension Y and Z is always the full extent of the patch.

+
+

Warning

+

The size of clusters becomes particularly important when Task Parallelization is used.

+
+
+ +
+
+maxwell_solver
+
+
Default
+

‘Yee’

+
+
+

The solver for Maxwell’s equations. +Only "Yee" and "M4" are available for all geometries at the moment. +"Cowan", "Grassi", "Lehe" and "Bouchard" are available for 2DCartesian. +"Lehe" and "Bouchard" are available for 3DCartesian. +"Lehe" is available for AMcylindrical. +The M4 solver is described in this paper. +The Lehe solver is described in this paper. +The Bouchard solver is described in this thesis p. 109

+
+ +
+
+solve_poisson
+
+
Default
+

True

+
+
+

Decides if Poisson correction must be applied or not initially.

+
+ +
+
+poisson_max_iteration
+
+
Default
+

50000

+
+
+

Maximum number of iteration for the Poisson solver.

+
+ +
+
+poisson_max_error
+
+
Default
+

1e-14

+
+
+

Maximum error for the Poisson solver.

+
+ +
+
+solve_relativistic_poisson
+
+
Default
+

False

+
+
+

Decides if relativistic Poisson problem must be solved for at least one species. +See Field initialization for relativistic species for more details.

+
+ +
+
+relativistic_poisson_max_iteration
+
+
Default
+

50000

+
+
+

Maximum number of iteration for the Poisson solver.

+
+ +
+
+relativistic_poisson_max_error
+
+
Default
+

1e-22

+
+
+

Maximum error for the Poisson solver.

+
+ +
+
+EM_boundary_conditions
+
+
Type
+

list of lists of strings

+
+
Default
+

[["periodic"]]

+
+
+

The boundary conditions for the electromagnetic fields. Each boundary may have one of +the following conditions: "periodic", "silver-muller", "reflective", "ramp??" or "PML".

+
+
Syntax 1: [[bc_all]], identical for all boundaries.
+
Syntax 2: [[bc_X], [bc_Y], ...], different depending on x, y or z.
+
Syntax 3: [[bc_Xmin, bc_Xmax], ...], different on each boundary.
+
+
    +
  • "silver-muller" is an open boundary condition. +The incident wave vector \(k_{inc}\) on each face is defined by +"EM_boundary_conditions_k". +When using "silver-muller" as an injecting boundary, +make sure \(k_{inc}\) is aligned with the wave you are injecting. +When using "silver-muller" as an absorbing boundary, +the optimal wave absorption on a given face will be along \(k_{abs}\) +the specular reflection of \(k_{inc}\) on the considered face.

  • +
  • "ramp??" is a basic, open boundary condition designed +for the spectral solver in AMcylindrical geometry. +The ?? is an integer representing a number of cells +(smaller than the number of ghost cells). +Over the first half, the fields remain untouched. +Over the second half, all fields are progressively reduced down to zero.

  • +
  • "PML" stands for Perfectly Matched Layer. It is an open boundary condition. +The number of cells in the layer must be defined by "number_of_pml_cells". +It supports laser injection as in "silver-muller". +If not all boundary conditions are PML, make sure to set number_of_pml_cells=0 on boundaries not using PML.

  • +
+
+ +
+
+EM_boundary_conditions_k
+
+
Type
+

list of lists of floats

+
+
Default
+

[[1.,0.],[-1.,0.],[0.,1.],[0.,-1.]] in 2D

+
+
Default
+

[[1.,0.,0.],[-1.,0.,0.],[0.,1.,0.],[0.,-1.,0.],[0.,0.,1.],[0.,0.,-1.]] in 3D

+
+
+

For silver-muller absorbing boundaries, +the x,y,z coordinates of the unit wave vector k incident on each face +(sequentially Xmin, Xmax, Ymin, Ymax, Zmin, Zmax). +The number of coordinates is equal to the dimension of the simulation. +The number of given vectors must be equal to 1 or to the number of faces +which is twice the dimension of the simulation. In cylindrical geometry, +k coordinates are given in the xr frame and only the Rmax face is affected.

+
+
Syntax 1: [[1,0,0]], identical for all boundaries.
+
Syntax 2: [[1,0,0],[-1,0,0], ...], different on each boundary.
+
+
+ +
+
+number_of_pml_cells
+
+
Type
+

List of lists of integers

+
+
Default
+

[[10,10],[10,10],[10,10]]

+
+
+

Defines the number of cells in the "PML" layers using the same alternative syntaxes as "EM_boundary_conditions".

+
+ +
+
+pml_sigma
+
+
Type
+

List of profiles

+
+
Default
+

[lambda x : 20 * x**2]

+
+
+

Defines the sigma profiles across the transverse dimension of the PML for each dimension of the simulation. +It must be expressed as a list of profiles (1 per dimension).

+

If a single profile is given, it will be used for all dimensions.

+

For a given dimension, the same profile is applied to both sides of the domain.

+

The profile is given as a single variable function defined on the interval [0,1] where 0 is the inner bound of the PML and 1 is the outer bound of the PML. +Please refer to Perfectly Matched Layers if needed in AM geometry.

+
+ +
+
+pml_kappa
+
+
Type
+

List of profiles

+
+
Default
+

[lambda x : 1 + 79 * x**4]

+
+
+

Defines the kappa profiles across the transverse dimension of the PML for each dimension of the simulation. +It must be expressed as a list of profiles (1 per dimension).

+

If a single profile is given, it will be used for all dimensions.

+

For a given dimension, the same profile is applied to both sides of the domain.

+

The profile is given as a single variable function defined on the interval [0,1] where 0 is the inner bound of the PML and 1 is the outer bound of the PML. +Please refer to Perfectly Matched Layers if needed in AM geometry.

+
+ +
+
+time_fields_frozen
+
+
Default
+
    +
  1. +
+
+
+

Time, at the beginning of the simulation, during which fields are frozen.

+
+ +
+
+reference_angular_frequency_SI
+

The value of the reference angular frequency \(\omega_r\) in SI units, +only needed when collisions, ionization, radiation losses +or multiphoton Breit-Wheeler pair creation are requested. +This frequency is related to the normalization length according to \(L_r\omega_r = c\) +(see Units).

+
+ +
+ +

Number of timesteps between each info output on screen. By default, 10 outputs per +simulation.

+
+ +
+ +
+
Default
+

True

+
+
+

If False, the calculation of the expected disk usage, that is usually printed in the +standard output, is skipped. This might be useful in rare cases where this calculation +is costly.

+
+ +
+
+random_seed
+
+
Default
+

0

+
+
+

The value of the random seed. Each patch has its own random number generator, with a seed +equal to random_seed + the index of the patch.

+
+ +
+
+number_of_AM
+
+
Type
+

integer

+
+
Default
+

2

+
+
+

The number of azimuthal modes used for the Fourier decomposition in "AMcylindrical" geometry. +The modes range from mode 0 to mode "number_of_AM-1".

+
+ +
+
+number_of_AM_classical_Poisson_solver
+
+
Default
+

1

+
+
+

The number of azimuthal modes used for the field initialization with non relativistic Poisson solver in "AMcylindrical" geometry. +Note that this number must be lower or equal to the number of modes of the simulation.

+
+ +
+
+number_of_AM_relativistic_field_initialization
+
+
Default
+

1

+
+
+

The number of azimuthal modes used for the relativistic field initialization in "AMcylindrical" geometry. +Note that this number must be lower or equal to the number of modes of the simulation.

+
+
+use_BTIS3_interpolation
+
+
Default
+

False

+
+
+

If True, the B-translated interpolation scheme 3 (or B-TIS3) described in PIC algorithms is used.

+
+ +
+ +
+
+custom_oversize
+
+
Type
+

integer

+
+
Default
+

2

+
+
+

The number of ghost-cell for each patches. The default value is set accordingly with +the interpolation_order value.

+
+ +
+
+
+

Load Balancing

+

Load balancing (explained here) consists in exchanging +patches (domains of the simulation box) between MPI processes to reduce the +computational load imbalance. +The block LoadBalancing is optional. If you do not define it, load balancing will +occur every 150 iterations.

+
LoadBalancing(
+    initial_balance = True,
+    every = 150,
+    cell_load = 1.,
+    frozen_particle_load = 0.1
+)
+
+
+
+
+initial_balance
+
+
Default
+

True

+
+
+

Decides if the load must be balanced at initialization. If not, the same amount of +patches will be attributed to each MPI rank.

+
+ +
+
+every
+
+
Default
+

150

+
+
+

Number of timesteps between each load balancing or a time selection. +The value 0 suppresses all load balancing.

+
+ +
+
+cell_load
+
+
Default
+
    +
  1. +
+
+
+

Computational load of a single grid cell considered by the dynamic load balancing algorithm. +This load is normalized to the load of a single particle.

+
+ +
+
+frozen_particle_load
+
+
Default
+

0.1

+
+
+

Computational load of a single frozen particle considered by the dynamic load balancing algorithm. +This load is normalized to the load of a single particle.

+
+ +
+
+
+

Multiple decomposition of the domain

+

The block MultipleDecomposition is necessary for spectral solvers and optional in all other cases. +When present, it activates +the Single-domain multiple decompositions (SDMD) technique +which separates the decomposition of the field grids from that of the particles. +Fields are set on large sub-domain called regions (1 region per MPI process) while +particles are kept as small patches as in the standard decomposition (many patches per MPI process). +Benefits of this option are illustrated in this paper.

+
MultipleDecomposition(
+    region_ghost_cells = 2
+)
+
+
+
+
+region_ghost_cells
+
+
Type
+

integer

+
+
Default
+

2

+
+
+

The number of ghost cells for each region. +The default value is set accordingly with the interpolation_order. +The same number of ghost cells is used in all dimensions except for spectral solver in AM geometry for which the number of radial ghost cells is always automatically set to be the same as patches.

+
+ +
+
+
+

Vectorization

+

The block Vectorization is optional. +It controls the SIMD operations that can enhance the performance of some computations. +The technique is detailed in Ref. [Beck2019] and summarized in this doc. +It requires additional compilation options to be actived.

+
Vectorization(
+    mode = "adaptive",
+    reconfigure_every = 20,
+    initial_mode = "on"
+)
+
+
+
+
+mode
+
+
Default
+

"off"

+
+
+
    +
  • "off": non-vectorized operators are used. +Recommended when the number of particles per cell stays below 10.

  • +
  • "on": vectorized operators are used. +Recommended when the number of particles per cell stays above 10. +Particles are sorted per cell.

  • +
  • "adaptive": the best operators (scalar or vectorized) +are determined and configured dynamically and locally +(per patch and per species). For the moment this mode is only supported in 3Dcartesian geometry. +Particles are sorted per cell.

  • +
+

In the "adaptive" mode, cluster_width is set to the maximum.

+
+ +
+
+reconfigure_every
+
+
Default
+

20

+
+
+

The number of timesteps between each dynamic reconfiguration of +the vectorized operators, when using the "adaptive" vectorization mode. +It may be set to a time selection as well.

+
+ +
+
+initial_mode
+
+
Default
+

off

+
+
+

Default state when the "adaptive" mode is activated +and no particle is present in the patch.

+
+ +
+
+
+

Moving window

+

The simulated domain can move relatively to its the initial position. The “moving window” +is (almost) periodically shifted in the x_max direction. +Each “shift” consists in removing a column of patches from the x_min border and +adding a new one after the x_max border, thus changing the physical domain that the +simulation represents but keeping the same box size. This is particularly useful to +follow waves or plasma moving at high speed. +The frequency of the shifts is adjusted so that the average displacement velocity +over many shifts matches the velocity given by the user. +The user may ask for a given number of additional shifts at a given time. +These additional shifts are not taken into account for the evaluation of the average +velocity of the moving window.

+

The block MovingWindow is optional. The window does not move it you do not define it.

+
+

Warning

+

When the window starts moving, all laser injections via Silver-Muller boundary conditions +are immediately stopped for physical correctness.

+
+
MovingWindow(
+    time_start = 0.,
+    velocity_x = 1.,
+    number_of_additional_shifts = 0.,
+    additional_shifts_time = 0.,
+)
+
+
+
+
+time_start
+
+
Type
+

Float.

+
+
Default
+
    +
  1. +
+
+
+

The time at which the window starts moving.

+
+ +
+
+velocity_x
+
+
Type
+

Float.

+
+
Default
+
    +
  1. +
+
+
+

The average velocity of the moving window in the x_max direction. It muste be between 0 and 1.

+
+ +
+
+number_of_additional_shifts
+
+
Type
+

Integer.

+
+
Default
+
    +
  1. +
+
+
+

The number of additional shifts of the moving window.

+
+ +
+
+additional_shifts_time
+
+
Type
+

Float.

+
+
Default
+
    +
  1. +
+
+
+

The time at which the additional shifts are done.

+
+ +
+

Note

+

The particle binning diagnostics accept an “axis” called moving_x +corresponding to the x coordinate corrected by the moving window’s current movement.

+
+
+
+
+

Current filtering

+

The present version of Smilei provides a +multi-pass binomial filter on the current densities, +which parameters are controlled in the following block:

+
CurrentFilter(
+    model = "binomial",
+    passes = [0],
+    kernelFIR = [0.25,0.5,0.25]
+)
+
+
+
+
+model
+
+
Default
+

"binomial"

+
+
+

The model for current filtering.

+
    +
  • "binomial" for a binomial filter.

  • +
  • "customFIR" for a custom FIR kernel.

  • +
+
+ +
+
+passes
+
+
Type
+

A python list of integers.

+
+
Default
+

[0]

+
+
+

The number of passes (at each timestep) given for each dimension. +If the list is of length 1, the same number of passes is assumed for all dimensions.

+
+ +
+
+kernelFIR
+
+
Default
+

"[0.25,0.5,0.25]"

+
+
+

The FIR kernel for the "customFIR" model. The number of coefficients +must be less than twice the number of ghost cells +(adjusted using custom_oversize).

+
+ +
+
+
+

Field filtering

+

The present version of Smilei provides a method for field filtering +(at the moment, only the Friedman electric field time-filter is available) +which parameters are controlled in the following block:

+
FieldFilter(
+    model = "Friedman",
+    theta = 0.,
+)
+
+
+
+
+model
+
+
Default
+

"Friedman"

+
+
+

The model for field filtering. Presently, only "Friedman" field filtering is available.

+
+ +
+
+theta
+
+
Default
+

0.

+
+
+

The \(\theta\) parameter (between 0 and 1) of Friedman’s method.

+
+ +
+
+
+

Species

+

Each species has to be defined in a Species block:

+
Species(
+    name      = "electrons1",
+    position_initialization = "random",
+    momentum_initialization = "maxwell-juettner",
+    regular_number = [],
+    particles_per_cell = 100,
+    mass = 1.,
+    atomic_number = None,
+    #maximum_charge_state = None,
+    number_density = 10.,
+    # charge_density = None,
+    charge = -1.,
+    mean_velocity = [0.],
+    #mean_velocity_AM = [0.],
+    temperature = [1e-10],
+    boundary_conditions = [
+        ["reflective", "reflective"],
+    #    ["periodic", "periodic"],
+    #    ["periodic", "periodic"],
+    ],
+    # thermal_boundary_temperature = None,
+    # thermal_boundary_velocity = None,
+    time_frozen = 0.0,
+    # ionization_model = "none",
+    # ionization_electrons = None,
+    # ionization_rate = None,
+    is_test = False,
+    pusher = "boris",
+
+    # Radiation reaction, for particles only:
+    radiation_model = "none",
+    radiation_photon_species = "photon",
+    radiation_photon_sampling = 1,
+    radiation_photon_gamma_threshold = 2,
+    radiation_max_emissions = 10,
+
+    # Relativistic field initialization:
+    relativistic_field_initialization = "False",
+
+    # For photon species only:
+    multiphoton_Breit_Wheeler = ["electron","positron"],
+    multiphoton_Breit_Wheeler_sampling = [1,1]
+
+    # Merging
+    merging_method = "vranic_spherical",
+    merge_every = 5,
+    merge_min_particles_per_cell = 16,
+    merge_max_packet_size = 4,
+    merge_min_packet_size = 4,
+    merge_momentum_cell_size = [16,16,16],
+)
+
+
+
+
+name
+

The name you want to give to this species. +It should be more than one character and can not start with "m_".

+
+ +
+
+position_initialization
+

The method for initialization of particle positions. Options are:

+
    +
  • "regular" for regularly spaced. See regular_number.

  • +
  • "random" for randomly distributed.

  • +
  • "centered" for centered in each cell (not supported in AMcylindrical geometry.

  • +
  • The name of another species from which the positions are copied. +The source species must have positions initialized using one of the three +other options above, and must be defined before this species.

  • +
  • A numpy array or an HDF5 file defining all the positions of the particles. +In this case you must also provide the weight of each particle (see Macro-particle weights). +See Initialize particles from an array or a file.

  • +
+
+ +
+
+regular_number
+
+
Type
+

A list of as many integers as the simulation dimension

+
+
+

When position_initialization = "regular", this sets the number of evenly-spaced +particles per cell in each direction: [Nx, Ny, Nz] in cartesian geometries and +[Nx, Nr, Ntheta] in AMcylindrical in which case we recommend +Ntheta \(\geq 4\times (\) number_of_AM \(-1)\). +If unset, particles_per_cell must be a power of the simulation dimension, +for instance, a power of 2 in 2Dcartesian.

+
+ +
+
+momentum_initialization
+

The method for initialization of particle momenta. Options are:

+ +

The first 2 distributions depend on the parameter temperature explained below.

+
+ +
+
+particles_per_cell
+
+
Type
+

float or profile

+
+
+

The number of particles per cell.

+
+ +
+
+mass
+

The mass of particles, in units of the electron mass \(m_e\).

+
+ +
+
+atomic_number
+
+
Default
+

0

+
+
+

The atomic number of the particles, required only for ionization. +It must be lower than 101.

+
+ +
+
+maximum_charge_state
+
+
Default
+

0

+
+
+

The maximum charge state of a species for which the ionization model is "from_rate".

+
+ +
+
+number_density
+
+charge_density
+
+
Type
+

float or profile

+
+
+

The absolute value of the charge density or number density (choose one only) +of the particle distribution, in units of the reference density \(N_r\) (see Units).

+
+ +
+
+charge
+
+
Type
+

float or profile

+
+
+

The particle charge, in units of the elementary charge \(e\).

+
+ +
+
+mean_velocity
+
+
Type
+

a list of 3 floats or profiles

+
+
+

The initial drift velocity of the particles, in units of the speed of light \(c\), in the x, y and z directions.

+

WARNING: For massless particles, this is actually the momentum in units of \(m_e c\).

+
+ +
+
+mean_velocity_AM
+
+
Type
+

a list of 3 floats or profiles

+
+
+

The initial drift velocity of the particles, in units of the speed of light \(c\), in the longitudinal, radial and azimuthal directions. +This entry is available only in AMcylindrical velocity and cannot be used if also mean_velocity is used in the same Species: only one of the two can be chosen.

+

WARNING: For massless particles, this is actually the momentum in units of \(m_e c\).

+

WARNING: The initial cylindrical drift velocity is applied to each particle, thus it can be computationally demanding.

+
+ +
+
+temperature
+
+
Type
+

a list of 3 floats or profiles

+
+
+

The initial temperature of the particles, in units of \(m_ec^2\).

+
+ +
+
+boundary_conditions
+
+
Type
+

a list of lists of strings

+
+
Default
+

[["periodic"]]

+
+
+

The boundary conditions for the particles of this species. +Each boundary may have one of the following conditions: +"periodic", "reflective", "remove" (particles are deleted), +"stop" (particle momenta are set to 0), and "thermalize". +For photon species (mass=0), the last two options are not available.

+
+
Syntax 1: [[bc_all]], identical for all boundaries.
+
Syntax 2: [[bc_X], [bc_Y], ...], different depending on x, y or z.
+
Syntax 3: [[bc_Xmin, bc_Xmax], ...], different on each boundary.
+
+
+ +
+
+thermal_boundary_temperature
+
+
Default
+

None

+
+
+

A list of floats representing the temperature of the thermal boundaries (those set to +"thermalize" in boundary_conditions) for each spatial coordinate. +Currently, only the first coordinate (x) is taken into account.

+
+ +
+
+thermal_boundary_velocity
+
+
Default
+

[]

+
+
+

A list of floats representing the components of the particles’ drift velocity after +encountering the thermal boundaries (those set to "thermalize" in boundary_conditions).

+
+ +
+
+time_frozen
+
+
Default
+
    +
  1. +
+
+
+

The time during which the particles are “frozen”, in units of \(T_r\). +Frozen particles do not move and therefore do not deposit any current density either. +Nonetheless, they deposit a charge density. +They are computationally much cheaper than non-frozen particles and oblivious to any EM-fields +in the simulation. Note that frozen particles can be ionized (this is computationally much cheaper +if ion motion is not relevant).

+
+ +
+
+ionization_model
+
+
Default
+

"none"

+
+
+

The model for ionization:

+ +
+ +
+
+ionization_rate
+

A python function giving the user-defined ionisation rate as a function of various particle attributes. +To use this option, the numpy package must be available in your python installation. +The function must have one argument, that you may call, for instance, particles. +This object has several attributes x, y, z, px, py, pz, charge, weight and id. +Each of these attributes are provided as numpy arrays where each cell corresponds to one particle.

+

The following example defines, for a species with maximum charge state of 2, +an ionization rate that depends on the initial particle charge +and linear in the x coordinate:

+
from numpy import exp, zeros_like
+
+def my_rate(particles):
+    rate = zeros_like(particles.x)
+    charge_0 = (particles.charge==0)
+    charge_1 = (particles.charge==1)
+    rate[charge_0] = r0 * particles.x[charge_0]
+    rate[charge_1] = r1 * particles.x[charge_1]
+    return rate
+
+Species( ..., ionization_rate = my_rate )
+
+
+
+ +
+
+ionization_electrons
+

The name of the electron species that ionization_model uses when creating new electrons.

+
+ +
+
+is_test
+
+
Default
+

False

+
+
+

Flag for test particles. If True, this species will contain only test particles +which do not participate in the charge and currents.

+
+ +
+
+pusher
+
+
Default
+

"boris"

+
+
+

Type of pusher to be used for this species. Options are:

+
    +
  • "boris": The relativistic Boris pusher

  • +
  • "borisnr": The non-relativistic Boris pusher

  • +
  • "vay": The relativistic pusher of J. L. Vay

  • +
  • "higueracary": The relativistic pusher of A. V. Higuera and J. R. Cary

  • +
  • "norm": For photon species only (rectilinear propagation)

  • +
  • "ponderomotive_boris": modified relativistic Boris pusher for species interacting with the laser envelope model. Valid only if the species has non-zero mass

  • +
  • "borisBTIS3": as "boris", but using B fields interpolated with the B-TIS3 scheme.

  • +
  • "ponderomotive_borisBTIS3": as "ponderomotive_boris", but using B fields interpolated with the B-TIS3 scheme.

  • +
+

WARNING: "borisBTIS3" and "ponderomotive_borisBTIS3" can be used only when use_BTIS3_interpolation=True in the Main block.

+
+ +
+
+radiation_model
+
+
Default
+

"none"

+
+
+

The radiation reaction model used for this species (see High-energy photon emission & radiation reaction).

+
    +
  • "none": no radiation

  • +
  • "Landau-Lifshitz" (or ll): Landau-Lifshitz model approximated for high energies

  • +
  • "corrected-Landau-Lifshitz" (or cll): with quantum correction

  • +
  • "Niel": a stochastic radiation model based on the work of Niel et al..

  • +
  • "Monte-Carlo" (or mc): Monte-Carlo radiation model. This model can be configured to generate macro-photons with radiation_photon_species.

  • +
+

This parameter cannot be assigned to photons (mass = 0).

+

Radiation is emitted only with the "Monte-Carlo" model when +radiation_photon_species is defined.

+
+ +
+
+radiation_photon_species
+

The name of the photon species in which the Monte-Carlo radiation_model +will generate macro-photons. If unset (or None), no macro-photon will be created. +The target photon species must be have its mass set to 0, and appear after the +particle species in the namelist.

+

This parameter cannot be assigned to photons (mass = 0).

+
+ +
+
+radiation_photon_sampling
+
+
Default
+

1

+
+
+

The number of macro-photons generated per emission event, when the macro-photon creation +is activated (see radiation_photon_species). The total macro-photon weight +is still conserved.

+

A large number may rapidly slow down the performances and lead to memory saturation.

+

This parameter cannot be assigned to photons (mass = 0).

+
+ +
+
+radiation_max_emissions
+
+
Default
+

10

+
+
+

The maximum number of emission Monte-Carlo event a macro-particle can undergo during a timestep. +Since this value is used to allocate some buffers, a high value can saturate memory.

+

This parameter cannot be assigned to photons (mass = 0).

+
+ +
+
+radiation_photon_gamma_threshold
+
+
Default
+

2

+
+
+

The threshold on the photon energy for the macro-photon emission when using the +radiation reaction Monte-Carlo process. +Under this threshold, the macro-photon from the radiation reaction Monte-Carlo +process is not created but still taken into account in the energy balance. +The default value corresponds to twice the electron rest mass energy that +is the required energy to decay into electron-positron pairs.

+

This parameter cannot be assigned to photons (mass = 0).

+
+ +
+
+relativistic_field_initialization
+
+
Default
+

False

+
+
+

Flag for relativistic particles. If True, the electromagnetic fields of this species will added to the electromagnetic fields already present in the simulation. +This operation will be performed when time equals time_frozen. See Field initialization for relativistic species for details on the computation of the electromagentic fields of a relativistic species. +To have physically meaningful results, we recommend to place a species which requires this method of field initialization far from other species, otherwise the latter could experience instantly turned-on unphysical forces by the relativistic species’ fields.

+
+ +
+
+multiphoton_Breit_Wheeler
+
+
Default
+

[None,None]

+
+
+

An list of the name of two species: electrons and positrons created through +the Multiphoton Breit-Wheeler pair creation. +By default, the process is not activated.

+

This parameter can only be assigned to photons species (mass = 0).

+
+ +
+
+multiphoton_Breit_Wheeler_sampling
+
+
Default
+

[1,1]

+
+
+

A list of two integers: the number of electrons and positrons generated per photon decay +in the Multiphoton Breit-Wheeler pair creation. The total macro-particle weight is still +conserved.

+

Large numbers may rapidly slow down the performances and lead to memory saturation.

+

This parameter can only be assigned to photons species (mass = 0).

+
+ +
+
+keep_interpolated_fields
+
+
Default
+

[]

+
+
+

A list of interpolated fields that should be stored in memory for all particles of this species, +instead of being located in temporary buffers. These fields can then +be accessed in some diagnostics such as particle binning or +tracking. The available fields are "Ex", "Ey", "Ez", +"Bx", "By" and "Bz".

+

Additionally, the work done by each component of the electric field is available as +"Wx", "Wy" and "Wz". Contrary to the other interpolated fields, these quantities +are accumulated over time.

+
+ +
+
+
+

Particle Injector

+

Injectors enable to inject macro-particles in the simulation domain from the boundaries. +By default, some parameters that are not specified are inherited from the associated species.

+

Each particle injector has to be defined in a ParticleInjector block:

+
ParticleInjector(
+    name      = "injector1",
+    species   = "electrons1",
+    box_side  = "xmin",
+    time_envelope = tgaussian(start=0, duration=10., order=4),
+
+    # Parameters inherited from the associated ``species`` by default
+
+    position_initialization = "species",
+    momentum_initialization = "rectangular",
+    mean_velocity = [0.5,0.,0.],
+    temperature = [1e-30],
+    number_density = 1,
+    particles_per_cell = 16,
+)
+
+
+
+
+name
+

The name you want to give to this injector. +If you do not specify a name, it will be attributed automatically. +The name is useful if you want to inject particles at the same position of another injector.

+
+ +
+
+species
+

The name of the species in which to inject the new particles

+
+ +
+
+box_side
+

From where the macro-particles are injected. Options are:

+
    +
  • "xmin"

  • +
  • "xmax"

  • +
  • "ymin"

  • +
  • "ymax"

  • +
  • "zmax"

  • +
  • "zmin"

  • +
+
+ +
+
+time_envelope
+
+
Type
+

a python function or a time profile

+
+
Default
+

tconstant()

+
+
+

The temporal envelope of the injector.

+
+ +
+
+position_initialization
+
+
Default
+

parameters provided the species

+
+
+

The method for initialization of particle positions. Options are:

+
    +
  • "species" or empty "": injector uses the option of the specified species.

  • +
  • "regular" for regularly spaced. See regular_number.

  • +
  • "random" for randomly distributed

  • +
  • "centered" for centered in each cell

  • +
  • The name of another injector from which the positions are copied. +This option requires (1) that the target injector’s positions are initialized +using one of the three other options above.

  • +
+
+ +
+
+momentum_initialization
+
+
Default
+

parameters provided the species

+
+
+

The method for initialization of particle momenta. Options are:

+
    +
  • "species" or empty "": injector uses the option of the specified species.

  • +
  • "maxwell-juettner" for a relativistic maxwellian (see how it is done)

  • +
  • "rectangular" for a rectangular distribution

  • +
+
+ +
+
+mean_velocity
+
+
Type
+

a list of 3 floats or profiles

+
+
Default
+

parameters provided the species

+
+
+

The initial drift velocity of the particles, in units of the speed of light \(c\).

+

WARNING: For massless particles, this is actually the momentum in units of \(m_e c\).

+
+ +
+
+temperature
+
+
Type
+

a list of 3 floats or profiles

+
+
Default
+

parameters provided the species

+
+
+

The initial temperature of the particles, in units of \(m_ec^2\).

+
+ +
+
+particles_per_cell
+
+
Type
+

float or profile

+
+
Default
+

parameters provided the species

+
+
+

The number of particles per cell to use for the injector.

+
+ +
+
+number_density
+
+charge_density
+
+
Type
+

float or profile

+
+
Default
+

parameters provided the species

+
+
+

The absolute value of the number density or charge density (choose one only) +of the particle distribution, in units of the reference density \(N_r\) (see Units)

+
+ +
+
+regular_number
+
+
Type
+

A list of as many integers as the simulation dimension

+
+
+

Same as for Species. When position_initialization = "regular", this sets the number of evenly-spaced +particles per cell in each direction: [Nx, Ny, Nz] in cartesian geometries.

+
+ +
+
+
+

Particle Merging

+

The macro-particle merging method is documented in +the corresponding page. +Note that for merging to be able to operate either vectorization or cell sorting must be activated. +It is optionnally specified in the Species block:

+
Species(
+    ....
+
+    # Merging
+    merging_method = "vranic_spherical",
+    merge_every = 5,
+    merge_min_particles_per_cell = 16,
+    merge_max_packet_size = 4,
+    merge_min_packet_size = 4,
+    merge_momentum_cell_size = [16,16,16],
+    merge_discretization_scale = "linear",
+    # Extra parameters for experts:
+    merge_min_momentum_cell_length = [1e-10, 1e-10, 1e-10],
+    merge_accumulation_correction = True,
+)
+
+
+
+
+merging_method
+
+
Default
+

"none"

+
+
+

The particle merging method to use:

+
    +
  • "none": no merging

  • +
  • "vranic_cartesian": method of M. Vranic with a cartesian momentum-space decomposition

  • +
  • "vranic_spherical": method of M. Vranic with a spherical momentum-space decomposition

  • +
+
+ +
+
+merge_every
+
+
Default
+

0

+
+
+

Number of timesteps between each merging event +or a time selection.

+
+ +
+
+min_particles_per_cell
+
+
Default
+

4

+
+
+

The minimum number of particles per cell for the merging.

+
+ +
+
+merge_min_packet_size
+
+
Default
+

4

+
+
+

The minimum number of particles per packet to merge. Must be greater or equal to 4.

+
+ +
+
+merge_max_packet_size
+
+
Default
+

4

+
+
+

The maximum number of particles per packet to merge.

+
+ +
+
+merge_momentum_cell_size
+
+
Default
+

[16,16,16]

+
+
+

A list of 3 integers defining the number of sub-groups in each direction +for the momentum-space discretization.

+
+ +
+
+merge_discretization_scale
+
+
Default
+

"linear"

+
+
+

The momentum discretization scale:: "linear" or "log". +The "log" scale only works with the spherical discretization at the moment.

+
+ +
+
+merge_min_momentum
+
+
Default
+

1e-5

+
+
+

[for experts] The minimum momentum value when the log scale +is chosen (merge_discretization_scale = log). +This avoids a potential 0 value in the log domain.

+
+ +
+
+merge_min_momentum_cell_length
+
+
Default
+

[1e-10,1e-10,1e-10]

+
+
+

[for experts] The minimum sub-group length for the momentum-space +discretization (below which the number of sub-groups is set to 1).

+
+ +
+
+merge_accumulation_correction
+
+
Default
+

True

+
+
+

[for experts] Activates the accumulation correction +(see Particle Merging for more information). +The correction only works in linear scale.

+
+ +
+
+
+

Lasers

+

A laser consists in applying oscillating boundary conditions for the magnetic +field on one of the box sides. The only boundary condition that supports lasers +is "silver-muller" (see EM_boundary_conditions). +There are several syntaxes to introduce a laser in Smilei:

+
+

Note

+

The following definitions are given for lasers incoming from the xmin or xmax +boundaries. For lasers incoming from ymin or ymax, replace the By +profiles by Bx profiles. For lasers incoming from zmin or zmax, +replace By and Bz profiles by Bx and By profiles, respectively.

+
+

1. Defining a generic wave

+
+
Laser(
+    box_side = "xmin",
+    space_time_profile = [ By_profile, Bz_profile ]
+    space_time_profile_AM = [ Br_mode0, Bt_mode0, Br_mode1, Bt_mode1, ... ]
+)
+
+
+
+
+
+box_side
+
+
Default
+

"xmin"

+
+
+

Side of the box from which the laser originates: "xmin", "xmax", "ymin", +"ymax", "zmin" or "zmax".

+

In the cases of "ymin" or "ymax", replace, in the following profiles, +coordinates y by x, and fields \(B_y\) by \(B_x\).

+

In the cases of "zmin" or "zmax", replace, in the following profiles, +coordinates y by x, coordinates z by y, fields \(B_y\) by \(B_x\) +and fields \(B_z\) by \(B_y\).

+
+ +
+
+space_time_profile
+
+
Type
+

A list of two python functions

+
+
+

The full wave expression at the chosen box side. It is a list of two python +functions taking several arguments depending on the simulation dimension: +\((t)\) for a 1-D simulation, \((y,t)\) for a 2-D simulation (etc.) +The two functions represent \(B_y\) and \(B_z\), respectively. +This can be used only in Cartesian geometries.

+
+ +
+
+space_time_profile_AM
+
+
Type
+

A list of maximum 2 x number_of_AM python functions.

+
+
+

These profiles define the first modes of \(B_r\) and \(B_\theta\) in the +order shown in the above example. Undefined modes are considered zero. +This can be used only in AMcylindrical geometry. In this +geometry a two-dimensional \((x,r)\) grid is used and the laser is injected from a +\(x\) boundary, thus the provided profiles must be a function of \((r,t)\).

+
+ +

2. Defining the wave envelopes

+
+
Laser(
+    box_side       = "xmin",
+    omega          = 1.,
+    chirp_profile  = tconstant(),
+    time_envelope  = tgaussian(),
+    space_envelope = [ By_profile  , Bz_profile   ],
+    phase          = [ PhiY_profile, PhiZ_profile ],
+    delay_phase    = [ 0., 0. ]
+)
+
+
+

This implements a wave of the form:

+
+\[ \begin{align}\begin{aligned}B_y(\mathbf{x}, t) = S_y(\mathbf{x})\; T\left(t-t_{0y}\right) +\;\sin\left( \omega(t) t - \phi_y(\mathbf{x}) \right)\\B_z(\mathbf{x}, t) = S_z(\mathbf{x})\; T\left(t-t_{0z}\right) +\;\sin\left( \omega(t) t - \phi_z(\mathbf{x}) \right)\end{aligned}\end{align} \]
+

where \(T\) is the temporal envelope, \(S_y\) and \(S_z\) are the +spatial envelopes, \(\omega\) is the time-varying frequency, +\(\phi_y\) and \(\phi_z\) are the phases, and we defined the delays +\(t_{0y} = (\phi_y(\mathbf{x})-\varphi_y)/\omega(t)\) and +\(t_{0z} = (\phi_z(\mathbf{x})-\varphi_z)/\omega(t)\).

+
+
+omega
+
+
Default
+
    +
  1. +
+
+
+

The laser angular frequency.

+
+ +
+
+chirp_profile
+
+
Type
+

a python function or a time profile

+
+
Default
+

tconstant()

+
+
+

The variation of the laser frequency over time, such that +\(\omega(t)=\) omega x chirp_profile \((t)\).

+
+ +
+

Warning

+

This definition of the chirp profile is not standard. +Indeed, \(\omega(t)\) as defined here is not the instantaneous frequency, \(\omega_{\rm inst}(t)\), +which is obtained from the time derivative of the phase \(\omega(t) t\).

+

Should one define the chirp as \(C(t) = \omega_{\rm inst}(t)/\omega\) (with \(\omega\) defined by the input +parameter \(\mathtt{omega}\)), the user can easily obtain the corresponding chirp profile as defined in +Smilei as:

+
+\[\mathtt{chirp\_profile}(t) = \frac{1}{t} \int_0^t dt' C(t')\,.\]
+

Let us give as an example the case of a linear chirp, with the instantaneous frequency +\(\omega_{\rm inst}(t) = \omega [1+\alpha\,\omega(t-t_0)]\). +\(C(t) = 1+\alpha\,\omega(t-t_0)\). The corresponding input chirp profile reads:

+
+\[\mathtt{chirp\_profile}(t) = 1 - \alpha\, \omega t_0 + \frac{\alpha}{2} \omega t\]
+

Similarly, for a geometric (exponential) chirp such that \(\omega_{\rm inst}(t) = \omega\, \alpha^{\omega t}\), +\(C(t) = \alpha^{\omega t}\), and the corresponding input chirp profile reads:

+
+\[\mathtt{chirp\_profile}(t) = \frac{\alpha^{\omega t} - 1}{\omega t \, \ln \alpha}\,.\]
+
+
+
+time_envelope
+
+
Type
+

a python function or a time profile

+
+
Default
+

tconstant()

+
+
+

The temporal envelope of the laser.

+
+ +
+
+space_envelope
+
+
Type
+

a list of two python functions or two spatial profiles

+
+
Default
+

[ 1., 0. ]

+
+
+

The two spatial envelopes \(S_y\) and \(S_z\).

+
+ +
+
+phase
+
+
Type
+

a list of two python functions or two spatial profiles

+
+
Default
+

[ 0., 0. ]

+
+
+

The two spatially-varying phases \(\phi_y\) and \(\phi_z\).

+
+ +
+
+delay_phase
+
+
Type
+

a list of two floats

+
+
Default
+

[ 0., 0. ]

+
+
+

An extra phase for the time envelopes of \(B_y\) and \(B_z\). Useful in the +case of elliptical polarization where the two temporal profiles might have a slight +delay due to the mismatched phase.

+
+ +
+

3. Defining a 1D planar wave

+
+

For one-dimensional simulations, you may use the simplified laser creator:

+
LaserPlanar1D(
+    box_side         = "xmin",
+    a0               = 1.,
+    omega            = 1.,
+    polarization_phi = 0.,
+    ellipticity      = 0.,
+    time_envelope    = tconstant()
+)
+
+
+
+
+a0
+
+
Default
+
    +
  1. +
+
+
+

The normalized vector potential

+
+ +
+
+polarization_phi
+
+
Default
+
    +
  1. +
+
+
+

The angle of the polarization ellipse major axis relative to the X-Y plane, in radians.

+
+ +
+
+ellipticity
+
+
Default
+
    +
  1. +
+
+
+

The polarization ellipticity: 0 for linear and \(\pm 1\) for circular.

+
+ +
+

4. Defining a 2D gaussian wave

+
+

For two-dimensional simulations, you may use the simplified laser creator:

+
LaserGaussian2D(
+    box_side         = "xmin",
+    a0               = 1.,
+    omega            = 1.,
+    focus            = [50., 40.],
+    waist            = 3.,
+    incidence_angle  = 0.,
+    polarization_phi = 0.,
+    ellipticity      = 0.,
+    time_envelope    = tconstant()
+)
+
+
+
+
+focus
+
+
Type
+

A list of two floats [X, Y]

+
+
+

The X and Y positions of the laser focus.

+
+ +
+
+waist
+

The waist value. Transverse coordinate at which the field is at 1/e of its maximum value.

+
+ +
+
+incidence_angle
+
+
Default
+
    +
  1. +
+
+
+

The angle of the laser beam relative to the normal to the injection plane, in radians.

+
+ +
+
+time_envelope
+

Time envelope of the field (not intensity).

+
+ +
+

5. Defining a 3D gaussian wave

+
+

For three-dimensional simulations, you may use the simplified laser creator:

+
LaserGaussian3D(
+    box_side         = "xmin",
+    a0               = 1.,
+    omega            = 1.,
+    focus            = [50., 40., 40.],
+    waist            = 3.,
+    incidence_angle  = [0., 0.1],
+    polarization_phi = 0.,
+    ellipticity      = 0.,
+    time_envelope    = tconstant()
+)
+
+
+

This is almost the same as LaserGaussian2D, with the focus parameter having +now 3 elements (focus position in 3D), and the incidence_angle being a list of +two angles, corresponding to rotations around y and z, respectively.

+

When injecting on "ymin" or "ymax", the incidence angles corresponds to +rotations around x and z, respectively.

+
+

6. Defining a gaussian wave with Azimuthal Fourier decomposition

+
+

For simulations with "AMcylindrical" geometry, you may use the simplified laser creator:

+
LaserGaussianAM(
+    box_side         = "xmin",
+    a0               = 1.,
+    omega            = 1.,
+    focus            = [50., 0.],
+    waist            = 3.,
+    polarization_phi = 0.,
+    ellipticity      = 0.,
+    time_envelope    = tconstant()
+)
+
+
+

Note that here, the focus is given in [x,r] coordinates.

+
+

7. Defining a generic wave at some distance from the boundary

+
+

In some cases, the laser field is not known at the box boundary, but rather at some +plane inside the box. Smilei can pre-calculate the corresponding wave at the boundary +using the angular spectrum method. This technique is only available in 2D and 3D +cartesian geometries and requires the python packages numpy. +A detailed explanation of the method is available. +The laser is introduced using:

+
LaserOffset(
+    box_side               = "xmin",
+    space_time_profile     = [ By_profile, Bz_profile ],
+    offset                 = 10.,
+    extra_envelope          = tconstant(),
+    keep_n_strongest_modes = 100,
+    angle = 10./180.*3.14159
+)
+
+
+
+
+space_time_profile
+
+
Type
+

A list of two python functions

+
+
+

The magnetic field profiles at some arbitrary plane, as a function of space and time. +The arguments of these profiles are (y,t) in 2D and (y,z,t) in 3D.

+
+ +
+
+offset
+

The distance from the box boundary to the plane where space_time_profile +is defined.

+
+ +
+
+extra_envelope
+
+
Type
+

a python function or a python profile

+
+
Default
+

lambda *z: 1., which means a profile of value 1 everywhere

+
+
+

An extra envelope applied at the boundary, on top of the space_time_profile. +This envelope takes two arguments (y, t) in 2D, and three arguments (y, z, t) +in 3D. +As the wave propagation technique stores a limited number of Fourier modes (in the time +domain) of the wave, some periodicity can be obtained in the actual laser. +One may thus observe that the laser pulse is repeated several times. +The envelope can be used to remove these spurious repetitions.

+
+ +
+
+keep_n_strongest_modes
+
+
Default
+

100

+
+
+

The number of temporal Fourier modes that are kept during the pre-processing. +See this page for more details.

+
+ +
+
+angle
+
+
Default
+
    +
  1. +
+
+
+

Angle between the boundary and the profile’s plane, the rotation being around \(z\). +See this page for more details.

+
+ +
+
+fft_time_window
+
+
Default
+

simulation_time

+
+
+

Time during which the space_time_profile is sampled (calculating the +LaserOffset on the whole simulation duration can be costly). Note that +the Fourier approach will naturally repeat the signal periodically.

+
+ +
+
+fft_time_step
+
+
Default
+

timestep

+
+
+

Temporal step between each sample of the space_time_profile. +Chosing a larger step can help reduce the memory load but will remove high temporal frequencies.

+
+ +
+
+number_of_processes
+
+
Default
+

all available processes

+
+
+

The number of MPI processes that will be used for computing the LaserOffset. +Using more processes computes the FFT faster, but too many processes may +be very costly in communication. In addition, using too few may not allow +the arrays to fit in memory.

+
+ +
+
+file
+
+
Default
+

None

+
+
+

The path to a LaserOffset*.h5 file generated from a previous simulation. This option +can help reduce the computation time by re-using the LaserOffset computation +from a previous simulation.

+
+ +
+
+
+
+

Laser envelope model

+

In all the available geometries, it is possible to model a laser pulse +propagating in the x direction +using an envelope model (see Laser envelope model for the advantages +and limits of this approximation). +The fast oscillations of the laser are neglected and all the physical +quantities of the simulation, including the electromagnetic fields and +their source terms, as well as the particles positions and momenta, are +meant as an average over one or more optical cycles. +Effects involving characteristic lengths comparable to the laser central +wavelength (i.e. sharp plasma density profiles) cannot be modeled with +this option.

+
+

Note

+

The envelope model in "AMcylindrical" geometry is implemented only in the hypothesis of +cylindrical symmetry, i.e. only one azimuthal mode. Therefore, to use it the user must choose +number_of_AM = 1.

+
+

Contrarily to a standard Laser initialized with the Silver-Müller +boundary conditions, the laser envelope will be entirely initialized inside +the simulation box at the start of the simulation.

+

Currently only one laser pulse of a given frequency propagating in the positive +x direction can be speficified. However, a multi-pulse set-up can be initialized +if a multi-pulse profile is specified, e.g. if the temporal profile is given by two adjacents gaussian functions. +The whole multi-pulse profile would have the same carrier frequency and would propagate in the positive +x direction. For the moment it is not possible to specify more than one laser envelope profile, e.g. +two counterpropagating lasers, or two lasers with different carrier frequency.

+

Please note that describing a laser through its complex envelope loses physical accuracy if its +characteristic space-time variation scales are too small, i.e. of the order of the laser +central wavelength (see Laser envelope model). +Thus, space-time profiles with variation scales larger than this length should be used.

+

1. Defining a generic laser envelope

+

Following is the generic laser envelope creator

+
LaserEnvelope(
+    omega          = 1.,
+    envelope_solver = 'explicit',
+    envelope_profile = envelope_profile,
+    Envelope_boundary_conditions = [["reflective"]]
+    polarization_phi = 0.,
+    ellipticity      = 0.
+)
+
+
+
+
+omega
+
+
Default
+

1.

+
+
+

The laser angular frequency.

+
+ +
+
+envelope_profile
+
+
Type
+

a python function or a python profile

+
+
Default
+

None

+
+
+

The laser space-time profile, so if the geometry is 3Dcartesian a function of 4 arguments (3 for space, 1 for time) is necessary. +Please note that the envelope will be entirely initialized in the simulation box +already at the start of the simulation, so the time coordinate will be applied +to the x direction instead of time. It is recommended to initialize the +laser envelope in vacuum, separated from the plasma, to avoid unphysical +results. +Envelopes with variation scales near to the laser wavelength do not +satisfy the assumptions of the envelope model (see Laser envelope model), +yielding inaccurate results.

+
+ +
+
+envelope_solver
+
+
Default
+

explicit

+
+
+

The solver scheme for the envelope equation.

+
    +
  • "explicit": an explicit scheme based on central finite differences.

  • +
  • "explicit_reduced_dispersion": the finite difference derivatives along x in the "explicit" solver are substituted by +optimized derivatives to reduce numerical dispersion. For more accurate results over long distances, the use of this solver is recommended. +Please note that the CFL limit of this solver is lower than the one of the "explicit" solver. Thus, a smaller integration +timestep may be necessary.

  • +
+
+ +
+
+Envelope_boundary_conditions
+
+
Type
+

list of lists of strings

+
+
Default
+

[["reflective"]]

+
+
+

Defines the boundary conditions used for the envelope. Either "reflective" or "PML". +In the case of "PML", make sure to define "number_of_pml_cells" in the Main block.

+
+ +
+
+polarization_phi
+
+
Default
+
    +
  1. +
+
+
+

The angle of the polarization ellipse major axis relative to the X-Y plane, in radians. Needed only for ionization.

+
+ +
+
+ellipticity
+
+
Default
+
    +
  1. +
+
+
+

The polarization ellipticity: 0 for linear and 1 for circular. For the moment, only these two polarizations are available.

+
+ +

2. Defining a 1D laser envelope

+

Following is the simplified laser envelope creator in 1D

+
LaserEnvelopePlanar1D(
+    a0              = 1.,
+    time_envelope   = tgaussian(center=150., fwhm=40.),
+    envelope_solver = 'explicit',
+    Envelope_boundary_conditions = [ ["reflective"] ],
+    polarization_phi = 0.,
+    ellipticity      = 0.
+)
+
+
+

3. Defining a 2D gaussian laser envelope

+

Following is the simplified gaussian laser envelope creator in 2D

+
LaserEnvelopeGaussian2D(
+    a0              = 1.,
+    focus           = [150., 40.],
+    waist           = 30.,
+    time_envelope   = tgaussian(center=150., fwhm=40.),
+    envelope_solver = 'explicit',
+    Envelope_boundary_conditions = [ ["reflective"] ],
+    polarization_phi = 0.,
+    ellipticity      = 0.
+)
+
+
+

4. Defining a 3D gaussian laser envelope

+

Following is the simplified laser envelope creator in 3D

+
LaserEnvelopeGaussian3D(
+    a0              = 1.,
+    focus           = [150., 40., 40.],
+    waist           = 30.,
+    time_envelope   = tgaussian(center=150., fwhm=40.),
+    envelope_solver = 'explicit',
+    Envelope_boundary_conditions = [ ["reflective"] ],
+    polarization_phi = 0.,
+    ellipticity      = 0.
+)
+
+
+

5. Defining a cylindrical gaussian laser envelope

+

Following is the simplified laser envelope creator in "AMcylindrical" geometry (remember that +in this geometry the envelope model can be used only if number_of_AM = 1)

+
LaserEnvelopeGaussianAM(
+    a0              = 1.,
+    focus           = [150., 40.],
+    waist           = 30.,
+    time_envelope   = tgaussian(center=150., fwhm=40.),
+    envelope_solver = 'explicit',
+    Envelope_boundary_conditions = [ ["reflective"] ],
+    polarization_phi = 0.,
+    ellipticity      = 0.
+)
+
+
+

The arguments appearing LaserEnvelopePlanar1D, LaserEnvelopeGaussian2D, +LaserEnvelopeGaussian3D and LaserEnvelopeGaussianAM have the same meaning they would have in a +normal LaserPlanar1D, LaserGaussian2D, LaserGaussian3D and LaserGaussianAM, +with some differences:

+
+
+time_envelope
+

Since the envelope will be entirely initialized in the simulation box +already at the start of the simulation, the time envelope will be applied +in the x direction instead of time. It is recommended to initialize the +laser envelope in vacuum, separated from the plasma, to avoid unphysical +results. +Temporal envelopes with variation scales near to the laser wavelength do not +satisfy the assumptions of the envelope model (see Laser envelope model), +yielding inaccurate results.

+
+ +
+
+waist
+

Please note that a waist size comparable to the laser wavelength does not +satisfy the assumptions of the envelope model.

+
+ +

It is important to remember that the profile defined through the blocks +LaserEnvelopePlanar1D, LaserEnvelopeGaussian2D, LaserEnvelopeGaussian3D +correspond to the complex envelope of the laser vector potential component +\(\tilde{A}\) in the polarization direction. +The calculation of the correspondent complex envelope for the laser electric field +component in that direction is described in Laser envelope model.

+

Note that only order 2 interpolation and projection are supported in presence of +the envelope model for the laser.

+

The parameters polarization_phi and ellipticity specify the polarization state of the laser. In envelope model implemented in Smilei, +they are only used to compute the rate of ionization and the initial momentum of the electrons newly created by ionization, +where the polarization of the laser plays an important role (see Ionization). +For all other purposes (e.g. the particles equations of motions, the computation of the ponderomotive force, +the evolution of the laser), the polarization of the laser plays no role in the envelope model.

+
+
+
+

External fields

+

An initial field can be applied over the whole box +at the beginning of the simulation using the ExternalField block:

+
ExternalField(
+    field = "Ex",
+    profile = constant(0.01, xvacuum=0.1)
+)
+
+
+
+
+field
+

Field name in Cartesian geometries: "Ex", "Ey", "Ez", "Bx", "By", "Bz", "Bx_m", "By_m", "Bz_m" +Field name in AM geometry: "El", "Er", "Et", "Bl", "Br", "Bt", "Bl_m", "Br_m", "Bt_m", "A", "A0" .

+
+ +
+
+profile
+
+
Type
+

float or profile

+
+
+

The initial spatial profile of the applied field. +Refer to Units to understand the units of this field.

+

Note that when using standard FDTD schemes, B fields are given at time t=0.5 dt and B_m fields at time t=0 like E fields. +It is important to initialize B_m fields at t=0 if there are particles in the simulation domain at the start of the simulation. +If B_m is omited, it is assumed that the magnetic field is constant and that B_m=B.

+

Note that in AM geometry all field names must be followed by the number "i" of the mode that is currently passed with the string "_mode_i". For instance "Er_mode_1". +In this geometry, an external envelope field can also be used. It needs to be initialized at times "t=0" in "A_mode_1" and "t=-dt" in "A0_mode_1". +The user must use the "_mode_1" suffix for these two fields because there is no other possible mode for them.

+
+ +
+
+
+

Prescribed fields

+

User-defined electromagnetic fields, with spatio-temporal dependence, +can be superimposed to the self-consistent Maxwell fields. +These fields push the particles but do not participate in the Maxwell solver: +they are not self-consistent. +They are however useful to describe charged particles’ dynamics in a given +electromagnetic field.

+

This feature is accessible using the PrescribedField block:

+
from numpy import cos, sin
+def myPrescribedProfile(x,t):
+      return cos(x)*sin(t)
+
+PrescribedField(
+    field = "Ex",
+    profile = myPrescribedProfile
+)
+
+
+
+
+field
+

Field name: "Ex", "Ey", "Ez", "Bx_m", "By_m" or "Bz_m".

+
+ +
+

Warning

+

When prescribing a magnetic field, always use the time-centered fields "Bx_m", "By_m" or "Bz_m". +These fields are those used in the particle pusher, and are defined at integer time-steps.

+
+
+
+profile
+
+
Type
+

float or profile

+
+
+

The spatio-temporal profile of the applied field: a python function +with arguments (x, t) or (x, y, t), etc. +Refer to Units to understand the units of this field.

+
+ +
+
+
+

Antennas

+

An antenna is an extra current applied during the whole simulation. +It is applied using an Antenna block:

+
Antenna(
+    field = "Jz",
+    space_profile = gaussian(0.01),
+    time_profile = tcosine(base=0., duration=1., freq=0.1)
+)
+
+
+
+
+field
+

The name of the current: "Jx", "Jy" or "Jz".

+
+ +
+
+space_profile
+
+
Type
+

float or profile

+
+
+

The initial spatial profile of the applied antenna. +Refer to Units to understand the units of this current.

+
+ +
+
+time_profile
+
+
Type
+

float or profile

+
+
+

The temporal profile of the applied antenna. It multiplies space_profile.

+
+ +
+
+space_time_profile
+
+
Type
+

float or profile

+
+
+

A space & time profile for the antenna (not compatible with space_profile +or time_profile). It should have N+1``arguments, where ``N is the dimension +of the simulation. For instance (x,t) in 1D, (x,y,t) in 2D, etc.

+

The function must accept x, y and z either as floats or numpy arrays. +If it accepts floats, the return value must be a float. +If it accepts numpy arrays, these arrays will correspond to the coordinates of 1 patch, +and the return value must be a numpy array of the same size.

+
+ +
+
+
+

Walls

+

A wall can be introduced using a PartWall block in order to +reflect, stop, thermalize or kill particles which reach it:

+
PartWall(
+    kind = "reflective",
+    x = 20.
+)
+
+
+
+
+kind
+

The kind of wall: "reflective", "stop", "thermalize" or "remove".

+
+ +
+
+x
+
+y
+
+z
+

Position of the wall in the desired direction. Use only one of x, y or z.

+
+ +
+
+
+

Collisions & reactions

+

Binary collisions & reactions account for short-range Coulomb interactions of particles (shorter than the +cell size), but also include other effects such as impact ionization and nuclear reactions. +These are gathered under this section because they are treated as binary processes (meaning +they happen during the encounter of two macro-particles).

+

They are specified by one or several Collisions blocks:

+
Collisions(
+    species1 = ["electrons1",  "electrons2"],
+    species2 = ["ions1"],
+    debug_every = 1000,
+    coulomb_log = 0.,
+    coulomb_log_factor = 1.,
+    ionizing = False,
+#      nuclear_reaction = [],
+)
+
+
+
+
+species1
+
+species2
+

Lists of species’ name.

+

The collisions and reactions will occur between all species under the group species1 +and all species under the group species2. For example, to collide all +electrons with ions:

+
species1 = ["electrons1", "electrons2"], species2 = ["ions"]
+
+
+
+

Warning

+

This does not make electrons1 collide with electrons2.

+
+

The two groups of species have to be completely different OR exactly equal. +In other words, if species1 is not equal to species2, +then they cannot have any common species. +If the two groups are exactly equal, we call this situation intra-collisions.

+
+

Note

+

If both lists species1 and species2 contain only one species, +the algorithm is potentially faster than the situation with several +species in one or the other list. This is especially true if the +machine accepts SIMD vectorization.

+
+
+ +
+
+every
+
+
Default
+

1

+
+
+

Number of timesteps between each computation of the collisions or reactions. +Use a number higher than 1 only if you know the collision frequency is low +with respect to the inverse of the timestep.

+
+ +
+
+debug_every
+
+
Default
+

0

+
+
+

Number of timesteps between each output of information about collisions or reactions. +If 0, there will be no outputs.

+
+ +
+
+time_frozen
+
+
Default
+
    +
  1. +
+
+
+

The time during which no collisions or reactions happen, in units of \(T_r\).

+
+ +
+
+coulomb_log
+
+
Default
+
    +
  1. +
+
+
+

The Coulomb logarithm.

+
    +
  • If \(= 0\), the Coulomb logarithm is automatically computed for each collision.

  • +
  • If \(> 0\), the Coulomb logarithm is equal to this value.

  • +
  • If \(< 0\), collisions are not treated (but other reactions may happen).

  • +
+
+ +
+
+coulomb_log_factor
+
+
Default
+
    +
  1. +
+
+
+

A constant, strictly positive factor that multiplies the Coulomb logarithm, regardless +of coulomb_log being automatically computed or set to a constant value. +This can help, for example, to compensate artificially-reduced ion masses.

+
+ +
+
+ionizing
+
+
Default
+

False

+
+
+

Collisional ionization is set when this parameter is not False. +It can either be set to the name of a pre-existing electron species (where the ionized +electrons are created), or to True (the first electron species in species1 +or species2 is then chosen for ionized electrons).

+

One of the species groups must be all electrons (mass = 1), and the other +one all ions of the same atomic_number.

+
+ +
+
+nuclear_reaction
+
+
Type
+

a list of strings

+
+
Default
+

None (no nuclear reaction)

+
+
+

A list of the species names for the products of Nuclear reactions +that may occur during collisions. You may omit product species if they are not necessary +for the simulation.

+

All members of species1 must be the same type of atoms, which is automatically +recognized by their mass and atomic_number. The same applies for +all members of species2.

+

In the current version, only the reaction D(d,n)He³ is available.

+
+ +
+
+nuclear_reaction_multiplier
+
+
Type
+

a float

+
+
Default
+
    +
  1. (automatically adjusted)

  2. +
+
+
+

The rate multiplier for nuclear reactions. It is a positive number that artificially +increases the occurence of reactions so that a good statistics is obtained. The number +of actual reaction products is adjusted by changing their weights in order to provide +a physically correct number of reactions. Leave this number to 0. for an automatic +rate multiplier: the final number of produced macro-particles will be of the same order +as that of reactants.

+
+ +
+
+
+

Radiation reaction

+

The block RadiationReaction() enables to tune the radiation loss properties +(see High-energy photon emission & radiation reaction). +Many parameters are used for the generation of the cross-section tables +for the Monte-Carlo emission process. +If the tables already exist in the simulation directory, then they will be read +and no new table will be generated by Smilei. +Otherwise, Smilei can compute and output these +tables.

+
RadiationReaction(
+
+  # Radiation parameters
+  minimum_chi_continuous = 1e-3,
+  minimum_chi_discontinuous = 1e-2,
+  table_path = "<path to the external table folder>",
+
+  # Parameters for Niel et al.
+  Niel_computation_method = "table",
+
+)
+
+
+
+
+minimum_chi_continuous
+
+
Default
+

1e-3

+
+
+

Threshold on the particle quantum parameter particle_chi. When a particle has a +quantum parameter below this threshold, radiation reaction is not taken +into account.

+
+ +
+
+minimum_chi_discontinuous
+
+
Default
+

1e-2

+
+
+

Threshold on the particle quantum parameter particle_chi between the continuous +and the discontinuous radiation model.

+
+ +
+
+table_path
+
+
Default
+

""

+
+
+

Path to the directory that contains external tables for the radiation losses. +If empty, the default tables are used. +Default tables are embedded in the code. +External tables can be generated using the external tool smilei_tables (see Generation of the external tables).

+
+ +
+
+Niel_computation_method
+
+
Default
+

"table"

+
+
+

Method to compute the value of the table h of Niel et al during the emission process. +The possible values are:

+
    +
  • "table": the h function is tabulated. The table is computed at initialization or read from an external file.

  • +
  • "fit5": A polynomial fit of order 5 is used. No table is required. +The maximal relative error to the reference data is of maximum of 0.02. +The fit is valid for quantum parameters \(\chi\) between 1e-3 and 10.

  • +
  • "fit10": A polynomial fit of order 10 is used. No table is required. +The precision if better than the fit of order 5 with a maximal relative error of 0.0002. +The fit is valid for quantum parameters \(\chi\) between 1e-3 and 10.

  • +
  • "ridgers": The fit of Ridgers given in Ridgers et al., ArXiv 1708.04511 (2017)

  • +
+

The use of tabulated values is best for accuracy but not for performance. +Table access prevent total vectorization. +Fits are vectorizable.

+
+ +
+
+
+

Multiphoton Breit-Wheeler

+

The block MultiphotonBreitWheeler enables to tune parameters of the +multiphoton Breit-Wheeler process and particularly the table generation. +For more information on this physical mechanism, see Multiphoton Breit-Wheeler pair creation.

+

There are three tables used for the multiphoton Breit-Wheeler refers to as the +integration_dT_dchi, min_particle_chi_for_xi and xi table.

+
MultiphotonBreitWheeler(
+
+  # Path to the tables
+  table_path = "<path to the external table folder>",
+
+)
+
+
+
+
+table_path
+
+
Default
+

""

+
+
+

Path to the directory that contains external tables for the multiphoton Breit-Wheeler. +If empty, the default tables are used. +Default tables are embedded in the code. +External tables can be generated using the external tool smilei_tables (see Generation of the external tables).

+
+ +
+
+
+

Scalar diagnostics

+

Smilei can collect various scalar data, such as total particle energy, total field energy, etc. +This is done by including the block DiagScalar:

+
DiagScalar(
+    every = 10 ,
+    vars = ["Utot", "Ukin", "Uelm"],
+    precision = 10
+)
+
+
+
+
+every
+

Number of timesteps between each output or a time selection.

+
+ +
+
+vars
+
+
Default
+

[]

+
+
+
+
List of scalars that will be actually output. Note that most scalars are computed anyways.
+
Omit this argument to include all scalars.
+
+
+ +
+
+precision
+
+
Default
+

10

+
+
+

Number of digits of the outputs.

+
+ +
+

Warning

+

Scalars diagnostics min/max cell are not yet supported in "AMcylindrical" geometry.

+
+

The full list of available scalars is given in the table below.

+
+

Warning

+

As some of these quantities are integrated in space and/or time, their +units are unusual, and depend on the simulation dimension. +All details here.

+
+ +++ + + + + + + + + + + + + + + + + + + +

Space-integrated energy densities

++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Utot

Total

Ukin

Total kinetic (in the particles)

Uelm

Total electromagnetic (in the fields)

Uexp

Expected (Initial \(-\) lost \(+\) gained)

Ubal

Balance (Utot \(-\) Uexp)

Ubal_norm

Normalized balance (Ubal \(/\) Utot)

Uelm_Ex

Ex field contribution (\(\int E_x^2 dV /2\))

… same for fields Ey, Ez, Bx_m, By_m and Bz_m

Urad

Total radiated

UmBWpairs

Total energy converted into electron-position pairs

+

Space- & time-integrated Energies lost/gained at boundaries

++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Ukin_bnd

Time-accumulated kinetic energy exchanged at the boundaries

Uelm_bnd

Time-accumulated EM energy exchanged at boundaries

PoyXminInst

Poynting contribution through xmin boundary during the timestep

PoyXmin

Time-accumulated Poynting contribution through xmin boundary

… same for other boundaries

Ukin_new

Time-accumulated kinetic energy from new particles (injector)

Ukin_out_mvw

Time-accumulated kinetic energy lost by the moving window

Ukin_inj_mvw

Time-accumulated kinetic energy gained by the moving window

Uelm_out_mvw

Time-accumulated EM energy lost by the moving window

Uelm_inj_mvw

Time-accumulated EM energy gained by the moving window

+

Particle information

++++ + + + + + + + + + + + + + + + + + + + + +

Zavg_abc

Average charge of species “abc” (equals nan if no particle)

Dens_abc

… its integrated density

Ukin_abc

… its integrated kinetic energy density

Urad_abc

… its integrated radiated energy density

Ntot_abc

… and number of macro-particles

+

Fields information

++++ + + + + + + + + + + + + + + + + + +

ExMin

Minimum of \(E_x\)

ExMinCell

… and its location (cell index)

ExMax

Maximum of \(E_x\)

ExMaxCell

… and its location (cell index)

… same for fields Ey Ez Bx_m By_m Bz_m Jx Jy Jz Rho

+
+

Checkout the post-processing documentation as well.

+
+
+
+

Fields diagnostics

+

Smilei can collect various field data (electromagnetic fields, currents and density) +taken at the location of the PIC grid, both as instantaneous values and averaged values. +This is done by including a block DiagFields:

+
DiagFields(
+    #name = "my field diag",
+    every = 10,
+    time_average = 2,
+    fields = ["Ex", "Ey", "Ez"],
+    #subgrid = None
+)
+
+
+
+
+name
+

Optional name of the diagnostic. Used only for post-processing purposes.

+
+ +
+
+every
+

Number of timesteps between each output or a time selection.

+
+ +
+
+flush_every
+
+
Default
+

1

+
+
+

Number of timesteps or a time selection.

+

When flush_every coincides with every, the output +file is actually written (“flushed” from the buffer). Flushing +too often can dramatically slow down the simulation.

+
+ +
+
+time_average
+
+
Default
+

1 (no averaging)

+
+
+

The number of timesteps for time-averaging.

+
+ +
+
+fields
+
+
Default
+

[] (all fields are written)

+
+
+

List of the field names that are saved. By default, they all are. +The full list of fields that are saved by this diagnostic:

+ ++++ + + + + + + + + + + + + + + + + + + + + +
+
Bx
+
By
+
Bz
+
+
+

+
Components of the magnetic field
+

+
+
+
Bx_m
+
By_m
+
Bz_m
+
+
+

+
Components of the magnetic field (time-centered)
+

+
+
+
Ex
+
Ey
+
Ez
+
+
+

+
Components of the electric field
+

+
+
+
Jx
+
Jy
+
Jz
+
+
+

+
Components of the total current
+

+
+
+
Jx_abc
+
Jy_abc
+
Jz_abc
+
+
+

+
Components of the current due to species “abc”
+

+
+
+
Rho
+
Rho_abc
+
+
+
Total density
+
Density of species “abc”
+
+
+

In AMcylindrical geometry, the x, y and z +indices are replaced by l (longitudinal), r (radial) and t (theta). In addition, +the angular Fourier modes are denoted by the suffix _mode_i where i +is the mode number. +If a field is specified without its associated mode number, all available modes will be included. +In summary, the list of fields reads as follows.

+ ++++ + + + + + + + + + + +
+
Bl_mode_0, Bl_mode_1, etc.
+
Br_mode_0, Br_mode_1, etc.
+
Bt_mode_0, Bt_mode_1, etc.
+
+
+

+
Components of the magnetic field
+

+
+
+
El_mode_0, El_mode_1, etc.
+
Er_mode_0, Er_mode_1, etc.
+
Et_mode_0, Et_mode_1, etc.
+
+
+

+
Components of the electric field
+

+
+

The same notation works for Jl, Jr, Jt, and Rho

+

In the case of an envelope model for the laser (see Laser envelope model), +the following fields are also available:

+ ++++ + + + + + + + + + + + + + + +
+

+
Env_A_abs
+

+
+
+
Module of laser vector potential’s complex envelope
+
\(\tilde{A}\) (component along the transverse
+
direction)
+
+
+
Env_Chi
+
+
+
Total susceptibility \(\chi\)
+
+
+

+
Env_E_abs
+

+
+
+
Module of laser electric field’s complex envelope
+
\(\tilde{E}\) (component along the transverse
+
direction)
+
+
+

+
Env_Ex_abs
+

+
+
+
Module of laser electric field’s complex envelope
+
\(\tilde{E}_x\) (component along the propagation
+
direction)
+
+
+

In the case the B-TIS3 interpolation is activated (see PIC algorithms), +the following fields are also available:

+ ++++ + + + + + + + + +
+
By_mBTIS3
+
By_mBTIS3
+

+
+
+
Components of the magnetic field
+
for the B-TIS3 interpolation
+
(time-centered)
+
+
+
Br_mBTIS3_mode_0, Br_mBTIS3_mode_1, etc.
+
Bt_mBTIS3_mode_0, Bt+mBTIS3_mode_1, etc.
+

+
+
+
Components of the magnetic field
+
for the B-TIS3 interpolation
+
(AMcylindrical geometry, time-centered)
+
+
+
+ +
+

Note

+

In a given DiagFields, all fields must be of the same kind: either real or complex. Therefore To write these last three envelope real fields in "AMcylindrical" geometry, +a dedicated block DiagFields must be defined, e.g. with fields = ["Env_A_abs", "Env_Chi"].

+
+
+
+subgrid
+
+
Default
+

None (the whole grid is used)

+
+
+

A list of slices indicating a portion of the simulation grid to be written by this +diagnostic. This list must have as many elements as the simulation dimension. +For example, in a 3D simulation, the list has 3 elements. Each element can be:

+
    +
  • None, to select the whole grid along that dimension

  • +
  • an integer, to select only the corresponding cell index along that dimension

  • +
  • a python slice object +to select regularly-spaced cell indices along that dimension.

  • +
+

This can be easily implemented using the +numpy.s_ expression. +For instance, in a 3D simulation, the following subgrid selects only every other element +in each dimension:

+
from numpy import s_
+DiagFields( #...
+    subgrid = s_[::2, ::2, ::2]
+)
+
+
+

while this one selects cell indices included in a contiguous parallelepiped:

+
subgrid = s_[100:300, 300:500, 300:600]
+
+
+
+ +
+
+datatype
+
+
Default
+

"double"

+
+
+

The data type when written to the HDF5 file. Accepts "double" (8 bytes) or "float" (4 bytes).

+
+ +
+
+
+

Probe diagnostics

+

The fields from the previous section are taken at the PIC grid locations, +but it is also possible to obtain the fields at arbitrary locations. +These are called probes.

+

A probe interpolates the fields at either one point (0-D), +several points arranged in a line (1-D), +or several points arranged in a 2-D or 3-D grid.

+
+

Note

+
    +
  • Probes follow the moving window. +To obtain the fields at fixed points in the plasma instead, create a cold, +chargeless species, and track the particles.

  • +
  • In “AMcylindrical” geometry, probes are defined with 3D Cartesian coordinates +and cannot be separated per mode. Use Field diagnostics for cylindrical coordinates and +information per mode.

  • +
+
+

To add one probe diagnostic, include the block DiagProbe:

+
DiagProbe(
+    #name = "my_probe",
+    every    = 10,
+    origin   = [1., 1.],
+    corners  = [
+        [1.,10.],
+        [10.,1.],
+    ],
+    number   = [100, 100],
+    fields   = ["Ex", "Ey", "Ez"]
+)
+
+
+
+
+name
+

Optional name of the diagnostic. Used only for post-processing purposes.

+
+ +
+
+every
+

Number of timesteps between each output or a time selection.

+
+ +
+
+flush_every
+
+
Default
+

1

+
+
+

Number of timesteps or a time selection.

+

When flush_every coincides with every, the output +file is actually written (“flushed” from the buffer). Flushing +too often can dramatically slow down the simulation.

+
+ +
+
+origin
+
+
Type
+

A list of floats, of length equal to the simulation dimensionality.

+
+
+

The coordinates of the origin of the probe grid

+
+ +
+
+corners
+
+vectors
+
+
Type
+

A list of lists of floats.

+
+
+

Defines the corners of the probe grid. +Each corner is a list of coordinates (as many as the simulation dimensions).

+

When using corners, the absolute coordinates of each corner must be specified. +When using vectors, the coordinates relative to origin must be specified.

+
+ +
+
+number
+
+
Type
+

A list of integers, one for each dimension of the probe.

+
+
+

The number of points in each probe axis. Must not be defined for a 0-D probe.

+
+ +
+
+fields
+
+
Default
+

[], which means ["Ex", "Ey", "Ez", "Bx", "By", "Bz", "Jx", "Jy", "Jz", "Rho"]

+
+
+

A list of fields among:

+
    +
  • the electric field components "Ex", "Ey", "Ez"

  • +
  • the magnetic field components "Bx", "By", "Bz"

  • +
  • the Poynting vector components "PoyX", "PoyY", "PoyZ"

  • +
  • the current density components "Jx", "Jy", "Jz" and density "Rho"

  • +
  • the current density "Jx_abc", "Jy_abc", "Jz_abc" and density "Rho_abc" +of a given species named "abc"

  • +
+

In the case of an envelope model for the laser (see Laser envelope model), +the following fields are also available: "Env_Chi", "Env_A_abs", "Env_E_abs", "Env_Ex_abs". +They are respectively the susceptibility, the envelope of the laser transverse vector potential, +the envelope of the laser transverse electric field and the envelope of the laser longitudinal +electric field.

+

If the B-TIS3 interpolation scheme is activated (see PIC algorithms), +the following fields are also available: "ByBTIS3", "BzBTIS3".

+
+ +
+
+time_integral
+
+
Default
+

False

+
+
+

If True, the output is integrated over time. As this option forces field interpolation +at every timestep, it is recommended to use few probe points.

+
+ +
+
+datatype
+
+
Default
+

"double"

+
+
+

The data type when written to the HDF5 file. Accepts "double" (8 bytes) or "float" (4 bytes).

+
+ +

Examples of probe diagnostics

+
    +
  • 0-D probe in 1-D simulation

    +
    DiagProbe(
    +    every = 1,
    +    origin = [1.2]
    +)
    +
    +
    +
  • +
  • 1-D probe in 1-D simulation

    +
    DiagProbe(
    +    every = 1,
    +    origin  = [1.2],
    +    corners = [[5.6]],
    +    number  = [100]
    +)
    +
    +
    +
  • +
  • 1-D probe in 2-D simulation

    +
    DiagProbe(
    +    every = 1,
    +    origin  = [1.2, 4.],
    +    corners = [[5.6, 4.]],
    +    number  = [100]
    +)
    +
    +
    +
  • +
  • 2-D probe in 2-D simulation

    +
    DiagProbe(
    +    every = 1,
    +    origin   = [0., 0.],
    +    corners  = [ [10.,0.], [0.,10.] ],
    +    number   = [100, 100]
    +)
    +
    +
    +
  • +
+
+
+
+

ParticleBinning diagnostics

+

A particle binning diagnostic collects data from the macro-particles and processes them during runtime. +It does not provide information on individual particles: instead, it produces +averaged quantities like the particle density, currents, etc.

+

The data is discretized inside a “grid” chosen by the user. This grid may be of any dimension.

+

Examples:

+
    +
  • 1-dimensional grid along the position \(x\) (gives density variation along \(x\))

  • +
  • 2-dimensional grid along positions \(x\) and \(y\) (gives density map)

  • +
  • 1-dimensional grid along the velocity \(v_x\) (gives the velocity distribution)

  • +
  • 2-dimensional grid along position \(x\) and momentum \(p_x\) (gives the phase-space)

  • +
  • 1-dimensional grid along the kinetic energy \(E_\mathrm{kin}\) (gives the energy distribution)

  • +
  • 3-dimensional grid along \(x\), \(y\) and \(E_\mathrm{kin}\) (gives the density map for several energies)

  • +
  • 1-dimensional grid along the charge \(Z^\star\) (gives the charge distribution)

  • +
  • 0-dimensional grid (simply gives the total integrated particle density)

  • +
+

Each dimension of the grid is called “axis”.

+

You can add a particle binning diagnostic by including a block DiagParticleBinning() in the namelist, +for instance:

+
DiagParticleBinning(
+    #name = "my binning",
+    deposited_quantity = "weight",
+    every = 5,
+    time_average = 1,
+    species = ["electrons1", "electrons2"],
+    axes = [
+        ["x", 0., 10, 100],
+        ["ekin", 0.1, 100, 1000, "logscale", "edge_inclusive"]
+    ]
+)
+
+
+
+
+name
+

Optional name of the diagnostic. Used only for post-processing purposes.

+
+ +
+
+deposited_quantity
+

The type of data that is summed in each cell of the grid. +Consider reading this to understand the meaning of the weight.

+
    +
  • "weight" results in a number density.

  • +
  • "weight_charge" results in a charge density.

  • +
  • "weight_charge_vx" results in the \(j_x\) current density (same with \(y\) and \(z\)).

  • +
  • "weight_p" results in the momentum density (same with \(p_x\), \(p_y\) and \(p_z\)).

  • +
  • "weight_ekin" results in the energy density.

  • +
  • "weight_vx_px" results in the xx pressure (same with yy, zz, xy, yz and xz).

  • +
  • "weight_chi" results in the quantum parameter density (only for species with radiation losses).

  • +
  • with a user-defined python function, an arbitrary quantity can be calculated (the numpy +module is necessary). This function should take one argument, for instance +particles, which contains the attributes x, y, z, px, py, +pz, charge, weight, chi and id (additionally, it may also have the +attributes Ex, Bx, Ey, and so on, depending on keep_interpolated_fields). +Each of these attributes is a numpy array +containing the data of all particles in one patch. The function must return a numpy +array of the same shape, containing the desired deposition of each particle. For example, +defining the following function:

    +
    def stuff(particles):
    +    return particles.weight * particles.px
    +
    +
    +

    passed as deposited_quantity=stuff, the diagnostic will sum the weights +\(\times\; p_x\).

    +

    You may also pass directly an implicit (lambda) function using:

    +
    deposited_quantity = lambda p: p.weight * p.px
    +
    +
    +
  • +
+
+ +
+
+every
+

The number of time-steps between each output, or a time selection.

+
+ +
+
+flush_every
+
+
Default
+

1

+
+
+

Number of timesteps or a time selection.

+

When flush_every coincides with every, the output +file is actually written (“flushed” from the buffer). Flushing +too often can dramatically slow down the simulation.

+
+ +
+
+time_average
+
+
Default
+

1

+
+
+

The number of time-steps during which the data is averaged before output.

+
+ +
+
+species
+

A list of one or several species’ name. +All these species are combined into the same diagnostic.

+
+ +
+
+axes
+

A list of axes that define the grid. +There may be as many axes as wanted (there may be zero axes).

+

Syntax of one axis: [type, min, max, nsteps, "logscale", "edge_inclusive"]

+
    +
  • type is one of:

    +
      +
    • "x", "y", "z": spatial coordinates ("moving_x" with a moving window)

    • +
    • "px", "py", "pz", "p": momenta

    • +
    • "vx", "vy", "vz", "v": velocities

    • +
    • "gamma", "ekin": energies

    • +
    • "chi": quantum parameter

    • +
    • "charge": the particles’ electric charge

    • +
    • or a python function with the same syntax as the deposited_quantity. +Namely, this function must accept one argument only, for instance particles, +which holds the attributes x, y, z, px, py, pz, charge, +weight and id. Each of these attributes is a numpy array containing the +data of all particles in one patch. The function must return a numpy array of +the same shape, containing the desired quantity of each particle that will decide +its location in the histogram binning.

    • +
    +
  • +
  • The axis is discretized for type from min to max in nsteps bins.

  • +
  • The min and max may be set to "auto" so that they are automatically +computed from all the particles in the simulation. This option can be bad for performances.

  • +
  • The optional keyword logscale sets the axis scale to logarithmic instead of linear +(bins become uneven).

  • +
  • The optional keyword edge_inclusive includes the particles outside the range +[min, max] into the extrema bins.

  • +
+
+ +

Examples of particle binning diagnostics

+
    +
  • Variation of the density of species electron1 +from \(x=0\) to 1, every 5 time-steps, without time-averaging

    +
    DiagParticleBinning(
    +    deposited_quantity = "weight",
    +    every = 5,
    +    time_average = 1,
    +    species = ["electron1"],
    +    axes = [ ["x",    0.,    1.,    30] ]
    +)
    +
    +
    +
  • +
  • Density map from \(x=0\) to 1, \(y=0\) to 1

    +
    DiagParticleBinning(
    +    deposited_quantity = "weight",
    +    every = 5,
    +    time_average = 1,
    +    species = ["electron1"],
    +    axes = [ ["x",    0.,    1.,    30],
    +             ["y",    0.,    1.,    30] ]
    +)
    +
    +
    +
  • +
  • Velocity distribution from \(v_x = -0.1\) to \(0.1\)

    +
    DiagParticleBinning(
    +    deposited_quantity = "weight",
    +    every = 5,
    +    time_average = 1,
    +    species = ["electron1"],
    +    axes = [ ["vx",   -0.1,    0.1,    100] ]
    +)
    +
    +
    +
  • +
  • Phase space from \(x=0\) to 1 and from \(px=-1\) to 1

    +
    DiagParticleBinning(
    +    deposited_quantity = "weight",
    +    every = 5,
    +    time_average = 1,
    +    species = ["electron1"],
    +    axes = [ ["x",    0.,    1.,    30],
    +             ["px",   -1.,   1.,    100] ]
    +)
    +
    +
    +
  • +
  • Energy distribution from 0.01 to 1 MeV in logarithmic scale. +Note that the input units are \(m_ec^2 \sim 0.5\) MeV

    +
    DiagParticleBinning(
    +    deposited_quantity = "weight",
    +    every = 5,
    +    time_average = 1,
    +    species = ["electron1"],
    +    axes = [ ["ekin",    0.02,    2.,   100, "logscale"] ]
    +)
    +
    +
    +
  • +
  • \(x\)-\(y\) density maps for three bands of energy: \([0,1]\), \([1,2]\), \([2,\infty]\). +Note the use of edge_inclusive to reach energies up to \(\infty\)

    +
    DiagParticleBinning(
    +    deposited_quantity = "weight",
    +    every = 5,
    +    time_average = 1,
    +    species = ["electron1"],
    +    axes = [ ["x",    0.,    1.,    30],
    +             ["y",    0.,    1.,    30],
    +             ["ekin", 0.,    6.,    3,  "edge_inclusive"] ]
    +)
    +
    +
    +
  • +
  • Charge distribution from \(Z^\star =0\) to 10

    +
    DiagParticleBinning(
    +    deposited_quantity = "weight",
    +    every = 5,
    +    time_average = 1,
    +    species = ["electron1"],
    +    axes = [ ["charge",    -0.5,   10.5,   11] ]
    +)
    +
    +
    +
  • +
+
+
+
+

Screen diagnostics

+

A screen collects data from the macro-particles when they cross a surface. +It processes this data similarly to the particle binning diagnostics +as it makes a histogram of the macro-particle properties. The only difference is +that the histogram is made only by the particles that cross the surface.

+

You can add a screen by including a block DiagScreen() in the namelist, +for instance:

+
DiagScreen(
+    #name = "my screen",
+    shape = "plane",
+    point = [5., 10.],
+    vector = [1., 0.],
+    direction = "canceling",
+    deposited_quantity = "weight",
+    species = ["electron"],
+    axes = [["a", -10.*l0, 10.*l0, 40],
+            ["px", 0., 3., 30]],
+    every = 10
+)
+
+
+
+
+name
+

Optional name of the diagnostic. Used only for post-processing purposes.

+
+ +
+
+shape
+

The shape of the screen surface: "plane", "sphere", or "cylinder".

+
+ +
+
+point
+
+
Type
+

A list of floats [X] in 1D, [X,Y] in 2D, [X,Y,Z] in 3D

+
+
+

The coordinates of a point that defines the screen surface: +a point of the "plane", the center of the "sphere", +or a point on the "cylinder" axis.

+
+ +
+
+vector
+
+
Type
+

A list of floats [X] in 1D, [X,Y] in 2D, [X,Y,Z] in 3D

+
+
+

The coordinates of a vector that defines the screen surface: +the normal to the "plane", a radius of the "sphere". +or the axis of the "cylinder" (in the latter case, the vector +norm defines the cylinder radius).

+
+ +
+
+direction
+
+
Default
+

"both"

+
+
+

Determines how particles are counted depending on which side of the screen they come from.

+
    +
  • "both" to account for both sides.

  • +
  • "forward" for only the ones in the direction of the vector.

  • +
  • "backward" for only the ones in the opposite direction.

  • +
  • "canceling" to count negatively the ones in the opposite direction.

  • +
+
+ +
+
+deposited_quantity
+

Identical to the deposited_quantity of particle binning diagnostics.

+
+ +
+
+every
+

The number of time-steps between each output, or a time selection.

+
+ +
+
+flush_every
+
+
Default
+

1

+
+
+

Number of timesteps or a time selection.

+

When flush_every coincides with every, the output +file is actually written (“flushed” from the buffer). Flushing +too often can dramatically slow down the simulation.

+
+ +
+
+species
+

A list of one or several species’ name. +All these species are combined into the same diagnostic.

+
+ +
+
+axes
+

A list of “axes” that define the grid of the histogram. +It is identical to that of particle binning diagnostics, with the +addition of four types of axes:

+
    +
  • If shape="plane", then "a" and "b" are the axes perpendicular to the vector.

  • +
  • If shape="sphere", then "theta" and "phi" are the angles with respect to the vector.

  • +
  • If shape="cylinder", then "a" is along the cylinder axis and "phi" is the angle around it.

  • +
+
+ +
+
+
+

RadiationSpectrum diagnostics

+

A radiation spectrum diagnostic computes (at a given time) the instantaneous +power spectrum following from the incoherent emission of high-energy +photons by accelerated charge (see High-energy photon emission & radiation reaction for more details +on the emission process and its implementation in Smilei).

+

It is similar to the particle binning diagnostics, +with an extra axis of binning: the emitted photon energy. +The other axes remain available to the user.

+

A radiation spectrum diagnostic is defined by a block RadiationSpectrum():

+
DiagRadiationSpectrum(
+    #name = "my radiation spectrum",
+    every = 5,
+    flush_every = 1,
+    time_average = 1,
+    species = ["electrons1", "electrons2"],
+    photon_energy_axis = [0., 1000., 100, 'logscale'],
+    axes = []
+)
+
+
+
+
+name
+

Optional name of the diagnostic. Used only for post-processing purposes.

+
+ +
+
+every
+

The number of time-steps between each output, or a time selection.

+
+ +
+
+flush_every
+
+
Default
+

1

+
+
+

Number of timesteps or a time selection.

+

When flush_every coincides with every, the output +file is actually written (“flushed” from the buffer). Flushing +too often can dramatically slow down the simulation.

+
+ +
+
+time_average
+
+
Default
+

1

+
+
+

The number of time-steps during which the data is averaged before output.

+
+ +
+
+species
+

A list of one or several species’ name that emit the radiation. +All these species are combined into the same diagnostic.

+
+ +
+
+photon_energy_axis
+

The axis of photon energies (in units of \(m_e c^2\)). +The syntax is similar to that of +particle binning diagnostics.

+

Syntax: [min, max, nsteps, "logscale"]

+
+ +
+
+axes
+

An additional list of “axes” that define the grid. +There may be as many axes as wanted (there may be zero axes). +Their syntax is the same that for “axes” of a +particle binning diagnostics.

+
+ +

Examples of radiation spectrum diagnostics

+
    +
  • Time-integrated over the full duration of the simulation:

    +
    DiagRadiationSpectrum(
    +    every = Nt,
    +    time_average = Nt,
    +    species = ["electrons"],
    +    photon_energy_axis = [0., 1000., 100, 'logscale'],
    +    axes = []
    +)
    +
    +
    +
  • +
  • Angularly-resolved instantaneous radiation spectrum. +The diagnostic considers that all electrons emit radiation in +the direction of their velocity:

    +
    from numpy import arctan2, pi
    +
    +def angle(p):
    +    return arctan2(p.py,p.px)
    +
    +DiagRadiationSpectrum(
    +    every = 10,
    +    species = ["electrons"],
    +    photon_energy_axis = [0., 1000., 100, 'logscale'],
    +    axes = [
    +        [angle,-pi,pi,90]
    +    ]
    +)
    +
    +
    +
  • +
+
+
+
+

TrackParticles diagnostics

+

A particle tracking diagnostic records the macro-particle positions and momenta at various timesteps. +Typically, this is used for plotting trajectories.

+

You can add a tracking diagnostic by including a block DiagTrackParticles() in the namelist, +for instance:

+
DiagTrackParticles(
+    species = "electron",
+    every = 10,
+#    flush_every = 100,
+#    filter = my_filter,
+#    attributes = ["x", "px", "py", "Ex", "Ey", "Bz"]
+)
+
+
+
+
+species
+

The name of the species to be tracked.

+
+ +
+
+every
+
+
Default
+

0

+
+
+

Number of timesteps between each output of particles trajectories, or a time selection. +If non-zero, the particles positions will be tracked and written in a file named TrackParticlesDisordered_abc.h5 +(where abc is the species’ name).

+
+ +
+
+flush_every
+
+
Default
+

1

+
+
+

Number of timesteps or a time selection.

+

When flush_every coincides with every, the output +file for tracked particles is actually written (“flushed” from the buffer). Flushing +too often can dramatically slow down the simulation.

+
+ +
+
+filter
+

A python function giving some condition on which particles are tracked. +If none provided, all particles are tracked. +To use this option, the numpy package must +be available in your python installation.

+

The function must have one argument, that you may call, for instance, particles. +This object has several attributes x, y, z, px, py, pz, charge, +weight and id (additionally, it may also have the +attributes Ex, Bx, Ey, and so on, depending on keep_interpolated_fields). +Each of these attributes +are provided as numpy arrays where each cell corresponds to one particle. +The function must return a boolean numpy array of the same shape, containing True +for particles that should be tracked, and False otherwise.

+

The following example selects all the particles that verify \(-1<p_x<1\) +or \(p_z>3\):

+
def my_filter(particles):
+    return (particles.px>-1.)*(particles.px<1.) + (particles.pz>3.)
+
+
+
+ +
+

Warning

+

The px, py and pz quantities are not exactly the momenta. +They are actually the velocities multiplied by the lorentz factor, i.e., +\(\gamma v_x\), \(\gamma v_y\) and \(\gamma v_z\). This is true only +inside the filter function (not for the output of the diagnostic).

+
+
+

Note

+

The id attribute contains the particles identification number. +This number is set to 0 at the beginning of the simulation. Only after particles have +passed the filter, they acquire a positive id.

+
+
+

Note

+

For advanced filtration, Smilei provides the quantity Main.iteration, +accessible within the filter function. Its value is always equal to the current +iteration number of the PIC loop. The current time of the simulation is thus +Main.iteration * Main.timestep.

+
+
+
+attributes
+
+
Default
+

["x","y","z","px","py","pz","w"]

+
+
+

A list of strings indicating the particle attributes to be written in the output. +The attributes may be the particles’ spatial coordinates ("x", "y", "z"), +their momenta ("px", "py", "pz"), their electrical charge ("q"), +their statistical weight ("w"), their quantum parameter +("chi", only for species with radiation losses) or the fields interpolated +at their positions ("Ex", "Ey", "Ez", "Bx", "By", "Bz").

+
+ +
+
+
+

NewParticles diagnostics

+

A new-particle diagnostic records the macro-particle information only at the time when +they are generated by Ionization or other Physics modules.

+

You can add a new-particle diagnostic by including a block DiagNewParticles() in the namelist, +for instance:

+
DiagNewParticles(
+    species = "electron",
+    every = 10,
+#    attributes = ["x", "px", "py", "Ex", "Ey", "Bz"]
+)
+
+
+

All the arguments are identical to those of TrackParticles. +However, there are particular considerations:

+
    +
  • Although the creation of particles is recorded at every timestep, the argument every +only indicates how often the data is written to the file. It is recommended to avoid +small values of every for better performance.

  • +
  • In the case of Ionization, if the chosen species is that of the ionized electrons, +then the attribute “q” is not the charge of the electron, but the charge of the +ion, before ionization occurred.

  • +
+
+
+
+

Performances diagnostics

+

The performances diagnostic records information on the computational load and timers +for each MPI process or for each patch in the simulation.

+

Only one block DiagPerformances() may be added in the namelist, for instance:

+
DiagPerformances(
+    every = 100,
+#    flush_every = 100,
+#    patch_information = True,
+)
+
+
+
+
+every
+
+
Default
+

0

+
+
+

Number of timesteps between each output, or a time selection.

+
+ +
+
+flush_every
+
+
Default
+

1

+
+
+

Number of timesteps or a time selection.

+

When flush_every coincides with every, the output file is actually written +(“flushed” from the buffer). Flushing too often might dramatically slow down the simulation.

+
+ +
+
+patch_information
+
+
Default
+

False

+
+
+

If True, some information is calculated at the patch level (see Performances()) +but this may impact the code performances.

+
+ +
+
+
+

Time selections

+

Several components (mainly diagnostics) may require a selection of timesteps to +be chosen by the user. When one of these timesteps is reached, the diagnostics will +output data. A time selection is given through the parameter every and is a list +of several numbers.

+

You may chose between five different syntaxes:

+
every = [               period                    ] # Syntax 1
+every = [       start,  period                    ] # Syntax 2
+every = [ start,  end,  period                    ] # Syntax 3
+every = [ start,  end,  period,  repeat           ] # Syntax 4
+every = [ start,  end,  period,  repeat,  spacing ] # Syntax 5
+
+
+

where

+
    +
  • start is the first timestep of the selection (defaults to 0);

  • +
  • end is the last timestep of the selection (defaults to ∞);

  • +
  • period is the separation between outputs (defaults to 1);

  • +
  • repeat indicates how many outputs to do at each period (defaults to 1);

  • +
  • spacing is the separation between each repeat (defaults to 1).

  • +
+

For more clarity, this graph illustrates the five syntaxes for time selections:

+../_images/TimeSelections.png +
+

Tips

+
    +
  • The syntax every = period is also accepted.

  • +
  • Any value set to 0 will be replaced by the default value.

  • +
  • Special case: every=0 means no output.

  • +
  • The numbers may be non-integers (apart from repeat). The closest timesteps are chosen.

  • +
+
+
+
+
+

Checkpoints

+

The simulation state can be saved (dumped) at given times (checkpoints) +in order to be later restarted at that point.

+

A few things are important to know when you need dumps and restarts.

+
    +
  • Do not restart the simulation in the same directory as the previous one. Files will be +overwritten, and errors may occur. Create a new directory for your restarted simulation.

  • +
  • Manage your disk space: each MPI process dumps one file, and the total can be significant.

  • +
  • The restarted runs must have the same namelist as the initial simulation, except the +Checkpoints block, which can be modified.

  • +
+
Checkpoints(
+    # restart_dir = "dump1",
+    dump_step = 10000,
+    dump_minutes = 240.,
+    exit_after_dump = True,
+    keep_n_dumps = 2,
+)
+
+
+

Parameters to save the state of the current simulation

+
+
+
+dump_step
+
+
Default
+

0

+
+
+

The number of timesteps between each dump. +If 0, no dump is done.

+
+ +
+
+dump_minutes
+
+
Default
+

0.

+
+
+

The number of minutes between each dump. +If 0., no dump is done.

+

May be used in combination with dump_step.

+
+ +
+
+exit_after_dump
+
+
Default
+

True

+
+
+

If True, the code stops after the first dump. If False, the simulation continues.

+
+ +
+
+keep_n_dumps
+
+
Default
+

2

+
+
+

This tells Smilei to keep, in the current run, only the last n dumps. +Older dumps will be overwritten.

+

The default value, 2, saves one extra dump in case of a crash during the next dump.

+
+ +
+
+file_grouping
+
+
Default
+

0 (no grouping)

+
+
+

The maximum number of checkpoint files that can be stored in one directory. +Subdirectories are created to accomodate for all files. +This is useful on filesystem with a limited number of files per directory.

+
+ +
+
+dump_deflate
+

to do

+
+ +
+

Parameters to restart from a previous simulation

+
+
+
+restart_dir
+
+
Default
+

None

+
+
+

The directory of a previous run from which Smilei should restart. +For the first run, do not specify this parameter.

+

This path must either absolute or be relative to the current directory.

+
+

Note

+

In many situations, the restarted runs will have the exact same namelist as the initial +simulation, except this restart_dir parameter, which points to the previous simulation +folder. +You can use the same namelist file, and simply add an extra argument when you launch the +restart:

+

mpirun ... ./smilei mynamelist.py "Checkpoints.restart_dir='/path/to/previous/run'"

+
+
+ +
+
+restart_number
+
+
Default
+

None

+
+
+

The number of the dump (in the previous run) that should be used for the restart. +For the first run, do not specify this parameter.

+

In a previous run, the simulation state may have been dumped several times. +These dumps are numbered 0, 1, 2, etc. until the number keep_n_dumps.

+
+ +
+
+
+
+

Variables defined by Smilei

+

Smilei passes the following variables to the python interpreter for use in the +namelist. They should not be re-defined by the user!

+
+
+smilei_mpi_rank
+

The MPI rank of the current process.

+
+ +
+
+smilei_mpi_size
+

The total number of MPI processes.

+
+ +
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/optimization_flags.html b/Use/optimization_flags.html new file mode 100644 index 000000000..d6c794729 --- /dev/null +++ b/Use/optimization_flags.html @@ -0,0 +1,689 @@ + + + + + + + + + Optimization and vectorization compilation options — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Optimization and vectorization compilation options

+

Modern and mature compilers can automatically and deeply optimize the code for specific hardware. +Optimization features can be activated and tuned using compiler flags. +Among possible optimization capabilities, we can mention loop refactoring (unrolling, reordoring, splitting, etc), inlining, vectorization, pipelining and more. +Each compiler has its own flags. +While some share a common syntax, others provide more fine tuning options for specific processors (like Fujitsu for the A64FX).

+

Some optimization flags are automatically set in the makefile; +others are specified in the machine files because they are specific to given compilers, hardwares or processor families. +SIMD vectorization in Smilei, for instance, +can be automatic, or can rely on OpenMP’s directive #pragma omp simd.

+

Options are passed to the compiler through the environment variable CXXFLAGS. +Most machine files include appropriate flags to ensure the best performance +on a given processor type using a given compiler (most often Intel but also GNU, LLVM, ARMCLANG and Fujitsu).

+

For instance, Smilei has been tested on +Intel processors (Skylake 8168) with an Intel environment. +The following flags, located in the skylake machine file, provide a good performance:

+
-xCOMMON-AVX512 -ip -ipo -inline-factor=1000 -D__INTEL_SKYLAKE_8168 -fno-alias
+
+
+

The vectorization must also be activated in the namelist.

+

The following explains the meaning of the flags commonly used in our machine files. +You can use this section to design your own machine file.

+

Intel compiler flags for optimization and vectorization

+

The following options are commonly used by Smilei’s machine files to compile on most modern x86 processors (both Intel and AMD). They enure the best performance of the code, especially for vectorization.

+
    +
  • -O3: this option directly integrated in the makefile tells the compiler to use agressive optimization at compilation

  • +
  • -march=cpu-type: Tells the compiler to generate code for processors that support certain features. See this page for more info.

  • +
  • -xCPU-TYPE: Tells the compiler which processor features it may target, including which instruction sets and optimizations it may generate. CPU-TYPE can be the instruction set or the processor family name. This option is important for vectorization. See this page for more info.

    +
    +
      +
    • -xCOMMON-AVX512: for processors that support AVX512 (Skylake, Cascadelake)

    • +
    • -xMIC-AVX512: suitable for first-generation AVX512 processors (KNL family)

    • +
    • -xCORE-AVX2: for processors using the AVX2 instruction set such as Intel Broadwell (3nd generation E3, E5 and E7 Xeon family) and AMD Epyc processors

    • +
    • -xAVX: for the first generation E3 and E5 Xeon family

    • +
    • -xSKYLAKE

    • +
    • -xKNL

    • +
    • -xBROADWELL

    • +
    • and more…

    • +
    +
    +
  • +
  • -ip: interprocedural optimizations for single-file compilation. This flag is important for function inline in a single C++ file. This option is not by default in the makefile but is available in many machine files.

  • +
  • -ipo: Interprocedural optimization, a step that examines function calls between files when the program is linked. This flag must be used to compile and when linking. Compile times are very long with this flag, however depending on the application there may be appreciable performance improvements when combined with the -O* flags. This flag is not by default in the makefile and is rarely used due to long compilation time. Use this flag for production runs if you do not plan to often recompile.

  • +
  • -inline-factor=1000: Specifies the percentage multiplier that should be applied to all inlining options that define upper limits.

  • +
  • -fno-alias: this is recommended only as an experiment, possibly to see whether a useful restrict keyword has been missed. It would mean that the compiler could ignore unproven aliasing hazards.

  • +
+

A detailed description of the available flags for x86 instruction sets is given on this page. +All Intel compiler flags are listed on this page.

+

More examples:

+
    +
  • For AMD EPYC ROME processors:

  • +
+
-march=core-avx2 -xCORE-AVX2 -ip -inline-factor=1000 -fno-alias #-ipo
+
+
+
    +
  • For Intel Broadwell processors:

  • +
+
-xCORE-AVX2 -O3 -ip -inline-factor=1000 -D__INTEL_BDW_E5_2697_V4 -fno-alias
+
+
+
    +
  • For Intel Cascadelake processors:

  • +
+
-march=cascadelake -xCOMMON-AVX512 -ip -inline-factor=1000 -D__INTEL_CASCADELAKE_6248 -qopt-zmm-usage=high -fno-alias #-ipo
+
+
+
    +
  • For Intel KNL processors:

  • +
+
-march=knl -xMIC-AVX512 -ip -inline-factor=1000 -D__INTEL_KNL_7250 -qopt-zmm-usage=high -fno-alias #-ipo
+
+
+

GNU compiler flags for optimization and vectorization

+
    +
  • -O3: this option directly integrated in the makefile tells the compiler to use agressive optimization at compilation

  • +
  • -Ofast: Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs.It can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications.

  • +
  • -mtune=cpu-type: This option specifies that GCC should tune the performance of the code as if the target were of the type specified in this option, here cpu-type.For some ARM implementations better performance can be obtained by using this option. Possible common cpu types are

    +
    +
      +
    • cascadelake

    • +
    • skylake-avx512

    • +
    • a64fx for A64FX Fujitsu processor

    • +
    • knl

    • +
    • broadwell

    • +
    • znver2 for 2nd generation AMD EPYC processors

    • +
    • znver2 for 3rd generation AMD EPYC processors

    • +
    +
    +
  • +
  • -march=cpu-type: This flag does additional tuning for specific processor types. Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise.

    +
    +
      +
    • cascadelake

    • +
    • skylake-avx512

    • +
    • sve to generate SVE instructions (vectorization on ARM like A64FX)

    • +
    • armv8.2-a to generate armv8 instructions (like A64FX)

    • +
    • knl

    • +
    • broadwell

    • +
    • znver2 for 2nd generation AMD EPYC processors

    • +
    • znver3 for 3rd generation AMD EPYC processors

    • +
    +
    +
  • +
  • -msve-vector-bits=512: Specify the number of bits in an SVE vector register on ARM architecture using SVE (useful for A64FX).

  • +
  • -ffast-math: This option is not turned on by any -O option besides -Ofast since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications.

  • +
+

Find out more information:

+ +

LLVM compiler flags for optimization and vectorization

+

The LLVM compiler shares many flags with the GNU one.

+
    +
  • -O3: this option directly integrated in the makefile tells the compiler to use agressive optimization at compilation

  • +
  • -Ofast: Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs.It can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications.

  • +
  • -mtune=cpu-type: This option specifies that LLVM should tune the performance of the code as if the target were of the type specified in this option, here cpu-type.For some ARM implementations better performance can be obtained by using this option. Possible common cpu types are

    +
    +
      +
    • cascadelake

    • +
    • skylake-avx512

    • +
    • a64fx for A64FX Fujitsu processor

    • +
    • knl

    • +
    • broadwell

    • +
    • znver2 for 2nd generation AMD EPYC processors

    • +
    • znver2 for 3rd generation AMD EPYC processors

    • +
    +
    +
  • +
  • -march=cpu-type: This flag does additional tuning for specific processor types. Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise.

    +
    +
      +
    • cascadelake

    • +
    • skylake-avx512

    • +
    • sve to generate SVE instructions (vectorization on ARM like A64FX)

    • +
    • armv8.2-a to generate armv8 instructions (like A64FX)

    • +
    • knl

    • +
    • broadwell

    • +
    • znver2 for 2nd generation AMD EPYC processors

    • +
    • znver3 for 3rd generation AMD EPYC processors

    • +
    +
    +
  • +
  • -ffast-math: Enable fast-math mode. This option lets the compiler make aggressive, potentially-lossy assumptions about floating-point math.

  • +
  • -ffinite-math-only: Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.

  • +
  • -ffp-contract=off|on|fast|fast-honor-pragmas: Specify when the compiler is permitted to form fused floating-point operations, such as fused multiply-add (FMA). Fused operations are permitted to produce more precise results than performing the same operations separately.

  • +
+

Some examples:

+
    +
  • For Intel Cascade processors:

  • +
+
-mtune=cascadelake -march=cascadelake -ffinite-math-only -ffp-contract=fast
+
+
+
    +
  • For the A64FX processor:

  • +
+
-march=armv8.2-a+sve -ffinite-math-only -fsimdmath -fopenmp-simd -ffp-contract=fast #-ffast-math
+
+
+

Find out more information:

+ +

Fujitsu compiler flags for optimization and vectorization

+

Fujitsu compiler is only used or the A64FX processor so far. +The compiler can work in two differents modes called Trad and Clang mode. +The Clang mode uses the Clang compilation flags. +The Trad moe is usually the default one, the Clang mode an be activated using the flag -Nclang.

+
    +
  • -O3 (bothy in Trad and clang mode): by default in the makefile

  • +
  • -Kfast (in Trad mode) / -Ofast (in Clang mode)

  • +
  • -KA64FX (in Trad mode)

  • +
  • -KSVE (in Trad mode) / -march=sve (in Clang mode)

  • +
  • -KSSL2 (in Trad mode)

  • +
  • -Kparallel (in Trad mode)

  • +
  • -Kunroll (in Trad mode)

  • +
  • -Ksimd=2 (in Trad mode)

  • +
  • -Kassume=notime_saving_compilation (in Trad mode)

  • +
  • -Kocl (in Trad mode) / -ffj-ocl (in Clang mode)

  • +
+

Smilei compiler flags for adaptive vectorization

+

Performance models are implemented in Smilei for adaptive vectorization. +By default, a general performance model is used but some performance models can be used for specific types of processors:

+
    +
  • -D__INTEL_CASCADELAKE_6248

  • +
  • -D__INTEL_SKYLAKE_8168

  • +
  • -D__AMD_ROME_7H12

  • +
  • -D__INTEL_KNL_7250: available in 3D only

  • +
  • -D__INTEL_BDW_E5_2697_V4: available in 3D only

  • +
  • -D__INTEL_HSW_E5_2680_v3: available in 3D only

  • +
+

These flags are used in the corresponding machine files.

+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/particle_initialization.html b/Use/particle_initialization.html new file mode 100644 index 000000000..1702a1154 --- /dev/null +++ b/Use/particle_initialization.html @@ -0,0 +1,546 @@ + + + + + + + + + Initialize particles from an array or a file — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Initialize particles from an array or a file

+

In the namelist, position_initialization and momentum_initialization +may be set to a numpy array or to an HDF5 file containing particle data to be imported.

+

The position initialization is incompatible with number_density, +charge_density and particles_per_cell. +Particles initialized outside of the initial simulation domain will not be created.

+

The momentum initialization is incompatible with temperature +and mean_velocity.

+
+
+

From a numpy array

+

The position_initialization may be a numpy array of shape (Ndim+1, Npart) +where Ndim is the number of particle dimensions, +and Npart is the total number of particles. +Positions components x, y, z are given along the first Ndim columns +and the weights are given in the last column of the array.

+

The momentum_initialization may be a numpy array of shape (3, Npart). +It requires that position_initialization also be an array +with the same number of particles Npart. +Momentum components px, py, pz are given in successive columns.

+
+
+
+

From an HDF5 file

+

The position_initialization may be a path to an HDF5 file containing the +appropriate data structure. The path may point to a file, +such as "some_folder/some_data.h5", but it may also contain the path +to a group inside the file, such as "some_folder/some_data.h5/group1/group2".

+

The HDF5 location must contain the following datasets, all 1-dimensional of equal size:

+
    +
  • position/x, list of x coordinates

  • +
  • position/y, list of y coordinates

  • +
  • position/z, list of z coordinates

  • +
  • weight, list of statistical weights

  • +
+

The momentum_initialization works the same way. It must be an HDF5 location +containing the following datasets, all 1-dimensional of equal size:

+
    +
  • momentum/x, list of px

  • +
  • momentum/y, list of py

  • +
  • momentum/z, list of pz

  • +
+
+

Note

+

This file structure is identical to that obtained from the TrackParticles diagnostics, +meaning that you can directly pass the output of a previous simulation, for instance +"path/to/results/TrackParticlesDisordered_myspecies.h5/data/0000003000/particles/myspecies".

+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/post-processing.html b/Use/post-processing.html new file mode 100644 index 000000000..d8d57c5d3 --- /dev/null +++ b/Use/post-processing.html @@ -0,0 +1,1722 @@ + + + + + + + + + Post-process — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ + + + +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Post-process

+

This page describes the usage of the python module happi for extracting, viewing +and post-processing simulation data. First, you need to install happi.

+

The module can be imported directly in python:

+
import happi
+
+
+
+
+

Open a simulation

+

In a python command line (or script), call the following function to open +your Smilei simulation. Note that several simulations can be opened at once, +as long as they correspond to several restarts of the same simulation.

+
+
+happi.Open(results_path='.', reference_angular_frequency_SI=None, show=True, verbose=True, scan=True, pint=True)
+
    +
  • results_path: path or list of paths to the directory-ies +where the results of the simulation-s are stored. It can also contain wildcards, +such as * and ? in order to include several simulations at once.

  • +
  • reference_angular_frequency_SI: overrides the value of the simulation parameter +reference_angular_frequency_SI, in order to re-scale units.

  • +
  • show: if False, figures will not plot on screen. Make sure that +you have not loaded another simulation or the matplotlib package. You may need to +restart python.

  • +
  • verbose: if False, less information is printed while post-processing.

  • +
  • scan: if False, HDF5 output files are not scanned initially, and the namelist is not read.

  • +
  • pint: if True, happi attempts to load the Pint package and to use it for managing units.

  • +
+
+ +
+
Returns: An object containing various methods to extract and manipulate the simulation

outputs, as described below.

+
+
+

Example:

+
S = happi.Open("path/to/my/results")
+
+
+

Once a simulation is opened, several methods are available to find information on the +namelist or open various diagnostics. Checkout the namelist documentation to find out +which diagnostics are included in Smilei: scalars, +fields, probes, +particle binning, trajectories +and performances.

+
+
+
+

Extract namelist information

+

Once a simulation is opened as shown above, you can access the content of the namelist +using the attribute namelist:

+
S = happi.Open("path/to/my/results") # Open a simulation
+print(S.namelist.Main.timestep)   # print the timestep
+print(S.namelist.Main.geometry)   # print the simulation dimensions
+
+
+

All the variables defined in the original namelist are copied into this variable.

+

Concerning components like Species, External fields or Probe diagnostics, of which +several instances may exist, you can directly iterate over them:

+
for species in S.namelist.Species:
+    print("species "+species.name+" has mass "+str(species.mass))
+
+
+

You can also access to a specific component by referencing its number:

+
F = S.namelist.ExternalField[0]  # get the first external field
+print("An external field "+F.field+" was applied")
+
+
+

In the case of the species, you can also obtain a given species by its name:

+
species = S.namelist.Species["electron1"]
+print("species "+species.name+" has mass "+str(species.mass))
+
+
+
+
+
+

Obtain diagnostic information

+

Print available diagnostics

+

Commands S.Scalar, S.Field, S.Probe (etc.) will display general information +about the corresponding diagnostics in the simulation.

+

List available diagnostics

+
+
+getDiags(diagType)
+

Returns a list of available diagnostics of the given type

+
    +
  • diagType: The diagnostic type ("Field", "Probe", etc.)

  • +
+
+ +
+
+getTrackSpecies()
+

Returns a list of available tracked species.

+
+ +

Information on specific diagnostics

+
+
+fieldInfo(diag)
+
    +
  • diag: the number or name of a Field diagnostic

  • +
+

Returns a dictionnary containing:

+
    +
  • "diagNumber": the diagnostic number

  • +
  • "diagName": the diagnostic name

  • +
  • "fields": list of the available fields in this diagnostic. In the case of +AMcylindrical geometry, this is a dictionnary with a list of modes for each field.

  • +
+
+ +
+
+probeInfo(diag)
+
    +
  • diag: the number or name of a Probe diagnostic

  • +
+

Returns a dictionnary containing:

+
    +
  • "probeNumber": the diagnostic number

  • +
  • "probeName": the diagnostic name

  • +
  • "fields": list of the available fields in this diagnostic

  • +
+
+ +
+
+performanceInfo()
+

Returns a dictionnary containing:

+
    +
  • "quantities_uint": a list of the available integer quantities

  • +
  • "quantities_double": a list of the available float quantities

  • +
  • "patch_arrangement": the type of patch arrangement

  • +
  • "timesteps": the list of timesteps

  • +
+
+ +
+
+
+

Open a Scalar diagnostic

+
+
+Scalar(scalar=None, timesteps=None, units=[''], data_log=False, data_transform=None, **kwargs)
+
    +
  • +
    scalar: The name of the scalar.
    +
    If not given, then a list of available scalars is printed.
    +
    +
    +
    +
  • +
  • +
    timesteps: The requested timestep(s).
    +
    If omitted, all timesteps are used.
    +
    If one number given, the nearest timestep available is used.
    +
    If two numbers given, all the timesteps in between are used.
    +
    +
    +
    +
  • +
  • units: A unit specification (see Specifying units)

  • +
  • +
    data_log:
    +
    If True, then \(\log_{10}\) is applied to the output.
    +
    +
    +
    +
  • +
  • +
    data_transform:
    +
    If this is set to a function, the function is applied to the output before plotting.
    +
    +
    +
    +
  • +
  • See also Other arguments for diagnostics

  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+Diag = S.Scalar("Utot")
+
+
+
+
+
+

Open a Field diagnostic

+
+
+Field(diagNumber=None, field=None, timesteps=None, subset=None, average=None, units=[''], data_log=False, data_transform=None, moving=False, export_dir=None, **kwargs)
+
    +
  • timesteps, units, data_log, data_transform: same as before.

  • +
  • +
    diagNumber: number or name of the fields diagnostic
    +
    If not given, then a list of available diagnostic numbers is printed.
    +
    +
    +
    +
  • +
  • +
    field: The name of a field ("Ex", "Ey", etc.)
    +
    If not given, then a list of available fields is printed.
    +
    The string can also be an operation between several fields, such as "Jx+Jy".
    +
    +
    +
    +
  • +
  • +
    subset: A selection of coordinates to be extracted.
    +
    Syntax 1: subset = { axis : location, ... }
    +
    Syntax 2: subset = { axis : [start, stop] , ... }
    +
    Syntax 3: subset = { axis : [start, stop, step] , ... }
    +
    axis must be "x", "y" , "z" or "r".
    +
    Only the data within the chosen axes’ selections is extracted.
    +
    WARNING: THE VALUE OF step IS A NUMBER OF CELLS.
    +
    Example: subset = {"y":[10, 80, 4]}
    +
    +
    +
    +
  • +
  • +
    average: A selection of coordinates on which to average.
    +
    Syntax 1: average = { axis : "all", ... }
    +
    Syntax 2: average = { axis : location, ... }
    +
    Syntax 3: average = { axis : [start, stop] , ... }
    +
    axis must be "x", "y" , "z" or "r".
    +
    The chosen axes will be removed:
    +
    - With syntax 1, an average is performed over all the axis.
    +
    - With syntax 2, only the bin closest to location is kept.
    +
    - With syntax 3, an average is performed from start to stop.
    +
    Example: average = {"x":[4,5]} will average for \(x\) within [4,5].
    +
    +
    +
    +
  • +
  • moving: If True, plots will display the X coordinates evolving according to the +moving window

  • +
  • export_dir: The directory where to export VTK files.

  • +
  • See also Other arguments for diagnostics

  • +
+

In the case of an azimuthal mode cylindrical geometry (AMcylindrical), additional argument are +available. You must choose one of theta or build3d, defined below, in order +to construct fields from their complex angular Fourier modes. In addition, the modes +argument is optional.

+
    +
  • +
    theta: An angle (in radians)
    +
    Calculates the field in a plane passing through the \(r=0\) axis
    +
    and making an angle theta with the \(xy\) plane.
    +
    +
    +
    +
  • +
  • +
    build3d: A list of three ranges
    +
    Calculates the field interpolated in a 3D \(xyz\) grid.
    +
    Each range is a list [start, stop, step] indicating the beginning,
    +
    the end and the step of this grid.
    +
    +
    +
    +
  • +
  • +
    modes: An integer or a list of integers
    +
    Only these modes numbers will be used in the calculation. If omited, all modes are used.
    +
    +
    +
    +
  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+Diag = S.Field(0, "Ex", average = {"x":[4,5]}, theta=math.pi/4.)
+
+
+
+
+
+

Open a Probe diagnostic

+
+
+Probe(probeNumber=None, field=None, timesteps=None, subset=None, average=None, units=[''], data_log=False, data_transform=None, **kwargs)
+
    +
  • timesteps, units, data_log, data_transform, export_dir: same as before.

  • +
  • +
    probeNumber: number or name of the probe (the first one has number 0).
    +
    If not given, a list of available probes is printed.
    +
    +
    +
    +
  • +
  • +
    field: name of the field ("Bx", "By", "Bz", "Ex", "Ey", "Ez", "Jx", "Jy", "Jz" or "Rho").
    +
    If not given, a list of available fields is printed.
    +
    The string can also be an operation between several fields, such as "Jx+Jy".
    +
    +
    +
    +
  • +
  • subset and average are very similar to those of Field(), but they can only have the axes: "axis1", "axis2" and "axis3". +For instance, average={"axis1":"all"}. Note that the axes are not necessarily \(x\), \(y\) or \(z\) because the probe mesh is arbitrary.

  • +
  • See also Other arguments for diagnostics

  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+Diag = S.Probe(0, "Ex")
+
+
+
+
+Probe.changeField(field)
+

In cases where happi’s performance is an issue, it is possible to switch between different fields +of an open Probe diagnostic using this method. The field argument is the same as in Probe(...) above.

+
+ +
+
+
+

Open a ParticleBinning diagnostic

+
+
+ParticleBinning(diagNumber=None, timesteps=None, subset=None, average=None, units=[''], data_log=False, data_transform=None, **kwargs)
+
    +
  • timesteps, units, data_log, data_transform, export_dir: same as before.

  • +
  • +
    diagNumber: number or name of the particle binning diagnostic (starts at 0).
    +
    If not given, a list of available diagnostics is printed.
    +
    It can also be an operation between several diagnostics.
    +
    For example, "#0/#1" computes the division by diagnostics 0 and 1.
    +
    +
    +
    +
  • +
  • +
    subset is similar to that of Field(), although the axis must be one of

    "x", "y", "z", "px", "py", "pz", "p", "gamma", "ekin", "vx", "vy", "vz", "v" or "charge".

    +

    WARNING: With the syntax subset={axis:[start, stop, step]}, the value of step +is a number of bins.

    +
    +
    +
  • +
  • +
    average: a selection of coordinates on which to average the data.
    +
    Syntax 1: average = { axis : "all", ... }
    +
    Syntax 2: average = { axis : location, ... }
    +
    Syntax 3: average = { axis : [begin, end] , ... }
    +
    +

    axis must be "x", "y", "z", "px", "py", "pz", "p", "gamma", "ekin", "vx", "vy", "vz", "v" or "charge".

    +
    +
    The chosen axes will be removed:
    +
    - With syntax 1, an average is performed over all the axis.
    +
    - With syntax 2, only the bin closest to location is kept.
    +
    - With syntax 3, an average is performed between begin and end.
    +
    Example: average={"x":[4,5]} will average all the data for x within [4,5].
    +
    +
    +
    +
  • +
  • See also Other arguments for diagnostics

  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+Diag = S.ParticleBinning(1)
+
+
+

Units of the results:

+
+

The raw quantity stored in the output file has the units of the deposited_quantity. +Generally, this is a sum of macro-particle weights. As those weights +are not in units of density (but of density multiplied by hypervolume), a correction +is applied in happi: it divides the data by an hypervolume. More precisely, +for each direction x, y or z, if this direction is not included in one of +the diagnostic’s axes, happi divides by the length of the box in that direction.

+

In addition, in order to make the units relative to the bin size, happi divides the data +in each bin by the bin size.

+
+
+
+
+

Open a Screen diagnostic

+
+
+Screen(diagNumber=None, timesteps=None, subset=None, average=None, units=[''], data_log=False, data_transform=None, **kwargs)
+
    +
  • timesteps, units, data_log, data_transform, export_dir: same as before.

  • +
  • diagNumber, subset and average: identical to that of ParticleBinning diagnostics.

  • +
  • See also Other arguments for diagnostics

  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+Diag = S.Screen(0)
+
+
+
+
+
+

Open a RadiationSpectrum diagnostic

+
+
+ParticleBinning(diagNumber=None, timesteps=None, subset=None, average=None, units=[''], data_log=False, data_transform=None, **kwargs)
+
    +
  • timesteps, units, data_log, data_transform, export_dir: same as before.

  • +
  • diagNumber, subset and average: identical to that of ParticleBinning diagnostics.

  • +
  • See also Other arguments for diagnostics

  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+Diag = S.RadiationSpectrum(0)
+
+
+
+

Note

+

The resulting spectral power is in units of \(\omega_r\). +If additional axes are used, the power spectrum is divided by the size of the bins of each axes.

+
+
+
+
+

Open a TrackParticles diagnostic

+
+
+TrackParticles(species=None, select='', axes=[], timesteps=None, sort=True, length=None, units=[''], **kwargs)
+
    +
  • timesteps, units, export_dir: same as before.

  • +
  • species: the name of a tracked-particle species. +If omitted, a list of available tracked-particle species is printed.

  • +
  • select: Instructions for selecting particles among those available. +A detailed explanation is provided below

  • +
  • +
    axes: A list of axes for plotting the trajectories or obtaining particle data.

    Each axis is one of the attributes defined in the namelist. +In addition, when there is a moving window, the axis "moving_x" is automatically available.

    +
    +
    Example: axes = ["x"] corresponds to \(x\) versus time.
    +
    Example: axes = ["x","y"] correspond to 2-D trajectories.
    +
    Example: axes = ["x","px"] correspond to phase-space trajectories.
    +
    +
    +
    +
  • +
  • sort: may be either

    +
      +
    • False: the particles are not sorted by ID. This can save significant +time, but prevents plotting, exporting to VTK, and the select argument. Only +getData and iterParticles are available in this mode. +Read this for more information on particle IDs.

    • +
    • True: the particles are sorted in a new file, unless this file already exists. +If it does, sorted particles are directly read from the sorted file.

    • +
    • A string for selecting particles (same syntax as select): only selected +particles are sorted in a new file. The file name must be defined +in the argument sorted_as. If timesteps is used, only selected timesteps +will be included in the created file.

    • +
    +
  • +
  • sorted_as: a keyword that defines the new sorted file name (when sort is a +selection) or refers to a previously user-defined sorted file name (when sort is not given).

  • +
  • length: The length of each plotted trajectory, in number of timesteps.

  • +
  • See also Other arguments for diagnostics

  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+Diag = S.TrackParticles("electrons", axes=["px","py"])
+
+
+

Detailed explanation of the select parameter

+
+
Say times is a condition on timesteps t, for instance t>50.
+
Say condition is a condition on particles properties (x, y, z, px, py, pz), for instance px>0.
+
+
    +
  • +
    Syntax 1: select="any(times, condition)"
    +
    Selects particles satisfying condition for at least one of the times.
    +
    For example, select="any(t>0, px>1.)" selects those reaching \(p_x>1\) at some point.
    +
    +
  • +
  • +
    Syntax 2: select="all(times, condition)"
    +
    Selects particles satisfying condition at all times.
    +
    For example, select="all(t<40, px<1)" selects those having \(p_x<1\) until timestep 40.
    +
    +
  • +
  • +
    Syntax 3: select=[ID1, ID2, ...]
    +
    Selects the provided particle IDs.
    +
    +
  • +
  • +
    It is possible to make logical operations: + is OR; * is AND; ~ is NOT.
    +
    For example, select="any((t>30)*(t<60), px>1) + all(t>0, (x>1)*(x<2))"
    +
    +
  • +
+
+
+
+

Open a NewParticles diagnostic

+
+
+NewParticles(species=None, select='', axes=[], units=[''], **kwargs)
+
    +
  • units: same as before.

  • +
  • species: same as for TrackParticles

  • +
  • axes: same as for TrackParticles, with the addition of another axis t +that represents the time when the particle was born.

  • +
  • select: Instructions for selecting particles among those available. +It must be a condition on particles properties axes, for instance px>0. +It is possible to make logical operations: + is OR; * is AND; ~ is NOT.

    +
    +
    Example: select="(x>1)*(x<2)"
    +
    +

    It is also possible to select directly a list of IDs.

    +
    +
    Example: select=[ID1, ID2, ...]
    +
    +
  • +
+
+ +
+
+
+

Open a Performances diagnostic

+

The post-processing of the performances diagnostic may be achieved in three different +modes: raw, map, or histogram, described further below. You must choose one +and only one mode between those three.

+
+
+Performances(raw=None, map=None, histogram=None, timesteps=None, units=[''], data_log=False, data_transform=None, species=None, cumulative=True, **kwargs)
+
    +
  • timesteps, units, data_log, data_transform, export_dir: same as before.

  • +
  • raw: The name of a quantity, or an operation between them (see quantities below). +The requested quantity is listed for each process.

  • +
  • map: The name of a quantity, or an operation between them (see quantities below). +The requested quantity is mapped vs. space coordinates (1D and 2D only).

  • +
  • histogram: the list ["quantity", min, max, nsteps]. +Makes a histogram of the requested quantity between min an max, with nsteps bins. +The "quantity" may be an operation between the quantities listed further below.

  • +
  • cumulative: may be True for timers accumulated for the duration of the simulation, +or False for timers reset to 0 at each output.

  • +
  • See also Other arguments for diagnostics

  • +
+
+ +

Quantities at the MPI-process level (contain many patches):

+
+
    +
  • hindex : the starting index of each proc in the hilbert curve

  • +
  • number_of_cells : the number of cells in each proc

  • +
  • number_of_particles : the total number of non-frozen macro-particles in each proc (includes all species)

  • +
  • number_of_frozen_particles : the number of frozen particles in each proc

  • +
  • total_load : the load of each proc (number of macro-particles and cells weighted by cell_load coefficients)

  • +
  • timer_global : global simulation time (only available for proc 0)

  • +
  • timer_particles : time spent computing particles by each proc

  • +
  • timer_maxwell : time spent solving maxwell by each proc

  • +
  • timer_envelope : time spent solving the envelope propagation by each proc

  • +
  • timer_densities : time spent projecting densities by each proc

  • +
  • timer_collisions : time spent computing collisions by each proc

  • +
  • timer_movWindow : time spent handling the moving window by each proc

  • +
  • timer_loadBal : time spent balancing the load by each proc

  • +
  • timer_partMerging : time spent merging particles by each proc

  • +
  • timer_syncPart : time spent synchronzing particles by each proc

  • +
  • timer_syncField : time spent synchronzing fields by each proc

  • +
  • timer_syncDens : time spent synchronzing densities by each proc

  • +
  • timer_syncSusceptibility : time spent synchronzing susceptibility by each proc

  • +
  • timer_diags : time spent by each proc calculating and writing diagnostics

  • +
  • timer_total : the sum of all timers above (except timer_global)

  • +
  • memory_total : the total memory (RSS) used by the process in GB

  • +
  • memory_peak : the peak memory (peak RSS) used by the process in GB

  • +
+

WARNING: The timers loadBal and diags include global communications. +This means they might contain time doing nothing, waiting for other processes. +The sync*** timers contain proc-to-proc communications, which also represents +some waiting time.

+
+

Quantities at the patch level:

+
+

This requires patch_information in the namelist.

+
    +
  • mpi_rank : the MPI rank that contains the current patch

  • +
  • vecto : the mode of the specified species in the current patch +(vectorized of scalar) when the adaptive mode is activated. Here the species argument has to be specified.

  • +
+

WARNING: The patch quantities are only compatible with the raw mode +and only in 3Dcartesian geometry. The result is a patch matrix with the +quantity on each patch.

+
+

Example: performance diagnostic at the MPI level:

+
S = happi.Open("path/to/my/results")
+Diag = S.Performances(map="total_load")
+
+
+

Example: performance diagnostic at the patch level:

+
S = happi.Open("path/to/my/results")
+Diag = S.Performances(raw="vecto", species="electron")
+
+
+
+
+
+

Specifying units

+

By default, all the diagnostics data is in code units (see Units).

+

To change the units, all the methods Scalar(), +Field(), Probe(), +ParticleBinning() and +TrackParticles() support a units argument. +It has three different syntaxes:

+
    +
  1. A list, for example units = ["um/ns", "feet", "W/cm^2"]

    +

    In this case, any quantity found to be of the same dimension as one of these units +will be converted.

    +
  2. +
  3. A dictionary, for example units = {"x":"um", "y":"um", "v":"Joule"}

    +

    In this case, we specify the units separately for axes x and y, and for the +data values v.

    +
  4. +
  5. A Units object, for example units = happi.Units("um/ns", "feet", x="um")

    +

    This version combines the two previous ones.

    +
  6. +
+

Requirements for changing units

+
    +
  • The Pint module.

  • +
  • To obtain units in a non-normalized system (e.g. SI), the simulation must have the +parameter reference_angular_frequency_SI set to a finite value. +Otherwise, this parameter can be set during post-processing as an argument to the +happi.Open() function.

  • +
+
+
+
+

Other arguments for diagnostics

+

All diagnostics above can use additional keyword arguments (kwargs) +to manipulate the plotting options:

+
    +
  • figure: The figure number that is passed to matplotlib.

  • +
  • vmin, vmax: data value limits.

  • +
  • vsym: makes data limits symmetric about 0 (vmin and vmax are ignored), +and sets the colormap to smileiD.

    +
      +
    • If vsym = True, autoscale symmetrically.

    • +
    • If vsym is a number, limits are set to [-vsym, vsym].

    • +
    +
  • +
  • xmin, xmax, ymin, ymax: axes limits.

  • +
  • xfactor, yfactor: factors to rescale axes.

  • +
  • title: a string that replaces the plot title (or the y-label in a 1D plot). +The current simulation time can be included with the placeholders {time} and +{time_units}, together with formatting instructions conforming to +python’s string formatter. +For instance: title = "Density @ $t = {time:.0f} {time_units}$".

  • +
  • side: "left" (by default) or "right" puts the y-axis on the left- +or the right-hand-side.

  • +
  • transparent: None (by default), "over", "under", "both", or a function. +The colormap becomes transparent over, under, or outside both the boundaries +set by vmin and vmax. +This argument may be set instead to a function mapping the data value \(\in [0,1]\) to the +transparency \(\in [0,1]\). For instance lambda x: 1-x.

  • +
  • Other Matplotlib arguments listed in Advanced plotting options.

  • +
+
+
+
+

Obtain the data

+
+
+Scalar.getData(timestep=None)
+
+Field.getData(timestep=None)
+
+Probe.getData(timestep=None)
+
+ParticleBinning.getData(timestep=None)
+
+Screen.getData(timestep=None)
+
+TrackParticles.getData(timestep=None)
+

Returns a list of the data arrays (one element for each timestep requested). +In the case of TrackParticles, this method returns a dictionary containing one +entry for each axis, and if sort==False, these entries are included inside an entry +for each timestep.

+
    +
  • timestep, if specified, is the only timestep number that is read and returned.

  • +
+

Example:

+
S = happi.Open("path/to/results") # Open the simulation
+Diag = S.Field(0, "Ex")       # Open Ex in the first Field diag
+result = Diag.getData()       # Get list of Ex arrays (one for each time)
+
+
+
+ +
+
+Scalar.getTimesteps()
+
+Field.getTimesteps()
+
+Probe.getTimesteps()
+
+ParticleBinning.getTimesteps()
+
+Screen.getTimesteps()
+
+TrackParticles.getTimesteps()
+

Returns a list of the timesteps requested.

+
+ +
+
+Scalar.getTimes()
+
+Field.getTimes()
+
+Probe.getTimes()
+
+ParticleBinning.getTimes()
+
+Screen.getTimes()
+
+TrackParticles.getTimes()
+

Returns the list of the times requested. +By default, times are in the code’s units, but are converted to the diagnostic’s +units defined by the units argument, if provided.

+
+ +
+
+Scalar.getAxis(axis)
+
+Field.getAxis(axis, timestep)
+
+Probe.getAxis(axis)
+
+ParticleBinning.getAxis(axis, timestep)
+
+Screen.getAxis(axis, timestep)
+

Returns the list of positions of the diagnostic data along the requested axis. +If the axis is not available, returns an empty list. +By default, axis positions are in the code’s units, but are converted to +the diagnostic’s units defined by the units argument, if provided.

+
    +
  • axis: the name of the requested axis.

    +
      +
    • For Field: this is "x", "y" or "z"

    • +
    • For Probe: this is "axis1", "axis2" or "axis3"

    • +
    • For ParticleBinning and Screen: this is the type of the axes +defined in the namelist

    • +
    +
  • +
  • timestep: The timestep at which the axis is obtained. Only matters in +ParticleBinning, Screen and RadiationSpectrum when auto axis +limits are requested; or in Field when moving=True.

  • +
+
+ +
+
+TrackParticles.iterParticles(timestep, chunksize=1)
+

This method, specific to the tracked particles, provides a fast iterator on chunks of particles +for a given timestep. The argument chunksize is the number of particles in each chunk. +Note that the data is not ordered by particle ID, meaning that particles are not ordered +the same way from one timestep to another.

+

The returned quantity for each iteration is a python dictionary containing key/value +pairs axis:array, where axis is the name of the particle characteristic ("x", +"px", etc.) and array contains the corresponding particle values.

+

Example:

+
S = happi.Open("path/to/my/results")        # Open the simulation
+Diag = S.TrackParticles("my_particles") # Open the tracked particles
+npart = 0
+sum_px = 0.
+# Loop particles of timestep 100 by chunks of 10000
+for particle_chunk in Diag.iterParticles(100, chunksize=10000):
+    npart  += particle_chunk["px"].size
+    sum_px += particle_chunk["px"].sum()
+# Calculate the average px
+mean_px = sum_px / npart
+
+
+
+ +
+
+Field.getXmoved(timestep)
+

Specific to Field diagnostics, this method returns the displacement of the moving +window at the required timestep.

+
+ +
+
+
+

Export 2D or 3D data to VTK

+
+
+Field.toVTK(numberOfPieces=1)
+
+Probe.toVTK(numberOfPieces=1)
+
+ParticleBinning.toVTK(numberOfPieces=1)
+
+Performances.toVTK(numberOfPieces=1)
+
+Screen.toVTK(numberOfPieces=1)
+
+TrackParticles.toVTK(rendering='trajectory', data_format='xml')
+

Converts the data from a diagnostic object to the vtk format. +Note the export_dir argument available for each diagnostic (see above).

+
    +
  • numberOfPieces: the number of files into which the data will be split.

  • +
  • rendering: the type of output in the case of TrackParticles():

    +
      +
    • "trajectory": show particle trajectories. One file is generated for all trajectories. +This rendering requires the particles to be sorted.

    • +
    • "cloud": show a cloud of particles. One file is generated for each iteration. +This rendering can be used without sorting the particles.

    • +
    +
  • +
  • data_format: the data formatting in the case of TrackParticles(), +either "vtk" or "xml". The format "vtk" results in ascii.

  • +
+

Example for tracked particles:

+
S = happi.Open("path/to/my/results")
+tracked_particles = S.TrackParticles("electron", axes=["x","y","z","px","py","pz","Id"], timesteps=[1,10])
+# Create cloud of particles in separate files for each iteration
+tracked_particles.toVTK(rendering="cloud",data_format="xml");
+# Create trajectory in a single file
+tracked_particles.toVTK(rendering="trajectory",data_format="xml");
+
+
+
+ +
+
+
+

Plot the data at one timestep

+

This is the first method to plot the data. It produces a static image of the data +at one given timestep.

+
+
+Scalar.plot(...)
+
+Field.plot(...)
+
+Probe.plot(...)
+
+ParticleBinning.plot(...)
+
+TrackParticles.plot(...)
+
+Screen.plot(...)
+

All these methods have the same arguments described below.

+
+ +
+
+plot(timestep=None, saveAs=None, axes=None, dpi=200, **kwargs)
+
+
If the data is 1D, it is plotted as a curve.
+
If the data is 2D, it is plotted as a map.
+
If the data is 0D, it is plotted as a curve as function of time.
+
+
    +
  • timestep: The iteration number at which to plot the data.

  • +
  • saveAs: name of a directory where to save each frame as figures. +You can even specify a filename such as mydir/prefix.png and it will automatically +make successive files showing the timestep: mydir/prefix0.png, mydir/prefix1.png, +etc.

  • +
  • axes: Matplotlib’s axes handle on which to plot. If None, make new axes.

  • +
  • dpi: the number of dots per inch for saveAs.

  • +
+

You may also have keyword-arguments (kwargs) described in Other arguments for diagnostics.

+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+S.ParticleBinning(1).plot(timestep=40, vmin=0, vmax=1e14)
+
+
+
+
+
+

Plot the data streaked over time

+

This second type of plot works only for 1D data. All available timesteps +are streaked to produce a 2D image where the second axis is time.

+
+
+Scalar.streak(...)
+
+Field.streak(...)
+
+Probe.streak(...)
+
+ParticleBinning.streak(...)
+
+TrackParticles.streak(...)
+
+Screen.streak(...)
+

All these methods have the same arguments described below.

+
+ +
+
+streak(saveAs=None, axes=None, **kwargs)
+

All arguments are identical to those of plot, with the exception of timestep.

+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+S.ParticleBinning(1).streak()
+
+
+
+
+
+

Animated plot

+

This third plotting method animates the data over time.

+
+
+Scalar.animate(...)
+
+Field.animate(...)
+
+Probe.animate(...)
+
+ParticleBinning.animate(...)
+
+TrackParticles.animate(...)
+
+Screen.animate(...)
+

All these methods have the same arguments described below.

+
+ +
+
+animate(movie='', fps=15, dpi=200, saveAs=None, axes=None, **kwargs)
+

All arguments are identical to those of streak, with the addition of:

+
    +
  • movie: name of a file to create a movie, such as "movie.avi" or "movie.gif". +If movie="" no movie is created.

  • +
  • fps: number of frames per second (only if movie requested).

  • +
  • dpi: number of dots per inch for both movie and saveAs

  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+S.ParticleBinning(1).animate()
+
+
+
+
+
+

Plot with a slider

+

This methods provides an interactive slider to change the time.

+
+
+Scalar.slide(...)
+
+Field.slide(...)
+
+Probe.slide(...)
+
+ParticleBinning.slide(...)
+
+TrackParticles.slide(...)
+
+Screen.slide(...)
+

All these methods have the same arguments described below.

+
+ +
+
+slide(axes=None, **kwargs)
+

See plot for the description of the arguments.

+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+S.ParticleBinning(1).slide(vmin=0)
+
+
+
+
+
+

Simultaneous plotting of multiple diagnostics

+
+
+happi.multiPlot(diag1, diag2, ..., **kwargs)
+

Makes an animated figure containing several plots (one for each diagnostic). +If all diagnostics are of similar type, they may be overlayed on only one plot.

+
    +
  • +
    diag1, diag2, etc.
    +
    Diagnostics prepared by Scalar(), Field(), Probe(), etc.
    +
    +
    +
    +
  • +
+

Keyword-arguments kwargs are:

+
    +
  • figure: The figure number that is passed to matplotlib (default is 1).

  • +
  • shape: The arrangement of plots inside the figure. For instance, [2, 1] +makes two plots stacked vertically, and [1, 2] makes two plots stacked horizontally. +If absent, stacks plots vertically.

  • +
  • legend_font: dictionnary to set the legend’s font properties, +such as {'size':15, 'weight':'bold', 'family':'serif', 'color':'k'}.

  • +
  • movie : filename to create a movie.

  • +
  • fps : frames per second for the movie.

  • +
  • dpi : resolution of the movie or saveAs.

  • +
  • saveAs: name of a directory where to save each frame as figures. +You can even specify a filename such as mydir/prefix.png and it will automatically +make successive files showing the timestep: mydir/prefix0.png, mydir/prefix1.png, etc.

  • +
  • skipAnimation : if True, plots only the last frame.

  • +
  • timesteps: same as the timesteps argument of the plot() method.

  • +
+
+ +
+
+happi.multiSlide(diag1, diag2, ..., **kwargs)
+

Identical to happi.multiPlot but uses a time slider instead of an animation.

+
    +
  • +
    diag1, diag2, etc.
    +
    Diagnostics prepared by Scalar(), Field(), Probe(), etc.
    +
    +
    +
    +
  • +
  • figure, shape, and legend_font: same as in happi.multiPlot.

  • +
+
+ +

Example:

+
S = happi.Open("path/to/my/results")
+A = S.Probe(probeNumber=0, field="Ex")
+B = S.ParticleBinning(diagNumber=1)
+happi.multiPlot( A, B, figure=1 )
+
+
+
+

This plots a Probe and a ParticleBinning on the same figure, and makes an animation for all available timesteps.

+
+
+

Note

+

To plot several quantities on the same graph, you can try shape=[1,1]. +One diagnostic may have the option side="right" to use the right-hand-side axis.

+
+
+
+
+

Advanced plotting options

+

In addition to figure, vmin, vmax, xmin, xmax, ymin and ymax, +there are many more optional arguments. They are directly passed to the matplotlib package.

+

For the figure: figsize, dpi, facecolor, edgecolor

+
+

Please refer to +matplotlib’s figure options.

+
+

For the axes frame: aspect, axis_facecolor, frame_on, position, +visible, xlabel, xscale, xticklabels, xticks, +ylabel, yscale, yticklabels, yticks, zorder

+
+

Please refer to matplotlib’s axes options: the same as functions starting +with set_ listed here.

+
+

For the lines: color, dashes, drawstyle, fillstyle, +label, linestyle, linewidth, +marker, markeredgecolor, markeredgewidth, +markerfacecolor, markerfacecoloralt, markersize, markevery, +visible, zorder

+
+

Please refer to +matplotlib’s line options.

+
+

For the image: cmap, aspect, interpolation, norm

+
+

Please refer to +matplotlib’s image options.

+
+

For the colorbar: cbaspect, orientation, fraction, pad, +shrink, anchor, panchor, extend, extendfrac, extendrect, +spacing, ticks, format, drawedges, size, clabel

+
+
+

For the tick number format: style_x, scilimits_x, useOffset_x, +style_y, scilimits_y, useOffset_y

+
+
+

For fonts: title_font, xlabel_font, xticklabels_font, +ylabel_font, yticklabels_font, colorbar_font

+
+

These options are dictionnaries that may contain the entries available in +matplotlib’s font properties, +for instance:

+
title_font = {'size': 15, 'weight': 'bold', 'family':'serif', 'color': 'k'}
+
+
+
+

Example:

+
+

To choose a gray colormap of the image, use cmap="gray":

+
S = happi.Open("path/to/my/results")
+S.ParticleBinning(0, figure=1, cmap="gray") .plot()
+
+
+
+
+

Many colormaps are available from the matplotlib package. With cmap="", you will get a list of available colormaps. +Smilei’s default colormaps are: smilei, smilei_r, smileiD and smileiD_r.

+
+
+
+
+

Update the plotting options

+
+
+Scalar.set(...)
+
+Field.set(...)
+
+Probe.set(...)
+
+ParticleBinning.set(...)
+
+Screen.set(...)
+

Example:

+
S = happi.Open("path/to/my/results")
+A = S.ParticleBinning(diagNumber=0, figure=1, vmax=1)
+A.plot( figure=2 )
+A.set( vmax=2 )
+A.plot()
+
+
+
+ +
+
+
+

Other tools in happi

+
+
+happi.openNamelist(namelist)
+

Reads a namelist and stores all its content in the returned object.

+
    +
  • namelist: the path to the namelist.

  • +
+
+ +

Example:

+
namelist = happi.openNamelist("path/no/my/namelist.py")
+print namelist.Main.timestep
+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/profiles.html b/Use/profiles.html new file mode 100644 index 000000000..53953952f --- /dev/null +++ b/Use/profiles.html @@ -0,0 +1,816 @@ + + + + + + + + + Profiles — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Profiles

+

Several quantities require the input of a profile: particle charge, particle density, +external fields, etc. Depending on the case, they can be spatial or temporal +profiles.

+
+
+

Constant profiles

+
    +
  • Species( ... , charge = -3., ... ) defines a species with charge \(Z^\star=3\).

  • +
  • Species( ... , number_density = 10., ... ) defines a species with density \(10\,N_r\). +You can choose number_density or charge_density

  • +
  • Species( ... , mean_velocity = [0.05, 0., 0.], ... ) defines a species +with drift velocity \(v_x = 0.05\,c\) over the whole box.

  • +
  • Species(..., momentum_initialization="maxwell-juettner", temperature=[1e-5], ...) defines +a species with a Maxwell-Jüttner distribution of temperature \(T = 10^{-5}\,m_ec^2\) over the whole box. +Note that the temperature may be anisotropic: temperature=[1e-5, 2e-5, 2e-5].

  • +
  • Species( ... , particles_per_cell = 10., ... ) defines a species with 10 particles per cell.

  • +
  • ExternalField( field="Bx", profile=0.1 ) defines a constant external field \(B_x = 0.1 B_r\).

  • +
+
+
+
+

Python profiles

+

Any python function can be a profile. Examples:

+
def f(x):
+    if x<1.: return 0.
+    else: return 1.
+
+
+
import math
+def f(x,y):    # two variables for 2D simulation
+    twoPI = 2.* math.pi
+    return math.cos(  twoPI * x/3.2 )
+
+
+
f = lambda x: x**2 - 1.
+
+
+

Once the function is created, you have to include it in the block you want, +for example:

+
Species( ... , charge = f, ... )
+
+Species( ... , mean_velocity = [f, 0, 0], ... )
+
+
+
+

Note

+

It is possible, for higher performances, to create functions with +arguments (x, y, etc.) that are actually numpy arrays. If the function returns +a numpy array of the same size, it will automatically be considered as a profile +acting on arrays instead of single floats. Currently, this feature is only available +on Species’ profiles.

+
+
+
+
+

Pre-defined spatial profiles

+
+
+constant(value, xvacuum=0., yvacuum=0.)
+
+
Parameters
+
    +
  • value – the magnitude

  • +
  • xvacuum – vacuum region before the start of the profile.

  • +
+
+
+
+ +
+
+trapezoidal(max, xvacuum=0., xplateau=None, xslope1=0., xslope2=0., yvacuum=0., yplateau=None, yslope1=0., yslope2=0.)
+
+
Parameters
+
    +
  • max – maximum value

  • +
  • xvacuum – empty length before the ramp up

  • +
  • xplateau – length of the plateau (default is grid_length \(-\) xvacuum)

  • +
  • xslope1 – length of the ramp up

  • +
  • xslope2 – length of the ramp down

  • +
+
+
+
+ +
+
+gaussian(max, xvacuum=0., xlength=None, xfwhm=None, xcenter=None, xorder=2, yvacuum=0., ylength=None, yfwhm=None, ycenter=None, yorder=2)
+
+
Parameters
+
    +
  • max – maximum value

  • +
  • xvacuum – empty length before starting the profile

  • +
  • xlength – length of the profile (default is grid_length \(-\) xvacuum)

  • +
  • xfwhm – gaussian FWHM (default is xlength/3.)

  • +
  • xcenter – gaussian center position (default is in the middle of xlength)

  • +
  • xorder – order of the gaussian.

  • +
+
+
Note
+

If yorder equals 0, then the profile is constant over \(y\).

+
+
+
+ +
+
+polygonal(xpoints=[], xvalues=[])
+
+
Parameters
+
    +
  • xpoints – list of the positions of the points

  • +
  • xvalues – list of the values of the profile at each point

  • +
+
+
+
+ +
+
+cosine(base, amplitude=1., xvacuum=0., xlength=None, xphi=0., xnumber=1)
+
+
Parameters
+
    +
  • base – offset of the profile value

  • +
  • amplitude – amplitude of the cosine

  • +
  • xvacuum – empty length before starting the profile

  • +
  • xlength – length of the profile (default is grid_length \(-\) xvacuum)

  • +
  • xphi – phase offset

  • +
  • xnumber – number of periods within xlength

  • +
+
+
+
+ +
+
+polynomial(x0=0., y0=0., z0=0., order0=[], order1=[], ...)
+
+
Parameters
+
    +
  • x0,y0 – The reference position(s)

  • +
  • order0 – Coefficient for the 0th order

  • +
  • order1 – Coefficient for the 1st order (2 coefficients in 2D)

  • +
  • order2 – Coefficient for the 2nd order (3 coefficients in 2D)

  • +
  • etc

  • +
+
+
+

Creates a polynomial of the form

+
+\[\begin{split}\begin{eqnarray} +&\sum_i a_i(x-x_0)^i & \quad\mathrm{in\, 1D}\\ +&\sum_i \sum_j a_{ij}(x-x0)^{i-j}(y-y0)^j & \quad\mathrm{in\, 2D}\\ +&\sum_i \sum_j \sum_k a_{ijk}(x-x0)^{i-j-k}(y-y0)^j(z-z0)^k & \quad\mathrm{in\, 3D} +\end{eqnarray}\end{split}\]
+

Each orderi is a coefficient (or list of coefficents) associated to the order i. +In 1D, there is only one coefficient per order. In 2D, each orderi is a list +of i+1 coefficients. For instance, the second order has three coefficients +associated to \(x^2\), \(xy\) and \(y^2\), respectively. +In 3D, each orderi is a list of (i+1)*(i+2)/2 coefficients. For instance, +the second order has 6 coefficients associated to \(x^2\), \(xy\), \(xz\), +\(y^2\), \(yz\) and \(z^2\), respectively.

+
+ +

Examples:

+
Species( ... , density = gaussian(10., xfwhm=0.3, xcenter=0.8), ... )
+
+ExternalField( ..., profile = constant(2.2), ... )
+
+
+

Illustrations of the pre-defined spatial profiles

+../_images/pythonprofiles.png +
+
+
+

Pre-defined temporal profiles

+
+
+tconstant(start=0.)
+
+
Parameters
+

start – starting time

+
+
+
+ +
+
+ttrapezoidal(start=0., plateau=None, slope1=0., slope2=0.)
+
+
Parameters
+
    +
  • start – starting time

  • +
  • plateau – duration of the plateau (default is simulation_time \(-\) start)

  • +
  • slope1 – duration of the ramp up

  • +
  • slope2 – duration of the ramp down

  • +
+
+
+
+ +
+
+tgaussian(start=0., duration=None, fwhm=None, center=None, order=2)
+
+
Parameters
+
    +
  • start – starting time

  • +
  • duration – duration of the profile (default is simulation_time \(-\) start)

  • +
  • fwhm – gaussian FWHM (default is duration/3.)

  • +
  • center – gaussian center time (default is in the middle of duration)

  • +
  • order – order of the gaussian

  • +
+
+
+
+ +
+
+tpolygonal(points=[], values=[])
+
+
Parameters
+
    +
  • points – list of times

  • +
  • values – list of the values at each time

  • +
+
+
+
+ +
+
+tcosine(base=0., amplitude=1., start=0., duration=None, phi=0., freq=1.)
+
+
Parameters
+
    +
  • base – offset of the profile value

  • +
  • amplitude – amplitude of the cosine

  • +
  • start – starting time

  • +
  • duration – duration of the profile (default is simulation_time \(-\) start)

  • +
  • phi – phase offset

  • +
  • freq – frequency

  • +
+
+
+
+ +
+
+tpolynomial(t0=0., order0=[], order1=[], ...)
+
+
Parameters
+
    +
  • t0 – The reference position

  • +
  • order0 – Coefficient for the 0th order

  • +
  • order1 – Coefficient for the 1st order

  • +
  • order2 – Coefficient for the 2nd order

  • +
  • etc

  • +
+
+
+

Creates a polynomial of the form \(\sum_i a_i(t-t_0)^i\).

+
+ +
+
+tsin2plateau(start=0., fwhm=0., plateau=None, slope1=fwhm, slope2=slope1)
+
+
Parameters
+
    +
  • start – Profile is 0 before start

  • +
  • fwhm – Full width half maximum of the profile

  • +
  • plateau – Length of the plateau

  • +
  • slope1 – Duration of the ramp up of the profil

  • +
  • slope2 – Duration of the ramp down of the profil

  • +
+
+
+

Creates a sin squared profil with a plateau in the middle if needed. If slope1 and 2 are used, fwhm is overwritten.

+
+ +

Example:

+
Antenna( ... , time_profile = tcosine(freq=0.01), ... )
+
+
+

Illustrations of the pre-defined temporal profiles

+../_images/pythonprofiles_t.png +
+
+
+

Extract the profile from a file

+

The following profiles may be given directly as an HDF5 file:

+
    +
  • Species.charge_density

  • +
  • Species.number_density

  • +
  • Species.particles_per_cell

  • +
  • Species.charge

  • +
  • Species.mean_velocity

  • +
  • Species.temperature

  • +
  • ExternalField.profile except when complex (cylindrical geometry)

  • +
+

You must provide the path to the file, and the path to the dataset +inside the file. +For instance charge_density = "myfile.h5/path/to/dataset".

+

The targeted dataset located in the file must be an array with +the same dimension and the same number of cells as the simulation grid.

+
+

Warning

+

For ExternalField, the array size must take into account the +number of ghost cells in each direction. There is also one extra cell +in specific directions due to the grid staggering (see this doc).

+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/run.html b/Use/run.html new file mode 100644 index 000000000..c551e7c25 --- /dev/null +++ b/Use/run.html @@ -0,0 +1,652 @@ + + + + + + + + + Run — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ + + + +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Run

+

Before you launch Smilei, write a namelist file +containing all the information of your simulation (grid shape, particles, lasers, diagnostics, etc.).

+

You can also start from an example provided in the benchmarks directory.

+
+
+

The smilei executable

+

Compiling Smilei creates an executable file smilei in the source directory.

+
smilei arg1 arg2 arg3 ...
+
+
+

The command-line arguments arg1, arg2, arg3 (etc.) can be:

+
    +
  • the path to a namelist

  • +
  • any python instruction that you want to execute during the namelist reading.

  • +
+

The simplest example, to run your namelist my_namelist.py, is

+
./smilei  my_namelist.py
+
+
+

You may also add an additional instruction to be appended at the end of the namelist:

+
./smilei  my_namelist.py  "Main.print_every=10"
+
+
+

Note that, in addition, you will generally use the mpirun or mpiexec command +to run Smilei on several MPI processes:

+
mpirun -n 4 ./smilei  my_namelist.py  "Main.print_every=10"
+
+
+

If you want to run several openMP threads per MPI processes, you usually have to set +the following environment variable to the desired number of threads before running +mpirun:

+
export OMP_NUM_THREADS=4
+
+
+

When running Smilei, the output log will remind you how many MPI processes and openMP threads +your simulation is using.

+
+
+
+

Running in test mode

+

A second executable smilei_test is available (after the usual compilation) +to run in the test mode:

+
./smilei_test my_namelist.py
+
+
+

This test mode does the same initialization as the normal mode, +except it only loads the first patch of the full simulation. After initialization, +the test mode exits so that the PIC loop is not computed.

+

This mode may be used to check the consistency of the namelist, and to make sure +simple errors will not occur. It does not check all possible errors, but it runs fast.

+

Running in test mode requires to run on 1 MPI process only. However, it is possible +to indicate what is the partition of MPI processes and OpenMP threads intended for the +actual simulation. For instance, to test your namelist that is intended to run on 1024 MPI +processes, each hosting 12 OpenMP threads, use the following syntax:

+
./smilei_test 1024 12 my_namelist.py
+
+
+
+
+
+

Directory management

+

Let us assume you have written your namelist my_namelist.py, and that you placed it +inside your home directory. Also, we assume that the Smilei directory is also there, +so that the smilei executable is located in ~/Smilei/.

+

Knowing that Smilei generally writes out all the results in the current directory, +it is recommended to create a new directory to store these results. For instance:

+
$ mkdir ~/my_simulation                     # New directory to store results
+$ cp ~/my_namelist.py ~/my_simulation       # Copies the namelist there
+$ cd ~/my_simulation                        # Goes there
+$ mpirun -n 4 ~/Smilei/smilei my_namelist   # Run with 4 processors
+
+
+
+
+
+

Using the provided script

+

For simple cases such as the previous one, use the script smilei.sh, provided in +the Smilei directory. You only have to run

+
$ ./smilei.sh 4 my_namelist.py
+
+
+

where the number 4 says that the code will run 4 MPI processes. A directory with all +the results will automatically be created next to your namelist.

+
+
+
+

Running on large clusters

+

We do not provide instructions to run on super-computers yet. Please refer to your +administrators.

+
+
+
+

Running on GPU-equiped nodes

+

On a supercomputer equipped with GPUs it is necessary to use a binding script. +Here are two examples:

+

With Nvidia GPUs: +srun bind_gpu.sh  ./smilei input.py

+

With AMD GPUs using cray on Adastra: +srun --cpu-bind=none --mem-bind=none --mpi=cray_shasta --kill-on-bad-exit=1 -- ./bind ./smilei input.py

+

For the binding scripts themselves, as it depends completely on the node +architecture, please contact your admin support team.

+

Be aware that GPU support is in development and not all features are currently available. +Please refer to the list of current supported features.

+
+
+
+

Debugging

+

In case of problems, the code can be compiled with additional debugging flags (usual -g and -O0) and internal +checks by compiling it with

+
make config=debug
+
+
+

Compiling the whole code with this command will make it very slow to run. +But to check only a particular file for errors, first compile the code with make, then +modify the file, and recompile in debug mode.

+

In debug mode, these C++ macros are activated:

+
    +
  • DEBUG("some text" [<< other streamable])

  • +
  • HEREIAM("some text" [<< other streamable])

  • +
+
+
+
+

Known issues

+
    +
  • OpenMPI 2.* often causes unstable behavior in Smilei. +For instance, with openmpi 2.1, the vader protocol seems to interfere with Smilei’s +memory management and comunications. We therefore recommend to disable this +protocol when running mpirun, as follows:

    +
    $ mpirun --mca btl ^vader -n 4 ~/Smilei/smilei my_namelist   # Disable vader
    +
    +
    +
  • +
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/tables.html b/Use/tables.html new file mode 100644 index 000000000..4d3ca5f39 --- /dev/null +++ b/Use/tables.html @@ -0,0 +1,818 @@ + + + + + + + + + Generation of the external tables — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Generation of the external tables

+

By default, Smilei embeds tables directly in the sources. +Nonetheless, a user may want to use different tables. +For this reason, Smilei can read external tables.

+

Several physical mechanisms can use external tables to work:

+ +

An external tool called smilei_tables is available to generate these tables.

+
+
+

Installation

+

The C++ sources of this tool is located in tools/tables.

+

Required dependencies are the following:

+
    +
  • A C++11 compiler

  • +
  • A MPI library

  • +
  • HDF5 installed at least in serial

  • +
  • Boost

  • +
+

Boost is a C++ library that provides efficient advanced mathematical functions. +This is the only dependency not required to install Smilei. +This library can be easily installed manually on Linux, MacOS or Windows systems. +It is also available via different package managers (Debian, Homebrew). +The environment variable BOOST_ROOT must be defined.

+

The tool can be then installed using the makefile and the argument tables:

+
make tables
+
+
+

The compilation generates an executable called smilei_tables on the root of the repository.

+
+
+
+

Execution

+

The tool works with command line arguments. +For each physical mechanism, smilei_tables generates all the tables for this mechanism. +The first argument therefore corresponds to the physical mechanism:

+
    +
  • Nonlinear inverse Compton scattering: nics

  • +
  • Multiphoton Breit-Wheeler: mbw

  • +
  • For help: -h or `--help

  • +
+
mpirun -np <number of processes> ./smilei_tables -h
+
+
+

Then, once the physical mechanism is selected, the following arguments are the numerical parameters for the table generation. +For each physical argument, -h or --help gives the full list of arguments.

+

For Nonlinear inverse Compton Scattering:

+
mpirun -np <number of processes> ./smilei_tables nics -h
+
+_______________________________________________________________________
+
+Smilei Tables
+_______________________________________________________________________
+
+You have selected the creation of tables for the nonlinear inverse Compton scattering.
+
+Help page specific to the nonlinear inverse Compton Scattering:
+
+List of available commands:
+-h, --help                       print a help message and exit.
+-s, --size       int int         respective size of the particle and photon chi axis. (default 128 128)
+-b, --boundaries double double   min and max of the particle chi axis. (default 1e-3 1e3)
+-e, --error      int             compute error due to discretization and use the provided int as a number of draws. (default 0)
+-t, --threshold  double          Minimum targeted value of xi in the computation the minimum particle quantum parameter. (default 1e-3)
+-p, --power      int             Maximum decrease in order of magnitude for the search for the minimum particle quantum parameter. (default 4)
+-v, --verbose                    Dump the tables
+
+
+

For multiphoton Breit-Wheeler:

+
mpirun -np <number of processes> ./smilei_tables mbw -h
+
+_______________________________________________________________________
+
+Smilei Tables
+_______________________________________________________________________
+
+You have selected the creation of tables for the multiphoton Breit Wheeler process.
+
+Help page specific to the multiphoton Breit-Wheeler:
+
+List of available commands:
+-h, --help                       print a help message and exit.
+-s, --size       int int         respective size of the photon and particle chi axis. (default 128 128)
+-b, --boundaries double double   min and max of the photon chi axis. (default 1e-2 1e2)
+-e, --error      int             compute error due to discretization and use the provided int as a number of draws. (default 0)
+-t, --threshold  double          Minimum targeted value of xi in the computation the minimum photon quantum parameter. (default 1e-3)
+-p, --power      int             Maximum decrease in order of magnitude for the search for the minimum photon quantum parameter. (default 4)
+-v, --verbose                    Dump the tables
+
+
+

The tables are generated where the code is executed using HDF5 with the following names:

+
    +
  • Nonlinear inverse Compton Scattering: radiation_tables.h5

  • +
  • multiphoton Breit-Wheeler: multiphoton_breit_wheeler_tables.h5

  • +
+
+
+
+

Precomputed tables

+

We have computed some tables with several levels of discretization that you can download here.

+
+

256 points

+

This table size is a good compromise between accuracy and memory cost. +2D tables can fit in L2 cache although the pressure on the cache will be high. +This set of tables is the one included by default in the sources of Smilei

+
mpirun -np <number of processes> ./smilei_tables nics -s 256 256 -b 1e-4 1e3
+
+
+

tables_256/radiation_tables.h5

+
mpirun -np <number of processes> ./smilei_tables mbw -s 256 256 -b 1e-2 1e2
+
+
+

tables_256/multiphoton_breit_wheeler_tables.h5

+

These tables can be generated on a normal desktop computer in few minutes.

+
+
+

512 points

+

With a size of 512 points in 1D and 512x512 for 2D tables, these tables offer better accuracy at a larger memory cost. +2D tables of this size are too large to fit in L2 cache but can be contained in L3.

+
mpirun -np <number of processes> ./smilei_tables nics -s 512 512 -b 1e-4 1e3
+
+
+

tables_512/radiation_tables.h5

+
mpirun -np <number of processes> ./smilei_tables mbw -s 512 512 -b 1e-2 1e2
+
+
+

tables_512/multiphoton_breit_wheeler_tables.h5

+
+
+

1024 points

+

With a size of 1024 points in 1D and 1024x1024 for 2D tables, these tables offer the best accuracy at a high memory cost (around 8.5 Mb per file). +2D tables of this size are too large to fit in L2 cache and L3 cache.

+
mpirun -np <number of processes> ./smilei_tables nics -s 1024 1024 -b 1e-4 1e3
+
+
+

tables_1024/radiation_tables.h5

+
mpirun -np <number of processes> ./smilei_tables mbw -s 1024 1024 -b 1e-2 1e2
+
+
+

tables_1024/multiphoton_breit_wheeler_tables.h5

+
+
+
+
+

Python visualization scripts

+

You can easily visualize the tables provided by our tools using the python scripts located in the tools/tables folder:

+
    +
  • show_nonlinear_inverse_Compton_scattering.py

  • +
  • show_multiphoton_Breit_Wheeler.py

  • +
+

For instance:

+
python ./tools/tables/show_nonlinear_inverse_Compton_scattering.py ./radiation_tables.h5
+
+
+
+
+
+

Detailed description of the tables

+
+

Nonlinear Inverse Compton Scattering

+

The file radiation_tables.h5 is used for the nonlinear inverse Compton scattering radiation +mechanism described in the dedicated section.

+

It first contains the integfochi table that represents +the integration of the synchortron emissivity of Ritus et al:

+
+(72)\[\int_{0}^{\chi_\pm} \frac{S(\chi_\pm , x)}{x} dx = \int_{0}^{\chi_\pm} \frac{2 x}{ 3 \chi_\pm^2} \left[ \int_{2y}^{+\infty}{K_{1/3(y)}dy} - \frac{2 + 3 x y}{2} K_{2/3}(\nu) \right] dx\]
+

where

+
+(73)\[y = \frac{x}{3 \chi_\pm (\chi_\pm - x)}\]
+

The \(x\) value corresponds to the photon quantum parameter. +We integrate the whole spectrum. +This table is used by the Monte-Carlo method to compute the radiation emission cross-section.

+
+../_images/nics_integration_F_over_chi.png +
+

Fig. 63 Plot of the integfochi table for a particle quantum parameter ranging +from \(\chi = 10^{-4}\) to \(10^{3}\) using the pre-computed table of 512 points.

+
+
+

The table h is used for the Niel stochastic model ([Niel2018a]). +It is given by the following integration:

+
+(74)\[ h \left( \chi \right) = \frac{9 \sqrt{3}}{4 \pi} \int_0^{+\infty}{d\nu + \left[ \frac{2\chi^3 \nu^3}{\left( 2 + 3\nu\chi \right)^3} K_{5/3}(\nu) + + \frac{54 \chi^5 \nu^4}{\left( 2 + 3 \nu \chi \right)^5} K_{2/3}(\nu) \right]}\]
+
+../_images/nics_h_niel.png +
+

Fig. 64 Plot of the h table for a particle quantum parameter ranging +from \(\chi = 10^{-4}\) to \(10^{3}\) using the pre-computed table of 512 points.

+
+
+

The table min_photon_chi_for_xi is the minimum boundary used +by the table xi for the photon quantum parameter axis.

+

This minimum value \(\chi_{\gamma,\min}\) is computed using the following inequality:

+
+(75)\[ \frac{\displaystyle{\int_0^{\chi_{\gamma,\min}}{S(\chi_\pm, x) / x + dx}}}{\displaystyle{\int_0^{\chi_\pm}{S(\chi_\pm, x) / x dx}}} < \varepsilon\]
+

We generally use \(\varepsilon = 10^{-3}\). +It corresponds to the argument parameter xi_threshold. +We have to determine a minimum photon quantum parameter because +we cannot have a logarithmic discretization starting from 0. +It basically means that we ignore the radiated energy below \(\chi_{\gamma,\min}\) +that is less than \(10^{-3}\) of the total radiated energy. +The parameter xi_power is the precision of the \(\chi_{\gamma,\min}\) value. +For instance, a xi_power of 4 as used for our tables mean that we look for a precision of 4 digits.

+
+../_images/nics_min_photon_chi.png +
+

Fig. 65 Plot of the minimal photon quantum parameter \(\chi_{\gamma,\min}\) +corresponding to the minimum boundary of the xi table +as a function of the particle quantum parameter \(\chi_\pm\) ranging +from \(10^{-4}\) to \(10^{3}\). It corresponds to the pre-computed table of 512 points.

+
+
+

The table xi corresponds to the following fraction:

+
+(76)\[ \xi = \frac{\displaystyle{\int_0^{\chi_{\gamma}}{S(\chi_\pm, x) / x + dx}}}{\displaystyle{\int_0^{\chi_\pm}{S(\chi_\pm, x) / x dx}}}\]
+

For a given \(\chi_\pm\) and a randomly drawn parameter \(\xi\), +we obtain the quantum parameter \(\chi_\gamma\) of the emitted photon. +This method is used by the Monte-Carlo method to determine the radiated energy of the emitted photon. +For a given \(\chi_\pm\), \(\chi_\gamma\) ranges from \(\chi_{\gamma,\min}\) to \(\chi_\pm\).

+
+../_images/nics_xi.png +
+

Fig. 66 Plot of the xi table as a function of the particle quantum parameter \(\chi_\pm\) +and index for the \(\chi_\gamma\) axis. +The \(\chi_\pm\) axis ranges from \(10^{-4}\) to \(10^{3}\). +The \(\chi_\gamma\) axis ranges from \(\chi_{\gamma,\min}\) to \(\chi_\pm\). +It corresponds to the pre-computed table of 512 points.

+
+
+
+
+

Multiphoton Breit-Wheeler

+

The file multiphoton_breit_wheeler_tables.h5 is used for the multiphoton Breit-Wheeler process +described in the dedicated section.

+

It first contains the T table that represents +the following integration:

+
+(77)\[T \left( \chi_\gamma \right) = +\int_{0}^{+\infty}{\int_{x}^{+\infty}{\sqrt{s} K_{1/3} \left( \frac{2}{3} s^{3/2} +\right) ds - \left( 2 - \chi_\gamma x^{3/2} \right) K_{2/3} \left( \frac{2}{3} x^{3/2} \right) }} d\chi_-\]
+

where

+
+(78)\[x = \left( \chi_\gamma / (\chi_{-} \chi_{+}) \right)^{2/3}\]
+

And

+
+(79)\[\chi_\gamma = \chi_{-} + \chi_{+}.\]
+

It is used to compute the production rate of electron-positron pairs +from a single photon of quantum parameter \(\chi_\gamma\). +In the Monte-Carlo algorithm, it is used to determine the photon decay probability.

+
+../_images/mbw_T.png +
+

Fig. 67 Plot of the table T +as a function of the photon quantum parameter \(\chi_\gamma\) ranging +from \(10^{-2}\) to \(10^{2}\). +It corresponds to the pre-computed table size of 512 points.

+
+
+

The table min_particle_chi_for_xi is the minimum boundary used +by the table xi for the particle quantum parameter axis. +The particle can be either a positron or an electron. +The mechanism is symmetric.

+

This minimum value \(\chi_{\pm,\min}\) is computed using the following inequality:

+
+(80)\[\frac{\displaystyle{\int_0^{\chi_{\pm,\min}}{\frac{dT}{dx}(\chi_\gamma, x) +dx}}}{\displaystyle{\int_0^{\chi_\gamma}{\frac{dT}{dx}(\chi_\gamma, x) dx}}} < \varepsilon\]
+

We use here \(\varepsilon = 10^{-9}\). +It corresponds to the argument parameter xi_threshold. +We have to determine a minimum photon quantum parameter because +we cannot have a logarithmic discretization starting from 0. +The parameter xi_power is the precision of the \(\chi_{\pm,\min}\) value. +For instance, a xi_power of 4 as used for our tables mean that we look for a precision of 4 digits.

+
+../_images/mbw_min_particle_chi.png +
+

Fig. 68 Plot of the minimal particle quantum parameter \(\chi_{\pm,\min}\) corresponding to the minimum boundary of the xi table +as a function of the photon quantum parameter \(\chi_\gamma\) ranging +from \(10^{-2}\) to \(10^{2}\). +It corresponds to the pre-computed table of 512 points.

+
+
+

The table xi corresponds to the following fraction:

+
+(81)\[\xi = \frac{\displaystyle{\int_0^{\chi_{\pm}}{\frac{dT}{dx}(\chi_\gamma, x) +dx}}}{\displaystyle{\int_0^{\chi_\gamma}{\frac{dT}{dx}(\chi_\gamma, x) dx}}}\]
+

For a given \(\chi_\gamma\) and a randomly drawn parameter \(\xi\), +we obtain the quantum parameter \(\chi_\pm\) of either the generated electron or positron. +Once we have one, we deduce the second from \(\chi_\gamma = \chi_+ + \chi_-\) +This method is used by the Monte-Carlo method to determine the energy of the created electron and the positron. +For a given \(\chi_\gamma\), \(\chi_\pm\) ranges from \(\chi_{\pm,\min}\) to \(\chi_\gamma\).

+
+../_images/mbw_xi.png +
+

Fig. 69 Plot of the xi table as a function of the photon quantum parameter \(\chi_\gamma\) +and index for the \(\chi_\pm\) axis. +The \(\chi_\gamma\) axis ranges from \(10^{-2}\) to \(10^{2}\). +The \(\chi_\pm\) axis ranges from \(\chi_{\pm,\min}\) to \(\chi_\pm\). +It corresponds to the pre-computed table of 512 points.

+
+
+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/Use/troubleshoot.html b/Use/troubleshoot.html new file mode 100644 index 000000000..c6897515b --- /dev/null +++ b/Use/troubleshoot.html @@ -0,0 +1,592 @@ + + + + + + + + + Troubleshoot — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+ + + + +
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Troubleshoot

+

If you encounter issues running your simulation, you can ask for help in the chat room on Element or publish an Issue on GitHub. +From previous users experience, the cause of most of the issues can be found performing some basic checks, listed in the following. +Also, performing these simple tests helps us while finding an answer to your Issue.

+
+
+

Simulation not starting / Error running a simulation

+

Your simulation does not start or has an error while running.

+
    +
  • Check that the smilei executable is called correctly, e.g. it is present in the input namelist folder or correctly called from there. See also Run.

  • +
  • Check that smilei runs correctly with at least one input namelist in the benchmarks folder.

  • +
  • Use the smilei_test executable on your input namelist. Does it display error or warning messages?

  • +
  • Check your Profiles in the input namelist, e.g. Avoid NaN values if you read them from a file or generate them through a Python function.

  • +
  • Try git pull, make clean and compile again. Also, be sure that uou have already used make happi for postprocessing. All these operations must be performed in the installation folder on your machine to run the simulations.

  • +
  • Change the numerical parameters in the input namelist e.g. resolution, timestep, particles per cell, number of patches. Does the error occur again? See the dedicated sections in Write a namelist.

  • +
  • Change the number of MPI process, OpenMP threads. Do the simulations in the benchmarks folder run correctly with only one MPI process/OpenMP thread?

  • +
  • Check that your MPI and OpenMP configuration is correct through parallel Hello World tests or other basic parallel programs.

  • +
  • Try running a reduced simulation (less particles per cell, coarser resolution).

  • +
  • Try using the same input namelist, and/or a reduced version (less particles per cell, coarser resolution) on a different machine.

  • +
  • If the simulation stops after its start, does the error occur always at the same iteration? With print_every in the input namelist you can change the iteration print frequency in the log file.

  • +
+
+
+
+

New simulation does not run

+

You have already run successfully other similar simulations, but a new one gives an error at the start.

+
    +
  • Use the input namelist of the simulation that works correctly and then progressively change the input to arrive to the simulation you want to run. At each step check if something goes wrong and what is the change in the input namelist that caused the issue.

  • +
  • Try running the new simulation with the smilei executable used for the simulation that worked correctly, if different. Changing the code version creates the problem?

  • +
+
+
+
+

Postprocessing error

+

You can run the simulation but you cannot open/read the results.

+
    +
  • Do git pull and make happi in your installation folder to have the postprocessing library happi ready for use. Afterwards, remember to close and reopen the Python interface you are using, e.g. IPython. See also Install.

  • +
  • Check if you can correctly open the results of a simulation using one input namelist in the benchmarks folder.

  • +
  • Carefully read the doc about the Post-process method you are trying to use.

  • +
+
+
+
+

Physical error in the results.

+

The physical results are not the ones you expect.

+
    +
  • Read the doc on the physical methods you are using (e.g. Binary collisions & reactions, +Ionization, Laser envelope model, …). +Are the underlying physical assumptions satisfied?

  • +
  • Check that the units given in the input namelist are properly normalized. +See also Units.

  • +
  • Some physical processes like Binary collisions & reactions, Ionization +need a reference frequency in SI in the Main block of the input namelist. Did you provide it? +See also Write a namelist.

  • +
  • Check the CFL condition in the input namelist. See PIC algorithms

  • +
  • See with the Scalar diagnostics (See Post-process ) if the kinetic energy Ukin +or electromagnetic energy Uelm display strange behaviours (e.g. exponential growths).

  • +
  • Verify the overall consistency of the physical set-up, e.g. only immobile or almost immobile +particles while using a Poisson solver.

  • +
  • Verify that the physical initialization is correct. Should you use a classical or +relativistic Poisson solver (See Field initialization for relativistic species) +for the initial fields. Is it necessary to use a Poisson solver?

  • +
  • Check the presence of numerical effects running the simulation with different numerical +parameters, e.g. changing the resolution, timestep, in the input namelist.

  • +
  • If using the AMcylindrical geometry, check that the origin of the axes you are using +in the input namelist is the one described in See Azimuthal modes decomposition.

  • +
+
+
+
+

Performances issues

+

The simulation is very slow / the performances are not as expected.

+
    +
  • Change the number of MPI process and OpenMP threads.

  • +
  • Change the number of patches and/or their distribution in each direction. +See also Parallelization basics.

  • +
  • Check that LoadBalancing is activated in the Write a namelist +(if the physical set-up is suitable for its use). See also Parallelization basics.

  • +
  • If using Vectorization, check that the compilation flags for vectorization +were correctly used. See also Install.

  • +
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_images/AM_grid_particles.jpg b/_images/AM_grid_particles.jpg new file mode 100644 index 000000000..aee819743 Binary files /dev/null and b/_images/AM_grid_particles.jpg differ diff --git a/_images/AM_modes.png b/_images/AM_modes.png new file mode 100644 index 000000000..ae4ccb766 Binary files /dev/null and b/_images/AM_modes.png differ diff --git a/_images/AMcylindrical_vs_cartesian.png b/_images/AMcylindrical_vs_cartesian.png new file mode 100644 index 000000000..0b378c84e Binary files /dev/null and b/_images/AMcylindrical_vs_cartesian.png differ diff --git a/_images/BTIS3_effect.png b/_images/BTIS3_effect.png new file mode 100644 index 000000000..576a51f75 Binary files /dev/null and b/_images/BTIS3_effect.png differ diff --git a/_images/Cluster_definition_doc.png b/_images/Cluster_definition_doc.png new file mode 100644 index 000000000..123ad357d Binary files /dev/null and b/_images/Cluster_definition_doc.png differ diff --git a/_images/Cluster_width_scan_doc.png b/_images/Cluster_width_scan_doc.png new file mode 100644 index 000000000..0b239af31 Binary files /dev/null and b/_images/Cluster_width_scan_doc.png differ diff --git a/_images/Coordinate_Reference_AMcylindrical.png b/_images/Coordinate_Reference_AMcylindrical.png new file mode 100644 index 000000000..b71cb5571 Binary files /dev/null and b/_images/Coordinate_Reference_AMcylindrical.png differ diff --git a/_images/DLB_balancing.png b/_images/DLB_balancing.png new file mode 100644 index 000000000..e0f991c9a Binary files /dev/null and b/_images/DLB_balancing.png differ diff --git a/_images/Energy_spectrum_laser_vs_envelope.png b/_images/Energy_spectrum_laser_vs_envelope.png new file mode 100644 index 000000000..cae6aff2a Binary files /dev/null and b/_images/Energy_spectrum_laser_vs_envelope.png differ diff --git a/_images/Envelope_Figure.png b/_images/Envelope_Figure.png new file mode 100644 index 000000000..fb263c136 Binary files /dev/null and b/_images/Envelope_Figure.png differ diff --git a/_images/FieldIonization.png b/_images/FieldIonization.png new file mode 100644 index 000000000..1d14549b9 Binary files /dev/null and b/_images/FieldIonization.png differ diff --git a/_images/LWFA_Plas@Par.jpg b/_images/LWFA_Plas@Par.jpg new file mode 100644 index 000000000..002204fcd Binary files /dev/null and b/_images/LWFA_Plas@Par.jpg differ diff --git a/_images/LaserOffsetAngle.png b/_images/LaserOffsetAngle.png new file mode 100644 index 000000000..e5408e263 Binary files /dev/null and b/_images/LaserOffsetAngle.png differ diff --git a/_images/MPIandOpenMP.png b/_images/MPIandOpenMP.png new file mode 100644 index 000000000..5d80ee574 Binary files /dev/null and b/_images/MPIandOpenMP.png differ diff --git a/_images/Maxwellianization1.png b/_images/Maxwellianization1.png new file mode 100644 index 000000000..2ba7d8365 Binary files /dev/null and b/_images/Maxwellianization1.png differ diff --git a/_images/NodeWith2Processes.png b/_images/NodeWith2Processes.png new file mode 100644 index 000000000..82f5c6df1 Binary files /dev/null and b/_images/NodeWith2Processes.png differ diff --git a/_images/NodesCoresThreads.png b/_images/NodesCoresThreads.png new file mode 100644 index 000000000..203f9c2db Binary files /dev/null and b/_images/NodesCoresThreads.png differ diff --git a/_images/PWFA.jpg b/_images/PWFA.jpg new file mode 100644 index 000000000..88f0c5130 Binary files /dev/null and b/_images/PWFA.jpg differ diff --git a/_images/PatchDecomposition.svg b/_images/PatchDecomposition.svg new file mode 100644 index 000000000..1d157ad03 --- /dev/null +++ b/_images/PatchDecomposition.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 960 cells + 32 patches + 5 MPI patch
collections + + diff --git a/_images/PatchDecompositionHilbert.svg b/_images/PatchDecompositionHilbert.svg new file mode 100644 index 000000000..005fa5399 --- /dev/null +++ b/_images/PatchDecompositionHilbert.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/PatchDecompositionNodes.svg b/_images/PatchDecompositionNodes.svg new file mode 100644 index 000000000..98ef5b870 --- /dev/null +++ b/_images/PatchDecompositionNodes.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + threads + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + threads + + + + + + + + + + + + + + + threads + + + + + + + + + + + + + + + threads + + + + + + + + + + + + + + + threads + + + + + + + + + diff --git a/_images/Patch_loadcomparision.jpg b/_images/Patch_loadcomparision.jpg new file mode 100644 index 000000000..1b141827b Binary files /dev/null and b/_images/Patch_loadcomparision.jpg differ diff --git a/_images/QED_cascade_electron_px_py_distribution.png b/_images/QED_cascade_electron_px_py_distribution.png new file mode 100644 index 000000000..adfcb2791 Binary files /dev/null and b/_images/QED_cascade_electron_px_py_distribution.png differ diff --git a/_images/QED_cascade_gamma_spectrum.png b/_images/QED_cascade_gamma_spectrum.png new file mode 100644 index 000000000..ce9f28ccf Binary files /dev/null and b/_images/QED_cascade_gamma_spectrum.png differ diff --git a/_images/QED_cascade_iteration_time.png b/_images/QED_cascade_iteration_time.png new file mode 100644 index 000000000..ec2b8a359 Binary files /dev/null and b/_images/QED_cascade_iteration_time.png differ diff --git a/_images/QED_cascade_photon_px_py_distribution.png b/_images/QED_cascade_photon_px_py_distribution.png new file mode 100644 index 000000000..8c4232913 Binary files /dev/null and b/_images/QED_cascade_photon_px_py_distribution.png differ diff --git a/_images/QED_cascade_scalar.png b/_images/QED_cascade_scalar.png new file mode 100644 index 000000000..8b7cabc48 Binary files /dev/null and b/_images/QED_cascade_scalar.png differ diff --git a/_images/Radiation_Pressure_Rho.png b/_images/Radiation_Pressure_Rho.png new file mode 100644 index 000000000..c2f43027b Binary files /dev/null and b/_images/Radiation_Pressure_Rho.png differ diff --git a/_images/Rho_2D_IonizationEnvelope_PRE.jpg b/_images/Rho_2D_IonizationEnvelope_PRE.jpg new file mode 100644 index 000000000..8689d66db Binary files /dev/null and b/_images/Rho_2D_IonizationEnvelope_PRE.jpg differ diff --git a/_images/SIMD.png b/_images/SIMD.png new file mode 100644 index 000000000..dbbb2994f Binary files /dev/null and b/_images/SIMD.png differ diff --git a/_images/Stopping_power123.png b/_images/Stopping_power123.png new file mode 100644 index 000000000..cbd8c6b91 Binary files /dev/null and b/_images/Stopping_power123.png differ diff --git a/_images/Task_tracing_doc.png b/_images/Task_tracing_doc.png new file mode 100644 index 000000000..ce4a94609 Binary files /dev/null and b/_images/Task_tracing_doc.png differ diff --git a/_images/TimeSelections.png b/_images/TimeSelections.png new file mode 100644 index 000000000..7aa790420 Binary files /dev/null and b/_images/TimeSelections.png differ diff --git a/_images/Weibel_3d_ne_vecto_it510.jpg b/_images/Weibel_3d_ne_vecto_it510.jpg new file mode 100644 index 000000000..c0f847769 Binary files /dev/null and b/_images/Weibel_3d_ne_vecto_it510.jpg differ diff --git a/_images/beam_relaxation123.png b/_images/beam_relaxation123.png new file mode 100644 index 000000000..2aeef29c2 Binary files /dev/null and b/_images/beam_relaxation123.png differ diff --git a/_images/beam_relaxation456.png b/_images/beam_relaxation456.png new file mode 100644 index 000000000..722a56723 Binary files /dev/null and b/_images/beam_relaxation456.png differ diff --git a/_images/beam_relaxation789.png b/_images/beam_relaxation789.png new file mode 100644 index 000000000..d124108d9 Binary files /dev/null and b/_images/beam_relaxation789.png differ diff --git a/_images/bin_decomposition.png b/_images/bin_decomposition.png new file mode 100644 index 000000000..0064b7c38 Binary files /dev/null and b/_images/bin_decomposition.png differ diff --git a/_images/conductivity.png b/_images/conductivity.png new file mode 100644 index 000000000..4c73357be Binary files /dev/null and b/_images/conductivity.png differ diff --git a/_images/counter_pair_smilei.png b/_images/counter_pair_smilei.png new file mode 100644 index 000000000..87a82d106 Binary files /dev/null and b/_images/counter_pair_smilei.png differ diff --git a/_images/data_container.png b/_images/data_container.png new file mode 100644 index 000000000..0a53444dc Binary files /dev/null and b/_images/data_container.png differ diff --git a/_images/data_structure.png b/_images/data_structure.png new file mode 100644 index 000000000..67a42139a Binary files /dev/null and b/_images/data_structure.png differ diff --git a/_images/decomposition_summary.png b/_images/decomposition_summary.png new file mode 100644 index 000000000..9f249e8dd Binary files /dev/null and b/_images/decomposition_summary.png differ diff --git a/_images/domain.png b/_images/domain.png new file mode 100644 index 000000000..a0390637d Binary files /dev/null and b/_images/domain.png differ diff --git a/_images/download.svg b/_images/download.svg new file mode 100644 index 000000000..e91a8d265 --- /dev/null +++ b/_images/download.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/element-logo.svg b/_images/element-logo.svg new file mode 100644 index 000000000..7334ac856 --- /dev/null +++ b/_images/element-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/factories.png b/_images/factories.png new file mode 100644 index 000000000..002989d91 Binary files /dev/null and b/_images/factories.png differ diff --git a/_images/figSpectra_LR.png b/_images/figSpectra_LR.png new file mode 100644 index 000000000..06e2f6122 Binary files /dev/null and b/_images/figSpectra_LR.png differ diff --git a/_images/figYee.png b/_images/figYee.png new file mode 100644 index 000000000..d19068729 Binary files /dev/null and b/_images/figYee.png differ diff --git a/_images/github-logo.svg b/_images/github-logo.svg new file mode 100644 index 000000000..9b6cc5331 --- /dev/null +++ b/_images/github-logo.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/_images/gothenburg.png b/_images/gothenburg.png new file mode 100644 index 000000000..ec3d0d75f Binary files /dev/null and b/_images/gothenburg.png differ diff --git a/_images/hhg1.jpg b/_images/hhg1.jpg new file mode 100644 index 000000000..8e401d0f7 Binary files /dev/null and b/_images/hhg1.jpg differ diff --git a/_images/hhg2.jpg b/_images/hhg2.jpg new file mode 100644 index 000000000..e73c45a29 Binary files /dev/null and b/_images/hhg2.jpg differ diff --git a/_images/iapras.png b/_images/iapras.png new file mode 100644 index 000000000..4915cd027 Binary files /dev/null and b/_images/iapras.png differ diff --git a/_images/idris.png b/_images/idris.png new file mode 100644 index 000000000..b5edba844 Binary files /dev/null and b/_images/idris.png differ diff --git a/_images/intel.png b/_images/intel.png new file mode 100644 index 000000000..c6312273c Binary files /dev/null and b/_images/intel.png differ diff --git a/_images/ionization_multiple.png b/_images/ionization_multiple.png new file mode 100644 index 000000000..6aa5c46b3 Binary files /dev/null and b/_images/ionization_multiple.png differ diff --git a/_images/ionization_rate.png b/_images/ionization_rate.png new file mode 100644 index 000000000..c0bb13541 Binary files /dev/null and b/_images/ionization_rate.png differ diff --git a/_images/ionization_recombination.png b/_images/ionization_recombination.png new file mode 100644 index 000000000..32cd1c8fe Binary files /dev/null and b/_images/ionization_recombination.png differ diff --git a/_images/ionization_stopping_power.png b/_images/ionization_stopping_power.png new file mode 100644 index 000000000..f0ae7fd6b Binary files /dev/null and b/_images/ionization_stopping_power.png differ diff --git a/_images/iramis.png b/_images/iramis.png new file mode 100644 index 000000000..c88e74bf1 Binary files /dev/null and b/_images/iramis.png differ diff --git a/_images/irap.png b/_images/irap.png new file mode 100644 index 000000000..7a298ffaa Binary files /dev/null and b/_images/irap.png differ diff --git a/_images/llr.png b/_images/llr.png new file mode 100644 index 000000000..0db69dfb8 Binary files /dev/null and b/_images/llr.png differ diff --git a/_images/lpgp.png b/_images/lpgp.png new file mode 100644 index 000000000..2eaf757dc Binary files /dev/null and b/_images/lpgp.png differ diff --git a/_images/lpp.png b/_images/lpp.png new file mode 100644 index 000000000..4b3520443 Binary files /dev/null and b/_images/lpp.png differ diff --git a/_images/luli.png b/_images/luli.png new file mode 100644 index 000000000..0e27f464b Binary files /dev/null and b/_images/luli.png differ diff --git a/_images/magnetic_shower_gamma_distribution_log.png b/_images/magnetic_shower_gamma_distribution_log.png new file mode 100644 index 000000000..b04640a6b Binary files /dev/null and b/_images/magnetic_shower_gamma_distribution_log.png differ diff --git a/_images/magnetic_shower_photon_energy_distribution.png b/_images/magnetic_shower_photon_energy_distribution.png new file mode 100644 index 000000000..b32c33a61 Binary files /dev/null and b/_images/magnetic_shower_photon_energy_distribution.png differ diff --git a/_images/magnetic_shower_photon_pxpy_distribution.png b/_images/magnetic_shower_photon_pxpy_distribution.png new file mode 100644 index 000000000..bdec9a47f Binary files /dev/null and b/_images/magnetic_shower_photon_pxpy_distribution.png differ diff --git a/_images/mbw_T.png b/_images/mbw_T.png new file mode 100644 index 000000000..334ca397c Binary files /dev/null and b/_images/mbw_T.png differ diff --git a/_images/mbw_min_particle_chi.png b/_images/mbw_min_particle_chi.png new file mode 100644 index 000000000..6634b401b Binary files /dev/null and b/_images/mbw_min_particle_chi.png differ diff --git a/_images/mbw_xi.png b/_images/mbw_xi.png new file mode 100644 index 000000000..ed6b90391 Binary files /dev/null and b/_images/mbw_xi.png differ diff --git a/_images/mdls.png b/_images/mdls.png new file mode 100644 index 000000000..b7f428f8a Binary files /dev/null and b/_images/mdls.png differ diff --git a/_images/mpi_patch_collection.png b/_images/mpi_patch_collection.png new file mode 100644 index 000000000..0057b3e52 Binary files /dev/null and b/_images/mpi_patch_collection.png differ diff --git a/_images/nics_h_niel.png b/_images/nics_h_niel.png new file mode 100644 index 000000000..cdeeb7d87 Binary files /dev/null and b/_images/nics_h_niel.png differ diff --git a/_images/nics_integration_F_over_chi.png b/_images/nics_integration_F_over_chi.png new file mode 100644 index 000000000..ad3d0d81b Binary files /dev/null and b/_images/nics_integration_F_over_chi.png differ diff --git a/_images/nics_min_photon_chi.png b/_images/nics_min_photon_chi.png new file mode 100644 index 000000000..6a1b6929b Binary files /dev/null and b/_images/nics_min_photon_chi.png differ diff --git a/_images/nics_xi.png b/_images/nics_xi.png new file mode 100644 index 000000000..ed2720521 Binary files /dev/null and b/_images/nics_xi.png differ diff --git a/_images/openMP_balancing.png b/_images/openMP_balancing.png new file mode 100644 index 000000000..3d661fb2c Binary files /dev/null and b/_images/openMP_balancing.png differ diff --git a/_images/openpmd.jpg b/_images/openpmd.jpg new file mode 100644 index 000000000..4e7ea8f36 Binary files /dev/null and b/_images/openpmd.jpg differ diff --git a/_images/operator.png b/_images/operator.png new file mode 100644 index 000000000..81635679c Binary files /dev/null and b/_images/operator.png differ diff --git a/_images/p2io.png b/_images/p2io.png new file mode 100644 index 000000000..9bb002e64 Binary files /dev/null and b/_images/p2io.png differ diff --git a/_images/palm.png b/_images/palm.png new file mode 100644 index 000000000..ea215277e Binary files /dev/null and b/_images/palm.png differ diff --git a/_images/paper.svg b/_images/paper.svg new file mode 100644 index 000000000..9bc194a85 --- /dev/null +++ b/_images/paper.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/_images/paper_topics.png b/_images/paper_topics.png new file mode 100644 index 000000000..6a6eaa7c1 Binary files /dev/null and b/_images/paper_topics.png differ diff --git a/_images/particle_injector.png b/_images/particle_injector.png new file mode 100644 index 000000000..d1eb585bb Binary files /dev/null and b/_images/particle_injector.png differ diff --git a/_images/particle_injector_regular_random.png b/_images/particle_injector_regular_random.png new file mode 100644 index 000000000..693d711b1 Binary files /dev/null and b/_images/particle_injector_regular_random.png differ diff --git a/_images/patch_domain_decomposition.png b/_images/patch_domain_decomposition.png new file mode 100644 index 000000000..c33cb0409 Binary files /dev/null and b/_images/patch_domain_decomposition.png differ diff --git a/_images/people.svg b/_images/people.svg new file mode 100644 index 000000000..5bd995e05 --- /dev/null +++ b/_images/people.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/_images/plasapar.png b/_images/plasapar.png new file mode 100644 index 000000000..ba4d164f3 Binary files /dev/null and b/_images/plasapar.png differ diff --git a/_images/pump_seed.jpg b/_images/pump_seed.jpg new file mode 100644 index 000000000..16a2c7bfc Binary files /dev/null and b/_images/pump_seed.jpg differ diff --git a/_images/pythonprofiles.png b/_images/pythonprofiles.png new file mode 100644 index 000000000..ac8ca75d0 Binary files /dev/null and b/_images/pythonprofiles.png differ diff --git a/_images/pythonprofiles_t.png b/_images/pythonprofiles_t.png new file mode 100644 index 000000000..08c17467c Binary files /dev/null and b/_images/pythonprofiles_t.png differ diff --git a/_images/qed_pair_cascade.png b/_images/qed_pair_cascade.png new file mode 100644 index 000000000..554e019b2 Binary files /dev/null and b/_images/qed_pair_cascade.png differ diff --git a/_images/rad_counter_prop_scalar.png b/_images/rad_counter_prop_scalar.png new file mode 100644 index 000000000..9adada54b Binary files /dev/null and b/_images/rad_counter_prop_scalar.png differ diff --git a/_images/rad_counter_prop_track.png b/_images/rad_counter_prop_track.png new file mode 100644 index 000000000..164726869 Binary files /dev/null and b/_images/rad_counter_prop_track.png differ diff --git a/_images/reconnection.jpg b/_images/reconnection.jpg new file mode 100644 index 000000000..dfc50b6ce Binary files /dev/null and b/_images/reconnection.jpg differ diff --git a/_images/shock1.jpg b/_images/shock1.jpg new file mode 100644 index 000000000..84470c65c Binary files /dev/null and b/_images/shock1.jpg differ diff --git a/_images/shock3.jpg b/_images/shock3.jpg new file mode 100644 index 000000000..9bde0ebad Binary files /dev/null and b/_images/shock3.jpg differ diff --git a/_images/smileiIconRed.svg b/_images/smileiIconRed.svg new file mode 100644 index 000000000..13548b1fa --- /dev/null +++ b/_images/smileiIconRed.svg @@ -0,0 +1,37 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/_images/smileiLogo.svg b/_images/smileiLogo.svg new file mode 100644 index 000000000..1b70b4a5c --- /dev/null +++ b/_images/smileiLogo.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + diff --git a/_images/smilei_main_loop.png b/_images/smilei_main_loop.png new file mode 100644 index 000000000..e3120f7e2 Binary files /dev/null and b/_images/smilei_main_loop.png differ diff --git a/_images/spherical_coordinates.png b/_images/spherical_coordinates.png new file mode 100644 index 000000000..411ad3dfe Binary files /dev/null and b/_images/spherical_coordinates.png differ diff --git a/_images/spherical_discretization.png b/_images/spherical_discretization.png new file mode 100644 index 000000000..f4524cd39 Binary files /dev/null and b/_images/spherical_discretization.png differ diff --git a/_images/synchrotron_pairs_dNdt.png b/_images/synchrotron_pairs_dNdt.png new file mode 100644 index 000000000..4b3143502 Binary files /dev/null and b/_images/synchrotron_pairs_dNdt.png differ diff --git a/_images/synchrotron_pairs_energy_spectra_chi1.png b/_images/synchrotron_pairs_energy_spectra_chi1.png new file mode 100644 index 000000000..71665cd7e Binary files /dev/null and b/_images/synchrotron_pairs_energy_spectra_chi1.png differ diff --git a/_images/synchrotron_pairs_energy_spectra_chi20.png b/_images/synchrotron_pairs_energy_spectra_chi20.png new file mode 100644 index 000000000..ba89b101b Binary files /dev/null and b/_images/synchrotron_pairs_energy_spectra_chi20.png differ diff --git a/_images/synchrotron_scalar.png b/_images/synchrotron_scalar.png new file mode 100644 index 000000000..4b79fc9e8 Binary files /dev/null and b/_images/synchrotron_scalar.png differ diff --git a/_images/synchrotron_t_gamma_ne.png b/_images/synchrotron_t_gamma_ne.png new file mode 100644 index 000000000..656184caa Binary files /dev/null and b/_images/synchrotron_t_gamma_ne.png differ diff --git a/_images/synchrotron_x_y_gamma.png b/_images/synchrotron_x_y_gamma.png new file mode 100644 index 000000000..828940d8b Binary files /dev/null and b/_images/synchrotron_x_y_gamma.png differ diff --git a/_images/temperature_isotropization1.png b/_images/temperature_isotropization1.png new file mode 100644 index 000000000..b8f5eac0e Binary files /dev/null and b/_images/temperature_isotropization1.png differ diff --git a/_images/thermalisation_ei123.png b/_images/thermalisation_ei123.png new file mode 100644 index 000000000..92e9dc299 Binary files /dev/null and b/_images/thermalisation_ei123.png differ diff --git a/_images/thin_foil_scalar.png b/_images/thin_foil_scalar.png new file mode 100644 index 000000000..82e965041 Binary files /dev/null and b/_images/thin_foil_scalar.png differ diff --git a/_images/thin_foil_x_chi_ne.png b/_images/thin_foil_x_chi_ne.png new file mode 100644 index 000000000..ca233538a Binary files /dev/null and b/_images/thin_foil_x_chi_ne.png differ diff --git a/_images/thin_foil_x_px_ne.png b/_images/thin_foil_x_px_ne.png new file mode 100644 index 000000000..1e77c942e Binary files /dev/null and b/_images/thin_foil_x_px_ne.png differ diff --git a/_images/transverse_axis.png b/_images/transverse_axis.png new file mode 100644 index 000000000..cad8a42d3 Binary files /dev/null and b/_images/transverse_axis.png differ diff --git a/_images/userDefinedRate.png b/_images/userDefinedRate.png new file mode 100644 index 000000000..9a728664d Binary files /dev/null and b/_images/userDefinedRate.png differ diff --git a/_images/vecto_domain_decomposition.png b/_images/vecto_domain_decomposition.png new file mode 100644 index 000000000..4978813de Binary files /dev/null and b/_images/vecto_domain_decomposition.png differ diff --git a/_images/vecto_efficiency_o2_all_fit.png b/_images/vecto_efficiency_o2_all_fit.png new file mode 100644 index 000000000..3a42cd204 Binary files /dev/null and b/_images/vecto_efficiency_o2_all_fit.png differ diff --git a/_images/vecto_efficiency_o2_all_mc.png b/_images/vecto_efficiency_o2_all_mc.png new file mode 100644 index 000000000..dd8f973ce Binary files /dev/null and b/_images/vecto_efficiency_o2_all_mc.png differ diff --git a/_images/vecto_particle_times_o2_all.png b/_images/vecto_particle_times_o2_all.png new file mode 100644 index 000000000..346be075b Binary files /dev/null and b/_images/vecto_particle_times_o2_all.png differ diff --git a/_images/vranic_3d_schematics.png b/_images/vranic_3d_schematics.png new file mode 100644 index 000000000..7ac8c42cf Binary files /dev/null and b/_images/vranic_3d_schematics.png differ diff --git a/_images/vranic_momentum_cell_vector.png b/_images/vranic_momentum_cell_vector.png new file mode 100644 index 000000000..5fa445cd7 Binary files /dev/null and b/_images/vranic_momentum_cell_vector.png differ diff --git a/_images/vranic_momentum_discretization.png b/_images/vranic_momentum_discretization.png new file mode 100644 index 000000000..c9650e5a6 Binary files /dev/null and b/_images/vranic_momentum_discretization.png differ diff --git a/_images/vranic_particle_merging.png b/_images/vranic_particle_merging.png new file mode 100644 index 000000000..2440bf65f Binary files /dev/null and b/_images/vranic_particle_merging.png differ diff --git a/_images/vranic_planar_merging.png b/_images/vranic_planar_merging.png new file mode 100644 index 000000000..7bd7728ea Binary files /dev/null and b/_images/vranic_planar_merging.png differ diff --git a/_images/weak_scaling_efficiency.png b/_images/weak_scaling_efficiency.png new file mode 100644 index 000000000..04545f128 Binary files /dev/null and b/_images/weak_scaling_efficiency.png differ diff --git a/_sources/Overview/highlights.rst.txt b/_sources/Overview/highlights.rst.txt new file mode 100644 index 000000000..1e755f6e2 --- /dev/null +++ b/_sources/Overview/highlights.rst.txt @@ -0,0 +1,459 @@ +Highlights +---------- + +Improved performance using GPU offloading +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:program:`Smilei` computational performance has been recently enhanced with GPU offloading support, +in particular the projection of current has been accelerated with a CUDA kernel while other features +have been accelerated with the use of either OpenAcc Pragmas or OpenMP pragmas. + +SMILEI can bes tested on recent supercomputers such as Adastra where it shows great weak scaling efficiency even while using diagnostics as shown in figure below: + +.. image:: /_static/weak_scaling_efficiency.png + :width: 12cm + :align: center + +---- + +Mitigation of numerical artifacts with relativistic particles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The staggering in space and time of the electromagnetic fields and the numerical dispersion of electromagnetic solvers +using finite differences in the time domain, typically used in electromagnetic Particle in Cell codes, create +numerical artifacts that become increasingly detrimental in presence of relativisitc macro-particles. + +A typical example of simulation where the effects of these artifacts can become relevant and alter the numerical results +is Laser Wakefield Acceleration. In this kind of simulation, a numerical artifact called Numerical Cherenkov Radiation is +generated by the spurious interaction between relativistic macro-particles and electromagnetic fields that are numerically +slower due to the dispersion of the Finite Difference Time Domain solver for Maxwell's equations. +This artifact can significantly alter the dynamics of relativistic electron beams accelerated in plasma waves, quickly increasing +their divergence along their propagation in the plasma. + +Recently an interpolation scheme called B-TIS3 has been implemented in the code CALDER and published in `P.-L. Bourgeois, X. Davoine (2023) `_ +This scheme can significantly reduce the effects of Numerical Cherenkov Radiation and of the staggering of the electromagnetic fields, +as shown in this Figure: + +.. image:: /_static/BTIS3_effect.png + :width: 18cm + :align: center + +Both panels show a field proportional to the `y` component of the Lorentz force acting on the electron macro-particles in a Smilei simulation of Laser Wakefield Acceleration. +Top panel: simulation not using the B-TIS3 interpolation. +Bottom panel: simulation using the B-TIS3 interpolation. +The high frequency modulations, due to the Numerical Cherenkov Radiation are evident in the top panel, while they are +considerably reduced in the bottom panel. +These two simulations were obtained using the `AMcylindrical` geometry (1 azimuthal mode) and the Laser Envelope model. + + +---- + + +Laser Envelope model and averaged tunnel ionization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Laser-plasma interaction in underdense plasmas can be accurately simulated under certain conditions through a +laser envelope model, where the high frequency oscillations of the laser pulse do not need to be resolved. +In this model the laser effect on the plasma is described through the ponderomotive force and the effect of the precence of the +plasma on the laser pulse is described through the plasma susceptibility. These terms in the laser plasma interaction +can be expressed only as function of the laser complex envelope. + +This technique relaxes the constraint on the minimum spatial and temporal scales to be resolved and can yield +speed-ups of some orders of magnitude, expecially if coupled with a purely cylindrical geometry +(where only one azimuthal mode is taken into account). + +The envelope model is particularly used for Laser Wakefield Acceleration, where often the laser pulse envelope is at least ten +times longer than the laser carrier wavelength. Recently an new averaged tunnel ionization model has been developed for the envelope model, +allowing the simulation of Laser Wakefield Acceleration with ionization injection with this efficient technique. + +Following is the comparison of the electron density from two LWFA simulations, one using the laser envelope model and the averaged +tunnel ionization module (a) and one without the envelope model (b). + +.. image:: /_static/Rho_2D_IonizationEnvelope_PRE.jpg + :width: 14cm + :align: center + + +In these simulations an intense laser pulse is propagating in a plasma composed of helium and partially ionized nitrogen. +The laser field near the pulse's center is intense enough to further ionize the nitrogen ions, releasing electrons that can be trapped and +accelerated in the relativistic plasma wave behind the laser pulse. + +Previous averaged tunnel ionization models did not allow to accurately describe this LWFA scheme at relativistic regimes. +In this new model also the longitudinal momentum of the electrons obtained through ionization is initialized following analytical derivations. +Including this longitudinal momentum initialization allows to accurately describe the dynamics of these electrons. + +Following is a comparison of the accelerated electron spectra at the end of these simulations. + +.. image:: /_static/Energy_spectrum_laser_vs_envelope.png + :width: 14cm + :align: center + +In the green line it is shown the result of the previously known averaged ionization model. Without the longitudinal +momentum initialization, few electrons obtained through ionization are trapped and accelerated in the plasma wave. +The red line shows the result with the new averaged ionization model implemented in :program:`Smilei`, which accurately reproduces +the spectrum obtained with the simulation without an envelope model (blue line). + + +The envelope simulation required an amount of computing resources orders of magnitude smaller than those required by the simulation without a +laser envelope model. + +More details on the envelope model and the averaged tunnel ionization model in :program:`Smilei` can be found `here `_ + +---- + +Field initialization of a relativistic particle beam +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In Plasma Wakefield Acceleration (PWFA) a plasma wave is generated behind a relativistic particle +beam propagating in a plasma. + +To simulate this phenomenon, it is necessary to self-consistently initialize the electromagnetic fields +of a relativistic particle beam in vacuum, before its entrance into the plasma. + +Following is the image of a PWFA simulation which used this technique at its start. + +.. image:: /_static/PWFA.jpg + :width: 14cm + :align: center + +The "driver" relativistic electron beam (in yellow) propagates through a plasma and drives a nonlinear Langmuir wave (in blue) that +propagates at a velocity close to that of light in its wake. A "witness" relativistic electron bunch injected in this wave +can be accelerated with electric fields orders of magnitude higher than those sustainable by metallic radio-frequency +accelerating cavities. + +---- + +Azimuthal Fourier decomposition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In Laser Wakefield Acceleration (LWFA) a plasma wave is generated behind an intense laser pulse +propagating in an underdense plasma. +The physics in this phenomenon cannot be accurately simulated through 2D Cartesian +simulations. Nonetheless, 3D Cartesian simulations can be computationally demanding, +hence preliminary studies for LWFA experiments, typically consisting of many PIC simulations, +cannot be realissically be carried with 3D Cartesian simulations. + +The azimuthal Fourier decomposition addresses this issue by using a cylindrical grid, hence +a 2D grid, decomposing the fields in azimuthal harmonics to take into account a third dimension in space +and treating macro-particles in the 6D phase space. + +This technique can yield thus simulations with a computational cost comparable to that of 2D simulations, but +at the same time with an accuracy comparable to that of a full 3D Cartesian simulation. + +Following is the image of a LWFA simulation using azimuthal Fourier decomposition, which has made it +feasible in a medium-scale laboratory cluster. An equivalent 3D Cartesian simulation would have required +an amount of resources greater by at least an order of magnitude. + +.. image:: /_static/LWFA_Plas@Par.jpg + :width: 13cm + :align: center + +The laser (in red) propagates through a low density plasma and drives a nonlinear Langmuir wave (in blue) that +propagates at a velocity close to that of light in its wake. In this simulation, a moving window is used +so we can follow the laser as it propagates through the plasma. We see electrons (in white) being self-injected +in this wakefield where they see a strong electric field that accelerates them up to ultra-relativistic (GeV) energy level. + +An animation generated from the simulation data can be found `here `_ + +---- + +Improved performance using vectorization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:program:`Smilei` computational performance has been recently enhanced with +:doc:`vectorized operations`, +in particular the projection of currents and the interpolation of fields. +Typically, the new algorithms are more efficient than the old ones above +10 particles per cell, up to 3 times faster. An *adaptive* switching technique +ensures that the best version is used, dynamically and locally. + +This has been validated on large-scale simulations. +An example of a mildly-relativistic collisionless shock simulation is provided +in :numref:`weibel_3d_ne_vecto_it510_fig1` (watch the `video `_). + +.. _weibel_3d_ne_vecto_it510_fig1: + +.. figure:: /_static/Weibel_3d_ne_vecto_it510.jpg + :width: 90% + :align: center + :name: weibel_3d_ne_vecto_it510 + + Mildly-relativistic collisionless shock simulation, with two drifting + plasmas colliding in the middle of the box. + Top panel: electron density. + Bottom panel: regions switched to vectorized operators are highlighted. + +High-density regions are switched to vectorized operators while low-density +regions remain scalar (they have only 8 particles per cell). +In this particular case, the treatment of particles can be sped-up by 2. + +For more details, checkout the :doc:`doc` and this +`ArXiV paper `_. + +---- + +Scalability in a wakefield acceleration simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Wakefield-acceleration of electrons in an underdense plasma creates a +hotspot of electrons, which makes the simulation strongly imbalanced. +This spot represent a large part of the total calculations, so that +more computing power should be allocated on it. + +Please refer to the doc :doc:`/Understand/parallelization` to learn the basics of the +parallelization techniques employed in this section. + +.. rubric :: 1. OpenMP + +In a local area around this hotspot, OpenMP is able to manage the computing +resources to make the overall simulation faster. The following figure shows +the evolution of the time to calculate 100 iterations, as a function of time. +Each line corresponds to a different partition of the box in terms of +MPI processes and OpenMP threads: :math:`N\times M`, where :math:`N` is +the total number of MPI processes, and :math:`M` is the number of threads +in each MPI process. + +.. image:: /_static/openMP_balancing.png + :width: 500px + :align: center + +Using more OpenMP threads per MPI process (while keeping the total number +of threads constant) clearly reduces the simulation time, because the +computing power is balanced within each MPI patch collection. + + +.. rubric :: 2. Dynamic load balancing between MPI processes + +At the global simulation scale, OpenMP cannot be used to smoothen the balance. +Instead, a dynamic load balancing (DLB) algorithm periodically exchanges pieces of +the simulation box (*patches*) between MPI processes, so that each MPI +process owns a fair amount of the simulation load. The following figure +shows how this balancing reduces the time of the simulation. + +.. image:: /_static/DLB_balancing.png + :width: 500px + :align: center + +The red curve is the best situation obtained in the previous section, while +the black curve corresponds to the DLB algorithm enabled. + +The portion of the box belonging to each MPI process varies when the load balancing +occurs. The following figure shows how each of these portions evolve with time. + +.. image:: /_static/Patch_loadcomparision.jpg + +The four panels correspond to four timesteps during the simulation. +The colorscale represents the log-scaled load of each patch. +The black lines show the borders of each MPI process' portion of the box. +The MPI processes that are close to the hotspot tend to handle a smaller portion +of the box. + +---- + +High-harmonic generation +^^^^^^^^^^^^^^^^^^^^^^^^ + +The interaction between an ultra-intense (:math:`I>10^{18}~{\rm W/cm^2}`) femtosecond laser pulse +with a solid target generates a dense "plasma mirror" at its surface that reflects the laser +in a strongly non-linear manner. The temporal distortion of the reflected wave creates +a train of ultra-short attosecond pulses, associated, in the frequency domain, +to a comb of high-order harmonics. + +We present a 2-dimensional :program:`Smilei` simulation of laser-solid interaction +with wavelength :math:`\lambda_0 = 0.8` µm, peak intensity +:math:`2\times10^{19}~{\rm W/cm^2}`, at 45° incidence with p-polarization on an overdense plasma slab +of constant electron density :math:`n_0=200\,n_c` (:math:`n_c` being the critical density), +:math:`5\lambda_0`-thick, with an exponential pre-plasma of gradient length :math:`0.1\,\lambda_0` +down to a cut-off density :math:`0.05\,n_c`. The full box size is +:math:`80\,\lambda_0 \times 60\lambda_0` and the simulation time :math:`150\,\lambda_0/c` +with a total of :math:`\sim 1.4` billion quasi-particles in the box. + +The following figure (top panel) shows half of the simulation box in the +y-direction, and the laser field is reported at three different times. +The reflected laser pulse (at time :math:`t_2`) shows a different spectral content than +the incident pulse (at time :math:`t_0`). The plasma electron density is shown in black. +A close-up view of the interaction region is given in the bottom panel, illustrating +the electron bunches being pulled out from the plasma surface. + +.. image:: /_static/hhg1.jpg + :width: 13cm + :align: center + +Fourier analysis of the reflected laser field, in space and time, provides the +angular distribution of the frequency spectrum of the reflected light, shown in the +following figure (top panel). High harmonics appear up to order 16. + +.. image:: /_static/hhg2.jpg + :width: 13cm + :align: center + +The bottom panel shows trajectories of accelerated electrons ejected from the target. +The angular histogram shows that the momenta of the escaping energetic electrons +(1 to 10 MeV) are mostly directed along two directions which are close to the reflected +laser direction. + +This simulation was run on the CINES/Occigen (Bullx) machine using 256 MPI x 14 OpenMP +threads for about 10700 CPU-hours. The characteristic computing time per particle +(average PIC iteration divided by the number of particles) is of the order of +0.7 µs, including 25% for diagnostics. + + + + + +---- + +Brillouin amplification +^^^^^^^^^^^^^^^^^^^^^^^ + +Coupling, in a plasma, a long energetic "pump" pulse of moderate intensity to +a short counter-propagating "seed" pulse of initially low intensity can transfer energy +from the pump to the seed thanks to the excitation of a plasma or ion-acoustic wave. + +Here, we look specifically at +the `stimulated Brillouin scattering `_ +(SBS) amplification, where the excited waves are ion-acoustic waves. + +A pump with intensity :math:`10^{15}` W/cm² (wavelength 1 µm) +correspond to the "strong-coupling" regime, particularly robust with respect to +plasma inhomogeneities and seed frequency [Chiaramello2016]_. + +A 2-dimensional simulation, in conditions close to actual experiments, ran +on a box size of 1024 µm x 512 µm for 10 ps +with 25 billion quasi-particles. The following figure shows the evolution +of the pump and seed intensities in the head-on collision at three different times. +The blue-yellow maps correspond to the plasma density while the white-red maps +correspond to the lasers intensity. + +.. image:: /_static/pump_seed.jpg + :align: center + +The final seed intensity is nearly 5 times its initial intensity +while the spot size and phase front are well conserved, +suggesting that such a beam could be further focused using plasma mirrors. + +This simulation used the IDRIS/Turing (BlueGene/Q) super-computer using 1.8 million +CPU-hours on 32768 MPI processes, and 4 OpenMP threads per core. +The average time to push a particle was 1.9 µs, including 5% +for diagnostics. On the CINES/Occigen (Bullx) machine, we obtained an average time +of 0.43 µs to push one particle (without diagnostics). + +---- + +Magnetic reconnection at the Earth magnetopause +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Magnetic reconnection at the Earth magnetopause regulates the transport of matter, +momentum and energy from the solar wind to the internal magnetosphere. +The solar wind plasma temperature is typically one tenth that of the magnetospheric plasma, +but its density is about ten times larger, and its magnetic field 2-3 times smaller. +This asymmetry makes the reconnection dynamics vastly more complex than in symmetric +environments, and has only been studied for a decade +via `numerical simulations `_ +and spacecraft observations. + +Studying the impact of a plasmaspheric plume on magnetopause reconnection +via kinetic numerical simulation is difficult. The simulation first needs +to reach a quasi-steady state reconnection with a typical magnetopause asymmetry, +see the arrival of the plume and then last longer for a quasi-steady state plume +reconnection regime to settle. Due to the large particle density of plumes, +the transition and last phases have substantially longer time scales than the early phase, +which makes the simulation heavy. The domain must be long enough in the downstream direction +for the plasma, expelled during the early and transition phases, to be evacuated from +the reconnection region. Otherwise, upstream plasma would not inflow, +thereby stopping reconnection. + +Three ion populations are present. +The solar wind and magnetospheric populations have densities equal to :math:`n_0` and :math:`n_0/10`, +respectively, on their side of the current sheet, and fall to zero on the other side. +The plume population increases from 0 to :math:`2\,n_0` at :math:`20\,c/\omega_{pi}` from the initial +current sheet on the magnetospheric side. The magnetic field amplitude goes from :math:`2\,B_0` +in the magnetosphere to :math:`B_0=m_e\omega_{pe}/e` in the solar wind and is totally in the +simulation plane. The temperature is initially isotropic and its profile is calculated +to balance the total pressure. + +The domain size is 1280 :math:`c/\omega_{pi} \times` 256 :math:`c/\omega_{pi}`. +The total simulation time is :math:`800\times` the ion gyration time. +We used a reduced ion to electron mass ratio :math:`m_i/m_e = 25`, and a ratio +50 of the speed of light by the Alfvén velocity. +There are initially 8.6 billion quasi-protons for the three populations, and 13 billion electrons. + +.. image:: /_static/reconnection.jpg + :width: 15cm + :align: center + +This figure presents some of the simulation results: +the electron density at three different times. +In the top panel, reconnection is in steady state between the solar wind plasma of +density :math:`\simeq n_0` and the magnetosphere plasma of density :math:`\simeq 0.1~n_0`. +At this time, the exhaust is filled with mixed solar wind/hot magnetospheric plasma as +the plume (of density :math:`\simeq 2~n_0`) is still located at :math:`\simeq 10~c/\omega_{pi}` +from the magnetospheric separatrix. The reconnection rate during this period has a +typical value around :math:`0.1~\Omega_{ci}^{-1}`, with important fluctuations caused +by plasmoid formation. The plume, originally at :math:`20~c/\omega_{pi}` from the magnetopause, +is slowly advected towards the magnetosphere separatrix and finally touches the +reconnection site at about :math:`t=300~\Omega_{ci}^{-1}`. The second panel at +:math:`t=370~\Omega_{ci}^{-1}` shows the plume starting to fill the exhaust after +reaching the reconnection site and mixing with solar wind plasma. +At this time, the reconnection rate collapses to about half its previous value. +The transition phase lasts for about :math:`100~\Omega_{ci}^{-1}` before a plume +reconnection regime reaches a quasi-steady state. +The third panel shows the electron density at the end of the simulation, +where the exhaust is filled with plume and solar wind plasma. + +This large-scale simulation has run for a total of 14 million CPU-hours on 16384 cores +of the CINES/Occigen (Bullx) supercomputer within a GENCI-CINES special call. +Overall, the characteristic (full) push-time for a single particle was of the order +of 1.6 µs (including 31% for diagnostics). +No dynamic load balancing was used for this simulation. + +---- + +Collisionless shock in pair plasmas +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Relativistic collisionless shocks play a fundamental role in various astrophysical scenarios +(active galactic nuclei, micro-quasars, pulsar wind nebulae and gamma-ray bursts) +where they cause high-energy radiation and particle acceleration related to the +cosmic-ray spectrum. In the absence of particle collisions, the shock is mediated +by collective plasma processes, produced by electromagnetic plasma instabilities +at the shock front. + +Specifically, the Weibel (or current filamentation) instability +is observed in most of the astrophysical relativistic outflows interacting with +the interstellar medium. It can be excited by counter-streaming unmagnetized relativistic +flows, and dominates the instability spectrum for a wide range of parameters. +The resulting strong magnetic turbulence can isotropize the incoming flow, +hence stopping it and leading to compression of the downstream (shocked plasma) and shock formation. + +We present a 2-dimensional PIC simulation of such shock, +driven in an initially unmagnetized electron-positron plasma. +The simulation relies on the "piston" method that consists in initializing the +simulation with a single cold electron-positron plasma drifting +at a relativistic velocity :math:`v_0 \simeq 0.995\,c`. +Reflecting boundary conditions at the right border creates a counter-penetrating flow. + +The simulation box size is 2048 :math:`\delta_e \times` 128 :math:`\delta_e` +(:math:`\delta_e = c/\omega_p` being the electron skin-depth of the initial flow), +with a total of 2.15 billion quasi-particles. +The following figure show an unstable overlapping region of incoming and +reflected flows, resulting in the creation, before the shock +of filamentary structures in both the magnetic field (panel a) and +the total plasma density (panel b). + +.. image:: /_static/shock1.jpg + :width: 15cm + :align: center + +The magnetic field at the shock front becomes turbulent and it is strong +enough to stop the incoming particles leading to a pile-up of the plasma +density (panel c). + + +The following figure demonstrates the build-up, at late times, of a supra-thermal tail +in the downstream particle energy distribution. +It is characteristic of first-order Fermi acceleration at the shock front, +and appears to follow a :math:`\gamma^{-2.5}` power law. + +.. image:: /_static/shock3.jpg + :width: 11cm + :align: center + +This simulation run on the TGCC/Curie machine using 128 MPI x 8 OpenMP threads +for a total of 18800 CPU-hours for 49780 timesteps. +The average push time for one quasi-particle was of 0.63 µs (including 20% for diagnostics). \ No newline at end of file diff --git a/_sources/Overview/licence.rst.txt b/_sources/Overview/licence.rst.txt new file mode 100644 index 000000000..65f06a09e --- /dev/null +++ b/_sources/Overview/licence.rst.txt @@ -0,0 +1,36 @@ +Licence +------- + +:program:`Smilei` is protected by a **licence CeCILL**, the french equivalent to +the open-source Gnu GPL license. + +Extract: + + *This software is governed by the CeCILL-B license under French law and + abiding by the rules of distribution of free software. You can use, + modify and/ or redistribute the software under the terms of the CeCILL-B + license as circulated by CEA, CNRS and INRIA at the following URL* + `http://www.cecill.info `_. + +More information `here `_. + +---- + +.. _HowToCite: + +How to cite Smilei +^^^^^^^^^^^^^^^^^^ + +Smilei's development depends on its visibility from publications or presentations +featuring its results. When publishing simulation results involving Smilei, +**please cite the following article**: + + J. Derouillat, A. Beck, F. Pérez, T. Vinci, M. Chiaramello, A. Grassi, M. Flé, G. Bouchard, I. Plotnikov, N. Aunai, J. Dargent, C. Riconda, M. Grech, + `SMILEI: a collaborative, open-source, multi-purpose particle-in-cell code for plasma simulation`, + `Comput. Phys. Commun. 222, 351-373 (2018) `_, + +If help or changes in the code were obtained from Smilei developers, +please acknowledge their participation in any subsequent publication or presentation. + +If your publication makes significant use of Smilei, we will gladly list it +in the :doc:`material`. diff --git a/_sources/Overview/material.rst.txt b/_sources/Overview/material.rst.txt new file mode 100644 index 000000000..34c183811 --- /dev/null +++ b/_sources/Overview/material.rst.txt @@ -0,0 +1,895 @@ + +.. rst-class:: bigcitation + +Publications +------------ + +.. rst-class:: emphlink + + Tip: :ref:`How should I cite Smilei in my publication? ` + +.. rst-class:: emphlink + + Tip: :ref:`How can I add my publication to this list? ` + +---- + +Reference article +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. [Derouillat2018] + + J. Derouillat, A. Beck, F. Pérez, T. Vinci, M. Chiaramello, A. Grassi, M. Flé, G. Bouchard, I. Plotnikov, N. Aunai, J. Dargent, C. Riconda and M. Grech, + `SMILEI: a collaborative, open-source, multi-purpose particle-in-cell code for plasma simulation`, + `Comput. Phys. Commun. 222, 351-373 (2018) `_, + `arXiv:1702.05128 `_ + +---- + +Papers involving Smilei +^^^^^^^^^^^^^^^^^^^^^^^^ + +Only papers published in peer-reviewed journals are listed (for the complete list of citing papers see `Google Scholar `_). +As of November 2021, 90 papers have been published covering a broad range of topics: + +* laser-plasma interaction (LPI) / inertial fusion (FCI) +* ultra-high intensity (UHI) applications +* quantum electrodynamics (QED) processes in plasmas +* astrophysical and space plasmas +* high-performance computing (HPC) + +.. _fig_paper_topics: + +.. figure:: /_static/figures/paper_topics.png + :width: 50% + +.. READ THIS + There is now a utility to add new entries to this list. + Use the python script doc/doi2publications.py to generate entries from a DOI number, and paste them here +.. [Drobniak2023] + + P. Drobniak, E. Baynard, C. Bruni, K. Cassou, C. Guyot, G. Kane, S. Kazamias, V. Kubytskyi, N. Lericheux, B. Lucas, M. Pittman, F. Massimo, A. Beck, A. Specka, P. Nghiem, and D. Minenna, + `Random scan optimization of a laser-plasma electron injector based on fast particle-in-cell simulations`, + `Phys. Rev. Accel. Beams 26, 091302 (2023) `_ + +.. [Bukharskii2023] + + N. Bukharskii and Ph. Korneev, + `Intense widely controlled terahertz radiation from laser-driven wires`, + `Matter Radiat. Extremes 8, 044401 (2023) `_ + +.. [Schmitz2023] + + B. Schmitz, D. Kreuter, and O. Boine-Frankenheim, + `Modeling of a Liquid Leaf Target TNSA Experiment Using Particle-In-Cell Simulations and Deep Learning`, + `Laser and Particle Beams, 2868112 (2023) `_ + + + +.. [Paschke_Bruehl2023] + + F. Paschke-Bruehl, M. Banjafar, M. Garten, L. G. Huang, B. E. Marré, M. Nakatsutsumi, L. Randolph, T. E. Cowan, U. Schramm and T. Kluge, + `Heating in multi-layer targets at ultra-high intensity laser irradiation and the impact of density oscillation`, + `New Journal of Physics 25 (2023) `_ + +.. [Vladisavlevici2023] + + I. M. Vladisavlevici, D. Vizman and E. d'Humières, + `Theoretical investigation of the interaction of ultra-high intensity laser pulses with near critical density plasmas`, + `Plasma Physics and Controlled Fusion 65, 4 (2023) `_ + +.. [Gao2023] + + Xiaohui Gao, + `Ionization dynamics of sub-micrometer-sized clusters in intense ultrafast laser pulses`, + `Phys. Plasmas 30, 052102 (2023) `_ + +.. [Krafft2023] + + C. Krafft and P. Savoini, + `Dynamics of Two-dimensional Type III Electron Beams in Randomly Inhomogeneous Solar Wind Plasmas`, + `The Astrophysical Journal 949, 1 (2023) `_ + +.. [Hadjikyriacou2023] + + A. Hadjikyriacou, J. Psikal, L. Giuffrida and M. Kucharik, + `Novel approach to TNSA enhancement using multi-layered targets—a numerical study`, + `Plasma Physics and Controlled Fusion 65, 8 (2023) `_ + +.. [Ghizzo2023] + + Alain Ghizzo, Daniele Del Sarto, and Homam Betar, + `Collisionless Heating Driven by Vlasov Filamentation in a Counterstreaming Beams Configuration`, + `Phys. Rev. Lett. 131, 035101 (2023) `_ + +.. [Yang2023] + + Tong Yang, Zhen Guo, Yang Yan, Minjian Wu, Yadong Xia, Qiangyou He, Hao Cheng, Yuze Li, Yanlv Fang, Yanying Zhao, Xueqing Yan and Chen Lin, + `Measurements of Plasma Density Profile Evolutions with Channel-guided Laser`, + `High Power Laser Science and Engineering pp. 1-15 (2023) `_ + +.. [Yao2023] + + W. Yao, A. Fazzini, S.N. Chen, K. Burdonov, J. Béard, M. Borghesi, A. Ciardi, M. Miceli, S. Orlando, X. Ribeyre, E. d'Humières and J. Fuchs, + `Investigating particle acceleration dynamics in interpenetrating magnetized collisionless super-critical shocks`, + `J. Plasma Phys. 89, 915890101 (2023) `_ + +.. [Pak2023] + + Taegyu Pak, Mohammad Rezaei-Pandari, Sang Beom Kim, Geonwoo Lee, Dae Hee Wi, Calin Ioan Hojbota, Mohammad Mirzaie, Hyeongmun Kim, Jae Hee Sung, Seong Ku Lee, Chul Kang and Ki-Yong Kim, + `Multi-millijoule terahertz emission from laser-wakefield-accelerated electrons`, + `Light Sci Appl 12, 37 (2023) `_ + +.. [Istokskaia2023] + + Valeriia Istokskaia, Marco Tosca, Lorenzo Giuffrida, Jan Psikal, Filip Grepl, Vasiliki Kantarelou, Stanislav Stancek, Sabrina Di Siena, Arsenios Hadjikyriacou, Aodhan McIlvenny, Yoann Levy, Jaroslav Huynh, Martin Cimrman, Pavel Pleskunov, Daniil Nikitin, Andrei Choukourov, Fabio Belloni, Antonino Picciotto, Satyabrata Kar, Marco Borghesi, Antonio Lucianetti, Tomas Mocek and Daniele Margarone, + `A multi-MeV alpha particle source via proton-boron fusion driven by a 10-GW tabletop laser`, + `Commun Phys 6, 27 (2023) `_ + +.. [Yoon2023] + + Young Dae Yoon, Deirdre E. Wendel and Gunsu S. Yun, + `Equilibrium selection via current sheet relaxation and guide field amplification`, + `Nat Commun 14, 139 (2023) `_ + +.. [Galbiati2023] + + Marta Galbiati, Arianna Formenti, Mickael Grech and Matteo Passoni, + `Numerical investigation of non-linear inverse Compton scattering in double-layer targets`, + `Front. Phys. 11, fphy.2023.1117543 (2023) `_ + +.. [Sakai2023] + + K. Sakai, T. Nishimoto, S. Isayama, S. Matsukiyo and Y. Kuramitsu, + `Ion-acoustic feature of collective Thomson scattering in non-equilibrium two-stream plasmas`, + `Physics of Plasmas 30, 012105 (2023) `_ + +.. [Golovanov2023] + + A. Golovanov, I. Yu. Kostyukov, A. Pukhov and V. Malka, + `Energy-Conserving Theory of the Blowout Regime of Plasma Wakefield`, + `Phys. Rev. Lett. 130, 105001 (2023) `_ + +.. [Miethlinger2023] + + Thomas Miethlinger, Nico Hoffmann and Thomas Kluge, + `Acceptance Rates of Invertible Neural Networks on Electron Spectra from Near-Critical Laser-Plasmas: A Comparison`, + `Parallel Processing and Applied Mathematics, 273-284 (2023) `_ + +.. [Zepter2023] + + C. Zepter, A. Seidel, M. Zepf, M. C. Kaluza and A. Sävert, + `Role of spatiotemporal couplings in stimulated Raman side scattering`, + `Phys. Rev. Research 5, L012023 (2023) `_ + +.. [Marini2023] + + S. Marini, M. Grech, P. S. Kleij, M. Raynaud and C. Riconda, + `Electron acceleration by laser plasma wedge interaction`, + `Phys. Rev. Research 5, 013115 (2023) `_ + +.. [Glek2022b] + + P. B. Glek and A. M. Zheltikov, + `Enhanced coherent transition radiation from midinfrared‐laser‐driven microplasmas`, + `Scientific Reports 12, 7660 (2022) `_ + +.. [Margarone2022] + + D. Margarone, J. Bonvalet, L. Giuffrida, A. Morace, V. Kantarelou, M. Tosca, D. Raffestin, P. Nicolai, A. Picciotto, Y. Abe, Y. Arikawa, S. Fujioka, Y. Fukuda, Y. Kuramitsu, H. Habara and D. Batani, + `In-Target Proton–Boron Nuclear Fusion Using a PW-Class Laser`, + `Appl. Sci. 12(3), 1444 (2022) `_ + +.. [Kochetkov2022] + + Iu. V. Kochetkov, N. D. Bukharskii, M. Ehret, Y. Abe, K. F. F. Law,V. Ospina‐Bohorquez, J. J. Santos, S. Fujioka, G. Schaumann, B. Zielbauer, A. Kuznetsov and Ph. Korneev, + `Neural network analysis of quasistationary magnetic fields in microcoils driven by short laser pulses`, + `Scientific Reports 12, 13734 (2022) `_ + +.. [Oudin2022] + + A. Oudin, A. Debayle, C. Ruyer, D. Benisti, + `Cross-beam energy transfer between spatially smoothed laser beams`, + `Phys. Plasmas 29, 112112 (2022) `_ + +.. [Chen2022] + + Q. Chen, Dominika Maslarova, J. Wang, S. Li, and D. Umstadter, + `Injection of electron beams into two laser wakefields and generation of electron rings`, + `Phys. Rev. E 106, 055202 (2022) `_ + +.. [Kumar2022b] + + Sonu Kumar, Rajat Dhawan, D.K. Singh and Hitendra K. Malik, + `Diagnostic of laser wakefield acceleration with ultra – Short laser pulse by using SMILEI PIC code`, + `Materials Today: Proceedings 62, 3203-3207 (2022) `_ + +.. [Kumar2022a] + + Sonu Kumar, Dhananjay K Singh and Hitendra K Malik, + `Comparative study of ultrashort single-pulse and multi-pulse driven laser wakefield acceleration`, + `Laser Phys. Lett. 20, 026001 (2022) `_ + +.. [Miloshevsky2022] + + G. Miloshevsky, + `Pic Modeling of Omega Experiments on Ablation of Plasmas`, + `2022 IEEE International Conference on Plasma Science (ICOPS), ICOPS45751.2022.9813047 (2022) `_ + +.. [Zhang2022b] + + Yue Zhang, Feng Wang, Jianyong Liu and Jizhong Sun, + `Simulation of the inverse bremsstrahlung absorption by plasma plume in laser penetration welding`, + `Chemical Physics Letters 793, 139434 (2022) `_ + +.. [Vladisavlevici2022] + + Iuliana-Mariana Vladisavlevici, Daniel Vizman and Emmanuel d’Humières, + `Laser Driven Electron Acceleration from Near-Critical Density Targets towards the Generation of High Energy γ-Photons`, + `Photonics 9, 953 (2022) `_ + +.. [Ouatu2022] + + I. Ouatu, B. T. Spiers, R. Aboushelbaya, Q. Feng, M. W. von der Leyen, R. W. Paddock, R. Timmis, C. Ticos, K. M. Krushelnick and P. A. Norreys, + `Ionization states for the multipetawatt laser-QED regime`, + `Phys. Rev. E 106, 015205 (2022) `_ + +.. [Beth2022] + + A. Beth, H. Gunell, C. Simon Wedlund, C. Goetz, H. Nilsson and M. Hamrin, + `First investigation of the diamagnetic cavity boundary layer with a 1D3V PIC simulation`, + `A&A 667, A143 (2022) `_ + +.. [Guo2022] + + Yinlong Guo, Xuesong Geng, Liangliang Ji, Baifei Shen and Ruxin Li, + `Improving the accuracy of hard photon emission by sigmoid sampling of the quantum-electrodynamic table in particle-in-cell Monte Carlo simulations`, + `Phys. Rev. E 105, 025309 (2022) `_ + +.. [Pae2022] + + Ki Hong Pae, Chul Min Kim, Vishwa Bandhu Pathak, Chang-Mo Ryu and Chang Hee Nam, + `Direct laser acceleration of electrons from a plasma mirror by an intense few-cycle Laguerre–Gaussian laser and its dependence on the carrier-envelope phase`, + `Plasma Phys. Control. Fusion 64, 055013 (2022) `_ + + +.. [Zhang2022a] + + Cui-Wen Zhang, Yi-Xuan Zhu, Jian-Feng Lv and Bai-Song Xie, + `Simulation Study of a Bright Attosecond γ-ray Source Generation by Irradiating an Intense Laser on a Cone Target`, + `Applied Sciences 12, 4361 (2022) `_ + +.. [Han2022] + + Qianqian Han, Xuesong Geng, Baifei Shen, Zhizhan Xu and Liangliang Ji, + `Ultra-fast polarization of a thin electron layer in the rotational standing-wave field driven by double ultra-intense laser pulses`, + `New J. Phys. 24, 063013 (2022) `_ + +.. [Gothel2022] + + Ilja Göthel, Constantin Bernert, Michael Bussmann, Marco Garten, Thomas Miethlinger, Martin Rehwald, Karl Zeil, Tim Ziegler, Thomas E Cowan, Ulrich Schramm and Thomas Kluge, + `Optimized laser ion acceleration at the relativistic critical density surface`, + `Plasma Phys. Control. Fusion 64, 044010 (2022) `_ + +.. [Fazzini2022] + + A. Fazzini, W. Yao, K. Burdonov, J. Béard, S. N. Chen, A. Ciardi, E. d’Humières, R. Diab, E. D. Filippov, S. Kisyov, V. Lelasseux, M. Miceli, Q. Moreno, S. Orlando, S. Pikuz, X. Ribeyre, M. Starodubtsev, R. Zemskov and J. Fuchs, + `Particle energization in colliding subcritical collisionless shocks investigated in the laboratory`, + `A&A 665, A87 (2022) `_ + +.. [Bykov2022] + + A. M. Bykov, S. M. Osipov and V. I. Romanskii, + `Acceleration of Cosmic Rays to Energies above 1015 eV by Transrelativistic Shocks`, + `J. Exp. Theor. Phys. 134, 487-497 (2022) `_ + +.. [Sundstrom2022] + + Andréas Sundström, Mickael Grech, István Pusztai and Caterina Riconda, + `Stimulated-Raman-scattering amplification of attosecond XUV pulses with pulse-train pumps and application to local in-depth plasma-density measurement`, + `Phys. Rev. E 106, 045208 (2022) `_ + + + +.. [Krafft2022b] + + C. Krafft and P. Savoini, + `Third and Fourth Harmonics of Electromagnetic Emissions by a Weak Beam in a Solar Wind Plasma with Random Density Fluctuations`, + `ApJL 934, L28 (2022) `_ + +.. [Krafft2022a] + + C. Krafft and P. Savoini, + `Fundamental Electromagnetic Emissions by a Weak Electron Beam in Solar Wind Plasmas with Density Fluctuations`, + `ApJL 924, L24 (2022) `_ + +.. [Kong2022] + + Defeng Kong, Guoqiang Zhang, Yinren Shou, Shirui Xu, Zhusong Mei, Zhengxuan Cao, Zhuo Pan, Pengjie Wang, Guijun Qi, Yao Lou, Zhiguo Ma, Haoyang Lan, Wenzhao Wang, Yunhui Li, Peter Rubovic, Martin Veselsky, Aldo Bonasera, Jiarui Zhao, Yixing Geng, Yanying Zhao, Changbo Fu, Wen Luo, Yugang Ma, Xueqing Yan and Wenjun Ma, + `High-energy-density plasma in femtosecond-laser-irradiated nanowire-array targets for nuclear reactions`, + `Matter and Radiation at Extremes 7, 064403 (2022) `_ + +.. [Davidson2022] + + Conor Davidson, Zheng-Ming Sheng, Thomas Wilson and Paul McKenna, + `Theoretical and computational studies of the Weibel instability in several beam–plasma interaction configurations`, + `J. Plasma Phys. 88, 905880206 (2022) `_ + +.. [Glek2022] + + P. B. Glek and A. M. Zheltikov, + `Subcycle terahertz field waveforms clocked by attosecond high-harmonic pulses from relativistic laser plasmas`, + `Journal of Applied Physics 131, 103104 (2022) `_ + +.. [Umstadter2022] + D. Umstadter + `Controlled Injection of Electrons for Improved Performance of Laser-Wakefield Acceleration`, + `United States: N. p., (2022) `_ + +.. [Massimo2022] + + Francesco Massimo, Mathieu Lobet, Julien Derouillat, Arnaud Beck, Guillaume Bouchard, Mickael Grech, Frédéric Pérez, Tommaso Vinci, + `A Task Programming Implementation for the Particle in Cell Code Smilei`, + `PASC '22: Proceedings of the Platform for Advanced Scientific Computing Conference 5, 1 (2022) `_, + `arXiv:2204.12837 `_ + +.. [Yao2022] + + W. Yao, A. Fazzini, S. N. Chen, K. Burdonov, P. Antici, J. Béard, S. Bolaños, A. Ciardi, R. Diab, E. D. Filippov, S. Kisyov, V. Lelasseux, M. Miceli, Q. Moreno, V. Nastasa, S. Orlando, S. Pikuz, D. C. Popescu, G. Revet, X. Ribeyre, E. d’Humières and J. Fuchs, + `Detailed characterization of a laboratory magnetized supercritical collisionless shock and of the associated proton energization`, + `Matter and Radiation at Extremes 7, 014402 (2022) `_ + +.. [Singh2022] + + P. K. Singh, F.-Y. Li, C.-K. Huang, A. Moreau, R. Hollinger, A. Junghans, A. Favalli, C. Calvi, S. Wang, Y. Wang, H. Song, J. J. Rocca, R. E. Reinovsky and S. Palaniyappan, + `Vacuum laser acceleration of super-ponderomotive electrons using relativistic transparency injection`, + `Nat Commun 13, 54 (2022) `_ + +.. [Lobet2022] + + M. Lobet, F. Massimo, A. Beck, G. Bouchard, F. Perez, T. Vinci, and M. Grech. + `Simple adaptations to speed-up the Particle-In-Cell code Smilei on the ARM-based Fujitsu A64FX processor.`, + `In International Conference on High Performance Computing in Asia-Pacific Region Workshops (HPCAsia 2022 Workshop). + Association for Computing Machinery, New York, NY, USA, 40–48. (2022) `_ + + + .. [Tomassini2021] + + Paolo Tomassini, Francesco Massimo, Luca Labate and Leonida A. Gizzi, + `Accurate electron beam phase-space theory for ionization-injection schemes driven by laser pulses`, + `High Pow Laser Sci Eng 10, e15 (2021) `_ + +.. [Meinhold2021] + + Tim Arniko Meinhold and Naveen Kumar, + `Radiation pressure acceleration of protons from structured thin-foil targets`, + `J. Plasma Phys. 87, 905870607 (2021) `_ + +.. [Bonvalet2021b] + + J. Bonvalet, P. Loiseau, J.-R. Marquès, E. Atukpor, E. d'Humières, J. Domange, P. Forestier-Colleoni, F. Hannachi, L. Lancia, D. Raffestin, M. Tarisien, V. Tikhonchuk and Ph. Nicolaï, + `Laser-driven collisionless shock acceleration of protons from gas jets tailored by one or two nanosecond beams`, + `Physics of Plasmas 28, 113102 (2021) `_ + +.. [Shi2021b] + + Yin Shi, David R Blackman and Alexey Arefiev, + `Electron acceleration using twisted laser wavefronts`, + `Plasma Phys. Control. Fusion 63, 125032 (2021) `_ + +.. [Kumar2021] + + Naveen Kumar and Brian Reville, + `Nonthermal Particle Acceleration at Highly Oblique Nonrelativistic Shocks`, + `ApJL 921, L14 (2021) `_ + +.. [Ghaith2021] + + A. Ghaith, M.-E. Couprie, D. Oumbarek-Espinos, I.A. Andriyash, F. Massimo, J.A. Clarke, M. Courthold, V. Bayliss, A. Bernhard, M. Trunk, M. Valléau, O. Marcouillé, A. Chancé, S. Licciardi, V. Malka, F. Nguyen and G. Dattoli, + `Undulator design for a laser-plasma-based free-electron-laser`, + `Physics Reports 937, 1-73 (2021) `_ + +.. [Horny2021] + + Vojtěch Horný and László Veisz, + `Generation of single attosecond relativistic electron bunch from intense laser interaction with a nanosphere`, + `Plasma Phys. Control. Fusion 63, 125025 (2021) `_ + +.. [Krafft2021] + + C. Krafft and P. Savoini, + `Second Harmonic Electromagnetic Emissions by an Electron Beam in Solar Wind Plasmas with Density Fluctuations`, + `ApJL 917, L23 (2021) `_ + +.. [Khalilzadeh2021c] + + E. Khalilzadeh, M. J. Jafari and A. Chakhmachi, + `Stochastic heating of electrons due to Raman backscatter radiations in interaction of intense laser pulse with nitrogen atoms`, + `Physics of Plasmas 28, 072304 (2021) `_ + +.. [Marini2021b] + + S. Marini, P. S. Kleij, F. Amiranoff, M. Grech, C. Riconda and M. Raynaud, + `Key parameters for surface plasma wave excitation in the ultra-high intensity regime`, + `Physics of Plasmas 28, 073104 (2021) `_ + +.. [Sladkov2021] + + A. Sladkov, R. Smets, N. Aunai and A. Korzhimanov, + `Numerical study of non-gyrotropic electron pressure effects in collisionless magnetic reconnection`, + `Physics of Plasmas 28, 072108 (2021) `_ + +.. [Shou2021] + + Yinren Shou, Dahui Wang, Pengjie Wang, Jianbo Liu, Zhengxuan Cao, Zhusong Mei, Shirui Xu, Zhuo Pan, Defeng Kong, Guijun Qi, Zhipeng Liu, Yulan Liang, Ziyang Peng, Ying Gao, Shiyou Chen, Jiarui Zhao, Yanying Zhao, Han Xu, Jun Zhao, Yanqing Wu, Xueqing Yan and Wenjun Ma, + `High-efficiency generation of narrowband soft x rays from carbon nanotube foams irradiated by relativistic femtosecond lasers`, + `Opt. Lett. 46, 3969 (2021) `_ + +.. [Khalilzadeh2021b] + + E. Khalilzadeh, A. Chakhmachi, Z. Dehghani, S. Rezaei and M. J. Jafari, + `Electron energy spectrum in the field‐ionized plasma`, + `Contributions to Plasma Physics 61, ctpp.202000219 (2021) `_ + +.. [Hosseinkhani2021] + + H. Hosseinkhani, M. Pishdast, J. Yazdanpanah and S.A. Ghasemi, + `Investigation of the classical and quantum radiation reaction effect on interaction of ultra high power laser with near critical plasma`, + `J. Nuclear Sci. Technol. 42, 27-35 (2021) `_ + +.. [MercuriBaron2021] + + A Mercuri-Baron, M Grech, F Niel, A Grassi, M Lobet, A Di Piazza and C Riconda, + `Impact of the laser spatio-temporal shape on Breit–Wheeler pair production`, + `New J. Phys. 23, 085006 (2021) `_ + +.. [Peng2021] + + H. Peng, C. Riconda, S. Weber, C.T. Zhou and S.C. Ruan, + `Frequency Conversion of Lasers in a Dynamic Plasma Grating`, + `Phys. Rev. Applied 15, 054053 (2021) `_ + +.. [Shi2021a] + + Yin Shi, David Blackman, Dan Stutman and Alexey Arefiev, + `Generation of Ultrarelativistic Monoenergetic Electron Bunches via a Synergistic Interaction of Longitudinal Electric and Magnetic Fields of a Twisted Laser`, + `Phys. Rev. Lett. 126, 234801 (2021) `_ + +.. [Bonvalet2021a] + + J. Bonvalet, Ph. Nicolaï, D. Raffestin, E. D'humieres, D. Batani, V. Tikhonchuk, V. Kantarelou, L. Giuffrida, M. Tosca, G. Korn, A. Picciotto, A. Morace, Y. Abe, Y. Arikawa, S. Fujioka, Y. Fukuda, Y. Kuramitsu, H. Habara and D. Margarone, + `Energetic α-particle sources produced through proton-boron reactions by high-energy high-intensity laser beams`, + `Phys. Rev. E 103, 053202 (2021) `_ + +.. [Shekhanov2021] + + S A Shekhanov and V T Tikhonchuk, + `SRS-SBS competition and nonlinear laser energy absorption in a high temperature plasma`, + `Plasma Phys. Control. Fusion 63, 115016 (2021) `_ + +.. [Psikal2021] + + J Psikal, + `Laser-driven ion acceleration from near-critical Gaussian plasma density profile`, + `Plasma Phys. Control. Fusion 63, 064002 (2021) `_ + +.. [Yoon2021b] + + Young Dae Yoon, Gunsu S. Yun, Deirdre E. Wendel and James L. Burch, + `Collisionless relaxation of a disequilibrated current sheet and implications for bifurcated structures`, + `Nat Commun 12, 3774 (2021) `_ + +.. [Lavorenti2021] + + F. Lavorenti, P. Henri, F. Califano, S. Aizawa and N. André, + `Electron acceleration driven by the lower-hybrid-drift instability. An extended quasilinear model`, + `A&A 652, 202141049 (2021) `_ + +.. [Golovanov2021] + + A A Golovanov, I Yu Kostyukov, L Reichwein, J Thomas and A Pukhov, + `Excitation of strongly nonlinear plasma wakefield by electron bunches`, + `Plasma Phys. Control. Fusion 63, 085004 (2021) `_ + +.. [Jirka2021] + + M. Jirka, P. Sasorov, S. S. Bulanov, G. Korn, B. Rus and S. V. Bulanov, + `Reaching high laser intensity by a radiating electron`, + `Phys. Rev. A 103, 053114 (2021) `_ + +.. [Marques2021] + + J.-R. Marquès, P. Loiseau, J. Bonvalet, M. Tarisien, E. d'Humières, J. Domange, F. Hannachi, L. Lancia, O. Larroche, P. Nicolaï, P. Puyuelo-Valdes, L. Romagnani, J. J. Santos and V. Tikhonchuk, + `Over-critical sharp-gradient plasma slab produced by the collision of laser-induced blast-waves in a gas jet: Application to high-energy proton acceleration`, + `Physics of Plasmas 28, 023103 (2021) `_ + +.. [Do2021] + + Hue Thi Bich Do, Ding Wen Jun, Zackaria Mahfoud, Wu Lin and Michel Bosman, + `Electron dynamics in plasmons`, + `Nanoscale 13, 2801-2810 (2021) `_ + +.. [Khalilzadeh2021a] + + E. Khalilzadeh, M.J. Jafari, S. Rezaei and Z. Dehghani, + `The effect of the laser pulse shape on the wakefield generation in field-ionized plasma`, + `Chinese Journal of Physics 71, 212-223 (2021) `_ + +.. [Babjak2021] + + R. Babjak and J. Psikal, + `The role of standing wave in the generation of hot electrons by femtosecond laser beams incident on dense ionized target`, + `Physics of Plasmas 28, 023107 (2021) `_ + +.. [Cantono2021] + + Giada Cantono, Alexander Permogorov, Julien Ferri, Evgeniya Smetanina, Alexandre Dmitriev, Anders Persson, Tünde Fülöp and Claes-Göran Wahlström, + `Laser-driven proton acceleration from ultrathin foils with nanoholes`, + `Sci Rep 11, 5006 (2021) `_ + +.. [Perez2021] + + F. Pérez, F. Amiranoff, C. Briand, S. Depierreux, M. Grech, L. Lancia, P. Loiseau, J.-R. Marquès, C. Riconda and T. Vinci, + `Numerical study of Langmuir wave coalescence in laser-plasma interaction`, + `Physics of Plasmas 28, 043102 (2021) `_ + +.. [Yoon2021a] + + Young Dae Yoon and Paul M. Bellan, + `How Hall electric fields intrinsically chaotize and heat ions during collisionless magnetic reconnection`, + `Physics of Plasmas 28, 022113 (2021) `_ + +.. [Sampath2021] + + Archana Sampath, Xavier Davoine, Sébastien Corde, Laurent Gremillet, Max Gilljohann, Maitreyi Sangal, Christoph H. Keitel, Robert Ariniello, John Cary, Henrik Ekerfelt, Claudio Emma, Frederico Fiuza, Hiroki Fujii, Mark Hogan, Chan Joshi, Alexander Knetsch, Olena Kononenko, Valentina Lee, Mike Litos, Kenneth Marsh, Zan Nie, Brendan O’Shea, J. Ryan Peterson, Pablo San Miguel Claveria, Doug Storey, Yipeng Wu, Xinlu Xu, Chaojie Zhang and Matteo Tamburini, + `Extremely Dense Gamma-Ray Pulses in Electron Beam-Multifoil Collisions`, + `Phys. Rev. Lett. 126, 064801 (2021) `_ + +.. [Marini2021a] + + S. Marini, P. S. Kleij, F. Pisani, F. Amiranoff, M. Grech, A. Macchi, M. Raynaud and C. Riconda, + `Ultrashort high energy electron bunches from tunable surface plasma waves driven with laser wavefront rotation`, + `Phys. Rev. E 103, L021201 (2021) `_ + +.. [Yao2021] + + W. Yao, A. Fazzini, S. N. Chen, K. Burdonov, P. Antici, J. Béard, S. Bolaños, A. Ciardi, R. Diab, E. D. Filippov, S. Kisyov, V. Lelasseux, M. Miceli, Q. Moreno, V. Nastasa, S. Orlando, S. Pikuz, D. C. Popescu, G. Revet, X. Ribeyre, E. d’Humières and J. Fuchs, + `Laboratory evidence for proton energization by collisionless shock surfing`, + `Nat. Phys. 17, 1177-1182 (2021) `_ + +.. [Gelfer2021] + + E G Gelfer, A M Fedotov and S Weber, + `Radiation induced acceleration of ions in a laser irradiated transparent foil`, + `New J. Phys. 23, 095002 (2021) `_ + `arXiv:1907.02621 `_ + +.. [Siminos2021] + + E. Siminos, I. Thiele and C. Olofsson, + `Laser Wakefield Driven Generation of Isolated Carrier-Envelope-Phase Tunable Intense Subcycle Pulses`, + `Phys. Rev. Lett. 126, 044801 (2021) `_ + `arXiv:1902.05014 `_ + +.. [Budriga2020] + + O. Budriga, L. E. Ionel, D. Tatomirescu and K. A. Tanaka, + `Enhancement of laser-focused intensity greater than 10 times through a re-entrant cone in the petawatt regime`, + `Optics Letters 45, 3454 (2020) `_ + +.. [Nghiem2020] + + P. A. P. Nghiem, R. Assmann, A. Beck et al., + `Toward a plasma-based accelerator at high beam energy with high beam charge and high beam quality`, + `Phys. Rev. Accel. Beams 23, 031301 (2020) `_ + +.. [Pisarczyk2020] + + T. Pisarczyk, M. Kalal, S. Yu. Gus'kov et al., + `Hot electron retention in laser plasma created under terawatt subnanosecond irradiation of Cu targets`, + `Plasma Phys. Control. Fusion 62, 115020 (2020) `_ + +.. [Pagano2020] + + I. Pagano, J. Brooks, A. Bernstein, R. Zgadzaj, J. Leddy, J. Cary and M. C. Downer, + `Low Density Plasma Waveguides Driven by Ultrashort (30 fs) and Long (300 ps) Pulses for Laser Wakefield Acceleration`, + `2018 IEEE Advanced Accelerator Concepts Workshop (AAC), 1 `_ + +.. [Ruyer2020] + + C. Ruyer, A. Debayle, P. Loiseau, M. Casanova and P. E. Masson-Laborde, + `Kinetic analytical modeling of Gaussian pulse beam-bending including the transient regime`, + `Physics of Plasmas 27, 102105 (2020) `_ + +.. [Peng2020] + + H. Peng, C. Riconda, M. Grech, C.-T. Zhou and S. Weber, + `Dynamical aspects of plasma gratings driven by a static ponderomotive potential`, + `Plasma Phys. Control. Fusion 62, 115015 (2020) `_ + +.. [Glek2020] + + P. B. Glek, A. A. Voronin, V. Ya. Panchenko and A. M. Zheltikov, + `Relativistic electron bunches locked to attosecond optical field waveforms: an attosecond light–matter bound state`, + `Laser Phys. Lett. 17 055401 (2020) `_ + +.. [Margarone2020] + + D. Margarone, A. Morace, J. Bonvalet et al., + `Generation of α-Particle Beams With a Multi-kJ, Peta-Watt Class Laser System`, + `Front. Phys. 8, 343 (2020) `_ + +.. [Sinha2020] + + U. Sinha and N. Kumar, + `Pair-beam propagation in a magnetized plasma for modeling the polarized radiation emission from gamma-ray bursts in laboratory astrophysics experiments`, + `Phys. Rev. E 101, 063204 (2020) `_ + +.. [Mitrofanov2020] + + A. V. Mitrofanov, D. A. Sidorov-Biryukov, P. B. Glek, M. V. Rozhko, E. A. Stepanov, A. D. Shutov, S. V. Ryabchuk, A. A. Voronin, A. B. Fedotov, and A. M. Zheltikov, + `Chirp-controlled high-harmonic and attosecond-pulse generation via coherent-wake plasma emission driven by mid-infrared laser pulses`, + `Optics Letters 45, 750 (2020) `_ + +.. [Spiers2020] + + B. T. Spiers, M. P. Hill, C. Brown, L. Ceurvorst, N. Ratan, A. F. Savin, P. Allan, E. Floyd, J. Fyrth, L. Hobbs, S. James, J. Luis, M. Ramsay, N. Sircombe, J. Skidmore, R. Aboushelbaya, M. W. Mayr, R. Paddock, R. H. W. Wang and P. A. Norreys, + `Whole-beam self-focusing in fusion-relevant plasma`, + `Phil. Trans. R. Soc. A379, 20200159 `_ + +.. [Derouillat2020] + + J. Derouillat and A. Beck, + `Single Domain Multiple Decompositions for Particle-in-Cell simulations`, + `J. Phys.: Conf. Ser. 1596, 012052 (2020) `_ + `arXiv:1912.04064 `_ + +.. [Zemzemi2020] + + I. Zemzemi, F. Massimo and A. Beck, + `Azimuthal decomposition study of a realistic laser profile for efficient modeling of Laser WakeField Acceleration`, + `J. Phys.: Conf. Ser. 1596, 012055 (2020) `_ + +.. [Massimo2020b] + + F. Massimo, I. Zemzemi, A. Beck, J. Derouillat and A. Specka, + `Efficient cylindrical envelope modeling for laser wakefield acceleration`, + `J. Phys.: Conf. Ser. 1596, 012054 (2020) `_ + `arXiv:1912.04674 `_ + +.. [Massimo2020a] + + F. Massimo, A. Beck, J. Derouillat, I. Zemzemi and A. Specka, + `Numerical modeling of laser tunneling ionization in particle-in-cell codes with a laser envelope model`, + `Phys. Rev. E 102, 033204 (2020) `_ + `arXiv:2006.04433 `_ + +.. [Marcowith2020] + + Alexandre Marcowith, Gilles Ferrand, Mickael Grech, Zakaria Meliani, Illya Plotnikov and Rolf Walder, + `Multi-scale simulations of particle acceleration in astrophysical systems`, + `Living Rev Comput Astrophys 6, 1 (2020) `_ + `arXiv:2002.09411 `_ + +.. [Dargent2020] + + J. Dargent, N. Aunai, B. Lavraud, S. Toledo‐Redondo and F. Califano, + `Simulation of Plasmaspheric Plume Impact on Dayside Magnetic Reconnection`, + `Geophys. Res. Lett. 47, 2019GL086546 (2020) `_ + `arXiv:2002.02243 `_ + +.. [Sundström2020b] + + A. Sundström, L. Gremillet, E. Siminos and I. Pusztai, + `Collisional effects on the electrostatic shock dynamics in thin-foil targets driven by an ultraintense short pulse laser`, + `Plasma Phys. Control. Fusion 62, 085015 (2020) `_ + +.. [Sundström2020a] + + A. Sundström, L. Gremillet, E. Siminos and I. Pusztai, + `Fast collisional electron heating and relaxation in thin foils driven by a circularly polarized ultraintense short-pulse laser`, + `J. Plasma Phys. 86, 755860201 (2020) `_ + `arXiv:1911.09562 `_ + +.. [Gelfer2020] + + E. G. Gelfer, A. M. Fedotov, O. Klimo and S. Weber, + `Absorption and opacity threshold for a thin foil in a strong circularly polarized laser field`, + `Phys. Rev. E 101, 033204 (2020) `_ + `arXiv:1906.05902 `_ + +.. [Ferri2020] + + J. Ferri, I. Thiele, E. Siminos, L. Gremillet, E. Smetanina, A. Dmitriev, G. Cantono, C.-G. Wahlström and T. Fülöp, + `Enhancement of laser-driven ion acceleration in non-periodic nanostructured targets`, + `J. Plasma Phys. 86, 905860101 (2020) `_ + `arXiv:1905.11131 `_ + +.. [Marques2019] + + J.-R. Marquès, L. Lancia, T. Gangolf, M. Blecher, S. Bolaños, J. Fuchs, O. Willi, F. Amiranoff, R. L. Berger, M. Chiaramello, S. Weber, and C. Riconda, + `Joule-Level High-Efficiency Energy Transfer to Subpicosecond Laser Pulses by a Plasma-Based Amplifier`, + `Phys. Rev. X 9, 021008 (2019) `_ + +.. [Plotnikov2019] + I. Plotnikov and L. Sironi, + `The synchrotron maser emission from relativistic shocks in Fast Radio Bursts: 1D PIC simulations of cold pair plasmas`, + `Monthly Notices of the Royal Astronomical Society 485, 3816 (2019) `_ + +.. [Dargent2019b] + + J. Dargent, N. Aunai, B. Lavraud, S. Toledo-Redondo and F. Califano, + `Signatures of Cold Ions in a Kinetic Simulation of the Reconnecting Magnetopause`, + `Journal of Geophysical Research: Space Physics, 124, 2497 (2019) `_ + +.. [Dargent2019a] + + J. Dargent, F. Lavorenti, F. Califano, P. Henri, F. Pucci and S. S. Cerri, + `Interplay between Kelvin–Helmholtz and lower-hybrid drift instabilities`, + `Journal of Plasma Physics 85, 805850601 `_ + +.. [Geng2019] + + X. S. Geng, L. L. Ji, B. F. Shen et al., + `Quantum reflection above the classical radiation-reaction barrier in the quantum electro-dynamics regime`, + `Commun. Phys. 2, 66 (2019) `_ + +.. [Sinha2019] + + U. Sinha, C. H. Keitel, and N. Kumar, + `Polarized Light from the Transportation of a Matter-Antimatter Beam in a Plasma`, + `Phys. Rev. Lett. 122, 204801 (2019) `_ + +.. [Malko2019] + + S. Malko, X. Vaisseau, F. Perez, D. Batani, A. Curcio, M. Ehret, J. Honrubia, K. Jakubowska, A. Morace, J. J. Santos and L. Volpe, + `Enhanced relativistic-electron beam collimation using two consecutive laser pulses`, + `Sci Rep 9, 14061 (2019) `_ + +.. [Peng2019] + + H. Peng, C. Riconda, M. Grech, J.-Q. Su and S. Weber, + `Nonlinear dynamics of laser-generated ion-plasma gratings: A unified description`, + `Phys. Rev. E 100, 061201 (2019) `_ + `arXiv:1911.03440 `_ + +.. [Fang2019] + + Jun Fang, Chun-Yan Lu, Jing-Wen Yan and Huan Yu, + `Early acceleration of electrons and protons at the nonrelativistic quasiparallel shocks with different obliquity angles`, + `Res. Astron. Astrophys. 19, 182 (2019) `_ + `arXiv:1908.08170 `_ + +.. [Yoon2019b] + + Young Dae Yoon and Paul M. Bellan, + `Kinetic Verification of the Stochastic Ion Heating Mechanism in Collisionless Magnetic Reconnection`, + `ApJ 887, L29 (2019) `_ + +.. [Yoon2019a] + + Young Dae Yoon and Paul M. Bellan, + `The electron canonical battery effect in magnetic reconnection: Completion of the electron canonical vorticity framework`, + `Physics of Plasmas 26, 100702 (2019) `_ + +.. [Massimo2019] + + F Massimo, A Beck, J Derouillat, M Grech, M Lobet, F Pérez, I Zemzemi and A Specka, + `Efficient start-to-end 3D envelope modeling for two-stage laser wakefield acceleration experiments`, + `Plasma Phys. Control. Fusion 61, 124001 (2019) `_ + `arXiv:1912.04127 `_ + +.. [Beck2019] + + A. Beck, J. Derouillat, M. Lobet, A. Farjallah, F. Massimo, I. Zemzemi, F. Perez, T. Vinci and M. Grech, + `Adaptive SIMD optimizations in particle-in-cell codes with fine-grain particle sorting`, + `Computer Physics Communications 244, 246-263 (2019) `_ + `arXiv:1810.03949 `_ + +.. [Pérez2019] + + F. Pérez and M. Grech, + `Oblique-incidence, arbitrary-profile wave injection for electromagnetic simulations`, + `Phys. Rev. E 99, 033307 (2019) `_ + `arXiv:1809.04435 `_ + +.. [Thiele2019] + + I. Thiele, E. Siminos and T. Fülöp, + `Electron Beam Driven Generation of Frequency-Tunable Isolated Relativistic Subcycle Pulses`, + `Phys. Rev. Lett. 122, 104803 (2019) `_ + `arXiv:1806.04976 `_ + +.. [Massimo2018] + + F. Massimo, A. Beck, A. Specka, I. Zemzemi, J. Derouillat, M. Grech and F. Pérez, + `Efficient Modeling of Laser Wakefield Acceleration Through the PIC Code Smilei in CILEX Project`, + `Proc. 13th International Computational Accelerator Physics Conference (ICAP'18), Key West, FL, USA, 20-24 October 2018 `_ + +.. [ToledoRedondo2018] + + S. Toledo-Redondo, J. Dargent, N. Aunai, B. Lavraud, M. André, W. Li, B. Giles, P.-A. Lindvist, R. E. Ergun, C. T. Russel and J. L. Burch, + `Perpendicular Current Reduction Caused by Cold Ions of Ionospheric Origin in Magnetic Reconnection at the Magnetopause: Particle-in-Cell Simulations and Spacecraft Observations`, + `Geophys. Res. Lett. 45, 10,033 (2018) `_ + +.. [Gelfer2018] + + E. Gelfer, N. Elkina and A. Fedotov, + `Unexpected impact of radiation friction: enhancing production of longitudinal plasma waves`, + `Sci. Rep. 8, 6478 (2018) `_ + +.. [Niel2018b] + + F Niel, C Riconda, F Amiranoff, M Lobet, J Derouillat, F Pérez, T Vinci and M Grech, + `From quantum to classical modeling of radiation reaction: a focus on the radiation spectrum`, + `Plasma Phys. Control. Fusion 60, 094002 (2018) `_ + `arXiv:1802.02927 `_ + +.. [Plotnikov2018] + + Illya Plotnikov, Anna Grassi and Mickael Grech, + `Perpendicular relativistic shocks in magnetized pair plasma`, + `Monthly Notices of the Royal Astronomical Society 477, 5238-5260 (2018) `_ + `arXiv:1712.02883 `_ + +.. [Niel2018a] + + F. Niel, C. Riconda, F. Amiranoff, R. Duclous and M. Grech, + `From quantum to classical modeling of radiation reaction: A focus on stochasticity effects`, + `Phys. Rev. E 97, 043209 (2018) `_ + `arXiv:1707.02618 `_ + +.. [Grassi2017b] + + A. Grassi, M. Grech, F. Amiranoff, A. Macchi and C. Riconda, + `Radiation-pressure-driven ion Weibel instability and collisionless shocks`, + `Phys. Rev. E 96, 033204 (2017) `_ + `arXiv:1705.05402 `_ + +.. [Fedeli2017] + + L Fedeli, A Formenti, L Cialfi, A Sgattoni, G Cantono and M Passoni, + `Structured targets for advanced laser-driven sources`, + `Plasma Phys. Control. Fusion 60, 014013 (2017) `_ + +.. [Golovanov2017] + + A. A. Golovanov, I. Yu. Kostyukov, J. Thomas and A. Pukhov, + `Analytic model for electromagnetic fields in the bubble regime of plasma wakefield in non-uniform plasmas`, + `Physics of Plasmas 24, 103104 (2017) `_ + +.. [Dargent2017] + + J. Dargent, N. Aunai, B. Lavraud, S. Toledo-Redondo, M. A. Shay, P. A. Cassak and K. Malakit, + `Kinetic simulation of asymmetric magnetic reconnection with cold ions`, + `J. Geophys. Res. Space Physics 122, 5290-5306 (2017) `_ + +.. [Grassi2017a] + + A. Grassi, M. Grech, F. Amiranoff, F. Pegoraro, A. Macchi and C. Riconda, + `Electron Weibel instability in relativistic counterstreaming plasmas with flow-aligned external magnetic fields`, + `Phys. Rev. E 95, 023203 (2017) `_ + +.. [Dargent2016] + + J. Dargent, N. Aunai, G. Belmont, N. Dorville, B. Lavraud and M. Hesse, + `Full particle-in-cell simulations of kinetic equilibria and the role of the initial current sheet on steady asymmetric magnetic reconnection`, + `J. Plasma Phys. 82, 905820305 (2016) `_ + +.. [Chiaramello2016] + + M. Chiaramello, C. Riconda, F. Amiranoff, J. Fuchs, M. Grech, L. Lancia, J.-R. Marquès, T. Vinci and S. Weber, + `Optimization of interaction conditions for efficient short laser pulse amplification by stimulated Brillouin scattering in the strongly coupled regime`, + `Physics of Plasmas 23, 072103 (2016) `_ + +.. [Beck2016] + + A. Beck, J.T. Frederiksen and J. Dérouillat, + `Load management strategy for Particle-In-Cell simulations in high energy particle acceleration`, + `Nucl. Inst. Meth. in Phys. Res. A 829, 418-421 (2016) `_ + +.. [Lancia2016] + + L. Lancia, A. Giribono, L. Vassura, M. Chiaramello, C. Riconda, S. Weber, A. Castan, A. Chatelain, A. Frank, T. Gangolf, M. N. Quinn, J. Fuchs and J.-R. Marquès, + `Signatures of the Self-Similar Regime of Strongly Coupled Stimulated Brillouin Scattering for Efficient Short Laser Pulse Amplification`, + `Phys. Rev. Lett. 116, 075001 (2016) `_ diff --git a/_sources/Overview/partners.rst.txt b/_sources/Overview/partners.rst.txt new file mode 100644 index 000000000..2170321ba --- /dev/null +++ b/_sources/Overview/partners.rst.txt @@ -0,0 +1,235 @@ +Partners +-------- + +.. |mdls| image:: /_static/labs/mdls.png + :width: 6em + :align: middle + +.. |luli| image:: /_static/labs/luli.png + :width: 6em + :align: middle + +.. |llr| image:: /_static/labs/llr.png + :width: 6em + :align: middle + +.. |lpgp| image:: /_static/labs/lpgp.png + :width: 6em + :align: middle + +.. |idris| image:: /_static/labs/idris.png + :width: 6em + :align: middle + +.. |lpp| image:: /_static/labs/lpp.png + :width: 6em + :align: middle + +.. |intel| image:: /_static/labs/intel.png + :width: 6em + :align: middle + +.. |IAPRAS| image:: /_static/labs/iapras.png + :width: 6em + :align: middle + +.. |IRAMIS| image:: /_static/labs/iramis.png + :width: 6em + :align: middle + +.. |IRAP| image:: /_static/labs/irap.png + :width: 6em + :align: middle + +.. |GOTHB| image:: /_static/labs/gothenburg.png + :width: 6em + :align: middle + +.. rst-class:: noborder + ++------------+---------------------------------------------------------------------------------------------------------+ +| |mdls| | | +| | `Maison de la Simulation `_ (MdlS), USR 3441 | +| | | ++ +---------------------------------------------------------------------------------------------------------+ +| | * `Olga Abramkina `_ | +| | * `Julien Dérouillat `_ | +| | * `Haithem Kallala `_ | +| | * `Mathieu Lobet `_ | +| | * `Francesco Massimo `_ | +| | * `Charles Prouveur `_ | +| | | ++------------+---------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+-------------------------------------------------------------------------------------------------------------+ +| |luli| | | +| | `Laboratoire pour l'Utilisation des Lasers Intenses `_ (LULI), UMR 7605 | +| | | ++ +-------------------------------------------------------------------------------------------------------------+ +| | * `Mickael Grech `_ | +| | * `Tommaso Vinci `_ | +| | * `Marco Chiaramello `_ | +| | * `Anna Grassi `_ | +| | * `Frédéric Pérez `_ | +| | * `Caterina Riconda `_ | +| | | ++------------+-------------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+---------------------------------------------------------------------------------------------------------+ +| |llr| | | +| | `Laboratoire Leprince-Ringuet `_ (LLR), UMR 7638 | ++ +---------------------------------------------------------------------------------------------------------+ +| | | +| | * `Arnaud Beck `_ | +| | * `Imen Zemzemi `_ | +| | * `Guillaume Bouchard `_ | ++------------+---------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+----------------------------------------------------------------------------------------------------------------------+ +| |lpgp| | | +| | `Laboratoire de Physique des Gaz et des Plasmas `_ (LPGP), UMR 8578 | ++ +----------------------------------------------------------------------------------------------------------------------+ +| | | +| | * `Francesco Massimo `_ | ++------------+----------------------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+----------------------------------------------------------------------------------------------------------------------+ +| |idris| | | +| | `Institut du developpement et des ressources en informatique scientifique `_ (IDRIS), UPS 851 | ++ +----------------------------------------------------------------------------------------------------------------------+ +| | | +| | * `Olga Abramkina `_ | +| | * `Marie Flé `_ | ++------------+----------------------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+------------------------------------------------------------------------------------------------------------------+ +| |lpp| | | +| | `Laboratoire de Physique des Plasmas `_ (LPP), UMR 7648 | ++ +------------------------------------------------------------------------------------------------------------------+ +| | | +| | * `Nicolas Aunai `_ | +| | * `Jérémy Dargent `_ | +| | | ++------------+------------------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+------------------------------------------------------------------------------------------------------------------+ +| |IRAMIS| | | +| | `Institut Rayonnement Matière de Saclay `_ (Iramis) | ++ +------------------------------------------------------------------------------------------------------------------+ +| | | +| | | ++------------+------------------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+------------------------------------------------------------------------------------------------------------------+ +| |IRAP| | | +| | `Institut de Recherche en Astrophysique et Planétologie `_ (IRAP) | ++ +------------------------------------------------------------------------------------------------------------------+ +| | | +| | * `Illya Plotnikov `_ | +| | | ++------------+------------------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+------------------------------------------------------------------------------------------------------------------+ +| |intel| | | +| | `Intel `_ | ++ +------------------------------------------------------------------------------------------------------------------+ +| | | +| | * `Asma Farjallah `_ | +| | | ++------------+------------------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+------------------------------------------------------------------------------------------------------------------+ +| |IAPRAS| | | +| | `Institute of Applied Physics, Russian Academy of Science `_ | ++ +------------------------------------------------------------------------------------------------------------------+ +| | | +| | * `Anton Golovanov `_ | +| | | ++------------+------------------------------------------------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+------------------------------------------------------------------------------------------------------------------+ +| |GOTHB| | | +| | `University of Gothenburg `_ | ++ +------------------------------------------------------------------------------------------------------------------+ +| | | +| | * `Evangelos Siminos `_ | +| | * `Illia Thiele (Chalmers University) `_ | +| | | ++------------+------------------------------------------------------------------------------------------------------------------+ + +---- + +Related projects +^^^^^^^^^^^^^^^^ + +.. |openpmd| image:: /_static/labs/openpmd.jpg + :width: 6em + :align: middle + +.. rst-class:: noborder + ++------------+-----------------------------------------------------------------------------+ +| |openpmd| | | +| | The `OpenPMD `_ standard for formatting PIC data | +| | is progressively adopted in Smilei. | ++------------+-----------------------------------------------------------------------------+ + +---- + +Acknowledgments +^^^^^^^^^^^^^^^ + +Financial support from the *Laboratoires d'Excellence*: + +.. |plasapar| image:: /_static/labs/plasapar.png + :width: 130px + :align: middle + +.. |palm| image:: /_static/labs/palm.png + :width: 130px + :align: middle + +.. |P2IO| image:: /_static/labs/p2io.png + :width: 6em + :align: middle + +.. rst-class:: noborder + ++------------+-----------------------------------------------------------------------------+ +| |plasapar| | | `Plas@Par `_ provided grants for 2 PhD thesis. | +| | | and 1 post-doc. | ++------------+-----------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+-----------------------------------------------------------------------------+ +| |palm| | | Smilei was initiated thanks to the SimPLE junior chair | +| | | granted by the labex `PALM `_. | ++------------+-----------------------------------------------------------------------------+ + +.. rst-class:: noborder + ++------------+-----------------------------------------------------------------------------+ +| |P2IO| | | Francesco Massimo's 2 years post-doc was funded by the | +| | | labex `P2IO `_. | ++------------+-----------------------------------------------------------------------------+ diff --git a/_sources/Overview/releases.rst.txt b/_sources/Overview/releases.rst.txt new file mode 100644 index 000000000..c5669af1f --- /dev/null +++ b/_sources/Overview/releases.rst.txt @@ -0,0 +1,451 @@ +Releases +-------- + + +Get Smilei +^^^^^^^^^^^^^^^^ + +**Clone the latest version of Smilei from** `GitHub `_: + +.. code :: + + git clone https://github.com/SmileiPIC/Smilei.git + +*Learn about Git* `here `_. + + +You can find older, `unsupported versions here `_ + +---- + +.. _latestVersion: + +Changes made in the repository (not released) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +... + +---- + +Projects +^^^^^^^^^^^^^^^^ + +* Already available, but experimental: + + * Particle merging + * Nuclear reactions + * Perfectly Matched Layers + * NewParticles diagnostic + +* In preparation: + + * Spectral solvers + + +---- + +Release 5.0 +^^^^^^^^^^^^^^^^^^^^^ + +* **GPU support** (not all features are supported at the moment) + + * Both AMD and Nvidia GPUs + * Cartesian geometry in 2D and in 3D + * Moving Window + * Diagnostics: Field, Probes, Scalar, ParticleBinning, TrackParticles + +---- + +Release 4.8 +^^^^^^^^^^^^^^^^^^^^^ + +* **LaserEnvelope model**: + + * Now compatible with ``PML`` boundaries + * In ``AMcylindrical`` geometry, the number of modes can be greater than 1 (only affects electromagnetic + fields and the densities, not envelope or susceptibility) + * multi-level tunnel ionization creates multiple electrons, improving the sampling + +* **Diagnostics** + + * Much faster ``DiagFields`` (speedup ~ x3) + * ``DiagFields`` and ``DiagProbe``: new parameter ``datatype`` + * ``DiagPerformances``: new parameter ``cumulative`` + +* **Collisions**: new parameter ``time_frozen`` +* **Species**: in ``AMcylindrical`` geometry, the initial drift velocity profiles may be defined + either in the ``x,r,θ`` directions with ``mean_velocity_AM`` or in the ``x,y,z`` directions with ``mean_velocity``. +* **Lasers**: changed the delay and phase of gaussian lasers at high incidence to make them consistent between boundaries. + +* **Happi**: + + * Operations in ``Fields``, ``Probe``, and ``ParticleBinning`` may now accept physical constants, units, + or basic functions such as ``exp()`` or ``sin()`` + * ``Probe`` has a new method ``changeField`` + * ``Open`` has a new argument ``pint`` to disable the *Pint* package + * ``multiPlot`` and ``multiSlide`` have a new argument ``legend_font`` + * The ``title`` can be formatted with a placeholder for the current time in an animation + * Various performance improvements + +* **Friedman filter**: now available in geometries ``1Dcartesian`` and ``AMcylindrical`` (previously available only in ``2Dcartesian``) +* **Lehe solver** for Maxwell equations now available in ``AMcylindrical`` geometry + +* **Bugfixes**: + + * Compilation fixed for the newest version of GNU make + * Poisson Solver correction was not properly accounted for with SDMD + * Bug correction using Monte-Carlo radiation and multiphoton Breit-Wheeler processes with checkpoints + * C++11 compilation issue + * Reading particle weights and momenta from hdf5 file + * ``PML`` are now compatible with dynamic load balancing. + * solved segfault with Multiphoton Breit-Wheeler process in `AMcylindrical` geometry + * Collisional ionization incorrect for :math:`Z^\star = Z-1` + * ``Field.getAxis`` was not accounting for the ``timestep`` + * Bug correction in 1D relativistic Poisson solver + +* **Experimental** + + * B-TIS3 interpolation scheme to reduce the effects of numerical Cherenkov radiation is implemented up to interpolation order 2 + * New diagnostic: ``DiagNewParticles`` records particle information when they are created by ionization or other mechanisms + +.. + * :doc:`/Understand/task_parallelization` of macro-particle operations with OpenMP + * Rudimentary visualization for macro-particle operation scheduling, activated through a compilation flag + +* **For developers**: new table management for Monte-Carlo physical processes (transparent to users) + +---- + +Release 4.7 +^^^^^^^^^^^^^^^^^^^^^ + +* **Perfectly Matched Layers** boundary conditions for EM fields (+2D Cartesian benchmark). +* Improved performance for ARM-based processors including the Fujitsu A64FX +* Improved performance for GNU, LLVM, arm-clang and Fujitsu compilers on all types of architectures +* Lasers can be injected from all boundaries +* Flag ``ponderomotive_dynamics`` removed from ``Species`` block. All ``Species`` interact with ``LaserEnvelope`` if present +* Option to create neutrons for D-D fusion +* Collisions can be done less often +* Lasers can be injected from all boundaries +* New 4th-order non-standard FDTD solver ``M4`` +* Timestep dependent field interpolation scheme +* ``LaserOffset``: + + * may be re-used from a previous simulation + * available from ``ymin``, ``ymax``, ``zmin`` and ``zmax`` + * has new arguments ``fft_time_window`` and ``fft_time_step`` + +* Diagnostics: + + * Probes can include components of the Poynting vector ``PoyX``, ``PoyY``, ``PoyZ`` + * Probes can be time-integrated + * ``ParticleBinning`` diagnostics may accept ``"auto"`` as axis limits + * Particle IDs may be modified in the ``DiagTrackParticles.filter`` (8 available bits) + * Screens may have a ``cylinder`` shape + * Scalar diagnostics for AM geometry now available + * happi ``ParticleBinning`` now uses the keyword ``average`` instead of ``sum`` + +* Bugfixes: + + * Poynting scalars behaviour with several patches, or with checkpoints + * Densities too low are put to 0 to avoid underflow + * Prescribed fields in 2D + * ``ellipticity = -1.`` was doing ``+1.`` + * Setting ``units`` in happi's ``TrackParticles`` was wrong (for plotting only) + * Current communication correction for FIR filters + * Fix for particle merging segmentation fault in spherical and Cartesian modes + * Tracked particles with the vectorized mode + * ``momentum_initialization`` from a file did not take the proper file + +---- + +Release 4.6 +^^^^^^^^^^^^^^^^^^^^^ + +* :doc:`/Understand/SDMD` +* New 4th-order non-standard FDTD solver ``Bouchard`` for 2D and 3D geometries +* New method for current filtering with a user-provided FIR kernel for 1D, 2D and 3D geometries +* Diagnostics may now have a ``name`` (useful during post-processing) +* Laser Envelope: + + * linear and circular polarization + * ionization model + * normalized laser frequency can be different from 1 + +* Particles can be imported from a file +* Some :doc:`/Use/profiles` can be imported from a file +* Coulomb logarithm may be multiplied by a constant factor +* Happi: + + * handles fonts + * time slider available with multiple plotting + * ``vsym`` option for symmetric graph + * ``getXmoved`` now accounts for requested units + * Tracked particles can be selected before sorting + +* Bugfixes: + + * Fix in the vectorized projection at order 4 + * Photons could not be read from numpy array + * DiagFields with ``time_average`` did not work for densities + * Prescribed fields caused unstable real fields + * Initialisation from numpy or hdf5 caused wrong weights in AM geometry + * Better positionning of collisionally-ionised electrons + * Fix segfault from thermalizing boundary + * Running a simulation displayed the wrong version v4.4 + +---- + +Release 4.5 +^^^^^^^^^^^^^^^^^^^^^ + +* Changes: + + * Current filtering with adjustable number of passes per dimension + * Improved axial boundary conditions for ``AMcylindrical`` geometry + * Units in ``RadiationSpectrum`` diagnostic are more consistent with that + of ``ParticleBinning`` + * Ionisation current at fourth order of interpolation + * Correction for :doc:`/Understand/collisions` as suggested in [Higginson2020]_ + +* Bugfixes: + + * ``PrescribedField`` was sometimes not applied by some OpenMP threads + * Scalar ``Ukin_bnd`` was sometimes wrong with load balancing + * Scalar ``Urad`` was sometimes wrong with moving window + * On some systems, particles IDs were incorrect with ionization + + +---- + +Release 4.4 +^^^^^^^^^^^^^^^^^^^^^ + +* Changed radiation tables: see :doc:`the doc `. + + * :red:`Old tables are not valid anymore, input files must be updated.` + * Default tables are now embebded in the code + * Possibility to read external generated by an :doc:`external tool ` (more efficient and stable) + +* New ``RadiationSpectrum`` diagnostics available (see :doc:`the doc `) +* ``AMcylindrical``: sorting, documentation, subgrid in DiagFields, + species-related currents and density in probes (not per mode anymore) +* LaserOffset is not recomputed after restart +* Prescribed fields that only contribute to pushing particles +* Laser Envelope: added envelope equation solver with reduced numerical dispersion +* Bugfixes: + + * Weight-initialization bug in AM geometry when a species was initialized + on top of a regularly-initialized species + * LaserOffset was off sideways and temporally by a couple of cells + * Do not project twice a frozen species + * Probes for species faulty when 4th order of interpolation + * Checkpoints ``restart_number=0`` was not used + * Checkpointing with ``dump_minutes`` could be out of sync between MPI process + * Prevent deadlock when restart files are corrupted + * Checkpoints ``file_grouping`` had typo with python3 + * Scalar ``Ukin`` for ions was incorrect, thus ``Ubal`` was also wrong + * happi had incorrect unit conversion with a sum of two fields + * fix error occurring when envelope Probes on axis are used in AM geometry + + +---- + +Release 4.3 +^^^^^^^^^^^^^^^^^^^^^ + + +* ``AMcylindrical`` : envelope, ionization, additional diagnotics, + number of ppc per direction, binomial current filter, poisson solver, + non-separable laser initialization per mode, improved diag field nomenclature +* Particle injector +* More control over the moving window movement +* More control over the regular position initialization in Cartesian geometries +* Bugfixes: + + * ionization of frozen species + * particle binning was not following the moving window + * gaussian profile with order 0 was incorrect + * tracked particles post-processing was incorrect above 20M particles + * better management of particle binning in collisions + * Intel 19 optimizations + + +---- + +Release 4.2 +^^^^^^^^^^^^^^^^^^^^^ + +* ``AMcylindrical`` geometry with azimuthal Fourier decomposition (beta version) +* Different convention for circular polarization amplitude +* 1D and 2D laser envelope model +* Compatibility between various ionization and QED models +* Bugfixes: + + * Binomial filter in Cartesian 3D parallel implementation + * Various crashes linked to vectorization + * ``LaserGaussian2D`` when focused far from boundary + * Laser :py:data:`a0` normalization to :py:data:`omega` + * Frozen particles are now properly ionized + * Position initialization over another species with moving window + * Tracked particles output was missing the mass factor for momenta + * Breit-Wheeler pair production with fine grain sorted particles + + +---- + +Release 4.1 +^^^^^^^^^^^^^^^^^^^^^ + +* Probe diagnostics of currents and density per species +* Field diagnostics with more than 2^32 points +* Bugfixes: + + * collisions (badly affected by vectorization) + * adaptive vectorization with dynamic load balancing + * memory leak in the laser envelope model + +* Disable usage of ``-ipo`` to compile on supercomputers + despite of saving time simulation + + * it needs too many resources (time and memory) to link + * it is recommended to do some tests on a new supercomputer + without and then to re-establish it + +.. warning:: + + Since version 4.1, the :ref:`definition of macro-particle weights` + has changed to ensure they do not depend on the cell volume. This impacts + only the users working directly with values of weights. Other simulation + results should be unchanged. + + +---- + +Release 4.0 +^^^^^^^^^^^^^^^^^^^^^ + +* :ref:`vectorization` +* :ref:`laser_envelope` +* MPI option ``MPI_THREAD_MULTIPLE`` is now optional (but recommended) +* Faster collisions +* Bugfixes: handling ``sum`` for happi's ``ParticleBinning`` + +---- + +Release 3.5 +^^^^^^^^^^^^^^^^^^^^^ + +* :doc:`Laser defined in tilted plane` +* Bugfixes: Field diagnostic subgrid, Scalar diagnostic PoyInst, + MPI tags for large number of patches + +---- + +Release 3.4.1 +^^^^^^^^^^^^^^^^^^^^^ + +* Ionization considering a user-defined rate + +---- + +Release 3.4 +^^^^^^^^^^^ + +* Compatibility with Python 3 +* New 'Performances' diagnostic +* Tracked particles may output the fields at their location +* 'subgrid' option in Fields diagnostics +* Printout of the expected disk usage +* Laser propagation pre-processing +* More flexible domain decomposition +* Relativistic initialization +* Particles injection using Numpy arrays +* Possibility to use user-defined ionization rates +* Bugfixes: circular polarization, collisional ionization + +---- + +Release 3.3 +^^^^^^^^^^^ + +* **Major** :doc:`syntax changes` in the namelist +* QED radiation reaction +* Monte-Carlo QED photon emission +* *Test mode* to quickly check the namelist consistency +* *ParticleBinning* and *Screen* diagnostics accept a python function as their + ``deposited_quantity`` and ``axis``. +* Bugfixes: 4th order, field ionization + +---- + +Release 3.2 +^^^^^^^^^^^ + +* New pushers (Vay's and Higuera-Cary's) +* *Numpy* used for filtering track particles +* Fourth order in 3D +* Add some missing 3D features: external fields management, boundary conditions + and non-neutral plasma initialization +* OpenMP support in moving window +* Tracked particles post-processing improved for large files +* Bugfixes: energy computation in 3D or with moving window, random number seed + +---- + +Release 3.1 +^^^^^^^^^^^ + +* *Screen* diagnostics +* Exporting 3D diagnostics to VTK for reading in ParaView or VisIt +* Partial support of the `OpenPMD `_ standard +* Improvements: moving window (OpenMP), 3D projection +* Bugfixes: tracked particles, walls, collisional ionization, etc. + +Notes: + +* Outputs of Fields and Tracks are incompatible with 3.0 +* The input "output_dir" is not supported anymore + +---- + +Release 3.0 +^^^^^^^^^^^ + +* **3D geometry** +* Field and scalar diagnostics improved for more flexibility and memory saving +* Faster initialization (including Maxwell-Jüttner sampling) +* Post-processing handles restarts +* Bugfixes in checkpoints, timers, memory profile + +---- + +Release 2.3 +^^^^^^^^^^^ + +* Post-processing scripts have been turned into a *python* module +* Many bugfixes, such as addressing diagnostics efficiency + + +---- + +Release 2.2 +^^^^^^^^^^^ + +* **state-of-the-art dynamic load balancing** +* full *python* namelist, allowing for complex, user-friendly input +* external fields and antennas +* binary Coulomb collisions +* new diagnostics +* *python* scripts for post-processing + +---- + +Release 1.0 +^^^^^^^^^^^ + +* 1D & 2D cartesian geometries +* Moving window +* Hybrid MPI-OpenMP parallelization +* Field ionization +* Some python diagnostics diff --git a/_sources/Overview/synopsis.rst.txt b/_sources/Overview/synopsis.rst.txt new file mode 100644 index 000000000..be3c6331a --- /dev/null +++ b/_sources/Overview/synopsis.rst.txt @@ -0,0 +1,48 @@ +Synopsis +-------- + +Smilei is a collaborative project providing physicists with an open-source, +user-friendly, high-performance and multi-purpose +**electromagnetic Particle-In-Cell (PIC) code for plasma simulation**. + +The code is developed in C++ based on an object-oriented architecture. +To face the diverse needs of the Smilei community, it offers modularity: + +* various geometries (Cartesian 1D, 2D, 3D or cylindrical with decomposition into azimuthal modes), +* arbitrary laser or plasma profiles (any Python function), +* various Maxwell solvers, particle pushers, interpolators, projectors +* an envelope solver, including in the cylindrical geometry +* advanced boundary conditions (e.g. Perfectly-Matched Layers) +* etc. + +The **user-friendly interface** consists in input files written in the Python language, +and a whole set of run-time diagnostics (outputs in HDF5) and user-friendly (Python) +:doc:`post-processing ` tools complement the code. + +Co-developed by HPC specialists and physicists, Smilei is **designed for high performances** +on massively-parallel super-computers. It benefits from a state-of-the-art hybrid +MPI/OpenMP parallelization, dynamic load balancing and SIMD vectorization. +It has been successfully tested on various architectures, among which the most recent +Intel Cascadelake (CSL) & Fujitsu A64FX (ARM). + +Recently, GPU acceleration has been implemented in SMILEI and allows offloading on Nvidia or AMD GPUs, such as V100, A100 or MI250. +As of yet, not all features are supported. + +In Smilei, Maxwell’s equations are solved using a Yee mesh, where the +electric and magnetic fields are centered following the finite-difference time-domain (FDTD) +method or related methods. A pseudo-spectral analytical time domain method is +also available as an experimental feature. +Charge deposition follows a charge-conservation scheme. + +As a multi-purpose code, Smilei is applied to a **wide range of physics-related studies**: +from relativistic laser-plasma interaction to astrophysics. Smilei thus benefits from +various additional physics modules, among which :ref:`field ionization `, +:doc:`binary collisions and impact ionization `. QED processes, such as +high-energy photon emission and its :doc:`back-reaction ` +on the electron dynamics, as well as +:doc:`pair production ` through the Breit-Wheeler +process, are also included. + +An initial detailed account (as of 2018) of Smilei's capabilities is given in +`this article `_. +For publications on more advanced features, please refer to the :doc:`material` section of this documentation. diff --git a/_sources/Understand/GPU_offloading.rst.txt b/_sources/Understand/GPU_offloading.rst.txt new file mode 100644 index 000000000..20fb5ac07 --- /dev/null +++ b/_sources/Understand/GPU_offloading.rst.txt @@ -0,0 +1,25 @@ +GPU offloading +---------------------- + +To support recent supercomputers, :program:`Smilei` has been ported on GPU (graphical processing units). +Initially built to handle complex graphical output and related to rendering and video games, +GPUs appeared only relatively recently in the HPC ecosystem. +Unlike CPUs, GPUs can do much smaller sets of tasks with massive data throughput. + +Currently 7 of the 10 most powerful supercomputers are based on GPU acceleration and +the trend seems confirmed at least in the near future: +the announced exaflopic supercomputers will include GPUs. + +* Guideline: in general it is recommended to use one patch per GPU + to obtain the best performance. However, for better memory management, + testing a few patches per GPU is encouraged. + +* Currently supported features: + + * Both AMD's GPUs and Nvidia's GPUs are supported + * Cartesian geometry in 2D and in 3D + * Diagnostics: Field, Probes, Scalar, ParticleBinning, TrackParticles + * Moving Window. + +* A few key features remain to be implemented (AM geometry, ionization, PML, envelope, + additional physics), but the fundamentals of the code are ported. \ No newline at end of file diff --git a/_sources/Understand/PML.rst.txt b/_sources/Understand/PML.rst.txt new file mode 100644 index 000000000..9ff3d45d8 --- /dev/null +++ b/_sources/Understand/PML.rst.txt @@ -0,0 +1,92 @@ +Perfectly Matched Layers +------------------------------------- + +Perfectly Matched Layers (PML) are open boundary conditions for electromagnetic and laser envelope fields. +This means that a wave propagating through the boundary will be absorbed and not reintroduced into the simulation. +In that regard, it plays the same role as the "Silver-Muller" boundary conditions which is supported for electromagnetic fields only (not envelope). + +At the cost of having a slightly higher computing cost than Silver-Muller, PML have several very interesting advantages: + +* All resolved frequencies are equally absorbed. +* Absorption is efficient for any incident angle. +* The overall absorption of exiting waves is, in most cases, much better than Silver-Muller. + +This leads to a more accurate result of course but can also relaxes constraints on the size of the simulation domain. +Very large transverse sizes to let the laser diffract more before it hits the boundary is no longer necessary for instance. + +.. rubric:: Basic use + +A PML is in fact several layers of absorbing media which are contiguous to the simulation domain and through which exiting waves are going. +The waves are progressively absorbed as they travel across this absorbing media. +The thickness of this media can be tuned with the parameter `number_of_pml_cells` and is in fact equal to + +.. math:: + :label: PMLthickness + + PML_{\rm thickness} = {\rm number\_of\_pml\_cells[0]}\times {\rm dx}, + +in the `x` direction. + +Keep in mind that **the absorbing power of a PML increases with its physical thickness**. + +This means that the more layers are set, the more absorbing the PML is. +But adding layers also increases computing time of course because it is similar to increasing the simulation domain size. + +It also means that the absorption of the PML depends on the resolution `dx`. +Higher resolution simulations will need more cells in order to keep the same thickness and therefore the same absorption as a less resolved one. + +The default number of pml cells is 6. + +.. rubric:: Rules of thumb for a good use of the PML + +First of all, it is important to realize that open boundary conditions are only good at letting waves out of the domain. +It does not relax any constraint on the quality of the initial conditions and will not prevent reflections if these are physical. + +The typical case is a vacuum/plasma interface at the boundary of the simulation box when a `remove` boundary condition is chosen for particles. +In that configuration, if the plasma density is high enough at the interface, there can be perfectly physical reflections that PML are not designed to mitigate. +We therefore advise to use plasma profiles whith decreasing densities close to the boundaries. + +.. rubric:: Advanced settings for Cartesian Geometry + +In the PML medium, the complex susceptibility is given by + +.. math:: + :label: PMLsusceptibility + + s = \kappa + \frac{\sigma}{i\omega\epsilon_0}, + +where :math:`\kappa` and :math:`\sigma` can be chosen by the user. +They are functions of a single space variable which describes the normal position in the PML. +This variable ranges from 0 (the inner bound of the PML) to 1, the outer bound of the PML. + +One profile per simulation dimension is required and the same profile is applied to both sides of a given dimension. + +.. rubric:: Expert settings for AM geometry + +In the specific case of the AM geometry, using arbitrary susceptibility profiles is trickier because an integration along the radial direction is necessary. +Therefore it is important that :program:`Smilei` knows not only the profiles of `sigma` and `kappa` but also a primitive of these profiles along the radial dimension. + +It is up to the user to provide such primitives in the namelist using the following syntax (here is an example for `sigma`): + + | **Syntax 1:** ``[sigma, integrate_sigma]``, identical for all dimensions. + | **Syntax 2:** ``[sigma_x, sigma_r, integrate_sigma_r]``, different on each dimension. + +The default profiles identical for all dimensions and are given by: + +.. code-block:: python + + def sigma(u): + return 20. * u**2 + def integrate_sigma(u): + return 20./3. * u**3 + def kappa(u): + return 1 + 79. * u**4 + def integrate_kappa(u): + return u + 79./5. * u**5 + +.. rubric:: PML for the envelope model + +For stability purposes, the PML boundaries for the envelope use frequency shifting which prevents from using arbitrary profiles for the susceptibility. +Therefore it is not possible to tune its profile. + +Details of the method will be published soon. diff --git a/_sources/Understand/SDMD.rst.txt b/_sources/Understand/SDMD.rst.txt new file mode 100644 index 000000000..3bb432369 --- /dev/null +++ b/_sources/Understand/SDMD.rst.txt @@ -0,0 +1,36 @@ +.. rst-class:: experimental + +Single-domain multiple decompositions +------------------------------------- + +The standard decomposition of the simulated domain consists in splitting +the grid in rectangular "patches" that contain both fields and particles +(see :doc:`parallelization`). A new technique has been developed for Smilei, +"Single-Domain Multiple Decompositions" (SDMD), where two decompositions are +made: + +* Particles are still contained in the same small, rectangular patches. +* Fields are contained in large, rectangular "regions". + +Each MPI process owns many patches but only (and exactly) one region. +A single region extent therefore covers the equivalent of many patches allowing +communication-less operations over a larger area. + +Fields are simply communicated from regions to patches in order to interpolate their +values at the particles locations. Inversely, currents and densities are communicated +from patches to regions in order to solve Maxwell's equations. + +The region extents are always Cartesian and their size is as homogeneous as possible. +The association between MPI processes and regions is dynamically reconsidered +during the simulation if dynamic load balancing is used. +The goal is to maximize the overlap between the region and the collection of +patches owned by the MPI process at all times in order to reduce communication overhead. + +.. rubric:: Advantages + +* The synchronization overhead induced by the use of very small patches is reduced. +* Operations requiring many ghost cells (like large-stencil filters or spectral solvers) + can be executed much more efficiently. + +The benefits of SDMD are illustrated +`in this paper `_. diff --git a/_sources/Understand/algorithms.rst.txt b/_sources/Understand/algorithms.rst.txt new file mode 100644 index 000000000..4c52ef231 --- /dev/null +++ b/_sources/Understand/algorithms.rst.txt @@ -0,0 +1,492 @@ + +PIC algorithms +-------------- + +This document describes the theoretical basis with which :program:`Smilei` simulates +the behaviour of plasmas. Note that all quantities are expressed in terms of the +:doc:`reference units `. + +---- + +The Maxwell-Vlasov model +^^^^^^^^^^^^^^^^^^^^^^^^ + +The kinetic description of a collisionless plasma relies on the so-called Vlasov-Maxwell +system of equations. In this description, the different species of particles constituting +the plasma are described by their respective distribution functions +:math:`f_s(t,\mathbf{x},\mathbf{p})`, where :math:`s` denotes a given species consisting +of particles of charge :math:`q_s`, mass :math:`m_s`, and :math:`\mathbf{x}` and +:math:`\mathbf{p}` denote the position and momentum of a phase-space element. +The distribution :math:`f_s` satisfies Vlasov's equation: + +.. math:: + :label: Vlasov + + \left(\partial_t + \frac{\mathbf{p}}{m_s \gamma} \cdot \nabla + \mathbf{F}_L \cdot \nabla_{\mathbf{p}} \right) f_s = 0\,, + +where :math:`\gamma = \sqrt{1+\mathbf{p}^2/m_s^2}` is the (relativistic) Lorentz factor, + +.. math:: + :label: LorentzForce + + \mathbf{F}_L = q_s\,(\mathbf{E} + \mathbf{v} \times \mathbf{B}) + +is the Lorentz force acting on the particles. +This force follows from the existence, in the plasma, of collective (macroscopic) +electric [:math:`\mathbf{E}(t,\mathbf{x})`] and magnetic [:math:`\mathbf{B}(t,\mathbf{x})`] +fields satisfying Maxwell's equations: + +.. math:: + :label: Maxwell + + \begin{eqnarray} + \nabla \cdot \mathbf{B} &=& 0 \,,\\ + \nabla \cdot \mathbf{E} &=& \rho \,,\\ + \nabla \times \mathbf{B} &=& \mathbf{J} + \partial_t \mathbf{E} \,,\\ + \nabla \times \mathbf{E} &=& -\partial_t \mathbf{B} \,. + \end{eqnarray} + +The Vlasov-Maxwell system of equations :eq:`Vlasov`--:eq:`Maxwell` describes the +self-consistent dynamics of the plasma which consistuents are subject to the Lorentz force, +and in turn modify the collective electric and magnetic fields through their charge and +current densities: + +.. math:: + :label: rhoJ + + \begin{eqnarray} + \rho(t,\mathbf{x}) &=& \sum_s q_s\int\!d^3\!p f_s(t,\mathbf{x},\mathbf{p})\,,\\ + \mathbf{J}(t,\mathbf{x}) &=& \sum_s q_s\int\! d^3\!p\,\mathbf{v} f_s(t,\mathbf{x},\mathbf{p})\,, + \end{eqnarray} + +where we have introduced the velocity :math:`\mathbf{v} = \mathbf{p}/(m_s\,\gamma)`. + + +---- + +.. _QuasiParticlesSection: + +Quasi-particles +^^^^^^^^^^^^^^^ + +The *Particle-In-Cell* method owes its name to the discretization of the distribution +function :math:`f_s` as a sum of :math:`N_s` *quasi-particles* (also referred to as +*super-particles* or *macro-particles*): + +.. math:: + :label: fs_discretized + + f_s(t,\mathbf{x},\mathbf{p}) = + \sum_{p=1}^{N_s}\,\frac{w_p}{V_c}\,\,S\big(\mathbf{x}-\mathbf{x}_p(t)\big)\,\delta\big(\mathbf{p}-\mathbf{p}_p(t)\big)\,, + +where :math:`w_p` is a quasi-particle *weight*, :math:`\mathbf{x}_p` is its position, +:math:`\mathbf{p}_p` is its momentum, :math:`V_c` is the hypervolume of the cell, +:math:`S` is the shape-function of all quasi-particles, +and :math:`\delta` is the Dirac distribution. + +In PIC codes, Vlasov's equation :eq:`Vlasov` is integrated along the continuous trajectories +of these quasi-particles, while Maxwell's equations :eq:`Maxwell` are solved on a +discrete spatial grid, the spaces between consecutive grid points being referred to as +*cells*. Injecting the discrete distribution function of +Eq. :eq:`fs_discretized` in Vlasov's equation :eq:`Vlasov`, multiplying the result by +:math:`\mathbf{p}` and integrating over all :math:`\mathbf{p}` and over the volume of +the quasi-particles, leads to the relativistic equations of motion of individual +quasi-particles: + +.. math:: + + \begin{eqnarray} + \frac{d\mathbf{x}_p}{dt} &=& \frac{\mathbf{u}_p}{\gamma_p}\,\\ + \frac{d\mathbf{u}_p}{dt} &=& r_s \, \left( \mathbf{E}_p + \frac{\mathbf{u}_p}{\gamma_p} \times \mathbf{B}_p \right), + \end{eqnarray} + +where :math:`r_s = q_s/m_s` is the charge-over-mass ratio (for species :math:`s`), +:math:`\mathbf{u}_p = \mathbf{p}_p/m_s` is the reduced momentum and +:math:`\gamma_p=\sqrt{1+\mathbf{u}_p^2}` is the Lorentz factor. + + +---- + +.. _StaggeredGrid: + +Time and space discretization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Maxwell's equations are solved here using +the `Finite Difference Time Domain (FDTD) approach `_ +as well as `refined methods based on this algorithm `_. +In these methods, the electromagnetic +fields are discretized onto a staggered grid, the so-called Yee-grid that allows for +spatial-centering of the discretized curl operators in Maxwell's equations. +The following figure summarizes at which points of the Yee-grid are defined the +electromagnetic fields as well as charge and density currents. + +.. image:: /_static/figYee.png + :width: 13cm + +Similarly, the time-centering +of the time-derivative in Maxwell's equations is ensured by considering the electric fields +as defined at integer time-steps :math:`(n)` and magnetic fields at half-integer +time-steps :math:`(n+\tfrac{1}{2})`. Time-centering of the magnetic fields is however +necessary for diagnostic purposes, and most importantly when computing the Lorentz force +acting on the quasi-particles. + + + +A *leap-frog* scheme is used to advance the particles in time, so that the particle positions +and velocities are defined at integer :math:`(n)` and half-integer :math:`(n-\tfrac{1}{2})` +time-steps, respectively. + +---- + +Initialization of the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The initialization of a PIC simulation is a three-step process consisting in + +#. loading particles, +#. computing the initial total charge and current densities on the grid, +#. computing the initial electric and magnetic field at the grid points. + +In :program:`Smilei`, all three steps can be done either as a restart of a previous simulation +(in which case the particles, charge and current densities and electromagnetic fields are +directly copied from a file generated at the end of a previous simulation), or from a +user-defined input file. In that case, the user defines the initial conditions of the +particle, charge and current densities as well as the initial electromagnetic fields +over the whole simulation domain. + +In particular, the number density :math:`n_s(\mathbf{x})`, mean velocity +:math:`\mathbf{v}_s(\mathbf{x})` and temperature :math:`T_s(\mathbf{x})` of all species +:math:`s` in a given cell (located at position :math:`\mathbf{x}`) at time :math:`t=0` +have to be prescribed. The particle loading then consists in creating, in each cell, +:math:`N_s` particles with positions :math:`\mathbf{x}_p` (either randomly chosen or +regularly spaced) such that particles are uniformly distributed within the cell, +and momentum :math:`\mathbf{p}_p` randomly chosen such that the particle distribution +follows a Maxwell-Jüttner distribution with mean-velocity :math:`\mathbf{v}_s(\mathbf{x})` +and temperature :math:`T_s(\mathbf{x})`. + +In :program:`Smilei`, a weight is assigned to each particle depending on the density associated +to the cell it originates from: + +.. math:: + + w_p = \frac{n_s\big(\mathbf{x}_p(t=0)\big)}{N_s} V_c\,. + +This variable weighting is particularly beneficial when considering initially +highly-inhomogeneous density distributions. + +Once all particles in the simulation domain have been created, the total charge and +current densities :math:`\rho(t=0,\mathbf{x})` and :math:`\mathbf{J}(t=0,\mathbf{x})` +are computed on the grid using a simple projection technique: + +.. math:: + + \rho(t=0,\mathbf{x}) = \sum_s\,\sum_p\,W_p\,S\big(\mathbf{x}-\mathbf{x}_p(t=0)\big)\,, + +where :math:`W_p = q_s w_p / V_c`. + +Then, the initial electric fields are computed from :math:`\rho(t=0,\mathbf{x})` +by solving Poisson's equation. In :program:`Smilei`, this is done using the conjugate gradient +method. This iterative method is particularly interesting +as it is easily implemented on massively parallel computers and requires mainly +local information exchange between adjacent processes. + +External (divergence-free) electric and/or magnetic fields can then be added to the +resulting electrostatic fields, provided they fullfill Maxwell's equations :eq:`Maxwell`, +and in particular Gauss' and Poisson's. + +Note that a relativistically drifting plasma needs :doc:`special treatment `. + +---- + +The PIC loop +^^^^^^^^^^^^ + +At the end of the initialization stage [time-step :math:`(n=0)`], all quasi-particles +in the simulation have been loaded and the electromagnetic fields have been computed +over the whole simulation grid. The PIC loop is then started over :math:`N` time-steps +each consisting in + +#. interpolating the electromagnetic fields at the particle positions, +#. computing the new particle velocities and positions, +#. projecting the new charge and current densities on the grid, +#. computing the new electromagnetic fields on the grid. + +In this section, we describe these four steps which advance the time from +time-step :math:`(n)` to time-step :math:`(n+1)`. + + +Field interpolation +""""""""""""""""""" + +At the beginning of time-step :math:`(n)`, the particles velocity and position are known +at time-step :math:`(n-\tfrac{1}{2})` and :math:`(n)`, respectively. For each particle +:math:`p`, the electromagnetic fields [at time-step :math:`(n)`] are computed at the +particle position using a simple interpolation technique: + +.. math:: + + \begin{eqnarray} + \mathbf{E}_p^{(n)} = V_c^{-1} \int d^3\mathbf{x}\, S\left(\mathbf{x}-\mathbf{x}_p^{(n)}\right) \mathbf{E}^{(n)}(\mathbf{x})\,,\\ + \mathbf{B}_p^{(n)} = V_c^{-1} \int d^3\mathbf{x}\, S\left(\mathbf{x}-\mathbf{x}_p^{(n)}\right) \mathbf{B}^{(n)}(\mathbf{x})\,, + \end{eqnarray} + +where we have used the time-centered magnetic fields +:math:`\mathbf{B}^{(n)}=\tfrac{1}{2}[\mathbf{B}^{(n+1/2) } + \mathbf{B}^{(n-1/2)}]`. + + +Particle push +""""""""""""" + +Knowing, for each quasi-particle, the electromagnetic fields at its position, the new +particle momentum and position are computed using a (second order) leap-frog integrator. + +In :program:`Smilei`, different schemes have been implemented: +the well-known `Boris pusher `_ +both in the classical and relativistic form, +the `pusher developed by J.-L. Vay `_, +and the `pusher of Higuera and Cary `_. + +All schemes compute the new particle momentum and position according to + +.. math:: + + \mathbf{u}_p^{n+\tfrac{1}{2}}=\mathbf{v}_p^{n-\tfrac{1}{2}} + r_s \Delta t \, \left[ E_p^{(n)} + \frac{\mathbf{v}_p^{(n+\tfrac{1}{2})}+\mathbf{v}_p^{(n-\tfrac{1}{2})}}{2} \times B_p^{(n)}\right], + +.. math:: + + \mathbf{x}_p^{n+1}=\mathbf{x}_p^{n} + \Delta t \, \frac{\mathbf{u}_p^{n+\tfrac{1}{2}}}{\gamma_p}, + +where :math:`\Delta t` denotes the duration of a time-step. + + +Current deposition +"""""""""""""""""" + +Charge deposition (i.e. charge and current density projection onto the grid) is then +performed using the charge-conserving algorithm +`proposed by Esirkepov `_. +The current densities along the dimensions of the grid +(i.e., the :math:`x`-direction for 1D3V simulations, +both :math:`x`- and :math:`y`-directions for 2D3V simulations, +and all three :math:`x`-, :math:`y`- and :math:`z`-directions for 3D3V simulations) +are computed from the charge flux through the cell borders +(hence ensuring charge conservation) while the current densities along the other +dimensions are performed using a simple projection. + +To illustrate this point, we take the example of current deposition in a 2D3V simulation. +The current densities in the :math:`x`- and :math:`y`-directions associated to a particle +with charge :math:`q` are computed as: + +.. math:: + + \begin{eqnarray} + (J_x)_{i+\tfrac{1}{2},j}^{(n+\tfrac{1}{2})} = (J_x)_{i-\tfrac{1}{2},j}^{(n+\tfrac{1}{2})} + W_p\,\frac{\Delta x}{\Delta t}\,(W_x)_{i+\tfrac{1}{2},j}^{(n+\tfrac{1}{2})}\,\\ + (J_y)_{i,j+\tfrac{1}{2}}^{(n+\tfrac{1}{2})} = (J_y)_{i,j-\tfrac{1}{2}}^{(n+\tfrac{1}{2})} + W_p\,\frac{\Delta y}{\Delta t}\,(W_y)_{j,i+\tfrac{1}{2}}^{(n+\tfrac{1}{2})}\, + \end{eqnarray} + +where :math:`(W_x)^{(n+\tfrac{1}{2})}` and :math:`(W_y)^{(n+\tfrac{1}{2})}` are quantities computed +from the particle current and former positions :math:`x_p^{(n+1)}` and :math:`x_p^{(n)}`, +respectively, using the method developed by Esirkepov. +The particle current in the :math:`z`-direction (not a dimension of the grid) is, +in this geometry, computed using a simple projection: + +.. math:: + + (J_z)_{i,j} = W_r \mathbf{v}_p\,S(\mathbf{x}_{i,j}-\mathbf{x}_p)\,. + + +In all cases, the charge density deposited by the particle is obtained using the simple +projection: + +.. math:: + + (\rho)_{i,j}^{(n+1)} = W_p\,S(\mathbf{x}_{i,j}-\mathbf{x}_p^{(n+1)})\,. + +The total charge and current densities henceforth gather the contributions of all +quasi-particles of all species. It is worth noting that, within a charge-conserving +framework, charge densities are only projected on the grid for diagnostics purposes +(as we will see in the next paragraph, it is not used to advance the electromagnetic fields). + + +Maxwell solvers +""""""""""""""" + +Now that the currents are known at time-step :math:`n+\tfrac{1}{2}`, the electromagnetic +fields can be advanced solving Maxwell's equations :eq:`Maxwell`. + +First, Maxwell-Ampère is solved, giving the advanced electric fields + +.. math:: + + \mathbf{E}^{(n+1)} = \mathbf{E}^{(n)} + \Delta t\, \left[\left(\nabla \times \mathbf{B}\right)^{(n+\tfrac{1}{2})} - \mathbf{J}^{(n+\tfrac{1}{2})} \right]\,. + +Then, Maxwell-Faraday is computed, leading to the advanced magnetic fields + +.. math:: + + \mathbf{B}^{(n+\tfrac{3}{2})} = \mathbf{B}^{(n+\tfrac{1}{2})} - \Delta t\, \left(\nabla \times \mathbf{E}\right)^{(n+1)}\,. + +The discretization of the curl-operator is not detailed here. + +It is worth +noting that computing the two previous equations is sufficient to get a complete description +of the new electromagnetic fields. Indeed, it can be shown that this conserves a +divergence-free magnetic field if Gauss' equation is satisfied at time :math:`t=0`. +Similarly, Poisson's equation is verified as long as it is satisfied +at time :math:`t=0`, if the charge deposition algorithm fulfills the charge conservation +equation: + +.. math:: + + \partial_t \rho + \nabla \cdot \mathbf{J} = 0 + +(this motivated the use of Esirkepov's projection scheme discussed in the previous paragraph). + + +---- + +Boundary conditions +^^^^^^^^^^^^^^^^^^^ + + +After new quasi-particle positions and velocities have been computed, boundary conditions (BCs) +are applied to each quasi-particle that may be located in a ghost cell, +i.e. outside of the 'real' grid. +Quasi-particle species may have a different BC for each boundary of the simulation box: +the quasi-particles can either loop around the box (periodic), +be stopped (momentum set to zero), +suppressed (removed from memory), +reflected (momentum and position follow specular reflection rules) +or thermalized. +In the latter case, the quasi-particle is set back inside the simulation box, +and its new momentum is randomly sampled in a Maxwellian distribution +with a given temperature and drift velocity, both specified by the user. + +BCs are applied to the electromagnetic fields after Maxwell's equations have been solved. +Each boundary of the simulation box can feature a different BC. +First, injecting/absorbing BCs inspired from the Silver-Müller BC +are able to inject an electromagnetic wave (e.g. a laser) and/or +to absorb outgoing electromagnetic waves. +In contrast, the reflective electromagnetic BC will reflect any outgoing +electromagnetic wave reaching the simulation boundary. +Lastly, periodic BCs correspond to applying the fields from the opposite boundary. + + +---- + +.. _multipassBinomialFilter: + +Multi-pass filtering of the current densities +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A multi-pass filter on the current densities is available in :program:`Smilei`. +The user can choose a simple 3-points FIR binomial filter, +which implementation follows that presented by +`Vay et al. (2011) `_, +or a N-point kernel FIR filter. +Each pass consists in a N-point spatial averaging (in one or all spatial dimensions) +of the current densities, so that the filtered current density (here defined +at location i on a one-dimensional grid) is recomputed as: + +.. math:: + + J_{f,i} = \sum_{n=-(N-1)/2}^{+(N-1)/2} K_{(N-1)/2+n}J_{i+n} + +In particular, the binomial filter uses a kernel *K = [0.25,0.5,0.25]* resulting in + +.. math:: + + J_{f,i} = \frac{1}{2} J_i + \frac{J_{i+1}+J_{i-1}}{4} + +A user-provided FIR kernel must be of length *N* with an odd number of coefficients +(symmetrical to avoid phase effects). +The number of ghost cells must be greater than *(N-1)/2*. +Moreover, the sum of the kernel's coefficients must be equal to one. +This `online tool `_ is handy to design a custom filter. + +Current filtering, if requested by the user, is applied before solving +Maxwell’s equation, and the number of passes is an :ref:`input parameter ` +defined by the user. + +---- + +.. _EfieldFilter: + +Friedman filter on the electric field +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A method for temporal filtering of the electric field is also available in :program:`Smilei`. +It is the so-called Friedman filter detailed in `Greenwood et al. (2004) `_. +This method consists in computing the filtered electric field at time-step :math:`n`: + +.. math:: + + {\bf E}_f^{(n)} = \left(1+\frac{\theta}{2}\right) {\bf E}^{(n)} - \theta \left(1-\frac{\theta}{2}\right) {\bf E}^{(n-1)} + \frac{1}{2} \theta \big(1-\theta\big)^2 \bar{\bf E}^{(n-2)}, + +where: + +.. math:: + + \bar{\bf E}^{(n-2)} = {\bf E}^{(n-2)} + \theta \bar{\bf E}^{(n-3)}, + +and :math:`\theta \in [0,1[` is an :ref:`input parameter ` defined by the user. +Note that the filtered field :math:`E_f` is not used to push particles, but is used when solving the Maxwell-Faraday equation. +Also note that, as underlined in `Greenwood et al. (2004) `_, +using this particular filter modifies the CFL condition of the Maxwell solver. +A simple trick to ensure that this condition is still verified is to use (for :math:`\Delta x = \Delta y = \Delta z`) the +magic time-step :math:`\Delta t = \Delta x/2` whenever the Friedman filter is employed. + +Both filters on the :ref:`currents ` and :ref:`electric fields ` can be used together or +separately. They can be used, e.g., to mitigate the numerical Cherenkov instability that plagues PIC simulations dealing with +relativistically drifting flows. +An exemple of their use to mitigate this effect is highlighted in the work by `Plotnikov et al. (2017) `_. + +---- + +.. _BTIS3: + +B-translated interpolation scheme version 3 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This interpolation scheme, called B-TIS3 and described in detail in `P.-L. Bourgeois, X. Davoine (2023) `_, mitigates some numerical artifacts +that arise when macro-particles at relativistic velocities are present in the simulation: + +- inaccurate :math:`\mathbf{B}` interpolation due to the time and space staggering of :math:`\mathbf{E}` and :math:`\mathbf{B}` in the Yee grid. The associated errors are particularly detrimental for the accuracy of simulations with relativistic particles; + +- Numerical Cherenkov radiation (see e.g. `R. Lehe et al. (2013) `_) that arises with the interaction of relativistic particles and the numerical dispersion of Finite Difference methods used to solve Maxwell's Equations. As explained in the same reference, this numerical artefact can increase the divergence and emittance of relativistic particle beams. + +The B-TIS3 interpolation scheme can give a more accurate computation of the force acting on particles in presence of +fields that move at speed close to the speed of light in the `x` direction, which is the underlying hypothesis where this scheme can be used safely. +This hypothesis is also partially satisfied by Numerical Cherenkov radiation, as shown in `P.-L. Bourgeois, X. Davoine (2020) `_. +Please note that this scheme does not remove this numerical artifact (which will remain visible e.g. in ``Field`` diagnostics), but it mitigates its effects on the macro-particles. Instead, the effects of this interpolation scheme on the force acting on the macro-particles can be seen also through ``Probes`` showing the associated B-TIS3 fields. This because ``Probes`` act as macro-particles interpolating the fields from the grid as if they were plasma macro-particles. + +As described in `P.-L. Bourgeois, X. Davoine (2023) `_, the correction given by the B-TIS3 scheme on force interpolation (compared to the usual +interpolation of the magnetic field) is effective only when the normalized integration timestep :math:`\Delta t` is near to the value :math:`\Delta x` of the +grid cell size along the `x` direction. + +As explained before, in a typical PIC code using a Yee scheme to solve Maxwell's equations, the magnetic field interpolated on the macro-particles' +positions is often linearly interpolated in time. For example, for the :math:`B_z` component of the magnetic field: + +.. math:: + + B_{z,i-1/2}^{(n)}=\tfrac{1}{2}[B_{z,i-1/2}^{(n+1/2) } + B_{z,i-1/2}^{(n-1/2)}]. + +The B-TIS3 scheme tries to reduce the errors associated to this temporal interpolation and to the staggering of the electric and magnetic fields in the Yee cell, +interpolating a magnetic field defined at the same `x` spatial indices of the electric field when necessary. + +For example, in the `y` component of the Lorentz force, the electric field component :math:`E_y` is defined on the primal grid in the `x` direction, +but :math:`B_z` is defined on the dual grid in the `x` direction. + +Thus, in the B-TIS3 scheme a translated interpolation scheme is used for :math:`B_z` in the Lorentz force: + +.. math:: + + B_{z,i}^{(n), B-TIS3}=\tfrac{1}{2}[B_{z,i-1/2}^{(n-1/2) } + B_{z,i+1/2}^{(n+1/2)}]. + +As explained in the B-TIS3 reference, for :math:`\mathbf{B}` fields moving near to the speed of light in the `x` direction and for :math:`c\Delta t` near to the value :math:`\Delta x`, +this choice is more accurate than the usual linear temporal intepolation of the magnetic fields. + +Note that in the `x` component of the Lorentz force the electric field :math:`E_x` is defined on the +dual grid in the `x` direction, thus the usual Yee-centered and linearly interpolated :math:`B_z` (also defined on the +dual grid in the `x` direction) is maintained. diff --git a/_sources/Understand/azimuthal_modes_decomposition.rst.txt b/_sources/Understand/azimuthal_modes_decomposition.rst.txt new file mode 100644 index 000000000..ca6fca59f --- /dev/null +++ b/_sources/Understand/azimuthal_modes_decomposition.rst.txt @@ -0,0 +1,538 @@ + +Azimuthal modes decomposition +------------------------------------------ + +:program:`Smilei` can run in **cyclindrical geometry** with +a decomposition in azimuthal modes (*AM*), as described in +`this article `_. +This requires a system with cylindrical symmetry or close to cylindrical symmetry +(around the ``x`` axis in :program:`Smilei`). + +---- + +Mathematical definition +^^^^^^^^^^^^^^^^^^^^^^^ + +.. figure:: /_static/Coordinate_Reference_AMcylindrical.png + :width: 11cm + + Coordinates in azimuthal geometry. + +Any scalar field :math:`F(x,r,\theta)` can be decomposed into a basis of +azimuthal modes, or harmonics, defined as :math:`\exp(-im\theta)`, +where :math:`m` is the number of the mode. Writing each Fourier coefficient +as :math:`\tilde{F}^{m}` leads to: + +.. math:: + :label: AzimuthalDecomposition1 + + F\left(x,r,\theta\right) = \textrm{Re}\left[ + \sum_{m=0}^{+\infty}\tilde{F}^{m}\left(x,r\right)\exp{\left(-im\theta\right)} + \right], + +The mode :math:`m=0` has cylindrical symmetry (no dependence +on :math:`\theta`). The following figure shows the real part +of the first four azimuthal modes. + +.. figure:: /_static/AM_modes.png + :width: 15cm + + Real part of the first four pure azimuthal modes :math:`exp(-im\theta)` + on the ``yz`` plane. + +Eq. :eq:`AzimuthalDecomposition1` can be expanded as: + +.. math:: + :label: AzimuthalDecomposition2 + + F\left(x,r,\theta\right) = + \tilde{F}^{0}_{real} + + \tilde{F}^{1}_{real}\cos(\theta) + + \tilde{F}^{1}_{imag}\sin(\theta) + + \tilde{F}^{2}_{real}\cos(2\theta) + + \tilde{F}^{2}_{imag}\sin(2\theta) + ... + + +The complex coefficients :math:`\tilde{F}^{m}` can be calculated from :math:`F` +according to: + +.. math:: + + \tilde{F}^{m} &=& \frac{1}{\pi}\int_0^{2\pi} F\left(x,r,\theta\right)\exp{\left(-im\theta\right)}d\theta + & \quad\textrm{ for } m>0 \\ + \tilde{F}^{0} &=& \frac{1}{2\pi}\int_0^{2\pi}F\left(x,r,\theta\right)d\theta. + & \textrm{ for } m=0 + +---- + +Decomposition of vector fields +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Vector fields can also be decomposed in azimuthal modes through a +decomposition of each of their components along the cylindrical +coordinates :math:`(\mathbf{e_x},\mathbf{e_r},\mathbf{e_\theta})`. +For example, the transverse field :math:`\mathbf{E}_\perp` of a laser pulse +polarized in the :math:`y` direction with cylindrically symmetric envelope +can be written as + +.. math:: + + \mathbf{E}_\perp(x,r,\theta, t) &= E_y(x,r,\theta, t) \mathbf{e_y} \\ + &= E_r (x,r,\theta, t) \mathbf{e_r} + E_{\theta}(x,r,\theta, t) \mathbf{e_{\theta}}\\ + &= E_y(x,r,t) [\cos(\theta) \mathbf{e_r} - \sin(\theta) \mathbf{e_{\theta}}]. + +Thus, comparing to Eq :eq:`AzimuthalDecomposition2`, we recognize +a pure azimuthal mode of order :math:`m=1` for both :math:`E_r` +and :math:`E_\theta`, with the Fourier coefficients: + +.. math:: + + \tilde{E}^1_r (x,r,t) = E_y(x,r,t),\\ + + \tilde{E}^1_{\theta} (x,r,t) = -iE_y(x,r,t). + +Similarly, an elliptically (or cylindrically) polarized laser +is described by a pure mode :math:`m=1`, as it can be seen as the linear +superposition of two linearly polarized lasers. A difference in phase or in the polarization direction simply +corresponds to a multiplication of the Fourier coefficients by a complex exponential. + +The AM decomposition is most suited for +physical phenomena close to cylindrical symmetry as a low number +of modes is sufficient. +For example, in a basic Laser Wakefield Acceleration setup, +a linearly-polarized laser pulse with cylindrically symmetric envelope may be +described only by the mode :math:`m=1`. +As the wakefield wave is mainly determined by the cylindrically symmetric +ponderomotive force, it can be described by the mode :math:`m=0`. +Thus, such a simulation only needs, in principle, two azimuthal modes. + + +---- + +Maxwell's equations in cylindrical geometry +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In an AM simulation, the :math:`\tilde{F}^{m}(x,r)` are stored and computed +for each scalar field and for each component of the vector fields. +Each of them is a :math:`(x,r)` grid of complex values. + +From the linearity of Maxwell's Equations, and assuming that the densities +and currents can also be decomposed in modes, we obtain the following +evolution of the mode :math:`m`: + +.. math:: + :label: MaxwellEqsAzimuthalModes + + \partial_t \tilde{B}^m_{x} &=-\frac{1}{r}\partial_r(r\tilde{E}^m_{\theta})-\frac{im}{r}\tilde{E}^m_r,\\ + \partial_t \tilde{B}^m_r &= \frac{im}{r}\tilde{E}^m_x+\partial_x \tilde{E}^m_{\theta},\\ + \partial_t \tilde{B}^m_{\theta} &=-\partial_x \tilde{E}^m_{r} + \partial_r \tilde{E}^m_{x},\\ + \partial_t \tilde{E}^m_{x} &=\frac{1}{r}\partial_r(r\tilde{B}^m_{\theta})+\frac{im}{r}\tilde{B}^m_r-\tilde{J}^m_{x},\\ + \partial_t \tilde{E}^m_r &= -\frac{im}{r}\tilde{B}^m_x-\partial_x \tilde{B}^m_{\theta}-\tilde{J}^m_{r},\\ + \partial_t \tilde{E}^m_{\theta} &=\partial_x \tilde{B}^m_{r} - \partial_r \tilde{B}^m_{x}-\tilde{J}^m_{\theta}. + +Thus, even in presence of a plasma, at each timestep, +these equations are solved independently. +The coupling between the modes occurs when the total electromagnetic fields +push the macro-particles, creating, in turn, the currents :math:`\tilde{J}^m` +of their current density. + + +---- + +Interaction with the macro-particles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The azimuthal decomposition concerns only the grid quantities +(EM fields and current densities), which are thus defined on a 2D grid, +but macro-particles evolve in a full three-dimensional +space with cartesian coordinates. + +.. figure:: /_static/AM_grid_particles.jpg + :width: 10cm + + Blue arrows: the ``x`` and ``r`` axes of the 2D grid (red) + where the electromagnetic fields are defined. + Macro-particle positions and momenta are defined in 3D. + +During each iteration, the macro-particles are pushed in phase space +using reconstructed 3D cartesian electromagnetic fields +at their position :math:`(x,r,\theta)` (see Eq. :eq:`AzimuthalDecomposition1`). +Then, their contribution to the current densities :math:`(J_x,J_r,J_{\theta})` +is computed to update the electromagnetic fields at the next iteration +(see Eqs :eq:`MaxwellEqsAzimuthalModes`). + + +---- + +Tips +^^^^ + +Note that each mode :math:`\tilde{F}^{m}` is a function of :math:`x`, +the longitudinal coordinate and :math:`r`, the radial coordinate. +Therefore, each of them is only two dimensional. Thus, the computational cost +of AM simulations scales approximately as 2D simulations multiplied by the +number of modes. However, a higher number of macro-particles might be necessary +to obtain convergence of the results (always check the convergence of your +results by increasing the number of macro-particles and modes). +A rule of thumb is to use at least 4 times the number of modes as +macro-particles along :math:`\theta`. + + +---- + +Conventions for the namelist +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Several differences appear in the notations and definitions between +the AM and 3D geometries: + +* The origin of the coordinates is on the axis of the cylinder + (see figure below). + +.. figure:: /_static/AMcylindrical_vs_cartesian.png + + Origin of coordinates in AM cylindrical and 3D cartesian. + +* The AM radial grid size (``grid_length[1]``) represents the radius + of the cylinder; not its diameter. Thus, it is half the size of + the 3D transverse grid. + +* Particles are defined 3D space, so their coordinates should be + provided in terms of *x*, *y*, *z* if needed (e.g. a ``Species`` + initialized with a numpy array). + However, the density profiles of particles are assimilated to + scalar fields defined on the :math:`(x,r)` grid. + +* ``Field`` diagnostics really correspond to the complex fields + of each mode on :math:`(x,r)` grids. However, ``Probes`` + diagnostics are defined in 3D space just like the particles: + all fields are interpolated at their 3D positions, and reconstructed + by summing over the modes. + +* ``ExternalFields`` are grid quantities in :math:`(x,r)` coordinates. + One must be defined for each mode. + + + +---- + +Classical and relativistic Poisson's equation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Given the linearity of the relativistic Poisson's equation +described in :doc:`relativistic_fields_initialization`, +it can be decomposed in azimuthal modes +with the corresponding mode of the charge density +:math:`-\tilde{\rho}^m` as source term. +For the mode *m* of the potential :math:`\Phi`, +it writes: + +.. math:: + :label: RelPoissonModes + + \left[ + \frac{1}{\gamma^2_0}\partial^2_x\tilde{\Phi}^m + +\frac{1}{r}\partial_r\left(r\partial_r\tilde{\Phi}^m\right) + -\frac{m^2}{r^2}\tilde{\Phi}^m + \right] = -\tilde{\rho}^m. + +By solving each of these relativistic Poisson's equations +we initialize the azimuthal components of the electromagnetic fields: + +.. math:: + \begin{eqnarray} + \tilde{E}^m_x &=& -\frac{1}{\gamma_0^2}\partial_x \tilde{\Phi}^m,\\ + \tilde{E}^m_r &=& -\partial_r \tilde{\Phi}^m, \\ + \tilde{E}^m_{\theta} &=& \frac{im}{r} \tilde{\Phi}^m, \\ + \tilde{\mathbf{B}}^m &=& \beta_0\mathbf{\hat{x}}\times\tilde{\mathbf{E}}^m. + \end{eqnarray} + +The initialization of the electric field with the non-relativistic +Poisson's equation is performed similarly, and the underlying equations simply +reduce to the previous equations, with :math:`\gamma_0 = 1` and +:math:`\beta_0 = 0` (i.e. an immobile Species). + + +---- + +The envelope model in cylindrical coordinates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :doc:`laser_envelope` for cartesian geometries has been +implemented also in cylindrical geometry, as described in [Massimo2020b]_. + +Only the mode :math:`m=0` is available for the envelope +in the present implementation, i.e. the electromagnetic and +envelope fields have perfect cylindrical symmetry with respect +to the envelope propagation axis :math:`x`. + +The main difference compared to the cartesian geometry lies in the envelope +equation (see Eq. :eq:`envelope_equation`). The assumption of cylindrical +symmetry removes derivatives with respect :math:`\theta`, leading to: + +.. math:: + :label: envelope_equation_AM + + \partial^2_x\tilde{A} + +\frac{1}{r}\partial_r(r\partial_r\tilde{A}) + +2i\left(\partial_x \tilde{A} + \partial_t \tilde{A}\right) + -\partial^2_t\tilde{A} + = \chi \tilde{A}. + +The envelope approximation coupled to the cylindrical symmetry +can greatly speed-up the simulation: compared to a 3D envelope simulation +with the same number of particles, it has a speed-up which scales linearly +as twice the transverse number of cells. +This speed-up can reach 100 for lasers with transverse sizes of the order +of tens of microns. Compared to a standard 3D laser simulation with the +same number of particles, the speed-up of a cylindrical envelope simulation +can reach 1000 for lasers of durations of the order of tens of femtoseconds. +These comparisons assume the same longitudinal window size and the same +transverse size for the simulated physical space. + + +---- + +On-Axis boundary conditions in FDTD +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the AM geometry, specific boundary conditions are derived on-axis for the FDTD solver using a Yee lattice. +This section presents the actual implementation in :program:`Smilei`. +It is mostly based on the `original paper `_ but also includes +original contributions from X. Davoine and the :program:`Smilei` team. + +Primal and Dual grids +"""""""""""""""""""""""""""""" + +In :program:`Smilei`, ghost cells in the radial direction are located "before" the axis. +So if you have :math:`N_{ghost}` ghost cells, you have as many primal points on the radial axis before +reaching the actual geometric axis :math:`r=0`. +If :math:`dr` is a radial cell size, the dual radial axis is shifted by :math:`-dr/2`. +Below is an example for :math:`N_{ghost}=2`. +All equations in this section are given for this specific case. +For different numbers of ghost cells, simply add the difference in all indices. +:math:`jp` and :math:`jd` stand for the primal and dual indices. + +.. figure:: /_static/transverse_axis.png + :width: 10cm + +Cancellation on axis +""""""""""""""""""""""" + +The first basic principle is that a mode 0 field defined on axis can only be longitudinal otherwise it would be ill defined. +On the opposite, longitudinal fields on axis can only be of mode 0 since they do not depend on :math:`theta`. +From this we can already state that :math:`E_r^{m=0},\ E_t^{m=0},\ B_r^{m=0},\ B_t^{m=0},\ E_l^{m>0},\ B_l^{m>0}` are zero on axis. + + +This condition is straight forward for primal fields in R which take a value on axis exactly. +We simply set this value to zero. + +.. math:: + E_{\theta}^{m=0}[2] = 0 + + B_r^{m=0}[2] = 0 + + E_l^{m>0}[2] = 0 + +For dual fields in R, we set a value such as a linear interpolation between nearest grid points gives a zero on axis. + +.. math:: + E_r^{m=0}[2] = -E_r^{m=0}[3] + + B_{\theta}^{m=0}[2] = -B_{\theta}^{m=0}[3] + + B_l^{m>0}[2] = -B_l^{m>0}[3] + +Transverse field on axis +"""""""""""""""""""""""""""" + +The transverse electric field can be written as follows + +.. math:: + \mathbf{E_\perp} = \mathbf{E_y} + \mathbf{E_z} = (E_r\cos{\theta}-E_{\theta}\sin{\theta})\mathbf{e_y} + (E_r\sin{\theta}+E_{\theta}\cos{\theta})\mathbf{e_z} + +The transverse field on axis can not depend on :math:`\theta` otherwise it would be ill defined. +Therefore we have the following condition on axis: + +.. math:: + \frac{\partial\mathbf{E_\perp}}{\partial\theta} = 0\ \forall\theta + +which leads to the following relation: + +.. math:: + \cos{\theta}\left(\frac{\partial E_r}{\partial\theta}-E_{\theta}\right) + \sin{\theta}\left(\frac{\partial E_{\theta}}{\partial\theta}+E_r\right)=0\ \forall\theta + +Being true for all :math:`\theta`, this leads to + +.. math:: + \frac{\partial E_r}{\partial\theta}-E_{\theta}=0\ \forall\theta + + \frac{\partial E_{\theta}}{\partial\theta}+E_r=0\ \forall\theta + +Remembering that for a given mode :math:`m` and a given field :math:`F`, we have :math:`F=Re\left(\tilde{F}^m\exp{(-im\theta)}\right)`, +we can write the previous equations for all modes :math:`m` as follows: + +.. math:: + :label: transverse_on_axis + + \tilde{E_r}^m=\frac{i\tilde{E_{\theta}}^m}{m} + + \tilde{E_r}^m=mi\tilde{E_{\theta}}^m + +We have already established in the previuos section that the modes :math:`m=0` must cancel on axis and we are concerned only about :math:`m>0`. +Equations :eq:`transverse_on_axis` can have a non zero solution only for :math:`m=1` and is also valid for the magnetic field. +We therefore conclude that all modes must cancel on axis except for :math:`m=1`. + +.. math:: + E_{\theta}^{m>1}[2] = 0 + + B_r^{m>1}[2] = 0 + + E_r^{m>1}[2] = -E_r^{m>1}[3] + + B_{\theta}^{m>1}[2] = -B_{\theta}^{m>1}[3] + +Let's now write the Gauss law for mode :math:`m=1`: + +.. math:: + div(\mathbf{\tilde{E}^{m=1}})=\tilde{\rho}^{m=1} + +where :math:`\rho` is the charge density. +We have already established that on axis the longitudinal field are zero for all modes :math:`m>0`. +The charge density being a scalar field, it follows the same rule and is zero as well on axis. +The continuity equation on axis and written in cylindrical coordinates becomes: + +.. math:: + \frac{\tilde{E_r}^{m=1}-im\tilde{E_{\theta}}^{m=1}}{r} + \frac{\partial \tilde{E_r}^{m=1}}{\partial r} = 0 + +Eq. :eq:`transverse_on_axis` already establishes that the first term is zero. +It is only necessary to cancel the second term. + +In order to do so, let's build an uncentered finite dfference scheme of the second order. +Simple Taylor developments give for any quantity :math:`u`: + +.. math:: + u(x+\frac{dx}{2})=u(x)+\frac{dx}{2}u'(x)+\frac{dx^2}{8}u''(x)+O(dx3) + + u(x+\frac{3dx}{2})=u(x)+\frac{3dx}{2}u'(x)+\frac{9dx^2}{8}u''(x)+O(dx3) + +By combination we obtain the scheme we are looking for: + +.. math:: + u'(x) = \frac{9u(x+\frac{dx}{2})-u(x+\frac{3dx}{2})-8u(x)}{3dx} + +We can therefore write: + +.. math:: + \frac{\partial \tilde{E_r}^{m=1}}{\partial r}(r=0)= 9\tilde{E_r}^{m=1}(r=\frac{dr}{2})-\tilde{E_r}^{m=1}(r=\frac{3dr}{2})-8\tilde{E_r}^{m=1}(r=0) = 0 + +which gives: + +.. math:: + \tilde{E_r}^{m=1}(r=0)=\frac{1}{8}\left(9\tilde{E_r}^{m=1}(r=\frac{dr}{2})-\tilde{E_r}^{m=1}(r=\frac{3dr}{2})\right) + +And from :eq:`transverse_on_axis` this turns into: + +.. math:: + \tilde{E_{\theta}}^{m=1}(r=0)=\frac{-i}{8}\left(9\tilde{E_r}^{m=1}(r=\frac{dr}{2})-\tilde{E_r}^{m=1}(r=\frac{3dr}{2})\right) + +giving the corresponding boundary condition for :math:`E_{\theta}^{m=1}`: + +.. math:: + E_{\theta}^{m=1}[2] = \frac{-i}{8}\left(9E_r^{m=1}[3]-E_r^{m=1}[4]\right) + +Once :math:`E_{\theta}^{m=1}` is defined on axis, we need to pick :math:`E_r^{m=1}` so that :eq:`transverse_on_axis` is matched. +With a linear interpolation we obtain: + +.. math:: + E_r^{m=1}[2] = 2iE_{\theta}^{m=1}[2]-E_r^{m=1}[3] + +All the equation derived here are also valid for the magnetic field. +But because of a different duality, it is more convenient to use a different approach. +The equations :eq:`MaxwellEqsAzimuthalModes` has a :math:`\frac{E_l}{r}` term in the expression of :math:`B_r` which makes it undefined on axis. +Nevertheless, we need to evaluate this term for the mode :math:`m=1` and it can be done as follows. + +.. math:: + \lim_{r\to 0}\frac{E_l^{m=1}(r)}{r} = \lim_{r\to 0}\frac{E_l^{m=1}(r)-E_l^{m=1}(0)}{r} + +since we established in the previous section that :math:`E_l^{m=1}(r=0)=0`. +And by definition of a derivative we have: + +.. math:: + \lim_{r\to 0}\frac{E_l^{m=1}(r)-E_l^{m=1}(0)}{r}=\frac{\partial E_l^{m=1} }{\partial r}(r=0) + +This derivative can be evaluated by a simple finite difference scheme and using again that :math:`E_l^{m=1}` is zero on axis we get: + +.. math:: + :label: derivative_limit + + \lim_{r\to 0}\frac{E_l^{m=1}(r)}{r} = \frac{E_l^{m=1}(dr)}{dr} + +Introducing this result in the standard FDTD scheme for :math:`B_r` we get the axis bounday condition: + +.. math:: + B_{r}^{m=1,n+1}[i,2] = B_{r}^{m=1,n}[i,2] + dt\left(\frac{i}{dr}E_l^{m=1}[i,3]+\frac{E_{\theta}^{m=1}[i+1,2]-E_{\theta}^{m=1}[i,2]}{dl}\right) + +where the :math:`n` indice indicates the time step and :math:`i` the longitudinal indice. +Exactly as for the electric field, we need to have :math:`B_{r}^{m=1}=iB_{\theta}^{m=1}`. +With a similar interpolation we obtain the boundary condition on axis for :math:`B_{\theta}^{m=1}`: + +.. math:: + B_{\theta}^{m=1}[2]=-2iB_{r}^{m=1}[2]-B_{\theta}^{m=1}[3] + +Longitudinal fields on axis +""""""""""""""""""""""""""""" + +We have alreayd established that only modes :math:`m=0` of longitudinal fields are non zero on axis. +In order to get an evaluation of :math:`E_l^{m=0}` on axis one can use the same approach as for :math:`B_r^{m=1}`. +Since we have already shown that :math:`E_{\theta}^{m=0}` is zero on axis, we have the following relation which is demonstrated using +similar arguments as Eq. :eq:`derivative_limit`: + +.. math:: + \lim_{r\to 0}\frac{1}{r}\frac{\partial rB_{\theta}^{m=0}}{\partial r} = \frac{4B_{\theta}^{m=0}(dr/2)}{dr} + +Introducing this result in the standard FDTD expression of :math:`E_l` we get: + +.. math:: + E_{l}^{m=0,n+1}[i,2] = E_{l}^{m=0,n}[i,2] + dt\left(\frac{4}{dr}B_{\theta}^{m=0}[i,3]-J_{l}^{m=0}[i,2]\right) + +Again, the :math:`n` indice indicates the time step here. + +:math:`B_l^{m=0}` is independant of :math:`\theta`. If we assume it is differentiable at :math:`r=0` then its derivative along :math:`r` is zero +on axis (derivative of a pair function is zero at :math:`x=0` ). From this we get: + +.. math:: + B_{l}^{m=0}[2]=B_{l}^{m=0}[3] + +Below axis +"""""""""""""""""""""""""""" + +Fields "below" axis are primal fields data with indice :math:`j<2` and dual fields with indice :math:`j<3`. +These fields are not physical in the sense that they do not contribute to the reconstruction of any physical field in real space and are not obtained by solving Maxwell's equations. +Nevertheless, it is numerically convenient to give them a value in order to facilitate field interpolation for macro-particles near axis. +This is already what is done for dual fields in :math:`r` which cancel on axis for instance. +We extend this logic to primal fields in :math:`r`: + +.. math:: + + E_{l}^{m=0}[1] = E_{l}^{m=0}[3] + + E_{l}^{m>0}[1] = -E_{l}^{m>0}[3] + + E_{\theta}^{m\neq1}[1] = -E_{\theta}^{m\neq1}[3] + + E_{\theta}^{m=1}[1] = E_{\theta}^{m=1}[3] + + B_{r}^{m\neq1}[1] = -B_{r}^{m\neq1}[3] + + B_{r}^{m=1}[1] = B_{r}^{m=1}[3] + +Currents near axis +""""""""""""""""""""" + +A specific treatment must be applied to charge and current densities near axis because the projector deposits charge and current "below" axis. +Quantities below axis must be brought back in the "physical" terms on and above axis. + +Using the continuity equation instead of Gauss law for transverse current of mode :math:`m=1` on axis, we can derive the exact same boundary conditions +on axis for current density as for the electric field. + diff --git a/_sources/Understand/collisions.rst.txt b/_sources/Understand/collisions.rst.txt new file mode 100644 index 000000000..281ff0764 --- /dev/null +++ b/_sources/Understand/collisions.rst.txt @@ -0,0 +1,586 @@ +Binary collisions & reactions +----------------------------- + + +Relativistic binary collisions between particles have been implemented in +:program:`Smilei` following these references: + +* [Perez2012]_: overview of the technique. +* [Nanbu1997]_ and [Nanbu1998]_: the original approach. +* [Sentoku2008]_, [Lee1984]_ and [Frankel1979]_: additional information. +* The correction suggested in [Higginson2020]_ has been applied since v4.5. + +This collision scheme can host reactions between the colliding +macro-particles, when requested: + +* Ionization of an atom by collision with an electron. +* Nuclear reaction between two atoms. + +Please refer to :ref:`that doc ` for an explanation of how to add +collisions in the namelist file. + + +---- + +The binary collision scheme +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Collisions are calculated at each timestep and for each collision block +given in the input file: + +* Macro-particles that should collide are randomly paired. +* Average parameters are calculated (densities, etc.). +* For each pair: + + * Calculate the momenta in the center-of-mass (COM) frame. + * Calculate the coulomb log if requested (see [Perez2012]_). + * If the collision corresponds to a nuclear reaction (optional), + the reaction probability is computed and new particles are created + if successful. + * Calculate the collision rate. + * Randomly pick the deflection angle. + * Deflect particles in the COM frame and switch back to the laboratory frame. + * If the collision corresponds to ionization (optional), + its probability is computed and new electrons are created + if successful. + +.. rubric:: Modifications in Smilei + +* A typo from [Perez2012]_ is corrected: in Eq. (22), corresponding to + the calculation of the Coulomb Logarithm, the last parenthesis is + written as a squared expression, but should not. + +* The deflection angle distribution given by [Nanbu1997]_ + (which is basically a fit from Monte-Carlo simulations) + is modified for better accuracy and performance. + Given Nanbu's :math:`s` parameter and a random number :math:`U\in [0,1]`, + the deflection angle :math:`\chi` is: + + .. math:: + + \sin^2\frac\chi 2 = \begin{cases} + \alpha U/\sqrt{1-U + \alpha^2 U} &, s < 4\\ + 1-U &, \textrm{otherwise} + \end{cases} + + where :math:`\alpha = 0.37 s-0.005 s^2-0.0064 s^3`. + +---- + +Test cases for collisions +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. rubric:: 1. Beam relaxation + +An electron beam with narrow energy spread enters an ion background with :math:`T_i=10` eV. +The ions are of very small mass :math:`m_i=10 m_e` to speed-up the calculation. +Only e-i collisions are calculated. +The beam gets strong isotropization => the average velocity relaxes to zero. + +Three figures show the time-evolution of the longitudinal :math:`\left` +and transverse velocity :math:`\sqrt{\left}` + +* :numref:`beam1` : initial velocity = 0.05, ion charge = 1 +* :numref:`beam2` : initial velocity = 0.01, ion charge = 1 +* :numref:`beam3` : initial velocity = 0.01, ion charge = 3 + +Each of these figures show 3 different blue and red curves which correspond to different +ratios of particle weights: 0.1, 1, and 10. + +.. _beam1: + +.. figure:: /_static/beam_relaxation123.png + :width: 10cm + + Relaxation of an electron beam. Initial velocity = 0.05, ion charge = 1. + +.. _beam2: + +.. figure:: /_static/beam_relaxation456.png + :width: 10cm + + Relaxation of an electron beam. Initial velocity = 0.01, ion charge = 1. + +.. _beam3: + +.. figure:: /_static/beam_relaxation789.png + :width: 10cm + + Relaxation of an electron beam. Initial velocity = 0.01, ion charge = 3. + + +The black lines correspond to the theoretical rates taken from the NRL formulary: + +.. math:: + + \nu_\| = -\left(1+\frac{m_e}{m_i}\right)\nu_0 + \quad\textrm{and}\quad + \nu_\perp = 2\;\nu_0 + \quad\textrm{where}\quad + \nu_0=\frac{e^4\,Z^{\star 2}\,n_i\,\ln\Lambda } { 4 \pi \epsilon_0^2 \,m_e^2\,v_e^3 } + + +The distribution is quickly non-Maxwellian so that theory is valid only at the beginning. + + +.. rubric:: 2. Thermalization + +A population of electrons has a different temperature from that of the ion population. +Through e-i collisions, the two temperatures become equal. +The ions are of very small mass :math:`m_i=10 m_e` to speed-up the calculation. +Three cases are simulated, corresponding to different ratios of weights: 0.2, 1 and 5. +They are plotted in :numref:`thermalization`. + +.. _thermalization: + +.. figure:: /_static/thermalisation_ei123.png + :width: 9cm + + Thermalization between two species. + +The black lines correspond to the theoretical rates taken from the NRL formulary: + +.. math:: + + \nu_\epsilon = \frac{2}{3}\sqrt\frac{2}{\pi} + \frac{e^4\,Z^{\star 2} \sqrt{m_em_i}\,n_i\,\ln\Lambda } + { 4 \pi\epsilon_0^2 \,\left(m_eT_e+m_iT_i\right)^{3/2} } + + + + +.. rubric:: 3. Temperature isotropization + +Electrons have a longitudinal temperature different from their transverse temperature. +They collide only with themselves (intra-collisions) and the anisotropy disappears +as shown in :numref:`temperature_isotropization`. + +.. _temperature_isotropization: + +.. figure:: /_static/temperature_isotropization1.png + :width: 10cm + + Temperature isotropization of an electron population. + +The black lines correspond to the theoretical rates taken from the NRL formulary: + +.. math:: + + \nu_T=\frac{e^4 \,n_e\,\ln\Lambda } { 8\pi^{3/2} \epsilon_0^2 \,m_e^{1/2}T_\|^{3/2} } + A^{-2} \left[-3+(3-A)\frac{\rm{arctanh}(\sqrt{A})}{\sqrt{A}}\right] + \quad \rm{where}\quad A=1-\frac{T_\perp}{T_\|} + + + +.. rubric:: 4. Maxwellianization + +Electrons start with zero temperature along :math:`y` and :math:`z`. +Their velocity distribution along :math:`x` is rectangular. +They collide only with themselves and the rectangle becomes a maxwellian +as shown in :numref:`maxwellianization`. + +.. _maxwellianization: + +.. figure:: /_static/Maxwellianization1.png + :width: 10cm + + Maxwellianization of an electron population. + Each blue curve is the distribution at a given time. + The red curve is an example of a gaussian function. + + + +.. rubric:: 5. Stopping power + +Test electrons (very low density) collide with background electrons of density +:math:`10\,n_c` and :math:`T_e=5` keV. +Depending on their initial velocity, they are slowed down at different rates, +as shown in :numref:`stoppingpower`. + +.. _stoppingpower: + +.. figure:: /_static/Stopping_power123.png + :width: 10cm + + Stopping power of test electrons into a background electron population. + Each point is one simulation. The black line is Frankel's theory [Frankel1979]_. + + +.. rubric:: 6. Conductivity + +Solid-density Cu is simulated at different temperatures (e-i equilibrium) with only +e-i collisions. An electric field of :math:`E=3.2` GV/m (0.001 in code units) is +applied using two charged layers on each side of the solid Cu. +The electron velocity increases until a limit value :math:`v_f`. +The resulting conductivity :math:`\sigma=en_ev_f/E` is compared in +:numref:`conductivity` to the models in [Lee1984]_ and [Perez2012]_. + +.. _conductivity: + +.. figure:: /_static/conductivity.png + :width: 10cm + + Conductivity of solid-density copper. Each point is one simulation. + + +---- + +.. _CollIonization: + +Collisional ionization +^^^^^^^^^^^^^^^^^^^^^^ + +The binary collisions can also be ionizing if they are **electron-ion** collisions. +The approach is almost the same as that provided in [Perez2012]_. + +When ionization is requested by setting ``ionizing=True``, a few additional operations +are executed: + +* At the beginning of the run, cross-sections are calculated from tabulated binding + energies (available for ions up to atomic number 100). These cross-sections are then + tabulated for each requested ion species. +* Each timestep, the particle density :math:`n = n_e n_i/n_{ei}` + (similar to the densities above for collisions) is calculated. +* During each collision, a probability for ionization is computed. If successful, + the ion charge is increased, the incident electron is slowed down, and a new electron + is created. + +.. rubric:: Warnings + +* This scheme does not account for recombination, which would balance ionization + over long time scales. + +.. rubric:: Relativistic change of frame + +A modification has been added to the theory of [Perez2012]_ in order to account for the +laboratory frame being different from the ion frame. Considering :math:`\overrightarrow{p_e}` +and :math:`\overrightarrow{p_i}` the electron and ion momenta in the laboratory frame, +and their associated Lorentz factors :math:`\gamma_e` and :math:`\gamma_i`, we define +:math:`\overrightarrow{q_e}=\overrightarrow{p_e}/(m_e c)` and +:math:`\overrightarrow{q_i}=\overrightarrow{p_i}/(m_i c)`. +The Lorentz factor of the electron in the ion frame is +:math:`\gamma_e^\star=\gamma_e\gamma_i-\overrightarrow{q_e}\cdot\overrightarrow{q_i}`. +The probability for ionization reads: + +.. math:: + + P = 1-\exp\left( - v_e \sigma n \Delta t \right) = 1-\exp\left( -V^\star \sigma^\star n \Delta t \right) + +where :math:`v_e` is the electron velocity in the laboratory frame, +:math:`\sigma` is the cross-section in the laboratory frame, :math:`\sigma^\star` +is the cross-section in the ion frame, and +:math:`V^\star=c\sqrt{\gamma_e^{\star\,2}-1}/(\gamma_e\gamma_i)`. + +The loss of energy :math:`m_ec^2 \delta\gamma` of the incident electron translates into a change in momentum +:math:`{q_e^\star}' = \alpha_e q_e^\star` in the ion frame, with +:math:`\alpha_e=\sqrt{(\gamma_e^\star-\delta\gamma)^2-1}/\sqrt{\gamma_e^{\star2}-1}`. +In the laboratory frame, it becomes +:math:`\overrightarrow{q_e'}=\alpha_e\overrightarrow{q_e}+((1-\alpha_e)\gamma_e^\star-\delta\gamma)\overrightarrow{q_i}`. + +A similar operation is done for defining the momentum of the new electron in the lab frame. +It is created with energy :math:`m_ec^2 (\gamma_w-1)` and its momentum is +:math:`q_w^\star = \alpha_w q_e^\star` in the ion frame, with +:math:`\alpha_w=\sqrt{\gamma_w^2-1}/\sqrt{\gamma_e^{\star 2}-1}`. +In the laboratory frame, it becomes +:math:`\overrightarrow{q_w}=\alpha_w\overrightarrow{q_e}+(\gamma_w-\alpha_w\gamma_e^\star)\overrightarrow{q_i}`. + + +.. rubric:: Multiple ionization + +A modification has been added to the theory of [Perez2012]_ in order to account for +multiple ionization in a single timestep. The approach for field ionization +by `Nuter et al `_ +has been adapted to calculate the successive impact ionization probabilities +when an ion is ionized several times in a row. + +Writing the probability to not ionize an ion already ionized :math:`i` times as +:math:`\bar{P}^i = \exp\left( -W_i\Delta t\right)`, and defining +:math:`R^m_n = (1-W_m/W_n)^{-1}`, we can calculate the probability to ionize :math:`k` times +the ion: + +.. math:: + + P^i_k = \left\{ + \begin{array}{ll} + \bar{P}^i + & + \quad\mathrm{if}\quad k=0 + \\ + \sum\limits_{p=0}^{k-1} R^{i+k}_{i+p} \left(\bar{P}^{i+k} - \bar{P}^{i+p}\right) + \prod\limits_{j=0,j\ne p}^{k-1} R^{i+p}_{i+j} + & + \quad\mathrm{if}\quad 0U`. + +---- + +Test cases for ionization +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. rubric:: 1. Ionization rate + +A cold plasma of :math:`\mathrm{Al}^{3+}` is set with density :math:`n_e=10^{21} \mathrm{cm}^{-3}` +and with all electrons drifting at a velocity :math:`v_e=0.03\,c`. The charge state of ions +versus time is shown in :numref:`IonizationRate` where the three dotted curves correspond +to three different weight ratios between electrons and ions. + +.. _IonizationRate: + +.. figure:: /_static/ionization_rate.png + :width: 10cm + + Ionization of an aluminium plasma by drifting electrons. + +The theoretical curve (in black) corresponds to :math:`1-\exp\left(v_en_e\sigma t\right)` +where :math:`\sigma` is the ionization cross section of :math:`\mathrm{Al}^{3+}` at the +right electron energy. The discrepancy at late time is due to the changing velocity +distributions and to the next level starting to ionize. + + +.. rubric:: 2. Inelastic stopping power + +A cold, non-ionized Al plasma is set with density :math:`n_e=10^{21} \mathrm{cm}^{-3}`. +Electrons of various initial velocities are slowed down by ionizing collisions and their +energy loss is recorded as a function of time. + +A few examples are given in the left graph of :numref:`IonizationStoppinPower`. +The theoretical curve is obtained from [Rohrlich1954]_. Note that this theory does not +work below a certain average ionization energy, in our case :math:`\sim 200` eV. + +.. _IonizationStoppinPower: + +.. figure:: /_static/ionization_stopping_power.png + :width: 14cm + + Left: ionization slowing down versus time, for electrons injected at various + initial energies into cold Al. Right: corresponding stopping power versus initial + electron energy. + +In the same figure, the graph on the right-hand-side provides the stopping power value +in the same context, at different electron energies. It is compared to the same theory. + + +.. rubric:: 3. Multiple ionization + +If the timestep is large, multiple ionization can occur, especially with cold high-Z +material and high-energy electrons. The multiple ionization algorithm is not perfect, +as it does not shuffle the particles for each ionization. Thus, good statistical +sampling is reached after several timesteps. To test the potential error, +we ran simulations of electrons at 1 MeV incident on cold atoms. The evolution of the +secondary electron density is monitored versus time in :numref:`IonizationMultiple`. + +.. _IonizationMultiple: + +.. figure:: /_static/ionization_multiple.png + :width: 10cm + + Secondary electron density *vs* time, for cold plasmas traversed by a 1 MeV electron beam. + +The solid lines correspond to a very-well resolved ionization, whereas the dashed lines +correspond to a large timestep. A difference is visible initially, but decreases +quickly as the statistical sampling increases and as the subsequent ionization +cross-sections decrease. + + +.. rubric:: 3. Effect of neglecting recombination + +As recombination is not accounted for, we can expect excess ionization to occur indefinitely +without being balanced to equilibrium. However, in many cases, the recombination rate +is small and can be neglected over the duration of the simulation. We provide an example +that is relevant to picosecond-scale laser-plasma interaction. Plasmas initially at +a density of 10 times the critical density are given various initial temperatures. +Ionization initially increases while the temperature decreases, until, after a while, +their charge state stagnates (it still increases, but very slowly). +In :numref:`IonizationRecombination`, these results are compared to a Thomas-Fermi model +from [Desjarlais2001]_. + +.. _IonizationRecombination: + +.. figure:: /_static/ionization_recombination.png + :width: 12cm + + Final charge state of various plasmas at various temperatures. + +The model does not account for detailed ionization potentials. It provides a rough +approximation, and is particularly questionable for low temperatures or high Z. +We observe that Smilei's approach for impact ionization provides decent estimates +of the ionization state. Detailed comparison to atomic codes has not been done yet. + + +---- + +.. _CollNuclearReactions: + +.. rst-class:: experimental + +Nuclear reactions +^^^^^^^^^^^^^^^^^^^^ + +Nuclear reactions may occur during collisions when requested. The reaction +scheme is largely inspired from [Higginson2019]_. + +.. rubric:: 1. Outline of the nuclear reaction process + +We take advantage of the +relativistic kinematics calculations of the binary collision scheme +to introduce the nuclear reactions in the COM frame: + +* The cross-section :math:`\sigma` (tabulated for some reactions) + is interpolated, given the kinetic energies. +* The probability for the reaction to occur is calculated. +* This probability is randomly sampled and, if successful: + + * New macro-particles (the reaction products) are created. + * Their angle is sampled from a tabulated distribution. + * Their mpmenta are calculated from the conservation of total energy and momentum. + * Their momenta are boosted back to the simulation frame. + +* Otherwise: the collision process proceeds as usual. + +.. rubric:: 2. Nuclear reaction probability + +The probability for the reaction to occur is calculated as +:math:`P=1-\exp(R\, v\, n\, \sigma\, \Delta t)` where *v* is the relative +velocity, *n* is a corrected density (see [Higginson2020]_), and *R* is +a *rate multiplier* (see [Higginson2019]_). + +This factor *R* is of great importance for most applications, because +almost no reactions would occur when :math:`R=1`. This factor artificially +increases the number of reactions to ensure enough statistics. The weights +of the products are adjusted accordingly, and the reactants are not destroyed +in the process: we simply decrease their weight by the same amount. + +In Smilei, this factor *R* can be forced by the user to some value, but by +default, it is automatically adjusted so that the final number of created particles +approches the initial number of pairs. + +.. rubric:: 3. Creation of the reaction products + +Special care must be taken when creating new charged particles while +conserving Poisson's equation. Following Ref. [Higginson2019], we choose to +create two macro-particles of each type. To explain in detail, let us write +the following reaction: + +.. math:: + + 1 + 2 \rightarrow 3 + 4 + +Two particles of species 3 are created: one at the position of particle 1, +the other at the position of particle 2. Two particles of species 4 are also +created. To conserve the charge at each position, the weights of the new +particles must be: + +.. math:: + + W_3^{@1} = w \frac{q_1}{q_1+q_2} q_3\\ + W_3^{@2} = w \frac{q_2}{q_1+q_2} q_3\\ + W_4^{@1} = w \frac{q_1}{q_1+q_2} q_4\\ + W_4^{@2} = w \frac{q_2}{q_1+q_2} q_4 + +where :math:`w` is the products' weight, and the :math:`q_i` are the charges. + +.. rubric:: 4. Calculation of the resulting momenta + +The conservation of energy reads: + +.. math:: + + K_1 + K_2 + Q = K_3 + K_4 + +where the :math:`K_i` are kinetic energies, and :math:`Q` is the reaction's +Q-value. In the COM frame, we have, by definition, equal momenta: :math:`p_3 = p_4`. +Using the relativistic expression :math:`(K_k+m_k)^2=p_k^2+m_k^2`, we can +calculate that + +.. math:: + + 0=p_4^2-p_3^2=K_4 (K_4 + 2m_4) - K_3(K_3+2m_3) + +Substituting for :math:`K_4` using the conservation of energy, this translates into + +.. math:: + + 0=A_{00} A_{02} - (A_{20}+A_{02})K_3 + +where we have defined :math:`A_{ij}=K_1 + K_2 +Q+i\,m_3+j\,m_4`. We thus obtain + +.. math:: + + K_3 = \frac{A_{00}A_{02}}{A_{20}+A_{02}}\\ + K_3+2m_3 = ... = \frac{A_{20}A_{22}}{A_{20}+A_{02}} + +Finally, + +.. math:: + + p_3^2 = K_3(K_3+2m_3) = ... = \frac{A_{00}A_{02}A_{20}A_{22}}{(2A_{11})^2} + +which expresses the resulting momentum as a function of the initial energies. + +---- + +Collisions debugging +^^^^^^^^^^^^^^^^^^^^ + +Using the parameter ``debug_every`` in a ``Collisions()`` group (see :ref:`Collisions`) +will create a file with info about these collisions. +These information are stored in the files "Collisions0.h5", "Collisions1.h5", etc. + +The *hdf5* files are structured as follows: + One HDF5 file contains several groups called ``"t********"`` where ``"********"`` + is the timestep. Each of these groups contains several arrays, which represent + quantities *vs.* space. + +The available arrays are: + + * ``s``: defined in [Perez2012]_: :math:`s=N\left<\theta^2\right>`, where :math:`N` is + the typical number of real collisions during a timestep, and + :math:`\left<\theta^2\right>` is the average square deviation of individual + real collisions. This quantity somewhat represents the typical amount of angular + deflection accumulated during one timestep. + **It is recommended that** :math:`s<1` **in order to have realistic collisions.** + * ``coulomb_log``: average Coulomb logarithm. + * ``debyelength``: Debye length (not provided if all Coulomb logs are manually defined). + +The arrays have the same dimension as the plasma, but each element of these arrays +is an average over all the collisions occurring in a single *patch*. + + +---- + +References +^^^^^^^^^^ + +.. [Desjarlais2001] `M. Desjarlais, Contrib. Plasma Phys. 41, 267 (2001) `_ + +.. [Frankel1979] `N. E. Frankel, K. C. Hines, and R. L. Dewar, Phys. Rev. A 20, 2120 (1979) `_ + +.. [Higginson2019] `D. P. Higginson, A. Link, A. Schmidt, J. Comput. Phys. 388, 439 (2019) `_ + +.. [Higginson2020] `D. P. Higginson, I. Holod and A. Link, J. Comput. Phys. 413, 109450 (2020) `_ + +.. [Lee1984] `Y. T. Lee and R. M. More, Phys. Fluids 27, 1273 (1984) `_ + +.. [Nanbu1997] `K. Nanbu, Phys. Rev. E 55, 4642 (1997) `_ + +.. [Nanbu1998] `K. Nanbu and S. Yonemura, J. Comput. Phys. 145, 639 (1998) `_ + +.. [Perez2012] `F. Pérez et al., Phys. Plasmas 19, 083104 (2012) `_ + +.. [Rohrlich1954] `F. Rohrlich and B. C. Carlson, Phys. Rev. 93, 38 (1954) `_ + +.. [Sentoku2008] `Y. Sentoku and A. J. Kemp, J. Comput. Phys. 227, 6846 (2008) `_ + + diff --git a/_sources/Understand/ionization.rst.txt b/_sources/Understand/ionization.rst.txt new file mode 100644 index 000000000..33734c1b7 --- /dev/null +++ b/_sources/Understand/ionization.rst.txt @@ -0,0 +1,342 @@ +Ionization +---------------------------------- + +Three types of ionization have been introduced in Smilei (4 if you count field ionization with a laser envelope as a separate type). + +---- + +Collisional ionization +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Ionization may occur during collisions. +A detailed description is given on the :ref:`corresponding page`. + + +---- + +.. _field_ionization: + +Field ionization +^^^^^^^^^^^^^^^^^ + +Field ionization is a process of particular importance for laser-plasma interaction +in the ultra-high intensity regime. +It can affect ion acceleration driven by irradiating a solid target with +an ultra-intense laser, or can be used to inject electrons through +the accelerating field in laser wakefield acceleration. +This process is not described in the standard PIC (Vlasov-Maxwell) formulation, +and an *ad hoc* description needs to be implemented. +A Monte-Carlo module for field ionization has thus been developed in :program:`Smilei`, +closely following the method proposed in [Nuter2011]_. + +Physical model for field ionization +"""""""""""""""""""""""""""""""""""""" + +This scheme relies on the quasi-static rate for tunnel ionization derived in +[Perelomov1966]_, [Perelomov1967]_ and [Ammosov1986]_. +Considering an ion with atomic number :math:`Z` being ionized from charge state +:math:`Z^\star-1` to :math:`Z^\star \le Z` in a constant electric field :math:`\mathbf{E}` +of magnitude :math:`\vert E\vert`, the ionization rate reads: + +.. math:: + :label: ionizationRate1 + + \Gamma_{\rm ADK, DC} = A_{n^\star,l^\star}\,B_{l,\vert m\vert}\, + I_p\,\left( \frac{2 (2 I_p)^{3/2}}{\vert E\vert} \right)^{2n^\star-\vert m \vert -1}\, + \exp\!\left( -\frac{2 (2 I_p)^{3/2}}{3 \vert E\vert} \right)\,, + +where :math:`I_p` is the :math:`Z^{\star}-1` ionization potential of the ion, +:math:`n^\star=Z^\star/\sqrt{2 I_p}` and :math:`l^\star=n^\star-1` denote +the effective principal quantum number and angular momentum, +and :math:`l` and :math:`m` denote the angular momentum and its projection on +the laser polarization direction, respectively. +:math:`\Gamma_{\rm ADK, DC}`, :math:`I_p` and :math:`E` are here expressed in atomic units +The coefficients :math:`A_{n^\star,l^\star}` and :math:`B_{l,\vert m\vert}` are given by: + +.. math:: + + \begin{array}{lll} + A_{n^\star,l^\star}&=& \frac{2^{2n^\star}}{n^\star\,\Gamma(n^\star+l^\star+1)\,\Gamma(n^\star-l^\star)},\\ + B_{l,\vert m\vert} &=& \frac{(2l+1)(l+\vert m\vert)!}{2^{\vert m\vert} \vert m\vert! (l-\vert m\vert)!}\,, + \end{array} + +where :math:`\Gamma(x)` is the gamma function. +Note that considering an electric field :math:`E=\vert E\vert\,\cos(\omega t)` +oscillating in time at the frequency :math:`\omega`, averaging Eq. :eq:`ionizationRate1` +over a period :math:`2\pi/\omega` leads to the well-known cycle-averaged ionization rate: + +.. math:: + :label: ADKrate + + \Gamma_{\rm ADK, AC} = \sqrt{\frac{3}{\pi}}A_{n^\star,l^\star}\,B_{l,\vert m\vert} + \,I_p\,\left( \frac{2 (2 I_p)^{3/2}}{\vert E\vert} \right)^{2n^\star-\vert m \vert -3/2}\, + \exp\!\left( -\frac{2 (2 I_p)^{3/2}}{3 \vert E\vert} \right)\,. + +In :program:`Smilei`, following [Nuter2011]_, the ionization rate of :eq:`ionizationRate1` +is computed for :math:`\vert m \vert=0` only. +Indeed, as shown in [Ammosov1986]_, the ratio :math:`R` of the ionization rate +computed for :math:`\vert m\vert=0` by the rate computed for :math:`\vert m\vert=1` is: + +.. math:: + + R = \frac{\Gamma_{{\rm qs},\vert m \vert = 0}}{\Gamma_{{\rm qs},\vert m \vert = 1}} + = 2\frac{(2\,I_p)^{3/2}}{\vert E\vert} + \simeq 7.91\,10^{-3} \,\,\frac{(I_p[\rm eV])^{3/2}}{a_0\,\hbar\omega_0[\rm eV]}\,, + +where, in the practical units formulation, we have considered ionization +by a laser with normalized vector potential :math:`a_0=e\vert E\vert /(m_e c \omega_0)`, +and photon energy :math:`\hbar\omega_0` in eV. +Typically, ionization by a laser with wavelength :math:`1~{\rm \mu m}` +(correspondingly :math:`\hbar \omega_0 \sim 1~{\rm eV}`) occurs for values +of :math:`a_0\ll 1` (even for large laser intensities for which ionization +would occur during the rising time of the pulse) while the ionization potential +ranges from a couple of eV (for electrons on the most external shells) +up to a few tens of thousands of eV (for electrons on the internal shell +of high-Z atoms). As a consequence, :math:`R\gg1`, and the probability +of ionization of an electron with magnetic quantum number :math:`\vert m \vert=0` +greatly exceeds that of an electron with :math:`\vert m \vert = 1`. + +The initial velocity of the electrons newly created by ionization is chosen as equal to the ion velocity. +This constitutes a minor violation of momentum conservation, as the ion mass is not decreased after ionization. + + +Monte-Carlo scheme +"""""""""""""""""""""""""""""""""""""" + +In :program:`Smilei`, tunnel ionization is treated for each species +(defined by the user as subject to field ionization) right after field interpolation +and before applying the pusher. +For all quasi-particles (henceforth referred to as quasi-ion) of the considered species, +a Monte-Carlo procedure has been implemented that allows to treat multiple ionization +events in a single timestep. It relies on the cumulative probability derived +in Ref. [Nuter2011]_: + +.. math:: + + F_k^{Z^{\star}-1} = \sum_{j=0}^k p_j^{Z^{\star}-1}\,, + +to ionize from 0 to :math:`k` times a quasi-ion with initial charge state +:math:`Z^{\star}-1` during a simulation timestep :math:`\Delta t`, +:math:`p_j^{Z^{\star}-1}` being the probability to ionize exactly :math:`j` times this ion. + +The Monte-Carlo procedure proceeds as follows. +A random number :math:`r` with uniform distribution between 0 and 1 is picked. +If :math:`r` is smaller than the probability :math:`p_0^{Z^{\star}-1}` +to not ionize the quasi-ion, then the quasi-ion is not ionized during this time step. +Otherwise, we loop over the number of ionization events :math:`k`, +from :math:`k=1` to :math:`k_{\rm max}=Z-Z^{\star}+1` +(for which :math:`F_{k_{\rm max}}^{Z^{\star}-1}=1` by construction), +until :math:`r1`, effects which manifest mainly as an initial average longitudinal momentum. +For relativistic regimes, the longitudinal momentum effects significantly change the relativistic Lorentz factor +and thus start to significantly influence also the evolution of the transverse momenta. + +If the envelope approximation hypotheses are satisfied, the charge created with ionization and the momentum distribution +of the newly created electrons computed with this procedure should agree with those obtained with a standard laser simulation, +provided that the comparison is made after the end of the interaction with the laser. +Examples of these comparisons and the derivation of the described electron momentum initialization can be found in [Massimo2020a]_. +A comparison made in a timestep where the interaction with the laser is still taking place would show the effects of the quiver motion in the electron momenta +in the standard laser simulation (e.g. peaks in the transverse momentum spectrum). These effects would be absent in the envelope simulation. + +Apart from the different ionization rate and the ad hoc momentum initialization of the new electrons, +the implementation of the field ionization with a laser envelope follows the same procedure +described in the above section treating the usual field ionization. + +In presence of a laser envelope, an energy conservation equation analogous to :eq:`EnergyConservation` +cannot be written, since the information about the direction of the ionizing field is lost with the envelope +description. However, in many situations where the envelope approximation is valid the ion current can be +neglected and the error on energy conservation is negligible. + + + +---- + +.. _rate_ionization: + +User-defined ionization rate +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:program:`Smilei` can treat ionization considering a fixed rate prescribed by the user. +The ionization rates are defined, for a given ``Species``, as described :ref:`here `. +The Monte-Carlo procedure behind the treatment of ionization in this case closely follows +that developed for field ionization. + +.. warning:: + Note that, in the case of a user-defined ionization rate, only single ionization event per timestep are possible. + + +Let us introduce two benchmarks for which the rate of ionization is defined by the user. +The first benchmark considers an initially neutral species that can be potentially ionized twice. +To run this case, a constant and uniform ionization rate is considered that depends only on the particle current charge +state. For this particular case, we have considered a rate :math:`r_0 = 0.1` (in code units) for ionization from +charge state 0 to 1, and a rate :math:`r_1 = 0.05` (in code units) for ionization from charge state 1 to 2. +The simulation results presented in Fig. :numref:`FigFromRateIonization` (top panel) shows the time evolution of the +fraction in each possible charge states (:math:`Z=0`, :math:`Z=1` and :math:`Z=2`). +Super-imposed (dashed lines) are the corresponding theoretical predictions. + +The second benchmark features an initially neutral species homogeneously distributed in the simulation box. +The ionization rate is here chosen as a function of the spatial coordinate :math:`x`, +and reads :math:`r(x) = r_0 \exp(-(x-x_c)^2/2)` with :math:`r_0 = 0.02` the maximum ionization rate and +:math:`x_c=5` the center of the simulation box. +The simulation results presented in Fig. :numref:`FigFromRateIonization` (bottom panel) shows, +at the end of the simulation :math:`t=20`, the electron number density as a function of space. +Super-imposed (in red) is the corresponding theoretical prediction. + +.. _FigFromRateIonization: + +.. figure:: /_static/userDefinedRate.png + + Results of the two benchmarks for the ionization model using user-defined rates as described above. + +---- + +References +^^^^^^^^^^ + +.. [Ammosov1986] `M. V. Ammosov, N. B. Delone, and V. P. Krainov, Sov. Phys. JETP 64, 1191 (1986) `_ + +.. [Nuter2011] `R. Nuter et al., Phys. of Plasmas 19, 033107 (2011) `_ + +.. [Perelomov1966] `A. M. Perelomov, V. S. Popov, and M. V. Terent’ev, Sov. Phys. JETP 23, 924 (1966) `_ + +.. [Perelomov1967] `A. M. Perelomov, V. S. Popov, and M. V. Terent’ev, Sov. Phys. JETP 24, 207 (1967) `_ + +.. [Chen2013] `M. Chen, E. Cormier-Michel, C. G. R. Geddes, D. L. Bruwhiler, L. L. Yu, E. Esarey, C. B. Schroeder, W. P. Leemans, Journ. Comput. Phys. 236, 220 (2013) `_ + +.. [Tomassini2017] `P. Tomassini, S. De Nicola, L. Labate, P. Londrillo, R. Fedele, D. Terzani, and L. A. Gizzi, Physics of Plasmas 24, 103120 (2017) `_ + +.. [Schroeder2014] `C. B. Schroeder, J.-L. Vay, E. Esarey, S. S. Bulanov, C. Benedetti, L.-L. Yu, M. Chen, C. G. R. Geddes, and W. P. Leemans, Phys. Rev. ST Accel. Beams 17, 101301 `_ + +.. [Gibbon] P. Gibbon, Short Pulse Laser Interactions with Matter - An Introduction, Imperial College Press (2005) diff --git a/_sources/Understand/laser_envelope.rst.txt b/_sources/Understand/laser_envelope.rst.txt new file mode 100644 index 000000000..1b1381a96 --- /dev/null +++ b/_sources/Understand/laser_envelope.rst.txt @@ -0,0 +1,370 @@ + +Laser envelope model +-------------------- + +In many physical situations, the spatial and temporal scales of interest (e.g. the plasma wavelength :math:`\lambda_p`) are much larger than the scales related to the laser central wavelength :math:`\lambda_0`. +In these cases, if the laser pulse is much longer than :math:`\lambda_0`, the computation time can be substantially reduced: one only needs to sample the laser envelope instead of :math:`\lambda_0`, as depicted in the following figure. + +.. figure:: /_static/Envelope_Figure.png + :width: 10cm + + Blue: laser vector potential component :math:`\hat{A}` along the transverse direction. Red: the module of its complex envelope :math:`|\tilde{A}|`. Both the lines display a suitable number of points for a proper sampling. In this case, the envelope is sampled by a number of points smaller by a factor ten. + + +The description of the physical system in terms of the complex envelope of the laser vector potential, neglecting its fast oscillations, is the essence of the envelope approximation. +However, a main limit of this technique is the impossibility to model phenomena at the scale of :math:`\lambda_0`. + +In the following, the equations of the envelope model are presented, following mainly [Cowan2011]_, [Terzani]_, [MassimoPPCF2019]_ . Their numerical solution is briefly described as well. + +---- + +The envelope approximation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The use of envelope models to describe a laser pulse is well known in PIC codes [Mora1997]_, [Quesnel1998]_, [Gordon2000]_, [Huang2006]_, [Cowan2011]_, [Benedetti2012]_. The basic blocks of a PIC code using an envelope description for the laser are an envelope equation, to describe the evolution of the laser, and equations of motion for the macro-particles, to take into account their interactions with the laser. +The effect of the plasma on laser propagation is taken into account in the envelope equation through the plasma susceptibility, as described in the following section. +The various PIC codes using an envelope model for the laser solve different versions of the envelope equation, depending mostly on which terms are retained and which ones are neglected, or the set of coordinates used to derive the envelope equation. Also the numerical schemes used to solve the envelope equation and the equations of motion of the macro-particles vary accordingly. +In :program:`Smilei`, the version of the envelope model written in laboratory frame coordinates, first demonstrated in the PIC code :program:`ALaDyn` [Benedetti2008]_, [Terzani]_ is implemented, including the same numerical scheme to solve the lab frame coordinates envelope equation. + +The basic assumption of the model is the description of the laser pulse vector potential in the transverse direction :math:`\mathbf{\hat{A}}(\mathbf{x},t)` as a slowly varying envelope :math:`\mathbf{\tilde{A}}(\mathbf{x},t)` modulated by fast oscillations at wavelength :math:`\lambda_0`, moving at the speed of light :math:`c`: + +.. math:: + :label: envelope + + \mathbf{\hat{A}}(\mathbf{x},t)=\textrm{Re}\left[\mathbf{\tilde{A}}(\mathbf{x},t)e^{ik_0(x-ct)}\right], + +where :math:`k_0=2\pi/\lambda_0`. In the language of signal processing, :math:`\mathbf{\tilde{A}}` is the complex envelope of :math:`\mathbf{\hat{A}}`. In other words, the spectral content of :math:`\mathbf{\tilde{A}}` is given by the positive frequency components of :math:`\mathbf{\hat{A}}` around :math:`k_0`, but centered around the origin of the frequency :math:`k` axis. +As the laser is the source term of the phenomena of interest, in general any vector :math:`\mathbf{A}` will be therefore given by the summation of a slowly varying part :math:`\mathbf{\bar{A}}` and a fast oscillating part :math:`\mathbf{\hat{A}}` with the same form of Eq. :eq:`envelope`: + +.. math:: + + \mathbf{A}=\mathbf{\bar{A}} + \mathbf{\hat{A}}. + +In the envelope model context, "slowly varying" means that the spatial and temporal variations of :math:`\mathbf{\bar{A}}` and :math:`\mathbf{\tilde{A}}` are small enough to be treated perturbatively with respect to the ratio :math:`\epsilon=\lambda_0/\lambda_p`, as described in detail in [Mora1997]_, [Quesnel1998]_, [Cowan2011]_. The laser envelope transverse size :math:`R` and longitudinal size :math:`L` are thus assumed to scale as :math:`R \approx L \approx \lambda_0 / \epsilon` [Mora1997]_, [Quesnel1998]_. +As described thoroughly in the same references, the coupling between the laser envelope and the plasma macro-particles can be modeled through the addiction of a ponderomotive force term in the macro-particles equations of motion. This term, not representing a real force, is a term rising from an averaging process in the perturbative treatment of the macro-particles motion over the laser optical cycles. + +Modeling the laser through a complex envelope and its coupling with the plasma through the ponderomotive force will yield physically meaningful results only if the variation scales in space and time are greater than :math:`\lambda_0`, :math:`1/\omega_0`. Examples violating these hypotheses include, but are not limited to, tightly focused lasers, few optical cycles lasers, sharp gradients in the plasma density. + + + +---- + + +The envelope equation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The evolution of the laser pulse is described by d'Alembert's equation, which in normalized units reads: + +.. math:: + :label: dalembert + + \nabla^2 \mathbf{\hat{A}}-\partial^2_t\mathbf{\hat{A}}=-\mathbf{\hat{J}}, + +where :math:`\mathbf{\hat{J}}` is the fast oscillating part of the current density in the laser polarization direction. Through the assumption given by Eq. :eq:`envelope`, Eq. :eq:`dalembert` can be reduced to an envelope equation: + +.. math:: + :label: envelope_equation + + \nabla^2 \mathbf{\tilde{A}}+2i\left(\partial_x \mathbf{\tilde{A}} + \partial_t \mathbf{\tilde{A}}\right)-\partial^2_t\mathbf{\tilde{A}}=\chi \mathbf{\tilde{A}}, + +which describes the evolution of the laser pulse only in terms of the laser envelope :math:`\mathbf{\tilde{A}}`. The function :math:`\chi` represents the plasma susceptibility, which is computed similarly to the charge density (see :doc:`algorithms`) as + +.. math:: + :label: susceptibility + + \chi(\mathbf{x}) = \sum_s\,\frac{q^2_s}{m_s}\,\sum_p\,\frac{w_p}{\bar{\gamma}_p}\,S\big(\mathbf{x}-\mathbf{\bar{x}}_p\big)\, + +where :math:`\bar{\gamma}_p` is the averaged Lorentz factor of the macro-particle :math:`p`. This averaged quantity is computed from the averaged macro-particle momentum :math:`\mathbf{\bar{u}}_p=\mathbf{\bar{p}}_p/m_s` and the envelope :math:`\mathbf{\tilde{A}}`: + +.. math:: + :label: gamma_ponderomotive + + \bar{\gamma}_p = \sqrt{1+\mathbf{\bar{u}}^2_p+\frac{|\mathbf{\tilde{A}}(\mathbf{\bar{x}}_p)|^2}{2}}. + +The term at the right hand side of Eq. :eq:`envelope`, where the plasma susceptibility :math:`\chi` appears, allows to describe phenomena where the plasma alters the propagation of the laser pulse, as relativistic self-focusing. + +Note that if in Eq. :eq:`envelope` the temporal variation of the envelope :math:`\mathbf{\tilde{A}}` is neglected, and :math:`\partial^2_x \mathbf{\tilde{A}} \ll 2i\partial_x \mathbf{\tilde{A}}` is assumed, the well-known paraxial wave equation is retrieved in vacuum (:math:`\chi=0`): + +.. math:: + :label: paraxial_wave_equation + + \nabla_{\perp}^2 \mathbf{\tilde{A}}+2i\partial_x \mathbf{\tilde{A}}=0. + +In :program:`Smilei`, no assumptions on the derivatives are made and the scalar versions of Eq. :eq:`envelope_equation` is solved (see next sections). + +---- + +The ponderomotive equations of motion +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The process of averaging over the time scale of a laser oscillation period yields a simple result for the macro-particles equations of motion. +The averaged position :math:`\mathbf{\bar{x}}_p` and momentum :math:`\mathbf{\bar{u}}_p` of the macro-particle :math:`p` are related to the averaged electromagnetic fields :math:`\mathbf{\bar{E}}_p=\mathbf{\bar{E}}(\mathbf{\bar{x}}_p)`, :math:`\mathbf{\bar{B}}_p=\mathbf{\bar{B}}(\mathbf{\bar{x}}_p)` through the usual equations of motion, with the addition of a ponderomotive force term which models the interaction with the laser: + +.. math:: + :label: ponderomotive_equations_of_motion + + \begin{eqnarray} + \frac{d\mathbf{\bar{x}}_p}{dt} &=& \frac{\mathbf{\bar{u}_p}}{\bar{\gamma}_p}, \,\\ + \frac{d\mathbf{\bar{u}}_p}{dt} &=& r_s \, \left( \mathbf{\bar{E}}_p + \frac{\mathbf{\bar{u}}_p}{\bar{\gamma}_p} \times \mathbf{\bar{B}}_p \right)-r^2_s\thinspace\frac{1}{4\bar{\gamma}_p}\nabla\left(|\mathbf{\tilde{A}}_p|^2\right), + \end{eqnarray} + +where :math:`r_s = q_s/m_s` is the charge-over-mass ratio (for species :math:`s`). +The presence of the ponderomotive force :math:`\mathbf{F}_{pond}=-r^2_s\thinspace\frac{1}{4\bar{\gamma}_p}\nabla\left(|\mathbf{\tilde{A}}|^2\right)` and of the ponderomotive potential :math:`\Phi_{pond}=\frac{|\mathbf{\tilde{A}}|^2}{2}` +in the envelope and particle equations is the reason why the envelope model is also called ponderomotive guiding center model [Gordon2000]_. + +---- + + +The averaged electromagnetic fields +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the envelope model, Maxwell's equations remain unaltered, except for the fact that they describe the evolution of the averaged electromagnetic fields :math:`\mathbf{\bar{E}}(\mathbf{x},t)`, :math:`\mathbf{\bar{B}}(\mathbf{x},t)` in terms of the averaged charge density :math:`\bar{\rho}(\mathbf{x},t)` and averaged current density :math:`\mathbf{\bar{J}}(\mathbf{x},t)`: + +.. math:: + :label: Maxwell_envelope + + \begin{eqnarray} + \nabla \cdot \mathbf{\bar{B}} &=& 0 \,,\\ + \nabla \cdot \mathbf{\bar{E}} &=& \bar{\rho} \,,\\ + \nabla \times \mathbf{\bar{B}} &=& \mathbf{\bar{J}} + \partial_t \mathbf{\bar{E}} \,,\\ + \nabla \times \mathbf{\bar{E}} &=& -\partial_t \mathbf{\bar{B}} \,. + \end{eqnarray} + +Note that the averaged electromagnetic fields do not include the laser fields. Thus, also in the diagnostics of :program:`Smilei`, the fields will include only the averaged fields. + +---- + +The ponderomotive PIC loop +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Since Maxwell's equations :eq:`Maxwell_envelope` remain unaltered, their solution can employ the same techniques used in a standard PIC code. The main difficulty in the solution of the other equations, namely the envelope equation Eq. :eq:`envelope_equation` and the macroparticles equations of motion Eqs. :eq:`ponderomotive_equations_of_motion`, is that the source terms contain the unknown terms. +For example, in the envelope equations, the source term involves the unknown envelope itself and the susceptibility, which depends on the envelope. Also, the equations of motion contain the term :math:`\bar{\gamma}`, which depends on the envelope. +The PIC loop described in :doc:`algorithms` is thus modified to self-consistently solve the envelope model equations. At each timestep, the code performs the following operations + +#. interpolating the electromagnetic fields and the ponderomotive potential at the macro-particle positions, +#. projecting the new plasma susceptibility on the grid, +#. computing the new macro-particle velocities, +#. computing the new envelope values on the grid, +#. computing the new macro-particle positions, +#. projecting the new charge and current densities on the grid, +#. computing the new electromagnetic fields on the grid. + +Note that the momentum advance and position advance are separated by the envelope equation solution in this modified PIC loop. +In this section, we describe these steps which advance the time from time-step :math:`(n)` to time-step :math:`(n+1)`. + + +Field interpolation +""""""""""""""""""" +The electromagnetic fields and ponderomotive potential interpolation at the macro-particle position at time-step :math:`(n)` follow the same technique described in :doc:`algorithms`: + +.. math:: + + \begin{eqnarray} + \mathbf{\bar{E}}_p^{(n)} = V_c^{-1} \int d\mathbf{x}\, S\left(\mathbf{x}-\mathbf{\bar{x}}_p^{(n)}\right) \mathbf{\bar{E}}^{(n)}(\mathbf{x})\,,\\ + \mathbf{\bar{B}}_p^{(n)} = V_c^{-1} \int d\mathbf{x}\, S\left(\mathbf{x}-\mathbf{\bar{x}}_p^{(n)}\right) \mathbf{\bar{B}}^{(n)}(\mathbf{x})\,,\\ + \mathbf{\Phi}_p^{(n)} = V_c^{-1} \int d\mathbf{x}\, S\left(\mathbf{x}-\mathbf{\bar{x}}_p^{(n)}\right) \mathbf{\Phi}^{(n)}(\mathbf{x})\,, + \end{eqnarray} + +where we have used the time-centered magnetic fields +:math:`\mathbf{\bar{B}}^{(n)}=\tfrac{1}{2}[\mathbf{\bar{B}}^{(n+1/2) } + \mathbf{\bar{B}}^{(n-1/2)}]`, +and :math:`V_c` denotes the volume of a cell. + +Susceptibility deposition +"""""""""""""""""""""""""""" +The macro-particle averaged positions :math:`\mathbf{\bar{x}}_p^{(n)}` and averaged momenta :math:`\mathbf{\bar{p}}_p^{(n)}` +and the ponderomotive potential :math:`\mathbf{\Phi}_p^{(n)}` are used to compute the ponderomotive Lorentz factor :math:`\bar{\gamma}_p` :eq:`gamma_ponderomotive` +and deposit the susceptibility on the grid through Eq. :eq:`susceptibility`. + +Ponderomotive momentum push +"""""""""""""""""""""""""""" +The momentum push is performed through a modified version of the well-known `Boris Pusher `_, derived +and proposed in [Terzani]_. +The plasma electric, magnetic and ponderomotive potential fields at the macro-particle position :math:`\mathbf{\bar{E}}_p^{(n)}`, +:math:`\mathbf{\bar{B}}_p^{(n)}`, :math:`\mathbf{\Phi}_p^{(n)}` are used to advance the momentum :math:`\mathbf{\bar{p}}_p^{(n-1/2)}` +from time-step :math:`n−1/2` to time-step :math:`n + 1/2`, solving the momentum equation in Eqs. :eq:`ponderomotive_equations_of_motion` + +Envelope equation solution +"""""""""""""""""""""""""""" +Now that the averaged susceptibility is known at time-step :math:`n`, the envelope can be advanced solving the envelope equation :eq:`envelope_equation`. +In the two solver schemes available in the code (see below), the envelope :math:`\mathbf{\tilde{A}}` at time-step :math:`n+1` is computed from its value +at timesteps :math:`n`, :math:`n-1` and the suceptibility :math:`\chi` at time-step :math:`n`. The value of the envelope at timestep :math:`n` is conserved for the next iteration of the time loop. +A main advantage of these explicit numerical schemes is their straightforward parallelization in 3D, due to the locality of the operations involved. + +Ponderomotive position push +"""""""""""""""""""""""""""" +The updated ponderomotive potential is interpolated at macro-particle positions to obtain :math:`\mathbf{\Phi}_p^{(n+1)}`. +Afterwards, the temporal interpolation :math:`\mathbf{\Phi}_p^{(n+1/2)}=\left(\mathbf{\Phi}_p^{(n)}+\mathbf{\Phi}_p^{(n+1)}\right)/2` is performed. +The updated ponderomotive Lorentz factor :math:`\bar{\gamma}_p^{(n+1/2)}` can be computed and the averaged position of each macro-particle +can be advanced solving the last of Eqs. :eq:`ponderomotive_equations_of_motion`: + +.. math:: + + \mathbf{\bar{x}}_p^{n+1}=\mathbf{\bar{x}}_p^{n} + \Delta t \, \frac{\mathbf{\bar{p}}_p^{n+\tfrac{1}{2}}}{m_s\bar{\gamma}_p^{(n+1/2)}}, + + +Current deposition +"""""""""""""""""" +The averaged charge deposition (i.e. charge and current density projection onto the grid) is then +performed exactly as in the standard PIC loop for the non averaged quantities (see :doc:`algorithms`), using the charge-conserving algorithm +`proposed by Esirkepov `_. + + +Maxwell solvers +""""""""""""""" +Now that the averaged currents are known at time-step :math:`n+\tfrac{1}{2}`, the averaged electromagnetic +fields can be advanced solving Maxwell's equations :eq:`Maxwell_envelope`. Their solution is identical to the one described in :doc:`algorithms` for the corresponding non-averaged quantities. + + +---- + +Laser polarization in the envelope model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In :program:`Smilei`, the envelope model is implemented to take into account either linear or circular polarization +(``ellipticity = 0`` and ``ellipticity = 1`` in the input namelist respectively). The default polarization is linear along the `y` direction. +The envelope of a laser pulse propagating in the positive ``x`` direction can be written as + +.. math:: + + \mathbf{\tilde{A}} (\mathbf{x},t)= \tilde{A}(\mathbf{x},t) \left[ \eta\thinspace\hat{y} + i(1-\eta^2)^{1/2}\hat{z} \right] , + +where :math:`\eta=1` or :math:`\eta=0` for linear polarization along ``y`` or ``z``, and :math:`\eta\pm1/\sqrt{2}` for circular polarization. +Although Eq. :eq:`envelope_equation` is a vector equation nonlinear, these two polarizations allow to solve only one scalar equation +at each timestep, because once the susceptibility at a given timestep is known, the envelope equation can be considered linear. +Thus, after calculating the susceptibility we can solve the equation: + +.. math:: + :label: envelope_equation_scalar + + \nabla^2 \tilde{A}+2i\left(\partial_x \tilde{A} + \partial_t \tilde{A}\right)-\partial^2_t\tilde{A}=\chi \tilde{A}, + +where :math:`\tilde{A}` is the nonzero component of :math:`\mathbf{\tilde{A}}` for linear polarization and :math:`\tilde{A}/\sqrt{2}` for circular polarization. +This approach gives accurate results only if the ponderomotive potential :math:`\Phi_{pond}=\frac{|\mathbf{\tilde{A}}|^2}{2}` is computed +accordingly to the vector definition of :math:`\mathbf{\tilde{A}}`. This means that :math:`\Phi_{pond}=\frac{|\tilde{A}|^2}{2}` for both linear and +circular polarization. +Besides, with this approach the absolute value of :math:`\tilde{A}` and the derived electric field :math:`\tilde{E}` (see next section) are directly comparable with +standard laser simulations with the same polarization and :math:`a_0`. + + +---- + +Computing the laser electric field from the laser envelope +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is always useful (and recommendable) to compare the results of an envelope simulation and of a standard laser simulation, +to check if the envelope approximation is suitable for the physical case that is simulated. +For this purpose, the plasma electromagnetic fields and the charge densities are easily comparable. +However, in an envelope simulation all the plasma dynamics is written as function of the envelope of the transverse component +of the vector potential :math:`\tilde{A}`, as explained in the previous sections, and not as function of the laser electric field. + +Furthermore, in case of envelope simulations with ionization, the ionization rate formula is computed using the electric field +(longitudinal and transverse components) of the laser. + +For these two reasons (diagnostic and ionization), in an envelope simulation two additional fields are computed, +:math:`\tilde{E}` and :math:`\tilde{E_x}`, which represent respectively the envelope of the transverse component +and of the longitudinal component of the laser electric field. + + +From Eq. :eq:`envelope`, the laser transverse electric field's complex envelope :math:`\tilde{E}` can be derived. +In the context of the perturbative treatment, the laser scalar potential can be neglected [Cowan2011]_, yielding: + +.. math:: + + \hat{E} = -\partial_t \hat{A} = -\partial_t \Big\{\textrm{Re}\left[\tilde{A}(\mathbf{x},t)e^{ik_0(x-ct)}\right]\Big\} = \textrm{Re}\left[-\left(\partial_t-ik_0c\right)\tilde{A}(\mathbf{x},t)e^{ik_0(x-ct)}\right], + +which can be expressed, following the definition in Eq. :eq:`envelope`, also as + +.. math:: + + \hat{E} = \textrm{Re}\left[\tilde{E}(\mathbf{x},t)e^{ik_0(x-ct)}\right]. + + +The laser transverse electric field's complex envelope :math:`\tilde{E}` can thus be defined: + +.. math:: + + \tilde{E} = -\left(\partial_t-ik_0c\right)\tilde{A}(\mathbf{x},t). + +In the same theoretical framework, it can be shown that the laser longitudinal electric field's envelope can be computed through +a partial derivative along the direction perpendicular to the laser propagation direction: + +.. math:: + + \tilde{E_x} = -\partial_{\perp}\tilde{A}(\mathbf{x},t). + +In the diagnostics, the absolute value of the fields :math:`\tilde{E}`, :math:`\tilde{E_x}` are available, under the names ``Env_E_abs`` and ``Env_Ex_abs``. + + + + + + + +---- + +The numerical solution of the envelope equation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To solve Eq. :eq:`envelope_equation_scalar`, two explicit numerical schemes are implemented in the code, first implemented in the PIC code :program:`ALaDyn` [Benedetti2008]_ and described in [Terzani]_. + +In the first scheme, denoted as ``"explicit"`` in the input namelist, the well known central finite differences are used to discretize the envelope equation. +In 1D for example, the spatial and time derivatives of the envelope :math:`\tilde{A}` at time-step :math:`n` and spatial index :math:`i` are thus approximated by: + +.. math:: + + D_x\tilde{A}\bigg\rvert^{n}_{i}&=&\frac{\tilde{A}^n_{i+1}-\tilde{A}^n_{i-1}}{2\Delta x},\\ + D_t\tilde{A}\bigg\rvert^{n}_{i}&=&\frac{\tilde{A}^{n+1}_{i}-\tilde{A}^{n-1}_{i}}{2\Delta t},\\ + D_{xx}\tilde{A}\bigg\rvert^{n}_{i}&=&\frac{\tilde{A}^n_{i+1}-2\tilde{A}^n_{i}+\tilde{A}^n_{i-1}}{\Delta x^2},\\ + D_{tt}\tilde{A}\bigg\rvert^{n}_{i}&=&\frac{\tilde{A}^{n+1}_{i}-2\tilde{A}^n_{i}+\tilde{A}^{n-1}_{i}}{\Delta t^2}, + +where :math:`\Delta x, \Delta t` are the cell size in the `x` direction and the integration time-step respectively. + +In the second scheme, denoted as ``"explicit_reduced_dispersion"`` in the input namelist, the finite difference approximations for the derivatives along +the propagation direction `x` are substituted by optimized finite differences that reduce the numerical dispersion in that direction (see [Terzani]_ for the derivation). +Namely, defining :math:`\nu=\Delta t/\Delta x`, :math:`\delta=(1-\nu^2)/3`, these optimized derivatives can be written as: + +.. math:: + + D_{x,opt}\tilde{A}\bigg\rvert^{n}_{i}&=& (1+\delta)D_x\tilde{A}\bigg\rvert^{n}_{i}-\delta\left(\frac{\tilde{A}^n_{i+2}-\tilde{A}^n_{i-2}}{4\Delta x}\right),\\ + D_{xx,opt}\tilde{A}\bigg\rvert^{n}_{i}&=& (1+\delta)D_{xx}\tilde{A}\bigg\rvert^{n}_{i}-\delta\left(\frac{\tilde{A}^n_{i+2}-2\tilde{A}^n_{i}+\tilde{A}^n_{i-2}}{4\Delta x^2}\right).\\ + +In both schemes, after substituting the spatial and temporal derivative with the chosen finite differences forms, +an explicit update of :math:`\tilde{A}^{n+1}_i`, function of :math:`\tilde{A}^{n}_i`, :math:`\tilde{A}^{n}_{i-1}`, :math:`\tilde{A}^{n}_{i+1}`, :math:`\tilde{A}^{n-1}_i` and :math:`\chi^{n}_i` can be easily found. +In the reduced dispersion scheme, also the values :math:`\tilde{A}^{n}_{i-2}`, :math:`\tilde{A}^{n}_{i+2}` are necessary for the update. +The locality of the abovementioned finite difference stencils allows a parallelization with well known techniques and the extension to the other geometries is straightforward. +The discretization of the transverse components of the Laplacian in Eq. :eq:`envelope_equation` in Cartesian geometry uses the central finite differences defined above, applied to the `y` and `z` axes. +In cylindrical geometry (see :doc:`azimuthal_modes_decomposition`), the transverse part of the Laplacian is discretized as: + +.. math:: + + D^2_{\perp, cyl}\tilde{A}\rvert^{n}_{i,j} = \frac{\tilde{A}^n_{i,j+1}-2\tilde{A}^n_{i,j}+\tilde{A}^n_{i,j-1}}{\Delta r^2} + \frac{1}{r_j}\frac{\tilde{A}^n_{i,j+1}-\tilde{A}^n_{i,j-1}}{2\Delta r}, + +where :math:`j, r, \Delta r` are the transverse index, the distance from the propagation axis and the radial cell size respectively. + + + + +---- + +References +^^^^^^^^^^ + +.. [Mora1997] `P. Mora and T. M. Antonsen Jr, Physics of Plasmas 4, 217 (1997) `_ + +.. [Quesnel1998] `B. Quesnel and P. Mora, Physics Review E 58, 3719 (1998) `_ + +.. [Gordon2000] `D. F. Gordon et al.,IEEE Transactions on Plasma Science 28, 4 (2000) `_ + +.. [Huang2006] `C. Huang et al., Journal of Physics: Conference Series 46, 190 (2006) `_ + +.. [Cowan2011] `B. M. Cowan et al., Journal of Computational Physics 230, 61 (2011) `_ + +.. [Benedetti2012] `C. Benedetti et al., Proceedings of the 11th International Computational Accelerator Physics Conference (ICAP 2012) `_ + +.. [Benedetti2008] `C. Benedetti et al., IEEE Transactions on Plasma Science 36, 1790 (2008) `_ + +.. [Terzani] `D. Terzani and P. Londrillo, Computer Physics Communications 242, 49 (2019) `_ + +.. [MassimoPPCF2019] `F. Massimo et al., Plasma Phys. Control. Fusion (2019) `_ + + diff --git a/_sources/Understand/multiphoton_Breit_Wheeler.rst.txt b/_sources/Understand/multiphoton_Breit_Wheeler.rst.txt new file mode 100644 index 000000000..1185f2e97 --- /dev/null +++ b/_sources/Understand/multiphoton_Breit_Wheeler.rst.txt @@ -0,0 +1,372 @@ +.. _multiphotonBreitWheelerPage: + +Multiphoton Breit-Wheeler pair creation +-------------------------------------------------------------------------------- + +The multiphoton Breit-Wheeler (:math:`\gamma + n\omega \rightarrow e^- + e^+`), +also referred to as +the nonlinear Breit-Wheeler, corresponds to the decay of a +high-energy photon into a pair of electron-positron +when interacting with a strong electromagnetic field. + +In the vacuum, the electromagnetic field becomes nonlinear from the Schwinger +electric field :math:`E_s = 1.3 \times 10^{18}\ \mathrm{V/m}` corresponding +to an intensity of :math:`10^{29}\ \mathrm{Wcm^{-2}}` for +:math:`\lambda = 1\ \mu m`. In such a field, spontaneous apparitions of electron-positron pairs from +the nonlinear vacuum are possible. If this field is not reachable in the laboratory +frame, it will be very close in the boosted frame of highly-accelerated electrons. At +:math:`10^{24}\ \mathrm{Wcm^{-2}}`, a Lorentz factor of :math:`\gamma \sim 10^5` +is required to reach the Schwinger limit. +This is the reason why quantum electrodynamics effects and in particular strong- +field pair generation is accessible with the extreme-intensity lasers (multipetawatt lasers). + +As for electrons or positrons, the strength of QED effects depends +on the photon quantum parameter: + +.. math:: + :label: photonQuantumParameter1 + + \chi_\gamma = \frac{\gamma_\gamma}{E_s} \sqrt{ \left( \mathbf{E}_\perp + + \mathbf{c} \times \mathbf{B} \right)^2 } + +where +:math:`\gamma_\gamma = \varepsilon_\gamma / m_e c^2` is the photon normalized energy, +:math:`m_e` the electron mass, +:math:`c` the speed of light in vacuum, +:math:`\mathbf{E}_\perp` is the electric field orthogonal to +the propagation direction of the photon, +:math:`\mathbf{B}` the magnetic field. + +-------------------------------------------------------------------------------- + +Physical model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The energy distribution of the production rate of pairs by a hard photon +is given by the Ritus formulae + +.. math:: + :label: BWEnergyDistribution + + \frac{d^2N_{BW}}{d \chi_{\pm} dt} = \frac{\alpha_f m_e^2 c^4}{\pi \sqrt{3} \hbar \varepsilon_\gamma \chi_\gamma} + \int_{x}^{+\infty}{\sqrt{s} K_{1/3} \left( \frac{2}{3} s^{3/2} \right) ds - \left( 2 - \chi_\gamma x^{3/2} \right) K_{2/3} \left( \frac{2}{3} x^{3/2} \right) } + +where :math:`x = \left( \chi_\gamma / (\chi_{-} \chi_{+}) \right)^{2/3}`. +The parameters :math:`\chi_{-}` and :math:`\chi_{+}` are the respective Lorentz +invariant of the electron and the positron after pair creation. +Furthermore, one has :math:`\chi_- = \chi_\gamma - \chi_+` meaning that :math:`\chi_-` +and :math:`\chi_+` can be interchanged. + +The total production rate of pairs can be written + +.. math:: + :label: BWproductionRate + + \frac{dN_{BW}}{dt} = \frac{\alpha_f m_e^2 c^4}{ \hbar \varepsilon_\gamma} \chi_\gamma T \left( \chi_\gamma \right) + +where + +.. math:: + :label: BWTfunction + + T \left( \chi_\gamma \right) = \frac{1}{\pi \sqrt{3} \chi_\gamma^2 } + \int_{0}^{+\infty}{\int_{x}^{+\infty}{\sqrt{s} K_{1/3} \left( \frac{2}{3} s^{3/2} + \right) ds - \left( 2 - \chi_\gamma x^{3/2} \right) K_{2/3} \left( \frac{2}{3} x^{3/2} \right) }} d\chi_- + +A photon of energy :math:`\varepsilon_\gamma` traveling in a constant electric field :math:`E` has a Lorentz +parameter equal to :math:`\chi_\gamma = \varepsilon_\gamma E / (E_s m_e c^2)`. + +We consider the case where photon interact in a constant uniform electric field. +For a field of amplitude :math:`E = 500 m_e \omega c / e`, the energy +distribution and the production rate of pair creation as a function of :math:`\chi_\gamma` are +plotted in :numref:`synchrotron_pairs_dNdt`. It shows that the total production +rate of electron-positron pairs rises rapidly to reach a peak around +:math:`\chi_\gamma = 10` with almost a pair generated per femtosecond. +Under :math:`\chi_\gamma = 0.1`, the production rate is very weak with +less than a pair after 100 picoseconds of interaction. +Above :math:`\chi_\gamma = 10`, the production decreases slowly with +:math:`\chi_\gamma`. + +The right subplot in :numref:`synchrotron_pairs_dNdt` gives the probability +for a photon to decay into a pair as a function of the energy given to the electron +(using approximation :math:`\chi_\gamma / \chi_- = \gamma_\gamma / \gamma_-`) +for a field of amplitude :math:`E = 500 m_e \omega c / e`. +It can also be seen as the pair creation energy distribution. +The distribution is symmetric with respect to :math:`\chi_- / \chi_\gamma = 1/2`. +Below :math:`\chi_\gamma = 10`, The maximum probability corresponds to +equal electron-positron energies :math:`\chi_- = \chi_+ = \chi_\gamma / 2`. +Above this threshold, the energy dispersion increases with :math:`\chi_\gamma`. + +.. _synchrotron_pairs_dNdt: + +.. figure:: /_static/synchrotron_pairs_dNdt.png + :width: 18cm + + (left) - Normalized total pair production distribution given by Eq. :eq:`BWproductionRate`. + (right) - Normalized pair creation :math:`\chi` distribution given by Eq. :eq:`BWEnergyDistribution`. + + +-------------------------------------------------------------------------------- + +.. _BWStochasticSchemeSection: + +Stochastic scheme +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Multiphoton Breit-Wheeler is treated with a Monte-Carlo process similar +to the nonlinear inverse Compton Scattering +(see :ref:`the radiation reaction page `). +It is close to what has been done in +[Duclous2011]_, [Lobet2013]_, [Lobet2015]_. + +The first preliminary step consists +on introducing the notion of macro-photon. Macro-photons are simply the equivalent of +macro-particles (see :ref:`the macro-particle section `) +extended to photons. +There are defined by a charge and a mass equal to 0. The momentum is substituted +by the photon momentum :math:`\mathbf{p}_\gamma = \hbar \mathbf{k}` where +:math:`\mathbf{k}` is the wave vector. +The momentum contains the photon energy so that +:math:`\mathbf{p}_\gamma = \gamma_\gamma m_e \mathbf{c}`. +The definition of the photon Lorentz factor is therefore also slightly different +than particles. + +1. An incremental optical depth :math:`\tau`, initially set to 0, is assigned to the macro-photon. +Decay into pairs occurs when it reaches the final optical depth :math:`\tau_f` +sampled from :math:`\tau_f = -\log{(\xi)}` where :math:`\xi` is a random number in :math:`\left]0,1\right]`. + +2. The optical depth :math:`\tau` evolves according to the photon quantum parameter +following: + +.. math:: + :label: mBW_MCDtauDt + + \frac{d\tau}{dt} = \frac{dN_{BW}}{dt}\left( \chi_\gamma \right) + +that is also the production rate of pairs +(integration of Eq. :eq:`BWEnergyDistribution`). + +3. The emitted electron's quantum parameter :math:`\chi_-` is computed by +inverting the cumulative distribution function: + +.. math:: + :label: mBW_CumulativeDistr + + P(\chi_-,\chi_\gamma) = \frac{\displaystyle{\int_0^{\chi_-}{ + \frac{d^2N_{BW}}{d \chi dt} d\chi}}}{\displaystyle{\int_0^{\chi_\gamma}{\frac{d^2N_{BW}}{d \chi dt} d\chi}}} + +The inversion of :math:`P(\chi_-,\chi_\gamma)=\xi'` is done after drawing +a second random number +:math:`\xi' \in \left[ 0,1\right]` to find :math:`\chi_-`. +The positron quantum parameter is :math:`\chi_+ = \chi_\gamma - \chi_-`. + +4. The energy of the emitted electron is then computed: +:math:`\varepsilon_- = mc^2 \gamma_- = mc^2 \left[ 1 + \left(\gamma_\gamma - 2\right) \chi_- / \chi_\gamma \right]`. +If :math:`\gamma_\gamma < 2`, the pair creation is not possible since the photon +energy is below the rest mass of the particles. + +5. The photon momentum is then updated. +Propagation direction is the same as for the photon. Pairs are created at the +same position as for the photon. The weight is conserved. It is possible to +create more than a macro-electron or a macro-positron in order to improve +the phenomenon statistics. In this case, the weight of each macro-particle is +the photon weight divided by the number of emissions. + +-------------------------------------------------------------------------------- + +Implementation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +C++ classes for the multiphoton Breit-Wheeler process are located +in the directory ``src/MultiphotonBreitWheeler``. +In :program:`Smilei`, the multiphoton Breit-Wheeler process is not incorporated +in the photon pusher in order to preserve vector performance of the latter one. + +Description of the files: + +* Class ``MultiphotonBreitWheelerTables``: This class initializes and manages the + multiphoton Breit-Wheeler parameters. + It contains the methods to read the tables and data structures to store them. + It also contains default embebded tables. + Then, it provides several methods to look for values in the tables for the Monte-Carlo process + and compute different parameters used by this physical mechanism. +* Class ``MultiphotonBreitWheeler``: this class contains the methods to + perform the Breit-Wheeler Monte-Carlo process described in :ref:`the previous section `). +* Class ``MultiphotonBreitWheelerFactory``: this class is supposed to + manage the different Breit-Wheeler algorithms. + For the moment, only one model is implemented. + +If the multiphoton Breit-Wheeler is activated for a photon species, the factory +will initialize the instance ``Multiphoton_Breit_Wheeler_process`` of +the class ``MultiphotonBreitWheeler`` +declared in the corresponding ``species`` (see ``species.cpp``). + +The multiphoton Breit-Wheeler Monte-Carlo process is performed in the method ``dynamics`` of ``species``. +It is called after the particle field interpolation (field gathering), +after ionization and radiation reaction and before the particle pusher. +At this stage, the new particles are stored in a temporary buffer called ``new_pair``. +This is an array of two instances of ``Particles``. +It is declared in ``Multiphoton_Breit_Wheeler_process``. +Particles are imported in the main species particle arrays +(``particles`` object in ``species``) only after the current deposition +and before the boundary conditions using the method ``importParticles`` +of the class ``Particles``. + +-------------------------------------------------------------------------------- + +Tables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +External tables can be generated using an external tools called :program:`smilei_tables`. +More information can be found in :doc:`/Use/tables`. + +-------------------------------------------------------------------------------- + +Benchmarks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Synchrotron, 2D +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +In this configuration, a mono-energetic bunch of photons is initialized +in a constant uniform strong magnetic field. +The photons decay into pairs via the multiphoton Breit-Wheeler progressively. +In this particular case, the generated electrons and positrons do not radiate +in order to capture the emission energy spectrum. +Two cases are simulated with different +initial quantum parameters: + +* Case 1: :math:`\chi_{\gamma,0} = 1`, :math:`B = 270`, :math:`\gamma_{\gamma,0} = 1500` +* Case 2: :math:`\chi_{\gamma,0} = 20`, :math:`B = 1000`, :math:`\gamma_{\gamma,0} = 8125` + +The results of the first case are shown in +:numref:`synchrotron_pairs_energy_spectra_chi1`. The two first figures +represent respectively the electron (left) and the positron energy (center) spectrum at the end +of the simulation when all photons have been converted into pairs. +The last one on the right is the time evolution of the photon (green), electron (blue), +positron (orange) and total (black) kinetic energy. +The quantum parameter of all photons is initially equal to +:math:`\chi_{\gamma,0} = 1`. According to :numref:`synchrotron_pairs_dNdt`, +we are located in an area of the energy distribution where electrons and +positrons are more likely to be created with almost the same energy +(:math:`\chi_{+} = \chi_{-} =\chi_{\gamma,0} /2`). +This is confirmed in :numref:`synchrotron_pairs_energy_spectra_chi1`. +Electron and positron energy spectra are well similar, symmetric and centered +at half the initial photon energy equal to :math:`\gamma = 750`. +The energy balance (right figure) shows that positron and electron kinetic energies +have the same behaviors and converge to half the initial photon energy +at the end of the simulation. +The total energy is well constant and conserved in time. + +.. _synchrotron_pairs_energy_spectra_chi1: + +.. figure:: /_static/synchrotron_pairs_energy_spectra_chi1.png + :width: 18cm + + (left) - Electron energy spectrum at the end of the run. + (middle) - Positron energy spectrum at the end of the run. + (right) - Time evolution of the photon (green), electron (blue), positron + (orange) and total (black) normalized energy :math:`U / U_{tot}`. + +The results of the second case are shown in +:numref:`synchrotron_pairs_energy_spectra_chi20` as for the first case. +Here, the quantum parameter of all photons is initially equal to +:math:`\chi_{\gamma,0} = 20`. This means that contrary to the previous case, +the probability to generate electrons and positrons of similar energy +is not the most significant. +As in :numref:`synchrotron_pairs_dNdt`, the energy spectra exhibit two maximums. +This maximums are located approximately at 10% and 90% of the initial photon +energy of :math:`\gamma_{\gamma,0} = 8125`. +Electron and positron spectra are nonetheless similar and symmetric in respect +to half the initial photon energy. +Again, the energy balance (right figure) shows that positron and electron kinetic energies +have the same behaviors and converge to half the initial photon energy +at the end of the simulation. +The total energy is well constant and conserved in time. + +.. _synchrotron_pairs_energy_spectra_chi20: + +.. figure:: /_static/synchrotron_pairs_energy_spectra_chi20.png + :width: 18cm + + (left) - Electron energy spectrum at the end of the run. + (middle) - Positron energy spectrum at the end of the run. + (right) - Time evolution of the photon (green), electron (blue) + and positron (orange) + normalized energy :math:`U / U_{tot}`. + +The benchmark ``tst2d_10_multiphoton_Breit_Wheeler`` is very close to +the second case presented here. + +Counter-propagating plane wave, 1D +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +In this test case, a bunch of electrons is initialized at the right side +of the domain with an initial energy of 4 GeV. The bunch is made to collide head-on +with a laser plane wave injected from the left side of the domain. +The laser has a maximal intensity of :math:`10^{23}\ \mathrm{Wcm^{-2}}`. +It is circularly polarized and has a temporal Gaussian profile with a +FWHM (full width at half maximum) of 10 periods +(approximately corresponding to 33 fs). +A wavelength of :math:`1\ \mathrm{\mu m}` is considered. + +This configuration is one of the most efficient to trigger QED effects +since it maximizes the particle and photon quantum parameters. + +By interacting with the laser pulse, the high-energy electron will first +radiate high-energy gamma photons that will be generated as macro-photons by the code +via the nonlinear Compton scattering. +These photons are generated in the same direction of the electrons with an energy up +to almost the electron kinetic energy. +Then, the macro-photons interact in turn with the laser field and can decay +into electron-positron pairs via the multiphoton Breit-Wheeler process. + +The first plot on left of :numref:`counter_pair_smilei` shows the energy +balance of the simulation. +The second plot on the center of :numref:`counter_pair_smilei` shows the +time evolution of the number of macro-electrons, macro-positrons and macro-photons. +The electron bunch energy rapidly drops +after entering the laser field around :math:`t = 240 \omega_r^{-1}`. +At the same time, many macro-photons are generated by the particle number evolution +as shown in :numref:`counter_pair_smilei`. The photon energy therefore rapidly rises +as the electron energy decreases. + +.. _counter_pair_smilei: + +.. figure:: /_static/counter_pair_smilei.png + :width: 18cm + + (left) - Energy balance of the simulation. In the legend, **Photon** represents the macro-photon + energy and **Radiation** represents the radiated energy excluding the macro-photons. + (center) - Time evolution of the number of macro-electrons (blue), + macro-positrons (orange) and macro-photons (green) in the simulation. + (right) - Final energy spectrum of the electrons (blue), positrons (orange), + and photons (green). + +The multiphoton Breit-Wheeler generation of electron-positron starts latter +when emitted macro-photons enters the high-intensity region of the laser. +This is revealed by the yield of macro-positron. +When electrons and positrons have lost sufficient energy, they can not produce +macro-photons anymore and radiated energy is therefore added directly +in the energy balance. +This is shown by the red curve of the energy balance of :numref:`counter_pair_smilei`. +The radiated energy rises after the main phase of the macro-photon generation after +:math:`t = 250 \omega_r^{-1}`. The radiated energy contains the energy from +the continuous radiation reaction model and from the discontinuous Monte-Carlo +if the energy of the emitted photon is below :math:`\gamma = 2`. +Under this threshold, the photon can not decay into electron-positron pair. +It is therefore useless and costly to generated a macro-photon. + +The final electron, positron and photon energy spectra are shown in +the right plot of :numref:`counter_pair_smilei`. At the end of the simulation, +the photon spectrum is a broad decreasing profile ranging from 1 MeV to 1 GeV. +This is the consequence of two main facts: + +* The highest is the photon energy, more important is the probability to decay into pairs. +* As electron and positron lose energy, they continue to radiate smaller ans smaller photon energy. + +Electron and positron spectra are very similar ranging from 20 MeV +to mainly 200 MeV. +Few particles have an energy above this threshold up to 1 GeV. + +This corresponds to the benchmark ``benchmark/tst1d_10_pair_electron_laser_collision.py``. diff --git a/_sources/Understand/numerical_techniques.rst.txt b/_sources/Understand/numerical_techniques.rst.txt new file mode 100644 index 000000000..66c743761 --- /dev/null +++ b/_sources/Understand/numerical_techniques.rst.txt @@ -0,0 +1,15 @@ + +Advanced numerical techniques +============================= + +In specific situations, advanced techniques may help reduce the simulation +run time. + +.. toctree:: + :maxdepth: 1 + + azimuthal_modes_decomposition + laser_envelope + particle_merging + particle_injector + relativistic_fields_initialization diff --git a/_sources/Understand/parallelization.rst.txt b/_sources/Understand/parallelization.rst.txt new file mode 100644 index 000000000..f4f4efa0b --- /dev/null +++ b/_sources/Understand/parallelization.rst.txt @@ -0,0 +1,250 @@ +Parallelization basics +---------------------- + +For high performances, :program:`Smilei` uses parallel computing, +and it is important to understand the basics of this technology. Parallel simply +means that many processors can run the simulation at the same time, but there is +much more than that. + +---- + +Nodes, cores, processes and threads +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. warning:: + + The terminology of *nodes, cores, processes and threads* is not universal. + Depending on the computer, software (etc.), they can have various meanings. + Typical examples: *socket* instead of *node*; *cpu* instead of *core*; + *task* instead of *process*. + +Supercomputers have complex architectures, mainly due to their processors +capability to **work together on the same memory space**. More precisely, +the smallest computing units, called *cores*, +are grouped in *nodes*. All the cores in one node share the same memory space. +In other terms, the cores of the same node can operate on the same data, at the +same time; no need for sending the data back and forth. +This hardware architecture is summarized in :numref:`NodesCoresThreads`. + +.. _NodesCoresThreads: + +.. figure:: /_static/NodesCoresThreads.png + :width: 11cm + + Simplified super-computer architecture. + +This same figure shows how the software is structured. +A *thread* is essentially the sequence of instructions from the program. +It is executed by one core, and a given core can operate only one thread at a time +(if two threads are associated with one core, they are handled one after the other). +A *process* refers to a group of threads which are assigned to a single (shared) +memory space: one process will not handle the memory of another process. The +*process* provides the communication between its threads so that they can work +on their memory space without conflicts. + +The association between the software *threads* and the hardware *cores* can be more +complicated. :numref:`NodeWith2Processes` shows an example where two processes share the +same node. In this case, we illustrate the memory of this node as split in two parts because +the two processes cannot access to the same memory. + +.. _NodeWith2Processes: + +.. figure:: /_static/NodeWith2Processes.png + :width: 6cm + + An example where two processes share the same node. + +Note that many computer architectures have a different meaning for *nodes*. +Indeed, their *nodes* have a memory space that is already split into several +*sockets*. In this situation, one process is associated with one socket. + +---- + +Managing processes and threads +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Although two processes do not share their memory, they must sometimes synchronize their +advance in the execution of the program, or communicate data between each other. +For instance, to calculate the total energy in the simulation, they must communicate +their contribution to the others and compute the sum. +In :program:`Smilei`, these tasks are accomplished by the Message Passing Interface (MPI) protocol. + +At the thread level, the communications do not work in the same manner because threads +already share their data. However, they need synchronization and management to decide +which core handles which thread. In :program:`Smilei`, this is accomplished by the *OpenMP* protocol. + +An illustration of the roles of MPI and OpenMP is provided in :numref:`MPIandOpenMP` + +.. _MPIandOpenMP: + +.. figure:: /_static/MPIandOpenMP.png + :width: 9cm + + MPI handles process-to-process communications, while OpenMP manages threads in a given process. + +---- + +Decomposition of the whole domain +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Traditionally, PIC codes would +split the spatial grid into :math:`N` portions, where :math:`N` is the number +of cores. Each core would manage its own portion on a separate memory space, +and information is communicated between cores using the MPI protocol. +:program:`Smilei` proposes a different approach: +portions are much smaller so that each core handle many portions. + +Let us explain this difference in details. +:numref:`PatchDecomposition` gives an example of a grid containing 960 cells. +It is decomposed in :math:`4\times8 = 32` portions, called **patches**. +Each patch has :math:`5\times6` cells. +This patch size is actually reasonable for :program:`Smilei`, whereas +traditional PIC codes would have much larger portions. + +The issue is now to decide where these patches will be stored in the memory, +and to choose which cores should handle which patches. +Recall that all the cores handled by one process share the same memory: +we will refer to this memory as an *MPI patch collection*. +This means that one process manages one exclusive MPI patch collection. +:numref:`PatchDecomposition` shows an example with the 32 patches split +in 5 collections recognized by their different colors. +Note that these collections are connex, but not necessarily rectangular. + +.. _PatchDecomposition: + +.. figure:: /_static/PatchDecomposition.svg + :width: 600 + + Decomposition of a grid in *patches* and *MPI patch collections*. + +Each MPI patch collection is handled by all the threads of the process. For example, if there are +4 threads in the process that handles the patch collection colored in green, this means the +4 threads will handle 10 patches. The 4 threads will work in parallel, patch by patch, +until all patches are done. + +.. figure:: /_static/PatchDecompositionNodes.svg + :width: 700 + + Each process handles one collection of patches. Patches are treated one by one by + the available threads. + + +The great advantage of this scheme is that, inside one MPI patch collection, the threads do not +need to wait for their colleagues to go to the next patch; they can continue working on +the available patches, thus avoiding long waiting times. +This is a form of **local dynamic load balancing**. + +---- + +.. _LoadBalancingExplanation: + +Load balancing between MPI patch collections +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As we just explained, threads treat patches asynchronously, thus balancing their computational loads. +Indeed, some patches may have more particles than others and therefore represent a heavier load. +In the meantime, other threads can take care of several lighter patches. +Unfortunately, it may not be sufficient. +When one MPI patch collection holds more total load than the others, it will take a long +time to compute, while the other processes have already finished and wait for this one. +This can cause large delays. + +:program:`Smilei` has an algorithm able to reduce this imbalance by exchanging patches +from one MPI patch collection to another. A process that has too much load will give patches to +other processes in order to reduce the size of its MPI patch collection. This algorithm is based +on an ordering of the patches by a *Hilbert curve*, as drawn in +:numref:`PatchDecompositionHilbert`. One MPI patch collection contains only patches that contiguously +follow this curve. If this "portion" of the curve has too much load, it will send +some patches to the portions ahead or after, along the same curve. By repeating this +operation every now and then, we ensure that all regions manage an equitable computational load. + +.. _PatchDecompositionHilbert: + +.. figure:: /_static/PatchDecompositionHilbert.svg + :width: 400 + + The shape of the Hilbert curve which determines the patch order. + +---- + +Practical setup +^^^^^^^^^^^^^^^ + +The user must choose the number of processes and threads (see :doc:`/Use/run`). +Furthermore, they must define how the whole domain is split into patches +(see :py:data:`number_of_patches`). Here are a few rules and recommendations +to help deciding this splitting. + +* In each direction :math:`x`, :math:`y`, :math:`z`, + the **number of patches must be a power of 2**. + +* The minimum patch size depends on the order of the :py:data:`interpolation_order`. + For the default order 2, the minimum size is 6 cells in each direction. + +* **Have reasonably small patches**. + Small patches are beneficial to efficient load balancing and cache use, + but they increase the synchronization costs. + The optimal patch size depends strongly on the type of simulation. + Use small patches (down to 6x6x6 cells) if your simulation has small regions with many particles. + Use larger patches (typically 100x100 or 25x25x25 cells) otherwise. + +* For high performances, each process should own more patches than threads. + And even many more if possible. This means that **the total number of patches + should be larger than the total number of threads**, at the very least. + +* **Have only as many MPI processes as sockets** in order to optimize the memory distribution. + Less MPI processes is not possible because they cannot be split among separate memory spaces. + More MPI processes is not recommended because they are not as efficient as OpenMP threads. + +* **Have as many threads per process as cores per socket**. + If you have less threads than cores, you will not be using all your cores. + Use more threads than cores only if your architecture supports it well. + +* Use dynamic scheduling for the OpenMP protocol, by setting the environment variable:: + + export OMP_SCHEDULE=dynamic + + This affects only the particles treatment, which will be assigned to threads dynamically + (fields are always assigned statically). + +* **Take these recommendations with a pinch of salt**. Do your own tests and send us feedback! + +---- + +MPI patch collections forming rectangular areas +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For some plasma shapes, following the hilbert +curve (as described above) may not be efficient. +In Smilei, it is possible to use a classical grouping of patches in rectangles +or cubes. + +In the namelist:: + + Main( + ... + patch_arrangement = "linearized_XY", # 2D + patch_arrangement = "linearized_XYZ", # 3D + ... + ) + +Those linearized decompositions are oriented to contiguously store patches +along the innermost direction (**Z**, then **Y**, then **X**). +The storage order can be modified through following options :: + + Main( + ... + patch_arrangement = "linearized_YX", # 2D + patch_arrangement = "linearized_ZYX", # 3D + ... + ) + +These options has several consequences: + +* No more restrictions on the number of patches per direction. +* Load balancing is not available. +* To use the :ref:`DiagFields`, the number of patches per process must allow + a rectangular tessellation of the simulation box. For instance: + + * 8 x 8 patches on 4 MPI process : **ok**, each process own 2 x 8 patches slice. + * 6 x 8 patches on 4 MPI process : **not ok**, each process owns 12 patches which overlap 2 tiles. diff --git a/_sources/Understand/particle_injector.rst.txt b/_sources/Understand/particle_injector.rst.txt new file mode 100644 index 000000000..9f54cc5a8 --- /dev/null +++ b/_sources/Understand/particle_injector.rst.txt @@ -0,0 +1,54 @@ +Particle Injector +================================================================================ + +Particle injectors provide a continuous flow of fresh +macro-particles from the boundaries into the simulation domain. + +---- + +The method implemented in Smilei +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the PIC loop structure, the particle injection occurs +after current projection on the grid, particle sorting and synchronizations. +Injected macro-particles therefore do not contribute to the current and fields +of the current iteration but they are taken into account in the diagnostics. + +.. _fig_particle_injector: + +.. figure:: /_static/figures/particle_injector.png + :width: 100% + + +---- + +Recommendation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Although a single species may be injected, we recommend to inject both + positively and negatively charged species at the same time to ensure + a neutral plasma. To strengthen neutrality, species may be created at + the same positions. + +* If the particle momentum is drawn from a Maxwellian, we recommend to use a random + positionning instead of the regular one. + Regular positionning may induce numerical effects such as loss of charge and spurious field near the boundary. + The reason is explained in the following figure. + The regular positionning works when injecting a drifting cold plasma with a drift velocity + sufficiently high to let the particles entering the simulation domain. + +.. _fig_particle_injector_regular_random: + +.. figure:: /_static/figures/particle_injector_regular_random.png + :width: 100% + +---- + +Implementation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The particle injector algorithm is coded in the file +``Patch/VectorPatch.cpp`` in the function ``injectParticlesFromBoundaries``. + +The class ``ParticleInjector`` manages the injector's parameters and properties, +while new macro-particles are initialized using the class ``ParticleCreator``. diff --git a/_sources/Understand/particle_merging.rst.txt b/_sources/Understand/particle_merging.rst.txt new file mode 100644 index 000000000..909f1bf98 --- /dev/null +++ b/_sources/Understand/particle_merging.rst.txt @@ -0,0 +1,575 @@ +.. rst-class:: experimental + +Particle Merging +================================================================================ + + :red:`Be careful when using this module and read + carefully the documentation.` + + :red:`Note that the nomenclature might change` + +The ability to merge macro-particles can speed-up the code efficiency +and reduce the memory footprint in some specific simulation scenarii: + +* When macro-particles accumulate in a fraction of the simulation domain + hence strongly worsening the load imbalance (ex: Weibel collision shocks, + laser wakefield electron acceleration). +* When macro-particles are generated in a large quantity due to some + additional physical mechanisms (ionization, macro-photon emission, + QED pair production...) +* When macro-particles travel in large quantities outside interesting + physical regions. + +Smilei's merging method is inspired from that of M. Vranic +[Vranic2005]_ with some additions. + +Please refer to :ref:`that doc ` for +the definitions in the namelist file. + +.. _ref_understand_vranic_method: + +---- + +Understand the method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The method of M. Vranic, illustrated (in 2D) in +Fig. :numref:`fig_vranic_particle_merging`, consists in 3 main steps: + +1. Decompose macro-particles into groups according to their location so that + they have nearby positions. + In :program:`Smilei`, macro-particles are sorted by field cells, + even though, in Vranic *et al.*, the decomposition can be larger + than just one cell. + +2. Subdivide groups into sub-groups in momentum space so that macro-particles + share close kinetic properties. + +3. Merge macro-particles located in the same sub-group into 2 new + macro-particles, while conserving charge, energy and momentum. + +.. _fig_vranic_particle_merging: + +.. figure:: /_static/vranic_particle_merging.png + :width: 100% + + Basic description of M. Vranic merging method in 2D geometry. + +This method has several advantages: + +* it is relatively easy to understand and implement, +* it has a relatively low computational cost, +* it is efficient without impacting significantly the physical results. + +.. warning:: + + This assumes that the parameters are adequately tuned. + Otherwise, the macro-particle merging can affect the final simulation results. + +1. Momentum sub-groups +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +The momentum (:math:`\mathbf p`) space may be decomposed either in +cartesian (:math:`p_x`, :math:`p_y`, :math:`p_z`) +or spherical (:math:`p`, :math:`\theta`, :math:`\phi`) coordinates. + +In each cell, for each coordinate :math:`\alpha`: + +* we compute the overall limits in momentum space. +* This space is divided in :math:`N_{\alpha}` sub-groups (as prescribed by the + user) of length :math:`\Delta_{\alpha}`. + +.. _fig_vranic_momentum_discretization: + +.. figure:: /_static/vranic_momentum_discretization.png + :width: 100% + + Cartesian and spherical momentum discretizations, in 2D. + +The spherical components are related to the Cartesian momentum components by: + +.. math:: + :label: spherical_discretization + + p = \sqrt{ p_x^2 + p_y^2 + p_z^2 }\\ + \theta = \arctan{ \left( p_y / p_x \right)}\\ + \phi = \arcsin{\left( p_z / p \right)} + +.. _fig_spherical_coordinates: + +.. figure:: /_static/spherical_coordinates.png + :width: 50% + + Spherical coordinates used for the momentum cell discretization. + +Since macro-particle momentum components are defined in Cartesian geometry +by default, the spherical discretization induces small additional computation. +However, it makes the merging process more accurate. +Indeed, in the Cartesian discretization, the maximum angle between the momentum +directions of two macro-particles located in the same sub-group +depends on the sub-group. +For instance, in the cell adjacent to the origin :math:`p_x = p_y = p_z = 0`, +this angle equal up to :math:`\pi / 2` whatever the discretization. +The spherical geometry ensures that the merging accuracy depends +on the discretization and is similar for all momentum cells. +The overhead induced by the change of geometry is +a small fraction of the entire process. + +2. Merging algorithm for massive macro-particles +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +In step 3, for each sub-group containing more than 4 macro-particles, +the algorithm merges them into 2 macro-particles. +Let us denote by :math:`k` the macro-particles in a given sub-group +:math:`\mathrm{M}`, their weights by :math:`w_k`, their energies +by :math:`\varepsilon_k` and their momenta by :math:`\mathbf{p}_k`. +We start by computing total quantities: + +.. math:: + :label: total_quantities + + w_t = \sum_{k \in \mathrm{M}}{w_k}\\ + \varepsilon_t = \sum_{k \in \mathrm{M}}{w_k \varepsilon_k}\\ + \mathbf{p}_t = \sum_{k \in \mathrm{M}}{w_k \mathbf{p}_k}\\ + +In spherical geometry, the total angles are also defined: + +.. math:: + :label: total_angles + + \theta_t = \sum_{k \in \mathrm{M}}{w_k \theta_k}\\ + \phi_t = \sum_{k \in \mathrm{M}}{w_k \phi_k} + +Merging all the macro-particles into one cannot always conserve weight, +energy and momentum. Vranic *et al.* propose to merge into 2 macro-particles: + +.. math:: + :label: merged_particle_relation + + w_t = w_a + w_b \\ + \mathbf{p}_t = w_a \mathbf{p}_a + w_b \mathbf{p}_b \\ + \varepsilon_t = w_a \varepsilon_a + w_b \varepsilon_b + +The following energy-momentum relation has to be satisfied +for both macro-particles a and b: + +.. math:: + :label: energy_momentum_relation + + \varepsilon^2 = p^2 + 1 + +To simplify the problem, Vranic *et al* assume that merged macro-particles +have the same weight :math:`w_a = w_b = w_t / 2` +and same energy :math:`\varepsilon_a = \varepsilon_b = \varepsilon_t / w_t`. + +.. _fig_vranic_planar_merging: + +.. figure:: /_static/vranic_planar_merging.png + :width: 100% + + View of the plane made by vector :math:`\mathbf{d}` and :math:`\mathbf{p_t}`. + The corresponding Cartesian frame is given by :math:`(\mathbf{e_1}, \mathbf{e_2}, \mathbf{e_3})`. + +As illustrated in :numref:`fig_vranic_planar_merging`, it follows that: + +.. math:: + :label: new_momentum_relation + + \mathbf{p}_a + \mathbf{p}_b = \frac{2 \mathbf{p}_t}{w_t} \\ + \mathbf{p}_{a,\perp} = - \mathbf{p}_{b,\perp} \\ + \mathbf{p}_{a,\parallel} = \mathbf{p}_{b,\parallel} = \mathbf{p_t} / w_t + +We denote by :math:`\omega` the angle between +:math:`\mathbf{p_a}` and :math:`\mathbf{p_t}` so that: + +.. math:: + :label: angle_omega + + \cos{\omega} = \frac{\mathbf{p_t}}{w_t \mathbf{p_a}} + +We denote by :math:`\mathbf{d}` the coordinate vector of the sub-group +where the macro-particles are located. + +.. _fig_momentum_cell_vector: + +.. figure:: /_static/vranic_momentum_cell_vector.png + :width: 100% + + Sub-group coordinate vector in Cartesian and spherical geometries. + +The plane :math:`(\mathbf{e_1},\mathbf{e_2})` is the plane made by +the vectors :math:`\mathbf{p_t}` and :math:`\mathbf{d}`. +We choose that it contains :math:`\mathbf{p_a}` and :math:`\mathbf{p_b}` +so that we have only one possible solution. + +The vectors :math:`\mathbf{e_1}` and :math:`\mathbf{e_2}` are given by the +following formula in the PIC code's momentum frame: + +.. math:: + :label: planar_coordinates_e1 + + \mathbf{e_1} = \mathbf{p_t} / p_t + +.. math:: + :label: planar_coordinates_e3 + + \mathbf{e_3} = \frac{ \mathbf{d} \times \mathbf{e_1} }{d} +.. math:: + :label: planar_coordinates_e2 + + \mathbf{e_2} = \mathbf{e_1} \times \mathbf{e_3} + +Finally, the new macro-particle momentums are: + +.. math:: + :label: new_macroparticle_momentum + + \mathbf{p_a} = p_a \left( \cos{\left( \omega \right)} \mathbf{e_1} + \sin{\left(\omega\right)} \mathbf{e_2} \right) \\ + \mathbf{p_b} = p_b \left( \cos{\left( \omega \right)} \mathbf{e_1} - \sin{\left(\omega\right)} \mathbf{e_2} \right) + +.. _fig_3d_schematic: + +.. figure:: /_static/vranic_3d_schematics.png + :width: 100% + + 3D view of the different vectors involved in the merging method. + Generated by `this python script <_static/vranic_geometry.py>`_. + + +The new macro-particle positions are assigned the position of one of +the merged macro-particles. +We have tested to assign them randomly +or to the first macro-particles of the merged list and we did +not observe any difference. + +This algorithm does not work when the total momentum :math:`\mathbf{p}_t` +of the macro-particles to be merged is in the direction of :math:`\mathbf{d}`. +In this case :math:`|| \mathbf{e_3} || = 0` and the system cannot be solved. +In this specific case, the merging is not performed. + +3. Merging algorithm for macro-photons +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Macro-photons can be merged with the same algorithm, the only difference +being that the momentum norm is equal to the energy :math:`\varepsilon = p`. + +When the total momentum :math:`\mathbf{p}_t` is in the direction +of :math:`\mathbf{d}`, macro-photons can be merged into a single one, +contrary to the massive macro-particles case, +since :math:`\varepsilon_t = || \mathbf{p}_t ||`. +This specific situation is implemented in the code. + +.. _vranic_implementation: + +---- + +Implementation details +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Vranic merging method is implemented with both Cartesian +and the spherical discretizations in the directory ``src/Merging``. +It is considered as a particle operator and the merging algorithm is +managed with a factory (``MergingFactory.h``) as +any operator with multiple implementations. +The Cartesian implementation is done in the class ``MergingVranicCartesian`` +and the spherical one in ``MergingVranicSpherical``. + +For both methods, the implemented algorithm is very similar. + + For each cell: + + 1. Initialization of the sub-group discretization + 2. Computation of the direction vectors (:math:`\mathbf{d}`): + this step depends on the discretization and + can be efficiently vectorized. + 3. Computation of the sub-group indexes for each macro-particle. + Efficiently Vectorizable. + 4. Computation of the number of particles per sub-group. + Not vectorizable because of random memory accesses. + 5. Computation of the index of each sub-group in the + sorted array of particles (only the particle indexes are sorted). + Not vectorizable. + 6. Sorting of the macro-particles per sub-groups, the index + previously computed determines where + each sub-group starts. Not vectorizable. + + Then, for each sub-group: + + 1. Division of the macro-particles of the sub-groupinto + packets (size depends on the user parameters ``merge_min_packet_size`` + and ``merge_max_packet_size``) + 2. Merge of the packs using the previously described Vranic algorithm. + Partly vectorized. + 3. Creation of the merged macro-particles at the position + of the previous ones + 4. Tag of the macro-particles to be removed + + Then, once the merging finished for a given patch: + + 1. Compression of the macro-particle list (remove hole in arrays let + by removed and tagged particles). + By cleaning the particle vector at the end, we limit the computational + impact of this step. + +1. Cartesian sub-group discretization +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +How to discretize momentum space is in fact one of the most important points. +The user provides :math:`N_x`, :math:`N_y` and :math:`N_z` via the namelist, +but it may be slightly adjusted for algorithmic reasons: + +* If the momentum space is very narrow in one direction, only one + sub-group may be used. +* We force the origin (:math:`p = 0`) to delimit two sub-groups + so that a sub-group cannot contain two opposite momenta. + This may require an extra sub-group to fit the whole momentum space. + +2. Spherical sub-group discretization +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +The user provides :math:`N_p`, :math:`N_\theta` and :math:`N_\phi` +via the namelist, but adjustments may occur: + +* If the momentum space is very narrow in one direction, only one + sub-group may be used. +* The :math:`\Delta_{\alpha}` are modified by a factor 1.01 to + include the maximum boundary. + +3. Solid-angle correction in 3D +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +A rudimentary spherical discretization does not ensure that all sub-groups +span similar solid-angles, as they becomes arbitrarily small at the poles. + +.. _fig_spherical_discretization: + +.. figure:: /_static/spherical_discretization.png + :width: 100% + + Rudimentary spherical discretization (a) and the spherical discretization + with solid angle correction (b). This figure was generated with the + following `Python script <_static/scripts/vranic_spherical_discretization.py>`_. + +To obtain a solid angle approximately constant, the discretization in +:math:`\theta` is adjusted depending on the value of :math:`\phi`. +Denoting by :math:`\Omega_{0}` the solid angle at the smallest :math:`|\phi|`, +the sub-groups length :math:`\Delta_\theta` along :math:`\theta` varies to +satisfy :math:`\Omega = \sin{(\phi)}\Delta \theta \Delta \phi = \Omega_{0}`. + +.. _vranic_accumulation_effect: + +4. Accumulation effect +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +In one merging event, the strongest contribution comes from weightiest +macro-particles, which mostly come from a previous merging event instead +of the smaller macro-particles. +Some macro-particles may thus become uncontrollably heavy and dominate +others with little changes in their kinetic properties. +This effect may be particularly strong with large sub-groups and broad +momentum distributions, which are not well conserved. + +To illustrate this phenomenon, let us consider a 3D magnetic shower benchmark: +the domain is filled with an electron-positron plasma with all macro-particles +initialized using the same Lorentz factor :math:`\gamma = 8125` +in the same direction. +They propagate orthogonally to a constant and uniform magnetic field of +amplitude :math:`B = 1000 e/(m\omega)`, corresponding to a quantum parameter +of :math:`\chi = 20` for both electrons and positrons. +The input script of this simulation is available +`here <_static/magnetic_shower_3d_vranic_merging.py>`_. + +This accumulation effect creates peaks in the photon energy distribution +as shown in :numref:`fig_magnetic_shower_photon_energy_distribution` a). + +.. + + Need to explain the correction. + +.. _fig_magnetic_shower_photon_energy_distribution: + +.. figure:: /_static/figures/magnetic_shower_photon_energy_distribution.png + :width: 100% + + Photon energy distribution at the end of the simulation. + +.. _fig_magnetic_shower_photon_pxpy_distribution: + +.. figure:: /_static/figures/magnetic_shower_photon_pxpy_distribution.png + :width: 100% + + Photon px-py momentum distribution at the end of the simulation. + +**Warning:** the accumulation correction is not working with the logarithmic discretization. + +.. _vranic_log_scale: + +5. Logarithmic scale +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +For the **spherical discretization** only, the momentum norm :math:`p` +discretization may be chosen logarithmically scaled. +Due to the logarithm computation, this option is slightly slower than the +linear version. +Nonetheless, it can handle more appropriately broad momentum distributions. + +On the magnetic shower case presented in the previous section, +the logarithmic discretization reproduces nicely +the distribution obtained without merging. + +.. _magnetic_shower_gamma_distribution_log: + +.. figure:: /_static/figures/magnetic_shower_gamma_distribution_log.png + :width: 100% + + Photon energy distribution for the 3D magnetic shower benchmark + at the end of the simulation. + +**Warning:** the logarithmic discretization is subject to accumulation +oscillations but is not compatible with the accumulation correction. + +---- + +.. _vranic_simulation results: + +Simulation results +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. 3D QED cascade +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +In this section, the particle merging is tested with a 3D scenario +of electron-positron pair cascading. +Like the magnetic shower, a seed of electrons or positrons in a strong +electromagnetic field generates high-energy photons that, in turn, decay +into electron-positron pairs. +The difference is that the seed particles and the newly created ones may +gain some energy from the fields and participate to the generation of pairs. +The production of electron-positron pairs can therefore be maintained +(the `cascade`) as long as there is a source of energy. +In such a scenario, we can expect an exponential growth of the number of +particles leading to the creation of an electron-positron plasma. + +A plasma of electrons and positrons (the seed) is initially irradiated +by two counter-propagating lasers (strong field and source of energy), +chosen as circularly-polarized plane waves. + +.. _fig_qed_pair_cascade: + +.. figure:: /_static/figures/qed_pair_cascade.png + :width: 100% + + QED pair cascade configuration with two counter-propagating lasers. + +When they collide, the two waves form a steady plane wave of very strong +amplitude able to trigger strong QED effects. +Detailed simulation parameters are available +`in this namelist <_static/scripts/qed_pair_cascade.py>`_. + +An aggressive merging process is performed at every timestep +with a relatively sparse momentum-space discretization. +Note that, in 1D and 2D, it could use smaller sub-groups and +be performed more often as there would be more particles per cell. +The merging is applied on all species. +All cases are run during a maximum of 1000 seconds. + +As presented in :numref:`fig_qed_cascade_scalar`, the merging process +starts when the number of macro-particles is high enough: +:math:`\sim 10^5` macro-photons. +Between 10% and 20% more iterations are achieved, compared to the no +merging case. + +Each merging method does not exactly gives the same kinetic +energy and weight evolution. As we will see, the merging processes modify +the momentum distribution and influence the physical processes. + +.. _fig_qed_cascade_scalar: + +.. figure:: /_static/figures/QED_cascade_scalar.png + :width: 100% + + Effect of various merging configurations on the + number of macro-particles, their total weight, and their total + kinetic energy. + +We now compare energy spectra at time :math:`t = 39 \omega^{-1}` +(nearly when the no merging case saturates) +in :numref:`fig_qed_cascade_photon_gamma_spectrum`. +All merging methods significantly affect the energy distributions, +and oscillations are most visible in the photon distribution +due to the accumulation effect. + +.. _fig_qed_cascade_photon_gamma_spectrum: + +.. figure:: /_static/figures/QED_cascade_gamma_spectrum.png + :width: 100% + + Effect of various merging configurations on energy spectra. + +:numref:`fig_qed_cascade_photon_pxpy_spectrum` shows the +:math:`k_x-k_y` momentum distribution of the photons. +It clearly shows that, with their level of discretization, +none of the merging processes can adequately reproduce the +reference distribution. + +.. _fig_qed_cascade_photon_pxpy_spectrum: + +.. figure:: /_static/figures/QED_cascade_photon_px_py_distribution.png + :width: 100% + + :math:`k_x-k_y` photon momentum distributions at simulation + time :math:`t = 39.5 \omega^{-1}` + for the various merging configurations. + +:numref:`fig_qed_cascade_electron_pxpy_spectrum` shows the +:math:`p_x-p_y` momentum distribution of the electrons. + +.. _fig_qed_cascade_electron_pxpy_spectrum: + +.. figure:: /_static/figures/QED_cascade_electron_px_py_distribution.png + :width: 100% + + :math:`p_x-p_y` electron momentum distributions at simulation + time :math:`t = 39.5 \omega^{-1}` + for the various merging configurations. + +To compare the merging methods in term of performance, +:numref:`fig_qed_cascade_iteration_time` shows the CPU time necessary +to compute a numerical timestep as a function of time. +The linear spherical discretization is the fastest method because +the solid angle correction reduces the number of sub-groups. +The logarithmic spherical discretization has the same advantage +but it is slowed down by the computation of logarithms, and, in the end, +similar to the original cartesian method described in [Vranic2005]_. + + +.. _fig_qed_cascade_iteration_time: + +.. figure:: /_static/figures/QED_cascade_iteration_time.png + :width: 100% + + Computation time per iteration as a function of time. + +The following video illustrates the simulation benchmark +in the case of a logarithmic spherical discretization. +Specifically, it shows the time evolution of the electron, the positron +and the photon densities in the plane *x-y*, integrating over *z*. +It shows and exponential growth of photons and massive particles +happening first in the *y-z* plane near the center of the domain +then expanding longitudinally. + +.. _video_qed_cascade: + +.. raw:: html + + + +-------------------------------------------------------------------------------- + +References +^^^^^^^^^^ + +.. [Vranic2005] `M. Vranic et al., CPC, 191 65-73 (2015) `_ diff --git a/_sources/Understand/performances.rst.txt b/_sources/Understand/performances.rst.txt new file mode 100644 index 000000000..56a15df76 --- /dev/null +++ b/_sources/Understand/performances.rst.txt @@ -0,0 +1,17 @@ +Parallelization & optimization +============================== + +To reach high performances on supercomputers, several techniques have +been developed in Smilei. +While a good understanding of :doc:`parallelization ` is mandatory +to run a meaningful PIC simulation for any supercomputer user, other advanced +techniques, such as :doc:`vectorization`, are optional even though they can +provide important advantages. + +.. toctree:: + :maxdepth: 1 + + parallelization + SDMD + vectorization + GPU_offloading diff --git a/_sources/Understand/physics_modules.rst.txt b/_sources/Understand/physics_modules.rst.txt new file mode 100644 index 000000000..b4a76c2a4 --- /dev/null +++ b/_sources/Understand/physics_modules.rst.txt @@ -0,0 +1,18 @@ + +Physics modules +=============== + +The basic :doc:`algorithms` do not reproduce all the physics of a plasma. +For instance, the typical cell size is too coarse to model :doc:`collisions ` +so that a specific module is necessary. Similarly, atomic physics and +quantum processes require physics modules such as :doc:`ionization` and +:doc:`radiation_loss`. + + +.. toctree:: + :maxdepth: 1 + + collisions + ionization + radiation_loss + multiphoton_Breit_Wheeler \ No newline at end of file diff --git a/_sources/Understand/radiation_loss.rst.txt b/_sources/Understand/radiation_loss.rst.txt new file mode 100644 index 000000000..1125f39bb --- /dev/null +++ b/_sources/Understand/radiation_loss.rst.txt @@ -0,0 +1,866 @@ +.. _radiationReactionPage: + +High-energy photon emission & radiation reaction +------------------------------------------------ + +Accelerated charges emit electromagnetic radiation, and by doing so, lose some of their energy and momentum. +This process is particularly important for high-energy particles traveling in strong electromagnetic fields +where it can strongly influence the dynamics of the radiating charges, a process known as radiation reaction. + +In :program:`Smilei`, different modules treating high-energy photon emission & its back-reaction have been implemented. +We first give a short overview of the physics (and assumptions) underlying these modules, before giving more pratical +information on what each module does. We then give examples & benchmarks, while the last two sections give additional +information on the implementation of the various modules and their performances. + +.. warning:: + The processes discussed in this section bring into play a characteristic length + [the classical radius of the electron :math:`r_e = e^2/(4\pi \epsilon_0 m_e c^2)` in classical electrodynamics (CED) + or the standard Compton wavelength :math:`\lambda_C=\hbar/(m_e c)` in quantum electrodynamics (QED)]. + As a result, a simulation will require the user to define the absolute scale of the system by defining + the ``reference_angular_frequency_SI`` parameter (see :doc:`units` for more details). + + Also note that, unless specified otherwise, SI units are used throughout this section, and we use standard notations + with :math:`m_e`, :math:`e`, :math:`c` and :math:`\hbar` the electron mass, elementary charge, speed of light + and reduced Planck constant, respectively, and :math:`\epsilon_0` the permittivity of vacuum. + +-------------------------------------------------------------------------------- + +Inverse Compton scattering +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This paragraph describes the physical model and assumptions behind the different modules +for high-energy photon emission & radiation reaction that have been implemented in :program:`Smilei`. +The presentation is based on the work [Niel2018a]_. + +Assumptions +""""""""""" + +All the modules developed so far in :program:`Smilei` assume that: + +- the radiating particles (either electrons or positrons) are ultra-relativistic (their Lorentz factor :math:`\gamma \gg 1`), + hence radiation is emitted in the direction given by the radiating particle velocity, +- the electromagnetic field varies slowly over the formation time of the emitted photon, which requires + relativistic field strengths [i.e., the field vector potential is :math:`e\vert A^{\mu}\vert/(mc^2) \gg 1`], + and allows to use quasi-static models for high-energy photon emission (*locally-constant cross-field approximation*), +- the electromagnetic fields are small with respect to the critical field of Quantum Electrodynamics (QED), + more precisely both field invariants :math:`\sqrt{c^2{\bf B}^2-{\bf E}^2}` and :math:`\sqrt{c{\bf B}\cdot{\bf E}}` are small with + respect to the Schwinger field :math:`E_s = m^2 c^3 / (\hbar e) \simeq 1.3 \times 10^{18}\ \mathrm{V/m}`, +- all (real) particles radiate independently of their neighbors (incoherent emission), which requires the emitted radiation + wavelength to be much shorter than the typical distance between (real) particles :math:`\propto n_e^{-1/3}`. + +Rate of photon emission and associated quantities +""""""""""""""""""""""""""""""""""""""""""""""""" + +Under these assumptions, high-energy photon emission reduces to the incoherent process of +**nonlinear inverse Compton scattering**. +The corresponding rate of high-energy photon emission is given by [Ritus1985]_: + +.. math:: + :label: photonProductionRate + + \frac{d^2 N_{\gamma}}{d\tau d\chi_{\gamma}} = \frac{2}{3}\frac{\alpha^2}{\tau_e}\,\frac{S(\chi,\chi_{\gamma}/\chi)}{\chi_{\gamma}} + +with :math:`\tau_e = r_e/c` the time for light to cross the classical radius of the electron, +and :math:`\alpha` the fine-structure constant. +This rate depends on two Lorentz invariants, the *electron quantum parameter*: + +.. math:: + :label: particleQuantumParameter + + \chi = \frac{\gamma}{E_s} \sqrt{ \left({\bf E} + {\bf v} \times {\bf B}\right)^2 - ({\bf v }\cdot{\bf E})^2/c^2 } + +and the *photon quantum parameter* (at the time of photon emission): + +.. math:: + :label: photonQuantumParameter2 + + \chi_{\gamma} = \frac{\gamma_{\gamma}}{E_s} \sqrt{ \left({\bf E} + {\bf c} \times {\bf B}\right)^2 - ({\bf c }\cdot{\bf E})^2/c^2 } + +where :math:`\gamma = \varepsilon / (m_e c^2)` and :math:`\gamma_{\gamma} = \varepsilon_{\gamma} / (m_e c^2)` are +the normalized energies of the radiating particle and emitted photon, respectively, and :math:`{\bf v}` and +:math:`{\bf c}` their respective velocities. + +Note that considering ultra-relativistic (radiating) particles, both parameters are related by: + +.. math:: + :label: xi_definition + + \xi = \frac{\chi_{\gamma}}{\chi} = \frac{\gamma_{\gamma}}{\gamma}\,. + +In the photon production rate Eq. :eq:`photonProductionRate` appears the quantum emissivity: + +.. math:: + :label: particleQuantumEmissivity + + S(\chi,\xi) = \frac{\sqrt{3}}{2\pi}\,\xi\,\left[\int_{\nu}^{+\infty} {\rm K}_{5/3}(y) dy + + \frac{\xi^2}{1-\xi}\,{\rm K}_{2/3}(\nu)\right]\,, + +with :math:`\nu = 2\xi/[3\chi(1-\xi)]`. + +Finally, the *instantaneous radiated power energy-spectrum* reads: + +.. math:: + :label: radiatedPowerSpectrum + + \frac{dP_{\rm inst}}{d\gamma_{\gamma}} = P_{\alpha}\,\gamma^{-1}\,S(\chi,\chi_{\gamma}/\chi)\,, + +with :math:`P_{\alpha}=2\alpha^2 m_e c^2/(3\tau_e)`, and the *instantaneous radiated power*: + +.. math:: + :label: radiatedPower + + P_{\rm inst} = P_{\alpha}\,\chi^2\,g(\chi)\,, + +with :math:`g(\chi)` the so-called *quantum correction*: + +.. math:: + :label: g + + g(\chi) = \frac{9 \sqrt{3} }{8 \pi} \int_0^{+\infty}{d\nu + \left[ \frac{2\nu^2 }{\left( 2 + 3 \nu \chi \right) ^2}K_{5/3}(\nu) + + \frac{4 \nu \left( 3 \nu \chi\right)^2 }{\left( 2 + 3 \nu \chi \right)^4}K_{2/3}(\nu) \right]}\,. + + +Regimes of radiation reaction +""""""""""""""""""""""""""""" + +Knowing exactly which model of radiation reaction is best to describe a given situation is not always easy, and the domain of application +of each model is still discussed in the recent literature (again see [Niel2018a]_ for more details). +However, the typical value of the electron quantum parameter :math:`\chi` in a simulation can be used as a way to +assess which model is most suitable. +We adopt this simple (yet sometimes not completely satisfactory) point of view below to describe the three main approaches +used in :program:`Smilei` to account for high-energy photon emission and its back-reaction on the electron dynamics. + +For arbitrary values of the electron quantum parameter :math:`\chi` (but mandatory in the quantum regime :math:`\chi \gtrsim 1`) +****************************************************************************************************************************************************** + +The model of high-energy photon emission described above is generic, and applies for any value of +the electron quantum parameter :math:`\chi` (of course as long as the assumptions listed above hold!). +In particular, it gives a correct description of high-energy photon emission and its back-reaction on +the particle (electron or positron) dynamics in the quantum regime :math:`\chi \gtrsim 1`. +In this regime, photons with energies of the order of the energy of the emitting particle can be produced. +As a result, the particle energy/velocity can exhibit abrupt jumps, and the stochastic nature of high-energy +photon emission is important. +Under such conditions, a Monte-Carlo description of discrete high-energy photon emission (and their feedback +on the radiating particle dynamics) is usually used (see [Timokhin2010]_, [Elkina2011]_, [Duclous2011]_, and [Lobet2013]_). +More details on the implementation are given below. + +In :program:`Smilei` the corresponding description is accessible for an electron species by defining +``radiation_model = "Monte-Carlo"`` or ``"MC"`` in the ``Species()`` block (see :doc:`/Use/namelist` for details). + + +Intermediate, moderately quantum regime :math:`\chi \lesssim 1` +***************************************************************** + +In the intermediate regime (:math:`\chi \lesssim 1`), the energy of the emitted photons remains +small with respect to that of the emitting electrons. Yet, the stochastic nature of photon emission cannot be neglected. +The electron dynamics can then be described by a stochastic differential equation derived from a Fokker-Planck +expansion of the full quantum (Monte-Carlo) model described above [Niel2018a]_. + +In particular, the change in electron momentum during a time interval :math:`dt` reads: + +.. math:: + :label: NielStochasticForce + + d{\bf p} = {\bf F}_{\rm L} dt + {\bf F}_{\rm rad} dt + mc^2 \sqrt{R\left( \chi, \gamma \right)} dW + \mathbf{u} / \left( \mathbf{u}^2 c\right) + +where we recognize 3 terms: + +* the Lorentz force :math:`{\bf F}_{\rm L} = \pm e ({\bf E} + {\bf v}\times{\bf B})` (with :math:`\pm e` the particle's charge), + +* a deterministic force term :math:`{\bf F}_{\rm rad}` (see below for its expression), so-called *drift term*, which is nothing but the leading term + of the Landau-Lifshitz radiation reaction force with the quantum correction :math:`g(\chi)`, + +* a stochastic force term, so-called *diffusion term*, proportional to :math:`dW`, a Wiener process of variance :math:`dt`. + This last term allows to account for the stochastic nature of high-energy photon emission, and it depends on functions + which are derived from the stochastic model of radiation emission presented above: + + .. math:: + :label: NielR + + R\left( \chi, \gamma \right) = \frac{2}{3} \frac{\alpha^2}{\tau_e} \gamma + h \left( \chi \right) + + and + + .. math:: + :label: Nielh + + h \left( \chi \right) = \frac{9 \sqrt{3}}{4 \pi} \int_0^{+\infty}{d\nu + \left[ \frac{2\chi^3 \nu^3}{\left( 2 + 3\nu\chi \right)^3} K_{5/3}(\nu) + + \frac{54 \chi^5 \nu^4}{\left( 2 + 3 \nu \chi \right)^5} K_{2/3}(\nu) \right]} + +In :program:`Smilei` the corresponding description is accessible for an electron species by defining +``radiation_model = "Niel"`` in the ``Species()`` block (see :doc:`/Use/namelist` for details). + + +The classical regime :math:`\chi \ll 1` +************************************************** + +Quantum electrodynamics (QED) effects are negligible (classical regime) when :math:`\chi \ll 1`. +Radiation reaction follows from the cummulative effect of incoherent photon emission. +It can be treated as a continuous friction force acting on the particles. +Several models for the radiation friction force have been proposed (see [DiPiazza2012]_). +The ones used in :program:`Smilei` are based on the Landau-Lifshitz (LL) model [Landau1947]_ +approximated for high Lorentz factors (:math:`\gamma \gg 1`). +Indeed, as shown in [Niel2018a]_, the LL force with the quantum correction :math:`g(\chi)` +naturaly emerges from the full quantum description given above. +This can easily be seen from Eq. :eq:`NielStochasticForce`, in which the *diffusion term* vanishes +in the limit :math:`\chi \ll 1` so that one obtains for the deterministic equation of motion for the electron: + +.. math:: + + \frac{d{\bf p}}{dt} = {\bf F}_{\rm L} + {\bf F}_{\rm rad} + +with + +.. math:: + :label: correctedLLforce + + {\bf F}_{\rm rad} = -P_{\alpha} \chi^2 g(\chi)\,\mathbf{u} / \left( \mathbf{u}^2 c\right) + +In :program:`Smilei` the corresponding description is accessible for an electron species by defining +``radiation_model = "corrected-Landau-Lifshitz"`` or ``"cLL"`` in the ``Species()`` block (see :doc:`/Use/namelist` for details). + +.. note:: + + * for :math:`\chi \rightarrow 0`, the quantum correction :math:`g(\chi) \rightarrow 1`, + :math:`P_{\rm inst} \rightarrow P_{\alpha}\,\chi^2` (which is the Larmor power) + and :math:`dP_{\rm inst}/d\gamma_{\gamma}` [Eq. :eq:`radiatedPowerSpectrum`] reduces to the classical + spectrum of *synchrotron* radiation. + * the purely classical (not quantum-corrected) LL radiation friction is also accessible in :program:`Smilei`, + using ``radiation_model = "Landau-Lifshitz"`` or ``"LL"`` in the ``Species()``. + + +Choosing the good model for your simulation +******************************************* + +The next sections describe in more details the different models implemented in :program:`Smilei`. +For the user convenience, :numref:`radiationRegimes` briefly summarises the models and how to choose +the most appropriate radiation reaction model for your simulation. + +.. Note:: + + In [Niel2018a]_, an extensive study of the links between the different models for radiation reaction and their domain + of applicability is presented. The following table is mainly informative. + +.. _radiationRegimes: + +.. table:: Radiation model regimes + + +-------------------------------------+--------------------------+------------------------------------------------+---------------------------+ + | Regime | :math:`\chi` value | Description | Models | + +=====================================+==========================+================================================+===========================+ + | Classical radiation emission | :math:`\chi \sim 10^{-3}`| :math:`\gamma_\gamma \ll \gamma`, | Landau-Lifshitz | + | | | radiated energy overestimated for | | + | | | :math:`\chi > 10^{-2}` | | + +-------------------------------------+--------------------------+------------------------------------------------+---------------------------+ + | Semi-classical radiation emission | :math:`\chi \sim 10^{-2}`| :math:`\gamma_\gamma \ll \gamma`, | Corrected Landau-Lifshitz | + | | | no stochastic effects | | + +-------------------------------------+--------------------------+------------------------------------------------+---------------------------+ + | Weak quantum regime | :math:`\chi \sim 10^{-1}`| :math:`\gamma_\gamma < \gamma`, | Stochastic model of | + | | | :math:`\gamma_\gamma \gg mc^2` | Niel `et al` / Monte-Carlo| + +-------------------------------------+--------------------------+------------------------------------------------+---------------------------+ + | Quantum regime | :math:`\chi \sim 1` | :math:`\gamma_\gamma \gtrsim \gamma` | Monte-Carlo | + | | | | | + +-------------------------------------+--------------------------+------------------------------------------------+---------------------------+ + + +-------------------------------------------------------------------------------- + +Implementation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +C++ classes for the radiation processes are located in the directory ``src/Radiation``. +In :program:`Smilei`, the radiative processes are not incorporated in the pusher in +order to preserve the vector performance of the pusher when using non-vectorizable +radiation models such as the Monte-Carlo process. + +Description of the files: + +* Class ``RadiationTable``: useful tools, parameters and the tables. +* Class ``Radiation``: the generic class from which will inherit specific + classes for each model. +* Class ``RadiationFactory``: manages the choice of the radiation model among the following. +* Class ``RadiationLandauLifshitz``: classical Landau-Lifshitz radiation process. +* Class ``RadiationCorrLandauLifshitz``: corrected Landau-Lifshitz radiation process. +* Class ``RadiationNiel``: stochastic diffusive model of [Niel2018a]_. +* Class ``RadiationMonteCarlo``: Monte-Carlo model. + +As explained below, many functions have been tabulated because of +the cost of their computation for each particle. +Tables can be generated by the external tool +:program:`smilei_tables`. +More information can be found in :doc:`/Use/tables`. + +Continuous, Landau-Lifshitz-like models +""""""""""""""""""""""""""""""""""""""" + +Two models of continuous radiation friction force are available in :program:`Smilei`: +(i) the approximation for high-math:`\gamma` of the Landau-Lifshitz equation (taking :math:`g(\chi)=1` in Eq. :eq:`correctedLLforce`), +and (ii) the corrected Landau-Lifshitz equation Eq. :eq:`correctedLLforce`. +The modelS are accessible in the species configuration under the name +``Landau-Lifshitz`` (equiv. ``LL``) and ``corrected-Landau-Lifshitz`` (equiv. 'cLL'). + +The implementation of these continuous radiation friction forces consists in a modification of the particle pusher, +and follows the simple splitting technique proposed in [Tamburini2010]_. +Note that for the quantum correction, we use a fit of the function +:math:`g(\chi)` given by + +.. math:: + :label: quantumCorrFit + + g \left( \chi_{\pm} \right) = \left[ 1 + 4.8 \left( 1 + \chi_{\pm} \right) + \log \left( 1 + 1.7 \chi_{\pm} \right) + 2.44 \chi_{\pm}^2 \right]^{-2/3} + +This fit enables to keep the vectorization of the particle loop. + +Fokker-Planck stochastic model of Niel *et al*. +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Equation :eq:`NielStochasticForce` is implemented in :program:`Smilei` using +a simple explicit scheme, see [Niel2018a]_ Sec. VI.B for more details. +This stochastic diffusive model is accessible in the species configuration +under the name ``Niel``. + +The direct computation of Eq. :eq:`Nielh` during the emission process is too expensive. +For performance issues, :program:`Smilei` uses tabulated values or fit functions. + +Concerning the tabulation, :program:`Smilei` first checks the presence of +an external table at the specified path. +If the latter does not exist at the specified path, the table is computed at initialization. +The new table is outputed on disk in the current simulation directory. +It is recommended to use existing external tables to save simulation time. +The computation of *h* during the simulation can slow down the initialization +and represents an important part of the total simulation. +The parameters such as the :math:`\chi` range and the discretization can be +given in :ref:`RadiationReaction `. + +Polynomial fits of this integral can be obtained in log-log +or log10-log10 domain. However, high accuracy requires high-order polynomials +(order 20 for an accuracy around :math:`10^{-10}` for instance). +In :program:`Smilei`, an order 5 (see Eq. :eq:`fit5`) and 10 polynomial fits are implemented. +They are valid for quantum parameters :math:`\chi` between :math:`10^{-3}` and 10. + +.. math:: + :label: fit5 + + h_{o5}(\chi) = \exp{ \left(1.399937206900322 \times 10^{-4} \log(\chi)^5 \\ + + 3.123718241260330 \times 10^{-3} \log{(\chi)}^4 \\ + + 1.096559086628964 \times 10^{-2} \log(\chi)^3 \\ + -1.733977278199592 \times 10^{-1} \log(\chi)^2 \\ + + 1.492675770100125 \log(\chi) \\ + -2.748991631516466 \right) } + +An additional fit from [Ridgers2017]_ has been implemented and the formula +is given in Eq. :eq:`h_fit_ridgers`. + +.. math:: + :label: h_fit_ridgers + + h_{Ridgers}(\chi) = \chi^3 \frac{165}{48 \sqrt{3}} \left(1. + (1. + 4.528 \chi) \log(1.+12.29 \chi) + 4.632 \chi^2 \right)^{-7/6} + + + +Monte-Carlo full-quantum model +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +The Monte-Carlo treatment of the emission is more complex process than +the previous ones and can be divided into several steps ([Duclous2011]_, +[Lobet2013]_, [Lobet2015]_): + +1. An incremental optical depth :math:`\tau`, initially set to 0, is assigned to the particle. + Emission occurs when it reaches the final optical depth :math:`\tau_f` + sampled from :math:`\tau_f = -\log{\xi}` where :math:`\xi` is a random number in :math:`\left]0,1\right]`. + +2. The optical depth :math:`\tau` evolves according to the field and particle + energy variations following this integral: + + .. math:: + :label: MCDtauDt + + \frac{d\tau}{dt} = \int_0^{\chi_{\pm}}{ \frac{d^2N}{d\chi dt} d\chi } + = \frac{2}{3} \frac{\alpha^2}{\tau_e} \int_0^{\chi_{\pm}}{ \frac{S(\chi_\pm, \chi/\chi_{\pm})}{\chi} d\chi } + \equiv \frac{2}{3} \frac{\alpha^2}{\tau_e} K (\chi_\pm) + + that simply is the production rate of photons + (computed from Eq. :eq:`photonProductionRate`). + Here, :math:`\chi_{\pm}` is the emitting electron (or positron) quantum parameter and + :math:`\chi` the integration variable. + +3. The emitted photon's quantum parameter :math:`\chi_{\gamma}` is computed by + inverting the cumulative distribution function: + + .. math:: + :label: CumulativeDistr + + \xi = P(\chi_\pm,\chi_{\gamma}) = \frac{\displaystyle{\int_0^{\chi_\gamma}{ d\chi S(\chi_\pm, \chi/\chi_{\pm}) / \chi + }}}{\displaystyle{\int_0^{\chi_\pm}{d\chi S(\chi_\pm, \chi/\chi_{\pm}) / \chi }}}. + + The inversion of :math:`\xi = P(\chi_\pm,\chi_{\gamma})` is done after drawing + a second random number + :math:`\phi \in \left[ 0,1\right]` to find :math:`\chi_{\gamma}` by solving : + + .. math:: + :label: inverse_xi + + \xi^{-1} = P^{-1}(\chi_\pm, \chi_{\gamma}) = \phi + +4. The energy of the emitted photon is then computed: + :math:`\varepsilon_\gamma = mc^2 \gamma_\gamma = + mc^2 \gamma_\pm \chi_\gamma / \chi_\pm`. + +5. The particle momentum is then updated using momentum conservation and + considering forward emission (valid when :math:`\gamma_\pm \gg 1`). + + .. math:: + :label: momentumUpdate + + d{\bf p} = - \frac{\varepsilon_\gamma}{c} \frac{\mathbf{p_\pm}}{\| \mathbf{p_\pm} \|} + + The resulting force follows from the recoil induced by the photon emission. + Radiation reaction is therefore a discrete process. + Note that momentum conservation does not exactly conserve energy. + It can be shown that the error :math:`\epsilon` tends to 0 when the particle + energy tends to infinity [Lobet2015]_ and that the error is small when + :math:`\varepsilon_\pm \gg 1` and :math:`\varepsilon_\gamma \ll \varepsilon_\pm`. + Between emission events, the electron dynamics is still governed by the + Lorentz force. + + If the photon is emitted as a macro-photon, its initial position is the same as + for the emitting particle. The (numerical) weight is also conserved. + + +The computation of Eq. :eq:`MCDtauDt` would be too expensive for every single +particles. +Instead, the integral of the function :math:`S(\chi_\pm, \chi/\chi_{\pm}) / \chi` +also referred to as :math:`K(\chi_\pm)` is tabulated. + +This table is named ``integfochi`` +Related parameters are stored in the structure ``integfochi`` in the code. + +Similarly, Eq. :eq:`CumulativeDistr` is tabulated (named ``xi`` in the code). +The only difference is that a minimum photon quantum parameter +:math:`\chi_{\gamma,\min}` is computed before for the integration so that: + +.. math:: + :label: chiMin + + \frac{\displaystyle{\int_{0}^{\chi_{\gamma,\min}}{d\chi S(\chi_\pm, \chi/\chi_{\pm}) / \chi}}} + {\displaystyle{\int_0^{\chi_\pm}{d\chi S(\chi_\pm, \chi/\chi_{\pm}) / \chi}}} < \epsilon + +This enables to find a lower bound to the :math:`\chi_\gamma` range +(discretization in the log domain) so that the +remaining part is negligible in term of radiated energy. +The parameter :math:`\epsilon` is called ``xi_threshold`` in +:ref:`RadiationReaction ` and the tool :program:`smilei_tables` (:doc:`/Use/tables`.). + +The Monte-Carlo model is accessible in the species configuration +under the name ``Monte-Carlo`` or ``mc``. + +---- + +Benchmarks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Radiation emission by ultra-relativistic electrons in a constant magnetic field +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +This benchmark closely follows ``benchmark/tst1d_18_radiation_spectrum_chi0.1.py``. +It considers a bunch of electrons with initial Lorentz factor :math:`\gamma=10^3` radiating in a constant magnetic field. +The magnetic field is perpendicular to the initial electrons' velocity, +and its strength is adjusted so that the electron quantum parameter is either :math:`\chi=0.1` or :math:`\chi=1`. +In both cases, the simulation is run over a single gyration time of the electron (computed neglecting radiation losses), +and 5 electron species are considered (one neglecting all radiation losses, the other four each corresponding +to a different radiation model: ``LL``, ``cLL``, ``FP`` and ``MC``). + +In this benchmark, we focus on the differences obtained on the energy spectrum of the emitted radiation +considering different models of radiation reaction. +When the Monte-Carlo model is used, the emitted radiation spectrum is obtained by applying a ``ParticleBinning`` diagnostic +on the photon species. +When other models are considered, the emitted radiation spectrum is reconstructed using a ``RadiationSpectrum`` diagnostic, +as discussed in :ref:`DiagRadiationSpectrum`, and given by Eq. :eq:`radiatedPowerSpectrum` (see also [Niel2018b]_). +:numref:`radSpectra` presents for both values of the initial quantum parameter :math:`\chi=0.1` and :math:`\chi=1` +the resulting power spectra obtained from the different models, focusing of the (continuous) corrected-Landau-Lifshitz (``cLL``), +(stochastic) Fokker-Planck (``Niel``) and Monte-Carlo (``MC``) models. +At :math:`\chi=0.1`, all three descriptions give the same results, which is consistent with the idea that at small quantum parameters, +the three descriptions are equivalent. +In contrast, for :math:`\chi=1`, the stochastic nature of high-energy photon emission (not accounted for in the continuous `cLL` model) +plays an important role on the electron dynamics, and in turns on the photon emission. Hence only the two stochastic model give a +satisfactory description of the photon emitted spectra. +More details on the impact of the model on both the electron and photon distribution are given in [Niel2018b]_. + +.. _radSpectra: + +.. figure:: /_static/figSpectra_LR.png + :width: 15cm + + Energy distribution (power spectrum) of the photon emitted by an ultra-relativistic electron bunch in a constant magnetic field. + (left) for :math:`\chi=0.1`, (right) for :math:`\chi=1`. + +Counter-propagating plane wave, 1D +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +In the benchmark ``benchmark/tst1d_09_rad_electron_laser_collision.py``, +a GeV electron bunch is initialized near the right +domain boundary and propagates towards the left boundary from which a plane +wave is injected. The laser has an amplitude of :math:`a_0 = 270` +corresponding to an intensity of :math:`10^{23}\ \mathrm{Wcm^{-2}}` at +:math:`\lambda = 1\ \mathrm{\mu m}`. +The laser has a Gaussian profile of full-with at half maxium of +:math:`20 \pi \omega_r^{-1}` (10 laser periods). +The maximal quantum parameter :math:`\chi` +value reached during the simulation is around 0.5. + +.. _rad_counter_prop_scalar: + +.. figure:: /_static/rad_counter_prop_scalar.png + :width: 15cm + + Kinetic, radiated and total energy plotted respectively with solid, dashed and dotted lines for + the :blue:`Monte-Carlo` (**MC**), :orange:`Niel` (**Niel**), + :green:`corrected Landau-Lifshitz` (**CLL**) and the :red:`Landau-Lifshitz` (**LL**) models. + +:numref:`rad_counter_prop_scalar` shows that the Monte-Carlo, the Niel and +the corrected Landau-Lifshitz models exhibit very similar +results in term of the total radiated and kinetic energy evolution with a final +radiation rate of 80% the initial kinetic energy. The relative error on the +total energy is small (:math:`\sim 3\times10^{-3}`). +As expected, the Landau-Lifshitz model overestimates the radiated energy +because the interaction happens mainly in the quantum regime. + +.. _rad_counter_prop_track: + +.. figure:: /_static/rad_counter_prop_track.png + :width: 18cm + + Evolution of the normalized kinetic energy + :math:`\gamma - 1` of some selected electrons as a function of their position. + +:numref:`rad_counter_prop_track` shows that the Monte-Carlo and the Niel models +reproduce the stochastic nature of the trajectories as opposed to the +continuous approaches (corrected Landau-Lifshitz and Landau-Lifshitz). +In the latter, every particles initially located at the same position will +follow the same trajectories. +The stochastic nature of the emission for high :math:`\chi` values can +have consequences in term of final spatial and energy distributions. +Not shown here, the Niel stochastic model does not reproduce correctly the +moment of order 3 as explained in [Niel2018a]_. + +Synchrotron, 2D +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +A bunch of electrons of initial momentum :math:`p_{-,0}` +evolves in a constant magnetic field :math:`B` orthogonal +to their initial propagation direction. +In such a configuration, the electron bunch is supposed to rotate endlessly +with the same radius :math:`R = p_{-,0} /e B` without radiation energy loss. +Here, the magnetic field is so strong that the electrons +radiate their energy as in a synchrotron facility. +In this setup, each electron quantum parameter depends on their Lorentz +factors :math:`\gamma_{-}` according to +:math:`\chi_{-} = \gamma_{-} B /m_e E_s`. +The quantum parameter is maximum at the beginning of the interaction. +The strongest radiation loss are therefore observed at the beginning too. +As energy decreases, radiation loss becomes less and less important so that +the emission regime progressively move from the quantum to the classical regime. + + +Similar simulation configuration can be found in the benchmarks. +It corresponds to two different input files in the benchmark folder: + +* ``tst2d_08_synchrotron_chi1.py``: tests and compares the corrected + Landau-Lifshitz and the Monte-Carlo model for an initial :math:`\chi = 1`. +* ``tst2d_09_synchrotron_chi0.1.py``: tests and compares the corrected + Landau-Lifshitz and the Niel model for an initial :math:`\chi = 0.1`. + +In this section, we focus on the case with initial quantum parameter +:math:`\chi = 0.1`. +The magnetic field amplitude is :math:`B = 90 m \omega_r / e`. +The initial electron Lorentz factor is +:math:`\gamma_{-,0} = \varepsilon_{-,0}/mc^2 = 450`. +Electrons are initialized with a Maxwell-Juttner distribution of temperature +:math:`0.1 m_e c^2`. + +:numref:`synchrotron_scalar` shows the time evolution of the particle kinetic energy, +the radiated energy and the total energy. All radiation models provide +similar evolution of these integrated quantities. The relative error on the +total energy is between :math:`2 \times 10^{-9}` and :math:`3 \times 10^{-9}`. + +.. _synchrotron_scalar: + +.. figure:: /_static/synchrotron_scalar.png + :width: 15cm + + Kinetic, radiated and total energies plotted respectively with solid, dashed and dotted + lines for various models. + +The main difference between models can be understood by studying the +particle trajectories and phase spaces. For this purpose, the local kinetic energy spatial-distribution +at :math:`25 \omega_r^{-1}` is shown in +:numref:`synchrotron_x_y_gamma` for the different models. +With continuous radiation energy loss +(corrected Landau-Lifshitz case), each electron of the bunch rotates with a decreasing +radius but the bunch. +Each electron of similar initial energies have the same trajectories. +In the case of a cold bunch (null initial temperature), +the bunch would have kept its original shape. +The radiation with this model only acts as a cooling mechanism. +In the cases of the Niel and the Monte-Carlo radiation models, +stochastic effects come into play and lead the bunch to spread spatially. +Each individual electron of the bunch, even with similar initial energies, +have different trajectories depending on their emission history. +Stochastic effects are particularly strong at the beginning with the highest +:math:`\chi` values when the radiation +recoil is the most important. + +.. _synchrotron_x_y_gamma: + +.. figure:: /_static/synchrotron_x_y_gamma.png + :width: 18cm + + Average normalized kinetic energy at time :math:`25 \omega_r^{-1}` + for the simulations with the Monte-Carlo, the Niel + and the corrected Landau-Lifshitz (**CLL**) models. + +:numref:`synchrotron_t_gamma_ne` shows the time evolution of +the electron Lorentz factor distribution (normalized energy) for different +radiation models. +At the beginning, the distribution is extremely broad due to the Maxwell-Juttner parameters. +The average energy is well around :math:`\gamma_{-,0} = \varepsilon_{-,0}/mc^2 = 450` +with maximal energies above :math:`\gamma_{-} = 450`. + +In the case of a initially-cold electron beam, +stochastic effects would have lead the bunch to spread energetically +with the Monte-Carlo and the Niel stochastic models at the beginning of the simulation. +This effect is hidden since electron energy is already highly spread at the +beginning of the interaction. +This effect is the strongest when the quantum parameter is high in the quantum regime. + +In the Monte-Carlo case, some electrons have lost all their energy almost immediately +as shown by the lower part of the distribution below :math:`\gamma_{-} = 50` +after comparison with the Niel model. + +Then, as the particles cool down, the interaction enters the semi-classical +regime where energy jumps are smaller. +In the classical regime, radiation loss acts oppositely to the quantum regime. +It reduces the spread in energy and space. +In the Landau-Lifshitz case, this effect starts at the beginning even +in the quantum regime due to the nature of the model. +For a initially-cold electron bunch, there would not have been +energy spread at the beginning of the simulation. All electron would have lost +their energy in a similar fashion (superimposed behavior). +This model can be seen as the average behavior of the stochastic ones of +electron groups having the same initial energy. + +.. _synchrotron_t_gamma_ne: + +.. figure:: /_static/synchrotron_t_gamma_ne.png + :width: 18cm + + Time evolution of the electron energy distribution for the Monte-Carlo, the Niel + and the corrected Landau-Lifshitz (**CLL**) models. + +Thin foil, 2D +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +This case is not in the list of available benchmarks but we decided to present +these results here as an example of simulation study. +An extremely intense plane wave in 2D interacts with a thin, fully-ionized carbon foil. +The foil is located 4 µm from the left border (:math:`x_{min}`). +It starts with 1 µm of linear pre-plasma density, followed by +3 µm of uniform plasma of density 492 times critical. +The target is irradiated by a gaussian plane wave of peak intensity +:math:`a_0 = 270` (corresponding to :math:`10^{23}\ \mathrm{Wcm^{-2}}`) +and of FWHM duration 50 fs. +The domain has a discretization of 64 cells per µm in +both directions x and y, with 64 particles per cell. +The same simulation has been performed with the different radiation models. + +Electrons can be accelerated and injected in +the target along the density gradient through the combined action of +the transverse electric and the magnetic fields (*ponderomotive* effects). +In the relativistic regime and linear polarization, +this leads to the injection of bunches of hot electrons +every half laser period that contribute to heat the bulk. +When these electrons reach the rear surface, they start to expand in the vacuum, +and, being separated from the slow ion, create a longitudinal charge-separation field. +This field, along the surface normal, has two main effects: + +* It acts as a reflecting barrier for electrons of moderate energy (refluxing electrons). +* It accelerates ions located at the surface (target normal sheath acceleration, TNSA). + +At the front side, a charge separation cavity appears +between the electron layer pushed forward by the ponderomotive force and ions +left-behind that causes ions to be consequently accelerated. This +strong ion-acceleration mechanism +is known as the radiation pressure acceleration (RPA) or laser piston. + +Under the action of an extremely intense laser pulse, electrons accelerated at +the target front radiate. It is confirmed in :numref:`thin_foil_x_chi_ne` +showing the distribution of the quantum parameter :math:`\chi` along the x axis +for the Monte-Carlo, the Niel and the corrected Landau-Lifshitz (**CLL**) radiation models. +The maximum values can be seen at the front where the electrons +interact with the laser. Radiation occurs in the quantum regime +:math:`\chi > 0.1`. Note that there is a second peak for :math:`\chi` at the +rear where electrons interact with the target normal sheath field. +The radiation reaction can affect electron energy absorption and therefore the ion +acceleration mechanisms. + +.. _thin_foil_x_chi_ne: + +.. figure:: /_static/thin_foil_x_chi_ne.png + :width: 18cm + + :math:`x - \chi` electron distribution at time 47 fs for the Monte-Carlo, + the Niel and the corrected Landau-Lifshitz (**CLL**) model. + +The time evolutions of the electron kinetic energy, the carbon ion +kinetic energy, the radiated energy and the total +absorbed energy are shown in :numref:`thin_foil_scalar`. +The :green:`corrected-Landau-Lifshitz`, the :orange:`Niel` +and the :blue:`Monte-Carlo` models present very +similar behaviors. +The absorbed electron energy is only slightly lower in the Niel model. +This difference depends on the random seeds and the +simulation parameters. +The radiated energy represents around 14% of the total laser energy. +The :purple:`classical Landau-Lifshitz` model overestimates the radiated energy; +the energy absorbed by electrons and ions is therefore slightly lower. +In all cases, radiation reaction strongly impacts the overall particle energy absorption +showing a difference close to 20% with the :red:`non-radiative` run. + + +.. _thin_foil_scalar: + +.. figure:: /_static/thin_foil_scalar.png + :width: 18cm + + Time evolution of the electron kinetic energy (solid lines), the carbon ion + kinetic energy (dashed line), the radiated energy (dotted line) and the total + absorbed energy by particle and radiation (dotted-dashed lines), for various models. + +The differences between electron :math:`p_x` distributions are shown +in :numref:`thin_foil_x_px_ne`. Without radiation reaction, electrons refluxing +at the target front can travel farther in vacuum (negative :math:`p_x`) +before being injected back to the target. +With radiation reaction, these electrons are rapidly slowed down +and newly accelerated by the ponderotive force. +Inside the target, accelerated bunches of hot electrons correspond to +the regular positive spikes in :math:`p_x` (oscillation at :math:`\lambda /2`). +The maximum electron energy is almost twice lower with radiation reaction. + +.. _thin_foil_x_px_ne: + +.. figure:: /_static/thin_foil_x_px_ne.png + :width: 18cm + + :math:`x - p_x` electron distribution at time 47 fs for the Monte-Carlo, + the Niel, the corrected Landau-Lifshitz (**CLL**) model and + without radiation loss (**none**). + +-------------------------------------------------------------------------------- + +Performances +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The cost of the different models is summarized in :numref:`radiationTimes`. +Reported times are for the field projection, the particle pusher and +the radiation reaction together. Percentages correspond to the overhead induced by +the radiation module in comparison to the standard PIC pusher. + +All presented numbers are not generalizable and are only indicated to give +an idea of the model costs. The creation of macro-photons is not enabled for +the Monte-Carlo radiation process. + +.. _radiationTimes: + +.. table:: Radiation model performances + + +-------------------------------------+------------+----------+--------------+----------+---------------------+ + | Radiation model | None | LL | CLL | Niel | MC | + +=====================================+============+==========+==============+==========+=====================+ + | Counter-propagating Plane Wave 1D | 0.2s | 0.23s | 0.24s | 0.26s | 0.3s | + | Haswell (Jureca) | | | | | | + +-------------------------------------+------------+----------+--------------+----------+---------------------+ + | Synchrotron 2D Haswell (Jureca) | 10s | 11s | 12s | 14s | 15s | + | :math:`\chi=0.05`, :math:`B=100` | | | | | | + +-------------------------------------+------------+----------+--------------+----------+---------------------+ + | Synchrotron 2D Haswell (Jureca) | 10s | 11s | 12s | 14s | 22s | + | :math:`\chi=0.5`, :math:`B=100` | | | | | | + +-------------------------------------+------------+----------+--------------+----------+---------------------+ + | Synchrotron 2D KNL (Frioul) | 21s | 23s | 23s | 73s | 47s | + | :math:`\chi=0.5`, :math:`B=100` | | | | | | + +-------------------------------------+------------+----------+--------------+----------+---------------------+ + | Interaction with a carbon thin foil | 6.5s | 6.5s | 6.6s | 6.8s | 6.8s | + | 2D Sandy Bridge (Poincare) | | | | | | + +-------------------------------------+------------+----------+--------------+----------+---------------------+ + + +Descriptions of the cases: + +* **Counter-propagating Plane Wave 1D**: run on a single node of *Jureca* with 2 MPI ranks and 12 OpenMP + threads per rank. + +* **Synchrotron 2D**: The domain has a dimension of 496x496 cells with + 16 particles per cell and 8x8 patches. + A 4th order B-spline shape factor is used for the projection. + The first case has been run on a single Haswell node of *Jureca* with 2 MPI ranks and + 12 OpenMP threads per rank. the second one has been run on a single KNL node of *Frioul* + configured in quadrant cache using 1 MPI rank and 64 OpenMP threads. + On KNL, the ``KMP_AFFINITY`` is set to ``fine`` and ``scatter``. + +.. + + Only the Niel model provides better performance with a ``compact`` affinity. + +* **Thin foil 2D**: + The domain has a discretization of 64 cells per :math:`\mu\mathrm{m}` in + both directions, with 64 particles per cell. + The case is run on 16 nodes of *Poincare* with 2 MPI ranks and 8 OpenMP + threads per rank. + +The LL and CLL models are vectorized efficiently. +These radiation reaction models represent a small overhead +to the particle pusher. + +The Niel model implementation is split into several loops to +be partially vectorized. The table lookup is the only phase that +can not be vectorized. Using a fit function enables to have a fully +vectorized process. The gain depends on the order of the fit. +The radiation process with the Niel model is dominated +by the normal distribution random draw. + +The Monte-Carlo pusher is not vectorized because the Monte-Carlo loop has +not predictable end and contains many if-statements. +When using the Monte-Carlo radiation model, code performance is likely to be +more impacted running on SIMD architecture with large vector registers +such as Intel Xeon Phi processors. This can be seen in :numref:`radiationTimes` +in the synchrotron case run on KNL. + +---- + +References +^^^^^^^^^^ + +.. [DiPiazza2012] `Di Piazza et al. (2012), Rev. Mod. Phys. 84, 1177 `_ + +.. [Duclous2011] `Duclous, Kirk and Bell (2011), Plasma Physics and Controlled Fusion, 53 (1), 015009 `_ + +.. [Elkina2011] `Elkina et al. (2011), Physical Review Accelerators and Beam, 14, 054401 `_ + +.. [Landau1947] `Landau and Lifshitz (1947), The classical theory of fields. Butterworth-Heinemann `_ + +.. [Lobet2013] `Lobet et al. (2016), J. Phys.: Conf. Ser. 688, 012058 `_ + +.. [Lobet2015] `Lobet (2015), Effets radiatifs et d'électrodynamique quantique dans l'interaction laser-matière ultra-relativiste (2015) `_ + +.. [Ridgers2017] `Ridgers et al. (2017), Journal of Plasma Physics, 83(5) `_ + +.. [Ritus1985] `Ritus (1985), Journal of Soviet Laser Research, 6, 497, ISSN 0270-2010 `_ + +.. [Tamburini2010] `Tamburini et al. (2010), New J. Phys. 12, 123005 `_ + +.. [Timokhin2010] `Timokhin (2010), Monthly Notices of the Royal Astronomical Society, 408 (4), 2092, ISSN 1365-2966 `_ + diff --git a/_sources/Understand/relativistic_fields_initialization.rst.txt b/_sources/Understand/relativistic_fields_initialization.rst.txt new file mode 100644 index 000000000..de723d904 --- /dev/null +++ b/_sources/Understand/relativistic_fields_initialization.rst.txt @@ -0,0 +1,149 @@ +Field initialization for relativistic species +-------------------------------------------------------------------------------- + +As explained in :doc:`algorithms`, if a net charge is present at the beginning of the simulation, the initial electromagnetic fields are computed. +For static charge distributions, the solution of Poisson's equation will be necessary to find the initial electrostatic field. +If the initial charge has a non-zero initial speed, in general the electric and magnetic field should be computed solving the full set of Maxwell's equations or equivalently the potentials equations. +In some physical setups of interest, one or more relativistic species are injected in a plasma. In these cases, the computation of the initial electromagnetic fields can be reduced to the solution of a modified version of Poisson's equation. + + +---- + +The relativistic Poisson's equation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +From the continuity equation :math:`\partial_t \rho + \nabla \cdot \mathbf{J} = 0` +and Maxwell's equations, it can be shown that the quantities :math:`\nabla\cdot\mathbf{B}` and :math:`\nabla\cdot\mathbf{E}-\rho` do not change over time: + +.. math:: + + \begin{eqnarray} + \partial_t \left( \nabla\cdot\mathbf{B} \right ) &=& 0, \\ + \partial_t \left( \nabla\cdot\mathbf{E}-\rho \right ) &=& \nabla\cdot\partial_t\mathbf{E}-\partial_t\rho = \nabla\cdot\left(\nabla\times\mathbf{B}-\mathbf{J}\right)-\partial_t\rho = - \left(\nabla\cdot\mathbf{J}+\partial_t \rho\right). + \end{eqnarray} + +Thus, if a simulation starts with :math:`\rho\neq0`, the electromagnetic fields must be properly initialized. + +In the case of a static charge distribution, i.e. :math:`\rho\neq0`, :math:`\mathbf{J}=0`, the initial electrostatic potential :math:`\Phi` can be computed solving Poisson's equation: + +.. math:: + + \nabla^2 \Phi = -\rho, + +and then be integrated to find the initial electric field: :math:`\mathbf{E}=-\nabla\Phi`. The initial magnetic field :math:`\mathbf{B}` will be zero. + +In general when the initial current :math:`\mathbf{J}` is not zero, the full set of fields equations should be solved to correctly initialize the electromagnetic fields. + +However, if a species is already relativistic when the simulation starts, e.g. a relativistic electron bunch, its initial electromagnetic fields can be computed through a simplified procedure, described in [Vay2008]_, [Londrillo2014]_, [Massimo2016]_ and [Marocchino2018]_. + +An important assumption of this calculation is that the species is highly relativistic, moving in the positive :math:`x` direction, with negligible momentum spread. Under this hypothesis, the transverse components of the species current density are neglected and the four-current quadrivector can be written as: + +.. math:: + + \left(\mathbf{J},\rho\right) = \left(\rho \beta_0 , 0, 0, \rho \right), + +where :math:`\beta_0` is the initial mean velocity of the relativistic species. At least locally, the potentials :math:`\mathbf{A}`, :math:`\Phi` in the laboratory frame will be only function of :math:`x-\beta_0 t`, as they are propagating with the species at uniform relativistic velocity. + +In the relativistic species rest frame :math:`S'`, the charge distribution is static and the electrostatic potential in that reference frame :math:`\Phi'` is related to the charge density in that reference frame :math:`\rho'` through Poisson's equation: + +.. math:: + :label: Poisson + + \nabla'^2 \Phi' = -\rho', + +where the Laplacian operator is computed in the reference frame :math:`S'`: + +.. math:: + + \nabla'^2=\partial^2_{x'}+\partial^2_{y'}+\partial^2_{z'}. + +The vector potential in the species rest frame can be set to zero: :math:`\mathbf{A'}=0`. Through the above mentioned assumptions, it is possible to rewrite Eq. :eq:`Poisson` only in terms of laboratory frame quantities. + +Lorentz transformation of the four-vector :math:`\left(\mathbf{J},\rho \right)` yields :math:`\rho'=\rho/\gamma_0`, where :math:`\gamma_0=1/\sqrt{1-\beta^2_0}` is the average Lorentz factor of the relativistic species. +Similarly, the potential :math:`\Phi'` can be rewritten in terms of the potential in the laboratory frame: :math:`\Phi'=\Phi/\gamma_0`. The Lorentz back-transformation of coordinates + +.. math:: + + x=\gamma_0(x'+\beta_0 t'),\quad t = \gamma_0(t'+\beta_0 x'), \quad y=y', \quad z=z' + +allows to transform the derivatives in Eq. :eq:`Poisson` as + +.. math:: + + \partial_{x'}=\gamma_0\left(\partial_x+\beta_0\partial_t\right), \quad \partial_{y'}=\partial_y, \quad \partial_{z'}=\partial_z. + +The partial derivative along the :math:`x'` direction can be further simplified, through the hypothesis of temporary dependence of all quantities on :math:`x-\beta_0 t`, implying :math:`\partial_t=-\beta_0\partial_x`: + +.. math:: + + \partial_{x'}=\frac{1}{\gamma_0}\partial_x. + +Equation :eq:`Poisson` can thus be rewritten as + +.. math:: + :label: RelPoisson + + \left( \frac{1}{\gamma^2_0}\partial^2_x+\nabla_{\perp}^2\right) \Phi = -\rho, + +here informally referred to as the relativistic Poisson's equation. In :program:`Smilei`, as for Eq. :eq:`Poisson`, the solution of the relativistic Poisson's equation is performed through the conjugate gradient method. + +Once the potential :math:`\Phi` is found, we can compute all the components of the electromagnetic field, using again the relations :math:`\partial_t=-\beta_0\partial_x`, :math:`\Phi'=-\Phi/\gamma_0` and the Lorentz back-transformation of the vector potential :math:`\mathbf{A}`: + +.. math:: + + A_x = \gamma_0(A_x'+\beta_0 \Phi')=\gamma_0\beta_0 \Phi'=\beta_0\Phi,\quad A_y = A_y'=0, \quad A_z = A_z'=0. + +From all these relations, the electromagnetic field can be computed as usual, through the definitions of potentials :math:`\mathbf{E}=-\nabla\Phi-\partial_t\mathbf{A}`, :math:`\mathbf{B}=-\nabla\times\mathbf{A}`: + +.. math:: + \begin{eqnarray} + E_x &=& -\partial_x \Phi - \partial_t A_x = -\partial_x \Phi + \beta_0^2 \partial_x \Phi = -\frac{1}{\gamma_0^2}\partial_x \Phi,\\ + E_y &=& -\partial_y \Phi - \partial_t A_y = -\partial_y \Phi,\\ + E_z &=& -\partial_z \Phi - \partial_t A_z = -\partial_z \Phi,\newline\\ + B_x &=& \partial_y A_z - \partial_z A_y = 0 ,\\ + B_y &=& \partial_z A_x - \partial_x A_z = \partial_z A_x = \beta_0 \partial_z \Phi = - \beta_0 E_z,\\ + B_z &=& \partial_x A_y - \partial_y A_x = - \partial_y A_x = - \beta_0 \partial_y \Phi = \beta_0 E_y, + \end{eqnarray} + +or in more compact form: :math:`\mathbf{E}=\left( -\frac{1}{\gamma_0^2}\partial_x \Phi, -\partial_y \Phi,-\partial_z \Phi \right)`, :math:`\mathbf{B}=\beta_0\mathbf{\hat{x}}\times\mathbf{E}`. + +From the previous equations, it can be inferred that, in a 1D cartesian geometry, the fields computed through this procedure equal those obtained through the standard Poisson's problem. +This can also be inferred from the relativistic transformations of fields, which conserve the :math:`x` components of the electromagnetic fields for boosts in the :math:`x` direction. + + + +---- + +Recommendations for relativistic species field initialization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In :program:`Smilei`, each species can independently benefit from this field initialization procedure. Its field will be initialized when the species will start to move, in order not to interfere with the other species' dynamics. +The initialized fields will be superimposed to the electromagnetic fields already present in the simulation. To have physically meaningful results, we recommend to place a species which requires this method of field initialization far from other species, otherwise the latter could experience instantaneous unphysical forces by the relativistic species’ fields. + +Remember that the transverse field of a moving charge with relativistic factor :math:`\gamma` is greater than the electrostatic transverse field of that charge, by a factor :math:`\gamma`. +This means that for highly relativistic particles, you will need to use a transversely large simulation window to let the field decrease enough to reduce border effects during its propagation. +A complete absence of boundary effects in this case would be provided by perfectly absorbing boundary conditions, which are not implemented yet in the code. +If the relativistic species propagates in a plasma, these border effects could be partially screened by the plasma. + +A relativistic mean velocity in the :math:`x` direction and a negligible energy spread are assumed in the hypotheses of this procedure, so the user must ensure these conditions when defining the species requiring field initialization in the namelist. +The procedure could be extended to non-monoenergetic species, dividing the species macro-particles in monoenergetic energy bins and then superimposing the fields by each of the monoenergetic bins, computed with the same procedure. +At the moment, this energy binning technique is not available in :program:`Smilei`. + + + +---- + +References +^^^^^^^^^^ + +.. [Vay2008] `J.-L. Vay, Physics of Plasmas 15, 056701 (2008) `_ + +.. [Londrillo2014] `P. Londrillo, C. Gatti and M. Ferrario, Nucl. Instr. and Meth. A 740, 236-241 (2014) `_ + +.. [Massimo2016] `F. Massimo, A. Marocchino and A. R. Rossi, Nucl. Instr. and Meth. A 829, 378-382 (2016) `_ + +.. [Marocchino2018] `A. Marocchino, E. Chiadroni, M. Ferrario, F. Mira and A.R. Rossi, Nucl. Instr. and Meth. A (2018) `_ + + + + diff --git a/_sources/Understand/task_parallelization.rst.txt b/_sources/Understand/task_parallelization.rst.txt new file mode 100644 index 000000000..aa08cfd62 --- /dev/null +++ b/_sources/Understand/task_parallelization.rst.txt @@ -0,0 +1,161 @@ +Task Parallelization +---------------------- + +Task parallelization is a method to spread the computing workload on the many cores +of a computer. Instead of splitting the *data* accross cores and apply the same task +to all these pieces, different *tasks* are split accross the cores with the +data necessary to complete them. This approach can often make the computation faster, +especially with non-uniform plasma distributions. + +Task parallelization of macro-particle operations in Smilei (using OpenMP) is +published in [Massimo2022]_. + +---- + +Motivation +^^^^^^^^^^ + +Usually, most of the computing time is spent on macro-particle operations. +Consequently, a non-uniform plasma distribution results in load imbalance: +some cpu cores are loaded with less macro-particles, and idly wait for the +other cores to finish their work. + +Worse: adding more cpu cores will not result in significant speedup, as only +a few of them are performing most of the work. This "strong scaling" curve +(speed-up vs number of cpu-cores) starts to saturate. Several methods for +parallelism can increase the number of computing units where +the saturation occurs. + +In :program:`Smilei`, by default, the data is split in *patches* (see +:doc:`parallelization`) and, when the environment variable ``OMP_SCHEDULE`` +is set to ``dynamic``, the OpenMP scheduler dynamically assigns each patch +to each core. This provides for some load balancing inside each MPI process, as +cores can work asynchronously on different patches. + +This strategy implies that only 1 OpenMP thread can work on a given patch, +which includes potentially several ``Species`` and all the PIC operators +(interpolation, push, etc). These constraints can considerably slow down the +simulation in some situations (many species with non-uniform distribution, +and/or low number of patches per core). + +A first solution is to split the data to a finer level: separate the +treatment of species, and split the patch in smaller structures (in Smilei, +patches are divided in ``clusters`` along the dimension ``x``). This +can improve the strong scaling results, but some constructs cannot be +parallelized with this data splitting (e.g. irregularly nested loops, recursion, +etc). The task parallelism has been introduced to answer these issues. + +---- + +Task approach +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:program:`Smilei` exploits the task parallelization (including task dependencies) +available with OpenMP 4.5. +The main idea is to split the work in smaller units that can be run asynchronously, +respecting the logical order in which these units of work must be completed. + +In addition to separated species treatment and patches split in clusters +(see :py:data:`cluster_width` and the following Figure), the macro-particle +operators (interpolation, push, etc) are defined as tasks. +All the combinations of [operator-cluster-species-patch] +correspond to different tasks that can be run in parallel. + +.. _Cluster_definition_doc: + +.. figure:: /_static/Cluster_definition_doc.png + :width: 60% + :align: center + + Definition of clusters in a patch. The depicted 2D patch’s size is 16 × 6 cells + in the `x` and `y` directions respectively. In the Figure each cluster has an `x` + extension equal to ``cluster_width = 4`` cells in the `x` direction. + +---- + +Task dependency graph +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some tasks logically depend on other tasks, e.g. the position and momenta of the +macro-particles of a certain [cluster-species-patch] combination can be +advanced in a given iteration only after that the electromagnetic force acting +on them in that iteration has been interpolated from the grid. + +The combinations [operator-cluster-species-patch] are defined as tasks, with +dependencies respecting the PIC macro-particle operator sequence +(Interpolation, Push, Projection) on the respective [cluster-species-patch] +combinations. + +In task programming, the task dependencies of an algorithm are represented by +a task dependency graph, where each task is a node of the graph and the directed +edges between nodes are the task dependencies. If in this graph an arrow spawns +from task A to task B, then task B logically depends on task A. + +In the code, the dependency graph is provided to OpenMP in form of ``depend`` +clauses in the ``omp task`` directives. This way, the tasks are dynamically assigned +to OpenMP threads, in the correct order (preventing data race conditions). +The user does not have to worry about the assignment of tasks to +the available threads, as this operation is done dynamically by the OpenMP scheduler. + +This is described in [Massimo2022]_. + +---- + +Performance Results +^^^^^^^^^^^^^^^^^^^^^ + +Some results from [Massimo2022]_ are shown in the following. + +In the following Figure, a 2D uniform thermal plasma case shows that with +uniform macro-particle distributions the task-parallelization in :program:`Smilei` +does not have a performance advantage. +In the same Figure, a 2D radiation pressure acceleration case shows that task +parallelization can have a performance advantage with non-uniform macro-particle +distributions. + +.. _Cluster_width_scan_doc: + +.. figure:: /_static/Cluster_width_scan_doc.png + :width: 90% + :align: center + + Performances with and without task parallelization in a 2D uniform plasma case + (left) and in a 2D radiation pressure acceleration case (right). + +Note in the following Figure the non-uniformity of the electrons distribution +in the radiation pressure acceleration case. The non-uniformity is present since +the start of the simulation. A namelist for a similar case can be found in the +``benchmarks/tst2d_02_radiation_pressure_acc``. + + +.. _radiation_pressure_rho: + +.. figure:: /_static/Radiation_Pressure_Rho.png + :width: 60% + :align: center + + Electron density divided by the critical density in a 2D radiation pressure + benchmark at 0 (left) and 1500 iterations (right). The non-uniformity of the + macro-particle distribution is present since the start of the simulation. + +The scheduling of macro-particle operations without and with task parallelization +can be seen in the following figures. +Note how in the first Figure (without task parallelization), the end of the +treatment of macro-particle operators (around 0.1 s) is determined by the +OpenMP thread 0 of the MPI process 0. In the second Figure (with task parallelization), +the OpemMP thread 2 of MPI process 0 determines the end of the +treatment of macro-particle operators (around 0.07 s). In this case, the finer +decomposition given by the clusters and the relaxation of the constraints involved +in the assignment of macro-particle operations to threads yields a shorter time +to the result. + +.. _part_event_tracing: + +.. figure:: /_static/Task_tracing_doc.png + :width: 100% + :align: center + + Scheduling of macro-particle operations for the 2D radiation pressure benchmark, + 4 MPI processes and 4 OpenMP threads, during iteration 1200, + without (left panel) and with task parallelization, 4 clusters per patch (right panel). + diff --git a/_sources/Understand/units.rst.txt b/_sources/Understand/units.rst.txt new file mode 100644 index 000000000..cad2870bd --- /dev/null +++ b/_sources/Understand/units.rst.txt @@ -0,0 +1,194 @@ +Units +----- + +Like many PIC codes, :program:`Smilei` handles only **dimension-less variables**, +normalized to *reference* quantities. + +---- + +Basic reference quantities +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The speed of light, the elementary charge and the electron mass provide the basis +of the normalizations in :program:`Smilei`: + +* Reference electric charge :math:`Q_r = e` (the elementary charge) +* Reference mass :math:`M_r = m_e` (the electron mass) +* Reference velocity :math:`V_r = c` (the speed of light) + +We can derive from these: + +* a reference energy :math:`K_r = m_e c^2` +* a reference momentum :math:`P_r = m_e c` + +Even with these normalizations, :program:`Smilei` **does not know the scale of the problem**: +it lacks a reference distance, or equivalently, a reference time. + +---- + +Arbitrary reference quantities +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Instead of choosing a physical constant (for example, the electron radius) as a reference, +the scale of the problem is not decided *a priori*, and the user is free to scale the result +of the simulation to any value. +In fact, quantities are proportional an *unknown* reference frequency +:math:`\omega_r`, which can be scaled by the user *a posteriori*. + +Usually, :math:`\omega_r` will be an important frequency of the problem. +For example, if there is a laser, it could be the laser frequency. +Or it could be the electron plasma frequency. + +From this reference frequency :math:`\omega_r`, we define: + +* a reference time :math:`T_r = 1/\omega_r` +* a reference length :math:`L_r = c/\omega_r` +* a reference electric field :math:`E_r = m_e c \omega_r / e` +* a reference magnetic field :math:`B_r = m_e \omega_r / e` +* a reference particle density :math:`N_r = \varepsilon_0 m_e \omega_r^2 /e^2` +* a reference current :math:`J_r = c\, e\, N_r` + +.. warning:: + + :math:`1/N_r` is a volume, but counter-intuitively, it is **not equal** to :math:`L_r^{3}`. + +Normalizing all quantities to these references is convenient for resolving Maxwell's equations, +and the charges equation of motion, as it converts them into a dimension-less set of equations: + +.. math:: + + \mathbf{\nabla}\cdot\mathbf{E} = \rho + \quad\quad + \nabla\cdot\mathbf{B} & = 0 \\ + + \nabla\times\mathbf{E} = - \partial_t \mathbf{B} + \quad\quad + \nabla\times\mathbf{B} = & \; \mathbf{j} + \partial_t \mathbf{E} + +.. math:: + + \partial_t \mathbf{p} = Z \mathbf{E} + Z \mathbf{v}\times\mathbf{B} + +where :math:`\mathbf{E}`, :math:`\mathbf{B}`, :math:`\mathbf{j}` and :math:`\mathbf{\rho}` +are the electric field, magnetic field, current density and charge density, normalized to +:math:`E_r`, :math:`B_r`, :math:`J_r` and :math:`Q_r N_r`, respectively. :math:`Z` and +:math:`\mathbf p` are a particle's charge and momentum, normalized to :math:`Q_r` and +:math:`P_r`, respectively. Note that the temporal and spatial derivatives are also +normalized to :math:`T_r` and :math:`L_r`, respectively. + + +---- + +Tips for the namelist +^^^^^^^^^^^^^^^^^^^^^ + +In the :doc:`namelist `, the user must provide all parameters in units of :math:`Q_r`, +:math:`M_r`, :math:`V_r`, :math:`K_r`, :math:`P_r`, :math:`T_r`, :math:`L_r`, :math:`E_r`, +:math:`B_r`, :math:`N_r` or :math:`J_r`. + +This may be cumbersome if you know your input data in other units. +However, the namelist is actually a *python* code that can compute conversions easily. + +For example, let us assume that you know your problem size in units of the wavelength. +Knowing that the reference wavelength is :math:`2\pi L_r`, you can multiply all your +lengths by :math:`2\pi`:: + + from math import pi + wavelength = 2. * pi + cell_length = [0.05 * wavelength] + grid_length = [100. * wavelength] + + +---- + +Problems requiring explicit units +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sometimes, :program:`Smilei` may be requested to compute other things than Maxwell's +equations. That is the case, for example, for computing :doc:`collisions ` or ionization. +In these situations, equations cannot be normalized to dimension-less terms, and +the code must know the value of :math:`\omega_r` in physical units. This requires +defining an :ref:`extra parameter in the namelist `. + +For instance, ``reference_angular_frequency_SI = 2.*pi*3e8/1e-6`` means that +:math:`L_r = 1\,\mathrm{\mu m} /(2\pi)`. +This information will be used only in some specific parts of the code (collisions, ionization, ...) +but not in the main PIC algorithms. + +.. warning:: + + The outputs of the code are not converted to SI. + They are all kept in the reference units listed above. + +---- + +.. _integrated_quantities: + +Quantities integrated over the grid +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Special care must be taken when considering local quantities that are spatially +integrated. + +.. rubric:: 1. The spatially-integrated kinetic energy density + +The particle kinetic energy density is naturally in units of :math:`K_r N_r`. +Integrating over space give different results depending on the simulation dimension. +In 1D, this space is a length, with units :math:`L_r`; in 2D, it is a surface, with units +:math:`L_r^2`; and in 3D, it is a volume, with units :math:`L_r^3`. +Overall, the integrated energy has the units :math:`K_r N_r L_r^D` +where :math:`D` is the simulation dimension. Note that we could expect +to obtain, in 3D, an energy with units :math:`K_r`, but counter-intuitively +it has the units :math:`K_r N_r L_r^3`. + +These kinetic energies appear, for instance, in the :ref:`DiagScalar` as +``Ukin`` (and associated quantities). + +.. rubric:: 2. The spatially-integrated electromagnetic energy density + +The electromagnetic energy density has the units :math:`E_r^2/\varepsilon_0 = K_r N_r`. +Consequently, the spatially-integrated electromagnetic energy density has +the units :math:`K_r N_r L_r^D`; the same as the integrated kinetic energy density above. + +These electromagnetic energies appear, for instance, in the :ref:`DiagScalar` as +``Uelm`` (and associated quantities). + +.. rubric:: 3. The space- & time-integrated Poynting flux + +The Poynting flux has the units :math:`E_r B_r / \mu_0 = V_r K_r N_r`. +Consequently, the flux integrated over a boundary, and over time, has the units +:math:`V_r K_r N_r L_r^{D-1} T_r = K_r N_r L_r^D`, which is the same as the +integrated energy densities above. + +This integrated Poynting flux appears, for instance, in the :ref:`DiagScalar` as +``Uelm_bnd``, ``PoyXmin``, ``PoyXminInst`` (and associated quantities). + + +---- + +.. _Weights: + +Macro-particle weights +^^^^^^^^^^^^^^^^^^^^^^ + +Macro-particles are assigned a *statistical weight* which measures +their contribution to the plasma distribution function. +In :program:`Smilei`, this weight is defined for each particle at the moment of its creation +(usually at the beginning of the simulation), +and is never modified afterwards. Its definition reads: + +.. math:: + + \textrm{macro-particle weight} = \frac + {\textrm{species density} \times \textrm{cell hypervolume}} + {\textrm{number of macro-particles in cell}} + +As the density is in units of :math:`N_r` and the cell hypervolume in +units of :math:`L_r^D` (where :math:`D` is the simulation dimension), +then the units of weights is :math:`N_r L_r^D`. + +This definition of weights ensures that they do not depend on the +cell hypervolume, i.e. they can be reused in another simulation, as long as +:math:`D`, :math:`L_r` and :math:`N_r` are unchanged. + + diff --git a/_sources/Understand/vectorization.rst.txt b/_sources/Understand/vectorization.rst.txt new file mode 100644 index 000000000..cd187c9c6 --- /dev/null +++ b/_sources/Understand/vectorization.rst.txt @@ -0,0 +1,282 @@ +Vectorization +---------------------- + +For enhanced performances on most recent CPUs, :program:`Smilei` exploits +efficiently vectorization using refactored and optimized operators. + +Vectorization optimizations are published in [Beck2019]_. + +---- + +Notion of Single Instruction Multiple Data (SIMD) Vectorization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Single Instruction Multiple Data (SIMD) vectorization consists on performing on +a contiguous set of data, usually called vector, the same operation(s) +in a single instruction. +On modern Computational Processing Units (CPU), vector registers have a length 512 kb +that corresponds to 8 double precision floats (on Intel Skylake processors for +instance and future ARM architecture). +Each processing unit can perform a Fused Multiply Add instruction (FMA) that +combines an addition and a multiplication. +If-conditions can be handled using mask registers. +Modern SIMD vectorization is described in :numref:`simd_fig`. + +.. _simd_fig: + +.. figure:: /_static/SIMD.png + :width: 90% + :align: center + + Single Instruction Multiple Data (SIMD) vectorization + +On SIMD CPUs, an application has to use SIMD vectorization to reach the maximum +of the core computational peak performance. A scalar code without FMA +uses less than 7% of the core computational power. +This affirmation can nonetheless be mitigated on Intel Skylake processors that +adapt their frequency on the used vectorization instruction set. + +---- + +SIMD vectorization of the particle operators +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Optimization efforts have been recently done to vectorize efficiently the +particle operators of :program:`Smilei`. + +A new sorting method has been first implemented in order to then make +the particle operator vectorization easier. +This method, referred to as cycle sort, minimizes the number of data movements +by performing successive permutation. + +The most expensive operators and most difficult to vectorize are the current projection +(deposition) and the field interpolation (gathering) steps where +there is an interpolation between the grids and the macro-particles. +These two steps have been vectorized taking advantage of the cycle sort. + +---- + +Vectorization Performance +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Vectorization is not always the most efficient choice. +It depends on the number of macro-particles per cell. +To demonstrate this, we have evaluated in [Beck2019]_ the performance with a series of tests on different architectures: Intel Cascade +Lake, Intel Skylake, Intel Knights Landing, Intel Haswell, Intel Broadwell. +The Cascade Lake processor is not in the original study and has been added after. +We have used the 3D homogeneous Maxwellian benchmark available `here <_static/vecto_maxwellian_plasma_3d.py>`_. +The number of macro-particles per cell is varied from 1 to 512. +This study has been focused on the particle operators (interpolator, pusher, projector, sorting) and discards the +computational costs of the Maxwell solver and of the communications between processes. +Each run has been performed on a single node with both the scalar and the vectorized operators.. +Since the number of cores varies from an architecture +to another, the runs were conducted so that the load per core +(i.e. OpenMP thread) is constant. +The number of patches per core also remains the same for all cores throughout the whole simulation since the imbalance +in this configuration is never high enough to trigger patch exchanges. +The patch size is kept constant at 8 × 8 × 8 cells. +The total number of patches for each architecture is determined so that each core has 8 patches to handle. +The numerical parameters are given in :numref:`vecto_numerical_parameters`. + +.. _vecto_numerical_parameters: + +.. table:: Numerical parameters for vectorization + + +-------------------------------------+-------------------------------------------------------+-------------------+---------------------------+ + | Cluster | Architecture | Number of patches | Configuration | + +=====================================+=======================================================+===================+===========================+ + | Jean Zay, IDRIS, France | 2 x Cascade Lake (Intel® Xeon® Gold 6248, 20 cores) | 5 x 8 x 8 | Intel 19, IntelMPI 19 | + +-------------------------------------+-------------------------------------------------------+-------------------+---------------------------+ + | Irene Joliot-Curie, TGCC, France | 2 x skylake (Intel® Skylake 8168, 24 cores) | 6 x 8 x 8 | Intel 18, IntelMPI 18 | + +-------------------------------------+-------------------------------------------------------+-------------------+---------------------------+ + | Frioul, Cines, France | 2 x Knights Landing (Intel® Xeon® Phi 7250, 68 cores) | 8 x 8 x 8 | Intel 18, IntelMPI 18 | + +-------------------------------------+-------------------------------------------------------+-------------------+---------------------------+ + | Tornado, LPP, France | 2 x Broadwell (Intel® Xeon® E5-2697 v4, 16 cores) | 4 x 8 x 8 | Intel 17, openMPI 1.6.5 | + +-------------------------------------+-------------------------------------------------------+-------------------+---------------------------+ + | Jureca, Juelich, Germany | 2 x Haswell (Intel® Xeon® E5-2680 v3, 12 cores) | 3 x 8 x 8 | Intel 18, IntelMPI 18 | + +-------------------------------------+-------------------------------------------------------+-------------------+---------------------------+ + +The results of the simulation tests (shape factor of order 2) for both scalar and vectorized versions are +shown in :numref:`vecto_particle_times_o2_all`. +Contrary to the scalar mode, the vectorized operators efficiency depends strongly on the number of particles per cell. +It shows improved efficiency, compared to the scalar mode, above a certain number of particles per cell denoted *inversion point*. + +.. _vecto_particle_times_o2_all: + +.. figure:: /_static/vecto_particle_times_o2_all.png + :width: 100% + + Particle computational cost as a function of the number of particles per cell. Vectorized + operators are compared to their scalar versions on various cluster + architectures. Note that the Skylake compilations accepts both AVX512 and AVX2 + instruction sets. + +The lower performances of the vectorized operators at low particles per cell can be easily understood: + +1. The complexity of vectorized algorithms is higher than their scalar counter-parts. +#. New schemes with additional loops and local buffers induced an overhead that is onmy compensated when the number of particles is large enough. +#. SIMD instructions are not efficient if not fulfilled +#. SIMD instructions operate at a lower clock frequency than scalar ones on recent architectures + +The location of the inversion point of the speed-ups brought by vectorization depends on the architecture. +The performance results are summarized in :numref:`vecto_performance_results`. + +.. _vecto_performance_results: + +.. table:: Vectorization performance + + +-------------------------------------+-------------------------------------------------------+------------------------+ + | Architecture (Cluster) | Inversion point (particles per cell) | Vectorization speed-up | + +=====================================+=======================================================+========================+ + | Cascade lake (Jean Zay) | 8 particles per cell | x2 | + +-------------------------------------+-------------------------------------------------------+------------------------+ + | Skylake (Irene Joliot-Curie) | 10 particles per cell (most advanced instruction set) | x2.1 | + +-------------------------------------+-------------------------------------------------------+------------------------+ + | KNL (Frioul) | 12 particles per cell | x2.8 | + +-------------------------------------+-------------------------------------------------------+------------------------+ + | Broadwell (LLR) | 10 particles per cell | x1.9 | + +-------------------------------------+-------------------------------------------------------+------------------------+ + | Haswell (Jureca) | 10 particles per cell | x1.9 | + +-------------------------------------+-------------------------------------------------------+------------------------+ + +Vectorization efficiency increases with the number of particles per cell above the inversion point. +It tends to stabilize far from the inversion point above 256 particles per cell. + + +---- + +Adaptive vectorization +^^^^^^^^^^^^^^^^^^^^^^^^ + +Adaptive vectorization consists on switching localy between scalar and +vectorized operators during the simulation, choosing the most efficient one +in the region of interest. +The concept has been successfully implemented at the lower granularity of the code. +Every given number of time steps, for each +patch, and for each species, the most efficient set of operator is determined +from the number of particles per cell. +The concept is schematically described in :numref:`fig_vecto_domain_decomposition`. + +.. _fig_vecto_domain_decomposition: + +.. figure:: /_static/vecto_domain_decomposition.png + :width: 100% + + Description of the adaptive vectorization withn the multi-stage domain decomposition. + Patches with many macro-particles per cell are faster in with vectorized operators whereas with few macro-particles per cell, scalar operators are more efficient. + +An advanced empirical criterion has been developed. +It is computed from the parametric studies presented in :numref:`vecto_particle_times_o2_all` +summarizes their results and indicates, for a given species in a given patch, the approximate time to compute the particle +operators using both the scalar and the vectorized operator. +The computation times have been normalized to that of the scalar operator for a single particle. +The comparision of all normalized curves is presented in :numref:`fig_vecto_efficiency_o2_all_mc`. + +.. _fig_vecto_efficiency_o2_all_mc: + +.. figure:: /_static/vecto_efficiency_o2_all_mc.png + :width: 100% + + Normalized time per particle spent for all particle operators in + the scalar and vectorized modes with various architectures, and 2nd-order + interpolation shape functions. + +The outcomes from different architectures appear sufficiently similar to consider an average between their results. +A linear regression of the average between all is applied on the scalar results to have a fit function to implement in the code. +It writes: + +.. math:: + :label: fit_scalar + + S(N) = -1.11 \times 10^{-2} \log{\left( N \right)} + 9.56 \times 10^{-1} + +S is the computation time per particle normalized to that with 1 PPC, and N is the number of PPC. +For the average between vectorized results, a fourth-order polynomial regression writes: + +.. math:: + :label: vecto_scalar + + V(N) = 1.76 \times 10^{ -3 } \log{ \left( N \right)}^4 \\ \nonumber + + 8.41 \times 10^{ -2 } \log{ \left( N \right)}^3 \\ \nonumber + + 1.45 \times 10^{ -2 } \log{ \left( N \right)}^2 \\ \nonumber + -1.19 \log{ \left( N \right) } \\ \nonumber + + 2.86 + +The polynomial regressions are shown in :numref:`vecto_efficiency_o2_all_fit`. + +.. _vecto_efficiency_o2_all_fit: + +.. figure:: /_static/vecto_efficiency_o2_all_fit.png + :width: 100% + + Averages of the curves of :numref:`fig_vecto_efficiency_o2_all_mc` , and polynomial regressions. + +These functions are implemented in the code to determine approximately the normalized single-particle cost. +Assuming every particle takes the same amount of time, the total time to advance a species in a given patch can then be simply evaluated with a +sum on all cells within the patch as: + +.. math:: + :label: adaptive_vecto_time_evaluation + + T_{\rm s,v} = \sum_{c \ \in\ patch\ cells} N(c) \times F\!\left(N(c)\right) + +where F is either S or V. +Comparing :math:`T_s` and :math:`T_v` determines which of the scalar or vectorized operators should be locally selected. +This operation is repeated every given number of time steps to adapt to the evolving plasma distribution. Note that similar +approximations may be computed for specific processors instead of using a general rule. +In Smilei, other typical processors have been included, requiring an additional compilation flag automatically included in the machine files for ``make``. + +The process of computing the faster mode and changing operators accordingly is called reconfiguration + +Large-scale simulations +^^^^^^^^^^^^^^^^^^^^^^^^ + +Adaptive vectorization has been validated on large-scale simulations with +different benchmarks. +The following video enables to visualize on different scenarii the behavior of the adaptive vectorization. + +.. _video_adaptive_vecto_3d: + +.. raw:: html + + + +Mildly-relativistic collisionless shock +""""""""""""""""""""""""""""""""""""""" + +One of the case was the simulation of Mildly-relativistic collisionless shock. +The effect of the adaptive vectorization mode is illustrated by :numref:`fig_weibel_3d_ne_vecto_it510`. +The electron density is shown in the volume rendering of the top. +The volume rendering at the bottom shows and patch computational state for the electron species. + +.. _fig_weibel_3d_ne_vecto_it510: + +.. figure:: /_static/Weibel_3d_ne_vecto_it510.jpg + :width: 100% + :align: center + :target: https://youtu.be/-ENUekyE_A4 + + Mildly-relativistic collisionless shock: On the top, volume rendering of the normalized + electron density :math:`n_e /n_c` (:math:`n_c` the critical density) at + time :math:`t = 34 \omega^{-1}` (:math:`\omega` the laser frequency) after the beginning of the collision. + On the bottom, patches in vectorized + mode for the electron species at the same time. + An animated version of these can be viewed by clicking on this image. + + +Thanks to the adaptive vectorization, high-density regions that contains many macro-particles per cell corresponds to the patches in vectorized mode. +Incoming plasma flows, with 8 particles per cell in average, are in scalar mode. +The following video shows how the patches are dynamically switched in vectorized or scalar mode. + +.. _video_weibel_3d_ne_vecto_it510: + +.. raw:: html + + + +For this specific benchmark, the speed-up obtained with vectorization is of x2. +Adaptive vectorization brinds a small additional speed-up in some cases. + + diff --git a/_sources/Use/contribute.rst.txt b/_sources/Use/contribute.rst.txt new file mode 100644 index 000000000..8690816b5 --- /dev/null +++ b/_sources/Use/contribute.rst.txt @@ -0,0 +1,229 @@ +Contribute +---------- + +Contributions to the development of :program:`Smilei` are welcome. + +* `Chatroom `_ for discussion and sharing. +* `GitHub issues `_ for bugs and requests. +* Develop new features (clone the repository clicking the "fork" button the `GitHub page `_ so you can then make a `pull request `_ to integrate them in the main repository). + +Guidelines for new developments are: + +* Write clear, commented code, or self-explanatory. +* Write the documentation corresponding to the new features, if any. +* Make validation cases, and reference data, corresponding to the added features. + +---- + +.. _HowToListMyPaper: + +Add my publication to the list on Smilei's website +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can easily add your paper to the :doc:`/Overview/material`. + +* On GitHub, edit the file + `material.rst `_. + and add a few lines such as:: + + .. [MyNameYEAR] + + M. Name, A. Collaborator and B. Collaborator, + `Title of my paper`, + `Reference of the Paper `_, + `arXiv:xxxx.xxxx `_ + +* Make a pull request to share your update. + +---- + +.. _HowToWriteDoc: + +Write documentation +^^^^^^^^^^^^^^^^^^^ + +The documentation you are currently reading is written in the +`reStructuredText `_ (rST) language, and included +in the main :program:`Smilei` repository. This is a fairly simple markup language. You +can see examples from the source files, which are located in the +``doc/Sphinx`` folder and have the extension ``.rst``. + +To transform it into an *html* website, it is +processed using the `sphinx `_ python package that you may have to +install. +If you have sphinx installed, you may simply go to the +main :program:`Smilei` folder from a command line terminal, then run the command + +.. code-block:: bash + + make doc + +This creates a local *html* website accessible in the ``build/html/`` folder. Simply +open the ``build/html/index.html`` file in your favorite web browser. + +To document a new feature, please modify the file ``namelist.rst`` to indicate the +syntax changes in the input file. If the feature requires detailed physical or numerical +background, you may add a new page in the "Understand" section of the website. +To do that, create a new ``.rst`` file, then reference it in the table of contents +located in ``index.rst``. + +---- + +.. _Validation: + +Validate your changes +^^^^^^^^^^^^^^^^^^^^^ + +:program:`Smilei` has a system of test cases combined with reference results that must be +validated, ideally, for every *push* submitted to the git repository. +These **test cases** are located in the ``benchmarks/`` folder. + +Each benchmark has an associated **validation file**, written in *python*, which contains +instructions on how to produce an analysis of the results that can validate that particular +benchmark. The validation files are located in the ``validation/analyses/`` folder. +They have the same name as the benchmarks, with the prefix ``validate_``. + +Once a benchmark has been run, the corresponding ``validate_*`` file is run in *python* +to compare the analysis results with a **reference file** located in the folder +``validation/references/``. Note that the analysis produced by the ``validate_*`` file +can also be used to generate the reference file the first time. + +**When you code a new feature, you must provide a new benchmark, the corresponding +analysis and reference file** + +To make this process easier, a *python* script is available. + +.. rubric:: How do I use the ``validation.py`` script? + +The script ``validation/validation.py`` can do three things: + +* generate validation reference(s) for given benchmark(s) +* compare benchmark(s) to their reference(s) +* show visually differences between benchmark(s) and their reference(s) + +Usage: + +.. + + .. code-block:: bash + + python validation.py [-c] [-h] [-v] [-o ] [-m ] [-b [-g | -s]] [-r ] [-t ] + + * | Option ``-b ``: + | ```` : benchmark(s) to validate. Accepts wildcards. + | ``=?`` : ask input for a benchmark + | DEFAULT : All benchmarks are validated. + + * | Option ``-o ``: + | ```` : number of OpenMP threads used for the execution + | DEFAULT : 4 + + * | Option ``-m ``: + | ```` : number of MPI processes used for the execution + | DEFAULT : 4 + + * Option ``-g``: Generation of references only (no validation) + * Option ``-s``: Plot differences with references only (no validation) + * Option ``-c``: Compilation only (no run, no validation) + * Option ``-r ``: Force the simulation to be broken in several restarts + * Option ``-v``: Verbose + * Option ``-h``: Help + * Option ``-t ``: maximum wall time (format ``"hh:mm:ss"``) + + +Exit status of the script: + +.. + + * 0 validated + * 1 validation fails + * 2 execution fails + * 3 compilation fails + * 4 bad option + + +Examples: + +.. + + .. code-block:: bash + + ./validation.py -v + + Compiles and validates all cases in verbose mode. + + .. code-block:: bash + + ./validation.py -v -b tst1d_00_em_propagation.py + + Validates only the benchmark ``tst1d_00_em_propagation.py``. + + .. code-block:: bash + + ./validation.py -v -b tst1d_00_em_propagation.py -g + + Generates the reference file for the benchmark ``tst1d_00_em_propagation.py``. + + .. code-block:: bash + + ./validation.py -v -b tst1d_00_em_propagation.py -s + + Runs the benchmark ``tst1d_00_em_propagation.py``, and plots the differences with the reference file. + + + +.. rubric:: What does ``validation.py`` actually do? + +It creates a new ``validation/workdirs`` directory (that may be freely deleted later). + +It compiles the code: + +.. + + If the "workdirs" directory lacks a smilei binary, or it is too old, + then the "workdirs" is backed up, and a new compilation occurs. + The compilation output is logged in ``compilation_output``. + If compiling errors occur, ``compilation_errors`` is created and the script exits with status 3. + +It runs each benchmark: + +.. + + If the directory ``wd_//`` does not exist then: + + * it is created. + * ``smilei`` is executed in that directory for the requested benchmark. + * if execution fails, the script exits with status 2. + +It analyses the results (for each requested benchmark) using the ``validate_*`` script: + +.. + + * If requested to compare to previous references (default option), the analysis + is compared to the reference data. + * If requested to generate references (option ``-g``), the analysis is stored + as reference data. + * If requested to show differences to previous references (option ``-s``), + the analysis is plotted vs. the reference data. + + +.. rubric:: How should I make the ``validate_*`` script? + +The ``validate_*`` script should load the simulation results using whatever means suits +the benchmark the best. In many cases, the :doc:`happi ` module is +employed to extract diagnostics results. + +Any *python* instructions may be used to process the simulation results. Once the data +has been crunched into a meaningful value, string, or array, then it must be passed to the +following predefined function: + +.. py:method:: Validate( description, data, epsilon ) + + * ``description``: a string describing the data + * ``data``: a float, a *numpy* float array, or any other python data + * ``epsilon`` (optional): acceptable difference between data and reference + +The ``data`` passed to this function constitutes the *analysis* that is compared to previous +reference files. It is the same analysis that is used to generate those reference files +in the first place. + diff --git a/_sources/Use/ids.rst.txt b/_sources/Use/ids.rst.txt new file mode 100644 index 000000000..48f36df93 --- /dev/null +++ b/_sources/Use/ids.rst.txt @@ -0,0 +1,35 @@ +Identification of tracked particles +----------------------------------- + +:ref:`Tracked particles ` require an identification number (ID) in +order to be recognized after they move around. In Smilei, the particles ID are not simply +the integers from 0 to *N-1*, where *N* is the total number of particles in the +simulation. Instead, a more subtle approach is taken. + +If all numbers from 0 to *N-1* were used, then processors would have to communicate +together each time a new particle is created to avoid duplicates. That would be too +costly. We choose to avoid unnecessary communications, meaning that processors manage +particle IDs independently from each other. This is reflected in the structure of the +output files for the :ref:`tracked particles diagnostic `. These +files, named ``TrackParticlesDisordered_***.h5``, contain arrays where each proc *owns* +a contiguous block, corresponding to the amount of particles it needs to write:: + + |------- Proc 0 ------|----------- Proc 1 ------------|--- Proc 2 ---|-- ....... + +These blocs have distinct sizes in general, and contain particles that are not sorted by +ID, as they move sometimes from one processor to another. + +However, particles keep, in their ID, the number of the processor in which they were +created. More precisely, the ID of a particle is a ``uint64``, a positive integer whose +binary representation has 64 bits. To illustrate the content of these 64 bits let us +replace zeros and ones by X, Y or Z:: + + XXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ + +There are 64 bits available. The first 8 (X) are not parsed by the code, but may be set +by users for custom purposes. The next 24 (Y) represent the processor number. For instance, +for processor 0, all Y will equal 0; for processor 1, only the last Y will be 1. The last +32 bits (Z) indicate the particle number. This number is not unique among processors: for +example, the first particle of each proc always has number 0. The combination of these +last two numbers (YYYYY... and ZZZZZZ....) ensures a unique ID across the whole simulation. +Clearly, the IDs are not represented by a contiguous list of integers from 0 to *N-1*. diff --git a/_sources/Use/install_linux.rst.txt b/_sources/Use/install_linux.rst.txt new file mode 100644 index 000000000..17e5bb7d1 --- /dev/null +++ b/_sources/Use/install_linux.rst.txt @@ -0,0 +1,89 @@ + +Install dependencies on Linux +----------------------------- + +Here we present the packages you need to install in order to be able to compile Smilei. Please be aware that distribution change quite often the package names. As +result this guide could partially or totally outdated. In case you find some error, please fill a `github issue `_ . + + +ArchLinux +^^^^^^^^^ + +.. code-block:: bash + + sudo pacman -S git hdf5-openmpi python-numpy python-sphinx python-h5py-openmpi python-matplotlib python-pint make gcc + + +Fedora +^^^^^^ + +.. code-block:: bash + + sudo dnf install gcc-c++ git hdf5-openmpi hdf5-openmpi-devel openmpi-devel python python-devel python3-h5py ipython python3-pint python3-sphinx python3-matplotlib + +Add the following lines to your ``~/.bashrc`` or ``~/.bash_profile`` file + +.. code-block:: bash + + module load mpi + + +Debian or Ubuntu +^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + sudo apt-get install git python3-h5py python3-ipython python3-pint python3-sphinx python3-matplotlib python3-dev python3-numpy build-essential gcc libhdf5-openmpi-dev + +Add the following lines to your ``~/.bashrc`` or ``~/.bash_profile`` file + +.. code-block:: bash + + export PYTHONEXE=python3 + export HDF5_ROOT_DIR=/usr/lib/x86_64-linux-gnu/hdf5/openmpi + + +Troubleshooting: +^^^^^^^^^^^^^^^^ + +Besides Python Smilei need a quite recent mpi (with mpi-thread-multiple enabled) and a parallel hdf5 library. +In case you system doe not provide them, here is a (non exhaustive) help to instlal them: + + +1. If your system ``openmpi`` is not compiled with ``--enable-mpi-thread-multiple``, a manual installation is required. + Add the following lines to your ``~/.bashrc`` or ``~/.bash_profile`` file + (You may choose any ``${INSTALL_DIR}``) + + .. code-block:: bash + + export INSTALL_DIR=/usr/local + export PATH=${INSTALL_DIR}/openmpi/bin:${PATH} + export LD_LIBRARY_PATH=${INSTALL_DIR}/openmpi/lib:${LD_LIBRARY_PATH} + export PATH=${INSTALL_DIR}/hdf5/bin:${PATH} + export LD_LIBRARY_PATH=${INSTALL_DIR}/hdf5/lib:${LD_LIBRARY_PATH} + export HDF5_ROOT_DIR=${INSTALL_DIR}/hdf5 + +2. Restart your terminal + +3. Download `OpenMPI `_ and install. + + .. code-block:: bash + + tar zxvf openmpi-*.*.*.tar.gz + cd openmpi-*.*.* + ./configure --prefix=${INSTALL_DIR}/openmpi --enable-mpi-thread-multiple --enable-mpirun-prefix-by-default + make + sudo make install + +4. Restart your terminal + +5. Download `HDF5 `_ and install + + .. code-block:: bash + + tar zxvf hdf5-*.*.*.tar.gz + cd hdf5-*.*.* + ./configure --prefix=${INSTALL_DIR}/hdf5 --enable-parallel --with-pic --enable-linux-lfs --enable-shared --enable-build-mode=production --disable-sharedlib-rpath --enable-static CC=mpicc FC=mpif90 + make + sudo make install + diff --git a/_sources/Use/install_macos.rst.txt b/_sources/Use/install_macos.rst.txt new file mode 100644 index 000000000..2bb6831ec --- /dev/null +++ b/_sources/Use/install_macos.rst.txt @@ -0,0 +1,136 @@ + +Install dependencies on MacOS +--------------------------------- + +First, you will need to install Xcode and the Command Line Tools in order to be able to compile Smilei + + .. code-block:: bash + + xcode-select --install + +and follow the instructions. + +Here we show how to install all dependendencies needed by Smilei using Brew or Macports. Please note that you need to install one *and only one* package manager. + +---- + +Brew : install Smilei +^^^^^^^^^^^^^^^^^^^^^^^^ + +This installation procedure has been tested on macOS 10.14.4 + +#. Install `HomeBrew `_ via: + + .. code-block:: bash + + /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + +#. Install Smilei + + .. code-block:: bash + + brew install --HEAD iltommi/brews/smilei + + Smilei executables (``smilei`` and ``smilei_test``) and the python module are now accessible from everywhere. + +#. Install python packages needed for the happi python module: + + .. code-block:: bash + + pip3 install ipython h5py pint sphinx matplotlib scipy + + +Documentation can be opened with + + .. code-block:: bash + + open /usr/local/opt/smilei/share/html/index.html + +To update Smilei with just type + + .. code-block:: bash + + brew upgrade --fetch-HEAD smilei + +---- + +Brew : install dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In case you want ot keep a private version of Smilei where you can make changes to the core code, +you might want to just install the Smilei dependencies to be able to compile Smilei from you directory: + +#. install Smilei dependencies + + .. code-block:: bash + + brew install iltommi/brews/smilei --HEAD --only-dependencies + +#. Edit your ``.bash_profile`` (or ``.zprofile`` on Catalina) hidden file located in your home folder: + + .. code-block:: bash + + open ~/.bash_profile + + and add the following lines at the end: + + .. code-block:: bash + + export OMPI_CXX=g++-11 + export HDF5_ROOT_DIR=`brew --prefix`/opt/hdf5-parallel + export PYTHONEXE=python3 + +#. In a new terminal window, you can now compile :program:`smilei` (see :ref:`compile` for other options) + +---- + +Macports : install dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Please note that these guidelines might be slightly outdated. Tested on Mojave in january 2021** + +If you find any error, please fill an issue on GitHub: https://github.com/SmileiPIC/Smilei/issues + +This installation procedure relies on the software `MacPorts `_ +that you can install following `these instructions `_. + +#. In a terminal, run the following command to install the C++ compiler with MPI and HDF5: + + .. code-block:: bash + + sudo port -N install openmpi-gcc10 +threads + sudo port select --set mpi openmpi-gcc10-fortran + sudo port -N install hdf5 +openmpi+gcc10 + +#. Edit your ``.bash_profile`` hidden file located in your home folder: + + .. code-block:: bash + + open ~/.bash_profile + + and add the following lines at the end: + + .. code-block:: bash + + export HDF5_ROOT_DIR=/opt/local + export PYTHONEXE=python3 + +#. Python should be already installed by default, but in case you need + a specific version, run: + + .. code-block:: bash + + sudo port -N install python38 + sudo port select --set python3 python38 + +#. If you wish to run the Python post-processing scripts provided in :program:`Smilei`, + you need several modules (h5py, numpy, matplotlib, sphinx, pint). + We recommend to install :program:`IPython` which includes some of these. + + .. code-block:: bash + + sudo port -N install py38-h5py # mandatory for opening any HDF5 file + sudo port -N install py38-matplotlib # plottting + sudo port -N install py38-pint # only for auto unit conversion + sudo port -N install py38-ipython # nicer python console + sudo port -N install py38-sphinx # only for building the doc diff --git a/_sources/Use/install_supercomputer.rst.txt b/_sources/Use/install_supercomputer.rst.txt new file mode 100644 index 000000000..0ab2310f9 --- /dev/null +++ b/_sources/Use/install_supercomputer.rst.txt @@ -0,0 +1,81 @@ +Installation on supercomputers +------------------------------- + +On a large cluster, refer to the administrator to install the requirements +and to choose the compilation options. + +For a few existing machines, we provide instructions in the folder +``scripts/compile_tools/machine``. Each file contains compiler flags +and environment setup to optimize Smilei's performance. + +.. rst-class:: fancy + ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Archer2 `_ | | Archer2 (GNU compiler): ``archer2`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Cori `_ | | Haswell: ``cori_hsw`` | +| | | KNL: ``cori_knl`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Frioul `_ | | ``frioul`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `FUGAKU `_ | | Fujitsu compiler in trad mode : ``fugaku_fujitsu_tm`` | +| | | Fujitsu compiler in clang mode : ``fugaku_fujitsu_cm`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Joliot-Curie `_ | | KNL (Intel compiler): ``joliot_curie_knl`` | +| | | Skylake (Intel compiler): ``joliot_curie_skl`` | +| | | Rome (Intel compiler): ``joliot_curie_rome`` | +| | | A64FX with the GNU compiler: ``joliot_curie_gnu_a64fx`` | +| | | A64FX with the ARM compiler: ``joliot_curie_arm_a64fx`` | +| | | A64FX with the Fujitsu compiler: ``joliot_curie_fujitsu_a64fx`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Jean Zay `_ | | Cascadelake: ``jean_zay`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Jureca `_ | | Haswell: ``jureca`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Marconi `_ | | Broadwell: ``marconi_bdw`` | +| | | KNL: ``marconi_knl`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Occigen `_ | | Haswell: ``occigen`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Ruche `_ | | Cascadelake (Intel): ``ruche`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ +| `Stampede `_ | | KNL: ``stampede2_knl`` | +| | | skylake: ``stampede2_skylake`` | ++---------------------------------------------------------------------------+-----------------------------------------------------------------------+ + + +We also provide instructions for some common architectures: + +- Intel Cascadelake processors: ``cascadelake`` +- Intel Skylake processors: ``skylake`` +- Intel Knights Landing processors: ``knl`` +- Intel Broadwell processors: ``broadwell`` +- Intel Haswell processors: ``haswell`` + +All these files contain: + +* Commented commands that must be executed manually by the user +* Compiler options automatically accounted for during compilation + +To print out the commands to be executed, type ``make machine=target help``. +See, for instance: + +.. code-block:: bash + + $ make machine=occigen help + ... + Machine comments for occigen: + # module purge + # module load intel intelmpi hdf5/1.8.18 qt/4.8.6 python/2.7.12 mesa/17.2.4 VTK/7.0.0 + +After copying and pasting those commands to the terminal, you can use the +command ``make machine=target`` to compile Smilei. For instance: + +.. code-block:: bash + + $ make machine=occigen + + +If your machine is not in this list, please contact your administrator +for help on the installation. You may submit your installation instructions +to the Smilei repository so that we can add your machine to the list. diff --git a/_sources/Use/installation.rst.txt b/_sources/Use/installation.rst.txt new file mode 100644 index 000000000..2ce4fec64 --- /dev/null +++ b/_sources/Use/installation.rst.txt @@ -0,0 +1,213 @@ +Install +------- + +Before installing :program:`Smilei`, you need to install a few dependencies: + +* A C++11 compiler, optionally implementing openMP version > 4.5 + (gcc users: v6.0 or newer recommended) +* an MPI library (by default a version supporting ``MPI_THREAD_MULTIPLE`` + is required: v4.0 or newer recommended) +* an HDF5 library compatible with your versions of C++ and MPI +* Python 2.7 or Python 3+ (with header files) + +Optional dependencies are: + +* Git +* Python modules: sphinx, h5py, numpy, matplotlib, pint +* ffmpeg +* CUDA for NVIDIA GPUs or HIP-SYCL for AMD GPUs (it is recommended to use the already installed software stack and the support team of a supercomputer you have access to). + +---- + +Install the dependencies +^^^^^^^^^^^^^^^^^^^^^^^^ + +There are various ways to install all dependencies, depending on the platform: + +* :doc:`On MacOs` +* :doc:`On Linux` +* :doc:`On a supercomputer` + +The command ``make help`` can give you some information about your environment. + +If you have successfully installed these dependencies on other platforms, +please :doc:`contact us ` and share! + + +---- + +Setup environment variables for compilation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Several environment variables may be required, depending on your setup. + +* ``SMILEICXX``: the MPI-C++ compiler. + Defaults to ``mpicxx``. +* ``HDF5_ROOT_DIR``: the folder for the HDF5 library. + Defaults to ``$HDF5_ROOT``. +* ``BUILD_DIR``: the folder where the compilation should occur. + Defaults to ``./build``. +* ``PYTHONEXE``: the python executable to use in smilei. + Defaults to ``python``. + +The usual ``CXXFLAGS`` and ``LDFLAGS`` can also be used to pass other +arguments to the compiler and linker. + + +---- + +.. _compile: + +Download and compile +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +#. Clone the latest :program:`Smilei` version from Github: + + .. code-block:: bash + + cd /path/of/your/choice/ + git clone https://github.com/SmileiPIC/Smilei.git + + If you do not have ``git``, you can dowload a tarball :ref:`here ` + and extract it in a new folder. + +#. In a terminal, go to that location and compile: + + .. code-block:: bash + + cd Smilei + make + + If the compilation is successful, you should now have a new ``smilei`` executable. + +#. The next step is to :doc:`write a namelist `. + +---- + +Advanced compilation options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. rubric:: Compile with several processors (fast compilation) + +.. code-block:: bash + + make -j 4 + +.. rubric:: Compilation configuration with keyword "config" + +.. code-block:: bash + + make config=debug # With debugging output (slow execution) + make config=noopenmp # Without OpenMP support + make config=no_mpi_tm # Without a MPI library which supports MPI_THREAD_MULTIPLE + make config=scalasca # For the Scalasca profiler + make config=advisor # For Intel Advisor + make config=vtune # For Intel Vtune + make config=inspector # For Intel Inspector + make config=detailed_timers # More detailed timers, but somewhat slower execution + make config=omptasks # use OpenMP task parallelization, not supported by old compilers + make config=part_event_tracing_tasks_off # trace the use particle operators, without task parallelization + make config=part_event_tracing_tasks_on # trace the use particle operators, with OpenMP task parallelization + make config="gpu_nvidia noopenmp" # For Nvidia GPU acceleration + make config="gpu_amd" # For AMD GPU acceleration + +It is possible to combine arguments above within quotes, for instance: + +.. code-block:: bash + + make config="debug noopenmp" # With debugging output, without OpenMP + +However, some arguments may not be compatible, e.g. ``noopenmp`` and ``omptasks``. + +.. rubric:: Obtain some information about the compilation + +.. code-block:: bash + + make print-XXX # Prints the value of makefile variable XXX + make env # Prints the values of all makefile variables + make help # Gets some help on compilation + +.. rubric:: Machine-specific compilation + +Each machine may require a specific configuration (environment variables, +modules, etc.). These instructions may be included in a file of your choice, +via the ``machine`` argument: + +.. code-block:: bash + + make machine=my_machine_file + +where ``my_machine_file`` is a file, located in +``scripts/compile_tools/machine``, containing the lines of command to be +executed before compilation. If you successfully write such a file for +a common supercomputer, please share it with developpers so that it can +be included in the next release of :program:`Smilei`. + +---- + +.. _vectorization_flags: + +Optimization and vectorization options explained +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To tune optimization and vectorization options, :program:`Smilei` uses the *machine files* described above. They contain compiler options for specific hardware architectures or processor families. + +This :doc:`page ` explains in detail optimization flags used in machine files and therefore how to generate your own machine file. + +---- + +Create the documentation +^^^^^^^^^^^^^^^^^^^^^^^^ + +If you have installed the python module ``sphinx``, you can create the +documentation (which you are currently reading) with: + +.. code-block:: bash + + make doc + +This creates a local *html* website accessible in your ``build/html/`` folder. + +---- + +.. _installModule: + +Install the happi module +^^^^^^^^^^^^^^^^^^^^^^^^ + +A python module, ``happi``, is provided to view, extract and post-process +data from all the diagnostics. +There are several ways to load this module in python. + +1. Recommended: + + .. code-block:: bash + + make happi + + This has to be done only once, unless you move the smilei directory elsewhere. + This command creates a small file in the Python *user-site* directory that tells python + where to find the module. + To remove it use the command ``make uninstall_happi``. + + The module will directly be accessible from *python*:: + + >>> import happi + +2. Alternative: Execute the ``Diagnostics.py`` script from python + + Adding a new *python* module is not always possible. + Instead, we provide the script ``Diagnostics.py`` which is able to find the + ``happi`` module and import it into *python*. + + You may add the following command in your own python script:: + + >>> execfile("/path/to/Smilei/scripts/Diagnostics.py") + +---- + +Install the ``smilei_tables`` tool +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generation of the tables is handled by an external tools. +A full documentation is available on :doc:`the dedicated page `. diff --git a/_sources/Use/laser_offset.rst.txt b/_sources/Use/laser_offset.rst.txt new file mode 100644 index 000000000..d77e19068 --- /dev/null +++ b/_sources/Use/laser_offset.rst.txt @@ -0,0 +1,195 @@ +Laser propagation preprocessing +----------------------------------- + +In Smilei, :ref:`Lasers` are provided as oscillating fields at the box boundaries. +For instance, at the ``xmin`` boundary of a 3D cartesian box, the user may define the +:math:`B_y(y,z,t)` and :math:`B_z(y,z,t)` profiles. But in some cases, the laser field +only known analytically at some arbitrary plane that does not coincide with the box +boundary. This appears typically in the case of tightly-focused beams that cannot be +described with a paraxial approximation. + +At the beginning of the simulation (during the initialization), Smilei is able to perform +a laser *backwards* propagation from an arbitrary plane to the box boundary. The +calculated field is then injected from then boundary like a normal laser. From the user's +perspective, this simply requires the definition of the laser profile at some arbitrary +plane. + +The general technique is taken from [Thiele2016]_ but it has been improved for parallel +computation in both 2D and 3D geometries. Further below, another improvement is presented: +the propagation towards a tilted plane. + +---- + +Theoretical background +^^^^^^^^^^^^^^^^^^^^^^^^ + +The method employed for the propagation preprocessing is similar to the *angular spectrum +method*. We illustrate this method on an arbitrary scalar field :math:`A`, but it is +valid for all components of a field satisfying a wave equation: + + .. math:: + + c^2 \Delta A(x,y,z,t) = \partial_t^2 A(x,y,z,t) + +The 3D Fourier transform of this equation for the variables :math:`y`, :math:`z` and +:math:`t` gives: + + .. math:: + + (\partial_x^2 + k_x^2) \hat A(x,k_y,k_z,\omega) = 0 + +where :math:`k_y`, :math:`k_z` and :math:`\omega` are the conjugate variables in the +frequency domain, and :math:`k_x(k_y,k_z,\omega) \equiv \sqrt{\omega^2/c^2-k_y^2-k_z^2}`. +This equation has general solutions proportional to :math:`\exp(-i k_x x)` for waves +propagating towards positive :math:`x`. This means that, if the profile is known at some +plane :math:`x=x_0+\delta`, the profile at :math:`x=x_0` is obtained after multiplying +:math:`\hat A` by :math:`\exp(i k_x \delta)`: + + .. math:: + + \hat A(x_0,k_y,k_z,\omega) = \exp(i k_x \delta) \hat A(x_0+\delta,k_y,k_z,\omega) + +To recover the field profile in real space, a 3D inverse Fourier transform would be +sufficient. However, storing all values of the :math:`(y,z,t)` profile would consume too +much time and disk space. +Instead, Smilei does only a 2D inverse Fourier transform on :math:`k_y` and +:math:`k_z`. This results in a :math:`\tilde A(y,z,\omega)` profile, where :math:`\omega` are +the temporal Fourier modes. Keeping only a few of these modes (the most intense ones) +ensures a reasonable disk space usage. + +The full :math:`A(y,z,t)` profile is calculated during the actual PIC simulation, summing +over the different :math:`\omega`. + +---- + +Numerical process +^^^^^^^^^^^^^^^^^^ + +Let us summarize how the calculation above is realized numerically. We suppose that the +grid is 3D cartesian with the number of cells :math:`(N_x, N_y, N_z)` in the three +directions, but the same process works in 2D. We write :math:`N_t` the total number of +timesteps. + +**The points 1 to 7 are realized during initialization.** + +.. rubric:: 1. The user profile :math:`B(y, z, t)` is sampled + +.. + + This profile corresponds to the magnetic field at the plane :math:`x=x_0+\delta`. + Smilei calculates an array of size :math:`(N_y, N_z, N_t)` sampling + this profile for all points of this plane, and all times of the simulation. + +.. rubric:: 2. Smilei calculates the 3D Fourier transform along y, z and t + +.. + + Using the FFT capabilities of the *numpy* python package, a parallel Fourier transform + is achieved, giving a transformed array of the same size :math:`(N_y, N_z, N_t)`. + This array represents :math:`\hat B(k_y,k_z,\omega)` + +.. rubric:: 3. Frequencies with the most intense values are selected + +.. + + Summing for all :math:`k_y` and :math:`k_z` provides a (temporal) spectrum of the wave. + By default, the 100 frequencies giving the strongest values of this spectrum are kept, + but this can be changed in the namelist (see :py:data:`keep_n_strongest_modes`). + The resulting array is of size :math:`(N_y, N_z, 100)`. + +.. rubric:: 4. The array is multiplied by the propagation term + +.. + + This term :math:`\exp(i k_x \delta)` depends on the coordinates of the array because + :math:`k_x` is a function of :math:`k_y`, :math:`k_z` and :math:`\omega`. + Note that the :math:`\delta` corresponds to the attribute :py:data:`offset`. + +.. rubric:: 5. The inverse 2D Fourier transform is computed + +.. + + This provides an array representing :math:`\tilde B(y,z,\omega)` + +.. rubric:: 6. The array is stored in an HDF5 file + +.. + + This file is named ``LaserOffset0.h5``, ``LaserOffset1.h5``, etc. if there are several + lasers. + + +.. rubric:: 7. Each patch reads the part of the array that it owns + +.. + + This means that each patch of the PIC mesh will own a distinct portion of the overall + array. + + +**The point 8 is realized at runtime, for each iteration.** + +.. rubric:: 8. For each timestep, the laser profile is calculated + +.. + + The 100 selected modes are summed according to + + .. math:: + + B(y,z,t) = f(y,z,t) \sum_\omega \left| \tilde B(y,z,\omega) \right| \sin\left(\omega t + \phi(y,z,\omega)\right) + + where :math:`\phi` is the complex argument of :math:`\tilde B` and :math:`f(y,z,t)` is + an additional :py:data:`extra_envelope`, defined by the user. + This envelope helps removing spurious repetitions of the laser pulse that can + occur due to the limited number of frequencies that are kept. + + +---- + +Tilted plane +^^^^^^^^^^^^^ + +The method above describes a wave propagation between two parallel planes. In Smilei, a +technique inspired from [Matsushima2003]_ allows for the propagation from a title plane. + +This rotation happens in the Fourier space: wave vectors :math:`k_x` and :math:`k_y` are +rotated around :math:`k_z` by an angle :math:`\theta`, according to + +.. math:: + + \begin{array}{rcl} + k_x & = & k_x^\prime \cos\theta - k_y^\prime \sin\theta \\ + k_y & = & k_x^\prime \sin\theta + k_y^\prime \cos\theta \\ + k_z & = & k_z^\prime + \end{array} + +This transforms :math:`\hat A(x,k_y,k_z,\omega)` into +:math:`\hat A^\prime(x,k_y^\prime,k_z,\omega)`, thus the operation is merely a change of one +variable (:math:`k_y`). + +Numerically, the process is not that straightforward because :math:`\hat A^\prime` is an +array in which the axis :math:`k_y^\prime` is linearly sampled, but the corresponding +values :math:`k_y` do not match this linear sampling. We developed an interpolation method +to obtain the transformed values at any point. + +In the end, the prescribed laser profile lies in a plane located at a distance +:math:`\delta` and rotated around :math:`z` by an angle :math:`\theta`, according to the +following figure. + +.. figure:: /_static/LaserOffsetAngle.png + :width: 9cm + + The position of the plane where the laser profile is defined, with respect to the box. + + +---- + +References +^^^^^^^^^^ + +.. [Matsushima2003] `K. Matsushima et al., J. Opt. Soc. Am. A 20, 1755 (2003) `_ + +.. [Thiele2016] `I. Thiele et al., J. Comput. Phys. 321, 1110 (2016) `_ + + diff --git a/_sources/Use/maxwell-juttner.rst.txt b/_sources/Use/maxwell-juttner.rst.txt new file mode 100644 index 000000000..e88af5606 --- /dev/null +++ b/_sources/Use/maxwell-juttner.rst.txt @@ -0,0 +1,57 @@ +Sampling a Maxwell-Jüttner distribution +--------------------------------------- + +We base our method on that described in the Appendix B of +an `article by Schnittman and Krolik `_. + +The Maxwell-Jüttner distribution, as a function of the Lorentz factor :math:`\gamma`, reads + +.. math:: + + f(\gamma) = \gamma^2 \beta + \exp\left(- \frac {\gamma}{\theta} \right) + +where :math:`\theta` is the temperature divided by :math:`mc^2`. +It is problematic that the change of variable :math:`\gamma/\theta` is impossible, because +it requires the cumulative distribution function to be computed for every different temperature. + +Instead, the "rejection method" makes it possible to choose another function :math:`g(\gamma)` +such that :math:`g(\gamma)>f(\gamma)` everywhere. It can be chosen so that the cumulative +distribution function :math:`G(\gamma)` is easy to inverse. First, we take a random +number :math:`U_1` between 0 and 1, and sample the value :math:`\gamma_1=G^{-1}(U_1)`. +Second, we pick another random number :math:`U_2`, and if :math:`U_2f(\gamma)` and which has the cumulative distribution function + +.. math:: + + G(\gamma) = \int_1^\gamma g(x) dx = 1 - \exp\left[H(\gamma/\theta)-H(1/\theta)\right] + +where :math:`H(u) = -u +\ln(1+u+u^2/2)`. + +The rejection methods proceeds as + +1. pick a random :math:`U_1` +2. calculate :math:`\gamma_1=G^{-1}(U_1)=\theta\; H^{-1}[\ln(1-U_1)+H(1/\theta)]` +3. pick a random :math:`U_2` +4. select :math:`\gamma_1` if :math:`U_2<\sqrt{1-\gamma_1^{-2}}`, otherwise restart from point 1 + +Now, to do this, we need to know :math:`H^{-1}`, which is not easy. We choose to tabulate it +in Smilei. For :math:`X>-\exp(-26)`, we use the series development :math:`H^{-1}(X) = (-6X)^{1/3}`. +For :math:`X<-\exp(12)`, we use the fit :math:`H^{-1}(X) = -X + 11.35(-X)^{0.06}`. +For all points in between, the function is linearly interpolated in log-log scale over 1000 +tabulated values. + +Note that the rejection method requires to pick several random numbers if the functions +:math:`f` and :math:`g` differ significantly. This strongly slows the calculation down +when the temperature is non-relativistic. For this reason, we fall back to the +Maxwell-Boltzmann distribution when :math:`\theta<0.1`. \ No newline at end of file diff --git a/_sources/Use/namelist.rst.txt b/_sources/Use/namelist.rst.txt new file mode 100644 index 000000000..997a4f18f --- /dev/null +++ b/_sources/Use/namelist.rst.txt @@ -0,0 +1,3590 @@ +Write a namelist +---------------- + +Before you run :program:`Smilei`, you need a *namelist* (an input file). The namelist +is written in the *python* language. It is thus recommended to know the basics of *python*. + +We suggest you copy one existing namelist from the folder *benchmarks*. +All namelists have the extension ``.py``. + + +---- + +General rules +^^^^^^^^^^^^^ + +* :program:`Smilei` requires a few *blocks* to be defined, such as:: + + Main( + # ... + timestep = 0.01, # defines the timestep value + grid_length = [10., 20.], # defines the 2D box dimensions + # ... + ) + + Outside blocks, you can calculate anything you require. + Inside a block, you must only define variables for :program:`Smilei`. + +* The *python* syntax requires special indentation of each line. + You begin with no indentation, but you have to **add four spaces at the + beginning of lines inside a group**, and so on. + For instance:: + + if a == 0: + timestep = 0.1 + if b == 1: + timestep = 0.2 + else: + timestep = 0.3 + +* You will need to use `lists `_, + which are series of things in *python*, + defined between brackets ``[]`` and separated by commas. + For example, ``mean_velocity = [0., 1.1, 3.]``. + +* You are free to import any installed *python* package into the namelist. + For instance, you may obtain :math:`\pi` using ``from math import pi``. + +* All quantities are normalized to arbitrary values: see :doc:`/Understand/units`. + +---- + +Python workflow +^^^^^^^^^^^^^^^ + +*Python* is started at the beginning of the simulation (one *python* interpreter +for each MPI process). The following steps are executed: + +#. A few variables from :program:`Smilei` are passed to *python* so that they are + available to the user: + + * The rank of the current MPI process as :py:data:`smilei_mpi_rank`. + * The total number of MPI processes as :py:data:`smilei_mpi_size`. + * The maximum random integer as :py:data:`smilei_rand_max`. + +#. The namelist(s) is executed. + +#. *Python* runs :py:data:`preprocess()` if the user has defined it. + This is a good place to calculate things that are not needed for + post-processing with :program:`happi`. + +#. The simulation is initialized (including field and particle arrays). + +#. *Python* runs :py:data:`cleanup()` if the user has defined it. + This is a good place to delete unused heavy variables. + +#. *Python* checks whether the *python* interpreter is needed during the simulation + (e.g. the user has defined a temporal :doc:`profile ` which requires *python* + to calculate it every timestep). Otherwise, *python* is stopped. + +All these instructions are summarized in a file ``smilei.py``, +so that the user can directly run ``python -i smilei.py`` for post-processing purposes. + +---- + +Main variables +^^^^^^^^^^^^^^ + +The block ``Main`` is **mandatory** and has the following syntax:: + + Main( + geometry = "1Dcartesian", + interpolation_order = 2, + interpolator = "momentum-conserving", + grid_length = [16. ], + cell_length = [0.01], + simulation_time = 15., + timestep = 0.005, + number_of_patches = [64], + cluster_width = 5, + maxwell_solver = 'Yee', + EM_boundary_conditions = [ + ["silver-muller", "silver-muller"], + # ["silver-muller", "silver-muller"], + # ["silver-muller", "silver-muller"], + ], + time_fields_frozen = 0., + reference_angular_frequency_SI = 0., + print_every = 100, + random_seed = 0, + ) + +.. py:data:: geometry + + The geometry of the simulation: + + * ``"1Dcartesian"`` + * ``"2Dcartesian"`` + * ``"3Dcartesian"`` + * ``"AMcylindrical"``: cylindrical geometry with :doc:`/Understand/azimuthal_modes_decomposition`. + + In the following documentation, all references to dimensions or coordinates + depend on the ``geometry``. + 1D, 2D and 3D stand for 1-dimensional, 2-dimensional and 3-dimensional cartesian + geometries, respectively. All coordinates are ordered as :math:`(x)`, :math:`(x,y)` or :math:`(x,y,z)`. + In the ``"AMcylindrical"`` case, all grid coordinates are 2-dimensional + :math:`(x,r)`, while particle coordinates (in :ref:`Species`) + are expressed in the 3-dimensional Cartesian frame :math:`(x,y,z)`. + + .. warning:: + + The ``"AMcylindrical"`` geometry has some restrictions. + Boundary conditions must be set to ``"remove"`` for particles, + ``"silver-muller"`` for longitudinal EM boundaries and + ``"buneman"`` for transverse EM boundaries. + You can alternatively use ``"PML"`` for any EM boundary. + Collisions and + order-4 interpolation are not supported yet. + +.. py:data:: interpolation_order + + :default: ``2`` + + Interpolation order, defines particle shape function: + + * ``2`` : 3 points stencil, supported in all configurations. + * ``4`` : 5 points stencil, not supported in vectorized 2D geometry. + +.. py:data:: interpolator + + :default: ``"momentum-conserving"`` + + * ``"momentum-conserving"`` + * ``"wt"`` + + The interpolation scheme to be used in the simulation. + ``"wt"`` is for the timestep dependent field interpolation scheme described in + `this paper `_ . + +.. py:data:: grid_length + number_of_cells + + A list of numbers: size of the simulation box for each dimension of the simulation. + * Either ``grid_length``, the simulation length in each direction in units of :math:`L_r`, + * or ``number_of_cells``, the number of cells in each direction. + + +.. py:data:: cell_length + + A list of floats: sizes of one cell in each direction in units of :math:`L_r`. + + +.. py:data:: simulation_time + number_of_timesteps + + Duration of the simulation. + * Either ``simulation_time``, the simulation duration in units of :math:`T_r`, + * or ``number_of_timesteps``, the total number of timesteps. + + +.. py:data:: timestep + timestep_over_CFL + + Duration of one timestep. + * Either ``timestep``, in units of :math:`T_r`, + * or ``timestep_over_CFL``, in units of the *Courant–Friedrichs–Lewy* (CFL) time. + +.. py:data:: gpu_computing + + :default: ``False`` + Activates GPU acceleration if set to True + +.. py:data:: number_of_patches + + A list of integers: the number of patches in each direction. + Each integer must be a power of 2, and the total number of patches must be + greater or equal than the number of MPI processes. + It is also strongly advised to have more patches than the total number of openMP threads. + See :doc:`/Understand/parallelization`.On the other hand, in case of GPU-acceleration it is recommended to use one patch per MPI-rank + (with one MPI-rank per GPU) + + +.. py:data:: patch_arrangement + + :default: ``"hilbertian"`` + + Determines the ordering of patches and the way they are separated into the + various MPI processes. Options are: + + * ``"hilbertian"``: following the Hilbert curve (see :ref:`this explanation`). + * ``"linearized_XY"`` in 2D or ``"linearized_XYZ"`` in 3D: following the + row-major (C-style) ordering. + * ``"linearized_YX"`` in 2D or ``"linearized_ZYX"`` in 3D: following the + column-major (fortran-style) ordering. This prevents the usage of + :ref:`Fields diagnostics` (see :doc:`/Understand/parallelization`). + +.. py:data:: cluster_width + + :default: set to minimize the memory footprint of the particles pusher, especially interpolation and projection processes + + For advanced users. Integer specifying the cluster width along X direction in number of cells. + The "cluster" is a sub-patch structure in which particles are sorted for cache improvement. + ``cluster_width`` must divide the number of cells in one patch (in dimension X). + The finest sorting is achieved with ``cluster_width=1`` and no sorting with ``cluster_width`` equal to the full size of a patch along dimension X. + The cluster size in dimension Y and Z is always the full extent of the patch. + + .. warning:: + + The size of clusters becomes particularly important when :doc:`/Understand/task_parallelization` is used. + +.. py:data:: maxwell_solver + + :default: 'Yee' + + The solver for Maxwell's equations. + Only ``"Yee"`` and ``"M4"`` are available for all geometries at the moment. + ``"Cowan"``, ``"Grassi"``, ``"Lehe"`` and ``"Bouchard"`` are available for ``2DCartesian``. + ``"Lehe"`` and ``"Bouchard"`` are available for ``3DCartesian``. + ``"Lehe"`` is available for ``AMcylindrical``. + The M4 solver is described in `this paper `_. + The Lehe solver is described in `this paper `_. + The Bouchard solver is described in `this thesis p. 109 `_ + +.. py:data:: solve_poisson + + :default: True + + Decides if Poisson correction must be applied or not initially. + +.. py:data:: poisson_max_iteration + + :default: 50000 + + Maximum number of iteration for the Poisson solver. + +.. py:data:: poisson_max_error + + :default: 1e-14 + + Maximum error for the Poisson solver. + +.. py:data:: solve_relativistic_poisson + + :default: False + + Decides if relativistic Poisson problem must be solved for at least one species. + See :doc:`/Understand/relativistic_fields_initialization` for more details. + +.. py:data:: relativistic_poisson_max_iteration + + :default: 50000 + + Maximum number of iteration for the Poisson solver. + +.. py:data:: relativistic_poisson_max_error + + :default: 1e-22 + + Maximum error for the Poisson solver. + +.. py:data:: EM_boundary_conditions + + :type: list of lists of strings + :default: ``[["periodic"]]`` + + The boundary conditions for the electromagnetic fields. Each boundary may have one of + the following conditions: ``"periodic"``, ``"silver-muller"``, ``"reflective"``, ``"ramp??"`` or ``"PML"``. + + | **Syntax 1:** ``[[bc_all]]``, identical for all boundaries. + | **Syntax 2:** ``[[bc_X], [bc_Y], ...]``, different depending on x, y or z. + | **Syntax 3:** ``[[bc_Xmin, bc_Xmax], ...]``, different on each boundary. + + * ``"silver-muller"`` is an open boundary condition. + The incident wave vector :math:`k_{inc}` on each face is defined by + ``"EM_boundary_conditions_k"``. + When using ``"silver-muller"`` as an injecting boundary, + make sure :math:`k_{inc}` is aligned with the wave you are injecting. + When using ``"silver-muller"`` as an absorbing boundary, + the optimal wave absorption on a given face will be along :math:`k_{abs}` + the specular reflection of :math:`k_{inc}` on the considered face. + + * ``"ramp??"`` is a basic, open boundary condition designed + for the spectral solver in ``AMcylindrical`` geometry. + The ``??`` is an integer representing a number of cells + (smaller than the number of ghost cells). + Over the first half, the fields remain untouched. + Over the second half, all fields are progressively reduced down to zero. + + * ``"PML"`` stands for Perfectly Matched Layer. It is an open boundary condition. + The number of cells in the layer must be defined by ``"number_of_pml_cells"``. + It supports laser injection as in ``"silver-muller"``. + If not all boundary conditions are ``PML``, make sure to set ``number_of_pml_cells=0`` on boundaries not using PML. + +.. py:data:: EM_boundary_conditions_k + + :type: list of lists of floats + :default: ``[[1.,0.],[-1.,0.],[0.,1.],[0.,-1.]]`` in 2D + :default: ``[[1.,0.,0.],[-1.,0.,0.],[0.,1.,0.],[0.,-1.,0.],[0.,0.,1.],[0.,0.,-1.]]`` in 3D + + For ``silver-muller`` absorbing boundaries, + the *x,y,z* coordinates of the unit wave vector ``k`` incident on each face + (sequentially Xmin, Xmax, Ymin, Ymax, Zmin, Zmax). + The number of coordinates is equal to the dimension of the simulation. + The number of given vectors must be equal to 1 or to the number of faces + which is twice the dimension of the simulation. In cylindrical geometry, + ``k`` coordinates are given in the ``xr`` frame and only the Rmax face is affected. + + | **Syntax 1:** ``[[1,0,0]]``, identical for all boundaries. + | **Syntax 2:** ``[[1,0,0],[-1,0,0], ...]``, different on each boundary. + +.. py:data:: number_of_pml_cells + + :type: List of lists of integers + :default: ``[[10,10],[10,10],[10,10]]`` + + Defines the number of cells in the ``"PML"`` layers using the same alternative syntaxes as ``"EM_boundary_conditions"``. + +.. rst-class:: experimental + +.. py:data:: pml_sigma + + :type: List of profiles + :default: [lambda x : 20 * x**2] + + Defines the sigma profiles across the transverse dimension of the PML for each dimension of the simulation. + It must be expressed as a list of profiles (1 per dimension). + + If a single profile is given, it will be used for all dimensions. + + For a given dimension, the same profile is applied to both sides of the domain. + + The profile is given as a single variable function defined on the interval [0,1] where 0 is the inner bound of the PML and 1 is the outer bound of the PML. + Please refer to :doc:`/Understand/PML` if needed in AM geometry. + +.. rst-class:: experimental + +.. py:data:: pml_kappa + + :type: List of profiles + :default: [lambda x : 1 + 79 * x**4] + + Defines the kappa profiles across the transverse dimension of the PML for each dimension of the simulation. + It must be expressed as a list of profiles (1 per dimension). + + If a single profile is given, it will be used for all dimensions. + + For a given dimension, the same profile is applied to both sides of the domain. + + The profile is given as a single variable function defined on the interval [0,1] where 0 is the inner bound of the PML and 1 is the outer bound of the PML. + Please refer to :doc:`/Understand/PML` if needed in AM geometry. + +.. py:data:: time_fields_frozen + + :default: 0. + + Time, at the beginning of the simulation, during which fields are frozen. + + +.. _reference_angular_frequency_SI: + +.. py:data:: reference_angular_frequency_SI + + The value of the reference angular frequency :math:`\omega_r` in SI units, + **only needed when collisions, ionization, radiation losses + or multiphoton Breit-Wheeler pair creation are requested**. + This frequency is related to the normalization length according to :math:`L_r\omega_r = c` + (see :doc:`/Understand/units`). + + +.. py:data:: print_every + + Number of timesteps between each info output on screen. By default, 10 outputs per + simulation. + + +.. py:data:: print_expected_disk_usage + + :default: ``True`` + + If ``False``, the calculation of the expected disk usage, that is usually printed in the + standard output, is skipped. This might be useful in rare cases where this calculation + is costly. + + +.. py:data:: random_seed + + :default: 0 + + The value of the random seed. Each patch has its own random number generator, with a seed + equal to ``random_seed`` + the index of the patch. + +.. py:data:: number_of_AM + + :type: integer + :default: 2 + + The number of azimuthal modes used for the Fourier decomposition in ``"AMcylindrical"`` geometry. + The modes range from mode 0 to mode ``"number_of_AM-1"``. + +.. py:data:: number_of_AM_classical_Poisson_solver + + :default: 1 + + The number of azimuthal modes used for the field initialization with non relativistic Poisson solver in ``"AMcylindrical"`` geometry. + Note that this number must be lower or equal to the number of modes of the simulation. + +.. py:data:: number_of_AM_relativistic_field_initialization + + :default: 1 + + The number of azimuthal modes used for the relativistic field initialization in ``"AMcylindrical"`` geometry. + Note that this number must be lower or equal to the number of modes of the simulation. + + .. py:data:: use_BTIS3_interpolation + + :default: ``False`` + + If ``True``, the B-translated interpolation scheme 3 (or B-TIS3) described in :doc:`/Understand/algorithms` is used. + +.. py:data:: custom_oversize + + :type: integer + :default: 2 + + The number of ghost-cell for each patches. The default value is set accordingly with + the ``interpolation_order`` value. + +.. + .. py:data:: spectral_solver_order + + :type: A list of integers + :default: ``[0,0]`` in AM geometry. + + The order of the spectral solver in each dimension. Set order to zero for infinite order. + In AM geometry, only infinite order is supported along the radial dimension. + +.. + .. py:data:: initial_rotational_cleaning + + :default: ``False`` + + If ``True``, uses the picsar library to do the rotational cleaning. + + Rotational cleaning corrects field initialization in spectral space + in order to make sure that the fields at :math:`t=0` are a valid solution + of the Maxwell equation. + This operation is only supported in AM geometry and with picsar + spectral solver. It requires a FFT of the full domain on a single MPI + process so very large simulations may face problems with this procedure. + +.. + .. py:data:: cell_sorting + + :default: ``False`` + + If ``True``, forces the use of cell sorting for particles. This flag is + automatically set to true if any feature requiring cell sorting is requested + (vectorization, collisions or + particle merging) so it is mainly a convenience for developers. + +---- + +Load Balancing +^^^^^^^^^^^^^^ + +Load balancing (explained :ref:`here `) consists in exchanging +patches (domains of the simulation box) between MPI processes to reduce the +computational load imbalance. +The block ``LoadBalancing`` is optional. If you do not define it, load balancing will +occur every 150 iterations. + +.. code-block:: python + + LoadBalancing( + initial_balance = True, + every = 150, + cell_load = 1., + frozen_particle_load = 0.1 + ) + +.. py:data:: initial_balance + + :default: True + + Decides if the load must be balanced at initialization. If not, the same amount of + patches will be attributed to each MPI rank. + +.. py:data:: every + + :default: 150 + + Number of timesteps between each load balancing **or** a :ref:`time selection `. + The value ``0`` suppresses all load balancing. + +.. py:data:: cell_load + + :default: 1. + + Computational load of a single grid cell considered by the dynamic load balancing algorithm. + This load is normalized to the load of a single particle. + +.. py:data:: frozen_particle_load + + :default: 0.1 + + Computational load of a single frozen particle considered by the dynamic load balancing algorithm. + This load is normalized to the load of a single particle. + +---- + +.. rst-class:: experimental + +Multiple decomposition of the domain +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The block ``MultipleDecomposition`` is necessary for spectral solvers and optional in all other cases. +When present, it activates +the :doc:`/Understand/SDMD` (SDMD) technique +which separates the decomposition of the field grids from that of the particles. +Fields are set on large sub-domain called *regions* (1 region per MPI process) while +particles are kept as small *patches* as in the standard decomposition (many patches per MPI process). +Benefits of this option are illustrated `in this paper `_. + + +.. code-block:: python + + MultipleDecomposition( + region_ghost_cells = 2 + ) + +.. py:data:: region_ghost_cells + + :type: integer + :default: 2 + + The number of ghost cells for each region. + The default value is set accordingly with the ``interpolation_order``. + The same number of ghost cells is used in all dimensions except for spectral solver in AM geometry for which the number of radial ghost cells is always automatically set to be the same as patches. + + +---- + +.. _Vectorization: + +Vectorization +^^^^^^^^^^^^^^^^^^^^^ + +The block ``Vectorization`` is optional. +It controls the SIMD operations that can enhance the performance of some computations. +The technique is detailed in Ref. [Beck2019]_ and summarized in :doc:`this doc `. +It requires :ref:`additional compilation options` to be actived. + +.. code-block:: python + + Vectorization( + mode = "adaptive", + reconfigure_every = 20, + initial_mode = "on" + ) + +.. py:data:: mode + + :default: ``"off"`` + + * ``"off"``: non-vectorized operators are used. + Recommended when the number of particles per cell stays below 10. + * ``"on"``: vectorized operators are used. + Recommended when the number of particles per cell stays above 10. + Particles are sorted per cell. + * ``"adaptive"``: the best operators (scalar or vectorized) + are determined and configured dynamically and locally + (per patch and per species). For the moment this mode is only supported in ``3Dcartesian`` geometry. + Particles are sorted per cell. + + In the ``"adaptive"`` mode, :py:data:`cluster_width` is set to the maximum. + +.. py:data:: reconfigure_every + + :default: 20 + + The number of timesteps between each dynamic reconfiguration of + the vectorized operators, when using the ``"adaptive"`` vectorization mode. + It may be set to a :ref:`time selection ` as well. + + +.. py:data:: initial_mode + + :default: ``off`` + + Default state when the ``"adaptive"`` mode is activated + and no particle is present in the patch. + + +---- + +.. _movingWindow: + +Moving window +^^^^^^^^^^^^^ + +The simulated domain can move relatively to its the initial position. The "moving window" +is (almost) periodically shifted in the ``x_max`` direction. +Each "shift" consists in removing a column of patches from the ``x_min`` border and +adding a new one after the ``x_max`` border, thus changing the physical domain that the +simulation represents but keeping the same box size. This is particularly useful to +*follow* waves or plasma moving at high speed. +The frequency of the shifts is adjusted so that the average displacement velocity +over many shifts matches the velocity given by the user. +The user may ask for a given number of additional shifts at a given time. +These additional shifts are not taken into account for the evaluation of the average +velocity of the moving window. + +The block ``MovingWindow`` is optional. The window does not move it you do not define it. + +.. warning:: + + When the window starts moving, all laser injections via Silver-Muller boundary conditions + are immediately stopped for physical correctness. + +.. code-block:: python + + MovingWindow( + time_start = 0., + velocity_x = 1., + number_of_additional_shifts = 0., + additional_shifts_time = 0., + ) + + +.. py:data:: time_start + + :type: Float. + :default: 0. + + The time at which the window starts moving. + + +.. py:data:: velocity_x + + :type: Float. + :default: 0. + + The average velocity of the moving window in the ``x_max`` direction. It muste be between 0 and 1. + +.. py:data:: number_of_additional_shifts + + :type: Integer. + :default: 0. + + The number of additional shifts of the moving window. + +.. py:data:: additional_shifts_time + + :type: Float. + :default: 0. + + The time at which the additional shifts are done. + + +.. note:: + + The :ref:`particle binning diagnostics ` accept an "axis" called ``moving_x`` + corresponding to the ``x`` coordinate corrected by the moving window's current movement. + +---- + +.. _CurrentFilter: + +Current filtering +^^^^^^^^^^^^^^^^^ + +The present version of :program:`Smilei` provides a +:ref:`multi-pass binomial filter ` on the current densities, +which parameters are controlled in the following block:: + + CurrentFilter( + model = "binomial", + passes = [0], + kernelFIR = [0.25,0.5,0.25] + ) + +.. py:data:: model + + :default: ``"binomial"`` + + The model for current filtering. + + * ``"binomial"`` for a binomial filter. + * ``"customFIR"`` for a custom FIR kernel. + +.. py:data:: passes + + :type: A python list of integers. + :default: ``[0]`` + + The number of passes (at each timestep) given for each dimension. + If the list is of length 1, the same number of passes is assumed for all dimensions. + +.. py:data:: kernelFIR + + :default: ``"[0.25,0.5,0.25]"`` + + The FIR kernel for the ``"customFIR"`` model. The number of coefficients + must be less than twice the number of ghost cells + (adjusted using :py:data:`custom_oversize`). + + +---- + +.. _FieldFilter: + +Field filtering +^^^^^^^^^^^^^^^^^ + +The present version of :program:`Smilei` provides a method for field filtering +(at the moment, only the :ref:`Friedman electric field time-filter ` is available) +which parameters are controlled in the following block:: + + FieldFilter( + model = "Friedman", + theta = 0., + ) + +.. py:data:: model + + :default: ``"Friedman"`` + + The model for field filtering. Presently, only ``"Friedman"`` field filtering is available. + +.. py:data:: theta + + :default: ``0.`` + + The :math:`\theta` parameter (between 0 and 1) of Friedman's method. + + +---- + +.. _Species: + +Species +^^^^^^^ + +Each species has to be defined in a ``Species`` block:: + + Species( + name = "electrons1", + position_initialization = "random", + momentum_initialization = "maxwell-juettner", + regular_number = [], + particles_per_cell = 100, + mass = 1., + atomic_number = None, + #maximum_charge_state = None, + number_density = 10., + # charge_density = None, + charge = -1., + mean_velocity = [0.], + #mean_velocity_AM = [0.], + temperature = [1e-10], + boundary_conditions = [ + ["reflective", "reflective"], + # ["periodic", "periodic"], + # ["periodic", "periodic"], + ], + # thermal_boundary_temperature = None, + # thermal_boundary_velocity = None, + time_frozen = 0.0, + # ionization_model = "none", + # ionization_electrons = None, + # ionization_rate = None, + is_test = False, + pusher = "boris", + + # Radiation reaction, for particles only: + radiation_model = "none", + radiation_photon_species = "photon", + radiation_photon_sampling = 1, + radiation_photon_gamma_threshold = 2, + radiation_max_emissions = 10, + + # Relativistic field initialization: + relativistic_field_initialization = "False", + + # For photon species only: + multiphoton_Breit_Wheeler = ["electron","positron"], + multiphoton_Breit_Wheeler_sampling = [1,1] + + # Merging + merging_method = "vranic_spherical", + merge_every = 5, + merge_min_particles_per_cell = 16, + merge_max_packet_size = 4, + merge_min_packet_size = 4, + merge_momentum_cell_size = [16,16,16], + ) + +.. py:data:: name + + The name you want to give to this species. + It should be more than one character and can not start with ``"m_"``. + +.. py:data:: position_initialization + + The method for initialization of particle positions. Options are: + + * ``"regular"`` for regularly spaced. See :py:data:`regular_number`. + * ``"random"`` for randomly distributed. + * ``"centered"`` for centered in each cell (not supported in ``AMcylindrical`` geometry. + * The :py:data:`name` of another species from which the positions are copied. + The *source* species must have positions initialized using one of the three + other options above, and must be defined before this species. + * A *numpy* array or an *HDF5* file defining all the positions of the particles. + In this case you must also provide the weight of each particle (see :ref:`Weights`). + See :doc:`particle_initialization`. + + +.. py:data:: regular_number + + :type: A list of as many integers as the simulation dimension + + When ``position_initialization = "regular"``, this sets the number of evenly-spaced + particles per cell in each direction: ``[Nx, Ny, Nz]`` in cartesian geometries and + ``[Nx, Nr, Ntheta]`` in ``AMcylindrical`` in which case we recommend + ``Ntheta`` :math:`\geq 4\times (` ``number_of_AM`` :math:`-1)`. + If unset, ``particles_per_cell`` must be a power of the simulation dimension, + for instance, a power of 2 in ``2Dcartesian``. + +.. py:data:: momentum_initialization + + The method for initialization of particle momenta. Options are: + + * ``"maxwell-juettner"`` for a relativistic maxwellian (see :doc:`how it is done`) + * ``"rectangular"`` for a rectangular distribution + * ``"cold"`` for zero temperature + * A *numpy* array or an *HDF5* file defining all the momenta of the particles. + See :doc:`particle_initialization`. + + The first 2 distributions depend on the parameter :py:data:`temperature` explained below. + +.. py:data:: particles_per_cell + + :type: float or :doc:`profile ` + + The number of particles per cell. + + +.. py:data:: mass + + The mass of particles, in units of the electron mass :math:`m_e`. + + +.. py:data:: atomic_number + + :default: 0 + + The atomic number of the particles, required only for ionization. + It must be lower than 101. + +.. py:data:: maximum_charge_state + + :default: 0 + + The maximum charge state of a species for which the ionization model is ``"from_rate"``. + +.. py:data:: number_density + charge_density + + :type: float or :doc:`profile ` + + The absolute value of the charge density or number density (choose one only) + of the particle distribution, in units of the reference density :math:`N_r` (see :doc:`/Understand/units`). + + +.. py:data:: charge + + :type: float or :doc:`profile ` + + The particle charge, in units of the elementary charge :math:`e`. + + +.. py:data:: mean_velocity + + :type: a list of 3 floats or :doc:`profiles ` + + The initial drift velocity of the particles, in units of the speed of light :math:`c`, in the `x`, `y` and `z` directions. + + **WARNING**: For massless particles, this is actually the momentum in units of :math:`m_e c`. + +.. py:data:: mean_velocity_AM + + :type: a list of 3 floats or :doc:`profiles ` + + The initial drift velocity of the particles, in units of the speed of light :math:`c`, in the longitudinal, radial and azimuthal directions. + This entry is available only in ``AMcylindrical`` velocity and cannot be used if also ``mean_velocity`` is used in the same ``Species``: only one of the two can be chosen. + + **WARNING**: For massless particles, this is actually the momentum in units of :math:`m_e c`. + + **WARNING**: The initial cylindrical drift velocity is applied to each particle, thus it can be computationally demanding. + +.. py:data:: temperature + + :type: a list of 3 floats or :doc:`profiles ` + + The initial temperature of the particles, in units of :math:`m_ec^2`. + + +.. py:data:: boundary_conditions + + :type: a list of lists of strings + :default: ``[["periodic"]]`` + + The boundary conditions for the particles of this species. + Each boundary may have one of the following conditions: + ``"periodic"``, ``"reflective"``, ``"remove"`` (particles are deleted), + ``"stop"`` (particle momenta are set to 0), and ``"thermalize"``. + For photon species (``mass=0``), the last two options are not available. + + | **Syntax 1:** ``[[bc_all]]``, identical for all boundaries. + | **Syntax 2:** ``[[bc_X], [bc_Y], ...]``, different depending on x, y or z. + | **Syntax 3:** ``[[bc_Xmin, bc_Xmax], ...]``, different on each boundary. + +.. py:data:: thermal_boundary_temperature + + :default: None + + A list of floats representing the temperature of the thermal boundaries (those set to + ``"thermalize"`` in :py:data:`boundary_conditions`) for each spatial coordinate. + Currently, only the first coordinate (x) is taken into account. + +.. py:data:: thermal_boundary_velocity + + :default: [] + + A list of floats representing the components of the particles' drift velocity after + encountering the thermal boundaries (those set to ``"thermalize"`` in :py:data:`boundary_conditions`). + +.. py:data:: time_frozen + + :default: 0. + + The time during which the particles are "frozen", in units of :math:`T_r`. + Frozen particles do not move and therefore do not deposit any current density either. + Nonetheless, they deposit a charge density. + They are computationally much cheaper than non-frozen particles and oblivious to any EM-fields + in the simulation. Note that frozen particles can be ionized (this is computationally much cheaper + if ion motion is not relevant). + +.. py:data:: ionization_model + + :default: ``"none"`` + + The model for ionization: + + * ``"tunnel"`` for :ref:`field ionization ` (requires species with an :py:data:`atomic_number`) + * ``"tunnel_envelope_averaged"`` for :ref:`field ionization with a laser envelope ` + * ``"from_rate"``, relying on a :ref:`user-defined ionization rate ` (requires species with a :py:data:`maximum_charge_state`). + +.. py:data:: ionization_rate + + A python function giving the user-defined ionisation rate as a function of various particle attributes. + To use this option, the `numpy package `_ must be available in your python installation. + The function must have one argument, that you may call, for instance, ``particles``. + This object has several attributes ``x``, ``y``, ``z``, ``px``, ``py``, ``pz``, ``charge``, ``weight`` and ``id``. + Each of these attributes are provided as **numpy** arrays where each cell corresponds to one particle. + + The following example defines, for a species with maximum charge state of 2, + an ionization rate that depends on the initial particle charge + and linear in the x coordinate: + + .. code-block:: python + + from numpy import exp, zeros_like + + def my_rate(particles): + rate = zeros_like(particles.x) + charge_0 = (particles.charge==0) + charge_1 = (particles.charge==1) + rate[charge_0] = r0 * particles.x[charge_0] + rate[charge_1] = r1 * particles.x[charge_1] + return rate + + Species( ..., ionization_rate = my_rate ) + +.. py:data:: ionization_electrons + + The name of the electron species that :py:data:`ionization_model` uses when creating new electrons. + + +.. py:data:: is_test + + :default: ``False`` + + Flag for test particles. If ``True``, this species will contain only test particles + which do not participate in the charge and currents. + + +.. .. py:data:: c_part_max +.. +.. :red:`to do` +.. + +.. py:data:: pusher + + :default: ``"boris"`` + + Type of pusher to be used for this species. Options are: + + * ``"boris"``: The relativistic Boris pusher + * ``"borisnr"``: The non-relativistic Boris pusher + * ``"vay"``: The relativistic pusher of J. L. Vay + * ``"higueracary"``: The relativistic pusher of A. V. Higuera and J. R. Cary + * ``"norm"``: For photon species only (rectilinear propagation) + * ``"ponderomotive_boris"``: modified relativistic Boris pusher for species interacting with the laser envelope model. Valid only if the species has non-zero mass + * ``"borisBTIS3"``: as ``"boris"``, but using B fields interpolated with the B-TIS3 scheme. + * ``"ponderomotive_borisBTIS3"``: as ``"ponderomotive_boris"``, but using B fields interpolated with the B-TIS3 scheme. + + **WARNING**: ``"borisBTIS3"`` and ``"ponderomotive_borisBTIS3"`` can be used only when ``use_BTIS3_interpolation=True`` in the ``Main`` block. + +.. py:data:: radiation_model + + :default: ``"none"`` + + The **radiation reaction** model used for this species (see :doc:`/Understand/radiation_loss`). + + * ``"none"``: no radiation + * ``"Landau-Lifshitz"`` (or ``ll``): Landau-Lifshitz model approximated for high energies + * ``"corrected-Landau-Lifshitz"`` (or ``cll``): with quantum correction + * ``"Niel"``: a `stochastic radiation model `_ based on the work of Niel `et al.`. + * ``"Monte-Carlo"`` (or ``mc``): Monte-Carlo radiation model. This model can be configured to generate macro-photons with :py:data:`radiation_photon_species`. + + This parameter cannot be assigned to photons (mass = 0). + + Radiation is emitted only with the ``"Monte-Carlo"`` model when + :py:data:`radiation_photon_species` is defined. + +.. py:data:: radiation_photon_species + + The :py:data:`name` of the photon species in which the Monte-Carlo :py:data:`radiation_model` + will generate macro-photons. If unset (or ``None``), no macro-photon will be created. + The *target* photon species must be have its mass set to 0, and appear *after* the + particle species in the namelist. + + This parameter cannot be assigned to photons (mass = 0). + +.. py:data:: radiation_photon_sampling + + :default: ``1`` + + The number of macro-photons generated per emission event, when the macro-photon creation + is activated (see :py:data:`radiation_photon_species`). The total macro-photon weight + is still conserved. + + A large number may rapidly slow down the performances and lead to memory saturation. + + This parameter cannot be assigned to photons (mass = 0). + +.. py:data:: radiation_max_emissions + + :default: ``10`` + + The maximum number of emission Monte-Carlo event a macro-particle can undergo during a timestep. + Since this value is used to allocate some buffers, a high value can saturate memory. + + This parameter cannot be assigned to photons (mass = 0). + +.. py:data:: radiation_photon_gamma_threshold + + :default: ``2`` + + The threshold on the photon energy for the macro-photon emission when using the + radiation reaction Monte-Carlo process. + Under this threshold, the macro-photon from the radiation reaction Monte-Carlo + process is not created but still taken into account in the energy balance. + The default value corresponds to twice the electron rest mass energy that + is the required energy to decay into electron-positron pairs. + + This parameter cannot be assigned to photons (mass = 0). + +.. py:data:: relativistic_field_initialization + + :default: ``False`` + + Flag for relativistic particles. If ``True``, the electromagnetic fields of this species will added to the electromagnetic fields already present in the simulation. + This operation will be performed when time equals :py:data:`time_frozen`. See :doc:`/Understand/relativistic_fields_initialization` for details on the computation of the electromagentic fields of a relativistic species. + To have physically meaningful results, we recommend to place a species which requires this method of field initialization far from other species, otherwise the latter could experience instantly turned-on unphysical forces by the relativistic species' fields. + + + +.. py:data:: multiphoton_Breit_Wheeler + + :default: ``[None,None]`` + + An list of the :py:data:`name` of two species: electrons and positrons created through + the :doc:`/Understand/multiphoton_Breit_Wheeler`. + By default, the process is not activated. + + This parameter can **only** be assigned to photons species (mass = 0). + +.. py:data:: multiphoton_Breit_Wheeler_sampling + + :default: ``[1,1]`` + + A list of two integers: the number of electrons and positrons generated per photon decay + in the :doc:`/Understand/multiphoton_Breit_Wheeler`. The total macro-particle weight is still + conserved. + + Large numbers may rapidly slow down the performances and lead to memory saturation. + + This parameter can **only** be assigned to photons species (mass = 0). + +.. py:data:: keep_interpolated_fields + + :default: ``[]`` + + A list of interpolated fields that should be stored in memory for all particles of this species, + instead of being located in temporary buffers. These fields can then + be accessed in some diagnostics such as :ref:`particle binning ` or + :ref:`tracking `. The available fields are ``"Ex"``, ``"Ey"``, ``"Ez"``, + ``"Bx"``, ``"By"`` and ``"Bz"``. + + Additionally, the work done by each component of the electric field is available as + ``"Wx"``, ``"Wy"`` and ``"Wz"``. Contrary to the other interpolated fields, these quantities + are accumulated over time. + +---- + +.. _Particle_injector: + +Particle Injector +^^^^^^^^^^^^^^^^^ + +Injectors enable to inject macro-particles in the simulation domain from the boundaries. +By default, some parameters that are not specified are inherited from the associated :py:data:`species`. + +Each particle injector has to be defined in a ``ParticleInjector`` block:: + + ParticleInjector( + name = "injector1", + species = "electrons1", + box_side = "xmin", + time_envelope = tgaussian(start=0, duration=10., order=4), + + # Parameters inherited from the associated ``species`` by default + + position_initialization = "species", + momentum_initialization = "rectangular", + mean_velocity = [0.5,0.,0.], + temperature = [1e-30], + number_density = 1, + particles_per_cell = 16, + ) + +.. py:data:: name + + The name you want to give to this injector. + If you do not specify a name, it will be attributed automatically. + The name is useful if you want to inject particles at the same position of another injector. + +.. py:data:: species + + The name of the species in which to inject the new particles + +.. py:data:: box_side + + From where the macro-particles are injected. Options are: + + * ``"xmin"`` + * ``"xmax"`` + * ``"ymin"`` + * ``"ymax"`` + * ``"zmax"`` + * ``"zmin"`` + +.. py:data:: time_envelope + + :type: a *python* function or a :doc:`time profile ` + :default: ``tconstant()`` + + The temporal envelope of the injector. + +.. py:data:: position_initialization + + :default: parameters provided the species + + The method for initialization of particle positions. Options are: + + * ``"species"`` or empty ``""``: injector uses the option of the specified :py:data:`species`. + * ``"regular"`` for regularly spaced. See :py:data:`regular_number`. + * ``"random"`` for randomly distributed + * ``"centered"`` for centered in each cell + * The :py:data:`name` of another injector from which the positions are copied. + This option requires (1) that the *target* injector's positions are initialized + using one of the three other options above. + +.. py:data:: momentum_initialization + + :default: parameters provided the species + + The method for initialization of particle momenta. Options are: + + * ``"species"`` or empty ``""``: injector uses the option of the specified :py:data:`species`. + * ``"maxwell-juettner"`` for a relativistic maxwellian (see :doc:`how it is done`) + * ``"rectangular"`` for a rectangular distribution + +.. py:data:: mean_velocity + + :type: a list of 3 floats or :doc:`profiles ` + :default: parameters provided the species + + The initial drift velocity of the particles, in units of the speed of light :math:`c`. + + **WARNING**: For massless particles, this is actually the momentum in units of :math:`m_e c`. + +.. py:data:: temperature + + :type: a list of 3 floats or :doc:`profiles ` + :default: parameters provided the species + + The initial temperature of the particles, in units of :math:`m_ec^2`. + +.. py:data:: particles_per_cell + + :type: float or :doc:`profile ` + :default: parameters provided the species + + The number of particles per cell to use for the injector. + +.. py:data:: number_density + charge_density + + :type: float or :doc:`profile ` + :default: parameters provided the species + + The absolute value of the number density or charge density (choose one only) + of the particle distribution, in units of the reference density :math:`N_r` (see :doc:`/Understand/units`) + +.. py:data:: regular_number + + :type: A list of as many integers as the simulation dimension + + Same as for :ref:`species`. When ``position_initialization = "regular"``, this sets the number of evenly-spaced + particles per cell in each direction: ``[Nx, Ny, Nz]`` in cartesian geometries. + +---- + +.. rst-class:: experimental + +.. _Particle_merging: + +Particle Merging +^^^^^^^^^^^^^^^^ + +The macro-particle merging method is documented in +the :doc:`corresponding page `. +Note that for merging to be able to operate either vectorization or cell sorting must be activated. +It is optionnally specified in the ``Species`` block:: + + Species( + .... + + # Merging + merging_method = "vranic_spherical", + merge_every = 5, + merge_min_particles_per_cell = 16, + merge_max_packet_size = 4, + merge_min_packet_size = 4, + merge_momentum_cell_size = [16,16,16], + merge_discretization_scale = "linear", + # Extra parameters for experts: + merge_min_momentum_cell_length = [1e-10, 1e-10, 1e-10], + merge_accumulation_correction = True, + ) + +.. py:data:: merging_method + + :default: ``"none"`` + + The particle merging method to use: + + * ``"none"``: no merging + * ``"vranic_cartesian"``: method of M. Vranic with a cartesian momentum-space decomposition + * ``"vranic_spherical"``: method of M. Vranic with a spherical momentum-space decomposition + +.. py:data:: merge_every + + :default: ``0`` + + Number of timesteps between each merging event + **or** a :ref:`time selection `. + +.. py:data:: min_particles_per_cell + + :default: ``4`` + + The minimum number of particles per cell for the merging. + +.. py:data:: merge_min_packet_size + + :default: ``4`` + + The minimum number of particles per packet to merge. Must be greater or equal to 4. + +.. py:data:: merge_max_packet_size + + :default: ``4`` + + The maximum number of particles per packet to merge. + +.. py:data:: merge_momentum_cell_size + + :default: ``[16,16,16]`` + + A list of 3 integers defining the number of sub-groups in each direction + for the momentum-space discretization. + +.. py:data:: merge_discretization_scale + + :default: ``"linear"`` + + The momentum discretization scale:: ``"linear"`` or ``"log"``. + The ``"log"`` scale only works with the spherical discretization at the moment. + +.. py:data:: merge_min_momentum + + :default: ``1e-5`` + + :red:`[for experts]` The minimum momentum value when the log scale + is chosen (``merge_discretization_scale = log``). + This avoids a potential 0 value in the log domain. + +.. py:data:: merge_min_momentum_cell_length + + :default: ``[1e-10,1e-10,1e-10]`` + + :red:`[for experts]` The minimum sub-group length for the momentum-space + discretization (below which the number of sub-groups is set to 1). + +.. py:data:: merge_accumulation_correction + + :default: ``True`` + + :red:`[for experts]` Activates the accumulation correction + (see :doc:`/Understand/particle_merging` for more information). + The correction only works in linear scale. + + + +---- + +.. _Lasers: + +Lasers +^^^^^^ + +A laser consists in applying oscillating boundary conditions for the magnetic +field on one of the box sides. The only boundary condition that supports lasers +is ``"silver-muller"`` (see :py:data:`EM_boundary_conditions`). +There are several syntaxes to introduce a laser in :program:`Smilei`: + +.. note:: + + The following definitions are given for lasers incoming from the ``xmin`` or ``xmax`` + boundaries. For lasers incoming from ``ymin`` or ``ymax``, replace the ``By`` + profiles by ``Bx`` profiles. For lasers incoming from ``zmin`` or ``zmax``, + replace ``By`` and ``Bz`` profiles by ``Bx`` and ``By`` profiles, respectively. + +.. rubric:: 1. Defining a generic wave + +.. + + .. code-block:: python + + Laser( + box_side = "xmin", + space_time_profile = [ By_profile, Bz_profile ] + space_time_profile_AM = [ Br_mode0, Bt_mode0, Br_mode1, Bt_mode1, ... ] + ) + +.. py:data:: box_side + + :default: ``"xmin"`` + + Side of the box from which the laser originates: ``"xmin"``, ``"xmax"``, ``"ymin"``, + ``"ymax"``, ``"zmin"`` or ``"zmax"``. + + In the cases of ``"ymin"`` or ``"ymax"``, replace, in the following profiles, + coordinates *y* by *x*, and fields :math:`B_y` by :math:`B_x`. + + In the cases of ``"zmin"`` or ``"zmax"``, replace, in the following profiles, + coordinates *y* by *x*, coordinates *z* by *y*, fields :math:`B_y` by :math:`B_x` + and fields :math:`B_z` by :math:`B_y`. + + +.. py:data:: space_time_profile + + :type: A list of two *python* functions + + The full wave expression at the chosen box side. It is a list of **two** *python* + functions taking several arguments depending on the simulation dimension: + :math:`(t)` for a 1-D simulation, :math:`(y,t)` for a 2-D simulation (etc.) + The two functions represent :math:`B_y` and :math:`B_z`, respectively. + This can be used only in Cartesian geometries. + +.. py:data:: space_time_profile_AM + + :type: A list of maximum 2 x ``number_of_AM`` *python* functions. + + These profiles define the first modes of :math:`B_r` and :math:`B_\theta` in the + order shown in the above example. Undefined modes are considered zero. + This can be used only in ``AMcylindrical`` geometry. In this + geometry a two-dimensional :math:`(x,r)` grid is used and the laser is injected from a + :math:`x` boundary, thus the provided profiles must be a function of :math:`(r,t)`. + + + +.. rubric:: 2. Defining the wave envelopes + +.. + + .. code-block:: python + + Laser( + box_side = "xmin", + omega = 1., + chirp_profile = tconstant(), + time_envelope = tgaussian(), + space_envelope = [ By_profile , Bz_profile ], + phase = [ PhiY_profile, PhiZ_profile ], + delay_phase = [ 0., 0. ] + ) + + This implements a wave of the form: + + .. math:: + + B_y(\mathbf{x}, t) = S_y(\mathbf{x})\; T\left(t-t_{0y}\right) + \;\sin\left( \omega(t) t - \phi_y(\mathbf{x}) \right) + + B_z(\mathbf{x}, t) = S_z(\mathbf{x})\; T\left(t-t_{0z}\right) + \;\sin\left( \omega(t) t - \phi_z(\mathbf{x}) \right) + + where :math:`T` is the temporal envelope, :math:`S_y` and :math:`S_z` are the + spatial envelopes, :math:`\omega` is the time-varying frequency, + :math:`\phi_y` and :math:`\phi_z` are the phases, and we defined the delays + :math:`t_{0y} = (\phi_y(\mathbf{x})-\varphi_y)/\omega(t)` and + :math:`t_{0z} = (\phi_z(\mathbf{x})-\varphi_z)/\omega(t)`. + + .. py:data:: omega + + :default: 1. + + The laser angular frequency. + + .. py:data:: chirp_profile + + :type: a *python* function or a :doc:`time profile ` + :default: ``tconstant()`` + + The variation of the laser frequency over time, such that + :math:`\omega(t)=` ``omega`` x ``chirp_profile`` :math:`(t)`. + + .. warning:: + + This definition of the chirp profile is not standard. + Indeed, :math:`\omega(t)` as defined here **is not** the instantaneous frequency, :math:`\omega_{\rm inst}(t)`, + which is obtained from the time derivative of the phase :math:`\omega(t) t`. + + Should one define the chirp as :math:`C(t) = \omega_{\rm inst}(t)/\omega` (with :math:`\omega` defined by the input + parameter :math:`\mathtt{omega}`), the user can easily obtain the corresponding chirp profile as defined in + :program:`Smilei` as: + + .. math:: + + \mathtt{chirp\_profile}(t) = \frac{1}{t} \int_0^t dt' C(t')\,. + + Let us give as an example the case of a *linear chirp*, with the instantaneous frequency + :math:`\omega_{\rm inst}(t) = \omega [1+\alpha\,\omega(t-t_0)]`. + :math:`C(t) = 1+\alpha\,\omega(t-t_0)`. The corresponding input chirp profile reads: + + .. math:: + + \mathtt{chirp\_profile}(t) = 1 - \alpha\, \omega t_0 + \frac{\alpha}{2} \omega t + + Similarly, for a *geometric (exponential) chirp* such that :math:`\omega_{\rm inst}(t) = \omega\, \alpha^{\omega t}`, + :math:`C(t) = \alpha^{\omega t}`, and the corresponding input chirp profile reads: + + .. math:: + + \mathtt{chirp\_profile}(t) = \frac{\alpha^{\omega t} - 1}{\omega t \, \ln \alpha}\,. + + + .. py:data:: time_envelope + + :type: a *python* function or a :doc:`time profile ` + :default: ``tconstant()`` + + The temporal envelope of the laser. + + .. py:data:: space_envelope + + :type: a list of two *python* functions or two :doc:`spatial profiles ` + :default: ``[ 1., 0. ]`` + + The two spatial envelopes :math:`S_y` and :math:`S_z`. + + .. py:data:: phase + + :type: a list of two *python* functions or two :doc:`spatial profiles ` + :default: ``[ 0., 0. ]`` + + The two spatially-varying phases :math:`\phi_y` and :math:`\phi_z`. + + .. py:data:: delay_phase + + :type: a list of two floats + :default: ``[ 0., 0. ]`` + + An extra phase for the time envelopes of :math:`B_y` and :math:`B_z`. Useful in the + case of elliptical polarization where the two temporal profiles might have a slight + delay due to the mismatched :py:data:`phase`. + + + +.. rubric:: 3. Defining a 1D planar wave + +.. + + For one-dimensional simulations, you may use the simplified laser creator:: + + LaserPlanar1D( + box_side = "xmin", + a0 = 1., + omega = 1., + polarization_phi = 0., + ellipticity = 0., + time_envelope = tconstant() + ) + + .. py:data:: a0 + + :default: 1. + + The normalized vector potential + + .. py:data:: polarization_phi + + :default: 0. + + The angle of the polarization ellipse major axis relative to the X-Y plane, in radians. + + .. py:data:: ellipticity + + :default: 0. + + The polarization ellipticity: 0 for linear and :math:`\pm 1` for circular. + + + +.. rubric:: 4. Defining a 2D gaussian wave + +.. + + For two-dimensional simulations, you may use the simplified laser creator:: + + LaserGaussian2D( + box_side = "xmin", + a0 = 1., + omega = 1., + focus = [50., 40.], + waist = 3., + incidence_angle = 0., + polarization_phi = 0., + ellipticity = 0., + time_envelope = tconstant() + ) + + .. py:data:: focus + + :type: A list of two floats ``[X, Y]`` + + The ``X`` and ``Y`` positions of the laser focus. + + .. py:data:: waist + + The waist value. Transverse coordinate at which the field is at 1/e of its maximum value. + + .. py:data:: incidence_angle + + :default: 0. + + The angle of the laser beam relative to the normal to the injection plane, in radians. + + .. py:data:: time_envelope + + Time envelope of the field (not intensity). + + +.. rubric:: 5. Defining a 3D gaussian wave + +.. + + For three-dimensional simulations, you may use the simplified laser creator:: + + LaserGaussian3D( + box_side = "xmin", + a0 = 1., + omega = 1., + focus = [50., 40., 40.], + waist = 3., + incidence_angle = [0., 0.1], + polarization_phi = 0., + ellipticity = 0., + time_envelope = tconstant() + ) + + This is almost the same as ``LaserGaussian2D``, with the ``focus`` parameter having + now 3 elements (focus position in 3D), and the ``incidence_angle`` being a list of + two angles, corresponding to rotations around ``y`` and ``z``, respectively. + + When injecting on ``"ymin"`` or ``"ymax"``, the incidence angles corresponds to + rotations around ``x`` and ``z``, respectively. + +.. rubric:: 6. Defining a gaussian wave with Azimuthal Fourier decomposition + +.. + + For simulations with ``"AMcylindrical"`` geometry, you may use the simplified laser creator:: + + LaserGaussianAM( + box_side = "xmin", + a0 = 1., + omega = 1., + focus = [50., 0.], + waist = 3., + polarization_phi = 0., + ellipticity = 0., + time_envelope = tconstant() + ) + + Note that here, the focus is given in [x,r] coordinates. + +.. rubric:: 7. Defining a generic wave at some distance from the boundary + +.. + + In some cases, the laser field is not known at the box boundary, but rather at some + plane inside the box. Smilei can pre-calculate the corresponding wave at the boundary + using the *angular spectrum method*. This technique is only available in 2D and 3D + cartesian geometries and requires the python packages *numpy*. + A :doc:`detailed explanation ` of the method is available. + The laser is introduced using:: + + LaserOffset( + box_side = "xmin", + space_time_profile = [ By_profile, Bz_profile ], + offset = 10., + extra_envelope = tconstant(), + keep_n_strongest_modes = 100, + angle = 10./180.*3.14159 + ) + + .. py:data:: space_time_profile + + :type: A list of two *python* functions + + The magnetic field profiles at some arbitrary plane, as a function of space and time. + The arguments of these profiles are ``(y,t)`` in 2D and ``(y,z,t)`` in 3D. + + .. py:data:: offset + + The distance from the box boundary to the plane where :py:data:`space_time_profile` + is defined. + + .. py:data:: extra_envelope + + :type: a *python* function or a :doc:`python profile ` + :default: ``lambda *z: 1.``, which means a profile of value 1 everywhere + + An extra envelope applied at the boundary, on top of the :py:data:`space_time_profile`. + This envelope takes two arguments (``y``, ``t``) in 2D, and three arguments (``y``, ``z``, ``t``) + in 3D. + As the wave propagation technique stores a limited number of Fourier modes (in the time + domain) of the wave, some periodicity can be obtained in the actual laser. + One may thus observe that the laser pulse is repeated several times. + The envelope can be used to remove these spurious repetitions. + + .. py:data:: keep_n_strongest_modes + + :default: 100 + + The number of temporal Fourier modes that are kept during the pre-processing. + See :doc:`this page ` for more details. + + .. py:data:: angle + + :default: 0. + + Angle between the boundary and the profile's plane, the rotation being around :math:`z`. + See :doc:`this page ` for more details. + + .. py:data:: fft_time_window + + :default: :py:data:`simulation_time` + + Time during which the ``space_time_profile`` is sampled (calculating the + ``LaserOffset`` on the whole simulation duration can be costly). Note that + the Fourier approach will naturally repeat the signal periodically. + + .. py:data:: fft_time_step + + :default: :py:data:`timestep` + + Temporal step between each sample of the ``space_time_profile``. + Chosing a larger step can help reduce the memory load but will remove high temporal frequencies. + + .. py:data:: number_of_processes + + :default: *all available processes* + + The number of MPI processes that will be used for computing the ``LaserOffset``. + Using more processes computes the FFT faster, but too many processes may + be very costly in communication. In addition, using too few may not allow + the arrays to fit in memory. + + .. py:data:: file + + :default: ``None`` + + The path to a ``LaserOffset*.h5`` file generated from a previous simulation. This option + can help reduce the computation time by re-using the ``LaserOffset`` computation + from a previous simulation. + + +---- + +.. _laser_envelope: + +Laser envelope model +^^^^^^^^^^^^^^^^^^^^^^ + +In all the available geometries, it is possible to model a laser pulse +propagating in the ``x`` direction +using an envelope model (see :doc:`/Understand/laser_envelope` for the advantages +and limits of this approximation). +The fast oscillations of the laser are neglected and all the physical +quantities of the simulation, including the electromagnetic fields and +their source terms, as well as the particles positions and momenta, are +meant as an average over one or more optical cycles. +Effects involving characteristic lengths comparable to the laser central +wavelength (i.e. sharp plasma density profiles) cannot be modeled with +this option. + +.. note:: + + The envelope model in ``"AMcylindrical"`` geometry is implemented only in the hypothesis of + cylindrical symmetry, i.e. only one azimuthal mode. Therefore, to use it the user must choose + ``number_of_AM = 1``. + +Contrarily to a standard Laser initialized with the Silver-Müller +boundary conditions, the laser envelope will be entirely initialized inside +the simulation box at the start of the simulation. + +Currently only one laser pulse of a given frequency propagating in the positive +`x` direction can be speficified. However, a multi-pulse set-up can be initialized +if a multi-pulse profile is specified, e.g. if the temporal profile is given by two adjacents gaussian functions. +The whole multi-pulse profile would have the same carrier frequency and would propagate in the positive +`x` direction. For the moment it is not possible to specify more than one laser envelope profile, e.g. +two counterpropagating lasers, or two lasers with different carrier frequency. + + +Please note that describing a laser through its complex envelope loses physical accuracy if its +characteristic space-time variation scales are too small, i.e. of the order of the laser +central wavelength (see :doc:`/Understand/laser_envelope`). +Thus, space-time profiles with variation scales larger than this length should be used. + +.. rubric:: 1. Defining a generic laser envelope + +.. + +Following is the generic laser envelope creator :: + + LaserEnvelope( + omega = 1., + envelope_solver = 'explicit', + envelope_profile = envelope_profile, + Envelope_boundary_conditions = [["reflective"]] + polarization_phi = 0., + ellipticity = 0. + ) + + +.. py:data:: omega + + :default: ``1.`` + + The laser angular frequency. + +.. py:data:: envelope_profile + + :type: a *python* function or a :doc:`python profile ` + :default: None + + The laser space-time profile, so if the geometry is ``3Dcartesian`` a function of 4 arguments (3 for space, 1 for time) is necessary. + Please note that the envelope will be entirely initialized in the simulation box + already at the start of the simulation, so the time coordinate will be applied + to the ``x`` direction instead of time. It is recommended to initialize the + laser envelope in vacuum, separated from the plasma, to avoid unphysical + results. + Envelopes with variation scales near to the laser wavelength do not + satisfy the assumptions of the envelope model (see :doc:`/Understand/laser_envelope`), + yielding inaccurate results. + +.. py:data:: envelope_solver + + :default: ``explicit`` + + The solver scheme for the envelope equation. + + * ``"explicit"``: an explicit scheme based on central finite differences. + * ``"explicit_reduced_dispersion"``: the finite difference derivatives along ``x`` in the ``"explicit"`` solver are substituted by + optimized derivatives to reduce numerical dispersion. For more accurate results over long distances, the use of this solver is recommended. + Please note that the CFL limit of this solver is lower than the one of the ``"explicit"`` solver. Thus, a smaller integration + timestep may be necessary. + +.. py:data:: Envelope_boundary_conditions + + :type: list of lists of strings + :default: ``[["reflective"]]`` + + Defines the boundary conditions used for the envelope. Either ``"reflective"`` or ``"PML"``. + In the case of ``"PML"``, make sure to define ``"number_of_pml_cells"`` in the ``Main`` block. + +.. py:data:: polarization_phi + + :default: 0. + + The angle of the polarization ellipse major axis relative to the X-Y plane, in radians. Needed only for ionization. + +.. py:data:: ellipticity + + :default: 0. + + The polarization ellipticity: 0 for linear and 1 for circular. For the moment, only these two polarizations are available. + +.. rubric:: 2. Defining a 1D laser envelope + +.. + +Following is the simplified laser envelope creator in 1D :: + + LaserEnvelopePlanar1D( + a0 = 1., + time_envelope = tgaussian(center=150., fwhm=40.), + envelope_solver = 'explicit', + Envelope_boundary_conditions = [ ["reflective"] ], + polarization_phi = 0., + ellipticity = 0. + ) + +.. rubric:: 3. Defining a 2D gaussian laser envelope + +.. + +Following is the simplified gaussian laser envelope creator in 2D :: + + LaserEnvelopeGaussian2D( + a0 = 1., + focus = [150., 40.], + waist = 30., + time_envelope = tgaussian(center=150., fwhm=40.), + envelope_solver = 'explicit', + Envelope_boundary_conditions = [ ["reflective"] ], + polarization_phi = 0., + ellipticity = 0. + ) + +.. rubric:: 4. Defining a 3D gaussian laser envelope + +.. + +Following is the simplified laser envelope creator in 3D :: + + LaserEnvelopeGaussian3D( + a0 = 1., + focus = [150., 40., 40.], + waist = 30., + time_envelope = tgaussian(center=150., fwhm=40.), + envelope_solver = 'explicit', + Envelope_boundary_conditions = [ ["reflective"] ], + polarization_phi = 0., + ellipticity = 0. + ) + +.. rubric:: 5. Defining a cylindrical gaussian laser envelope + +.. + +Following is the simplified laser envelope creator in ``"AMcylindrical"`` geometry (remember that +in this geometry the envelope model can be used only if ``number_of_AM = 1``) :: + + LaserEnvelopeGaussianAM( + a0 = 1., + focus = [150., 40.], + waist = 30., + time_envelope = tgaussian(center=150., fwhm=40.), + envelope_solver = 'explicit', + Envelope_boundary_conditions = [ ["reflective"] ], + polarization_phi = 0., + ellipticity = 0. + ) + + +The arguments appearing ``LaserEnvelopePlanar1D``, ``LaserEnvelopeGaussian2D``, +``LaserEnvelopeGaussian3D`` and ``LaserEnvelopeGaussianAM`` have the same meaning they would have in a +normal ``LaserPlanar1D``, ``LaserGaussian2D``, ``LaserGaussian3D`` and ``LaserGaussianAM``, +with some differences: + +.. py:data:: time_envelope + + Since the envelope will be entirely initialized in the simulation box + already at the start of the simulation, the time envelope will be applied + in the ``x`` direction instead of time. It is recommended to initialize the + laser envelope in vacuum, separated from the plasma, to avoid unphysical + results. + Temporal envelopes with variation scales near to the laser wavelength do not + satisfy the assumptions of the envelope model (see :doc:`/Understand/laser_envelope`), + yielding inaccurate results. + +.. py:data:: waist + + Please note that a waist size comparable to the laser wavelength does not + satisfy the assumptions of the envelope model. + + +It is important to remember that the profile defined through the blocks +``LaserEnvelopePlanar1D``, ``LaserEnvelopeGaussian2D``, ``LaserEnvelopeGaussian3D`` +correspond to the complex envelope of the laser vector potential component +:math:`\tilde{A}` in the polarization direction. +The calculation of the correspondent complex envelope for the laser electric field +component in that direction is described in :doc:`/Understand/laser_envelope`. + +Note that only order 2 interpolation and projection are supported in presence of +the envelope model for the laser. + +The parameters ``polarization_phi`` and ``ellipticity`` specify the polarization state of the laser. In envelope model implemented in :program:`Smilei`, +they are only used to compute the rate of ionization and the initial momentum of the electrons newly created by ionization, +where the polarization of the laser plays an important role (see :doc:`/Understand/ionization`). +For all other purposes (e.g. the particles equations of motions, the computation of the ponderomotive force, +the evolution of the laser), the polarization of the laser plays no role in the envelope model. + + +---- + +.. _ExternalField: + +External fields +^^^^^^^^^^^^^^^ + +An initial field can be applied over the whole box +at the beginning of the simulation using the ``ExternalField`` block:: + + ExternalField( + field = "Ex", + profile = constant(0.01, xvacuum=0.1) + ) + +.. py:data:: field + + Field name in Cartesian geometries: ``"Ex"``, ``"Ey"``, ``"Ez"``, ``"Bx"``, ``"By"``, ``"Bz"``, ``"Bx_m"``, ``"By_m"``, ``"Bz_m"`` + Field name in AM geometry: ``"El"``, ``"Er"``, ``"Et"``, ``"Bl"``, ``"Br"``, ``"Bt"``, ``"Bl_m"``, ``"Br_m"``, ``"Bt_m"``, ``"A"``, ``"A0"`` . + +.. py:data:: profile + + :type: float or :doc:`profile ` + + The initial spatial profile of the applied field. + Refer to :doc:`/Understand/units` to understand the units of this field. + + Note that when using standard FDTD schemes, ``B`` fields are given at time ``t=0.5 dt`` and ``B_m`` fields at time ``t=0`` like ``E`` fields. + It is important to initialize ``B_m`` fields at ``t=0`` if there are particles in the simulation domain at the start of the simulation. + If ``B_m`` is omited, it is assumed that the magnetic field is constant and that ``B_m=B``. + + Note that in AM geometry all field names must be followed by the number ``"i"`` of the mode that is currently passed with the string ``"_mode_i"``. For instance ``"Er_mode_1"``. + In this geometry, an external envelope field can also be used. It needs to be initialized at times ``"t=0"`` in ``"A_mode_1"`` and ``"t=-dt"`` in ``"A0_mode_1"``. + The user must use the ``"_mode_1"`` suffix for these two fields because there is no other possible mode for them. + + +---- + +.. _PrescribedField: + +Prescribed fields +^^^^^^^^^^^^^^^^^ + +User-defined electromagnetic fields, with spatio-temporal dependence, +can be superimposed to the self-consistent Maxwell fields. +These fields push the particles but **do not participate in the Maxwell solver**: +they are not self-consistent. +They are however useful to describe charged particles' dynamics in a given +electromagnetic field. + +This feature is accessible using the ``PrescribedField`` block:: + + from numpy import cos, sin + def myPrescribedProfile(x,t): + return cos(x)*sin(t) + + PrescribedField( + field = "Ex", + profile = myPrescribedProfile + ) + +.. py:data:: field + + Field name: ``"Ex"``, ``"Ey"``, ``"Ez"``, ``"Bx_m"``, ``"By_m"`` or ``"Bz_m"``. + +.. warning:: + + When prescribing a magnetic field, always use the time-centered fields ``"Bx_m"``, ``"By_m"`` or ``"Bz_m"``. + These fields are those used in the particle pusher, and are defined at integer time-steps. + +.. py:data:: profile + + :type: float or :doc:`profile ` + + The spatio-temporal profile of the applied field: a *python* function + with arguments (*x*, *t*) or (*x*, *y*, *t*), etc. + Refer to :doc:`/Understand/units` to understand the units of this field. + + +---- + +.. _antennas: + +Antennas +^^^^^^^^ + +An antenna is an extra current applied during the whole simulation. +It is applied using an ``Antenna`` block:: + + Antenna( + field = "Jz", + space_profile = gaussian(0.01), + time_profile = tcosine(base=0., duration=1., freq=0.1) + ) + +.. py:data:: field + + The name of the current: ``"Jx"``, ``"Jy"`` or ``"Jz"``. + +.. py:data:: space_profile + + :type: float or :doc:`profile ` + + The initial spatial profile of the applied antenna. + Refer to :doc:`/Understand/units` to understand the units of this current. + + +.. py:data:: time_profile + + :type: float or :doc:`profile ` + + The temporal profile of the applied antenna. It multiplies ``space_profile``. + +.. py:data:: space_time_profile + + :type: float or :doc:`profile ` + + A space & time profile for the antenna (not compatible with ``space_profile`` + or ``time_profile``). It should have ``N+1``arguments, where ``N`` is the dimension + of the simulation. For instance ``(x,t)`` in 1D, ``(x,y,t)`` in 2D, etc. + + The function must accept ``x``, ``y`` and ``z`` either as floats or numpy arrays. + If it accepts floats, the return value must be a float. + If it accepts numpy arrays, these arrays will correspond to the coordinates of 1 patch, + and the return value must be a numpy array of the same size. + +---- + +Walls +^^^^^ + +A wall can be introduced using a ``PartWall`` block in order to +reflect, stop, thermalize or kill particles which reach it:: + + PartWall( + kind = "reflective", + x = 20. + ) + +.. py:data:: kind + + The kind of wall: ``"reflective"``, ``"stop"``, ``"thermalize"`` or ``"remove"``. + +.. py:data:: x + y + z + + Position of the wall in the desired direction. Use only one of ``x``, ``y`` or ``z``. + + + +---- + +.. _Collisions: + +Collisions & reactions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:doc:`/Understand/collisions` account for short-range Coulomb interactions of particles (shorter than the +cell size), but also include other effects such as impact ionization and nuclear reactions. +These are gathered under this section because they are treated as *binary processes* (meaning +they happen during the encounter of two macro-particles). + +They are specified by one or several ``Collisions`` blocks:: + + Collisions( + species1 = ["electrons1", "electrons2"], + species2 = ["ions1"], + debug_every = 1000, + coulomb_log = 0., + coulomb_log_factor = 1., + ionizing = False, + # nuclear_reaction = [], + ) + + +.. py:data:: species1 + species2 + + Lists of species' :py:data:`name`. + + The collisions and reactions will occur between all species under the group ``species1`` + and all species under the group ``species2``. For example, to collide all + electrons with ions:: + + species1 = ["electrons1", "electrons2"], species2 = ["ions"] + + .. warning:: + + This does not make ``electrons1`` collide with ``electrons2``. + + The two groups of species have to be *completely different* OR *exactly equal*. + In other words, if ``species1`` is not equal to ``species2``, + then they cannot have any common species. + If the two groups are exactly equal, we call this situation **intra-collisions**. + + .. note:: + + If both lists ``species1`` and ``species2`` contain only one species, + the algorithm is potentially faster than the situation with several + species in one or the other list. This is especially true if the + machine accepts SIMD vectorization. + + +.. py:data:: every + + :default: 1 + + Number of timesteps between each computation of the collisions or reactions. + Use a number higher than 1 only if you know the collision frequency is low + with respect to the inverse of the timestep. + + +.. py:data:: debug_every + + :default: 0 + + Number of timesteps between each output of information about collisions or reactions. + If 0, there will be no outputs. + +.. py:data:: time_frozen + + :default: 0. + + The time during which no collisions or reactions happen, in units of :math:`T_r`. + +.. py:data:: coulomb_log + + :default: 0. + + The Coulomb logarithm. + + * If :math:`= 0`, the Coulomb logarithm is automatically computed for each collision. + * If :math:`> 0`, the Coulomb logarithm is equal to this value. + * If :math:`< 0`, collisions are not treated (but other reactions may happen). + + +.. py:data:: coulomb_log_factor + + :default: 1. + + A constant, strictly positive factor that multiplies the Coulomb logarithm, regardless + of :py:data:`coulomb_log` being automatically computed or set to a constant value. + This can help, for example, to compensate artificially-reduced ion masses. + +.. _CollisionalIonization: + +.. py:data:: ionizing + + :default: ``False`` + + :ref:`Collisional ionization ` is set when this parameter is not ``False``. + It can either be set to the name of a pre-existing electron species (where the ionized + electrons are created), or to ``True`` (the first electron species in :py:data:`species1` + or :py:data:`species2` is then chosen for ionized electrons). + + One of the species groups must be all electrons (:py:data:`mass` = 1), and the other + one all ions of the same :py:data:`atomic_number`. + + +.. rst-class:: experimental + +.. py:data:: nuclear_reaction + + :type: a list of strings + :default: ``None`` (no nuclear reaction) + + A list of the species names for the products of :ref:`Nuclear reactions ` + that may occur during collisions. You may omit product species if they are not necessary + for the simulation. + + All members of :py:data:`species1` must be the same type of atoms, which is automatically + recognized by their :py:data:`mass` and :py:data:`atomic_number`. The same applies for + all members of :py:data:`species2`. + + In the current version, only the reaction D(d,n)He³ is available. + +.. rst-class:: experimental + +.. py:data:: nuclear_reaction_multiplier + + :type: a float + :default: 0. (automatically adjusted) + + The rate multiplier for nuclear reactions. It is a positive number that artificially + increases the occurence of reactions so that a good statistics is obtained. The number + of actual reaction products is adjusted by changing their weights in order to provide + a physically correct number of reactions. Leave this number to ``0.`` for an automatic + rate multiplier: the final number of produced macro-particles will be of the same order + as that of reactants. + + + +-------------------------------------------------------------------------------- + +.. _RadiationReaction: + +Radiation reaction +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The block ``RadiationReaction()`` enables to tune the radiation loss properties +(see :doc:`/Understand/radiation_loss`). +Many parameters are used for the generation of the cross-section tables +for the Monte-Carlo emission process. +If the tables already exist in the simulation directory, then they will be read +and no new table will be generated by :program:`Smilei`. +Otherwise, :program:`Smilei` can compute and output these +tables. + +:: + + RadiationReaction( + + # Radiation parameters + minimum_chi_continuous = 1e-3, + minimum_chi_discontinuous = 1e-2, + table_path = "", + + # Parameters for Niel et al. + Niel_computation_method = "table", + + ) + +.. py:data:: minimum_chi_continuous + + :default: 1e-3 + + Threshold on the particle quantum parameter *particle_chi*. When a particle has a + quantum parameter below this threshold, radiation reaction is not taken + into account. + +.. py:data:: minimum_chi_discontinuous + + :default: 1e-2 + + Threshold on the particle quantum parameter *particle_chi* between the continuous + and the discontinuous radiation model. + +.. py:data:: table_path + + :default: ``""`` + + Path to the **directory** that contains external tables for the radiation losses. + If empty, the default tables are used. + Default tables are embedded in the code. + External tables can be generated using the external tool :program:`smilei_tables` (see :doc:`tables`). + +.. py:data:: Niel_computation_method + + :default: ``"table"`` + + Method to compute the value of the table *h* of Niel *et al* during the emission process. + The possible values are: + + * ``"table"``: the *h* function is tabulated. The table is computed at initialization or read from an external file. + * ``"fit5"``: A polynomial fit of order 5 is used. No table is required. + The maximal relative error to the reference data is of maximum of 0.02. + The fit is valid for quantum parameters :math:`\chi` between 1e-3 and 10. + * ``"fit10"``: A polynomial fit of order 10 is used. No table is required. + The precision if better than the fit of order 5 with a maximal relative error of 0.0002. + The fit is valid for quantum parameters :math:`\chi` between 1e-3 and 10. + * ``"ridgers"``: The fit of Ridgers given in Ridgers *et al.*, ArXiv 1708.04511 (2017) + + The use of tabulated values is best for accuracy but not for performance. + Table access prevent total vectorization. + Fits are vectorizable. + +-------------------------------------------------------------------------------- + +.. _MultiphotonBreitWheeler: + +Multiphoton Breit-Wheeler +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The block ``MultiphotonBreitWheeler`` enables to tune parameters of the +multiphoton Breit-Wheeler process and particularly the table generation. +For more information on this physical mechanism, see :doc:`/Understand/multiphoton_Breit_Wheeler`. + +There are three tables used for the multiphoton Breit-Wheeler refers to as the +*integration_dT_dchi*, *min_particle_chi_for_xi* and *xi* table. + +:: + + MultiphotonBreitWheeler( + + # Path to the tables + table_path = "", + + ) + +.. py:data:: table_path + + :default: ``""`` + + Path to the **directory** that contains external tables for the multiphoton Breit-Wheeler. + If empty, the default tables are used. + Default tables are embedded in the code. + External tables can be generated using the external tool :program:`smilei_tables` (see :doc:`tables`). + +-------------------------------------------------------------------------------- + +.. _DiagScalar: + +*Scalar* diagnostics +^^^^^^^^^^^^^^^^^^^^^ + +:program:`Smilei` can collect various scalar data, such as total particle energy, total field energy, etc. +This is done by including the block ``DiagScalar``:: + + DiagScalar( + every = 10 , + vars = ["Utot", "Ukin", "Uelm"], + precision = 10 + ) + +.. py:data:: every + + Number of timesteps between each output **or** a :ref:`time selection `. + +.. py:data:: vars + + :default: ``[]`` + + | List of scalars that will be actually output. Note that most scalars are computed anyways. + | Omit this argument to include all scalars. + +.. py:data:: precision + + :default: 10 + + Number of digits of the outputs. + +.. warning:: + + Scalars diagnostics min/max cell are not yet supported in ``"AMcylindrical"`` geometry. + +The full list of available scalars is given in the table below. + +.. warning:: + + As some of these quantities are integrated in space and/or time, their + units are unusual, and depend on the simulation dimension. + All details :ref:`here`. + +.. rst-class:: fancy + ++--------------------------------------------------------------------------------------------+ +| **Space-integrated energy densities** | ++--------------------------------------------------------------------------------------------+ +| +--------------+-------------------------------------------------------------------------+ | +| | Utot | Total | | +| +--------------+-------------------------------------------------------------------------+ | +| | Ukin | Total kinetic (in the particles) | | +| +--------------+-------------------------------------------------------------------------+ | +| | Uelm | Total electromagnetic (in the fields) | | +| +--------------+-------------------------------------------------------------------------+ | +| | Uexp | Expected (Initial :math:`-` lost :math:`+` gained) | | +| +--------------+-------------------------------------------------------------------------+ | +| | Ubal | Balance (Utot :math:`-` Uexp) | | +| +--------------+-------------------------------------------------------------------------+ | +| | Ubal_norm | Normalized balance (Ubal :math:`/` Utot) | | +| +--------------+-------------------------------------------------------------------------+ | +| | Uelm_Ex | Ex field contribution (:math:`\int E_x^2 dV /2`) | | +| +--------------+-------------------------------------------------------------------------+ | +| | | ... same for fields Ey, Ez, Bx_m, By_m and Bz_m | | +| +--------------+-------------------------------------------------------------------------+ | +| | Urad | Total radiated | | +| +--------------+-------------------------------------------------------------------------+ | +| | UmBWpairs | Total energy converted into electron-position pairs | | +| +--------------+-------------------------------------------------------------------------+ | ++--------------------------------------------------------------------------------------------+ +| **Space- & time-integrated Energies lost/gained at boundaries** | ++--------------------------------------------------------------------------------------------+ +| +--------------+-------------------------------------------------------------------------+ | +| | Ukin_bnd | Time-accumulated kinetic energy exchanged at the boundaries | | +| +--------------+-------------------------------------------------------------------------+ | +| | Uelm_bnd | Time-accumulated EM energy exchanged at boundaries | | +| +--------------+-------------------------------------------------------------------------+ | +| | PoyXminInst | Poynting contribution through xmin boundary during the timestep | | +| +--------------+-------------------------------------------------------------------------+ | +| | PoyXmin | Time-accumulated Poynting contribution through xmin boundary | | +| +--------------+-------------------------------------------------------------------------+ | +| | | ... same for other boundaries | | +| +--------------+-------------------------------------------------------------------------+ | +| | Ukin_new | Time-accumulated kinetic energy from new particles (injector) | | +| +--------------+-------------------------------------------------------------------------+ | +| | Ukin_out_mvw | Time-accumulated kinetic energy lost by the moving window | | +| +--------------+-------------------------------------------------------------------------+ | +| | Ukin_inj_mvw | Time-accumulated kinetic energy gained by the moving window | | +| +--------------+-------------------------------------------------------------------------+ | +| | Uelm_out_mvw | Time-accumulated EM energy lost by the moving window | | +| +--------------+-------------------------------------------------------------------------+ | +| | Uelm_inj_mvw | Time-accumulated EM energy gained by the moving window | | +| +--------------+-------------------------------------------------------------------------+ | ++--------------------------------------------------------------------------------------------+ +| **Particle information** | ++--------------------------------------------------------------------------------------------+ +| +--------------+-------------------------------------------------------------------------+ | +| | Zavg_abc | Average charge of species "abc" (equals ``nan`` if no particle) | | +| +--------------+-------------------------------------------------------------------------+ | +| | Dens_abc | ... its integrated density | | +| +--------------+-------------------------------------------------------------------------+ | +| | Ukin_abc | ... its integrated kinetic energy density | | +| +--------------+-------------------------------------------------------------------------+ | +| | Urad_abc | ... its integrated radiated energy density | | +| +--------------+-------------------------------------------------------------------------+ | +| | Ntot_abc | ... and number of macro-particles | | +| +--------------+-------------------------------------------------------------------------+ | +| +--------------+-------------------------------------------------------------------------+ | ++--------------------------------------------------------------------------------------------+ +| **Fields information** | ++--------------------------------------------------------------------------------------------+ +| +--------------+-------------------------------------------------------------------------+ | +| | ExMin | Minimum of :math:`E_x` | | +| +--------------+-------------------------------------------------------------------------+ | +| | ExMinCell | ... and its location (cell index) | | +| +--------------+-------------------------------------------------------------------------+ | +| | ExMax | Maximum of :math:`E_x` | | +| +--------------+-------------------------------------------------------------------------+ | +| | ExMaxCell | ... and its location (cell index) | | +| +--------------+-------------------------------------------------------------------------+ | +| | | ... same for fields Ey Ez Bx_m By_m Bz_m Jx Jy Jz Rho | | +| +--------------+-------------------------------------------------------------------------+ | ++--------------------------------------------------------------------------------------------+ + +Checkout the :doc:`post-processing ` documentation as well. + +---- + +.. _DiagFields: + +*Fields* diagnostics +^^^^^^^^^^^^^^^^^^^^ + +:program:`Smilei` can collect various field data (electromagnetic fields, currents and density) +taken at the location of the PIC grid, both as instantaneous values and averaged values. +This is done by including a block ``DiagFields``:: + + DiagFields( + #name = "my field diag", + every = 10, + time_average = 2, + fields = ["Ex", "Ey", "Ez"], + #subgrid = None + ) + +.. py:data:: name + + Optional name of the diagnostic. Used only for post-processing purposes. + +.. py:data:: every + + Number of timesteps between each output **or** a :ref:`time selection `. + +.. py:data:: flush_every + + :default: 1 + + Number of timesteps **or** a :ref:`time selection `. + + When ``flush_every`` coincides with ``every``, the output + file is actually written ("flushed" from the buffer). Flushing + too often can *dramatically* slow down the simulation. + + +.. py:data:: time_average + + :default: ``1`` *(no averaging)* + + The number of timesteps for time-averaging. + + +.. py:data:: fields + + :default: ``[]`` *(all fields are written)* + + List of the field names that are saved. By default, they all are. + The full list of fields that are saved by this diagnostic: + + .. rst-class:: fancy + + +----------------+-------------------------------------------------------+ + | | Bx | | | + | | By | | Components of the magnetic field | + | | Bz | | | + +----------------+-------------------------------------------------------+ + | | Bx_m | | | + | | By_m | | Components of the magnetic field (time-centered) | + | | Bz_m | | | + +----------------+-------------------------------------------------------+ + | | Ex | | | + | | Ey | | Components of the electric field | + | | Ez | | | + +----------------+-------------------------------------------------------+ + | | Jx | | | + | | Jy | | Components of the total current | + | | Jz | | | + +----------------+-------------------------------------------------------+ + | | Jx_abc | | | + | | Jy_abc | | Components of the current due to species "abc" | + | | Jz_abc | | | + +----------------+-------------------------------------------------------+ + | | Rho | | Total density | + | | Rho_abc | | Density of species "abc" | + +----------------+-------------------------------------------------------+ + + In ``AMcylindrical`` geometry, the ``x``, ``y`` and ``z`` + indices are replaced by ``l`` (longitudinal), ``r`` (radial) and ``t`` (theta). In addition, + the angular Fourier modes are denoted by the suffix ``_mode_i`` where ``i`` + is the mode number. + If a field is specified without its associated mode number, all available modes will be included. + In summary, the list of fields reads as follows. + + .. rst-class:: fancy + + +------------------------------+-----------------------------------------+ + | | Bl_mode_0, Bl_mode_1, etc. | | | + | | Br_mode_0, Br_mode_1, etc. | | Components of the magnetic field | + | | Bt_mode_0, Bt_mode_1, etc. | | | + +------------------------------+-----------------------------------------+ + | | El_mode_0, El_mode_1, etc. | | | + | | Er_mode_0, Er_mode_1, etc. | | Components of the electric field | + | | Et_mode_0, Et_mode_1, etc. | | | + +------------------------------+-----------------------------------------+ + | The same notation works for Jl, Jr, Jt, and Rho | + +------------------------------+-----------------------------------------+ + + In the case of an envelope model for the laser (see :doc:`/Understand/laser_envelope`), + the following fields are also available: + + .. rst-class:: fancy + + +----------------+-------------------------------------------------------+ + | | | | Module of laser vector potential's complex envelope | + | | Env_A_abs | | :math:`\tilde{A}` (component along the transverse | + | | | | direction) | + +----------------+-------------------------------------------------------+ + | | Env_Chi | | Total susceptibility :math:`\chi` | + +----------------+-------------------------------------------------------+ + | | | | Module of laser electric field's complex envelope | + | | Env_E_abs | | :math:`\tilde{E}` (component along the transverse | + | | | | direction) | + +----------------+-------------------------------------------------------+ + | | | | Module of laser electric field's complex envelope | + | | Env_Ex_abs | | :math:`\tilde{E}_x` (component along the propagation| + | | | | direction) | + +----------------+-------------------------------------------------------+ + + In the case the B-TIS3 interpolation is activated (see :doc:`/Understand/algorithms`), + the following fields are also available: + + .. rst-class:: fancy + + +--------------------------------------------+-----------------------------------------------+ + | | By_mBTIS3 | | Components of the magnetic field | + | | By_mBTIS3 | | for the B-TIS3 interpolation | + | | | | (time-centered) | + +--------------------------------------------+-----------------------------------------------+ + | | Br_mBTIS3_mode_0, Br_mBTIS3_mode_1, etc. | | Components of the magnetic field | + | | Bt_mBTIS3_mode_0, Bt+mBTIS3_mode_1, etc. | | for the B-TIS3 interpolation | + | | | | (``AMcylindrical`` geometry, time-centered) | + +--------------------------------------------+-----------------------------------------------+ + + +.. Note:: In a given `DiagFields`, all fields must be of the same kind: either real or complex. Therefore To write these last three envelope real fields in ``"AMcylindrical"`` geometry, + a dedicated block ``DiagFields`` must be defined, e.g. with ``fields = ["Env_A_abs", "Env_Chi"]``. + +.. py:data:: subgrid + + :default: ``None`` *(the whole grid is used)* + + A list of slices indicating a portion of the simulation grid to be written by this + diagnostic. This list must have as many elements as the simulation dimension. + For example, in a 3D simulation, the list has 3 elements. Each element can be: + + * ``None``, to select the whole grid along that dimension + * an integer, to select only the corresponding cell index along that dimension + * a *python* `slice object `_ + to select regularly-spaced cell indices along that dimension. + + This can be easily implemented using the + `numpy.s_ expression `_. + For instance, in a 3D simulation, the following subgrid selects only every other element + in each dimension:: + + from numpy import s_ + DiagFields( #... + subgrid = s_[::2, ::2, ::2] + ) + + while this one selects cell indices included in a contiguous parallelepiped:: + + subgrid = s_[100:300, 300:500, 300:600] + + +.. py:data:: datatype + + :default: ``"double"`` + + The data type when written to the HDF5 file. Accepts ``"double"`` (8 bytes) or ``"float"`` (4 bytes). + + +---- + +.. _DiagProbe: + +*Probe* diagnostics +^^^^^^^^^^^^^^^^^^^ + +The fields from the previous section are taken at the PIC grid locations, +but it is also possible to obtain the fields at arbitrary locations. +These are called *probes*. + +A probe interpolates the fields at either one point (0-D), +several points arranged in a line (1-D), +or several points arranged in a 2-D or 3-D grid. + +.. note:: + + * **Probes follow the moving window.** + To obtain the fields at fixed points in the plasma instead, create a cold, + chargeless species, and :ref:`track the particles `. + * **In "AMcylindrical" geometry**, probes are defined with 3D Cartesian coordinates + and cannot be separated per mode. Use Field diagnostics for cylindrical coordinates and + information per mode. + + +To add one probe diagnostic, include the block ``DiagProbe``:: + + DiagProbe( + #name = "my_probe", + every = 10, + origin = [1., 1.], + corners = [ + [1.,10.], + [10.,1.], + ], + number = [100, 100], + fields = ["Ex", "Ey", "Ez"] + ) + +.. py:data:: name + + Optional name of the diagnostic. Used only for post-processing purposes. + +.. py:data:: every + + Number of timesteps between each output **or** a :ref:`time selection `. + +.. py:data:: flush_every + + :default: 1 + + Number of timesteps **or** a :ref:`time selection `. + + When ``flush_every`` coincides with ``every``, the output + file is actually written ("flushed" from the buffer). Flushing + too often can *dramatically* slow down the simulation. + + +.. py:data:: origin + + :type: A list of floats, of length equal to the simulation dimensionality. + + The coordinates of the origin of the probe grid + +.. py:data:: corners + vectors + + :type: A list of lists of floats. + + Defines the corners of the probe grid. + Each corner is a list of coordinates (as many as the simulation dimensions). + + When using ``corners``, the absolute coordinates of each corner must be specified. + When using ``vectors``, the coordinates relative to :py:data:`origin` must be specified. + +.. py:data:: number + + :type: A list of integers, one for each dimension of the probe. + + The number of points in each probe axis. Must not be defined for a 0-D probe. + +.. py:data:: fields + + :default: ``[]``, which means ``["Ex", "Ey", "Ez", "Bx", "By", "Bz", "Jx", "Jy", "Jz", "Rho"]`` + + A list of fields among: + + * the electric field components ``"Ex"``, ``"Ey"``, ``"Ez"`` + * the magnetic field components ``"Bx"``, ``"By"``, ``"Bz"`` + * the Poynting vector components ``"PoyX"``, ``"PoyY"``, ``"PoyZ"`` + * the current density components ``"Jx"``, ``"Jy"``, ``"Jz"`` and density ``"Rho"`` + * the current density ``"Jx_abc"``, ``"Jy_abc"``, ``"Jz_abc"`` and density ``"Rho_abc"`` + of a given species named ``"abc"`` + + In the case of an envelope model for the laser (see :doc:`/Understand/laser_envelope`), + the following fields are also available: ``"Env_Chi"``, ``"Env_A_abs"``, ``"Env_E_abs"``, ``"Env_Ex_abs"``. + They are respectively the susceptibility, the envelope of the laser transverse vector potential, + the envelope of the laser transverse electric field and the envelope of the laser longitudinal + electric field. + + If the B-TIS3 interpolation scheme is activated (see :doc:`/Understand/algorithms`), + the following fields are also available: ``"ByBTIS3"``, ``"BzBTIS3"``. + +.. py:data:: time_integral + + :default: ``False`` + + If ``True``, the output is integrated over time. As this option forces field interpolation + at every timestep, it is recommended to use few probe points. + +.. py:data:: datatype + + :default: ``"double"`` + + The data type when written to the HDF5 file. Accepts ``"double"`` (8 bytes) or ``"float"`` (4 bytes). + + +**Examples of probe diagnostics** + +* 0-D probe in 1-D simulation + :: + + DiagProbe( + every = 1, + origin = [1.2] + ) + +* 1-D probe in 1-D simulation + :: + + DiagProbe( + every = 1, + origin = [1.2], + corners = [[5.6]], + number = [100] + ) + +* 1-D probe in 2-D simulation + :: + + DiagProbe( + every = 1, + origin = [1.2, 4.], + corners = [[5.6, 4.]], + number = [100] + ) + +* 2-D probe in 2-D simulation + :: + + DiagProbe( + every = 1, + origin = [0., 0.], + corners = [ [10.,0.], [0.,10.] ], + number = [100, 100] + ) + + +---- + +.. _DiagParticleBinning: + +*ParticleBinning* diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A *particle binning diagnostic* collects data from the macro-particles and processes them during runtime. +It does not provide information on individual particles: instead, it produces +**averaged quantities** like the particle density, currents, etc. + +The data is discretized inside a "grid" chosen by the user. This grid may be of any dimension. + +Examples: + +* 1-dimensional grid along the position :math:`x` (gives density variation along :math:`x`) +* 2-dimensional grid along positions :math:`x` and :math:`y` (gives density map) +* 1-dimensional grid along the velocity :math:`v_x` (gives the velocity distribution) +* 2-dimensional grid along position :math:`x` and momentum :math:`p_x` (gives the phase-space) +* 1-dimensional grid along the kinetic energy :math:`E_\mathrm{kin}` (gives the energy distribution) +* 3-dimensional grid along :math:`x`, :math:`y` and :math:`E_\mathrm{kin}` (gives the density map for several energies) +* 1-dimensional grid along the charge :math:`Z^\star` (gives the charge distribution) +* 0-dimensional grid (simply gives the total integrated particle density) + +Each dimension of the grid is called "axis". + +You can add a particle binning diagnostic by including a block ``DiagParticleBinning()`` in the namelist, +for instance:: + + DiagParticleBinning( + #name = "my binning", + deposited_quantity = "weight", + every = 5, + time_average = 1, + species = ["electrons1", "electrons2"], + axes = [ + ["x", 0., 10, 100], + ["ekin", 0.1, 100, 1000, "logscale", "edge_inclusive"] + ] + ) + +.. py:data:: name + + Optional name of the diagnostic. Used only for post-processing purposes. + +.. py:data:: deposited_quantity + + The type of data that is summed in each cell of the grid. + Consider reading :ref:`this ` to understand the meaning of the ``weight``. + + * ``"weight"`` results in a number density. + * ``"weight_charge"`` results in a charge density. + * ``"weight_charge_vx"`` results in the :math:`j_x` current density (same with :math:`y` and :math:`z`). + * ``"weight_p"`` results in the momentum density (same with :math:`p_x`, :math:`p_y` and :math:`p_z`). + * ``"weight_ekin"`` results in the energy density. + * ``"weight_vx_px"`` results in the ``xx`` pressure (same with yy, zz, xy, yz and xz). + * ``"weight_chi"`` results in the quantum parameter density (only for species with radiation losses). + * with a user-defined python function, an arbitrary quantity can be calculated (the *numpy* + module is necessary). This function should take one argument, for instance + ``particles``, which contains the attributes ``x``, ``y``, ``z``, ``px``, ``py``, + ``pz``, ``charge``, ``weight``, ``chi`` and ``id`` (additionally, it may also have the + attributes ``Ex``, ``Bx``, ``Ey``, and so on, depending on :py:data:`keep_interpolated_fields`). + Each of these attributes is a *numpy* array + containing the data of all particles in one patch. The function must return a *numpy* + array of the same shape, containing the desired deposition of each particle. For example, + defining the following function:: + + def stuff(particles): + return particles.weight * particles.px + + passed as ``deposited_quantity=stuff``, the diagnostic will sum the weights + :math:`\times\; p_x`. + + You may also pass directly an implicit (*lambda*) function using:: + + deposited_quantity = lambda p: p.weight * p.px + + +.. py:data:: every + + The number of time-steps between each output, **or** a :ref:`time selection `. + +.. py:data:: flush_every + + :default: 1 + + Number of timesteps **or** a :ref:`time selection `. + + When ``flush_every`` coincides with ``every``, the output + file is actually written ("flushed" from the buffer). Flushing + too often can *dramatically* slow down the simulation. + + +.. py:data:: time_average + + :default: 1 + + The number of time-steps during which the data is averaged before output. + + +.. py:data:: species + + A list of one or several species' :py:data:`name`. + All these species are combined into the same diagnostic. + +.. py:data:: axes + + A list of *axes* that define the grid. + There may be as many axes as wanted (there may be zero axes). + + Syntax of one axis: ``[type, min, max, nsteps, "logscale", "edge_inclusive"]`` + + * ``type`` is one of: + + * ``"x"``, ``"y"``, ``"z"``: spatial coordinates (``"moving_x"`` with a :ref:`moving window`) + * ``"px"``, ``"py"``, ``"pz"``, ``"p"``: momenta + * ``"vx"``, ``"vy"``, ``"vz"``, ``"v"``: velocities + * ``"gamma"``, ``"ekin"``: energies + * ``"chi"``: quantum parameter + * ``"charge"``: the particles' electric charge + * or a *python function* with the same syntax as the ``deposited_quantity``. + Namely, this function must accept one argument only, for instance ``particles``, + which holds the attributes ``x``, ``y``, ``z``, ``px``, ``py``, ``pz``, ``charge``, + ``weight`` and ``id``. Each of these attributes is a *numpy* array containing the + data of all particles in one patch. The function must return a *numpy* array of + the same shape, containing the desired quantity of each particle that will decide + its location in the histogram binning. + + * The axis is discretized for ``type`` from ``min`` to ``max`` in ``nsteps`` bins. + * The ``min`` and ``max`` may be set to ``"auto"`` so that they are automatically + computed from all the particles in the simulation. This option can be bad for performances. + * The optional keyword ``logscale`` sets the axis scale to logarithmic instead of linear + (bins become uneven). + * The optional keyword ``edge_inclusive`` includes the particles outside the range + [``min``, ``max``] into the extrema bins. + +**Examples of particle binning diagnostics** + +* Variation of the density of species ``electron1`` + from :math:`x=0` to 1, every 5 time-steps, without time-averaging + :: + + DiagParticleBinning( + deposited_quantity = "weight", + every = 5, + time_average = 1, + species = ["electron1"], + axes = [ ["x", 0., 1., 30] ] + ) + +* Density map from :math:`x=0` to 1, :math:`y=0` to 1 + :: + + DiagParticleBinning( + deposited_quantity = "weight", + every = 5, + time_average = 1, + species = ["electron1"], + axes = [ ["x", 0., 1., 30], + ["y", 0., 1., 30] ] + ) + +* Velocity distribution from :math:`v_x = -0.1` to :math:`0.1` + :: + + DiagParticleBinning( + deposited_quantity = "weight", + every = 5, + time_average = 1, + species = ["electron1"], + axes = [ ["vx", -0.1, 0.1, 100] ] + ) + +* Phase space from :math:`x=0` to 1 and from :math:`px=-1` to 1 + :: + + DiagParticleBinning( + deposited_quantity = "weight", + every = 5, + time_average = 1, + species = ["electron1"], + axes = [ ["x", 0., 1., 30], + ["px", -1., 1., 100] ] + ) + +* Energy distribution from 0.01 to 1 MeV in logarithmic scale. + Note that the input units are :math:`m_ec^2 \sim 0.5` MeV + :: + + DiagParticleBinning( + deposited_quantity = "weight", + every = 5, + time_average = 1, + species = ["electron1"], + axes = [ ["ekin", 0.02, 2., 100, "logscale"] ] + ) + +* :math:`x`-:math:`y` density maps for three bands of energy: :math:`[0,1]`, :math:`[1,2]`, :math:`[2,\infty]`. + Note the use of ``edge_inclusive`` to reach energies up to :math:`\infty` + :: + + DiagParticleBinning( + deposited_quantity = "weight", + every = 5, + time_average = 1, + species = ["electron1"], + axes = [ ["x", 0., 1., 30], + ["y", 0., 1., 30], + ["ekin", 0., 6., 3, "edge_inclusive"] ] + ) + +* Charge distribution from :math:`Z^\star =0` to 10 + :: + + DiagParticleBinning( + deposited_quantity = "weight", + every = 5, + time_average = 1, + species = ["electron1"], + axes = [ ["charge", -0.5, 10.5, 11] ] + ) + + +---- + +.. _DiagScreen: + +*Screen* diagnostics +^^^^^^^^^^^^^^^^^^^^ + +A *screen* collects data from the macro-particles when they cross a surface. +It processes this data similarly to the :ref:`particle binning diagnostics ` +as it makes a histogram of the macro-particle properties. The only difference is +that the histogram is made only by the particles that cross the surface. + +You can add a screen by including a block ``DiagScreen()`` in the namelist, +for instance:: + + DiagScreen( + #name = "my screen", + shape = "plane", + point = [5., 10.], + vector = [1., 0.], + direction = "canceling", + deposited_quantity = "weight", + species = ["electron"], + axes = [["a", -10.*l0, 10.*l0, 40], + ["px", 0., 3., 30]], + every = 10 + ) + +.. py:data:: name + + Optional name of the diagnostic. Used only for post-processing purposes. + +.. py:data:: shape + + The shape of the screen surface: ``"plane"``, ``"sphere"``, or ``"cylinder"``. + +.. py:data:: point + + :type: A list of floats ``[X]`` in 1D, ``[X,Y]`` in 2D, ``[X,Y,Z]`` in 3D + + The coordinates of a point that defines the screen surface: + a point of the ``"plane"``, the center of the ``"sphere"``, + or a point on the ``"cylinder"`` axis. + +.. py:data:: vector + + :type: A list of floats ``[X]`` in 1D, ``[X,Y]`` in 2D, ``[X,Y,Z]`` in 3D + + The coordinates of a vector that defines the screen surface: + the normal to the ``"plane"``, a radius of the ``"sphere"``. + or the axis of the ``"cylinder"`` (in the latter case, the vector + norm defines the cylinder radius). + +.. py:data:: direction + + :default: ``"both"`` + + Determines how particles are counted depending on which side of the screen they come from. + + * ``"both"`` to account for both sides. + * ``"forward"`` for only the ones in the direction of the ``vector``. + * ``"backward"`` for only the ones in the opposite direction. + * ``"canceling"`` to count negatively the ones in the opposite direction. + +.. py:data:: deposited_quantity + + Identical to the ``deposited_quantity`` of :ref:`particle binning diagnostics `. + +.. py:data:: every + + The number of time-steps between each output, **or** a :ref:`time selection `. + +.. py:data:: flush_every + + :default: 1 + + Number of timesteps **or** a :ref:`time selection `. + + When ``flush_every`` coincides with ``every``, the output + file is actually written ("flushed" from the buffer). Flushing + too often can *dramatically* slow down the simulation. + +.. py:data:: species + + A list of one or several species' :py:data:`name`. + All these species are combined into the same diagnostic. + +.. py:data:: axes + + A list of "axes" that define the grid of the histogram. + It is identical to that of :ref:`particle binning diagnostics `, with the + addition of four types of axes: + + * If ``shape="plane"``, then ``"a"`` and ``"b"`` are the axes perpendicular to the ``vector``. + * If ``shape="sphere"``, then ``"theta"`` and ``"phi"`` are the angles with respect to the ``vector``. + * If ``shape="cylinder"``, then ``"a"`` is along the cylinder axis and ``"phi"`` is the angle around it. + + +---- + +.. _DiagRadiationSpectrum: + +*RadiationSpectrum* diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A *radiation spectrum diagnostic* computes (at a given time) the instantaneous +power spectrum following from the incoherent emission of high-energy +photons by accelerated charge (see :doc:`/Understand/radiation_loss` for more details +on the emission process and its implementation in :program:`Smilei`). + +It is similar to the :ref:`particle binning diagnostics `, +with an extra axis of binning: the emitted photon energy. +The other axes remain available to the user. + +A radiation spectrum diagnostic is defined by a block ``RadiationSpectrum()``:: + + DiagRadiationSpectrum( + #name = "my radiation spectrum", + every = 5, + flush_every = 1, + time_average = 1, + species = ["electrons1", "electrons2"], + photon_energy_axis = [0., 1000., 100, 'logscale'], + axes = [] + ) + +.. py:data:: name + + Optional name of the diagnostic. Used only for post-processing purposes. + +.. py:data:: every + + The number of time-steps between each output, **or** a :ref:`time selection `. + +.. py:data:: flush_every + + :default: 1 + + Number of timesteps **or** a :ref:`time selection `. + + When ``flush_every`` coincides with ``every``, the output + file is actually written ("flushed" from the buffer). Flushing + too often can *dramatically* slow down the simulation. + +.. py:data:: time_average + + :default: 1 + + The number of time-steps during which the data is averaged before output. + +.. py:data:: species + + A list of one or several species' :py:data:`name` that emit the radiation. + All these species are combined into the same diagnostic. + +.. py:data:: photon_energy_axis + + The axis of photon energies (in units of :math:`m_e c^2`). + The syntax is similar to that of + :ref:`particle binning diagnostics `. + + Syntax: ``[min, max, nsteps, "logscale"]`` + +.. py:data:: axes + + An additional list of "axes" that define the grid. + There may be as many axes as wanted (there may be zero axes). + Their syntax is the same that for "axes" of a + :ref:`particle binning diagnostics `. + + +**Examples of radiation spectrum diagnostics** + +* Time-integrated over the full duration of the simulation:: + + DiagRadiationSpectrum( + every = Nt, + time_average = Nt, + species = ["electrons"], + photon_energy_axis = [0., 1000., 100, 'logscale'], + axes = [] + ) + +* Angularly-resolved instantaneous radiation spectrum. + The diagnostic considers that all electrons emit radiation in + the direction of their velocity:: + + from numpy import arctan2, pi + + def angle(p): + return arctan2(p.py,p.px) + + DiagRadiationSpectrum( + every = 10, + species = ["electrons"], + photon_energy_axis = [0., 1000., 100, 'logscale'], + axes = [ + [angle,-pi,pi,90] + ] + ) + +---- + +.. _DiagTrackParticles: + +*TrackParticles* diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A *particle tracking diagnostic* records the macro-particle positions and momenta at various timesteps. +Typically, this is used for plotting trajectories. + +You can add a tracking diagnostic by including a block ``DiagTrackParticles()`` in the namelist, +for instance:: + + DiagTrackParticles( + species = "electron", + every = 10, + # flush_every = 100, + # filter = my_filter, + # attributes = ["x", "px", "py", "Ex", "Ey", "Bz"] + ) + +.. py:data:: species + + The :py:data:`name` of the species to be tracked. + +.. py:data:: every + + :default: 0 + + Number of timesteps between each output of particles trajectories, **or** a :ref:`time selection `. + If non-zero, the particles positions will be tracked and written in a file named ``TrackParticlesDisordered_abc.h5`` + (where ``abc`` is the species' :py:data:`name`). + +.. py:data:: flush_every + + :default: 1 + + Number of timesteps **or** a :ref:`time selection `. + + When ``flush_every`` coincides with ``every``, the output + file for tracked particles is actually written ("flushed" from the buffer). Flushing + too often can *dramatically* slow down the simulation. + +.. py:data:: filter + + A python function giving some condition on which particles are tracked. + If none provided, all particles are tracked. + To use this option, the `numpy package `_ must + be available in your python installation. + + The function must have one argument, that you may call, for instance, ``particles``. + This object has several attributes ``x``, ``y``, ``z``, ``px``, ``py``, ``pz``, ``charge``, + ``weight`` and ``id`` (additionally, it may also have the + attributes ``Ex``, ``Bx``, ``Ey``, and so on, depending on :py:data:`keep_interpolated_fields`). + Each of these attributes + are provided as **numpy** arrays where each cell corresponds to one particle. + The function must return a boolean **numpy** array of the same shape, containing ``True`` + for particles that should be tracked, and ``False`` otherwise. + + The following example selects all the particles that verify :math:`-13`:: + + def my_filter(particles): + return (particles.px>-1.)*(particles.px<1.) + (particles.pz>3.) + +.. Warning:: The ``px``, ``py`` and ``pz`` quantities are not exactly the momenta. + They are actually the velocities multiplied by the lorentz factor, i.e., + :math:`\gamma v_x`, :math:`\gamma v_y` and :math:`\gamma v_z`. This is true only + inside the ``filter`` function (not for the output of the diagnostic). + +.. Note:: The ``id`` attribute contains the :doc:`particles identification number`. + This number is set to 0 at the beginning of the simulation. **Only after particles have + passed the filter**, they acquire a positive ``id``. + +.. Note:: For advanced filtration, Smilei provides the quantity ``Main.iteration``, + accessible within the ``filter`` function. Its value is always equal to the current + iteration number of the PIC loop. The current time of the simulation is thus + ``Main.iteration * Main.timestep``. + +.. py:data:: attributes + + :default: ``["x","y","z","px","py","pz","w"]`` + + A list of strings indicating the particle attributes to be written in the output. + The attributes may be the particles' spatial coordinates (``"x"``, ``"y"``, ``"z"``), + their momenta (``"px"``, ``"py"``, ``"pz"``), their electrical charge (``"q"``), + their statistical weight (``"w"``), their quantum parameter + (``"chi"``, only for species with radiation losses) or the fields interpolated + at their positions (``"Ex"``, ``"Ey"``, ``"Ez"``, ``"Bx"``, ``"By"``, ``"Bz"``). + +---- + +.. rst-class:: experimental + +.. _DiagNewParticles: + +*NewParticles* diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A *new-particle diagnostic* records the macro-particle information only at the time when +they are generated by :doc:`../Understand/ionization` or other :doc:`../Understand/physics_modules`. + +You can add a new-particle diagnostic by including a block ``DiagNewParticles()`` in the namelist, +for instance:: + + DiagNewParticles( + species = "electron", + every = 10, + # attributes = ["x", "px", "py", "Ex", "Ey", "Bz"] + ) + +**All the arguments are identical to those of TrackParticles.** +However, there are particular considerations: + +* Although the creation of particles is recorded at every timestep, the argument ``every`` + only indicates how often the data is written to the file. It is recommended to avoid + small values of ``every`` for better performance. +* In the case of :doc:`../Understand/ionization`, if the chosen ``species`` is that of the ionized electrons, + then the attribute "``q``" is not the charge of the electron, but the charge of the + ion, *before ionization occurred*. + +---- + +.. _DiagPerformances: + +*Performances* diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The *performances* diagnostic records information on the computational load and timers +for each MPI process or for each patch in the simulation. + +Only one block ``DiagPerformances()`` may be added in the namelist, for instance:: + + DiagPerformances( + every = 100, + # flush_every = 100, + # patch_information = True, + ) + +.. py:data:: every + + :default: 0 + + Number of timesteps between each output, **or** a :ref:`time selection `. + +.. py:data:: flush_every + + :default: 1 + + Number of timesteps **or** a :ref:`time selection `. + + When ``flush_every`` coincides with ``every``, the output file is actually written + ("flushed" from the buffer). Flushing too often might *dramatically* slow down the simulation. + +.. py:data:: patch_information + + :default: ``False`` + + If ``True``, some information is calculated at the patch level (see :py:meth:`Performances`) + but this may impact the code performances. + +---- + +.. _TimeSelections: + +Time selections +^^^^^^^^^^^^^^^ + +Several components (mainly diagnostics) may require a selection of timesteps to +be chosen by the user. When one of these timesteps is reached, the diagnostics will +output data. A time selection is given through the parameter ``every`` and is a list +of several numbers. + +You may chose between five different syntaxes:: + + every = [ period ] # Syntax 1 + every = [ start, period ] # Syntax 2 + every = [ start, end, period ] # Syntax 3 + every = [ start, end, period, repeat ] # Syntax 4 + every = [ start, end, period, repeat, spacing ] # Syntax 5 + +where + +* ``start`` is the first timestep of the selection (defaults to 0); + +* ``end`` is the last timestep of the selection (defaults to ∞); + +* ``period`` is the separation between outputs (defaults to 1); + +* ``repeat`` indicates how many outputs to do at each period (defaults to 1); + +* ``spacing`` is the separation between each repeat (defaults to 1). + +For more clarity, this graph illustrates the five syntaxes for time selections: + +.. image:: /_static/TimeSelections.png + :width: 33em + :align: center + +.. + +.. admonition:: Tips + + * The syntax ``every = period`` is also accepted. + * Any value set to ``0`` will be replaced by the default value. + * Special case: ``every=0`` means no output. + * The numbers may be non-integers (apart from ``repeat``). The closest timesteps are chosen. + +---- + +.. _Checkpoints: + +Checkpoints +^^^^^^^^^^^ + +The simulation state can be saved (*dumped*) at given times (*checkpoints*) +in order to be later *restarted* at that point. + +A few things are important to know when you need dumps and restarts. + +* Do not restart the simulation in the same directory as the previous one. Files will be + overwritten, and errors may occur. Create a new directory for your restarted simulation. +* Manage your disk space: each MPI process dumps one file, and the total can be significant. +* The restarted runs must have the same namelist as the initial simulation, except the + :ref:`Checkpoints` block, which can be modified. + +:: + + Checkpoints( + # restart_dir = "dump1", + dump_step = 10000, + dump_minutes = 240., + exit_after_dump = True, + keep_n_dumps = 2, + ) + +**Parameters to save the state of the current simulation** + + .. py:data:: dump_step + + :default: ``0`` + + The number of timesteps between each dump. + If ``0``, no dump is done. + + .. py:data:: dump_minutes + + :default: ``0.`` + + The number of minutes between each dump. + If ``0.``, no dump is done. + + May be used in combination with :py:data:`dump_step`. + + .. py:data:: exit_after_dump + + :default: ``True`` + + If ``True``, the code stops after the first dump. If ``False``, the simulation continues. + + .. py:data:: keep_n_dumps + + :default: ``2`` + + This tells :program:`Smilei` to keep, in the current run, only the last ``n`` dumps. + Older dumps will be overwritten. + + The default value, ``2``, saves one extra dump in case of a crash during the next dump. + + .. py:data:: file_grouping + + :default: ``0`` (no grouping) + + The maximum number of checkpoint files that can be stored in one directory. + Subdirectories are created to accomodate for all files. + This is useful on filesystem with a limited number of files per directory. + + .. py:data:: dump_deflate + + :red:`to do` + +**Parameters to restart from a previous simulation** + + .. py:data:: restart_dir + + :default: ``None`` + + The directory of a previous run from which :program:`Smilei` should restart. + For the first run, do not specify this parameter. + + **This path must either absolute or be relative to the current directory.** + + .. Note:: + + In many situations, the restarted runs will have the exact same namelist as the initial + simulation, except this ``restart_dir`` parameter, which points to the previous simulation + folder. + You can use the same namelist file, and simply add an extra argument when you launch the + restart: + + ``mpirun ... ./smilei mynamelist.py "Checkpoints.restart_dir='/path/to/previous/run'"`` + + .. py:data:: restart_number + + :default: ``None`` + + The number of the dump (in the previous run) that should be used for the restart. + For the first run, do not specify this parameter. + + In a previous run, the simulation state may have been dumped several times. + These dumps are numbered 0, 1, 2, etc. until the number :py:data:`keep_n_dumps`. + + +---- + +Variables defined by Smilei +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:program:`Smilei` passes the following variables to the python interpreter for use in the +namelist. They should not be re-defined by the user! + +.. py:data:: smilei_mpi_rank + + The MPI rank of the current process. + +.. py:data:: smilei_mpi_size + + The total number of MPI processes. + +.. + <> + .. py:data:: smilei_rand_max + + The largest random integer. + diff --git a/_sources/Use/optimization_flags.rst.txt b/_sources/Use/optimization_flags.rst.txt new file mode 100644 index 000000000..246cc943c --- /dev/null +++ b/_sources/Use/optimization_flags.rst.txt @@ -0,0 +1,219 @@ +Optimization and vectorization compilation options +----------------------------------------------------- + +Modern and mature compilers can automatically and deeply optimize the code for specific hardware. +Optimization features can be activated and tuned using compiler flags. +Among possible optimization capabilities, we can mention loop refactoring (unrolling, reordoring, splitting, etc), inlining, vectorization, pipelining and more. +Each compiler has its own flags. +While some share a common syntax, others provide more fine tuning options for specific processors (like Fujitsu for the A64FX). + +Some optimization flags are automatically set in the makefile; +others are specified in the *machine files* because they are specific to given compilers, hardwares or processor families. +:doc:`SIMD vectorization ` in Smilei, for instance, +can be automatic, or can rely on OpenMP's directive ``#pragma omp simd``. + + +Options are passed to the compiler through the environment variable ``CXXFLAGS``. +Most machine files include appropriate flags to ensure the best performance +on a given processor type using a given compiler (most often Intel but also GNU, LLVM, ARMCLANG and Fujitsu). + +For instance, :program:`Smilei` has been tested on +Intel processors (Skylake 8168) with an Intel environment. +The following flags, located in the ``skylake`` machine file, provide a good performance: + +.. code-block:: bash + + -xCOMMON-AVX512 -ip -ipo -inline-factor=1000 -D__INTEL_SKYLAKE_8168 -fno-alias + +The vectorization must also be activated :ref:`in the namelist `. + +The following explains the meaning of the flags commonly used in our machine files. +You can use this section to design your own machine file. + +.. rubric:: Intel compiler flags for optimization and vectorization + +The following options are commonly used by Smilei's machine files to compile on most modern x86 processors (both Intel and AMD). They enure the best performance of the code, especially for vectorization. + +* ``-O3``: this option directly integrated in the makefile tells the compiler to use agressive optimization at compilation + +* ``-march=cpu-type``: Tells the compiler to generate code for processors that support certain features. See `this page `_ for more info. + +* ``-xCPU-TYPE``: Tells the compiler which processor features it may target, including which instruction sets and optimizations it may generate. ``CPU-TYPE`` can be the instruction set or the processor family name. This option is important for vectorization. See `this page `_ for more info. + + * ``-xCOMMON-AVX512``: for processors that support AVX512 (Skylake, Cascadelake) + * ``-xMIC-AVX512``: suitable for first-generation AVX512 processors (KNL family) + * ``-xCORE-AVX2``: for processors using the AVX2 instruction set such as Intel Broadwell (3nd generation E3, E5 and E7 Xeon family) and AMD Epyc processors + * ``-xAVX``: for the first generation E3 and E5 Xeon family + * ``-xSKYLAKE`` + * ``-xKNL`` + * ``-xBROADWELL`` + * and more... + +* ``-ip``: interprocedural optimizations for single-file compilation. This flag is important for function inline in a single C++ file. This option is not by default in the makefile but is available in many machine files. + +* ``-ipo``: Interprocedural optimization, a step that examines function calls between files when the program is linked. This flag must be used to compile and when linking. Compile times are very long with this flag, however depending on the application there may be appreciable performance improvements when combined with the -O* flags. This flag is not by default in the makefile and is rarely used due to long compilation time. Use this flag for production runs if you do not plan to often recompile. + +* ``-inline-factor=1000``: Specifies the percentage multiplier that should be applied to all inlining options that define upper limits. + +* ``-fno-alias``: this is recommended only as an experiment, possibly to see whether a useful restrict keyword has been missed. It would mean that the compiler could ignore unproven aliasing hazards. + +A detailed description of the available flags for x86 instruction sets is given on this `page `_. +All Intel compiler flags are listed on this `page `_. + +More examples: + +* For AMD EPYC ROME processors: + +.. code-block:: bash + + -march=core-avx2 -xCORE-AVX2 -ip -inline-factor=1000 -fno-alias #-ipo + +* For Intel Broadwell processors: + +.. code-block:: bash + + -xCORE-AVX2 -O3 -ip -inline-factor=1000 -D__INTEL_BDW_E5_2697_V4 -fno-alias + +* For Intel Cascadelake processors: + +.. code-block:: bash + + -march=cascadelake -xCOMMON-AVX512 -ip -inline-factor=1000 -D__INTEL_CASCADELAKE_6248 -qopt-zmm-usage=high -fno-alias #-ipo + +* For Intel KNL processors: + +.. code-block:: bash + + -march=knl -xMIC-AVX512 -ip -inline-factor=1000 -D__INTEL_KNL_7250 -qopt-zmm-usage=high -fno-alias #-ipo + +.. rubric:: GNU compiler flags for optimization and vectorization + +* ``-O3``: this option directly integrated in the makefile tells the compiler to use agressive optimization at compilation + +* ``-Ofast``: Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs.It can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications. + +* ``-mtune=cpu-type``: This option specifies that GCC should tune the performance of the code as if the target were of the type specified in this option, here ``cpu-type``.For some ARM implementations better performance can be obtained by using this option. Possible common cpu types are + + * ``cascadelake`` + * ``skylake-avx512`` + * ``a64fx`` for A64FX Fujitsu processor + * ``knl`` + * ``broadwell`` + * ``znver2`` for 2nd generation AMD EPYC processors + * ``znver2`` for 3rd generation AMD EPYC processors + +* ``-march=cpu-type``: This flag does additional tuning for specific processor types. Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise. + + * ``cascadelake`` + * ``skylake-avx512`` + * ``sve`` to generate SVE instructions (vectorization on ARM like A64FX) + * ``armv8.2-a`` to generate armv8 instructions (like A64FX) + * ``knl`` + * ``broadwell`` + * ``znver2`` for 2nd generation AMD EPYC processors + * ``znver3`` for 3rd generation AMD EPYC processors + +* ``-msve-vector-bits=512``: Specify the number of bits in an SVE vector register on ARM architecture using SVE (useful for A64FX). + +* ``-ffast-math``: This option is not turned on by any -O option besides -Ofast since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications. + +Find out more information: + +* `Optimization flags for GNU `_. +* `g++ man page `_. +* `list of architecture options `_. +* `AMD quick reference guide `_. + +.. rubric:: LLVM compiler flags for optimization and vectorization + +The LLVM compiler shares many flags with the GNU one. + +* ``-O3``: this option directly integrated in the makefile tells the compiler to use agressive optimization at compilation + +* ``-Ofast``: Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs.It can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications. + +* ``-mtune=cpu-type``: This option specifies that LLVM should tune the performance of the code as if the target were of the type specified in this option, here ``cpu-type``.For some ARM implementations better performance can be obtained by using this option. Possible common cpu types are + + * ``cascadelake`` + * ``skylake-avx512`` + * ``a64fx`` for A64FX Fujitsu processor + * ``knl`` + * ``broadwell`` + * ``znver2`` for 2nd generation AMD EPYC processors + * ``znver2`` for 3rd generation AMD EPYC processors + +* ``-march=cpu-type``: This flag does additional tuning for specific processor types. Specifying ``-march=cpu-type`` implies ``-mtune=cpu-type``, except where noted otherwise. + + * ``cascadelake`` + * ``skylake-avx512`` + * ``sve`` to generate SVE instructions (vectorization on ARM like A64FX) + * ``armv8.2-a`` to generate armv8 instructions (like A64FX) + * ``knl`` + * ``broadwell`` + * ``znver2`` for 2nd generation AMD EPYC processors + * ``znver3`` for 3rd generation AMD EPYC processors + +* ``-ffast-math``: Enable fast-math mode. This option lets the compiler make aggressive, potentially-lossy assumptions about floating-point math. + +* ``-ffinite-math-only``: Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf. + +* ``-ffp-contract=off|on|fast|fast-honor-pragmas``: Specify when the compiler is permitted to form fused floating-point operations, such as fused multiply-add (FMA). Fused operations are permitted to produce more precise results than performing the same operations separately. + +Some examples: + +* For Intel Cascade processors: + +.. code-block:: bash + + -mtune=cascadelake -march=cascadelake -ffinite-math-only -ffp-contract=fast + +* For the A64FX processor: + +.. code-block:: bash + + -march=armv8.2-a+sve -ffinite-math-only -fsimdmath -fopenmp-simd -ffp-contract=fast #-ffast-math + +Find out more information: + +* `LLVM Clang user manual `_. + +.. rubric:: Fujitsu compiler flags for optimization and vectorization + +Fujitsu compiler is only used or the A64FX processor so far. +The compiler can work in two differents modes called Trad and Clang mode. +The Clang mode uses the Clang compilation flags. +The Trad moe is usually the default one, the Clang mode an be activated using the flag ``-Nclang``. + +* ``-O3`` (bothy in Trad and clang mode): by default in the makefile + +* ``-Kfast`` (in Trad mode) / ``-Ofast`` (in Clang mode) + +* ``-KA64FX`` (in Trad mode) + +* ``-KSVE`` (in Trad mode) / ``-march=sve`` (in Clang mode) + +* ``-KSSL2`` (in Trad mode) + +* ``-Kparallel`` (in Trad mode) + +* ``-Kunroll`` (in Trad mode) + +* ``-Ksimd=2`` (in Trad mode) + +* ``-Kassume=notime_saving_compilation`` (in Trad mode) + +* ``-Kocl`` (in Trad mode) / ``-ffj-ocl`` (in Clang mode) + +.. rubric:: Smilei compiler flags for adaptive vectorization + +Performance models are implemented in :program:`Smilei` for adaptive vectorization. +By default, a general performance model is used but some performance models can be used for specific types of processors: + +* ``-D__INTEL_CASCADELAKE_6248`` +* ``-D__INTEL_SKYLAKE_8168`` +* ``-D__AMD_ROME_7H12`` +* ``-D__INTEL_KNL_7250``: available in 3D only +* ``-D__INTEL_BDW_E5_2697_V4``: available in 3D only +* ``-D__INTEL_HSW_E5_2680_v3``: available in 3D only + +These flags are used in the corresponding machine files. diff --git a/_sources/Use/particle_initialization.rst.txt b/_sources/Use/particle_initialization.rst.txt new file mode 100644 index 000000000..6599ce995 --- /dev/null +++ b/_sources/Use/particle_initialization.rst.txt @@ -0,0 +1,58 @@ +Initialize particles from an array or a file +------------------------------------------------ + +In the namelist, :py:data:`position_initialization` and :py:data:`momentum_initialization` +may be set to a *numpy* array or to an *HDF5* file containing particle data to be imported. + +The position initialization is incompatible with :py:data:`number_density`, +:py:data:`charge_density` and :py:data:`particles_per_cell`. +Particles initialized outside of the initial simulation domain will not be created. + +The momentum initialization is incompatible with :py:data:`temperature` +and :py:data:`mean_velocity`. + +---- + +From a numpy array +^^^^^^^^^^^^^^^^^^ + +The :py:data:`position_initialization` may be a *numpy* array of shape ``(Ndim+1, Npart)`` +where ``Ndim`` is the number of particle dimensions, +and ``Npart`` is the total number of particles. +Positions components `x`, `y`, `z` are given along the first ``Ndim`` columns +and the weights are given in the last column of the array. + +The :py:data:`momentum_initialization` may be a *numpy* array of shape ``(3, Npart)``. +It requires that :py:data:`position_initialization` also be an array +with the same number of particles ``Npart``. +Momentum components `px`, `py`, `pz` are given in successive columns. + +---- + +From an *HDF5* file +^^^^^^^^^^^^^^^^^^^ + +The :py:data:`position_initialization` may be a path to an *HDF5* file containing the +appropriate data structure. The path may point to a file, +such as ``"some_folder/some_data.h5"``, but it may also contain the path +to a group inside the file, such as ``"some_folder/some_data.h5/group1/group2"``. + +The *HDF5* location must contain the following datasets, all 1-dimensional of equal size: + +* ``position/x``, list of `x` coordinates +* ``position/y``, list of `y` coordinates +* ``position/z``, list of `z` coordinates +* ``weight``, list of statistical weights + +The :py:data:`momentum_initialization` works the same way. It must be an *HDF5* location +containing the following datasets, all 1-dimensional of equal size: + +* ``momentum/x``, list of `px` +* ``momentum/y``, list of `py` +* ``momentum/z``, list of `pz` + +.. note:: + + This file structure is identical to that obtained from the :ref:`DiagTrackParticles`, + meaning that you can directly pass the output of a previous simulation, for instance + ``"path/to/results/TrackParticlesDisordered_myspecies.h5/data/0000003000/particles/myspecies"``. \ No newline at end of file diff --git a/_sources/Use/post-processing.rst.txt b/_sources/Use/post-processing.rst.txt new file mode 100644 index 000000000..32a6e02e8 --- /dev/null +++ b/_sources/Use/post-processing.rst.txt @@ -0,0 +1,1004 @@ +Post-process +------------ + +This page describes the usage of the python module ``happi`` for extracting, viewing +and post-processing simulation data. First, you need to :ref:`install happi `. + +The module can be imported directly in *python*:: + + import happi + + +---- + +Open a simulation +^^^^^^^^^^^^^^^^^^^ + +In a *python* command line (or script), call the following function to open +your :program:`Smilei` simulation. Note that several simulations can be opened at once, +as long as they correspond to several :ref:`restarts ` of the same simulation. + +.. py:method:: happi.Open(results_path=".", reference_angular_frequency_SI=None, show=True, verbose=True, scan=True, pint=True) + + * ``results_path``: path or list of paths to the directory-ies + where the results of the simulation-s are stored. It can also contain wildcards, + such as ``*`` and ``?`` in order to include several simulations at once. + + * ``reference_angular_frequency_SI``: overrides the value of the simulation parameter + :py:data:`reference_angular_frequency_SI`, in order to re-scale units. + + * ``show``: if ``False``, figures will not plot on screen. Make sure that + you have not loaded another simulation or the matplotlib package. You may need to + restart python. + + * ``verbose``: if ``False``, less information is printed while post-processing. + + * ``scan``: if ``False``, HDF5 output files are not scanned initially, and the namelist is not read. + + * ``pint``: if ``True``, *happi* attempts to load the *Pint* package and to use it for managing units. + + +**Returns:** An object containing various methods to extract and manipulate the simulation + outputs, as described below. + +**Example**:: + + S = happi.Open("path/to/my/results") + + +Once a simulation is opened, several methods are available to find information on the +namelist or open various diagnostics. Checkout the namelist documentation to find out +which diagnostics are included in Smilei: :ref:`scalars `, +:ref:`fields `, :ref:`probes `, +:ref:`particle binning `, :ref:`trajectories ` +and :ref:`performances `. + +---- + +Extract namelist information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Once a simulation is opened as shown above, you can access the content of the namelist +using the attribute ``namelist``:: + + S = happi.Open("path/to/my/results") # Open a simulation + print(S.namelist.Main.timestep) # print the timestep + print(S.namelist.Main.geometry) # print the simulation dimensions + +All the variables defined in the original namelist are copied into this variable. + +Concerning components like :ref:`Species`, :ref:`ExternalField` or :ref:`DiagProbe`, of which +several instances may exist, you can directly iterate over them:: + + for species in S.namelist.Species: + print("species "+species.name+" has mass "+str(species.mass)) + +You can also access to a specific component by referencing its number:: + + F = S.namelist.ExternalField[0] # get the first external field + print("An external field "+F.field+" was applied") + +In the case of the species, you can also obtain a given species by its name:: + + species = S.namelist.Species["electron1"] + print("species "+species.name+" has mass "+str(species.mass)) + + +---- + +Obtain diagnostic information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. rubric:: Print available diagnostics + +Commands ``S.Scalar``, ``S.Field``, ``S.Probe`` (etc.) will display general information +about the corresponding diagnostics in the simulation. + +.. rubric:: List available diagnostics + +.. py:method:: getDiags(diagType) + + Returns a list of available diagnostics of the given type + + * ``diagType``: The diagnostic type (``"Field"``, ``"Probe"``, etc.) + +.. py:method:: getTrackSpecies() + + Returns a list of available tracked species. + +.. rubric:: Information on specific diagnostics + +.. py:method:: fieldInfo(diag) + + * ``diag``: the number or name of a Field diagnostic + + Returns a dictionnary containing: + + * ``"diagNumber"``: the diagnostic number + * ``"diagName"``: the diagnostic name + * ``"fields"``: list of the available fields in this diagnostic. In the case of + ``AMcylindrical`` geometry, this is a dictionnary with a list of modes for each field. + +.. py:method:: probeInfo(diag) + + * ``diag``: the number or name of a Probe diagnostic + + Returns a dictionnary containing: + + * ``"probeNumber"``: the diagnostic number + * ``"probeName"``: the diagnostic name + * ``"fields"``: list of the available fields in this diagnostic + +.. py:method:: performanceInfo() + + Returns a dictionnary containing: + + * ``"quantities_uint"``: a list of the available integer quantities + * ``"quantities_double"``: a list of the available float quantities + * ``"patch_arrangement"``: the type of patch arrangement + * ``"timesteps"``: the list of timesteps + +---- + +Open a Scalar diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: Scalar(scalar=None, timesteps=None, units=[""], data_log=False, data_transform=None, **kwargs) + + * ``scalar``: The name of the scalar. + | If not given, then a list of available scalars is printed. + * ``timesteps``: The requested timestep(s). + | If omitted, all timesteps are used. + | If one number given, the nearest timestep available is used. + | If two numbers given, all the timesteps in between are used. + * ``units``: A unit specification (see :ref:`units`) + * ``data_log``: + | If ``True``, then :math:`\log_{10}` is applied to the output. + * ``data_transform``: + | If this is set to a function, the function is applied to the output before plotting. + * See also :ref:`otherkwargs` + +**Example**:: + + S = happi.Open("path/to/my/results") + Diag = S.Scalar("Utot") + +---- + +Open a Field diagnostic +^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: Field(diagNumber=None, field=None, timesteps=None, subset=None, average=None, units=[""], data_log=False, data_transform=None, moving=False, export_dir=None, **kwargs) + + * ``timesteps``, ``units``, ``data_log``, ``data_transform``: same as before. + * ``diagNumber``: number or ``name`` of the fields diagnostic + | If not given, then a list of available diagnostic numbers is printed. + * ``field``: The name of a field (``"Ex"``, ``"Ey"``, etc.) + | If not given, then a list of available fields is printed. + | The string can also be an operation between several fields, such as ``"Jx+Jy"``. + * ``subset``: A selection of coordinates to be extracted. + | Syntax 1: ``subset = { axis : location, ... }`` + | Syntax 2: ``subset = { axis : [start, stop] , ... }`` + | Syntax 3: ``subset = { axis : [start, stop, step] , ... }`` + | ``axis`` must be ``"x"``, ``"y"`` , ``"z"`` or ``"r"``. + | Only the data within the chosen axes' selections is extracted. + | **WARNING:** THE VALUE OF ``step`` IS A NUMBER OF CELLS. + | Example: ``subset = {"y":[10, 80, 4]}`` + * ``average``: A selection of coordinates on which to average. + | Syntax 1: ``average = { axis : "all", ... }`` + | Syntax 2: ``average = { axis : location, ... }`` + | Syntax 3: ``average = { axis : [start, stop] , ... }`` + | ``axis`` must be ``"x"``, ``"y"`` , ``"z"`` or ``"r"``. + | The chosen axes will be removed: + | - With syntax 1, an average is performed over all the axis. + | - With syntax 2, only the bin closest to ``location`` is kept. + | - With syntax 3, an average is performed from ``start`` to ``stop``. + | Example: ``average = {"x":[4,5]}`` will average for :math:`x` within [4,5]. + * ``moving``: If ``True``, plots will display the X coordinates evolving according to the + :ref:`moving window` + * ``export_dir``: The directory where to export VTK files. + * See also :ref:`otherkwargs` + + In the case of an azimuthal mode cylindrical geometry (``AMcylindrical``), additional argument are + available. You must choose one of ``theta`` or ``build3d``, defined below, in order + to construct fields from their complex angular Fourier modes. In addition, the ``modes`` + argument is optional. + + * ``theta``: An angle (in radians) + | Calculates the field in a plane passing through the :math:`r=0` axis + | and making an angle ``theta`` with the :math:`xy` plane. + * ``build3d``: A list of three *ranges* + | Calculates the field interpolated in a 3D :math:`xyz` grid. + | Each *range* is a list ``[start, stop, step]`` indicating the beginning, + | the end and the step of this grid. + * ``modes``: An integer or a list of integers + | Only these modes numbers will be used in the calculation. If omited, all modes are used. + + +**Example**:: + + S = happi.Open("path/to/my/results") + Diag = S.Field(0, "Ex", average = {"x":[4,5]}, theta=math.pi/4.) + + +---- + +Open a Probe diagnostic +^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: Probe(probeNumber=None, field=None, timesteps=None, subset=None, average=None, units=[""], data_log=False, data_transform=None, **kwargs) + + * ``timesteps``, ``units``, ``data_log``, ``data_transform``, ``export_dir``: same as before. + * ``probeNumber``: number or ``name`` of the probe (the first one has number 0). + | If not given, a list of available probes is printed. + * ``field``: name of the field (``"Bx"``, ``"By"``, ``"Bz"``, ``"Ex"``, ``"Ey"``, ``"Ez"``, ``"Jx"``, ``"Jy"``, ``"Jz"`` or ``"Rho"``). + | If not given, a list of available fields is printed. + | The string can also be an operation between several fields, such as ``"Jx+Jy"``. + * ``subset`` and ``average`` are very similar to those of :py:meth:`Field`, but they can only have the axes: ``"axis1"``, ``"axis2"`` and ``"axis3"``. + For instance, ``average={"axis1":"all"}``. Note that the axes are not necessarily :math:`x`, :math:`y` or :math:`z` because the probe mesh is arbitrary. + * See also :ref:`otherkwargs` + +**Example**:: + + S = happi.Open("path/to/my/results") + Diag = S.Probe(0, "Ex") + + +.. py:method:: Probe.changeField(field) + + In cases where happi's performance is an issue, it is possible to switch between different fields + of an open ``Probe`` diagnostic using this method. The ``field`` argument is the same as in ``Probe(...)`` above. + +---- + +Open a ParticleBinning diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: ParticleBinning(diagNumber=None, timesteps=None, subset=None, average=None, units=[""], data_log=False, data_transform=None, **kwargs) + + * ``timesteps``, ``units``, ``data_log``, ``data_transform``, ``export_dir``: same as before. + * ``diagNumber``: number or ``name`` of the particle binning diagnostic (starts at 0). + | If not given, a list of available diagnostics is printed. + | It can also be an operation between several diagnostics. + | For example, ``"#0/#1"`` computes the division by diagnostics 0 and 1. + * ``subset`` is similar to that of :py:meth:`Field`, although the axis must be one of + ``"x"``, ``"y"``, ``"z"``, ``"px"``, ``"py"``, ``"pz"``, ``"p"``, ``"gamma"``, ``"ekin"``, ``"vx"``, ``"vy"``, ``"vz"``, ``"v"`` or ``"charge"``. + + **WARNING:** With the syntax ``subset={axis:[start, stop, step]}``, the value of ``step`` + is a number of bins. + * ``average``: a selection of coordinates on which to average the data. + | Syntax 1: ``average = { axis : "all", ... }`` + | Syntax 2: ``average = { axis : location, ... }`` + | Syntax 3: ``average = { axis : [begin, end] , ... }`` + + ``axis`` must be ``"x"``, ``"y"``, ``"z"``, ``"px"``, ``"py"``, ``"pz"``, ``"p"``, ``"gamma"``, ``"ekin"``, ``"vx"``, ``"vy"``, ``"vz"``, ``"v"`` or ``"charge"``. + + | The chosen axes will be removed: + | - With syntax 1, an average is performed over all the axis. + | - With syntax 2, only the bin closest to ``location`` is kept. + | - With syntax 3, an average is performed between ``begin`` and ``end``. + | Example: ``average={"x":[4,5]}`` will average all the data for x within [4,5]. + * See also :ref:`otherkwargs` + +**Example**:: + + S = happi.Open("path/to/my/results") + Diag = S.ParticleBinning(1) + + +**Units of the results:** + + The raw quantity stored in the output file has the units of the :py:data:`deposited_quantity`. + Generally, this is a sum of :ref:`macro-particle weights`. As those weights + are not in units of density (but of density multiplied by hypervolume), a correction + is applied in *happi*: it divides the data by an hypervolume. More precisely, + for each direction ``x``, ``y`` or ``z``, if this direction is not included in one of + the diagnostic's axes, *happi* divides by the length of the box in that direction. + + In addition, in order to make the units relative to the bin size, *happi* divides the data + in each bin by the bin size. + + +---- + +Open a Screen diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: Screen(diagNumber=None, timesteps=None, subset=None, average=None, units=[""], data_log=False, data_transform=None, **kwargs) + + * ``timesteps``, ``units``, ``data_log``, ``data_transform``, ``export_dir``: same as before. + * ``diagNumber``, ``subset`` and ``average``: identical to that of ParticleBinning diagnostics. + * See also :ref:`otherkwargs` + +**Example**:: + + S = happi.Open("path/to/my/results") + Diag = S.Screen(0) + + +---- + +Open a RadiationSpectrum diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: ParticleBinning(diagNumber=None, timesteps=None, subset=None, average=None, units=[""], data_log=False, data_transform=None, **kwargs) + + * ``timesteps``, ``units``, ``data_log``, ``data_transform``, ``export_dir``: same as before. + * ``diagNumber``, ``subset`` and ``average``: identical to that of ParticleBinning diagnostics. + * See also :ref:`otherkwargs` + +**Example**:: + + S = happi.Open("path/to/my/results") + Diag = S.RadiationSpectrum(0) + +.. note:: + + The resulting spectral power is in units of :math:`\omega_r`. + If additional axes are used, the power spectrum is divided by the size of the bins of each axes. + +---- + +Open a TrackParticles diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: TrackParticles(species=None, select="", axes=[], timesteps=None, sort=True, length=None, units=[""], **kwargs) + + * ``timesteps``, ``units``, ``export_dir``: same as before. + * ``species``: the name of a tracked-particle species. + If omitted, a list of available tracked-particle species is printed. + * ``select``: Instructions for selecting particles among those available. + A detailed explanation is provided below + * ``axes``: A list of axes for plotting the trajectories or obtaining particle data. + Each axis is one of the :py:data:`attributes` defined in the namelist. + In addition, when there is a moving window, the axis ``"moving_x"`` is automatically available. + + | **Example:** ``axes = ["x"]`` corresponds to :math:`x` versus time. + | **Example:** ``axes = ["x","y"]`` correspond to 2-D trajectories. + | **Example:** ``axes = ["x","px"]`` correspond to phase-space trajectories. + * ``sort``: may be either + + * ``False``: the particles are not sorted by ID. This can save significant + time, but prevents plotting, exporting to VTK, and the ``select`` argument. Only + ``getData`` and ``iterParticles`` are available in this mode. + Read :doc:`this ` for more information on particle IDs. + * ``True``: the particles are sorted in a new file, unless this file already exists. + If it does, sorted particles are directly read from the sorted file. + * A string for selecting particles (same syntax as ``select``): only selected + particles are sorted in a new file. The file name must be defined + in the argument ``sorted_as``. If ``timesteps`` is used, only selected timesteps + will be included in the created file. + + * ``sorted_as``: a keyword that defines the new sorted file name (when ``sort`` is a + selection) or refers to a previously user-defined sorted file name (when ``sort`` is not given). + * ``length``: The length of each plotted trajectory, in number of timesteps. + * See also :ref:`otherkwargs` + +**Example**:: + + S = happi.Open("path/to/my/results") + Diag = S.TrackParticles("electrons", axes=["px","py"]) + + +.. rubric:: Detailed explanation of the ``select`` parameter + +| Say ``times`` is a condition on timesteps ``t``, for instance ``t>50``. +| Say ``condition`` is a condition on particles properties (``x``, ``y``, ``z``, ``px``, ``py``, ``pz``), for instance ``px>0``. + +* | **Syntax 1:** ``select="any(times, condition)"`` + | Selects particles satisfying ``condition`` for at least one of the ``times``. + | For example, ``select="any(t>0, px>1.)"`` selects those reaching :math:`p_x>1` at some point. + +* | **Syntax 2:** ``select="all(times, condition)"`` + | Selects particles satisfying ``condition`` at all ``times``. + | For example, ``select="all(t<40, px<1)"`` selects those having :math:`p_x<1` until timestep 40. + +* | **Syntax 3:** ``select=[ID1, ID2, ...]`` + | Selects the provided particle IDs. + +* | It is possible to make logical operations: ``+`` is *OR*; ``*`` is *AND*; ``~`` is *NOT*. + | For example, ``select="any((t>30)*(t<60), px>1) + all(t>0, (x>1)*(x<2))"`` + + +---- + +.. rst-class:: experimental + +Open a NewParticles diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: NewParticles(species=None, select="", axes=[], units=[""], **kwargs) + + * ``units``: same as before. + * ``species``: same as for ``TrackParticles`` + * ``axes``: same as for ``TrackParticles``, with the addition of another axis ``t`` + that represents the time when the particle was born. + * ``select``: Instructions for selecting particles among those available. + It must be a condition on particles properties ``axes``, for instance ``px>0``. + It is possible to make logical operations: ``+`` is *OR*; ``*`` is *AND*; ``~`` is *NOT*. + + | **Example:** ``select="(x>1)*(x<2)"`` + + It is also possible to select directly a list of IDs. + + | **Example:** ``select=[ID1, ID2, ...]`` + +---- + +Open a Performances diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The post-processing of the *performances* diagnostic may be achieved in three different +modes: ``raw``, ``map``, or ``histogram``, described further below. You must choose one +and only one mode between those three. + +.. py:method:: Performances(raw=None, map=None, histogram=None, timesteps=None, units=[""], data_log=False, data_transform=None, species=None, cumulative=True, **kwargs) + + * ``timesteps``, ``units``, ``data_log``, ``data_transform``, ``export_dir``: same as before. + * ``raw``: The name of a quantity, or an operation between them (see quantities below). + The requested quantity is listed for each process. + * ``map``: The name of a quantity, or an operation between them (see quantities below). + The requested quantity is mapped vs. space coordinates (1D and 2D only). + * ``histogram``: the list ``["quantity", min, max, nsteps]``. + Makes a histogram of the requested quantity between ``min`` an ``max``, with ``nsteps`` bins. + The ``"quantity"`` may be an operation between the quantities listed further below. + * ``cumulative``: may be ``True`` for timers accumulated for the duration of the simulation, + or ``False`` for timers reset to 0 at each output. + * See also :ref:`otherkwargs` + + +**Quantities at the MPI-process level** (contain many patches): + + * ``hindex`` : the starting index of each proc in the hilbert curve + * ``number_of_cells`` : the number of cells in each proc + * ``number_of_particles`` : the total number of non-frozen macro-particles in each proc (includes all species) + * ``number_of_frozen_particles`` : the number of frozen particles in each proc + * ``total_load`` : the `load` of each proc (number of macro-particles and cells weighted by cell_load coefficients) + * ``timer_global`` : global simulation time (only available for proc 0) + * ``timer_particles`` : time spent computing particles by each proc + * ``timer_maxwell`` : time spent solving maxwell by each proc + * ``timer_envelope`` : time spent solving the envelope propagation by each proc + * ``timer_densities`` : time spent projecting densities by each proc + * ``timer_collisions`` : time spent computing collisions by each proc + * ``timer_movWindow`` : time spent handling the moving window by each proc + * ``timer_loadBal`` : time spent balancing the load by each proc + * ``timer_partMerging`` : time spent merging particles by each proc + * ``timer_syncPart`` : time spent synchronzing particles by each proc + * ``timer_syncField`` : time spent synchronzing fields by each proc + * ``timer_syncDens`` : time spent synchronzing densities by each proc + * ``timer_syncSusceptibility`` : time spent synchronzing susceptibility by each proc + * ``timer_diags`` : time spent by each proc calculating and writing diagnostics + * ``timer_total`` : the sum of all timers above (except timer_global) + * ``memory_total`` : the total memory (RSS) used by the process in GB + * ``memory_peak`` : the peak memory (peak RSS) used by the process in GB + + **WARNING**: The timers ``loadBal`` and ``diags`` include *global* communications. + This means they might contain time doing nothing, waiting for other processes. + The ``sync***`` timers contain *proc-to-proc* communications, which also represents + some waiting time. + +**Quantities at the patch level**: + + This requires :py:data:`patch_information` in the namelist. + + * ``mpi_rank`` : the MPI rank that contains the current patch + * ``vecto`` : the mode of the specified species in the current patch + (vectorized of scalar) when the adaptive mode is activated. Here the ``species`` argument has to be specified. + + **WARNING**: The patch quantities are only compatible with the ``raw`` mode + and only in ``3Dcartesian`` :py:data:`geometry`. The result is a patch matrix with the + quantity on each patch. + + +**Example**: performance diagnostic at the MPI level:: + + S = happi.Open("path/to/my/results") + Diag = S.Performances(map="total_load") + +**Example**: performance diagnostic at the patch level:: + + S = happi.Open("path/to/my/results") + Diag = S.Performances(raw="vecto", species="electron") + +---- + +.. _units: + +Specifying units +^^^^^^^^^^^^^^^^ + +By default, all the diagnostics data is in code units (see :doc:`/Understand/units`). + +To change the units, all the methods :py:meth:`Scalar() `, +:py:meth:`Field() `, :py:meth:`Probe() `, +:py:meth:`ParticleBinning() ` and +:py:meth:`TrackParticles() ` support a ``units`` argument. +It has three different syntaxes: + +1. **A list**, for example ``units = ["um/ns", "feet", "W/cm^2"]`` + + In this case, any quantity found to be of the same dimension as one of these units + will be converted. + +2. **A dictionary**, for example ``units = {"x":"um", "y":"um", "v":"Joule"}`` + + In this case, we specify the units separately for axes ``x`` and ``y``, and for the + data values ``v``. + +3. **A** ``Units`` **object**, for example ``units = happi.Units("um/ns", "feet", x="um")`` + + This version combines the two previous ones. + +.. rubric:: Requirements for changing units + +* The `Pint module `_. +* To obtain units in a non-normalized system (e.g. SI), the simulation must have the + parameter :py:data:`reference_angular_frequency_SI` set to a finite value. + Otherwise, this parameter can be set during post-processing as an argument to the + :py:meth:`happi.Open` function. + +---- + +.. _otherkwargs: + +Other arguments for diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All diagnostics above can use additional keyword arguments (``kwargs``) +to manipulate the plotting options: + +* ``figure``: The figure number that is passed to matplotlib. +* ``vmin``, ``vmax``: data value limits. +* ``vsym``: makes data limits symmetric about 0 (``vmin`` and ``vmax`` are ignored), + and sets the colormap to ``smileiD``. + + * If ``vsym = True``, autoscale symmetrically. + * If ``vsym`` is a number, limits are set to [-``vsym``, ``vsym``]. + +* ``xmin``, ``xmax``, ``ymin``, ``ymax``: axes limits. +* ``xfactor``, ``yfactor``: factors to rescale axes. +* ``title``: a string that replaces the plot title (or the y-label in a 1D plot). + The current simulation time can be included with the placeholders ``{time}`` and + ``{time_units}``, together with formatting instructions conforming to + `python's string formatter `_. + For instance: ``title = "Density @ $t = {time:.0f} {time_units}$"``. +* ``side``: ``"left"`` (by default) or ``"right"`` puts the y-axis on the left- + or the right-hand-side. +* ``transparent``: ``None`` (by default), ``"over"``, ``"under"``, ``"both"``, or a *function*. + The colormap becomes transparent *over*, *under*, or *outside both* the boundaries + set by ``vmin`` and ``vmax``. + This argument may be set instead to a function mapping the data value :math:`\in [0,1]` to the + transparency :math:`\in [0,1]`. For instance ``lambda x: 1-x``. +* Other Matplotlib arguments listed in :ref:`advancedOptions`. + +---- + +Obtain the data +^^^^^^^^^^^^^^^ + +.. py:method:: Scalar.getData( timestep=None ) + Field.getData( timestep=None ) + Probe.getData( timestep=None ) + ParticleBinning.getData( timestep=None ) + Screen.getData( timestep=None ) + TrackParticles.getData( timestep=None ) + + Returns a list of the data arrays (one element for each timestep requested). + In the case of ``TrackParticles``, this method returns a dictionary containing one + entry for each axis, and if ``sort==False``, these entries are included inside an entry + for each timestep. + + * ``timestep``, if specified, is the only timestep number that is read and returned. + + **Example**:: + + S = happi.Open("path/to/results") # Open the simulation + Diag = S.Field(0, "Ex") # Open Ex in the first Field diag + result = Diag.getData() # Get list of Ex arrays (one for each time) + + +.. py:method:: Scalar.getTimesteps() + Field.getTimesteps() + Probe.getTimesteps() + ParticleBinning.getTimesteps() + Screen.getTimesteps() + TrackParticles.getTimesteps() + + Returns a list of the timesteps requested. + + +.. py:method:: Scalar.getTimes() + Field.getTimes() + Probe.getTimes() + ParticleBinning.getTimes() + Screen.getTimes() + TrackParticles.getTimes() + + Returns the list of the times requested. + By default, times are in the code's units, but are converted to the diagnostic's + units defined by the ``units`` argument, if provided. + + +.. py:method:: Scalar.getAxis( axis ) + Field.getAxis( axis, timestep ) + Probe.getAxis( axis ) + ParticleBinning.getAxis( axis, timestep ) + Screen.getAxis( axis, timestep ) + + Returns the list of positions of the diagnostic data along the requested axis. + If the axis is not available, returns an empty list. + By default, axis positions are in the code's units, but are converted to + the diagnostic's units defined by the ``units`` argument, if provided. + + * ``axis``: the name of the requested axis. + + * For ``Field``: this is ``"x"``, ``"y"`` or ``"z"`` + * For ``Probe``: this is ``"axis1"``, ``"axis2"`` or ``"axis3"`` + * For ``ParticleBinning`` and ``Screen``: this is the ``type`` of the :py:data:`axes` + defined in the namelist + + * ``timestep``: The timestep at which the axis is obtained. Only matters in + ``ParticleBinning``, ``Screen`` and ``RadiationSpectrum`` when ``auto`` axis + limits are requested; or in ``Field`` when ``moving=True``. + + +.. py:method:: TrackParticles.iterParticles(timestep, chunksize=1) + + This method, specific to the tracked particles, provides a fast iterator on chunks of particles + for a given timestep. The argument ``chunksize`` is the number of particles in each chunk. + Note that the data is *not ordered* by particle ID, meaning that particles are not ordered + the same way from one timestep to another. + + The returned quantity for each iteration is a python dictionary containing key/value + pairs ``axis:array``, where ``axis`` is the name of the particle characteristic (``"x"``, + ``"px"``, etc.) and ``array`` contains the corresponding particle values. + + **Example**:: + + S = happi.Open("path/to/my/results") # Open the simulation + Diag = S.TrackParticles("my_particles") # Open the tracked particles + npart = 0 + sum_px = 0. + # Loop particles of timestep 100 by chunks of 10000 + for particle_chunk in Diag.iterParticles(100, chunksize=10000): + npart += particle_chunk["px"].size + sum_px += particle_chunk["px"].sum() + # Calculate the average px + mean_px = sum_px / npart + +.. py:method:: Field.getXmoved( timestep ) + + Specific to Field diagnostics, this method returns the displacement of the moving + window at the required ``timestep``. + +---- + +Export 2D or 3D data to VTK +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: Field.toVTK( numberOfPieces=1 ) + Probe.toVTK( numberOfPieces=1 ) + ParticleBinning.toVTK( numberOfPieces=1 ) + Performances.toVTK( numberOfPieces=1 ) + Screen.toVTK( numberOfPieces=1 ) + TrackParticles.toVTK( rendering="trajectory", data_format="xml" ) + + Converts the data from a diagnostic object to the vtk format. + Note the ``export_dir`` argument available for each diagnostic (see above). + + * ``numberOfPieces``: the number of files into which the data will be split. + + * ``rendering``: the type of output in the case of :py:meth:`TrackParticles`: + + * ``"trajectory"``: show particle trajectories. One file is generated for all trajectories. + This rendering requires the particles to be sorted. + * ``"cloud"``: show a cloud of particles. One file is generated for each iteration. + This rendering can be used without sorting the particles. + + * ``data_format``: the data formatting in the case of :py:meth:`TrackParticles`, + either ``"vtk"`` or ``"xml"``. The format ``"vtk"`` results in ascii. + + **Example for tracked particles**:: + + S = happi.Open("path/to/my/results") + tracked_particles = S.TrackParticles("electron", axes=["x","y","z","px","py","pz","Id"], timesteps=[1,10]) + # Create cloud of particles in separate files for each iteration + tracked_particles.toVTK(rendering="cloud",data_format="xml"); + # Create trajectory in a single file + tracked_particles.toVTK(rendering="trajectory",data_format="xml"); + +---- + +Plot the data at one timestep +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is the first method to plot the data. It produces a static image of the data +at one given timestep. + +.. py:method:: Scalar.plot(...) + Field.plot(...) + Probe.plot(...) + ParticleBinning.plot(...) + TrackParticles.plot(...) + Screen.plot(...) + + All these methods have the same arguments described below. + +.. py:function:: plot(timestep=None, saveAs=None, axes=None, dpi=200, **kwargs) + + | If the data is 1D, it is plotted as a **curve**. + | If the data is 2D, it is plotted as a **map**. + | If the data is 0D, it is plotted as a **curve** as function of time. + + * ``timestep``: The iteration number at which to plot the data. + * ``saveAs``: name of a directory where to save each frame as figures. + You can even specify a filename such as ``mydir/prefix.png`` and it will automatically + make successive files showing the timestep: ``mydir/prefix0.png``, ``mydir/prefix1.png``, + etc. + * ``axes``: Matplotlib's axes handle on which to plot. If None, make new axes. + * ``dpi``: the number of dots per inch for ``saveAs``. + + You may also have keyword-arguments (``kwargs``) described in :ref:`otherkwargs`. + +**Example**:: + + S = happi.Open("path/to/my/results") + S.ParticleBinning(1).plot(timestep=40, vmin=0, vmax=1e14) + +---- + +Plot the data streaked over time +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This second type of plot works only for 1D data. All available timesteps +are streaked to produce a 2D image where the second axis is time. + +.. py:method:: Scalar.streak(...) + Field.streak(...) + Probe.streak(...) + ParticleBinning.streak(...) + TrackParticles.streak(...) + Screen.streak(...) + + All these methods have the same arguments described below. + +.. py:function:: streak(saveAs=None, axes=None, **kwargs) + + All arguments are identical to those of ``plot``, with the exception of ``timestep``. + +**Example**:: + + S = happi.Open("path/to/my/results") + S.ParticleBinning(1).streak() + +---- + +Animated plot +^^^^^^^^^^^^^ + +This third plotting method animates the data over time. + +.. py:method:: Scalar.animate(...) + Field.animate(...) + Probe.animate(...) + ParticleBinning.animate(...) + TrackParticles.animate(...) + Screen.animate(...) + + All these methods have the same arguments described below. + +.. py:function:: animate(movie="", fps=15, dpi=200, saveAs=None, axes=None, **kwargs) + + All arguments are identical to those of ``streak``, with the addition of: + + * ``movie``: name of a file to create a movie, such as ``"movie.avi"`` or ``"movie.gif"``. + If ``movie=""`` no movie is created. + * ``fps``: number of frames per second (only if movie requested). + * ``dpi``: number of dots per inch for both ``movie`` and ``saveAs`` + +**Example**:: + + S = happi.Open("path/to/my/results") + S.ParticleBinning(1).animate() + +---- + +Plot with a slider +^^^^^^^^^^^^^^^^^^ + +This methods provides an interactive slider to change the time. + +.. py:method:: Scalar.slide(...) + Field.slide(...) + Probe.slide(...) + ParticleBinning.slide(...) + TrackParticles.slide(...) + Screen.slide(...) + + All these methods have the same arguments described below. + +.. py:function:: slide(axes=None, **kwargs) + + See ``plot`` for the description of the arguments. + +**Example**:: + + S = happi.Open("path/to/my/results") + S.ParticleBinning(1).slide(vmin=0) + +---- + +Simultaneous plotting of multiple diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:function:: happi.multiPlot(diag1, diag2, ... , **kwargs) + + Makes an animated figure containing several plots (one for each diagnostic). + If all diagnostics are of similar type, they may be overlayed on only one plot. + + * ``diag1``, ``diag2``, etc. + | Diagnostics prepared by ``Scalar()``, ``Field()``, ``Probe()``, etc. + + Keyword-arguments ``kwargs`` are: + + * ``figure``: The figure number that is passed to matplotlib (default is 1). + * ``shape``: The arrangement of plots inside the figure. For instance, ``[2, 1]`` + makes two plots stacked vertically, and ``[1, 2]`` makes two plots stacked horizontally. + If absent, stacks plots vertically. + * ``legend_font``: dictionnary to set the legend's font properties, + such as ``{'size':15, 'weight':'bold', 'family':'serif', 'color':'k'}``. + * ``movie`` : filename to create a movie. + * ``fps`` : frames per second for the movie. + * ``dpi`` : resolution of the ``movie`` or ``saveAs``. + * ``saveAs``: name of a directory where to save each frame as figures. + You can even specify a filename such as ``mydir/prefix.png`` and it will automatically + make successive files showing the timestep: ``mydir/prefix0.png``, ``mydir/prefix1.png``, etc. + * ``skipAnimation`` : if True, plots only the last frame. + * ``timesteps``: same as the ``timesteps`` argument of the :py:func:`plot` method. + + +.. py:function:: happi.multiSlide(diag1, diag2, ... , **kwargs) + + Identical to ``happi.multiPlot`` but uses a time slider instead of an animation. + + * ``diag1``, ``diag2``, etc. + | Diagnostics prepared by ``Scalar()``, ``Field()``, ``Probe()``, etc. + * ``figure``, ``shape``, and ``legend_font``: same as in ``happi.multiPlot``. + + +**Example**:: + + S = happi.Open("path/to/my/results") + A = S.Probe(probeNumber=0, field="Ex") + B = S.ParticleBinning(diagNumber=1) + happi.multiPlot( A, B, figure=1 ) + +.. + + This plots a Probe and a ParticleBinning on the same figure, and makes an animation for all available timesteps. + +.. note:: + + To plot several quantities on the same graph, you can try ``shape=[1,1]``. + One diagnostic may have the option ``side="right"`` to use the right-hand-side axis. + +---- + +.. _advancedOptions: + +Advanced plotting options +^^^^^^^^^^^^^^^^^^^^^^^^^ + +In addition to ``figure``, ``vmin``, ``vmax``, ``xmin``, ``xmax``, ``ymin`` and ``ymax``, +there are many more optional arguments. They are directly passed to the *matplotlib* package. + +.. rubric:: For the figure: ``figsize``, ``dpi``, ``facecolor``, ``edgecolor`` + +.. + + Please refer to + `matplotlib's figure options `_. + +.. rubric:: For the axes frame: ``aspect``, ``axis_facecolor``, ``frame_on``, ``position``, + ``visible``, ``xlabel``, ``xscale``, ``xticklabels``, ``xticks``, + ``ylabel``, ``yscale``, ``yticklabels``, ``yticks``, ``zorder`` + +.. + + Please refer to matplotlib's axes options: the same as functions starting + with ``set_`` listed `here `_. + +.. rubric:: For the lines: ``color``, ``dashes``, ``drawstyle``, ``fillstyle``, + ``label``, ``linestyle``, ``linewidth``, + ``marker``, ``markeredgecolor``, ``markeredgewidth``, + ``markerfacecolor``, ``markerfacecoloralt``, ``markersize``, ``markevery``, + ``visible``, ``zorder`` + +.. + + Please refer to + `matplotlib's line options `_. + +.. rubric:: For the image: ``cmap``, ``aspect``, ``interpolation``, ``norm`` + +.. + + Please refer to + `matplotlib's image options `_. + +.. rubric:: For the colorbar: ``cbaspect``, ``orientation``, ``fraction``, ``pad``, + ``shrink``, ``anchor``, ``panchor``, ``extend``, ``extendfrac``, ``extendrect``, + ``spacing``, ``ticks``, ``format``, ``drawedges``, ``size``, ``clabel`` + +.. + + Please refer to + `matplotlib's colorbar options `_. + +.. rubric:: For the tick number format: ``style_x``, ``scilimits_x``, ``useOffset_x``, + ``style_y``, ``scilimits_y``, ``useOffset_y`` + + +.. + + Please refer to + `matplotlib's tick label format `_. + +.. rubric:: For fonts: ``title_font``, ``xlabel_font``, ``xticklabels_font``, + ``ylabel_font``, ``yticklabels_font``, ``colorbar_font`` + +.. + + These options are dictionnaries that may contain the entries available in + `matplotlib's font properties `_, + for instance:: + + title_font = {'size': 15, 'weight': 'bold', 'family':'serif', 'color': 'k'} + +**Example**: + + To choose a gray colormap of the image, use ``cmap="gray"``:: + + S = happi.Open("path/to/my/results") + S.ParticleBinning(0, figure=1, cmap="gray") .plot() + +.. + + Many colormaps are available from the *matplotlib* package. With ``cmap=""``, you will get a list of available colormaps. + Smilei's default colormaps are: ``smilei``, ``smilei_r``, ``smileiD`` and ``smileiD_r``. + +---- + +Update the plotting options +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: Scalar.set(...) + Field.set(...) + Probe.set(...) + ParticleBinning.set(...) + Screen.set(...) + + + **Example**:: + + S = happi.Open("path/to/my/results") + A = S.ParticleBinning(diagNumber=0, figure=1, vmax=1) + A.plot( figure=2 ) + A.set( vmax=2 ) + A.plot() + +---- + +Other tools in ``happi`` +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:method:: happi.openNamelist(namelist) + + Reads a namelist and stores all its content in the returned object. + + * ``namelist``: the path to the namelist. + +**Example**:: + + namelist = happi.openNamelist("path/no/my/namelist.py") + print namelist.Main.timestep diff --git a/_sources/Use/profiles.rst.txt b/_sources/Use/profiles.rst.txt new file mode 100644 index 000000000..fb7039c9e --- /dev/null +++ b/_sources/Use/profiles.rst.txt @@ -0,0 +1,244 @@ +Profiles +-------- + +Several quantities require the input of a profile: particle charge, particle density, +external fields, etc. Depending on the case, they can be *spatial* or *temporal* +profiles. + +---- + +Constant profiles +^^^^^^^^^^^^^^^^^^^^ + +* ``Species( ... , charge = -3., ... )`` defines a species with charge :math:`Z^\star=3`. + +* ``Species( ... , number_density = 10., ... )`` defines a species with density :math:`10\,N_r`. + You can choose ``number_density`` or ``charge_density`` + +* ``Species( ... , mean_velocity = [0.05, 0., 0.], ... )`` defines a species + with drift velocity :math:`v_x = 0.05\,c` over the whole box. + +* ``Species(..., momentum_initialization="maxwell-juettner", temperature=[1e-5], ...)`` defines + a species with a Maxwell-Jüttner distribution of temperature :math:`T = 10^{-5}\,m_ec^2` over the whole box. + Note that the temperature may be anisotropic: ``temperature=[1e-5, 2e-5, 2e-5]``. + +* ``Species( ... , particles_per_cell = 10., ... )`` defines a species with 10 particles per cell. + +* ``ExternalField( field="Bx", profile=0.1 )`` defines a constant external field :math:`B_x = 0.1 B_r`. + + +---- + +*Python* profiles +^^^^^^^^^^^^^^^^^^^^ + +Any *python* function can be a profile. Examples:: + + def f(x): + if x<1.: return 0. + else: return 1. + +.. code-block:: python + + import math + def f(x,y): # two variables for 2D simulation + twoPI = 2.* math.pi + return math.cos( twoPI * x/3.2 ) + +.. code-block:: python + + f = lambda x: x**2 - 1. + + +Once the function is created, you have to include it in the block you want, +for example:: + + Species( ... , charge = f, ... ) + + Species( ... , mean_velocity = [f, 0, 0], ... ) + + +.. note:: It is possible, for higher performances, to create functions with + arguments *(x, y, etc.)* that are actually *numpy* arrays. If the function returns + a *numpy* array of the same size, it will automatically be considered as a profile + acting on arrays instead of single floats. Currently, this feature is only available + on Species' profiles. + +---- + +Pre-defined *spatial* profiles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:function:: constant(value, xvacuum=0., yvacuum=0.) + + :param value: the magnitude + :param xvacuum: vacuum region before the start of the profile. + +.. py:function:: trapezoidal(max, \ + xvacuum=0., xplateau=None, xslope1=0., xslope2=0., \ + yvacuum=0., yplateau=None, yslope1=0., yslope2=0. ) + + :param max: maximum value + :param xvacuum: empty length before the ramp up + :param xplateau: length of the plateau (default is :py:data:`grid_length` :math:`-` ``xvacuum``) + :param xslope1: length of the ramp up + :param xslope2: length of the ramp down + +.. py:function:: gaussian(max, \ + xvacuum=0., xlength=None, xfwhm=None, xcenter=None, xorder=2, \ + yvacuum=0., ylength=None, yfwhm=None, ycenter=None, yorder=2 ) + + :param max: maximum value + :param xvacuum: empty length before starting the profile + :param xlength: length of the profile (default is :py:data:`grid_length` :math:`-` ``xvacuum``) + :param xfwhm: gaussian FWHM (default is ``xlength/3.``) + :param xcenter: gaussian center position (default is in the middle of ``xlength``) + :param xorder: order of the gaussian. + :note: If ``yorder`` equals 0, then the profile is constant over :math:`y`. + +.. py:function:: polygonal( xpoints=[], xvalues=[] ) + + :param xpoints: list of the positions of the points + :param xvalues: list of the values of the profile at each point + +.. py:function:: cosine( base, amplitude=1., \ + xvacuum=0., xlength=None, xphi=0., xnumber=1 ) + + :param base: offset of the profile value + :param amplitude: amplitude of the cosine + :param xvacuum: empty length before starting the profile + :param xlength: length of the profile (default is :py:data:`grid_length` :math:`-` ``xvacuum``) + :param xphi: phase offset + :param xnumber: number of periods within ``xlength`` + +.. py:function:: polynomial( x0=0., y0=0., z0=0., order0=[], order1=[], ... ) + + :param x0,y0: The reference position(s) + :param order0: Coefficient for the 0th order + :param order1: Coefficient for the 1st order (2 coefficients in 2D) + :param order2: Coefficient for the 2nd order (3 coefficients in 2D) + :param etc: + + Creates a polynomial of the form + + .. math:: + + \begin{eqnarray} + &\sum_i a_i(x-x_0)^i & \quad\mathrm{in\, 1D}\\ + &\sum_i \sum_j a_{ij}(x-x0)^{i-j}(y-y0)^j & \quad\mathrm{in\, 2D}\\ + &\sum_i \sum_j \sum_k a_{ijk}(x-x0)^{i-j-k}(y-y0)^j(z-z0)^k & \quad\mathrm{in\, 3D} + \end{eqnarray} + + Each ``orderi`` is a coefficient (or list of coefficents) associated to the order ``i``. + In 1D, there is only one coefficient per order. In 2D, each ``orderi`` is a list + of ``i+1`` coefficients. For instance, the second order has three coefficients + associated to :math:`x^2`, :math:`xy` and :math:`y^2`, respectively. + In 3D, each ``orderi`` is a list of ``(i+1)*(i+2)/2`` coefficients. For instance, + the second order has 6 coefficients associated to :math:`x^2`, :math:`xy`, :math:`xz`, + :math:`y^2`, :math:`yz` and :math:`z^2`, respectively. + +**Examples**:: + + Species( ... , density = gaussian(10., xfwhm=0.3, xcenter=0.8), ... ) + + ExternalField( ..., profile = constant(2.2), ... ) + +.. rubric:: Illustrations of the pre-defined spatial profiles + +.. image:: /_static/pythonprofiles.png + +---- + +Pre-defined *temporal* profiles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:function:: tconstant(start=0.) + + :param start: starting time + +.. py:function:: ttrapezoidal(start=0., plateau=None, slope1=0., slope2=0.) + + :param start: starting time + :param plateau: duration of the plateau (default is :py:data:`simulation_time` :math:`-` ``start``) + :param slope1: duration of the ramp up + :param slope2: duration of the ramp down + +.. py:function:: tgaussian(start=0., duration=None, fwhm=None, center=None, order=2) + + :param start: starting time + :param duration: duration of the profile (default is :py:data:`simulation_time` :math:`-` ``start``) + :param fwhm: gaussian FWHM (default is ``duration/3.``) + :param center: gaussian center time (default is in the middle of ``duration``) + :param order: order of the gaussian + +.. py:function:: tpolygonal( points=[], values=[] ) + + :param points: list of times + :param values: list of the values at each time + +.. py:function:: tcosine( base=0., amplitude=1., start=0., duration=None, phi=0., freq=1. ) + + :param base: offset of the profile value + :param amplitude: amplitude of the cosine + :param start: starting time + :param duration: duration of the profile (default is :py:data:`simulation_time` :math:`-` ``start``) + :param phi: phase offset + :param freq: frequency + +.. py:function:: tpolynomial( t0=0., order0=[], order1=[], ... ) + + :param t0: The reference position + :param order0: Coefficient for the 0th order + :param order1: Coefficient for the 1st order + :param order2: Coefficient for the 2nd order + :param etc: + + Creates a polynomial of the form :math:`\sum_i a_i(t-t_0)^i`. + +.. py:function:: tsin2plateau( start=0., fwhm=0., plateau=None, slope1=fwhm, slope2=slope1 ) + + :param start: Profile is 0 before start + :param fwhm: Full width half maximum of the profile + :param plateau: Length of the plateau + :param slope1: Duration of the ramp up of the profil + :param slope2: Duration of the ramp down of the profil + + Creates a sin squared profil with a plateau in the middle if needed. If slope1 and 2 are used, fwhm is overwritten. + +**Example**:: + + Antenna( ... , time_profile = tcosine(freq=0.01), ... ) + + +.. rubric:: Illustrations of the pre-defined temporal profiles + +.. image:: /_static/pythonprofiles_t.png + + +---- + +Extract the profile from a file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following profiles may be given directly as an HDF5 file: + +* ``Species.charge_density`` +* ``Species.number_density`` +* ``Species.particles_per_cell`` +* ``Species.charge`` +* ``Species.mean_velocity`` +* ``Species.temperature`` +* ``ExternalField.profile`` except when complex (cylindrical geometry) + +You must provide the path to the file, and the path to the dataset +inside the file. +For instance ``charge_density = "myfile.h5/path/to/dataset"``. + +The targeted dataset located in the file must be an array with +the same dimension and the same number of cells as the simulation grid. + +.. warning:: + + For ``ExternalField``, the array size must take into account the + number of ghost cells in each direction. There is also one extra cell + in specific directions due to the grid staggering (see :ref:`this doc `). \ No newline at end of file diff --git a/_sources/Use/run.rst.txt b/_sources/Use/run.rst.txt new file mode 100644 index 000000000..903274ad2 --- /dev/null +++ b/_sources/Use/run.rst.txt @@ -0,0 +1,183 @@ +.. _run: + +Run +--- + +Before you launch :program:`Smilei`, :doc:`write a namelist file` +containing all the information of your simulation (grid shape, particles, lasers, diagnostics, etc.). + +You can also start from an example provided in the ``benchmarks`` directory. + +---- + +The ``smilei`` executable +^^^^^^^^^^^^^^^^^^^^^^^^^ + +`Compiling Smilei `_ creates an executable file ``smilei`` in the source directory. + +.. code-block:: bash + + smilei arg1 arg2 arg3 ... + +The command-line arguments ``arg1``, ``arg2``, ``arg3`` (etc.) can be: + +* the path to a namelist +* any *python* instruction that you want to execute during the namelist reading. + +The simplest example, to run your namelist ``my_namelist.py``, is + +.. code-block:: bash + + ./smilei my_namelist.py + +You may also add an additional instruction to be appended at the end of the namelist: + +.. code-block:: bash + + ./smilei my_namelist.py "Main.print_every=10" + +Note that, in addition, you will generally use the ``mpirun`` or ``mpiexec`` command +to run :program:`Smilei` on several MPI processes: + +.. code-block:: bash + + mpirun -n 4 ./smilei my_namelist.py "Main.print_every=10" + +If you want to run several openMP threads per MPI processes, you usually have to set +the following environment variable to the desired number of threads before running +``mpirun``: + +.. code-block:: bash + + export OMP_NUM_THREADS=4 + +When running :program:`Smilei`, the output log will remind you how many MPI processes and openMP threads +your simulation is using. + +---- + +Running in *test mode* +^^^^^^^^^^^^^^^^^^^^^^ + +A second executable ``smilei_test`` is available (after the usual compilation) +to run in the *test mode*: + +.. code-block:: bash + + ./smilei_test my_namelist.py + +This *test mode* does the same initialization as the normal mode, +except it only loads the first patch of the full simulation. After initialization, +the test mode exits so that the PIC loop is *not* computed. + +This mode may be used to check the consistency of the namelist, and to make sure +simple errors will not occur. It does not check all possible errors, but it runs fast. + +Running in **test mode requires to run on 1 MPI process only**. However, it is possible +to indicate what is the partition of MPI processes and OpenMP threads intended for the +actual simulation. For instance, to test your namelist that is intended to run on 1024 MPI +processes, each hosting 12 OpenMP threads, use the following syntax: + +.. code-block:: bash + + ./smilei_test 1024 12 my_namelist.py + +---- + +Directory management +^^^^^^^^^^^^^^^^^^^^ + +Let us assume you have written your namelist ``my_namelist.py``, and that you placed it +inside your home directory. Also, we assume that the ``Smilei`` directory is also there, +so that the ``smilei`` executable is located in ``~/Smilei/``. + +Knowing that :program:`Smilei` generally writes out all the results in the current directory, +it is recommended to create a new directory to store these results. For instance: + +.. code-block:: bash + + $ mkdir ~/my_simulation # New directory to store results + $ cp ~/my_namelist.py ~/my_simulation # Copies the namelist there + $ cd ~/my_simulation # Goes there + $ mpirun -n 4 ~/Smilei/smilei my_namelist # Run with 4 processors + +---- + +Using the provided script +^^^^^^^^^^^^^^^^^^^^^^^^^ + +For simple cases such as the previous one, use the script ``smilei.sh``, provided in +the ``Smilei`` directory. You only have to run + +.. code-block:: bash + + $ ./smilei.sh 4 my_namelist.py + +where the number 4 says that the code will run 4 MPI processes. A directory with all +the results will automatically be created next to your namelist. + +---- + +Running on large clusters +^^^^^^^^^^^^^^^^^^^^^^^^^ + +We do not provide instructions to run on super-computers yet. Please refer to your +administrators. + + +---- + +Running on GPU-equiped nodes +^^^^^^^^^^^^^^^^^^^^^^^^^ + +On a supercomputer equipped with GPUs it is necessary to use a binding script. +Here are two examples: + +With Nvidia GPUs: +``srun bind_gpu.sh ./smilei input.py`` + +With AMD GPUs using cray on Adastra: +``srun --cpu-bind=none --mem-bind=none --mpi=cray_shasta --kill-on-bad-exit=1 -- ./bind ./smilei input.py`` + +For the binding scripts themselves, as it depends completely on the node +architecture, please contact your admin support team. + +Be aware that GPU support is in development and not all features are currently available. +Please refer to the list of current supported features. + +---- + +Debugging +^^^^^^^^^ + +In case of problems, the code can be compiled with additional debugging flags (usual ``-g`` and ``-O0``) and internal +checks by compiling it with + +.. code-block:: bash + + make config=debug + +Compiling the whole code with this command will make it very slow to run. +But to check only a particular file for errors, first compile the code with ``make``, then +modify the file, and recompile in debug mode. + +In debug mode, these C++ macros are activated: + +* ``DEBUG("some text" [<< other streamable])`` +* ``HEREIAM("some text" [<< other streamable])`` + + +---- + +Known issues +^^^^^^^^^^^^ + +* OpenMPI ``2.*`` often causes unstable behavior in Smilei. + For instance, with ``openmpi 2.1``, the `vader` protocol seems to interfere with Smilei's + memory management and comunications. We therefore recommend to disable this + protocol when running ``mpirun``, as follows: + + .. code-block:: bash + + $ mpirun --mca btl ^vader -n 4 ~/Smilei/smilei my_namelist # Disable vader + diff --git a/_sources/Use/tables.rst.txt b/_sources/Use/tables.rst.txt new file mode 100644 index 000000000..a509bf490 --- /dev/null +++ b/_sources/Use/tables.rst.txt @@ -0,0 +1,407 @@ +.. _tablePage: + +Generation of the external tables +-------------------------------------------------------------------------------- + +By default, :program:`Smilei` embeds tables directly in the sources. +Nonetheless, a user may want to use different tables. +For this reason, :program:`Smilei` can read external tables. + +Several physical mechanisms can use external tables to work: + +* Radiation loss and photon emission via nonlinear inverse Compton scattering (see :doc:`/Understand/radiation_loss`) +* Electron-positon pair creation via the Multiphoton Breit-Wheeler (see :doc:`/Understand/multiphoton_Breit_Wheeler`) + +An external tool called :program:`smilei_tables` is available to generate these tables. + +---- + +Installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The C++ sources of this tool is located in ``tools/tables``. + +Required dependencies are the following: + +* A C++11 compiler +* A MPI library +* HDF5 installed at least in serial +* `Boost `_ + +Boost is a C++ library that provides efficient advanced mathematical functions. +This is the only dependency not required to install :program:`Smilei`. +This library can be easily installed manually on Linux, MacOS or Windows systems. +It is also available via different package managers (Debian, Homebrew). +The environment variable ``BOOST_ROOT`` must be defined. + +The tool can be then installed using the makefile and the argument ``tables``: + +.. code-block:: bash + + make tables + +The compilation generates an executable called :program:`smilei_tables` on the root of the repository. + +---- + +Execution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The tool works with command line arguments. +For each physical mechanism, :program:`smilei_tables` generates all the tables for this mechanism. +The first argument therefore corresponds to the physical mechanism: + +* Nonlinear inverse Compton scattering: ``nics`` +* Multiphoton Breit-Wheeler: ``mbw`` +* For help: ``-h`` or ```--help`` + +.. code-block:: bash + + mpirun -np ./smilei_tables -h + +Then, once the physical mechanism is selected, the following arguments are the numerical parameters for the table generation. +For each physical argument, ``-h`` or ``--help`` gives the full list of arguments. + +**For Nonlinear inverse Compton Scattering:** + +.. code-block:: bash + + mpirun -np ./smilei_tables nics -h + + _______________________________________________________________________ + + Smilei Tables + _______________________________________________________________________ + + You have selected the creation of tables for the nonlinear inverse Compton scattering. + + Help page specific to the nonlinear inverse Compton Scattering: + + List of available commands: + -h, --help print a help message and exit. + -s, --size int int respective size of the particle and photon chi axis. (default 128 128) + -b, --boundaries double double min and max of the particle chi axis. (default 1e-3 1e3) + -e, --error int compute error due to discretization and use the provided int as a number of draws. (default 0) + -t, --threshold double Minimum targeted value of xi in the computation the minimum particle quantum parameter. (default 1e-3) + -p, --power int Maximum decrease in order of magnitude for the search for the minimum particle quantum parameter. (default 4) + -v, --verbose Dump the tables + +**For multiphoton Breit-Wheeler:** + +.. code-block:: bash + + mpirun -np ./smilei_tables mbw -h + + _______________________________________________________________________ + + Smilei Tables + _______________________________________________________________________ + + You have selected the creation of tables for the multiphoton Breit Wheeler process. + + Help page specific to the multiphoton Breit-Wheeler: + + List of available commands: + -h, --help print a help message and exit. + -s, --size int int respective size of the photon and particle chi axis. (default 128 128) + -b, --boundaries double double min and max of the photon chi axis. (default 1e-2 1e2) + -e, --error int compute error due to discretization and use the provided int as a number of draws. (default 0) + -t, --threshold double Minimum targeted value of xi in the computation the minimum photon quantum parameter. (default 1e-3) + -p, --power int Maximum decrease in order of magnitude for the search for the minimum photon quantum parameter. (default 4) + -v, --verbose Dump the tables + +The tables are generated where the code is executed using HDF5 with the following names: + +* Nonlinear inverse Compton Scattering: ``radiation_tables.h5`` +* multiphoton Breit-Wheeler: ``multiphoton_breit_wheeler_tables.h5`` + +---- + +Precomputed tables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We have computed some tables with several levels of discretization that you can download here. + +256 points +""""""""""" + +This table size is a good compromise between accuracy and memory cost. +2D tables can fit in L2 cache although the pressure on the cache will be high. +This set of tables is the one included by default in the sources of :program:`Smilei` + +.. code-block:: bash + + mpirun -np ./smilei_tables nics -s 256 256 -b 1e-4 1e3 + +`tables_256/radiation_tables.h5 `_ + +.. code-block:: bash + + mpirun -np ./smilei_tables mbw -s 256 256 -b 1e-2 1e2 + +`tables_256/multiphoton_breit_wheeler_tables.h5 `_ + +These tables can be generated on a normal desktop computer in few minutes. + +512 points +""""""""""" + +With a size of 512 points in 1D and 512x512 for 2D tables, these tables offer better accuracy at a larger memory cost. +2D tables of this size are too large to fit in L2 cache but can be contained in L3. + +.. code-block:: bash + + mpirun -np ./smilei_tables nics -s 512 512 -b 1e-4 1e3 + +`tables_512/radiation_tables.h5 `_ + +.. code-block:: bash + + mpirun -np ./smilei_tables mbw -s 512 512 -b 1e-2 1e2 + +`tables_512/multiphoton_breit_wheeler_tables.h5 `_ + +1024 points +""""""""""" + +With a size of 1024 points in 1D and 1024x1024 for 2D tables, these tables offer the best accuracy at a high memory cost (around 8.5 Mb per file). +2D tables of this size are too large to fit in L2 cache and L3 cache. + +.. code-block:: bash + + mpirun -np ./smilei_tables nics -s 1024 1024 -b 1e-4 1e3 + +`tables_1024/radiation_tables.h5 `_ + +.. code-block:: bash + + mpirun -np ./smilei_tables mbw -s 1024 1024 -b 1e-2 1e2 + +`tables_1024/multiphoton_breit_wheeler_tables.h5 `_ + + +---- + +Python visualization scripts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can easily visualize the tables provided by our tools using the python scripts located in the ``tools/tables`` folder: + +* ``show_nonlinear_inverse_Compton_scattering.py`` +* ``show_multiphoton_Breit_Wheeler.py`` + +For instance: + +.. code-block:: bash + + python ./tools/tables/show_nonlinear_inverse_Compton_scattering.py ./radiation_tables.h5 + +---- + +Detailed description of the tables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Nonlinear Inverse Compton Scattering +"""""""""""""""""""""""""""""""""""" + +The file ``radiation_tables.h5`` is used for the nonlinear inverse Compton scattering radiation +mechanism described in :doc:`the dedicated section `. + +It first contains the ``integfochi`` table that represents +the integration of the synchortron emissivity of Ritus *et al*: + +.. math:: + :label: eq_integfochi + + \int_{0}^{\chi_\pm} \frac{S(\chi_\pm , x)}{x} dx = \int_{0}^{\chi_\pm} \frac{2 x}{ 3 \chi_\pm^2} \left[ \int_{2y}^{+\infty}{K_{1/3(y)}dy} - \frac{2 + 3 x y}{2} K_{2/3}(\nu) \right] dx + +where + +.. math:: + :label: eq_y + + y = \frac{x}{3 \chi_\pm (\chi_\pm - x)} + +The :math:`x` value corresponds to the photon quantum parameter. +We integrate the whole spectrum. +This table is used by the Monte-Carlo method to compute the radiation emission cross-section. + +.. _nics_integration_F_over_chi: + +.. figure:: /_static/nics/nics_integration_F_over_chi.png + :scale: 50 % + + Plot of the integfochi table for a particle quantum parameter ranging + from :math:`\chi = 10^{-4}` to :math:`10^{3}` using the pre-computed table of 512 points. + +The table ``h`` is used for the Niel stochastic model ([Niel2018a]_). +It is given by the following integration: + +.. math:: + :label: eq_h_Nielh + + h \left( \chi \right) = \frac{9 \sqrt{3}}{4 \pi} \int_0^{+\infty}{d\nu + \left[ \frac{2\chi^3 \nu^3}{\left( 2 + 3\nu\chi \right)^3} K_{5/3}(\nu) + + \frac{54 \chi^5 \nu^4}{\left( 2 + 3 \nu \chi \right)^5} K_{2/3}(\nu) \right]} + +.. _nics_h_for_niel: + +.. figure:: /_static/nics/nics_h_niel.png + :scale: 50 % + + Plot of the h table for a particle quantum parameter ranging + from :math:`\chi = 10^{-4}` to :math:`10^{3}` using the pre-computed table of 512 points. + +The table ``min_photon_chi_for_xi`` is the minimum boundary used +by the table ``xi`` for the photon quantum parameter axis. + +This minimum value :math:`\chi_{\gamma,\min}` is computed using the following inequality: + +.. math:: + :label: eq_nics_min_photon_chi_for_xi + + \frac{\displaystyle{\int_0^{\chi_{\gamma,\min}}{S(\chi_\pm, x) / x + dx}}}{\displaystyle{\int_0^{\chi_\pm}{S(\chi_\pm, x) / x dx}}} < \varepsilon + +We generally use :math:`\varepsilon = 10^{-3}`. +It corresponds to the argument parameter ``xi_threshold``. +We have to determine a minimum photon quantum parameter because +we cannot have a logarithmic discretization starting from 0. +It basically means that we ignore the radiated energy below :math:`\chi_{\gamma,\min}` +that is less than :math:`10^{-3}` of the total radiated energy. +The parameter ``xi_power`` is the precision of the :math:`\chi_{\gamma,\min}` value. +For instance, a ``xi_power`` of 4 as used for our tables mean that we look for a precision of 4 digits. + +.. _nics_min_photon_chi: + +.. figure:: /_static/nics/nics_min_photon_chi.png + :scale: 50 % + + Plot of the minimal photon quantum parameter :math:`\chi_{\gamma,\min}` + corresponding to the minimum boundary of the ``xi`` table + as a function of the particle quantum parameter :math:`\chi_\pm` ranging + from :math:`10^{-4}` to :math:`10^{3}`. It corresponds to the pre-computed table of 512 points. + +The table ``xi`` corresponds to the following fraction: + +.. math:: + :label: eq_nics_xi + + \xi = \frac{\displaystyle{\int_0^{\chi_{\gamma}}{S(\chi_\pm, x) / x + dx}}}{\displaystyle{\int_0^{\chi_\pm}{S(\chi_\pm, x) / x dx}}} + +For a given :math:`\chi_\pm` and a randomly drawn parameter :math:`\xi`, +we obtain the quantum parameter :math:`\chi_\gamma` of the emitted photon. +This method is used by the Monte-Carlo method to determine the radiated energy of the emitted photon. +For a given :math:`\chi_\pm`, :math:`\chi_\gamma` ranges from :math:`\chi_{\gamma,\min}` to :math:`\chi_\pm`. + +.. _nics_xi: + +.. figure:: /_static/nics/nics_xi.png + :scale: 50 % + + Plot of the xi table as a function of the particle quantum parameter :math:`\chi_\pm` + and index for the :math:`\chi_\gamma` axis. + The :math:`\chi_\pm` axis ranges from :math:`10^{-4}` to :math:`10^{3}`. + The :math:`\chi_\gamma` axis ranges from :math:`\chi_{\gamma,\min}` to :math:`\chi_\pm`. + It corresponds to the pre-computed table of 512 points. + +Multiphoton Breit-Wheeler +"""""""""""""""""""""""""""""""""""" + +The file ``multiphoton_breit_wheeler_tables.h5`` is used for the multiphoton Breit-Wheeler process +described in :doc:`the dedicated section `. + +It first contains the ``T`` table that represents +the following integration: + +.. math:: + :label: eq_mbw_T + + T \left( \chi_\gamma \right) = + \int_{0}^{+\infty}{\int_{x}^{+\infty}{\sqrt{s} K_{1/3} \left( \frac{2}{3} s^{3/2} + \right) ds - \left( 2 - \chi_\gamma x^{3/2} \right) K_{2/3} \left( \frac{2}{3} x^{3/2} \right) }} d\chi_- + +where + +.. math:: + :label: eq_mbw_x + + x = \left( \chi_\gamma / (\chi_{-} \chi_{+}) \right)^{2/3} + +And + +.. math:: + :label: eq_mbw_chi + + \chi_\gamma = \chi_{-} + \chi_{+}. + +It is used to compute the production rate of electron-positron pairs +from a single photon of quantum parameter :math:`\chi_\gamma`. +In the Monte-Carlo algorithm, it is used to determine the photon decay probability. + +.. _mbw_T: + +.. figure:: /_static/mbw/mbw_T.png + :scale: 50 % + + Plot of the table ``T`` + as a function of the photon quantum parameter :math:`\chi_\gamma` ranging + from :math:`10^{-2}` to :math:`10^{2}`. + It corresponds to the pre-computed table size of 512 points. + +The table ``min_particle_chi_for_xi`` is the minimum boundary used +by the table ``xi`` for the particle quantum parameter axis. +The particle can be either a positron or an electron. +The mechanism is symmetric. + +This minimum value :math:`\chi_{\pm,\min}` is computed using the following inequality: + +.. math:: + :label: eq_mbw_min_particle_chi_for_xi + + \frac{\displaystyle{\int_0^{\chi_{\pm,\min}}{\frac{dT}{dx}(\chi_\gamma, x) + dx}}}{\displaystyle{\int_0^{\chi_\gamma}{\frac{dT}{dx}(\chi_\gamma, x) dx}}} < \varepsilon + +We use here :math:`\varepsilon = 10^{-9}`. +It corresponds to the argument parameter ``xi_threshold``. +We have to determine a minimum photon quantum parameter because +we cannot have a logarithmic discretization starting from 0. +The parameter ``xi_power`` is the precision of the :math:`\chi_{\pm,\min}` value. +For instance, a ``xi_power`` of 4 as used for our tables mean that we look for a precision of 4 digits. + +.. _mbw_min_particle_chi: + +.. figure:: /_static/mbw/mbw_min_particle_chi.png + :scale: 50 % + + Plot of the minimal particle quantum parameter :math:`\chi_{\pm,\min}` corresponding to the minimum boundary of the xi table + as a function of the photon quantum parameter :math:`\chi_\gamma` ranging + from :math:`10^{-2}` to :math:`10^{2}`. + It corresponds to the pre-computed table of 512 points. + +The table ``xi`` corresponds to the following fraction: + +.. math:: + :label: eq_mbw_xi + + \xi = \frac{\displaystyle{\int_0^{\chi_{\pm}}{\frac{dT}{dx}(\chi_\gamma, x) + dx}}}{\displaystyle{\int_0^{\chi_\gamma}{\frac{dT}{dx}(\chi_\gamma, x) dx}}} + +For a given :math:`\chi_\gamma` and a randomly drawn parameter :math:`\xi`, +we obtain the quantum parameter :math:`\chi_\pm` of either the generated electron or positron. +Once we have one, we deduce the second from :math:`\chi_\gamma = \chi_+ + \chi_-` +This method is used by the Monte-Carlo method to determine the energy of the created electron and the positron. +For a given :math:`\chi_\gamma`, :math:`\chi_\pm` ranges from :math:`\chi_{\pm,\min}` to :math:`\chi_\gamma`. + +.. _mbw_xi: + +.. figure:: /_static/mbw/mbw_xi.png + :scale: 50 % + + Plot of the xi table as a function of the photon quantum parameter :math:`\chi_\gamma` + and index for the :math:`\chi_\pm` axis. + The :math:`\chi_\gamma` axis ranges from :math:`10^{-2}` to :math:`10^{2}`. + The :math:`\chi_\pm` axis ranges from :math:`\chi_{\pm,\min}` to :math:`\chi_\pm`. + It corresponds to the pre-computed table of 512 points. + diff --git a/_sources/Use/troubleshoot.rst.txt b/_sources/Use/troubleshoot.rst.txt new file mode 100644 index 000000000..c5e451f5a --- /dev/null +++ b/_sources/Use/troubleshoot.rst.txt @@ -0,0 +1,92 @@ +Troubleshoot +--------------------- + +If you encounter issues running your simulation, you can ask for help in the chat room on Element or publish an ``Issue`` on `GitHub `_. +From previous users experience, the cause of most of the issues can be found performing some basic checks, listed in the following. +Also, performing these simple tests helps us while finding an answer to your ``Issue``. + +---- + +Simulation not starting / Error running a simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Your simulation does not start or has an error while running. + +* Check that the ``smilei`` executable is called correctly, e.g. it is present in the input namelist folder or correctly called from there. See also :doc:`run`. +* Check that ``smilei`` runs correctly with at least one input namelist in the ``benchmarks`` folder. +* Use the ``smilei_test`` executable on your input namelist. Does it display error or warning messages? +* Check your :doc:`profiles` in the input namelist, e.g. Avoid ``NaN`` values if you read them from a file or generate them through a Python function. +* Try ``git pull``, ``make clean`` and compile again. Also, be sure that uou have already used ``make happi`` for postprocessing. All these operations must be performed in the installation folder on your machine to run the simulations. +* Change the numerical parameters in the input namelist e.g. resolution, timestep, particles per cell, number of patches. Does the error occur again? See the dedicated sections in :doc:`namelist`. +* Change the number of MPI process, OpenMP threads. Do the simulations in the ``benchmarks`` folder run correctly with only one MPI process/OpenMP thread? +* Check that your MPI and OpenMP configuration is correct through parallel Hello World tests or other basic parallel programs. +* Try running a reduced simulation (less particles per cell, coarser resolution). +* Try using the same input namelist, and/or a reduced version (less particles per cell, coarser resolution) on a different machine. +* If the simulation stops after its start, does the error occur always at the same iteration? With ``print_every`` in the input namelist you can change the iteration print frequency in the log file. + +---- + +New simulation does not run +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You have already run successfully other similar simulations, but a new one gives an error at the start. + +* Use the input namelist of the simulation that works correctly and then progressively change the input to arrive to the simulation you want to run. At each step check if something goes wrong and what is the change in the input namelist that caused the issue. +* Try running the new simulation with the ``smilei`` executable used for the simulation that worked correctly, if different. Changing the code version creates the problem? + +---- + +Postprocessing error +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can run the simulation but you cannot open/read the results. + +* Do ``git pull`` and ``make happi`` in your installation folder to have the postprocessing library ``happi`` ready for use. Afterwards, remember to close and reopen the Python interface you are using, e.g. IPython. See also :doc:`installation`. +* Check if you can correctly open the results of a simulation using one input namelist in the ``benchmarks`` folder. +* Carefully read the doc about the :doc:`post-processing` method you are trying to use. + + +---- + +Physical error in the results. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The physical results are not the ones you expect. + +* Read the doc on the physical methods you are using (e.g. :doc:`/Understand/collisions`, + :doc:`/Understand/ionization`, :doc:`/Understand/laser_envelope`, ...). + Are the underlying physical assumptions satisfied? +* Check that the units given in the input namelist are properly normalized. + See also :doc:`/Understand/units`. +* Some physical processes like :doc:`/Understand/collisions`, :doc:`/Understand/ionization` + need a reference frequency in SI in the ``Main`` block of the input namelist. Did you provide it? + See also :doc:`namelist`. +* Check the CFL condition in the input namelist. See :doc:`/Understand/algorithms` +* See with the Scalar diagnostics (See :doc:`post-processing` ) if the kinetic energy ``Ukin`` + or electromagnetic energy ``Uelm`` display strange behaviours (e.g. exponential growths). +* Verify the overall consistency of the physical set-up, e.g. only immobile or almost immobile + particles while using a Poisson solver. +* Verify that the physical initialization is correct. Should you use a classical or + relativistic Poisson solver (See :doc:`/Understand/relativistic_fields_initialization`) + for the initial fields. Is it necessary to use a Poisson solver? +* Check the presence of numerical effects running the simulation with different numerical + parameters, e.g. changing the resolution, timestep, in the input namelist. +* If using the ``AMcylindrical`` geometry, check that the origin of the axes you are using + in the input namelist is the one described in See :doc:`/Understand/azimuthal_modes_decomposition`. + +---- + +Performances issues +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The simulation is very slow / the performances are not as expected. + +* Change the number of MPI process and OpenMP threads. +* Change the number of patches and/or their distribution in each direction. + See also :doc:`/Understand/parallelization`. +* Check that ``LoadBalancing`` is activated in the :doc:`namelist` + (if the physical set-up is suitable for its use). See also :doc:`/Understand/parallelization`. +* If using :doc:`/Understand/vectorization`, check that the compilation flags for vectorization + were correctly used. See also :doc:`installation`. + + diff --git a/_sources/implementation.rst.txt b/_sources/implementation.rst.txt new file mode 100644 index 000000000..46bf953e9 --- /dev/null +++ b/_sources/implementation.rst.txt @@ -0,0 +1,872 @@ +Implementation +****************************************** + +I. Introduction +=============================================== + +Smilei is a C++ code that uses relatively simple C++ features for modularity +and conveniency for non-advanced C++ users. + +The repository is composed of the following directories: + +- ``Licence``: contains code licence information +- ``doc``: conatins the Sphinx doc files +- ``src``: contains all source files +- ``happi``: contains the sources of the happi Python tool for visualization +- ``benchmarks``: contains the benchmarks used by the validation process. these becnhamrks are also examples for users. +- ``scripts``: contains multiple tool scripts for compilation and more + + - ``compile_tools``: contains scripts and machine files used by the makefile for compilation + +- ``tools``: contains some additional programs for Smilei +- ``validation``: contains the python scripts used by the validation process + +The source files directory is as well composed of several sub-directories to organise the `.cpp` and `.h` files by related thematics. +The main is the file `Smilei.cpp`. +There is always only one class definition per file and the file name correcponds to the class name. + +The general implementation is later summarized in :numref:`smilei_main_loop` + +----------------------------------------------------------------- + +II. General concept and vocabulary +=================================================== + +This section presents some implicit notions to understand the philosophy of the code. + +Notion of data container +------------------------------------ + +Data containers are classes (or sometime just structures) used to store a specific type of data, +often considered as raw data such as particles or fields. +Some methods can be implemented in a data container for managing or accessing the data. + +.. _dataContainer: + +.. figure:: /_static/figures/data_container.png + :width: 8cm + + Data container. + +Notion of operators +------------------------------------ + +An operator is a class that operates on input data to provide a processed information. +Input data can be parameters and data containers. +Output data can be processed data from data containers or updated data containers. +An operator is a class functor (overloadind of the ``()`` ). +Sometime, operator provides additional methods called wrappers to provide differents simplified or adapted interfaces. +An operator do not store data or temporarely. +for instance, the particle interpolation, push and proection are operators. + +.. _operator: + +.. figure:: /_static/figures/operator.png + :width: 10cm + + Operator. + +Notion of domain parts +------------------------------------ + +Domain parts are classes that represents some specific levels of the domain decomposition. +They can be seen as high-level data container or container of data container. +They contain some methods to handle, manange and access the local data. +For instance, patches and ``Species`` are domain parts: + +- ``Species`` contains the particles. +- ``Patch`` contains ``Species`` and ``Fields``. + +Notion of factory +------------------------------------ + +Some objects such as operators or data containers have sereral variations. +For this we use inheritance. +A base class is used for common parameters and methods and derived classes are used for all variations. +The factory uses user-defined input parameters to determine the right derive class to choose and initiate them as shown in :numref:`factory`. +For instance, there are several ``push`` operators implemented all derived from a base ``push`` class. +The ``push`` factory will determine the right one to use. + +.. _factory: + +.. figure:: /_static/figures/factories.png + :width: 15cm + + Description of the factory concept. + +Other +------------------------------------ + +Some classes are used for specific actions in the code such as the initilization process. + +----------------------------------------------------------------- + +III. Domain decomposition and parallelism +=========================================== + +The simulation domain is divided multiple times following a succession of decomposition levels. +The whole domain is the superimposition of different grids for each electromagnetic field component +and macro-particules. +Let us represent schematically the domain as an array of cells as in Fig. :numref:`full_domain`. +Each cell contains a certain population of particles (that can differ from cell to cell). + +.. _full_domain: + +.. figure:: /_static/figures/domain.png + :width: 20cm + + Example of a full domain with 960 cells. + +In :program:`smilei`, the cells are first reorganized into small group so-called patches. +The domain becomes a collection of patches as shown in :numref:`patch_domain_decomposition`. + +.. _patch_domain_decomposition: + +.. figure:: /_static/figures/patch_domain_decomposition.png + :width: 20cm + + The domain in :program:`Smilei` is a collection of patches. + +A patch is an independant piece of the whole simulation domain. +It therefore owns local electrmognatic grids and list of macro-particles. +Electromagnetic grids have ghost cells that represent the information located in the neighboring patches (not shown in :numref:`patch_domain_decomposition`). +All patches have the same spatial size .i.e. the same number of cells. +The size of a patch is calculated so that all local field grids (ghost cells included) can fit in L2 cache. + +Patches are then distributed among MPI processes in so-called MPI patch collections. +The distribution can be ensured in an equal cartesian way or using a load balancing strategy based on the Hilbert curve. + +.. _mpi_patch_collection: + +.. figure:: /_static/figures/mpi_patch_collection.png + :width: 20cm + + Patches are then distributed among MPI processes in so-called MPI patch collections. + +Inside MPI patch collection, OpenMP loop directives are used to distribute the computation of the patches among the available threads. +Since each patch have a different number of particles, this approach enables a dynamic scheduling depending on the specified OpenMP scheduler. +As shown in :numref:`smilei_main_loop`, a synchronization step is required to exchange grid ghost cells and particles traveling from patch to patch. + +The patch granularity is used for: + +- creating more parallelism for OpenMP +- enabling a load balancing capability through OpenMP scheduling +- ensuring a good cache memory efficiency at L3 and L2 levels. + +The patch is not the smaller decomposition grain-size. +The patch can be decomposed into bins as shown in :numref:`bin_decomposition`. + +.. _bin_decomposition: + +.. figure:: /_static/figures/bin_decomposition.png + :width: 12cm + + Bin decomposition. + +Contrary to patch, a bin is not an independant data structure with its own arrays. +It represents a smaller portion of the patch grids through specific start and end indexes. +For the macro-particles, a sorting algorithm is used to ensure that in the macro-particles +located in the same bin are grouped and contiguous in memory. + +Finally, the decomposition levels are summarized in :numref:`decomposition_summary`. + +.. _decomposition_summary: + +.. figure:: /_static/figures/decomposition_summary.png + :width: 15cm + + Domain decomposition summary. + +-------------------------------------------------------------------------------- + +IV. Coding and community rules +=================================================================== + +Coding style rules +------------------------------------ + +Line and indentation style +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- A line should be no more than 140 characters. +- The code should not have some characters outside [0,127] in the ASCII table +- There should be no more than 2 empty successive lines. +- Only 1 statement per line is allowed. +- An indentation block is only composed of 4 spaces, no tab is permitted. +- If possible, keep trailing spaces in empty lines to respect indentation + +For instance, this line is not correct:: + + a1 = b1 + c1*d1; a2 = b2 + c2*d2; + +and should be replaced by:: + + a1 = b1 + c1*d1; + a2 = b2 + c2*d2; + +Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Variable names (public, protected, private, local) should be composed of lowercase and underscore between words. +- The lowercase rule does not apply on acronyms and people names + +For instance:: + + int number_of_elements; + int lignes_of_Smilei; + int age_of_GNU; + +Classes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- A class name starts with a capital letter +- A capital letter is used between each word that composes the class name +- No underscore + +For instance:: + + class MyClassIsGreat + { + public: + int public_integer_; + private: + int private_integer_; + } + +- A class variable respects the rules of variables previously described. +- A variable member has an underscore at the end of the name + +Functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Functions and member functions should start with a lowercase letter. +- No underscore. +- Each word starts with a capital letter. + +For instance:: + + int myGreatFunction(...) + { + ... + } + +- Names should be explicit as much as possible. +- Avoid using shortened expression. + +For instance:: + + void computeParticlePosition(...) + { + ... + } + +instead of:: + + void computePartPos(...) + { + ... + } + +If-statement +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Any if-statement should have curly brackets. + +For instance:: + + if( condition ) { + a = b + c*d; + } + +ERROR and OUTPUT management +------------------------------------ + +Developers should use the dedicated error our output macro definition +located in the file `src/Tools.h`. + +- `ERROR`: this function is the default one used to throw a SIGABRT error with a simple messages. +- `ERROR_NAMELIST`: this function should be used for namelist error. It takes in argument a simple message and a link to the documentation. It throws as well a SIGABRT signal. +- `MESSAGE`: this function should be used to output an information message (it uses `std::cout`). +- `DEBUG` : should be used for debugging messages (for the so-called DEBUG mode) +- `WARNING` : should be used to thrown a warning. A warning alerts the users of a possible issue or to be carreful with some parameters without stoping the program. + +-------------------------------------------------------------------------------- + +V. Data structures and main classes +======================================= + +This section describes the main classes and the tree-like smilei data structure. +The whole picture is shown in :numref:`data_structure`. + +.. _data_structure: + +.. figure:: /_static/figures/data_structure.png + :width: 20cm + + General of the main tree-like data structure of Smilei. + +Class ``VectorPatch`` +------------------------------------ + +The class ``VectorPatch`` represents the MPI Patch collection described above and is the highest structure level. +The class description (``vectorPatch.h`` and ``vectorPatch.cpp``) is located in the directory `src/Patch `_. +Among the data components stored in this class, one of the most important is the list of patches. +By definition, each MPI process has therefore only one declared ``vectorPatch`` object. + +.. cpp:class:: VectorPatch + + .. cpp:member:: std::vector patches_ + + *List of patches located in this MPI patch collection.* + + + +The class ``VectorPatch`` contains the methods directly called in the PIC time loop in ``smilei.cpp``. + +Class ``Patch`` +------------------------------------ + +The class ``Patch`` is an advanced data container that represents a single patch. +The base class description (``Patch.h`` and ``Patch.cpp``) is located in the directory `src/Patch `_. +From this base class can be derived several versions (marked as ``final``) depending on the geometry dimension: + +- ``Patch1D`` +- ``Patch2D`` +- ``Patch3D`` +- ``PatchAM`` for the AM geometry + +The class ``Patch`` has a list of object ``Species`` called ``vecSpecies``. + +.. cpp:class:: Patch + + .. cpp:member:: std::vector vecSpecies + + *List of species in the patch* + + .. cpp:member:: ElectroMagn * EMfields + + *Electromagnetic fields and densities (E, B, J, rho) of the current Patch* + +class ``Species`` +------------------------------------ + +The class ``Species`` is an advanced data container that represents a single species. +The base class description (``Species.h`` and ``Species.cpp``) is located in the directory `src/Species `_. +From this base class can be derived several versions (marked as ``final``): + +- ``SpeciesNorm`` +- ``SpeciesNormV`` +- ``SpeciesV`` +- ``SpeciesVAdaptive`` +- ``SpeciesVAdaptiveMixedSort`` + +The correct species object is initialized using the species factory implemented in the file ``speciesFactory.h``. + +The class ``Species`` owns the particles through the object ``particles`` of class ``Particles*``. + +.. cpp:class:: Species + + .. cpp:member:: Particles * particles + + *Vector containing all Particles of the considered Speciesh* + +class ``Particles`` +------------------------------------ + +The class ``Particles`` is a data container that contains the particle properties. +The base class description (``Particles.h`` and ``Particles.cpp``) is located in the directory `src/Particles `_. +It contains several arrays storing the particles properties such as the positions, momenta, weight and others. + +.. cpp:class:: Particles + + .. cpp:member:: std::vector< std::vector > Position + + *Array containing the particle position* + + .. cpp:member:: std::vector< std::vector > Momentum + + *Array containing the particle moments* + + .. cpp:member:: std::vector< double > Weight + + *Containing the particle weight: equivalent to a charge density* + + .. cpp:member:: std::vector< double > Chi + + *containing the particle quantum parameter* + + .. cpp:member:: std::vector< double > Tau + + *Incremental optical depth for the Monte-Carlo process* + + .. cpp:member:: std::vector< short > Charge + + *Charge state of the particle (multiples of e>0)* + + .. cpp:member:: std::vector< uint64_t > Id + + *Id of the particle* + + .. cpp:member:: std::vector< int > cell_keys + + *cell_keys of the particle* + +Many of the methods implemented in ``Particles`` are used to access or manage the data. + +class ``ElectroMagn`` +------------------------------------ + +The class ``ElectroMagn`` is a high-level data container that contains the electromagnetic fields and currents. +The base class description (``ElectroMagn.h`` and ``ElectroMagn.cpp``) is located in the directory `src/ElectroMagn `_. +From this base class can be derived several versions (marked as ``final``) based on the dimension: + +- ``ElectroMagn1D`` +- ``ElectroMagn2D`` +- ``ElectroMagn3D`` +- ``ElectroMagnAM`` + +The correct final class is determined using the factory ``ElectroMagnFactory.h``. + +.. cpp:class:: ElectroMagn + + .. cpp:member:: Field * Ex_ + + *x-component of the electric field* + +class ``Field`` +------------------------------------ + +The class ``Field`` is a data-container that represent a field grid for a given component. +The base class description (``Field.h`` and ``Field.cpp``) is located in the directory `src/Field `_. +It contains a linearized allocatable array to store all grid nodes whatever the dimension. + +.. cpp:class:: Field + + .. cpp:member:: double *data_ + + *pointer to the linearized field array* + + From this base class can be derived several versions (marked as ``final``) based on the dimension: + + - ``Field1D`` + - ``Field2D`` + - ``Field3D`` + +The correct final class is determined using the factory ``FieldFactory.h``. + +Smilei MPI +------------------------------------ + +The class ``SmileiMPI`` is a specific class that contains interfaces and advanced methods for the custom and adapted use of MPI within Smilei. +The base class description (``SmileiMPI.h`` and ``SmileiMPI.cpp``) is located in the directory `src/SmileiMPI `_. + +.. cpp:class:: SmileiMPI + +----------------------------------------------------------------- + +VI. The :program:`Smilei` PIC loop implementation +============================================================== + +The initialization and the main loop are explicitely done in the main file ``Smilei.cpp``. +The time loop is schematically described in :numref:`smilei_main_loop`. + +.. _smilei_main_loop: + +.. figure:: /_static/figures/smilei_main_loop.png + :width: 20cm + + Smilei main loop implementation (click on the figure for more details). + +The time loop is explicitely written step by step in the main +file ``Smilei.cpp`` thought calls to different ``vecPatches`` methods. + +* **Patch reconfiguration**: if adaptive vectorization is activated, then the patch may be + reconfigured for scalar or vectorized mode. + +.. highlight:: c++ + :linenothreshold: 5 + +.. code-block:: c++ + + vecPatches.reconfiguration( params, timers, itime ); + +* **Collision**: particle collisions are performed before the particle dynamics part + +.. code-block:: c++ + + vecPatches.applyBinaryProcesses( params, itime, timers ); + +* **Relativistic poisson solver**: ... + +.. code-block:: c++ + + vecPatches.runRelativisticModule( time_prim, params, &smpi, timers ); + +* **Charge**: reset global charge and currents densities to zero and computes rho old before moving particles + +.. code-block:: c++ + + vecPatches.computeCharge(true); + +* **Particle dynamics**: this step processes the full particle dynamics + including field interpolation, advanced physical operators (radiation, ionization...), + boundary condition pre-processing and projection + +.. code-block:: c++ + + vecPatches.dynamics( params, &smpi, simWindow, radiation_tables_, + MultiphotonBreitWheelerTables, + time_dual, timers, itime ); + +* **Envelope module**: ... + +.. code-block:: c++ + + vecPatches.runEnvelopeModule( params, &smpi, simWindow, time_dual, timers, itime ); + +* **Sum of currents and densities**: current et charge reduction from different species + and perform the synchronization step with communication + +.. code-block:: c++ + + vecPatches.sumDensities( params, time_dual, timers, itime, simWindow, &smpi ); + +* **Maganement of the antenna**: apply currents from antennas + +.. code-block:: c++ + + vecPatches.applyAntennas( time_dual ); + +* **Maxwell solvers**: solve Maxwell + +.. code-block:: c++ + + vecPatches.solveMaxwell( params, simWindow, itime, time_dual, timers, &smpi ); + +* **Particle communication**: finalize particle exchanges and sort particles + +.. code-block:: c++ + + vecPatches.finalizeAndSortParticles( params, &smpi, simWindow, + time_dual, timers, itime ); + +* **Particle merging**: merging process for particles (still experimental) + +.. code-block:: c++ + + vecPatches.mergeParticles(params, time_dual,timers, itime ); + +* **Particle injection**: injection of particles from the boundaries + +.. code-block:: c++ + + vecPatches.injectParticlesFromBoundaries(params, timers, itime ); + +* **Cleaning**: Clean buffers and resize arrays + +.. code-block:: c++ + + vecPatches.cleanParticlesOverhead(params, timers, itime ); + +* **Field synchronization**: Finalize field synchronization and exchanges + +.. code-block:: c++ + + vecPatches.finalizeSyncAndBCFields( params, &smpi, simWindow, time_dual, timers, itime ); + +* **Diagnostics**: call the various diagnostics + +.. code-block:: c++ + + vecPatches.runAllDiags( params, &smpi, itime, timers, simWindow ); + +* **Moving window**: manage the shift of the moving window + +.. code-block:: c++ + + timers.movWindow.restart(); + simWindow->shift( vecPatches, &smpi, params, itime, time_dual, region ); + + if (itime == simWindow->getAdditionalShiftsIteration() ) { + int adjust = simWindow->isMoving(time_dual)?0:1; + for (unsigned int n=0;n < simWindow->getNumberOfAdditionalShifts()-adjust; n++) + simWindow->shift( vecPatches, &smpi, params, itime, time_dual, region ); + } + timers.movWindow.update(); + +* **Checkpointing**: manage the checkoints + +.. code-block:: c++ + + checkpoint.dump( vecPatches, region, itime, &smpi, simWindow, params ); + +Particle Dynamics +--------------------------------------- + +The particle dynamics is the large step in the time loop that performs the particle movement computation: + +* Field interpolation +* Radiation loss +* Ionization +* Pair creation +* Push +* Detection of leaving particles at patch boundaries +* Charge and current projection + +This step is performed in the method ``vecPatches::dynamics``. +We first loop on the patches and then the species of +each patch ``ipatch``: ``(*this )( ipatch )->vecSpecies.size()``. +For each species, the method ``Species::dynamics`` is called to perform the +dynamic step of the respective particles. +The OpenMP parallelism is explicitely applied in ``vecPatches::dynamics`` on the patch loop as shown +in the following pieces of code. + +.. code-block:: c++ + + #pragma omp for schedule(runtime) + for( unsigned int ipatch=0 ; ipatchsize() ; ipatch++ ) { + + // ... + + for( unsigned int ispec=0 ; ispec<( *this )( ipatch )->vecSpecies.size() ; ispec++ ) { + Species *spec = species( ipatch, ispec ); + + // .... + + spec->Species::dynamics( time_dual, ispec, + emfields( ipatch ), + params, diag_flag, partwalls( ipatch ), + ( *this )( ipatch ), smpi, + RadiationTables, + MultiphotonBreitWheelerTables ); + + // ... + + } + } + +.. _pusherImplementation: + +Pusher +--------------------------------------- + +The pusher is the operator that moves the macro-particles using the equations of movement. +The operator implementation is +located in the directory `src/Pusher `_. +The base class is ``Pusher`` implemented in ``Pusher.h`` and ``Pusher.cpp``. +From this base class can be derived several versions (marked as ``final``): + +* ``PusherBoris``: pusher of Boris +* ``PusherBorisNR``: non-relativistic Boris pusher +* ``PusherBorisV``: vectorized Boris pusher +* ``PusherVay``: pusher of J. L. Vay +* ``PusherHigueraCary``: pusher of Higuera and Cary +* ``PusherPhoton``: pusher of photons (ballistic movement) + +A factory called ``PusherFactory`` is used to select the requested pusher for each patch and each species. + +.. note:: + + Whatever the mode on CPU, the pusher is always vectorized. + + +.. _pusherBorisCPUImplementation: + +Boris pusher for CPU +^^^^^^^^^^^^^^^^^^^^^^ + +The pusher implementation is one of the most simple algorithm of the PIC loop. +In the initialization part of the functor, we use pointers to simplify the access to the different arrays. +The core of the pusher is then composed of a single vectorized loop (``omp simd``) over a group of macro-particles. + +.. literalinclude:: ../../src/Pusher/PusherBoris.cpp + :lines: 52-98 + :linenos: + +Boris pusher for GPU +^^^^^^^^^^^^^^^^^^^^^^^ + +On GPU, the ``omp simd`` directives is simply changed for the ``#pragma acc loop gang worker vector``. +The macro-particles are distributed on the GPU threads (``vector`` level). + +.. _radiationReactionImplementation: + +Nonlinear Inverse Compton radiation operator +--------------------------------------------------------------------------------- + +The physical details of this module are given in the page :ref:`radiationReactionPage`. +The implementation for this operator and the related files are located in the directory +`src/Radiation `_. +The base class used to derive the different versions of this operator is called ``Radiation`` +and is implemented in the files ``Radiation.h`` and ``Radiation.cpp``. + +A factory called ``RadiationFactory`` is used to select the requested radiation model for each patch and species. + +The different radiation model implementation details are given in the following sections. + +.. _LandauLifshitzImplementation: + +Landau-Lifshift +^^^^^^^^^^^^^^^^^^^ + +The derived class that correspponds to the Landau-Lifshift model is called ``RadiationLandauLifshitz`` and +is implemented in the corresponding files. +The implementation is relatively simple and is similar to what is done in the ``Pusher`` +since this radiation model is an extension of the classical particle push. + +.. literalinclude:: ../../src/Radiation/RadiationLandauLifshitz.cpp + :lines: 108-147 + :linenos: + +It is composed of a vectorized loop on a group of particles using the ``istart`` and ``iend`` indexes +given as argument parameters to perform the following steps: + +* Commputation of the particle Lorentz factor +* Commputation of the particle quantum parameter (``particle_chi``) +* Update of the momentum: we use the function ``getClassicalRadiatedEnergy`` implemented in the class ``RadiationTables`` to + get the classical radiated energy for the given particle. +* Computation of the radiated energy: this energy is first stored + per particle in the local array ``rad_norm_energy`` + +The second loop performs a vectorized reduction of the radiated energy for the current thread. + +.. literalinclude:: ../../src/Radiation/RadiationLandauLifshitz.cpp + :lines: 151-157 + :linenos: + +The third vectorized loop compute again the quantum parameters based on the new momentum +and this time the result is stored in the dedicated array ``chi[ipart]`` to be used in +the following part of the time step. + +.. literalinclude:: ../../src/Radiation/RadiationLandauLifshitz.cpp + :lines: 162-178 + :linenos: + +Corrected Landau-Lifshift +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The derived class that correspponds to the corrected Landau-Lifshift model is called ``RadiationCorrLandauLifshitz`` and +is implemented in the corresponding files. + +Niel +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The derived class that correspponds to the Nield model is called ``RadiationNiel`` and +is implemented in the corresponding files. + +Monte-Carlo +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The derived class that correspponds to the Monte-Carlo model is called ``RadiationMonteCarlo`` and +is implemented in the corresponding files. + +Radiation Tables +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The class ``RadiationTables`` is used to store and manage the different tabulated functions +used by some of the radiation models. + +Radiation Tools +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The class ``RadiationTools`` contains some function tools for the radiation. +Some methods provide function fit from tabulated values obtained numerically. + +Task Parallelization +--------------------------------------- +As explained in the dedicated page, if OpenMP tasks are activated, the +macro-particle operations, in particular those inside ``vecPatches::dynamics``, +are parallelized with the task programming paradigm. + +Inside ``vecPatches::dynamics``, instead of using an ``#pragma omp for schedule(dynamics)`` +on the patch loop, a task is generated for each of the ``ipatch-ispec`` combination. +Instead of the thread number, a ``buffer_id`` is given as input to the ``Species::dynamicsTasks`` +method, to avoid race conditions. Indeed, a buffer (indices, ``deltaold``, etc.) +is created for each of the ``ipatch-ispec`` combination. + +The method ``Species::dynamicsTasks`` replaces the use of the usual ``Species::dynamics`` +method (to be used when tasks are not activated). + +Inside each call to ``Species::dynamics`` a task is generated for each ``operator-ibin`` +combination, using ``depend`` to ensure the correct order of execution of the operators. +For example, for macro-particles inside a given combination ``ipatch-ispec-ibin`` +the Pusher operator can be executed only after the Interpolator, and so on. +The bins have a size of ``cluster_width`` cells along the x direction. + +To further avoid race conditions, the Interpolators must use local variables for the +temporary indices and coefficients they compute. + +The Pusher and the Boundary Conditions operators do not present risks of race +conditions. + +Operators which create new macro-particles, as Ionization, must create them in +separated lists for each bin. + +Probably the most critical operator for task parallelization is the Projector. +To avoid race conditions, each ``ipatch-ispec-ibin`` combination has its own +copy of the grid representing the physical space where its macro-particles belong. +The Projector operator must thus project on these independent subgrids. +For this, with tasks the ``bin_shift`` argument in the operator is used; without tasks it is +zero by default. + +These operators acting on a certain ``ipatch-ispec`` combination are enclosed in +a ``#pragma omp taskgroup`` directive to ensure that they are completed before +other tasks are generated in that scope. + +Afterwards, in ``vecPatches::dynamics`` some tasks containing reductions are generated. +The densities in the subgrids are summed in the main grid, and the lists containing the new +macro-particles (e.g. from ionization) for each bin are joined in the main lists +with the new particles. + +Before the synchronisations, a ``#pragma omp taskwait`` directive is used to wait +that the tasks are completed. + +The same concepts are used for the envelope module and for the vectorized versions +of ``dynamics``. In particular, for the envelope module the Projector for +susceptibility uses a local subgrid. + + .. warning:: + + Without tasks, the number buffer vectors (for each buffer) is equal to the number of OpenMP + threads. Each time a thread treats a ``Species`` inside a patch it is trating, + the corresponding buffer is resized to the number of macro-particles inside + that ``Species`` in that patch. + With tasks, the number of buffer vectors (for each buffer) is equal to the + number of patches times the number of ``Species``. To avoid a memory leak, + at the end of ``Species::dynamicsTasks`` these vectors are resized to 1 element. + This operation, as all ``resize`` operations on the macro-particle buffers, + takes memory and time, but unfortunately no better solution has been found. + With the envelope loop, this precaution does not seem necessary, since typically + less macro-particles are used. This memory increase, summed to the one given + by the mentioned subgrids, make tasks memory-consuming. It is advised to + use them with a lot of computing units to avoid using too much memory for each + unit. + + .. warning:: + + A word on debugging with tasks. The typical non-trivial bugs which arise developing + with tasks are given by bad synchronizations which cause data races, causing + segfaults. Since using a debugger (e.g. allinea ddt) changes the execution time + and the syncrhonization, often these bugs disappear, making them tricky to detect. + The best strategies to avoid these bugs with tasks are 1) use local variables + as much as possible and 2) First check if the code works with all ``omp task`` + directives commented (i.e. not using tasks). Then, progressively decomment + these directives, one by one, introducing a barrier like a ``#pragma omp taskwait`` + between them and check which task introduces the segfault. + +Particle Event Tracing +--------------------------------------- +To visualize the scheduling of operations, with or without tasks, an macro-particle +event tracing diagnostic saves the time when each OpenMP thread executes one of these +operations and the involved thread's number. The PIC operators (and the advanced ones like +Ionization, Radiation) acting on each ``ipatch-ispec-ibin`` combination are +included in this diagnostic. +This way, the macro-particle operations executed by each OpenMP thread in each +MPI process can be visualized. The information of which bin, ``Species``, patch +is involved is not stored, since it would be difficult to visualize this level of +detail. However it can be added to this diagnostic in principle. + +This visualization becomes clearer when a small number of patches, ``Species``, +bins is used. In other cases the plot may become unreadable. + + diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 000000000..54d2e8194 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,100 @@ +.. title:: Home + +.. rst-class:: version + +.. + + .. image:: /_static/smileiLogo.svg + + +**Smilei** is a Particle-In-Cell code for plasma simulation. +Open-source, collaborative, user-friendly and designed for high performances on super-computers, +it is applied to a wide range of physics studies: from relativistic laser-plasma +interaction to astrophysics. + +.. raw:: html + + +
+ 4th user & training workshop: 8-10 Nov 2023 in Prague (Czechia) +
+
+ +
+
+ +.. raw:: html + +
+ + +.. image:: /_static/download.svg + +.. raw:: html + + Download + + +.. raw:: html + + + +.. image:: /_static/github-logo.svg + +.. raw:: html + + GitHub + + +.. raw:: html + + + +.. image:: /_static/element-logo.svg + +.. raw:: html + + Chat + + +.. raw:: html + + + +.. image:: /_static/people.svg + +.. raw:: html + + Partners + + +.. raw:: html + + + +.. image:: /_static/paper.svg + +.. raw:: html + + Publications + + + +.. raw:: html + + + +.. image:: /_static/smileiIconRed.svg + +.. raw:: html + + Tutorials + +.. toctree:: + :maxdepth: 2 + :hidden: + + overview + understand + use + site diff --git a/_sources/overview.rst.txt b/_sources/overview.rst.txt new file mode 100644 index 000000000..72d50ab83 --- /dev/null +++ b/_sources/overview.rst.txt @@ -0,0 +1,13 @@ +.. title:: Overview + +Overview +======== + +.. toctree:: + + Overview/synopsis + Overview/highlights + Overview/releases + Overview/licence + Overview/material + Overview/partners diff --git a/_sources/site.rst.txt b/_sources/site.rst.txt new file mode 100644 index 000000000..58050f2ba --- /dev/null +++ b/_sources/site.rst.txt @@ -0,0 +1,33 @@ +Index +----- + +.. toctree:: + :maxdepth: 2 + + overview + understand + use + +---- + +Unreferenced pages +^^^^^^^^^^^^^^^^^^ + +.. rst-class:: small + +.. toctree:: + :maxdepth: 1 + + /Use/ids + /Use/install_linux + /Use/install_macos + /Use/install_supercomputer + /Use/laser_offset + /Use/maxwell-juttner + /Use/particle_initialization + /Use/profiles + /Use/tables + /Use/optimization_flags + /Understand/task_parallelization + syntax_changes + implementation diff --git a/_sources/syntax_changes.rst.txt b/_sources/syntax_changes.rst.txt new file mode 100644 index 000000000..3ef584405 --- /dev/null +++ b/_sources/syntax_changes.rst.txt @@ -0,0 +1,107 @@ +Syntax changes +-------------- + +A number of changes in the syntax have been brought in Smilei's version 3.3. +Most changes only affect keywords names. + +---- + +In the namelist +^^^^^^^^^^^^^^^ + ++--------------------------------------------+-------------------------------------------------------------------+ +| Old | New | ++============================================+===================================================================+ +| ``"1d3v"``, ``"2d3v"``, ``"3d3v"`` | ``"1Dcartesian"``, ``"2Dcartesian"``, ``"3Dcartesian"`` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``maxwell_sol`` | :py:data:`maxwell_solver` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``sim_length`` | :py:data:`grid_length` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``sim_time`` | :py:data:`simulation_time` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``bc_em_type_*`` | :py:data:`EM_boundary_conditions` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``referenceAngularFrequency_SI`` | :py:data:`reference_angular_frequency_SI` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``currentFilter_int`` | :ref:`CurrentFilter ` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``Friedman_filter`` | :ref:`FieldFilter ` | +| ``Friedman_theta`` | | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``poisson_iter_max`` | :py:data:`poisson_max_iteration` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``poisson_error_max`` | :py:data:`poisson_max_error` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``species_type`` | :py:data:`name` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``initPosition_type`` | :py:data:`position_initialization` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``initMomentum_type`` | :py:data:`momentum_initialization` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``n_part_per_cell`` | :py:data:`particles_per_cell` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``nb_density`` | :py:data:`number_density` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``bc_part_type_****`` | :py:data:`boundary_conditions` | ++--------------------------------------------+-------------------------------------------------------------------+ +| Particle boundary condition ``"none"`` | ``"periodic"`` | ++--------------------------------------------+-------------------------------------------------------------------+ +| Particle boundary condition ``"refl"`` | ``"reflective"`` | ++--------------------------------------------+-------------------------------------------------------------------+ +| Particle boundary condition ``"supp"`` | ``"remove"`` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``thermT`` | :py:data:`thermal_boundary_temperature` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``thermVelocity`` | :py:data:`thermal_boundary_velocity` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``isTest`` | :py:data:`is_test` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``dynamics_type`` | :py:data:`pusher` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``boxSide`` | :py:data:`box_side` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``polarizationPhi`` | :py:data:`polarization_phi` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``dump_file_sequence`` | :py:data:`keep_n_dumps` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``coef_cell`` | :py:data:`cell_load` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``coef_frozen`` | :py:data:`frozen_particle_load` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``DumpRestart`` | :ref:`Checkpoints ` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``ExtField`` | :ref:`ExternalField ` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``track_******`` | :ref:`DiagTrackParticles ` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``track_filter`` | The :py:data:`filter` function syntax has changed | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``DiagParticles`` | :ref:`DiagParticleBinning ` | ++--------------------------------------------+-------------------------------------------------------------------+ +| ``output`` of ``DiagParticles`` | | :py:data:`deposited_quantity` | +| | | The values of this argument have changed | ++--------------------------------------------+-------------------------------------------------------------------+ + + +---- + +In the post-processing module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ++--------------------------------------------------------+---------------------------------------------------------+ +| Old | New | ++========================================================+=========================================================+ +| | ``from Smilei import *`` | | ``import happi`` | +| | ``S = Smilei("my/simulation/path/")`` | | ``S = happi.Open("my/simulation/path/")`` | ++--------------------------------------------------------+---------------------------------------------------------+ +| ``ParticleDiagnostic()`` | :py:meth:`ParticleBinning() ` | ++--------------------------------------------------------+---------------------------------------------------------+ +| ``slice`` argument | ``average`` or ``sum``, depending on the diagnostic | ++--------------------------------------------------------+---------------------------------------------------------+ +| ``stride`` argument | more complete ``subset`` | ++--------------------------------------------------------+---------------------------------------------------------+ +| | ``average`` argument of :py:meth:`Probe() ` | now requires coordinates in code units | +| | used bins indices | | ++--------------------------------------------------------+---------------------------------------------------------+ + diff --git a/_sources/understand.rst.txt b/_sources/understand.rst.txt new file mode 100644 index 000000000..22559f799 --- /dev/null +++ b/_sources/understand.rst.txt @@ -0,0 +1,13 @@ +.. title:: Understand + +Understand +========== + +.. toctree:: + + Understand/units + Understand/algorithms + Understand/performances + Understand/physics_modules + Understand/numerical_techniques + Understand/PML diff --git a/_sources/use.rst.txt b/_sources/use.rst.txt new file mode 100644 index 000000000..ae2c1c9d6 --- /dev/null +++ b/_sources/use.rst.txt @@ -0,0 +1,14 @@ +.. title:: Use + +Use +======== + +.. toctree:: + + Use/installation + Smilei tutorials + Use/namelist + Use/run + Use/post-processing + Use/contribute + Use/troubleshoot diff --git a/_static/AM_grid_particles.jpg b/_static/AM_grid_particles.jpg new file mode 100644 index 000000000..aee819743 Binary files /dev/null and b/_static/AM_grid_particles.jpg differ diff --git a/_static/AM_modes.png b/_static/AM_modes.png new file mode 100644 index 000000000..ae4ccb766 Binary files /dev/null and b/_static/AM_modes.png differ diff --git a/_static/AMcylindrical_vs_cartesian.png b/_static/AMcylindrical_vs_cartesian.png new file mode 100644 index 000000000..0b378c84e Binary files /dev/null and b/_static/AMcylindrical_vs_cartesian.png differ diff --git a/_static/BPmonoRound.otf b/_static/BPmonoRound.otf new file mode 100644 index 000000000..72c6c30a3 Binary files /dev/null and b/_static/BPmonoRound.otf differ diff --git a/_static/BPreplay.otf b/_static/BPreplay.otf new file mode 100644 index 000000000..3b67c1117 Binary files /dev/null and b/_static/BPreplay.otf differ diff --git a/_static/BPreplayBold.otf b/_static/BPreplayBold.otf new file mode 100644 index 000000000..4d11fb7a3 Binary files /dev/null and b/_static/BPreplayBold.otf differ diff --git a/_static/BPreplayBoldItalics.otf b/_static/BPreplayBoldItalics.otf new file mode 100644 index 000000000..ef3b4376a Binary files /dev/null and b/_static/BPreplayBoldItalics.otf differ diff --git a/_static/BPreplayItalics.otf b/_static/BPreplayItalics.otf new file mode 100644 index 000000000..9f5d544bf Binary files /dev/null and b/_static/BPreplayItalics.otf differ diff --git a/_static/BTIS3_effect.png b/_static/BTIS3_effect.png new file mode 100644 index 000000000..576a51f75 Binary files /dev/null and b/_static/BTIS3_effect.png differ diff --git a/_static/Cluster_definition_doc.png b/_static/Cluster_definition_doc.png new file mode 100644 index 000000000..123ad357d Binary files /dev/null and b/_static/Cluster_definition_doc.png differ diff --git a/_static/Cluster_width_scan_doc.png b/_static/Cluster_width_scan_doc.png new file mode 100644 index 000000000..0b239af31 Binary files /dev/null and b/_static/Cluster_width_scan_doc.png differ diff --git a/_static/Coordinate_Reference_AMcylindrical.png b/_static/Coordinate_Reference_AMcylindrical.png new file mode 100644 index 000000000..b71cb5571 Binary files /dev/null and b/_static/Coordinate_Reference_AMcylindrical.png differ diff --git a/_static/DLB_balancing.png b/_static/DLB_balancing.png new file mode 100644 index 000000000..e0f991c9a Binary files /dev/null and b/_static/DLB_balancing.png differ diff --git a/_static/Energy_spectrum_laser_vs_envelope.png b/_static/Energy_spectrum_laser_vs_envelope.png new file mode 100644 index 000000000..cae6aff2a Binary files /dev/null and b/_static/Energy_spectrum_laser_vs_envelope.png differ diff --git a/_static/Envelope_Figure.png b/_static/Envelope_Figure.png new file mode 100644 index 000000000..fb263c136 Binary files /dev/null and b/_static/Envelope_Figure.png differ diff --git a/_static/FieldIonization.png b/_static/FieldIonization.png new file mode 100644 index 000000000..1d14549b9 Binary files /dev/null and b/_static/FieldIonization.png differ diff --git a/_static/LWFA_Plas@Par.jpg b/_static/LWFA_Plas@Par.jpg new file mode 100644 index 000000000..002204fcd Binary files /dev/null and b/_static/LWFA_Plas@Par.jpg differ diff --git a/_static/LaserOffsetAngle.png b/_static/LaserOffsetAngle.png new file mode 100644 index 000000000..e5408e263 Binary files /dev/null and b/_static/LaserOffsetAngle.png differ diff --git a/_static/LaserOffsetAngle.svg b/_static/LaserOffsetAngle.svg new file mode 100644 index 000000000..2925d9420 --- /dev/null +++ b/_static/LaserOffsetAngle.svg @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + δ + θ + Box axes + x + y + profile's plane + + + diff --git a/_static/MPIandOpenMP.png b/_static/MPIandOpenMP.png new file mode 100644 index 000000000..5d80ee574 Binary files /dev/null and b/_static/MPIandOpenMP.png differ diff --git a/_static/Maxwellianization1.png b/_static/Maxwellianization1.png new file mode 100644 index 000000000..2ba7d8365 Binary files /dev/null and b/_static/Maxwellianization1.png differ diff --git a/_static/NodeWith2Processes.png b/_static/NodeWith2Processes.png new file mode 100644 index 000000000..82f5c6df1 Binary files /dev/null and b/_static/NodeWith2Processes.png differ diff --git a/_static/NodesCoresThreads.png b/_static/NodesCoresThreads.png new file mode 100644 index 000000000..203f9c2db Binary files /dev/null and b/_static/NodesCoresThreads.png differ diff --git a/_static/PWFA.jpg b/_static/PWFA.jpg new file mode 100644 index 000000000..88f0c5130 Binary files /dev/null and b/_static/PWFA.jpg differ diff --git a/_static/PatchDecomposition.svg b/_static/PatchDecomposition.svg new file mode 100644 index 000000000..1d157ad03 --- /dev/null +++ b/_static/PatchDecomposition.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 960 cells + 32 patches + 5 MPI patch
collections + + diff --git a/_static/PatchDecompositionHilbert.svg b/_static/PatchDecompositionHilbert.svg new file mode 100644 index 000000000..005fa5399 --- /dev/null +++ b/_static/PatchDecompositionHilbert.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/PatchDecompositionNodes.svg b/_static/PatchDecompositionNodes.svg new file mode 100644 index 000000000..98ef5b870 --- /dev/null +++ b/_static/PatchDecompositionNodes.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + threads + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + threads + + + + + + + + + + + + + + + threads + + + + + + + + + + + + + + + threads + + + + + + + + + + + + + + + threads + + + + + + + + + diff --git a/_static/Patch_loadcomparision.jpg b/_static/Patch_loadcomparision.jpg new file mode 100644 index 000000000..1b141827b Binary files /dev/null and b/_static/Patch_loadcomparision.jpg differ diff --git a/_static/Radiation_Pressure_Rho.png b/_static/Radiation_Pressure_Rho.png new file mode 100644 index 000000000..c2f43027b Binary files /dev/null and b/_static/Radiation_Pressure_Rho.png differ diff --git a/_static/Radiation_pressure_develop_tracing.png b/_static/Radiation_pressure_develop_tracing.png new file mode 100644 index 000000000..4a0341371 Binary files /dev/null and b/_static/Radiation_pressure_develop_tracing.png differ diff --git a/_static/Rho_2D_IonizationEnvelope_PRE.jpg b/_static/Rho_2D_IonizationEnvelope_PRE.jpg new file mode 100644 index 000000000..8689d66db Binary files /dev/null and b/_static/Rho_2D_IonizationEnvelope_PRE.jpg differ diff --git a/_static/Rho_electron1long.ogg b/_static/Rho_electron1long.ogg new file mode 100644 index 000000000..b36d3abb5 Binary files /dev/null and b/_static/Rho_electron1long.ogg differ diff --git a/_static/SIMD.png b/_static/SIMD.png new file mode 100644 index 000000000..dbbb2994f Binary files /dev/null and b/_static/SIMD.png differ diff --git a/_static/SMILEI_Scaling.png b/_static/SMILEI_Scaling.png new file mode 100644 index 000000000..933def170 Binary files /dev/null and b/_static/SMILEI_Scaling.png differ diff --git a/_static/Scan_Radiation_Pressure_2D.png b/_static/Scan_Radiation_Pressure_2D.png new file mode 100644 index 000000000..e4325b34e Binary files /dev/null and b/_static/Scan_Radiation_Pressure_2D.png differ diff --git a/_static/Scan_Uniform_Plasma_2D.png b/_static/Scan_Uniform_Plasma_2D.png new file mode 100644 index 000000000..bac540301 Binary files /dev/null and b/_static/Scan_Uniform_Plasma_2D.png differ diff --git a/_static/Stopping_power123.png b/_static/Stopping_power123.png new file mode 100644 index 000000000..cbd8c6b91 Binary files /dev/null and b/_static/Stopping_power123.png differ diff --git a/_static/Task_tracing_doc.png b/_static/Task_tracing_doc.png new file mode 100644 index 000000000..ce4a94609 Binary files /dev/null and b/_static/Task_tracing_doc.png differ diff --git a/_static/TimeSelections.png b/_static/TimeSelections.png new file mode 100644 index 000000000..7aa790420 Binary files /dev/null and b/_static/TimeSelections.png differ diff --git a/_static/Tutorial1.png b/_static/Tutorial1.png new file mode 100644 index 000000000..dc3983d3d Binary files /dev/null and b/_static/Tutorial1.png differ diff --git a/_static/Tutorial2.png b/_static/Tutorial2.png new file mode 100644 index 000000000..76f974865 Binary files /dev/null and b/_static/Tutorial2.png differ diff --git a/_static/Tutorial3.png b/_static/Tutorial3.png new file mode 100644 index 000000000..daabccbca Binary files /dev/null and b/_static/Tutorial3.png differ diff --git a/_static/Tutorial4.png b/_static/Tutorial4.png new file mode 100644 index 000000000..aa1407302 Binary files /dev/null and b/_static/Tutorial4.png differ diff --git a/_static/Tutorial5.png b/_static/Tutorial5.png new file mode 100644 index 000000000..3b84beb28 Binary files /dev/null and b/_static/Tutorial5.png differ diff --git a/_static/Tutorial6.png b/_static/Tutorial6.png new file mode 100644 index 000000000..693b87185 Binary files /dev/null and b/_static/Tutorial6.png differ diff --git a/_static/Tutorial7.png b/_static/Tutorial7.png new file mode 100644 index 000000000..bbcf84bd5 Binary files /dev/null and b/_static/Tutorial7.png differ diff --git a/_static/Tutorial8.png b/_static/Tutorial8.png new file mode 100644 index 000000000..f0b0e83d3 Binary files /dev/null and b/_static/Tutorial8.png differ diff --git a/_static/Tutorial9.png b/_static/Tutorial9.png new file mode 100644 index 000000000..79fa7fd64 Binary files /dev/null and b/_static/Tutorial9.png differ diff --git a/_static/Weibel_3d_ne_vecto_it510.jpg b/_static/Weibel_3d_ne_vecto_it510.jpg new file mode 100644 index 000000000..c0f847769 Binary files /dev/null and b/_static/Weibel_3d_ne_vecto_it510.jpg differ diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 000000000..603f6a879 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,905 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/beam_relaxation123.png b/_static/beam_relaxation123.png new file mode 100644 index 000000000..2aeef29c2 Binary files /dev/null and b/_static/beam_relaxation123.png differ diff --git a/_static/beam_relaxation456.png b/_static/beam_relaxation456.png new file mode 100644 index 000000000..722a56723 Binary files /dev/null and b/_static/beam_relaxation456.png differ diff --git a/_static/beam_relaxation789.png b/_static/beam_relaxation789.png new file mode 100644 index 000000000..d124108d9 Binary files /dev/null and b/_static/beam_relaxation789.png differ diff --git a/_static/conductivity.png b/_static/conductivity.png new file mode 100644 index 000000000..4c73357be Binary files /dev/null and b/_static/conductivity.png differ diff --git a/_static/counter_pair_smilei.png b/_static/counter_pair_smilei.png new file mode 100644 index 000000000..87a82d106 Binary files /dev/null and b/_static/counter_pair_smilei.png differ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 000000000..8cbf1b161 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,323 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 000000000..f5f7f1c61 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,12 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '5.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/_static/download.svg b/_static/download.svg new file mode 100644 index 000000000..e91a8d265 --- /dev/null +++ b/_static/download.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/_static/element-logo.svg b/_static/element-logo.svg new file mode 100644 index 000000000..7334ac856 --- /dev/null +++ b/_static/element-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_static/figSpectra_LR.png b/_static/figSpectra_LR.png new file mode 100644 index 000000000..06e2f6122 Binary files /dev/null and b/_static/figSpectra_LR.png differ diff --git a/_static/figYee.png b/_static/figYee.png new file mode 100644 index 000000000..d19068729 Binary files /dev/null and b/_static/figYee.png differ diff --git a/_static/figures/QED_cascade_electron_px_py_distribution.png b/_static/figures/QED_cascade_electron_px_py_distribution.png new file mode 100644 index 000000000..adfcb2791 Binary files /dev/null and b/_static/figures/QED_cascade_electron_px_py_distribution.png differ diff --git a/_static/figures/QED_cascade_gamma_spectrum.png b/_static/figures/QED_cascade_gamma_spectrum.png new file mode 100644 index 000000000..ce9f28ccf Binary files /dev/null and b/_static/figures/QED_cascade_gamma_spectrum.png differ diff --git a/_static/figures/QED_cascade_iteration_time.png b/_static/figures/QED_cascade_iteration_time.png new file mode 100644 index 000000000..ec2b8a359 Binary files /dev/null and b/_static/figures/QED_cascade_iteration_time.png differ diff --git a/_static/figures/QED_cascade_photon_px_py_distribution.png b/_static/figures/QED_cascade_photon_px_py_distribution.png new file mode 100644 index 000000000..8c4232913 Binary files /dev/null and b/_static/figures/QED_cascade_photon_px_py_distribution.png differ diff --git a/_static/figures/QED_cascade_scalar.png b/_static/figures/QED_cascade_scalar.png new file mode 100644 index 000000000..8b7cabc48 Binary files /dev/null and b/_static/figures/QED_cascade_scalar.png differ diff --git a/_static/figures/bin_decomposition.png b/_static/figures/bin_decomposition.png new file mode 100644 index 000000000..0064b7c38 Binary files /dev/null and b/_static/figures/bin_decomposition.png differ diff --git a/_static/figures/data_container.png b/_static/figures/data_container.png new file mode 100644 index 000000000..0a53444dc Binary files /dev/null and b/_static/figures/data_container.png differ diff --git a/_static/figures/data_structure.png b/_static/figures/data_structure.png new file mode 100644 index 000000000..67a42139a Binary files /dev/null and b/_static/figures/data_structure.png differ diff --git a/_static/figures/decomposition_summary.png b/_static/figures/decomposition_summary.png new file mode 100644 index 000000000..9f249e8dd Binary files /dev/null and b/_static/figures/decomposition_summary.png differ diff --git a/_static/figures/domain.png b/_static/figures/domain.png new file mode 100644 index 000000000..a0390637d Binary files /dev/null and b/_static/figures/domain.png differ diff --git a/_static/figures/factories.png b/_static/figures/factories.png new file mode 100644 index 000000000..002989d91 Binary files /dev/null and b/_static/figures/factories.png differ diff --git a/_static/figures/magnetic_shower_gamma_distribution_log.png b/_static/figures/magnetic_shower_gamma_distribution_log.png new file mode 100644 index 000000000..b04640a6b Binary files /dev/null and b/_static/figures/magnetic_shower_gamma_distribution_log.png differ diff --git a/_static/figures/magnetic_shower_photon_energy_distribution.png b/_static/figures/magnetic_shower_photon_energy_distribution.png new file mode 100644 index 000000000..b32c33a61 Binary files /dev/null and b/_static/figures/magnetic_shower_photon_energy_distribution.png differ diff --git a/_static/figures/magnetic_shower_photon_pxpy_distribution.png b/_static/figures/magnetic_shower_photon_pxpy_distribution.png new file mode 100644 index 000000000..bdec9a47f Binary files /dev/null and b/_static/figures/magnetic_shower_photon_pxpy_distribution.png differ diff --git a/_static/figures/mpi_patch_collection.png b/_static/figures/mpi_patch_collection.png new file mode 100644 index 000000000..0057b3e52 Binary files /dev/null and b/_static/figures/mpi_patch_collection.png differ diff --git a/_static/figures/operator.png b/_static/figures/operator.png new file mode 100644 index 000000000..81635679c Binary files /dev/null and b/_static/figures/operator.png differ diff --git a/_static/figures/paper_topics.png b/_static/figures/paper_topics.png new file mode 100644 index 000000000..6a6eaa7c1 Binary files /dev/null and b/_static/figures/paper_topics.png differ diff --git a/_static/figures/particle_injector.png b/_static/figures/particle_injector.png new file mode 100644 index 000000000..d1eb585bb Binary files /dev/null and b/_static/figures/particle_injector.png differ diff --git a/_static/figures/particle_injector_regular_random.png b/_static/figures/particle_injector_regular_random.png new file mode 100644 index 000000000..693d711b1 Binary files /dev/null and b/_static/figures/particle_injector_regular_random.png differ diff --git a/_static/figures/patch_domain_decomposition.png b/_static/figures/patch_domain_decomposition.png new file mode 100644 index 000000000..c33cb0409 Binary files /dev/null and b/_static/figures/patch_domain_decomposition.png differ diff --git a/_static/figures/qed_pair_cascade.png b/_static/figures/qed_pair_cascade.png new file mode 100644 index 000000000..554e019b2 Binary files /dev/null and b/_static/figures/qed_pair_cascade.png differ diff --git a/_static/figures/smilei_main_loop.png b/_static/figures/smilei_main_loop.png new file mode 100644 index 000000000..e3120f7e2 Binary files /dev/null and b/_static/figures/smilei_main_loop.png differ diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/_static/file.png differ diff --git a/_static/github-logo.svg b/_static/github-logo.svg new file mode 100644 index 000000000..9b6cc5331 --- /dev/null +++ b/_static/github-logo.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/_static/gitlab-logo.svg b/_static/gitlab-logo.svg new file mode 100644 index 000000000..88a4541b5 --- /dev/null +++ b/_static/gitlab-logo.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_static/hhg1.jpg b/_static/hhg1.jpg new file mode 100644 index 000000000..8e401d0f7 Binary files /dev/null and b/_static/hhg1.jpg differ diff --git a/_static/hhg2.jpg b/_static/hhg2.jpg new file mode 100644 index 000000000..e73c45a29 Binary files /dev/null and b/_static/hhg2.jpg differ diff --git a/_static/ionization_multiple.png b/_static/ionization_multiple.png new file mode 100644 index 000000000..6aa5c46b3 Binary files /dev/null and b/_static/ionization_multiple.png differ diff --git a/_static/ionization_rate.png b/_static/ionization_rate.png new file mode 100644 index 000000000..c0bb13541 Binary files /dev/null and b/_static/ionization_rate.png differ diff --git a/_static/ionization_recombination.png b/_static/ionization_recombination.png new file mode 100644 index 000000000..32cd1c8fe Binary files /dev/null and b/_static/ionization_recombination.png differ diff --git a/_static/ionization_stopping_power.png b/_static/ionization_stopping_power.png new file mode 100644 index 000000000..f0ae7fd6b Binary files /dev/null and b/_static/ionization_stopping_power.png differ diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 000000000..624bca829 --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,10879 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2021-02-16 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | M + | N + | O + | P + | R + | S + | T + | U + | V + | W + | X + | Y + | Z + +
+

A

+ + + +
+ +

B

+ + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

K

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + +
+ +

V

+ + + +
+ +

W

+ + +
+ +

X

+ + +
+ +

Y

+ + +
+ +

Z

+ + +
+ + + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/implementation.html b/implementation.html new file mode 100644 index 000000000..02290b918 --- /dev/null +++ b/implementation.html @@ -0,0 +1,1484 @@ + + + + + + + + + Implementation — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Implementation

+
+

I. Introduction

+

Smilei is a C++ code that uses relatively simple C++ features for modularity +and conveniency for non-advanced C++ users.

+

The repository is composed of the following directories:

+
    +
  • Licence: contains code licence information

  • +
  • doc: conatins the Sphinx doc files

  • +
  • src: contains all source files

  • +
  • happi: contains the sources of the happi Python tool for visualization

  • +
  • benchmarks: contains the benchmarks used by the validation process. these becnhamrks are also examples for users.

  • +
  • scripts: contains multiple tool scripts for compilation and more

    +
      +
    • compile_tools: contains scripts and machine files used by the makefile for compilation

    • +
    +
  • +
  • tools: contains some additional programs for Smilei

  • +
  • validation: contains the python scripts used by the validation process

  • +
+

The source files directory is as well composed of several sub-directories to organise the .cpp and .h files by related thematics. +The main is the file Smilei.cpp. +There is always only one class definition per file and the file name correcponds to the class name.

+

The general implementation is later summarized in Fig. 83

+
+
+
+

II. General concept and vocabulary

+

This section presents some implicit notions to understand the philosophy of the code.

+
+

Notion of data container

+

Data containers are classes (or sometime just structures) used to store a specific type of data, +often considered as raw data such as particles or fields. +Some methods can be implemented in a data container for managing or accessing the data.

+
+_images/data_container.png +
+

Fig. 74 Data container.

+
+
+
+
+

Notion of operators

+

An operator is a class that operates on input data to provide a processed information. +Input data can be parameters and data containers. +Output data can be processed data from data containers or updated data containers. +An operator is a class functor (overloadind of the () ). +Sometime, operator provides additional methods called wrappers to provide differents simplified or adapted interfaces. +An operator do not store data or temporarely. +for instance, the particle interpolation, push and proection are operators.

+
+_images/operator.png +
+

Fig. 75 Operator.

+
+
+
+
+

Notion of domain parts

+

Domain parts are classes that represents some specific levels of the domain decomposition. +They can be seen as high-level data container or container of data container. +They contain some methods to handle, manange and access the local data. +For instance, patches and Species are domain parts:

+
    +
  • Species contains the particles.

  • +
  • Patch contains Species and Fields.

  • +
+
+
+

Notion of factory

+

Some objects such as operators or data containers have sereral variations. +For this we use inheritance. +A base class is used for common parameters and methods and derived classes are used for all variations. +The factory uses user-defined input parameters to determine the right derive class to choose and initiate them as shown in Fig. 76. +For instance, there are several push operators implemented all derived from a base push class. +The push factory will determine the right one to use.

+
+_images/factories.png +
+

Fig. 76 Description of the factory concept.

+
+
+
+
+

Other

+

Some classes are used for specific actions in the code such as the initilization process.

+
+
+
+
+

III. Domain decomposition and parallelism

+

The simulation domain is divided multiple times following a succession of decomposition levels. +The whole domain is the superimposition of different grids for each electromagnetic field component +and macro-particules. +Let us represent schematically the domain as an array of cells as in Fig. Fig. 77. +Each cell contains a certain population of particles (that can differ from cell to cell).

+
+_images/domain.png +
+

Fig. 77 Example of a full domain with 960 cells.

+
+
+

In smilei, the cells are first reorganized into small group so-called patches. +The domain becomes a collection of patches as shown in Fig. 78.

+
+_images/patch_domain_decomposition.png +
+

Fig. 78 The domain in Smilei is a collection of patches.

+
+
+

A patch is an independant piece of the whole simulation domain. +It therefore owns local electrmognatic grids and list of macro-particles. +Electromagnetic grids have ghost cells that represent the information located in the neighboring patches (not shown in Fig. 78). +All patches have the same spatial size .i.e. the same number of cells. +The size of a patch is calculated so that all local field grids (ghost cells included) can fit in L2 cache.

+

Patches are then distributed among MPI processes in so-called MPI patch collections. +The distribution can be ensured in an equal cartesian way or using a load balancing strategy based on the Hilbert curve.

+
+_images/mpi_patch_collection.png +
+

Fig. 79 Patches are then distributed among MPI processes in so-called MPI patch collections.

+
+
+

Inside MPI patch collection, OpenMP loop directives are used to distribute the computation of the patches among the available threads. +Since each patch have a different number of particles, this approach enables a dynamic scheduling depending on the specified OpenMP scheduler. +As shown in Fig. 83, a synchronization step is required to exchange grid ghost cells and particles traveling from patch to patch.

+

The patch granularity is used for:

+
    +
  • creating more parallelism for OpenMP

  • +
  • enabling a load balancing capability through OpenMP scheduling

  • +
  • ensuring a good cache memory efficiency at L3 and L2 levels.

  • +
+

The patch is not the smaller decomposition grain-size. +The patch can be decomposed into bins as shown in Fig. 80.

+
+_images/bin_decomposition.png +
+

Fig. 80 Bin decomposition.

+
+
+

Contrary to patch, a bin is not an independant data structure with its own arrays. +It represents a smaller portion of the patch grids through specific start and end indexes. +For the macro-particles, a sorting algorithm is used to ensure that in the macro-particles +located in the same bin are grouped and contiguous in memory.

+

Finally, the decomposition levels are summarized in Fig. 81.

+
+_images/decomposition_summary.png +
+

Fig. 81 Domain decomposition summary.

+
+
+
+
+
+

IV. Coding and community rules

+
+

Coding style rules

+
+

Line and indentation style

+
    +
  • A line should be no more than 140 characters.

  • +
  • The code should not have some characters outside [0,127] in the ASCII table

  • +
  • There should be no more than 2 empty successive lines.

  • +
  • Only 1 statement per line is allowed.

  • +
  • An indentation block is only composed of 4 spaces, no tab is permitted.

  • +
  • If possible, keep trailing spaces in empty lines to respect indentation

  • +
+

For instance, this line is not correct:

+
a1 = b1 + c1*d1; a2 = b2 + c2*d2;
+
+
+

and should be replaced by:

+
a1 = b1 + c1*d1;
+a2 = b2 + c2*d2;
+
+
+
+
+

Variables

+
    +
  • Variable names (public, protected, private, local) should be composed of lowercase and underscore between words.

  • +
  • The lowercase rule does not apply on acronyms and people names

  • +
+

For instance:

+
int number_of_elements;
+int lignes_of_Smilei;
+int age_of_GNU;
+
+
+
+
+

Classes

+
    +
  • A class name starts with a capital letter

  • +
  • A capital letter is used between each word that composes the class name

  • +
  • No underscore

  • +
+

For instance:

+
class MyClassIsGreat
+{
+    public:
+    int public_integer_;
+    private:
+    int private_integer_;
+}
+
+
+
    +
  • A class variable respects the rules of variables previously described.

  • +
  • A variable member has an underscore at the end of the name

  • +
+
+
+

Functions

+
    +
  • Functions and member functions should start with a lowercase letter.

  • +
  • No underscore.

  • +
  • Each word starts with a capital letter.

  • +
+

For instance:

+
int myGreatFunction(...)
+{
+...
+}
+
+
+
    +
  • Names should be explicit as much as possible.

  • +
  • Avoid using shortened expression.

  • +
+

For instance:

+
void computeParticlePosition(...)
+{
+...
+}
+
+
+

instead of:

+
void computePartPos(...)
+{
+...
+}
+
+
+
+
+

If-statement

+

Any if-statement should have curly brackets.

+

For instance:

+
if( condition ) {
+    a = b + c*d;
+}
+
+
+
+
+
+

ERROR and OUTPUT management

+

Developers should use the dedicated error our output macro definition +located in the file src/Tools.h.

+
    +
  • ERROR: this function is the default one used to throw a SIGABRT error with a simple messages.

  • +
  • ERROR_NAMELIST: this function should be used for namelist error. It takes in argument a simple message and a link to the documentation. It throws as well a SIGABRT signal.

  • +
  • MESSAGE: this function should be used to output an information message (it uses std::cout).

  • +
  • DEBUG : should be used for debugging messages (for the so-called DEBUG mode)

  • +
  • WARNING : should be used to thrown a warning. A warning alerts the users of a possible issue or to be carreful with some parameters without stoping the program.

  • +
+
+
+
+
+

V. Data structures and main classes

+

This section describes the main classes and the tree-like smilei data structure. +The whole picture is shown in Fig. 82.

+
+_images/data_structure.png +
+

Fig. 82 General of the main tree-like data structure of Smilei.

+
+
+
+

Class VectorPatch

+

The class VectorPatch represents the MPI Patch collection described above and is the highest structure level. +The class description (vectorPatch.h and vectorPatch.cpp) is located in the directory src/Patch. +Among the data components stored in this class, one of the most important is the list of patches. +By definition, each MPI process has therefore only one declared vectorPatch object.

+
+
+class VectorPatch
+
+
+std::vector<Patch*> patches_
+
+ +

List of patches located in this MPI patch collection.

+
+ +

The class VectorPatch contains the methods directly called in the PIC time loop in smilei.cpp.

+
+
+

Class Patch

+

The class Patch is an advanced data container that represents a single patch. +The base class description (Patch.h and Patch.cpp) is located in the directory src/Patch. +From this base class can be derived several versions (marked as final) depending on the geometry dimension:

+
    +
  • Patch1D

  • +
  • Patch2D

  • +
  • Patch3D

  • +
  • PatchAM for the AM geometry

  • +
+

The class Patch has a list of object Species called vecSpecies.

+
+
+class Patch
+
+
+std::vector<Species*> vecSpecies
+
+ +

List of species in the patch

+
+
+ElectroMagn *EMfields
+
+ +

Electromagnetic fields and densities (E, B, J, rho) of the current Patch

+
+ +
+
+

class Species

+

The class Species is an advanced data container that represents a single species. +The base class description (Species.h and Species.cpp) is located in the directory src/Species. +From this base class can be derived several versions (marked as final):

+
    +
  • SpeciesNorm

  • +
  • SpeciesNormV

  • +
  • SpeciesV

  • +
  • SpeciesVAdaptive

  • +
  • SpeciesVAdaptiveMixedSort

  • +
+

The correct species object is initialized using the species factory implemented in the file speciesFactory.h.

+

The class Species owns the particles through the object particles of class Particles*.

+
+
+class Species
+
+
+Particles *particles
+
+ +

Vector containing all Particles of the considered Speciesh

+
+ +
+
+

class Particles

+

The class Particles is a data container that contains the particle properties. +The base class description (Particles.h and Particles.cpp) is located in the directory src/Particles. +It contains several arrays storing the particles properties such as the positions, momenta, weight and others.

+
+
+class Particles
+
+
+std::vector<std::vector<double>> Position
+
+ +

Array containing the particle position

+
+
+std::vector<std::vector<double>> Momentum
+
+ +

Array containing the particle moments

+
+
+std::vector<double> Weight
+
+ +

Containing the particle weight: equivalent to a charge density

+
+
+std::vector<double> Chi
+
+ +

containing the particle quantum parameter

+
+
+std::vector<double> Tau
+
+ +

Incremental optical depth for the Monte-Carlo process

+
+
+std::vector<short> Charge
+
+ +

Charge state of the particle (multiples of e>0)

+
+
+std::vector<uint64_t> Id
+
+ +

Id of the particle

+
+
+std::vector<int> cell_keys
+
+ +

cell_keys of the particle

+
+ +

Many of the methods implemented in Particles are used to access or manage the data.

+
+
+

class ElectroMagn

+

The class ElectroMagn is a high-level data container that contains the electromagnetic fields and currents. +The base class description (ElectroMagn.h and ElectroMagn.cpp) is located in the directory src/ElectroMagn. +From this base class can be derived several versions (marked as final) based on the dimension:

+
    +
  • ElectroMagn1D

  • +
  • ElectroMagn2D

  • +
  • ElectroMagn3D

  • +
  • ElectroMagnAM

  • +
+

The correct final class is determined using the factory ElectroMagnFactory.h.

+
+
+class ElectroMagn
+
+
+Field *Ex_
+
+ +

x-component of the electric field

+
+ +
+
+

class Field

+

The class Field is a data-container that represent a field grid for a given component. +The base class description (Field.h and Field.cpp) is located in the directory src/Field. +It contains a linearized allocatable array to store all grid nodes whatever the dimension.

+
+
+class Field
+
+
+double *data_
+
+ +

pointer to the linearized field array

+

From this base class can be derived several versions (marked as final) based on the dimension:

+
    +
  • Field1D

  • +
  • Field2D

  • +
  • Field3D

  • +
+
+ +

The correct final class is determined using the factory FieldFactory.h.

+
+
+

Smilei MPI

+

The class SmileiMPI is a specific class that contains interfaces and advanced methods for the custom and adapted use of MPI within Smilei. +The base class description (SmileiMPI.h and SmileiMPI.cpp) is located in the directory src/SmileiMPI.

+
+
+class SmileiMPI
+
+ +
+
+
+
+

VI. The Smilei PIC loop implementation

+

The initialization and the main loop are explicitely done in the main file Smilei.cpp. +The time loop is schematically described in Fig. 83.

+
+_images/smilei_main_loop.png +
+

Fig. 83 Smilei main loop implementation (click on the figure for more details).

+
+
+

The time loop is explicitely written step by step in the main +file Smilei.cpp thought calls to different vecPatches methods.

+
    +
  • Patch reconfiguration: if adaptive vectorization is activated, then the patch may be +reconfigured for scalar or vectorized mode.

  • +
+
vecPatches.reconfiguration( params, timers, itime );
+
+
+
    +
  • Collision: particle collisions are performed before the particle dynamics part

  • +
+
vecPatches.applyBinaryProcesses( params, itime, timers );
+
+
+
    +
  • Relativistic poisson solver: …

  • +
+
vecPatches.runRelativisticModule( time_prim, params, &smpi,  timers );
+
+
+
    +
  • Charge: reset global charge and currents densities to zero and computes rho old before moving particles

  • +
+
vecPatches.computeCharge(true);
+
+
+
    +
  • Particle dynamics: this step processes the full particle dynamics +including field interpolation, advanced physical operators (radiation, ionization…), +boundary condition pre-processing and projection

  • +
+
vecPatches.dynamics( params, &smpi, simWindow, radiation_tables_,
+                                 MultiphotonBreitWheelerTables,
+                                 time_dual, timers, itime );
+
+
+
    +
  • Envelope module: …

  • +
+
vecPatches.runEnvelopeModule( params, &smpi, simWindow, time_dual, timers, itime );
+
+
+
    +
  • Sum of currents and densities: current et charge reduction from different species +and perform the synchronization step with communication

  • +
+
vecPatches.sumDensities( params, time_dual, timers, itime, simWindow, &smpi );
+
+
+
    +
  • Maganement of the antenna: apply currents from antennas

  • +
+
vecPatches.applyAntennas( time_dual );
+
+
+
    +
  • Maxwell solvers: solve Maxwell

  • +
+
vecPatches.solveMaxwell( params, simWindow, itime, time_dual, timers, &smpi );
+
+
+
    +
  • Particle communication: finalize particle exchanges and sort particles

  • +
+
vecPatches.finalizeAndSortParticles( params, &smpi, simWindow,
+                                             time_dual, timers, itime );
+
+
+
    +
  • Particle merging: merging process for particles (still experimental)

  • +
+
vecPatches.mergeParticles(params, time_dual,timers, itime );
+
+
+
    +
  • Particle injection: injection of particles from the boundaries

  • +
+
vecPatches.injectParticlesFromBoundaries(params, timers, itime );
+
+
+
    +
  • Cleaning: Clean buffers and resize arrays

  • +
+
vecPatches.cleanParticlesOverhead(params, timers, itime );
+
+
+
    +
  • Field synchronization: Finalize field synchronization and exchanges

  • +
+
vecPatches.finalizeSyncAndBCFields( params, &smpi, simWindow, time_dual, timers, itime );
+
+
+
    +
  • Diagnostics: call the various diagnostics

  • +
+
vecPatches.runAllDiags( params, &smpi, itime, timers, simWindow );
+
+
+
    +
  • Moving window: manage the shift of the moving window

  • +
+
1timers.movWindow.restart();
+2simWindow->shift( vecPatches, &smpi, params, itime, time_dual, region );
+3
+4if (itime == simWindow->getAdditionalShiftsIteration() ) {
+5    int adjust = simWindow->isMoving(time_dual)?0:1;
+6    for (unsigned int n=0;n < simWindow->getNumberOfAdditionalShifts()-adjust; n++)
+7        simWindow->shift( vecPatches, &smpi, params, itime, time_dual, region );
+8}
+9timers.movWindow.update();
+
+
+
    +
  • Checkpointing: manage the checkoints

  • +
+
checkpoint.dump( vecPatches, region, itime, &smpi, simWindow, params );
+
+
+
+

Particle Dynamics

+

The particle dynamics is the large step in the time loop that performs the particle movement computation:

+
    +
  • Field interpolation

  • +
  • Radiation loss

  • +
  • Ionization

  • +
  • Pair creation

  • +
  • Push

  • +
  • Detection of leaving particles at patch boundaries

  • +
  • Charge and current projection

  • +
+

This step is performed in the method vecPatches::dynamics. +We first loop on the patches and then the species of +each patch ipatch: (*this )( ipatch )->vecSpecies.size(). +For each species, the method Species::dynamics is called to perform the +dynamic step of the respective particles. +The OpenMP parallelism is explicitely applied in vecPatches::dynamics on the patch loop as shown +in the following pieces of code.

+
 1#pragma omp for schedule(runtime)
+ 2for( unsigned int ipatch=0 ; ipatch<this->size() ; ipatch++ ) {
+ 3
+ 4    // ...
+ 5
+ 6    for( unsigned int ispec=0 ; ispec<( *this )( ipatch )->vecSpecies.size() ; ispec++ ) {
+ 7        Species *spec = species( ipatch, ispec );
+ 8
+ 9        // ....
+10
+11        spec->Species::dynamics( time_dual, ispec,
+12                                 emfields( ipatch ),
+13                                 params, diag_flag, partwalls( ipatch ),
+14                                 ( *this )( ipatch ), smpi,
+15                                 RadiationTables,
+16                                 MultiphotonBreitWheelerTables );
+17
+18        // ...
+19
+20    }
+21}
+
+
+
+
+

Pusher

+

The pusher is the operator that moves the macro-particles using the equations of movement. +The operator implementation is +located in the directory src/Pusher. +The base class is Pusher implemented in Pusher.h and Pusher.cpp. +From this base class can be derived several versions (marked as final):

+
    +
  • PusherBoris: pusher of Boris

  • +
  • PusherBorisNR: non-relativistic Boris pusher

  • +
  • PusherBorisV: vectorized Boris pusher

  • +
  • PusherVay: pusher of J. L. Vay

  • +
  • PusherHigueraCary: pusher of Higuera and Cary

  • +
  • PusherPhoton: pusher of photons (ballistic movement)

  • +
+

A factory called PusherFactory is used to select the requested pusher for each patch and each species.

+
+

Note

+

Whatever the mode on CPU, the pusher is always vectorized.

+
+
+

Boris pusher for CPU

+

The pusher implementation is one of the most simple algorithm of the PIC loop. +In the initialization part of the functor, we use pointers to simplify the access to the different arrays. +The core of the pusher is then composed of a single vectorized loop (omp simd) over a group of macro-particles.

+
 1    #pragma omp target is_device_ptr( /* to: */                               \
+ 2                                      charge /* [istart:particle_number] */ ) \
+ 3        is_device_ptr( /* tofrom: */                                          \
+ 4                       momentum_x /* [istart:particle_number] */,             \
+ 5                       momentum_y /* [istart:particle_number] */,             \
+ 6                       momentum_z /* [istart:particle_number] */,             \
+ 7                       position_x /* [istart:particle_number] */,             \
+ 8                       position_y /* [istart:particle_number] */,             \
+ 9                       position_z /* [istart:particle_number] */ )
+10    #pragma omp teams distribute parallel for
+11#elif defined(SMILEI_OPENACC_MODE)
+12    const int istart_offset   = istart - ipart_buffer_offset;
+13    const int particle_number = iend - istart;
+14
+15    #pragma acc parallel present(Ex [0:nparts],    \
+16                                 Ey [0:nparts],    \
+17                                 Ez [0:nparts],    \
+18                                 Bx [0:nparts],    \
+19                                 By [0:nparts],    \
+20                                 Bz [0:nparts],    \
+21                                 invgf [0:nparts]) \
+22        deviceptr(position_x,                                           \
+23                  position_y,                                           \
+24                  position_z,                                           \
+25                  momentum_x,                                           \
+26                  momentum_y,                                           \
+27                  momentum_z,                                           \
+28                  charge)
+29    #pragma acc loop gang worker vector
+30#else
+31    #pragma omp simd
+32#endif
+33    for( int ipart=istart ; ipart<iend; ipart++ ) {
+34
+35        const int ipart2 = ipart - ipart_buffer_offset;
+36
+37        const double charge_over_mass_dts2 = ( double )( charge[ipart] )*one_over_mass_*dts2;
+38
+39        // init Half-acceleration in the electric field
+40        double pxsm = charge_over_mass_dts2*( Ex[ipart2] );
+41        double pysm = charge_over_mass_dts2*( Ey[ipart2] );
+42        double pzsm = charge_over_mass_dts2*( Ez[ipart2] );
+43
+44        //(*this)(particles, ipart, (*Epart)[ipart], (*Bpart)[ipart] , (*invgf)[ipart]);
+45        const double umx = momentum_x[ipart] + pxsm;
+46        const double umy = momentum_y[ipart] + pysm;
+
+
+
+
+

Boris pusher for GPU

+

On GPU, the omp simd directives is simply changed for the #pragma acc loop gang worker vector. +The macro-particles are distributed on the GPU threads (vector level).

+
+
+
+

Nonlinear Inverse Compton radiation operator

+

The physical details of this module are given in the page High-energy photon emission & radiation reaction. +The implementation for this operator and the related files are located in the directory +src/Radiation. +The base class used to derive the different versions of this operator is called Radiation +and is implemented in the files Radiation.h and Radiation.cpp.

+

A factory called RadiationFactory is used to select the requested radiation model for each patch and species.

+

The different radiation model implementation details are given in the following sections.

+
+

Landau-Lifshift

+

The derived class that correspponds to the Landau-Lifshift model is called RadiationLandauLifshitz and +is implemented in the corresponding files. +The implementation is relatively simple and is similar to what is done in the Pusher +since this radiation model is an extension of the classical particle push.

+
 1    // _______________________________________________________________
+ 2    // Computation
+ 3
+ 4    #ifndef SMILEI_OPENACC_MODE
+ 5        #pragma omp simd aligned(rad_norm_energy:64)
+ 6    #else
+ 7        int np = iend-istart;
+ 8        #pragma acc parallel \
+ 9            present(Ex[istart:np],Ey[istart:np],Ez[istart:np],\
+10            Bx[istart:np],By[istart:np],Bz[istart:np]) \
+11            deviceptr(momentum_x,momentum_y,momentum_z,charge,weight,chi) \
+12            reduction(+:radiated_energy_loc)
+13    {
+14        #pragma acc loop reduction(+:radiated_energy_loc) gang worker vector private(rad_norm_energy)
+15    #endif
+16    for( int ipart=istart ; ipart<iend; ipart++ ) {
+17        
+18        // charge / m^2
+19        const double charge_over_mass_square = ( double )( charge[ipart] )*one_over_mass_square;
+20
+21        // Gamma
+22        const double gamma = sqrt( 1.0 + momentum_x[ipart]*momentum_x[ipart]
+23                      + momentum_y[ipart]*momentum_y[ipart]
+24                      + momentum_z[ipart]*momentum_z[ipart] );
+25
+26        // Computation of the Lorentz invariant quantum parameter
+27        const double particle_chi = Radiation::computeParticleChi( charge_over_mass_square,
+28                       momentum_x[ipart], momentum_y[ipart], momentum_z[ipart],
+29                       gamma,
+30                       Ex[ipart-ipart_ref], Ey[ipart-ipart_ref], Ez[ipart-ipart_ref] ,
+31                       Bx[ipart-ipart_ref], By[ipart-ipart_ref], Bz[ipart-ipart_ref] );
+32
+33        // Effect on the momentum
+34        if( gamma > 1.1 && particle_chi >= minimum_chi_continuous ) {
+35
+36            // Radiated energy during the time step
+37            const double temp =
+38                radiation_tables.getClassicalRadiatedEnergy( particle_chi, dt_ ) * gamma / ( gamma*gamma-1. );
+
+
+

It is composed of a vectorized loop on a group of particles using the istart and iend indexes +given as argument parameters to perform the following steps:

+
    +
  • Commputation of the particle Lorentz factor

  • +
  • Commputation of the particle quantum parameter (particle_chi)

  • +
  • Update of the momentum: we use the function getClassicalRadiatedEnergy implemented in the class RadiationTables to +get the classical radiated energy for the given particle.

  • +
  • Computation of the radiated energy: this energy is first stored +per particle in the local array rad_norm_energy

  • +
+

The second loop performs a vectorized reduction of the radiated energy for the current thread.

+
1            momentum_z[ipart] -= temp*momentum_z[ipart];
+2                                              
+3    // _______________________________________________________________
+4    // Computation of the thread radiated energy
+5                                              
+6#ifndef SMILEI_OPENACC_MODE
+
+
+

The third vectorized loop compute again the quantum parameters based on the new momentum +and this time the result is stored in the dedicated array chi[ipart] to be used in +the following part of the time step.

+
 1                                              + momentum_z[ipart]*momentum_z[ipart] );
+ 2        }
+ 3    }
+ 4
+ 5    #pragma omp simd reduction(+:radiated_energy_loc)
+ 6    for( int ipart=0 ; ipart<iend-istart; ipart++ ) {
+ 7        radiated_energy_loc += weight[ipart]*rad_norm_energy[ipart] ;
+ 8    }
+ 9#else
+10            radiated_energy_loc += weight[ipart]*(gamma - std::sqrt( 1.0
+11                                              + momentum_x[ipart]*momentum_x[ipart]
+12                                              + momentum_y[ipart]*momentum_y[ipart]
+13                                              + momentum_z[ipart]*momentum_z[ipart] ));
+14#endif
+15
+16
+17    // _______________________________________________________________
+
+
+
+
+

Corrected Landau-Lifshift

+

The derived class that correspponds to the corrected Landau-Lifshift model is called RadiationCorrLandauLifshitz and +is implemented in the corresponding files.

+
+
+

Niel

+

The derived class that correspponds to the Nield model is called RadiationNiel and +is implemented in the corresponding files.

+
+
+

Monte-Carlo

+

The derived class that correspponds to the Monte-Carlo model is called RadiationMonteCarlo and +is implemented in the corresponding files.

+
+
+

Radiation Tables

+

The class RadiationTables is used to store and manage the different tabulated functions +used by some of the radiation models.

+
+
+

Radiation Tools

+

The class RadiationTools contains some function tools for the radiation. +Some methods provide function fit from tabulated values obtained numerically.

+
+
+
+

Task Parallelization

+

As explained in the dedicated page, if OpenMP tasks are activated, the +macro-particle operations, in particular those inside vecPatches::dynamics, +are parallelized with the task programming paradigm.

+

Inside vecPatches::dynamics, instead of using an #pragma omp for schedule(dynamics) +on the patch loop, a task is generated for each of the ipatch-ispec combination. +Instead of the thread number, a buffer_id is given as input to the Species::dynamicsTasks +method, to avoid race conditions. Indeed, a buffer (indices, deltaold, etc.) +is created for each of the ipatch-ispec combination.

+

The method Species::dynamicsTasks replaces the use of the usual Species::dynamics +method (to be used when tasks are not activated).

+

Inside each call to Species::dynamics a task is generated for each operator-ibin +combination, using depend to ensure the correct order of execution of the operators. +For example, for macro-particles inside a given combination ipatch-ispec-ibin +the Pusher operator can be executed only after the Interpolator, and so on. +The bins have a size of cluster_width cells along the x direction.

+

To further avoid race conditions, the Interpolators must use local variables for the +temporary indices and coefficients they compute.

+

The Pusher and the Boundary Conditions operators do not present risks of race +conditions.

+

Operators which create new macro-particles, as Ionization, must create them in +separated lists for each bin.

+

Probably the most critical operator for task parallelization is the Projector. +To avoid race conditions, each ipatch-ispec-ibin combination has its own +copy of the grid representing the physical space where its macro-particles belong. +The Projector operator must thus project on these independent subgrids. +For this, with tasks the bin_shift argument in the operator is used; without tasks it is +zero by default.

+

These operators acting on a certain ipatch-ispec combination are enclosed in +a #pragma omp taskgroup directive to ensure that they are completed before +other tasks are generated in that scope.

+

Afterwards, in vecPatches::dynamics some tasks containing reductions are generated. +The densities in the subgrids are summed in the main grid, and the lists containing the new +macro-particles (e.g. from ionization) for each bin are joined in the main lists +with the new particles.

+

Before the synchronisations, a #pragma omp taskwait directive is used to wait +that the tasks are completed.

+

The same concepts are used for the envelope module and for the vectorized versions +of dynamics. In particular, for the envelope module the Projector for +susceptibility uses a local subgrid.

+
+
+

Warning

+

Without tasks, the number buffer vectors (for each buffer) is equal to the number of OpenMP +threads. Each time a thread treats a Species inside a patch it is trating, +the corresponding buffer is resized to the number of macro-particles inside +that Species in that patch. +With tasks, the number of buffer vectors (for each buffer) is equal to the +number of patches times the number of Species. To avoid a memory leak, +at the end of Species::dynamicsTasks these vectors are resized to 1 element. +This operation, as all resize operations on the macro-particle buffers, +takes memory and time, but unfortunately no better solution has been found. +With the envelope loop, this precaution does not seem necessary, since typically +less macro-particles are used. This memory increase, summed to the one given +by the mentioned subgrids, make tasks memory-consuming. It is advised to +use them with a lot of computing units to avoid using too much memory for each +unit.

+
+
+

Warning

+

A word on debugging with tasks. The typical non-trivial bugs which arise developing +with tasks are given by bad synchronizations which cause data races, causing +segfaults. Since using a debugger (e.g. allinea ddt) changes the execution time +and the syncrhonization, often these bugs disappear, making them tricky to detect. +The best strategies to avoid these bugs with tasks are 1) use local variables +as much as possible and 2) First check if the code works with all omp task +directives commented (i.e. not using tasks). Then, progressively decomment +these directives, one by one, introducing a barrier like a #pragma omp taskwait +between them and check which task introduces the segfault.

+
+
+
+
+

Particle Event Tracing

+

To visualize the scheduling of operations, with or without tasks, an macro-particle +event tracing diagnostic saves the time when each OpenMP thread executes one of these +operations and the involved thread’s number. The PIC operators (and the advanced ones like +Ionization, Radiation) acting on each ipatch-ispec-ibin combination are +included in this diagnostic. +This way, the macro-particle operations executed by each OpenMP thread in each +MPI process can be visualized. The information of which bin, Species, patch +is involved is not stored, since it would be difficult to visualize this level of +detail. However it can be added to this diagnostic in principle.

+

This visualization becomes clearer when a small number of patches, Species, +bins is used. In other cases the plot may become unreadable.

+
+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000..a374eabc5 --- /dev/null +++ b/index.html @@ -0,0 +1,503 @@ + + + + + + + + + Home — Smilei 5.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+
_images/smileiLogo.svg
+

Smilei is a Particle-In-Cell code for plasma simulation. +Open-source, collaborative, user-friendly and designed for high performances on super-computers, +it is applied to a wide range of physics studies: from relativistic laser-plasma +interaction to astrophysics.

+ +
+ 4th user & training workshop: 8-10 Nov 2023 in Prague (Czechia) +
+
+ +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 000000000..f444c2821 Binary files /dev/null and b/objects.inv differ diff --git a/overview.html b/overview.html new file mode 100644 index 000000000..983f9af28 --- /dev/null +++ b/overview.html @@ -0,0 +1,553 @@ + + + + + + + + + Overview — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 000000000..26003561f --- /dev/null +++ b/search.html @@ -0,0 +1,497 @@ + + + + + + + + Search — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 000000000..bfe79fab7 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["Overview/highlights","Overview/licence","Overview/material","Overview/partners","Overview/releases","Overview/synopsis","Understand/GPU_offloading","Understand/PML","Understand/SDMD","Understand/algorithms","Understand/azimuthal_modes_decomposition","Understand/collisions","Understand/ionization","Understand/laser_envelope","Understand/multiphoton_Breit_Wheeler","Understand/numerical_techniques","Understand/parallelization","Understand/particle_injector","Understand/particle_merging","Understand/performances","Understand/physics_modules","Understand/radiation_loss","Understand/relativistic_fields_initialization","Understand/task_parallelization","Understand/units","Understand/vectorization","Use/contribute","Use/ids","Use/install_linux","Use/install_macos","Use/install_supercomputer","Use/installation","Use/laser_offset","Use/maxwell-juttner","Use/namelist","Use/optimization_flags","Use/particle_initialization","Use/post-processing","Use/profiles","Use/run","Use/tables","Use/troubleshoot","implementation","index","overview","site","syntax_changes","understand","use"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["Overview/highlights.rst","Overview/licence.rst","Overview/material.rst","Overview/partners.rst","Overview/releases.rst","Overview/synopsis.rst","Understand/GPU_offloading.rst","Understand/PML.rst","Understand/SDMD.rst","Understand/algorithms.rst","Understand/azimuthal_modes_decomposition.rst","Understand/collisions.rst","Understand/ionization.rst","Understand/laser_envelope.rst","Understand/multiphoton_Breit_Wheeler.rst","Understand/numerical_techniques.rst","Understand/parallelization.rst","Understand/particle_injector.rst","Understand/particle_merging.rst","Understand/performances.rst","Understand/physics_modules.rst","Understand/radiation_loss.rst","Understand/relativistic_fields_initialization.rst","Understand/task_parallelization.rst","Understand/units.rst","Understand/vectorization.rst","Use/contribute.rst","Use/ids.rst","Use/install_linux.rst","Use/install_macos.rst","Use/install_supercomputer.rst","Use/installation.rst","Use/laser_offset.rst","Use/maxwell-juttner.rst","Use/namelist.rst","Use/optimization_flags.rst","Use/particle_initialization.rst","Use/post-processing.rst","Use/profiles.rst","Use/run.rst","Use/tables.rst","Use/troubleshoot.rst","implementation.rst","index.rst","overview.rst","site.rst","syntax_changes.rst","understand.rst","use.rst"],objects:{"":[[42,0,1,"_CPPv411ElectroMagn","ElectroMagn"],[42,1,1,"_CPPv4N11ElectroMagn3Ex_E","ElectroMagn::Ex_"],[42,0,1,"_CPPv45Field","Field"],[42,1,1,"_CPPv4N5Field5data_E","Field::data_"],[42,0,1,"_CPPv49Particles","Particles"],[42,1,1,"_CPPv4N9Particles6ChargeE","Particles::Charge"],[42,1,1,"_CPPv4N9Particles3ChiE","Particles::Chi"],[42,1,1,"_CPPv4N9Particles2IdE","Particles::Id"],[42,1,1,"_CPPv4N9Particles8MomentumE","Particles::Momentum"],[42,1,1,"_CPPv4N9Particles8PositionE","Particles::Position"],[42,1,1,"_CPPv4N9Particles3TauE","Particles::Tau"],[42,1,1,"_CPPv4N9Particles6WeightE","Particles::Weight"],[42,1,1,"_CPPv4N9Particles9cell_keysE","Particles::cell_keys"],[42,0,1,"_CPPv45Patch","Patch"],[42,1,1,"_CPPv4N5Patch8EMfieldsE","Patch::EMfields"],[42,1,1,"_CPPv4N5Patch10vecSpeciesE","Patch::vecSpecies"],[42,0,1,"_CPPv49SmileiMPI","SmileiMPI"],[42,0,1,"_CPPv47Species","Species"],[42,1,1,"_CPPv4N7Species9particlesE","Species::particles"],[42,0,1,"_CPPv411VectorPatch","VectorPatch"],[42,1,1,"_CPPv4N11VectorPatch8patches_E","VectorPatch::patches_"],[34,2,1,"","EM_boundary_conditions"],[34,2,1,"","EM_boundary_conditions_k"],[34,2,1,"","Envelope_boundary_conditions"],[37,3,1,"","Field"],[37,3,1,"","NewParticles"],[34,2,1,"","Niel_computation_method"],[37,3,1,"id0","ParticleBinning"],[37,3,1,"","Performances"],[37,3,1,"","Probe"],[37,3,1,"","Scalar"],[37,3,1,"","Screen"],[37,3,1,"","TrackParticles"],[26,3,1,"","Validate"],[34,2,1,"","a0"],[34,2,1,"","additional_shifts_time"],[34,2,1,"","angle"],[37,4,1,"","animate"],[34,2,1,"","atomic_number"],[34,2,1,"","attributes"],[34,2,1,"id60","axes"],[34,2,1,"","boundary_conditions"],[34,2,1,"id19","box_side"],[34,2,1,"","cell_length"],[34,2,1,"","cell_load"],[34,2,1,"","charge"],[34,2,1,"id15","charge_density"],[34,2,1,"","chirp_profile"],[34,2,1,"","cluster_width"],[38,4,1,"","constant"],[34,2,1,"","corners"],[38,4,1,"","cosine"],[34,2,1,"","coulomb_log"],[34,2,1,"","coulomb_log_factor"],[34,2,1,"","custom_oversize"],[34,2,1,"id43","datatype"],[34,2,1,"","debug_every"],[34,2,1,"","delay_phase"],[34,2,1,"id50","deposited_quantity"],[34,2,1,"","direction"],[34,2,1,"","dump_deflate"],[34,2,1,"","dump_minutes"],[34,2,1,"","dump_step"],[34,2,1,"id25","ellipticity"],[34,2,1,"","envelope_profile"],[34,2,1,"","envelope_solver"],[34,2,1,"id65","every"],[34,2,1,"","exit_after_dump"],[34,2,1,"","extra_envelope"],[34,2,1,"","fft_time_step"],[34,2,1,"","fft_time_window"],[34,2,1,"id31","field"],[37,3,1,"","fieldInfo"],[34,2,1,"id42","fields"],[34,2,1,"","file"],[34,2,1,"","file_grouping"],[34,2,1,"","filter"],[34,2,1,"id66","flush_every"],[34,2,1,"","focus"],[34,2,1,"","frozen_particle_load"],[38,4,1,"","gaussian"],[34,2,1,"","geometry"],[37,3,1,"","getDiags"],[37,3,1,"","getTrackSpecies"],[34,2,1,"","gpu_computing"],[34,2,1,"","grid_length"],[34,2,1,"","incidence_angle"],[34,2,1,"","initial_balance"],[34,2,1,"","initial_mode"],[34,2,1,"","interpolation_order"],[34,2,1,"","interpolator"],[34,2,1,"","ionization_electrons"],[34,2,1,"","ionization_model"],[34,2,1,"","ionization_rate"],[34,2,1,"","ionizing"],[34,2,1,"","is_test"],[34,2,1,"","keep_interpolated_fields"],[34,2,1,"","keep_n_dumps"],[34,2,1,"","keep_n_strongest_modes"],[34,2,1,"","kernelFIR"],[34,2,1,"","kind"],[34,2,1,"","mass"],[34,2,1,"","maximum_charge_state"],[34,2,1,"","maxwell_solver"],[34,2,1,"id11","mean_velocity"],[34,2,1,"","mean_velocity_AM"],[34,2,1,"","merge_accumulation_correction"],[34,2,1,"","merge_discretization_scale"],[34,2,1,"","merge_every"],[34,2,1,"","merge_max_packet_size"],[34,2,1,"","merge_min_momentum"],[34,2,1,"","merge_min_momentum_cell_length"],[34,2,1,"","merge_min_packet_size"],[34,2,1,"","merge_momentum_cell_size"],[34,2,1,"","merging_method"],[34,2,1,"","min_particles_per_cell"],[34,2,1,"","minimum_chi_continuous"],[34,2,1,"","minimum_chi_discontinuous"],[34,2,1,"","mode"],[34,2,1,"id0","model"],[34,2,1,"id10","momentum_initialization"],[34,2,1,"","multiphoton_Breit_Wheeler"],[34,2,1,"","multiphoton_Breit_Wheeler_sampling"],[34,2,1,"id55","name"],[34,2,1,"","nuclear_reaction"],[34,2,1,"","nuclear_reaction_multiplier"],[34,2,1,"","number"],[34,2,1,"id14","number_density"],[34,2,1,"","number_of_AM"],[34,2,1,"","number_of_AM_classical_Poisson_solver"],[34,2,1,"","number_of_AM_relativistic_field_initialization"],[34,2,1,"","number_of_additional_shifts"],[34,2,1,"","number_of_cells"],[34,2,1,"","number_of_patches"],[34,2,1,"","number_of_pml_cells"],[34,2,1,"","number_of_processes"],[34,2,1,"","number_of_timesteps"],[34,2,1,"","offset"],[34,2,1,"id23","omega"],[34,2,1,"","origin"],[34,2,1,"id13","particles_per_cell"],[34,2,1,"","passes"],[34,2,1,"","patch_arrangement"],[34,2,1,"","patch_information"],[37,3,1,"","performanceInfo"],[34,2,1,"","phase"],[34,2,1,"","photon_energy_axis"],[37,4,1,"","plot"],[34,2,1,"","pml_kappa"],[34,2,1,"","pml_sigma"],[34,2,1,"","point"],[34,2,1,"","poisson_max_error"],[34,2,1,"","poisson_max_iteration"],[34,2,1,"id24","polarization_phi"],[38,4,1,"","polygonal"],[38,4,1,"","polynomial"],[34,2,1,"id9","position_initialization"],[34,2,1,"","precision"],[34,2,1,"","print_every"],[34,2,1,"","print_expected_disk_usage"],[37,3,1,"","probeInfo"],[34,2,1,"id29","profile"],[34,2,1,"","pusher"],[34,2,1,"","radiation_max_emissions"],[34,2,1,"","radiation_model"],[34,2,1,"","radiation_photon_gamma_threshold"],[34,2,1,"","radiation_photon_sampling"],[34,2,1,"","radiation_photon_species"],[34,2,1,"","random_seed"],[34,2,1,"","reconfigure_every"],[34,2,1,"","reference_angular_frequency_SI"],[34,2,1,"","region_ghost_cells"],[34,2,1,"id16","regular_number"],[34,2,1,"","relativistic_field_initialization"],[34,2,1,"","relativistic_poisson_max_error"],[34,2,1,"","relativistic_poisson_max_iteration"],[34,2,1,"","restart_dir"],[34,2,1,"","restart_number"],[34,2,1,"","shape"],[34,2,1,"","simulation_time"],[37,4,1,"","slide"],[34,2,1,"","smilei_mpi_rank"],[34,2,1,"","smilei_mpi_size"],[34,2,1,"","solve_poisson"],[34,2,1,"","solve_relativistic_poisson"],[34,2,1,"","space_envelope"],[34,2,1,"","space_profile"],[34,2,1,"id32","space_time_profile"],[34,2,1,"","space_time_profile_AM"],[34,2,1,"id61","species"],[34,2,1,"","species1"],[34,2,1,"","species2"],[37,4,1,"","streak"],[34,2,1,"","subgrid"],[34,2,1,"id35","table_path"],[38,4,1,"","tconstant"],[38,4,1,"","tcosine"],[34,2,1,"id12","temperature"],[38,4,1,"","tgaussian"],[34,2,1,"","thermal_boundary_temperature"],[34,2,1,"","thermal_boundary_velocity"],[34,2,1,"","theta"],[34,2,1,"id58","time_average"],[34,2,1,"id26","time_envelope"],[34,2,1,"","time_fields_frozen"],[34,2,1,"id34","time_frozen"],[34,2,1,"","time_integral"],[34,2,1,"","time_profile"],[34,2,1,"","time_start"],[34,2,1,"","timestep"],[34,2,1,"","timestep_over_CFL"],[38,4,1,"","tpolygonal"],[38,4,1,"","tpolynomial"],[38,4,1,"","trapezoidal"],[38,4,1,"","tsin2plateau"],[38,4,1,"","ttrapezoidal"],[34,2,1,"","use_BTIS3_interpolation"],[34,2,1,"","vars"],[34,2,1,"","vector"],[34,2,1,"","vectors"],[34,2,1,"","velocity_x"],[34,2,1,"id27","waist"],[34,2,1,"","x"],[34,2,1,"","y"],[34,2,1,"","z"]],Field:[[37,3,1,"","animate"],[37,3,1,"","getAxis"],[37,3,1,"","getData"],[37,3,1,"","getTimes"],[37,3,1,"","getTimesteps"],[37,3,1,"","getXmoved"],[37,3,1,"","plot"],[37,3,1,"","set"],[37,3,1,"","slide"],[37,3,1,"","streak"],[37,3,1,"","toVTK"]],ParticleBinning:[[37,3,1,"","animate"],[37,3,1,"","getAxis"],[37,3,1,"","getData"],[37,3,1,"","getTimes"],[37,3,1,"","getTimesteps"],[37,3,1,"","plot"],[37,3,1,"","set"],[37,3,1,"","slide"],[37,3,1,"","streak"],[37,3,1,"","toVTK"]],Performances:[[37,3,1,"","toVTK"]],Probe:[[37,3,1,"","animate"],[37,3,1,"","changeField"],[37,3,1,"","getAxis"],[37,3,1,"","getData"],[37,3,1,"","getTimes"],[37,3,1,"","getTimesteps"],[37,3,1,"","plot"],[37,3,1,"","set"],[37,3,1,"","slide"],[37,3,1,"","streak"],[37,3,1,"","toVTK"]],Scalar:[[37,3,1,"","animate"],[37,3,1,"","getAxis"],[37,3,1,"","getData"],[37,3,1,"","getTimes"],[37,3,1,"","getTimesteps"],[37,3,1,"","plot"],[37,3,1,"","set"],[37,3,1,"","slide"],[37,3,1,"","streak"]],Screen:[[37,3,1,"","animate"],[37,3,1,"","getAxis"],[37,3,1,"","getData"],[37,3,1,"","getTimes"],[37,3,1,"","getTimesteps"],[37,3,1,"","plot"],[37,3,1,"","set"],[37,3,1,"","slide"],[37,3,1,"","streak"],[37,3,1,"","toVTK"]],TrackParticles:[[37,3,1,"","animate"],[37,3,1,"","getData"],[37,3,1,"","getTimes"],[37,3,1,"","getTimesteps"],[37,3,1,"","iterParticles"],[37,3,1,"","plot"],[37,3,1,"","slide"],[37,3,1,"","streak"],[37,3,1,"","toVTK"]],happi:[[37,3,1,"","Open"],[37,4,1,"","multiPlot"],[37,4,1,"","multiSlide"],[37,3,1,"","openNamelist"]]},objnames:{"0":["cpp","class","C++ class"],"1":["cpp","member","C++ member"],"2":["py","data","Python data"],"3":["py","method","Python method"],"4":["py","function","Python function"]},objtypes:{"0":"cpp:class","1":"cpp:member","2":"py:data","3":"py:method","4":"py:function"},terms:{"0":[0,7,9,10,11,12,13,14,18,21,22,23,24,26,27,30,31,32,33,34,37,38,40,42,44],"00":11,"0000003000":36,"0002":34,"001":11,"005":[11,34],"006":12,"0064":11,"01":[11,18,34,38],"012052":2,"012054":2,"012055":2,"012058":21,"012105":2,"013115":2,"014013":2,"014402":2,"015009":21,"015205":2,"02":[11,12,34],"021008":2,"022113":2,"02243":2,"023103":2,"023107":2,"023203":2,"025309":2,"026001":2,"02618":2,"02621":2,"0270":21,"02883":2,"02927":2,"03":11,"031301":2,"033":2,"033107":12,"033204":2,"033307":2,"03440":2,"035101":2,"03949":2,"04":12,"04064":2,"04127":2,"043102":2,"043209":2,"044010":2,"04433":2,"04435":2,"044401":2,"044801":2,"04511":34,"045208":2,"04674":2,"04976":2,"05":[0,11,12,21,24,38],"05014":2,"05128":2,"052102":2,"053114":2,"053202":2,"05402":2,"054053":2,"054401":21,"055013":2,"055202":2,"055401":2,"056701":22,"05902":2,"06":33,"061201":2,"063013":2,"063204":2,"064002":2,"064403":2,"064801":2,"07":23,"072103":2,"072108":2,"072304":2,"073104":2,"075001":2,"08170":2,"083104":11,"085004":2,"085006":2,"085015":2,"091302":2,"094002":2,"09411":2,"095002":2,"09562":2,"096559086628964":21,"0d":37,"0f":37,"0th":38,"0y":34,"0z":34,"1":[0,2,3,7,9,10,11,12,13,14,22,23,24,25,26,27,30,32,33,34,36,37,38,39,40,42,44,47],"10":[0,2,6,11,12,14,16,18,21,25,29,34,37,38,39,40,43],"100":[0,2,10,11,14,21,24,32,34,37],"1000":[10,14,18,33,34,35],"10000":[34,37],"100702":2,"100x100":16,"101":[2,34],"101301":12,"1015":2,"102":2,"102105":2,"1024":[0,39],"1024x1024":40,"103":2,"103104":2,"103120":12,"104803":2,"105":2,"105001":2,"106":2,"10700":0,"109":34,"109450":11,"11":[2,4,11,12,21,25,29,31,33,34,40],"1110":32,"11131":2,"1117543":2,"112112":2,"113102":2,"115015":2,"115016":2,"115020":2,"116":2,"1177":[2,21],"1182":2,"1191":12,"11th":13,"12":[2,12,16,21,25,30,33,39],"1200":23,"122":2,"123005":21,"123718241260330":21,"124":2,"124001":2,"125025":2,"125032":2,"126":2,"127":42,"1273":11,"128":[0,40],"1280":0,"12837":2,"13":[0,2,25],"130":2,"131":2,"134":2,"1365":21,"13734":2,"139":2,"139434":2,"13th":2,"14":[0,2,11,12,21,29,34],"140":42,"14061":2,"14159":34,"1444":2,"145":11,"15":[0,2,11,21,22,34,37],"150":[0,34],"1500":[14,23],"1596":2,"16":[0,11,12,21,23,25,34],"16384":0,"165":21,"17":[2,11,12,25,30],"1702":2,"1705":2,"1707":2,"1708":34,"1712":2,"1755":32,"1790":13,"18":[0,2,11,14,21,25,30],"180":34,"1802":2,"1806":2,"1809":2,"1810":2,"182":2,"18800":0,"19":[0,2,4,11,12,25],"190":13,"1902":2,"1905":2,"1906":2,"1907":2,"1908":2,"191":18,"1911":2,"1912":2,"1947":21,"1954":11,"1966":12,"1967":12,"1979":11,"1984":11,"1985":21,"1986":12,"1997":[11,13],"1998":[11,13],"1_":10,"1_r":10,"1d":[2,4,5,13,18,22,24,34,37,38,40,47],"1d3v":[2,9,46],"1dcartesian":[4,34,46],"1e":[24,34,38,40],"1e14":37,"1e2":40,"1e3":40,"1st":38,"2":[0,2,3,7,9,10,11,12,13,14,16,21,22,23,24,25,26,27,30,31,32,33,34,35,37,38,39,40,42,44,47],"20":[0,2,7,11,12,14,18,21,25,32,34],"200":[0,11,14,37],"2000":13,"2001":11,"2002":2,"2003":32,"2004":9,"2005":12,"2006":[2,13],"2008":[11,13,22],"2010":21,"2011":[9,12,13,21],"2012":[11,13,21],"2013":[9,12],"2014":22,"2015":[18,21],"2016":[2,21,22,32],"2017":[2,9,12,21,34],"2018":[1,2,5,22],"2019":[2,11,13],"2019gl086546":2,"2020":[2,9,11],"202000219":2,"20200159":2,"2021":[2,29],"202141049":2,"2022":2,"2023":[0,2,9,43],"2048":0,"204801":2,"207":12,"2092":21,"20m":4,"21":[11,21],"212":2,"2120":11,"217":13,"22":[2,11,21,34],"220":12,"2204":2,"222":[1,2],"223":2,"227":11,"23":[2,11,12,14,21],"230":13,"234801":2,"236":[12,22],"24":[2,11,12,14,21,25,27],"240":[14,34],"241":22,"242":13,"244":2,"246":2,"2497":2,"25":[0,2,9,11,21,34],"250":14,"256":[0,25],"25x25x25":16,"26":[2,12,21,33],"263":2,"267":11,"2680":25,"2697":25,"27":[2,11,12],"270":[14,21],"273":2,"28":[2,13,21],"2801":2,"2810":2,"284":2,"2868112":2,"29":[2,14,21],"2966":21,"2_":[13,22],"2_0":[10,22],"2_p":13,"2_t":[10,13],"2_x":[10,13,22],"2a_":11,"2d":[0,4,5,6,10,16,18,23,24,32,34,38,40,47,48],"2d3v":[9,46],"2dcartesian":[4,34,46],"2e":38,"2i":[10,13],"2i_p":12,"2ib_":10,"2ie_":10,"2l":12,"2m_3":11,"2m_4":11,"2n":[12,21],"2n_":14,"2nd":[25,35,38],"2s":21,"2y":40,"3":[0,2,7,10,11,12,13,14,16,21,24,25,26,31,32,33,34,36,37,38,40,44,46,47],"30":[2,21,34,37],"300":[0,2,34],"31":[0,21],"32":[4,16,21,27],"3203":2,"3207":2,"321":32,"32768":0,"33":[14,21],"34":[21,25],"343":2,"3441":3,"3454":2,"35":[2,21,33],"351":[1,2],"36":[13,14,21],"37":[2,11,14],"370":0,"3719":13,"373":[1,2],"3774":2,"378":22,"38":[11,14],"3816":2,"382":22,"388":11,"39":[14,18],"3969":2,"399937206900322":21,"3d":[0,2,4,5,6,10,13,16,24,25,32,34,35,38,47,48],"3d3v":[9,46],"3dcartesian":[34,37,46],"3dr":10,"3dx":10,"3e8":24,"3nd":35,"3rd":35,"3s":21,"4":[0,2,7,9,10,11,12,13,14,16,21,23,25,26,29,30,31,32,34,37,39,40,42,44,47],"40":[2,14,34,37],"408":21,"41":[10,11,25],"413":11,"418":2,"42":[2,10],"421":2,"43":[0,10],"4361":2,"439":11,"44":21,"45":[0,2,25],"450":21,"46":[2,10,13,18],"4642":11,"47":[2,10,21],"477":2,"48":[2,13,21],"485":2,"487":2,"49":[13,18],"492":21,"492675770100125":21,"496x496":21,"497":[2,21],"49780":0,"4b_":10,"4th":[4,21,43],"5":[0,2,7,9,11,12,14,16,21,23,25,31,32,34,37,38,40,44,47],"50":[0,10,13,21,34,37],"500":[14,34],"50000":34,"5006":2,"51":13,"512":[0,25,35],"512x512":40,"52":[12,13],"5238":2,"5260":2,"528":21,"5290":2,"53":[18,21],"5306":2,"54":[2,13,21,40],"55":[11,12,13],"56":[13,25],"57":18,"58":[13,18],"59":18,"5s":21,"6":[0,2,7,11,12,16,21,23,24,25,30,32,34,38,44],"60":[0,2,18,37],"600":34,"61":[2,13,18],"62":2,"6248":25,"63":[0,2],"632":21,"639":11,"64":[2,12,21,27,34,42],"6478":2,"65":[2,18],"652":2,"66":2,"665":2,"667":2,"68":[22,25],"6846":11,"688":21,"6d":0,"6s":21,"6x":33,"6x6x6":16,"7":[0,2,6,12,16,21,25,30,31,32,34,44],"71":2,"7250":25,"73":[2,18,21],"733977278199592":21,"740":22,"748991631516466":21,"750":[2,14],"755860201":2,"76":[25,42],"7605":3,"7638":3,"7648":3,"7660":2,"77":42,"78":42,"79":[7,34],"793":2,"8":[0,2,10,11,12,16,21,25,27,30,32,34,38,40,43,44],"80":[0,21,37,42],"800":0,"805850601":2,"81":[12,42],"8125":[14,18],"8168":[25,35],"82":[2,42],"829":[2,22],"83":[21,42],"84":21,"85":2,"851":3,"8578":3,"86":[2,25],"87":2,"88":2,"887":2,"89":2,"8s":21,"8u":10,"8x8":21,"9":[0,2,10,12,21,25,40],"90":[2,14,21,34],"905820305":2,"905860101":2,"905870607":2,"905880206":2,"91":12,"915890101":2,"917":2,"921":2,"924":[2,12],"93":11,"934":2,"937":2,"949":2,"95":2,"953":2,"96":2,"960":[16,42],"97":2,"9813047":2,"99":2,"995":0,"9dx":10,"9e_r":10,"9u":10,"\u00b5m":[0,21],"\u00b5s":0,"\u00e9lectrodynamiqu":21,"\u03b1":2,"\u03b3":2,"\u03b8":4,"alfv\u00e9n":0,"amp\u00e8r":9,"andr\u00e9":2,"andr\u00e9a":2,"b\u00e9ard":2,"bola\u00f1o":2,"boolean":34,"byte":34,"case":[0,7,9,10,12,13,14,16,18,21,22,23,24,25,26,28,29,32,33,34,37,38,39,42,47],"chanc\u00e9":2,"class":[2,14,17,18,21],"cm\u00b2":0,"const":42,"d\u00e9rouillat":[2,3],"default":[4,7,11,13,14,16,18,23,26,28,29,31,32,34,35,37,38,40,42],"do":[0,2,4,6,10,13,14,16,17,20,21,22,24,26,31,32,33,34,35,37,39,41,42],"export":[4,16,28,29,39,48],"f\u00fcl\u00f6p":2,"final":[0,11,12,14,18,21,34,42],"fl\u00e9":[1,2,3],"float":[25,26,34,35,37,38],"fr\u00e9d\u00e9ric":[2,3],"function":[0,4,5,7,9,10,11,12,13,14,17,18,21,22,24,25,26,32,33,34,35,37,38,40,41,46],"g\u00f6ran":2,"g\u00f6thel":2,"he\u00b3":34,"horn\u00fd":2,"humi\u00e8r":2,"import":[0,4,7,11,12,14,16,18,19,21,22,24,31,34,35,36,37,38,42,46],"int":[9,13,34,40,42],"istv\u00e1n":2,"j\u00e9r\u00e9my":3,"j\u00fcttner":[4,9,38,45],"l\u00e1szl\u00f3":2,"long":[0,2,9,11,12,16,18,21,24,34,35,37],"m\u00fcller":[9,34],"marcouill\u00e9":2,"marqu\u00e8":2,"marr\u00e9":2,"mati\u00e8r":[3,21],"new":[0,2,4,8,9,11,12,13,14,17,18,21,25,26,27,29,31,34,37,39,42,46,48],"nicola\u00ef":2,"null":21,"p\u00e9rez":[1,2,3,11],"p\u00e9rez2019":2,"plan\u00e9tologi":3,"public":[1,5,42,43,44,45,48],"return":[7,34,37,38],"s\u00e4vert":2,"s\u00e9bastien":2,"short":[0,2,12,21,34,42],"static":[2,12,16,21,22,28,37],"sundstr\u00f6m":2,"sundstr\u00f6m2020a":2,"sundstr\u00f6m2020b":2,"super":[0,2,5,9,12,16,39,43],"switch":[0,11,25,37],"t\u00fcnde":2,"throw":42,"transient":2,"true":[10,11,34,37,42],"try":[37,41],"vall\u00e9au":2,"var":34,"void":42,"vojt\u011bch":2,"wahlstr\u00f6m":2,"while":[0,9,11,12,16,17,18,19,21,34,35,37,41],A:[0,1,2,5,6,7,8,9,10,11,12,13,14,16,18,21,22,23,25,26,31,32,34,35,37,39,40,42,46],AND:37,And:[10,16,40],As:[2,5,9,10,11,12,13,14,16,18,21,22,24,28,34,37,42],At:[0,7,9,11,12,13,14,16,21,22,32,41],Be:[18,39],Being:10,But:[7,10,32,39],By:[10,14,16,18,32,34,35,37,40,42],For:[0,4,5,7,9,10,11,12,13,14,16,18,20,22,24,25,27,30,31,32,33,34,35,37,38,39,40,42,47],IS:37,If:[1,10,11,12,14,16,17,18,21,22,23,25,26,27,28,29,30,31,34,37,38,39,41],In:[0,2,4,5,7,9,10,11,12,13,14,15,16,17,18,21,22,23,24,25,26,27,28,29,31,32,33,34,36,37,38,39,40,42,43],Is:41,It:[0,5,7,9,10,11,12,13,14,16,18,21,25,26,31,33,34,35,36,37,38,39,40,42],Its:[22,24,34],NOT:37,Near:2,No:[0,16,34,42],Not:[18,21],OF:37,OR:[34,37],On:[0,4,18,21,25,26,30,31,34,39,42,47],One:[7,10,11,16,25,34,37],Or:24,THE:37,That:[24,27],The:[0,2,3,4,5,7,8,12,14,16,18,20,23,24,25,26,27,31,32,33,34,35,36,37,38,40,41,46,47,48],Their:[11,13,34],Then:[9,10,14,18,21,40,42],There:[0,14,27,31,34,38,42],These:[0,10,11,12,14,16,21,23,24,25,26,27,31,34,35,37,40,42],To:[0,5,6,9,11,12,13,16,17,18,19,22,25,26,27,29,30,31,32,34,37,42],With:[2,10,21,31,37,39,40,41,42],_:[9,10,11,12,13,14,18,21,26],_______________________________________________________________:42,_______________________________________________________________________:40,_a:18,_b:18,_cell:7,_f:9,_i:13,_k:18,_l:9,_mode_1:34,_mode_i:34,_of:7,_p:[9,13],_pml:7,_profil:34,_s:9,_t:18,_x:[12,34],a0:[4,34],a0_mode_1:34,a100:5,a143:2,a1:42,a2:42,a379:2,a64fx:[2,4,5,30,35],a87:2,a_0:[12,13,21],a_:[11,12,38],a_i:[22,38],a_mode_1:34,a_x:22,a_z:22,aac:2,ab:[2,26,34],abc:34,abid:1,abil:18,abl:[0,9,16,18,28,29,31,32,34],ablat:2,aboushelbaya:2,about:[0,4,10,11,12,23,31,34,35,37,41],abov:[0,2,4,10,11,12,13,14,16,21,22,24,25,31,32,34,37,42],abovement:13,abramkina:3,abrupt:21,absenc:[0,22],absent:[12,37],absolut:[13,21,34],absorb:[7,9,21,22,34],absorpt:[2,7,21,34],ac:12,academi:3,acc:42,accel:[2,12],acceler:[2,5,6,10,12,13,14,18,21,23,31,34,42,44],accept:[2,4,25,26,34],access:[14,16,18,21,26,29,31,34,37,42],accomod:34,accomplish:16,accord:[9,10,14,18,21,32,34,37],accordingli:[11,13,25,34],account:[0,4,5,11,12,13,17,21,30,34,38],accross:23,accumul:[11,34,37,47],accur:[0,2,7,9,13,18,34],accuraci:[0,2,9,11,18,21,34,40],achiev:[18,32,34,37],acknowledg:[1,44],acoust:[0,2],acquir:34,acronym:42,across:[7,27,34],act:[0,9,21,23,38,42],action:[21,42],activ:[0,14,34,35,37,39,41,42],actual:[0,10,16,24,26,32,34,38,39],ad:[4,7,9,11,12,14,23,25,26,31,34,42],adapt:[0,2,4,11,34,35,37,42,47],adastra:[0,39],add:[2,4,10,11,25,28,29,30,31,34,35,39,48],addict:13,addit:[4,5,6,11,13,18,21,23,25,32,34,35,37,39,42],addition:[12,34],additional_shifts_tim:34,address:[0,4],adequ:18,adjac:[9,18,34],adjust:[4,11,18,21,34,42],adk:12,admin:39,administr:[30,39],adopt:[3,21],advanc:[2,5,7,9,13,16,19,23,25,34,40,42,45,47,48],advantag:[7,8,11,13,16,18,19,23,25,34],advect:0,advis:[7,34,42],advisor:31,affect:[4,12,16,18,21,34,46],affin:21,affirm:25,after:[0,4,9,11,12,13,14,16,17,21,23,25,27,30,32,34,39,41,42],afterward:[12,13,24,41,42],again:[10,14,21,22,41,42],age_of_gnu:42,aggress:[18,35],agre:12,agreement:12,agress:35,ahead:16,aizawa:2,al:[2,9,11,12,13,18,32,34,40,47],aladyn:13,alain:2,aldo:2,alembert:13,alert:42,alexand:2,alexandr:2,alexei:2,algorithm:[0,11,13,14,16,17,20,22,23,24,25,34,40,41,42,45,47],alia:35,alias:35,align:[2,34,42],all:[4,5,7,8,9,10,11,12,13,14,16,18,20,21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37,39,40,41,42],allan:2,allinea:42,alloc:[0,34],allocat:42,allow:[0,4,5,8,9,12,13,16,21,22,32,34,35,42],almost:[11,14,21,34,41],along:[0,7,9,10,11,12,13,16,18,21,22,23,32,34,36,37,42],alpha:[2,11,18,21,34],alpha_:11,alpha_f:14,alpha_w:11,alreadi:[4,10,11,16,21,22,29,31,34,37,41],alreayd:10,also:[0,4,5,7,9,10,11,12,13,14,18,21,22,24,25,26,30,31,34,35,36,37,38,39,40,41,42],alter:[0,13],altern:[31,34],although:[13,16,17,34,37,40],aluminium:11,alwai:[8,10,13,16,18,21,25,27,31,34,41,42],am:[4,6,7,10,32,34,42],amcylindr:[0,4,34,37,41],amd:[4,5,6,31,35,39],amiranoff:2,ammosov1986:12,ammosov:12,among:[5,16,21,27,34,35,37,42],amount:[0,11,25,27,34],amplif:[2,44],amplifi:2,amplitud:[0,4,12,14,18,21,38],an:[0,2,4,5,7,9,10,11,12,13,14,16,18,21,22,23,24,25,26,27,29,31,32,33,34,35,37,38,39,40,41,42,45],analog:12,analys:26,analysi:[0,2,26],analyt:[0,2,5,32],anchor:37,ander:2,andrei:2,andriyash:2,angl:[2,7,11,32,34,37,47],angular:[0,11,12,32,34,37],angularli:34,ani:[1,5,7,9,10,13,18,19,21,24,26,28,29,32,34,35,37,38,39,42],anim:[0,4,25,48],anisotrop:38,anisotropi:11,anna:[2,3],announc:6,anoth:[4,16,24,25,27,32,33,34,37],answer:[23,41],antenna:[4,38,42,48],antici:2,antimatt:2,anton:3,antonino:2,antonio:2,antonsen:13,anymor:[4,14],anyth:34,anywai:34,aodhan:2,apart:[12,34],apj:2,apjl:2,apparit:14,appear:[0,6,10,13,21,24,25,32,34],append:39,appendix:33,appl:2,appli:[2,3,4,5,7,9,10,11,12,13,18,21,23,25,34,35,37,42,43],applic:[2,11,21,25,35],applyantenna:42,applybinaryprocess:42,appreci:35,approach:[2,9,10,11,13,16,21,27,34,42],approch:11,appropri:[18,21,35,36],approx:13,approxim:[10,11,12,14,18,21,25,32,34,47],apt:28,ar:[0,2,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,21,22,23,24,25,26,27,29,31,32,34,35,36,37,38,39,40,41,42],arbitrari:[2,5,7,32,34,37,47],arbitrarili:18,archana:2,archer2:30,architectur:[4,5,16,21,25,30,31,35,39],arcsin:18,arctan2:34,arctan:18,arctanh:11,area:[0,8,14,47],arefiev:2,arg1:39,arg2:39,arg3:39,argument:[4,10,31,32,34,35,38,39,40,42,46,48],arianna:2,arikawa:2,ariniello:2,aris:[9,42],arm:[2,4,5,25,30,35],armclang:35,armv8:35,arnaud:[2,3],arniko:2,around:[0,9,10,13,14,21,23,27,32,34,40],arrai:[2,4,10,11,12,14,18,26,27,32,34,37,38,42,45],arrang:[34,37],arriv:[0,41],arrow:[10,23],arsenio:2,art:[4,5],artefact:9,articl:[1,5,10,33,44],artifact:[9,44],artifici:[11,34],arxiv:[0,2,26,34],ascii:[37,42],asia:2,ask:[26,34,41],asma:3,aspect:[2,37],assess:21,assign:[9,12,14,16,18,21,23,24,34],assimil:10,assmann:2,associ:[0,2,8,9,11,16,24,26,34,38,47],assum:[10,13,18,21,22,24,25,34,35,39],assumpt:[10,13,22,34,35,41,47],astron:2,astronom:[2,21],astrophi:2,astrophys:[0,2,5,43],astrophysiqu:3,asymmetr:2,asymmetri:0,asynchron:[16,23],atom:[2,11,12,20,34],atomic_numb:34,attempt:37,attosecond:[0,2],attribut:[32,34,37],atukpor:2,aunai:[1,2,3],auto:[4,29,34,37],automat:[11,25,30,34,35,37,38,39],autoscal:37,avail:[4,5,9,10,11,13,16,18,21,22,23,25,26,27,31,34,35,37,38,39,40,42],averag:[4,9,11,12,21,22,25,34,37,44,46,47],avi:37,avoid:[4,9,16,27,34,41,42],avx2:[25,35],avx512:[25,35],awar:[28,39],ax:[10,13,34,37,41],axi:[4,13,21,32,34,37,40,47],axial:4,axis1:37,axis2:37,axis3:37,axis_facecolor:37,azimuth:[2,4,5,13,15,34,37,41,44,47],b1:42,b2:42,b:[0,1,2,4,10,11,12,13,14,18,21,22,23,24,26,32,33,34,37,40,42,47],b_0:0,b_:[9,10,12,34],b_l:10,b_m:34,b_p:9,b_r:[10,24,34,38],b_t:10,b_x:[22,34,38],b_y:[22,32,34],b_z:[9,22,32,34],babjak2021:2,babjak:2,back:[5,9,10,11,16,21,22,26,33],background:[11,26],backscatt:2,backward:[32,34],bad:[26,34,39,42],badli:4,bai:2,baifei:2,balanc:[0,4,5,8,11,14,23,37,42,47,48],ballist:42,band:34,bandhu:2,banjafar:2,bar:[9,11,13],baron:2,barrier:[2,21,42],base:[2,4,5,6,9,10,16,21,33,34,38,42],bash_profil:[28,29],bashrc:28,basi:[9,10,24],basic:[0,4,7,8,10,11,13,18,19,20,23,34,40,41,47],batani:2,batteri:2,bayliss:2,baynard:2,bc:9,bc_all:34,bc_em_type_:46,bc_part_type_:46,bc_x:34,bc_xmax:34,bc_xmin:34,bc_y:34,beam:[2,9,11,12,21,32,34,44],becaus:[0,7,9,10,11,13,16,18,21,32,33,34,35,37,40],beck2016:2,beck2019:[2,25,34],beck:[1,2,3],becnhamrk:42,becom:[0,10,11,14,18,21,34,37,42],been:[0,2,4,5,6,8,9,10,11,12,14,19,21,23,25,26,29,32,34,35,42,46],befor:[0,4,7,9,10,12,14,21,31,34,37,38,39,42],begin:[9,10,11,12,13,21,22,24,25,32,34,37,38],behavior:[14,21,25,39],behaviour:[4,9,41],behind:[0,12,21],being:[0,9,10,11,12,18,21,34],bell:21,bellan:2,belloni:2,belmont:2,belong:[0,42],below:[0,11,13,14,21,32,34,37,40,47],bench:26,benchmark:[4,18,23,25,26,34,39,41,42,47],bend:2,benedetti2008:13,benedetti2012:13,benedetti:[12,13],benefici:[9,16],benefit:[5,8,22,34],benisti:2,beom:2,berger:2,bernert:2,bernhard:2,bernstein:2,bes:0,besid:[13,28,35],best:[0,6,21,26,34,35,40,42],beta:[4,22,33],beta_0:[10,22],betar:2,beth2022:2,beth:2,better:[4,6,7,11,12,21,34,35,40,42],between:[0,2,4,8,9,10,11,12,13,18,21,23,25,26,32,33,34,35,37,40,42,47],bf:[9,12,21],bich:2,bifurc:2,big:[9,13],bigg:13,billion:0,bin:[4,22,28,29,34,37,42,46],bin_shift:42,binari:[4,5,20,26,27,34,41,47],bind:[11,39],bind_gpu:39,binomi:[4,9,34],biryukov:2,bit:[4,27,35],bl:34,bl_m:34,bl_mode_0:34,bl_mode_1:34,black:[0,11,14],blackman:2,blast:2,blecher:2,bloc:27,block:[4,11,13,21,27,34,38,41,42],blowout:2,blue:[0,10,11,13,14],bluegen:0,bohorquez:2,boin:2,bold:37,boltzmann:33,bonasera:2,bonvalet2021a:2,bonvalet2021b:2,bonvalet:2,boost:[11,14,22,40],boost_root:40,border:[0,9,21,22,34],borghesi:2,bori:[9,13,34],borisbtis3:34,borisnr:34,born:37,boron:2,bosman:2,both:[0,4,6,7,8,9,10,12,13,17,18,21,25,32,34,35,37],bothi:35,bottom:[0,12,25],bouchard:[1,2,3,4,34],bound:[2,7,21,34],boundai:10,boundari:[0,2,4,5,7,14,17,18,21,22,24,32,34,37,40,42,46,47],boundary_condit:[34,46],bourgeoi:[0,9],box:[0,7,9,12,16,32,34,37,38],box_sid:[34,46],boxsid:46,bpart:42,br:34,br_m:34,br_mbtis3_mode_0:34,br_mbtis3_mode_1:34,br_mode0:34,br_mode1:34,br_mode_0:34,br_mode_1:34,bracket:[34,42],breit:[2,4,5,20,47,48],bremsstrahlung:2,brendan:2,brian:2,briand:2,bridg:21,briefli:[13,21],bright:2,brillouin:[2,44],brind:25,bring:21,broad:[2,14,18,21],broadwel:[25,30,35],broken:26,brook:2,brought:[10,25,46],brown:2,browser:26,bruehl:2,bruni:2,bruwhil:12,bt:34,bt_m:34,bt_mbtis3_mode_0:34,bt_mode0:34,bt_mode1:34,bt_mode_0:34,bt_mode_1:34,btl:39,bubbl:2,budriga2020:2,budriga:2,buffer:[14,25,34,42],buffer_id:42,bug:[4,26,42],bugfix:4,build3d:37,build:[0,10,26,28,29,31],build_dir:31,built:6,bukharskii2023:2,bukharskii:2,bulanov:[2,12],bulk:21,bullx:0,bunch:[0,2,14,21,22],buneman:34,burch:2,burdonov:2,burst:[0,2],bussmann:2,butterworth:21,button:26,bw:14,bx:[34,37,38,42],bx_m:34,by_m:34,by_mbtis3:34,by_profil:34,bybtis3:34,bykov2022:2,bykov:2,bz:[34,37,42],bz_m:34,bz_profil:34,bzbtis3:34,c1:42,c2:42,c:[0,1,2,4,5,9,11,12,13,14,21,22,24,25,26,28,29,31,32,34,35,38,39,40,42],cach:[16,21,34,40,42],calcul:[0,10,11,12,13,16,22,32,33,34,37,42],calder:0,califano:2,calin:2,call:[0,9,11,13,14,16,21,25,34,35,37,40,41,42],calvi:2,can:[0,1,2,4,6,7,8,9,10,11,12,13,14,16,18,19,21,22,23,24,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42],cancel:[34,47],cannot:[0,12,16,18,21,23,24,32,34,40,41],canon:2,cantono2021:2,cantono:2,cao:2,capabl:[5,16,32,35,42],capit:42,captur:14,carbon:[2,12,21],care:[11,16,18,24],carefulli:[18,41],cari:[2,4,9,34,42],carlo:[2,4,11,14,34,40,47],carlson:11,carr:42,carri:0,carrier:[0,2,34],cartesian:[0,4,5,6,7,8,10,13,22,32,34,42,47],casanova:2,cascad:[25,35,47],cascadelak:[5,30,35],cassak:2,cassou:2,castan:2,catalina:29,caterina:[2,3],caus:[0,2,4,12,16,21,39,41,42],caviti:[0,2,21],cbaspect:37,cc:28,cd:[28,31,39],cdot:[9,11,12,13,21,22,24],cea:1,cecil:1,ced:21,cell:[0,1,2,4,5,7,8,9,10,12,13,16,18,20,21,23,24,25,32,34,37,38,41,42,43],cell_kei:42,cell_length:[24,34],cell_load:[34,37,46],center:[0,5,9,11,12,13,14,18,34,38],central:[13,34],cerri:2,certain:[0,11,23,25,35,42],ceurvorst:2,cfl:[9,34,41],chair:3,chakhmachi:2,chalmer:3,chan:2,chang:[1,2,11,12,18,21,22,25,28,29,32,33,34,37,41,42,44,45,48],changbo:2,changefield:[4,37],channel:2,chaoji:2,chaotiz:2,charact:[34,42],character:2,characterist:[0,12,21,34,37],charg:[2,5,9,10,11,12,13,14,17,18,21,22,24,34,37,38,42],charge_0:34,charge_1:34,charge_dens:[34,36,38],charge_over_mass_dts2:42,charge_over_mass_squar:42,chargeless:34,charl:3,chat:[41,43],chatelain:2,chatroom:26,cheaper:34,check:[4,10,13,21,34,39,41,42],checkoint:42,checkout:[0,34,37],checkpoint:[4,42,46,48],chemic:2,chen2013:12,chen2022:2,chen:[2,12],cheng:2,cherenkov:[0,4,9],chi:[10,11,13,14,18,34,40,42,47],chi_:[14,21,40],chiadroni:22,chiaramello2016:[0,2],chiaramello:[1,2,3],chines:2,chirp:[2,34],chirp_profil:34,choic:[9,21,25,31],choos:[9,11,16,18,24,25,27,28,30,33,34,37,38,42,47],chose:34,chosen:[7,9,12,13,18,33,34,37],choukourov:2,christoph:2,chul:2,chun:2,chunk:37,chunksiz:37,ci:0,cialfi:2,ciardi:2,cilex:2,cimrman:2,cine:[0,25],circul:1,circular:[4,12,13,34],circularli:[2,14,18],cite:[2,44],clabel:37,clae:2,clang:[4,30,35],clariti:34,clark:2,classic:[2,9,16,41,42,47],claudio:2,claus:23,claveria:2,clean:[18,41,42],cleanparticlesoverhead:42,cleanup:34,clear:26,clearer:42,clearli:[0,18,27],click:[25,26,42],cll:[21,34],clock:[2,25],clone:[4,26,31],close:[0,7,9,10,12,14,18,21,41],closest:[34,37],cloud:37,cluster:[0,2,23,25,30,34,48],cluster_width:[23,34,42],cm:[0,11,12,37],cmap:37,cnr:1,co:[5,10,12,18,32,34,38],coalesc:2,coars:20,coarser:41,code:[0,1,2,4,5,6,9,11,12,13,14,16,17,18,21,22,23,24,25,26,27,29,34,35,37,39,40,41,43,46],coef_cel:46,coef_frozen:46,coeffic:38,coeffici:[9,10,12,34,37,38,42],coher:2,coincid:[32,34],cold:[0,2,11,17,21,34],collabor:[1,2,5,26,43],collaps:0,colleagu:16,collect:[0,2,8,9,34,42,47],colleg:12,colleoni:2,collid:[0,2,11,14,18,34],collim:2,collis:[0,2,4,5,12,18,20,24,25,37,41,42,47,48],collision:[2,4,34,47],collisionless:[2,9,44,47],collisions0:11,collisions1:11,color:[16,37],colorbar:37,colorbar_font:37,colormap:37,colorscal:0,column:[34,36],com:[4,11,29,31],comb:0,combin:[10,12,21,23,25,26,27,31,34,35,37,42],come:[18,21,34],comma:34,command:[26,29,30,31,37,39,40],comment:[26,30,42],common:[30,31,34,35,42],commonli:35,commput:42,commun:[1,2,4,5,8,13,16,25,27,34,37],compact:[21,22],compar:[0,2,9,10,11,13,18,21,25,26,34],comparis:25,comparison:[0,2,10,11,12,21],compat:[4,18,31,34,37],compens:[25,34],competit:2,compil:[4,25,26,28,29,30,34,39,40,41,42,45,48],compilation_error:26,compilation_output:26,compile_tool:[30,31,42],complement:5,complet:[2,9,21,22,23,34,39,42,46],complex:[0,4,6,7,10,13,16,21,25,32,34,37,38],complianc:35,compliant:35,complic:16,compon:[0,4,9,10,12,13,18,22,32,34,36,37,42],compos:[0,42],compress:[0,18],compromis:40,compton:[2,14,47],comput:[0,1,2,4,5,7,9,10,11,12,14,16,18,21,22,23,24,25,32,33,34,37,39,40,42,43,47],computation:[0,34],computecharg:42,computeparticlechi:42,computeparticleposit:42,computepartpo:42,comun:39,conatin:42,concept:[2,25],concern:[10,21,37],conclud:10,condit:[0,2,4,5,7,14,21,22,23,25,34,37,41,42,46,47],conduct:[11,25],cone:2,conf:[2,21],confer:[2,13],config:[31,39],configur:[2,7,12,14,18,21,25,28,31,34,41],confirm:[6,14,21],conflict:16,conform:37,conjug:[9,22,32],connex:16,conor:2,consecut:[2,9],consequ:[12,14,16,21,23,24],conserv:[0,2,5,9,11,12,13,14,18,21,22,34],consid:[4,9,11,12,13,14,18,21,24,25,34,38,42],consider:[0,23,34],consist:[0,4,5,8,9,12,13,14,18,21,25,34,39,41],consistu:9,consol:29,constant:[0,4,12,14,18,24,25,34,47],constantin:2,constitut:[9,12,26],constraint:[0,7,23],construct:[12,23,37],consum:[32,42],contact:[30,31,39],contain:[8,11,13,14,16,18,21,25,26,27,30,31,34,36,37,39,40],content:[0,13,26,27,37],context:[11,13],contigu:[7,16,25,27,34,42],continu:[9,10,14,16,17,22,34,47],contract:35,contrari:[14,18,25,34,42],contrarili:34,contrast:[9,21],contrib:11,contribut:[2,4,9,10,16,17,18,21,24,34,45,48],control:[2,4,13,21,34],conveni:[10,21,24,42],convent:[4,47],converg:[10,14],convers:[2,4,24,29],convert:[14,24,34,37],cool:21,coordin:[12,13,18,22,32,34,36,37,46,47],copi:[9,30,34,37,39,42],copper:11,cord:2,core:[0,23,25,29,35,42,47],cori:30,cori_hsw:30,cori_knl:30,cormier:12,corner:34,correcpond:42,correct:[4,9,11,21,23,34,37,41,47],correctli:[12,21,22,41],correspond:[0,9,10,11,12,13,14,18,21,23,25,26,27,32,34,35,37,40,42],correspondingli:12,corresppond:42,corrupt:4,cosin:38,cosmic:[0,2],cost:[0,7,10,16,18,21,25,40],costli:[14,27,34],could:[0,4,18,22,24,28,34,35],coulomb:[4,11,34],coulomb_log:[11,34],coulomb_log_factor:34,count:[12,34],counter:[0,18,24,25,47],counterpropag:34,counterstream:2,coupl:[0,2,4,10,12,13],coupri:2,courant:34,cours:[7,21],courthold:2,cout:42,cover:[2,8],cowan2011:13,cowan:[2,13,34],cp:39,cpc:18,cpp:[14,17,42],cpu:[0,6,16,18,23,25,35,39],crai:39,crash:[4,34],cray_shasta:39,creat:[0,2,4,9,10,11,12,14,17,18,21,26,27,34,36,37,38,39,40,41,42,48],creation:[0,11,18,20,21,24,34,40,42,47],creator:34,criterion:25,critic:[0,2,11,21,23,25,42],cross:[2,11,21,34,40],crunch:26,csl:5,ct:13,ctpp:2,cu:[2,11],cube:16,cuda:[0,31],cui:2,cumbersom:24,cummul:21,cumul:[4,11,12,14,21,33,37],curcio:2,curi:[0,25,30],curl:[9,29],curli:42,current:[0,2,4,6,8,12,14,17,21,22,24,25,26,31,37,38,39,42,47,48],currentfilt:[34,46],currentfilter_int:46,curv:[0,11,14,16,23,25,34,37,42],custom:[9,27,34,42],custom_overs:34,customfir:34,cut:0,cxxflag:[31,35],cycl:[2,12,13,25,34],cyclindr:10,cyl:13,cylind:[4,10,34],cylindr:[0,2,5,13,34,37,38,47],czechia:43,d1:42,d2:42,d:[2,3,4,9,10,11,12,13,14,18,21,24,34,37,40,42],d_:13,d__amd_rome_7h12:35,d__intel_bdw_e5_2697_v4:35,d__intel_cascadelake_6248:35,d__intel_hsw_e5_2680_v3:35,d__intel_knl_7250:35,d__intel_skylake_8168:35,d_t:13,d_x:13,dae:2,dahui:2,dan:[2,21],daniel:2,daniil:2,dargent2016:2,dargent2017:2,dargent2019a:2,dargent2019b:2,dargent2020:2,dargent:[1,2,3],dash:[11,12,21,37],data:[0,3,6,10,14,16,23,24,26,31,34,36,47,48],data_:42,data_format:37,data_log:37,data_transform:37,dataset:[36,38],datatyp:[4,34],dattoli:2,david:2,davidson2022:2,davidson:2,davoin:[0,2,9,10],daysid:2,dc:12,ddt:42,de:[3,12],deadlock:4,deal:9,debayl:2,debian:40,debug:[31,42,47,48],debug_everi:[11,34],debugg:42,deby:11,debyelength:11,decad:0,decai:[14,18,34,40],decent:11,decid:[16,21,24,34],declar:[14,42],decom:42,decompos:[0,10,16,18,42],decomposit:[2,4,5,13,15,18,19,23,25,41,44,47,48],decreas:[7,11,12,14,21,22,40],dedic:[31,34,40,41,42],deduc:40,deep:2,deepli:35,def:[7,34,38],defeng:2,defin:[4,9,10,11,13,14,16,18,21,22,23,24,32,35,37,40,42,47,48],definit:[4,11,12,13,14,18,22,23,24,32,34,42,47],deflect:11,dehghani:2,deirdr:2,del:2,delai:[4,16,34],delay_phas:34,delet:[26,34],delimit:18,delon:12,delta:[9,11,12,13,18,32],delta_:[0,12,18],deltaold:42,demand:[0,34],demonstr:[0,10,13,25],denot:[9,12,13,18,25,34],dens:[0,2],dens_abc:34,densiti:[0,2,4,7,8,10,11,12,13,18,21,22,23,24,25,34,37,38,42,47],depend:[1,2,4,7,9,10,11,12,13,14,16,18,21,22,24,25,32,34,35,38,39,40,42,45,46,48],dependend:29,depict:[13,23],depierreux:2,deposit:[5,10,14,25,34,47],deposited_quant:[4,34,37,46],depth:[0,2,14,21,42],der:2,deriv:[0,9,10,12,13,21,22,24,34,42],derouillat2018:2,derouillat2020:2,derouillat:[1,2],describ:[0,7,9,10,12,13,14,16,18,21,22,23,25,26,31,32,33,34,37,40,41,42],descript:[2,9,12,13,14,18,21,25,26,35,37,42],design:[2,5,7,9,34,35,43],desir:[34,39],desjarlai:11,desjarlais2001:11,desktop:40,despit:4,destroi:11,detail:[0,2,5,7,9,11,12,13,16,21,26,31,34,35,37,42,47],detailed_tim:31,detect:42,determin:[10,16,18,23,25,34,40,42],determinist:21,detriment:[0,9],dev:28,devel:28,develop:[0,1,4,5,8,9,10,12,19,21,25,26,32,33,39,42],developp:[3,31],deviat:11,deviceptr:42,dewar:11,dfferenc:10,dhananjai:2,dhawan:2,di:[2,21],diab:2,diag1:37,diag2:37,diag:[4,34,37],diag_flag:42,diagfield:[4,34],diagnam:37,diagnewparticl:[4,34],diagnost:[0,2,4,5,6,9,10,13,16,17,21,24,26,27,31,36,39,41,42,46,48],diagnot:4,diagnumb:37,diagparticl:46,diagparticlebin:[34,46],diagperform:[4,34],diagprob:[4,34],diagradiationspectrum:34,diagscalar:34,diagscreen:34,diagtrackparticl:[4,34,46],diagtyp:37,diamagnet:2,diamet:10,dictionari:37,dictionnari:37,did:[0,4,18,41],differ:[0,2,4,5,7,9,10,11,12,13,14,16,18,21,23,24,25,26,32,33,34,35,37,40,41,42],differenti:[10,21],difficult:[0,25,42],difficulti:13,diffract:7,diffus:21,digit:[34,40],dimens:[0,4,7,9,11,21,23,24,34,36,37,38,42],dimension:[0,2,9,10,34,36],ding:2,dipiazza2012:21,dirac:9,direct:[0,2,4,7,9,10,12,13,14,16,18,21,22,23,32,34,35,37,38,41,42],directli:[4,9,13,14,31,34,35,36,37,38,40,42],directori:[14,18,21,26,29,31,34,37,42,48],disabl:[4,28,39],disappear:[11,42],discard:25,discontinu:[14,34],discrep:11,discret:[13,21,34,40,47],discuss:[9,21,26],disequilibr:2,disk:[4,21,32,34],dispers:[0,4,9,13,14,34],displac:[34,37],displai:[4,13,37,41],displaystyl:[14,21,40],disregard:35,distanc:[13,21,24,32,34],distinct:[27,32],distort:0,distribut:[0,1,9,11,12,14,16,18,21,22,23,24,25,28,34,38,41,42,45],div:10,diverg:[0,9],divers:5,divid:[0,14,18,21,22,23,33,34,37,42],divis:[18,37],dl:10,dlb:0,dmitriev:2,dn_:14,dnf:28,do2021:2,doc:[0,3,4,11,18,26,29,31,34,38,41,42],document:[4,5,9,18,29,34,37,42,48],doe:[7,9,11,12,18,21,23,24,26,28,32,34,35,37,39,42,48],domain:[0,2,4,5,7,9,14,17,18,19,21,25,32,36,47,48],domang:2,domin:[0,18,21],dominika:2,done:[4,9,10,11,14,16,18,21,23,25,31,34,42],dorvil:2,dot:[11,21,37],doubl:[2,25,34,40,42],doug:2,dowload:31,down:[0,11,16,18,21,23,33,34,38],downer:2,download:[28,29,40,43,48],downstream:0,dp_:21,dpi:37,dr:10,dramat:34,draw:[14,21,40],drawedg:37,drawn:[12,16,17,40],drawstyl:37,drift:[0,2,4,9,11,12,17,21,34,38],drive:0,driven:[0,2,12],driver:0,drobniak2023:2,drobniak:2,drop:14,ds:[14,40],dt:[9,10,12,13,14,21,34,40],dt_:42,dts2:42,du:3,dual:[9,47],dualiti:10,duclou:[2,21],duclous2011:[14,21],due:[0,2,9,11,12,13,16,18,21,32,34,35,38,40],dump1:34,dump:[34,40,42],dump_defl:34,dump_file_sequ:46,dump_minut:[4,34],dump_step:34,dumprestart:46,duplic:27,durat:[9,10,11,21,34,37,38],dure:[0,2,4,8,10,11,12,18,21,22,23,25,30,32,34,37,39,42],dv:34,dw:21,dx3:10,dx:[7,10,33,40],dy:[21,40],dynam:[0,2,4,5,8,9,13,14,16,21,22,23,25,34],dynamics_typ:46,dynamicstask:42,e15:2,e3:35,e5:[25,35],e7:35,e:[0,2,5,9,10,11,12,13,14,18,21,22,23,24,25,29,31,34,37,40,41,42],e_1:18,e_2:18,e_3:18,e_:[10,12,14,21,34],e_f:9,e_i:[9,10,22],e_l:10,e_p:9,e_r:[10,24],e_t:10,e_x:[9,10,13,22,34],e_z:[10,22],each:[0,7,8,9,10,11,12,13,14,16,18,21,22,23,24,25,26,27,30,31,32,34,35,37,38,39,40,41,42],earli:[0,2],earth:44,easi:[18,21,33],easier:[25,26],easili:[9,13,21,24,25,26,34,40],ecosystem:6,edg:23,edge_inclus:34,edgecolor:37,edit:[26,29],effect:[0,2,4,9,11,12,13,14,17,21,22,25,34,41,42,47],effet:21,effici:[0,2,4,7,8,11,14,16,18,21,25,40,42],effort:25,ehret:2,ei:11,either:[0,4,9,13,18,21,25,34,37,40],eject:0,ekerfelt:2,ekin:[34,37],el:34,el_mode_0:34,el_mode_1:34,electr:[0,2,5,10,11,12,14,21,22,24,34,42,47],electrmognat:42,electro:2,electrodynam:[2,14,21],electromagent:34,electromagn1d:42,electromagn2d:42,electromagn3d:42,electromagnam:42,electromagnet:[0,2,4,5,7,9,10,14,18,21,22,23,24,34,41,42,47],electromagnfactori:42,electron1:[34,37],electron:[0,2,4,5,11,12,14,18,22,23,24,25,34,37,40,47],electrons1:34,electrons2:34,electrostat:[2,9,22],element:[9,11,34,37,41,42],elementari:[21,24,34],elif:42,elkina2011:21,elkina:[2,21],ellips:34,ellipt:[4,10,12,13,34],els:[34,38,42],elsewher:31,em:[4,10,34],em_boundary_condit:[34,46],em_boundary_conditions_k:34,emb:40,embebd:[4,14],embed:34,emerg:21,emfield:42,emiss:[2,4,5,14,18,20,34,40,42,47],emit:[14,21,34,40],emitt:9,emma:2,emmanuel:2,empir:25,emploi:[0,9,13,26,32],empti:[34,37,38,42],en:3,en_ev_f:11,enabl:[0,21,25,28,34,35,42],enclos:42,encount:[34,41],encourag:6,end:[0,2,9,10,11,12,13,14,18,21,22,23,29,32,34,37,38,39,42],endif:42,endlessli:21,energ:2,energet:[0,2,14,21],energi:[0,2,4,5,11,12,14,16,18,20,22,24,34,40,41,42,47],eng:2,engin:2,enhanc:[0,2,25,34],enough:[0,7,11,12,13,18,22,25],ensur:[0,4,9,11,12,16,17,18,22,24,27,32,35,42],enter:[11,14,17,21],entir:[18,34],entranc:0,entrant:2,entri:[34,37],enur:35,env:31,env_a_ab:34,env_chi:34,env_e_ab:[13,34],env_ex_ab:[13,34],envelop:[2,4,5,6,7,15,32,37,41,42,44,47,48],envelope_boundary_condit:34,envelope_profil:34,envelope_solv:34,environ:[0,16,23,30,35,39,40,48],epart:42,epsilon:[11,13,21,26],epsilon_0:[7,11,21],epyc:35,eq:[9,10,11,12,13,14,21,22],eqnarrai:[9,10,13,22,38],equal:[0,7,9,11,12,14,18,22,23,24,27,34,36,38,42],equat:[0,4,5,8,9,11,12,21,24,32,34,42,47],equilibria:2,equilibrium:[2,11],equip:48,equit:16,equiv:[21,32],equival:[0,1,8,14,21,22,24,42],er:34,er_mode_0:34,er_mode_1:34,ergun:2,error:[4,9,11,12,21,26,28,29,34,39,40,48],error_namelist:42,esarei:12,escap:0,esirkepov:[9,13],especi:[11,23,34,35],espino:2,essenc:13,essenti:[16,28],establish:[4,10],estim:11,et:[2,3,9,11,12,13,18,32,34,40,42,47],et_mode_0:34,et_mode_1:34,eta:13,etc:[4,5,11,16,23,31,32,34,35,37,38,39,42],ev:[2,11,12],evacu:0,evalu:[10,25,34],evangelo:3,even:[0,10,12,16,18,19,21,24,37],evenli:34,event:[12,18,21,34],everi:[16,18,21,25,26,33,34],everywher:[29,33,34],evgeniya:2,evid:[0,2],evolut:[0,2,10,11,12,13,14,18,21,34],evolv:[0,10,14,21,25,37],ex:[18,34,37,42],ex_:42,exact:[10,34,35],exactli:[8,10,12,13,18,21,34],exaflop:6,examin:35,exampl:[0,7,9,10,11,12,13,16,21,24,26,27,34,35,37,38,39,42],exce:12,excel:[3,12],except:[10,13,34,35,37,38,39],excess:11,exchang:[0,9,16,25,34,42],excit:[0,2],exclud:14,exclus:16,execfil:31,execut:[8,11,16,26,29,30,31,34,41,42,48],exempl:9,exhaust:[0,28],exhibit:[14,21],exist:[9,21,26,30,34,37],exit:[7,26,39,40],exit_after_dump:34,exmax:34,exmaxcel:34,exmin:34,exmincel:34,exp:[2,4,10,11,12,21,32,33,34],expand:[10,18,21],expans:21,expeci:0,expect:[4,11,18,21,24,34,41],expel:0,expens:[21,25],experi:[0,2,22,34,35,41],experiment:[4,5,42],expert:[7,34],explain:[9,11,13,16,17,18,21,22,34,35,42,48],explan:[11,34,37],explanatori:26,explicit:[13,21,34,42,47],explicit_reduced_dispers:[13,34],exploit:[23,25],exponenti:[0,10,18,34,41],export_dir:37,express:[0,9,10,11,12,13,21,34,42],extend:[2,10,14,22,37],extendfrac:37,extendrect:37,extens:[13,21,23,26,34,42],extent:[8,34],extern:[2,4,9,12,14,21,31,37,38,45,48],externalfield:[10,34,37,38,46],extfield:46,extra:[18,24,34,38],extra_envelop:[32,34],extract:[1,26,31,48],extrem:[2,14,21],extrema:34,ey:[34,37,42],ez:[34,37,42],f:[1,2,9,10,11,13,21,22,25,32,33,37,38],f_:[9,12],f_k:12,fabio:2,face:[5,34],facecolor:37,facil:21,facilit:10,fact:[7,13,14,18,24],factor:[4,9,11,12,13,14,18,21,22,25,33,34,35,37,42],factori:[14,18],fail:26,fair:0,fairli:26,fall:[0,33],fals:[34,37],famili:[31,35,37],fang2019:2,fang:2,far:[4,21,22,25,34,35],faradai:9,farjallah:[2,3],farther:21,fashion:21,fast:[2,13,31,34,35,37,39],faster:[0,4,23,25,34,35],fastest:18,fault:4,faulti:4,faval:2,favorit:26,fazzini2022:2,fazzini:2,fc:28,fci:2,fdtd:[4,5,9,34,47],feasibl:0,featur:[0,1,2,4,5,6,9,12,26,34,35,38,39,42],fede:2,fedel:12,fedeli2017:2,fedotov:2,feedback:[16,21],feet:37,femtosecond:[0,2,10,14],feng:2,fermi:[0,11],ferrand:2,ferrario:22,ferri2020:2,ferri:2,fetch:29,few:[0,2,6,11,12,13,14,16,23,25,26,30,31,32,34,40],ffast:35,ffinit:35,ffj:35,ffmpeg:31,ffp:35,fft:[32,34],fft_time_step:[4,34],fft_time_window:[4,34],field1d:42,field2d:42,field3d:42,field:[2,4,5,6,7,8,11,14,15,16,17,18,24,25,32,38,41,44,47,48],fieldfactori:42,fieldfilt:[34,46],fieldinfo:37,fig:[0,11,12,14,16,18,21,25,42],figsiz:37,figur:[0,9,10,11,13,14,16,17,18,23,32,37,42],filament:[0,2],filamentari:0,file:[4,5,9,11,14,17,18,21,25,26,27,28,29,30,31,32,34,35,37,39,40,41,42,45],file_group:[4,34],filenam:37,filesystem:34,filip:2,filippov:2,fill:[0,18,28,29],fillstyl:37,filter:[4,8,46,47,48],filtrat:34,finalizeandsortparticl:42,finalizesyncandbcfield:42,financi:3,find:[4,14,21,22,28,29,31,35,37,41],fine:[2,4,21,35],finer:23,finest:34,finish:[16,18,23],finit:[0,5,9,10,13,34,37],fir:[4,9,34],first:[0,2,7,9,10,12,13,14,18,21,23,25,26,27,29,33,34,35,36,37,39,40,42],fit10:34,fit5:34,fit:[11,18,21,25,33,34,40,42],fiuza:2,five:34,fix:[4,12,34],fl:2,flag:[4,25,30,31,34,35,39,41],flexibl:4,flow:[0,2,9,17,25],floyd:2,fluctuat:[0,2],fluid:11,flush:34,flush_everi:34,flux:[9,24],fma:[25,35],fno:35,foam:2,focu:[2,21,34],focus:[0,2,4,13,21,25,32],foil:[2,47],fokker:47,folder:[21,26,29,30,31,34,40,41],follow:[0,1,4,5,7,9,10,11,12,13,14,16,17,18,21,23,25,26,28,29,31,32,34,35,36,37,38,39,40,41,42],font:[4,37],footprint:[18,34],fopenmp:35,foral:10,forc:[0,9,10,11,12,13,18,21,22,23,26,34],foresti:2,fork:26,form:[9,13,18,22,23,34,35,38,47],format:[0,3,4,21,26,37],formatt:37,formenti:2,former:9,formul:12,formula:[12,13,14,18,21],formulari:11,forth:16,fortran:[29,34],forward:[10,21,34],found:[0,12,13,14,21,22,23,33,37,41,42],four:[0,9,10,21,22,34],fourier:[4,10,32,34,37,44],fourth:[2,4,25],fp:[21,37],fphy:2,frac:[7,9,10,11,12,13,14,18,21,22,24,33,34,40],fraction:[12,18,37,40],frame:[11,13,14,18,22,34,37],frame_on:37,framework:[2,9,13],franc:25,francesco:[2,3],frank:2,frankel1979:11,frankel:11,frankenheim:2,frederico:2,frederiksen:2,free:[1,2,9,24,34],freeli:26,french:1,freq:[34,38],frequenc:[0,2,4,7,12,13,24,25,32,34,38,41],frequent:12,fresh:17,friction:[2,21],friedman:[4,34,47],friedman_filt:46,friedman_theta:46,friedrich:34,friendli:[4,5,43],frioul:[21,25,30],frog:9,from:[0,1,2,3,4,5,7,8,9,10,11,12,14,16,17,18,21,22,23,24,25,26,27,29,31,32,33,34,37,39,40,41,42,43,45,46,47],from_rat:34,front:[0,2,21],frozen:[4,34,37],frozen_particle_load:[34,46],fs:[2,12,14,21],fsimdmath:35,fssl:29,fu:2,fuch:2,fugaku:30,fugaku_fujitsu_cm:30,fugaku_fujitsu_tm:30,fujii:2,fujioka:2,fujitsu:[2,4,5,30,35],fukuda:2,fulfil:[9,25],full:[0,2,4,10,14,22,31,32,34,38,39,40,42,47],fullfil:9,fulli:21,functor:42,fund:3,fundament:[0,2,6],further:[0,22,32,37,42],furthermor:[12,13,14,16],fuse:[25,35],fusion:[2,4,13,21],futur:[6,25],fwhm:[12,14,21,34,38],fyrth:2,g:[1,2,5,9,10,12,13,21,22,23,26,29,31,33,34,35,37,39,41,42],ga:2,gain:[18,21,34],galact:0,galbiati2023:2,galbiati:2,game:6,gamma:[0,2,9,10,11,12,13,14,18,21,22,33,34,37,40,42],gamma_0:[10,22],gamma_1:33,gamma_:[11,12,14,21],gamma_i:[11,12],gamma_p:9,gamma_w:11,gang:42,gangolf:2,gao2023:2,gao:2,garten:2,gather:[9,14,25,34],gatti:22,gauss:[9,10],gaussian:[2,4,11,12,14,21,34,38],gaz:3,gb:37,gcc10:29,gcc:[28,31,35],gedd:12,gelfer2018:2,gelfer2020:2,gelfer2021:2,gelfer:2,genci:0,gener:[2,4,6,9,13,14,18,21,22,25,26,27,31,32,35,37,39,41,44,45,48],generaliz:21,geng2019:2,geng:2,geometr:[10,34],geometri:[0,4,5,6,7,9,13,18,22,32,34,37,38,41,42,47],geonwoo:2,geophi:2,geophys:2,geq:34,germani:25,get:[9,10,11,28,31,37,42,44],getadditionalshiftsiter:42,getaxi:[4,37],getclassicalradiatedenergi:42,getdata:37,getdiag:37,getnumberofadditionalshift:42,gettim:37,gettimestep:37,gettrackspeci:37,getxmov:[4,37],gev:[0,14,21],gg1:12,gg:21,ghaith2021:2,ghaith:2,ghasemi:2,ghizzo2023:2,ghizzo:2,ghost:[8,9,10,34,38,42],giada:2,gibbon:12,gif:37,gile:2,gill:2,gilljohann:2,giribono:2,git:[4,26,28,31,41],github:[4,26,28,29,31,41,43],githubusercont:29,giuffrida:2,give:[9,10,13,14,16,18,21,24,31,32,34,40,41],given:[0,5,7,9,10,11,12,13,14,16,18,21,23,25,26,34,35,36,37,38,40,41,42],gizzi:[2,12],gladli:1,glek2020:2,glek2022:2,glek2022b:2,glek:2,global:[0,37,42],gnu:[1,4,28,30,35],go:[7,16,26,31],goal:8,goe:[0,39,41],goetz:2,gold:25,golovanov2017:2,golovanov2021:2,golovanov2023:2,golovanov:[2,3],good:[7,11,19,33,34,35,40,42,47],googl:2,gordon2000:13,gordon:13,gothel2022:2,gothenburg:3,govern:[1,21],gpl:1,gpu:[4,5,19,31,34,44,47,48],gpu_amd:31,gpu_comput:34,gpu_nvidia:31,gradient:[0,2,9,13,21,22],grai:[12,37],grain:[2,4,42],grant:3,granular:[25,42],graph:[4,11,34,37],graphic:6,grassi2017a:2,grassi2017b:2,grassi:[1,2,3,34],grate:2,great:[0,11,16],greater:[0,2,4,9,12,13,22,34],greatli:[10,12],grech:[1,2,3],green:[0,14,16],greenwood:9,gremillet:2,grepl:2,grid:[0,8,9,12,13,16,17,23,25,32,34,37,38,39,42,47],grid_length:[10,24,34,38,46],group1:36,group2:36,group:[11,16,21,34,36,42,47],groupinto:18,growth:[12,18,41],gtrsim:47,gu:2,guarante:35,guid:[2,13,28,35],guidelin:[6,26,29],guijun:2,guillaum:[2,3],gunel:2,gunsu:2,guo2022:2,guo:2,guoqiang:2,guyot:2,gv:11,gw:2,gyrat:[0,21],gyrotrop:2,gz:28,h5:[11,27,32,34,36,38,40],h5py:[28,29,31],h:[2,18,21,26,33,34,40,42],h_:21,ha:[0,4,5,6,8,10,11,12,14,16,18,21,22,23,24,25,26,27,29,31,32,33,34,35,37,38,41,42,46],habara:2,had:4,hadjikyriac:2,hadjikyriacou2023:2,haithem:3,half:[0,9,10,14,21,34,38,42],hall:2,hamrin:2,han2022:2,han:2,hand:[11,13,34,37],handi:9,handl:[0,4,6,16,18,24,25,31,37,42],hannachi:2,hao:2,haoyang:2,happen:[18,21,32,34],happi:[4,26,29,34,41,42,46,48],hard:[2,14],hardwar:[16,31,35],harmon:[2,10,44],haswel:[21,25,30],hat:[10,13,22,32],have:[0,2,4,7,9,10,11,12,13,14,16,18,19,21,22,23,25,26,27,31,34,37,38,39,40,41,42,46],hazard:35,hbar:[12,14,21],hdf5:[4,5,11,28,29,30,31,32,34,37,38,40],hdf5_root:31,hdf5_root_dir:[28,29,31],he:2,head:[0,14,29],header:31,heat:[2,21],heavi:[0,18,34],heavier:16,hee:2,heinemann:21,helium:0,hello:41,helmholtz:2,help:[1,15,16,26,28,30,31,32,34,40,41],henc:[0,9,18,21],henceforth:[9,12],henri:2,henrik:2,here:[0,1,4,7,9,10,12,14,16,18,21,22,25,28,29,31,34,35,37,39,40],hereiam:39,hess:2,hh:26,hidden:[21,29],higginson2019:11,higginson2020:[4,11],higginson:11,high:[2,4,5,7,11,12,14,16,17,18,19,20,25,34,35,40,42,43,44,47],higher:[0,7,10,25,34,38],highest:[14,21,42],highli:[2,9,14,21,22],highlight:[9,44,45],higuera:[4,9,34,42],higueracari:34,hilbert:[16,34,37,42],hilbertian:34,hill:2,hindex:37,hine:11,hip:31,hiroki:2,histogram:[0,34,37],histori:21,hit:7,hitendra:2,hobb:2,hoc:12,hoffmann:2,hogan:2,hojbota:2,hold:[16,21,34],hole:18,holling:2,holod:11,homam:2,home:[29,39],homebrew:[29,40],homogen:[8,12,25],hong:2,honor:35,honrubia:2,horizont:37,horny2021:2,hosseinkhani2021:2,hosseinkhani:2,host:[11,39],hot:[0,2,21],hotspot:0,hour:0,how:[0,2,11,16,18,21,23,25,26,29,31,32,34,39,44],howev:[6,9,10,11,12,13,16,18,21,22,24,27,31,32,34,35,39,42],hpc:[2,5,6],hpcasia:2,html:[26,29,31],http:[1,4,26,29,31],huan:2,huang2006:13,huang:[2,13],hue:2,humier:2,huynh:2,hybrid:[2,4,5],hydrogen:12,hyeongmun:2,hypervolum:[9,24,37],hypothes:[12,13,22],hypothesi:[9,22,34],i:[0,1,2,7,9,10,11,12,13,21,22,24,25,26,32,34,37,38],i_j:11,i_k:11,i_l:12,i_p:12,ib_:10,ibin:42,icap:[2,13],icop:2,icops45751:2,id1:37,id2:37,id:[4,27,34,37,42],idea:[21,23],ideal:26,ident:[7,13,34,36,37],identif:[34,45],idli:23,idri:[0,3,25],ie_i:10,ieee:[2,13,35],iend:42,ifndef:42,ignor:[35,37,40],ii:21,iii:2,ij:[11,38],ijk:38,ik_0:13,ik_0c:13,ilja:2,ill:10,illia:3,illustr:[0,8,9,16,18,25,27,32,34,38],illya:[2,3],iltommi:29,im:10,imag:[0,10,25,37],imbal:[16,18,23,25,34],imbalanc:0,imen:3,immedi:[21,34],immobil:[10,41],impact:[0,2,4,5,11,18,21,34],imperi:12,implement:[0,2,4,5,6,9,10,11,12,13,22,25,31,34,35,45,47],impli:[22,23,35],implic:2,implicit:[34,42],importantli:9,importparticl:14,impos:12,imposs:[13,33],improv:[2,4,14,23,25,32,34,35,44],inaccur:[9,34],inc:34,inch:37,incid:[0,2,4,7,11,34],incidence_angl:34,includ:[0,2,4,5,6,10,13,18,23,25,26,29,31,34,35,37,38,40,42],incoher:[21,34],incom:[0,25,34],incompat:[4,36],incorpor:[14,21],incorrect:[4,35],increas:[0,7,9,10,11,12,14,16,23,25,34,42],increasingli:0,increment:[14,21,42],inde:[9,12,16,18,21,34,42],indefinit:11,indent:34,independ:[10,21,22,27,42],index:[13,18,26,29,34,37,40,42],indic:[9,10,12,21,25,26,27,34,37,39,42,46],individu:[9,11,21,34],induc:[2,8,17,18,21,25],inelast:11,inequ:40,inerti:2,inf:35,infer:22,infin:21,inflow:0,influenc:[12,18,21],info:[1,11,34,35],inform:[1,4,9,11,12,14,16,21,22,24,31,34,35,39,42,48],informatiqu:3,infrar:2,infti:[10,14,21,34,40],inherit:[21,34,42],inhomogen:[0,2,9],init:[12,42],initi:[2,3,4,5,6,7,10,11,12,14,15,17,18,21,32,34,37,39,41,42,44,45,47],initial_bal:34,initial_mod:34,initialis:4,initil:42,initmomentum_typ:46,initposition_typ:46,inject:[0,2,4,9,11,12,14,17,21,22,32,34,42],injector1:34,injector:[2,4,15,47,48],injectparticlesfromboundari:[17,42],inlin:35,inner:[7,34],innermost:16,input:[4,5,9,11,13,18,21,24,26,34,38,39,41,42],inria:1,insid:[9,16,21,23,34,36,37,38,39,42],inspector:31,inspir:[9,11,18,32],inst:[2,21,34],instabl:[0,2,9],instal:[26,34,37,41,45,48],install_dir:28,instanc:[7,10,14,16,18,20,21,24,25,27,30,31,32,34,35,36,37,38,39,40,42],instantan:[21,22,34],instantli:34,instead:[0,4,9,10,12,13,16,17,18,21,23,24,25,27,31,32,33,34,37,38,42],institut:3,instlal:28,instr:22,instruct:[16,26,29,30,31,34,35,37,39,47],int_0:[10,14,21,34,40],int_1:33,int_:[14,21,40],integ:[9,27,34,37],integfochi:[21,40],integr:[4,7,9,12,13,14,18,21,22,26,34,35,40,47],integrate_kappa:7,integrate_sigma:7,integrate_sigma_r:7,integration_dt_dchi:34,intel:[3,4,5,21,25,30,31,35],intelmpi:[25,30],intend:39,intens:[0,2,3,12,14,21,32,34],intepol:9,interact:[0,2,4,5,9,11,12,13,14,21,34,37,43,47],interchang:14,interest:[7,9,13,18,22,25],interfac:[5,7,16,41,42],interfer:[22,39],intermedi:47,intern:[0,2,12,13,39],interpenetr:2,interplai:2,interpol:[0,4,5,8,10,11,12,14,23,25,32,33,34,37,42,47],interpolation_ord:[16,34],interpret:34,interprocedur:35,interstellar:0,interv:[21,34],intra:[11,34],intrins:2,introduc:[9,10,11,12,14,23,34,42],introduct:12,intuit:24,invari:[14,21,42],invers:[2,8,14,25,32,33,34,47],invert:[2,14,21],investig:2,invgf:42,involv:[1,13,18,23,34,42,44],ioan:2,ion:[0,2,4,11,12,21,34],ionel:2,ionis:[4,34],ioniz:[2,4,5,6,13,14,18,20,21,24,34,41,42,44,47],ionization_electron:34,ionization_model:34,ionization_r:34,ionospher:2,ions1:34,ip:35,ipart2:42,ipart:42,ipart_buffer_offset:42,ipart_ref:42,ipatch:42,ipo:[4,35],ipython:[28,29,41],irami:3,irap:3,iren:25,irradi:[2,12,18,21],irregularli:23,is_device_ptr:42,is_test:[34,46],isayama:2,ismov:42,iso:35,isol:2,isotrop:[0,11],ispec:42,issn:21,issu:[0,4,16,21,23,26,28,29,37,42,48],istart:42,istart_offset:42,istest:46,istokskaia2023:2,istokskaia:2,iter:[0,9,10,13,17,18,23,32,34,37,41],iterparticl:37,itim:42,its:[0,1,2,5,7,9,10,11,12,13,16,21,22,24,34,35,37,41,42],itself:13,iu:2,iuliana:2,j:[1,2,9,10,11,12,13,21,22,24,31,32,34,38,42],j_:[9,10],j_i:9,j_r:[10,24],j_x:[9,10,34],j_y:9,j_z:9,jae:2,jafari:2,jakubowska:2,jame:2,jan:2,januari:29,jaroslav:2,jd:10,jean:[25,30],jean_zai:30,jet:2,jetp:12,ji:2,jian:2,jianbo:2,jianyong:2,jiarui:2,jing:2,jirka2021:2,jirka:2,jizhong:2,jl:34,john:2,join:42,joliot:[25,30],joliot_curie_arm_a64fx:30,joliot_curie_fujitsu_a64fx:30,joliot_curie_gnu_a64fx:30,joliot_curie_knl:30,joliot_curie_rom:30,joliot_curie_skl:30,joshi:2,joul:[2,37],journ:12,journal:[2,13,21],jp:10,jr:[13,34],jt:34,juelich:25,juettner:[34,38],julien:[2,3],jump:21,jun:2,junghan:2,junior:3,jureca:[21,25,30],just:[10,16,18,29,42],juttner:21,jx:[34,37],jx_abc:34,jy:[34,37],jy_abc:34,jz:[34,37],jz_abc:34,k:[2,9,11,12,13,14,18,21,32,34,37,38],k_0:13,k_1:11,k_2:11,k_3:11,k_4:11,k_:[9,11,12,14,21,34,40],k_i:11,k_k:11,k_r:24,k_x:[18,32],k_y:[18,32],k_z:32,ka64fx:35,kalal:2,kallala:3,kaluza:2,kane:2,kang:2,kantarel:2,kappa:[7,34],kar:2,karl:2,kassum:35,kazamia:2,kb:25,keep:[0,7,21,27,29,32,33,34,42],keep_interpolated_field:34,keep_n_dump:[34,46],keep_n_strongest_mod:[32,34],kei:[2,6,37],keitel:2,kelvin:2,kemp:11,kenneth:2,kept:[12,21,24,25,32,34,37],kernel:[0,4,9,34],kernelfir:34,kev:11,keyword:[4,31,34,35,37,46],kfast:35,khalilzadeh2021a:2,khalilzadeh2021b:2,khalilzadeh2021c:2,khalilzadeh:2,ki:2,kill:[34,39],kim:2,kin:34,kind:[0,34],kinemat:11,kinet:[0,2,9,11,14,18,21,24,34,41],kirk:21,kisyov:2,kj:2,kleij:2,klimo:2,kluge:2,kmp_affin:21,knetsch:2,knight:[25,30],knl:[21,25,30,35],know:[7,9,21,24,33,34,39],known:[0,9,12,13,21,32,34,48],kochetkov2022:2,kochetkov:2,kocl:35,kong2022:2,kong:2,kononenko:2,korn:2,korneev:2,korzhimanov:2,kostyukov:2,kov:2,kparallel:35,krafft2021:2,krafft2022a:2,krafft2022b:2,krafft2023:2,krafft:2,krainov:12,kreuter:2,kroeneck:12,krolik:33,krushelnick:2,ksimd:35,kssl2:35,ksve:35,ku:2,kubytskyi:2,kucharik:2,kumar2021:2,kumar2022a:2,kumar2022b:2,kumar:2,kunrol:35,kuramitsu:2,kuznetsov:2,kwarg:37,l012023:2,l021201:2,l0:34,l14:2,l23:2,l24:2,l28:2,l29:2,l2:[40,42],l3:[40,42],l:[0,2,3,9,10,11,12,13,21,22,34,42],l_r:[24,34],la:3,lab:[11,13],labat:[2,12],label:37,labex:3,laboratoir:3,laboratori:[0,2,11,13,14,22],labord:2,lack:[24,26],laguerr:2,lake:25,lambda:[11,14,21,34,37,38],lambda_0:[0,12,13],lambda_c:21,lambda_p:13,lan:2,lancia2016:2,lancia:2,land:[25,30],landau1947:21,landau:[34,47],langmuir:[0,2],languag:[5,13,26,34],laplacian:[13,22],larg:[0,4,7,8,11,12,16,18,21,22,30,34,40,42,47,48],larger:[0,8,12,13,16,18,34,40],larmor:21,larroch:2,laser:[2,3,4,5,7,9,10,11,14,15,18,21,24,25,39,41,43,44,45,47,48],laserenvelop:[4,34],laserenvelopegaussian2d:34,laserenvelopegaussian3d:34,laserenvelopegaussianam:34,laserenvelopeplanar1d:34,lasergaussian2d:[4,34],lasergaussian3d:34,lasergaussianam:34,laseroffset0:32,laseroffset1:32,laseroffset:[4,34],laserplanar1d:34,last:[0,11,13,14,21,27,34,36,37],lastli:9,late:[0,11],later:[26,34,42],latest:[4,31],latter:[9,14,21,22,34],lattic:10,launch:[34,39],laurent:2,lavorenti2021:2,lavorenti:2,lavraud:2,law:[0,1,2,10],layer:[2,4,5,11,21,34,45,47],ld_library_path:28,ldflag:31,le:12,lead:[0,7,9,10,12,18,21,34],leaf:2,leak:[4,42],leap:9,learn:[0,2,4],least:[0,6,10,16,22,34,37,40,41],leav:[34,42],leddi:2,lee1984:11,lee:[2,11],leeman:12,left:[9,10,11,12,13,14,18,21,22,23,25,32,33,34,37,40],legend:[14,37],legend_font:[4,37],lehe:[4,9,34],lelasseux:2,length:[0,9,11,18,21,24,25,34,37,38],leonida:2,leprinc:3,lericheux:2,less:[4,7,8,14,16,21,23,24,25,34,37,40,41,42],lesssim:47,let:[7,10,11,12,16,17,18,22,24,27,32,34,35,39,42],lett:2,letter:[2,42],level:[0,2,4,11,12,16,18,23,34,37,40,42],levi:2,lewi:34,leyen:2,lf:28,li:[2,10,32],liang:2,liangliang:2,lib:28,libhdf5:28,librari:[28,31,40,41],licciardi:2,licenc:[42,44,45],licens:1,lifshitz:[34,47],light:[0,2,9,13,14,21,24,34],lighter:16,lignes_of_smilei:42,like:[8,10,14,18,24,32,34,35,37,41,42,47],lim_:10,limit:[4,11,13,14,18,21,32,34,35,37],limits_:11,lin:2,lindvist:2,line:[0,11,12,13,21,26,28,29,31,34,37,39,40],linear:[0,2,4,9,10,12,13,16,18,21,25,32,34,42],linearized_xi:[16,34],linearized_xyz:[16,34],linearized_yx:[16,34],linearized_zyx:[16,34],linearli:[9,10,12,32,33],linestyl:37,linewidth:37,link:[4,11,21,26,35,42],linker:31,linux:[31,40,45],liquid:2,list:[1,2,18,21,24,27,30,34,35,36,37,38,39,40,41,42,48],literatur:21,lito:2,littl:18,liu:2,live:2,ll:[11,12,13,34,47],lll:12,llr:[3,25],llvm:[4,35],ln:[11,33,34],load:[0,2,4,5,8,9,18,23,25,26,28,30,31,37,39,42,47,48],loadbal:37,loadbalanc:[34,41],lobet2013:[14,21],lobet2015:[14,21],lobet2022:2,lobet:[2,3,21],local:[0,2,9,12,13,16,21,22,24,25,26,28,29,31,34,42],locali:25,locat:[0,4,8,9,10,14,18,21,25,26,29,31,32,34,35,36,37,38,39,40,42],lock:2,log10:21,log:[0,11,14,21,25,26,33,34,39,41],log_:37,logarithm:[4,11,34,40,47],logic:[10,23,37],logscal:34,loiseau:2,londrillo2014:22,londrillo:[12,13,22],longer:[0,7,13],longitudin:[0,2,11,12,13,18,21,34,47],look:[0,10,14,40],lookup:21,loop:[11,12,17,21,23,25,34,35,37,39,47],lorentz:[0,9,11,12,13,14,18,21,22,33,34,42],lorenzo:2,lose:[14,21,34],loss:[11,17,21,34,40,42],lossi:35,lost:[12,14,21,34],lot:42,lou:2,low:[0,2,4,10,11,12,18,23,25,34],lower:[2,21,25,34],lowercas:42,lpgp:3,lpi:2,lpp:[3,25],lu:2,luca:2,lucianetti:2,lui:2,luli:3,luo:2,lv:2,lwfa:0,m4:[4,34],m:[0,1,2,10,11,12,13,14,18,21,22,24,26,34,42],m_3:11,m_4:11,m_:[9,10,13,34],m_e:[0,11,12,14,21,24,34],m_ec:[11,34,38],m_em_i:11,m_et_:11,m_i:[0,11],m_it_i:11,m_k:11,m_n:11,m_r:[10,24],m_x:10,ma:2,macchi:2,machin:[0,25,30,31,34,35,41,42],machineri:2,maco:[31,40,45],macro:[0,4,9,11,13,14,17,21,22,23,25,34,37,39,42,47],macroparticl:13,macroscop:9,made:[0,8,12,13,14,18,34,44],magan:42,magic:9,magnet:[2,5,9,10,12,13,14,18,22,24,32,34,44,47],magnetopaus:[2,44],magnetospher:0,magnitud:[0,12,38,40],mahfoud:2,mai:[4,9,10,11,12,15,16,17,18,24,25,26,27,28,30,31,32,34,35,36,37,38,39,40,42],main:[10,12,13,14,16,18,21,23,24,26,37,39,41,48],mainli:[9,10,12,13,14,16,21,34],maintain:[9,18],maison:3,maitreyi:2,major:[4,34],make:[0,1,4,10,18,23,25,26,28,29,30,31,33,34,35,37,39,40,41,42],makefil:[31,35,40,42],malakit:2,malik:2,malka:2,malko2019:2,malko:2,man:35,manag:[0,2,4,6,14,17,18,21,27,29,34,37,40,47,48],manang:42,mandatori:[19,29,34,47],mani:[0,4,8,10,11,12,13,14,16,21,23,24,25,26,34,35,37,39,42],manifest:12,manipul:37,manner:[0,16],manual:[11,28,30,35,40],map:[0,34,37],march:35,marco:[2,3],marconi:30,marconi_bdw:30,marconi_knl:30,marcowith2020:2,marcowith:2,margaron:2,margarone2020:2,margarone2022:2,mari:3,mariana:2,marini2021a:2,marini2021b:2,marini2023:2,marini:2,mark:[2,42],marker:37,markeredgecolor:37,markeredgewidth:37,markerfacecolor:37,markerfacecoloralt:37,markers:37,markeveri:37,markup:26,marocchino2018:22,marocchino:22,marques2019:2,marques2021:2,marsh:2,marta:2,martin:2,maser:2,mask:25,maslarova:2,mass:[0,4,9,11,12,13,14,21,24,34,37],massimo2016:22,massimo2018:2,massimo2019:2,massimo2020a:[2,12],massimo2020b:[2,10],massimo2022:[2,23],massimo:[2,3,13,22],massimoppcf2019:13,massiv:[5,6,9,47],massless:34,masson:2,master:29,match:[4,5,10,32,34,45,47],materi:[2,11,12,26],math:[21,24,34,35,37,38],mathbf:[9,10,12,13,14,18,21,22,24,34],mathemat:[2,40,47],mathieu:[2,3],mathrm:[11,14,18,21,24,34,38],mathtt:34,matplotlib:[28,29,31,37],matrix:37,matsukiyo:2,matsushima2003:32,matsushima:32,matteo:2,matter:[0,2,12,37],matur:35,max:[2,11,12,34,37,38,40],max_tim:26,maxim:[8,14,21,34],maximum:[12,14,18,21,25,26,34,38,40],maximum_charge_st:34,maxium:21,maxwel:[0,4,5,8,12,21,22,24,25,34,37,38,42,45,47],maxwell_sol:46,maxwell_solv:[34,46],maxwellian:[9,11,17,25,34],mayr:2,mb:40,mbtis3_mode_1:34,mbw:40,mc:[14,21,33,34],mca:39,mcilvenni:2,mckenna:2,mdl:3,mean:[7,9,13,14,16,22,24,26,27,32,34,35,36,37,40],mean_px:37,mean_veloc:[4,34,36,38],mean_velocity_am:[4,34],meaning:[13,19,22,26,34],meant:34,meantim:16,measur:[2,24],mechan:[2,4,14,18,21,34,40],media:7,mediat:0,medium:[0,7],mei:2,meinhold2021:2,meinhold:2,meliani:2,mem:39,member:[34,42],memori:[4,6,9,16,18,34,37,39,40,42],memory_peak:37,memory_tot:37,mention:[22,35,42],mercuri:2,mercuribaron2021:2,mere:32,merg:[4,15,37,42,47,48],merge_accumulation_correct:34,merge_discretization_scal:34,merge_everi:34,merge_max_packet_s:[18,34],merge_min_momentum:34,merge_min_momentum_cell_length:34,merge_min_packet_s:[18,34],merge_min_particles_per_cel:34,merge_momentum_cell_s:34,mergeparticl:42,merging_method:34,mergingfactori:18,mergingvraniccartesian:18,mergingvranicspher:18,mesa:30,mesh:[5,32,37],messag:[16,40,41,42],metal:0,meth:[2,22],method:[0,4,5,7,9,12,14,22,23,25,32,33,34,37,40,41,42,47],mev:[0,2,11,14,34],mi250:5,mi:10,mice:2,michael:2,michel:[2,12],mickael:[2,3],micro:0,microcoil:2,micromet:2,micron:10,microplasma:2,mid:2,middl:[0,14,38],midinfrar:2,miethling:2,miethlinger2023:2,might:[10,18,29,34,37],miguel:2,mike:2,mildli:[0,47],millijoul:2,million:0,miloshevski:2,miloshevsky2022:2,min:[2,21,34,37,40],min_particle_chi_for_xi:[34,40],min_particles_per_cel:34,min_photon_chi_for_xi:40,mind:7,minenna:2,ming:2,minim:[25,34,40],minimum:[0,16,21,34,40],minimum_chi_continu:[34,42],minimum_chi_discontinu:34,minjian:2,minor:12,minut:[34,40],mira:22,mirror:[0,2],mirzai:2,mismatch:34,miss:[4,35],mitig:[7,9,25,44],mitrofanov2020:2,mitrofanov:2,mix:0,mkdir:39,mm:26,mo:2,mocek:2,mod:21,mode:[0,4,5,13,15,25,26,28,30,32,34,35,37,41,42,47,48],model:[2,4,7,11,15,20,35,40,41,42,44,47,48],moder:[0,47],modern:[25,35],modif:[11,21],modifi:[1,4,9,11,13,16,18,22,24,26,34,39],modul:[0,4,5,12,13,18,21,26,28,29,30,34,37,42,45,47,48],modular:[5,42],moe:35,mohammad:2,mojav:29,moment:[4,14,21,22,24,34,42],momenta:[0,4,10,11,12,13,18,23,34,42],momentum:[0,9,11,12,14,17,21,22,24,34,36,42,47],momentum_i:42,momentum_initi:[4,34,36,38,46],momentum_x:42,momentum_z:42,monitor:11,mono:14,monoenerget:[2,22],mont:[2,4,11,14,34,40,47],monthli:[2,21],mora1997:13,mora:13,morac:2,more:[0,1,4,5,7,8,9,10,11,14,16,18,21,22,23,25,27,31,34,35,37,42,46],moreau:2,moreno:2,moreov:9,most:[0,5,6,7,9,10,11,12,14,18,21,23,25,32,34,35,41,42,46],mostli:[0,10,13,18],motion:[9,12,21,24,34,47],motiv:9,move:[0,4,6,9,13,21,22,27,31,37,42,48],movement:[4,25,34,42],movi:37,moving_x:[34,37],movingwindow:34,movwindow:42,mpi:[0,4,5,8,21,23,26,28,29,31,34,37,39,40,41,47],mpi_rank:37,mpi_thread_multipl:[4,31],mpicc:28,mpicxx:31,mpiexec:39,mpif90:28,mpirun:[28,34,39,40],mpmenta:11,msve:35,mtune:35,mu:[12,14,21,24],mu_0:24,much:[4,6,7,8,12,13,16,21,32,34,42],muller:[7,34],multi:[1,2,4,5,25,34,47],multifoil:2,multipetawatt:[2,14],multiphoton:[4,20,47,48],multiphoton_breit_wheel:34,multiphoton_breit_wheeler_process:14,multiphoton_breit_wheeler_sampl:34,multiphoton_breit_wheeler_t:40,multiphotonbreitwheel:[14,34],multiphotonbreitwheelerfactori:14,multiphotonbreitwheelert:[14,42],multipl:[2,4,10,11,12,18,19,28,42,47,48],multipledecomposit:34,multipli:[4,9,10,11,24,25,32,34,35,37],multiplot:[4,37],multislid:[4,37],must:[0,4,9,10,11,12,16,22,23,24,26,30,34,35,36,37,38,40,41,42],my:[2,34,37,46,48],my_filt:34,my_machine_fil:31,my_namelist:39,my_particl:37,my_prob:34,my_rat:34,my_simul:39,myclassisgreat:42,mydir:37,myfil:38,mygreatfunct:42,mynamelist:34,mynameyear:26,myprescribedprofil:34,myspeci:36,n:[0,1,2,9,10,11,12,13,14,16,25,27,29,34,39,42],n_0:0,n_:[9,10,11,12,13,18,21],n_c:[0,11,25],n_e:[11,21,25],n_i:[11,12],n_p:18,n_part_per_cel:46,n_r:[24,34,38],n_t:32,n_x:[18,32],n_y:[18,32],n_z:[18,32],nabla:[9,13,22,24],nabla_:[9,13,22],nakatsutsumi:2,nam:2,name:[4,9,13,21,26,27,28,32,34,35,37,40,42,46],namelist:[4,7,11,13,16,18,21,22,23,26,31,32,35,36,39,41,42,45,47,48],nan:[34,35,41],nanbu1997:11,nanbu1998:11,nanbu:11,nanohol:2,nanoscal:2,nanosecond:2,nanospher:2,nanostructur:2,nanotub:2,nanowir:2,narrow:[11,18],narrowband:2,nastasa:2,nat:2,natur:[21,24,34],naturali:21,naveen:2,nb_densiti:46,nclang:35,ndim:36,ne:11,nearbi:18,nearest:[10,37],nearli:[0,18],nebula:0,necessari:[0,7,9,10,12,13,18,20,22,23,34,39,41,42],necessarili:[16,37],need:[0,4,5,7,9,10,12,13,16,18,22,27,28,29,31,33,34,37,38,41],neg:[17,21,34],neglect:[11,12,13,21,22,34],neglig:[12,21,22],neighbor:[21,42],neq0:22,neq1:10,nest:23,net:22,network:2,neural:2,neutral:[4,12,17],neutron:4,never:[24,25],nevertheless:10,new_pair:14,newer:31,newest:4,newli:[12,18,21,34],newlin:22,newparticl:[4,48],next:[9,10,11,13,16,21,27,31,34,39],nghiem2020:2,nghiem:2,nguyen:2,nic:40,nice:18,nicer:29,nico:2,nicola:[3,12],nicolai:2,nie:2,niel2018a:[2,21,40],niel2018b:[2,21],niel:[2,34,40,47],niel_computation_method:34,nield:42,nikitin:2,nilsson:2,nishimoto:2,nitrogen:[0,2],nmpi:26,no_mpi_tm:31,node:[21,23,25,42,47,48],nomenclatur:[4,18],nomp:26,non:[0,2,4,10,11,13,21,22,23,28,33,34,37,42],none:[18,21,34,37,38,39,46],nonetheless:[0,14,18,25,34,40],nonlinear:[0,2,13,14,21],nonrelativist:2,nontherm:2,nonumb:25,nonzero:13,noopenmp:31,norm:[18,34,37],normal:[4,7,9,12,13,14,21,24,25,32,34,37,39,40,41],norrei:2,notat:[10,21,34],note:[4,9,10,11,12,13,16,18,21,23,24,25,26,29,32,33,34,35,37,38,39],noth:[21,37],notic:[2,21],notime_saving_compil:35,notion:[14,47],nov:43,novel:2,novemb:2,now:[4,9,10,13,16,18,29,31,33,34,46],np:[40,42],npart:[36,37,42],nr:34,nrestart:26,nrl:11,nrrestart:26,ns:37,nstep:[34,37],nt:34,ntheta:34,ntot_abc:34,nu:[13,21,40],nu_0:11,nu_:11,nu_t:11,nucl:[2,22],nuclear:[2,4,34,47],nuclear_react:34,nuclear_reaction_multipli:34,nuclei:0,number:[0,4,7,9,10,11,12,13,14,16,18,21,23,24,25,26,27,32,33,34,35,36,37,38,39,40,41,42,46],number_dens:[34,36,38,46],number_of_additional_shift:34,number_of_am:34,number_of_am_classical_poisson_solv:34,number_of_am_relativistic_field_initi:34,number_of_cel:[34,37],number_of_el:42,number_of_frozen_particl:37,number_of_particl:37,number_of_patch:[16,34],number_of_pml_cel:[7,34],number_of_process:34,number_of_timestep:34,numberofpiec:37,numer:[2,4,9,10,12,17,18,21,26,34,40,41,42,44,45,47],numpi:[4,10,26,28,29,31,32,34,38],nuter2011:12,nuter:[11,12],nvidia:[4,5,6,31,39],nx:34,ny:[2,34],nz:34,o0:39,o3:35,o5:21,o:[2,10,26,35],object:[5,14,34,37,42],obliqu:2,oblivi:34,observ:[0,2,11,18,21,34],obtain:[0,1,6,9,10,11,12,13,18,21,22,24,25,31,32,34,35,36,40,42,48],occigen:[0,30],occur:[0,4,10,11,12,14,17,18,21,23,26,31,32,34,39,41],ocl:35,octob:2,odd:9,ofast:35,off:[0,4,34,35],offer:[5,40],offload:[5,19,44,47],offset:[32,34,38],often:[0,4,9,18,23,28,34,35,39,42],ok:16,old:[0,4,26,31,42,46],older:[4,34],olena:2,olga:3,olofsson:2,omega:[2,4,7,12,14,18,25,32,34],omega_0:[12,13],omega_:[0,18,34],omega_p:0,omega_r:[14,21,24,34,37],omit:[34,37],omp:[23,35,42],omp_num_thread:39,omp_schedul:[16,23],ompi_cxx:29,omptask:31,onc:[9,10,13,18,22,26,31,37,38,40],one:[0,2,6,7,8,9,10,11,12,13,14,16,17,18,21,22,25,27,29,32,34,35,38,39,40,41,42,48],one_over_mass_:42,one_over_mass_squar:42,ones:[0,13,18,21,25,27,32,34,37,41,42],onli:[0,2,4,6,7,8,9,10,11,12,13,14,16,18,21,22,23,24,26,27,29,31,32,34,35,37,38,39,40,41,42,46],onlin:9,onmi:25,onto:[9,12,13],opac:2,opemmp:23,open:[1,2,4,5,7,26,29,34,41,43,46,48],openacc:0,openmp:[0,4,5,16,21,23,25,26,31,34,35,39,41,42],openmpi:[25,28,29,39],opennamelist:37,openpmd:[3,4],oper:[0,4,8,9,11,13,16,18,22,23,31,32,34,35,37,41,47],oppos:21,opposit:[9,10,18,21,34],opt:[2,13,29,32],optic:[2,12,13,14,21,34,42],optim:[2,4,13,16,25,30,34,45,47,48],option:[4,11,16,18,19,26,29,30,34,45,48],optionn:34,orang:14,order0:38,order1:38,order2:38,order:[0,4,7,8,9,10,11,14,16,21,22,23,25,27,28,29,34,37,38,40,42],orderi:38,org:26,organis:42,orient:[5,16,37],origin:[0,2,9,10,11,13,18,21,25,34,37,41],orlando:2,orthogon:[14,18,21],oscil:[0,2,12,13,18,21,32,34],osipov:2,ospina:2,ot:29,other:[0,4,9,11,13,16,18,19,21,22,23,24,25,26,27,29,31,34,35,39,41,48],otherwis:[0,10,11,12,16,18,21,22,33,34,35,37],ouatu2022:2,ouatu:2,oudin2022:2,oudin:2,oumbarek:2,our:[11,12,33,35,40,42],out:[0,4,7,30,35,37,39],outcom:25,outdat:[28,29],outer:[7,34],outflow:0,outgo:9,outlin:11,output:[4,5,6,21,24,26,27,31,34,35,36,37,39,46],output_dir:4,outsid:[9,18,34,36,37,42],over:[2,4,8,9,10,11,12,13,18,21,22,32,33,34,38,42,47,48],overal:[0,7,18,21,24,32,41],overdens:0,overestim:21,overhead:[8,18,21,25],overlai:37,overlap:[0,8,16],overloadind:42,overrid:37,overrightarrow:11,overview:[11,21,45],overwritten:[34,38],ow:9,own:[0,8,16,27,31,32,34,35,42],p2io:3,p:[0,2,9,11,12,13,14,18,21,22,24,34,37,40],p_0:12,p_3:11,p_4:11,p_:[12,21],p_a:18,p_b:18,p_e:11,p_i:11,p_j:12,p_k:11,p_r:24,p_t:18,p_x:[12,18,21,34,37],p_y:[18,34],p_z:[18,34],pablo:2,pacif:2,pack:18,packag:[4,26,28,29,32,34,37,40],packet:[18,34],pacman:28,pad:37,paddock:2,pae2022:2,pae:2,pagano2020:2,pagano:2,page:[12,14,26,31,34,35,37,40,42],pair:[2,4,5,10,11,18,20,34,37,40,42,44,47],pak2023:2,pak:2,palaniyappan:2,palm:3,pan:2,panchenko:2,panchor:37,pandari:2,panel:[0,12,23],paolo:2,paper:[0,8,10,26,34,44],par:3,paradigm:42,paragraph:[9,21],parallel:[0,2,4,5,8,9,13,18,28,29,31,32,34,41,45,47],parallelepip:34,param:42,paramet:[0,2,4,7,9,11,12,14,17,18,24,34,37,38,40,41,42,47],parametr:25,paraview:4,paraxi:[13,32],parenthesi:11,pars:27,part:[0,10,13,16,21,24,25,32],part_event_tracing_tasks_off:31,part_event_tracing_tasks_on:31,partial:[0,4,9,10,13,21,22,28],partial_:[13,22],partial_i:22,partial_r:10,partial_t:[9,10,13,22,24,32],partial_x:[10,13,22,32],partial_z:22,particip:[1,18,34],particl:[1,2,4,5,7,8,11,12,13,14,15,16,21,22,23,31,37,38,39,40,41,43,44,45,46,47,48],particle_chi:[34,42],particle_chunk:37,particle_numb:42,particlebin:[4,6,21,46,48],particlecr:17,particlediagnost:46,particleinjector:[17,34],particles_per_cel:[34,36,38,46],particul:42,particular:[0,9,12,14,21,26,33,34,39,42],particularli:[0,9,11,18,21,34],partit:[0,39],partli:18,partner:[43,44,45],partwal:[34,42],pasc:2,paschk:2,paschke_bruehl2023:2,pass:[4,16,26,31,34,35,36,37,47],passoni:2,past:30,patch1d:42,patch2d:42,patch3d:42,patch:[0,4,6,8,11,17,18,21,23,25,32,34,37,39,41,47],patch_arrang:[16,34,37],patch_inform:[34,37],patcham:42,patches_:42,path:[21,28,31,34,36,37,38,39,46],pathak:2,paul:2,pavel:2,pe:0,peak:[0,12,14,18,21,25,37],peer:2,pegoraro:2,penetr:[0,2],peng2019:2,peng2020:2,peng2021:2,peng:2,pengji:2,peopl:42,per:[0,4,6,7,12,14,16,18,21,23,25,34,37,38,39,40,41,42],percentag:[21,35],perelomov1966:12,perelomov1967:12,perelomov:12,perez2012:11,perez2021:2,perez:2,perfect:[10,11],perfectli:[4,5,22,34,45,47],perform:[2,4,5,6,9,10,11,13,14,16,18,19,22,30,32,35,38,42,43,44,47,48],performanceinfo:37,period:[0,2,9,12,13,14,21,34,38,46],permit:[35,42],permitt:21,permogorov:2,permut:25,perp:[10,11,12,13,14,18,22],perpendicular:[2,13,21,34],perspect:32,persson:2,perturb:13,peta:2,petawatt:2,peter:2,peterson:2,ph:2,phase:[0,2,4,9,10,14,21,34,37,38],phd:3,phenomena:[10,13],phenomenon:[0,14,18],phi:[10,13,18,21,22,25,32,34,38],phi_:13,phi_i:34,phi_k:18,phi_t:18,phi_z:34,phil:2,philosophi:42,phiy_profil:34,phiz_profil:34,photon:[2,4,5,12,14,20,34,40,42,47],photon_energy_axi:34,phy:[1,2,11,12,13,21,32],physic:[0,2,3,4,5,6,7,10,13,18,21,22,24,26,34,40,42,43,45,47,48],physicist:5,physiqu:3,pi:[0,10,11,12,13,14,18,21,24,34,37,38,40],piazza:[2,21],pic:[0,2,3,5,12,16,17,18,19,20,21,22,23,24,28,32,34,39,41,45,47],picciotto:2,pick:[10,11,12,33],picosecond:[11,14],pictur:42,piec:[0,23,42],pikuz:2,pile:0,pinch:16,pint:[4,28,29,31,37],pip3:29,pipelin:35,pisani:2,pisarczyk2020:2,pisarczyk:2,pishdast:2,piston:[0,21],pittman:2,pla:3,place:[12,22,26,34,39],placehold:[4,37],plagu:9,plai:[0,7,21,34],plan:35,planar:34,planck:47,plane:[0,4,10,12,18,34,37,47],plasma:[1,2,3,4,5,7,9,10,11,12,13,16,17,18,20,21,22,23,24,25,34,43,44],plasmaspher:[0,2],plasmoid:0,plasmon:2,plateau:38,platform:[2,31],pleas:[0,1,5,9,11,18,26,28,29,30,31,34,37,39],pleskunov:2,plot:[4,11,14,21,26,34,40,42,48],plotnikov2018:2,plotnikov2019:2,plotnikov:[1,2,3,9],plott:29,plume:[0,2],pm1:13,pm:[14,21,34,40],pml:[4,6,7,34],pml_:7,pml_kappa:34,pml_sigma:34,png:37,poincar:21,point:[4,9,10,11,12,13,18,21,25,32,33,34,35,36,37,38],pointer:42,poisson:[4,9,11,34,41,42,47],poisson_error_max:46,poisson_iter_max:46,poisson_max_error:[34,46],poisson_max_iter:[34,46],polar:[0,2,4,10,12,14,18,21,34,47],polarization_phi:[34,46],polarizationphi:46,pole:18,polygon:38,polynomi:[21,25,34,38],pond:13,ponderomot:[0,2,10,21,34,47],ponderomotive_bori:34,ponderomotive_borisbtis3:34,ponderomotive_dynam:4,ponderot:21,popescu:2,popov:12,popul:[0,11,12,42],port:[6,29],portion:[0,16,32,34,42],posit:[4,7,9,10,11,12,14,17,18,21,22,23,27,32,34,36,37,38,42,47],position_i:42,position_initi:[34,36,46],position_x:42,position_z:42,positon:40,positron:[0,14,18,21,34,40],possibl:[4,7,8,12,14,16,18,22,31,33,34,35,37,38,39,42],post:[3,4,5,29,31,34,41,45,48],posteriori:24,postprocess:48,potenti:[2,10,11,12,13,21,22,23,34,35],pour:3,pow:2,power:[0,2,6,7,11,16,21,25,34,37,40],poyi:[4,34],poyinst:4,poynt:[4,24,34],poyx:[4,34],poyxmin:[24,34],poyxmininst:[24,34],poyz:[4,34],pp:2,ppc:[4,25],practic:[12,47],pragma:[0,35,42],pragu:43,pratic:21,pre:[0,4,21,34,40,42],precaut:42,precenc:0,precis:[16,21,25,27,34,35,37,40],predefin:26,predict:[12,21],prefix0:37,prefix1:37,prefix:[26,28,29,37],preliminari:[0,14],prepar:[4,37],preprocess:[34,45],prescrib:[4,9,12,18,32,48],prescribedfield:[4,34],presenc:[0,9,10,12,13,21,34,41],present:[0,1,4,9,10,12,13,14,18,21,22,23,25,28,32,34,41,42],preserv:[14,21],press:12,pressur:[0,2,21,23,34,40],prevent:[4,7,23,34,37],previou:[0,4,9,10,13,14,18,21,22,26,34,36,37,39,41],previous:[0,4,18,37,42],previuo:10,primal:[9,47],prime:32,primit:7,princip:12,principl:[10,42],print:[30,31,34,37,40,41],print_everi:[34,39,41],print_expected_disk_usag:34,printout:4,priori:24,privat:[29,42],private_integer_:42,probabl:[11,12,14,40,42],probe:[4,6,9,10,46,48],probeinfo:37,probenam:37,probenumb:37,problem:[18,22,34,39,41,47],problemat:33,proc:[2,27,37],proce:[11,12,33],procedur:[12,22,29],proceed:[2,13],process:[0,2,4,5,6,8,9,11,12,13,14,18,20,21,23,25,26,29,31,34,39,40,41,42,45,47,48],processor:[2,4,16,21,25,27,30,31,35,39],prod:11,produc:[0,2,14,21,26,34,35,37],product:[2,4,5,11,14,18,21,28,34,35,40],proection:42,profil:[0,2,4,5,7,10,12,14,21,31,32,34,41,45],program:[2,16,23,35,41,42],progress:[3,7,14,21,34,41,42],project:[0,2,5,9,12,13,17,21,23,25,34,37,42,44],projector:[5,10,25,42],propag:[0,2,4,7,10,12,13,18,22,34,37,45,47],proper:[4,13],properli:[4,12,22,41],properti:[17,18,34,37,42],proport:[0,21,24,32],propos:[9,12,13,16,18,21],propto:21,protect:[1,42],protocol:[16,39],proton:[0,2],prouveur:3,provid:[0,3,4,5,7,9,10,11,12,14,16,17,18,19,21,22,23,24,26,28,29,30,31,32,34,35,37,38,40,41,42,48],ps:[0,2],pseudo:5,psikal2021:2,psikal:2,public_integer_:42,publish:[0,1,2,7,23,25,41],pucci:2,pukhov:2,pull:[0,26,41],puls:[0,2,10,12,13,14,21,32,34],pulsar:0,pump:[0,2],pure:[0,10,21],purg:30,purpos:[1,2,5,7,9,13,21,27,34],push:[0,4,10,21,23,26,34,42,47],pusher:[4,5,9,12,13,14,21,25,34,46],pusherbori:42,pusherborisnr:42,pusherborisv:42,pusherfactori:42,pusherhigueracari:42,pusherphoton:42,pushervai:42,pusztai:2,put:[4,37],puyuelo:2,pw:2,pwfa:0,px:[18,34,36,37],pxsm:42,py38:29,py:[14,18,21,26,31,34,36,37,39,40],pysm:42,python38:29,python3:[4,28,29],python:[4,5,18,24,26,28,29,30,31,32,37,39,41,42,48],pythonex:[28,29,31],pz:[34,36,37],pzsm:42,q:[0,2,9,11,13,34],q_1:11,q_2:11,q_3:11,q_4:11,q_:[9,13],q_e:11,q_i:11,q_r:24,q_w:11,qed:[2,4,5,14,21,47],qi:2,qiangyou:2,qianqian:2,qopt:35,qs:12,qt:30,quad:[10,11,22,24,38],quadrant:21,quadrivector:22,qualiti:[2,7],quantiqu:21,quantiti:[9,10,11,13,18,22,34,37,38,47],quantities_doubl:37,quantities_uint:37,quantum:[2,12,14,18,20,34,40,42,47],quasar:0,quasi:[0,12,21,47],quasilinear:2,quasiparallel:2,quasistationari:2,quesnel1998:13,quesnel:13,question:11,quick:35,quickli:[0,4,11,12],quinn:2,quit:28,quiver:12,quot:31,r0:34,r1:34,r:[2,4,9,10,11,12,13,21,22,26,34,37],r_0:12,r_1:12,r_:[9,13],r_e:21,r_j:13,race:[23,42],rad:21,rad_norm_energi:42,radi:21,radial:[7,10,13,34],radian:[34,37],radiat:[0,2,4,9,14,20,23,40,47,48],radiated_energy_loc:42,radiatif:21,radiation_max_emiss:34,radiation_model:[21,34],radiation_photon_gamma_threshold:34,radiation_photon_sampl:34,radiation_photon_speci:34,radiation_t:[40,42],radiation_tables_:42,radiationcorrlandaulifshitz:[21,42],radiationfactori:[21,42],radiationlandaulifshitz:[21,42],radiationmontecarlo:[21,42],radiationniel:[21,42],radiationreact:[21,34],radiationspectrum:[4,21,48],radiationt:[21,42],radiationtool:42,radio:[0,2],radiu:[10,21,24,34],raffestin:2,rai:[0,2],rajat:2,raman:2,ramp:[34,38],ramsai:2,ran:[0,11],randolph:2,random:[2,4,11,12,14,17,18,21,33,34],random_se:34,randomli:[2,9,11,12,18,34,40],rang:[0,2,5,7,12,14,21,34,37,40,43],rank:[21,34,37],rapidli:[14,21,34],rare:[34,35],ratan:2,rate:[0,2,4,11,13,14,34,40,47],rather:34,ratio:[0,9,11,12,13],raw:[29,37,42],raynaud:2,rayonn:3,rb_:10,rcl:32,re:[2,4,10,13,34,37],reach:[0,2,9,10,11,14,19,21,25,34,37],reachabl:14,reactant:[11,34],reaction:[2,4,5,14,20,40,41,42,47,48],read:[4,11,12,13,14,18,21,24,26,31,32,33,34,37,39,40,41],readi:41,real:[4,9,10,11,13,21,32,34],realiss:0,realist:[2,11],realiz:[7,32],realli:10,rear:21,reason:[13,14,16,17,18,32,33,40],recal:16,recent:[0,5,6,21,25,28],recherch:3,recogn:[10,16,21,27,34],recoil:21,recombin:11,recommend:[4,6,11,13,16,21,29,31,34,35,39,47],recompil:[35,39],recomput:[4,9],reconfigur:[25,34,42],reconfigure_everi:34,reconnect:[2,44],reconsid:8,reconstruct:[10,21],record:[4,11,34],recov:32,recreat:12,rectangl:[11,16],rectangular:[8,11,34,47],rectilinear:34,recurs:23,red:[0,10,11,12,13,14],redistribut:1,redondo:2,reduc:[0,4,8,9,10,13,15,16,18,21,22,34,41],reduct:[2,42],ref:[11,12,34],refactor:[25,35],refer:[0,5,9,14,16,25,26,30,34,35,37,38,39,41,44,47],referenc:37,reference_angular_frequency_si:[21,24,34,37,46],referenceangularfrequency_si:46,refin:9,refl:46,reflect:[0,2,7,9,21,27,34,46],reflux:21,regard:7,regardless:34,regim:[0,2,12,47],region:[0,2,8,14,16,18,25,34,38,42],region_ghost_cel:34,regist:[21,25,35],regress:25,regul:0,regular:[4,17,21,34],regular_numb:34,regularli:[4,9,34],rehwald:2,reichwein:2,reinovski:2,reintroduc:7,reject:33,rel:[6,11,12,18,21,34,37,42],relat:[0,4,5,6,10,13,18,21,22,34,42,44],relativisitc:0,relativist:[2,4,5,9,11,12,13,15,33,34,41,42,43,44,47],relativistic_field_initi:34,relativistic_poisson_max_error:34,relativistic_poisson_max_iter:34,relax:[0,2,7,11,23],releas:[0,31,44,45],relev:[0,2,11,34],reli:[0,9,12,29,34,35],remain:[0,6,9,13,21,25,34],rememb:[10,22,34,41],remind:39,remov:[4,7,9,10,18,31,32,34,37,46],render:[6,25,37],reopen:41,reordor:35,reorgan:42,rep:2,repeat:[16,25,34],repetit:[32,34],replac:[27,34,37,42],report:[0,2,21],repositori:[26,30,40,42,44],repres:[0,10,11,12,13,14,16,21,23,27,32,34,37,40,42],represent:27,reproduc:[0,12,18,20,21],request:[4,9,11,24,26,34,37,42],requir:[0,7,8,9,10,14,18,20,21,22,25,26,27,28,30,31,32,33,34,35,36,37,38,39,40,42,46,47],rescal:37,research:[2,21],reset:[37,42],residu:12,resiz:42,resolut:[7,37,41],resolv:[0,7,11,24,34],resourc:[0,4],respect:[0,9,10,12,13,14,21,23,24,32,34,38,40,42],ressourc:3,rest:[12,14,22,34],restart:[4,9,26,28,33,34,37,42],restart_dir:34,restart_numb:[4,34],restrict:[16,34,35],restructuredtext:26,result:[0,1,4,7,9,10,11,12,13,14,21,22,24,25,26,28,32,34,35,36,37,39,42,47,48],results_path:37,retain:13,retent:2,retriev:13,reus:24,rev:[2,11,12,21],reveal:14,revet:2,review:[2,13,21],revil:2,rewrit:22,rewritten:22,rezaei:2,rho:[9,10,13,22,24,34,37,42],rho_abc:34,ribeyr:2,riconda:[1,2,3],ridger:[21,34],ridgers2017:21,right:[0,9,10,11,12,13,14,18,21,22,23,25,32,33,34,37,40,42],rightarrow:[11,14,21],ring:2,ringuet:3,rise:[12,13,14],risk:42,ritu:[14,21,40],ritus1985:21,rm:[0,7,11,12,21,25,34],rmax:34,robert:2,robust:0,rocca:2,rohrlich1954:11,rohrlich:11,role:[0,2,7,16,21,34],rolf:2,romagnani:2,romanskii:2,rome:[30,35],room:41,root:40,rossi:22,rotat:[2,21,32,34],rough:11,row:[11,34],royal:[2,21],rozhko:2,rpa:21,rpath:28,rss:37,rst:26,ru:2,ruan:2,rubi:29,rubov:2,ruch:30,rudimentari:18,rule:[1,7,9,10,16,25,35,48],run:[0,4,5,10,11,12,14,15,16,18,19,21,23,25,26,29,34,35,45,48],runalldiag:42,runenvelopemodul:42,runrelativisticmodul:42,runtim:[32,34,42],russel:2,russian:3,ruxin:2,ruyer2020:2,ruyer:2,rvert:13,ryabchuk:2,ryan:2,ryu:2,s:[0,1,2,3,4,5,6,7,8,9,11,12,13,14,17,18,21,23,24,25,28,30,32,34,35,37,38,39,40,42,46,47,48],s_:34,s_y:34,s_z:34,sabrina:2,saclai:3,safe:9,sai:[37,39],sakai2023:2,sakai:2,salt:16,same:[0,7,8,9,10,11,12,13,14,16,17,18,21,22,23,24,25,26,32,34,35,36,37,38,39,41,42],sampath2021:2,sampath:2,sampl:[2,4,9,11,12,13,14,21,32,34,45],san:2,sandi:21,sang:2,sangal:2,santo:2,sarto:2,sasorov:2,satisfactori:21,satisfi:[9,12,18,32,34,37,41],satur:[18,23,34],satyabrata:2,save:[4,21,34,37,42],savea:37,savin:2,savoini:2,sb:[0,2],scalabl:44,scalar:[0,4,6,10,13,24,25,32,41,42,48],scalasca:31,scale:[0,2,10,11,12,13,21,23,24,33,34,37,47],scan:[2,37],scatter:[0,2,14,47],scenarii:[18,25],scenario:[0,18],schaumann:2,schedul:[16,23,42],schemat:[25,42],scheme:[0,2,4,5,10,13,16,21,25,34,47],schmidt:11,schmitz2023:2,schmitz:2,schnittman:33,scholar:2,schramm:2,schroeder2014:12,schroeder:12,schwinger:[14,21],sci:2,scienc:[2,3,13],scientif:2,scientifiqu:3,scilimits_i:37,scilimits_x:37,scipi:29,scope:42,screen:[4,22,48],script:[4,18,26,29,30,31,37,42,48],sdmd:[4,8,34],search:40,sec:21,second:[0,2,9,10,12,13,14,18,21,23,33,34,37,38,39,40,42],secondari:11,section:[0,5,9,10,11,12,13,14,18,21,26,34,35,40,41,42],see:[0,2,4,8,9,10,11,12,13,14,16,18,21,23,26,29,30,32,34,35,37,38,40,41],seed:[0,4,18,21,34],seem:[6,39,42],seen:[9,10,14,21,23,42],segfault:[4,42],segment:4,seidel:2,select:[2,4,21,25,29,32,33,37,40,42,48],self:[0,2,9,13,26,34],semi:21,send:16,sens:10,sentoku2008:11,sentoku:11,seong:2,separ:[4,9,12,13,16,21,23,34,35,37,42],separatrix:0,sequenc:[16,23],sequenti:34,ser:[2,21],serer:42,seri:[13,25,33,34],serial:40,serif:37,set:[4,5,6,7,9,10,11,12,13,14,16,21,22,23,24,25,27,29,34,35,36,37,39,40,41],set_:37,settl:0,setup:[10,21,22,30,47,48],sever:[2,4,7,10,11,14,16,18,19,21,23,26,29,31,32,33,34,37,38,39,40,42],sgattoni:2,sh:39,shai:2,shape:[2,4,9,12,16,21,25,34,36,37,39],share:[16,18,26,28,29,31,35],sharedlib:28,sharp:[2,13,34],shea:2,sheath:21,sheet:[0,2],shekhanov2021:2,shekhanov:2,shell:12,shen:2,sheng:2,shi2021a:2,shi2021b:2,shi:2,shift:[7,10,34,42],shirui:2,shiyou:2,shock:[2,18,44,47],shorten:42,shorter:[21,23,34],shou2021:2,shou:2,should:[0,2,4,10,11,12,16,22,25,26,29,31,34,35,41,42],show:[0,9,10,11,12,14,16,18,21,23,25,26,29,37],show_multiphoton_breit_wheel:40,show_nonlinear_inverse_compton_scatt:40,shower:18,shown:[0,9,10,11,12,13,14,18,21,22,23,25,34,37,42],shrink:37,shuffl:11,shutov:2,si:[21,24,34,37,41],side:[0,2,7,11,13,14,21,34,37],sidewai:4,sidorov:2,siena:2,sigabrt:42,sigma:[7,11,34],sigma_:12,sigma_r:7,sigma_x:7,sigmoid:2,signal:[13,34,42],signatur:2,signific:[1,12,14,23,34,37],significantli:[0,12,18,33],silver:[7,9,34],sim:[0,11,12,14,18,21,34],sim_length:46,sim_tim:46,simd:[2,5,21,34,35,42,47],simeq:[0,12,21],similar:[2,7,10,11,14,18,21,23,25,32,34,37,41,42],similarli:[9,10,13,20,21,22,34],simino:[2,3],siminos2021:2,simon:2,simpl:[2,3,9,10,13,21,26,39,41,42],simplest:39,simpli:[8,10,11,14,16,21,25,26,27,32,34,42],simplifi:[16,18,22,34,42],simul:[1,2,3,4,5,7,8,10,11,12,13,14,15,16,17,19,22,23,24,26,27,32,34,36,38,39,42,43,44,46,47,48],simulation_tim:[34,38,46],simultan:48,simwindow:42,sin:[4,10,11,18,32,34,38],sinc:[4,10,11,12,13,14,18,21,23,25,34,35,42],singh2022:2,singh:2,singl:[0,2,4,7,11,12,16,17,18,19,21,34,35,37,38,40,42,47],sinha2019:2,sinha2020:2,sinha:2,sircomb:2,sironi:2,site:[0,31],situat:[0,12,13,15,16,18,21,23,24,34],size:[0,2,7,8,9,10,13,16,18,20,23,24,25,27,32,34,36,37,38,40,42],skidmor:2,skin:0,skip:34,skipanim:37,skylak:[25,30,35],slab:[0,2],sladkov2021:2,sladkov:2,slice:[16,34,46],slide:37,slider:[4,48],slight:34,slightli:[7,14,18,21,29],slope1:38,slope2:38,slow:[11,18,21,23,31,33,34,39,41],slower:[0,18,31],slowli:[0,11,13,14,21],small:[8,11,13,16,18,21,25,31,34,42],smaller:[0,6,12,13,14,16,18,21,23,34,42],smallest:[16,18],smet:2,smetanina:2,smilei:[0,3,5,6,7,8,9,10,11,12,13,14,16,18,19,21,22,23,24,25,27,28,30,31,32,33,35,37,40,41,43,44,45,46,47,48],smilei_mpi_rank:34,smilei_mpi_s:34,smilei_openacc_mod:42,smilei_r:37,smilei_rand_max:34,smilei_t:[14,21,34,40,48],smilei_test:[29,39,41],smileicxx:31,smileid:37,smileid_r:37,smileimpi:42,smileip:[4,29,31],smooth:2,smoothen:0,smpi:42,so:[0,9,10,11,12,14,16,18,20,21,22,25,26,30,31,33,34,35,39,42],soc:[2,32],societi:[2,21],socket:16,soft:2,softwar:[1,16,29,31],solar:[0,2],solid:[0,11,12,21,47],solut:[10,18,22,23,32,42,47],solv:[4,5,8,9,10,12,13,18,21,22,34,37,42],solve_poisson:34,solve_relativistic_poisson:34,solvemaxwel:42,solver:[0,4,5,8,10,25,34,41,42,47],some:[0,4,9,11,16,18,21,22,23,24,25,28,29,30,31,32,34,35,37,39,40,41,42],some_data:36,some_fold:36,someth:41,sometim:[4,16,21,24,27,42],somewhat:[11,31],song:2,sonu:2,soon:7,sort:[2,4,17,18,25,27,34,37,42],sorted_a:37,sourc:[1,2,5,10,13,18,26,34,39,40,42,43],sov:12,soviet:21,space:[0,2,7,10,11,12,13,16,18,21,24,32,34,37,42,47],space_envelop:34,space_profil:34,space_time_profil:34,space_time_profile_am:34,spacecraft:[0,2],span:18,spars:18,spatial:[0,2,9,12,13,16,21,24,34,42],spatio:[2,34],spatiotempor:2,spawn:23,spec:42,speci:[4,9,10,11,12,13,14,15,17,18,21,23,24,25,37,38,41,47,48],special:[0,9,11,24,34],specialist:5,species1:34,species2:34,species_typ:46,speciesfactori:42,speciesh:42,speciesnorm:42,speciesnormv:42,speciesv:42,speciesvadapt:42,speciesvadaptivemixedsort:42,specif:[0,7,10,15,18,20,21,24,25,29,31,35,37,38,40,42],specifi:[9,21,34,35,42,48],specka:2,spectra:[0,2,14,18,21],spectral:[0,4,5,8,13,34,37],spectrum:[0,2,12,14,21,32,34,37,40],specular:[9,34],sped:0,speed:[0,2,9,10,11,13,14,18,21,22,23,24,25,34],speedup:[4,23],speficifi:34,spent:[23,25,37],sphere:34,spheric:[4,34,47],sphinx:[26,28,29,31,42],spier:2,spiers2020:2,spike:21,spline:21,split:[8,16,21,23,35,37],spontan:14,spot:0,spread:[11,12,21,22,23],spuriou:[0,17,32,34],sqrt:[9,11,12,13,14,18,21,22,32,33,40,42],squar:[11,38],sr:2,src:[14,18,21,42],srun:39,ss:26,st:12,stabil:[7,25],stabl:4,stack:[31,37],stage:[2,9,14,25],stagger:[0,9,38],stagnat:11,stai:34,stamped:30,stampede2_knl:30,stampede2_skylak:30,stancek:2,stand:[2,10,34],standard:[3,4,8,10,12,13,21,22,34,35],stanislav:2,star2:11,star:[4,11,12,34,38],starodubtsev:2,start:[0,2,9,11,12,14,18,21,22,23,33,34,37,38,39,40,42,48],state:[0,2,4,5,10,11,12,25,34,42],statement:21,statist:[11,12,14,24,34,36],statu:26,std:42,steadi:[0,2,18],stencil:[8,13,34],step:[9,10,12,13,14,18,21,25,31,34,35,37,41,42],stepanov:2,still:[0,8,9,11,12,21,34,42],stimul:[0,2],stochast:[2,34,40,47],stop:[0,9,11,34,37,41],stope:42,storag:16,store:[10,11,14,16,21,26,32,34,37,39,42],storei:2,str:37,straight:10,straightforward:[13,32],strang:41,strategi:[2,23,42],streak:48,stream:[0,2],streamabl:39,strength:[14,21],strengthen:17,strict:35,strictli:34,stride:46,string:[26,34,37],strip:12,strong:[0,2,11,14,18,21,23],strongest:[18,21,32],strongli:[0,2,16,18,21,25,33,34],structur:[0,2,11,14,16,17,21,23,27,34,36],studi:[0,2,5,21,25,43],stuff:34,stutman:2,style:34,style_i:37,style_x:37,su:2,sub:[2,34,42,47],subcrit:2,subcycl:2,subdirectori:34,subdivid:18,subgrid:[4,34,42],subject:[9,12,18],submit:[26,30],subnanosecond:2,subpicosecond:2,subplot:14,subsequ:[1,11],subset:[37,46],substanti:[0,13],substitut:[11,13,14,34],subtl:27,success:[11,25,31,36,37,42],successfulli:[5,25,31,41],sucept:13,sudo:[28,29],suffici:[9,10,14,16,17,25,32],suffix:34,suggest:[0,4,11,34],suit:[10,26],suitabl:[13,21,35,41],sum:[4,9,10,11,16,25,32,34,37,42,46],sum_:[9,10,11,12,13,18,25,32],sum_i:38,sum_j:38,sum_k:38,sum_p:[9,13],sum_px:37,sumdens:42,summar:[9,16,21,25,32,34,42],summari:[34,42],summaris:21,summat:13,sun:2,sundstrom2022:2,sung:2,supercomput:[0,4,6,16,19,31,39,45],supercrit:2,superimpos:[21,22,34],superimposit:42,superposit:10,supp:46,support:[0,3,4,5,6,7,16,31,34,35,37,39],suppos:[14,21,32],suppress:[9,34],supra:0,sure:[34,37,39,41],surf:2,surfac:[0,2,21,24,34],suscept:[0,4,7,34,37,42,47],sustain:0,sve:35,sycl:31,symmetr:[0,4,9,10,14,37,40],symmetri:[10,34],sync:[4,37],synchortron:40,synchron:[8,16,17,42],synchronis:42,synchronz:37,synchrotron:[2,47],syncrhon:42,synergist:2,synopsi:[44,45],syntax:[4,7,26,34,35,37,39,45],system:[2,4,9,10,13,18,21,26,28,37,40],t0:38,t:[0,1,2,9,10,11,12,13,14,18,22,25,26,32,34,37,38,40],t_0:[0,34,38],t_2:0,t_:[9,11,25,34],t_e:11,t_i:11,t_r:[24,34],t_v:25,tab:42,tabl:[2,4,21,25,26,31,34,45,47],table_path:34,tables_1024:40,tables_256:40,tables_512:40,tabletop:2,tabul:[11,21,33,34,42],taegyu:2,tag:[4,18],tail:0,tailor:2,take:[0,4,9,10,11,12,13,16,21,25,33,34,38,42],taken:[0,11,13,17,24,27,32,34],tamburini2010:21,tamburini:[2,21],tanaka:2,tar:28,tarbal:31,target:[0,2,12,21,30,34,35,38,40,42],tarisien:2,task:[2,6,16,31,34,45],taskgroup:42,taskwait:42,tatomirescu:2,tau:[14,21,42],tau_:21,tau_f:[14,21],tau_l:12,taylor:10,tconstant:[34,38],tcosin:[34,38],team:[10,31,39,42],techniqu:[0,8,9,11,12,13,19,21,22,32,34,45,47],technol:2,technolog:16,tell:[31,34,35],temp:42,temperatur:[0,2,9,11,21,33,34,36,38],tempor:[0,2,4,9,13,14,24,32,34],temporar:42,temporari:[14,22,34,42],ten:[0,10,12,13],tend:[0,21,25],tenth:0,terahertz:2,terawatt:2,terent:12,term:[0,1,9,10,12,13,16,18,21,22,24,32,34],termin:[26,28,29,30,31],terminolog:16,terzani:[12,13],tessel:16,test:[0,4,5,6,14,16,18,21,25,26,29,34,35,41,47,48],text:39,textrm:[10,11,13,24],tfrac:[9,13],tgaussian:[34,38],tgcc:[0,25],than:[0,2,4,7,9,12,13,14,16,18,21,22,24,25,34,35,40,42],thank:[0,3,25],thei:[0,4,7,9,10,11,13,14,16,17,18,19,21,22,24,26,27,31,34,35,37,38,42],them:[0,4,10,14,18,23,24,26,28,34,37,41,42],themat:42,themselv:[11,39],theor:2,theoret:[2,9,11,12,13],theori:[2,11,21],therebi:0,therefor:[7,8,10,13,14,16,17,18,21,31,34,39,40,42],thermal:[0,4,9,11,23,34],thermal_boundary_temperatur:[34,46],thermal_boundary_veloc:[34,46],thermt:46,thermveloc:46,thesi:[3,34],theta:[9,10,11,18,32,33,34,37],theta_k:18,theta_t:18,thi:[0,1,2,4,5,7,8,9,10,11,12,13,14,16,18,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,42,46],thick:[0,7],thiel:[2,3,32],thiele2016:32,thiele2019:2,thin:[2,12,47],thing:[24,26,34],thinspac:13,third:[0,2,37,42],thoma:[2,11],thomson:2,thoroughli:13,those:[0,12,16,22,26,30,34,37,42],though:[18,19],thought:42,thousand:12,thread:[0,4,21,23,25,26,28,29,34,39,41,42,47],three:[0,9,10,11,12,21,26,32,34,37,38],threshold:[2,14,34,40],through:[0,2,5,7,9,10,11,12,13,16,21,22,34,35,37,41,42],throughout:[21,25],throughput:6,thrown:42,thu:[0,4,5,9,10,11,12,13,16,18,22,32,34,42],thumb:[7,10],tick:37,tico:2,tightli:[13,32],tikhonchuk:2,tild:[10,12,13,32,34],tile:16,tilt:4,tim:2,time:[0,2,4,5,7,8,10,11,12,13,14,15,16,17,18,21,22,23,24,25,26,27,32,35,38,42,47,48],time_averag:[4,34],time_du:42,time_envelop:34,time_fields_frozen:34,time_frozen:[4,34],time_integr:34,time_prim:42,time_profil:[34,38],time_start:34,time_unit:37,timer:[4,31,34,37,42],timer_collis:37,timer_dens:37,timer_diag:37,timer_envelop:37,timer_glob:37,timer_loadb:37,timer_maxwel:37,timer_movwindow:37,timer_particl:37,timer_partmerg:37,timer_syncden:37,timer_syncfield:37,timer_syncpart:37,timer_syncsuscept:37,timer_tot:37,times10:[0,12,21],times6:16,times8:16,timestep:[0,4,9,10,11,12,13,18,32,34,41,48],timestep_over_cfl:34,timmi:2,timokhin2010:21,timokhin:21,tip:[2,47],tis3:[0,4,9,34],titl:[4,26,32,37],title_font:37,tnsa:[2,21],todai:2,tofrom:42,togeth:[9,16,21,27,37],toledo:2,toledoredondo2018:2,toma:2,tomassini2017:12,tomassini2021:2,tomassini:[2,12],tommaso:[2,3],tong:2,too:[4,16,20,21,26,27,32,34,40,42],tool:[4,5,9,14,21,29,34,40,48],top:[0,4,12,25,34],topic:2,tornado:25,tosca:2,tot:14,total:[0,9,10,11,12,14,16,18,21,25,27,28,32,34,36,37,40],total_load:37,touch:0,tovtk:37,toward:[0,2,21,32],tpolygon:38,tpolynomi:38,trace:31,track:[4,34,37,45],track_:46,track_filt:46,tracked_particl:37,trackparticl:[4,6,36,48],trackparticlesdisordered_:27,trackparticlesdisordered_abc:34,trackparticlesdisordered_myspeci:36,trad:[30,35],tradit:16,tradition:16,trail:42,train:[0,2,43],trajectori:[0,9,21,34,37],tran:2,transact:13,transfer:[0,2],transform:[22,26,32],transit:[0,2],translat:[11,34,47],transpar:[2,4,37],transport:[0,2],transrelativist:2,transvers:[7,11,12,13,21,22,34,47],trap:0,trapezoid:38,trate:42,travel:[7,14,18,21,42],travers:11,treat:[0,12,13,14,16,21,34,42],treatment:[0,9,10,12,13,16,21,23],tree:42,trend:6,tri:9,trick:9,tricki:42,trickier:7,trigger:[14,18,25],trivial:42,troubleshoot:[45,48],trunk:2,tsin2plateau:38,tst1d_00_em_propag:26,tst1d_09_rad_electron_laser_collis:21,tst1d_10_pair_electron_laser_collis:14,tst1d_18_radiation_spectrum_chi0:21,tst2d_02_radiation_pressure_acc:23,tst2d_08_synchrotron_chi1:21,tst2d_09_synchrotron_chi0:21,tst2d_10_multiphoton_breit_wheel:14,tt:13,ttrapezoid:38,tunabl:2,tune:[7,18,31,34,35],tunnel:[2,4,12,34,44],tunnel_envelope_averag:34,turbul:0,ture:0,turn:[4,9,10,14,18,21,34,35],tutori:[43,45,48],twice:[4,10,12,21,34],twist:2,two:[0,2,4,8,9,10,11,12,13,14,16,18,21,25,27,32,34,35,37,38,39],twopi:38,type:[2,4,11,12,16,29,30,34,35,37,42],typic:[0,7,9,11,12,16,20,21,25,32,34,42],typo:[4,11],u:[2,7,9,10,11,13,14,21,33],u_1:33,u_2:33,u_:14,ubal:[4,34],ubal_norm:34,uelm:[24,34,41],uelm_bnd:[24,34],uelm_ex:34,uelm_inj_mvw:34,uelm_out_mvw:34,uexp:34,uhi:2,uint64:27,uint64_t:42,ukin:[4,24,34,41],ukin_abc:34,ukin_bnd:[4,34],ukin_inj_mvw:34,ukin_new:34,ukin_out_mvw:34,ulrich:2,ultra:[0,2,12,47],ultrafast:2,ultraintens:2,ultrarelativist:2,ultrashort:2,ultrathin:2,um:37,umbwpair:34,umi:42,umr:3,umstadt:2,umstadter2022:2,umx:42,unalt:13,uncent:10,unchang:[4,24],uncontrol:18,undefin:[10,34],under:[0,1,2,13,14,21,22,34,37],underdens:0,underflow:4,undergo:34,underli:[9,10,21,41],underlin:9,underscor:42,understand:[16,19,26,34,42,45],understood:[21,25],undul:2,uneven:34,unexpect:2,unfortun:[16,42],unifi:2,uniform:[2,12,14,18,21,22,23],uniformli:9,uninstall_happi:31,uniqu:27,unit:[2,4,6,9,11,12,13,16,21,23,25,29,34,41,42,45,46,47,48],univers:[3,16],unknown:[13,24],unless:[21,31,37],unlik:6,unmagnet:0,unnecessari:27,unphys:[22,34],unproven:35,unread:42,unrol:35,unset:34,unsign:42,unstabl:[0,4,39],unsupport:4,until:[11,12,16,33,34,37],untouch:34,unus:34,unusu:34,uou:41,up:[0,2,3,4,7,10,11,12,14,18,23,25,26,34,38,41],updat:[4,10,13,14,21,26,29,42,48],upgrad:29,upper:35,upstream:0,urad:[4,34],urad_abc:34,url:1,us:[1,2,4,5,6,7,8,9,10,11,12,13,14,16,17,18,21,22,23,24,25,26,27,29,30,31,32,33,34,35,37,38,40,41,42,44,45,46],usa:2,usag:[4,26,32,34,35,37],use_btis3_interpol:34,useless:14,useoffset_i:37,useoffset_x:37,user:[4,5,7,9,11,16,18,19,21,22,23,24,27,30,31,32,34,35,37,40,41,42,43,47],usr:[3,28,29],usual:[9,11,12,13,21,22,23,24,25,31,34,35,39,42],utilis:3,utot:[34,37],v100:5,v3:25,v4:[4,11,25,31],v6:31,v:[2,9,11,12,14,21,24,25,26,34,37,40],v_0:0,v_:11,v_c:[9,13],v_e:11,v_en_:11,v_f:11,v_r:24,v_x:[34,38],v_y:34,v_z:34,vacuum:[0,2,7,13,14,21,34,38],vader:39,vai:[4,9,12,22,34,42],vaisseau:2,vald:2,valentina:2,valeriia:2,valid:[0,4,10,11,12,21,25,32,34,35,42,48],validate_:26,valu:[0,4,8,9,10,11,12,13,14,18,24,26,31,32,33,34,37,38,40,41,42,46,47],vanish:21,varepsilon:[18,21,40],varepsilon_0:24,varepsilon_:[14,21],varepsilon_a:18,varepsilon_b:18,varepsilon_k:18,varepsilon_t:18,vari:[0,13,18,21,25,34],variabl:[7,9,16,21,23,24,32,33,35,37,38,39,40,48],varianc:21,variat:[13,21,34,42],variou:[0,4,5,11,13,16,18,21,25,31,34,37,42],varphi_i:34,varphi_z:34,vasiliki:2,vassura:2,vastli:0,vay2008:22,vecpatch:42,vecspeci:42,vecto:37,vector:[4,5,12,13,14,18,19,21,22,32,37,41,42,44,45,47,48],vectoriz:[18,21,34],vectorpatch:17,veisz:2,veloc:[0,4,9,11,12,13,17,21,22,24,34,38],velocity_x:34,verbos:[26,37,40],veri:[7,8,11,14,16,18,21,34,35,37,39,41],verif:2,verifi:[9,33,34,41],version:[0,4,13,18,22,25,29,31,34,37,41,42,46,47],versu:[11,37],vert:[12,21],vertic:37,veselski:2,vi:21,via:[0,2,14,18,29,31,34,40],video:[0,6,18,25],view:[0,18,21,25,31,37],vinci:[1,2,3],violat:[12,13],vishwa:2,visibl:[1,9,11,18,37],visit:4,visual:[25,26,42],vizman:2,vladisavlevici2022:2,vladisavlevici2023:2,vladisavlevici:2,vlasov:[2,12,47],vmax:37,vmin:37,volp:2,volum:[4,9,13,24,25],von:2,voronin:2,vortic:2,vranic2005:18,vranic:[18,34],vranic_cartesian:34,vranic_spher:34,vs:[11,23,26,37],vsym:[4,37],vtk:[4,30,48],vtune:31,vx:[34,37],vy:[34,37],vz:[34,37],w:[0,2,11,12,34,37],w_3:11,w_4:11,w_:11,w_a:18,w_b:18,w_i:11,w_k:18,w_m:11,w_n:11,w_p:[9,13],w_r:9,w_t:18,w_x:9,w_y:9,wa:[0,3,4,18,25,37],wai:[11,21,23,31,34,36,37,42],waist:34,wait:[16,23,37,42],wake:[0,2],wakefield:[2,10,12,18,44],walder:2,wall:[4,26,48],wang:2,want:[29,34,38,39,40,41],warn:[11,18,34,37,41,42],watch:0,watt:2,wave:[0,2,7,9,10,12,13,18,32,34,47],waveform:2,wavefront:2,waveguid:2,wavelength:[0,12,13,14,21,24,34],wcm:[14,21],wd_:26,we:[0,1,7,9,10,11,12,13,14,16,17,18,21,22,24,25,27,28,29,30,31,32,33,34,35,37,39,40,42],weak:[0,2,14,21],web:26,weber:2,websit:[31,48],wedg:2,wedlund:2,weibel:[0,2,18],weight:[4,9,11,12,14,18,21,34,36,37,42,47],weight_charg:34,weight_charge_vx:34,weight_chi:34,weight_ekin:34,weight_p:34,weight_vx_px:34,weightiest:18,welcom:26,weld:2,well:[0,5,9,10,11,12,13,14,16,18,21,34,42],wen:2,wendel:2,wenjun:2,wenzhao:2,were:[0,1,4,9,25,27,35,41],west:2,what:[10,12,14,21,26,39,41,42],whatev:[18,26,42],wheeler:[2,4,5,20,47,48],when:[0,1,4,7,9,10,11,12,14,16,17,18,21,22,23,24,25,26,33,34,35,37,38,39,42],whenev:9,where:[0,5,7,8,9,10,11,12,13,14,16,18,21,22,23,24,25,27,29,31,32,33,34,35,36,37,39,40,42],wherea:[11,16,25],whether:[34,35],which:[0,5,7,9,10,11,12,13,16,18,21,22,23,24,25,26,27,29,31,32,33,34,35,37,42],white:0,whith:7,whole:[2,5,9,18,25,27,34,38,39,40,42,47],whose:27,why:[13,14],wi:2,wide:[0,2,5,43],width:[12,14,34,38],wiener:21,wildcard:[26,37],willi:2,wilson:2,wind:[0,2],window:[0,4,6,10,22,29,37,40,42,48],wire:2,wish:29,wit:0,within:[0,9,12,25,31,34,37,38,42],withn:25,without:[0,4,11,16,18,21,23,25,31,34,37,42],word:[13,34,42],work:[4,9,11,16,17,18,21,23,32,34,35,36,37,40,41,42],workdir:26,worker:42,workflow:48,workload:23,workshop:[2,43],world:41,worri:23,wors:23,worsen:18,worth:9,would:[0,10,11,12,16,18,21,22,27,32,34,35,42],wrapper:42,write:[10,11,21,25,27,31,32,37,39,41,45,48],written:[5,10,11,12,13,14,22,26,34,39,42],wrong:[4,41],wt:34,wu:2,www:1,wx:34,wy:34,wz:34,x0:38,x1:25,x2:25,x3:4,x86:35,x86_64:28,x:[0,2,4,7,9,10,11,12,13,14,16,18,21,22,23,25,27,32,33,34,36,37,38,40,42],x_0:[32,38],x_:21,x_c:12,x_max:34,x_min:34,x_p:9,xavier:2,xavx:35,xbroadwel:35,xcenter:38,xcode:29,xcommon:35,xcore:35,xcpu:35,xeon:[21,25,35],xfactor:37,xfwhm:38,xi:[14,21,34,40],xi_pow:40,xi_threshold:[21,40],xia:2,xiaohui:2,xie:2,xinlu:2,xknl:35,xlabel:37,xlabel_font:37,xlength:38,xmax:[34,37],xmic:35,xmin:[32,34,37],xml:37,xnumber:38,xorder:38,xphi:38,xplateau:38,xpoint:38,xr:34,xscale:37,xskylak:35,xslope1:38,xslope2:38,xtick:37,xticklabel:37,xticklabels_font:37,xu:2,xuan:2,xueq:2,xuesong:2,xuv:2,xvacuum:[34,38],xvalu:38,xx:[13,34],xxx:31,xxxx:26,xxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz:27,xy:[34,37,38],xyz:37,xz:[34,38],y0:38,y:[0,2,4,9,10,11,13,16,18,21,22,23,27,32,34,36,37,38,40],ya:2,yadong:2,yan:2,yang2023:2,yang:2,yani:2,yanlv:2,yanq:2,yao2021:2,yao2022:2,yao2023:2,yao:2,yazdanpanah:2,ycenter:38,year:3,yee:[5,9,10,34],yellow:0,yet:[5,11,21,22,34,39],yfactor:37,yfwhm:38,yi:2,yield:[0,12,13,14,22,23,34,35],yin:2,ying:2,yinlong:2,yinren:2,yipeng:2,yix:2,ylabel:37,ylabel_font:37,ylength:38,ymax:[4,34,37],ymin:[4,34,37],yoann:2,yonemura:11,yong:2,yoon2019a:2,yoon2019b:2,yoon2021a:2,yoon2021b:2,yoon2023:2,yoon:2,yorder:38,york:2,you:[1,4,10,12,16,22,24,26,28,29,30,31,34,35,36,37,38,39,40,41],young:2,your:[1,10,16,24,28,29,30,31,34,35,37,39,41,47,48],yplateau:38,yscale:37,yslope1:38,yslope2:38,ytick:37,yticklabel:37,yticklabels_font:37,yu:[2,12],yue:2,yugang:2,yulan:2,yun:2,yunhui:2,yuze:2,yvacuum:38,yy:34,yyyyi:27,yz:[10,34,38],z0:38,z:[2,4,9,10,11,12,13,16,18,22,24,27,32,34,36,37,38],zackaria:2,zai:[25,30],zakaria:2,zan:2,zavg_abc:34,zeil:2,zemskov:2,zemzemi2020:2,zemzemi:[2,3],zepf:2,zepter2023:2,zepter:2,zero:[0,9,10,11,12,22,27,34,42],zeros_lik:34,zgadzaj:2,zhang2022a:2,zhang2022b:2,zhang:2,zhao:2,zheltikov:2,zhen:2,zheng:2,zhengxuan:2,zhiguo:2,zhipeng:2,zhizhan:2,zhou:2,zhu:2,zhuo:2,zhusong:2,ziegler:2,zielbauer:2,ziyang:2,zmax:[4,34],zmin:[4,34],zmm:35,znver2:35,znver3:35,zorder:37,zprofil:29,zxvf:28,zz:34,zzzzzz:27},titles:["Highlights","Licence","Publications","Partners","Releases","Synopsis","GPU offloading","Perfectly Matched Layers","Single-domain multiple decompositions","PIC algorithms","Azimuthal modes decomposition","Binary collisions & reactions","Ionization","Laser envelope model","Multiphoton Breit-Wheeler pair creation","Advanced numerical techniques","Parallelization basics","Particle Injector","Particle Merging","Parallelization & optimization","Physics modules","High-energy photon emission & radiation reaction","Field initialization for relativistic species","Task Parallelization","Units","Vectorization","Contribute","Identification of tracked particles","Install dependencies on Linux","Install dependencies on MacOS","Installation on supercomputers","Install","Laser propagation preprocessing","Sampling a Maxwell-J\u00fcttner distribution","Write a namelist","Optimization and vectorization compilation options","Initialize particles from an array or a file","Post-process","Profiles","Run","Generation of the external tables","Troubleshoot","Implementation","Home","Overview","Index","Syntax changes","Understand","Use"],titleterms:{"0":4,"1":[4,18,21],"1024":40,"1d":[14,21],"2":[4,18],"256":40,"2d":[14,21,37],"3":[4,9,18],"3d":[18,37],"4":[4,18],"5":[4,18],"512":40,"6":4,"7":4,"8":4,"case":11,"class":42,"export":37,"function":42,"j\u00fcttner":33,"new":41,"public":[2,26],For:21,If:42,In:46,On:10,The:[9,10,11,13,17,21,22,39,42],acceler:0,accumul:18,acknowledg:3,adapt:25,add:26,advanc:[15,31,37],al:21,algorithm:[9,18],amplif:0,an:36,angl:18,anim:37,antenna:34,approach:23,approxim:13,arbitrari:[21,24],archlinux:28,area:16,argument:37,arrai:36,articl:2,artifact:0,associ:21,assumpt:21,averag:[0,13],axi:10,azimuth:[0,10],b:9,background:32,balanc:[16,34],basic:[16,24],beam:0,below:10,benchmark:[12,14,21],between:16,binari:11,bori:42,boundari:[9,10],breit:[14,34,40],brew:29,brillouin:0,cancel:10,carlo:[12,21,42],cartesian:18,cascad:18,chang:[4,26,46],checkpoint:34,chi:21,choos:21,cite:1,classic:[10,21],cluster:39,code:42,collect:16,collis:[11,34],collision:[11,12],collisionless:[0,25],commun:42,compil:[31,35],compton:[21,40,42],comput:13,concept:42,condit:[9,10],constant:[21,38],contain:42,continu:21,contribut:26,convent:10,coordin:10,core:16,correct:[18,42],counter:[14,21],cpu:42,creat:31,creation:14,current:[9,10,13,34],cylindr:10,data:[25,37,42],debian:28,debug:[11,39],decomposit:[0,8,10,16,34,42],defin:[12,34,38],definit:10,densiti:9,depend:[23,28,29,31],deposit:[9,13],descript:40,detail:[18,40],diagnost:[34,37],directori:39,discret:[9,18],distribut:33,document:[26,31],doe:41,domain:[8,16,34,42],download:31,dual:10,dynam:42,earth:0,effect:18,electr:[9,13],electromagn:42,electromagnet:13,electron:21,emiss:21,energi:21,envelop:[0,10,12,13,34],environ:31,equat:[10,13,22],equip:39,error:[41,42],et:21,event:42,execut:[39,40],explain:31,explicit:24,extern:[34,40],extract:[37,38],factori:42,fdtd:10,fedora:28,field:[0,9,10,12,13,21,22,34,37,42],file:[36,38],filter:[9,34],foil:21,fokker:21,form:16,fourier:0,friedman:9,from:[13,36,38],full:21,gener:[0,34,40,42],geometri:10,get:4,good:21,gpu:[0,6,39,42],graph:23,grid:[10,24],group:18,gtrsim:21,happi:[31,37],harmon:0,hdf5:36,high:[0,21],highlight:0,how:1,i:42,identif:27,ii:42,iii:42,implement:[14,17,18,21,42],improv:0,indent:42,index:45,inform:37,initi:[0,9,22,36],injector:[17,34],instal:[28,29,30,31,40],instruct:25,integr:24,interact:10,intermedi:21,interpol:[9,13],introduct:42,invers:[21,40,42],involv:2,ioniz:[0,11,12],issu:[39,41],iv:42,known:39,landau:[21,42],larg:[25,39],laser:[0,12,13,32,34],layer:7,lesssim:21,licenc:1,lifshift:42,lifshitz:21,like:21,line:42,linux:28,list:26,ll:21,load:[16,34],logarithm:18,longitudin:10,loop:[9,13,42],maco:29,macport:29,macro:[10,18,24],made:4,magnet:[0,21],magnetopaus:0,main:[34,42],manag:[16,39,42],mandatori:21,massiv:18,match:7,mathemat:10,maxwel:[9,10,13,33],merg:[18,34],method:[17,18],mildli:25,mitig:0,mode:[10,39],model:[0,9,10,12,13,14,21,34],moder:21,modul:[20,31,46],momentum:[13,18],mont:[12,21,42],motion:13,motiv:23,move:34,mpi:[16,42],multi:9,multiphoton:[14,34,40],multipl:[8,25,34,37],my:26,namelist:[10,24,34,37,46],newparticl:[34,37],niel:[21,42],node:[16,39],nonlinear:[40,42],notion:[25,42],nuclear:11,numer:[0,13,15,25,32],numpi:36,obtain:37,offload:[0,6],one:37,open:37,oper:[25,42],optim:[19,31,35],option:[31,35,37],other:[37,42],output:42,over:[24,37],overview:44,page:45,pair:[0,14],paper:2,parallel:[16,19,23,42],paramet:[21,25],part:42,particl:[0,9,10,17,18,24,25,27,34,36,42],particlebin:[34,37],partner:3,pass:9,patch:[16,42],perfectli:7,perform:[0,21,23,25,34,37,41],photon:[18,21],physic:[12,14,20,41],pic:[9,13,42],planck:21,plane:[14,21,32],plasma:0,plot:37,point:40,poisson:[10,22],polar:13,ponderomot:13,posit:13,post:[37,46],postprocess:41,practic:16,pre:38,precomput:40,preprocess:32,prescrib:34,primal:10,probe:[34,37],problem:24,process:[16,32,37,46],profil:38,project:[3,4],propag:[14,21,32],provid:39,push:[9,13],pusher:42,python:[34,38,40],qed:18,quantiti:[21,24],quantum:21,quasi:9,radiat:[21,34,42],radiationspectrum:[34,37],rate:[12,21],reaction:[11,21,34],recommend:[17,22],reconnect:0,rectangular:16,refer:[2,11,12,13,18,21,22,24,32],regim:21,relat:3,relativist:[0,10,21,22,25],releas:4,repositori:4,requir:24,result:[18,23,41],rule:[34,42],run:[39,41],s:[10,22,26],sampl:33,scalabl:0,scalar:[34,37],scale:[18,25],scatter:[21,40],scheme:[9,11,12,14],screen:[34,37],script:[39,40],select:34,setup:[16,31],shock:[0,25],simd:25,simul:[0,9,18,21,25,37,41],simultan:37,singl:[8,25],slider:37,smilei:[1,2,4,17,26,29,34,39,42],smilei_t:31,solid:18,solut:13,solver:[9,13],space:9,spatial:38,speci:[22,34,42],specifi:37,spheric:18,start:41,statement:42,stochast:[14,21],streak:37,structur:42,style:42,sub:18,supercomput:30,suscept:13,synchrotron:[14,21],synopsi:5,syntax:46,tabl:[14,40,42],task:[23,42],techniqu:15,tempor:38,test:[11,39],theoret:32,thin:21,thread:16,tilt:32,time:[9,34,37],timestep:37,tip:[10,24,34],tool:[31,37,42],trace:42,track:27,trackparticl:[34,37],translat:9,transvers:10,troubleshoot:[28,41],tunnel:0,ubuntu:28,ultra:21,understand:[18,47],unit:[24,37],unreferenc:45,updat:37,us:[0,39,48],user:12,v:42,valid:26,valu:21,variabl:[31,34,42],vector:[0,10,25,31,34,35],vectorpatch:42,version:9,vi:42,visual:40,vlasov:9,vocabulari:42,vtk:37,wakefield:0,wall:34,wave:[14,21],websit:26,weight:24,wheeler:[14,34,40],whole:16,window:34,workflow:34,write:[26,34],your:[21,26]}}) \ No newline at end of file diff --git a/site.html b/site.html new file mode 100644 index 000000000..4d31c0b8a --- /dev/null +++ b/site.html @@ -0,0 +1,550 @@ + + + + + + + + + Index — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/syntax_changes.html b/syntax_changes.html new file mode 100644 index 000000000..67ea80af3 --- /dev/null +++ b/syntax_changes.html @@ -0,0 +1,668 @@ + + + + + + + + + Syntax changes — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Syntax changes

+

A number of changes in the syntax have been brought in Smilei’s version 3.3. +Most changes only affect keywords names.

+
+
+

In the namelist

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Old

New

"1d3v", "2d3v", "3d3v"

"1Dcartesian", "2Dcartesian", "3Dcartesian"

maxwell_sol

maxwell_solver

sim_length

grid_length

sim_time

simulation_time

bc_em_type_*

EM_boundary_conditions

referenceAngularFrequency_SI

reference_angular_frequency_SI

currentFilter_int

CurrentFilter

Friedman_filter +Friedman_theta

FieldFilter

poisson_iter_max

poisson_max_iteration

poisson_error_max

poisson_max_error

species_type

name

initPosition_type

position_initialization

initMomentum_type

momentum_initialization

n_part_per_cell

particles_per_cell

nb_density

number_density

bc_part_type_****

boundary_conditions

Particle boundary condition "none"

"periodic"

Particle boundary condition "refl"

"reflective"

Particle boundary condition "supp"

"remove"

thermT

thermal_boundary_temperature

thermVelocity

thermal_boundary_velocity

isTest

is_test

dynamics_type

pusher

boxSide

box_side

polarizationPhi

polarization_phi

dump_file_sequence

keep_n_dumps

coef_cell

cell_load

coef_frozen

frozen_particle_load

DumpRestart

Checkpoints

ExtField

ExternalField

track_******

DiagTrackParticles

track_filter

The filter function syntax has changed

DiagParticles

DiagParticleBinning

output of DiagParticles

+ +
The values of this argument have changed
+
+
+
+
+
+

In the post-processing module

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Old

New

+
from Smilei import *
+
S = Smilei("my/simulation/path/")
+
+
+
import happi
+
S = happi.Open("my/simulation/path/")
+
+

ParticleDiagnostic()

ParticleBinning()

slice argument

average or sum, depending on the diagnostic

stride argument

more complete subset

+
average argument of Probe()
+
used bins indices
+
+

now requires coordinates in code units

+
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/understand.html b/understand.html new file mode 100644 index 000000000..d39695445 --- /dev/null +++ b/understand.html @@ -0,0 +1,697 @@ + + + + + + + + + Understand — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Understand

+
+ +
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/use.html b/use.html new file mode 100644 index 000000000..1556b7f19 --- /dev/null +++ b/use.html @@ -0,0 +1,598 @@ + + + + + + + + + Use — Smilei 5.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+

Use

+
+ +
+
+ + +
+
+
+
+
+
+ + + + + \ No newline at end of file