Esempio n. 1
0
  def getSignalEfficiency(self):
    '''
      eff(bin) = N_flat(bin) / N_gen
      N_gen = N_reco / filter_efficiency
    '''

    # get number of generated events
    f = ROOT.TFile.Open('root://t3dcachedb.psi.ch:1094/'+self.signal_file.filename, 'READ')
    n_reco = PlottingTools.getNminiAODEvts(self, f)
    n_gen = n_reco / self.signal_file.filter_efficiency

    # get number of selected reco events
    quantity = Quantity(name_flat='hnl_mass', nbins=1, bin_min=0, bin_max=1000)
    hist_flat_bin = PlottingTools.createHisto(self, f, 'signal_tree', quantity, branchname='flat', selection='ismatched==1' if self.selection=='' else 'ismatched==1 && '+self.selection)
    n_selected_bin = hist_flat_bin.GetBinContent(1)
    #print 'n_selected_bin',n_selected_bin

    efficiency = n_selected_bin / n_gen
    #print 'efficiency',efficiency

    return efficiency
Esempio n. 2
0
  def computeWeightQCDMCtoData(self, lumi_data):
    '''
      weight = lumi_data / lumi_mc
    '''

    # get lumi mc
    lumi_mc = 0

    for ifile, qcd_file in enumerate(self.qcd_files):
      if qcd_file.label not in self.white_list: continue

      f_mc = ROOT.TFile.Open('root://t3dcachedb.psi.ch:1094/'+qcd_file.filename, 'READ')
      
      weight = PlottingTools.computeQCDMCWeight(self, PlottingTools.getTree(self, f_mc, 'signal_tree'), qcd_file.cross_section, qcd_file.filter_efficiency)
      weight_mc = 1./weight
      lumi_mc += weight_mc

    weight = lumi_data / lumi_mc 
    err = 0.

    return weight, err
Esempio n. 3
0
  def computeApproxWeightQCDMCtoData(self, quantity, selection):
    '''
      weight = lumi_data / lumi_mc = N_data * sigma_mc / (N_mc * sigma_data) estimated as N_data / N_mc
    '''

    f_data = ROOT.TFile.Open('root://t3dcachedb.psi.ch:1094/'+self.data_file.filename, 'READ')
    hist_data = PlottingTools.createHisto(self, f_data, 'signal_tree', quantity, branchname='flat', selection=selection)
    hist_data.Sumw2()
    n_obs_data = hist_data.GetBinContent(1)
    n_err_data = math.sqrt(n_obs_data) #hist_data.GetBinError(1)

    hist_mc_tot = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=selection)
    n_obs_mc = hist_mc_tot.GetBinContent(1)
    n_err_mc = math.sqrt(n_obs_mc) #hist_mc_tot.GetBinError(1)

    weight = n_obs_data / n_obs_mc

    if n_obs_data != 0 and n_obs_mc != 0:
      err = weight* (n_err_data / n_obs_data + n_err_mc / n_obs_mc)
    else: 
      err = 0

    return weight, err
