Exemplo n.º 1
0
def current_profile(z, q, n_slices=10, len_slice=None):
    """Calculate the current profile of the given particle distribution.

    Parameters
    ----------
    z : array
        Contains the longitudinal position of the particles in units of meters

    q : array
        Contains the charge of the particles in C

    n_slices : array
        Number of longitudinal slices in which to divite the particle
        distribution. Not used if len_slice is specified.

    len_slice : array
        Length of the longitudinal slices. If not None, replaces n_slices.

    Returns
    -------
    A tuple containing:
    - An array with the current of each slice in units of A.
    - An array with the slice edges along z.
    """
    slice_lims, n_slices = create_beam_slices(z, n_slices, len_slice)
    sl_len = slice_lims[1] - slice_lims[0]
    charge_hist, z_edges = np.histogram(z, bins=n_slices, weights=q)
    sl_dur = sl_len / ct.c
    current_prof = charge_hist / sl_dur
    return current_prof, z_edges
Exemplo n.º 2
0
def fwhm_energy_spread(z, px, py, pz, w=None, n_slices=10, len_slice=None):
    """Calculate the absolute FWHM energy spread of the provided particle
    distribution

    Parameters
    ----------
    px : array
        Contains the transverse momentum in the x direction of the
        beam particles in non-dimmensional units (beta*gamma)

    py : array
        Contains the transverse momentum in the x direction of the
        beam particles in non-dimmensional units (beta*gamma)

    pz : array
        Contains the longitudonal momentum of the beam particles in
        non-dimmensional units (beta*gamma)

    w : array or single value
        Statistical weight of the particles.

    Returns
    -------
    A float with the energy spread value in non-dimmensional units,
    i.e. [1/(m_e c**2)]
    """
    part_ene = np.sqrt(1 + np.square(px) + np.square(py) + np.square(pz))
    slice_lims, n_slices = create_beam_slices(z, n_slices, len_slice)
    gamma_hist, z_edges = np.histogram(part_ene, bins=n_slices, weights=w)
    slice_pos = z_edges[1:] - abs(z_edges[1] - z_edges[0]) / 2
    peak = max(gamma_hist)
    slices_in_fwhm = slice_pos[np.where(gamma_hist >= peak / 2)]
    fwhm = max(slices_in_fwhm) - min(slices_in_fwhm)
    return fwhm
Exemplo n.º 3
0
def energy_profile(z, px, py, pz, w=None, n_slices=10, len_slice=None):
    """Calculate the sliced longitudinal energy profile of the distribution

    Parameters
    ----------
    z : array
        Contains the longitudinal position of the particles in units of meters

    px : array
        Contains the transverse momentum in the x direction of the
        beam particles in non-dimmensional units (beta*gamma)

    py : array
        Contains the transverse momentum in the x direction of the
        beam particles in non-dimmensional units (beta*gamma)

    pz : array
        Contains the longitudonal momentum of the beam particles in
        non-dimmensional units (beta*gamma)

    w : array or single value
        Statistical weight of the particles.

    n_slices : array
        Number of longitudinal slices in which to divite the particle
        distribution. Not used if len_slice is specified.

    len_slice : array
        Length of the longitudinal slices. If not None, replaces n_slices.

    Returns
    -------
    A tuple containing:
    - An array with the mean energy value in each slice.
    - An array with the statistical weight of each slice.
    - An array with the slice edges.
    """
    slice_lims, n_slices = create_beam_slices(z, n_slices, len_slice)
    slice_ene = np.zeros(n_slices)
    slice_weight = np.zeros(n_slices)
    for i in np.arange(0, n_slices):
        a = slice_lims[i]
        b = slice_lims[i + 1]
        slice_particle_filter = (z > a) & (z <= b)
        if slice_particle_filter.any():
            px_slice = px[slice_particle_filter]
            py_slice = py[slice_particle_filter]
            pz_slice = pz[slice_particle_filter]
            if hasattr(w, '__iter__'):
                w_slice = w[slice_particle_filter]
            else:
                w_slice = w
            slice_ene[i] = mean_energy(px_slice, py_slice, pz_slice, w_slice)
            slice_weight[i] = np.sum(w_slice)
    return slice_ene, slice_weight, slice_lims
Exemplo n.º 4
0
def normalized_transverse_rms_slice_emittance(z,
                                              x,
                                              px,
                                              py=None,
                                              pz=None,
                                              w=None,
                                              disp_corrected=False,
                                              corr_order=1,
                                              n_slices=10,
                                              len_slice=None):
    """Calculate the normalized transverse RMS slice emittance of the particle
    distribution in a given plane.

    Parameters
    ----------
    z : array
        Contains the longitudinal position of the particles in units of meters

    x : array
        Contains the transverse position of the particles in one of the
        transverse planes in units of meters

    px : array
        Contains the transverse momentum of the beam particles in the same
        plane as x in non-dimmensional units (beta*gamma)

    py : array
        Contains the transverse momentum of the beam particles in the opposite
        plane as as x in non-dimmensional units (beta*gamma). Necessary if
        disp_corrected=True.

    pz : array
        Contains the longitudinal momentum of the beam particles in
        non-dimmensional units (beta*gamma). Necessary if disp_corrected=True.

    w : array or single value
        Statistical weight of the particles.

    disp_corrected : bool
        Whether ot not to correct for dispersion contributions.

    corr_order : int
        Highest order up to which dispersion effects should be corrected.

    n_slices : array
        Number of longitudinal slices in which to divite the particle
        distribution. Not used if len_slice is specified.

    len_slice : array
        Length of the longitudinal slices. If not None, replaces n_slices.

    Returns
    -------
    A tuple containing:
    - An array with the emmitance value in each slice in units of m * rad.
    - An array with the statistical weight of each slice.
    - An array with the slice edges.
    - A float with the weigthed average of the slice values.
    """
    if disp_corrected:
        # remove x-gamma correlation
        gamma = np.sqrt(1 + np.square(px) + np.square(py) + np.square(pz))
        gamma_avg = np.average(gamma, weights=w)
        dgamma = (gamma - gamma_avg) / gamma_avg
        x = remove_correlation(dgamma, x, w, corr_order)
    slice_lims, n_slices = create_beam_slices(z, n_slices, len_slice)
    slice_em = np.zeros(n_slices)
    slice_weight = np.zeros(n_slices)
    for i in np.arange(0, n_slices):
        a = slice_lims[i]
        b = slice_lims[i + 1]
        slice_particle_filter = (z > a) & (z <= b)
        if slice_particle_filter.any():
            x_slice = x[slice_particle_filter]
            px_slice = px[slice_particle_filter]
            # if py is not None:
            #    py_slice = py[slice_particle_filter]
            # else:
            #    py_slice=None
            # if pz is not None:
            #    pz_slice = pz[slice_particle_filter]
            # else:
            #    pz_slice=None
            if hasattr(w, '__iter__'):
                w_slice = w[slice_particle_filter]
            else:
                w_slice = w
            slice_em[i] = normalized_transverse_rms_emittance(x_slice,
                                                              px_slice,
                                                              w=w_slice)
            slice_weight[i] = np.sum(w_slice)
    slice_avg = calculate_slice_average(slice_em, slice_weight)
    return slice_em, slice_weight, slice_lims, slice_avg