예제 #1
0
    def get_spectrogram(self,
                        t=None,
                        iteration=None,
                        pol=None,
                        theta=0,
                        slicing_dir='y',
                        plot=False,
                        **kw):
        """
        Calculates the spectrogram of a laserpulse, by the FROG method.

        Mathematically:
        $$ s(\omega, \tau) = | \int_{-\infty}^{\infty} E(t) |E(t-\tau)|^2
            \exp( -i\omega t) dt |^2 $$
        See Trebino, R: Frequency Resolved Optical Gating: The measurements of
        Ultrashort Laser Pulses: year 2000: formula 5.2

        The time is centered around the laser pulse.

        Parameters
        ----------
        t : float (in seconds), optional
            Time at which to obtain the data (if this does not correspond to
            an available file, the last file before `t` will be used)
            Either `t` or `iteration` should be given by the user.

        iteration : int
            The iteration at which to obtain the data
            Either `t` or `iteration` should be given by the user.

        pol : string
            Polarization of the laser field. Options are 'x', 'y'

        plot: bool, optional
            Whether to plot the spectrogram

        **kw : dict, otional
           Additional options to be passed to matplotlib's `imshow` method

        Returns
        -------
        - A 2d array with spectrogram
        - info : a FieldMetaInformation object
           (see the corresponding docstring)
        """
        # Get the field envelope
        env, _ = self.get_laser_envelope(t=t, iteration=iteration, pol=pol)
        # Get the field
        E, info = self.get_field(t=t,
                                 iteration=iteration,
                                 field='E',
                                 coord=pol,
                                 theta=theta,
                                 slicing_dir=slicing_dir)
        # Get central slice
        E = E[int(E.shape[0] / 2), :]
        Nz = len(E)
        # Get time domain of the data
        tmin = info.zmin / const.c
        tmax = info.zmax / const.c
        T = tmax - tmin
        dt = T / Nz
        # Normalize the Envelope
        env /= np.sqrt(np.trapz(env**2, dx=dt))
        # Allocate array for the gating function and the spectrogran
        E_shift = np.zeros_like(E)
        spectrogram = np.zeros((2 * Nz, Nz))
        # Loop over the time variable of the spectrogram
        for i in range(Nz * 2):
            itau = i % Nz
            # Shift the E field and fill the rest with zeros
            if i < Nz:
                E_shift[:itau] = env[Nz - itau:Nz]
                E_shift[itau:] = 0
            else:
                E_shift[itau:] = env[:Nz - itau]
                E_shift[:itau] = 0
            EE = E * E_shift**2
            fft_EE = np.fft.fft(EE)
            spectrogram[i, :] = np.abs(fft_EE)**2
        # Rotate and flip array to have input form of imshow
        spectrogram = np.flipud(np.rot90(spectrogram[:, int(Nz / 2):]))
        # Find the time at which the wigner transform is the highest
        maxi, maxj = np.unravel_index(spectrogram.argmax(), spectrogram.shape)
        tmin = -(T - T / spectrogram.shape[1] * maxj)
        info = FieldMetaInformation({
            0: 'omega',
            1: 't'
        },
                                    spectrogram.shape,
                                    grid_spacing=(2 * np.pi / T, dt / 2.),
                                    grid_unitSI=1,
                                    global_offset=(0, tmin),
                                    position=(0, 0))

        # Plot the result if needed
        if plot:
            check_matplotlib()
            iteration = self.iterations[self._current_i]
            time_fs = 1.e15 * self.t[self._current_i]
            plt.imshow(spectrogram,
                       extent=info.imshow_extent,
                       aspect='auto',
                       **kw)
            plt.title("Spectrogram at %.1f fs   (iteration %d)" %
                      (time_fs, iteration),
                      fontsize=self.plotter.fontsize)
            plt.xlabel('$t \;(s)$', fontsize=self.plotter.fontsize)
            plt.ylabel('$\omega \;(rad.s^{-1})$',
                       fontsize=self.plotter.fontsize)
        return (spectrogram, info)
