.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "tutorials/01_single_plasma_simulation.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_tutorials_01_single_plasma_simulation.py: Basics of plasma simulation =========================== This tutorial illustrates the basics of carrying out a plasma simulation with Wake-T: - Send beam through plasma target. - Simulate a laser-driven stage. - Specify a custom density profile. - Analyze output data. All cases are simulated using the ``'quasistatic_2d'`` wakefield model. .. GENERATED FROM PYTHON SOURCE LINES 17-28 Simple plasma target -------------------- To demonstrate the basic workflow of carrying out a plasma simulation we will begin with the simplest setup: sending an electron beam a through a plasma target of constant density. Generate initial particle bunch ``````````````````````````````` As a first step, let's generate a gaussian electron beam and keep a copy of it for later use: .. GENERATED FROM PYTHON SOURCE LINES 29-63 .. code-block:: Python from wake_t.utilities.bunch_generation import get_gaussian_bunch_from_size # Beam parameters. emitt_nx = emitt_ny = 1e-6 # m s_x = s_y = 3e-6 # m s_t = 3.0 # fs gamma_avg = 100 / 0.511 gamma_spread = 1.0 # % q_bunch = 30 # pC xi_avg = 0.0 # m n_part = 1e4 # Create particle bunch. bunch = get_gaussian_bunch_from_size( emitt_nx, emitt_ny, s_x, s_y, gamma_avg, gamma_spread, s_t, xi_avg, q_bunch, n_part, name="elec_bunch", ) # Store bunch copy (will be needed later). bunch_bkp = bunch.copy() # Show phase space. bunch.show() .. image-sg:: /tutorials/images/sphx_glr_01_single_plasma_simulation_001.png :alt: 01 single plasma simulation :srcset: /tutorials/images/sphx_glr_01_single_plasma_simulation_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 64-76 Simulate propagation through target ``````````````````````````````````` Next, we define the plasma target by using the general ``PlasmaStage`` class. The basic parameters which need to be provided are the length and density of the target, the wakefield model, and the parameters required by the particular model chosen. For the ``'quasistatic_2d'`` model, the needed parameters are the limits of the simulation box ``xi_max``, ``xi_min`` and ``r_max``, the number of grid elements ``n_xi`` and ``n_r`` along each direction, as well as the number of particles per cell (optional, ``ppc=2`` by default). .. GENERATED FROM PYTHON SOURCE LINES 76-91 .. code-block:: Python from wake_t import PlasmaStage plasma_target = PlasmaStage( length=1e-2, density=1e23, wakefield_model="quasistatic_2d", xi_max=30e-6, xi_min=-30e-6, r_max=30e-6, n_xi=120, n_r=60, ppc=4, ) .. GENERATED FROM PYTHON SOURCE LINES 92-93 Once the target is defined, we can track the beam through it simply by doing: .. GENERATED FROM PYTHON SOURCE LINES 93-95 .. code-block:: Python plasma_target.track(bunch) .. rst-class:: sphx-glr-script-out .. code-block:: none Plasma stage: 0%| | 0.000000/0.010000 m [00:00] Plasma stage: 0%| | 0.000032/0.010000 m [00:18] Plasma stage: 12%|█▏ | 0.001200/0.010000 m [00:18] Plasma stage: 24%|██▍ | 0.002400/0.010000 m [00:18] Plasma stage: 36%|███▌ | 0.003600/0.010000 m [00:18] Plasma stage: 48%|████▊ | 0.004800/0.010000 m [00:18] Plasma stage: 60%|██████ | 0.006000/0.010000 m [00:19] Plasma stage: 72%|███████▏ | 0.007200/0.010000 m [00:19] Plasma stage: 84%|████████▍ | 0.008400/0.010000 m [00:19] Plasma stage: 96%|█████████▌| 0.009600/0.010000 m [00:19] Plasma stage: 100%|██████████| 0.010000/0.010000 m [00:19] [, ] .. GENERATED FROM PYTHON SOURCE LINES 96-101 .. note:: The first time that ``track`` is called in a ``PlasmaStage``, a just-in-time compilation of the most compute-intensive methods is performed by ``numba``. This compilation usually takes approx. 10 s, but it only has to be performed once. Following calls to ``track`` will skip this step. .. GENERATED FROM PYTHON SOURCE LINES 103-106 The final phase space of the bunch shows the expected energy loss towards the tail as well as the emittance increase due to the non-uniform focusing fields: .. GENERATED FROM PYTHON SOURCE LINES 106-108 .. code-block:: Python bunch.show() .. image-sg:: /tutorials/images/sphx_glr_01_single_plasma_simulation_002.png :alt: 01 single plasma simulation :srcset: /tutorials/images/sphx_glr_01_single_plasma_simulation_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 109-121 Plasma target with laser driver ------------------------------- To increase the complexity of the simulation, we will now add a laser driver to the plasma stage. Wake-T currently supports several laser profiles, namely Gaussian, flattened Gaussian and Laguerre-Gauss. For the example below, we will add a Gaussian pulse placed :math:`60 \ \mathrm{\mu m}` ahead of the electron bunch. The size of the box has been increased to be able to fit the laser, and a higher resolution is also used to properly resolve the pulse. .. GENERATED FROM PYTHON SOURCE LINES 121-156 .. code-block:: Python from wake_t import GaussianPulse # Get again the original distribution. bunch = bunch_bkp.copy() # Laser parameters. laser_xi_c = 60e-6 # m (laser centroid in simulation box) w_0 = 40e-6 # m a_0 = 3 tau = 30e-15 # fs (FWHM in intensity) # Create Gaussian laser pulse. laser = GaussianPulse(laser_xi_c, w_0=w_0, a_0=a_0, tau=tau, z_foc=0.0) # Create plasma target (including laser driver). plasma_target = PlasmaStage( length=1e-2, density=1e23, wakefield_model="quasistatic_2d", xi_max=90e-6, xi_min=-40e-6, r_max=100e-6, n_xi=260, n_r=100, ppc=4, laser=laser, ) # Track bunch. plasma_target.track(bunch) # Show final phase space. bunch.show() .. image-sg:: /tutorials/images/sphx_glr_01_single_plasma_simulation_003.png :alt: 01 single plasma simulation :srcset: /tutorials/images/sphx_glr_01_single_plasma_simulation_003.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Plasma stage: 0%| | 0.000000/0.010000 m [00:00] Plasma stage: 0%| | 0.000032/0.010000 m [00:00] Plasma stage: 1%|▏ | 0.000130/0.010000 m [00:08] Plasma stage: 3%|▎ | 0.000260/0.010000 m [00:10] Plasma stage: 12%|█▏ | 0.001169/0.010000 m [00:11] Plasma stage: 21%|██ | 0.002078/0.010000 m [00:11] Plasma stage: 30%|██▉ | 0.002987/0.010000 m [00:11] Plasma stage: 39%|███▉ | 0.003896/0.010000 m [00:11] Plasma stage: 48%|████▊ | 0.004805/0.010000 m [00:11] Plasma stage: 57%|█████▋ | 0.005714/0.010000 m [00:11] Plasma stage: 66%|██████▌ | 0.006623/0.010000 m [00:11] Plasma stage: 75%|███████▌ | 0.007532/0.010000 m [00:11] Plasma stage: 84%|████████▍ | 0.008442/0.010000 m [00:11] Plasma stage: 94%|█████████▎| 0.009351/0.010000 m [00:12] Plasma stage: 100%|██████████| 0.010000/0.010000 m [00:12] .. GENERATED FROM PYTHON SOURCE LINES 157-161 Now that the plasma is driven by a laser, the electron bunch experiences an energy gain of around 100 MeV, showing also clear signs of beam loading. Although still mismatched to the focusing fields, the emittance growth is now largely reduced. .. GENERATED FROM PYTHON SOURCE LINES 163-178 LPA stage with guiding and custom density profile ------------------------------------------------- The final simulation example of this tutorial presents a more complete setup by adding a custom non-uniform longitudinal density profile as well as a parabolic transverse profile for laser guiding. Defining the longitudinal density profile ````````````````````````````````````````` The ``density`` parameter of the ``PlasmaStage`` accepts as an input either a constant value (as seen in the example above) or a function of ``z``, the longitudinal position along the stage. The code below shows an example of a user-provided density profile. .. GENERATED FROM PYTHON SOURCE LINES 178-220 .. code-block:: Python import numpy as np import matplotlib.pyplot as plt # Profile parameters. np0 = 1e23 ramp_up = 1e-3 plateau = 1e-2 ramp_down = 1e-3 ramp_decay_length = 0.5e-3 L_plasma = ramp_up + plateau + ramp_down # Density function. def density_profile(z): """Define plasma density as a function of ``z``.""" # Allocate relative density array. n = np.ones_like(z) # Add upramp. n = np.where(z < ramp_up, 1 / (1 + (ramp_up - z) / ramp_decay_length) ** 2, n) # Add downramp. n = np.where( (z > ramp_up + plateau) & (z <= ramp_up + plateau + ramp_down), 1 / (1 + (z - ramp_up - plateau) / ramp_decay_length) ** 2, n, ) # Make zero after downramp. n = np.where(z > ramp_up + plateau + ramp_down, 0, n) # Return absolute density. return n * np0 # Plot density profile. z_prof = np.linspace(0, L_plasma, 1000) np_prof = density_profile(z_prof) plt.figure(figsize=(5, 2)) plt.plot(z_prof * 1e2, np_prof, c="k", lw=1) plt.fill_between(z_prof * 1e2, np_prof, color="0.9") plt.xlabel("z [cm]") plt.ylabel("$n_p$ [$m^{-3}$]") plt.tight_layout() .. image-sg:: /tutorials/images/sphx_glr_01_single_plasma_simulation_004.png :alt: 01 single plasma simulation :srcset: /tutorials/images/sphx_glr_01_single_plasma_simulation_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 221-237 Defining the radial density profile ``````````````````````````````````` Currently, Wake-T supports only a limited tunability of the transverse profile: either a uniform density (default), or a parabolic shape. The parabolic shape is set by using the ``parabolic_coefficient`` parameter, which imprints a profile given by ``n_r = n_p * (1 + parabolic_coefficient * r**2)``, where n_p is the local on-axis plasma density and ``r`` the radial coordinate. Similarly to the ``density`` parameter, the ``parabolic_coefficient`` can also be a constant of a function of ``z``. In this example, we will assume that it is constant and matched to the laser spot size for optimal guiding. In addition, this example will also generate openpmd output which will be visualized later. .. GENERATED FROM PYTHON SOURCE LINES 237-271 .. code-block:: Python import scipy.constants as ct # Get again the original distribution. bunch = bunch_bkp.copy() # Calculate transverse parabolic profile. r_e = ct.e**2 / (4.0 * np.pi * ct.epsilon_0 * ct.m_e * ct.c**2) # elec. radius rel_delta_n_over_w2 = 1.0 / (np.pi * r_e * w_0**4 * np0) # Create Gaussian laser pulse. laser = GaussianPulse(laser_xi_c, w_0=w_0, a_0=a_0, tau=tau, z_foc=0.0) # Create plasma target (with laser driver and custom density profile). plasma_target = PlasmaStage( length=L_plasma, density=density_profile, wakefield_model="quasistatic_2d", xi_max=90e-6, xi_min=-40e-6, r_max=100e-6, n_xi=260, n_r=100, ppc=4, laser=laser, parabolic_coefficient=rel_delta_n_over_w2, n_out=10, ) # Track bunch. plasma_target.track(bunch, opmd_diag=True, diag_dir="tutorial_01_diags") # Show final phase space. bunch.show() .. image-sg:: /tutorials/images/sphx_glr_01_single_plasma_simulation_005.png :alt: 01 single plasma simulation :srcset: /tutorials/images/sphx_glr_01_single_plasma_simulation_005.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Plasma stage: 0%| | 0.000000/0.012000 m [00:00] Plasma stage: 5%|▌ | 0.000645/0.012000 m [00:00] Plasma stage: 12%|█▏ | 0.001419/0.012000 m [00:00] Plasma stage: 19%|█▉ | 0.002323/0.012000 m [00:00] Plasma stage: 26%|██▌ | 0.003097/0.012000 m [00:00] Plasma stage: 32%|███▏ | 0.003871/0.012000 m [00:00] Plasma stage: 40%|███▉ | 0.004774/0.012000 m [00:00] Plasma stage: 46%|████▋ | 0.005565/0.012000 m [00:00] Plasma stage: 53%|█████▎ | 0.006355/0.012000 m [00:00] Plasma stage: 60%|██████ | 0.007200/0.012000 m [00:00] Plasma stage: 67%|██████▋ | 0.008000/0.012000 m [00:01] Plasma stage: 73%|███████▎ | 0.008774/0.012000 m [00:01] Plasma stage: 80%|███████▉ | 0.009600/0.012000 m [00:01] Plasma stage: 87%|████████▋ | 0.010452/0.012000 m [00:01] Plasma stage: 94%|█████████▍| 0.011273/0.012000 m [00:01] Plasma stage: 100%|██████████| 0.012000/0.012000 m [00:01] .. GENERATED FROM PYTHON SOURCE LINES 272-275 As expected, thanks to the guiding, the energy gain is larger and with a smaller sign of beam loading. The plasma upramp also helps in further minimizing the emittance growth. .. GENERATED FROM PYTHON SOURCE LINES 277-283 Visualize output data --------------------- To finalize the tutorial, we will visualize the output data using the openpmd-viewer. .. GENERATED FROM PYTHON SOURCE LINES 283-288 .. code-block:: Python from openpmd_viewer.addons import LpaDiagnostics diags = LpaDiagnostics("tutorial_01_diags/hdf5") diags.get_field("rho", iteration=3, plot=True, vmin=-1e5) .. image-sg:: /tutorials/images/sphx_glr_01_single_plasma_simulation_006.png :alt: rho in the mode all at 1.20e-11 s (iteration 3) :srcset: /tutorials/images/sphx_glr_01_single_plasma_simulation_006.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (array([[ 6.45778559e+01, 5.84934813e+01, 5.17363147e+01, ..., -3.55754678e-11, -3.55754678e-11, -3.55754678e-11], [-3.52516003e+02, -3.52313383e+02, -3.50471624e+02, ..., -1.28071684e-10, -1.28071684e-10, -1.28071684e-10], [-2.09582775e+01, -2.14433008e+01, -2.18007198e+01, ..., -2.56143368e-10, -2.56143368e-10, -2.56143368e-10], ..., [-2.09582775e+01, -2.14433008e+01, -2.18007198e+01, ..., -2.56143368e-10, -2.56143368e-10, -2.56143368e-10], [-3.52516003e+02, -3.52313383e+02, -3.50471624e+02, ..., -1.28071684e-10, -1.28071684e-10, -1.28071684e-10], [ 6.45778559e+01, 5.84934813e+01, 5.17363147e+01, ..., -3.55754678e-11, -3.55754678e-11, -3.55754678e-11]], shape=(200, 260)), ) .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 34.897 seconds) .. _sphx_glr_download_tutorials_01_single_plasma_simulation.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 01_single_plasma_simulation.ipynb <01_single_plasma_simulation.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 01_single_plasma_simulation.py <01_single_plasma_simulation.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 01_single_plasma_simulation.zip <01_single_plasma_simulation.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_