Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to calculate central energy and energy spread #304

Merged
merged 10 commits into from
Jan 26, 2021
132 changes: 132 additions & 0 deletions openpmd_viewer/addons/pic/lpa_diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,90 @@ def __init__( self, path_to_dir, check_all_files=True, backend=None ):
OpenPMDTimeSeries.__init__( self, path_to_dir,
check_all_files=check_all_files, backend=backend )

def get_energy_spread( self, t=None, iteration=None, species=None,
select=None, center='mean', width='std', property='energy' ):
"""
Calculate the central energy and energy spread according to the
particle weights

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 : str
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 meters)
'z' : [0, 100] (Particles having z between 0 and 100 meters)

center : str
Method to find the central energy of the particle distribution
Should be one of

- 'mean'
- 'median'

width : str
Method to find the energy spread of the particle distribution
Should be one of

- 'std'
- 'mad'

property : str
Unit of energy. Should be one of

- 'energy' returns energy in eV
- 'gamma' returns Lorentz factor

Returns
-------
A tuple of floats with:
- central energy
- energy spread
"""
# Get particle data
ux, uy, uz, w, m = self.get_particle(
var_list=['ux', 'uy', 'uz', 'w', 'mass'], select=select,
species=species, t=t, iteration=iteration)
# Calculate Lorentz factor and energy for all particles
gamma = np.sqrt(1 + ux ** 2 + uy ** 2 + uz ** 2)
if property == 'energy':
prop = (gamma - 1) * m * const.c ** 2 / const.e * 1e-6

elif property == 'gamma':
prop = gamma
else:
raise ValueError('Invalid output property: %s'%property)

# Calculate weighted center
soerenjalas marked this conversation as resolved.
Show resolved Hide resolved
if center == 'mean':
p_center = w_ave(prop, w)
elif center == 'median':
p_center = w_median(prop, w)
else:
raise ValueError('Invalid center property: %s' % center)

# Calculate weighted width
soerenjalas marked this conversation as resolved.
Show resolved Hide resolved
if width == 'std':
p_width = w_std(prop, w)
elif width == 'mad':
p_width = w_mad(prop, w)
else:
raise ValueError('Invalid width property: %s' % width)

return p_center, p_width
soerenjalas marked this conversation as resolved.
Show resolved Hide resolved

def get_mean_gamma( self, t=None, iteration=None, species=None,
select=None ):
"""
Expand Down Expand Up @@ -1030,6 +1114,54 @@ def w_std( a, weights ):
variance = np.average((a - average) ** 2, weights=weights)
return( np.sqrt(variance) )

def w_median(a, weights):
"""
Compute the weighted median of a 1D numpy array.
Parameters
----------
a : ndarray
Input array (one dimension).
weights : ndarray
Array with the weights of the same size of `data`.
Returns
-------
median : float
The output value.
"""
quantile = .5
if not isinstance(a, np.matrix):
a = np.asarray(a)
if not isinstance(weights, np.matrix):
weights = np.asarray(weights)
if a.shape != weights.shape:
raise TypeError("the length of data and weights must be the same")
ind_sorted = np.argsort(a)
sorted_data = a[ind_sorted]
sorted_weights = weights[ind_sorted]

Sn = np.cumsum(sorted_weights)
# Center and normalize the cumsum (i.e. divide by the total sum)
Pn = (Sn - 0.5 * sorted_weights) / Sn[-1]
soerenjalas marked this conversation as resolved.
Show resolved Hide resolved
# Get the value of the weighted median
return np.interp(quantile, Pn, sorted_data)

def w_mad(a, w):
"""
Compute the weighted median absolute deviation of a 1D numpy array.
Parameters
----------
a : ndarray
Input array (one dimension).
weights : ndarray
Array with the weights of the same size of `data`.
Returns
-------
mad : float
The output value.
"""
med = w_median(a, w)
mad = w_median(np.abs(a - med), w)
return mad

def gaussian_profile( x, x0, E0, w0 ):
"""
Expand Down