예제 #2
0
    def get_spectrum(self,
                     t=None,
                     iteration=None,
                     pol=None,
                     m='all',
                     plot=False,
                     **kw):
        """
        Return the spectrum of the laser
        (Absolute value of the Fourier transform of the fields.)

        Parameters
        ----------
        t : float (in seconds), optional
            Time at which to obtain the data (if this does not correspond to
            an available file, the last file before `t` will be used)
            Either `t` or `iteration` should be given by the user.

        iteration : int
            The iteration at which to obtain the data
            Either `t` or `iteration` should be given by the user.

        pol : string
            Polarization of the field. Options are 'x', 'y'

        m : int or str, optional
           Only used for thetaMode geometry
           Either 'all' (for the sum of all the modes)
           or an integer (for the selection of a particular mode)

        plot: bool, optional
           Whether to plot the data

        **kw : dict, otional
           Additional options to be passed to matplotlib's `plot` method

        Returns
        -------
        A tuple with:
            - The 1D spectrum on axis
            - A FieldMetaInformation object
        """
        # Check if polarization has been entered
        if pol not in ['x', 'y']:
            raise ValueError('The `pol` argument is missing or erroneous.')
        if pol == 'x':
            slicing_dir = 'y'
            theta = 0
        else:
            slicing_dir = 'x'
            theta = np.pi / 2.

        # Get field data
        field, info = self.get_field(t=t,
                                     iteration=iteration,
                                     field='E',
                                     coord=pol,
                                     theta=theta,
                                     m=m,
                                     slicing_dir=slicing_dir)
        # Get central field lineout
        field1d = field[int(field.shape[0] / 2), :]
        # FFT of 1d data
        dt = (info.z[1] - info.z[0]) / const.c  # Integration step for the FFT
        fft_field = np.fft.fft(field1d) * dt
        # Take half of the data (positive frequencies only)
        spectrum = abs(fft_field[:int(len(fft_field) / 2)])
        # Create a FieldMetaInformation object
        T = (info.zmax - info.zmin) / const.c
        spect_info = FieldMetaInformation({0: 'omega'},
                                          spectrum.shape,
                                          grid_spacing=(2 * np.pi / T, ),
                                          grid_unitSI=1,
                                          global_offset=(0, ),
                                          position=(0, ))

        # Plot the field if required
        if plot:
            check_matplotlib()
            iteration = self.iterations[self._current_i]
            time_fs = 1.e15 * self.t[self._current_i]
            plt.plot(spect_info.omega, spectrum, **kw)
            plt.xlabel('$\omega \; (rad.s^{-1})$',
                       fontsize=self.plotter.fontsize)
            plt.ylabel('Spectrum', fontsize=self.plotter.fontsize)
            plt.title("Spectrum at %.1f fs   (iteration %d)" %
                      (time_fs, iteration),
                      fontsize=self.plotter.fontsize)
        return (spectrum, spect_info)
