h1a_eff = TEfficiency(h1a_numer, h1a_denom)
    h1a_eff.SetStatisticOption(0)  # kFCP
    h1a_eff.SetConfidenceLevel(0.682689492137)  # one sigma
    h1a_eff.SetMarkerColor(632)  # kRed
    h1a_eff.SetLineColor(632)  # kRed
    h1a_eff.SetLineWidth(2)

    h1b_eff = TEfficiency(h1b_numer, h1b_denom)
    h1b_eff.SetStatisticOption(0)  # kFCP
    h1b_eff.SetConfidenceLevel(0.682689492137)  # one sigma
    h1b_eff.SetMarkerColor(600)  # kBlue
    h1b_eff.SetLineColor(600)  # kBlue
    h1b_eff.SetLineWidth(2)

    gr = h1a_eff.CreateGraph()
    gr.Draw("ap")
    frame = gr.GetHistogram()
    frame = frame.Clone(hname + "_frame")
    frame.GetYaxis().SetTitle("#varepsilon")
    frame.SetMinimum(0.0)
    frame.SetMaximum(1.2)
    frame.SetStats(0)
    frame.Draw()
    xmin, xmax = frame.GetXaxis().GetXmin(), frame.GetXaxis().GetXmax()
    tline.DrawLine(xmin, 1.0, xmax, 1.0)
    #h1a_eff.Draw("same")
    h1b_eff.Draw("same")

    draw_cms_lumi()
    gPad.Print("figures_perf/" + hname + "_omtf" + ".png")
def get_mean_efficiency(array_pass, array_total, method=0):
    ''' Function to calculate the mean and the error of the efficiency using different approaches.
    No good approach was found.

    Parameters
    ---------
    array_pass : numpy array
        Array with tracks that were seen by the DUT. Can be a masked array.
    array_total : numpy array
        Array with total tracks in the DUT. Can be a masked array.
    method: number
        Select the method to calculate the efficiency:
          1: Take mean and RMS of the efficiency per bin. Each bin is weightd by the number of total tracks.
             Results in symmetric unphysical error bars that cover also efficiencies > 100%
          2: Takes a correct binomial distribution and calculate the correct confidence interval after combining all pixels.
             Gives correct mean and correct statistical error bars. Systematic efficiency variations are not taken into account, thus
             the error bar is very small. Further info: https://root.cern.ch/doc/master/classTEfficiency.html
          3: As 2. but for each efficiency bin separately. Then the distribution is fitted by a constant using the
             asymmetric error bars. Gives too high efficiencies and small,  asymmetric error bars.
          4: Use a special Binomial efficiency fit. Gives best mean efficiency but unphysical symmetric error
             bars. Further info: https://root.cern.ch/doc/master/classTBinomialEfficiencyFitter.html
    '''

    n_bins = np.ma.count(array_pass)
    logging.info('Calculate the mean efficiency from %d pixels', n_bins)

    if method == 0:

        def weighted_avg_and_std(
            values, weights
        ):  # http://stackoverflow.com/questions/2413522/weighted-standard-deviation-in-numpy
            average = np.average(values, weights=weights)
            variance = np.average(
                (values - average)**2,
                weights=weights)  # Fast and numerically precise
            return (average, np.sqrt(variance))

        efficiency = np.ma.compressed(array_pass) / np.ma.compressed(
            array_total)
        return weighted_avg_and_std(efficiency, np.ma.compressed(array_total))
    else:  # Use CERN ROOT
        try:
            from ROOT import TH1D, TEfficiency, TF1, TBinomialEfficiencyFitter
        except ImportError:
            raise RuntimeError(
                'To use these method you have to install CERN ROOT with python bindings.'
            )

        # Convert not masked numpy array values to 1D ROOT double histogram
        def fill_1d_root_hist(array, name):
            length = np.ma.count(array_pass)
            root_hist = TH1D(name, "hist", length, 0, length)
            for index, value in enumerate(np.ma.compressed(array).ravel()):
                root_hist.SetBinContent(index, value)
            return root_hist

        if method == 1:
            # The following combines all pixel and gives correct
            # statistical errors but does not take the systematic
            # variations of within the  efficiency histogram parts into account
            # Thus gives very small error bars
            hist_pass = TH1D("hist_pass", "hist", 1, 0, 1)
            hist_total = TH1D("hist_total", "hist", 1, 0, 1)
            hist_pass.SetBinContent(0, np.ma.sum(array_pass))
            hist_total.SetBinContent(0, np.ma.sum(array_total))
            efficiency = TEfficiency(hist_pass, hist_total)
            return efficiency.GetEfficiency(
                0), efficiency.GetEfficiencyErrorLow(
                    0), efficiency.GetEfficiencyErrorUp(0)
        elif method == 2:
            # The following fits the efficiency with a constant but
            # it gives symmetric error bars, thus unphysical results
            # This is not understood yet and thus not used

            # Convert numpy array to ROOT hists
            hist_pass = fill_1d_root_hist(array_pass, 'h_pass')
            hist_total = fill_1d_root_hist(array_total, 'h_total')
            f1 = TF1("f1", "pol0(0)", 0, n_bins)
            fitter = TBinomialEfficiencyFitter(hist_pass, hist_total)
            r = fitter.Fit(f1, "SE")
            eff_err_low = r.LowerError(0)
            eff_err_up = r.UpperError(0)
            efficiency = r.GetParams()[0]
            return efficiency, eff_err_low, eff_err_up
        elif method == 3:
            # Fit point of each efficiency bin using asymmetric error bars
            # Parameters described here: https://root.cern.ch/doc/master/classTGraph.html#a61269bcd47a57296f0f1d57ceff8feeb
            # This gives too high efficiency and too small error

            # Convert numpy array to ROOT hists
            hist_pass = fill_1d_root_hist(array_pass, 'h_pass')
            hist_total = fill_1d_root_hist(array_total, 'h_total')
            efficiency = TEfficiency(hist_pass, hist_total)
            f1 = TF1("f1", "pol0(0)", 0, n_bins)
            fit_result = efficiency.CreateGraph().Fit(f1, "SFEM")
            eff_mean = fit_result.GetParams()[0]
            eff_err_low = fit_result.LowerError(0)
            eff_err_up = fit_result.UpperError(0)
            return eff_mean, eff_err_low, eff_err_up