Beispiel #1
0
def test_calculate_bin_indices():
    from pyirf.binning import calculate_bin_indices

    bins = np.array([0, 1, 2])
    values = [0.5, 0.5, 1, 1.1, 1.9, 2, -1, 2.5]

    true_idx = np.array([0, 0, 1, 1, 1, 2, -1, 2])

    assert np.all(calculate_bin_indices(values, bins) == true_idx)

    # test with units
    bins *= u.TeV
    values *= 1000 * u.GeV
    assert np.all(calculate_bin_indices(values, bins) == true_idx)
Beispiel #2
0
def energy_bias_resolution(
    events,
    energy_bins,
    energy_type="true",
    bias_function=np.median,
    resolution_function=inter_quantile_distance,
):
    """
    Calculate bias and energy resolution.

    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".
    bias_function: callable
        Function used to calculate the energy bias
    resolution_function: callable
        Function used to calculate the energy resolution

    Returns
    -------
    result : astropy.table.Table
        Table containing the energy bias and resolution
        per each bin in true energy.
    """

    # create a table to make use of groupby operations
    table = Table(events[["true_energy", "reco_energy"]])
    table["rel_error"] = (events["reco_energy"] / events["true_energy"]) - 1

    table["bin_index"] = calculate_bin_indices(
        table[f"{energy_type}_energy"].quantity, energy_bins)

    result = Table()
    result[f"{energy_type}_energy_low"] = energy_bins[:-1]
    result[f"{energy_type}_energy_high"] = energy_bins[1:]
    result[f"{energy_type}_energy_center"] = 0.5 * (energy_bins[:-1] +
                                                    energy_bins[1:])

    result["bias"] = np.nan
    result["resolution"] = np.nan

    # use groupby operations to calculate the percentile in each bin
    by_bin = table.group_by("bin_index")

    index = by_bin.groups.keys["bin_index"]
    result["bias"][index] = by_bin["rel_error"].groups.aggregate(bias_function)
    result["resolution"][index] = by_bin["rel_error"].groups.aggregate(
        resolution_function)
    return result
Beispiel #3
0
def angular_resolution(
    events,
    energy_bins,
    energy_type="true",
):
    """
    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".

    Returns
    -------
    result : astropy.table.Table
        Table containing the 68% containment of the angular distance
        distribution per each reconstructed energy bin.
    """

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

    # create a table to make use of groupby operations
    table = Table(events[[f"{energy_type}_energy", "theta"]])

    table["bin_index"] = calculate_bin_indices(
        table[f"{energy_type}_energy"].quantity, energy_bins)

    n_bins = len(energy_bins) - 1
    mask = (table["bin_index"] >= 0) & (table["bin_index"] < n_bins)

    result = Table()
    result[f"{energy_type}_energy_low"] = energy_bins[:-1]
    result[f"{energy_type}_energy_high"] = energy_bins[1:]
    result[f"{energy_type}_energy_center"] = 0.5 * (energy_bins[:-1] +
                                                    energy_bins[1:])

    result["angular_resolution"] = np.nan * u.deg

    # use groupby operations to calculate the percentile in each bin
    by_bin = table[mask].group_by("bin_index")

    index = by_bin.groups.keys["bin_index"]
    result["angular_resolution"][index] = by_bin["theta"].groups.aggregate(
        lambda x: np.quantile(x, ONE_SIGMA_QUANTILE))
    return result