Introduction to openPMD-viewer laser-plasma tools

In addition to the general methods get_field and get_particle, openPMD-viewer can also include a set of domain-specific tools. For instance, this notebook describes a set of methods that are useful when analyzing simulations of laser-plasma acceleration.

If you are not interested in laser-plasma simulations, you can skip this notebook as these methods are only an add-on to openPMD-viewer.

You can run this notebook locally by downloading it from this link.

(optional) Preparing this notebook to run it locally

If you choose to run this notebook on your local machine, you will need to download the openPMD data files which will then be analysed. To do so, execute the following cell.

[1]:
import os

def download_if_absent( dataset_name ):
    "Function that downloads and decompress a chosen dataset"
    if os.path.exists( dataset_name ) is False:
        import wget, tarfile
        tar_name = "%s.tar.gz" %dataset_name
        url = "https://github.com/openPMD/openPMD-example-datasets/raw/draft/%s" %tar_name
        wget.download(url, tar_name)
        with tarfile.open( tar_name ) as tar_file:
            tar_file.extractall()
        os.remove( tar_name )

download_if_absent( 'example-2d' )

In addition, we choose here to incorporate the plots inside the notebook.

[2]:
%matplotlib inline

The LpaDiagnostics class

To use the laser-plasma acceleration (LPA) tools: - Load the class LpaDiagnostics from the module openpmd_viewer.addons

[3]:
from openpmd_viewer.addons import LpaDiagnostics
  • Create an LpaDiagnostics instance in the same way, as you would do for an OpenPMDTimeSeries.

[4]:
ts_2d = LpaDiagnostics('./example-2d/hdf5/')

The LpaDiagnostics class inherits from the OpenPMDTimeSeries class, and therefore it also has the methods get_field, get_particle and slider. For instance:

[5]:
ts_2d.slider()

Diagnostic methods

In addition to the methods get_particle, get_field and slider, the LpaDiagnotics class has an extra set of specialized methods.

These diagnostic methods are currently only implemented for API-like usage. In particular, either the time or iteration have to be specified when calling a method, by setting the t or iteration parameter.

Particle diagnostics

For methods involving particle data, the desired particle species also needs to be specified with the species parameter. Optionally, these methods can be applied to only a subset of the particles, by using the select parameter.

For instance, select={'uz' : [-1, 2]} will select only the particles which have a longitudinal normalized momentum between -1 and 2.

In the following the available particle diagnostic methods will be explained.

For more information a method’s documentation can be called with:

[6]:
ts_2d.get_mean_gamma?

Charge

get_charge calculates the charge of the given particle selection in Coulomb.

[7]:
ts_2d.get_charge(iteration=300, species='electrons')
[7]:
-0.002305747569782994

Note that the evolution of the charge (or of any of the quantities below) can be easily obtained with ts.iterate:

[8]:
ts_2d.iterate( ts_2d.get_charge, species='electrons' )
100%|██████████| 29/29 [00:00<00:00, 651.49it/s]
[8]:
array([-0.00210493, -0.00214036, -0.00215568, -0.00218178, -0.00220637,
       -0.00222916, -0.00225042, -0.00227048, -0.0022887 , -0.00230575,
       -0.00232129, -0.00233496, -0.0023471 , -0.00235652, -0.00236598,
       -0.00237395, -0.00237923, -0.00238449, -0.00238824, -0.0023905 ,
       -0.00239077, -0.00236674, -0.00233669, -0.00230665, -0.00227709,
       -0.00224705, -0.00221701, -0.00218697, -0.00215693, -0.00212689])

Mean gamma

To calculate the mean gamma value and standard deviation of the selected particles get_mean_gamma can be used. In the example below, only the particles with \(u_z > 0.05\) are selected.

[9]:
ts_2d.get_mean_gamma(iteration=300, species='electrons', select={'uz' : [0.05, None]})
[9]:
(1.0665548693800455, 0.10151101005407513)

Divergence

This method calculates the divergence of the selected particles, using \(\langle \arctan{u_{x/y}/u_z} \rangle\)

[10]:
ts_2d.get_divergence(iteration=300, species='electrons')
[10]:
(1.3080546184771429, 1.5751303670998402)

Emittance

This method can be used to calculate the normalized emittance in the x and y plane for selected particles by evaluating

\[\epsilon_{n,rms}=\sqrt{\langle x^2 \rangle \langle u_x^2 \rangle - \langle x u_x \rangle^2}\]
[11]:
ts_2d.get_emittance(iteration=300, species='electrons')
[11]:
(1.1078612528297555e-07, 1.6064831448020442e-09)

Current

get_current can be used to calculate the instantaneous current along the z_axis generated by the selected particles. When setting plot=True the resulting current profile is directly plotted. Otherwise an array with the data is returned.

[12]:
ts_2d.get_current(iteration=300, species='electrons', plot=True);
../_images/tutorials_5_Laser-plasma_tools_24_0.png

Laser diagnostic

The laser diagnostic methods require the user to specify the plane of laser polarisation by setting the argument pol= to either 'x' or 'y'

Laser envelope

This method calculates the envelope of a given laser field. This can be done for a 1D slice of the field or for an entire 2D plane. The resulting data is returned in form of a 1D or 2D array, respectively.

[13]:
ts_2d.get_laser_envelope(iteration=300, pol='y');

Spectrum

This function helps to easily calculate (and plot) the spectrum of a given laser field.

[14]:
ts_2d.get_spectrum(iteration=300, pol='y', plot=True);
../_images/tutorials_5_Laser-plasma_tools_29_0.png

Spectrogram

This method does a time-frequency analysis of the laser, by applying the FROG method.

Mathematically:

\[s(\omega, \tau) = \left| \int_{-\infty}^{\infty} E(t) |E(t-\tau)|^2 \exp( -i\omega t) dt \right|^2\]

(Additional matplotlib arguments for the plotting option can directly be passed to the function, e.g cmap='coolwarm' )

[15]:
ts_2d.get_spectrogram(iteration=300, pol='y', plot=True, cmap='YlGnBu_r');
../_images/tutorials_5_Laser-plasma_tools_31_0.png

Main frequency

To calculate the main frequency (i.e. maximum of the spectrum) call. This returns the frequency in \(rad.s^{-1}\).

[16]:
ts_2d.get_main_frequency(iteration=300, pol='y')
[16]:
2354564459136067.0

Laser \(a_0\)

A method to calculate the laser strength a0 as given by

\[a0 = E_{max} e / (m_e c \omega)\]
[17]:
ts_2d.get_a0(iteration=300, pol='y')
[17]:
1.0532383873717688

Laser waist

Calculate the waist of a (gaussian) laser pulse (i.e. \(\sqrt{2} \sigma_r\), where \(\sigma_r\) is the transverse RMS of the field).

[18]:
ts_2d.get_laser_waist(iteration=300, pol='y')
/home/docs/checkouts/readthedocs.org/user_builds/openpmd-viewer/envs/latest/lib/python3.11/site-packages/openpmd_viewer/addons/pic/lpa_diagnostics.py:982: OptimizeWarning: Covariance of the parameters could not be estimated
  params, _ = curve_fit( gaussian_profile, trans_pos,
[18]:
4.144713675767255e-06

Pulse length

Calculate the length of a (gaussian) laser pulse. Here ‘length’ means the ‘longitudinal waist’ (i.e \(\sqrt{2} \sigma_z\) where \(\sigma_z\) is the longitudinal RMS of the field).

[19]:
ts_2d.get_ctau(iteration=300, pol='y')
[19]:
2.9492685891734526e-06