예제 #3
0
    def get_current(self,
                    t=None,
                    iteration=None,
                    species=None,
                    select=None,
                    bins=100,
                    plot=False,
                    **kw):
        """
        Calculate the electric current along the z-axis for selected particles.

        Parameters
        ----------
         t : float (in seconds), optional
            Time at which to obtain the data (if this does not correspond to
            an available file, the last file before `t` will be used)
            Either `t` or `iteration` should be given by the user

        iteration : int
            The iteration at which to obtain the data
            Either `t` or `iteration` should be given by the user

        species : string
            Particle species to use for calculations

        select : dict, optional
            Either None or a dictionary of rules
            to select the particles, of the form
            'x' : [-4., 10.]   (Particles having x between -4 and 10 microns)
            'z' : [0, 100] (Particles having x between 0 and 100 microns)

        bins : int, optional
            Number of bins along the z-axis in which to calculate the current

        plot : bool, optional
           Whether to plot the requested quantity

        **kw : dict, otional
           Additional options to be passed to matplotlib's `plot` method
        Returns
        -------
        A tuple of arrays containig
        - The current in each bin in Ampere
        - A FieldMetaInformation object
          (see object's docstring for more details)

        """
        # Get particle data
        z, uz, uy, ux, w, q = self.get_particle(
            var_list=['z', 'uz', 'uy', 'ux', 'w', 'charge'],
            t=t,
            iteration=iteration,
            species=species,
            select=select)
        # Calculate Lorentz factor for all particles
        gamma = np.sqrt(1 + ux**2 + uy**2 + uz**2)
        # Calculate particle velocities
        vz = uz / gamma * const.c
        # Length to be seperated in bins
        len_z = np.max(z) - np.min(z)
        vzq_sum, _ = np.histogram(z, bins=bins, weights=(vz * w * q))
        # Calculete the current in each bin
        current = np.abs(vzq_sum * bins / (len_z * 1.e-6))
        # Info object with central position of the bins
        info = FieldMetaInformation({0: 'z'},
                                    current.shape,
                                    grid_spacing=(len_z / bins, ),
                                    grid_unitSI=1,
                                    global_offset=(np.min(z) +
                                                   len_z / bins / 2, ),
                                    position=(0, ))
        # Plot the result if needed
        if plot:
            check_matplotlib()
            iteration = self.iterations[self._current_i]
            time_fs = 1.e15 * self.t[self._current_i]
            plt.plot(info.z, current, **kw)
            plt.title("Current at %.1f fs   (iteration %d)" %
                      (time_fs, iteration),
                      fontsize=self.plotter.fontsize)
            plt.xlabel('$z \;(\mu m)$', fontsize=self.plotter.fontsize)
            plt.ylabel('$I \;(A)$', fontsize=self.plotter.fontsize)
        # Return the current and bin centers
        return (current, info)
예제 #4
0
    def get_laser_envelope(self,
                           t=None,
                           iteration=None,
                           pol=None,
                           m='all',
                           index='center',
                           theta=0,
                           slicing_dir='y',
                           plot=False,
                           **kw):
        """
        Calculate a laser field by filtering out high frequencies. Can either
        return the envelope slice-wise or a full 2D envelope.

        Parameters
        ----------
        t : float (in seconds), optional
            Time at which to obtain the data (if this does not correspond to
            an available file, the last file before `t` will be used)
            Either `t` or `iteration` should be given by the user.

        iteration : int
            The iteration at which to obtain the data
            Either `t` or `iteration` should be given by the user.

        pol : string
            Polarization of the field. Options are 'x', 'y'

        m : int or str, optional
           Only used for thetaMode geometry
           Either 'all' (for the sum of all the modes)
           or an integer (for the selection of a particular mode)

        index : int or str, optional
            Transversal index of the slice from which to calculate the envelope
            Default is 'center', using the center slice.
            Use 'all' to calculate a full 2D envelope

        theta : float, optional
           Only used for thetaMode geometry
           The angle of the plane of observation, with respect to the x axis

        slicing_dir : str, optional
           Only used for 3dcartesian geometry
           The direction along which to slice the data
           Either 'x', 'y'

        plot : bool, optional
           Whether to plot the requested quantity

        **kw : dict, otional
           Additional options to be passed to matplotlib's `plot`(1D) or
           `imshow` (2D) method

        Returns
        -------
        A tuple with:
        - Envelope data (1D or 2D array)
        - A FieldMetaInformation object
        """
        # Check if polarization has been entered
        if pol is None:
            raise ValueError('The `pol` argument is missing or erroneous.')
        # Get field data
        field = self.get_field(t=t,
                               iteration=iteration,
                               field='E',
                               coord=pol,
                               theta=theta,
                               m=m,
                               slicing_dir=slicing_dir)
        info = field[1]
        if index == 'all':
            # Filter the full 2D array
            e_complx = hilbert(field[0], axis=1)
        elif index == 'center':
            # Filter the central slice (1D array)
            field_slice = field[0][int(field[0].shape[0] / 2), :]
            e_complx = hilbert(field_slice)
        else:
            # Filter the requested slice (2D array)
            field_slice = field[0][index, :]
            e_complx = hilbert(field_slice)
        envelope = np.abs(e_complx)
        # Restrict the metainformation to 1d if needed
        if index != 'all':
            info.restrict_to_1Daxis(info.axes[1])

        # Plot the result if needed
        if plot:
            check_matplotlib()
            iteration = self.iterations[self._current_i]
            time_fs = 1.e15 * self.t[self._current_i]
            if index != 'all':
                plt.plot(1.e6 * info.z, envelope, **kw)
                plt.ylabel('$E_%s \;(V/m)$' % pol,
                           fontsize=self.plotter.fontsize)
            else:
                plt.imshow(envelope,
                           extent=1.e6 * info.imshow_extent,
                           aspect='auto',
                           **kw)
                plt.colorbar()
                plt.ylabel('$%s \;(\mu m)$' % pol,
                           fontsize=self.plotter.fontsize)
            plt.title("Laser envelope at %.1f fs   (iteration %d)" %
                      (time_fs, iteration),
                      fontsize=self.plotter.fontsize)
            plt.xlabel('$z \;(\mu m)$', fontsize=self.plotter.fontsize)
        # Return the result
        return (envelope, info)
