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
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
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
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