diff --git a/2d_average_chi_it5500.png b/2d_average_chi_it5500.png new file mode 100644 index 0000000..f6a5677 Binary files /dev/null and b/2d_average_chi_it5500.png differ diff --git a/2d_average_energy_it5500.png b/2d_average_energy_it5500.png new file mode 100644 index 0000000..9755966 Binary files /dev/null and b/2d_average_energy_it5500.png differ diff --git a/2d_density_it5500.png b/2d_density_it5500.png new file mode 100644 index 0000000..4c17a39 Binary files /dev/null and b/2d_density_it5500.png differ diff --git a/2d_fields_it5500.png b/2d_fields_it5500.png new file mode 100644 index 0000000..a5e2ca4 Binary files /dev/null and b/2d_fields_it5500.png differ diff --git a/AdvancedTutorial1.tar.gz b/AdvancedTutorial1.tar.gz new file mode 100644 index 0000000..c4774a6 Binary files /dev/null and b/AdvancedTutorial1.tar.gz differ diff --git a/AdvancedTutorial2.tar.gz b/AdvancedTutorial2.tar.gz new file mode 100644 index 0000000..d3209f8 Binary files /dev/null and b/AdvancedTutorial2.tar.gz differ diff --git a/_images/2d_average_chi_it5500.png b/_images/2d_average_chi_it5500.png new file mode 100644 index 0000000..f6a5677 Binary files /dev/null and b/_images/2d_average_chi_it5500.png differ diff --git a/_images/2d_average_energy_it5500.png b/_images/2d_average_energy_it5500.png new file mode 100644 index 0000000..9755966 Binary files /dev/null and b/_images/2d_average_energy_it5500.png differ diff --git a/_images/2d_density_it5500.png b/_images/2d_density_it5500.png new file mode 100644 index 0000000..4c17a39 Binary files /dev/null and b/_images/2d_density_it5500.png differ diff --git a/_images/2d_fields_it5500.png b/_images/2d_fields_it5500.png new file mode 100644 index 0000000..a5e2ca4 Binary files /dev/null and b/_images/2d_fields_it5500.png differ diff --git a/_images/LaguerreGauss.png b/_images/LaguerreGauss.png new file mode 100644 index 0000000..e030731 Binary files /dev/null and b/_images/LaguerreGauss.png differ diff --git a/_images/arrangement.png b/_images/arrangement.png new file mode 100644 index 0000000..881ae2b Binary files /dev/null and b/_images/arrangement.png differ diff --git a/_images/compare_density_radiative_models.png b/_images/compare_density_radiative_models.png new file mode 100644 index 0000000..e70e3bf Binary files /dev/null and b/_images/compare_density_radiative_models.png differ diff --git a/_images/compare_energy_balance_Landau_Lifshitz.png b/_images/compare_energy_balance_Landau_Lifshitz.png new file mode 100644 index 0000000..e49395d Binary files /dev/null and b/_images/compare_energy_balance_Landau_Lifshitz.png differ diff --git a/_images/compare_energy_balance_radiation_models.png b/_images/compare_energy_balance_radiation_models.png new file mode 100644 index 0000000..be2f4b0 Binary files /dev/null and b/_images/compare_energy_balance_radiation_models.png differ diff --git a/_images/energy_balance.png b/_images/energy_balance.png new file mode 100644 index 0000000..3bac308 Binary files /dev/null and b/_images/energy_balance.png differ diff --git a/_images/energy_spectrum_it8000.png b/_images/energy_spectrum_it8000.png new file mode 100644 index 0000000..5f3a994 Binary files /dev/null and b/_images/energy_spectrum_it8000.png differ diff --git a/_images/node.svg b/_images/node.svg new file mode 100644 index 0000000..931ec25 --- /dev/null +++ b/_images/node.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + memory + + + + + cores + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Node 1 + + + + + + + Node 2 + + + + + + + Node 3 + + + + + + \ No newline at end of file diff --git a/_images/particle_number.png b/_images/particle_number.png new file mode 100644 index 0000000..9f5d59d Binary files /dev/null and b/_images/particle_number.png differ diff --git a/_images/smileiLogo_tutorials_large.svg b/_images/smileiLogo_tutorials_large.svg new file mode 100644 index 0000000..482cb01 --- /dev/null +++ b/_images/smileiLogo_tutorials_large.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_sources/advanced.rst.txt b/_sources/advanced.rst.txt new file mode 100644 index 0000000..7b4611a --- /dev/null +++ b/_sources/advanced.rst.txt @@ -0,0 +1,17 @@ +.. title:: Advanced + +Advanced +============ + +.. toctree:: + + advanced_field_ionization + advanced_collisions + advanced_radiation_reaction + advanced_breit_wheeler + advanced_wakefield + advanced_wakefield_AMcylindrical + advanced_wakefield_electron_beam + advanced_wakefield_envelope + advanced_vtk + \ No newline at end of file diff --git a/_sources/advanced_breit_wheeler.rst.txt b/_sources/advanced_breit_wheeler.rst.txt new file mode 100644 index 0000000..e685863 --- /dev/null +++ b/_sources/advanced_breit_wheeler.rst.txt @@ -0,0 +1,470 @@ +Multiphoton Breit-Wheeler pair creation process +------------------------------------------------------------------------------- + +The goal of this tutorial is to present how to use the multiphoton Breit-Wheeler +pair creation process in :program:`Smilei`. +The following points will be addressed: + +* How to prepare input files for this physical module +* How to setup macro-photon species and the Monte-Carlo emission +* How to setup the multiphoton Breit-Wheeler pair creation process +* How to use diagnostics +* How to read and understand produced outputs + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^^^ + +A multi-GeV electron beam is made to collide with a counter-propagating plane wave. +This configuration is one of the most efficient to trigger radiative and QED effects. +It maximizes the value of the quantum parameter for a given electron energy and a +given field strength. + +The simulation is 2D Cartesian with a simulation size of :math:`30 \lambda \times 4 \lambda` +where :math:`\lambda` is the laser wavelength. The laser is injected from the left side +of the simulation domain while the electron beam is initialized at the extreme right. + +In this initial configuration, the laser has a wavelength of :math:`\lambda = 1\ \mu \mathrm{m}`, +an amplitude of :math:`10^{23}\ \mathrm{W/cm}^2` (:math:`a_0 \simeq 270`) and is linearly +polarized in the `y` direction. The temporal profile is Gaussian (order 4). +he full width at half maximum (FWHM) is of 10 laser periods (approximately 33 fs). + +The electron beam has an initial energy of 4 GeV and propagates to the left. +The beam density is of :math:`n_b = 10^{-5} n_c`. The electron beam is frozen the +time for the laser to be fully injected and so that the collision occurred at +the middle of the domain. This enables to have a shorter simulation box and +therefore save computational time. The beam is initialized with 32 particles +per cell for a total of 3648 macro-particles. + +---- + +Content of the tutorial +^^^^^^^^^^^^^^^^^^^^^^^^ + +Download `AdvancedTutorial2.tar.gz `_ and extract it. +It contains 2 directories: + +* ``Analysis`` +* ``Execution`` + +The directory ``Analysis`` contains `Python` scripts that will be used to analysis +and visualize the simulation outputs. Each script has been designed to focus on a +specific quantity: + +* ``show_energy_balance.py``: particle kinetic energy, photon energy and radiated energy (not in the photons) vs. time. +* ``show_particle_number.py``: number of macro-particles for each species vs. time. +* ``show_2d_density.py``: maps of the electron, positron and photon density. +* ``show_2d_average_energy.py``: maps of the electron, positron and photon average energy. +* ``show_2d_average_chi.py``: maps of the electron, positron and photon quantum parameter. +* ``show_2d_fields.py``: maps of the electric field :math:`E_y` and the magnetic field :math:`B_z`. +* ``show_energy_spectrum.py``: electron, positron and photon energy distribution at a given time. + +The ``Execution`` directory contains the input file: + +* ``tst2d_electron_laser_collision.py`` + +---- + +Simulation of the multiphoton Breit-Wheeler process +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We will first learn how to configure the input file for the Monte-Carlo process +with macro-photon emission followed by the Multiphoton Breit-Wheeler +pair creation process. +For this simulation case, we will need to define three species: electrons, positrons and photons. +After the configuration, we will then run our simulation test case. +Finally, we will see how to read and exploit diagnostic outputs via Python script +and the :program:`happi` post-processing module. + +* Make a copy of the directory ``Execution`` and name it + ``Multiphoton_Breit_Wheeler``. We will perform the simulation in this directory. + + .. code-block:: bash + + cp -r Execution Multiphoton_Breit_Wheeler + cd Multiphoton_Breit_Wheeler + + +* Open the input file ``tst2d_electron_laser_collision.py``. + +---- + +Configuration of the radiation reaction block +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Go to the ``RadiationReaction`` block. + +* The Monte-Carlo algorithm uses tabulated values. + The path can be specified in the block ``RadiationReaction`` via the parameter ``table_path`` + (read the documentation if you want to use non-default databases). + +* The parameter ``minimum_chi_continuous`` corresponds to the minimal value + of the quantum parameter at which the radiation reaction process is applied. + Below this value, the particle does not undergo radiation reaction. + Uncomment the corresponding line. + Specifying this parameter is actually not compulsory since it is defined + by default at :math:`10^{-3}`. + +* Uncomment the line with the parameter ``minimum_chi_discontinuous``. + The Monte-Carlo model is built to work with + the continuous corrected Landau-Lifshitz approach when the particle quantum parameter is too low. + This parameter corresponds to this threshold. + Above this value, a particle undergoes radiation reaction via the Monte-Carlo engine. + Below the continuous approach is used. + This parameter is by default equal to :math:`10^{-2}` + but it is modified to be :math:`10^{-3}` here. + +* The ``RadiationReaction`` should now look like: + + .. code-block:: python + + RadiationReaction( + minimum_chi_continuous = 1e-3 + minimum_chi_discontinuous = 1e-3, + #table_path = "" + ) + +**External tables:** some models such as the Monte-Carlo radiation model use complex mathematical functions to determine the production rate of +photons and energy. +These functions are tabulated because it would be too expensive to compute them on the fly for each macro-particles. +The :program:`Smilei` code includes default tables. +It is nonetheless possible to use more accurate external tables. +This is the purpose of the parameter `table_path` in the block `Radiation`. +For more information about the tables, see https://smileipic.github.io/Smilei/Use/tables.html. + +---- + +Configuration of the multiphoton Breit-Wheeler block +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Go to the ``MultiphotonBreitWheeler`` block. + This block controls the general parameters of the Multiphoton Breit-Wheeler process. + +* The Monte-Carlo algorithm for the Multiphoton Breit-Wheeler process uses tabulated values. + The path can be specified in the block ``MultiphotonBreitWheeler`` via the parameter ``table_path``, + if you wish to use non-default tables. + +* The ``MultiphotonBreitWheeler`` should now look like: + + .. code-block:: python + + MultiphotonBreitWheeler( + #table_path = "/databases/" + ) + +---- + +Configuration of the electron species +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* We will first configure the ``electron`` species that composes the beam so that + it can radiate via the Monte-Carlo model and generate macro-photons + Go to the ``electron`` species block. you can see that the radiation parameters + are commented. + +* The parameter ``radiation_model`` corresponds to the type of radiation model to be used. + Uncomment the corresponding line. We use here the ``Monte-Carlo``. + +* When ``radiation_photon_species`` is present and not set to ``None``, + the possibility to generate macro-photons is activated. This parameter has to be set to + the name of the ``photon`` species that will receive the created macro-photons. + Uncomment the corresponding line. The photon species is called ``photon``. + +* The parameter ``radiation_photon_sampling`` enables to control the number of + macro-photons generated per emission even. By default, an emission yields a + single macro-photons of weight similar to the emitting particle. to increase + the emission statistics, you can decide to increase this number so that several + macro-photons are generated per even. In this case, the weight is equally + divided between macro-photons for quantity conservation. + Uncomment the corresponding line. + +* The parameter ``radiation_photon_gamma_threshold`` enables to control the + minimum threshold on the photon energy that allow macro-photon emission. + Below the specified value, the radiation reaction is taken into account + but no macro-photon is created. + Here, since photons of energy below twice the electron rest mass energy have + no chance to turn into electron-positron pairs, this threshold is set to 2. + This value is actually the default one. + Uncomment the corresponding line. + +* The radiation parameters of the ``electron`` species block are now: + + .. code-block:: python + + Species( + name = "electron", + ... + radiation_model = "Monte-Carlo", + radiation_photon_species = "photon", + radiation_photon_sampling = 1, + radiation_photon_gamma_threshold = 2, + ... + ) + + +* The electron species is now configured. + +---- + +Configuration of the photon species +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* We will then configure the ``photon`` species that will receive the macro-photons + generated by the other species via the Monte-Carlo radiation model. + Go to the ``photon`` species block. you can see that the Multiphoton + Breit-Wheeler parameters are commented. They start by ``multiphoton_Breit_Wheeler``. + +* The parameter ``multiphoton_Breit_Wheeler`` is a list of two strings. + These strings respectively correspond + to the species name that will receive the created electron and the created positron. + Uncomment the corresponding line. + The electron and the positron species respectively correspond to ``electron`` and ``positron``. + When this parameter is commented, the multiphoton Breit-Wheeler is not activated. + +* The parameter ``multiphoton_Breit_Wheeler_sampling`` is the number of + macro-electron and macro-positron generated per Monte-Carlo event. + This parameter is a list of two integers. + By default, an electron and a positron are generated per event. + To improve the statistics, these numbers can be increased. + The macro-particle weight is then divided in consequence. + Uncomment the corresponding line. + +* The multiphoton Breit-Wheeler parameters for the ``photon`` species block are now: + + .. code-block:: python + + Species( + name = "photon", + ... + multiphoton_Breit_Wheeler = ["electron","positron"], + multiphoton_Breit_Wheeler_sampling = [1,1], + ... + ) + + +---- + +Configuration of the positron species +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* We will then configure the ``positron`` species that will receive the macro-positrons + generated via the multiphoton Breit-Wheeler. + Go to the ``positron`` species block. + +* As for the ``electron`` species, uncomment the radiation parameters as follow: + + .. code-block:: python + + Species( + name = "positron", + ... + radiation_model = "Monte-Carlo", + radiation_photon_species = "photon", + radiation_photon_sampling = 1, + radiation_photon_gamma_threshold = 2, + ... + ) + + +The positrons will also radiate with the Monte-Carlo model. + +---- + +Presentation of the diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Several diagnostics are defined in the input file. + +* Time-evolution of scalar quantities are configured via the ``DiagScalar`` block. + Here, output of the radiated energy (not including the macro-photons) + is requested via ``Urad``. ``Ukin_`` corresponds to the kinetic energy of ```` + (total energy for the photons). ``Ntot_`` is the number of macro-particles. + + .. code-block:: python + + DiagScalar( + every = 10, + vars=['Uelm','Ukin','Utot','Uexp','Ubal', + 'Urad', + 'Ukin_electron', + 'Ukin_positron', + 'Ukin_photon', + 'Ntot_electron', + 'Ntot_positron', + 'Ntot_photon'] + ) + + +* The field grids are written out every 500 iterations via the block ``DiagFields``. + +* The ``DiagParticleBinning`` blocks project the particle + quantities on specified multidimensional grids. + There are 4 types of diagnostics configured in the input file for each species: + + - 1. the species `weight` distribution + - 2. the kinetic energy times the weight (``weight_ekin``) + - 3. the quantum parameter time the weight (``weight_chi``) + - 4. the species energy distribution + + The particle binning diagnostics are written every 500 iterations. + +---- + +Simulation analysis +^^^^^^^^^^^^^^^^^^^^^^^^ + +After you have run the simulation, you may start analyzing its results. + +* Let us first analyze the time-evolution of the number of macro-particles + in the simulation. + Copy the file ``Analysis/show_particle_number.py`` in the working directory: + + .. code-block:: bash + + cp ../Analysis/show_particle_number.py . + + + Run the script using iPython: + + .. code-block:: bash + + ipython + run show_particle_number.py + + +* You should obtain the following graph: + + .. image:: _extra/particle_number.png + + When the laser starts to interact with the electron beam around :math:`t = 230 \omega_r^{-1}`, + the number of macro-photons rises rapidly due thanks to + the Monte-Carlo radiation model. + Later, these photons start to decay into electron-positron pairs + via the multiphoton Breit-Wheeler. + We can observe an increase of the number of macro-electrons and macro-positrons + from :math:`t = 235 \omega_r^{-1}` + +* Copy the file ``Analysis/show_energy_balance.py`` in the working directory + and run the script: + + .. code-block:: bash + + cp ../Analysis/show_energy_balance.py . + ipython + run show_energy_balance.py + + +* You should obtain the following graph: + + .. image:: _extra/energy_balance.png + +* We will now use the particle binning diagnostics. + Copy the file ``Analysis/show_2d_average_energy.py`` in the working directory + and run the script: + + .. code-block:: bash + + cp ../Analysis/show_2d_average_energy.py . + ipython + run show_2d_average_energy.py + + + You should obtain the following graph: + + .. image:: _extra/2d_average_energy_it5500.png + + From the top to the bottom, you have respectively the electron, positron + normalized kinetic energy and the photon normalized energy. + + You can also choose a different timestep using, for instance + + .. code-block:: bash + + run show_2d_average_energy.py 6000 + +* We will now do the same thing for the weight (normalized local density). + Copy the file ``Analysis/show_2d_density.py`` in the working directory + and run the script: + + .. code-block:: bash + + cp ../Analysis/show_2d_density.py . + ipython + run show_2d_density.py + + + You should obtain the following figure: + + .. image:: _extra/2d_density_it5500.png + + Change the ``timestep`` parameter to see how the beam shape evolves during + the simulation and how the positron are created. + +* We can also look at the quantum parameter. + Copy the file ``Analysis/show_2d_average_chi.py`` in the working directory + and run the script: + + .. code-block:: bash + + cp ../Analysis/show_2d_average_chi.py . + ipython + run show_2d_average_chi.py + + + You should obtain the following figure: + + .. image:: _extra/2d_average_chi_it5500.png + + The maximal value of the quantum parameter is printed in the terminal. + Change the ``timestep`` parameter to see how the electron, positron and photon + average quantum parameter evolve during + the simulation. + +* To get an idea of where in the laser field the beam is located, + you can use the script ``Analysis/show_2d_fields.py`` + Copy and run it: + + .. code-block:: bash + + cp ../Analysis/show_2d_fields.py . + ipython + run show_2d_fields.py + + + You should obtain the following figure: + + .. image:: _extra/2d_fields_it5500.png + + Change the ``timestep`` parameter as for the particle binning diagnostics. + +* Finally, we want to analyze the final energy spectra of the species. + Copy the script ``Analysis/show_energy_spectrum.py`` and run it. + + .. code-block:: bash + + cp ../Analysis/show_energy_spectrum.py . + ipython + run show_energy_spectrum + + + You should obtain the following figure: + + .. image:: _extra/energy_spectrum_it8000.png + + +---- + +To go beyond +^^^^^^^^^^^^^^^^^^^^^^^^ + +* **Optional exercice:** Change the laser and electron beam properties to see + how it affects the beam energy loss and the production of electron-positron pairs. + +* **Optional exercice:** Use the same input file to build a similar case in 3D. + You will have to increase the number of nodes. + Use a focused laser pulse instead a place wave and see how the pulse waist + affect the interaction (final positron energy, beam divergence...). + +* **Optional exercice:** Activate the load balancing and change the number of + patches to see how it affects the performances. diff --git a/_sources/advanced_collisions.rst.txt b/_sources/advanced_collisions.rst.txt new file mode 100644 index 0000000..865de0f --- /dev/null +++ b/_sources/advanced_collisions.rst.txt @@ -0,0 +1,147 @@ +Binary collisions and impact ionization +------------------------------------------------------------- + +Smilei includes binary collisions between various species, which can also generate +ionization when one of the species is ions and the other one electrons. +`Smilei's website `_ +already gives a description of the approach, and provides results from various benchmarks. + +The list of benchmarks, located in the ``benchmarks/collisions/`` folder is briefly +described below. You may run any of these benchmarks depending on your interests. + +Beam relaxation +^^^^^^^^^^^^^^^ + +An electron beam encounters a thermal ion population; *e-i* collisions slow the beam down +and make it spread. Various electron velocities and ion charges are considered. For each +case, the ratios of weights between electrons and ions is varied. + +.. rubric:: 1. initial velocity = 0.05, ion charge = 1 + +| ``beam_relaxation1.py`` +| ``beam_relaxation2.py`` +| ``beam_relaxation3.py`` +| Analysis and plotting provided in ``beam_relaxation123.py`` + +.. rubric:: 2. initial velocity = 0.01, ion charge = 1 + +| ``beam_relaxation4.py`` +| ``beam_relaxation5.py`` +| ``beam_relaxation6.py`` +| Analysis and plotting provided in ``beam_relaxation456.py`` + +.. rubric:: 3. initial velocity = 0.01, ion charge = 3 + +| ``beam_relaxation7.py`` +| ``beam_relaxation8.py`` +| ``beam_relaxation9.py`` +| Analysis and plotting provided in ``beam_relaxation789.py`` + + +Thermalization +^^^^^^^^^^^^^^ + +Thermal electrons start with a different temperature from that of ions. +The thermalization due to *e-i* collisions is monitored for three different weight ratios. + +| ``thermalisation_ei1.py`` +| ``thermalisation_ei2.py`` +| ``thermalisation_ei3.py`` +| Analysis and plotting provided in ``thermalisation_ei123.py`` + + +Temperature isotropization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Non-isotropic thermal electrons are isotropized with *e-e* collisions. + +| ``temperature_isotropization1.py`` +| ``temperature_isotropization2.py`` +| Analysis and plotting provided in ``temperature_isotropization.py`` + + +Maxwellianization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An electron population starting with a rectangular velocity distribution becomes +maxwellian due to *e-e* collisions. + +| ``Maxwellianization1.py`` +| Analysis and plotting provided in ``Maxwellianization.py`` + + +Stopping power +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The *e-e* slowing rate of test electrons passing through an electron plasma is monitored +*vs.* time and compared to a theoretical stopping power. + +| ``Stopping_power1.py`` : projectiles from 10 to 30 keV +| ``Stopping_power2.py`` : projectiles from 100 to 300 keV +| ``Stopping_power3.py`` : projectiles from 1 to 10 MeV +| Analysis and plotting provided in ``Stopping_power123.py`` + + +Ionization rate +^^^^^^^^^^^^^^^ + +Drifting electrons in a cold Al plasma cause *e-i* impact ionization at a rate compared +to theoretical values. The three inputs below correspond to various weight ratios +between electrons and ions. + +| ``ionization_rate1.py`` +| ``ionization_rate2.py`` +| ``ionization_rate3.py`` +| Analysis and plotting provided in ``ionization_rate.py`` + + +Inelastic stopping power +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ionizing *e-i* slowing rate of test electrons passing through an Al plasma +is monitored *vs.* time and compared to a theoretical stopping power. + +| ``ionization_stopping_power1.py`` : measurement for electrons at various energies + +| ``ionization_stopping_power2.py`` : +| ``ionization_stopping_power3.py`` : three examples to show the stopping dynamics +| ``ionization_stopping_power4.py`` : + +| Analysis and plotting provided in ``ionization_stopping_power.py`` + + +Multiple ionization +^^^^^^^^^^^^^^^^^^^ + +The capability to ionize several times in one timestep is illustrated for five different +materials. For each material, two cases are provided: the first is well resolved, while +the second has a low time resolution requiring multiple ionization. + +| ``ionization_multipleC1.py`` +| ``ionization_multipleC2.py`` +| ``ionization_multipleAl1.py`` +| ``ionization_multipleAl2.py`` +| ``ionization_multipleZn1.py`` +| ``ionization_multipleZn2.py`` +| ``ionization_multipleSn1.py`` +| ``ionization_multipleSn2.py`` +| ``ionization_multipleAu1.py`` +| ``ionization_multipleAu2.py`` +| Analysis and plotting provided in ``ionization_multiple.py`` + + +Effect of neglecting recombination +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As recombination is not accounted for, we can expect excess ionization to occur +indefinitely without being balanced to equilibrium. For picosecond laser interaction, +we illustrate here that the recombination rate can be neglected, thus providing +reasonable ionization state *vs.* temperature, in various materials. + +| ``ionization_equilibriumH.py`` +| ``ionization_equilibriumAl.py`` +| ``ionization_equilibriumZn.py`` +| ``ionization_equilibriumAu.py`` +| Analysis and plotting provided in ``ionization_equilibrium.py`` + + diff --git a/_sources/advanced_field_ionization.rst.txt b/_sources/advanced_field_ionization.rst.txt new file mode 100644 index 0000000..cbd07b4 --- /dev/null +++ b/_sources/advanced_field_ionization.rst.txt @@ -0,0 +1,86 @@ +Field ionization +============================= + +The goal of this tutorial is to present a simulation using an advanced physics module, +namely the field (tunnel) ionization module. +In the presence of tunnel ionization, one needs to set a reference temporal/spatial scale. +In :program:`Smilei`, this is done by defining, in SI units, the reference angular +frequency parameter: ``reference_angular_frequency_SI``. + +Briefly, this tutorial will help you: + +* use the ``reference_angular_frequency_SI`` +* use the ``.getData()`` tool of :program:`happi` to analyse your data and make your own figures. + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^ + +Download the input file `tunnel_ionization_1d.py `_ as well as +the analysis scripts `analysis_tunnel_ionization_1d.py `_ and `solve_rate_eqs.py `_. + +In a 1D cartesian geometry, a thin layer of neutral carbon is irradiated (thus ionized) +by a linearly-polarized laser pulse with intensity :math:`I = 5\times 10^{16}~{\rm W/cm^2}` +and a gaussian time profile. + +---- + +Check the input file and run the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The first step is to check that your `input file` is correct. +To do so, you will run (locally) :program:`Smilei` in test mode: + +.. code-block:: bash + + ./smilei_test tunnel_ionization_1d.py + +If your simulation `input file` is correct, you can run the simulation. + +.. warning:: + + For this simulation, we have specified in the input file that only 1 patch is created. + Therefore, this simulation can be run using a single processor only! + +Before going to the analysis of your simulation, check your ``log`` file! + + +---- + +Analyse the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^ + +A *python* script has been prepared to analyse the simulations results. +Open the file ``analysis_tunnel_ionization_1d.py`` and have look at what it does. +Note that it calls for the ``solve_rate_eqs.py`` file that is used to compute +the rate equations (obtained theoretically). + +.. warning:: + + Before running ``analysis_tunnel_ionization_1d.py``, give the + correct path to your simulation results by defining the + ``simulation_to_analyse`` variable! + +In an *ipython* prompt, run the analysis file: + +.. code-block:: python + + %run analysis_tunnel_ionization_1d.py + +What do you obtain? Check also if any ``.eps`` file is generated. + +.. note:: + + Some lines containing LateX commands have been commented out. + If your machine has LateX installed, it may provide higher-quality figures. + + +---- + +Changing the reference angular frequency +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As you have seen in the namelist, you have to specify a reference angular frequency in SI units. +This because the ionization rate is not invariant under the usual normalizations (see tutorial on ``Units``). +What happens to the results if you multiply this frequency by a factor ``0.5`` or ``2.0``? \ No newline at end of file diff --git a/_sources/advanced_radiation_reaction.rst.txt b/_sources/advanced_radiation_reaction.rst.txt new file mode 100644 index 0000000..7f33094 --- /dev/null +++ b/_sources/advanced_radiation_reaction.rst.txt @@ -0,0 +1,418 @@ +Synchrotron-like radiation reaction +------------------------------------------------------------------------------ + +The goal of this tutorial is to present how to use the radiative and QED processes in +:program:`Smilei`. +The following points will be addressed: + +* How to prepare input files for these physical modules +* How to setup radiation reaction models +* How to use :program:`Smilei` diagnostics +* How to read and understand generated outputs + +The radiation reaction module implemented in Smilei is described +`in this page `_. +It models the radiation emitted by accelerated charges and their subsequent +loss of energy, which is also known as Inverse Compton Scattering. + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^^ + +A multi-GeV electron beam is made to collide with a counter-propagating plane wave. +This configuration is one of the most efficient to trigger radiative and QED effects. +It maximizes the value of the quantum parameter for a given electron energy and a given +field strength. + +The simulation is 2D Cartesian with a box size of :math:`30 \lambda \times 4 \lambda` +where :math:`\lambda` is the laser wavelength. The laser is injected from the left side +of the simulation domain while the electron beam is initialized at the extreme right. + +In this initial configuration, the laser has a wavelength of :math:`\lambda = 1\ \mu \mathrm{m}`, +an amplitude of :math:`10^{22}\ \mathrm{W/cm}^2` (:math:`a_0 \simeq 100`) and is linearly polarized +in the :math:`y` direction. The temporal profile is Gaussian (order 4). +The full width at half maximum (FWHM) is of 10 laser periods (approximately 33 fs). + +The electron beam has an initial energy of 1 GeV and propagates to the left. +The beam density :math:`n_b = 10^{-5} n_c`, and contains 32 macro-particles per cell +for a total of 12480 macro-particles. To save computational time, the +electron beam is frozen until the laser is fully injected in the box. They collide at +middle of the domain. + +---- + +Content of the tutorial +^^^^^^^^^^^^^^^^^^^^^^^ + +Download `AdvancedTutorial1.tar.gz `_ and extract it with the command ``tar -xvf``. +It contains 2 directories: + +1. ``Execution`` which contains the input file ``tst2d_electron_laser_collision.py`` +2. ``Analysis`` where you will find `Python` scripts for the analysis and visualization of the simulation outputs. + Each script has been designed to focus on a specific quantity: + + * ``show_energy_balance.py``: electron kinetic energy and the radiated energy vs. time. + * ``show_2d_density.py``: map of the electron density. + * ``show_2d_average_energy.py``: map of the electron average energy. + * ``show_2d_average_chi.py``: map of the electron local quantum parameter. + * ``show_2d_fields.py``: maps of the electric field :math:`E_y` and the magnetic field :math:`B_z`. + * ``animate_2d_average_chi.py``: map of the electron local quantum parameter vs. time. + * ``compare_energy_balance_Landau_Lifshitz.py`` + * ``compare_energy_balance_radiation_models.py`` + * ``compare_2d_density_radiation_models.py`` + * ``compare_2d_average_energy_radiation_models.py`` + * ``compare_2d_average_chi_radiation_models.py`` + +All Python scripts use *happi*. + +---- + +First simulation: the classical model of Landau-Lifshitz +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let us first use the continuous, classical model of Landau-Lifshitz. +This radiation-reaction model is valid in the classical regime when +the particle quantum parameter ``chi`` is below :math:`10^{-2}`. +The version implemented in :program:`Smilei` is an approximation for high +gamma factors. + +* Copy the directory input file into a new directory called ``Radiation_Landau_Lifshitz`` + in which we will work: + + .. code-block:: bash + + cp -r Execution Radiation_Landau_Lifshitz + +* Go into this directory and open the input file. + + +We will now setup the radiation reaction parameters. + +* Go to the block called ``RadiationReaction``. This block is commented. + Uncomment this block with the parameter called ``minimum_chi_continuous`` only: + + .. code-block:: python + + RadiationReaction( + minimum_chi_continuous = 1e-3 + # minimum_chi_discontinuous = 1e-2, + # table_path = "" + ) + + This block is used to setup the general parameters. Only ``minimum_chi_continuous`` + is useful for the moment. This parameter corresponds to the minimal value of the + quantum parameter at which the radiation reaction process is applied. + Below this value, the particle does not undergo radiation loss. + To specify this parameter is not compulsory since it is defined by default at `1e-3`. + +* Now go to the block of the first species called ``electron``. + Only this species will be present in the simulation for the moment. + +* Uncomment the parameter ``radiation_model``. + This parameter corresponds to the radiation model you want to use. + By default, this parameter is set to ``None`` meaning no radiation loss. + To use the Landau-Lifshitz radiation model, use: + + .. code-block:: python + + radiation_model = "Landau-Lifshitz" + + The other commented parameters are not useful for the moment. + +* You may now run the simulation. We recommend you to run it in parallel + with at least 4 cores. By default, 16 patches have been specified. If you want + to run this input file with more than 16 MPI tasks and OpenMP threads, + you have to increase the number of patches accordingly. + + +At the end of the run, you can see that several files have been generated including +the particle binning (``ParticleBinning*.h5``), the fields (``Fields*.h5``) and +the scalar (``scalars.txt``) diagnostics. + + +* We will use the python script ``show_energy_balance.py`` to plot the time evolution + of the particle normalized kinetic energy. Copy this file from the Analysis directory + to the current one: + + .. code-block:: bash + + cp ../Analysis/show_energy_balance.py . + + +* Open this file and take the time to read and understand it. + You can see that the script is decomposed into several sections. + The section `Smilei general information` will open and scan the result directory + thanks to ``S = happi.Open(path, verbose=False)``. + The results are read in the section `Scalar diagnostics`. + The command ``S.Scalar("Ukin_electron")`` enables to select a scalar quantity object + (for the electron kinetic energy here). We use the method ``get`` to get the raw data + contains in the scalar object. We then manually plot the data via `Matplotlib`. + This method is another approach of using the :program:`Smilei` Python + library and differs from what you may have seen before. + +* Run the script using Python. For instance, in *ipython*:: + + %run show_energy_balance.py + + Or you can also run it directly in your terminal by adding the interactive option: + + .. code-block:: bash + + python -i show_energy_balance.py + + You obtain a plot of the time evolution of the electron normalized energy and + the radiated energy (purple). There are no positron or macro-photons here. + +* What do you observe? You can see that during the laser interaction + (starting from :math:`t = 240 \omega_r^{-1}`), the electron kinetic energy + is rapidly converted into radiations via the radiative model. + +* In order to estimate the maximal quantum parameter reached during the simulation. + you can use the python script ``Analysis/show_2d_average_chi.py``. + Copy this script in the current working directory and run it with Python: + + .. code-block:: python + + python -i show_2d_average_chi.py + + You obtain a 2D colormap of the beam at timestep 5500 when the field is + almost maximum at the beam location. + The color corresponds to the local value of the quantum parameter. + The terminal gives the maximal value. + What do you think about this value regarding the model validity? + +* You can change the timestep by specifing the number after ``show_2d_average_chi.py``: + + .. code-block:: python + + python -i show_2d_average_chi.py 6500 + + Particle binning diagnostics are output every 500 iterations. + By this way you can see when the beam starts to radiate while entering the laser field. + The maximal available iteration is 8000. + + You can also generate an animation using the script ``animate_2d_average_chi.py``: + + .. code-block:: python + + python -i animate_2d_average_chi.py + +* Similarly, use the Python script ``show_2d_density.py`` (located in ``Analysis``) + to plot a 2D colormap of the electron density and ``show_2d_average_energy.py`` + to plot the 2D colormap of the local average kinetic energy. + Copy these scripts in the current working directory and use `ipython` to run them + as in the previous item. Change the ``timestep`` to see how these quantities evolve. + + .. code-block:: python + + # For instance, to plot the density at timestep 6500 + python -i show_2d_density.py + +---- + +Second simulation: the corrected Landau-Lifshitz model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We will now perform the same simulation with the corrected Landau-Lifshitz model. +This model includes a quantum correction that extends the domain of validity +to higher quantum parameters, around :math:`\chi \sim 10^{-1}`. + +* copy the previous working directory ``Radiation_Landau_Lifshitz`` into a new directory + called ``Radiation_corrected_Landau_Lifshitz`` in which we will now work: + +.. code-block:: bash + + cp -r Radiation_Landau_Lifshitz Radiation_corrected_Landau_Lifshitz + cd Radiation_corrected_Landau_Lifshitz + + +* Open the input file script ``tst2d_electron_laser_collision``. + Go to the ``electron`` species block. + To use the ``corrected Landau-Lifshitz`` radiation model, simply use: + +.. code-block:: python + + radiation_model = "corrected-Landau-Lifshitz" + +This radiative model requires the same global setup as the ``Landau-Lifshitz`` one. + +* You can run the simulation. + +* Compare the evolution of the energy balance to the ``Landau-Lifshitz`` model. + For this aim you can copy the script ``show_energy_balance.py`` in the current + working directory and run it using ipython: + + .. code-block:: python + + %run show_energy_balance.py + + Compare the generated plot with the one from the ``Landau-Lifshitz`` simulation. + +* **Optional exercice:** using ``show_energy_balance.py``, create you own python script + to plot on the same figure the time evolution of the energy balance for the + classical Landau-Lifshitz and the corrected Landau-Lifshitz model. + + **Solution:** See the Python script ``Analysis/compare_energy_balance_Landau-Lifshitz.py``. + + .. image:: _extra/compare_energy_balance_Landau_Lifshitz.png + +* Question: What do you observe? You can see that the energy drops less rapidly + with the corrected Landau-Lifshitz model. + This means that we are out of the validity scope of the classical Landau-Lifshitz + model with the current laser and electron parameters. + +* **Optional exercice:** as for the previous model, use the Python scripts to + plot 2D colormap of the density (``show_2d_density.py``), the normalized kinetic + energy (``show_2d_average_energy.py``) and the quantum parameter (``show_2d_average_chi.py``). + +---- + +Third simulation: the stochastic model of Niel *et al.* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The model of Niel *et al.* is the first stochastic model available in :program:`Smilei`. +It is an extension of the corrected Landau-Lifshitz model with +an additional stochastic operator derived from a Fokker-Planck approach. + +* Copy the previous working directory ``Radiation_Landau_Lifshitz`` into a new directory + called ``Radiation_Niel`` in which we will now work: + + .. code-block:: bash + + cp -r Radiation_Landau_Lifshitz Radiation_Niel + cd Radiation_Niel + + +* Open the input file ``tst2d_electron_laser_collision.py`` and + go to the ``electron`` species block. Modify the ``radiation_model`` by + + .. code-block:: python + + radiation_model = "Niel" + +**External tables:** some models such as `Niel` use complex mathematical functions to determine the production rate of +photons and energy. +These functions are tabulated because it would be too expensive to compute them on the fly for each macro-particles. +The :program:`Smilei` code includes default tables. +It is nonetheless possible to use more accurate external tables. +This is the purpose of the parameter `table_path` in the block `Radiation`. +For more information about the tables, see https://smileipic.github.io/Smilei/Use/tables.html. + +* You can run the simulation + + By looking at the standart output (the *log*) that contains the simulation output, + you can check that the external tables have been well read. + +* Use the script ``show_energy_balance.py`` to plot the evolution of the energy + balance for this simulation. Compare the results to the corrected Landau-Lifshitz model. + +* **Optional exercice:** as for the previous model, use the Python scripts to + plot 2D colormap of the density (``show_2d_density.py``), the normalized kinetic + energy (``show_2d_average_energy.py``) and the quantum parameter (``show_2d_average_chi.py``). + +---- + +Fourth simulation: the Monte-Carlo model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Monte-Carlo model is the second stochastic one of the list of implemented models. +You can have more information about the model and its implementation on the page +``Synchrotron-like radiation reaction`` fn the :program:`Smilei` website. + +* copy the previous working directory ``Radiation_Niel`` into a new directory + called ``Radiation_Monte-Carlo`` in which we will now work: + + .. code-block:: bash + + cp -r Radiation_Niel Radiation_Monte_Carlo + cd Radiation_Monte_Carlo + + +* Open the input file ``tst2d_electron_laser_collision.py`` and + go to the ``electron`` species block. Modify the ``radiation_model`` by + + .. code-block:: python + + radiation_model = "Monte-Carlo" + + +* Like the Niel radiation model, the Monte-Carlo algorithm uses tabulated values. + The same path needs to be specified in the block ``RadiationReaction``. + In addition, set the parameter ``minimum_chi_discontinuous`` to ``1e-2`` + (uncomment the corresponding line). + The Monte-Carlo model is built to work with the continuous corrected + Landau-Lifshitz approach when the particle quantum parameter is too low. + This parameter corresponds to this threshold. + Above this value, a particle undergoes radiation reaction via the Monte-Carlo engine. + Below the continuous approach is used. + + .. code-block:: python + + RadiationReaction( + minimum_chi_continuous = 1e-3 + minimum_chi_discontinuous = 1e-3, + # table_path = " + ) + + In fact, the default value of ``minimum_chi_discontinuous`` is ``1e-2``. + Therefore, it has to be specified only to change the default value. + The Monte-Carlo radiation reaction is now fully set. + +* You can now run the simulation + +* Use the script ``show_energy_balance.py`` to plot the evolution of the energy + balance for this simulation. + +* **Optional exercice:** as for the previous model, use the Python scripts to + plot 2D colormap of the density (``show_2d_density.py``), the normalized kinetic + energy (``show_2d_average_energy.py``) and the quantum parameter (``show_2d_average_chi.py``). + +---- + +Comparison of the radiation reaction models +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* **Optional exercice:** Using ``show_energy_balance.py``, create you own python script + to plot on the same figure the time evolution of the energy balance + for the corrected Landau-Lifshitz, the Niel and the Monte-Carlo radiative models. + The solution is given in the next point. + +* **Solution:** The solution is the Python script + ``Analysis/compare_energy_balance_radiation_models.py``. + Go to the directory ``Analysis`` to run it. + You should obtain the following figure: + + .. image:: _extra/compare_energy_balance_radiation_models.png + +* **Optional exercice:** Using the script ``show_2d_density.py``, create a + new script to compare on the same figure the electron density of the corrected Landau-Lifshitz, + the Niel and the Monte-Carlo radiative simulation cases. + Observe the shape of the beam after the laser interaction in each case. + Do the same thing for the average local kinetic energy and the + average local quantum parameter using ``show_2d_kinetic_energy.py`` and ``show_2d_average_chi.py``. + See the next point for the solution. + +* **Solutions:** Solutions are the Python script ``Analysis/compare_2d_density_radiation_models.py``, + ``Analysis/compare_2d_kinetic_energy_radiation_models.py``, + ``Analysis/compare_2d_average_chi_radiation_models.py``. + Go to the directory ``Analysis`` to run the solutions. + The beam density at iteration 6500 at the end of the interaction should look + like the following figure: + + .. image:: _extra/compare_density_radiative_models.png + + With the script to compare the quantum parameter space-distribution, + you can also have the maximum value of the quantum parameter. + +* **Optional exercice:** Activate the track particle option to follow trajectories + of some particles in the corrected Landau-Lifshitz, + the Niel and the Monte-Carlo simulation cases and run them again. + Create a python script to read and plot the particle trajectories. + Describe the difference due to the stochasticity. + +* **Optional exercice**: Play with the laser and electron beam parameters + (laser amplitude, duration, profile and electron energy) to see how + the different models behave. Use the previous scripts to compute the maximum + value of the quantum parameter in each case and see the electron beam properties after + the laser interaction. diff --git a/_sources/advanced_vtk.rst.txt b/_sources/advanced_vtk.rst.txt new file mode 100644 index 0000000..46c2f0d --- /dev/null +++ b/_sources/advanced_vtk.rst.txt @@ -0,0 +1,298 @@ +Export to VTK and 3D visualization +------------------------------------- + +The goal of this tutorial is to learn how to export some diagnostics to the +`VTK `_ format and how to visualize them in 3D. +Two simulations will be run, one in ``"3Dcartesian"`` geometry and the other in ``"AMcylindrical"`` geometry. +In this tutorial we will use the open-source +application `Paraview `_ to open the VTK files and 3D +visualization, although this is not the only possible choice. + +This tutorial is meant as a +first introduction to the 3D visualization of ``Smilei`` results. +For the sake of clarity, only a few available representation options +will be explored, with no pretense of completeness in the field of +3D visualization or in the use of Paraview or similar software. + +In particular this tutorial will explain how to + + * export ``Fields`` results to VTK + * export the macro-particles' coordinates in the ``TrackParticles`` results to VTK + * visualize a Volume Rendering of ``Fields`` with ``Paraview`` + * visualize the tracked macro-particles as points with ``Paraview`` + * perform the same operations for a simulation in ``"AMcylindrical"`` geometry. + +The simulations used for this tutorial is relatively heavy so make sure to submit +the job on 40 cores at least to run in a few minutes. This tutorial +needs an installation of the ``vtk`` Python library to export the data +with ``happi``. The export in 3D of data obtained in ``"AMcylindrical"`` geometry +also requires the installation of the ``scipy`` Python library. + +**Disclaimer** This tutorial is not physically relevant. Proper simulations of this +kind must be done with better resolution in all directions, just to start. +This would give more accurate results, but it would make the simulations +even more demanding. + +**Warning** To avoid wasting computing resources it is highly recommended to start +small when learning how to visualize results in 3D. Apart from the simulation +generating the physically accurate data, the export and visualization of large amounts of +data requires resources and computing time. For these reasons, if you are learning +how to visualize VTK files we recommend to start with relatively small benchmarks +like the ones in this tutorial in order to learn the export/visualization tricks +and to familiarize with the data you may need for your future cases of interest. +Afterwards, you can improve the quality of your simulation results with better +resolution, more macro-particles, more frequent output, etc. and apply the same +export and visualization techniques you will have learned in the process. + +**Warning for non-experts** 3D visualizations can be good-looking and often artistic, they +help giving a qualitative picture of what is happening in your simulation, but +they are not recommended to draw accurate scientific conclusions. +Indeed, 3D pictures/animations often have too many details and graphical artifacts +coming from the rendering of 3D objects, so it's always essential to quantitatively +study your phenomena of interest with 1D and 2D plot to reduce at minimum the +unnecessary or misleading information. + +---- + +Physical configuration for the case in `"3Dcartesian"` geometry +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A Laguerre-Gauss laser pulse enters the window, where test electrons are present. +The laser pushes the electrons out of its propagation axis through ponderomotive force. + +---- + +Run your simulation +^^^^^^^^^^^^^^^^^^^^^^^^ + +Download the input namelist `export_VTK_namelist.py `_ and open +it with your favorite editor. Take some time to study it carefully. +This namelist allows to select between the geometries ``"3Dcartesian"`` and ``"AMcylindrical"``, +each corresponding to a similar case, through the variable `geometry` at the start of the namelist. +For the moment we will use ``geometry="3Dcartesian"`` for our first case. + +Note how we define a ``Laser`` profile corresponding to a Laguerre-Gauss mode +with azimuthal number :math:`m=1`. +This mode has an intensity profile that looks like a corkscrew in 3D. + +After the definition of the ``Laser``, a small block of electrons is defined, +with few test macro-particles to make the simulation and the postprocessing +quicker. Since these electrons are test macro-particles, they will not +influence the laser propagation, but they will be moved by its electromagnetic +field. + +Run the simulation and study the propagation of the laser intensity:: + + import happi; S=happi.Open() + S.Probe.Probe1("Ex**2+Ey**2+Ez**2").slide(figure=1) + +It would be difficult to visualize the corkscrew shape in 2D, even if we had +plotted only one component of the electric field. + +To visualize the trajectories of the electrons, we can use:: + + species_name="electron" + chunk_size = 600000 + track = S.TrackParticles(species = species_name, chunksize=chunk_size,axes = ["x","y"]) + track.slide(figure=2) + +In this plot too it is difficult to see how the particles are moving in 3D. + +It seems one of the occasions where 3D visualization gives a better qualitative +picture. + +**Warning** To visualize the macro-particles, a ``TrackParticle`` diagnostic is +defined in the namelist. No filter is used, since the number of tracked +macro-particles is not enormous. In a more realistic case you should select +only a subset of the particles to make the visualization understandable and to +keep the cost of simulation/export/visualization operations manageable. + + +---- + +Export the results in VTK format +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To start, we can select the fields we want to visualize and export them to VTK. +In this case, we can export the laser intensity:: + + E2 = S.Field.Field0("Ex**2+Ey**2+Ez**2") + E2.toVTK() + +If everything works smoothly, a folder called ``Field0_EzEyEx`` should be created +by ``happi`` after executing the ``toVTK()`` method. In general the folder name +will change with the selected field. +This folder contains the ``Fields`` exported to VTK format, for all the available +iterations. + +Afterwards, for all the available iterations, the ``TrackParticles`` can be +exported, creating a folder ``TrackParticles_electron_xyzpxpypzId``. Each +file within this folder contains the coordinates of the tracked macro-particles. + +The export command will be:: + + track_part = S.TrackParticles(species ="electron",axes = ["x","y","z","px","py","pz","Id"]) + track_part.toVTK(rendering="cloud") + +In the last commands we have selected the attributes to export with the +macro-particles, in this case coordinates, momentum components, Id. +Then, we have used ``rendering="cloud"`` to export a file for each iteration. + +If we wanted to visualize only one or some iterations, we could have selected +them in the variable definition before using the ``toVTK()`` method. + +In case you want to create a 3D animation of a new simulation (like the animation we +will create with this tutorial), before exporting a lot of data it is recommended +to export and visualize only the results from one or few iterations. +If everything you want to see is in place and clearly visible, +then you can export all the iterations necessary for an animation if +so desired. This will save a lot of time in case some diagnostic is missing +in your simulation or if the set-up is not correctly defined in the namelist. + +**Note** In a simulation with moving window you can +also export a coordinate called ``moving_x``, i.e. the ``x`` coordinate relative +to the moving window position. + +**Note** Also other diagnostics, e.g. ``Probes``, can be exported with ``toVTK()`` +See the +`relevant documentation `_ +for more details. + +**Warning** This tutorial has a relatively small amount of data to export. +If you want to export the results from a larger simulation on a cluster with +multiple users, use a job to avoid saturating the shared resources +of the login nodes. You can also speed-up the export operation parallelizing it +with MPI. + +---- + +Visualize the 3D data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Open ``Paraview``. This can be done from your machine if you have the VTK data +stored there, or from a remote machine with remote desktop screen sharing, +or using Paraview in a server-client mode (in this case you will need the same +version of Paraview on both the client and server machines). For large amounts of +data it is recommendable to work in this server-client mode. + +**Warning** from now on, the given instructions contain completely arbitrary +choices, e.g. the colors of representations. Feel free to make different choices +based on you personal tastes and what you want to highlight in your image/animation. +The figure at the end of the tutorial represents only the result of the +mentioned choices. + +First, to highlight the laser and particles we can set the background color to +black. To change the background color, click on the icon with the painter's brush +and color palette symbol and pick a background color. + +Volume Rendering of Fields +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Click on the folder icon in the top left part of the menu or in ``File->Open``, +then find the folder ``Field0_EzEyEx`` in your system where the ``Field`` +diagnostic has been exported. Select the multiple iterations files, they should +be grouped with the name ``Field0_EzEyEx_..pvti``. In the middle left part of +the screen, click on ``Apply``. + +In the central part of one of the top menu bars +you should see the word ``Outline``. Click on it and change the representation +mode to ``Volume`` to create a Volume Rendering. For the moment you will see nothing, +because the laser still has to enter the window. Click on the ``Play`` button +above to see the animation of the laser entering the window. + +You can zoom into the scene scrolling with the mouse or rotate the view +by left-clicking and moving the cursor. Try to change the colormap with +the dedicated button (try e.g. a black, white, blue colormap). +Afterwards, click on the button ``Rescale to Custom Data Range``, selecting +e.g. the interval ``4-10`` for the laser intensity. +This way the corkscrew shape should be visible. + +Point-like representation of Macro-particles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now let's superpose the tracked macro-particles. As before, click on +``File->Open``, then search for the folder ``TrackParticles_electron_xyzpxpypzId`` +where the macro-particles coordinates have been exported. +Select all the iterations, grouped under the name +``TrackParticles_electron_xyzpxpypzId_trajectory_..vtp``. +As before, click on ``Apply``. + +Again, in the central part of one of the top menu bars +you should see the word ``Outline``. Click on it and change the representation +mode to ``Point Gaussian``. If you are visualizing one of the last iterations you +should already be able to see the point-like electrons. Now you can play with +the options of this representation in the bottom left part of the screen. +For example, you can color them with a ``Solid Color`` white (choice made for the +figure in this tutorial), or color them according to their longitudinal +momentum. Selecting the option ``Emissive`` (macro-particles emitting light) from +the ``Search`` bar, you should be able to create an image like this for the +last iteration: + + + .. image:: _static/LaguerreGauss.png + :width: 40% + :align: center + + +Now you can visualize the animation of the laser entering the window and +pushing away the electrons, start experimenting with the many options of the selected +representations, or with the colormaps and transfer functions. + +Exporting data obtained in `"AMcylindrical"` geometry +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In this geometry a cylindrical ``(x,r)`` grid is used for the fields, as explained +its `documentation `_. +The axis ``r=0`` corresponds to the propagation axis of the laser pulse. +Furthermore, fields are defined through their cylindrical components, e.g. +``El``, ``Er``, ``Et`` instead of the ``Ex``, ``Ey``, ``Ez`` in ``"3Dcylindrical"``. +Therefore, when using ``geometry="AMcylindrical"`` in the same input script +you have used for this tutorial, some changes are made, in particular field and +density profiles are defined on a ``(x,r)`` grid and the origins of the axes +(in the profiles and the Probes) are shifted according to the different definition +of their origins. + +Change the ``geometry`` variable at the start of the namelist to have ``geometry="AMcylindrical"`` +and run the simulation. The physical set-up is almost identical to the one +simulated in ``"3Dcartesian"`` geometry, but for simplicity a Gaussian beam will +be used for the ``Laser`` instead of a Laguerre-Gauss beam. + +The commands to export macro-particle data from ``TrackParticles``, except for the +different axis origin, are identical to those used in the ``"3Dcartesian"`` case. +This because the macro-particles (exactly as ``Probes``) in ``"AMcylindrical"`` +geometry are defined in the 3D space. + +For the fields, you may in principle define 3D ``Probes`` in the namelist for the +Cartesian components of the fields and export them to VTK adapting the previous +commands, but we do not recommend this strategy. +This way, the code would have to sample the ``Probe`` data in 3D during the simulation, +creating a huge amount of data and slowing down your simulation, just to have +data for visualization. + +Instead, we recommend to export to vtk the ``Fields`` data defined in cylindrical geometry +to the 3D cartesian space, though the argument ``build3d`` of the ``Fields`` available +only in cylindrical geometry. For its synthax, see the +`Field documentation `_. + +First, you need to specify an interval in the 3D cartesian space where you want +have your VTK data. This interval is defined through a list, one for each axis ``x``, ``y``, ``z``. +Each list contains in order its lower and upper border and resolution in that direction. +In this case, we can for example extract the data from the physical space that was simulated, +so we can take the required values from the namelist. Afterwards, we export the `Field` +data proportional to the laser intensity using ``build3d``:: + + build3d_interval = [[0,S.namelist.Lx,S.namelist.dx]] + build3d_interval.append([-S.namelist.Ltrans,S.namelist.Ltrans,S.namelist.dtrans]) + build3d_interval.append([-S.namelist.Ltrans,S.namelist.Ltrans,S.namelist.dtrans]]) + E2 = S.Field.Field0("El**2+Er**2+Et**2",build3d = build3d_interval ) + +Note how we had to specify the cylindrical components of the fields. +You do not have to export all the physical space or to use the same resolution +specified in the namelist. For example, to reduce the amount of exported data +you may choose to subsample the physical space with a coarser cell length. + +**Action**: Try to define a Laguerre-Gauss beam profile in ``"AMcylindrical"`` geometry +and simulate the same case you have simulated in ``"3Dcartesian"`` geometry. +You will need some trigonometry to decompose the field in azimuthal modes, as +described in the `documentation `_. + + diff --git a/_sources/advanced_wakefield.rst.txt b/_sources/advanced_wakefield.rst.txt new file mode 100644 index 0000000..5fc64e2 --- /dev/null +++ b/_sources/advanced_wakefield.rst.txt @@ -0,0 +1,107 @@ +2D laser wakefield acceleration +------------------------------------- + +The goal of this tutorial is to give an introduction to Laser Wakefield acceleration simulation with :program:`Smilei`. +The following features will be addressed: + +* The moving window in order to follow the laser propagation. +* Variations on Silver-Muller transverse boundary conditions. +* Particle Binning diagnostic. +* Dynamic load balancing. + +The simulation used for this tutorial is relatively heavy so make sure to submit the job on 160 cores at least. + +Disclaimer: This tutorial is done in 2D which is not physically relevant. Proper simulation of this kind must be done in 3D +or in cylindrical geometry with azimuthal mode decomposition (see the related tutorial). +Even in 2D, this case is a bit heavy with respect to the other tutorial and can not be run on a laptop. +We suggest using around a hundred cores to run this tutorial in a reasonable time. + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^^^ + +An ultra high intensity laser enters an under dense plasma. +It propagates in the plasma and creates a non linear plasma wave in its wake. +Electrons from the plasma are eventually trapped in this wave and accelerated to high energies. + +Step by step tutorial +^^^^^^^^^^^^^^^^^^^^^^^^ + +Download `this input file `_ and open it with your favorite editor. +Keep open a page with the `documentation for the namelist `_ to follow the tutorial's steps. + +.. rubric:: 1. Transverse reflections + +Absorbing Silver-Muller boundary conditions are chosen for all faces. +By default, the optimal absorption angle is set to be normal to all faces. +In other words, the laser will be optimally absorbed on the +X face. + +The box is initially empty of plasma. + +To visualize e.g. the density ``-Rho`` and the laser ``Ey``, try:: + + import happi; S=happi.Open() + S.Probe.Probe1("-Rho").slide() + S.Probe.Probe1("Ey").slide(figure=2) + +**Action**: Try to run the simulation and observe laser absorption on the Ymin and Ymax faces with the Probe diagnostic. Notice that a fraction of the laser +is reflected back into the simulation domain. This is a numerical artefact induced by non perfect absorbing boundary conditions. + +**Hint**: In order to see more details, you can manually setup the color scale extrema in ``happi`` by using the ``vmin`` and ``vmax`` optional arguments. + +.. rubric:: 2. Optimize absorbing boundary conditions + +In order to reduce these reflexions, one can tune the Silver-Muller boundary conditions. + +**Action**: Change the Silver-Muller absorption angle in order to smoothly handle the laser at the transverse boundary. +Refers to the documentation in order to fix a proper absorbing vector. + +**Hint**: The absorbing vector :math:`k_{abs}` must be as much aligned as possible with the wave vector of the pulse you need to absorb but +it must keep a non zero normal component. + +.. rubric:: 3. Moving Window + +Now that the laser propagates without interfering with the simulation too much, we are interested in looking at the laser propagation over several box lengths. +Notice the ``MovingWindow`` block in the `documentation for the namelist `_. +This allows the simulation domain to constantly shifts toward the `x` direction in order to follow the laser propagation. + +**Action**: Give a proper velocity and start time to the moving window in order to follow the laser pulse and observe it enter the plasma. +Remember that the window speed is normalized by `c` as usual. +Increase the number of iterations from `3000` to `38000`. +This is a rather long simulation so make sure to use at least 160 cores. + +**Hint**: Remember that a variable can be given as a function of variables from other blocks. For instance, the grid length along x can be called as +``Main.grid_length[0]``. + +.. rubric:: 4. Particle binning + +Some electrons have been trapped and accelerated in the wakefield of the laser. +We can use the ``ParticleBinning`` diagnostic in order to visualize them in phase space:: + + S.ParticleBinning(0).slide() + +**Action**: Visualize the particle binning diagnostic and evaluate the accelerated beam energy. + +**Hint**: In order to see more details, also here you can manually setup the color scale extrema in ``happi`` by using the ``vmin`` and ``vmax`` optional arguments. + +**Hint**: Check the documentation in order to know the default normalization for energy. + +.. rubric:: 5. Performances diagnostic + +Do you feel like the load is correctly balanced? Check it via the ``Performance`` diagnostic! + +**Action**: Use the ``Performance`` diagnostic to observe load imbalance. + +**Hint**: Pick a specific quantity like "timer_particles" in order to highlight the imbalance. The :program:`timer_total` quantity is not relevant since it adds up all imbalances which compensate each other. + +.. rubric:: 6. Optimize simulation + +**Action**: Use the dynamic load balancing to improve the code performances, using the ``LoadBalancing`` block described in the namelist documentation. +Make sure to run this new simulation in a different directory in order to compare your performance diagnostics. Check that imbalance is reduced. + +**Hint**: Does the gain in performance compensate the cost of the dynamic load balancing ? If not, you probably set a too frequent load balance. +Comments: In that case load imbalance mostly builds up only at the end of the simulation. This is why performance gain is not spectacular. + + + diff --git a/_sources/advanced_wakefield_AMcylindrical.rst.txt b/_sources/advanced_wakefield_AMcylindrical.rst.txt new file mode 100644 index 0000000..07e5069 --- /dev/null +++ b/_sources/advanced_wakefield_AMcylindrical.rst.txt @@ -0,0 +1,359 @@ +Azimuthal-mode-decomposition cylindrical geometry +------------------------------------------------------ + +The goal of this tutorial is to give an introduction to the use of the cylindrical geometry +with azimuthal Fourier decomposition in :program:`Smilei`. +The chosen physical configuration is a case of laser wakefield acceleration. +This set-up will allow us to address advanced features that are available +also in other geometries. +The following topics will be addressed: + +* Understand the concept of azimuthal mode decomposition +* Set up a simulation in this geometry +* Automatic conversion of the output to SI units (``pint`` Python module required) +* The analysis of the grid fields in AM cylindrical geometry +* Observation of the effect of Perfectly Matched Layers (feature available also in other geometries) +* Reduce the effects of the Numerical Cherenkov Radiation (with features available also in other geometries). + +With 8 MPI processes and 10 OpenMP threads per MPI process, the simulation should need a few minutes. + + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^^^ + +An high intensity laser pulse, linearly polarized in the ``y`` direction, enters an under dense plasma. +It propagates in the plasma in the positive ``x`` direction and creates a non linear plasma wave in its wake. +The plasma density has a sharp density transition at its start, which triggers +the injection of an electron beam in the plasma wave. The plasma wave longitudinal +electric fields accelerate the electron beam. + +The moving window in the namelist has been set to contain the laser and the first wake period in the simulation window. + + +.. note:: + + The simulation in this tutorial uses a few macro-particles per cell and a coarse mesh too keep the + computational time reasonable. Physically relevant simulations of the considered phenomena would + require more macro-particles and a finer mesh. Apart from the numerical artefacts whose + mitigation will be addressed in this tutorial, the noise in the grid quantities will be caused + also by the small number of macro-particles. + +---- + + +A subtlety: why ions are not present? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Maxwell's equations and the continuity equation :math:`\nabla\cdot\mathbf{J}=-\partial_t\rho` +(which is true also for the single species) imply that :math:`\nabla\cdot\mathbf{E}-\rho` remains +constant throughout the simulation +(see `this `_). +This can be written :math:`\nabla\cdot\mathbf{E}-\rho_e-\rho_i=\nabla\cdot\mathbf{E_0}-\rho_{e0}-\rho_{i0}`. +If we consider ions immobile, then this becomes :math:`\nabla\cdot\mathbf{E}-\rho_e=\nabla\cdot\mathbf{E_0}-\rho_{e0}`, +because the ion continuity equation implies that if :math:`\mathbf{J}_{i}=0` then :math:`\rho_i=\rho_{i0}`. +Note that ions do not appear anymore so that they can be discarded from the simulation. +Assuming also :math:`\rho_{e0}+\rho_{i0}=0` and the initial field :math:`\mathbf{E_0}` being divergence free, +we have :math:`\nabla\cdot\mathbf{E}=\rho_e+\rho_{i0}` at all times. +The system will evolve as if there were ions, without having a real ion ``Species``. +This is a good approximation in our case: plasma oscillations driven by a short +laser pulse with the intensity used in this tutorial +do not substantially move the ions. Indeed, the ion mass is at least 2000 times +greater than the mass of an electron, so the characteristic timescales of the +ion motion are much greater than those of the electron motion. Discarding ions +represents an important gain of computational time. +If we were interested in phenomena like ionization or ion motion, +we would have needed to explicitly define an ion ``Species``. + +---- + + + +Azimuthal-mode-decomposition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In some physical situations like the one of this tutorial, the phenomena of interest have a cylindrical geometry or are very near to be cylindrically symmetric. + +The electromagnetic fields can then be decomposed in Fourier azimuthal modes (where the azimuthal angle is defined with respect to the propagation axis of the laser). +Each mode is defined on a 2D grid, where the two dimensions are the longitudinal and radial ones. + +In this case, Maxwell's Equations can evolve independently the 2D azimuthal modes, and to save time we can retain only a certain number of azimuthal modes, +without losing the relevant physics. In the case simulated in this tutorial, using only two azimuthal modes allows to catch the relevant physics. +The particles, on the other hand, move in the 3D space, pushed by the 3D Cartesian fields reconstructed from the electromagnetic azimuthal modes. +With this powerful technique, 3D features can be simulated at the cost of approximately N 2D simulations, where N is the number of modes we keep in the simulation. + +More details on the Azimuthal modes decomposition can be found `here `_. + +Simulation setup +^^^^^^^^^^^^^^^^^^^^^^^^ + +An input file to simulate laser wake excitation in this geometry will be very similar to a namelist in 2D geometry, with some important differences. +Check them in the input file: + +* The selected geometry is ``AMcylindrical`` + +* The grid resolution is given by a longitudinal and radial resolution, since the azimuthal modes are defined on a 2D grid + +* The number of azimuthal modes simulated is set in ``number_of_AM``. In this case only two of them are necessary to reproduce the relevant physics phenomena + +* The laser can be defined through the ``LaserGaussianAM`` block + +* When you define a plasma density profile, it will be defined with two coordinates ``(x,r)`` + +* Still in the plasma density profile definition, remember that ``r=0`` corresponds to the lower boundary of the grid, i.e. the laser propagation axis + +* The ``Probes`` origin and corners are defined with three coordinates, since they will interpolate the fields in the 3D space as if they were macro-particles in a 3D simulation. + + + +---- + +Conversion to SI units +^^^^^^^^^^^^^^^^^^^^^^^^ + +We have specified the ``reference_angular_frequency_SI`` in the ``Main`` block +of our input namelist. Therefore, if you have built ``happi`` with the ``pint`` Python module, +you should be able to automatically convert the normalized units of the outputs +towards SI units, as will be shown in the commands of this tutorial. + +To do this, while opening the diagnostic you will `specify the units in your plot `_, +e.g. ``units = ["um","GV/m"]``. If ``happi`` was not built with the ``pint`` module +or if you want to see the results in normalized units, just omit these units +and remember to adjust the ``vmin`` and ``vmax`` of your plot commands. + + +---- + + +Step by step tutorial +^^^^^^^^^^^^^^^^^^^^^^^^ + +Download `this input file `_ , open it with your favorite editor and run the simulation. +Then, open the results:: + + import happi + S = happi.Open("/example/path/to/the/simulation") + +.. rubric:: 1. Field diagnostic + +Now let's have a look at the grid fields, for example the electron density:: + + S.Field.Field0("-Rho",theta = 0.,units=["um","pC/cm^3"]).plot(figure=1, vmin = 0., vmax=1.5e12) + +In the previous command we have specified a certain angle ``theta = 0`` (i.e. the demi-plane including the positive ``y`` coordinates). +With the ``Field`` diagnostic, you can virtually specify any angle ``theta``. +See the reference frame `here `_ for the definition of this angle. + +At the cost of approximately N 2D simulations (N is the number of azimuthal modes, two in this case), you can obtain the fields in all the 3D space, like in a 3D simulation. +Note that in the ``Field`` diagnostic you will see only half of the plane, as the ``Field`` diagnostics shows the fields on the grid, defined on a half-plane in this geometry. + +By default, the last command we used will plot the last timestep available. You can also slide along the available timesteps:: + + S.Field.Field0("-Rho",theta = 0.,units=["um","pC/cm^3"]).slide(figure=1, vmin = 0., vmax=1.5e12) + +In the last command no azimuthal mode was specified. By default, if no mode is specified the reconstruction with all the modes is performed. + +To plot a specific mode (in this case the mode ``0``), you can use:: + + S.Field.Field0("-Rho",theta = 0.,units=["um","pC/cm^3"],modes=0).plot(figure=1, vmin = 0., vmax=3e12) + +The main azimuthal mode of the plasma wave in the wake of the laser is the mode 0. The mode 0 has a complete cylindrical symmetry. + +The azimuthal mode of the laser is the mode ``1``. +To see the transverse field of the laser, we can plot the mode ``1`` of +the transverse electric field (i.e. ``Er``):: + + S.Field.Field0("Er",theta=0.,modes=1,units=["um","TV/m"]).plot(figure=2,vmin=-20,vmax=20,cmap="seismic") + +On ``theta=0`` it will correspond ``Ey`` with our choice of laser polarization. + +You can plot the reconstruction of the whole longitudinal electric +field (laser and wake fields, modes ``1`` and ``0`` respectively) through:: + + S.Field.Field0("El",theta=0.,units=["um","GV/m"]).plot(figure=2,vmin=-500,vmax=500,cmap="seismic") + +You can also follow the evolution of any grid quantity (for example here the electron density) through the command ``animate()``:: + + S.Field.Field0("-Rho",theta = 0.,units=["um","pC/cm^3"],modes=0).slide(figure=1, vmin = 0., vmax=3e12) + +.. rubric:: 2. Probe 1D + +A quantity of interest e.g. for plasma acceleration is the longitudinal electric field on the laser propagation axis. +For this purpose, we have defined the first ``Probe`` in the namelist. +Check its ``origin`` and ``corners`` to understand where they are defined. +To be more precise, we have defined it parallel to the axis, but at a small distance from it. +You can try to define another 1D ``Probe`` at the end of the namelist, but you will see that the fields there are very noisy. + +The ``Probes`` interpolate the cartesian components of the fields from the grid, not the cylindrical ones. +Thus, to follow the evolution of the longitudinal electric field you can use:: + + S.Probe.Probe0("Ex",units=["um","GV/m"]).slide(figure=2) + +Note that we haven't specified the mode. The ``Probes`` reconstruct the fields including all the modes. + +.. rubric:: 3. Probe 2D + +In the namelist, a 2D ``Probe`` is defined on the plane parallel to the polarization direction of the laser. +For how we have defined it, you won't see only half plane as in the ``Field`` diagnostic, but both the negative and positive ``y`` points. + +Let's have a look at the evolution of the plasma density:: + + S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=1, vmin = 0., vmax=3e12) + +To see the evolution of the longitudinal electric field and the electric field in the ``y`` direction, you can use:: + + S.Probe.Probe1("Ex",units=["um","GV/m"]).slide(figure=2,vmin=-500,vmax=500,cmap="seismic") + S.Probe.Probe1("Ey",units=["um","TV/m"]).slide(figure=2,vmin=-1,vmax=1,cmap="seismic") + +Note that the ``Fields`` contained the cylindrical components of the fields, but the ``Probes`` diagnostics +contain the Cartesian reconstruction of the fields, thus with Cartesian components. + +---- + + +Perfectly Matched Layers +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Imperfect boundary conditions may cause unphysical effects when the laser's intense +electromagnetic fields arrive at the boundaries of the simulation window. +A larger box (transversally) could help fields decay near the boundaries. +However this can easily increase the simulation time beyond an acceptable level, +and only to avoid reflections, adding to the domain some physical regions where +no phenomenon of interest happens. + +Therefore, to avoid this inefficient approach, this namelist uses improved +boundary conditions called `Perfectly Matched Layers `_, +which add some cells to the simulation borders filled with a fictious medium +where the fields are damped and not reflected back inside the physical simulation window. +Note that these additional cells are not visible to the user. + +The Perfectly Matched Layers are activated in the ``Main`` block through:: + + EM_boundary_conditions = [ + ["PML","PML"], + ["PML","PML"], + ], + + number_of_pml_cells = [[20,20],[20,20]], + +**Action**: How do the results change if you decrease the number of PML cells +from 20 to 5? Are the fields more or less noisy? You may need to saturate the +colormap to see differences. +Check the field with:: + + S.Probe.Probe1("Ey",units=["um","TV/m"]).slide(figure=2,vmin=-1,vmax=1,cmap="seismic") + +We recommend to launch this simulation in a different directory to be able to +compare the two simulations. You should find some differences especially at +the window borders. + +**Action**: What happens if instead of the ``"PML"`` boundary conditions you use +the more classic following conditions?:: + + EM_boundary_conditions = [["silver-muller","silver-muller"],["buneman","buneman"],] + +We recommend to launch this simulation in a different directory to be able to +compare the two simulations. As in the previous exercise, check the fields at the border. +Small differences given by the presence (or not) of reflections at the borders +can have visible effects on the accelerated electron beam dynamics. +For example, check the shape of the electron beam by visualizing the electron +density:: + + S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=1, vmin = 0., vmax=3e12) + +How large should the simulation window be to avoid reflections without a Perfectly +Matched Layers? How much does the simulation time change with a larger window without +Perfectly Matched Layers? + +---- + + +Coping with the Numerical Cherenkov Radiation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The finite difference solver used in the simulation (``maxwell_solver="Yee"`` +is used by default) introduces a numerical dispersion in the wave propagation. +For example, the laser and plasma fields propagating in the `x` direction as in +the simulation of this tutorial are slowed down and this effect is stronger when +the timestep is set increasingly smaller compared to the cell length along `x`. +To reduce the dispersion ideally the normalized timestep should be as near as +possible to the normalized cell length along `x`. + +The interaction of relativistic macro-particles with these numerically slowed waves +generates a purely numerical artifact called Numerical Cherenkov Radiation, which +manifests as a high frequency electromagnetic fields around relativistic macro-particles +as (e.g. in accelerated electron beam in laser wakefield acceleration). These spurious +fields have visible effects on the simulated dynamics of the accelerated beams +and can easily propagate in the simulation window. Therefore, in order to have +more physically relevant results, some technique must be used to cope with this effect. +Unfortunately there is no universal solution that can remove the effects of the Numerical +Cherenkov Radiation in all physical set-ups that can be simulated and without +considerably increasing the simulation time, thus the user +must find the technique that yields the desired accuracy-performance compromise +depending on their case of interest. + +In this tutorial we will test the use of a low-pass filter on the currents and +a force interpolation technique that can reduce the effects of the Numerical Cherenkov +Radiation on the macro-particles. + +One of the simplest techniques to reduce the Numerical Cherenkov Radiation is to +filter the currents with a binomial filter. +Try to launch a new simulation using the same namelist, but decommenting the block:: + + CurrentFilter( + model = "binomial", + passes = [2], + ) + +**Action**: compare the results of the two simulations, with an without filter. +For example, you can use the ``Probes`` to check a combination of ``Probes`` proportional +to the force acting on the macro-particles in the `y` direction:: + + S.Probe.Probe1("Ey-c*Bz").slide(vmin=-0.02,vmax=0.02,cmap="seismic") + +Without the filter, you will see the high frequency oscillations of the numerical +Cherenkov Radiation, that have a visible effect also on the shape of the +accelerated electron beam inside the plasma waves. You can check this with:: + + .Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=1, vmin = 0., vmax=3e12) + +The electron beam simulated with the filter should be transversely smaller. +This happens because the filter reduces the growth of the spurious radiation, +whose effects include the heating the electron beams. +Using a low pass filter is not an ideal solution, since it can damp high frequencies +that are physical and adds time dedicated to communications, especially when +the number of filter passes is increased to further reduce the numerical artifact. + +A second solution, that we recommend, is the use of a force interpolation technique +called B-TIS3 described in +`P.-L. Bourgeois and X. Davoine, Journal of Plasma Physics 89 (2023) `_, +that does not remove the Numerical Cherenkov Radiation, but considerably reduces +its effects on the macro-particles, with minimal increase of the simulation time. + +**Action**: Run a new simulation (without filter), changing the variable ``use_BTIS3_interpolation`` +before the ``Main`` block to ``True``. Note how this changes the ``pusher`` +and adds some fields to the ``Probes`` in the namelist. +Activating the B-TIS3 interpolates the magnetic fields +in a way that is more physically accurate for fields moving close to the speed +of light in the positive `x` direction, and when the normalized timestep is close +to the normalized cell size along `x` (which is typical of laser wakefield simulations). +Check how the electron beam shape changes as you have done before with the filter +and then check this combination of ``Probes``:: + + S.Probe.Probe1("Ey-c*Bz",units=["um","GV/m"]).slide(figure=2,vmin=-200,vmax=200,cmap="seismic") + +The differences are small compared to the simulation with B-TIS3 and you will +still see the Numerical Cherenkov Radiation in the grid. However, in this simulations +the macro-particles are not pushed on the `y` direction with these fields, +but by a combination of fields that uses the B-TIS3 fields when necessary. +The force along `y` acting on the macro-particles in this case is proportional to:: + + S.Probe.Probe1("Ey-c*Bz",units=["um","GV/m"]).slide(figure=3,vmin=-200,vmax=200,cmap="seismic") + +Here you should see visible differences, especially near the electron beam. + +**Action**: After you will have learned how to analyse the ``TrackParticles`` +diagnostic in the next tutorials, compare the final electron beam +parameters with and without the techniques that we have explored to reduce +the effects of the Numerical Cherenkov Radiation. diff --git a/_sources/advanced_wakefield_electron_beam.rst.txt b/_sources/advanced_wakefield_electron_beam.rst.txt new file mode 100644 index 0000000..2695261 --- /dev/null +++ b/_sources/advanced_wakefield_electron_beam.rst.txt @@ -0,0 +1,377 @@ +Field initialization for a relativistic electron bunch +----------------------------------------------------------- + +The goal of this tutorial is to give an introduction to the use of the the +relativistic-species field initialization with :program:`Smilei`. + +With 8 MPI processes and 5 OpenMP threads the simulation of this tutorial should take a few minutes +(remember to set the number of OpenMP threads as explained in :doc:`basics_setup`). +The relativistic Poisson solver is parallelized through MPI but not with OpenMP, +sometimes for larger simulations a larger number of MPI processes is necessary +to reduce the time spent in field initialization. + +The following features will be addressed: + +* Automatic conversion of the output to SI units (``pint`` Python module required) +* Initialization of a `Species` through a `numpy` array +* Initialization of the electromagnetic field with relativistic species +* Observation of the plasma wakefield driven by a relativistic electron bunch +* Analysis of the bunch evolution with the ``DiagParticleBinning`` diagnostic +* Analysis of the bunch evolution with the ``TrackParticles`` diagnostic +* Observation of the effect of Perfectly Matched Layers + + + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^^^ + +A relativistic electron bunch enters a plasma in a ``AMcylindrical`` geometry. It propagates in +the plasma and creates a non linear plasma wave in its wake. + +.. note:: + + This tutorial is done in ``AMcylindrical`` with one azimuthal mode, thus assuming perfect cylindrical geometry in the fields (see also the related tutorial). + +Initializing our bunch through a plasma density and a Maxwell-JΓΌttner momentum distribution +would not allow us to set a certain emittance for the bunch +(this parameter is related to the transverse phase space distribution of the bunch particles). +Also, initializing a converging/diverging bunch or a particle distribution obtained from a beam +transport code would not be possible with this kind of initialization. + +To manage these situations, an initialization of a ``Species`` with a ``numpy`` array is more suitable. +The ``Species`` called ``electron_bunch`` in our input file the input file `advanced_beam_driven_wake.py `_ +will receive two ``numpy`` arrays, ``array_position`` and `array_momentum` in the ``position_initialization`` and ``momentum_initialization`` +arguments. + +Our bunch has ``npart`` particles, thus the shapes of these arrays will be ``(4,npart)`` +and ``(3,npart)`` respectively. The ``array_position`` contains the coordinates of our bunch particles. +Remember that the origin of the axes is set on the propagation axis in ``AMcylindrical`` geometry, +so the transverse coordinates may be positive or negative. Each of the first three rows represents the ``x``, ``y``, ``z`` +coordinates of the particles, while each column represents a particle. +The last row represents the weight given to each particle, related to the macro-particle charge. +Similarly, the ``array_momentum`` contains the particles momenta ``px``, ``py``, ``pz``. +With this initialization the density profile of the ``Species`` will be computed from the position of the +particles, and not from a profile given in the ``Species`` block as in other tutorials. + +In our case, we generate the particles and momenta distribution of the electron bunch +assuming a gaussian distribution in the momentum space, with custom average energy, emittance, rms sizes, etc. +The bunch is assumed as waist (i.e. not converging, nor diverging), but manipulating the ``numpy`` arrays of the +bunch particles it is easy to generate a more realistic electron bunch. + +More details on the initialization through numpy arrays or from a file can be +found `here `_. + + +.. note:: + + The simulation in this tutorial uses a few macro-particles per cell and a coarse mesh too keep the + computational time reasonable. Physically relevant simulations of the considered phenomena would + require more macro-particles and a finer mesh. Apart from the numerical artefacts whose + mitigation will be addressed in this tutorial, the noise in the grid quantities will be caused + also by the small number of macro-particles. + +---- + + +Preparing the case study +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Download the input file `advanced_beam_driven_wake.py `_ and open it with your +favorite editor. Note how the physical quantities are defined. +First the physical constants for conversions and then used to convert the physical quantities +of interest, e.g. the bunch size, from SI units to normalized units. + +The plasma electrons are initialized in a block ``Species`` named ``plasmaelectrons``. +The electron bunch driving the plasma wave is initalized in +a block ``Species`` named ``electronbunch``. + +The flag ``relativistic_field_initialization = True`` in the ``electronbunch`` `Species` +means that its self-consistent electromagnetic fields will be computed at the time when +this ``Species`` starts to move, in this case at ``t=0`` because ``time_frozen=0``. +The procedure used in :program:`Smilei` for this field initialization is detailed +`here `_. + +These electromagnetic fields will propagate with the bunch and push away the plasma electrons +(just like an intense laser pulse would do with its ponderomotive force) +triggering a plasma oscillation. + + +.. note:: + + You will see that the plasma does not fill all the simulation window. + This is because we want to include the electron bunch field in the window, but the plasma particles creating the plasma oscillations + are only those radially near to the electron beam. Plasma particles at greater radial distances would not contribute to the relevant physics, but they would + require additional computational time. Thus we can omit them to perform the simulation more quickly without losing relevant phenomena. + +.. note:: + + The moving window in the namelist has been set to contain the electron bunch and the first wake period in the simulation window. + + +---- + +Conversion to SI units +^^^^^^^^^^^^^^^^^^^^^^^^ + +We have specified the ``reference_angular_frequency_SI`` in the ``Main`` block +of our input namelist. Therefore, if you have built ``happi`` with the ``pint`` Python module, +you should be able to automatically convert the normalized units of the outputs +towards SI units, as will be shown in the commands of this tutorial. + +To do this, while opening the diagnostic you will `specify the units in your plot `_, +e.g. ``units = ["um","GV/m"]``. If ``happi`` was not built with the ``pint`` module +or if you want to see the results in normalized units, just omit these units +and remember to adjust the ``vmin`` and ``vmax`` of your plot commands. + + +---- + + +Relativistic field initialization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Run the simulation and open the results with ``happi``:: + + import happi + S = happi.Open("example/of/path/to/the/simulation") + +To visualize the initial bunch density and transverse electric field on the ``xy`` plane, use:: + + S.Probe.Probe1("-Rho",timesteps=0.,units=["um","pC/cm^3"]).plot(figure=1,vmin=0) + S.Probe.Probe1("Ey",timesteps=0.,units=["um","GV/m"]).plot(figure=2,cmap="seismic",vmin=-1.6,vmax=1.6) + +Note that the bunch is initially in vacuum. If a ``Species`` is initialized inside the plasma, +activating the initialization of its field creates non-physical forces. + +The bunch will move in the positive ``x`` (longitudinal) direction towards the plasma. +The field ``Ex`` is much lower than the transverse field ``Ey`` as for a relativistic moving charge. +The field ``Ey`` is the field that pushes the plasma electrons away from the bunch's path and triggers the plasma oscillations +in the bunch wake. + +**Action**: What happens to the fields if you increase the number of bunch particles ``npart``? +Are the fields more or less noisy? + +.. note:: + You will see from the simulation log that the iterative relativistic Poisson solver + does not converge in this simulation with the chosen maximum number of iterations + (``relativistic_poisson_max_iteration`` in the ``Main`` block). + However, the field obtained from this initialization will be accurate enough to + see a plasma wave driven by the electron beam's field and learn from this tutorial. + A more accurate initialization would probably require more iterations, increasing + the initialization time. There is no value for ``relativistic_poisson_max_iteration`` + or for the acceptable error ``relativistic_poisson_max_error`` suited + for all physical problems. The user should find the values suited to their + case of interest through careful trial and error. + + +---- + + +Nonlinear, beam-driven plasma oscillations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The plasma electrons pushed away from the bunch path will be attracted back to their original positions +by the immobile ions and start to oscillate. + +Visualize the nonlinear plasma wave forming in the wake of the electron bunch:: + + S.Probe.Probe0("-Rho",units=["um","pC/cm^3"]).slide(figure=1) + S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=2) + +The evolution of the longitudinal electric field on axis, very important for acceleration of another particle bunch, +can be visualized through:: + + S.Probe.Probe0("Ex",units=["um","GV/m"]).slide(figure=4) + S.Probe.Probe1("Ex",units=["um","GV/m"]).slide(figure=5,cmap="seismic",vmin=-2,vmax=2) + +The wave form has a shape of a sawtooth wave, +since the set-up is in the so-called nonlinear regime. + +Try to change the total bunch charge ``Q_bunch`` and rerun the simulation, for example multiplying it by a factor +``0.05`` (a linear regime), ``0.75`` (a weakly nonlinear regime). What happens to the ``Ex`` waveform? + + +**Action**: What happens to the fields if you increase the number of particles in the plasma? +Are the fields more or less noisy? + + +---- + +Particle Binning diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's study in detail the evolution of the electron bunch. +To start, the energy spectrum can be found using the first ``ParticleBinning`` diagnostic defined in the namelist:: + + S.ParticleBinning(0,units=["MeV","1/cm^3/MeV"]).slide() + +Note how the bunch energy spread is increasing and the average energy is decreasing as it drives the plasma waves in its propagation. + +The longitudinal phase space can be seen through the second ``ParticleBinning`` diagnostic of the namelist:: + + S.ParticleBinning(1,units=["um","MeV","1/cm^3/MeV"]).slide() + +Note how the bunch tail is losing its energy. That zone of the bunch is where the decelerating electric field +is generated. + +**Action**: Study the remaining ``ParticleBinning`` diagnostics, which contain the bunch distribution in transverse phase space +(``y`` and ``z`` phase space planes respectively). Note how the transverse coordinates can be negative in cylindrical geometry. + + +---- + +Track Particles diagnostic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Note how we had to specify the limits of the axes of our ``ParticleBinning`` diagnostics. +This can be a considerable constraint when these boundaries are not known. +Furthermore, if we wanted to compute more complex quantities derived from the +positions and momenta of the electron bunch, e.g. the energy spread of its longitudinal +slices, it would have not been easy to do with ``ParticleBinning`` diagnostics. +Finally, sometimes we want to export the final bunch distribution in the phase space, +i.e. the 3D positions and 3D momenta of all particles, e.g. to use them as input of +a beam dynamics code to design a magnetic transport line, so we would need the coordinates +of each macro-particle. + +For these reasons, often in wakefield simulations it is preferrable to use the +``TrackParticles`` diagnostic. This diagnostic allows to select a ``Species`` +and optionally a filter (e.g. macro-particles above a certain energy). The diagnostic +can give the id numbers, position, momentum and weight of the macro-particles of +that ``Species`` satisfying the filter. + +**Note** Specifying a filter can be essential to avoid exporting exceedingly large amount of +data. For example, in a laser wakefield acceleration where the accelerated electron +beam comes from the plasma itself, not specifying a filter would export the +data of all the plasma species macro-particles. In this case, using a filter e.g. +select only the macro-particles above a certain energy, would likely export the +macro-particles of interest for typical laser wakefield acceleration studies. + +In this simulation's namelist, a ``TrackParticles`` block is specified +to export the data of all the electron bunch macro-particles. +The bunch does not have many macro-particles, so we don't need to specify a filter. + +You can extract the ``TrackParticles`` data of a given ``timestep`` with:: + + # Read the DiagTrackParticles data + import numpy as np + chunk_size = 60000 + species_name = "electronbunch" + timestep = 0. + track = S.TrackParticles(species = species_name, chunksize=chunk_size, sort=False) + for particle_chunk in track.iterParticles(timestep, chunksize=chunk_size): + + + # positions + x = particle_chunk["x"] + y = particle_chunk["y"] + z = particle_chunk["z"] + + # momenta + px = particle_chunk["px"] + py = particle_chunk["py"] + pz = particle_chunk["pz"] + p = np.sqrt((px**2+py**2+pz**2)) + + # weights, proportional to che macro-particle charge + w = particle_chunk["w"] + + # energy + E = np.sqrt((1.+p**2)) + + Nparticles = np.size(w) + print(" ") + print("Read "+str(Nparticles)+" macro-particles from the file") + + +This way, you will have some numpy arrays, with the coordinates, momenta etc of all +the electron bunch macro-particles at the timestep ``timestep``, in normalized units. +In this case we exported the first timestep. You can find a list of the available +timesteps with:: + timesteps = track.getAvailableTimesteps() +Each array has a size equal to the number of macro-particles. +The argument ``chunksize`` denotes the maximum number macro-particles per chunk +you are reading. Extracting data in chunks avoids reading all the macro-particles at once, +which can be useful with large amounts of data. In this case we just need to read one chunk. + +Using these numpy arrays, you can easily compute derived quantities, e.g. +you can obtain the electron bunch charge by summing the weights of all the +macro-particles (which can in principle vary between macro-particles) and using +the appropriate conversion factor:: + + import scipy.constants + total_weight = w.sum() + weight_to_pC = S.namelist.e * S.namelist.ncrit + weight_to_pC = weight_to_pC * (S.namelist.c_over_omega0)**3 + Q_pC = total_weight * weight_to_pC * 10**(12) + print(" ") + print("Total bunch charge = "+str(Q_pC)+" pC") + +**Action** Check that this is the bunch charge set in the input namelist. + +**Action** Try to extract the evolution of the bunch parameters during the simulation. +Remember that you can extract the available timesteps and then loop the extraction +of the macro-particle arrays over the timesteps. + +**Action** plot the energy spectrum, i.e. the histogram of the macro-particles energies, +and check that the result is the same obtained with the ``ParticleBinning`` diagnostic. +Pay attention to the normalizations of the axes! + +**Action** Adapting this `script `_, +study the evolution of the bunch parameters, e.g. its emittance, energy spread, etc. + +---- + + +Perfectly Matched Layers +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Imperfect boundary conditions may cause unphysical effects when the bunch's intense +electromagnetic fields arrive at the boundaries of the simulation window. +A larger box (transversally) could help fields decay near the boundaries. +However this can easily increase the simulation time beyond an acceptable level, +and only to avoid reflections, adding to the domain some physical regions where +no phenomenon of interest happens. + +Therefore, to avoid this inefficient approach, this namelist uses improved +boundary conditions called `Perfectly Matched Layers `_, +which add some cells to the simulation borders filled with a fictious medium +where the fields are damped and not reflected back inside the physical simulation window. +Note that these additional cells are not visible to the user. + +The Perfectly Matched Layers are activated in the ``Main`` block through:: + + EM_boundary_conditions = [ + ["PML","PML"], + ["PML","PML"], + ], + + number_of_pml_cells = [[20,20],[20,20]], + +**Action**: How do the results change if you decrease the number of PML cells +from 20 to 5? Are the fields more or less noisy? + +**Action**: What happens if instead of the ``"PML"`` boundary conditions you use +the more classic following conditions?:: + + EM_boundary_conditions = [["silver-muller","silver-muller"],["buneman","buneman"],] + +How large should the simulation window be to avoid reflections without a Perfectly +Matched Layers? + +---- + +Acceleration of a witness bunch +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now you know everything necessary to simulate beam-driven plasma acceleration: try to define +a second, smaller electron bunch, with the same energy of the driver bunch, smaller charge and small enough to fit +in the plasma wave and injected in the accelerating phase of the plasma wave (i.e. negative ``Ex``). + +Use the ``numpy`` array initialization method as you have done for the bunch driving the waves. +Study the evolution of the energy spectrum of this witness bunch and check that its average energy is increasing. + + + + + \ No newline at end of file diff --git a/_sources/advanced_wakefield_envelope.rst.txt b/_sources/advanced_wakefield_envelope.rst.txt new file mode 100644 index 0000000..7e0dc50 --- /dev/null +++ b/_sources/advanced_wakefield_envelope.rst.txt @@ -0,0 +1,325 @@ +Envelope model for laser wakefield acceleration +----------------------------------------------------- + +The goal of this tutorial is to give an introduction to the use of the laser +envelope model with :program:`Smilei`. Before starting with this tutorial, we +recommend to complete first the tutorial on :doc:`advanced_wakefield_AMcylindrical`. In that +Tutorial, Laser Wakefield Acceleration is simulated in a standard way, i.e. the +laser is defined through its electromagnetic fields defined on the grid. +We recommend also to complete the tutorial :doc:`advanced_wakefield_electron_beam` +to familiarize with the diagnostics involving the macro-particle quantities. + +With 2 MPI processes and 20 OpenMP threads this simulation should run in a few minutes. +(remember to set the number of OpenMP threads as explained in :doc:`basics_setup`). + +The following features will be addressed: + +* Automatic conversion of the output to SI units (``pint`` Python module required) +* Laser envelope initialization "in the box" +* Initialization of the species interacting with the laser envelope +* Observation of relativistic self-focusing +* Automatic conversion of the output to SI units (``pint`` Python module required) +* Analysis of the grid fields when an envelope is present +* Use of the envelope ionization module. +* Use of the B-TIS3 interpolation scheme with a laser envelope + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^^^ + +An ultra high intensity laser enters an under dense plasma. It propagates in +the plasma and creates a non linear plasma wave in its wake. +The start of the plasma is made of a mixture of hydrogen and nitrogen, while the +rest of the plasma is made of pure hydrogen. The laser field is strong enough to +ionize the hydrogen and the first 5 levels of the nitrogen much before the arrival +of the laser peak field, thus the hydrogen will be assumed ionized and the nitrogen +ionized up to level 5. The field of the laser peak is intense enough to further +ionize the nitrogen ions. Some of the newly released electrons are trapped and +accelerated in the plasma wave behind the laser (hence the name laser wakefield +acceleration with ionization injection). + +The simulation is run with a `Laser Envelope model `_ +for the laser pulse. This allows to simulate the laser-plasma interaction in an underdense plasma +without the need to resolve the high frequency oscillations of the laser pulse. +This way, we can use a coarser cell size along the laser propagation direction `x` and +a coarser timestep, obtaining considerable speed-ups for our simulations. +Thus, although the envelope represents a laser pulse, you won't see the laser oscillations at wavelength +:math:`\lambda_0` since we are using a laser envelope model. + +Furthermore, the simulation of this tutorial is run in cylindrical geometry +(only one azimuthal mode), which further speeds-up the simulations. +The envelope model is available also in other geometries. + +.. note:: + + The simulation in this tutorial uses a few macro-particles per cell and a coarse mesh too keep the + computational time reasonable. Physically relevant simulations of the considered phenomena would + require more macro-particles and a finer mesh. Apart from the numerical artefacts whose + mitigation will be addressed in this tutorial, the noise in the grid quantities will be caused + also by the small number of macro-particles. + + +---- + + +Preparing the case study +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Download `this input file `_ and open it with your +favorite editor. + +First, note how we defined variables for physical constants and for conversions +from SI units to normalized units. Specifying a reference length, in this case +the laser wavelength, is important to treat ionization. This information is found +in the ``reference_angular_frequency_SI`` argument in the ``Main`` block. + +The laser is initialized via the use of ``LaserEnvelope`` +block. The laser envelope will be initialized in the box. The longitudinal +profile of the laser is called ``time_envelope`` in analogy with a standard +laser, but it does not represent a temporal variation during the simulation +as when the laser is injected from a window border, as in the tutorial in +:doc:`advanced_wakefield_AMcylindrical`. +To visualize it more easily, think of substituting the time ``t`` with the ``x`` coordinate. +Thus, the center of the laser profile (i.e. its position at ``t=0``) must be chosen +inside the simulation domain. Note that the focus of the laser can have a longitudinal +position different from the laser center. + +We have used the ``"explicit_reduced_dispersion"`` solver for the envelope equation. +For short propagation distances without strong self-focusing (see later in this tutorial) +you can use also the quicker ``"explicit"`` solver. +However, when long propagation distances or quick envelope evolutions +occur in a plasma we recommend to use ``"explicit_reduced_dispersion"`` to have more accurate results. +In those situations the results using the two solvers can be considerably different. +The stability condition for ``"explicit_reduced_dispersion"`` is more strict, so it is +possible that you will need a smaller integration timestep to use it. + + +**Action** Run the simulation and open the results:: + + import happi + S = happi.Open("/example/path/to/the/simulation") + + +---- + +Conversion to SI units +^^^^^^^^^^^^^^^^^^^^^^^^ + +We have specified the ``reference_angular_frequency_SI`` in the ``Main`` block +of our input namelist. Therefore, if you have built ``happi`` with the ``pint`` Python module, +you should be able to automatically convert the normalized units of the outputs +towards SI units, as will be shown in the commands of this tutorial. + +To do this, while opening the diagnostic you will `specify the units in your plot `_, +e.g. ``units = ["um","GV/m"]``. If ``happi`` was not built with the ``pint`` module +or if you want to see the results in normalized units, just omit these units +and remember to adjust the ``vmin`` and ``vmax`` of your plot commands. + +---- + +A subtlety: the envelope of the vector potential vs the envelope of the electric field +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +First, let's study the laser propagation. Note the ``MovingWindow`` block and +that the window starts moving since the very first iteration of the simulation. +This allows the simulation domain to constantly shift toward the `x` direction +in order to follow the laser propagation. + +Plot the values on the propagation axis of the fields called ``Env_A_abs`` and ``Env_E_abs``, +with the same scale. For this, use the diagnostic ``Fields`` (if the timestep is +not provided, the last one is plotted by default):: + + Env_A=S.Probe.Probe0("Env_A_abs", label="Env_A") + Env_E=S.Probe.Probe0("Env_E_abs", label="Env_E") + happi.multiSlide(Env_A,Env_E) + +Here we have used the ``happi`` command ``multiSlide``, that it is analogous to +the command ``multiPlot``, but allows to slide between multiple timesteps. +Note that we have not converted these outputs to SI units, since in laser wakefield +acceleration the peak normalized field (often called ``a0``) of the laser pulse can give important information +on the wave excitation regime (nonlinear for ``a0 > 1.`` for example, linear for ``a0 << 1.``). + +Do you see some differences when the simulation advances? +The complex envelope field used for calculations is the envelope of the vector potential +:math:`\tilde{A}`. In the diagnostics, you can plot its absolute value through ``Env_A_abs``. +Instead, the field ``Env_E_abs`` is the absolute value of the envelope of the electric field :math:`\tilde{E}`, +the latter defined to allow comparisons with the field of a standard laser: +:math:`\tilde{E}=-(\partial_t-ik_0c)\tilde{A}` (see `Smilei's website `_ for the derivation). +Remember that as explained in the documentation, when the laser +temporal variations are quick, the difference between the two fields will be +sensitive. Both the fields are complex quantities, the `abs` means that their +absolute value is plotted. These quick temporal evolutions can occur during the +propagation in plasmas. + +You can see how the two fields evolve differently in this nonlinear case extracting +the data at all timesteps and computing the peak of the field at each timestep:: + + import numpy as np + import matplotlib.pyplot as plt + + dt = S.namelist.dt + timesteps = S.Probe.Probe0("Env_E_abs").getAvailableTimesteps() + + Env_A_abs = S.Probe.Probe0("Env_A_abs").getData() + Env_A_abs = np.asarray(Env_A_abs) + Env_A_abs = np.amax(Env_A_abs,axis=1) + plt.plot(timesteps*dt,Env_A_abs,label="|Env_A|") + + Env_E_abs = S.Probe.Probe0("Env_E_abs").getData() + Env_E_abs = np.asarray(Env_E_abs) + Env_E_abs = np.amax(Env_E_abs,axis=1) + plt.plot(timesteps*dt,Env_E_abs,label="|Env_E|") + + plt.ylabel("field peak [normalized units]") + plt.xlabel("t [normalized units]") + plt.legend() + +In the namelist we have specified a peak value for the field equal to ``a0=1.8``, +and that is the peak value that the laser field in ``Env_E_abs`` would reach in vacuum at the focal plane. +From the previous plot you can see that the laser reaches higher values. +This is due to relativistic self-focusing that occurs in plasmas when the laser +power exceeds the power threshold for the occurrence of this phenomenon. +The interaction of the plasma on the laser pulse propagation is quantified by the +field ``Env_Chi``, which appears in the `envelope equation `_. + +**Action** Visualize in 2D the envelope fields on the plane `xy` through the other ``Probes`` +defined in the namelist, e.g.:: + + S.Probe.Probe1("Env_E_abs").slide() + +---- + + +Wakefield excitation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now let's observe the wakefield formation in the trail of the laser +envelope. Remember that the pusher scheme to use when a laser envelope model is present is +either ``pusher="ponderomotive_boris"`` or ``pusher="ponderomotive_borisBTIS3"``. + +**Action** Check that the defined ``Species`` has a compatible ``pusher`` scheme. + +Through the diagnostic ``Probe`` and the option ``animate`` or ``slide``, you can follow +the envelope propagation and plasma evolution during the simulation. As before, you can plot the +absolute value of the envelope ``Env_E_abs``. + +You can also follow the formation of the plasma wave, plotting the electron density ``Rho``. +To see it more clearly, we recommend the use of the option ``vmax`` in the +``slide()`` or ``plot()`` function, for example:: + + S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=2, vmin=0.,vmax=1.5e12) + +Note the formation of a bubble behind the laser, whose borders are full of +electrons and whose interior is emptied (or almost emptied in some regimes) of electrons. + +The longitudinal electric field on axis, very important for electron +Laser Wakefield Acceleration, can be plotted with the ``Probe`` defined on the propagation axis, +choosing the field ``Ex`` in your diagnostic:: + + S.Probe.Probe0("Ex",units=["um","GV/m"]).slide(figure=3) + +Through the function ``multiSlide``, follow the evolution of the envelope and the of +electron density on the axis:: + + envelope_E = S.Probe.Probe0("20*Env_E_abs",units=["um"],label="20*Env_E_abs") + Ex = S.Probe.Probe0("Ex",label="Ex",units=["um","GV/m"]) + happi.multiSlide(Ex,envelope_E) + +Note that we have multiplied the laser normalized electric field by 10 in the last command +to have a more readable scale in the plot. + +The evolution of both the envelope and the electron density can be studied in 2D at the same time +through the `transparent` argument of the `multiSlide` function. We'll make transparent +all the values of `Env_E_abs` below 1.:: + + Rho = S.Probe.Probe1("-Rho",units=["um","pC/cm^3"],cmap="Blues_r",vmin=0.,vmax=1.5e12) + Env_E = S.Probe.Probe1("Env_E_abs",units=["um"],cmap="hot",vmin=0.8,transparent="under") + happi.multiSlide(Rho,Env_E,xmin=0) + +This way you should see the laser pulse envelope and the plasma wave in the electron density. + + +---- + +Envelope ionization module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As explained in the tutorial for :doc:`advanced_field_ionization`, to correctly model +tunnel ionization it is essential to specify a reference frequency, which is already +done in the ``Main`` block of this tutorial's namelist. + +Afterwards, you have to specify a ``Species`` that will be ionized, in this case ``"nitrogen5plus"``, +whose ``charge`` state at the start of the simulation is lower than its ``atomic_number``. +Note also that you can keep this ``Species`` frozen and at the same time able to be +ionized. This will avoid spending time in moving macro-particles that do not move too much, +as the nitrogen ions of this laser wakefield simulation set-up. + +The new electrons created from the tunnel ionization of this ``Species`` will be +stored in another ``Species``, specified in ``ionization_electrons`` of ``"nitrogen5plus"``. +In our case this ``Species`` at the start of the simulation has zero macro-particles. +We could have chosen an already populated species of electrons like ``bckgelectron``, +but if you want to keep them separated like in this case it can be useful for diagnostics +(although it can take more simulation time, due to cache efficiency). + +To ionize ``"nitrogen5plus"``, a ``ionization_model`` must be selected in its ``Species`` +block. Since we are using a laser envelope model, we must use the ``"tunnel_envelope_averaged"`` model. +Physically tunnel ionization occurs at the peaks of the laser field, but these peaks +are not part of an envelope model, by definition. +How can we model tunnel ionization with a laser envelope model then? +The model ``"tunnel_envelope_averaged"`` uses an ADK ionization rate averaged over the +laser oscillations, and a similar averaging is taken into account when the newly created +electrons are initialized, to correctly recreate their transverse momentum dispersion +and the drift in their `x` direction from tunnel ionization occurring in relativistic regimes. +More details on this model can be found `here `_. + +**Action** Visualize the density of the electrons created through ionization:: + + S.Probe.Probe1("-Rho_electronfromion",units=["um","pC/cm^3"]).slide(figure=2, vmin=0.,vmax=1.5e12) + +Run two new simulations, changing the fraction of the nitrogen dopant in the gas mixture, +stored in the variable ``dopant_N_concentration=0.10`` (i.e. ten percent of nitrogen). +Try a value 1.5 times larger and 1.5 times smaller. How does the ``Rho_electronfromion`` +change? + +**Action** Using the same techniques you have used in the tutorial :doc:`advanced_wakefield_electron_beam`, +try to plot the energy spectrum of the electrons created through ionization. + +---- + +Reducing the effects of Numerical Cherenkov Radiation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As already discussed in this tutorial :doc:`advanced_wakefield_AMcylindrical`, +the use of finite difference solvers for Maxwell's equations introduces a numerical +dispersion, that interacting with relativistic macro-particles will generate +a numerical artefact called Numerical Cherenkov Radiation. +In that tutorial two methods are shown to cope with this artefact, one of which is +the B-TIS3 interpolation scheme described in +`P.-L. Bourgeois and X. Davoine, Journal of Plasma Physics 89 (2023) `_, +that does not remove the Numerical Cherenkov Radiation, but considerably reduces +its effects on the macro-particles, with minimal increase of the simulation time. +Now we will see how to use this feature with a laser envelope model. +The tricky part with an envelope model is that this feature works well only when +the normalized timestep (or ``dt``) is close to the normalized cell length along `x` (or ``dx``), which is +not always compatible with the stability of the envelope solver, expecially +the ``"explicit_reduced_dispersion"``. Try have at least ``dt>0.9*dx`` to use +the B-TIS3, but check that the solver results (i.e. the envelope fields) do not +increase exponentially due to a too high ``dt``. + +**Action**: Run a new simulation, changing the variable ``use_BTIS3_interpolation`` +before the ``Main`` block to ``True``. Note how this changes the ``pusher`` +to ``"ponderomotive_borisBTIS3"`` and adds some fields to the ``Probes`` in the namelist. +Check how the electron beam shape changes:: + + S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=2, vmin=0.,vmax=1.5e12) + +Afterwards, check this combination of ``Probes``, proportional to the force acting +on the macro-particles along the `y` direction:: + + S.Probe.Probe1("Ey-c*BzBTIS3",units=["um","GV/m"]).slide(figure=3,vmin=-20,vmax=20,cmap="seismic") + +What difference do you observe if you compare it with the equivalent combination +in the simulation without the B-TIS3 scheme (using ``Bz`` instead of ``BzBTIS3``)? + + diff --git a/_sources/basics.rst.txt b/_sources/basics.rst.txt new file mode 100644 index 0000000..d3849bf --- /dev/null +++ b/_sources/basics.rst.txt @@ -0,0 +1,12 @@ +.. title:: PIC basics + +PIC basics +========== + +.. toctree:: + + basics_setup + basics_laser_vacuum + basics_thermal_plasma + basics_weibel_twostream + basics_units \ No newline at end of file diff --git a/_sources/basics_laser_vacuum.rst.txt b/_sources/basics_laser_vacuum.rst.txt new file mode 100644 index 0000000..747a262 --- /dev/null +++ b/_sources/basics_laser_vacuum.rst.txt @@ -0,0 +1,272 @@ +Laser Propagation in vacuum +------------------------------------------ + +The goal of this tutorial is to run your first simulation with :program:`Smilei`. +The following points will be addressed: + +* How to prepare an input file +* How to check your input file using the ``test mode`` +* How to access your simulation results +* Get familiar with the `Courant-Friedrich-Lewy` (CFL) condition. + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^ + +Download the input file `laser_propagation_2d.py `_. +Note that this file is written in the *python* language. + +Read through this file and try to understand the contents of the ``Main(...)`` and +``LaserGaussian2D(...)`` blocks. You can obtain details on the meaning of all keywords +in this `documentation page `_. +Note that all units are normalized according to +`these conventions `_. + +A Gaussian (in both space and time) laser pulse enters in the simulation box from +the ``xmin`` side and propagates through the box. + +---- + +Setup the tutorial +^^^^^^^^^^^^^^^^^^ + +As explained in the :ref:`setup page `, you should make a new directory +to run your simulation. This directory should contain the input file that you just downloaded +and the executables ``smilei`` and ``smilei_test``. + + +---- + +Checking your input file in test mode +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The first step is to check that your `input file` is correct. +To do so, you will run (locally) :program:`Smilei` in test mode: + +.. code-block:: bash + + ./smilei_test laser_propagation_2d.py + + +This *test mode* does the same initialization as the normal mode but does not enter the PIC loop. +It provides you with a *log* (what appears on your screen). +What does this *log* tells you? Do you spot any ``ERROR`` message? + +If you did spot an ``ERROR``, can you correct it? If so, correct it, and try again! + +Once you have no more ``ERROR`` message. Do you get ``WARNING`` messages? + + + +---- + +Running the simulation +^^^^^^^^^^^^^^^^^^^^^^ + +Once your simulation `input file` is correct, you can +:ref:`run the simulation `. + +.. code-block:: bash + + ./smilei laser_propagation_2d.py + +Before going to the analysis of your simulation, check the output on the screen (the *log*). + +* What did change compared to the `test mode`? +* Did your run complete correctly? +* Check what output files have been generated: what are they? + + + +---- + +Preparing the post-processing tool +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's now turn to analysing the output of your run with the python post-processing +package :program:`happi`. +To do so, **open a new terminal window**, and start *ipython*: + +.. code-block:: bash + + ipython + +From *ipython*, import the happi module: + +.. code-block:: python + + import happi + +---- + +Get basic info on the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Open the simulation that you have just run: + +.. code-block:: python + + S=happi.Open("/path/to/the/simulation") + +.. warning:: + + Use the correct path to the simulation folder. + +See what is available from the simulation: + +.. code-block:: python + + S.namelist. # then press + +When pressing ````, *ipython* display the content of the simulation. +You can explore all these items. They should all be exactly the same as the ones +that were defined earlier in the namelist ``laser_propagation_2d.py``. + +---- + +Check laser using ``Scalar`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Read the namelist again and spot the line where the ``Scalar`` diagnostic has been defined. +You may get more information on this diagnostic +`on this page `_. + +Obtain a list of ``Scalar`` diagnostics: + +.. code-block:: python + + S.Scalar() + +Open the ``Uelm`` scalar and plot: + +.. code-block:: python + + diag = S.Scalar('Uelm') + diag.plot() + +This scalar represents the electromagnetic energy in the box. The plot we just obtained +should represent its evolution with time. + +---- + +More ``Scalar`` diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Check the evolution of the ``total energy`` in the simulation box: + +.. code-block:: python + + S.Scalar('Utot').plot() + +Check the evolution of the ``energy balance`` in the simulation box: + +.. code-block:: python + + S.Scalar('Ubal').plot() + +You can also compare the last two quantities on the same plot: + +.. code-block:: python + + happi.multiPlot( + S.Scalar('Utot', label="Total energy"), + S.Scalar('Ubal', label="Balance") + ) + + + +---- + +Plot laser using ``Field`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Read the namelist again and spot the line where the ``Field`` diagnostic has been defined. + +Open the ``Ey`` field and plot: + +.. code-block:: python + + diag = S.Field(0, "Ey") + diag.slide(vsym=1) + +This new function ``slide()`` makes a sliding bar to explore the time-evolution +of the simulation. + +Now, open the field with an average, and compare to the previous profile. +The following calculates the laser amplitude envelope using ``"Ey**2+Ez**2"``. +Then, using the argument ``average``, it makes an average of this envelope for x +close to 0 and y at 100. + +.. code-block:: python + + S.Field(0, "Ey**2+Ez**2", average={"x":[0,7],"y":100}).plot() + + +---- + +Compare the laser profile with the theory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We are going to overlay the previous plot of the laser profile with +the theoretical laser profile. + +Get the ``Laser`` block from the namelist: + +.. code-block:: python + + laser = S.namelist.Laser[0] + + laser + +Note that the ``laser`` is an object of type ````. + +See what is available in this laser object: + +.. code-block:: python + + laser. # then press + # This should display all info on the laser + + laser.time_envelope + +Note that this quantity is a python function: what function is it? +Some help is available `here `_. + +To plot the laser profile as a function of time, a list of times is necessary. +In the following, we use the package *numpy* to generate a list of times from 0 to +the end of the simulation, separated by the timestep. + +.. code-block:: python + + from numpy import array, arange + tstop = S.namelist.Main.simulation_time # simulation final time + tstep = S.namelist.Main.timestep # simulation timestep + times = arange(0., tstop, tstep) + +You may type ``times`` in order to see what is the list of times that we have created. + +Now, we execute the ``laser.time_envelope`` function on each of the times that we just created. +We obtain a list of values of the laser envelope corresponding to each time. + +.. code-block:: python + + laser_profile = array([laser.time_envelope(t) for t in times]) + +Plot the profile using the *matplotlib* package: + +.. code-block:: python + + %pylab + plot( times+5, laser_profile**2 / 2 ) + +---- + +Testing the CFL condition +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now change the `input file` and increase the time-step e.g. using :math:`\Delta t = 0.95\,\Delta x`. + +Re-run :program:`Smilei` and check the total energy and/or energy balance. + +What is going on? diff --git a/_sources/basics_setup.rst.txt b/_sources/basics_setup.rst.txt new file mode 100644 index 0000000..b6bb871 --- /dev/null +++ b/_sources/basics_setup.rst.txt @@ -0,0 +1,189 @@ +Setup +----- + +In these tutorials, we assume you are running on a UNIX machine that has access to internet +and can run simulation jobs on several cores. Ideally, it would run on 16 to 32 cores. +If you are, instead, using a home computer or workstation, we recommend you scale the +simulations down in order to reduce their execution time. + +We recommend getting some `basic understanding of parallel computing +`_ and some basic knowledge +on UNIX commands. + +You should first open a `terminal` or a `console`, then ``cd`` to the directory of your +choice. + +---- + +Obtain Smilei +^^^^^^^^^^^^^ + +Use ``git`` to download the code into a ``Smilei`` directory: + +.. code-block:: bash + + git clone --depth=1 https://github.com/SmileiPIC/Smilei.git + cd Smilei + +---- + +Compile the documentation +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the main ``Smilei`` folder, use the `sphinx` python package to compile +the documentation (`get sphinx here `_). + +.. code-block:: bash + + make doc + firefox build/html/index.html & + +Replace ``firefox`` by your favorite web browser. + + +---- + +Prepare the environment +^^^^^^^^^^^^^^^^^^^^^^^ + +The environment should be ready to accomodate for Smilei's installation. +Check `this page `_ +for details. + +In short, you need: + +* a `C++11` compiler +* a compatible `MPI` library (``MPI_THREAD_MULTIPLE`` support is strongly recommended) +* a compatible `HDF5` library +* `python 2.7+` + +We recommend that your `C++` compiler supports `OpenMP` for efficient +multi-threading. For best performances, the following environment variables should +be set, for instance in your ``.bash_profile`` or +``.bashrc`` configuration files. + +.. code-block:: bash + + export OMP_NUM_THREADS=8 + export OMP_SCHEDULE=dynamic + export OMP_PROC_BIND=true + +The number ``8`` indicates the number of threads per process. For most systems, +the ideal number is equal to the number of cores contained in one `node` or `socket`. +For example, if your machine has 12 cores that share the same memory, use +``OMP_NUM_THREADS=12``. + +---- + +Compile Smilei +^^^^^^^^^^^^^^ + +Once all dependencies are installed, go to the ``Smilei`` directory and compile: + +.. code-block:: bash + + make -j 8 + +The option ``-j 8`` provides 8 threads for compilation (faster). +When the compilation has succeeded, two executables are created: ``smilei`` +and ``smilei_test``. + +Install also, the post-processing package ``happi`` : + + +.. code-block:: bash + + make happi + + +.. _runsimulation: + +---- + +Run a simulation on your machine +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The first step for any simulation is to create a new directory to +contain all the simulation inputs and outputs. Otherwise, the many +generated files would pollute your current directory. + +.. code-block:: bash + + # Make a new folder and go inside + mkdir mysimulation + cd mysimulation + + # Copy necessary executables to the new folder + cp /path/to/Smilei/smilei . + cp /path/to/Smilei/smilei_test . + + # Copy the input file as well + cp /path/to/my_input.py . + +When running `Smilei` on your own computer, the first possibility +is to run directly the code in the current terminal: + +.. code-block:: bash + + ./smilei my_input.py + +If you want to use several computing units, you can use the relevant +``MPI`` executable on your machine. For example, with ``mpirun``: + +.. code-block:: bash + + # Run the simulation on 4 processes + mpirun -n 4 smilei my_input.py + +To facilitate this process, a script ``smilei.sh`` is already available. +See `help here `_. + +In this example, the simulation will use 4 processes, but remember that the option above +``OMP_NUM_THREADS=8`` will set 8 threads in each process, so a total of 24 threads. +As a consequence, this example is ideal for 4 nodes containing each 8 cores. +This parallel computing is studied in :doc:`this tutorial`. + + +---- + +Run a simulation on a cluster +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Most supercomputers provide two different options to run a simulation. Both are relevant +to this tutorial. You may choose either. + +1. **Run in interactive mode:** you may request a few nodes of the machine for a given amount + of time. You will have access interactively to the processes, so that the commands above + can be directly written in the command line to run the simulation. + +2. **Prepare a submission file** to submit a "job". You machine administrator should provide + you with a typical job submission file. It defines the number of nodes and cores that + you want to reserve. The command lines above have to be included in this file. + + +---- + +Tips +^^^^ + +* Launch a parallel interactive session: + + One hour with 2 nodes, 8 processors per node, on the ``default`` queue: + + * | with the *torque* (PBS) scheduler: + | ``qsub -I -l walltime=01:00:00,nodes=2:ppn=8 -q default`` + + * | with the *slurm* scheduler: + | ``srun -p default -I -N 2 -c 8 --pty -t 0-01:00`` + + * with intel's LoadLeveler + + +* Download a file from this webpage to your machine + + .. code-block:: bash + + curl -O http://URL/of/the/file + + + diff --git a/_sources/basics_thermal_plasma.rst.txt b/_sources/basics_thermal_plasma.rst.txt new file mode 100644 index 0000000..40de184 --- /dev/null +++ b/_sources/basics_thermal_plasma.rst.txt @@ -0,0 +1,139 @@ +Thermal plasma +--------------------------- + +The goal of this tutorial is to get familiar with: + +* the ``Species`` block that allows you to define a particle species, +* the ``ParticleBinning`` diagnostics to obtain particle energy spectra, +* the problem of `numerical heating` and the necessity to correctly `resolve the electron dynamics` + in explicit PIC codes. + + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^ + +Download the input file `thermal_plasma_1d.py `_. + +An `infinite` electron-ion plasma is let free to evolve in a 1D cartesian +geometry with periodic boundary conditions. + + + +---- + +Check input file and run the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The first step is to check that your `input file` is correct. +To do so, you will run (locally) :program:`Smilei` in test mode: + +.. code-block:: bash + + ./smilei_test thermal_plasma_1d.py + +If your simulation `input file` is correct, you can now run the simulation. +Before going to the analysis of your simulation, check your *log* and/or +*error* output. + +Check what output files have been generated: what are they? + +---- + +Preparing the post-processing tool +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's now turn to analysing the output of your run with :program:`happi`. +To do so, open an ``ipython`` session: + +.. code-block:: bash + + ipython + +In *ipython*, import the :program:`happi` package: + +.. code-block:: python + + import happi + +then open your simulation: + +.. code-block:: python + + S = happi.Open('/path/to/the/simulation') + +.. warning:: + + Use the correct simulation path. + +You are now ready to take a look at your simulation's results. + +---- + +The ``Field`` diagnostics using ``happi.multiPlot`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To have a quick access at your data and `check` what is going on, you will plot +the electron and ion densities together with the electrostatic field :math:`E_x`. + +First, `prepare` the data: + +.. code-block:: python + + # minus the electron density + ne = S.Field(0,'-Rho_eon', label="e- density") + + # ion density + ni = S.Field(0,'Rho_ion', label="ion density") + + # Ex field + ex = S.Field(0,'Ex', label="Ex field", vmin=-0.25,vmax=2) + +You may plot all these quantities independently using ``ex.plot()`` or ``ex.slide()``, +but you can also use the ``multiSlide`` function of :program:`happi`: + +.. code-block:: python + + happi.multiSlide(ne,ni,ex) + +---- + +The ``ParticleBinning`` diagnostics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now, have a look at the ``ParticleBinning`` diagnostics in the input file. +What kind of data will this diagnostic provide? + +You can compare the results at the beginning and at the end of the simulation: + +.. code-block:: python + + Nt = S.ParticleBinning(0).getTimesteps()[-1] # the last timestep + f_initial = S.ParticleBinning(0, data_log=True, timesteps=0 , label="initial") + f_final = S.ParticleBinning(0, data_log=True, timesteps=Nt, label="final") + happi.multiPlot(f_initial, f_final) + +What can you conclude? + +---- + +Effect of spatial resolution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Have a look at the total energy and energy balance in your simulation +(remember the ``Utot`` and ``Ubal`` scalars). +Note the level of energy imbalance at the end of this simulation for which +the spatial resolution is equal to the Debye Length (:math:`\Delta x = \lambda_{\rm De}`). + +Increase your spatial resolution to :math:`\Delta x = 16 \times \lambda_{\rm De}`. +Run the simulation again, and check the energy imbalance at the end of the simulation. +What do you observe? +Can you check the electron spectrum at the beginning and end of the simulation? +What is going on? + +Finally, increase your spatial resolution to +:math:`\Delta x = 2\,c/\omega_{pe} = 2\,c\lambda_{\rm De}/v_{\rm th}` (you will need to extend +your simulation box size to have enough cells). +Check the evolution of the total energy. +What do you observe? diff --git a/_sources/basics_units.rst.txt b/_sources/basics_units.rst.txt new file mode 100644 index 0000000..33fd0c6 --- /dev/null +++ b/_sources/basics_units.rst.txt @@ -0,0 +1,199 @@ +Units +================================================ + +The goal of this tutorial is to familiarize with the use of physical units in ``Smilei``. + +This tutorial will allow you to: + +* get familiar with the units of the input namelist +* postprocess the results displaying units of your choice + +This tutorial requires the installation of the `pint` Python package. + +---- + +What units are used by the code? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Usually, physics codes work with normalized units to simplify the equations and reduce the number +of multiplications. + +For the electromagnetic PIC method, the system given by Maxwell's and Vlasov's equations +can be easily written in normalized `units `_, +normalizing speeds by :math:`c`, masses by the electron mass :math:`m_e` and charges +by the unit charge :math:`e`. +However, there is no natural length or time normalization in this system of equations. +To complete the normalization, one must choose a reference length :math:`L_r`, or equivalently +a reference time :math:`T_r`, or equivalently a reference angular frequency :math:`\omega_r`. +In the following, we choose :math:`\omega_r` as our normalization quantity (:math:`L_r` and +:math:`T_r` are deduced from :math:`\omega_r`). + +Importantly, it is not even necessary to choose a value for this last normalization. +Indeed, it automatically cancels out, so that the system of equations does not depend on +:math:`\omega_r`. This means that the result of the simulation is true for any value of +:math:`\omega_r`! That is why is it usually not necessary to set a value to :math:`\omega_r` +in the simulation input file. + +In practice, we always know our problem in terms of real-world units, but in Smilei's +input file, all quantities must be normalized. + +1. Choose :math:`\omega_r` as one important frequency of your problem (i.e. laser frequency, + plasma frequency, ...) +2. Deduce other reference quantities such as :math:`L_r` and :math:`T_r` +3. The parameters in the input file should be normalized accordingly + +During post-processing, you will obtain results in terms of normalized quantities, +but :program:`happi` gives you the possibility to convert to units of your choice. + + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^ + +Download the input file `radiation_pressure_2d.py `_. + +In this simulation, a slab of pre-ionized overdense plasma of uniform density :math:`n_0` +is irradiated by a high-intensity laser pulse, triggering electron and ion expansion. + +---- + +Check input file and run the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The first step is to check that your `input file` is correct. +To do so, you will run (locally) :program:`Smilei` in test mode: + +.. code-block:: bash + + ./smilei_test radiation_pressure_2d.py + +Take some time to study the namelist, in particular how the physical parameters +have been defined. For the moment you can ignore the lines of code marked with ``Choice 2`` +at the start of the namelist. + +---- + +Normalized units in the input namelist +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The blocks of the input namelist will accept only quantities in normalized units. +As mentioned before, choosing a reference length/time/angular frequency yields +conversion factors for all physical units involved in a PIC simulation. +For more details, see the `units `_ +page in the documentation. + +Therefore, if you are accustomed to work with normalized units, you can directly +put your physical set-up's parameters in the input namelist in normalized units. +We will call this ``Choice 1`` in the following and in the input namelist. +The use of SI units will be called ``Choice 2`` and will be explored in the last section +of this tutorial. + +The provided input file already has ``Choice 1`` implemented in the namelist +(see the initial part of the file). As you can see reading the namelist, +most of the simulation parameters can be defined starting from the definition +of the laser wavelength, which will be also our reference wavelength. +This can be seen in the ``LaserGaussian2D`` block, where the ``Laser`` 's angular frequency +``omega`` in normalized units is 1, i.e. equal to our reference angular frequency. + +With this choice of normalization: + +* a length of :math:`2\pi` corresponds to a laser wavelength, +* a time interval :math:`2\pi` corresponds to an optical cycle of the laser, +* the reference density corresponds to the laser critical density :math:`n_c=\varepsilon_0 m_e \omega^2/e^2`. + +.. note:: In other set-ups you may want to choose the reference length equal to the Debye length, + or the plasma electron wave frequency, etc. In this case, if a ``Laser`` is present, + remember to redefine the ``omega`` in the ``Laser`` block accordingly. + +.. note:: Some reference quantities do not change with the choice of reference length/time, + e.g. the electron charge will be :math:`-1`, the electron mass will be :math:`1`, since the + reference charge and mass in our normalized units are those of the electron. + Also, the reference energy and speed are :math:`m_ec^2` and `c`, independently of the choice for + the reference length/time. + +**Question**: if we wanted a laser with frequency equal to two times the reference frequency, +what would be the value of ``omega`` in the ``Laser`` block? + +**Question**: for a reference length of :math:`L_r=0.8` Β΅m what would be +the reference density? See its definition `here `_ +(you may use the constants in the module ``scipy.constants``). +Is it equal to :math:`L_r^{-3}`? + +.. warning:: + + As you have seen, in this namelist there is no need to specify a reference angular frequency + or a reference length in SI units. However, when using advanced physical operators like + ionization, collisions, multiphoton Breit Wheeler pair generation, radiation emission + you will have to do it (see related tutorials and the ``Main`` block of their namelists). + This happens because these operators represent an extension of the basic Vlasov-Maxwell system of + PIC codes, and are not invariant under the described normalization. + + +---- + +Units in the postprocessing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's study the results, without specifying a conversion:: + + import happi; S_normalized = happi.Open('/path/to/your/simulation') + +If we plot the laser transverse field on the propagation axis, we can verify +that indeed a length of :math:`2\pi` corresponds to the laser wavelength:: + + S_normalized.Probe.Probe0("Ey").slide() + +Now, what if we wanted our results in physical units, e.g. SI units? While opening the output with happi, +we can specify a reference angular frequency in SI. In this case, we can choose it from +the laser wavelength:: + + import math + import scipy.constants + laser_wavelength_um = 0.8 + c = scipy.constants.c # Lightspeed, m/s + omega_r_SI = 2*math.pi*c/(laser_wavelength_um*1e-6) + S_SI = happi.Open('/path/to/your/simulation', reference_angular_frequency_SI=omega_r_SI) + +This allows ``happi`` to make the necessary conversions for our scale of interest. +Then, we have to specify the units we want in our plot:: + + S_SI.Probe.Probe0("Ey", units=['um','fs','GV/m']).slide(figure=2) + +**Question**: Does the peak transverse field of the laser correspond to the one in normalized units +at the same timestep and in the namelist? Compute first the reference electric field as explained `here `_ +and check the conversion to GV/m. + +**Action**: Similarly, try to plot the kinetic energy ``Ukin`` from the ``Scalar`` diagnostic +and the evolution of the electron density ``Rho_eon`` from the ``Field`` diagnostic +in normalized and physical units. + +**Note**: Other systems of units can be used, e.g. CGS, or different combinations of units, including ``inches``, ``feet``. +For more details, see `here `_. + +---- + +SI units in the input namelist +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you prefer to work with physical units, e.g. SI units, the use of Python for the input namelist +allows to easily convert our inputs in SI units to normalized inputs required by +the code. In the namelist there is a way to do it, marked with ``Choice 2`` +and commented for the moment. + +**Action**: Comment the two lines marked with the comment ``Choice 1`` in the input namelist. +Uncomment the lines marked with ``Choice 2`` and take some time to read them. + +As you can see, first we use the ``scipy.constants`` module to define some useful physical constants, +e.g. the speed of light. Then, we define the reference length, from which we derive some variables useful +for the conversions. +With these variables, it is easy to have the necessary quantities in normalized units and vice-versa:: + + length_normalized_units = length_SI / L_r + +**Question**: Near the ``Laser`` block, a variable ``E_r`` is defined, representing the reference +electric field. Using this variable, can you convert the normalized peak electric field of the laser ``a0`` +to TV/m? Similarly, can you convert the plasma density ``n0`` to :math:`\textrm{cm}^{-3}`? Note that instead of +defining the density as in the namelist we could have just used:: + + density_normalized_units = n0_SI / N_r \ No newline at end of file diff --git a/_sources/basics_weibel_twostream.rst.txt b/_sources/basics_weibel_twostream.rst.txt new file mode 100644 index 0000000..3afc09e --- /dev/null +++ b/_sources/basics_weibel_twostream.rst.txt @@ -0,0 +1,130 @@ +Weibel and two-stream instabilities +================================================ + +The goal of this tutorial is to run to physics simulations relating to streaming instabilities, +and in particular to the electron Weibel and two-stream instabilities. + +This tutorial will also allow you to: + +* get familiar with the ``happi.streak`` tool +* extract instability growth rates +* construct and extract phase-space distribution using the ``ParticleBinning`` diagnostics + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^ + +Download the two input files `weibel_1d.py `_ and +`two_stream_1d.py `_. + +In both simulations, a plasma with density :math:`n_0` is initialized (:math:`n_0 = 1`). +This makes code units equal to plasma units, i.e. times are normalized to the inverse of +the electron plasma frequency :math:`\omega_{p0} = \sqrt{e^2 n_0/(\epsilon_0 m_e)}`, +distances to the electron skin-depth :math:`c/\omega_{p0}`, etc... + +Ions are frozen during the whole simulation and just provide a neutralizing background. +Two electron species are initialized with density :math:`n_0/2` and +a mean velocity :math:`\pm \bf{v_0}`. + +---- + +Check input file and run the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The first step is to check that your `input files` are correct. +To do so, you will run (locally) :program:`Smilei` in test mode: + +.. code-block:: bash + + ./smilei_test weibel_1d.py + ./smilei_test two_stream_1d.py + +If your simulation `input files` are correct, you can run the simulations. + +Before going to the analysis, check your *logs*. + + +---- + +Weibel instability: analysis +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In an :program:`ipython` terminal, open the simulation: + +.. code-block:: python + + S = happi.Open('/path/to/your/simulation/weibel_1d') + +The ``streak`` function of :program:`happi` can plot any 1D diagnostic as a function of time. +Let's look at the time evolution of the total the current density :math:`J_z` and +the magnetic field :math:`B_y`: + +.. code-block:: python + + S.Field(0,'Jz' ).streak(vsym=True) + S.Field(0,'By_m').streak(vsym=True) + +Do you have any clue what is going on? +You can get another view using an animation: + +.. code-block:: python + + jz = S.Field(0,'Jz') + by = S.Field(0,'By_m',vmin=-0.5,vmax=0.5) + happi.multiSlide(jz,by) + +Now, using the ``Scalar`` diagnostics, check the temporal evolution of the energies +in the magnetic (:math:`B_y`) and electrostatic (:math:`E_z`) fields. +Can you distinguish the linear and non-linear phase of the instability? + +Have a closer look at the growth rates. Use the ``data_log=True`` options when loading +your scalar diagnostics, then use ``happi.multiPlot()`` to plot both energies as a +function of time. Can you extract the growth rates? What do they tell you? + +If you have time, run the simulation for different wavenumbers :math:`k`. +Check the growth rate as a function of :math:`k`. + +For those interested, you will find more in: +`Grassi et al., Phys. Rev. E 95, 023203 (2017) `_. + + + +---- + +Two-stream instability: analysis +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In an :program:`ipython` terminal, open the simulation: + +.. code-block:: python + + S = happi.Open('/path/to/your/simulation/two_stream_1d') + +then, have a first look at your simulation results: + +.. code-block:: python + + uel = S.Scalar('Uelm',data_log=True,vmin=-9,vmax=-2) + ne = S.Field(0,'-Rho_eon1-Rho_eon2', xmin=0, xmax=1.05, vmin=0, vmax=2) + ex = S.Field(0,'Ex', xmin=0, xmax=1.05, vmin=-0.2, vmax=0.2) + phs = S.ParticleBinning(0,cmap="smilei_r",vmin=0,vmax=200) + happi.multiSlide(uel,ne,ex,phs,shape=[1,4]) + +Any clue what's going on? + +Let's have a look at the energy in the electrostatic field :math:`E_x`: + +* Can you distinguish the linear and non-linear phase of the instability? +* Check the :math:`(x,p_x)`-phase-space distribution (and energy in the electromagnetic fields), + can you get any clue on what leads the instability to saturate? + +Try changing the simulation box size (which is also the wavelength of the considered +perturbation), e.g. taking: :math:`L_x =` 0.69, 1.03 or 1.68 :math:`c/\omega_{p0}`. +What do you observe? + +Now, take :math:`L_x =` 0.6, 0.31 or 0.16 :math:`c/\omega_{p0}`. What are the differences? +Can you explain them? + + + diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt index 68ae867..26576b7 100644 --- a/_sources/index.rst.txt +++ b/_sources/index.rst.txt @@ -1,20 +1,30 @@ -.. No Errors Test Project documentation master file, created by - sphinx-quickstart on Fri Aug 30 17:07:56 2019. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +.. title:: Smilei tutorials -Welcome to No Errors Test Project's documentation! -================================================== +.. image:: _static/smileiLogo_tutorials_large.svg -.. toctree:: - :maxdepth: 2 - :caption: Hello World! +This website provides tutorials for learning how to use the PIC code +`Smilei `_ and its post-processing +tool :program:`happi`. +Choose among the available tutorials in the top menu. +.. toctree:: + :maxdepth: 2 + :hidden: + + basics + perfs + advanced + +.. rubric:: Links to Smilei's documentation: -Indices and tables -================== +* `Smilei units `_ +* `Smilei input syntax `_ +* `Smilei post-processing `_ +* `Smilei tutorials source `_ -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. rubric:: Previous versions of these tutorials were used for training during Smilei workshops + in `2017 `_, + `2019 `_, + `2022 `_ and + `2023 `_. \ No newline at end of file diff --git a/_sources/perfs.rst.txt b/_sources/perfs.rst.txt new file mode 100644 index 0000000..ac40ecc --- /dev/null +++ b/_sources/perfs.rst.txt @@ -0,0 +1,10 @@ +.. title:: Performances + +Performances +============ + +.. toctree:: + + perfs_parallel_computing + perfs_patch_arrangement + diff --git a/_sources/perfs_parallel_computing.rst.txt b/_sources/perfs_parallel_computing.rst.txt new file mode 100644 index 0000000..02af869 --- /dev/null +++ b/_sources/perfs_parallel_computing.rst.txt @@ -0,0 +1,353 @@ +Parallel computing +================================= + +As supercomputers become larger, we can explore new domains of plasma physics +with more expensive simulations. However, this type of computer requires the +computation to be made by many computing cores at the same time, *in parallel*. + +Optimizing parallel algorithms on these new machines becomes increasingly difficult, +because their architecture complexity grows together with their power. +See this `introduction to parallelism `_. + +.. rubric:: Basic architecture of supercomputers: + +.. + + * Many **nodes** communicate through a *network*. Each node owns its own memory. + * Nodes are composed of many **computing units** (most often *cores*) which share the memory of the node. + + .. image:: _static/node.svg + :width: 50% + :align: center + + + +.. Cores access more and more advanced instructions sets, such as *SIMD* (Single Instruction Multiple Data) instructions + +.. In Smilei, these three points are respectivly adressed with MPI, OpenMP and vectorization using ``#pragma omp simd`` on Intel architecture. + +.. + + This defines two levels of parallelism: + + * *"Distributed memory"*: Communicating information between nodes that do not access the same memory. + * *"Shared memory"*: Synchronizing the operations of the cores that share the same memory. + +.. rubric:: Distributed memory + +.. + + The protocol that handles the communication of data between different nodes is called MPI. + Smilei will run independently on each of those locations, and we call each of these instances an **MPI process** + (sometimes also called **task**). One MPI process is usually associated to many cores inside one single node, + but it does not necessarily occupy all the cores in this node. + + The data is split into small pieces, called **patches**, so that it can be distributed to those MPI processes. + This is called *domain decomposition*. + + Each **MPI process** executes all the computation necessary to handle the patches he has been given using the ressources he has access to. + The main difficulty is to provide an equal amount of work to each MPI process. This is called **load balancing**. We will see how + Smilei distributes the patches to MPI processes in order to have a uniform load. + +.. rubric:: Shared memory + +.. + + Inside a given MPI process, where the shared memory contains many patches to be computed, + the work must be synchronized between available cores. + This is handled by the **OpenMP** protocol. + + OpenMP creates **threads** which are sequences of instructions to be executed by cores, and schedules + the parallel work of all available cores accordingly. + + Each thread will be assigned to successive patches, in parallel with other threads. + This is an effective way to balance the load inside the MPI process: when a patch is done, a core will automatically + work on the next patch withtout having to wait for another core that might still be working. + +.. rubric:: Summary + +.. + + The simulation domain should be divided into many patches for two reasons: + + * to distribute the computational load and feed all threads associated to each MPI process + * to be able to manage the load imbalance by moving patches between different MPI processes + + But, be careful: an excessively refined decomposition (with too many small patches) will + produce a large overhead due to communications and synchronizations. + + The goal of this tutorial is to understand how to setup a simulation to get good performances. + The following features will be addressed: + + * Decomposition of the simulation box into patches + * Choice of the number of MPI processes and OpenMP threads + * Smilei's *load balancing* feature + * Performance analysis with the ``DiagPerformances`` + +---- + +Physical configuration +^^^^^^^^^^^^^^^^^^^^^^ + +Download the input file `beam_2d.py `_. +A small plasma ball is set with an initial velocity :math:`v_x=0.3` +and traverses the box. + +---- + +Setup the tutorial +^^^^^^^^^^^^^^^^^^ + +As explained in the :ref:`setup page `, you should make a new directory +to run your simulation. This directory should contain the input file that you just downloaded +and the executables ``smilei`` and ``smilei_test``. + +We introduce this tutorial talking about supercomputers but we will run here single node simulations. +It could seems out of context but the idea is to illustrate how works the code parallelism and its limits. + +---- + + +Splitting the box +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In a first test, we will use a single core with in a single MPI process to focus on the box splitting. +Launch the simulation with 1 MPI and 1 thread only. For instance, you could use commands similar to: + +.. code-block:: bash + + export OMP_NUM_THREADS=1 + mpirun -np 1 smilei beam_2d.py + +The input file suggests to use 32x32 patches: + +.. code-block:: python + + Main( + number_of_patches = [ 32, 32 ], + ) + +Run the simulation for various number of patches, +and compare the computation time: + +* 32 x 32 patches +* 16 x 16 patches +* 8 x 8 patches +* a single patch + +Computation times are provided at the end of the simulation: + +* ``Time in time loop``: the whole PIC loop +* ``Particles`` : all particles operations except collisions +* ``Maxwell`` : Maxwell equations and the electromagnetic boundary conditions +* ``Diagnostics`` : all ``Diag`` blocks defined in the namelist +* ``Sync Particles`` : particle exchange between patches +* ``Sync Fields`` : ``E``, ``B`` exchange between patches +* ``Sync Densities`` : ``J`` exchange between patches + +.. rubric:: Details about timers + +The ``Sync`` timers concern exchange between patches owned by **a single MPI processes and/or by many**. +In this case, these timers could contain waiting times due to load imbalance inherent to PIC simulations. + +Whatever the case, ``Particles`` and ``Maxwell`` do not contain MPI waiting time, +they only accumulate pure computation time. + +``Load balancing``, ``Mov window`` or ``Diagnostics`` (which can be seen like a disk synchronization) +are global operations which require communications, they can contain waiting time. + +For many MPI processes simulation, these times are averaged on all processes. +Some detailed timing elements, such as minimum or maximum times on all processes +are provided in the file ``profil.txt`` and a full report can be obtained using the ``DiagPerformances``. + + +---- + +Introduce Smilei’s parallelism +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's make the first step to introduce parallel processing of all the patches. +We will use several OpenMP threads in a single MPI process. + +Use a good patch configuration found in the previous step: 8x8 patches. +The single patch simulation is maybe slightly faster but it cannot exhibit any parallelism. + +Setup 1 MPI process, and 16 threads per process. +You may need to adjust these settings according to your machine. TypicallyL + +.. code-block:: bash + + export OMP_NUM_THREADS=16 + export OMP_SCHEDULE=dynamic + mpirun -np 1 smilei beam_2d.py + +Make sure that, in the output log, it specifies the correct number of +processes and threads. + +Even though 16 threads are used, the speed-up is very poor. + +Let us now use ``happi`` to analyse the simulation. +Open an ``ipython`` prompt, then run:: + + import happi + S = happi.Open("/path/to/beam_2d/") + +You can have a quick understanding of what happens in the simulation using:: + + S.ParticleBinning(0).slide() + +A ball of plasma (30 cells radius) is moving through the box (256x256 cells): + +* With 8 x 8 patches, the size of a patch is 32 x 32 cells. + The plasma, which represents the main time cost, + occupies only a few patches of the simulation. + This means many threads are doing nothing. +* With 16 x 16 patches, the size of a patch is 16 x 16 cells, + an order of magnitude is earned regarding the number of patches loaded with particles. + Verify the speedup. +* With 32 x 32 patches, the size of a patch is 8 x 8 cells, + even more patches are loaded with particles, but with a synchronization overhead. + +Check the behavior of these three configurations running 16 threads. + +For this test, in the best case configuration, +an additionnal speed-up of 2 is obtained. +This is modest, but accelerating computations requires to split the particle load. +With a such local plasma, it is hard to achieve. + +---- + +Imbalance +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You applied some load balancing using OpenMP threading. +Indeed, the threads will keep working patch after patch in parallel on all the available patches +until all patches are done. +This is called *dynamic scheduling*. + +The *static scheduling*, instead, assigns an exclusive pool of patches +to each thread. In this situation, threads will only work on their own pool, +even if it is an empty region. This obviously prevents load balancing between threads. +It is used on grids computing function of Smilei which is naturraly balanced. + +To choose the type of OpenMP scheduling, you can set the environment +variable ``OMP_SCHEDULE`` to ``static``. Typically: + +.. code-block:: bash + + export OMP_NUM_THREADS=16 + export OMP_SCHEDULE=static + mpirun -np 1 smilei beam_2d.py + +OpenMP offers intermediary solutions but regarding the granularity of +the level of parallelism, we advice the ``dynamic`` scheduling. + +---- + +Imbalance and distributed memory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Run the 16 x 16 patches simulation but with a MPI-only configuration. +Typically, you can write: + +.. code-block:: bash + + export OMP_NUM_THREADS=1 + mpirun -np 12 smilei beam_2d.py + +This is technically similar to the ``static`` scheduling of the previous section: +the pool of patches is explicitly distributed over MPI processes starting the simulation. +Compare the time spent in the PIC loop to that previous case. + +We are now going to use the ``Performances`` diagnostic. +The list of available quantities can be obtained with:: + + S.Performances + +Let us try:: + + S.Performances(map="hindex").plot() + +You should obtain a map of the simulation box with one distinct color for +each memory region (i.e. each MPI process). There are 16 regions, as we requested +initially. You can see that these regions do not have necessarily the same shape. + +Now plot the number of particles in each region:: + + S.Performances(map="number_of_particles").slide(cmap="smilei_r", vmin=0) + +Clearly, at every given time, no more than only a few regions contain particles. +This is a typical situation where almost all processes have nothing to do +and wait for a single process to finish its computation. + +You can also visualize the time taken for computing particles using:: + + S.Performances(map="timer_particles",cumulative=False).slide(cmap="smilei_r", vmin=0) + + + +---- + +Balancing the load between processes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Smilei has an automated load-balancing feature that can move patches from one +process to another in order to ensure they all have a similar load. Activate it +in the input file using:: + + LoadBalancing( + every = 20 + ) + +Then run the simulation again with 16 processes and +have a look at the ``Load balancing`` timer. +Observe differences in the computation time, +compare it to the time saved regarding the simulation without dynamic load balancing. + +.. warning:: + + ``Sync`` timers are impacted by the imbalance of the + algorithm part which precedes it: + + * ``Particles`` + * ``Sync Densities`` + * ``Maxwell`` + * ``Sync Particles`` + * ``Sync Fields`` + + +Use again the performances diagnostic to monitor the evolution of the +regions and their computational load. + + +---- + +Realistic configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: + + To get familiar with Smilei's domain decomposition, distributed and shared memory parallelism, + we did not consider the NUMA (non uniform memory access) aspect of most supercomputers. + Indeed, a node is generally composed of several *sockets* which own many cores each. + Cores have privileged access to the memory associated to it socket. + +In general, supercomputers should be adressed with both: + +* MPI: to go through nodes **and** sockets (to enhance memory affinity), +* OpenMP: to feed threads and minimize imbalance + +The following example uses 2 MPI processes with 8 threads each: + +.. code-block:: bash + + export OMP_NUM_THREADS=8 + mpirun -np 2 smilei beam_2d.py + + +Between processes, threads, and the number of patches, there are many ways the +simulation performances can be modified. There is no general rule for finding +the optimal configuration, so we recommend trying several options. + + + diff --git a/_sources/perfs_patch_arrangement.rst.txt b/_sources/perfs_patch_arrangement.rst.txt new file mode 100644 index 0000000..3ee7a04 --- /dev/null +++ b/_sources/perfs_patch_arrangement.rst.txt @@ -0,0 +1,138 @@ +Patch arrangement +================================= + +In some situations with slow particles dynamics, the dynamic load balancing +may not be relevant to speed-up the simulation. +Moreover, as it relies on a +`Hilbert curve `_, +it may not be able to split intelligently the plasma in equal parts. + +Typically, this happens when the plasma is contained in a thin slab. +The Hilbert curve splitting is better replaced by a simple *linearized* splitting +that divides the box in slabs of equal size. + +The goal of this tutorial is to learn about these various arrangements of patches, +and test them in realistic cases. + +We recommand first to run the `parallel computing `_ tutorial. + +---- + +Configuration +^^^^^^^^^^^^^^^^^^^^^^ + +Starting case : + `radiation_pressure_acc_hilbert.py `_ + +To highlight the phenomenon and to simplify the discussion +we propose to run on several MPI processes and only 1 thread per process. + +---- + +Setting up the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set your simulation with 16 MPI processes, and only 1 thread per process. Typically: + +.. code-block:: bash + + export OMP_NUM_THREADS=1 + mpirun -np 16 smilei radiation_pressure_acc_hilbert.py + +Observe timers and the probe diagnostics results. + +.. note:: + + Field diagnostics do not work with the alternative ``patch_arrangement`` + so we use Probe diagnostics instead. + + +---- + +Change the patch arrangement +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Activate the dynamic load balancing to absorb synchronizations overhead + +.. code-block:: python + + LoadBalancing( + every = 20 + ) + +A look at the plasma shape shows that, at initialization, +the plasma is located within a thin slab along the Y axis. +Then, it is pushed along the X axis. +We propose to enforce an arrangement of patches that splits +the plasma into slabs along X, so that each region owns an +equal share of the computational load. +You may add the following line in the bloc ``Main()``:: + + patch_arrangement = "linearized_YX", + +We can imagine that splitting into slabs along Y would be a +terrible option, because all the plasma will be contained in +one process only. All other processes will need to wait and do nothing. +You can still try it:: + + patch_arrangement = "linearized_XY", + +You may want to stop the simulation before the end! + +.. figure:: _extra/arrangement.png + + Each numbered square represents a patch in an 8 x 8 patches configuration. + Each color represents one of the 16 MPI processes. + In this test case, the plasma is located in the 2nd column of the box. + You can observe how the dynamic load balancing (dlb) makes a coarse splitting + where there is no plasma. + + +---- + + +Tuning the patch arrangement +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the situation above, there was a maximum of 8 patches in the Y direction, +so that the plasma could not be split in more than 8 pieces. +We would like to split it in 16 pieces to make sure that each +of the 16 processes has something to work on. +Unfortunatly the patch size, 75 x 125 cells, does not permit to split more in Y. + +Study the following code, which slightly increases the spatial +resolution in Y to get a number of cells in Y divisible per 16. + +.. code-block:: python + + current_ncells_Y = Lsim[1] / (l0/resx) + target_ncells_Y = 1024. + target_cell_length_Y = (l0/resx*current_ncells_Y)/target_ncells_Y + + Main( + cell_length = [l0/resx,target_cell_length_Y], + ) + +It is available in the input file +`radiation_pressure_acc_linearized.py `_. + +Run again the ``linearized_YX`` configuration: the higher resolution +leads to more particles, thus a slightly higher computation time. + +You can now run the simulation with the 8 x 16 patches: + +.. code-block:: python + + number_of_patches = [ 8, 16 ], + +For a fair comparison, use this configuration with the ``hilbertian`` +arrangement (the default value of ``patch_arrangement``). +In this mode, when the number of patches is not the same along all directions, +the Hilbert pattern is replicated in the larger direction (Y here). +This can be beneficial here. + +.. note:: + The paramater ``number_of_patches`` must be a power of 2 + with the ``hilbertian`` arrangement. This is not required with the + ``linearized`` arrangement. + diff --git a/_sources/site.rst.txt b/_sources/site.rst.txt new file mode 100644 index 0000000..e41d7ae --- /dev/null +++ b/_sources/site.rst.txt @@ -0,0 +1,3 @@ +Index +----- + diff --git a/_static/BPmonoRound.otf b/_static/BPmonoRound.otf new file mode 100644 index 0000000..72c6c30 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 0000000..3b67c11 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 0000000..4d11fb7 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 0000000..ef3b437 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 0000000..9f5d544 Binary files /dev/null and b/_static/BPreplayItalics.otf differ diff --git a/_static/LaguerreGauss.png b/_static/LaguerreGauss.png new file mode 100644 index 0000000..e030731 Binary files /dev/null and b/_static/LaguerreGauss.png differ diff --git a/_static/documentation_options.js b/_static/documentation_options.js index 4790c4d..d1651be 100644 --- a/_static/documentation_options.js +++ b/_static/documentation_options.js @@ -1,7 +1,7 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '', - LANGUAGE: 'None', + VERSION: 'X.Y', + LANGUAGE: 'en', COLLAPSE_INDEX: false, BUILDER: 'html', FILE_SUFFIX: '.html', diff --git a/_static/labs/iapras.png b/_static/labs/iapras.png new file mode 100644 index 0000000..95ae1dd Binary files /dev/null and b/_static/labs/iapras.png differ diff --git a/_static/labs/idris.png b/_static/labs/idris.png new file mode 100644 index 0000000..b5edba8 Binary files /dev/null and b/_static/labs/idris.png differ diff --git a/_static/labs/intel.jpg b/_static/labs/intel.jpg new file mode 100644 index 0000000..48e7819 Binary files /dev/null and b/_static/labs/intel.jpg differ diff --git a/_static/labs/iramis.png b/_static/labs/iramis.png new file mode 100644 index 0000000..dc19b47 Binary files /dev/null and b/_static/labs/iramis.png differ diff --git a/_static/labs/irap.png b/_static/labs/irap.png new file mode 100644 index 0000000..b2d4f6a Binary files /dev/null and b/_static/labs/irap.png differ diff --git a/_static/labs/irfu.png b/_static/labs/irfu.png new file mode 100644 index 0000000..498d1d8 Binary files /dev/null and b/_static/labs/irfu.png differ diff --git a/_static/labs/llr.png b/_static/labs/llr.png new file mode 100644 index 0000000..0db69df Binary files /dev/null and b/_static/labs/llr.png differ diff --git a/_static/labs/lpgp.png b/_static/labs/lpgp.png new file mode 100644 index 0000000..2eaf757 Binary files /dev/null and b/_static/labs/lpgp.png differ diff --git a/_static/labs/lpp.png b/_static/labs/lpp.png new file mode 100644 index 0000000..4b35204 Binary files /dev/null and b/_static/labs/lpp.png differ diff --git a/_static/labs/luli.png b/_static/labs/luli.png new file mode 100644 index 0000000..28493cd Binary files /dev/null and b/_static/labs/luli.png differ diff --git a/_static/labs/mdls.png b/_static/labs/mdls.png new file mode 100644 index 0000000..b7f428f Binary files /dev/null and b/_static/labs/mdls.png differ diff --git a/_static/labs/openpmd.jpg b/_static/labs/openpmd.jpg new file mode 100644 index 0000000..4e7ea8f Binary files /dev/null and b/_static/labs/openpmd.jpg differ diff --git a/_static/labs/palm.png b/_static/labs/palm.png new file mode 100644 index 0000000..ea21527 Binary files /dev/null and b/_static/labs/palm.png differ diff --git a/_static/labs/picsar.jpg b/_static/labs/picsar.jpg new file mode 100644 index 0000000..147b06b Binary files /dev/null and b/_static/labs/picsar.jpg differ diff --git a/_static/labs/plasapar.png b/_static/labs/plasapar.png new file mode 100644 index 0000000..ba4d164 Binary files /dev/null and b/_static/labs/plasapar.png differ diff --git a/_static/node.svg b/_static/node.svg new file mode 100644 index 0000000..931ec25 --- /dev/null +++ b/_static/node.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + memory + + + + + cores + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Node 1 + + + + + + + Node 2 + + + + + + + Node 3 + + + + + + \ No newline at end of file diff --git a/_static/pygments.css b/_static/pygments.css index dd6621d..20c4814 100644 --- a/_static/pygments.css +++ b/_static/pygments.css @@ -1,77 +1,69 @@ .highlight .hll { background-color: #ffffcc } -.highlight { background: #f8f8f8; } -.highlight .c { color: #8f5902; font-style: italic } /* Comment */ -.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ -.highlight .g { color: #000000 } /* Generic */ -.highlight .k { color: #004461; font-weight: bold } /* Keyword */ -.highlight .l { color: #000000 } /* Literal */ -.highlight .n { color: #000000 } /* Name */ -.highlight .o { color: #582800 } /* Operator */ -.highlight .x { color: #000000 } /* Other */ -.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ -.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #8f5902 } /* Comment.Preproc */ -.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ -.highlight .gd { color: #a40000 } /* Generic.Deleted */ -.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #888888 } /* Generic.Output */ -.highlight .gp { color: #745334 } /* Generic.Prompt */ -.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ -.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ -.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ -.highlight .ld { color: #000000 } /* Literal.Date */ -.highlight .m { color: #990000 } /* Literal.Number */ -.highlight .s { color: #4e9a06 } /* Literal.String */ -.highlight .na { color: #c4a000 } /* Name.Attribute */ -.highlight .nb { color: #004461 } /* Name.Builtin */ -.highlight .nc { color: #000000 } /* Name.Class */ -.highlight .no { color: #000000 } /* Name.Constant */ -.highlight .nd { color: #888888 } /* Name.Decorator */ -.highlight .ni { color: #ce5c00 } /* Name.Entity */ -.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #000000 } /* Name.Function */ -.highlight .nl { color: #f57900 } /* Name.Label */ -.highlight .nn { color: #000000 } /* Name.Namespace */ -.highlight .nx { color: #000000 } /* Name.Other */ -.highlight .py { color: #000000 } /* Name.Property */ -.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #000000 } /* Name.Variable */ -.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ -.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ -.highlight .mb { color: #990000 } /* Literal.Number.Bin */ -.highlight .mf { color: #990000 } /* Literal.Number.Float */ -.highlight .mh { color: #990000 } /* Literal.Number.Hex */ -.highlight .mi { color: #990000 } /* Literal.Number.Integer */ -.highlight .mo { color: #990000 } /* Literal.Number.Oct */ -.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ -.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ -.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ -.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ -.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ -.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ -.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ -.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ -.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ -.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ -.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ -.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ -.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #000000 } /* Name.Function.Magic */ -.highlight .vc { color: #000000 } /* Name.Variable.Class */ -.highlight .vg { color: #000000 } /* Name.Variable.Global */ -.highlight .vi { color: #000000 } /* Name.Variable.Instance */ -.highlight .vm { color: #000000 } /* Name.Variable.Magic */ -.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/smileiIcon.png b/_static/smileiIcon.png new file mode 100644 index 0000000..1ff6737 Binary files /dev/null and b/_static/smileiIcon.png differ diff --git a/_static/smileiLogo_tutorials.svg b/_static/smileiLogo_tutorials.svg new file mode 100644 index 0000000..7bf2157 --- /dev/null +++ b/_static/smileiLogo_tutorials.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_static/smileiLogo_tutorials_large.svg b/_static/smileiLogo_tutorials_large.svg new file mode 100644 index 0000000..482cb01 --- /dev/null +++ b/_static/smileiLogo_tutorials_large.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_static/smilei_theme.css b/_static/smilei_theme.css new file mode 100644 index 0000000..c4d305c --- /dev/null +++ b/_static/smilei_theme.css @@ -0,0 +1,1012 @@ + + + +@import url("basic.css"); + +/* -- Fonts ----------------------------------------------------------- */ + +@font-face { + font-family: "BPreplay"; + src: url("BPreplay.otf"); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: "BPreplay"; + src: url("BPreplayBold.otf"); + font-weight: bold; + font-style: normal; +} +@font-face { + font-family: "BPreplay"; + src: url("BPreplayItalics.otf"); + font-weight: normal; + font-style: italic; +} +@font-face { + font-family: "BPreplay"; + src: url("BPreplayBoldItalics.otf"); + font-weight: bold; + font-style: italic; +} +@font-face { + font-family: "BPmonoRound"; + src: url("BPmonoRound.otf"); +} + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: tahoma, sans-serif; + font-size: 1em; + background-color: white; + color: #3E4349; + margin: 0; + padding: 0; +} + +div.document { + width:100%; +} + +div.documentwrapper { + max-width: 210mm; + margin: 12mm auto 0 auto; +} + +div.body { + background-color: white; + color: #3E4349; + padding: 0 1em 0 1em; + min-width: unset; +} + +div.footer { + max-width: 210mm; + margin: 1.5em auto; + font-size: 14px; + color: #888; + text-align: center; +} + +div.footer a { + color: #888; +} + +div.footer > div { + margin: 0.8em; + display: inline-block; +} + +div.logo { + padding-right: 2em; + margin: 0; + text-align: left; + height:12mm; +} + +div.logo a, +div.logo a:hover { + border: none; +} + +.version { + position: relative; +} + +.version::before { + display: inline-block; + content: "vX.Y"; + position: absolute; + bottom: 5%; + right: 5%; + font: bold 1.6em BPreplay; + color: #db2e13;; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #db2e13; + text-decoration: none; +} + +a:hover { + color: #ed7c6a; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: "BPreplay", sans-serif; + font-weight: bold; + margin: 10px 0px 10px 0px; + padding: 0; + color: #db2e13; +} + +div.body h1 { + font-size: 240%; + padding: 0.1em 0.3em 0.1em 1em; + background-color:#fce8e5; + display: inline-block; + border-radius:0.1em +} +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } +.small li { font-size: 1em !important; } + +:target { + margin-top: -14.399999999999999mm; + padding-top: 14.399999999999999mm; +} + +h1:target, h2:target, h3:target, dt:target { + background: #fce8e5 content-box !important; +} + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: transparent; +} + +div.body p, div.body li { + line-height: 1.4em; +} + +div.body p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +div.body dd > p { + margin: 0; +} + +dl.field-list > dt { + padding-top: 2px; +} + +div.body table p { + margin-bottom: 0; +} + +div.body li > p { + margin: 0; +} + +div.admonition { + padding:7px; + background-color: #EAF4FD; + border: 1px solid #0672BA; + overflow: hidden; +} + +div.admonition p.admonition-title { + font-family: "BPreplay", sans-serif; + font-weight: bold; + font-size: 1.2em; + margin: 0; + padding: 0; + line-height: 1; + display: inline; + float: inherit; +} + +p.admonition-title:after { + content: ":"; +} + +div.admonition p.last { + margin:5px 0; + float: right; +} + +div.highlight { + background-color: white; +} + +.highlight { + background: #fce8e5; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +pre, code { + font-family: 'Consolas', "BPmonoRound", 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +img.screenshot { +} + +.line-block{ + margin:0 +} + +code.descname, code.descclassname, span.descname, span.descclassname { + font-size: 0.95em; + color: #db9213; +} + +code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.docutils thead { + background-color: #fce8e5; +} + +table.field-list, table.footnote { + border: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.footnote td.label { + width: 0; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +table.nowrap { + white-space: nowrap; +} + +table.docutils div.line-block { + margin-bottom:0; +} + +table.noborder, table.noborder td { + border:0 !important; +} + +table.noborder td:first-child > .reference { + border-bottom:0 !important; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin: 0.5em 0 0.5em 1em; +} + +blockquote { + margin: 0 0 0 1em; + padding: 0; +} + +ul, ol { + margin: 4px 0 4px 1em; + padding: 0; +} + +li.toctree-l1 { + list-style: none; + font-weight: bold; + font-family: "BPreplay", sans-serif; + font-size: 1.4em; + margin-bottom: 10px; +} + +li.toctree-l1 ul { + list-style: none; + font-weight: normal; + font-size: 0.9em; +} + +li.toctree-l1 > ul { + font-size: 0.7em; +} + +pre { + background: #EEE; + padding: 7px 1em; + margin: 15px 0px; + line-height: 1.3em; +} + +div.highlight > pre { + padding-left:0.3em; +} + +code { + background-color: #EEE; + color: #222; + word-break: break-word; +} + +code.xref { + background-color: #EEE; + border-bottom: 1px solid transparent; +} + +a.reference { + text-decoration: none; +} + +a.reference:hover { + border-bottom: 1px solid #ed7c6a; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #db2e13; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #ed7c6a; +} + +a:hover code { + background: #EEE; +} + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide ugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border:none; +} + +/* ---- Header bar -------------------------------------------------------*/ + +#hcontainer { + position: fixed; + width: 100%; + top:0; + margin:0; + padding:0; + text-align: center; + z-index: 10; + font-family: "BPreplay", sans-serif; +} + +div.headercolor { + position:fixed; + top:0; + height: 12mm; + width: 100%; + background-color:#db2e13; +} + +div.hpositioner { + position: relative; + max-width: 210mm; + margin: 0 auto; + height:100%; +} + +div.header { + position: relative; + height: 100%; + font-size: 1em; + color: white; + display: inline-block; + text-align: left; +} + +div.header > * { + float:left; +} + +#nav_positioner { + position: fixed; + display: block; + margin:0; + height: 100%; + top: 0; + left: 50%; +} + +#nav { + position:absolute; + right:-105.0mm; + top:0; + text-align: left; + white-space: nowrap; + max-height:100%; + min-height:12mm; + min-width :6em; + padding: 12mm 12px 0 5px; + box-sizing: border-box; +} +#nav_button { + position:absolute; + right:0; + cursor:pointer; + text-align: center; + background-color: #eee; + color: #888; + border-right: 2px solid #aaa; + border-left: 2px solid #aaa; + border-bottom: 2px solid #aaa; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + margin-right:12px; + padding:0.2em 1em; + font-size:80%; + font-weight:bold; + z-index:10; +} +#nav_button.pushed { + display:none; +} +#nav_list { + display:none; + background-color: transparent; + position: relative; +} +#nav_list > ul a { + padding:0.3em 1em; +} +#nav_title { + line-height: 9.600000000000001mm; + border-left: 2px solid #aaa; + border-right: 2px solid #aaa; + background-color: #eee; + padding: 0 1em; + font-weight: bold; + font-size:120%; + position: relative; +} +#nav_title > a { + color: #444; +} +#nav_list > ul { + position: relative; + right:0; + background-color: #eee; + border-left: 2px solid #aaa; + border-right: 2px solid #aaa; + border-bottom: 2px solid #aaa; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; +} + +.menu { + position:relative; + display: block; + height: 12mm; + margin:0; +} + +.menu > div > a, +.menu > div > a:hover { + color: white; + text-decoration: none; +} + +.menu > div + div { + font-size: 1em; + position: absolute; + left:-1px; + top: 12mm; + white-space: nowrap; + min-width: 40mm; + -moz-box-shadow: 0 6px 12px rgba(0,0,0,0.175); + -webkit-box-shadow: 0 6px 12px rgba(0,0,0,0.175); + box-shadow: 0 6px 12px rgba(0,0,0,0.175); +} + +.last.menu > div + div { + left:unset; + right: -1px; +} + +.menuButton { + cursor:pointer; + padding: 0 2em; + line-height: 12mm; + height: 100%; +} + +.menuButton span { + font-size: 5.76mm; +} + +.menuButton.pushed { + background-color: #ed7c6a; +} + +.menu div.toctree-smilei { + border-left: 1px solid #db2e13; + border-right: 1px solid #db2e13; + border-bottom: 1px solid #db2e13; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; +} + +.menu div.toctree-smilei a { + padding: 0.4em 1em !important; +} + +#smallScreenMenuButton { + width: 14.399999999999999mm; + height:12mm; + cursor:pointer; + float:right; + text-align: center; + display:none; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + -o-user-select: none; +} + +#smallScreenMenuButton svg, #nav_button svg { + width: 12mm; + height:12mm; + margin:0 auto; +} + +#smallScreenMenuButton.pushed { + background-color: #fce8e5; +} + +#smallScreenMenuButton.pushed svg g { + fill:#db2e13 !important; +} + +#smallScreenMenu { + width: 100%; + position:fixed; + top:12mm; + bottom:0; + left:0; + padding:0.3em 0 0 0; + overflow-y: auto; + background-color:#fce8e5; + border: 0; + z-index:500; +} + +#smallScreenMenu > div { + padding-bottom: 2em; +} + +.on { + display:block; +} + +.off { + display:none; +} + +/* --------------------------------------------------------------------*/ +/* Color styles that are used in tags :red: or :blue: */ +.blue { + color:blue; +} +.red { + color:red; +} +.purple { + color:#6967AB; +} +.green { + color:green; +} +.orange { + color:orange; +} +.blue > a, .red > a, .purple > a, .green > a, .orange > a { + color: inherit; +} +.blue > a:hover, .red > a:hover, .purple > a:hover, .green > a:hover, .orange > a:hover { + border-bottom: 1px solid; +} + +/* Style for an emphasized link */ +.emphlink { + text-align:center; + font-size:1.3em; +} + +div.experimental > h1:first-of-type::after, +div.experimental > h2:first-of-type::after, +dl.experimental > dt:first-of-type::after, +ul.experimental p:first-of-type::after +{ + content: "experimental"; + display: inline-block; + background:red; + color:white; + margin: 4px 10px; + padding: 0 5px; + border-radius: 5px; + font-size: 0.8em; + font-family: "BPreplay"; + font-weight: bold; + line-height: normal; +} + +/* --------------------------------------------------------------------*/ +/* Logos and icons */ +img.logo { + height:12mm; +} +a.icon { + display:inline-block; + text-align:center; + margin:0.3em; + width:100px; + text-decoration:none; + color:#3E4349; +} +a.icon * { + margin:0 auto; + display:block; +} +a.icon img { + height:3em; +} +a.icon:hover { + color:#3E4349; + background-color:#fce8e5; +} +a.icon:active { + background-color:#ed7c6a; +} + +/* --------------------------------------------------------------------*/ +/* Styles for the lab logos container */ +div.lablogos { + border:0px solid #555; +} +div.lablogos > br.clear { + clear:both; +} +div.lablogos > div { + padding:5px; + float:left; +} + +/* --------------------------------------------------------------------*/ +/* table of contents */ +div.toctree-smilei { + background-color: #fce8e5; + font-weight:normal; +} + +div.toctree-smilei a { + text-decoration: none; + border:0 !important; + color: black; + display:block; +} +div.toctree-smilei > ul { + margin: 0; + list-style: none; +} +div.toctree-smilei > ul > li { + margin: 0; + padding: 0; +} +div.toctree-smilei > ul > li > a { + background-color: #db2e13; + color: #fce8e5; + padding: 0.4em 0 0.4em 1em; +} +div.toctree-smilei li.outer > a { + background-color: transparent; + color: #db2e13; +} +div.toctree-smilei li.outer > a:hover { + background-color: #ed7c6a; + color: #fce8e5; +} +div.toctree-smilei > ul > li > ul { + margin: 0; + list-style: none; +} +div.toctree-smilei > ul > li > ul > li > a { + padding:0.3em 0 0.3em 2.5em; +} +div.toctree-smilei > ul > li > ul > li > a:hover { + background-color: #ddd; +} + +div.toctree-smilei > ul > li > ul > li > ul { + display:none; +} + +/* --------------------------------------------------------------------*/ +/* Some tricks for the citations */ +table.citation td.label + td > em, +span.fn-backref { + display:none; +} +table.citation td.label + td ol { + margin-top: 0 !important; +} +/* Remove the back-reference link when there is one back-reference */ +table.citation td.label a, +dl.citation dt.label a { + pointer-events: none; + cursor: default; + text-decoration: none; + color: inherit; +} +/* Brackets for Sphinx 2.+ */ +a.brackets::before, span.brackets > a::before, +a.brackets::after , span.brackets > a::after { + content: ""; +} +.brackets::before { + content: "["; +} +.brackets::after { + content: "]"; +} +/* Margins for Sphinx 2.+ */ +dl.citation > dd > p { + margin: 0; +} +dl.citation > * { + margin-top: 0; + margin-bottom: 0; + padding: 0.25em 0.7em; +} +dl.citation p { + line-height: normal; +} + +/* Make a "bigcitation" class for citations with several lines */ +.bigcitation .citation td.label, .bigcitation .citation dt +{ + max-width: 0; +} +.bigcitation .citation td.label + td, .bigcitation .citation dt + dd +{ + padding-top: 1.5em; +} + +/* --------------------------------------------------------------------*/ +/* Adjust horizontal lines */ +hr { + margin-top:1em; + border: 0; + border-top: 2px solid #db2e13; +} +div.toctree-smilei hr { + margin: 0.2em 0; + background: #db2e13; + width:100%; +} + +/* --------------------------------------------------------------------*/ +/* Adjust figure */ +.figure { + text-align:center; +} +.caption-number { + margin-right:8px; + padding-right:4px; + border-right:1px solid #BBB; +} +.caption { + margin-top:0; + margin-bottom:0; +} +.image-reference { + border-bottom:0 !important; +} + +/* --------------------------------------------------------------------*/ +/* Index */ + +.siteindex { + width:100%; + text-align:center; +} +.siteindex > div { + display:inline-block; + text-align:left; +} + +@media print +{ + #hcontainer { display: none !important; } +} + +/* --------------------------------------------------------------------*/ +/* Search box */ + +#searchicon, #closesearchicon { + width:12mm; + text-align: center; + cursor:pointer; +} +#searchicon > svg, #closesearchicon > svg { + height:12mm; +} +#searchbox { + position: absolute; + right:12mm; + height:12mm; +} +#searchinput { + height:7.199999999999999mm; + width: 80mm; + font-size: 1em; + padding:1.2000000000000002mm 0.6em; + margin:1.2000000000000002mm 0; + border-radius:0.5em; + border:0; + color: #555; + background-color: white; +} +#search-results { + padding-top: 5px; +} + +/* ---- MathJax display issues ------------*/ +.MathJax_Display, .MathJax { + overflow-x: auto; + overflow-y: hidden; + z-index: 0; +} + + +@media screen and (max-width: 212.1mm) { + + body, div.documentwrapper, .bodywrapper { + margin:0; + } + + .version::before { + font-size: 3vw; + } + + ul, ol { + margin-left: 0.6em; + } + + .document { + position: relative; + width: auto !important; + z-index:0; + } + + .footer { + width: auto; + } + + .github, .rtd_doc_footer { + display: none; + } + + div.documentwrapper { + float: none; + background: white; + } + + div.document { + margin: 12mm 0 0 0; + padding: 0 1em 1em 1em; + } + + div.body { + min-height: 0; + padding: 0; + } + + div.body h1 { + padding: 0.1em 0.3em; + word-break: break-all; + } + + div.header { + display:block; + } + #smallScreenMenuButton { + display: block !important; + } + .menu, #nav { + display: none; + } + #searchicon, #closesearchicon { + display:none !important; + } + #searchbox { + display:block !important; + left:33.599999999999994mm; + right:22.799999999999997mm; + } + #searchinput { + display:block !important; + width:100%; + } + + table.fancy, table.fancy > tbody, table.fancy > tbody > tr { + display: block; + width: 100%; + } +} + + +@media screen and (min-width: 212.1mm) { + #smallScreenMenu { + display: none !important; + } +} diff --git a/_static/smileitheme.css b/_static/smileitheme.css new file mode 100644 index 0000000..8d53dde --- /dev/null +++ b/_static/smileitheme.css @@ -0,0 +1,281 @@ +/* --------------------------------------------------------------------*/ +/* Color styles that are used in tags :red: or :blue: */ +.blue { + color:blue; +} +.red { + color:red; +} +.purple { + color:#6967AB; +} +.green { + color:green; +} +.orange { + color:orange; +} + +/* --------------------------------------------------------------------*/ +/* Style for the "In progress" block */ +.inprogress { + text-align:center; + padding:5px; + margin:0 30%; + background-color: #e3f7f2; + border: 1px solid #db2e13; +} + +/* Style for an emphasized link */ +.emphlink { + text-align:center; + font-size:1.3em; +} + +/* --------------------------------------------------------------------*/ +/* Prevent tables to wrap lines */ +table.nowrap { + white-space: nowrap; +} +/* Remove bottom margin in table cells with line-blocks */ +table.docutils div.line-block { + margin-bottom:0; +} + +table.noborder, table.noborder td { + border:0 !important; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; + vertical-align:middle; +} +/* Make nicer table header */ +table.docutils thead { + background-color: #e3f7f2; +} + +/* --------------------------------------------------------------------*/ +/* Logos and icons */ +img.logo { + width:160px; +} +div.sphinxsidebarwrapper p.logo { + text-align: left; +} +.horizontallogo { + display:none; + height:5em; +} +@media screen and (max-width: 875px) { + .horizontallogo { + display:block; + } +} +.icon { + display:inline-block; + text-align:center; + margin:0.3em; + width:100px; +} +.icon * { + margin:0 auto; + display:block; +} +.icon img { + height:3em; +} +.icon, .icon:hover { + text-decoration:none; + color:#333; +} +.icon:hover { + background-color:#e3f7f2; +} +.icon:active { + background-color:#d7f4ec; +} + +/* --------------------------------------------------------------------*/ +/* Styles for the lab logos container */ +div.lablogos { + border:0px solid #555; +} +div.lablogos > br.clear { + clear:both; +} +div.lablogos > div { + padding:5px; + float:left; +} + +/* --------------------------------------------------------------------*/ +/* Nice blue menu on the sidebar */ +div.toctree-smilei > ul > li > a { + font-size: 100%; + font-weight: bold; + text-decoration: none; + color: #db2e13; + border:0; +} +div.toctree-smilei > ul, div.toctree-smilei > li { + margin: 0; + padding: 0; +} +/* Adjust the sidebar color for small screens */ +@media screen and (max-width: 875px) { + div.sphinxsidebar { + background: #e3f7f2; + padding: 10px 30px; + width: 100%; + } + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, div.sphinxsidebar h3 a { + color: #444; + } + div.sphinxsidebar a { + color: #444; + } +} + +/* --------------------------------------------------------------------*/ +/* Some tricks for the citations */ +/* Remove the weird shadows */ +table.docutils.citation, table.docutils.citation * { + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} +/* Remove the back-reference links when there are several back-references */ +table.citation td.label + td > em { + display:none; +} +table.citation td.label + td ol { + margin-top: 0 !important; +} +/* Remove the back-reference link when there is one back-reference */ +table.citation td.label a { + pointer-events: none; + cursor: default; + text-decoration: none; + color: inherit; +} +/* Make a "bigcitation" class for citations with several lines */ +table.bigcitation td.label { + max-width: 3px; +} +table.bigcitation td.label + td { + padding-top: 25px; +} + +/* --------------------------------------------------------------------*/ +/* Adjust code blocks */ +dl pre, blockquote pre, li pre { + margin-left:0; +} +div.highlight > pre { + padding-left:0.3em; +} + +/* --------------------------------------------------------------------*/ +/* Adjust horizontal lines */ +hr { + margin-top:1em; + border-color: #db2e13; +} +.toctree-smilei hr { + margin: 0.2em 0; + background: #db2e13 !important; + width:60% !important; +} + +/* --------------------------------------------------------------------*/ +/* Color for titles */ +h1, h2, h3, h4, h5, h6 { + color: #db2e13; + font-weight:bold !important; +} + +/* --------------------------------------------------------------------*/ +/* Smaller admonition box */ +div.admonition { + padding:7px !important; + margin:0px 30px !important; + background-color: #f7dad4; + border: 1px solid #db2e13; + overflow: hidden; +} +div.admonition p.admonition-title { + font-size: 18px; + font-weight: bold; + margin:0; + float: inherit; +} +div.admonition p { + margin:5px 0; + float: right; +} + +/* --------------------------------------------------------------------*/ +/* Adjust figure */ +.figure { + text-align:center; +} +.caption-number { + margin-right:8px; + padding-right:4px; + border-right:1px solid #BBB; +} +.caption { + margin-top:0; + margin-bottom:0; +} +.image-reference, table.noborder td:first-child > .reference { + border-bottom:0 !important; +} + + +div.related { + display: none; +} + +/* --------------------------------------------------------------------*/ +/* Back to top box */ + +#backToTopContainer { + position:fixed; + bottom:0; + left:50%; +} +#backToTopDiv { + position:relative; + left:-255px; + bottom:5px; + padding:5px; + text-decoration:none; + background-color:#EEE; + cursor:pointer; +} +#backToTopDiv img { + height:1em; +} +#backToTopDiv:hover { + text-decoration:none; +} +#backToTopDiv:hover { + background-color:#f7dad4; +} +#backToTopDiv:active { + background-color:#fcd2cc; +} + +@media screen and (max-width: 875px) { + #backToTopContainer { + left:0; + } + #backToTopDiv { + left:5px; + } +} +@media print +{ + #backToTopDiv { display: none !important; } +} \ No newline at end of file diff --git a/advanced.html b/advanced.html new file mode 100644 index 0000000..1398d0a --- /dev/null +++ b/advanced.html @@ -0,0 +1,566 @@ + + + + + + + Advanced — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

AdvancedΒΆ

+
+ +
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_beam_driven_wake.py b/advanced_beam_driven_wake.py new file mode 100644 index 0000000..f19e2d4 --- /dev/null +++ b/advanced_beam_driven_wake.py @@ -0,0 +1,259 @@ +################################################################################# +############################# Input namelist for Beam-driven Wakefield generation +############################# a relativistic electron bunch generates plasma waves + +# The bunch field is initialized with the relativistic Poisson solver. +# Perfectly Matched Layers are used to absorb the fields at the boundaries. +# The simulation parameters are based mostly on +# F. Massimo et al., Journal of Computational Physics 327 (2016) 841–850 +# in particular Fig. 8d + + +import math +import numpy as np +import scipy.constants + +##### Physical constants +lambda0 = 333.89e-6 # reference length, m - here it will be our plasma wavelength +c = scipy.constants.c # lightspeed, m/s +omega0 = 2*math.pi*c/lambda0 # reference angular frequency, rad/s +eps0 = scipy.constants.epsilon_0 # Vacuum permittivity, F/m +e = scipy.constants.e # Elementary charge, C +me = scipy.constants.m_e # Electron mass, kg +ncrit = eps0*omega0**2*me/e**2 # Plasma critical number density, m-3 +c_over_omega0 = lambda0/2./math.pi # converts from c/omega0 units to m +reference_frequency = omega0 # reference frequency, s-1 +E0 = me*omega0*c/e # reference electric field, V/m +electron_mass_MeV = scipy.constants.physical_constants["electron mass energy equivalent in MeV"][0] + + +##### Variables used for unit conversions +c_normalized = 1. # speed of light in vacuum in normalized units +um = 1.e-6/c_over_omega0 # 1 micron in normalized units +fs = 1.e-15*omega0 # 1 femtosecond in normalized units +mm_mrad = um # 1 millimeter-milliradians in normalized units +pC = 1.e-12/e # 1 picoCoulomb in normalized units +MeV = 1./electron_mass_MeV # 1 MeV in normalized units + +######################### Simulation parameters + +##### mesh resolution +dx = 1.00 *um # longitudinal mesh resolution +dr = 0.45*um # transverse mesh resolution +dt = 0.80*fs # integration timestep + +##### simulation window size +nx = 640 # number of mesh points in the longitudinal direction +nr = 240 # number of mesh points in the transverse direction +Lx = nx * dx # longitudinal size of the simulation window +Lr = nr * dr # transverse size of the simulation window + + +##### patches parameters (parallelization) +npatch_x = 64 +npatch_r = 8 + + +######################### Main simulation definition block + +Main( + geometry = "AMcylindrical", + number_of_AM = 1, # cylindrical symmetry + interpolation_order = 2, + + timestep = dt, + simulation_time = 1101*um, + cell_length = [dx, dr], + grid_length = [ Lx, Lr], + number_of_patches = [npatch_x,npatch_r], + + EM_boundary_conditions = [["PML","PML"],["PML","PML"],], + number_of_pml_cells = [[20,20],[20,20]], + + print_every = 100, + + reference_angular_frequency_SI = omega0, + + solve_poisson = False, + solve_relativistic_poisson = True, + relativistic_poisson_max_iteration = 50000, +) + +######################### Define a moving window + +MovingWindow( + time_start = 0., # window starts moving at the start of the simulation + velocity_x = c_normalized, +) + +######################### Define the plasma +center_bunch = Lx-166.5*um +##### plasma parameters +n0 = 1e22/ncrit # plasma plateau density in units of critical density defined above +Radius_plasma = 65.*um # Radius of plasma +Lramp = 100*um # Plasma density upramp length +Lplateau = 100.*Lx +Ldownramp = 0.1*Lx +begin_upramp = Lx +begin_plateau = begin_upramp+Lramp +end_plateau = begin_plateau+Lplateau +end_downramp = end_plateau+Ldownramp + +##### plasma density profile +longitudinal_profile = polygonal(xpoints=[begin_upramp,begin_plateau,end_plateau,end_downramp],xvalues=[0.,n0,n0,0.]) +def plasma_density(x,r): + profile_r = 0. + if ((r)**2 + + + + + Multiphoton Breit-Wheeler pair creation process — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Multiphoton Breit-Wheeler pair creation processΒΆ

+

The goal of this tutorial is to present how to use the multiphoton Breit-Wheeler +pair creation process in Smilei. +The following points will be addressed:

+
    +
  • How to prepare input files for this physical module

  • +
  • How to setup macro-photon species and the Monte-Carlo emission

  • +
  • How to setup the multiphoton Breit-Wheeler pair creation process

  • +
  • How to use diagnostics

  • +
  • How to read and understand produced outputs

  • +
+
+
+

Physical configurationΒΆ

+

A multi-GeV electron beam is made to collide with a counter-propagating plane wave. +This configuration is one of the most efficient to trigger radiative and QED effects. +It maximizes the value of the quantum parameter for a given electron energy and a +given field strength.

+

The simulation is 2D Cartesian with a simulation size of \(30 \lambda \times 4 \lambda\) +where \(\lambda\) is the laser wavelength. The laser is injected from the left side +of the simulation domain while the electron beam is initialized at the extreme right.

+

In this initial configuration, the laser has a wavelength of \(\lambda = 1\ \mu \mathrm{m}\), +an amplitude of \(10^{23}\ \mathrm{W/cm}^2\) (\(a_0 \simeq 270\)) and is linearly +polarized in the y direction. The temporal profile is Gaussian (order 4). +he full width at half maximum (FWHM) is of 10 laser periods (approximately 33 fs).

+

The electron beam has an initial energy of 4 GeV and propagates to the left. +The beam density is of \(n_b = 10^{-5} n_c\). The electron beam is frozen the +time for the laser to be fully injected and so that the collision occurred at +the middle of the domain. This enables to have a shorter simulation box and +therefore save computational time. The beam is initialized with 32 particles +per cell for a total of 3648 macro-particles.

+
+
+
+

Content of the tutorialΒΆ

+

Download AdvancedTutorial2.tar.gz and extract it. +It contains 2 directories:

+
    +
  • Analysis

  • +
  • Execution

  • +
+

The directory Analysis contains Python scripts that will be used to analysis +and visualize the simulation outputs. Each script has been designed to focus on a +specific quantity:

+
    +
  • show_energy_balance.py: particle kinetic energy, photon energy and radiated energy (not in the photons) vs. time.

  • +
  • show_particle_number.py: number of macro-particles for each species vs. time.

  • +
  • show_2d_density.py: maps of the electron, positron and photon density.

  • +
  • show_2d_average_energy.py: maps of the electron, positron and photon average energy.

  • +
  • show_2d_average_chi.py: maps of the electron, positron and photon quantum parameter.

  • +
  • show_2d_fields.py: maps of the electric field \(E_y\) and the magnetic field \(B_z\).

  • +
  • show_energy_spectrum.py: electron, positron and photon energy distribution at a given time.

  • +
+

The Execution directory contains the input file:

+
    +
  • tst2d_electron_laser_collision.py

  • +
+
+
+
+

Simulation of the multiphoton Breit-Wheeler processΒΆ

+

We will first learn how to configure the input file for the Monte-Carlo process +with macro-photon emission followed by the Multiphoton Breit-Wheeler +pair creation process. +For this simulation case, we will need to define three species: electrons, positrons and photons. +After the configuration, we will then run our simulation test case. +Finally, we will see how to read and exploit diagnostic outputs via Python script +and the happi post-processing module.

+
    +
  • Make a copy of the directory Execution and name it +Multiphoton_Breit_Wheeler. We will perform the simulation in this directory.

    +
    cp -r Execution Multiphoton_Breit_Wheeler
    +cd Multiphoton_Breit_Wheeler
    +
    +
    +
  • +
  • Open the input file tst2d_electron_laser_collision.py.

  • +
+
+
+
+

Configuration of the radiation reaction blockΒΆ

+
    +
  • Go to the RadiationReaction block.

  • +
  • The Monte-Carlo algorithm uses tabulated values. +The path can be specified in the block RadiationReaction via the parameter table_path +(read the documentation if you want to use non-default databases).

  • +
  • The parameter minimum_chi_continuous corresponds to the minimal value +of the quantum parameter at which the radiation reaction process is applied. +Below this value, the particle does not undergo radiation reaction. +Uncomment the corresponding line. +Specifying this parameter is actually not compulsory since it is defined +by default at \(10^{-3}\).

  • +
  • Uncomment the line with the parameter minimum_chi_discontinuous. +The Monte-Carlo model is built to work with +the continuous corrected Landau-Lifshitz approach when the particle quantum parameter is too low. +This parameter corresponds to this threshold. +Above this value, a particle undergoes radiation reaction via the Monte-Carlo engine. +Below the continuous approach is used. +This parameter is by default equal to \(10^{-2}\) +but it is modified to be \(10^{-3}\) here.

  • +
  • The RadiationReaction should now look like:

    +
    RadiationReaction(
    +     minimum_chi_continuous = 1e-3
    +     minimum_chi_discontinuous = 1e-3,
    +    #table_path = "<path to some Smilei tables>"
    +)
    +
    +
    +
  • +
+

External tables: some models such as the Monte-Carlo radiation model use complex mathematical functions to determine the production rate of +photons and energy. +These functions are tabulated because it would be too expensive to compute them on the fly for each macro-particles. +The Smilei code includes default tables. +It is nonetheless possible to use more accurate external tables. +This is the purpose of the parameter table_path in the block Radiation. +For more information about the tables, see https://smileipic.github.io/Smilei/Use/tables.html.

+
+
+
+

Configuration of the multiphoton Breit-Wheeler blockΒΆ

+
    +
  • Go to the MultiphotonBreitWheeler block. +This block controls the general parameters of the Multiphoton Breit-Wheeler process.

  • +
  • The Monte-Carlo algorithm for the Multiphoton Breit-Wheeler process uses tabulated values. +The path can be specified in the block MultiphotonBreitWheeler via the parameter table_path, +if you wish to use non-default tables.

  • +
  • The MultiphotonBreitWheeler should now look like:

    +
    MultiphotonBreitWheeler(
    +    #table_path = "<path_to_smilei>/databases/"
    +)
    +
    +
    +
  • +
+
+
+
+

Configuration of the electron speciesΒΆ

+
    +
  • We will first configure the electron species that composes the beam so that +it can radiate via the Monte-Carlo model and generate macro-photons +Go to the electron species block. you can see that the radiation parameters +are commented.

  • +
  • The parameter radiation_model corresponds to the type of radiation model to be used. +Uncomment the corresponding line. We use here the Monte-Carlo.

  • +
  • When radiation_photon_species is present and not set to None, +the possibility to generate macro-photons is activated. This parameter has to be set to +the name of the photon species that will receive the created macro-photons. +Uncomment the corresponding line. The photon species is called photon.

  • +
  • The parameter radiation_photon_sampling enables to control the number of +macro-photons generated per emission even. By default, an emission yields a +single macro-photons of weight similar to the emitting particle. to increase +the emission statistics, you can decide to increase this number so that several +macro-photons are generated per even. In this case, the weight is equally +divided between macro-photons for quantity conservation. +Uncomment the corresponding line.

  • +
  • The parameter radiation_photon_gamma_threshold enables to control the +minimum threshold on the photon energy that allow macro-photon emission. +Below the specified value, the radiation reaction is taken into account +but no macro-photon is created. +Here, since photons of energy below twice the electron rest mass energy have +no chance to turn into electron-positron pairs, this threshold is set to 2. +This value is actually the default one. +Uncomment the corresponding line.

  • +
  • The radiation parameters of the electron species block are now:

    +
    Species(
    +    name = "electron",
    +...
    +    radiation_model = "Monte-Carlo",
    +    radiation_photon_species = "photon",
    +    radiation_photon_sampling = 1,
    +    radiation_photon_gamma_threshold = 2,
    +...
    +)
    +
    +
    +
  • +
  • The electron species is now configured.

  • +
+
+
+
+

Configuration of the photon speciesΒΆ

+
    +
  • We will then configure the photon species that will receive the macro-photons +generated by the other species via the Monte-Carlo radiation model. +Go to the photon species block. you can see that the Multiphoton +Breit-Wheeler parameters are commented. They start by multiphoton_Breit_Wheeler.

  • +
  • The parameter multiphoton_Breit_Wheeler is a list of two strings. +These strings respectively correspond +to the species name that will receive the created electron and the created positron. +Uncomment the corresponding line. +The electron and the positron species respectively correspond to electron and positron. +When this parameter is commented, the multiphoton Breit-Wheeler is not activated.

  • +
  • The parameter multiphoton_Breit_Wheeler_sampling is the number of +macro-electron and macro-positron generated per Monte-Carlo event. +This parameter is a list of two integers. +By default, an electron and a positron are generated per event. +To improve the statistics, these numbers can be increased. +The macro-particle weight is then divided in consequence. +Uncomment the corresponding line.

  • +
  • The multiphoton Breit-Wheeler parameters for the photon species block are now:

    +
    Species(
    +    name = "photon",
    +...
    +    multiphoton_Breit_Wheeler = ["electron","positron"],
    +    multiphoton_Breit_Wheeler_sampling = [1,1],
    +...
    +)
    +
    +
    +
  • +
+
+
+
+

Configuration of the positron speciesΒΆ

+
    +
  • We will then configure the positron species that will receive the macro-positrons +generated via the multiphoton Breit-Wheeler. +Go to the positron species block.

  • +
  • As for the electron species, uncomment the radiation parameters as follow:

    +
    Species(
    +    name = "positron",
    +...
    +    radiation_model = "Monte-Carlo",
    +    radiation_photon_species = "photon",
    +    radiation_photon_sampling = 1,
    +    radiation_photon_gamma_threshold = 2,
    +...
    +)
    +
    +
    +
  • +
+

The positrons will also radiate with the Monte-Carlo model.

+
+
+
+

Presentation of the diagnosticsΒΆ

+

Several diagnostics are defined in the input file.

+
    +
  • Time-evolution of scalar quantities are configured via the DiagScalar block. +Here, output of the radiated energy (not including the macro-photons) +is requested via Urad. Ukin_<species> corresponds to the kinetic energy of <species> +(total energy for the photons). Ntot_<species> is the number of macro-particles.

    +
    DiagScalar(
    +    every = 10,
    +    vars=['Uelm','Ukin','Utot','Uexp','Ubal',
    +          'Urad',
    +          'Ukin_electron',
    +          'Ukin_positron',
    +          'Ukin_photon',
    +          'Ntot_electron',
    +          'Ntot_positron',
    +          'Ntot_photon']
    +)
    +
    +
    +
  • +
  • The field grids are written out every 500 iterations via the block DiagFields.

  • +
  • The DiagParticleBinning blocks project the particle +quantities on specified multidimensional grids. +There are 4 types of diagnostics configured in the input file for each species:

    +
      +
      1. +
      2. the species weight distribution

      3. +
      +
    • +
      1. +
      2. the kinetic energy times the weight (weight_ekin)

      3. +
      +
    • +
      1. +
      2. the quantum parameter time the weight (weight_chi)

      3. +
      +
    • +
      1. +
      2. the species energy distribution

      3. +
      +
    • +
    +

    The particle binning diagnostics are written every 500 iterations.

    +
  • +
+
+
+
+

Simulation analysisΒΆ

+

After you have run the simulation, you may start analyzing its results.

+
    +
  • Let us first analyze the time-evolution of the number of macro-particles +in the simulation. +Copy the file Analysis/show_particle_number.py in the working directory:

    +
    cp ../Analysis/show_particle_number.py .
    +
    +
    +

    Run the script using iPython:

    +
    ipython
    +run show_particle_number.py
    +
    +
    +
  • +
  • You should obtain the following graph:

    +_images/particle_number.png +

    When the laser starts to interact with the electron beam around \(t = 230 \omega_r^{-1}\), +the number of macro-photons rises rapidly due thanks to +the Monte-Carlo radiation model. +Later, these photons start to decay into electron-positron pairs +via the multiphoton Breit-Wheeler. +We can observe an increase of the number of macro-electrons and macro-positrons +from \(t = 235 \omega_r^{-1}\)

    +
  • +
  • Copy the file Analysis/show_energy_balance.py in the working directory +and run the script:

    +
    cp ../Analysis/show_energy_balance.py .
    +ipython
    +run show_energy_balance.py
    +
    +
    +
  • +
  • You should obtain the following graph:

    +_images/energy_balance.png +
  • +
  • We will now use the particle binning diagnostics. +Copy the file Analysis/show_2d_average_energy.py in the working directory +and run the script:

    +
    cp ../Analysis/show_2d_average_energy.py .
    +ipython
    +run show_2d_average_energy.py
    +
    +
    +

    You should obtain the following graph:

    +_images/2d_average_energy_it5500.png +

    From the top to the bottom, you have respectively the electron, positron +normalized kinetic energy and the photon normalized energy.

    +

    You can also choose a different timestep using, for instance

    +
    run show_2d_average_energy.py 6000
    +
    +
    +
  • +
  • We will now do the same thing for the weight (normalized local density). +Copy the file Analysis/show_2d_density.py in the working directory +and run the script:

    +
    cp ../Analysis/show_2d_density.py .
    +ipython
    +run show_2d_density.py
    +
    +
    +

    You should obtain the following figure:

    +_images/2d_density_it5500.png +

    Change the timestep parameter to see how the beam shape evolves during +the simulation and how the positron are created.

    +
  • +
  • We can also look at the quantum parameter. +Copy the file Analysis/show_2d_average_chi.py in the working directory +and run the script:

    +
    cp ../Analysis/show_2d_average_chi.py .
    +ipython
    +run show_2d_average_chi.py
    +
    +
    +

    You should obtain the following figure:

    +_images/2d_average_chi_it5500.png +

    The maximal value of the quantum parameter is printed in the terminal. +Change the timestep parameter to see how the electron, positron and photon +average quantum parameter evolve during +the simulation.

    +
  • +
  • To get an idea of where in the laser field the beam is located, +you can use the script Analysis/show_2d_fields.py +Copy and run it:

    +
    cp ../Analysis/show_2d_fields.py .
    +ipython
    +run show_2d_fields.py
    +
    +
    +

    You should obtain the following figure:

    +_images/2d_fields_it5500.png +

    Change the timestep parameter as for the particle binning diagnostics.

    +
  • +
  • Finally, we want to analyze the final energy spectra of the species. +Copy the script Analysis/show_energy_spectrum.py and run it.

    +
    cp ../Analysis/show_energy_spectrum.py .
    +ipython
    +run show_energy_spectrum
    +
    +
    +

    You should obtain the following figure:

    +_images/energy_spectrum_it8000.png +
  • +
+
+
+
+

To go beyondΒΆ

+
    +
  • Optional exercice: Change the laser and electron beam properties to see +how it affects the beam energy loss and the production of electron-positron pairs.

  • +
  • Optional exercice: Use the same input file to build a similar case in 3D. +You will have to increase the number of nodes. +Use a focused laser pulse instead a place wave and see how the pulse waist +affect the interaction (final positron energy, beam divergence…).

  • +
  • Optional exercice: Activate the load balancing and change the number of +patches to see how it affects the performances.

  • +
+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_collisions.html b/advanced_collisions.html new file mode 100644 index 0000000..e1579a4 --- /dev/null +++ b/advanced_collisions.html @@ -0,0 +1,630 @@ + + + + + + + Binary collisions and impact ionization — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Binary collisions and impact ionizationΒΆ

+

Smilei includes binary collisions between various species, which can also generate +ionization when one of the species is ions and the other one electrons. +Smilei’s website +already gives a description of the approach, and provides results from various benchmarks.

+

The list of benchmarks, located in the benchmarks/collisions/ folder is briefly +described below. You may run any of these benchmarks depending on your interests.

+
+

Beam relaxationΒΆ

+

An electron beam encounters a thermal ion population; e-i collisions slow the beam down +and make it spread. Various electron velocities and ion charges are considered. For each +case, the ratios of weights between electrons and ions is varied.

+

1. initial velocity = 0.05, ion charge = 1

+
+
beam_relaxation1.py
+
beam_relaxation2.py
+
beam_relaxation3.py
+
Analysis and plotting provided in beam_relaxation123.py
+
+

2. initial velocity = 0.01, ion charge = 1

+
+
beam_relaxation4.py
+
beam_relaxation5.py
+
beam_relaxation6.py
+
Analysis and plotting provided in beam_relaxation456.py
+
+

3. initial velocity = 0.01, ion charge = 3

+
+
beam_relaxation7.py
+
beam_relaxation8.py
+
beam_relaxation9.py
+
Analysis and plotting provided in beam_relaxation789.py
+
+
+
+

ThermalizationΒΆ

+

Thermal electrons start with a different temperature from that of ions. +The thermalization due to e-i collisions is monitored for three different weight ratios.

+
+
thermalisation_ei1.py
+
thermalisation_ei2.py
+
thermalisation_ei3.py
+
Analysis and plotting provided in thermalisation_ei123.py
+
+
+
+

Temperature isotropizationΒΆ

+

Non-isotropic thermal electrons are isotropized with e-e collisions.

+
+
temperature_isotropization1.py
+
temperature_isotropization2.py
+
Analysis and plotting provided in temperature_isotropization.py
+
+
+
+

MaxwellianizationΒΆ

+

An electron population starting with a rectangular velocity distribution becomes +maxwellian due to e-e collisions.

+
+
Maxwellianization1.py
+
Analysis and plotting provided in Maxwellianization.py
+
+
+
+

Stopping powerΒΆ

+

The e-e slowing rate of test electrons passing through an electron plasma is monitored +vs. time and compared to a theoretical stopping power.

+
+
Stopping_power1.py : projectiles from 10 to 30 keV
+
Stopping_power2.py : projectiles from 100 to 300 keV
+
Stopping_power3.py : projectiles from 1 to 10 MeV
+
Analysis and plotting provided in Stopping_power123.py
+
+
+
+

Ionization rateΒΆ

+

Drifting electrons in a cold Al plasma cause e-i impact ionization at a rate compared +to theoretical values. The three inputs below correspond to various weight ratios +between electrons and ions.

+
+
ionization_rate1.py
+
ionization_rate2.py
+
ionization_rate3.py
+
Analysis and plotting provided in ionization_rate.py
+
+
+
+

Inelastic stopping powerΒΆ

+

The ionizing e-i slowing rate of test electrons passing through an Al plasma +is monitored vs. time and compared to a theoretical stopping power.

+
+
ionization_stopping_power1.py : measurement for electrons at various energies
+
+
+
ionization_stopping_power2.py :
+
ionization_stopping_power3.py : three examples to show the stopping dynamics
+
ionization_stopping_power4.py :
+
+
+
Analysis and plotting provided in ionization_stopping_power.py
+
+
+
+

Multiple ionizationΒΆ

+

The capability to ionize several times in one timestep is illustrated for five different +materials. For each material, two cases are provided: the first is well resolved, while +the second has a low time resolution requiring multiple ionization.

+
+
ionization_multipleC1.py
+
ionization_multipleC2.py
+
ionization_multipleAl1.py
+
ionization_multipleAl2.py
+
ionization_multipleZn1.py
+
ionization_multipleZn2.py
+
ionization_multipleSn1.py
+
ionization_multipleSn2.py
+
ionization_multipleAu1.py
+
ionization_multipleAu2.py
+
Analysis and plotting provided in ionization_multiple.py
+
+
+
+

Effect of neglecting recombinationΒΆ

+

As recombination is not accounted for, we can expect excess ionization to occur +indefinitely without being balanced to equilibrium. For picosecond laser interaction, +we illustrate here that the recombination rate can be neglected, thus providing +reasonable ionization state vs. temperature, in various materials.

+
+
ionization_equilibriumH.py
+
ionization_equilibriumAl.py
+
ionization_equilibriumZn.py
+
ionization_equilibriumAu.py
+
Analysis and plotting provided in ionization_equilibrium.py
+
+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_field_ionization.html b/advanced_field_ionization.html new file mode 100644 index 0000000..42ccdb8 --- /dev/null +++ b/advanced_field_ionization.html @@ -0,0 +1,552 @@ + + + + + + + Field ionization — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Field ionizationΒΆ

+

The goal of this tutorial is to present a simulation using an advanced physics module, +namely the field (tunnel) ionization module. +In the presence of tunnel ionization, one needs to set a reference temporal/spatial scale. +In Smilei, this is done by defining, in SI units, the reference angular +frequency parameter: reference_angular_frequency_SI.

+

Briefly, this tutorial will help you:

+
    +
  • use the reference_angular_frequency_SI

  • +
  • use the .getData() tool of happi to analyse your data and make your own figures.

  • +
+
+
+

Physical configurationΒΆ

+

Download the input file tunnel_ionization_1d.py as well as +the analysis scripts analysis_tunnel_ionization_1d.py and solve_rate_eqs.py.

+

In a 1D cartesian geometry, a thin layer of neutral carbon is irradiated (thus ionized) +by a linearly-polarized laser pulse with intensity \(I = 5\times 10^{16}~{\rm W/cm^2}\) +and a gaussian time profile.

+
+
+
+

Check the input file and run the simulationΒΆ

+

The first step is to check that your input file is correct. +To do so, you will run (locally) Smilei in test mode:

+
./smilei_test tunnel_ionization_1d.py
+
+
+

If your simulation input file is correct, you can run the simulation.

+
+

Warning

+

For this simulation, we have specified in the input file that only 1 patch is created. +Therefore, this simulation can be run using a single processor only!

+
+

Before going to the analysis of your simulation, check your log file!

+
+
+
+

Analyse the simulationΒΆ

+

A python script has been prepared to analyse the simulations results. +Open the file analysis_tunnel_ionization_1d.py and have look at what it does. +Note that it calls for the solve_rate_eqs.py file that is used to compute +the rate equations (obtained theoretically).

+
+

Warning

+

Before running analysis_tunnel_ionization_1d.py, give the +correct path to your simulation results by defining the +simulation_to_analyse variable!

+
+

In an ipython prompt, run the analysis file:

+
%run analysis_tunnel_ionization_1d.py
+
+
+

What do you obtain? Check also if any .eps file is generated.

+
+

Note

+

Some lines containing LateX commands have been commented out. +If your machine has LateX installed, it may provide higher-quality figures.

+
+
+
+
+

Changing the reference angular frequencyΒΆ

+

As you have seen in the namelist, you have to specify a reference angular frequency in SI units. +This because the ionization rate is not invariant under the usual normalizations (see tutorial on Units). +What happens to the results if you multiply this frequency by a factor 0.5 or 2.0?

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_radiation_reaction.html b/advanced_radiation_reaction.html new file mode 100644 index 0000000..ec36fae --- /dev/null +++ b/advanced_radiation_reaction.html @@ -0,0 +1,851 @@ + + + + + + + Synchrotron-like radiation reaction — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Synchrotron-like radiation reactionΒΆ

+

The goal of this tutorial is to present how to use the radiative and QED processes in +Smilei. +The following points will be addressed:

+
    +
  • How to prepare input files for these physical modules

  • +
  • How to setup radiation reaction models

  • +
  • How to use Smilei diagnostics

  • +
  • How to read and understand generated outputs

  • +
+

The radiation reaction module implemented in Smilei is described +in this page. +It models the radiation emitted by accelerated charges and their subsequent +loss of energy, which is also known as Inverse Compton Scattering.

+
+
+

Physical configurationΒΆ

+

A multi-GeV electron beam is made to collide with a counter-propagating plane wave. +This configuration is one of the most efficient to trigger radiative and QED effects. +It maximizes the value of the quantum parameter for a given electron energy and a given +field strength.

+

The simulation is 2D Cartesian with a box size of \(30 \lambda \times 4 \lambda\) +where \(\lambda\) is the laser wavelength. The laser is injected from the left side +of the simulation domain while the electron beam is initialized at the extreme right.

+

In this initial configuration, the laser has a wavelength of \(\lambda = 1\ \mu \mathrm{m}\), +an amplitude of \(10^{22}\ \mathrm{W/cm}^2\) (\(a_0 \simeq 100\)) and is linearly polarized +in the \(y\) direction. The temporal profile is Gaussian (order 4). +The full width at half maximum (FWHM) is of 10 laser periods (approximately 33 fs).

+

The electron beam has an initial energy of 1 GeV and propagates to the left. +The beam density \(n_b = 10^{-5} n_c\), and contains 32 macro-particles per cell +for a total of 12480 macro-particles. To save computational time, the +electron beam is frozen until the laser is fully injected in the box. They collide at +middle of the domain.

+
+
+
+

Content of the tutorialΒΆ

+

Download AdvancedTutorial1.tar.gz and extract it with the command tar -xvf. +It contains 2 directories:

+
    +
  1. Execution which contains the input file tst2d_electron_laser_collision.py

  2. +
  3. Analysis where you will find Python scripts for the analysis and visualization of the simulation outputs. +Each script has been designed to focus on a specific quantity:

    +
      +
    • show_energy_balance.py: electron kinetic energy and the radiated energy vs. time.

    • +
    • show_2d_density.py: map of the electron density.

    • +
    • show_2d_average_energy.py: map of the electron average energy.

    • +
    • show_2d_average_chi.py: map of the electron local quantum parameter.

    • +
    • show_2d_fields.py: maps of the electric field \(E_y\) and the magnetic field \(B_z\).

    • +
    • animate_2d_average_chi.py: map of the electron local quantum parameter vs. time.

    • +
    • compare_energy_balance_Landau_Lifshitz.py

    • +
    • compare_energy_balance_radiation_models.py

    • +
    • compare_2d_density_radiation_models.py

    • +
    • compare_2d_average_energy_radiation_models.py

    • +
    • compare_2d_average_chi_radiation_models.py

    • +
    +
  4. +
+

All Python scripts use happi.

+
+
+
+

First simulation: the classical model of Landau-LifshitzΒΆ

+

Let us first use the continuous, classical model of Landau-Lifshitz. +This radiation-reaction model is valid in the classical regime when +the particle quantum parameter chi is below \(10^{-2}\). +The version implemented in Smilei is an approximation for high +gamma factors.

+
    +
  • Copy the directory input file into a new directory called Radiation_Landau_Lifshitz +in which we will work:

    +
    cp -r Execution Radiation_Landau_Lifshitz
    +
    +
    +
  • +
  • Go into this directory and open the input file.

  • +
+

We will now setup the radiation reaction parameters.

+
    +
  • Go to the block called RadiationReaction. This block is commented. +Uncomment this block with the parameter called minimum_chi_continuous only:

    +
    RadiationReaction(
    +     minimum_chi_continuous = 1e-3
    +#     minimum_chi_discontinuous = 1e-2,
    +#     table_path = "<path to some tables>"
    +)
    +
    +
    +

    This block is used to setup the general parameters. Only minimum_chi_continuous +is useful for the moment. This parameter corresponds to the minimal value of the +quantum parameter at which the radiation reaction process is applied. +Below this value, the particle does not undergo radiation loss. +To specify this parameter is not compulsory since it is defined by default at 1e-3.

    +
  • +
  • Now go to the block of the first species called electron. +Only this species will be present in the simulation for the moment.

  • +
  • Uncomment the parameter radiation_model. +This parameter corresponds to the radiation model you want to use. +By default, this parameter is set to None meaning no radiation loss. +To use the Landau-Lifshitz radiation model, use:

    +
    radiation_model = "Landau-Lifshitz"
    +
    +
    +

    The other commented parameters are not useful for the moment.

    +
  • +
  • You may now run the simulation. We recommend you to run it in parallel +with at least 4 cores. By default, 16 patches have been specified. If you want +to run this input file with more than 16 MPI tasks and OpenMP threads, +you have to increase the number of patches accordingly.

  • +
+

At the end of the run, you can see that several files have been generated including +the particle binning (ParticleBinning*.h5), the fields (Fields*.h5) and +the scalar (scalars.txt) diagnostics.

+
    +
  • We will use the python script show_energy_balance.py to plot the time evolution +of the particle normalized kinetic energy. Copy this file from the Analysis directory +to the current one:

    +
    cp ../Analysis/show_energy_balance.py .
    +
    +
    +
  • +
  • Open this file and take the time to read and understand it. +You can see that the script is decomposed into several sections. +The section Smilei general information will open and scan the result directory +thanks to S = happi.Open(path, verbose=False). +The results are read in the section Scalar diagnostics. +The command S.Scalar("Ukin_electron") enables to select a scalar quantity object +(for the electron kinetic energy here). We use the method get to get the raw data +contains in the scalar object. We then manually plot the data via Matplotlib. +This method is another approach of using the Smilei Python +library and differs from what you may have seen before.

  • +
  • Run the script using Python. For instance, in ipython:

    +
    %run show_energy_balance.py
    +
    +
    +

    Or you can also run it directly in your terminal by adding the interactive option:

    +
    python -i show_energy_balance.py
    +
    +
    +

    You obtain a plot of the time evolution of the electron normalized energy and +the radiated energy (purple). There are no positron or macro-photons here.

    +
  • +
  • What do you observe? You can see that during the laser interaction +(starting from \(t = 240 \omega_r^{-1}\)), the electron kinetic energy +is rapidly converted into radiations via the radiative model.

  • +
  • In order to estimate the maximal quantum parameter reached during the simulation. +you can use the python script Analysis/show_2d_average_chi.py. +Copy this script in the current working directory and run it with Python:

    +
    python -i show_2d_average_chi.py
    +
    +
    +

    You obtain a 2D colormap of the beam at timestep 5500 when the field is +almost maximum at the beam location. +The color corresponds to the local value of the quantum parameter. +The terminal gives the maximal value. +What do you think about this value regarding the model validity?

    +
  • +
  • You can change the timestep by specifing the number after show_2d_average_chi.py:

    +
    python -i show_2d_average_chi.py 6500
    +
    +
    +

    Particle binning diagnostics are output every 500 iterations. +By this way you can see when the beam starts to radiate while entering the laser field. +The maximal available iteration is 8000.

    +

    You can also generate an animation using the script animate_2d_average_chi.py:

    +
    python -i animate_2d_average_chi.py
    +
    +
    +
  • +
  • Similarly, use the Python script show_2d_density.py (located in Analysis) +to plot a 2D colormap of the electron density and show_2d_average_energy.py +to plot the 2D colormap of the local average kinetic energy. +Copy these scripts in the current working directory and use ipython to run them +as in the previous item. Change the timestep to see how these quantities evolve.

    +
    # For instance, to plot the density at timestep 6500
    +python -i show_2d_density.py
    +
    +
    +
  • +
+
+
+
+

Second simulation: the corrected Landau-Lifshitz modelΒΆ

+

We will now perform the same simulation with the corrected Landau-Lifshitz model. +This model includes a quantum correction that extends the domain of validity +to higher quantum parameters, around \(\chi \sim 10^{-1}\).

+
    +
  • copy the previous working directory Radiation_Landau_Lifshitz into a new directory +called Radiation_corrected_Landau_Lifshitz in which we will now work:

  • +
+
cp -r Radiation_Landau_Lifshitz Radiation_corrected_Landau_Lifshitz
+cd Radiation_corrected_Landau_Lifshitz
+
+
+
    +
  • Open the input file script tst2d_electron_laser_collision. +Go to the electron species block. +To use the corrected Landau-Lifshitz radiation model, simply use:

  • +
+
radiation_model = "corrected-Landau-Lifshitz"
+
+
+

This radiative model requires the same global setup as the Landau-Lifshitz one.

+
    +
  • You can run the simulation.

  • +
  • Compare the evolution of the energy balance to the Landau-Lifshitz model. +For this aim you can copy the script show_energy_balance.py in the current +working directory and run it using ipython:

    +
    %run show_energy_balance.py
    +
    +
    +

    Compare the generated plot with the one from the Landau-Lifshitz simulation.

    +
  • +
  • Optional exercice: using show_energy_balance.py, create you own python script +to plot on the same figure the time evolution of the energy balance for the +classical Landau-Lifshitz and the corrected Landau-Lifshitz model.

    +

    Solution: See the Python script Analysis/compare_energy_balance_Landau-Lifshitz.py.

    +_images/compare_energy_balance_Landau_Lifshitz.png +
  • +
  • Question: What do you observe? You can see that the energy drops less rapidly +with the corrected Landau-Lifshitz model. +This means that we are out of the validity scope of the classical Landau-Lifshitz +model with the current laser and electron parameters.

  • +
  • Optional exercice: as for the previous model, use the Python scripts to +plot 2D colormap of the density (show_2d_density.py), the normalized kinetic +energy (show_2d_average_energy.py) and the quantum parameter (show_2d_average_chi.py).

  • +
+
+
+
+

Third simulation: the stochastic model of Niel et al.ΒΆ

+

The model of Niel et al. is the first stochastic model available in Smilei. +It is an extension of the corrected Landau-Lifshitz model with +an additional stochastic operator derived from a Fokker-Planck approach.

+
    +
  • Copy the previous working directory Radiation_Landau_Lifshitz into a new directory +called Radiation_Niel in which we will now work:

    +
    cp -r Radiation_Landau_Lifshitz Radiation_Niel
    +cd Radiation_Niel
    +
    +
    +
  • +
  • Open the input file tst2d_electron_laser_collision.py and +go to the electron species block. Modify the radiation_model by

    +
    radiation_model = "Niel"
    +
    +
    +
  • +
+

External tables: some models such as Niel use complex mathematical functions to determine the production rate of +photons and energy. +These functions are tabulated because it would be too expensive to compute them on the fly for each macro-particles. +The Smilei code includes default tables. +It is nonetheless possible to use more accurate external tables. +This is the purpose of the parameter table_path in the block Radiation. +For more information about the tables, see https://smileipic.github.io/Smilei/Use/tables.html.

+
    +
  • You can run the simulation

    +

    By looking at the standart output (the log) that contains the simulation output, +you can check that the external tables have been well read.

    +
  • +
  • Use the script show_energy_balance.py to plot the evolution of the energy +balance for this simulation. Compare the results to the corrected Landau-Lifshitz model.

  • +
  • Optional exercice: as for the previous model, use the Python scripts to +plot 2D colormap of the density (show_2d_density.py), the normalized kinetic +energy (show_2d_average_energy.py) and the quantum parameter (show_2d_average_chi.py).

  • +
+
+
+
+

Fourth simulation: the Monte-Carlo modelΒΆ

+

The Monte-Carlo model is the second stochastic one of the list of implemented models. +You can have more information about the model and its implementation on the page +Synchrotron-like radiation reaction fn the Smilei website.

+
    +
  • copy the previous working directory Radiation_Niel into a new directory +called Radiation_Monte-Carlo in which we will now work:

    +
    cp -r Radiation_Niel Radiation_Monte_Carlo
    +cd Radiation_Monte_Carlo
    +
    +
    +
  • +
  • Open the input file tst2d_electron_laser_collision.py and +go to the electron species block. Modify the radiation_model by

    +
    radiation_model = "Monte-Carlo"
    +
    +
    +
  • +
  • Like the Niel radiation model, the Monte-Carlo algorithm uses tabulated values. +The same path needs to be specified in the block RadiationReaction. +In addition, set the parameter minimum_chi_discontinuous to 1e-2 +(uncomment the corresponding line). +The Monte-Carlo model is built to work with the continuous corrected +Landau-Lifshitz approach when the particle quantum parameter is too low. +This parameter corresponds to this threshold. +Above this value, a particle undergoes radiation reaction via the Monte-Carlo engine. +Below the continuous approach is used.

    +
    RadiationReaction(
    +     minimum_chi_continuous = 1e-3
    +     minimum_chi_discontinuous = 1e-3,
    +#    table_path = "<path_to_some_tables>
    +)
    +
    +
    +

    In fact, the default value of minimum_chi_discontinuous is 1e-2. +Therefore, it has to be specified only to change the default value. +The Monte-Carlo radiation reaction is now fully set.

    +
  • +
  • You can now run the simulation

  • +
  • Use the script show_energy_balance.py to plot the evolution of the energy +balance for this simulation.

  • +
  • Optional exercice: as for the previous model, use the Python scripts to +plot 2D colormap of the density (show_2d_density.py), the normalized kinetic +energy (show_2d_average_energy.py) and the quantum parameter (show_2d_average_chi.py).

  • +
+
+
+
+

Comparison of the radiation reaction modelsΒΆ

+
    +
  • Optional exercice: Using show_energy_balance.py, create you own python script +to plot on the same figure the time evolution of the energy balance +for the corrected Landau-Lifshitz, the Niel and the Monte-Carlo radiative models. +The solution is given in the next point.

  • +
  • Solution: The solution is the Python script +Analysis/compare_energy_balance_radiation_models.py. +Go to the directory Analysis to run it. +You should obtain the following figure:

    +_images/compare_energy_balance_radiation_models.png +
  • +
  • Optional exercice: Using the script show_2d_density.py, create a +new script to compare on the same figure the electron density of the corrected Landau-Lifshitz, +the Niel and the Monte-Carlo radiative simulation cases. +Observe the shape of the beam after the laser interaction in each case. +Do the same thing for the average local kinetic energy and the +average local quantum parameter using show_2d_kinetic_energy.py and show_2d_average_chi.py. +See the next point for the solution.

  • +
  • Solutions: Solutions are the Python script Analysis/compare_2d_density_radiation_models.py, +Analysis/compare_2d_kinetic_energy_radiation_models.py, +Analysis/compare_2d_average_chi_radiation_models.py. +Go to the directory Analysis to run the solutions. +The beam density at iteration 6500 at the end of the interaction should look +like the following figure:

    +_images/compare_density_radiative_models.png +

    With the script to compare the quantum parameter space-distribution, +you can also have the maximum value of the quantum parameter.

    +
  • +
  • Optional exercice: Activate the track particle option to follow trajectories +of some particles in the corrected Landau-Lifshitz, +the Niel and the Monte-Carlo simulation cases and run them again. +Create a python script to read and plot the particle trajectories. +Describe the difference due to the stochasticity.

  • +
  • Optional exercice: Play with the laser and electron beam parameters +(laser amplitude, duration, profile and electron energy) to see how +the different models behave. Use the previous scripts to compute the maximum +value of the quantum parameter in each case and see the electron beam properties after +the laser interaction.

  • +
+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_vtk.html b/advanced_vtk.html new file mode 100644 index 0000000..0b356f7 --- /dev/null +++ b/advanced_vtk.html @@ -0,0 +1,742 @@ + + + + + + + Export to VTK and 3D visualization — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Export to VTK and 3D visualizationΒΆ

+

The goal of this tutorial is to learn how to export some diagnostics to the +VTK format and how to visualize them in 3D. +Two simulations will be run, one in "3Dcartesian" geometry and the other in "AMcylindrical" geometry. +In this tutorial we will use the open-source +application Paraview to open the VTK files and 3D +visualization, although this is not the only possible choice.

+

This tutorial is meant as a +first introduction to the 3D visualization of Smilei results. +For the sake of clarity, only a few available representation options +will be explored, with no pretense of completeness in the field of +3D visualization or in the use of Paraview or similar software.

+

In particular this tutorial will explain how to

+
+
    +
  • export Fields results to VTK

  • +
  • export the macro-particles’ coordinates in the TrackParticles results to VTK

  • +
  • visualize a Volume Rendering of Fields with Paraview

  • +
  • visualize the tracked macro-particles as points with Paraview

  • +
  • perform the same operations for a simulation in "AMcylindrical" geometry.

  • +
+
+

The simulations used for this tutorial is relatively heavy so make sure to submit +the job on 40 cores at least to run in a few minutes. This tutorial +needs an installation of the vtk Python library to export the data +with happi. The export in 3D of data obtained in "AMcylindrical" geometry +also requires the installation of the scipy Python library.

+

Disclaimer This tutorial is not physically relevant. Proper simulations of this +kind must be done with better resolution in all directions, just to start. +This would give more accurate results, but it would make the simulations +even more demanding.

+

Warning To avoid wasting computing resources it is highly recommended to start +small when learning how to visualize results in 3D. Apart from the simulation +generating the physically accurate data, the export and visualization of large amounts of +data requires resources and computing time. For these reasons, if you are learning +how to visualize VTK files we recommend to start with relatively small benchmarks +like the ones in this tutorial in order to learn the export/visualization tricks +and to familiarize with the data you may need for your future cases of interest. +Afterwards, you can improve the quality of your simulation results with better +resolution, more macro-particles, more frequent output, etc. and apply the same +export and visualization techniques you will have learned in the process.

+

Warning for non-experts 3D visualizations can be good-looking and often artistic, they +help giving a qualitative picture of what is happening in your simulation, but +they are not recommended to draw accurate scientific conclusions. +Indeed, 3D pictures/animations often have too many details and graphical artifacts +coming from the rendering of 3D objects, so it’s always essential to quantitatively +study your phenomena of interest with 1D and 2D plot to reduce at minimum the +unnecessary or misleading information.

+
+
+

Physical configuration for the case in β€œ3Dcartesian” geometryΒΆ

+

A Laguerre-Gauss laser pulse enters the window, where test electrons are present. +The laser pushes the electrons out of its propagation axis through ponderomotive force.

+
+
+
+

Run your simulationΒΆ

+

Download the input namelist export_VTK_namelist.py and open +it with your favorite editor. Take some time to study it carefully. +This namelist allows to select between the geometries "3Dcartesian" and "AMcylindrical", +each corresponding to a similar case, through the variable geometry at the start of the namelist. +For the moment we will use geometry="3Dcartesian" for our first case.

+

Note how we define a Laser profile corresponding to a Laguerre-Gauss mode +with azimuthal number \(m=1\). +This mode has an intensity profile that looks like a corkscrew in 3D.

+

After the definition of the Laser, a small block of electrons is defined, +with few test macro-particles to make the simulation and the postprocessing +quicker. Since these electrons are test macro-particles, they will not +influence the laser propagation, but they will be moved by its electromagnetic +field.

+

Run the simulation and study the propagation of the laser intensity:

+
import happi; S=happi.Open()
+S.Probe.Probe1("Ex**2+Ey**2+Ez**2").slide(figure=1)
+
+
+

It would be difficult to visualize the corkscrew shape in 2D, even if we had +plotted only one component of the electric field.

+

To visualize the trajectories of the electrons, we can use:

+
species_name="electron"
+chunk_size  = 600000
+track       = S.TrackParticles(species = species_name, chunksize=chunk_size,axes = ["x","y"])
+track.slide(figure=2)
+
+
+

In this plot too it is difficult to see how the particles are moving in 3D.

+

It seems one of the occasions where 3D visualization gives a better qualitative +picture.

+

Warning To visualize the macro-particles, a TrackParticle diagnostic is +defined in the namelist. No filter is used, since the number of tracked +macro-particles is not enormous. In a more realistic case you should select +only a subset of the particles to make the visualization understandable and to +keep the cost of simulation/export/visualization operations manageable.

+
+
+
+

Export the results in VTK formatΒΆ

+

To start, we can select the fields we want to visualize and export them to VTK. +In this case, we can export the laser intensity:

+
E2 = S.Field.Field0("Ex**2+Ey**2+Ez**2")
+E2.toVTK()
+
+
+

If everything works smoothly, a folder called Field0_EzEyEx should be created +by happi after executing the toVTK() method. In general the folder name +will change with the selected field. +This folder contains the Fields exported to VTK format, for all the available +iterations.

+

Afterwards, for all the available iterations, the TrackParticles can be +exported, creating a folder TrackParticles_electron_xyzpxpypzId. Each +file within this folder contains the coordinates of the tracked macro-particles.

+

The export command will be:

+
track_part = S.TrackParticles(species ="electron",axes = ["x","y","z","px","py","pz","Id"])
+track_part.toVTK(rendering="cloud")
+
+
+

In the last commands we have selected the attributes to export with the +macro-particles, in this case coordinates, momentum components, Id. +Then, we have used rendering="cloud" to export a file for each iteration.

+

If we wanted to visualize only one or some iterations, we could have selected +them in the variable definition before using the toVTK() method.

+

In case you want to create a 3D animation of a new simulation (like the animation we +will create with this tutorial), before exporting a lot of data it is recommended +to export and visualize only the results from one or few iterations. +If everything you want to see is in place and clearly visible, +then you can export all the iterations necessary for an animation if +so desired. This will save a lot of time in case some diagnostic is missing +in your simulation or if the set-up is not correctly defined in the namelist.

+

Note In a simulation with moving window you can +also export a coordinate called moving_x, i.e. the x coordinate relative +to the moving window position.

+

Note Also other diagnostics, e.g. Probes, can be exported with toVTK() +See the +relevant documentation +for more details.

+

Warning This tutorial has a relatively small amount of data to export. +If you want to export the results from a larger simulation on a cluster with +multiple users, use a job to avoid saturating the shared resources +of the login nodes. You can also speed-up the export operation parallelizing it +with MPI.

+
+
+
+

Visualize the 3D dataΒΆ

+

Open Paraview. This can be done from your machine if you have the VTK data +stored there, or from a remote machine with remote desktop screen sharing, +or using Paraview in a server-client mode (in this case you will need the same +version of Paraview on both the client and server machines). For large amounts of +data it is recommendable to work in this server-client mode.

+

Warning from now on, the given instructions contain completely arbitrary +choices, e.g. the colors of representations. Feel free to make different choices +based on you personal tastes and what you want to highlight in your image/animation. +The figure at the end of the tutorial represents only the result of the +mentioned choices.

+

First, to highlight the laser and particles we can set the background color to +black. To change the background color, click on the icon with the painter’s brush +and color palette symbol and pick a background color.

+
+
+

Volume Rendering of FieldsΒΆ

+

Click on the folder icon in the top left part of the menu or in File->Open, +then find the folder Field0_EzEyEx in your system where the Field +diagnostic has been exported. Select the multiple iterations files, they should +be grouped with the name Field0_EzEyEx_..pvti. In the middle left part of +the screen, click on Apply.

+

In the central part of one of the top menu bars +you should see the word Outline. Click on it and change the representation +mode to Volume to create a Volume Rendering. For the moment you will see nothing, +because the laser still has to enter the window. Click on the Play button +above to see the animation of the laser entering the window.

+

You can zoom into the scene scrolling with the mouse or rotate the view +by left-clicking and moving the cursor. Try to change the colormap with +the dedicated button (try e.g. a black, white, blue colormap). +Afterwards, click on the button Rescale to Custom Data Range, selecting +e.g. the interval 4-10 for the laser intensity. +This way the corkscrew shape should be visible.

+
+
+

Point-like representation of Macro-particlesΒΆ

+

Now let’s superpose the tracked macro-particles. As before, click on +File->Open, then search for the folder TrackParticles_electron_xyzpxpypzId +where the macro-particles coordinates have been exported. +Select all the iterations, grouped under the name +TrackParticles_electron_xyzpxpypzId_trajectory_..vtp. +As before, click on Apply.

+

Again, in the central part of one of the top menu bars +you should see the word Outline. Click on it and change the representation +mode to Point Gaussian. If you are visualizing one of the last iterations you +should already be able to see the point-like electrons. Now you can play with +the options of this representation in the bottom left part of the screen. +For example, you can color them with a Solid Color white (choice made for the +figure in this tutorial), or color them according to their longitudinal +momentum. Selecting the option Emissive (macro-particles emitting light) from +the Search bar, you should be able to create an image like this for the +last iteration:

+
+
_images/LaguerreGauss.png +
+

Now you can visualize the animation of the laser entering the window and +pushing away the electrons, start experimenting with the many options of the selected +representations, or with the colormaps and transfer functions.

+
+
+

Exporting data obtained in β€œAMcylindrical” geometryΒΆ

+

In this geometry a cylindrical (x,r) grid is used for the fields, as explained +its documentation. +The axis r=0 corresponds to the propagation axis of the laser pulse. +Furthermore, fields are defined through their cylindrical components, e.g. +El, Er, Et instead of the Ex, Ey, Ez in "3Dcylindrical". +Therefore, when using geometry="AMcylindrical" in the same input script +you have used for this tutorial, some changes are made, in particular field and +density profiles are defined on a (x,r) grid and the origins of the axes +(in the profiles and the Probes) are shifted according to the different definition +of their origins.

+

Change the geometry variable at the start of the namelist to have geometry="AMcylindrical" +and run the simulation. The physical set-up is almost identical to the one +simulated in "3Dcartesian" geometry, but for simplicity a Gaussian beam will +be used for the Laser instead of a Laguerre-Gauss beam.

+

The commands to export macro-particle data from TrackParticles, except for the +different axis origin, are identical to those used in the "3Dcartesian" case. +This because the macro-particles (exactly as Probes) in "AMcylindrical" +geometry are defined in the 3D space.

+

For the fields, you may in principle define 3D Probes in the namelist for the +Cartesian components of the fields and export them to VTK adapting the previous +commands, but we do not recommend this strategy. +This way, the code would have to sample the Probe data in 3D during the simulation, +creating a huge amount of data and slowing down your simulation, just to have +data for visualization.

+

Instead, we recommend to export to vtk the Fields data defined in cylindrical geometry +to the 3D cartesian space, though the argument build3d of the Fields available +only in cylindrical geometry. For its synthax, see the +Field documentation.

+

First, you need to specify an interval in the 3D cartesian space where you want +have your VTK data. This interval is defined through a list, one for each axis x, y, z. +Each list contains in order its lower and upper border and resolution in that direction. +In this case, we can for example extract the data from the physical space that was simulated, +so we can take the required values from the namelist. Afterwards, we export the Field +data proportional to the laser intensity using build3d:

+
build3d_interval = [[0,S.namelist.Lx,S.namelist.dx]]
+build3d_interval.append([-S.namelist.Ltrans,S.namelist.Ltrans,S.namelist.dtrans])
+build3d_interval.append([-S.namelist.Ltrans,S.namelist.Ltrans,S.namelist.dtrans]])
+E2 = S.Field.Field0("El**2+Er**2+Et**2",build3d = build3d_interval )
+
+
+

Note how we had to specify the cylindrical components of the fields. +You do not have to export all the physical space or to use the same resolution +specified in the namelist. For example, to reduce the amount of exported data +you may choose to subsample the physical space with a coarser cell length.

+

Action: Try to define a Laguerre-Gauss beam profile in "AMcylindrical" geometry +and simulate the same case you have simulated in "3Dcartesian" geometry. +You will need some trigonometry to decompose the field in azimuthal modes, as +described in the documentation.

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_wakefield.html b/advanced_wakefield.html new file mode 100644 index 0000000..73ba885 --- /dev/null +++ b/advanced_wakefield.html @@ -0,0 +1,555 @@ + + + + + + + 2D laser wakefield acceleration — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

2D laser wakefield accelerationΒΆ

+

The goal of this tutorial is to give an introduction to Laser Wakefield acceleration simulation with Smilei. +The following features will be addressed:

+
    +
  • The moving window in order to follow the laser propagation.

  • +
  • Variations on Silver-Muller transverse boundary conditions.

  • +
  • Particle Binning diagnostic.

  • +
  • Dynamic load balancing.

  • +
+

The simulation used for this tutorial is relatively heavy so make sure to submit the job on 160 cores at least.

+

Disclaimer: This tutorial is done in 2D which is not physically relevant. Proper simulation of this kind must be done in 3D +or in cylindrical geometry with azimuthal mode decomposition (see the related tutorial). +Even in 2D, this case is a bit heavy with respect to the other tutorial and can not be run on a laptop. +We suggest using around a hundred cores to run this tutorial in a reasonable time.

+
+
+

Physical configurationΒΆ

+

An ultra high intensity laser enters an under dense plasma. +It propagates in the plasma and creates a non linear plasma wave in its wake. +Electrons from the plasma are eventually trapped in this wave and accelerated to high energies.

+
+
+

Step by step tutorialΒΆ

+

Download this input file and open it with your favorite editor. +Keep open a page with the documentation for the namelist to follow the tutorial’s steps.

+

1. Transverse reflections

+

Absorbing Silver-Muller boundary conditions are chosen for all faces. +By default, the optimal absorption angle is set to be normal to all faces. +In other words, the laser will be optimally absorbed on the +X face.

+

The box is initially empty of plasma.

+

To visualize e.g. the density -Rho and the laser Ey, try:

+
import happi; S=happi.Open()
+S.Probe.Probe1("-Rho").slide()
+S.Probe.Probe1("Ey").slide(figure=2)
+
+
+

Action: Try to run the simulation and observe laser absorption on the Ymin and Ymax faces with the Probe diagnostic. Notice that a fraction of the laser +is reflected back into the simulation domain. This is a numerical artefact induced by non perfect absorbing boundary conditions.

+

Hint: In order to see more details, you can manually setup the color scale extrema in happi by using the vmin and vmax optional arguments.

+

2. Optimize absorbing boundary conditions

+

In order to reduce these reflexions, one can tune the Silver-Muller boundary conditions.

+

Action: Change the Silver-Muller absorption angle in order to smoothly handle the laser at the transverse boundary. +Refers to the documentation in order to fix a proper absorbing vector.

+

Hint: The absorbing vector \(k_{abs}\) must be as much aligned as possible with the wave vector of the pulse you need to absorb but +it must keep a non zero normal component.

+

3. Moving Window

+

Now that the laser propagates without interfering with the simulation too much, we are interested in looking at the laser propagation over several box lengths. +Notice the MovingWindow block in the documentation for the namelist. +This allows the simulation domain to constantly shifts toward the x direction in order to follow the laser propagation.

+

Action: Give a proper velocity and start time to the moving window in order to follow the laser pulse and observe it enter the plasma. +Remember that the window speed is normalized by c as usual. +Increase the number of iterations from 3000 to 38000. +This is a rather long simulation so make sure to use at least 160 cores.

+

Hint: Remember that a variable can be given as a function of variables from other blocks. For instance, the grid length along x can be called as +Main.grid_length[0].

+

4. Particle binning

+

Some electrons have been trapped and accelerated in the wakefield of the laser. +We can use the ParticleBinning diagnostic in order to visualize them in phase space:

+
S.ParticleBinning(0).slide()
+
+
+

Action: Visualize the particle binning diagnostic and evaluate the accelerated beam energy.

+

Hint: In order to see more details, also here you can manually setup the color scale extrema in happi by using the vmin and vmax optional arguments.

+

Hint: Check the documentation in order to know the default normalization for energy.

+

5. Performances diagnostic

+

Do you feel like the load is correctly balanced? Check it via the Performance diagnostic!

+

Action: Use the Performance diagnostic to observe load imbalance.

+

Hint: Pick a specific quantity like β€œtimer_particles” in order to highlight the imbalance. The timer_total quantity is not relevant since it adds up all imbalances which compensate each other.

+

6. Optimize simulation

+

Action: Use the dynamic load balancing to improve the code performances, using the LoadBalancing block described in the namelist documentation. +Make sure to run this new simulation in a different directory in order to compare your performance diagnostics. Check that imbalance is reduced.

+

Hint: Does the gain in performance compensate the cost of the dynamic load balancing ? If not, you probably set a too frequent load balance. +Comments: In that case load imbalance mostly builds up only at the end of the simulation. This is why performance gain is not spectacular.

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_wakefield_AMcylindrical.html b/advanced_wakefield_AMcylindrical.html new file mode 100644 index 0000000..18dc996 --- /dev/null +++ b/advanced_wakefield_AMcylindrical.html @@ -0,0 +1,794 @@ + + + + + + + Azimuthal-mode-decomposition cylindrical geometry — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Azimuthal-mode-decomposition cylindrical geometryΒΆ

+

The goal of this tutorial is to give an introduction to the use of the cylindrical geometry +with azimuthal Fourier decomposition in Smilei. +The chosen physical configuration is a case of laser wakefield acceleration. +This set-up will allow us to address advanced features that are available +also in other geometries. +The following topics will be addressed:

+
    +
  • Understand the concept of azimuthal mode decomposition

  • +
  • Set up a simulation in this geometry

  • +
  • Automatic conversion of the output to SI units (pint Python module required)

  • +
  • The analysis of the grid fields in AM cylindrical geometry

  • +
  • Observation of the effect of Perfectly Matched Layers (feature available also in other geometries)

  • +
  • Reduce the effects of the Numerical Cherenkov Radiation (with features available also in other geometries).

  • +
+

With 8 MPI processes and 10 OpenMP threads per MPI process, the simulation should need a few minutes.

+
+
+

Physical configurationΒΆ

+

An high intensity laser pulse, linearly polarized in the y direction, enters an under dense plasma. +It propagates in the plasma in the positive x direction and creates a non linear plasma wave in its wake. +The plasma density has a sharp density transition at its start, which triggers +the injection of an electron beam in the plasma wave. The plasma wave longitudinal +electric fields accelerate the electron beam.

+

The moving window in the namelist has been set to contain the laser and the first wake period in the simulation window.

+
+

Note

+

The simulation in this tutorial uses a few macro-particles per cell and a coarse mesh too keep the +computational time reasonable. Physically relevant simulations of the considered phenomena would +require more macro-particles and a finer mesh. Apart from the numerical artefacts whose +mitigation will be addressed in this tutorial, the noise in the grid quantities will be caused +also by the small number of macro-particles.

+
+
+
+
+

A subtlety: why ions are not present?ΒΆ

+

Maxwell’s equations and the continuity equation \(\nabla\cdot\mathbf{J}=-\partial_t\rho\) +(which is true also for the single species) imply that \(\nabla\cdot\mathbf{E}-\rho\) remains +constant throughout the simulation +(see this). +This can be written \(\nabla\cdot\mathbf{E}-\rho_e-\rho_i=\nabla\cdot\mathbf{E_0}-\rho_{e0}-\rho_{i0}\). +If we consider ions immobile, then this becomes \(\nabla\cdot\mathbf{E}-\rho_e=\nabla\cdot\mathbf{E_0}-\rho_{e0}\), +because the ion continuity equation implies that if \(\mathbf{J}_{i}=0\) then \(\rho_i=\rho_{i0}\). +Note that ions do not appear anymore so that they can be discarded from the simulation. +Assuming also \(\rho_{e0}+\rho_{i0}=0\) and the initial field \(\mathbf{E_0}\) being divergence free, +we have \(\nabla\cdot\mathbf{E}=\rho_e+\rho_{i0}\) at all times. +The system will evolve as if there were ions, without having a real ion Species. +This is a good approximation in our case: plasma oscillations driven by a short +laser pulse with the intensity used in this tutorial +do not substantially move the ions. Indeed, the ion mass is at least 2000 times +greater than the mass of an electron, so the characteristic timescales of the +ion motion are much greater than those of the electron motion. Discarding ions +represents an important gain of computational time. +If we were interested in phenomena like ionization or ion motion, +we would have needed to explicitly define an ion Species.

+
+
+
+

Azimuthal-mode-decompositionΒΆ

+

In some physical situations like the one of this tutorial, the phenomena of interest have a cylindrical geometry or are very near to be cylindrically symmetric.

+

The electromagnetic fields can then be decomposed in Fourier azimuthal modes (where the azimuthal angle is defined with respect to the propagation axis of the laser). +Each mode is defined on a 2D grid, where the two dimensions are the longitudinal and radial ones.

+

In this case, Maxwell’s Equations can evolve independently the 2D azimuthal modes, and to save time we can retain only a certain number of azimuthal modes, +without losing the relevant physics. In the case simulated in this tutorial, using only two azimuthal modes allows to catch the relevant physics. +The particles, on the other hand, move in the 3D space, pushed by the 3D Cartesian fields reconstructed from the electromagnetic azimuthal modes. +With this powerful technique, 3D features can be simulated at the cost of approximately N 2D simulations, where N is the number of modes we keep in the simulation.

+

More details on the Azimuthal modes decomposition can be found here.

+
+
+

Simulation setupΒΆ

+

An input file to simulate laser wake excitation in this geometry will be very similar to a namelist in 2D geometry, with some important differences. +Check them in the input file:

+
    +
  • The selected geometry is AMcylindrical

  • +
  • The grid resolution is given by a longitudinal and radial resolution, since the azimuthal modes are defined on a 2D grid

  • +
  • The number of azimuthal modes simulated is set in number_of_AM. In this case only two of them are necessary to reproduce the relevant physics phenomena

  • +
  • The laser can be defined through the LaserGaussianAM block

  • +
  • When you define a plasma density profile, it will be defined with two coordinates (x,r)

  • +
  • Still in the plasma density profile definition, remember that r=0 corresponds to the lower boundary of the grid, i.e. the laser propagation axis

  • +
  • The Probes origin and corners are defined with three coordinates, since they will interpolate the fields in the 3D space as if they were macro-particles in a 3D simulation.

  • +
+
+
+
+

Conversion to SI unitsΒΆ

+

We have specified the reference_angular_frequency_SI in the Main block +of our input namelist. Therefore, if you have built happi with the pint Python module, +you should be able to automatically convert the normalized units of the outputs +towards SI units, as will be shown in the commands of this tutorial.

+

To do this, while opening the diagnostic you will specify the units in your plot, +e.g. units = ["um","GV/m"]. If happi was not built with the pint module +or if you want to see the results in normalized units, just omit these units +and remember to adjust the vmin and vmax of your plot commands.

+
+
+
+

Step by step tutorialΒΆ

+

Download this input file , open it with your favorite editor and run the simulation. +Then, open the results:

+
import happi
+S = happi.Open("/example/path/to/the/simulation")
+
+
+

1. Field diagnostic

+

Now let’s have a look at the grid fields, for example the electron density:

+
S.Field.Field0("-Rho",theta = 0.,units=["um","pC/cm^3"]).plot(figure=1, vmin = 0., vmax=1.5e12)
+
+
+

In the previous command we have specified a certain angle theta = 0 (i.e. the demi-plane including the positive y coordinates). +With the Field diagnostic, you can virtually specify any angle theta. +See the reference frame here for the definition of this angle.

+

At the cost of approximately N 2D simulations (N is the number of azimuthal modes, two in this case), you can obtain the fields in all the 3D space, like in a 3D simulation. +Note that in the Field diagnostic you will see only half of the plane, as the Field diagnostics shows the fields on the grid, defined on a half-plane in this geometry.

+

By default, the last command we used will plot the last timestep available. You can also slide along the available timesteps:

+
S.Field.Field0("-Rho",theta = 0.,units=["um","pC/cm^3"]).slide(figure=1, vmin = 0., vmax=1.5e12)
+
+
+

In the last command no azimuthal mode was specified. By default, if no mode is specified the reconstruction with all the modes is performed.

+

To plot a specific mode (in this case the mode 0), you can use:

+
S.Field.Field0("-Rho",theta = 0.,units=["um","pC/cm^3"],modes=0).plot(figure=1, vmin = 0., vmax=3e12)
+
+
+

The main azimuthal mode of the plasma wave in the wake of the laser is the mode 0. The mode 0 has a complete cylindrical symmetry.

+

The azimuthal mode of the laser is the mode 1. +To see the transverse field of the laser, we can plot the mode 1 of +the transverse electric field (i.e. Er):

+
S.Field.Field0("Er",theta=0.,modes=1,units=["um","TV/m"]).plot(figure=2,vmin=-20,vmax=20,cmap="seismic")
+
+
+

On theta=0 it will correspond Ey with our choice of laser polarization.

+

You can plot the reconstruction of the whole longitudinal electric +field (laser and wake fields, modes 1 and 0 respectively) through:

+
S.Field.Field0("El",theta=0.,units=["um","GV/m"]).plot(figure=2,vmin=-500,vmax=500,cmap="seismic")
+
+
+

You can also follow the evolution of any grid quantity (for example here the electron density) through the command animate():

+
S.Field.Field0("-Rho",theta = 0.,units=["um","pC/cm^3"],modes=0).slide(figure=1, vmin = 0., vmax=3e12)
+
+
+

2. Probe 1D

+

A quantity of interest e.g. for plasma acceleration is the longitudinal electric field on the laser propagation axis. +For this purpose, we have defined the first Probe in the namelist. +Check its origin and corners to understand where they are defined. +To be more precise, we have defined it parallel to the axis, but at a small distance from it. +You can try to define another 1D Probe at the end of the namelist, but you will see that the fields there are very noisy.

+

The Probes interpolate the cartesian components of the fields from the grid, not the cylindrical ones. +Thus, to follow the evolution of the longitudinal electric field you can use:

+
S.Probe.Probe0("Ex",units=["um","GV/m"]).slide(figure=2)
+
+
+

Note that we haven’t specified the mode. The Probes reconstruct the fields including all the modes.

+

3. Probe 2D

+

In the namelist, a 2D Probe is defined on the plane parallel to the polarization direction of the laser. +For how we have defined it, you won’t see only half plane as in the Field diagnostic, but both the negative and positive y points.

+

Let’s have a look at the evolution of the plasma density:

+
S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=1, vmin = 0., vmax=3e12)
+
+
+

To see the evolution of the longitudinal electric field and the electric field in the y direction, you can use:

+
S.Probe.Probe1("Ex",units=["um","GV/m"]).slide(figure=2,vmin=-500,vmax=500,cmap="seismic")
+S.Probe.Probe1("Ey",units=["um","TV/m"]).slide(figure=2,vmin=-1,vmax=1,cmap="seismic")
+
+
+

Note that the Fields contained the cylindrical components of the fields, but the Probes diagnostics +contain the Cartesian reconstruction of the fields, thus with Cartesian components.

+
+
+
+

Perfectly Matched LayersΒΆ

+

Imperfect boundary conditions may cause unphysical effects when the laser’s intense +electromagnetic fields arrive at the boundaries of the simulation window. +A larger box (transversally) could help fields decay near the boundaries. +However this can easily increase the simulation time beyond an acceptable level, +and only to avoid reflections, adding to the domain some physical regions where +no phenomenon of interest happens.

+

Therefore, to avoid this inefficient approach, this namelist uses improved +boundary conditions called Perfectly Matched Layers, +which add some cells to the simulation borders filled with a fictious medium +where the fields are damped and not reflected back inside the physical simulation window. +Note that these additional cells are not visible to the user.

+

The Perfectly Matched Layers are activated in the Main block through:

+
EM_boundary_conditions = [
+    ["PML","PML"],
+    ["PML","PML"],
+],
+
+number_of_pml_cells = [[20,20],[20,20]],
+
+
+

Action: How do the results change if you decrease the number of PML cells +from 20 to 5? Are the fields more or less noisy? You may need to saturate the +colormap to see differences. +Check the field with:

+
S.Probe.Probe1("Ey",units=["um","TV/m"]).slide(figure=2,vmin=-1,vmax=1,cmap="seismic")
+
+
+

We recommend to launch this simulation in a different directory to be able to +compare the two simulations. You should find some differences especially at +the window borders.

+

Action: What happens if instead of the "PML" boundary conditions you use +the more classic following conditions?:

+
EM_boundary_conditions  =  [["silver-muller","silver-muller"],["buneman","buneman"],]
+
+
+

We recommend to launch this simulation in a different directory to be able to +compare the two simulations. As in the previous exercise, check the fields at the border. +Small differences given by the presence (or not) of reflections at the borders +can have visible effects on the accelerated electron beam dynamics. +For example, check the shape of the electron beam by visualizing the electron +density:

+
S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=1, vmin = 0., vmax=3e12)
+
+
+

How large should the simulation window be to avoid reflections without a Perfectly +Matched Layers? How much does the simulation time change with a larger window without +Perfectly Matched Layers?

+
+
+
+

Coping with the Numerical Cherenkov RadiationΒΆ

+

The finite difference solver used in the simulation (maxwell_solver="Yee" +is used by default) introduces a numerical dispersion in the wave propagation. +For example, the laser and plasma fields propagating in the x direction as in +the simulation of this tutorial are slowed down and this effect is stronger when +the timestep is set increasingly smaller compared to the cell length along x. +To reduce the dispersion ideally the normalized timestep should be as near as +possible to the normalized cell length along x.

+

The interaction of relativistic macro-particles with these numerically slowed waves +generates a purely numerical artifact called Numerical Cherenkov Radiation, which +manifests as a high frequency electromagnetic fields around relativistic macro-particles +as (e.g. in accelerated electron beam in laser wakefield acceleration). These spurious +fields have visible effects on the simulated dynamics of the accelerated beams +and can easily propagate in the simulation window. Therefore, in order to have +more physically relevant results, some technique must be used to cope with this effect. +Unfortunately there is no universal solution that can remove the effects of the Numerical +Cherenkov Radiation in all physical set-ups that can be simulated and without +considerably increasing the simulation time, thus the user +must find the technique that yields the desired accuracy-performance compromise +depending on their case of interest.

+

In this tutorial we will test the use of a low-pass filter on the currents and +a force interpolation technique that can reduce the effects of the Numerical Cherenkov +Radiation on the macro-particles.

+

One of the simplest techniques to reduce the Numerical Cherenkov Radiation is to +filter the currents with a binomial filter. +Try to launch a new simulation using the same namelist, but decommenting the block:

+
CurrentFilter(
+   model  = "binomial",
+   passes = [2],
+)
+
+
+

Action: compare the results of the two simulations, with an without filter. +For example, you can use the Probes to check a combination of Probes proportional +to the force acting on the macro-particles in the y direction:

+
S.Probe.Probe1("Ey-c*Bz").slide(vmin=-0.02,vmax=0.02,cmap="seismic")
+
+
+

Without the filter, you will see the high frequency oscillations of the numerical +Cherenkov Radiation, that have a visible effect also on the shape of the +accelerated electron beam inside the plasma waves. You can check this with:

+
.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=1, vmin = 0., vmax=3e12)
+
+
+

The electron beam simulated with the filter should be transversely smaller. +This happens because the filter reduces the growth of the spurious radiation, +whose effects include the heating the electron beams. +Using a low pass filter is not an ideal solution, since it can damp high frequencies +that are physical and adds time dedicated to communications, especially when +the number of filter passes is increased to further reduce the numerical artifact.

+

A second solution, that we recommend, is the use of a force interpolation technique +called B-TIS3 described in +P.-L. Bourgeois and X. Davoine, Journal of Plasma Physics 89 (2023), +that does not remove the Numerical Cherenkov Radiation, but considerably reduces +its effects on the macro-particles, with minimal increase of the simulation time.

+

Action: Run a new simulation (without filter), changing the variable use_BTIS3_interpolation +before the Main block to True. Note how this changes the pusher +and adds some fields to the Probes in the namelist. +Activating the B-TIS3 interpolates the magnetic fields +in a way that is more physically accurate for fields moving close to the speed +of light in the positive x direction, and when the normalized timestep is close +to the normalized cell size along x (which is typical of laser wakefield simulations). +Check how the electron beam shape changes as you have done before with the filter +and then check this combination of Probes:

+
S.Probe.Probe1("Ey-c*Bz",units=["um","GV/m"]).slide(figure=2,vmin=-200,vmax=200,cmap="seismic")
+
+
+

The differences are small compared to the simulation with B-TIS3 and you will +still see the Numerical Cherenkov Radiation in the grid. However, in this simulations +the macro-particles are not pushed on the y direction with these fields, +but by a combination of fields that uses the B-TIS3 fields when necessary. +The force along y acting on the macro-particles in this case is proportional to:

+
S.Probe.Probe1("Ey-c*Bz",units=["um","GV/m"]).slide(figure=3,vmin=-200,vmax=200,cmap="seismic")
+
+
+

Here you should see visible differences, especially near the electron beam.

+

Action: After you will have learned how to analyse the TrackParticles +diagnostic in the next tutorials, compare the final electron beam +parameters with and without the techniques that we have explored to reduce +the effects of the Numerical Cherenkov Radiation.

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_wakefield_electron_beam.html b/advanced_wakefield_electron_beam.html new file mode 100644 index 0000000..4ab73fe --- /dev/null +++ b/advanced_wakefield_electron_beam.html @@ -0,0 +1,807 @@ + + + + + + + Field initialization for a relativistic electron bunch — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Field initialization for a relativistic electron bunchΒΆ

+

The goal of this tutorial is to give an introduction to the use of the the +relativistic-species field initialization with Smilei.

+

With 8 MPI processes and 5 OpenMP threads the simulation of this tutorial should take a few minutes +(remember to set the number of OpenMP threads as explained in Setup). +The relativistic Poisson solver is parallelized through MPI but not with OpenMP, +sometimes for larger simulations a larger number of MPI processes is necessary +to reduce the time spent in field initialization.

+

The following features will be addressed:

+
    +
  • Automatic conversion of the output to SI units (pint Python module required)

  • +
  • Initialization of a Species through a numpy array

  • +
  • Initialization of the electromagnetic field with relativistic species

  • +
  • Observation of the plasma wakefield driven by a relativistic electron bunch

  • +
  • Analysis of the bunch evolution with the DiagParticleBinning diagnostic

  • +
  • Analysis of the bunch evolution with the TrackParticles diagnostic

  • +
  • Observation of the effect of Perfectly Matched Layers

  • +
+
+
+

Physical configurationΒΆ

+

A relativistic electron bunch enters a plasma in a AMcylindrical geometry. It propagates in +the plasma and creates a non linear plasma wave in its wake.

+
+

Note

+

This tutorial is done in AMcylindrical with one azimuthal mode, thus assuming perfect cylindrical geometry in the fields (see also the related tutorial).

+
+

Initializing our bunch through a plasma density and a Maxwell-JΓΌttner momentum distribution +would not allow us to set a certain emittance for the bunch +(this parameter is related to the transverse phase space distribution of the bunch particles). +Also, initializing a converging/diverging bunch or a particle distribution obtained from a beam +transport code would not be possible with this kind of initialization.

+

To manage these situations, an initialization of a Species with a numpy array is more suitable. +The Species called electron_bunch in our input file the input file advanced_beam_driven_wake.py +will receive two numpy arrays, array_position and array_momentum in the position_initialization and momentum_initialization +arguments.

+

Our bunch has npart particles, thus the shapes of these arrays will be (4,npart) +and (3,npart) respectively. The array_position contains the coordinates of our bunch particles. +Remember that the origin of the axes is set on the propagation axis in AMcylindrical geometry, +so the transverse coordinates may be positive or negative. Each of the first three rows represents the x, y, z +coordinates of the particles, while each column represents a particle. +The last row represents the weight given to each particle, related to the macro-particle charge. +Similarly, the array_momentum contains the particles momenta px, py, pz. +With this initialization the density profile of the Species will be computed from the position of the +particles, and not from a profile given in the Species block as in other tutorials.

+

In our case, we generate the particles and momenta distribution of the electron bunch +assuming a gaussian distribution in the momentum space, with custom average energy, emittance, rms sizes, etc. +The bunch is assumed as waist (i.e. not converging, nor diverging), but manipulating the numpy arrays of the +bunch particles it is easy to generate a more realistic electron bunch.

+

More details on the initialization through numpy arrays or from a file can be +found here.

+
+

Note

+

The simulation in this tutorial uses a few macro-particles per cell and a coarse mesh too keep the +computational time reasonable. Physically relevant simulations of the considered phenomena would +require more macro-particles and a finer mesh. Apart from the numerical artefacts whose +mitigation will be addressed in this tutorial, the noise in the grid quantities will be caused +also by the small number of macro-particles.

+
+
+
+
+

Preparing the case studyΒΆ

+

Download the input file advanced_beam_driven_wake.py and open it with your +favorite editor. Note how the physical quantities are defined. +First the physical constants for conversions and then used to convert the physical quantities +of interest, e.g. the bunch size, from SI units to normalized units.

+

The plasma electrons are initialized in a block Species named plasmaelectrons. +The electron bunch driving the plasma wave is initalized in +a block Species named electronbunch.

+

The flag relativistic_field_initialization = True in the electronbunch Species +means that its self-consistent electromagnetic fields will be computed at the time when +this Species starts to move, in this case at t=0 because time_frozen=0. +The procedure used in Smilei for this field initialization is detailed +here.

+

These electromagnetic fields will propagate with the bunch and push away the plasma electrons +(just like an intense laser pulse would do with its ponderomotive force) +triggering a plasma oscillation.

+
+

Note

+

You will see that the plasma does not fill all the simulation window. +This is because we want to include the electron bunch field in the window, but the plasma particles creating the plasma oscillations +are only those radially near to the electron beam. Plasma particles at greater radial distances would not contribute to the relevant physics, but they would +require additional computational time. Thus we can omit them to perform the simulation more quickly without losing relevant phenomena.

+
+
+

Note

+

The moving window in the namelist has been set to contain the electron bunch and the first wake period in the simulation window.

+
+
+
+
+

Conversion to SI unitsΒΆ

+

We have specified the reference_angular_frequency_SI in the Main block +of our input namelist. Therefore, if you have built happi with the pint Python module, +you should be able to automatically convert the normalized units of the outputs +towards SI units, as will be shown in the commands of this tutorial.

+

To do this, while opening the diagnostic you will specify the units in your plot, +e.g. units = ["um","GV/m"]. If happi was not built with the pint module +or if you want to see the results in normalized units, just omit these units +and remember to adjust the vmin and vmax of your plot commands.

+
+
+
+

Relativistic field initializationΒΆ

+

Run the simulation and open the results with happi:

+
import happi
+S = happi.Open("example/of/path/to/the/simulation")
+
+
+

To visualize the initial bunch density and transverse electric field on the xy plane, use:

+
S.Probe.Probe1("-Rho",timesteps=0.,units=["um","pC/cm^3"]).plot(figure=1,vmin=0)
+S.Probe.Probe1("Ey",timesteps=0.,units=["um","GV/m"]).plot(figure=2,cmap="seismic",vmin=-1.6,vmax=1.6)
+
+
+

Note that the bunch is initially in vacuum. If a Species is initialized inside the plasma, +activating the initialization of its field creates non-physical forces.

+

The bunch will move in the positive x (longitudinal) direction towards the plasma. +The field Ex is much lower than the transverse field Ey as for a relativistic moving charge. +The field Ey is the field that pushes the plasma electrons away from the bunch’s path and triggers the plasma oscillations +in the bunch wake.

+

Action: What happens to the fields if you increase the number of bunch particles npart? +Are the fields more or less noisy?

+
+

Note

+

You will see from the simulation log that the iterative relativistic Poisson solver +does not converge in this simulation with the chosen maximum number of iterations +(relativistic_poisson_max_iteration in the Main block). +However, the field obtained from this initialization will be accurate enough to +see a plasma wave driven by the electron beam’s field and learn from this tutorial. +A more accurate initialization would probably require more iterations, increasing +the initialization time. There is no value for relativistic_poisson_max_iteration +or for the acceptable error relativistic_poisson_max_error suited +for all physical problems. The user should find the values suited to their +case of interest through careful trial and error.

+
+
+
+
+

Nonlinear, beam-driven plasma oscillationsΒΆ

+

The plasma electrons pushed away from the bunch path will be attracted back to their original positions +by the immobile ions and start to oscillate.

+

Visualize the nonlinear plasma wave forming in the wake of the electron bunch:

+
S.Probe.Probe0("-Rho",units=["um","pC/cm^3"]).slide(figure=1)
+S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=2)
+
+
+

The evolution of the longitudinal electric field on axis, very important for acceleration of another particle bunch, +can be visualized through:

+
S.Probe.Probe0("Ex",units=["um","GV/m"]).slide(figure=4)
+S.Probe.Probe1("Ex",units=["um","GV/m"]).slide(figure=5,cmap="seismic",vmin=-2,vmax=2)
+
+
+

The wave form has a shape of a sawtooth wave, +since the set-up is in the so-called nonlinear regime.

+

Try to change the total bunch charge Q_bunch and rerun the simulation, for example multiplying it by a factor +0.05 (a linear regime), 0.75 (a weakly nonlinear regime). What happens to the Ex waveform?

+

Action: What happens to the fields if you increase the number of particles in the plasma? +Are the fields more or less noisy?

+
+
+
+

Particle Binning diagnosticΒΆ

+

Let’s study in detail the evolution of the electron bunch. +To start, the energy spectrum can be found using the first ParticleBinning diagnostic defined in the namelist:

+
S.ParticleBinning(0,units=["MeV","1/cm^3/MeV"]).slide()
+
+
+

Note how the bunch energy spread is increasing and the average energy is decreasing as it drives the plasma waves in its propagation.

+

The longitudinal phase space can be seen through the second ParticleBinning diagnostic of the namelist:

+
S.ParticleBinning(1,units=["um","MeV","1/cm^3/MeV"]).slide()
+
+
+

Note how the bunch tail is losing its energy. That zone of the bunch is where the decelerating electric field +is generated.

+

Action: Study the remaining ParticleBinning diagnostics, which contain the bunch distribution in transverse phase space +(y and z phase space planes respectively). Note how the transverse coordinates can be negative in cylindrical geometry.

+
+
+
+

Track Particles diagnosticΒΆ

+

Note how we had to specify the limits of the axes of our ParticleBinning diagnostics. +This can be a considerable constraint when these boundaries are not known. +Furthermore, if we wanted to compute more complex quantities derived from the +positions and momenta of the electron bunch, e.g. the energy spread of its longitudinal +slices, it would have not been easy to do with ParticleBinning diagnostics. +Finally, sometimes we want to export the final bunch distribution in the phase space, +i.e. the 3D positions and 3D momenta of all particles, e.g. to use them as input of +a beam dynamics code to design a magnetic transport line, so we would need the coordinates +of each macro-particle.

+

For these reasons, often in wakefield simulations it is preferrable to use the +TrackParticles diagnostic. This diagnostic allows to select a Species +and optionally a filter (e.g. macro-particles above a certain energy). The diagnostic +can give the id numbers, position, momentum and weight of the macro-particles of +that Species satisfying the filter.

+

Note Specifying a filter can be essential to avoid exporting exceedingly large amount of +data. For example, in a laser wakefield acceleration where the accelerated electron +beam comes from the plasma itself, not specifying a filter would export the +data of all the plasma species macro-particles. In this case, using a filter e.g. +select only the macro-particles above a certain energy, would likely export the +macro-particles of interest for typical laser wakefield acceleration studies.

+

In this simulation’s namelist, a TrackParticles block is specified +to export the data of all the electron bunch macro-particles. +The bunch does not have many macro-particles, so we don’t need to specify a filter.

+

You can extract the TrackParticles data of a given timestep with:

+
# Read the DiagTrackParticles data
+import numpy as np
+chunk_size   = 60000
+species_name = "electronbunch"
+timestep     = 0.
+track = S.TrackParticles(species = species_name, chunksize=chunk_size, sort=False)
+for particle_chunk in track.iterParticles(timestep, chunksize=chunk_size):
+
+
+  # positions
+  x            = particle_chunk["x"]
+  y            = particle_chunk["y"]
+  z            = particle_chunk["z"]
+
+  # momenta
+  px           = particle_chunk["px"]
+  py           = particle_chunk["py"]
+  pz           = particle_chunk["pz"]
+  p            = np.sqrt((px**2+py**2+pz**2))
+
+  # weights, proportional to che macro-particle charge
+  w            = particle_chunk["w"]
+
+  # energy
+  E            = np.sqrt((1.+p**2))
+
+  Nparticles   = np.size(w)
+  print(" ")
+  print("Read "+str(Nparticles)+" macro-particles from the file")
+
+
+

This way, you will have some numpy arrays, with the coordinates, momenta etc of all +the electron bunch macro-particles at the timestep timestep, in normalized units. +In this case we exported the first timestep. You can find a list of the available +timesteps with:

+
timesteps = track.getAvailableTimesteps()
+
+
+

Each array has a size equal to the number of macro-particles. +The argument chunksize denotes the maximum number macro-particles per chunk +you are reading. Extracting data in chunks avoids reading all the macro-particles at once, +which can be useful with large amounts of data. In this case we just need to read one chunk.

+

Using these numpy arrays, you can easily compute derived quantities, e.g. +you can obtain the electron bunch charge by summing the weights of all the +macro-particles (which can in principle vary between macro-particles) and using +the appropriate conversion factor:

+
import scipy.constants
+total_weight = w.sum()
+weight_to_pC = S.namelist.e * S.namelist.ncrit
+weight_to_pC = weight_to_pC * (S.namelist.c_over_omega0)**3
+Q_pC         = total_weight * weight_to_pC * 10**(12)
+print(" ")
+print("Total bunch charge = "+str(Q_pC)+" pC")
+
+
+

Action Check that this is the bunch charge set in the input namelist.

+

Action Try to extract the evolution of the bunch parameters during the simulation. +Remember that you can extract the available timesteps and then loop the extraction +of the macro-particle arrays over the timesteps.

+

Action plot the energy spectrum, i.e. the histogram of the macro-particles energies, +and check that the result is the same obtained with the ParticleBinning diagnostic. +Pay attention to the normalizations of the axes!

+

Action Adapting this script, +study the evolution of the bunch parameters, e.g. its emittance, energy spread, etc.

+
+
+
+

Perfectly Matched LayersΒΆ

+

Imperfect boundary conditions may cause unphysical effects when the bunch’s intense +electromagnetic fields arrive at the boundaries of the simulation window. +A larger box (transversally) could help fields decay near the boundaries. +However this can easily increase the simulation time beyond an acceptable level, +and only to avoid reflections, adding to the domain some physical regions where +no phenomenon of interest happens.

+

Therefore, to avoid this inefficient approach, this namelist uses improved +boundary conditions called Perfectly Matched Layers, +which add some cells to the simulation borders filled with a fictious medium +where the fields are damped and not reflected back inside the physical simulation window. +Note that these additional cells are not visible to the user.

+

The Perfectly Matched Layers are activated in the Main block through:

+
EM_boundary_conditions = [
+    ["PML","PML"],
+    ["PML","PML"],
+],
+
+number_of_pml_cells = [[20,20],[20,20]],
+
+
+

Action: How do the results change if you decrease the number of PML cells +from 20 to 5? Are the fields more or less noisy?

+

Action: What happens if instead of the "PML" boundary conditions you use +the more classic following conditions?:

+
EM_boundary_conditions  =  [["silver-muller","silver-muller"],["buneman","buneman"],]
+
+
+

How large should the simulation window be to avoid reflections without a Perfectly +Matched Layers?

+
+
+
+

Acceleration of a witness bunchΒΆ

+

Now you know everything necessary to simulate beam-driven plasma acceleration: try to define +a second, smaller electron bunch, with the same energy of the driver bunch, smaller charge and small enough to fit +in the plasma wave and injected in the accelerating phase of the plasma wave (i.e. negative Ex).

+

Use the numpy array initialization method as you have done for the bunch driving the waves. +Study the evolution of the energy spectrum of this witness bunch and check that its average energy is increasing.

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/advanced_wakefield_envelope.html b/advanced_wakefield_envelope.html new file mode 100644 index 0000000..ce2b05c --- /dev/null +++ b/advanced_wakefield_envelope.html @@ -0,0 +1,771 @@ + + + + + + + Envelope model for laser wakefield acceleration — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Envelope model for laser wakefield accelerationΒΆ

+

The goal of this tutorial is to give an introduction to the use of the laser +envelope model with Smilei. Before starting with this tutorial, we +recommend to complete first the tutorial on Azimuthal-mode-decomposition cylindrical geometry. In that +Tutorial, Laser Wakefield Acceleration is simulated in a standard way, i.e. the +laser is defined through its electromagnetic fields defined on the grid. +We recommend also to complete the tutorial Field initialization for a relativistic electron bunch +to familiarize with the diagnostics involving the macro-particle quantities.

+

With 2 MPI processes and 20 OpenMP threads this simulation should run in a few minutes. +(remember to set the number of OpenMP threads as explained in Setup).

+

The following features will be addressed:

+
    +
  • Automatic conversion of the output to SI units (pint Python module required)

  • +
  • Laser envelope initialization β€œin the box”

  • +
  • Initialization of the species interacting with the laser envelope

  • +
  • Observation of relativistic self-focusing

  • +
  • Automatic conversion of the output to SI units (pint Python module required)

  • +
  • Analysis of the grid fields when an envelope is present

  • +
  • Use of the envelope ionization module.

  • +
  • Use of the B-TIS3 interpolation scheme with a laser envelope

  • +
+
+
+

Physical configurationΒΆ

+

An ultra high intensity laser enters an under dense plasma. It propagates in +the plasma and creates a non linear plasma wave in its wake. +The start of the plasma is made of a mixture of hydrogen and nitrogen, while the +rest of the plasma is made of pure hydrogen. The laser field is strong enough to +ionize the hydrogen and the first 5 levels of the nitrogen much before the arrival +of the laser peak field, thus the hydrogen will be assumed ionized and the nitrogen +ionized up to level 5. The field of the laser peak is intense enough to further +ionize the nitrogen ions. Some of the newly released electrons are trapped and +accelerated in the plasma wave behind the laser (hence the name laser wakefield +acceleration with ionization injection).

+

The simulation is run with a Laser Envelope model +for the laser pulse. This allows to simulate the laser-plasma interaction in an underdense plasma +without the need to resolve the high frequency oscillations of the laser pulse. +This way, we can use a coarser cell size along the laser propagation direction x and +a coarser timestep, obtaining considerable speed-ups for our simulations. +Thus, although the envelope represents a laser pulse, you won’t see the laser oscillations at wavelength +\(\lambda_0\) since we are using a laser envelope model.

+

Furthermore, the simulation of this tutorial is run in cylindrical geometry +(only one azimuthal mode), which further speeds-up the simulations. +The envelope model is available also in other geometries.

+
+

Note

+

The simulation in this tutorial uses a few macro-particles per cell and a coarse mesh too keep the +computational time reasonable. Physically relevant simulations of the considered phenomena would +require more macro-particles and a finer mesh. Apart from the numerical artefacts whose +mitigation will be addressed in this tutorial, the noise in the grid quantities will be caused +also by the small number of macro-particles.

+
+
+
+
+

Preparing the case studyΒΆ

+

Download this input file and open it with your +favorite editor.

+

First, note how we defined variables for physical constants and for conversions +from SI units to normalized units. Specifying a reference length, in this case +the laser wavelength, is important to treat ionization. This information is found +in the reference_angular_frequency_SI argument in the Main block.

+

The laser is initialized via the use of LaserEnvelope +block. The laser envelope will be initialized in the box. The longitudinal +profile of the laser is called time_envelope in analogy with a standard +laser, but it does not represent a temporal variation during the simulation +as when the laser is injected from a window border, as in the tutorial in +Azimuthal-mode-decomposition cylindrical geometry. +To visualize it more easily, think of substituting the time t with the x coordinate. +Thus, the center of the laser profile (i.e. its position at t=0) must be chosen +inside the simulation domain. Note that the focus of the laser can have a longitudinal +position different from the laser center.

+

We have used the "explicit_reduced_dispersion" solver for the envelope equation. +For short propagation distances without strong self-focusing (see later in this tutorial) +you can use also the quicker "explicit" solver. +However, when long propagation distances or quick envelope evolutions +occur in a plasma we recommend to use "explicit_reduced_dispersion" to have more accurate results. +In those situations the results using the two solvers can be considerably different. +The stability condition for "explicit_reduced_dispersion" is more strict, so it is +possible that you will need a smaller integration timestep to use it.

+

Action Run the simulation and open the results:

+
import happi
+S = happi.Open("/example/path/to/the/simulation")
+
+
+
+
+
+

Conversion to SI unitsΒΆ

+

We have specified the reference_angular_frequency_SI in the Main block +of our input namelist. Therefore, if you have built happi with the pint Python module, +you should be able to automatically convert the normalized units of the outputs +towards SI units, as will be shown in the commands of this tutorial.

+

To do this, while opening the diagnostic you will specify the units in your plot, +e.g. units = ["um","GV/m"]. If happi was not built with the pint module +or if you want to see the results in normalized units, just omit these units +and remember to adjust the vmin and vmax of your plot commands.

+
+
+
+

A subtlety: the envelope of the vector potential vs the envelope of the electric fieldΒΆ

+

First, let’s study the laser propagation. Note the MovingWindow block and +that the window starts moving since the very first iteration of the simulation. +This allows the simulation domain to constantly shift toward the x direction +in order to follow the laser propagation.

+

Plot the values on the propagation axis of the fields called Env_A_abs and Env_E_abs, +with the same scale. For this, use the diagnostic Fields (if the timestep is +not provided, the last one is plotted by default):

+
Env_A=S.Probe.Probe0("Env_A_abs", label="Env_A")
+Env_E=S.Probe.Probe0("Env_E_abs", label="Env_E")
+happi.multiSlide(Env_A,Env_E)
+
+
+

Here we have used the happi command multiSlide, that it is analogous to +the command multiPlot, but allows to slide between multiple timesteps. +Note that we have not converted these outputs to SI units, since in laser wakefield +acceleration the peak normalized field (often called a0) of the laser pulse can give important information +on the wave excitation regime (nonlinear for a0 > 1. for example, linear for a0 << 1.).

+

Do you see some differences when the simulation advances? +The complex envelope field used for calculations is the envelope of the vector potential +\(\tilde{A}\). In the diagnostics, you can plot its absolute value through Env_A_abs. +Instead, the field Env_E_abs is the absolute value of the envelope of the electric field \(\tilde{E}\), +the latter defined to allow comparisons with the field of a standard laser: +\(\tilde{E}=-(\partial_t-ik_0c)\tilde{A}\) (see Smilei’s website for the derivation). +Remember that as explained in the documentation, when the laser +temporal variations are quick, the difference between the two fields will be +sensitive. Both the fields are complex quantities, the abs means that their +absolute value is plotted. These quick temporal evolutions can occur during the +propagation in plasmas.

+

You can see how the two fields evolve differently in this nonlinear case extracting +the data at all timesteps and computing the peak of the field at each timestep:

+
import numpy as np
+import matplotlib.pyplot as plt
+
+dt        = S.namelist.dt
+timesteps = S.Probe.Probe0("Env_E_abs").getAvailableTimesteps()
+
+Env_A_abs = S.Probe.Probe0("Env_A_abs").getData()
+Env_A_abs = np.asarray(Env_A_abs)
+Env_A_abs = np.amax(Env_A_abs,axis=1)
+plt.plot(timesteps*dt,Env_A_abs,label="|Env_A|")
+
+Env_E_abs = S.Probe.Probe0("Env_E_abs").getData()
+Env_E_abs = np.asarray(Env_E_abs)
+Env_E_abs = np.amax(Env_E_abs,axis=1)
+plt.plot(timesteps*dt,Env_E_abs,label="|Env_E|")
+
+plt.ylabel("field peak [normalized units]")
+plt.xlabel("t [normalized units]")
+plt.legend()
+
+
+

In the namelist we have specified a peak value for the field equal to a0=1.8, +and that is the peak value that the laser field in Env_E_abs would reach in vacuum at the focal plane. +From the previous plot you can see that the laser reaches higher values. +This is due to relativistic self-focusing that occurs in plasmas when the laser +power exceeds the power threshold for the occurrence of this phenomenon. +The interaction of the plasma on the laser pulse propagation is quantified by the +field Env_Chi, which appears in the envelope equation.

+

Action Visualize in 2D the envelope fields on the plane xy through the other Probes +defined in the namelist, e.g.:

+
S.Probe.Probe1("Env_E_abs").slide()
+
+
+
+
+
+

Wakefield excitationΒΆ

+

Now let’s observe the wakefield formation in the trail of the laser +envelope. Remember that the pusher scheme to use when a laser envelope model is present is +either pusher="ponderomotive_boris" or pusher="ponderomotive_borisBTIS3".

+

Action Check that the defined Species has a compatible pusher scheme.

+

Through the diagnostic Probe and the option animate or slide, you can follow +the envelope propagation and plasma evolution during the simulation. As before, you can plot the +absolute value of the envelope Env_E_abs.

+

You can also follow the formation of the plasma wave, plotting the electron density Rho. +To see it more clearly, we recommend the use of the option vmax in the +slide() or plot() function, for example:

+
S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=2, vmin=0.,vmax=1.5e12)
+
+
+

Note the formation of a bubble behind the laser, whose borders are full of +electrons and whose interior is emptied (or almost emptied in some regimes) of electrons.

+

The longitudinal electric field on axis, very important for electron +Laser Wakefield Acceleration, can be plotted with the Probe defined on the propagation axis, +choosing the field Ex in your diagnostic:

+
S.Probe.Probe0("Ex",units=["um","GV/m"]).slide(figure=3)
+
+
+

Through the function multiSlide, follow the evolution of the envelope and the of +electron density on the axis:

+
envelope_E = S.Probe.Probe0("20*Env_E_abs",units=["um"],label="20*Env_E_abs")
+Ex         = S.Probe.Probe0("Ex",label="Ex",units=["um","GV/m"])
+happi.multiSlide(Ex,envelope_E)
+
+
+

Note that we have multiplied the laser normalized electric field by 10 in the last command +to have a more readable scale in the plot.

+

The evolution of both the envelope and the electron density can be studied in 2D at the same time +through the transparent argument of the multiSlide function. We’ll make transparent +all the values of Env_E_abs below 1.:

+
Rho        = S.Probe.Probe1("-Rho",units=["um","pC/cm^3"],cmap="Blues_r",vmin=0.,vmax=1.5e12)
+Env_E      = S.Probe.Probe1("Env_E_abs",units=["um"],cmap="hot",vmin=0.8,transparent="under")
+happi.multiSlide(Rho,Env_E,xmin=0)
+
+
+

This way you should see the laser pulse envelope and the plasma wave in the electron density.

+
+
+
+

Envelope ionization moduleΒΆ

+

As explained in the tutorial for Field ionization, to correctly model +tunnel ionization it is essential to specify a reference frequency, which is already +done in the Main block of this tutorial’s namelist.

+

Afterwards, you have to specify a Species that will be ionized, in this case "nitrogen5plus", +whose charge state at the start of the simulation is lower than its atomic_number. +Note also that you can keep this Species frozen and at the same time able to be +ionized. This will avoid spending time in moving macro-particles that do not move too much, +as the nitrogen ions of this laser wakefield simulation set-up.

+

The new electrons created from the tunnel ionization of this Species will be +stored in another Species, specified in ionization_electrons of "nitrogen5plus". +In our case this Species at the start of the simulation has zero macro-particles. +We could have chosen an already populated species of electrons like bckgelectron, +but if you want to keep them separated like in this case it can be useful for diagnostics +(although it can take more simulation time, due to cache efficiency).

+

To ionize "nitrogen5plus", a ionization_model must be selected in its Species +block. Since we are using a laser envelope model, we must use the "tunnel_envelope_averaged" model. +Physically tunnel ionization occurs at the peaks of the laser field, but these peaks +are not part of an envelope model, by definition. +How can we model tunnel ionization with a laser envelope model then? +The model "tunnel_envelope_averaged" uses an ADK ionization rate averaged over the +laser oscillations, and a similar averaging is taken into account when the newly created +electrons are initialized, to correctly recreate their transverse momentum dispersion +and the drift in their x direction from tunnel ionization occurring in relativistic regimes. +More details on this model can be found here.

+

Action Visualize the density of the electrons created through ionization:

+
S.Probe.Probe1("-Rho_electronfromion",units=["um","pC/cm^3"]).slide(figure=2, vmin=0.,vmax=1.5e12)
+
+
+

Run two new simulations, changing the fraction of the nitrogen dopant in the gas mixture, +stored in the variable dopant_N_concentration=0.10 (i.e. ten percent of nitrogen). +Try a value 1.5 times larger and 1.5 times smaller. How does the Rho_electronfromion +change?

+

Action Using the same techniques you have used in the tutorial Field initialization for a relativistic electron bunch, +try to plot the energy spectrum of the electrons created through ionization.

+
+
+
+

Reducing the effects of Numerical Cherenkov RadiationΒΆ

+

As already discussed in this tutorial Azimuthal-mode-decomposition cylindrical geometry, +the use of finite difference solvers for Maxwell’s equations introduces a numerical +dispersion, that interacting with relativistic macro-particles will generate +a numerical artefact called Numerical Cherenkov Radiation. +In that tutorial two methods are shown to cope with this artefact, one of which is +the B-TIS3 interpolation scheme described in +P.-L. Bourgeois and X. Davoine, Journal of Plasma Physics 89 (2023), +that does not remove the Numerical Cherenkov Radiation, but considerably reduces +its effects on the macro-particles, with minimal increase of the simulation time. +Now we will see how to use this feature with a laser envelope model. +The tricky part with an envelope model is that this feature works well only when +the normalized timestep (or dt) is close to the normalized cell length along x (or dx), which is +not always compatible with the stability of the envelope solver, expecially +the "explicit_reduced_dispersion". Try have at least dt>0.9*dx to use +the B-TIS3, but check that the solver results (i.e. the envelope fields) do not +increase exponentially due to a too high dt.

+

Action: Run a new simulation, changing the variable use_BTIS3_interpolation +before the Main block to True. Note how this changes the pusher +to "ponderomotive_borisBTIS3" and adds some fields to the Probes in the namelist. +Check how the electron beam shape changes:

+
S.Probe.Probe1("-Rho",units=["um","pC/cm^3"]).slide(figure=2, vmin=0.,vmax=1.5e12)
+
+
+

Afterwards, check this combination of Probes, proportional to the force acting +on the macro-particles along the y direction:

+
S.Probe.Probe1("Ey-c*BzBTIS3",units=["um","GV/m"]).slide(figure=3,vmin=-20,vmax=20,cmap="seismic")
+
+
+

What difference do you observe if you compare it with the equivalent combination +in the simulation without the B-TIS3 scheme (using Bz instead of BzBTIS3)?

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/analysis_tunnel_ionization_1d.py b/analysis_tunnel_ionization_1d.py new file mode 100644 index 0000000..0155578 --- /dev/null +++ b/analysis_tunnel_ionization_1d.py @@ -0,0 +1,106 @@ +# +# ANALYSIS OF TUNNEL IONISATION SIMULATION (Tutorial 4) +# + +simulation_to_analyse = 'tunnel_ionization_1d' + +# IMPORT SMILEI's POST-PROCESSING TOOL +# ------------------------------------ + +import happi + + +# IMPORT OTHER PYTHON PACKAGES +# ---------------------------- + +from numpy import array, pi +import matplotlib as mpl +import matplotlib.pyplot as plt + + +# DEFINE MATPLOTLIB PREFERENCES +# ----------------------------- + +### mpl.rcParams['text.usetex'] = True +mpl.rcParams.update({ + 'font.family' :'serif', + 'font.serif' :'Times', + 'font.size' :16, + 'xtick.major.size' :10, + 'ytick.major.size' :10, + 'xtick.minor.size' :5, + 'ytick.minor.size' :5, +}) + + +# LOADING SIMULATION & IMPORTANT VARIABLES FROM NAMELIST +# ------------------------------------------------------ + +S = happi.Open(simulation_to_analyse ,verbose=False) + +t0 = 2.*pi +Lv = S.namelist.Lv +Lp = S.namelist.Lp +dt = S.namelist.Main.timestep +Zat = S.namelist.Species[0].atomic_number + +print('- vector potential aL = '+str(S.namelist.aL)) +print('- ref. ang. frequency w0 = '+str(S.namelist.Main.reference_angular_frequency_SI)) + + +# SOLVE THE RATE EQUATION NUMERICALLY & PLOT THE RESULTS +# ------------------------------------------------------ + +from solve_rate_eqs import solve_rate_eqs_ +t, n, Env = solve_rate_eqs_(S.namelist) + +fig = plt.figure(1); +ax = fig.add_axes([0.15, 0.15, 0.8, 0.8]) +#plt.hold('on') +for Z in range(0,5): + ax.plot(t/t0, n[Z,:], color='0.60', linewidth=1) +plt.fill_between(t/t0, Env, 0, interpolate=True, color='0.90') +plt.xlim(4,10) +plt.ylim(0,1.) +plt.show() + + + +# SIMULATION ANALYSIS & COMPARISON TO RATE EQUATIONS +# -------------------------------------------------- + +# read n(Z,t): get the density of each charge state from the ParticleBinning diagnostics +n = array( S.ParticleBinning(0).getData() ) +n00 = n[0,0] +n = n/n00 + +# get corresponding time-steps +t = dt * array(S.ParticleBinning(0).get()['times']) +t = t - Lv - Lp # centering time axis + +# check conservation +nsum = sum( n[-1,:] ) +print('- checking conservation of the particle number: should give 1, returns:'+str(nsum)) + + +# assign a color to each charge state +lcolor=['k--','r--','b--','g--','c--','m--','k--'] + +# plot the density of each charge state as a function of time +for Z in range(5): + plt.plot(t/t0, n[:,Z], lcolor[Z], linewidth=2, label='Z = %d'%Z) + ### plt.plot(t/t0,n[:,Z],lcolor[Z],linewidth=2,label=r'$Z^{\star}=$ %d'%Z) + plt.legend(loc='upper left', frameon=False, borderpad=0.1, handletextpad=0.1, labelspacing=0.1) + +plt.xlim(4,10) +plt.ylim(0,1.) +plt.xlabel('t [in optical cycles]') ### plt.xlabel(r'$c t/\lambda_0$') +plt.ylabel('N[Z]/N0') ### plt.ylabel(r'$N_{Z^{\star}}(t)/N_{0}(t=0) $') +plt.xticks( (4.,6.,8.,10.), color='k') +plt.yticks( (0.,0.25,0.5,0.75,1.), color='k') +ax.tick_params('both', length=4) +plt.savefig('Figure_Carbon_Ionization.eps') +plt.show() + + + diff --git a/arrangement.png b/arrangement.png new file mode 100644 index 0000000..881ae2b Binary files /dev/null and b/arrangement.png differ diff --git a/basics.html b/basics.html new file mode 100644 index 0000000..2ffbcba --- /dev/null +++ b/basics.html @@ -0,0 +1,524 @@ + + + + + + + PIC basics — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + +
+ + + + + + \ No newline at end of file diff --git a/basics_laser_vacuum.html b/basics_laser_vacuum.html new file mode 100644 index 0000000..0004891 --- /dev/null +++ b/basics_laser_vacuum.html @@ -0,0 +1,695 @@ + + + + + + + Laser Propagation in vacuum — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Laser Propagation in vacuumΒΆ

+

The goal of this tutorial is to run your first simulation with Smilei. +The following points will be addressed:

+
    +
  • How to prepare an input file

  • +
  • How to check your input file using the test mode

  • +
  • How to access your simulation results

  • +
  • Get familiar with the Courant-Friedrich-Lewy (CFL) condition.

  • +
+
+
+

Physical configurationΒΆ

+

Download the input file laser_propagation_2d.py. +Note that this file is written in the python language.

+

Read through this file and try to understand the contents of the Main(...) and +LaserGaussian2D(...) blocks. You can obtain details on the meaning of all keywords +in this documentation page. +Note that all units are normalized according to +these conventions.

+

A Gaussian (in both space and time) laser pulse enters in the simulation box from +the xmin side and propagates through the box.

+
+
+
+

Setup the tutorialΒΆ

+

As explained in the setup page, you should make a new directory +to run your simulation. This directory should contain the input file that you just downloaded +and the executables smilei and smilei_test.

+
+
+
+

Checking your input file in test modeΒΆ

+

The first step is to check that your input file is correct. +To do so, you will run (locally) Smilei in test mode:

+
./smilei_test laser_propagation_2d.py
+
+
+

This test mode does the same initialization as the normal mode but does not enter the PIC loop. +It provides you with a log (what appears on your screen). +What does this log tells you? Do you spot any ERROR message?

+

If you did spot an ERROR, can you correct it? If so, correct it, and try again!

+

Once you have no more ERROR message. Do you get WARNING messages?

+
+
+
+

Running the simulationΒΆ

+

Once your simulation input file is correct, you can +run the simulation.

+
./smilei laser_propagation_2d.py
+
+
+

Before going to the analysis of your simulation, check the output on the screen (the log).

+
    +
  • What did change compared to the test mode?

  • +
  • Did your run complete correctly?

  • +
  • Check what output files have been generated: what are they?

  • +
+
+
+
+

Preparing the post-processing toolΒΆ

+

Let’s now turn to analysing the output of your run with the python post-processing +package happi. +To do so, open a new terminal window, and start ipython:

+
ipython
+
+
+

From ipython, import the happi module:

+
import happi
+
+
+
+
+
+

Get basic info on the simulationΒΆ

+

Open the simulation that you have just run:

+
S=happi.Open("/path/to/the/simulation")
+
+
+
+

Warning

+

Use the correct path to the simulation folder.

+
+

See what is available from the simulation:

+
S.namelist.  # then press <tab>
+
+
+

When pressing <tab>, ipython display the content of the simulation. +You can explore all these items. They should all be exactly the same as the ones +that were defined earlier in the namelist laser_propagation_2d.py.

+
+
+
+

Check laser using ScalarΒΆ

+

Read the namelist again and spot the line where the Scalar diagnostic has been defined. +You may get more information on this diagnostic +on this page.

+

Obtain a list of Scalar diagnostics:

+
S.Scalar()
+
+
+

Open the Uelm scalar and plot:

+
diag = S.Scalar('Uelm')
+diag.plot()
+
+
+

This scalar represents the electromagnetic energy in the box. The plot we just obtained +should represent its evolution with time.

+
+
+
+

More Scalar diagnosticsΒΆ

+

Check the evolution of the total energy in the simulation box:

+
S.Scalar('Utot').plot()
+
+
+

Check the evolution of the energy balance in the simulation box:

+
S.Scalar('Ubal').plot()
+
+
+

You can also compare the last two quantities on the same plot:

+
happi.multiPlot(
+    S.Scalar('Utot', label="Total energy"),
+    S.Scalar('Ubal', label="Balance")
+    )
+
+
+
+
+
+

Plot laser using FieldΒΆ

+

Read the namelist again and spot the line where the Field diagnostic has been defined.

+

Open the Ey field and plot:

+
diag = S.Field(0, "Ey")
+diag.slide(vsym=1)
+
+
+

This new function slide() makes a sliding bar to explore the time-evolution +of the simulation.

+

Now, open the field with an average, and compare to the previous profile. +The following calculates the laser amplitude envelope using "Ey**2+Ez**2". +Then, using the argument average, it makes an average of this envelope for x +close to 0 and y at 100.

+
S.Field(0, "Ey**2+Ez**2", average={"x":[0,7],"y":100}).plot()
+
+
+
+
+
+

Compare the laser profile with the theoryΒΆ

+

We are going to overlay the previous plot of the laser profile with +the theoretical laser profile.

+

Get the Laser block from the namelist:

+
laser = S.namelist.Laser[0]
+
+laser
+
+
+

Note that the laser is an object of type <Smilei Laser>.

+

See what is available in this laser object:

+
laser.  # then press <tab>
+        # This should display all info on the laser
+
+laser.time_envelope
+
+
+

Note that this quantity is a python function: what function is it? +Some help is available here.

+

To plot the laser profile as a function of time, a list of times is necessary. +In the following, we use the package numpy to generate a list of times from 0 to +the end of the simulation, separated by the timestep.

+
from numpy import array, arange
+tstop = S.namelist.Main.simulation_time # simulation final time
+tstep = S.namelist.Main.timestep        # simulation timestep
+times = arange(0., tstop, tstep)
+
+
+

You may type times in order to see what is the list of times that we have created.

+

Now, we execute the laser.time_envelope function on each of the times that we just created. +We obtain a list of values of the laser envelope corresponding to each time.

+
laser_profile = array([laser.time_envelope(t) for t in times])
+
+
+

Plot the profile using the matplotlib package:

+
%pylab
+plot( times+5, laser_profile**2 / 2 )
+
+
+
+
+
+

Testing the CFL conditionΒΆ

+

Now change the input file and increase the time-step e.g. using \(\Delta t = 0.95\,\Delta x\).

+

Re-run Smilei and check the total energy and/or energy balance.

+

What is going on?

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/basics_setup.html b/basics_setup.html new file mode 100644 index 0000000..40865d3 --- /dev/null +++ b/basics_setup.html @@ -0,0 +1,639 @@ + + + + + + + Setup — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

SetupΒΆ

+

In these tutorials, we assume you are running on a UNIX machine that has access to internet +and can run simulation jobs on several cores. Ideally, it would run on 16 to 32 cores. +If you are, instead, using a home computer or workstation, we recommend you scale the +simulations down in order to reduce their execution time.

+

We recommend getting some basic understanding of parallel computing and some basic knowledge +on UNIX commands.

+

You should first open a terminal or a console, then cd to the directory of your +choice.

+
+
+

Obtain SmileiΒΆ

+

Use git to download the code into a Smilei directory:

+
git clone --depth=1 https://github.com/SmileiPIC/Smilei.git
+cd Smilei
+
+
+
+
+
+

Compile the documentationΒΆ

+

In the main Smilei folder, use the sphinx python package to compile +the documentation (get sphinx here).

+
make doc
+firefox build/html/index.html &
+
+
+

Replace firefox by your favorite web browser.

+
+
+
+

Prepare the environmentΒΆ

+

The environment should be ready to accomodate for Smilei’s installation. +Check this page +for details.

+

In short, you need:

+
    +
  • a C++11 compiler

  • +
  • a compatible MPI library (MPI_THREAD_MULTIPLE support is strongly recommended)

  • +
  • a compatible HDF5 library

  • +
  • python 2.7+

  • +
+

We recommend that your C++ compiler supports OpenMP for efficient +multi-threading. For best performances, the following environment variables should +be set, for instance in your .bash_profile or +.bashrc configuration files.

+
export OMP_NUM_THREADS=8
+export OMP_SCHEDULE=dynamic
+export OMP_PROC_BIND=true
+
+
+

The number 8 indicates the number of threads per process. For most systems, +the ideal number is equal to the number of cores contained in one node or socket. +For example, if your machine has 12 cores that share the same memory, use +OMP_NUM_THREADS=12.

+
+
+
+

Compile SmileiΒΆ

+

Once all dependencies are installed, go to the Smilei directory and compile:

+
make -j 8
+
+
+

The option -j 8 provides 8 threads for compilation (faster). +When the compilation has succeeded, two executables are created: smilei +and smilei_test.

+

Install also, the post-processing package happi :

+
make happi
+
+
+
+
+
+

Run a simulation on your machineΒΆ

+

The first step for any simulation is to create a new directory to +contain all the simulation inputs and outputs. Otherwise, the many +generated files would pollute your current directory.

+
# Make a new folder and go inside
+mkdir mysimulation
+cd mysimulation
+
+# Copy necessary executables to the new folder
+cp /path/to/Smilei/smilei .
+cp /path/to/Smilei/smilei_test .
+
+# Copy the input file as well
+cp /path/to/my_input.py .
+
+
+

When running Smilei on your own computer, the first possibility +is to run directly the code in the current terminal:

+
./smilei my_input.py
+
+
+

If you want to use several computing units, you can use the relevant +MPI executable on your machine. For example, with mpirun:

+
# Run the simulation on 4 processes
+mpirun -n 4 smilei my_input.py
+
+
+

To facilitate this process, a script smilei.sh is already available. +See help here.

+

In this example, the simulation will use 4 processes, but remember that the option above +OMP_NUM_THREADS=8 will set 8 threads in each process, so a total of 24 threads. +As a consequence, this example is ideal for 4 nodes containing each 8 cores. +This parallel computing is studied in this tutorial.

+
+
+
+

Run a simulation on a clusterΒΆ

+

Most supercomputers provide two different options to run a simulation. Both are relevant +to this tutorial. You may choose either.

+
    +
  1. Run in interactive mode: you may request a few nodes of the machine for a given amount +of time. You will have access interactively to the processes, so that the commands above +can be directly written in the command line to run the simulation.

  2. +
  3. Prepare a submission file to submit a β€œjob”. You machine administrator should provide +you with a typical job submission file. It defines the number of nodes and cores that +you want to reserve. The command lines above have to be included in this file.

  4. +
+
+
+
+

TipsΒΆ

+
    +
  • Launch a parallel interactive session:

    +

    One hour with 2 nodes, 8 processors per node, on the default queue:

    +
      +
    • +
      with the torque (PBS) scheduler:
      +
      qsub -I -l walltime=01:00:00,nodes=2:ppn=8 -q default
      +
      +
    • +
    • +
      with the slurm scheduler:
      +
      srun -p default -I -N 2 -c 8 --pty -t 0-01:00
      +
      +
    • +
    • with intel’s LoadLeveler

    • +
    +
  • +
  • Download a file from this webpage to your machine

    +
    curl -O http://URL/of/the/file
    +
    +
    +
  • +
+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/basics_thermal_plasma.html b/basics_thermal_plasma.html new file mode 100644 index 0000000..f63073b --- /dev/null +++ b/basics_thermal_plasma.html @@ -0,0 +1,593 @@ + + + + + + + Thermal plasma — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Thermal plasmaΒΆ

+

The goal of this tutorial is to get familiar with:

+
    +
  • the Species block that allows you to define a particle species,

  • +
  • the ParticleBinning diagnostics to obtain particle energy spectra,

  • +
  • the problem of numerical heating and the necessity to correctly resolve the electron dynamics +in explicit PIC codes.

  • +
+
+
+

Physical configurationΒΆ

+

Download the input file thermal_plasma_1d.py.

+

An infinite electron-ion plasma is let free to evolve in a 1D cartesian +geometry with periodic boundary conditions.

+
+
+
+

Check input file and run the simulationΒΆ

+

The first step is to check that your input file is correct. +To do so, you will run (locally) Smilei in test mode:

+
./smilei_test thermal_plasma_1d.py
+
+
+

If your simulation input file is correct, you can now run the simulation. +Before going to the analysis of your simulation, check your log and/or +error output.

+

Check what output files have been generated: what are they?

+
+
+
+

Preparing the post-processing toolΒΆ

+

Let’s now turn to analysing the output of your run with happi. +To do so, open an ipython session:

+
ipython
+
+
+

In ipython, import the happi package:

+
import happi
+
+
+

then open your simulation:

+
S = happi.Open('/path/to/the/simulation')
+
+
+
+

Warning

+

Use the correct simulation path.

+
+

You are now ready to take a look at your simulation’s results.

+
+
+
+

The Field diagnostics using happi.multiPlotΒΆ

+

To have a quick access at your data and check what is going on, you will plot +the electron and ion densities together with the electrostatic field \(E_x\).

+

First, prepare the data:

+
# minus the electron density
+ne = S.Field(0,'-Rho_eon', label="e- density")
+
+# ion density
+ni = S.Field(0,'Rho_ion', label="ion density")
+
+# Ex field
+ex = S.Field(0,'Ex', label="Ex field", vmin=-0.25,vmax=2)
+
+
+

You may plot all these quantities independently using ex.plot() or ex.slide(), +but you can also use the multiSlide function of happi:

+
happi.multiSlide(ne,ni,ex)
+
+
+
+
+
+

The ParticleBinning diagnosticsΒΆ

+

Now, have a look at the ParticleBinning diagnostics in the input file. +What kind of data will this diagnostic provide?

+

You can compare the results at the beginning and at the end of the simulation:

+
Nt = S.ParticleBinning(0).getTimesteps()[-1] # the last timestep
+f_initial = S.ParticleBinning(0, data_log=True, timesteps=0 , label="initial")
+f_final   = S.ParticleBinning(0, data_log=True, timesteps=Nt, label="final")
+happi.multiPlot(f_initial, f_final)
+
+
+

What can you conclude?

+
+
+
+

Effect of spatial resolutionΒΆ

+

Have a look at the total energy and energy balance in your simulation +(remember the Utot and Ubal scalars). +Note the level of energy imbalance at the end of this simulation for which +the spatial resolution is equal to the Debye Length (\(\Delta x = \lambda_{\rm De}\)).

+

Increase your spatial resolution to \(\Delta x = 16 \times \lambda_{\rm De}\). +Run the simulation again, and check the energy imbalance at the end of the simulation. +What do you observe? +Can you check the electron spectrum at the beginning and end of the simulation? +What is going on?

+

Finally, increase your spatial resolution to +\(\Delta x = 2\,c/\omega_{pe} = 2\,c\lambda_{\rm De}/v_{\rm th}\) (you will need to extend +your simulation box size to have enough cells). +Check the evolution of the total energy. +What do you observe?

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/basics_units.html b/basics_units.html new file mode 100644 index 0000000..71eb038 --- /dev/null +++ b/basics_units.html @@ -0,0 +1,662 @@ + + + + + + + Units — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

UnitsΒΆ

+

The goal of this tutorial is to familiarize with the use of physical units in Smilei.

+

This tutorial will allow you to:

+
    +
  • get familiar with the units of the input namelist

  • +
  • postprocess the results displaying units of your choice

  • +
+

This tutorial requires the installation of the pint Python package.

+
+
+

What units are used by the code?ΒΆ

+

Usually, physics codes work with normalized units to simplify the equations and reduce the number +of multiplications.

+

For the electromagnetic PIC method, the system given by Maxwell’s and Vlasov’s equations +can be easily written in normalized units, +normalizing speeds by \(c\), masses by the electron mass \(m_e\) and charges +by the unit charge \(e\). +However, there is no natural length or time normalization in this system of equations. +To complete the normalization, one must choose a reference length \(L_r\), or equivalently +a reference time \(T_r\), or equivalently a reference angular frequency \(\omega_r\). +In the following, we choose \(\omega_r\) as our normalization quantity (\(L_r\) and +\(T_r\) are deduced from \(\omega_r\)).

+

Importantly, it is not even necessary to choose a value for this last normalization. +Indeed, it automatically cancels out, so that the system of equations does not depend on +\(\omega_r\). This means that the result of the simulation is true for any value of +\(\omega_r\)! That is why is it usually not necessary to set a value to \(\omega_r\) +in the simulation input file.

+

In practice, we always know our problem in terms of real-world units, but in Smilei’s +input file, all quantities must be normalized.

+
    +
  1. Choose \(\omega_r\) as one important frequency of your problem (i.e. laser frequency, +plasma frequency, …)

  2. +
  3. Deduce other reference quantities such as \(L_r\) and \(T_r\)

  4. +
  5. The parameters in the input file should be normalized accordingly

  6. +
+

During post-processing, you will obtain results in terms of normalized quantities, +but happi gives you the possibility to convert to units of your choice.

+
+
+
+

Physical configurationΒΆ

+

Download the input file radiation_pressure_2d.py.

+

In this simulation, a slab of pre-ionized overdense plasma of uniform density \(n_0\) +is irradiated by a high-intensity laser pulse, triggering electron and ion expansion.

+
+
+
+

Check input file and run the simulationΒΆ

+

The first step is to check that your input file is correct. +To do so, you will run (locally) Smilei in test mode:

+
./smilei_test radiation_pressure_2d.py
+
+
+

Take some time to study the namelist, in particular how the physical parameters +have been defined. For the moment you can ignore the lines of code marked with Choice 2 +at the start of the namelist.

+
+
+
+

Normalized units in the input namelistΒΆ

+

The blocks of the input namelist will accept only quantities in normalized units. +As mentioned before, choosing a reference length/time/angular frequency yields +conversion factors for all physical units involved in a PIC simulation. +For more details, see the units +page in the documentation.

+

Therefore, if you are accustomed to work with normalized units, you can directly +put your physical set-up’s parameters in the input namelist in normalized units. +We will call this Choice 1 in the following and in the input namelist. +The use of SI units will be called Choice 2 and will be explored in the last section +of this tutorial.

+

The provided input file already has Choice 1 implemented in the namelist +(see the initial part of the file). As you can see reading the namelist, +most of the simulation parameters can be defined starting from the definition +of the laser wavelength, which will be also our reference wavelength. +This can be seen in the LaserGaussian2D block, where the Laser β€˜s angular frequency +omega in normalized units is 1, i.e. equal to our reference angular frequency.

+

With this choice of normalization:

+
    +
  • a length of \(2\pi\) corresponds to a laser wavelength,

  • +
  • a time interval \(2\pi\) corresponds to an optical cycle of the laser,

  • +
  • the reference density corresponds to the laser critical density \(n_c=\varepsilon_0 m_e \omega^2/e^2\).

  • +
+
+

Note

+

In other set-ups you may want to choose the reference length equal to the Debye length, +or the plasma electron wave frequency, etc. In this case, if a Laser is present, +remember to redefine the omega in the Laser block accordingly.

+
+
+

Note

+

Some reference quantities do not change with the choice of reference length/time, +e.g. the electron charge will be \(-1\), the electron mass will be \(1\), since the +reference charge and mass in our normalized units are those of the electron. +Also, the reference energy and speed are \(m_ec^2\) and c, independently of the choice for +the reference length/time.

+
+

Question: if we wanted a laser with frequency equal to two times the reference frequency, +what would be the value of omega in the Laser block?

+

Question: for a reference length of \(L_r=0.8\) Β΅m what would be +the reference density? See its definition here +(you may use the constants in the module scipy.constants). +Is it equal to \(L_r^{-3}\)?

+
+

Warning

+

As you have seen, in this namelist there is no need to specify a reference angular frequency +or a reference length in SI units. However, when using advanced physical operators like +ionization, collisions, multiphoton Breit Wheeler pair generation, radiation emission +you will have to do it (see related tutorials and the Main block of their namelists). +This happens because these operators represent an extension of the basic Vlasov-Maxwell system of +PIC codes, and are not invariant under the described normalization.

+
+
+
+
+

Units in the postprocessingΒΆ

+

Let’s study the results, without specifying a conversion:

+
import happi; S_normalized = happi.Open('/path/to/your/simulation')
+
+
+

If we plot the laser transverse field on the propagation axis, we can verify +that indeed a length of \(2\pi\) corresponds to the laser wavelength:

+
S_normalized.Probe.Probe0("Ey").slide()
+
+
+

Now, what if we wanted our results in physical units, e.g. SI units? While opening the output with happi, +we can specify a reference angular frequency in SI. In this case, we can choose it from +the laser wavelength:

+
import math
+import scipy.constants
+laser_wavelength_um = 0.8
+c                   = scipy.constants.c     # Lightspeed, m/s
+omega_r_SI          = 2*math.pi*c/(laser_wavelength_um*1e-6)
+S_SI = happi.Open('/path/to/your/simulation', reference_angular_frequency_SI=omega_r_SI)
+
+
+

This allows happi to make the necessary conversions for our scale of interest. +Then, we have to specify the units we want in our plot:

+
S_SI.Probe.Probe0("Ey", units=['um','fs','GV/m']).slide(figure=2)
+
+
+

Question: Does the peak transverse field of the laser correspond to the one in normalized units +at the same timestep and in the namelist? Compute first the reference electric field as explained here +and check the conversion to GV/m.

+

Action: Similarly, try to plot the kinetic energy Ukin from the Scalar diagnostic +and the evolution of the electron density Rho_eon from the Field diagnostic +in normalized and physical units.

+

Note: Other systems of units can be used, e.g. CGS, or different combinations of units, including inches, feet. +For more details, see here.

+
+
+
+

SI units in the input namelistΒΆ

+

If you prefer to work with physical units, e.g. SI units, the use of Python for the input namelist +allows to easily convert our inputs in SI units to normalized inputs required by +the code. In the namelist there is a way to do it, marked with Choice 2 +and commented for the moment.

+

Action: Comment the two lines marked with the comment Choice 1 in the input namelist. +Uncomment the lines marked with Choice 2 and take some time to read them.

+

As you can see, first we use the scipy.constants module to define some useful physical constants, +e.g. the speed of light. Then, we define the reference length, from which we derive some variables useful +for the conversions. +With these variables, it is easy to have the necessary quantities in normalized units and vice-versa:

+
length_normalized_units = length_SI / L_r
+
+
+

Question: Near the Laser block, a variable E_r is defined, representing the reference +electric field. Using this variable, can you convert the normalized peak electric field of the laser a0 +to TV/m? Similarly, can you convert the plasma density n0 to \(\textrm{cm}^{-3}\)? Note that instead of +defining the density as in the namelist we could have just used:

+
density_normalized_units = n0_SI / N_r
+
+
+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/basics_weibel_twostream.html b/basics_weibel_twostream.html new file mode 100644 index 0000000..3847097 --- /dev/null +++ b/basics_weibel_twostream.html @@ -0,0 +1,579 @@ + + + + + + + Weibel and two-stream instabilities — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Weibel and two-stream instabilitiesΒΆ

+

The goal of this tutorial is to run to physics simulations relating to streaming instabilities, +and in particular to the electron Weibel and two-stream instabilities.

+

This tutorial will also allow you to:

+
    +
  • get familiar with the happi.streak tool

  • +
  • extract instability growth rates

  • +
  • construct and extract phase-space distribution using the ParticleBinning diagnostics

  • +
+
+
+

Physical configurationΒΆ

+

Download the two input files weibel_1d.py and +two_stream_1d.py.

+

In both simulations, a plasma with density \(n_0\) is initialized (\(n_0 = 1\)). +This makes code units equal to plasma units, i.e. times are normalized to the inverse of +the electron plasma frequency \(\omega_{p0} = \sqrt{e^2 n_0/(\epsilon_0 m_e)}\), +distances to the electron skin-depth \(c/\omega_{p0}\), etc…

+

Ions are frozen during the whole simulation and just provide a neutralizing background. +Two electron species are initialized with density \(n_0/2\) and +a mean velocity \(\pm \bf{v_0}\).

+
+
+
+

Check input file and run the simulationΒΆ

+

The first step is to check that your input files are correct. +To do so, you will run (locally) Smilei in test mode:

+
./smilei_test weibel_1d.py
+./smilei_test two_stream_1d.py
+
+
+

If your simulation input files are correct, you can run the simulations.

+

Before going to the analysis, check your logs.

+
+
+
+

Weibel instability: analysisΒΆ

+

In an ipython terminal, open the simulation:

+
S = happi.Open('/path/to/your/simulation/weibel_1d')
+
+
+

The streak function of happi can plot any 1D diagnostic as a function of time. +Let’s look at the time evolution of the total the current density \(J_z\) and +the magnetic field \(B_y\):

+
S.Field(0,'Jz'  ).streak(vsym=True)
+S.Field(0,'By_m').streak(vsym=True)
+
+
+

Do you have any clue what is going on? +You can get another view using an animation:

+
jz = S.Field(0,'Jz')
+by = S.Field(0,'By_m',vmin=-0.5,vmax=0.5)
+happi.multiSlide(jz,by)
+
+
+

Now, using the Scalar diagnostics, check the temporal evolution of the energies +in the magnetic (\(B_y\)) and electrostatic (\(E_z\)) fields. +Can you distinguish the linear and non-linear phase of the instability?

+

Have a closer look at the growth rates. Use the data_log=True options when loading +your scalar diagnostics, then use happi.multiPlot() to plot both energies as a +function of time. Can you extract the growth rates? What do they tell you?

+

If you have time, run the simulation for different wavenumbers \(k\). +Check the growth rate as a function of \(k\).

+

For those interested, you will find more in: +Grassi et al., Phys. Rev. E 95, 023203 (2017).

+
+
+
+

Two-stream instability: analysisΒΆ

+

In an ipython terminal, open the simulation:

+
S = happi.Open('/path/to/your/simulation/two_stream_1d')
+
+
+

then, have a first look at your simulation results:

+
uel = S.Scalar('Uelm',data_log=True,vmin=-9,vmax=-2)
+ne  = S.Field(0,'-Rho_eon1-Rho_eon2', xmin=0, xmax=1.05, vmin=0, vmax=2)
+ex  = S.Field(0,'Ex', xmin=0, xmax=1.05, vmin=-0.2, vmax=0.2)
+phs = S.ParticleBinning(0,cmap="smilei_r",vmin=0,vmax=200)
+happi.multiSlide(uel,ne,ex,phs,shape=[1,4])
+
+
+

Any clue what’s going on?

+

Let’s have a look at the energy in the electrostatic field \(E_x\):

+
    +
  • Can you distinguish the linear and non-linear phase of the instability?

  • +
  • Check the \((x,p_x)\)-phase-space distribution (and energy in the electromagnetic fields), +can you get any clue on what leads the instability to saturate?

  • +
+

Try changing the simulation box size (which is also the wavelength of the considered +perturbation), e.g. taking: \(L_x =\) 0.69, 1.03 or 1.68 \(c/\omega_{p0}\). +What do you observe?

+

Now, take \(L_x =\) 0.6, 0.31 or 0.16 \(c/\omega_{p0}\). What are the differences? +Can you explain them?

+
+
+ + +
+
+
+ + + + + + \ No newline at end of file diff --git a/beam_2d.py b/beam_2d.py new file mode 100644 index 0000000..aefc7a5 --- /dev/null +++ b/beam_2d.py @@ -0,0 +1,87 @@ +# ------------------- +# MY PYTHON VARIABLES +# ------------------- + +dx = 1./64 # spatial resolution +ncells = 256 # number of cells +nppc = 25 # number of particle-per-cell + +Te = 1e-6 # temperature in units of me c^2 + +# Initial plasma density profile +radius = 30.*dx +x0 = 40.*dx +y0 = 200.*dx +def ne(x,y): + if (x-x0)**2 + (y-y0)**2 < radius**2: + return 1. + else: + return 0. + +# -------------------------------------- +# SMILEI's VARIABLES (DEFINED IN BLOCKS) +# -------------------------------------- + +Main( + geometry = "2Dcartesian", + + interpolation_order = 2, + + timestep_over_CFL = 0.95, + simulation_time = 10., + + cell_length = [dx, dx], + number_of_cells = [ncells, ncells], + + number_of_patches = [ 32, 32 ], + + EM_boundary_conditions = [ ['periodic'] ] , + + solve_poisson = False, +) + +Species( + name = 'eon', + position_initialization = 'regular', + momentum_initialization = 'maxwell-juettner', + particles_per_cell = nppc, + mass = 1.0, + charge = -1.0, + number_density = ne, + temperature = [Te], + mean_velocity = [0.3, 0., 0.], + boundary_conditions = [ + ['periodic'], + ] +) +Species( + name = 'pon', + position_initialization = 'regular', + momentum_initialization = 'maxwell-juettner', + particles_per_cell = nppc, + mass = 1.0, + charge = 1.0, + number_density = ne, + temperature = [Te], + mean_velocity = [0.3, 0., 0.], + boundary_conditions = [ + ['periodic'], + ] +) + +### DIAGNOSTICS + +DiagParticleBinning( + deposited_quantity = "weight", + every = 10, + species = ["eon"], + axes = [ + ["x", 0., Main.grid_length[0], 200], + ["y", 0., Main.grid_length[1], 200], + ] +) + +DiagPerformances( + every = 10 +) + diff --git a/compare_density_radiative_models.png b/compare_density_radiative_models.png new file mode 100644 index 0000000..e70e3bf Binary files /dev/null and b/compare_density_radiative_models.png differ diff --git a/compare_energy_balance_Landau_Lifshitz.png b/compare_energy_balance_Landau_Lifshitz.png new file mode 100644 index 0000000..e49395d Binary files /dev/null and b/compare_energy_balance_Landau_Lifshitz.png differ diff --git a/compare_energy_balance_radiation_models.png b/compare_energy_balance_radiation_models.png new file mode 100644 index 0000000..be2f4b0 Binary files /dev/null and b/compare_energy_balance_radiation_models.png differ diff --git a/energy_balance.png b/energy_balance.png new file mode 100644 index 0000000..3bac308 Binary files /dev/null and b/energy_balance.png differ diff --git a/energy_spectrum_it8000.png b/energy_spectrum_it8000.png new file mode 100644 index 0000000..5f3a994 Binary files /dev/null and b/energy_spectrum_it8000.png differ diff --git a/export_VTK_namelist.py b/export_VTK_namelist.py new file mode 100644 index 0000000..05f872a --- /dev/null +++ b/export_VTK_namelist.py @@ -0,0 +1,213 @@ +import numpy as np +import cmath + + +geometry = "3Dcartesian" # or "AMcylindrical" + +# Spatial and temporal resolution +dx = 0.1 +dtrans = 3. +dt = 0.085 +# Mesh +nx = 512 +ntrans = 80 +Lx = nx * dx +Ltrans = ntrans*dtrans +npatch_x = 64 + +if (geometry == "3Dcartesian"): + cell_length = [dx , dtrans, dtrans] + grid_length = [Lx , Ltrans, Ltrans] + number_of_patches = [npatch_x, 4 , 4 ] + EM_boundary_conditions = [["silver-muller"]] + +elif (geometry == "AMcylindrical"): + cell_length = [dx , dtrans ] + # remember that in AM cylindrical geometry the grid represents the half plane (x,r) + # thus Ltrans is the transverse window size, i.e. from r=0 to r=Ltrans + grid_length = [Lx , Ltrans ] + number_of_patches = [npatch_x, 4 ] + EM_boundary_conditions = [["silver-muller","silver-muller"],["buneman","buneman"],] + +Main( + geometry = geometry, + interpolation_order = 2, + number_of_AM = 2, # this variable is used only in AMcylindrical geometry + timestep = dt, + simulation_time = Lx, + cell_length = cell_length, + grid_length = grid_length, + number_of_patches = number_of_patches, + EM_boundary_conditions = EM_boundary_conditions, + solve_poisson = False, + print_every = 100, +) + + +MovingWindow( + time_start = Main.grid_length[0], + velocity_x = 0.9997 +) + +LoadBalancing( + initial_balance = False, + every = 20, + cell_load = 1., + frozen_particle_load = 0.1 +) + + +if (geometry == "3Dcartesian"): + + boundary_conditions = [["remove", "remove"],["remove", "remove"],["remove", "remove"],] + particles_per_cell = 0.1 + + # We build a Laguerre-Gauss laser from scratch instead of using LaserGaussian3D + # The goal is to test the space_time_profile attribute + omega = 1. + a0 = 6. + focus = [0., Main.grid_length[1]/2., Main.grid_length[2]/2.] + waist = 10. + laser_fwhm = 20. + time_envelope = tgaussian(center=2**0.5*laser_fwhm, fwhm=laser_fwhm) + + Zr = omega * waist**2/2. + w = math.sqrt(1./(1.+(focus[0]/Zr)**2)) + invWaist2 = (w/waist)**2 + coeff = -omega * focus[0] * w**2 / (2.*Zr**2) + + m = 1 # azimuthal index + def phase(y,z): + return -m*np.arctan2((z-Ltrans/2.), (y-Ltrans/2.)) + + def By(y,z,t): + return 0. + def Bz(y,z,t): + r2 = (y-focus[1])**2 + (z-focus[2])**2 + omegat = omega*t - coeff*r2 + return a0 * w * math.exp( -invWaist2*r2 ) * time_envelope( omegat/omega ) * math.sin( omegat - phase(y,z)) + + # Define the laser pulse + Laser( box_side = "xmin",space_time_profile = [By, Bz]) + + # Define Plasma density profile + def my_profile(x,y,z): + center_plasma = [Lx/4.,Ltrans/2.,Ltrans/2.] + Radius = 20. + Length = 5. + if ((abs(x-center_plasma[0]) - + - Index — No Errors Test Project documentation - + Index — Smilei tutorials X.Y documentation + + + + + - - - - - - - -
-
-
- -
- + - +
+ - - - - + \ No newline at end of file diff --git a/index.html b/index.html index 7d336f4..d6bf61d 100644 --- a/index.html +++ b/index.html @@ -1,110 +1,482 @@ - + - Welcome to No Errors Test Project’s documentation! — No Errors Test Project documentation - + Smilei tutorials — Smilei tutorials X.Y documentation + + + + + + - - - - - - -
-
-
- +
+ + + -
- -
-

Welcome to No Errors Test Project’s documentation!ΒΆ

-
+
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+
-
-

Indices and tablesΒΆ

-
- -
+
+
+
-
-
-
+
- - - + \ No newline at end of file diff --git a/laser_propagation_2d.py b/laser_propagation_2d.py new file mode 100644 index 0000000..f440990 --- /dev/null +++ b/laser_propagation_2d.py @@ -0,0 +1,71 @@ +# ---------------------------------------------------------------------------------------- +# SIMULATION PARAMETERS FOR THE PIC-CODE SMILEI +# ---------------------------------------------------------------------------------------- + +from math import pi, sqrt + +l0 = 2. * pi # laser wavelength [in code units] +t0 = l0 # optical cycle +Lsim = [32.*l0, 32.*l0] # length of the simulation +Tsim = 50.*t0 # duration of the simulation +resx = 16. # nb of cells in one laser wavelength +rest = resx*sqt(2.)/0.95 # nb of timesteps in one optical cycle + +Main( + geometry = "2Dcartesian", + + interpolation_order = 2 , + + cell_length = [l0/resx,l0/resx], + grid_length = Lsim, + + number_of_patches = [ 8, 8 ], + + timestep = t0/rest, + simulation_time = Tsim, + + EM_boundary_conditions = [ + ['silver-muller'], + ['silver-muller'], + ], +) + +LaserGaussian2D( + a0 = 1., # normalized amplitude + omega = 1., + focus = [Lsim[0]/2., Lsim[1]/2.], # coordinates of laser focus + waist = 5.*l0, + incidence_angle = 0., + time_envelope = tgaussian(fwhm=4*t0, center=0.15*Tsim) +) + + +DiagScalar( + every = rest +) + +DiagFields( + every = rest, + fields = ['Ex','Ey','Ez','Bx','By','Bz'] +) + +# 2-dimensional grid diagnostic +DiagProbe( + every = 100, + number = [100, 100], # number of points in the grid + origin = [0., 10.*l0], # coordinates of origin point + corners = [ + [20.*l0, 0.*l0], # coordinates of first corner of the grid + [3.*l0 , 40.*l0], # coordinates of second corner of the grid + ], + fields = [] +) + +# probe diagnostic with 1 point +DiagProbe( + every = 10, + origin = [0.1*Lsim[0], 0.5*Lsim[1]], + fields = [] +) + + diff --git a/laser_wake.py b/laser_wake.py new file mode 100644 index 0000000..b9784af --- /dev/null +++ b/laser_wake.py @@ -0,0 +1,88 @@ + +dx = 0.125 +dy = 2. +dt = 0.124 +nx = 128*20 +ny = 320 +Lx = nx * dx +Ly = ny * dy +npatch_x = 256 +laser_fwhm = 40. +laser_waist = 200. +Niterations = 3000 + +Main( + geometry = "2Dcartesian", + interpolation_order = 2, + timestep = dt, + simulation_time = Niterations*dt, + cell_length = [dx, dy], + grid_length = [ Lx, Ly ], + number_of_patches = [npatch_x, 32], + EM_boundary_conditions = [ + ["silver-muller","silver-muller"], + ["silver-muller","silver-muller"], + ], + solve_poisson = False, + print_every = 100, +) + +Species( + name = "electron", + position_initialization = "regular", + momentum_initialization = "cold", + particles_per_cell = 9, + c_part_max = 1.0, + mass = 1.0, + charge = -1.0, + charge_density = trapezoidal(0.003, xvacuum=0., xplateau=1000000000, xslope1=1000.), + mean_velocity = [0.0, 0.0, 0.0], + pusher = "boris", + time_frozen = 0.0, + boundary_conditions = [ + ["remove", "remove"], + ["remove", "remove"], + ], +) + +LaserGaussian2D( + box_side = "xmin", + a0 = 4., + focus = [0., Main.grid_length[1]/2.], + waist = laser_waist, + time_envelope = tgaussian(center=3*laser_fwhm, fwhm=laser_fwhm) +) + + +DiagProbe( + every = 1000, + origin = [0., Main.grid_length[1]/2.], + corners = [ + [Main.grid_length[0], Main.grid_length[1]/2.], + ], + number = [nx], + fields = ['Ex','Ey','Rho','Jx'] +) + +DiagProbe( + every = 1000, + origin = [0., 0.], + vectors = [[Lx,0], [0,Ly]], + number = [nx,ny], + fields = ['Ex','Ey','Rho','Jx'] +) + +DiagParticleBinning( + deposited_quantity = "weight", + every = 1000, + species = ["electron"], + axes = [ + ["moving_x", 0, Lx, 300], + ["ekin", 1, 400, 100] + ] +) + +DiagPerformances( + every = 1000, + patch_information = False, +) diff --git a/laser_wake_AM.py b/laser_wake_AM.py new file mode 100644 index 0000000..8bd7ab0 --- /dev/null +++ b/laser_wake_AM.py @@ -0,0 +1,199 @@ +###### Laser Wakefield Acceleration tutorial in Azimuthal Modes cylindrical geometry +import math +import numpy as np +import scipy.constants + +##### Physical constants +lambda0 = 0.8e-6 # reference length, m - here it will be our plasma wavelength +c = scipy.constants.c # lightspeed, m/s +omega0 = 2*math.pi*c/lambda0 # reference angular frequency, rad/s +eps0 = scipy.constants.epsilon_0 # Vacuum permittivity, F/m +e = scipy.constants.e # Elementary charge, C +me = scipy.constants.m_e # Electron mass, kg +ncrit = eps0*omega0**2*me/e**2 # Plasma critical number density, m-3 +c_over_omega0 = lambda0/2./math.pi # converts from c/omega0 units to m +reference_frequency = omega0 # reference frequency, s-1 +E0 = me*omega0*c/e # reference electric field, V/m +electron_mass_MeV = scipy.constants.physical_constants["electron mass energy equivalent in MeV"][0] + + +##### Variables used for unit conversions +c_normalized = 1. # speed of light in vacuum in normalized units +um = 1.e-6/c_over_omega0 # 1 micron in normalized units +mm = 1.e-3/c_over_omega0 # 1 millimetre in normalized units +fs = 1.e-15*omega0 # 1 femtosecond in normalized units +mm_mrad = um # 1 millimetre-milliradians in normalized units +pC = 1.e-12/e # 1 picoCoulomb in normalized units +MeV = 1./electron_mass_MeV # 1 MeV in normalized units + + +##### Mesh and time evolution +dx = (lambda0/1e-6)*um/30 # longitudinal resolution +dr = 0.4*um # radial resolution + +nx = 1536 # number of grid points in the longitudinal direction +nr = 80 # number of grid points in the radial direction + +Lx = nx * dx # longitudinal size of the simulation window +Lr = nr * dr # radial size of the simulation window, which goes from r=0 to r=Lr + +npatch_x = 256 + +dt = 0.98*dx/c_normalized # integration timeestep +Niterations = 15000 + + +##### Boundary conditions +EM_boundary_conditions = [["PML","PML"],["PML","PML"],] +#EM_boundary_conditions = [ ["silver-muller","silver-muller"],["buneman","buneman"],] + +##### B-TIS3 interpolation to cope with numerical Cherenkov radiation +use_BTIS3_interpolation = False + +Main( + geometry = "AMcylindrical", + number_of_AM = 2, + timestep = dt, + simulation_time = Niterations*dt, + cell_length = [dx, dr], + grid_length = [Lx, Lr], + number_of_patches = [npatch_x, 8], + EM_boundary_conditions = EM_boundary_conditions, + number_of_pml_cells = [[20,20],[20,20]], + solve_poisson = False, + print_every = 100, + use_BTIS3_interpolation = use_BTIS3_interpolation, + reference_angular_frequency_SI = omega0, +) + +#### Define the plasma + +# The physics of interest in this case is near the axis, +# so no need to radially fill all the window with plasma + +density_plateau_cm_minus_3 = 3.e18 +density_plateau_normalized = density_plateau_cm_minus_3*1.e6/ncrit # convert to meters and then normalize +Radius_plasma = 140.*um + + +upramp_length = 100.*um +shock_downramp_length = 30. *um +plateau_length = 3. *mm +downramp_length = 100.*um + +x_start_plasma = Lx +x_density_transition_peak = x_start_plasma +upramp_length +x_plateau = x_density_transition_peak+shock_downramp_length +x_end_plateau = x_plateau +plateau_length +x_end_plasma = x_end_plateau +downramp_length + +longitudinal_profile = polygonal(xpoints=[x_start_plasma,x_density_transition_peak,x_plateau,x_end_plateau,x_end_plasma], + xvalues=[0.,2.*density_plateau_normalized,density_plateau_normalized,density_plateau_normalized,0.]) + +def nplasma(x,r): + profile_r = 0. + if (r10*MeV/c_normalized)) + +DiagTrackParticles( + species = "electron", + every = int(100*um/dt), + filter = my_filter, + attributes = ["x", "y", "z", "px", "py", "pz", "w"] +) diff --git a/laser_wake_envelope.py b/laser_wake_envelope.py new file mode 100644 index 0000000..e7a9a92 --- /dev/null +++ b/laser_wake_envelope.py @@ -0,0 +1,306 @@ +############################# Input namelist for Laser Wakefield Acceleration +############################# with ionization injection + +import math +import numpy as np +import scipy.constants + + +##### Physical constants +lambda0 = 0.8e-6 # laser wavelength, m +c = scipy.constants.c # lightspeed, m/s +omega0 = 2*math.pi*c/lambda0 # laser angular frequency, rad/s +eps0 = scipy.constants.epsilon_0 # Vacuum permittivity, F/m +e = scipy.constants.e # Elementary charge, C +me = scipy.constants.m_e # Electron mass, kg +ncrit = eps0*omega0**2*me/e**2 # Plasma critical number density, m-3 +c_over_omega0 = lambda0/2./math.pi # converts from c/omega0 units to m +reference_frequency = omega0 # reference frequency, s-1 +E0 = me*omega0*c/e # reference electric field, V/m +electron_mass_MeV = scipy.constants.physical_constants["electron mass energy equivalent in MeV"][0] + + +##### Variables used for unit conversions +c_normalized = 1. # speed of light in vacuum in normalized units +um = 1.e-6/c_over_omega0 # 1 micron in normalized units +fs = 1.e-15*omega0 # 1 femtosecond in normalized units +mm_mrad = um # 1 millimeter-milliradians in normalized units +pC = 1.e-12/e # 1 picoCoulomb in normalized units +me_over_me = 1.0 # normalized electron mass +mp_over_me = scipy.constants.proton_mass / scipy.constants.electron_mass # normalized proton mass +mn_over_me = scipy.constants.neutron_mass / scipy.constants.electron_mass # normalized neutron mass +MeV = 1./electron_mass_MeV # 1 MeV in normalized units + +######################### Simulation parameters + +##### mesh resolution +dx = 0.15*um # longitudinal mesh resolution +dr = 0.65*um # transverse mesh resolution +dt = 0.9*dx/c_normalized # integration timestep + +##### simulation window size +nx = 352 # number of mesh points in the longitudinal direction +nr = 48 # number of mesh points in the transverse direction +Lx = nx * dx # longitudinal size of the simulation window +Lr = nr * dr # transverse size of the simulation window + +##### Total simulation time +T_sim = 13001.*dt #3000.*dt + +##### patches parameters (parallelization) +npatch_x = 32 +npatch_r = 8 + + +######################### Main simulation definition block + +# Use True to activate a force interpolation scheme +# that reduces the effects of the Numerical Cherenkov Radiation +use_BTIS3_interpolation = False #True + +Main( + geometry = "AMcylindrical", + + interpolation_order = 2, + + timestep = dt, + simulation_time = T_sim, + + cell_length = [dx, dr], + grid_length = [Lx, Lr], + + number_of_AM = 1, + + number_of_patches = [npatch_x,npatch_r], + + EM_boundary_conditions = [["silver-muller"],["PML"],], + number_of_pml_cells = [[0,0],[20,20]], + + solve_poisson = False, + solve_relativistic_poisson = False, + + print_every = 100, + use_BTIS3_interpolation = use_BTIS3_interpolation, + + random_seed = 0, + reference_angular_frequency_SI = omega0, +) + +######################### Define the laser pulse + +#### laser parameters +a0 = 1.8 +laser_fwhm = 25.5*math.sqrt(2)*fs # laser FWHM duration in field, i.e. FWHM duration in intensity*sqrt(2) +laser_waist = 15.*um # laser waist, conversion from um +center_laser = Lx-1.7*laser_fwhm # laser position at the start of the simulation +x_focus_laser = 500*um + +#### Define a Gaussian Beam with Gaussian temporal envelope +LaserEnvelopeGaussianAM( + a0 = a0, + omega = (2.*math.pi/lambda0*c)/reference_frequency, # laser frequency, normalized + focus = [(Lx+x_focus_laser),0.], # laser focus, [x,r] position + waist = laser_waist, # laser waist + time_envelope = tgaussian(center=center_laser, fwhm=laser_fwhm), # time profile of the laser pulse + envelope_solver = 'explicit_reduced_dispersion', + Envelope_boundary_conditions = [ ["reflective"],["PML"] ], + Env_pml_sigma_parameters = [[0.9 ,2 ],[80.0,2] ,[80.0,2 ]], + Env_pml_kappa_parameters = [[1.00,1.00,2],[1.00,1.00,2],[1.00,1.00,2]], + Env_pml_alpha_parameters = [[0.90,0.90,1],[0.65,0.65,1],[0.65,0.65,1]] +) + + +######################### Define a moving window + +# window starts moving at the start of the simulation + +MovingWindow( + time_start = 0., + velocity_x = c_normalized, +) + +######################### Define the plasma + +##### plasma parameters +# atomic density +plasma_plateau_density_1_ov_cm3 = 1.3e18 +n_at = plasma_plateau_density_1_ov_cm3*1e6/ncrit # plasma plateau density in units of critical density defined above +R_plasma = 30.*um # Radius of plasma + +# Define the density function +# this plasma density profile tries to create the density distribution +# inside a gas cell with two chambers. +# In the first one, H2-N2 gas mixture is injected. In this chamber ionization injection occurs +# In the second one, pure H2 is injected +p_xmin = Lx*c_over_omega0 # Position of the beginning of the plasma (meters) +p_xmax = Lx*c_over_omega0+7.0e-3 # Position of the end of the plasma (meters) +xc1 = Lx*c_over_omega0+0.4e-3 # position of the max of density in the first chamber (m) +xc2 = Lx*c_over_omega0+0.8e-3 # position of the max of density in the second chamber (m) +mu1 = 0.2e-3 # 'Fermi energy' in the first chamber (m) +mu2 = 1.0e-3 # 'Fermi energy' in the second chamber (m) +T1 = 0.03e-3 # 'Temperature' at the cell entrance (m) +T2 = 0.04e-3 # 'Temperature' at the interface between the two chambers, assuming constant pressure (m) +T3 = 0.03e-3 # 'Temperature' at the cell entrance (m) +level_start_N = 5 # initial ionisation state of N atoms +Q_init_N = float(level_start_N) # initial charge of N atoms +dopant_N_concentration = 0.10 +Prop_N_in_1 = dopant_N_concentration # proportion of N atoms in H2-N2 mixture +Prop_H_in_1 = 1.-Prop_N_in_1 # proportion of H atoms in H2-N2 mixture + + +def dens_func_at1(x, r): + x_meters = (x)*c_over_omega0 + var1 = (1.+np.exp(-mu1/T1)) / (1.+np.exp(-(mu1+x_meters-xc1)/T1)) + var2 = (1.+np.exp(-mu1/T2)) / (1.+np.exp(-(mu1-x_meters+xc1)/T2)) + nat1 = np.where(x_meters < xc1, var1, var2) + nat1 = np.where(x_meters <= p_xmin, 0.0, nat1) + nat1 = np.where(x_meters >= p_xmax, 0.0, nat1) + + return nat1 + +def dens_func_at2(x, r): + x_meters = (x)*c_over_omega0 + var1 = (np.exp(-(mu1-x_meters+xc1)/T2)- np.exp(-mu1/T2)) / (1.+np.exp(-(mu1-x_meters+xc1)/T2)) + var1 = np.where(var1 > 0.0, var1, 0.0) + var2 = (1.+np.exp(-mu2/T3)) / (1.+np.exp(-(mu2-x_meters+xc2)/T3)) + nat2 = np.where(x_meters < xc2, var1, var2) + nat2 = np.where(x_meters <= p_xmin, 0.0, nat2) + nat2 = np.where(x_meters >= p_xmax, 0.0, nat2) + return nat2 + +def dens_func_e(x, r): + n1 = dens_func_at1(x, r) + n2 = dens_func_at2(x, r) + return (Prop_H_in_1 + Prop_N_in_1*Q_init_N)*n1 + n2 + +# number density profile of the dopant (nitrogen) +def my_density_profile_dopant(x,r): + radial_profile = 1. + if (r>R_plasma) or (xR_plasma) or (x5.*MeV/c_normalized)) + + +DiagTrackParticles( + species = "electronfromion", + every = int(50*um/dt), + filter = my_filter, + attributes = ["x", "y", "z", "px", "py", "pz", "w"] +) + + +######################### Load balancing (for parallelization) +LoadBalancing( + initial_balance = False, + every = 40, + cell_load = 1., + frozen_particle_load = 0.1 +) + +##### Field diagnostics, used for 3D export +DiagFields( + every = int(100*um/dt), + fields = ["Env_E_abs"], +) + +DiagFields( + every = int(100*um/dt), + fields = ["Rho_bckgelectron","Rho_electronfromion"], +) diff --git a/objects.inv b/objects.inv index 8c8a34f..658e7ff 100644 --- a/objects.inv +++ b/objects.inv @@ -1,7 +1,10 @@ # Sphinx inventory version 2 -# Project: No Errors Test Project -# Version: +# Project: Smilei tutorials +# Version: X.Y # The remainder of this file is compressed using zlib. -xΪmŽ± -1Dϋ|Εϊ'ΨΪ[X( -Φ1r'IV²{ Ώαοω%zδD»aζΝΞδ>{\HΤ/£="R³ 0ΉσNS€υ(ΝσμFθ‹8 :N eΪ2­Jα"΄‡(΅…OpϊΈέ…^½!!«ΥžσΜ$φ¦ΟΧζΤΫφCΔτ„ΐΧύ6ͺWα]Ν[`ž[N \ No newline at end of file +xΪ…”ΑnΫ0 †ο~ +ΫΥΆέ†a@»n@±(°n=ŒΜΔBeIδ€ιӏ–δ8N”φfύόωQ&ic»E-¨Ϊ/­PΜΪ‡.τ +ς©šδfεH†fΧ)r₯Δ₯#aξ€νL0Ηpύ˜₯αƒδ˜uFχs5a”’žCΎXj§:ΧR£ΫΓQκdoQΰ³|‰ufώZ’j›9R¬rjJ΅~Žjκ°•Qjψ½ΔEμΉ-μ΅θœ ΞθZΙ'‚ƒ&γ\kžŠpΦνΗ³5.@0ποαWlΗηΨJ? :»ψŸ(Ύlyˆ&π§Pθy„s +1υ΅ΉΊ{%uλ€@υz₯7/γ‹μ‡Π‘ͺ{ΣRέ’0½5^ΖΦ“7dz +n_Ί_PŒ­mV„ύwXxSΧ\τΠ@XΘΓQ|δΦ)`J…ΥΐΣ,^DoIKoέ!Ϋς4§€±*~u+τR,Ύ€$Ϊύνχ|ΞΖ&š-ŠaθΟ³α„ψ«ί;cq“š!5$ΓΔτ[€E=―όψ8ωCGGΥXΦc!qiH„‡€A&Τΐs*Ό}SβίρqςοHH5ag|p'ϋqΑ’(QŸGκœ-΅Έ’Š—…|΅!ΝJΟͺpτ3vRηv|¬f[}δψͺ }«x +@»―§@ώωšvP”Ρ–άzΡ‘(δuΰGΓ]δ τΙΨXt¨Ώοψ© AκΝYnΑ“qY‡ƒ~€Ρ5θκ υ€C‰yb™,Γ‘\ΉA{ώ+¨ωο}hΔٚ½{uε 3Ξ€M«γχΈ‘Š-‹Οs<Οι?fI±I \ No newline at end of file diff --git a/particle_number.png b/particle_number.png new file mode 100644 index 0000000..9f5d59d Binary files /dev/null and b/particle_number.png differ diff --git a/perfs.html b/perfs.html new file mode 100644 index 0000000..e061604 --- /dev/null +++ b/perfs.html @@ -0,0 +1,493 @@ + + + + + + + Performances — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + +
+
+ + + + + \ No newline at end of file diff --git a/perfs_parallel_computing.html b/perfs_parallel_computing.html new file mode 100644 index 0000000..da5ff61 --- /dev/null +++ b/perfs_parallel_computing.html @@ -0,0 +1,772 @@ + + + + + + + Parallel computing — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Parallel computingΒΆ

+

As supercomputers become larger, we can explore new domains of plasma physics +with more expensive simulations. However, this type of computer requires the +computation to be made by many computing cores at the same time, in parallel.

+

Optimizing parallel algorithms on these new machines becomes increasingly difficult, +because their architecture complexity grows together with their power. +See this introduction to parallelism.

+

Basic architecture of supercomputers:

+
+
    +
  • Many nodes communicate through a network. Each node owns its own memory.

  • +
  • Nodes are composed of many computing units (most often cores) which share the memory of the node.

  • +
+_images/node.svg +
+
+

This defines two levels of parallelism:

+
    +
  • β€œDistributed memory”: Communicating information between nodes that do not access the same memory.

  • +
  • β€œShared memory”: Synchronizing the operations of the cores that share the same memory.

  • +
+
+

Distributed memory

+
+

The protocol that handles the communication of data between different nodes is called MPI. +Smilei will run independently on each of those locations, and we call each of these instances an MPI process +(sometimes also called task). One MPI process is usually associated to many cores inside one single node, +but it does not necessarily occupy all the cores in this node.

+

The data is split into small pieces, called patches, so that it can be distributed to those MPI processes. +This is called domain decomposition.

+

Each MPI process executes all the computation necessary to handle the patches he has been given using the ressources he has access to. +The main difficulty is to provide an equal amount of work to each MPI process. This is called load balancing. We will see how +Smilei distributes the patches to MPI processes in order to have a uniform load.

+
+

Shared memory

+
+

Inside a given MPI process, where the shared memory contains many patches to be computed, +the work must be synchronized between available cores. +This is handled by the OpenMP protocol.

+

OpenMP creates threads which are sequences of instructions to be executed by cores, and schedules +the parallel work of all available cores accordingly.

+

Each thread will be assigned to successive patches, in parallel with other threads. +This is an effective way to balance the load inside the MPI process: when a patch is done, a core will automatically +work on the next patch withtout having to wait for another core that might still be working.

+
+

Summary

+
+

The simulation domain should be divided into many patches for two reasons:

+
    +
  • to distribute the computational load and feed all threads associated to each MPI process

  • +
  • to be able to manage the load imbalance by moving patches between different MPI processes

  • +
+

But, be careful: an excessively refined decomposition (with too many small patches) will +produce a large overhead due to communications and synchronizations.

+

The goal of this tutorial is to understand how to setup a simulation to get good performances. +The following features will be addressed:

+
    +
  • Decomposition of the simulation box into patches

  • +
  • Choice of the number of MPI processes and OpenMP threads

  • +
  • Smilei’s load balancing feature

  • +
  • Performance analysis with the DiagPerformances

  • +
+
+
+
+

Physical configurationΒΆ

+

Download the input file beam_2d.py. +A small plasma ball is set with an initial velocity \(v_x=0.3\) +and traverses the box.

+
+
+
+

Setup the tutorialΒΆ

+

As explained in the setup page, you should make a new directory +to run your simulation. This directory should contain the input file that you just downloaded +and the executables smilei and smilei_test.

+

We introduce this tutorial talking about supercomputers but we will run here single node simulations. +It could seems out of context but the idea is to illustrate how works the code parallelism and its limits.

+
+
+
+

Splitting the boxΒΆ

+

In a first test, we will use a single core with in a single MPI process to focus on the box splitting. +Launch the simulation with 1 MPI and 1 thread only. For instance, you could use commands similar to:

+
export OMP_NUM_THREADS=1
+mpirun -np 1 smilei beam_2d.py
+
+
+

The input file suggests to use 32x32 patches:

+
Main(
+     number_of_patches = [ 32, 32 ],
+)
+
+
+

Run the simulation for various number of patches, +and compare the computation time:

+
    +
  • 32 x 32 patches

  • +
  • 16 x 16 patches

  • +
  • 8 x 8 patches

  • +
  • a single patch

  • +
+

Computation times are provided at the end of the simulation:

+
    +
  • Time in time loop: the whole PIC loop

  • +
  • Particles : all particles operations except collisions

  • +
  • Maxwell : Maxwell equations and the electromagnetic boundary conditions

  • +
  • Diagnostics : all Diag blocks defined in the namelist

  • +
  • Sync Particles : particle exchange between patches

  • +
  • Sync Fields : E, B exchange between patches

  • +
  • Sync Densities : J exchange between patches

  • +
+

Details about timers

+

The Sync timers concern exchange between patches owned by a single MPI processes and/or by many. +In this case, these timers could contain waiting times due to load imbalance inherent to PIC simulations.

+

Whatever the case, Particles and Maxwell do not contain MPI waiting time, +they only accumulate pure computation time.

+

Load balancing, Mov window or Diagnostics (which can be seen like a disk synchronization) +are global operations which require communications, they can contain waiting time.

+

For many MPI processes simulation, these times are averaged on all processes. +Some detailed timing elements, such as minimum or maximum times on all processes +are provided in the file profil.txt and a full report can be obtained using the DiagPerformances.

+
+
+
+

Introduce Smilei’s parallelismΒΆ

+

Let’s make the first step to introduce parallel processing of all the patches. +We will use several OpenMP threads in a single MPI process.

+

Use a good patch configuration found in the previous step: 8x8 patches. +The single patch simulation is maybe slightly faster but it cannot exhibit any parallelism.

+

Setup 1 MPI process, and 16 threads per process. +You may need to adjust these settings according to your machine. TypicallyL

+
export OMP_NUM_THREADS=16
+export OMP_SCHEDULE=dynamic
+mpirun -np 1 smilei beam_2d.py
+
+
+

Make sure that, in the output log, it specifies the correct number of +processes and threads.

+

Even though 16 threads are used, the speed-up is very poor.

+

Let us now use happi to analyse the simulation. +Open an ipython prompt, then run:

+
import happi
+S = happi.Open("/path/to/beam_2d/")
+
+
+

You can have a quick understanding of what happens in the simulation using:

+
S.ParticleBinning(0).slide()
+
+
+

A ball of plasma (30 cells radius) is moving through the box (256x256 cells):

+
    +
  • With 8 x 8 patches, the size of a patch is 32 x 32 cells. +The plasma, which represents the main time cost, +occupies only a few patches of the simulation. +This means many threads are doing nothing.

  • +
  • With 16 x 16 patches, the size of a patch is 16 x 16 cells, +an order of magnitude is earned regarding the number of patches loaded with particles. +Verify the speedup.

  • +
  • With 32 x 32 patches, the size of a patch is 8 x 8 cells, +even more patches are loaded with particles, but with a synchronization overhead.

  • +
+

Check the behavior of these three configurations running 16 threads.

+

For this test, in the best case configuration, +an additionnal speed-up of 2 is obtained. +This is modest, but accelerating computations requires to split the particle load. +With a such local plasma, it is hard to achieve.

+
+
+
+

ImbalanceΒΆ

+

You applied some load balancing using OpenMP threading. +Indeed, the threads will keep working patch after patch in parallel on all the available patches +until all patches are done. +This is called dynamic scheduling.

+

The static scheduling, instead, assigns an exclusive pool of patches +to each thread. In this situation, threads will only work on their own pool, +even if it is an empty region. This obviously prevents load balancing between threads. +It is used on grids computing function of Smilei which is naturraly balanced.

+

To choose the type of OpenMP scheduling, you can set the environment +variable OMP_SCHEDULE to static. Typically:

+
export OMP_NUM_THREADS=16
+export OMP_SCHEDULE=static
+mpirun -np 1 smilei beam_2d.py
+
+
+

OpenMP offers intermediary solutions but regarding the granularity of +the level of parallelism, we advice the dynamic scheduling.

+
+
+
+

Imbalance and distributed memoryΒΆ

+

Run the 16 x 16 patches simulation but with a MPI-only configuration. +Typically, you can write:

+
export OMP_NUM_THREADS=1
+mpirun -np 12 smilei beam_2d.py
+
+
+

This is technically similar to the static scheduling of the previous section: +the pool of patches is explicitly distributed over MPI processes starting the simulation. +Compare the time spent in the PIC loop to that previous case.

+

We are now going to use the Performances diagnostic. +The list of available quantities can be obtained with:

+
S.Performances
+
+
+

Let us try:

+
S.Performances(map="hindex").plot()
+
+
+

You should obtain a map of the simulation box with one distinct color for +each memory region (i.e. each MPI process). There are 16 regions, as we requested +initially. You can see that these regions do not have necessarily the same shape.

+

Now plot the number of particles in each region:

+
S.Performances(map="number_of_particles").slide(cmap="smilei_r", vmin=0)
+
+
+

Clearly, at every given time, no more than only a few regions contain particles. +This is a typical situation where almost all processes have nothing to do +and wait for a single process to finish its computation.

+

You can also visualize the time taken for computing particles using:

+
S.Performances(map="timer_particles",cumulative=False).slide(cmap="smilei_r", vmin=0)
+
+
+
+
+
+

Balancing the load between processesΒΆ

+

Smilei has an automated load-balancing feature that can move patches from one +process to another in order to ensure they all have a similar load. Activate it +in the input file using:

+
LoadBalancing(
+    every = 20
+)
+
+
+

Then run the simulation again with 16 processes and +have a look at the Load balancing timer. +Observe differences in the computation time, +compare it to the time saved regarding the simulation without dynamic load balancing.

+
+

Warning

+

Sync timers are impacted by the imbalance of the +algorithm part which precedes it:

+
    +
  • Particles

  • +
  • Sync Densities

  • +
  • Maxwell

  • +
  • Sync Particles

  • +
  • Sync Fields

  • +
+
+

Use again the performances diagnostic to monitor the evolution of the +regions and their computational load.

+
+
+
+

Realistic configurationΒΆ

+
+

Note

+

To get familiar with Smilei’s domain decomposition, distributed and shared memory parallelism, +we did not consider the NUMA (non uniform memory access) aspect of most supercomputers. +Indeed, a node is generally composed of several sockets which own many cores each. +Cores have privileged access to the memory associated to it socket.

+
+

In general, supercomputers should be adressed with both:

+
    +
  • MPI: to go through nodes and sockets (to enhance memory affinity),

  • +
  • OpenMP: to feed threads and minimize imbalance

  • +
+

The following example uses 2 MPI processes with 8 threads each:

+
export OMP_NUM_THREADS=8
+mpirun -np 2 smilei beam_2d.py
+
+
+

Between processes, threads, and the number of patches, there are many ways the +simulation performances can be modified. There is no general rule for finding +the optimal configuration, so we recommend trying several options.

+
+
+ + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/perfs_patch_arrangement.html b/perfs_patch_arrangement.html new file mode 100644 index 0000000..83057f2 --- /dev/null +++ b/perfs_patch_arrangement.html @@ -0,0 +1,597 @@ + + + + + + + Patch arrangement — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+ +
+

Patch arrangementΒΆ

+

In some situations with slow particles dynamics, the dynamic load balancing +may not be relevant to speed-up the simulation. +Moreover, as it relies on a +Hilbert curve, +it may not be able to split intelligently the plasma in equal parts.

+

Typically, this happens when the plasma is contained in a thin slab. +The Hilbert curve splitting is better replaced by a simple linearized splitting +that divides the box in slabs of equal size.

+

The goal of this tutorial is to learn about these various arrangements of patches, +and test them in realistic cases.

+

We recommand first to run the parallel computing tutorial.

+
+
+

ConfigurationΒΆ

+
+
Starting case :

radiation_pressure_acc_hilbert.py

+
+
+

To highlight the phenomenon and to simplify the discussion +we propose to run on several MPI processes and only 1 thread per process.

+
+
+
+

Setting up the simulationΒΆ

+

Set your simulation with 16 MPI processes, and only 1 thread per process. Typically:

+
export OMP_NUM_THREADS=1
+mpirun -np 16 smilei radiation_pressure_acc_hilbert.py
+
+
+

Observe timers and the probe diagnostics results.

+
+

Note

+

Field diagnostics do not work with the alternative patch_arrangement +so we use Probe diagnostics instead.

+
+
+
+
+

Change the patch arrangementΒΆ

+

Activate the dynamic load balancing to absorb synchronizations overhead

+
LoadBalancing(
+    every = 20
+)
+
+
+

A look at the plasma shape shows that, at initialization, +the plasma is located within a thin slab along the Y axis. +Then, it is pushed along the X axis. +We propose to enforce an arrangement of patches that splits +the plasma into slabs along X, so that each region owns an +equal share of the computational load. +You may add the following line in the bloc Main():

+
patch_arrangement = "linearized_YX",
+
+
+

We can imagine that splitting into slabs along Y would be a +terrible option, because all the plasma will be contained in +one process only. All other processes will need to wait and do nothing. +You can still try it:

+
patch_arrangement = "linearized_XY",
+
+
+

You may want to stop the simulation before the end!

+
+_images/arrangement.png +

Fig. 1 Each numbered square represents a patch in an 8 x 8 patches configuration. +Each color represents one of the 16 MPI processes. +In this test case, the plasma is located in the 2nd column of the box. +You can observe how the dynamic load balancing (dlb) makes a coarse splitting +where there is no plasma.ΒΆ

+
+
+
+
+

Tuning the patch arrangementΒΆ

+

In the situation above, there was a maximum of 8 patches in the Y direction, +so that the plasma could not be split in more than 8 pieces. +We would like to split it in 16 pieces to make sure that each +of the 16 processes has something to work on. +Unfortunatly the patch size, 75 x 125 cells, does not permit to split more in Y.

+

Study the following code, which slightly increases the spatial +resolution in Y to get a number of cells in Y divisible per 16.

+
current_ncells_Y = Lsim[1] / (l0/resx)
+target_ncells_Y = 1024.
+target_cell_length_Y = (l0/resx*current_ncells_Y)/target_ncells_Y
+
+Main(
+    cell_length = [l0/resx,target_cell_length_Y],
+)
+
+
+

It is available in the input file +radiation_pressure_acc_linearized.py.

+

Run again the linearized_YX configuration: the higher resolution +leads to more particles, thus a slightly higher computation time.

+

You can now run the simulation with the 8 x 16 patches:

+
number_of_patches = [ 8, 16 ],
+
+
+

For a fair comparison, use this configuration with the hilbertian +arrangement (the default value of patch_arrangement). +In this mode, when the number of patches is not the same along all directions, +the Hilbert pattern is replicated in the larger direction (Y here). +This can be beneficial here.

+
+

Note

+

The paramater number_of_patches must be a power of 2 +with the hilbertian arrangement. This is not required with the +linearized arrangement.

+
+
+
+ + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/radiation_pressure_2d.py b/radiation_pressure_2d.py new file mode 100644 index 0000000..b9ed7e1 --- /dev/null +++ b/radiation_pressure_2d.py @@ -0,0 +1,127 @@ +from math import pi + +### Choice 1: Physical Inputs in normalized units ######################## + +# laser wavelength and period +l0 = 2*pi # laser wavelength in normalized units +t0 = 2*pi # optical cycle duration in normalized units +# Grid size and total simulated time +Lx = 6.*l0 +Ly = 10.*l0 +Tsim = 10.*t0 # duration of the simulation + +# ### Choice 2: Physical Inputs in normalized units, converted from SI units ####### + +# from scipy.constants import c, epsilon_0, e, m_e # constants in SI units +# wavelength_SI= 0.8e-6 # laser wavelength, m +# # Normalization quantities +# L_r = wavelength_SI # reference length is the wavelength +# T_r = L_r / c # reference time +# omega_r = 2*pi*c/L_r # reference angular frequency +# # Laser wavelength and period in normalized units +# l0 = wavelength_SI / L_r +# t0 = wavelength_SI/c / T_r +# # Grid size and total simulated time in normalized units +# Lx = 6. *wavelength_SI / L_r +# Ly = 10.*wavelength_SI / L_r +# Tsim = 10.*wavelength_SI/c / T_r # duration of the simulation + + +#################### Simulated domain and time interval ####################### +# Spatial and temporal resolution +resx = 100. # nb of cells in one laser wavelength +rest = 150. # nb of timesteps in one optical cycle +# Mesh and integration timestep +dx = l0/resx +dy = l0/resx +dt = t0/rest + +Main( + geometry = "2Dcartesian", + + interpolation_order = 2 , + + cell_length = [dx,dy], # normalized units + grid_length = [Lx,Ly], # normalized units + + number_of_patches = [ 8, 8 ], + + timestep = dt, # normalized units + simulation_time = Tsim, # normalized units + + EM_boundary_conditions = [ + ['silver-muller'], + ['periodic'], + ], +) + +# laser parameters +laser_a0 = 150. # normalized laser peak field +laser_waist = 2.0*l0 # laser waist +# eps0 = scipy.constants.epsilon_0 # Vacuum permittivity, F/m +# e = scipy.constants.e # Elementary charge, C +# me = scipy.constants.m_e # Electron mass, kg +# E_r = me*omega_r*c/e # Reference electric field, V/m + +LaserGaussian2D( + box_side = "xmin", + omega = 1., # normalized units + a0 = laser_a0, # normalized units + focus = [10.*l0, Ly/2.], # normalized units + waist = laser_waist, # normalized units + ellipticity = 1., # circular polarization + time_envelope = ttrapezoidal(slope1=t0), +) + +# plasma parameters +# N_r = eps0*omega0**2*me/e**2 # Reference density, m-3 +n0 = 100 # initial plasma density, normalized units +vacuum_length = l0 # distance between Xmin and the plasma, normalized units +plateau_length = 0.44*l0 # length of plateau of plasma density profile, normalized units + +Species( + name = 'ion', + position_initialization = 'regular', + momentum_initialization = 'cold', + particles_per_cell = 4, + mass = 1836., # normalized units + charge = 1., # normalized units + number_density = trapezoidal(n0,xvacuum=vacuum_length,xplateau=plateau_length), + boundary_conditions = [ + ["reflective", "reflective"], + ["periodic", "periodic"], + ], +) +Species( + name = 'eon', + position_initialization = 'regular', + momentum_initialization = 'mj', + particles_per_cell = 4, + mass = 1., # normalized units + charge = -1., # normalized units + number_density = trapezoidal(n0,xvacuum=vacuum_length,xplateau=plateau_length), + temperature = [0.001], # normalized units + boundary_conditions = [ + ["reflective", "reflective"], + ["periodic", "periodic"], + ], +) + +globalEvery = 75 + +DiagScalar(every=globalEvery) + +DiagProbe( + every = globalEvery, + origin = [0., Main.grid_length[1]/2.], + corners = [ + [Main.grid_length[0], Main.grid_length[1]/2.], + ], + number = [int(Lx/dx)], + fields = ['Ex','Ey','Ez','Bx','By','Bz','Rho_ion','Rho_eon'] +) + +DiagFields( + every = globalEvery, + fields = ['Ex','Ey','Ez','Bx','By','Bz','Rho_ion','Rho_eon'] +) diff --git a/radiation_pressure_acc_hilbert.py b/radiation_pressure_acc_hilbert.py new file mode 100644 index 0000000..58c202f --- /dev/null +++ b/radiation_pressure_acc_hilbert.py @@ -0,0 +1,124 @@ +# ---------------------------------------------------------------------------------------- +# SIMULATION PARAMETERS FOR THE PIC-CODE SMILEI +# ---------------------------------------------------------------------------------------- + +import math + +l0 = 2.0*math.pi # laser wavelength +t0 = l0 # optical cycle +Lsim = [6.*l0,10.*l0] # length of the simulation +Tsim = 10.*t0 # duration of the simulation +resx = 100. # nb of cells in on laser wavelength +rest = 150. # time of timestep in one optical cycle + +#current_ncells_Y = Lsim[1] / (l0/resx) +#target_ncells_Y = 1024. +#target_cell_length_Y = (l0/resx*current_ncells_Y)/target_ncells_Y + +target_cell_length_Y = l0/resx + +Main( + geometry = "2Dcartesian", + + interpolation_order = 2 , + + cell_length = [l0/resx,target_cell_length_Y], + grid_length = Lsim, + + number_of_patches = [ 8, 8 ], + #patch_arrangement = "linearized_YX", + #patch_arrangement = "linearized_XY", + + timestep = t0/rest, + simulation_time = Tsim, + + EM_boundary_conditions = [ + ['silver-muller'], + ['periodic'], + ], +) + +#LoadBalancing( +# every = 20, +# ) +# + +# We build a gaussian laser from scratch instead of using LaserGaussian2D +# The goal is to test the space_time_profile attribute +omega = 1. +a0 = 150. +waist = 2.0*l0 +Zr = omega * waist**2/2. +focus = [10.*l0, 5.*l0] + +amplitude = a0 / math.sqrt(2) +w = math.sqrt(1./(1.+(focus[0]/Zr)**2)) +invWaist2 = (w/waist)**2 +coeff = -omega * focus[0] * w**2 / (2.*Zr**2) +def By(y,t): + B = amplitude * w * math.exp( -invWaist2*(y-focus[1])**2 ) \ + * math.sin(omega*t - coeff*(y-focus[1])**2 + math.pi*0.5) + if t < t0: return t/t0 * B + else : return B +def Bz(y,t): + B = amplitude * w * math.exp( -invWaist2*(y-focus[1])**2 ) \ + * math.sin(omega*t - coeff*(y-focus[1])**2) + if t < t0: return t/t0 * B + else : return B + +Laser( + box_side = "xmin", + space_time_profile = [By, Bz] +) + +Species( + name = 'ion', + position_initialization = 'regular', + momentum_initialization = 'cold', + particles_per_cell = 16, + mass = 1836.0, + charge = 1.0, + number_density = trapezoidal(100.0,xvacuum=l0,xplateau=0.44*l0), + boundary_conditions = [ + ["reflective", "reflective"], + ["periodic", "periodic"], + ], +) + +Species( + name = 'eon', + position_initialization = 'regular', + momentum_initialization = 'mj', + particles_per_cell = 16, + mass = 1.0, + charge = -1.0, + number_density = trapezoidal(100.0,xvacuum=l0,xplateau=0.44*l0), + temperature = [0.001], + boundary_conditions = [ + ["reflective", "reflective"], + ["periodic", "periodic"], + ], + time_frozen = 0.1 +) + + + +globalEvery = int(rest/2.) + +DiagScalar(every=globalEvery) + +DiagProbe( + every = globalEvery, + number = [512, 1024], + origin = [0.*l0, 0.*l0], + corners = [ + [4.*l0, 0.*l0], + [0.*l0, 8.*l0] + ], + fields = ['Ex','Ey','Ez','Bx','By','Bz','Rho_ion','Rho_eon'] + ) + +DiagPerformances( + every = globalEvery, +) + diff --git a/radiation_pressure_acc_linearized.py b/radiation_pressure_acc_linearized.py new file mode 100644 index 0000000..668064a --- /dev/null +++ b/radiation_pressure_acc_linearized.py @@ -0,0 +1,124 @@ +# ---------------------------------------------------------------------------------------- +# SIMULATION PARAMETERS FOR THE PIC-CODE SMILEI +# ---------------------------------------------------------------------------------------- + +import math + +l0 = 2.0*math.pi # laser wavelength +t0 = l0 # optical cycle +Lsim = [6.*l0,10.*l0] # length of the simulation +Tsim = 10.*t0 # duration of the simulation +resx = 100. # nb of cells in on laser wavelength +rest = 150. # time of timestep in one optical cycle + +current_ncells_Y = Lsim[1] / (l0/resx) +target_ncells_Y = 1024. +target_cell_length_Y = (l0/resx*current_ncells_Y)/target_ncells_Y + +#target_cell_length_Y = l0/resx + +Main( + geometry = "2Dcartesian", + + interpolation_order = 2 , + + cell_length = [l0/resx,target_cell_length_Y], + grid_length = Lsim, + + number_of_patches = [ 8, 16 ], + patch_arrangement = "linearized_YX", + #patch_arrangement = "linearized_XY", + + timestep = t0/rest, + simulation_time = Tsim, + + EM_boundary_conditions = [ + ['silver-muller'], + ['periodic'], + ], +) + +#LoadBalancing( +# every = 20, +# ) +# + +# We build a gaussian laser from scratch instead of using LaserGaussian2D +# The goal is to test the space_time_profile attribute +omega = 1. +a0 = 150. +waist = 2.0*l0 +Zr = omega * waist**2/2. +focus = [10.*l0, 5.*l0] + +amplitude = a0 / math.sqrt(2) +w = math.sqrt(1./(1.+(focus[0]/Zr)**2)) +invWaist2 = (w/waist)**2 +coeff = -omega * focus[0] * w**2 / (2.*Zr**2) +def By(y,t): + B = amplitude * w * math.exp( -invWaist2*(y-focus[1])**2 ) \ + * math.sin(omega*t - coeff*(y-focus[1])**2 + math.pi*0.5) + if t < t0: return t/t0 * B + else : return B +def Bz(y,t): + B = amplitude * w * math.exp( -invWaist2*(y-focus[1])**2 ) \ + * math.sin(omega*t - coeff*(y-focus[1])**2) + if t < t0: return t/t0 * B + else : return B + +Laser( + box_side = "xmin", + space_time_profile = [By, Bz] +) + +Species( + name = 'ion', + position_initialization = 'regular', + momentum_initialization = 'cold', + particles_per_cell = 16, + mass = 1836.0, + charge = 1.0, + number_density = trapezoidal(100.0,xvacuum=l0,xplateau=0.44*l0), + boundary_conditions = [ + ["reflective", "reflective"], + ["periodic", "periodic"], + ], +) + +Species( + name = 'eon', + position_initialization = 'regular', + momentum_initialization = 'mj', + particles_per_cell = 16, + mass = 1.0, + charge = -1.0, + number_density = trapezoidal(100.0,xvacuum=l0,xplateau=0.44*l0), + temperature = [0.001], + boundary_conditions = [ + ["reflective", "reflective"], + ["periodic", "periodic"], + ], + time_frozen = 0.1 +) + + + +globalEvery = int(rest/2.) + +DiagScalar(every=globalEvery) + +DiagProbe( + every = globalEvery, + number = [512, 1024], + origin = [0.*l0, 0.*l0], + corners = [ + [4.*l0, 0.*l0], + [0.*l0, 8.*l0] + ], + fields = ['Ex','Ey','Ez','Bx','By','Bz','Rho_ion','Rho_eon'] + ) + + +DiagPerformances( + every = globalEvery, +) \ No newline at end of file diff --git a/search.html b/search.html index 055201e..8876769 100644 --- a/search.html +++ b/search.html @@ -1,111 +1,474 @@ - + - Search — No Errors Test Project documentation - + Search — Smilei tutorials X.Y documentation + - + + - - - - + + - - + + + - -
-
-
- +
- +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
-
- -
-
- +
+
- - - + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js index 2ba3b86..ad973e7 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["index"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.index":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:56},filenames:["index.rst"],objects:{},objnames:{},objtypes:{},terms:{index:0,modul:0,page:0,search:0},titles:["Welcome to No Errors Test Project\u2019s documentation!"],titleterms:{document:0,error:0,indic:0,project:0,tabl:0,test:0,welcom:0}}) \ No newline at end of file +Search.setIndex({docnames:["advanced","advanced_breit_wheeler","advanced_collisions","advanced_field_ionization","advanced_radiation_reaction","advanced_vtk","advanced_wakefield","advanced_wakefield_AMcylindrical","advanced_wakefield_electron_beam","advanced_wakefield_envelope","basics","basics_laser_vacuum","basics_setup","basics_thermal_plasma","basics_units","basics_weibel_twostream","index","perfs","perfs_parallel_computing","perfs_patch_arrangement","site"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.index":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:56},filenames:["advanced.rst","advanced_breit_wheeler.rst","advanced_collisions.rst","advanced_field_ionization.rst","advanced_radiation_reaction.rst","advanced_vtk.rst","advanced_wakefield.rst","advanced_wakefield_AMcylindrical.rst","advanced_wakefield_electron_beam.rst","advanced_wakefield_envelope.rst","basics.rst","basics_laser_vacuum.rst","basics_setup.rst","basics_thermal_plasma.rst","basics_units.rst","basics_weibel_twostream.rst","index.rst","perfs.rst","perfs_parallel_computing.rst","perfs_patch_arrangement.rst","site.rst"],objects:{},objnames:{},objtypes:{},terms:{"256x256":18,"2nd":19,"32x32":18,"3dcartesian":0,"3dcylindr":5,"3e12":7,"5e12":[7,9],"8x8":18,"case":[0,1,2,4,6,7,14,18,19],"catch":7,"default":[1,4,6,7,9,12,19],"export":[0,8,12,18,19],"final":[1,7,8,11,13],"function":[1,4,5,6,9,11,13,15,18],"import":[5,6,7,8,9,11,13,14,18],"j\u00fcttner":8,"long":[6,9],"new":[4,5,6,7,9,11,12,18],"short":[7,9,12],"static":18,"true":[7,8,9,12,13,14,15],"try":[5,6,7,8,9,11,14,15,18,19],"var":1,"while":[1,2,4,7,8,9,14],Are:[7,8],But:18,CGS:14,For:[1,2,3,4,5,6,7,8,9,12,14,15,18,19],Near:14,One:[7,12,18],PBS:12,That:[8,14],The:[1,2,3,4,5,6,7,8,9,10,11,12,14,15,18,19],Then:[5,7,11,14,18,19],There:[1,4,8,18],These:[1,4,7,8,9],Use:[1,4,6,8,9,11,12,13,15,18],Using:[4,7,8,9,14],With:[4,7,8,9,14,18],a_0:[1,4],abl:[5,7,8,9,18,19],about:[1,4,18,19],abov:[1,4,5,8,12,19],abs:[6,9],absolut:9,absorb:[6,19],absorpt:6,acceler:[0,4,7,18],accept:[7,8,14],access:[11,12,13,18],accomod:12,accord:[5,11,18],accordingli:[4,14,18],account:[1,2,9],accumul:18,accur:[1,4,5,7,8,9],accuraci:7,accustom:14,achiev:18,act:[7,9],action:[5,6,7,8,9,14],activ:[1,4,7,8,18,19],actual:1,adapt:[5,8],add:[6,7,8,9,19],adding:[4,7,8],addit:[4,7,8],additionn:18,address:[1,4,6,7,8,9,11,18],adjust:[7,8,9,18],adk:9,administr:12,adress:18,advanc:[3,7,9,14],advanced_beam_driven_wak:8,advancedtutorial1:4,advancedtutorial2:1,advic:18,affect:1,affin:18,after:[1,4,5,7,18],afterward:[5,9],again:[4,5,11,13,18,19],aim:4,algorithm:[1,4,18],align:6,all:[4,5,6,7,8,9,11,12,13,14,18,19],allow:[1,5,6,7,8,9,13,14,15],almost:[4,5,9,18],along:[6,7,9,19],alreadi:[2,5,9,12,14],also:[1,2,3,4,5,6,7,8,9,11,12,13,14,15,18],altern:19,although:[5,9],alwai:[5,9,14],amax:9,amcylindr:[0,7,8],among:16,amount:[5,8,12,18],amplitud:[1,4,11],analog:9,analys:[0,7,11,13,18],analysi:[0,2,3,4,7,8,9,10,11,13,18],analysis_tunnel_ionization_1d:3,analyz:1,angl:[6,7],angular:[0,14],ani:[2,3,7,11,12,14,15,18],anim:[4,5,7,9,15],animate_2d_average_chi:4,anoth:[4,7,8,9,15,18],anymor:7,apart:[5,7,8,9],appear:[7,9,11],append:5,appli:[1,4,5,18],applic:5,approach:[1,2,4,7,8],appropri:8,approxim:[1,4,7],arang:11,arbitrari:5,architectur:18,argument:[5,6,8,9,11],around:[1,4,6,7],arrai:[8,11],arrang:17,array_momentum:8,array_posit:8,arriv:[7,8,9],artefact:[6,7,8,9],artifact:[5,7],artist:5,asarrai:9,aspect:18,assign:18,associ:18,assum:[7,8,9,12],atomic_numb:9,attent:8,attract:8,attribut:5,autom:18,automat:[7,8,9,14,18],avail:[4,5,7,8,9,11,12,16,18,19],averag:[1,4,8,9,11,18],avoid:[5,7,8,9],awai:[5,8],axes:[5,8],axi:[5,7,8,9,14,19],azimuth:[0,5,6,8,9],b_y:15,b_z:[1,4],back:[6,7,8],background:[5,15],balanc:[1,2,4,6,11,13,17,19],ball:18,bar:[5,11],base:5,bash_profil:12,bashrc:12,basic:[12,14,18],bckgelectron:9,beam:[0,1,4,5,6,7,9],beam_2d:18,beam_relaxation123:2,beam_relaxation1:2,beam_relaxation2:2,beam_relaxation3:2,beam_relaxation456:2,beam_relaxation4:2,beam_relaxation5:2,beam_relaxation6:2,beam_relaxation789:2,beam_relaxation7:2,beam_relaxation8:2,beam_relaxation9:2,becaus:[1,3,4,5,7,8,14,18,19],becom:[2,7,18],been:[1,3,4,5,6,7,8,11,13,14,18],befor:[3,4,5,7,9,11,13,14,15,19],begin:13,behav:4,behavior:18,behind:9,being:[2,7],below:[1,2,4,9],benchmark:[2,5],benefici:19,best:[12,18],better:[5,19],between:[1,2,5,8,9,17],beyond:[0,7,8],bin:[0,1,4,6],binari:0,binomi:7,bit:6,black:5,bloc:19,block:[0,4,5,6,7,8,9,11,13,14,18],blue:5,blues_r:9,border:[5,7,8,9],both:[5,7,9,11,12,15,18],bottom:[1,5],boundari:[6,7,8,13,18],bourgeoi:[7,9],box:[1,4,6,7,8,9,11,13,15,17,19],breit:[0,14],briefli:[2,3],browser:12,brush:5,bubbl:9,build3d:5,build3d_interv:5,build:[1,6,12],built:[1,4,7,8,9],bunch:[0,9],buneman:[7,8],button:5,by_m:15,bzbtis3:9,c_over_omega0:8,cach:9,calcul:[9,11],call:[1,3,4,5,6,7,8,9,14,18],can:[1,2,3,4,5,6,7,8,9,11,12,13,14,15,18,19],cancel:14,cannot:18,capabl:2,carbon:3,care:[8,18],carefulli:5,carlo:[0,1],cartesian:[1,3,4,5,7,13],caus:[2,7,8,9],cdot:7,cell:[1,4,5,7,8,9,13,18,19],cell_length:19,center:9,central:5,certain:[7,8],cfl:10,chanc:1,chang:[0,1,4,5,6,7,8,9,11,14,15,17],characterist:7,charg:[2,4,8,9,14],che:8,check:[0,4,6,7,8,9,10,12,18],cherenkov:0,chi:4,choic:[5,7,12,14,18],choos:[1,5,9,12,14,16,18],chosen:[6,7,8,9],chunk:8,chunk_siz:[5,8],chunksiz:[5,8],clariti:5,classic:[0,7,8],clearli:[5,9,18],click:5,client:5,clone:12,close:[7,9,11],closer:15,cloud:5,clue:15,cluster:[5,10],cmap:[7,8,9,15,18],coars:[7,8,9,19],coarser:[5,9],code:[1,4,5,6,8,10,12,13,15,16,18,19],cold:2,collid:[1,4],collis:[0,1,14,18],color:[4,5,6,18,19],colormap:[4,5,7],column:[8,19],com:12,combin:[7,9,14],come:[5,8],command:[3,4,5,7,8,9,12,18],comment:[1,3,4,6,14],commun:[7,18],compar:[2,4,6,7,9,10,13,18],compare_2d_average_chi_radiation_model:4,compare_2d_average_energy_radiation_model:4,compare_2d_density_radiation_model:4,compare_2d_kinetic_energy_radiation_model:4,compare_energy_balance_landau:4,compare_energy_balance_landau_lifshitz:4,compare_energy_balance_radiation_model:4,comparison:[0,9,19],compat:[9,12],compens:6,compil:10,complet:[5,7,9,11,14],complex:[1,4,8,9,18],compon:[5,6,7],compos:[1,18],compromis:7,compton:4,compulsori:[1,4],comput:[1,3,4,5,7,8,9,12,14,17,19],concept:7,concern:18,conclud:13,conclus:5,condit:[6,7,8,9,10,13,18],configur:[0,10,12,17],consequ:[1,12],conserv:1,consid:[2,7,8,9,15,18],consider:[7,8,9],consist:8,consol:12,constant:[7,8,9,14],constantli:[6,9],constraint:8,construct:15,contain:[1,3,4,5,7,8,11,12,18,19],content:[0,11],context:18,continu:[1,4,7],contribut:8,control:1,convent:11,converg:8,convers:[0,14],convert:[4,7,8,9,14],coordin:[5,7,8,9],cope:[0,9],copi:[1,4,12],core:[4,5,6,12,18],corkscrew:5,corner:7,correct:[0,1,3,11,13,14,15,18],correctli:[5,6,9,11,13],correspond:[1,2,4,5,7,11,14],cost:[5,6,7,18],could:[5,7,8,9,14,18,19],counter:[1,4],courant:11,creat:[1,3,4,5,6,7,8,9,11,12,18],creation:0,critic:14,cumul:18,curl:12,current:[4,7,12,15],current_ncells_i:19,currentfilt:7,cursor:5,curv:19,custom:[5,8],cycl:14,cylindr:[0,5,6,8,9],damp:[7,8],data:[0,3,4,8,9,13,18],data_log:[13,15],databas:1,davoin:[7,9],deby:[13,14],decai:[1,7,8],deceler:8,decid:1,decom:7,decompos:[4,5,7],decomposit:[0,6,9,18],decreas:[7,8],dedic:[5,7],deduc:14,defin:[1,3,4,5,7,8,9,11,12,13,14,18],definit:[5,7,9,14],delta:[11,13],demand:5,demi:7,denot:8,dens:[6,7,9],densiti:[1,4,5,6,7,8,9,13,14,15,18],density_normalized_unit:14,depend:[2,7,12,14],depth:[12,15],deriv:[4,8,9,14],describ:[2,4,5,6,7,9,14],descript:2,design:[1,4,8],desir:[5,7],desktop:5,detail:[5,6,7,8,9,11,12,14,18],determin:[1,4],diag:[11,18],diagfield:1,diagnost:[0,4,5,6,7,9,10,14,15,18,19],diagparticlebin:[1,8],diagperform:18,diagscalar:1,diagtrackparticl:8,did:[11,18],differ:[1,2,4,5,6,7,9,12,14,15,18],difficult:[5,18],difficulti:18,dimens:7,direct:[1,4,5,6,7,8,9,19],directli:[4,12,14],directori:[1,4,6,7,11,12,18],discard:7,disclaim:[5,6],discuss:[9,19],disk:18,dispers:[7,9],displai:[11,14],distanc:[7,8,9,15],distinct:18,distinguish:15,distribut:[1,2,4,8,15,17],diverg:[1,7,8],divid:[1,18,19],divis:19,dlb:19,doc:12,document:[1,5,6,9,10,11,14,16],doe:[1,3,4,6,7,8,9,11,14,18,19],doing:18,domain:[1,4,6,7,8,9,18],don:8,done:[3,5,6,7,8,9,18],dopant:9,dopant_n_concentr:9,down:[2,5,7,12],download:[1,3,4,5,6,7,8,9,11,12,13,14,15,18],draw:5,drift:[2,9],drive:8,driven:[0,7],driver:8,drop:4,dtran:5,due:[1,2,4,9,18],durat:4,dure:[1,4,5,8,9,14,15,16],dynam:[2,6,7,8,12,13,18,19],e_0:7,e_i:[1,4],e_r:14,e_x:[13,15],e_z:15,each:[1,2,4,5,6,7,8,9,11,12,18,19],earlier:11,earn:18,easi:[8,14],easili:[7,8,9,14],editor:[5,6,7,8,9],effect:[0,1,4,7,8,10,18],effici:[1,4,9,12],either:[9,12],electr:[0,1,4,5,7,8,14],electromagnet:[5,7,8,9,11,14,15,18],electron:[0,2,4,5,6,7,9,13,14,15],electron_bunch:8,electronbunch:8,electrostat:[13,15],element:18,em_boundary_condit:[7,8],emiss:[1,5,14],emit:[1,4,5],emitt:8,empti:[6,9,18],enabl:[1,4],encount:2,end:[4,5,6,7,11,13,18,19],energi:[1,2,4,6,8,9,11,13,14,15],enforc:19,engin:[1,4],enhanc:18,enorm:5,enough:[8,9,13],ensur:18,enter:[4,5,6,7,8,9,11],env_:9,env_a:9,env_a_ab:9,env_chi:9,env_e_ab:9,envelop:[0,11],envelope_:9,environ:[10,18],eps:3,epsilon_0:15,equal:[1,8,9,12,13,14,15,18,19],equat:[3,7,9,14,18],equilibrium:2,equival:[9,14],error:[8,11,13],especi:7,essenti:[5,8,9],estim:4,etc:[5,8,14,15],evalu:6,even:[1,5,6,14,18],event:1,eventu:6,everi:[1,4,18,19],everyth:[5,8],evolut:[1,4,7,8,9,11,13,14,15,18],evolv:[1,4,7,9,13],exactli:[5,11],exampl:[2,5,7,8,9,12,18],exce:9,exceedingli:8,except:[5,18],excess:[2,18],exchang:18,excit:[0,7],exclus:18,execut:[1,4,5,11,12,18],exercic:[1,4],exercis:7,exhibit:18,expans:14,expeci:9,expect:2,expens:[1,4,18],experi:5,expert:5,explain:[5,8,9,11,14,15,18],explicit:[9,13],explicit_reduced_dispers:9,explicitli:[7,18],exploit:1,explor:[5,7,11,14,18],exponenti:9,export_vtk_namelist:5,extend:[4,13],extens:[4,14],extern:[1,4],extract:[1,4,5,8,9,15],extrem:[1,4],extrema:6,f_final:13,f_initi:13,face:6,facilit:12,fact:4,factor:[3,4,8,14],fair:19,fals:[4,8,18],familiar:[5,9,11,13,14,15,18],faster:[12,18],favorit:[5,6,7,8,9,12],featur:[6,7,8,9,18],feed:18,feel:[5,6],feet:14,few:[5,7,8,9,12,18],fictiou:[7,8],field0:[5,7],field0_ezeyex:5,field0_ezeyex_:5,field:[0,1,4,7,10,14,15,18,19],figur:[1,3,4,5,6,7,8,9,14],file:[0,1,4,5,6,7,8,9,10,12,18,19],fill:[7,8],filter:[5,7,8],find:[4,5,7,8,15,18],finer:[7,8,9],finish:18,finit:[7,9],firefox:12,first:[0,1,2,3,5,7,8,9,11,12,13,14,15,18,19],fit:8,five:2,fix:6,flag:8,fly:[1,4],focal:9,focu:[1,4,9,18],focus:[1,9],fokker:4,folder:[2,5,11,12],follow:[1,4,6,7,8,9,11,12,14,18,19],forc:[5,7,8,9],form:8,format:[0,9],found:[7,8,9,18],fourier:7,fourth:0,fraction:[6,9],frame:7,free:[5,7,13],frequenc:[0,7,9,14,15],frequent:[5,6],friedrich:11,from:[1,2,4,5,6,7,8,9,11,12,14,18],frozen:[1,4,9,15],full:[1,4,9,18],fulli:[1,4],further:[7,9],furthermor:[5,8,9],futur:5,fwhm:[1,4],gain:[6,7],gamma:4,gas:9,gauss:5,gaussian:[1,3,4,5,8,11],gener:[1,2,3,4,5,7,8,9,11,12,13,14,18],geometri:[0,3,6,8,9,13],get:[1,4,10,12,13,14,15,18,19],getavailabletimestep:[8,9],getdata:[3,9],gettimestep:13,gev:[1,4],git:12,github:[1,4,12],give:[2,3,4,5,6,7,8,9,14],given:[1,4,5,6,7,8,12,14,18],global:[4,18],goal:[1,3,4,5,6,7,8,9,11,13,14,15,18,19],going:[3,11,13,15,18],good:[5,7,18],granular:18,graph:1,graphic:5,grassi:15,greater:[7,8],grid:[1,5,6,7,8,9,18],grid_length:6,group:5,grow:18,growth:[7,15],had:[5,8],half:[1,4,7],hand:7,handl:[6,18],happen:[3,5,7,8,14,18,19],happi:[1,3,4,5,6,7,8,9,10,11,12,14,15,16,18],hard:18,has:[1,2,3,4,5,7,8,9,11,12,14,18,19],have:[1,3,4,5,6,7,8,9,11,12,13,14,15,18],haven:7,hdf5:12,heat:[7,13],heavi:[5,6],help:[3,5,7,8,11,12],henc:9,here:[1,2,4,6,7,8,9,11,12,14,18,19],high:[4,6,7,9,14],higher:[3,4,9,19],highli:5,highlight:[5,6,19],hilbert:19,hilbertian:19,hindex:18,hint:6,histogram:8,home:12,hot:9,hour:12,how:[1,4,5,7,8,9,11,14,16,18,19],howev:[7,8,9,14,18],html:[1,4,12],http:[1,4,12],huge:5,hundr:6,hydrogen:9,icon:5,idea:[1,18],ideal:[7,12],ident:5,ignor:14,ik_0c:9,illustr:[2,18],imag:5,imagin:19,imbal:[6,13,17],immobil:[7,8],impact:[0,18],imperfect:[7,8],implement:[4,14],impli:7,importantli:14,improv:[1,5,6,7,8],inch:14,includ:[1,2,4,7,8,12,14],increas:[1,4,6,7,8,9,11,13,19],increasingli:[7,18],inde:[5,7,14,18],indefinit:2,independ:[7,13,14,18],index:12,indic:12,induc:6,ineffici:[7,8],inelast:0,infinit:13,influenc:5,info:10,inform:[1,4,5,9,11,18],inher:18,init:8,initi:[0,1,2,4,6,7,9,11,13,14,15,18,19],inject:[1,4,7,8,9],input:[0,1,2,4,5,6,7,8,9,10,12,16,18,19],insid:[7,8,9,12,18],instabl:10,instal:[3,5,12,14],instanc:[1,4,6,12,18],instead:[1,5,7,8,9,12,14,18,19],instruct:[5,18],integ:1,integr:9,intel:12,intellig:19,intens:[3,5,6,7,8,9,14],interact:[1,2,4,7,9,12],interest:[2,5,6,7,8,14,15],interf:6,interior:9,intermediari:18,internet:12,interpol:[7,9],interv:[5,14],introduc:[7,9,17],introduct:[5,6,7,8,9,18],invari:[3,14],invers:[4,15],involv:[9,14],ion:[0,2,8,9,13,14,15],ioniz:[0,7,14],ionization_electron:9,ionization_equilibrium:2,ionization_equilibriumau:2,ionization_equilibriumh:2,ionization_equilibriumzn:2,ionization_model:9,ionization_multipl:2,ionization_multipleal1:2,ionization_multipleal2:2,ionization_multipleau1:2,ionization_multipleau2:2,ionization_multiplec1:2,ionization_multiplec2:2,ionization_multiplesn1:2,ionization_multiplesn2:2,ionization_multiplezn1:2,ionization_multiplezn2:2,ionization_r:2,ionization_rate1:2,ionization_rate2:2,ionization_rate3:2,ionization_stopping_pow:2,ionization_stopping_power1:2,ionization_stopping_power2:2,ionization_stopping_power3:2,ionization_stopping_power4:2,ipython:[1,3,4,11,13,15,18],irradi:[3,14],isotrop:0,item:[4,11],iter:[1,4,5,6,8,9],iterparticl:8,its:[1,4,5,6,7,8,9,11,14,16,18],itself:8,j_z:15,job:[5,6,12],journal:[7,9],just:[5,7,8,9,11,14,15,18],keep:[5,6,7,8,9,18],kev:2,keyword:11,kind:[5,6,8,13],kinet:[1,4,14],know:[6,8,14],knowledg:12,known:[4,8],l_r:14,l_x:15,label:[9,11,13],laguerr:5,lambda:[1,4],lambda_0:9,lambda_:13,landau:[0,1],languag:11,laptop:6,larg:[5,7,8,18],larger:[5,7,8,9,18,19],laser:[0,1,2,3,4,5,7,8,10,14],laser_profil:11,laser_propagation_2d:11,laser_wavelength_um:14,laserenvelop:9,lasergaussian2d:[11,14],lasergaussianam:7,last:[5,7,8,9,11,13,14],later:[1,9],latex:3,latter:9,launch:[7,12,18],layer:[0,3],lead:[15,19],learn:[1,5,7,8,16,19],least:[4,5,6,7,9],left:[1,4,5],legend:9,length:[5,6,7,9,13,14],length_normalized_unit:14,length_si:14,less:[4,7,8],let:[1,4,5,7,8,9,11,13,14,15,18],level:[7,8,9,13,18],lewi:11,librari:[4,5,12],lifshitz:[0,1],light:[5,7,14],lightspe:14,like:[0,1,6,7,8,9,14,18,19],limit:[8,18],line:[1,3,4,8,11,12,14,19],linear:[6,7,8,9,15,19],linearized_xi:19,linearized_yx:19,linearli:[1,3,4,7],link:16,list:[1,2,4,5,8,11,18],load:[1,6,15,17,19],loadbalanc:[6,18,19],loadlevel:12,local:[1,3,4,11,13,14,15,18],locat:[1,2,4,18,19],log:[3,4,8,11,13,15,18],login:5,longitudin:[5,7,8,9],look:[1,3,4,5,6,7,13,15,18,19],loop:[8,11,18],lose:[7,8],loss:[1,4],lot:5,low:[1,2,4,7],lower:[5,7,8,9],lsim:19,ltran:5,m_e:[14,15],m_ec:14,machin:[3,5,10,18],macro:[0,1,4,7,8,9],made:[1,4,5,9,18],magnet:[1,4,7,8,15],magnitud:18,mai:[1,2,3,4,5,7,8,11,12,13,14,18,19],main:[6,7,8,9,11,12,14,18,19],make:[1,2,3,5,6,9,11,12,14,15,18,19],manag:[5,8,18],mani:[5,8,12,18],manifest:7,manipul:8,manual:[4,6],map:[1,4,18],mark:14,mass:[1,7,14],match:0,materi:2,math:14,mathbf:7,mathemat:[1,4],mathrm:[1,4],matplotlib:[4,9,11],maxim:[1,4],maximum:[1,4,8,18,19],maxwel:[7,8,9,14,18],maxwell_solv:7,maxwellian:0,maxwellianization1:2,mayb:18,mean:[4,8,9,11,14,15,18],meant:5,measur:2,medium:[7,8],memori:[12,17],mention:[5,14],menu:[5,16],mesh:[7,8,9],messag:11,method:[4,5,8,9,14],mev:[2,8],middl:[1,4,5],might:18,minim:[1,4,7,9,18],minimum:[1,5,18],minimum_chi_continu:[1,4],minimum_chi_discontinu:[1,4],minu:13,minut:[5,7,8,9],mislead:5,miss:5,mitig:[7,8,9],mixtur:9,mkdir:12,mode:[0,3,5,6,8,9,10,12,13,14,15,19],model:[0,1,7],modest:18,modifi:[1,4,18],modul:[0,1,3,4,7,8,11,14],moment:[4,5,14],momenta:8,momentum:[5,8,9],momentum_initi:8,monitor:[2,18],mont:[0,1],more:[1,4,5,6,7,8,9,10,14,15,18,19],moreov:19,most:[1,4,12,14,18],mostli:6,motion:7,mous:5,mov:18,move:[5,6,7,8,9,18],moving_x:5,movingwindow:[6,9],mpi:[4,5,7,8,9,12,18,19],mpi_thread_multipl:12,mpirun:[12,18,19],much:[6,7,8,9],muller:[6,7,8],multi:[1,4,12],multidimension:1,multiphoton:[0,14],multiphoton_breit_wheel:1,multiphoton_breit_wheeler_sampl:1,multiphotonbreitwheel:1,multipl:[0,5,9,14],multipli:[3,8,9],multiplot:[9,10,11,15],multislid:[9,13,15],must:[5,6,7,9,14,18,19],my_input:12,mysimul:12,n0_si:14,n_0:[14,15],n_b:[1,4],n_c:[1,4,14],n_r:14,nabla:7,name:[1,3,5,8,9],namelist:[3,5,6,7,8,9,10,11,18],natur:14,naturrali:18,ncrit:8,necess:13,necessari:[5,7,8,11,12,14,18],necessarili:18,need:[1,3,4,5,6,7,8,9,12,13,14,18,19],neg:[7,8],neglect:0,network:18,neutral:[3,15],newli:9,next:[4,7,18],niel:0,nitrogen5plu:9,nitrogen:9,node:[1,5,12,18],nois:[7,8,9],noisi:[7,8],non:[1,2,5,6,7,8,9,15,18],none:[1,4],nonetheless:[1,4],nonlinear:[0,9],nor:8,normal:[1,3,4,6,7,8,9,10,11,15],note:[3,5,7,8,9,11,13,14],noth:[5,18,19],notic:6,now:[1,4,5,6,7,8,9,11,13,14,15,18,19],npart:8,nparticl:8,ntot_:1,ntot_electron:1,ntot_photon:1,ntot_positron:1,numa:18,number:[1,4,5,6,7,8,9,12,14,18,19],number_of_am:7,number_of_particl:18,number_of_patch:[18,19],number_of_pml_cel:[7,8],numer:[0,6,8,13],numpi:[8,9,11],object:[4,5,11],observ:[1,4,6,7,8,9,13,15,18,19],obtain:[0,1,3,4,7,8,9,10,11,13,14,18],obvious:18,occas:5,occupi:18,occur:[1,2,9],occurr:9,offer:18,often:[5,8,9,18],omega:14,omega_:[13,15],omega_r:[1,4,14],omega_r_si:14,omit:[7,8,9],omp_num_thread:[12,18,19],omp_proc_bind:12,omp_schedul:[12,18],onc:[8,11,12],one:[1,2,3,4,5,6,7,8,9,12,14,18,19],ones:[5,7,11],onli:[3,4,5,6,7,8,9,14,18,19],open:[1,3,4,5,6,7,8,9,11,12,13,14,15,18],openmp:[4,7,8,9,12,18],oper:[4,5,14,18],optic:14,optim:[6,18],option:[1,4,5,6,8,9,12,15,18,19],order:[1,4,5,6,7,9,11,12,18],origin:[5,7,8],oscil:[0,7,9],other:[1,2,4,5,6,7,8,9,14,18,19],otherwis:12,our:[1,5,7,8,9,14],out:[1,3,4,5,14,18],outlin:5,output:[1,4,5,7,8,9,11,12,13,14,18],over:[6,8,9,18],overdens:14,overhead:[18,19],overlai:11,own:[3,4,12,18,19],p_x:15,packag:[11,12,13,14],page:[4,6,11,12,14,18],pai:8,painter:5,pair:[0,14],palett:5,parallel:[4,5,7,8,12,17,19],paramat:19,paramet:[1,3,4,7,8,14],paraview:5,part:[5,9,14,18,19],partial_t:[7,9],particl:[0,1,4,6,7,9,13,18,19],particle_chunk:8,particlebin:[4,6,8,10,15,18],particular:[5,14,15],pass:[2,7],patch:[1,3,4,17,18],patch_arrang:19,path:[1,3,4,7,8,9,11,12,13,14,15,18],path_to_smilei:1,path_to_some_t:4,pattern:19,peak:[9,14],per:[1,4,7,8,9,12,18,19],percent:9,perfect:[6,8],perfectli:0,perform:[1,4,5,6,7,8,12,18],period:[1,4,7,8,13],permit:19,person:5,perturb:15,phase:[6,8,15],phenomena:[5,7,8,9],phenomenon:[7,8,9,19],photon:[0,4],phs:15,phy:15,physic:[0,10,17],pic:[11,13,14,16,18],pick:[5,6],picosecond:2,pictur:5,piec:[18,19],pint:[7,8,9,14],place:[1,5],plai:[4,5],planck:4,plane:[1,4,7,8,9],plasma:[0,2,6,7,9,10,14,15,18,19],plasmaelectron:8,plot:[2,4,5,7,8,9,10,13,14,15,18],plt:9,pml:[7,8],point:[0,1,4,7,11],poisson:8,polar:[1,3,4,7],pollut:12,ponderomot:[5,8],ponderomotive_bori:9,ponderomotive_borisbtis3:9,pool:18,poor:18,popul:[2,9],posit:[5,7,8,9],position_initi:8,positron:[0,4],possibl:[1,4,5,6,7,8,9,12,14],post:[1,10,12,14,16],postprocess:[5,10],potenti:0,power:[0,7,9,18,19],ppn:12,practic:14,pre:14,preced:18,precis:7,prefer:14,preferr:8,prepar:[0,1,3,4,10],presenc:[3,7],present:[0,3,4,5,9,14],press:11,pretens:5,prevent:18,previou:[4,5,7,9,11,16,18],principl:[5,8],print:[1,8],privileg:18,probabl:[6,8],probe0:[7,8,9,14],probe1:[5,6,7,8,9],probe:[5,6,7,8,9,14,19],problem:[8,13,14],procedur:8,process:[0,4,5,7,8,9,10,12,14,16,17,19],processor:[3,12],produc:[1,18],product:[1,4],profil:[1,3,4,5,7,8,9,10,18],project:1,projectil:2,prompt:[3,18],propag:[1,4,5,6,7,8,9,10,14],proper:[5,6],properti:[1,4],proport:[5,7,8,9],propos:19,protocol:18,provid:[2,3,9,11,12,13,14,15,16,18],pty:12,puls:[1,3,5,6,7,8,9,11,14],pure:[7,9,18],purpl:4,purpos:[1,4,7],push:[5,7,8,19],pusher:[7,9],put:14,pvti:5,pylab:11,pyplot:9,python:[1,3,4,5,7,8,9,11,12,14],q_bunch:8,q_pc:8,qed:[1,4],qsub:12,qualit:5,qualiti:[3,5],quantifi:9,quantit:5,quantiti:[1,4,6,7,8,9,11,13,14,18],quantum:[1,4],question:[4,14],queue:12,quick:[9,13,18],quicker:[5,9],quickli:8,radi:[1,4],radial:[7,8],radiat:[0,14],radiation_corrected_landau_lifshitz:4,radiation_landau_lifshitz:4,radiation_model:[1,4],radiation_mont:4,radiation_monte_carlo:4,radiation_niel:4,radiation_photon_gamma_threshold:1,radiation_photon_sampl:1,radiation_photon_speci:1,radiation_pressure_2d:14,radiation_pressure_acc_hilbert:19,radiation_pressure_acc_linear:19,radiationreact:[1,4],radiu:18,rang:5,rapidli:[1,4],rate:[0,1,3,4,9,15],rather:6,ratio:2,raw:4,reach:[4,9],reaction:0,read:[1,4,8,11,14],readabl:9,readi:[12,13],real:[7,14],realist:[5,8,17,19],reason:[2,5,6,7,8,9,18],receiv:[1,8],recombin:0,recommand:19,recommend:[4,5,7,9,12,18],reconstruct:7,recreat:9,rectangular:2,redefin:14,reduc:[0,5,6,7,8,12,14],refer:[0,6,7,9,14],reference_angular_frequency_si:[3,7,8,9,14],refin:18,reflect:[6,7,8],reflexion:6,regard:[4,18],regim:[4,8,9],region:[7,8,18,19],rel:[5,6],relat:[6,8,14,15],relativist:[0,7,9],relativistic_field_initi:8,relativistic_poisson_max_error:8,relativistic_poisson_max_iter:8,relax:0,releas:9,relev:[5,6,7,8,9,12,19],reli:19,remain:[7,8],rememb:[6,7,8,9,12,13,14],remot:5,remov:[7,9],render:0,replac:[12,19],replic:19,report:18,repres:[5,7,8,9,11,14,18,19],represent:0,reproduc:7,request:[1,12,18],requir:[2,4,5,7,8,9,14,18,19],rerun:8,rescal:5,reserv:12,resolut:[2,5,7,10,19],resolv:[2,9,13],resourc:5,respect:[1,6,7,8],ressourc:18,rest:[1,9],result:[0,1,2,3,4,7,8,9,11,13,14,15,19],resx:19,retain:7,rev:15,rho:[6,7,8,9],rho_:7,rho_e:7,rho_electronfromion:9,rho_eon1:15,rho_eon2:15,rho_eon:[13,14],rho_i:7,rho_ion:13,right:[1,4],rise:1,rms:8,rotat:5,row:8,rule:18,run:[0,1,2,4,6,7,8,9,10,18,19],s_normal:14,s_si:14,sake:5,same:[1,4,5,7,8,9,11,12,14,18,19],sampl:5,satisfi:8,satur:[5,7,15],save:[1,4,5,7,18],sawtooth:8,scalar:[1,4,10,13,14,15],scale:[3,6,9,12,14],scan:4,scatter:4,scene:5,schedul:[12,18],scheme:9,scientif:5,scipi:[5,8,14],scope:4,screen:[5,11],script:[1,3,4,5,8,12],scroll:5,search:5,second:[0,2,7,8],section:[4,14,18],see:[1,3,4,5,6,7,8,9,11,12,14,18],seem:[5,18],seen:[3,4,8,14,18],seismic:[7,8,9],select:[4,5,7,8,9],self:[8,9],sensit:9,separ:[9,11],sequenc:18,server:5,session:[12,13],set:[1,3,4,5,6,7,8,9,12,14,17,18],setup:[0,1,4,6,8,9,10,17],sever:[1,2,4,6,12,18,19],shape:[1,4,5,7,8,9,15,18,19],share:[5,12,18,19],sharp:7,shift:[5,6,9],shorter:1,should:[1,4,5,7,8,9,11,12,14,18],show:[2,7,19],show_2d_average_chi:[1,4],show_2d_average_energi:[1,4],show_2d_dens:[1,4],show_2d_field:[1,4],show_2d_kinetic_energi:4,show_energy_bal:[1,4],show_energy_spectrum:1,show_particle_numb:1,shown:[7,8,9],side:[1,4,11],silver:[6,7,8],sim:4,simeq:[1,4],similar:[1,5,7,9,18],similarli:[4,8,14],simpl:19,simplest:7,simpli:4,simplic:5,simplifi:[14,19],simul:[0,6,8,9,10,17,18],simulation_tim:11,simulation_to_analys:3,sinc:[1,4,5,6,7,8,9,14],singl:[1,3,7,18],situat:[7,8,9,18,19],size:[1,4,7,8,9,13,15,18,19],skin:15,slab:[14,19],slice:8,slide:[5,6,7,8,9,11,13,14,18],slightli:[18,19],slow:[2,5,7,19],slurm:12,small:[5,7,8,9,18],smaller:[7,8,9],smilei:[1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,19],smilei_r:[15,18],smilei_test:[3,11,12,13,14,15,18],smileip:[1,4,12],smoothli:[5,6],socket:[12,18],softwar:5,solid:5,solut:[4,7,18],solve_rate_eq:3,solver:[7,8,9],some:[1,3,4,5,6,7,8,9,11,12,14,18,19],someth:19,sometim:[8,18],sort:8,sourc:[5,16],space:[4,5,6,7,8,11,15],spatial:[3,10,19],speci:[0,2,4,5,7,8,9,13,15],species_nam:[5,8],specif:[1,4,6,7],specifi:[1,3,4,5,7,8,9,14,18],spectacular:6,spectra:[1,13],spectrum:[8,9,13],speed:[5,6,7,9,14,18,19],speedup:18,spend:9,spent:[8,18],sphinx:12,split:[17,19],spot:11,spread:[2,8],spuriou:7,sqrt:[8,15],squar:19,srun:12,stabil:9,standard:9,standart:4,start:[1,2,4,5,6,7,8,9,11,14,18,19],state:[2,9],statist:1,step:[0,3,11,12,13,14,15,18],still:[5,7,18,19],stochast:0,stop:[0,19],stopping_power123:2,stopping_power1:2,stopping_power2:2,stopping_power3:2,store:[5,9],str:8,strategi:5,streak:15,stream:10,strength:[1,4],strict:9,string:1,strong:9,stronger:7,strongli:12,studi:[0,5,12,14,19],submiss:12,submit:[5,6,12],subsampl:5,subsequ:4,subset:5,substanti:7,substitut:9,subtleti:0,succeed:12,success:18,suggest:[6,18],suit:8,suitabl:8,sum:8,summari:18,supercomput:[12,18],superpos:5,support:12,sure:[5,6,18,19],symbol:5,symmetr:7,symmetri:7,sync:18,synchron:[18,19],synchrotron:0,syntax:16,synthax:5,system:[5,7,12,14],t_r:14,tab:11,tabl:[1,4],table_path:[1,4],tabul:[1,4],tail:8,take:[4,5,8,9,13,14,15],taken:[1,9,18],talk:18,tar:[1,4],target_cell_length_i:19,target_ncells_i:19,task:[4,18],tast:5,technic:18,techniqu:[5,7,9],tell:[11,15],temperatur:0,temperature_isotrop:2,temperature_isotropization1:2,temperature_isotropization2:2,tempor:[1,3,4,9,15],ten:9,term:14,termin:[1,4,11,12,15],terribl:19,test:[1,2,3,5,7,10,13,14,15,18,19],textrm:14,than:[4,7,8,9,18,19],thank:[1,4],thei:[1,4,5,7,8,11,13,15,18],them:[1,4,5,6,7,8,9,14,15,19],theoret:[2,3,11],theori:10,therefor:[1,3,4,5,7,8,9,14],thermal:[0,10],thermal_plasma_1d:13,thermalisation_ei123:2,thermalisation_ei1:2,thermalisation_ei2:2,thermalisation_ei3:2,theta:7,thi:[1,3,4,5,6,7,8,9,11,12,13,14,15,16,18,19],thin:[3,19],thing:[1,4],think:[4,9],third:0,those:[5,7,8,9,14,15,18],though:[5,18],thread:[4,7,8,9,12,18,19],three:[1,2,7,8,18],threshold:[1,4,9],through:[2,5,7,8,9,11,18],throughout:7,thu:[2,3,7,8,9,19],tild:9,time:[1,2,3,4,5,6,7,8,9,11,12,13,14,15,18,19],time_envelop:[9,11],time_frozen:8,timer:[18,19],timer_particl:[6,18],timer_tot:6,timescal:7,timestep:[1,2,4,7,8,9,11,13,14],tip:10,tis3:[7,9],togeth:[13,18],too:[1,4,5,6,7,8,9,18],tool:[3,10,15,16],top:[1,5,16],topic:7,torqu:12,total:[1,4,8,11,12,13,15],total_weight:8,tovtk:5,toward:[6,7,8,9],track:[0,4,5],track_part:5,trackparticl:[5,7,8],trackparticles_electron_xyzpxpypzid:5,trackparticles_electron_xyzpxpypzid_trajectory_:5,trail:9,train:16,trajectori:[4,5],transfer:5,transit:7,transpar:9,transport:8,transvers:[6,7,8,9,14],trap:[6,9],travers:18,treat:9,trial:8,trick:5,tricki:9,trigger:[1,4,7,8,14],trigonometri:5,tst2d_electron_laser_collis:[1,4],tstep:11,tstop:11,tune:[6,17],tunnel:[3,9],tunnel_envelope_averag:9,tunnel_ionization_1d:3,turn:[1,11,13],tutori:[0,3,5,8,9,10,12,13,14,15,16,17,19],twice:1,two:[1,2,5,7,8,9,10,11,12,14,18],two_stream_1d:15,txt:[4,18],type:[1,11,18],typic:[7,8,12,18,19],typicallyl:18,ubal:[1,11,13],uel:15,uelm:[1,11,15],uexp:1,ukin:[1,14],ukin_:1,ukin_electron:[1,4],ukin_photon:1,ukin_positron:1,ultra:[6,9],uncom:[1,4,14],under:[3,5,6,7,9,14],underdens:9,undergo:[1,4],understand:[1,4,5,7,11,12,18],unfortun:7,unfortunatli:19,uniform:[14,18],unit:[0,3,10,11,12,15,16,18],univers:7,unix:12,unnecessari:5,unphys:[7,8],until:[4,18],upper:5,ups:[7,9,14],urad:1,url:12,use:[1,3,4,5,6,7,8,9,11,12,13,14,15,16,18,19],use_btis3_interpol:[7,9],used:[1,3,4,5,6,7,8,9,10,16,18],useful:[4,8,9,14],user:[5,7,8],uses:[1,4,7,8,9,18],using:[1,3,4,5,6,7,8,9,10,12,14,15,18],usual:[3,6,14,18],utot:[1,11,13],v_0:15,v_x:18,vacuum:[8,9,10],valid:4,valu:[1,2,4,5,8,9,11,14,19],varepsilon_0:14,vari:[2,8],variabl:[3,5,6,7,9,12,14,18],variat:[6,9],variou:[2,18,19],vector:[0,6],veloc:[2,6,15,18],verbos:4,veri:[7,8,9,18],verifi:[14,18],versa:14,version:[4,5,16],via:[1,4,6,9],vice:14,view:[5,15],virtual:7,visibl:[5,7,8],visual:[0,1,4,6,7,8,9,18],vlasov:14,vmax:[6,7,8,9,13,15],vmin:[6,7,8,9,13,15,18],volum:0,vsym:[11,15],vtk:0,vtp:5,wai:[4,5,7,8,9,14,18],waist:[1,8],wait:[18,19],wake:[6,7,8,9],wakefield:[0,7,8],walltim:12,want:[1,4,5,7,8,9,12,14,19],warn:[5,11],wast:5,wave:[1,4,6,7,8,9,14],waveform:8,wavelength:[1,4,9,14,15],wavenumb:15,weakli:8,web:12,webpag:12,websit:[2,4,9,16],weibel:10,weibel_1d:15,weight:[1,2,8],weight_chi:1,weight_ekin:1,weight_to_pc:8,well:[2,3,4,9,12],were:[7,11,16],what:[3,4,5,7,8,9,10,11,13,15,18],whatev:18,wheeler:[0,14],when:[1,2,4,5,7,8,9,11,12,14,15,18,19],where:[1,4,5,7,8,11,14,18,19],which:[1,2,4,6,7,8,9,13,14,15,18,19],white:5,whole:[7,15,18],whose:[7,8,9],why:[0,6,14],width:[1,4],window:[5,6,7,8,9,11,18],wish:1,wit:0,within:[5,19],without:[2,6,7,8,9,14,18],withtout:18,won:[7,9],word:[5,6],work:[1,4,5,9,14,18,19],workshop:16,workstat:12,world:14,would:[1,4,5,7,8,9,12,14,19],write:18,written:[1,7,11,12,14],xlabel:9,xmax:15,xmin:[9,11,15],xvf:4,yee:7,yield:[1,7,14],ylabel:9,ymax:6,ymin:6,you:[1,2,3,4,5,6,7,8,9,11,12,13,14,15,18,19],your:[0,2,3,4,6,7,8,9,10,13,14,15,18,19],zero:[6,9],zone:8,zoom:5},titles:["Advanced","Multiphoton Breit-Wheeler pair creation process","Binary collisions and impact ionization","Field ionization","Synchrotron-like radiation reaction","Export to VTK and 3D visualization","2D laser wakefield acceleration","Azimuthal-mode-decomposition cylindrical geometry","Field initialization for a relativistic electron bunch","Envelope model for laser wakefield acceleration","PIC basics","Laser Propagation in vacuum","Setup","Thermal plasma","Units","Weibel and two-stream instabilities","Smilei tutorials","Performances","Parallel computing","Patch arrangement","Index"],titleterms:{"3dcartesian":5,"case":[5,8,9],"export":5,The:13,acceler:[6,8,9],advanc:0,amcylindr:5,analys:3,analysi:[1,15],angular:3,arrang:19,azimuth:7,balanc:18,basic:[10,11],beam:[2,8],between:18,beyond:1,bin:8,binari:2,block:1,box:18,breit:1,bunch:8,carlo:4,cfl:11,chang:[3,19],check:[3,11,13,14,15],cherenkov:[7,9],classic:4,cluster:12,code:14,collis:2,compar:11,comparison:4,compil:12,comput:18,condit:11,configur:[1,3,4,5,6,7,8,9,11,13,14,15,18,19],content:[1,4],convers:[7,8,9],cope:7,correct:4,creation:1,cylindr:7,data:5,decomposit:7,diagnost:[1,8,11,13],distribut:18,document:12,driven:8,effect:[2,9,13],electr:9,electron:[1,8],envelop:9,environ:12,excit:9,field:[3,5,8,9,11,13],file:[3,11,13,14,15],first:4,format:5,fourth:4,frequenc:3,geometri:[5,7],get:11,happi:13,imbal:18,impact:2,index:20,inelast:2,info:11,initi:8,input:[3,11,13,14,15],instabl:15,introduc:18,ion:7,ioniz:[2,3,9],isotrop:2,landau:4,laser:[6,9,11],layer:[7,8],lifshitz:4,like:[4,5],load:18,machin:12,macro:5,match:[7,8],maxwellian:2,memori:18,mode:[7,11],model:[4,9],modul:9,mont:4,more:11,multiphoton:1,multipl:2,multiplot:13,namelist:14,neglect:2,niel:4,nonlinear:8,normal:14,numer:[7,9],obtain:[5,12],oscil:8,pair:1,parallel:18,particl:[5,8],particlebin:13,patch:19,perfectli:[7,8],perform:17,photon:1,physic:[1,3,4,5,6,7,8,9,11,13,14,15,18],pic:10,plasma:[8,13],plot:11,point:5,positron:1,post:[11,13],postprocess:14,potenti:9,power:2,prepar:[8,9,11,12,13],present:[1,7],process:[1,11,13,18],profil:11,propag:11,radiat:[1,4,7,9],rate:2,reaction:[1,4],realist:18,recombin:2,reduc:9,refer:3,relativist:8,relax:2,render:5,represent:5,resolut:13,result:5,run:[3,5,11,12,13,14,15],scalar:11,second:4,set:19,setup:[7,11,12,18],simul:[1,3,4,5,7,11,12,13,14,15,19],smilei:[12,18],spatial:13,speci:1,split:18,step:[6,7],stochast:4,stop:2,stream:15,studi:[8,9],subtleti:[7,9],synchrotron:4,temperatur:2,test:11,theori:11,thermal:[2,13],third:4,tip:12,tool:[11,13],track:8,tune:19,tutori:[1,4,6,7,11,18],two:15,unit:[7,8,9,14],used:14,using:[11,13],vacuum:11,vector:9,visual:5,volum:5,vtk:5,wakefield:[6,9],weibel:15,what:14,wheeler:1,why:7,wit:8,your:[5,11,12]}}) \ No newline at end of file diff --git a/site.html b/site.html new file mode 100644 index 0000000..2684ac2 --- /dev/null +++ b/site.html @@ -0,0 +1,529 @@ + + + + + + + Index — Smilei tutorials X.Y documentation + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/solve_rate_eqs.py b/solve_rate_eqs.py new file mode 100644 index 0000000..19e5f07 --- /dev/null +++ b/solve_rate_eqs.py @@ -0,0 +1,96 @@ +################################################################## +### SOLVING SIMPLE RATE EQUATIONS FOR THE IONIZATION OF CARBON ### +################################################################## + +from numpy import array, arange, zeros, pi, exp, sqrt, sin, vectorize +from math import gamma as math_gamma +math_gamma = vectorize(math_gamma) + +def solve_rate_eqs_( namelist ): + + # control parameter + tiny = 1.e-18 + + # conversion factor (between code units & atomic units) + w_ref = namelist.Main.reference_angular_frequency_SI + Lmu = 2.*pi * 3.e8/(w_ref*1.e-6) + au_to_w0 = 4.134137172e+16 / w_ref + Ec_to_au = 3.314742578e-15 * w_ref + + # laser + aL = max( namelist.Laser[0].space_envelope[0], namelist.Laser[0].space_envelope[1] ) + Eau = aL * Ec_to_au + delay = namelist.Laser[0].delay_phase[1] / namelist.Laser[0].omega + laser_time_envelope = namelist.Laser[0].time_envelope + + # PIC time-teps + dt = namelist.Main.timestep + nt = int(namelist.Main.simulation_time / dt) + print('********** ') + print('- [theory] dt = '+str(dt / w_ref * 1.0e15)+' fs') + print(' ') + + # Carbon atom properties + Zat = namelist.Species[0].atomic_number + Z = arange(0, Zat) + Ip = array([11.2602, 24.3845, 47.8877, 64.4935, 392.0905, 489.9931])/27.2114 + l = array([1,1,0,0,0,0]) + + nstar = (Z+1.) * sqrt(1./2./Ip) + cst = 2. * nstar + alpha = cst - 1. + beta = 2.**(cst-1.)/cst/math_gamma(cst) * (8.*l+4.) * Ip * au_to_w0 + gamma = 2.*(2.*Ip)**1.5 + Wadk = sqrt(6./pi) * beta * (gamma/Eau)**(cst-1.5) * exp(-1./3. * gamma/Eau) + + # Preparing arrays + t = zeros(nt) + E = zeros(nt) + n = zeros([Zat+1,nt]); n[0,0]=1. + Wint = zeros(Zat) + Env = zeros(nt) + + # Solving the rate equations numerically + for it in range(1,nt): + t[it] = it*dt+delay + E[it] = aL*sin(t[it]) * laser_time_envelope(t[it]-delay) + Env[it] = laser_time_envelope(t[it]-delay) + + # neutral atom + delta = gamma[0]/( abs(E[it])*Ec_to_au) + if (delta>tiny): + W = beta[0] * delta**alpha[0] * exp(-delta/3.) + Wint[0] += W + n[0,it] = (1.-W*dt/2.)/(1.+W*dt/2.) * n[0,it-1] + + # from charge 1 to charge Zat-1 + for Z in range(1,Zat): + deltam = gamma[Z-1]/( abs(E[it])*Ec_to_au) + deltap = gamma[Z] /( abs(E[it])*Ec_to_au) + if (deltam>tiny) and (deltap>tiny): + Wm = beta[Z-1] * (deltam)**alpha[Z-1] * exp(-deltam/3.) + Wp = beta[Z ] * (deltap)**alpha[Z ] * exp(-deltap/3.) + Wint[Z] += Wp + n[Z,it] = (1.-Wp*dt/2.)/(1.+Wp*dt/2.)*n[Z,it-1] + Wm*dt/(1.+Wm*dt/2.)*n[Z-1,it-1] + + # last charge state + delta = gamma[Zat-1]/( abs(E[it])*Ec_to_au) + if (delta>tiny): + W = beta[Zat-1] * (delta)**alpha[Zat-1] * exp(-delta/3.) + n[Zat,it] = n[Zat,it-1]+W*dt/(1.+W*dt/2.)*n[Zat-1,it-1] + + # Compare ionisation rates + Wint = Wint/nt + for Z in range(Zat): + print('- [theory] Z ='+str(Z)+'->'+str(Z+1) + +' Wadk='+str(Wadk[Z]* w_ref) + +' W ='+str(Wint[Z] * w_ref) + ) + + nsum = sum( n[:,-1] ) + print(' ') + print('- [theory] test cons. part. nb:'+str(nsum)) + print('********** ') + + return t, n, Env + diff --git a/thermal_plasma_1d.py b/thermal_plasma_1d.py new file mode 100644 index 0000000..2b9e8df --- /dev/null +++ b/thermal_plasma_1d.py @@ -0,0 +1,100 @@ +# ------------------- +# MY PYTHON VARIABLES +# ------------------- + +import math + +ne = 1. # electron density (code units => reference density) +Ld = 1./64. # Debye length (in code units => i.e. in skin-depth as ne=1) + +Te = ne*Ld**2 # Te normalised in mec^2 (code units) +vth = math.sqrt(Te) # normalised thermal velocity + +dx = 1.*Ld # spatial resolution +dt = 0.95*dx # timestep +Lx = 32. # simulation length +tsim = 1024. # duration of the simulation + +nppc = 16 # number of particle-per-cell + +diagEvery = int(16./dt) # frequency of outputs for DiagField + + +# -------------------------------------- +# SMILEI's VARIABLES (DEFINED IN BLOCKS) +# -------------------------------------- + +Main( + geometry = "1Dcartesian", + + interpolation_order = 2, + + timestep = dt, + simulation_time = tsim, + + cell_length = [dx], + grid_length = [Lx], + + number_of_patches = [ 8 ], + + EM_boundary_conditions = [ ['periodic'] ] , +) + +Species( + name = 'ion', + position_initialization = 'regular', + momentum_initialization = 'maxwell-juettner', + particles_per_cell = nppc, + mass = 1836., + charge = 1.0, + number_density = ne, + temperature = [Te], + boundary_conditions = [ + ['periodic'], + ], + time_frozen = 2.*tsim +) + +Species( + name = 'eon', + position_initialization = 'random', + momentum_initialization = 'maxwell-juettner', + particles_per_cell = nppc, + mass = 1.0, + charge = -1.0, + number_density = ne, + temperature = [Te], + thermal_boundary_temperature = [Te], + boundary_conditions = [ + ['periodic'], + ] +) + +LoadBalancing( + every = 100 +) + +### DIAGNOSTICS + +DiagScalar( + every = 2.5/dt +) + + +DiagFields( + every = diagEvery, + fields = ['Ex','Ey','Rho_ion','Rho_eon'] +) + + +DiagParticleBinning( + deposited_quantity = "weight", + every = diagEvery, + time_average = 1, + species = ["eon"], + axes = [ + ["ekin", 0., 4*Te, 32] + ] +) + + diff --git a/top.svg b/top.svg new file mode 100644 index 0000000..48f5977 --- /dev/null +++ b/top.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tunnel_ionization_1d.py b/tunnel_ionization_1d.py new file mode 100644 index 0000000..60ce0ae --- /dev/null +++ b/tunnel_ionization_1d.py @@ -0,0 +1,103 @@ + +from math import pi, sqrt + +l0 = 2.*pi # wavelength in normalized units +t0 = l0 # optical cycle in normalized units +resx = 64. # nb cells in 1 wavelength +rest = resx/0.95 # temporal resolution +Lv = 2.*l0 +Lp = l0/32. +Lx = 2.*l0+Lp # simulation length in x direction +Ly = 2.*l0+Lp # simulation length in y direction + +tmax = 20.*t0 +Tsim = Lv+Lp+tmax # duration of the simulation +nppc = 2048*4 # nb of particle per cells + +n0 = 1.e-2 # neutral density + +Lmu = 0.8 +I18 = 5.0e-2 +aL = sqrt(I18*Lmu**2/1.38) + +def n_(x): + if (Lv