Source code for pyirf.benchmarks.angular_resolution

import numpy as np
from astropy.table import QTable
from scipy.stats import norm
import astropy.units as u

from ..binning import calculate_bin_indices


ONE_SIGMA_QUANTILE = norm.cdf(1) - norm.cdf(-1)


[docs] def angular_resolution( events, energy_bins, energy_type="true", quantile=ONE_SIGMA_QUANTILE, ): """ Calculate the angular resolution. This implementation corresponds to the 68% containment of the angular distance distribution. Parameters ---------- events : astropy.table.QTable Astropy Table object containing the reconstructed events information. energy_bins: numpy.ndarray(dtype=float, ndim=1) Bin edges in energy. energy_type: str Either "true" or "reco" energy. Default is "true". quantile : float Which quantile to use for the angular resolution, by default, the containment of the 1-sigma region of the normal distribution (~68%) is used. Returns ------- result : astropy.table.QTable QTable containing the 68% containment of the angular distance distribution per each reconstructed energy bin. """ # create a table to make use of groupby operations energy_key = f"{energy_type}_energy" table = QTable(events[[energy_key, "theta"]]) bin_index, valid = calculate_bin_indices(table[energy_key], energy_bins) result = QTable() result[f"{energy_key}_low"] = energy_bins[:-1] result[f"{energy_key}_high"] = energy_bins[1:] result[f"{energy_key}_center"] = 0.5 * (energy_bins[:-1] + energy_bins[1:]) result["n_events"] = 0 key = "angular_resolution" result[key] = u.Quantity(np.nan, table["theta"].unit) # if we get an empty input (no selected events available) # we return the table filled with NaNs if len(events) == 0: return result # use groupby operations to calculate the percentile in each bin by_bin = table[valid].group_by(bin_index[valid]) for bin_idx, group in zip(by_bin.groups.keys, by_bin.groups): result[key][bin_idx] = np.nanquantile(group["theta"], quantile) result["n_events"][bin_idx] = len(group) return result