def calculate_residual_2D(efficiency_data: Hist, efficiency_function: Callable[..., float],
                          efficiency_period: Any, centrality_bin: int) -> Tuple[np.ndarray, List[float], List[float]]:
    """ Calculate residual for 2D tracking efficiency.

    There is a separate 1D and 2D function for convenience. If there is no entries for a particular
    bin, we set the value to NaN so that it can be ignored later when plotting.

    Args:
        efficiency_data: 2D efficiency data.
        efficiency_function: Efficiency function.
        efficiency_period: Efficiency period.
        centrality_bin: Centrality bin.
    Returns:
        Calculated residual, pt values where it was evaluated, eta values where it was evaluated.
    """
    pts = [efficiency_data.GetXaxis().GetBinCenter(x) for x in range(1, efficiency_data.GetXaxis().GetNbins() + 1)]
    etas = [efficiency_data.GetYaxis().GetBinCenter(y) for y in range(1, efficiency_data.GetYaxis().GetNbins() + 1)]
    residual = np.zeros(shape = (efficiency_data.GetXaxis().GetNbins(),
                                 efficiency_data.GetYaxis().GetNbins()))
    # Loop over all of the bins in the data histogram.
    chi_2 = []
    for pt_index, pt in enumerate(pts):
        for eta_index, eta in enumerate(etas):
            x = pt_index + 1
            y = eta_index + 1
            # Calculate the efficiency. It's calculated again here to ensure that it's evaluated at exactly
            # the same location as in the data histogram.
            efficiency_at_value = efficiency_function(pt, eta, centrality_bin, efficiency_period, "task_name")

            # Determine the histogram value, setting it to NaN if there's no entries.
            if np.abs(efficiency_data.GetBinContent(x, y)) < epsilon:
                value = np.nan
            else:
                value = (efficiency_data.GetBinContent(x, y) - efficiency_at_value) / efficiency_at_value * 100.
                # The points around the edges aren't super reliable for calcuating chi squared
                if pt > 1 and np.abs(eta) < 0.8:
                    chi_2.append(np.power(efficiency_data.GetBinContent(x, y) - efficiency_at_value, 2) / np.power(efficiency_data.GetBinError(x, y), 2))

            residual[pt_index, eta_index] = value

    # Check max values
    logger.debug(f"min efficiency_data: {efficiency_data.GetMinimum()}, "
                 f"max efficiency_data: {efficiency_data.GetMaximum()}")
    logger.debug(f"min residual: {np.nanmin(residual)}, max residual: {np.nanmax(residual)}")
    logger.debug(f"standard mean: {np.nanmean(residual)}")
    logger.debug(f"restricted mean: {np.nanmean(residual[:,np.abs(etas) < 0.8])}")
    logger.debug(f"len(pts): {len(pts)}, len(etas): {len(etas)}")

    # Check chi squared
    chi_squared = np.sum(chi_2)
    # 23 is the number of parameters (10 + 13) at any given point
    ndf = len(chi_2) - 23
    logger.warning("NOTE: The restricted chi squared value calculated here may not be super reliable.")
    logger.info(f"Chi squared: {chi_squared}")
    logger.info(f"NDF: {ndf}")
    logger.info(f"chi2/ndf: {chi_squared / ndf}")

    return residual, pts, etas
Ejemplo n.º 2
0
def _access_set_of_values_associated_with_a_bin(
    hist: Hist, bin_of_interest: int,
    response_normalization: ResponseNormalization
) -> Tuple[np.ndarray, np.ndarray]:
    """ Access a set of bins associated with a particular bin value in the other axis.

    For example, if the hist looks like this graphically:

    a b c
    d e f
    g h i <- values (here and above)
    1 2 3 <- bin number

    then in the case of accessing a set of y bins associated with an x bin, for example, x bin 2,
    it would return values h, e, and b.

    Args:
        hist: The histogram whose bins should be accessed. This must be a 2D hist.
        bin_of_interest: Bin which we would like to access.
        response_normalization: Response normalization convention, which dictates which axis to retrieve the bins from.
    Returns:
        Array of the bin contents, Array of bin errors
    """
    # Initial setup
    axis, get_bin = _setup_access_bins(
        response_normalization=response_normalization)

    #logger.debug(f"Axis: {axis(hist)}, getBin: {get_bin}")
    set_of_bins_content = np.zeros(axis(hist).GetNbins())
    set_of_bins_errors = np.zeros(axis(hist).GetNbins())
    for array_index, bin_index in enumerate(range(1,
                                                  axis(hist).GetNbins() + 1)):
        set_of_bins_content[array_index] = hist.GetBinContent(
            get_bin(hist, bin_of_interest, bin_index))
        set_of_bins_errors[array_index] = hist.GetBinError(
            get_bin(hist, bin_of_interest, bin_index))

    return set_of_bins_content, set_of_bins_errors