Esempio n. 4
0
  def computeCrossRatioFromQCDMC(self):
    '''
      Study the correlation of two variables computing the ratio
      r = N_A * ND / N_B * N_C
    '''
    quantity = Quantity(name_flat='hnl_mass', nbins=1, bin_min=0, bin_max=5.4)
    #hist_mc_tot_A = self.getHistoMC(quantity=quantity, selection=self.selection+' && b_mass<6.27 && hnl_charge==0')
    #hist_mc_tot_A = self.getHistoMC(quantity=quantity, selection=self.selection+' && hnl_cos2d>0.993 && hnl_charge==0')
    #hist_mc_tot_A = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && b_mass<6.27 && hnl_charge==0')
    hist_mc_tot_A = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && hnl_cos2d>0.993 && sv_prob>0.05')
    #hist_mc_tot_B = self.getHistoMC(quantity=quantity, selection=self.selection+' && b_mass<6.27 && hnl_charge!=0')
    #hist_mc_tot_B = self.getHistoMC(quantity=quantity, selection=self.selection+' && hnl_cos2d>0.993 && hnl_charge!=0')
    #hist_mc_tot_B = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && b_mass<6.27 && hnl_charge!=0')
    hist_mc_tot_B = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && hnl_cos2d>0.993 && sv_prob<0.05')
    #hist_mc_tot_C = self.getHistoMC(quantity=quantity, selection=self.selection+' && b_mass>6.27 && hnl_charge==0')
    #hist_mc_tot_C = self.getHistoMC(quantity=quantity, selection=self.selection+' && hnl_cos2d<0.993 && hnl_charge==0')
    #hist_mc_tot_C = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && b_mass>6.27 && hnl_charge==0')
    hist_mc_tot_C = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && hnl_cos2d<0.993 && sv_prob>0.05')
    #hist_mc_tot_D = self.getHistoMC(quantity=quantity, selection=self.selection+' && b_mass>6.27 && hnl_charge!=0')
    #hist_mc_tot_D = self.getHistoMC(quantity=quantity, selection=self.selection+' && hnl_cos2d<0.993 && hnl_charge!=0')
    #hist_mc_tot_D = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && b_mass>6.27 && hnl_charge!=0')
    hist_mc_tot_D = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && hnl_cos2d<0.993 && sv_prob<0.05')

    n_obs_mc_A = hist_mc_tot_A.GetBinContent(1)
    n_obs_mc_B = hist_mc_tot_B.GetBinContent(1)
    n_obs_mc_C = hist_mc_tot_C.GetBinContent(1)
    n_obs_mc_D = hist_mc_tot_D.GetBinContent(1)

    n_err_mc_A = hist_mc_tot_A.GetBinError(1) #math.sqrt(n_obs_mc_A) 
    n_err_mc_B = hist_mc_tot_B.GetBinError(1) #math.sqrt(n_obs_mc_B) 
    n_err_mc_C = hist_mc_tot_C.GetBinError(1) #math.sqrt(n_obs_mc_C) 
    n_err_mc_D = hist_mc_tot_D.GetBinError(1) #math.sqrt(n_obs_mc_D) 

    ratio = n_obs_mc_A*n_obs_mc_D/(n_obs_mc_B*n_obs_mc_C)
    err = ratio * (n_err_mc_A/n_obs_mc_A + n_err_mc_B/n_obs_mc_B + n_err_mc_C/n_obs_mc_C + n_err_mc_D/n_obs_mc_D)

    return ratio, err
