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