예제 #5
0
    def get_sigma_gamma_slice(self,
                              dz,
                              t=None,
                              iteration=None,
                              species=None,
                              select=None,
                              plot=False,
                              **kw):
        """
        Calculate the standard deviation of gamma for particles in z-slices of
        width dz

        Parameters
        ----------
        dz : float (in micrometers)
            Width of slices in which to calculate sigma gamma

        t : float (in seconds), optional
            Time at which to obtain the data (if this does not correspond to
            an available file, the last file before `t` will be used)
            Either `t` or `iteration` should be given by the user.

        iteration : int
            The iteration at which to obtain the data
            Either `t` or `iteration` should be given by the user.

        species : string
            Particle species to use for calculations

        select : dict, optional
            Either None or a dictionary of rules
            to select the particles, of the form
            'x' : [-4., 10.]   (Particles having x between -4 and 10 microns)
            'z' : [0, 100] (Particles having x between 0 and 100 microns)

        plot : bool, optional
           Whether to plot the requested quantity

        **kw : dict, otional
           Additional options to be passed to matplotlib's `plot` method

        Returns
        -------
        A tuple of arrays:
        - Sigma gamma in each slice
        - Central z position of each slice

        """
        z, uz, ux, uy, w = self.get_particle(
            t=t,
            species=species,
            select=select,
            var_list=['z', 'uz', 'ux', 'uy', 'w'],
            iteration=iteration)
        # Calculate gamma of each particle
        gamma = np.sqrt(1 + (uz**2 + ux**2 + uy**2))
        z0 = min(z)
        zend = max(z)
        N = int((zend - z0) / dz)
        spreads = np.zeros(N + 1)
        z_pos = np.linspace(z0, zend, N + 1)
        zi = z0 + dz / 2.
        i = 0
        # Iterate over slices and calculate sigma gamma
        while zi < zend:
            z_filter = (z > zi - dz / 2.) & (z < zi + dz / 2.)
            spreads[i] = w_std(gamma[z_filter], w[z_filter])
            zi += dz
            i += 1
        # Plot the result if needed
        if plot:
            check_matplotlib()
            iteration = self.iterations[self._current_i]
            time_fs = 1.e15 * self.t[self._current_i]
            plt.plot(z_pos, spreads, **kw)
            plt.title("Slice energy spread at %.1f fs   (iteration %d)" %
                      (time_fs, iteration),
                      fontsize=self.plotter.fontsize)
            plt.xlabel('$z \;(\mu m)$', fontsize=self.plotter.fontsize)
            plt.ylabel('$\sigma_\gamma (\Delta_z=%s\mu m)$' % dz,
                       fontsize=self.plotter.fontsize)
        return (spreads, z_pos)