Esempio n. 5
0
  def computeBkgYieldsFromABCDData(self):
    '''
      Estimate background yields from data using the ABCD method
      A = b_mass < 6.27 && hnl_charge == 0 (SR)
      B = b_mass < 6.27 && hnl_charge != 0 
      C = b_mass > 6.27 && hnl_charge == 0 
      D = b_mass > 6.27 && hnl_charge != 0 

      N_A = N_B * N_C/N_D
    '''
    f_data = ROOT.TFile.Open('root://t3dcachedb.psi.ch:1094/'+self.data_file.filename, 'READ')
    #quantity = Quantity(name_flat='hnl_mass', nbins=1, bin_min=0, bin_max=1000)
    quantity = Quantity(name_flat='hnl_mass', nbins=1, bin_min=2.83268, bin_max=3.13932)

    bin_selection = self.selection

    #hist_data_B = PlottingTools.createHisto(self, f_data, 'signal_tree', quantity, branchname='flat', selection=bin_selection+' && b_mass<6.27 && hnl_charge!=0')
    #hist_data_C = PlottingTools.createHisto(self, f_data, 'signal_tree', quantity, branchname='flat', selection=bin_selection+' && b_mass>6.27 && hnl_charge==0')
    #hist_data_D = PlottingTools.createHisto(self, f_data, 'signal_tree', quantity, branchname='flat', selection=bin_selection+' && b_mass>6.27 && hnl_charge!=0')
    hist_data_B = PlottingTools.createHisto(self, f_data, 'signal_tree', quantity, branchname='flat', selection=bin_selection+' && hnl_cos2d>0.993 && sv_prob<0.05')
    hist_data_C = PlottingTools.createHisto(self, f_data, 'signal_tree', quantity, branchname='flat', selection=bin_selection+' && hnl_cos2d<0.993 && sv_prob>0.05')
    hist_data_D = PlottingTools.createHisto(self, f_data, 'signal_tree', quantity, branchname='flat', selection=bin_selection+' && hnl_cos2d<0.993 && sv_prob<0.05')

    #hist_data.Sumw2()
    n_obs_data_B = hist_data_B.GetBinContent(1)
    n_obs_data_C = hist_data_C.GetBinContent(1)
    n_obs_data_D = hist_data_D.GetBinContent(1)

    n_err_data_B = math.sqrt(hist_data_B.GetBinContent(1))
    n_err_data_C = math.sqrt(hist_data_C.GetBinContent(1))
    n_err_data_D = math.sqrt(hist_data_D.GetBinContent(1))

    n_obs_data_A = n_obs_data_B * (n_obs_data_C / n_obs_data_D) 
    n_err_data_A = n_obs_data_A * (n_err_data_B / n_obs_data_B + n_err_data_C / n_obs_data_C + n_err_data_D / n_obs_data_D)

    return int(n_obs_data_A), int(n_err_data_A)
Esempio n. 6
0
 def __init__(self,
              filename,
              treename='Events',
              matchings=None,
              cuts=None,
              displacement_bins=None,
              pt_bins=None,
              title='',
              outdirlabel='default'):
     self.filename = filename
     self.treename = treename
     self.matchings = matchings
     self.displacement_bins = displacement_bins
     self.pt_bins = pt_bins
     #self.bins = bins # for 1D plot bins can either be in displacement or in pt
     self.cuts = cuts
     self.title = title
     self.outdirlabel = outdirlabel
     self.outputdir = PlottingTools.getOutDir(self, './myPlots/efficiency',
                                              self.outdirlabel)
Esempio n. 7
0
  def computeBkgYieldsFromMC(self):
    '''
      QCD MC (background) yields are computed as N_exp(SR) = N_obs(SR) * weight(CR)
    '''
    #quantity = Quantity(name_flat='hnl_mass', nbins=1, bin_min=0, bin_max=1000)
    quantity = Quantity(name_flat='hnl_mass', nbins=1, bin_min=2.83268, bin_max=3.13932)

    selection_extra = self.selection

    # we compute the weight in the control region
    weight, err_weight = self.computeApproxWeightQCDMCtoData(quantity, selection=('hnl_charge!=0' if selection_extra=='' else 'hnl_charge!=0 &&' + selection_extra))
    #weight, err_weight = self.computeWeightQCDMCtoData(lumi_data=774)

    #hist_mc_tot = self.getHistoMC(quantity=quantity, selection='hnl_charge==0' if selection_extra=='' else 'hnl_charge==0 &&' + selection_extra)
    hist_mc_tot = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection='hnl_charge==0' if selection_extra=='' else 'hnl_charge==0 &&' + selection_extra)
    n_obs_mc = hist_mc_tot.GetBinContent(1)
    n_err_mc = math.sqrt(n_obs_mc) #hist_mc_tot.GetBinError(1)

    n_exp_mc = n_obs_mc * weight
    err = n_exp_mc * (n_err_mc / n_obs_mc + err_weight / weight)

    return int(n_exp_mc), int(err), weight
Esempio n. 8
0
  def validateABCDOnQCDMC(self, plot_name='closure', label=''):
    '''
      Get mupi mass ditribution from data using the ABCD method
      A = b_mass < 6.27 && hnl_charge == 0 (SR)
      B = b_mass < 6.27 && hnl_charge != 0 
      C = b_mass > 6.27 && hnl_charge == 0 
      D = b_mass > 6.27 && hnl_charge != 0 

      and compare it to the actual distribution in the SR
    '''
    #quantity = Quantity(name_flat='hnl_mass', nbins=100, bin_min=0, bin_max=5.6)
    quantity = Quantity(name_flat='hnl_mass', nbins=50, bin_min=0, bin_max=5.37)

    bin_selection = self.selection
    #hist_mc_tot_A = self.getHistoMC(quantity=quantity, selection=self.selection+' && hnl_cos2d>0.993 && sv_prob>0.05')
    #hist_mc_tot_B = self.getHistoMC(quantity=quantity, selection=self.selection+' && b_mass<6.27 && hnl_charge!=0')
    #hist_mc_tot_C = self.getHistoMC(quantity=quantity, selection=self.selection+' && b_mass>6.27 && hnl_charge==0')
    #hist_mc_tot_D = self.getHistoMC(quantity=quantity, selection=self.selection+' && b_mass>6.27 && hnl_charge!=0')

    #hist_mc_tot_A = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && b_mass<6.27 && hnl_charge==0')
    #hist_mc_tot_B = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && b_mass<6.27 && hnl_charge!=0')
    #hist_mc_tot_C = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && b_mass>6.27 && hnl_charge==0')
    #hist_mc_tot_D = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && b_mass>6.27 && hnl_charge!=0')

    hist_mc_tot_A = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && hnl_cos2d>0.993 && sv_prob>0.05')
    hist_mc_tot_B = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && hnl_cos2d>0.993 && sv_prob<0.05')
    hist_mc_tot_C = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && hnl_cos2d<0.993 && sv_prob>0.05')
    hist_mc_tot_D = PlottingTools.createWeightedHistoQCDMC(self, self.qcd_files, self.white_list, quantity=quantity, selection=self.selection+' && hnl_cos2d<0.993 && sv_prob<0.05')

    #hist_estimate = ROOT.TH1D('hist_estimate', 'hist_estimate', 100, 0, 5.6)
    hist_estimate = ROOT.TH1D('hist_estimate', 'hist_estimate', 50, 0, 5.37)
    for ibin in range(1, hist_mc_tot_B.GetNbinsX()+1):
      n_obs_mc_B = hist_mc_tot_B.GetBinContent(ibin)
      n_obs_mc_C = hist_mc_tot_C.GetBinContent(ibin)
      n_obs_mc_D = hist_mc_tot_D.GetBinContent(ibin)
      n_err_mc_B = hist_mc_tot_B.GetBinError(ibin) 
      n_err_mc_C = hist_mc_tot_C.GetBinError(ibin) 
      n_err_mc_D = hist_mc_tot_D.GetBinError(ibin) 
      content = n_obs_mc_B * (n_obs_mc_C / n_obs_mc_D) if n_obs_mc_C != 0 and n_obs_mc_D != 0 else 0
      err = content * (n_err_mc_B / n_obs_mc_B + n_err_mc_C / n_obs_mc_C + n_err_mc_D / n_obs_mc_D) if n_obs_mc_B!=0 and n_obs_mc_C!=0 and n_obs_mc_D!=0 else 0 
      hist_estimate.SetBinContent(ibin, content)
      hist_estimate.SetBinError(ibin, err)

    ROOT.gStyle.SetOptStat(0)

    canv = PlottingTools.getTCanvas(self, 'canv', 800, 900)

    pad_up = ROOT.TPad("pad_up","pad_up",0,0.25,1,1)
    pad_up.SetBottomMargin(0.03)
    pad_up.Draw()
    canv.cd()
    pad_down = ROOT.TPad("pad_down","pad_down",0,0,1,0.25)
    pad_down.SetBottomMargin(0.25)
    pad_down.Draw()

    hist_estimate.SetLineWidth(3)
    hist_estimate.SetLineColor(ROOT.kOrange)
    #hist_estimate.SetTitle('Closure of the ABCD method in the Signal Region')
    hist_estimate.SetTitle('')
    #hist_estimate.GetXaxis().SetTitle('#mu#pi invariant mass [GeV]')
    hist_estimate.GetXaxis().SetLabelSize(0.0)
    hist_estimate.GetXaxis().SetTitleSize(0.0)
    #hist_estimate.GetXaxis().SetTitleOffset(1.1)
    hist_estimate.GetYaxis().SetTitle('Entries')
    hist_estimate.GetYaxis().SetLabelSize(0.037)
    hist_estimate.GetYaxis().SetTitleSize(0.042)
    hist_estimate.GetYaxis().SetTitleOffset(1.1)
    #hist_estimate.GetYaxis().SetRangeUser(1e-9, self.getMaxRangeY(hist_estimate, hist_mc_stack, do_log))

    hist_mc_tot_A.SetLineWidth(3)
    hist_mc_tot_A.SetLineColor(ROOT.kBlue)

    int_estimate = hist_estimate.Integral()
    hist_estimate.Scale(1/int_estimate)
    int_A = hist_mc_tot_A.Integral()
    hist_mc_tot_A.Scale(1/int_A)

    pad_up.cd()
    hist_estimate.Draw('histo')
    hist_mc_tot_A.Draw('histo same')

    legend = PlottingTools.getRootTLegend(self, xmin=0.55, ymin=0.65, xmax=0.8, ymax=0.85, size=0.043)
    legend.AddEntry(hist_estimate, 'QCD ABCD estimate')
    legend.AddEntry(hist_mc_tot_A, 'QCD true')
    legend.Draw()

    label_box = ROOT.TPaveText(0.65,0.4,0.8,0.6, "brNDC")
    label_box.SetBorderSize(0)
    label_box.SetFillColor(ROOT.kWhite)
    label_box.SetTextSize(0.042)
    label_box.SetTextAlign(11)
    label_box.SetTextFont(42)
    label_box.AddText(label)
    label_box.Draw()

    pad_down.cd()

    hist_ratio = PlottingTools.getRatioHistogram(self, hist_estimate, hist_mc_tot_A)
    hist_ratio.Sumw2()

    for ibin in range(0, hist_ratio.GetNbinsX()+1):
      if hist_estimate.GetBinContent(ibin) != 0 and hist_mc_tot_A.GetBinContent(ibin) != 0:
        #err = hist_ratio.GetBinContent(ibin) * (math.sqrt(hist_data.GetBinContent(ibin))/hist_data.GetBinContent(ibin) + math.sqrt(hist_mc_tot.GetBinContent(ibin))/hist_mc_tot.GetBinContent(ibin))
        #err = math.sqrt((math.sqrt(hist_data.GetBinContent(ibin))/hist_mc_tot.GetBinContent(ibin))**2 + (math.sqrt(hist_mc_tot.GetBinContent(ibin))*hist_data.GetBinContent(ibin)/(hist_mc_tot.GetBinContent(ibin))**2)**2)
        #err = math.sqrt((hist_data.GetBinError(ibin)/hist_mc_tot.GetBinContent(ibin))**2 + (hist_mc_tot.GetBinError(ibin)*hist_data.GetBinContent(ibin)/(hist_mc_tot.GetBinContent(ibin))**2)**2)
        err = hist_ratio.GetBinContent(ibin) * (hist_estimate.GetBinError(ibin) / hist_estimate.GetBinContent(ibin) + hist_mc_tot_A.GetBinError(ibin) / hist_mc_tot_A.GetBinContent(ibin))
      else: 
        err = 0
      if hist_ratio.GetBinContent(ibin) != 0: hist_ratio.SetBinError(ibin, err)

    hist_ratio.SetLineWidth(2)
    hist_ratio.SetLineColor(ROOT.kBlack)
    hist_ratio.SetMarkerStyle(20)
    hist_ratio.SetTitle('')
    hist_ratio.GetXaxis().SetTitle('#mu#pi invariant mass [GeV]')
    hist_ratio.GetXaxis().SetLabelSize(0.1)
    hist_ratio.GetXaxis().SetTitleSize(0.15)
    hist_ratio.GetXaxis().SetTitleOffset(0.73)
    hist_ratio.GetYaxis().SetTitle('Estimate/True')
    hist_ratio.GetYaxis().SetLabelSize(0.1)
    hist_ratio.GetYaxis().SetTitleSize(0.13)
    hist_ratio.GetYaxis().SetTitleOffset(0.345)
    #val_min = hist_ratio.GetBinContent(hist_ratio.GetMinimumBin())
    #val_max = hist_ratio.GetBinContent(hist_ratio.GetMaximumBin())
    hist_ratio.GetYaxis().SetRangeUser(-1, 3)

    hist_ratio.Draw('PE')

    line = ROOT.TLine(0, 1, 5.6, 1)
    line.SetLineColor(4)
    line.SetLineWidth(2)
    line.Draw('same')

    
    canv.cd()
    if not path.exists('./myPlots/ABCDClosure'):
      os.system('mkdir -p ./myPlots/ABCDClosure')
    canv.SaveAs('./myPlots/ABCDClosure/{}.png'.format(plot_name))
    canv.SaveAs('./myPlots/ABCDClosure/{}.pdf'.format(plot_name))
    canv.SaveAs('./myPlots/ABCDClosure/{}.C'.format(plot_name))
Esempio n. 9
0
    def getEfficiency(self, displacement_bins=None, pt_bins=None):
        f = ROOT.TFile.Open('root://t3dcachedb.psi.ch:1094/' + self.filename,
                            'READ')
        tree = PlottingTools.getTree(self, f, self.treename)

        if displacement_bins != None and pt_bins != None:
            n_num = np.zeros(
                (len(displacement_bins), len(pt_bins), len(self.matchings)
                 ))  #[[0] * len(displacement_bins)] * len(pt_bins)
            n_deno = np.zeros(
                (len(displacement_bins), len(pt_bins), len(self.matchings)
                 ))  #[[0] * len(displacement_bins)] * len(pt_bins)
            efficiency = np.zeros(
                (len(displacement_bins), len(pt_bins), len(self.matchings)
                 ))  #[[0] * len(displacement_bins)] * len(pt_bins)
            error = np.zeros(
                (len(displacement_bins), len(pt_bins), len(self.matchings)
                 ))  #[[0] * len(displacement_bins)] * len(pt_bins)
        else:
            n_num = np.zeros(len(self.cuts))
            n_deno = np.zeros(len(self.cuts))
            efficiency = np.zeros(len(self.cuts))
            error = np.zeros(len(self.cuts))

        for entry in tree:
            # only consider events with at least one candidate
            if entry.nBToMuMuPi == 0: continue

            #print '\n'
            # retrieve candidate matching information
            trgmu_ismatched = 0
            mu_ismatched = 0
            pi_ismatched = 0
            cand_ismatched = 0
            matched_idx = -1
            for icand in range(0, entry.nBToMuMuPi):
                if entry.BToMuMuPi_trg_mu_isMatched[icand] == 1:
                    trgmu_ismatched = 1
                if entry.BToMuMuPi_sel_mu_isMatched[icand] == 1:
                    mu_ismatched = 1
                if entry.BToMuMuPi_pi_isMatched[icand] == 1: pi_ismatched = 1
                if entry.BToMuMuPi_isMatched[icand] == 1:
                    matched_idx = icand
                    cand_ismatched = 1

            matching_cond = {}
            matching_cond['candidate'] = cand_ismatched == 1
            matching_cond['trigger_muon'] = trgmu_ismatched == 1
            matching_cond['muon'] = mu_ismatched == 1
            matching_cond['pion'] = pi_ismatched == 1

            hnl_idx = -1
            mother_idx = -1
            trgmu_idx = -1
            mu_idx = -1
            pi_idx = -1

            # search for hnl and its mother
            for igen in range(0, entry.nGenPart):
                if entry.GenPart_pdgId[igen] == 9900015:
                    hnl_idx = igen
                    mother_idx = entry.GenPart_genPartIdxMother[hnl_idx]

            # search for trigger muon and hnl daughters
            for igen in range(0, entry.nGenPart):
                if abs(
                        entry.GenPart_pdgId[igen]
                ) == 13 and entry.GenPart_genPartIdxMother[igen] == mother_idx:
                    trgmu_idx = igen
                if abs(entry.GenPart_pdgId[igen]
                       ) == 13 and entry.GenPart_pdgId[
                           entry.GenPart_genPartIdxMother[igen]] == 9900015:
                    mu_idx = igen
                if abs(entry.GenPart_pdgId[igen]
                       ) == 211 and entry.GenPart_pdgId[
                           entry.GenPart_genPartIdxMother[igen]] == 9900015:
                    pi_idx = igen

            # remove e-channel
            if mu_idx == -1: continue

            for imatch, matching in enumerate(self.matchings):
                if displacement_bins != None and pt_bins != None:
                    # fetch n_deno and n_num with acceptance cuts
                    if entry.GenPart_pt[mu_idx] > 1.5 and abs(entry.GenPart_eta[mu_idx]) < 2.5 \
                       and entry.GenPart_pt[pi_idx] > 0.7 and abs(entry.GenPart_eta[pi_idx]) < 2.5 \
                       and entry.GenPart_pt[trgmu_idx] > 7.5:
                        #if entry.GenPart_pt[mu_idx] > 3.5 and abs(entry.GenPart_eta[mu_idx]) < 2.5 \
                        #   and entry.GenPart_pt[pi_idx] > 0.7 and abs(entry.GenPart_eta[pi_idx]) < 2.5 \
                        #   and entry.GenPart_pt[trgmu_idx] > 9.5:
                        #if entry.GenPart_pt[mu_idx] > 0:
                        displacement = math.sqrt(
                            pow(
                                entry.GenPart_vx[mu_idx] -
                                entry.GenPart_vx[trgmu_idx], 2) + pow(
                                    entry.GenPart_vy[mu_idx] -
                                    entry.GenPart_vy[trgmu_idx], 2))
                        if matching == 'candidate':
                            obj_pt = entry.GenPart_pt[hnl_idx]
                        elif matching == 'trigger_muon':
                            obj_pt = entry.GenPart_pt[trgmu_idx]
                        elif matching == 'muon':
                            obj_pt = entry.GenPart_pt[mu_idx]
                        elif matching == 'pion':
                            obj_pt = entry.GenPart_pt[pi_idx]

                        for ibin_disp, displacement_bin in enumerate(
                                displacement_bins):
                            for ibin_pt, pt_bin in enumerate(pt_bins):
                                bin_min_disp, bin_max_disp = displacement_bin
                                bin_min_pt, bin_max_pt = pt_bin

                                if displacement > bin_min_disp and displacement < bin_max_disp and obj_pt > bin_min_pt and obj_pt < bin_max_pt:
                                    n_deno[ibin_disp][ibin_pt][
                                        imatch] = n_deno[ibin_disp][ibin_pt][
                                            imatch] + 1
                                    #print '{} {}'.format(matching, matching_cond[matching])
                                    if matching_cond[matching]:
                                        n_num[ibin_disp][ibin_pt][
                                            imatch] = n_num[ibin_disp][
                                                ibin_pt][imatch] + 1
                else:
                    for icut, cut in enumerate(self.cuts):
                        # fetch n_deno and n_num with acceptance cuts
                        #if entry.GenPart_pt[mu_idx] > float(cut) and abs(entry.GenPart_eta[mu_idx]) < 2.5: # \
                        if entry.GenPart_pt[mu_idx] > 1.5 and abs(entry.GenPart_eta[mu_idx]) < 2.5 \
                           and entry.GenPart_pt[pi_idx] > 0.7 and abs(entry.GenPart_eta[pi_idx]) < 2.5 \
                           and entry.GenPart_pt[trgmu_idx] > float(cut):
                            n_deno[icut] = n_deno[icut] + 1
                            if matching == 'candidate' and cand_ismatched == 1:
                                n_num[icut] = n_num[icut] + 1
                            elif matching == 'trigger_muon' and trgmu_ismatched == 1:
                                n_num[icut] = n_num[icut] + 1
                            elif matching == 'muon' and mu_ismatched == 1:
                                n_num[icut] = n_num[icut] + 1
                            elif matching == 'pion' and pi_ismatched == 1:
                                n_num[icut] = n_num[icut] + 1

        # compute efficiency
        if displacement_bins != None and pt_bins != None:
            for imatch, matching in enumerate(self.matchings):
                for ibin_disp, displacement_bin in enumerate(
                        displacement_bins):
                    for ibin_pt, pt_bin in enumerate(pt_bins):
                        efficiency[ibin_disp][ibin_pt][imatch] = float(
                            n_num[ibin_disp][ibin_pt][imatch]
                        ) / float(n_deno[ibin_disp][ibin_pt][imatch]) if float(
                            n_deno[ibin_disp][ibin_pt][imatch]) != 0. else 0.
                        if n_num[ibin_disp][ibin_pt][imatch] == 0:
                            n_num[ibin_disp][ibin_pt][imatch] = 1e-11
                        if float(n_num[ibin_disp][ibin_pt]
                                 [imatch]) != 0 and float(
                                     n_deno[ibin_disp][ibin_pt][imatch]) != 0:
                            error[ibin_disp][ibin_pt][imatch] = efficiency[
                                ibin_disp][ibin_pt][imatch] * (
                                    math.sqrt(
                                        float(n_num[ibin_disp][ibin_pt]
                                              [imatch])) /
                                    float(n_num[ibin_disp][ibin_pt][imatch]) +
                                    math.sqrt(
                                        float(n_deno[ibin_disp][ibin_pt]
                                              [imatch])) /
                                    float(n_deno[ibin_disp][ibin_pt][imatch]))
                        else:
                            error[ibin_disp][ibin_pt][imatch] = 0
                        # for aesthetics
                        if efficiency[ibin_disp][ibin_pt][imatch] == 0.:
                            efficiency[ibin_disp][ibin_pt][imatch] = 1e-9

            for imatch, matching in enumerate(self.matchings):
                print '\n'
                for ibin_disp, displacement_bin in enumerate(
                        displacement_bins):
                    for ibin_pt, pt_bin in enumerate(pt_bins):
                        print '{} {} {} {} {} {}+-{}'.format(
                            matching, displacement_bin, pt_bin,
                            n_deno[ibin_disp][ibin_pt][imatch],
                            n_num[ibin_disp][ibin_pt][imatch],
                            efficiency[ibin_disp][ibin_pt][imatch],
                            error[ibin_disp][ibin_pt][imatch])
        else:
            for icut, cut in enumerate(self.cuts):
                efficiency[icut] = float(n_num[icut]) / float(
                    n_deno[icut]) if float(n_deno[icut]) != 0. else 0.
                error[icut] = efficiency[icut] * (
                    math.sqrt(n_num[icut]) / n_num[icut] +
                    math.sqrt(n_deno[icut]) / n_deno[icut])

            #for icut, cut in enumerate(self.cuts):
            #  print '{} {} {} {}'.format(cut, n_deno[icut], n_num[icut], efficiency[icut])

        return efficiency, error