def splitTTjetFlavours(cfg, tree, noSel): subProc = cfg["subprocess"] if subProc == "ttbb": noSel = noSel.refine(subProc, cut=(tree.genTtbarId % 100) >= 52) elif subProc == "ttbj": noSel = noSel.refine(subProc, cut=(tree.genTtbarId % 100) == 51) elif subProc == "ttcc": noSel = noSel.refine(subProc, cut=op.in_range(40, tree.genTtbarId % 100, 46)) elif subProc == "ttjj": noSel = noSel.refine(subProc, cut=(tree.genTtbarId % 100) < 41) return noSel
def definePlots(self, tree, noSel, sample=None, sampleCfg=None): from bamboo.plots import Plot, SummedPlot from bamboo.plots import EquidistantBinning as EqBin from bamboo import treefunctions as op plots = [] metSel = noSel.refine("MET", cut=(tree.met.et > 30000)) trigSel = metSel.refine("trig", cut=op.OR(tree.trigE, tree.trigM)) goodLeptons = op.select( tree.lep, lambda l: op.AND(l.isTightID, l.pt > 35000., l.ptcone30 / l.pt < 0.1, l.etcone20 / l.pt < 0.1)) oneLepSel = trigSel.refine("1goodlep", cut=(op.rng_len(goodLeptons) == 1)) lep = goodLeptons[0] signalSel = oneLepSel.refine( "signalRegion", cut=op.AND( op.abs(lep.z0 * op.sin(lep.p4.theta())) < 0.5, op.multiSwitch( (lep.type == 11, op.AND( op.abs(lep.eta) < 2.46, op.NOT(op.in_range(1.37, op.abs(lep.eta), 1.52)), op.abs(lep.trackd0pvunbiased / lep.tracksigd0pvunbiased) < 5)), (lep.type == 13, op.AND( op.abs(lep.eta) < 2.5, op.abs(lep.trackd0pvunbiased / lep.tracksigd0pvunbiased) < 3)), op.c_bool(False)))) metp4 = makePtEtaPhiEP4(tree.met.et, op.c_float(0.), tree.met.phi, tree.met.et) plots.append( Plot.make1D("mt_w", (lep.p4 + metp4).Mt() / 1000., signalSel, EqBin(40, 60., 180.), title="m_{T}^{W#rightarrow l#nu} (GeV)", plotopts={"log-y-axis-range": [25., 2.5e8]})) return plots
def definePlots(self, tree, noSel, sample=None, sampleCfg=None): from bamboo.plots import Plot from bamboo.plots import EquidistantBinning as EqBin from bamboo import treefunctions as op plots = [] dimu_Z = op.combine( tree.Muon, N=2, pred=(lambda mu1, mu2: op.AND( mu1.charge != mu2.charge, op.in_range(60., op.invariant_mass(mu1.p4, mu2.p4), 120.)))) hasDiMuZ = noSel.refine("hasDiMuZ", cut=(op.rng_len(dimu_Z) > 0)) plots.append( Plot.make1D("dimuZ_MET", tree.MET.pt, hasDiMuZ, EqBin(100, 0., 2000.), title="MET (GeV)")) return plots
def definePlots(self, t, noSel, sample=None, sampleCfg=None): # Some imports # from bamboo.analysisutils import forceDefine era = sampleCfg['era'] # Get pile-up configs # puWeightsFile = None if era == "2016": sfTag = "94X" puWeightsFile = os.path.join(os.path.dirname(__file__), "data", "puweights2016.json") elif era == "2017": sfTag = "94X" puWeightsFile = os.path.join(os.path.dirname(__file__), "data", "puweights2017.json") elif era == "2018": sfTag = "102X" puWeightsFile = os.path.join(os.path.dirname(__file__), "data", "puweights2018.json") if self.isMC(sample) and puWeightsFile is not None: from bamboo.analysisutils import makePileupWeight noSel = noSel.refine("puWeight", weight=makePileupWeight(puWeightsFile, t.Pileup_nTrueInt, systName="pileup")) isMC = self.isMC(sample) plots = [] forceDefine(t._Muon.calcProd, noSel) ############################################################################# ################################ Muons ##################################### ############################################################################# # Wp // 2016- 2017 -2018 : Muon_mediumId // https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideMuonIdRun2#Muon_Isolation muonsByPt = op.sort(t.Muon, lambda mu: -mu.p4.Pt()) muons = op.select( muonsByPt, lambda mu: op.AND(mu.p4.Pt() > 10., op.abs(mu.p4.Eta()) < 2.4, mu.tightId, mu.pfRelIso04_all < 0.15)) # Scalefactors # #if era=="2016": # doubleMuTrigSF = get_scalefactor("dilepton", ("doubleMuLeg_HHMoriond17_2016"), systName="mumutrig") # muMediumIDSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "id_medium"), combine="weight", systName="muid") # muMediumISOSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "iso_tight_id_medium"), combine="weight", systName="muiso") # TrkIDSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "highpt"), combine="weight") # TrkISOSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "isotrk_loose_idtrk_tightidandipcut"), combine="weight") #else: # muMediumIDSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "id_medium"), systName="muid") # muMediumISOSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "iso_tight_id_medium"), systName="muiso") ############################################################################# ############################# Electrons ################################### ############################################################################# #Wp // 2016: Electron_cutBased_Sum16==3 -> medium // 2017 -2018 : Electron_cutBased ==3 --> medium ( Fall17_V2) # asking for electrons to be in the Barrel region with dz<1mm & dxy< 0.5mm // Endcap region dz<2mm & dxy< 0.5mm electronsByPt = op.sort(t.Electron, lambda ele: -ele.p4.Pt()) electrons = op.select( electronsByPt, lambda ele: op.AND(ele.p4.Pt() > 15., op.abs(ele.p4.Eta()) < 2.5, ele.cutBased >= 3) ) # //cut-based ID Fall17 V2 the recomended one from POG for the FullRunII # Scalefactors # #elMediumIDSF = get_scalefactor("lepton", ("electron_{0}_{1}".format(era,sfTag), "id_medium"), systName="elid") #doubleEleTrigSF = get_scalefactor("dilepton", ("doubleEleLeg_HHMoriond17_2016"), systName="eleltrig") #elemuTrigSF = get_scalefactor("dilepton", ("elemuLeg_HHMoriond17_2016"), systName="elmutrig") #mueleTrigSF = get_scalefactor("dilepton", ("mueleLeg_HHMoriond17_2016"), systName="mueltrig") OsElEl = op.combine( electrons, N=2, pred=lambda el1, el2: op.AND(el1.charge != el2.charge, el1.p4.Pt() > 25, el2.p4.Pt() > 15)) OsMuMu = op.combine( muons, N=2, pred=lambda mu1, mu2: op.AND(mu1.charge != mu2.charge, mu1.p4.Pt() > 25, mu2.p4.Pt() > 15)) OsElMu = op.combine((electrons, muons), pred=lambda el, mu: op.AND(el.charge != mu.charge, el.p4.Pt() > 25, mu.p4.Pt() > 15)) OsMuEl = op.combine((electrons, muons), pred=lambda el, mu: op.AND(el.charge != mu.charge, el.p4.Pt() > 15, mu.p4.Pt() > 25)) hasOsElEl = noSel.refine("hasOsElEl", cut=[op.rng_len(OsElEl) >= 1]) hasOsMuMu = noSel.refine("hasOsMuMu", cut=[op.rng_len(OsMuMu) >= 1]) hasOsElMu = noSel.refine("hasOsElMu", cut=[op.rng_len(OsElMu) >= 1]) hasOsMuEl = noSel.refine("hasOsMuEl", cut=[op.rng_len(OsMuEl) >= 1]) plots.append( Plot.make1D("ElEl_channel", op.rng_len(OsElEl), noSel, EquidistantBinning(10, 0, 10.), title='Number of dilepton events in ElEl channel', xTitle='N_{dilepton} (ElEl channel)')) plots.append( Plot.make1D("MuMu_channel", op.rng_len(OsMuMu), noSel, EquidistantBinning(10, 0, 10.), title='Number of dilepton events in MuMu channel', xTitle='N_{dilepton} (MuMu channel)')) plots.append( Plot.make1D("ElMu_channel", op.rng_len(OsElMu), noSel, EquidistantBinning(10, 0, 10.), title='Number of dilepton events in ElMu channel', xTitle='N_{dilepton} (ElMu channel)')) plots.append( Plot.make1D("MuEl_channel", op.rng_len(OsMuEl), noSel, EquidistantBinning(10, 0, 10.), title='Number of dilepton events in MuEl channel', xTitle='N_{dilepton} (MuEl channel)')) plots += makeDileptonPlots(self, sel=hasOsElEl, dilepton=OsElEl[0], suffix='hasOsdilep', channel='ElEl') plots += makeDileptonPlots(self, sel=hasOsMuMu, dilepton=OsMuMu[0], suffix='hasOsdilep', channel='MuMu') plots += makeDileptonPlots(self, sel=hasOsElMu, dilepton=OsElMu[0], suffix='hasOsdilep', channel='ElMu') plots += makeDileptonPlots(self, sel=hasOsMuEl, dilepton=OsMuEl[0], suffix='hasOsdilep', channel='MuEl') # Dilepton Z peak exclusion (charge already done in previous selection) # lambda_mllLowerband = lambda dilep: op.in_range( 12., op.invariant_mass(dilep[0].p4, dilep[1].p4), 80.) lambda_mllUpperband = lambda dilep: op.invariant_mass( dilep[0].p4, dilep[1].p4) > 100. lambda_mllCut = lambda dilep: op.OR(lambda_mllLowerband(dilep), lambda_mllUpperband(dilep)) hasOsElElOutZ = hasOsElEl.refine("hasOsElElOutZ", cut=[lambda_mllCut(OsElEl[0])]) hasOsMuMuOutZ = hasOsMuMu.refine("hasOsMuMuOutZ", cut=[lambda_mllCut(OsMuMu[0])]) hasOsElMuOutZ = hasOsElMu.refine("hasOsElMuOutZ", cut=[lambda_mllCut(OsElMu[0])]) hasOsMuElOutZ = hasOsMuEl.refine("hasOsMuElOutZ", cut=[lambda_mllCut(OsMuEl[0])]) plots += makeDileptonPlots(self, sel=hasOsElElOutZ, dilepton=OsElEl[0], suffix='hasOsdilep_OutZ', channel='ElEl') plots += makeDileptonPlots(self, sel=hasOsMuMuOutZ, dilepton=OsMuMu[0], suffix='hasOsdilep_OutZ', channel='MuMu') plots += makeDileptonPlots(self, sel=hasOsElMuOutZ, dilepton=OsElMu[0], suffix='hasOsdilep_OutZ', channel='ElMu') plots += makeDileptonPlots(self, sel=hasOsMuElOutZ, dilepton=OsMuEl[0], suffix='hasOsdilep_OutZ', channel='MuEl') ############################################################################# ################################ Jets ##################################### ############################################################################# # select jets // 2016 - 2017 - 2018 ( j.jetId &2) -> tight jet ID jetsByPt = op.sort(t.Jet, lambda jet: -jet.p4.Pt()) jetsSel = op.select(jetsByPt, lambda j: op.AND(j.p4.Pt() > 20., op.abs(j.p4.Eta()) < 2.4, (j.jetId & 2))) # Jets = AK4 jets fatjetsByPt = op.sort(t.FatJet, lambda fatjet: -fatjet.p4.Pt()) fatjetsSel = op.select( fatjetsByPt, lambda j: op.AND(j.p4.Pt() > 20., op.abs(j.p4.Eta()) < 2.4, (j.jetId & 2))) # FatJets = AK8 jets # exclude from the jetsSel any jet that happens to include within its reconstruction cone a muon or an electron. jets = op.select( jetsSel, lambda j: op.AND( op.NOT( op.rng_any(electrons, lambda ele: op.deltaR(j.p4, ele.p4) < 0.3)), op.NOT( op.rng_any(muons, lambda mu: op.deltaR(j.p4, mu.p4) < 0.3)) )) fatjets = op.select( fatjetsSel, lambda j: op.AND( op.NOT( op.rng_any(electrons, lambda ele: op.deltaR(j.p4, ele.p4) < 0.3)), op.NOT( op.rng_any(muons, lambda mu: op.deltaR(j.p4, mu.p4) < 0.3)) )) # Boosted and resolved jets categories # if era == "2016": # Must check that subJet exists before looking at the btag lambda_boosted = lambda fatjet: op.OR( op.AND(fatjet.subJet1._idx.result != -1, fatjet.subJet1. btagDeepB > 0.6321), op.AND(fatjet.subJet2._idx.result != -1, fatjet.subJet2. btagDeepB > 0.6321)) lambda_resolved = lambda jet: jet.btagDeepB > 0.6321 elif era == "2017": lambda_boosted = lambda fatjet: op.OR( op.AND(fatjet.subJet1._idx.result != -1, fatjet.subJet1. btagDeepB > 0.4941), op.AND(fatjet.subJet2._idx.result != -1, fatjet.subJet2. btagDeepB > 0.4941)) lambda_resolved = lambda jet: jet.btagDeepB > 0.4941 elif era == "2018": lambda_boosted = lambda fatjet: op.OR( op.AND(fatjet.subJet1._idx.result != -1, fatjet.subJet1. btagDeepB > 0.4184), op.AND(fatjet.subJet2._idx.result != -1, fatjet.subJet2. btagDeepB > 0.4184)) lambda_resolved = lambda jet: jet.btagDeepB > 0.4184 # Select the bjets we want # bjetsResolved = op.select(jets, lambda_resolved) bjetsBoosted = op.select(fatjets, lambda_boosted) # Define the boosted and Resolved (+exclusive) selections # hasBoostedJets = noSel.refine("hasBoostedJets", cut=[op.rng_len(bjetsBoosted) >= 1]) hasNotBoostedJets = noSel.refine("hasNotBoostedJets", cut=[op.rng_len(bjetsBoosted) == 0]) hasResolvedJets = noSel.refine( "hasResolvedJets", cut=[op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1]) hasNotResolvedJets = noSel.refine( "hasNotResolvedJets", cut=[op.OR(op.rng_len(jets) <= 1, op.rng_len(bjetsResolved) == 0)]) hasBoostedAndResolvedJets = noSel.refine( "hasBoostedAndResolvedJets", cut=[ op.rng_len(bjetsBoosted) >= 1, op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1 ]) hasNotBoostedAndResolvedJets = noSel.refine( "hasNotBoostedAndResolvedJets", cut=[ op.OR( op.rng_len(bjetsBoosted) == 0, op.rng_len(jets) <= 1, op.rng_len(bjetsResolved) == 0) ]) hasExlusiveResolvedJets = noSel.refine( "hasExlusiveResolved", cut=[ op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1, op.rng_len(bjetsBoosted) == 0 ]) hasNotExlusiveResolvedJets = noSel.refine( "hasNotExlusiveResolved", cut=[ op.OR( op.OR( op.rng_len(jets) <= 1, op.rng_len(bjetsResolved) == 0), op.AND( op.rng_len(bjetsBoosted) >= 1, op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1)) ]) hasExlusiveBoostedJets = noSel.refine( "hasExlusiveBoostedJets", cut=[ op.rng_len(bjetsBoosted) >= 1, op.OR(op.rng_len(jets) <= 1, op.rng_len(bjetsResolved) == 0) ]) hasNotExlusiveBoostedJets = noSel.refine( "hasNotExlusiveBoostedJets", cut=[ op.OR( op.rng_len(bjetsBoosted) == 0, op.AND( op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1)) ]) # Counting events from different selections for debugging # # Passing Boosted selection # PassedBoosted = Plot.make1D("PassedBoosted", op.c_int(1), hasBoostedJets, EquidistantBinning(2, 0., 2.), title='Passed Boosted', xTitle='Passed Boosted') FailedBoosted = Plot.make1D("FailedBoosted", op.c_int(0), hasNotBoostedJets, EquidistantBinning(2, 0., 2.), title='Failed Boosted', xTitle='Failed Boosted') plots.append( SummedPlot("BoostedCase", [FailedBoosted, PassedBoosted], xTitle="Boosted selection")) # Passing Resolved selection # PassedResolved = Plot.make1D("PassedResolved", op.c_int(1), hasResolvedJets, EquidistantBinning(2, 0., 2.), title='Passed Resolved', xTitle='Passed Resolved') FailedResolved = Plot.make1D("FailedResolved", op.c_int(0), hasNotResolvedJets, EquidistantBinning(2, 0., 2.), title='Failed Resolved', xTitle='Failed Resolved') plots.append( SummedPlot("ResolvedCase", [FailedResolved, PassedResolved], xTitle="Resolved selection")) # Passing Exclusive Resolved (Resolved AND NOT Boosted) # PassedExclusiveResolved = Plot.make1D( "PassedExclusiveResolved", op.c_int(1), hasExlusiveResolvedJets, EquidistantBinning(2, 0., 2.), title='Passed Exclusive Resolved', xTitle='Passed Exclusive Resolved') FailedExclusiveResolved = Plot.make1D( "FailedExclusiveResolved", op.c_int(0), hasNotExlusiveResolvedJets, EquidistantBinning(2, 0., 2.), title='Failed Exclusive Resolved', xTitle='Failed Exclusive Resolved') plots.append( SummedPlot("ExclusiveResolvedCase", [FailedExclusiveResolved, PassedExclusiveResolved], xTitle="Exclusive Resolved selection")) # Passing Exclusive Boosted (Boosted AND NOT Resolved) # PassedExclusiveBoosted = Plot.make1D("PassedExclusiveBoosted", op.c_int(1), hasExlusiveBoostedJets, EquidistantBinning(2, 0., 2.), title='Passed Exclusive Boosted', xTitle='Passed Exclusive Boosted') FailedExclusiveBoosted = Plot.make1D("FailedExclusiveBoosted", op.c_int(0), hasNotExlusiveBoostedJets, EquidistantBinning(2, 0., 2.), title='Failed Exclusive Boosted', xTitle='Failed Exclusive Boosted') plots.append( SummedPlot("ExclusiveBoostedCase", [FailedExclusiveBoosted, PassedExclusiveBoosted], xTitle="Exclusive Boosted selection")) # Passing Boosted AND Resolved # PassedBoth = Plot.make1D("PassedBoth", op.c_int(1), hasBoostedAndResolvedJets, EquidistantBinning(2, 0., 2.), title='Passed Both Boosted and Resolved', xTitle='Passed Boosted and Resolved') FailedBoth = Plot.make1D( "FailedBoth", # Means failed the (Boosted AND Resolved) = either one or the other op.c_int(0), hasNotBoostedAndResolvedJets, EquidistantBinning(2, 0., 2.), title='Failed combination Boosted and Resolved', xTitle='Failed combination') plots.append( SummedPlot("BoostedAndResolvedCase", [FailedBoth, PassedBoth], xTitle="Boosted and Resolved selection")) # Count number of boosted and resolved jets # plots.append( Plot.make1D("NBoostedJets", op.rng_len(bjetsBoosted), hasBoostedJets, EquidistantBinning(5, 0., 5.), title='Number of boosted jets in boosted case', xTitle='N boosted bjets')) plots.append( Plot.make1D( "NResolvedJets", op.rng_len(bjetsResolved), hasExlusiveResolvedJets, EquidistantBinning(5, 0., 5.), title='Number of resolved jets in exclusive resolved case', xTitle='N resolved bjets')) # Plot number of subjets in the boosted fatjets # lambda_noSubjet = lambda fatjet: op.AND( fatjet.subJet1._idx.result == -1, op.AND(fatjet.subJet2._idx.result == -1)) lambda_oneSubjet = lambda fatjet: op.AND( fatjet.subJet1._idx.result != -1, op.AND(fatjet.subJet2._idx.result == -1)) lambda_twoSubjet = lambda fatjet: op.AND( fatjet.subJet1._idx.result != -1, op.AND(fatjet.subJet2._idx.result != -1)) hasNoSubjet = hasBoostedJets.refine( "hasNoSubjet", cut=[lambda_noSubjet(bjetsBoosted[0])]) hasOneSubjet = hasBoostedJets.refine( "hasOneSubjet", cut=[lambda_oneSubjet(bjetsBoosted[0])]) hasTwoSubjet = hasBoostedJets.refine( "hasTwoSubjet", cut=[lambda_twoSubjet(bjetsBoosted[0])]) plot_hasNoSubjet = Plot.make1D( "plot_hasNoSubjet", # Fill bin 0 op.c_int(0), hasNoSubjet, EquidistantBinning(3, 0., 3.), title='Boosted jet without subjet') plot_hasOneSubjet = Plot.make1D( "plot_hasOneSubjet", # Fill bin 1 op.c_int(1), hasOneSubjet, EquidistantBinning(3, 0., 3.), title='Boosted jet with one subjet') plot_hasTwoSubjet = Plot.make1D( "plot_hasTwoSubjet", # Fill bin 2 op.c_int(2), hasTwoSubjet, EquidistantBinning(3, 0., 3.), title='Boosted jet with two subjets') plots.append( SummedPlot( "NumberOfSubjets", [plot_hasNoSubjet, plot_hasOneSubjet, plot_hasTwoSubjet], xTitle="Number of subjets in boosted jet")) # Plot jets quantities without the dilepton selections # plots += makeFatJetPlots(self, sel=hasBoostedJets, fatjet=bjetsBoosted[0], suffix="BoostedJets", channel="NoChannel") plots += makeJetsPlots(self, sel=hasResolvedJets, jets=bjetsResolved, suffix="ResolvedJets", channel="NoChannel") ############################################################################# ##################### Jets + Dilepton combination ########################### ############################################################################# # Combine dilepton and Resolved (Exclusive = NOT Boosted) selections # hasOsElElOutZResolvedJets = hasOsElElOutZ.refine( "hasOsElElOutZResolvedJets", cut=[ op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1, op.rng_len(bjetsBoosted) == 0 ]) hasOsMuMuOutZResolvedJets = hasOsMuMuOutZ.refine( "hasOsMuMuOutZResolvedJets", cut=[ op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1, op.rng_len(bjetsBoosted) == 0 ]) hasOsElMuOutZResolvedJets = hasOsElMuOutZ.refine( "hasOsElMuOutZResolvedJets", cut=[ op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1, op.rng_len(bjetsBoosted) == 0 ]) hasOsMuElOutZResolvedJets = hasOsMuElOutZ.refine( "hasOsMuElOutZResolvedJets", cut=[ op.rng_len(jets) >= 2, op.rng_len(bjetsResolved) >= 1, op.rng_len(bjetsBoosted) == 0 ]) # Combine dilepton and Boosted selections # hasOsElElOutZBoostedJets = hasOsElElOutZ.refine( "hasOsElElOutZBoostedJets", cut=[op.rng_len(bjetsBoosted) >= 1]) hasOsMuMuOutZBoostedJets = hasOsMuMuOutZ.refine( "hasOsMuMuOutZBoostedJets", cut=[op.rng_len(bjetsBoosted) >= 1]) hasOsElMuOutZBoostedJets = hasOsElMuOutZ.refine( "hasOsElMuOutZBoostedJets", cut=[op.rng_len(bjetsBoosted) >= 1]) hasOsMuElOutZBoostedJets = hasOsMuElOutZ.refine( "hasOsMuElOutZBoostedJets", cut=[op.rng_len(bjetsBoosted) >= 1]) # Plot dilepton with OS, Z peak and Resolved jets selections # plots += makeDileptonPlots(self, sel=hasOsElElOutZResolvedJets, dilepton=OsElEl[0], suffix='hasOsdilep_OutZ_ResolvedJets', channel='ElEl') plots += makeDileptonPlots(self, sel=hasOsMuMuOutZResolvedJets, dilepton=OsMuMu[0], suffix='hasOsdilep_OutZ_ResolvedJets', channel='MuMu') plots += makeDileptonPlots(self, sel=hasOsElMuOutZResolvedJets, dilepton=OsElMu[0], suffix='hasOsdilep_OutZ_ResolvedJets', channel='ElMu') plots += makeDileptonPlots(self, sel=hasOsMuElOutZResolvedJets, dilepton=OsMuEl[0], suffix='hasOsdilep_OutZ_ResolvedJets', channel='MuEl') # Plot dilepton with OS dilepton, Z peak and Boosted jets selections # plots += makeDileptonPlots(self, sel=hasOsElElOutZBoostedJets, dilepton=OsElEl[0], suffix='hasOsdilep_OutZ_BoostedJets', channel='ElEl') plots += makeDileptonPlots(self, sel=hasOsMuMuOutZBoostedJets, dilepton=OsMuMu[0], suffix='hasOsdilep_OutZ_BoostedJets', channel='MuMu') plots += makeDileptonPlots(self, sel=hasOsElMuOutZBoostedJets, dilepton=OsElMu[0], suffix='hasOsdilep_OutZ_BoostedJets', channel='ElMu') plots += makeDileptonPlots(self, sel=hasOsMuElOutZBoostedJets, dilepton=OsMuEl[0], suffix='hasOsdilep_OutZ_BoostedJets', channel='MuEl') # Plotting the fatjet for OS dilepton, Z peak and Boosted jets selections # plots += makeFatJetPlots(self, sel=hasOsElElOutZBoostedJets, fatjet=bjetsBoosted[0], suffix="hasOsdilep_OutZ_BoostedJets", channel="ElEl") plots += makeFatJetPlots(self, sel=hasOsMuMuOutZBoostedJets, fatjet=bjetsBoosted[0], suffix="hasOsdilep_OutZ_BoostedJets", channel="MuMu") plots += makeFatJetPlots(self, sel=hasOsElMuOutZBoostedJets, fatjet=bjetsBoosted[0], suffix="hasOsdilep_OutZ_BoostedJets", channel="ElMu") plots += makeFatJetPlots(self, sel=hasOsMuElOutZBoostedJets, fatjet=bjetsBoosted[0], suffix="hasOsdilep_OutZ_BoostedJets", channel="MuEl") # Plotting the jets for OS dilepton, Z peak and Resolved jets selections # plots += makeJetsPlots(self, sel=hasOsElElOutZResolvedJets, jets=bjetsResolved, suffix="hasOsdilep_OutZ_ResolvedJets", channel="ElEl") plots += makeJetsPlots(self, sel=hasOsMuMuOutZResolvedJets, jets=bjetsResolved, suffix="hasOsdilep_OutZ_ResolvedJets", channel="MuMu") plots += makeJetsPlots(self, sel=hasOsElMuOutZResolvedJets, jets=bjetsResolved, suffix="hasOsdilep_OutZ_ResolvedJets", channel="ElMu") plots += makeJetsPlots(self, sel=hasOsMuElOutZResolvedJets, jets=bjetsResolved, suffix="hasOsdilep_OutZ_ResolvedJets", channel="MuEl") ## helper selection (OR) to make sure jet calculations are only done once #hasOSLL = noSel.refine("hasOSLL", cut=op.OR(*( hasOSLL_cmbRng(rng) for rng in osLLRng.values()))) #forceDefine(t._Jet.calcProd, hasOSLL) #for varNm in t._Jet.available: # forceDefine(t._Jet[varNm], hasOSLL) return plots
def definePlots(self, tree, noSel, sample=None, sampleCfg=None): from bamboo.plots import Plot, SummedPlot from bamboo.plots import EquidistantBinning as EqBin from bamboo import treefunctions as op if self.args.examples == "all": examples = list(i+1 for i in range(self.nExamples)) # 1-4 are fine, so is 7 else: examples = list(set(int(tk) for tk in self.args.examples.split(","))) logger.info("Running the following examples: {0}".format(",".join(str(i) for i in examples))) plots = [] if 1 in examples: ## Example 1: Plot the missing ET of all events. plots.append(Plot.make1D("Ex1_MET", tree.MET.pt, noSel, EqBin(100, 0., 2000.), title="MET (GeV)")) if 2 in examples: ## Example 2: Plot pT of all jets in all events. plots.append(Plot.make1D("Ex2_jetPt", op.map(tree.Jet, lambda j : j.pt), noSel, EqBin(100, 15., 60.), title="Jet p_{T} (GeV/c)")) if 3 in examples: ## Example 3: Plot pT of jets with |η| < 1. centralJets1 = op.select(tree.Jet, lambda j : op.abs(j.eta) < 1.) plots.append(Plot.make1D("Ex3_central1_jetPt", op.map(centralJets1, lambda j : j.pt), noSel, EqBin(100, 15., 60.), title="Jet p_{T} (GeV/c)")) if 4 in examples: ## Example 4: Plot the missing ET of events that have at least two jets with pT > 40 GeV. jets40 = op.select(tree.Jet, lambda j : j.pt > 40) hasTwoJets40 = noSel.refine("twoJets40", cut=(op.rng_len(jets40) >= 2)) plots.append(Plot.make1D("Ex4_twoJets40_MET", tree.MET.pt, hasTwoJets40, EqBin(100, 0., 2000.), title="MET (GeV)")) if 5 in examples: ## Example 5: Plot the missing ET of events that have an opposite-sign muon pair with an invariant mass between 60 and 120 GeV. dimu_Z = op.combine(tree.Muon, N=2, pred=(lambda mu1, mu2 : op.AND( mu1.charge != mu2.charge, op.in_range(60., op.invariant_mass(mu1.p4, mu2.p4), 120.) ))) hasDiMuZ = noSel.refine("hasDiMuZ", cut=(op.rng_len(dimu_Z) > 0)) plots.append(Plot.make1D("Ex5_dimuZ_MET", tree.MET.pt, hasDiMuZ, EqBin(100, 0., 2000.), title="MET (GeV)")) if 6 in examples: ## Example 6: Plot pT of the trijet system with the mass closest to 172.5 GeV in each event and plot the maximum b-tagging discriminant value among the jets in the triplet. trijets = op.combine(tree.Jet, N=3) hadTop = op.rng_min_element_by(trijets, fun=lambda comb: op.abs((comb[0].p4+comb[1].p4+comb[2].p4).M()-172.5)) hadTop_p4 = (hadTop[0].p4 + hadTop[1].p4 + hadTop[2].p4) hasTriJet = noSel.refine("hasTriJet", cut=(op.rng_len(trijets) > 0)) plots.append(Plot.make1D("Ex6_trijet_topPt", hadTop_p4.Pt(), hasTriJet, EqBin(100, 15., 40.), title="Trijet p_{T} (GeV/c)")) plots.append(Plot.make1D("Ex6_trijet_maxbtag", op.max(op.max(hadTop[0].btag, hadTop[1].btag), hadTop[2].btag), hasTriJet, EqBin(100, 0., 1.), title="Trijet maximum b-tag")) if verbose: plots.append(Plot.make1D("Ex6_njets", op.rng_len(tree.Jet), noSel, EqBin(20, 0., 20.), title="Number of jets")) plots.append(Plot.make1D("Ex6_ntrijets", op.rng_len(trijets), noSel, EqBin(100, 0., 1000.), title="Number of 3-jet combinations")) plots.append(Plot.make1D("Ex6_trijet_mass", hadTop_p4.M(), hasTriJet, EqBin(100, 0., 250.), title="Trijet mass (GeV/c^{2})")) if 7 in examples: ## Example 7: Plot the sum of pT of jets with pT > 30 GeV that are not within 0.4 in ΔR of any lepton with pT > 10 GeV. el10 = op.select(tree.Electron, lambda el : el.pt > 10.) mu10 = op.select(tree.Muon , lambda mu : mu.pt > 10.) cleanedJets30 = op.select(tree.Jet, lambda j : op.AND( j.pt > 30., op.NOT(op.rng_any(el10, lambda el : op.deltaR(j.p4, el.p4) < 0.4 )), op.NOT(op.rng_any(mu10, lambda mu : op.deltaR(j.p4, mu.p4) < 0.4 )) )) plots.append(Plot.make1D("Ex7_sumCleanedJetPt", op.rng_sum(cleanedJets30, lambda j : j.pt), noSel, EqBin(100, 15., 200.), title="Sum p_{T} (GeV/c)")) if 8 in examples: ## Example 8: For events with at least three leptons and a same-flavor opposite-sign lepton pair, find the same-flavor opposite-sign lepton pair with the mass closest to 91.2 GeV and plot the transverse mass of the missing energy and the leading other lepton. # The plot is made for each of the different flavour categories (l+/- l-/+ l') and then summed, # because concatenation of containers is not (yet) supported. lepColl = { "El" : tree.Electron, "Mu" : tree.Muon } mt3lPlots = [] for dlNm,dlCol in lepColl.items(): dilep = op.combine(dlCol, N=2, pred=(lambda l1,l2 : op.AND(l1.charge != l2.charge))) hasDiLep = noSel.refine("hasDilep{0}{0}".format(dlNm), cut=(op.rng_len(dilep) > 0)) dilepZ = op.rng_min_element_by(dilep, fun=lambda ll : op.abs(op.invariant_mass(ll[0].p4, ll[1].p4)-91.2)) for tlNm,tlCol in lepColl.items(): if tlCol == dlCol: hasTriLep = hasDiLep.refine("hasTrilep{0}{0}{1}".format(dlNm,tlNm), cut=(op.rng_len(tlCol) > 2)) residLep = op.select(tlCol, lambda l : op.AND(l.idx != dilepZ[0].idx, l.idx != dilepZ[1].idx)) l3 = op.rng_max_element_by(residLep, lambda l : l.pt) else: hasTriLep = hasDiLep.refine("hasTriLep{0}{0}{1}".format(dlNm,tlNm), cut=(op.rng_len(tlCol) > 0)) l3 = op.rng_max_element_by(tlCol, lambda l : l.pt) mtPlot = Plot.make1D("Ex8_3lMT_{0}{0}{1}".format(dlNm,tlNm), op.sqrt(2*l3.pt*tree.MET.pt*(1-op.cos(l3.phi-tree.MET.phi))), hasTriLep, EqBin(100, 15., 250.), title="M_{T} (GeV/c^2)") mt3lPlots.append(mtPlot) plots.append(mtPlot) plots.append(SummedPlot("Ex8_3lMT", mt3lPlots)) return plots
def definePlots(self, t, noSel, sample=None, sampleCfg=None): from bamboo.plots import Plot, CutFlowReport from bamboo.plots import EquidistantBinning as EqB from bamboo import treefunctions as op plots = [] #definitions electrons = op.select(t.elec, lambda el : op.AND( el.pt > 20., op.abs(el.eta) < 2.5 )) muons = op.select(t.muon, lambda mu : op.AND( mu.pt > 20., op.abs(mu.eta) < 2.5 )) cleanedElectrons = op.select(electrons, lambda el : op.NOT( op.rng_any(muons, lambda mu : op.deltaR(el.p4, mu.p4) < 0.3 ) )) # we are taking the second isopass to be on which is equal to the medium working point isolatedElectrons = op.select(cleanedElectrons, lambda el : el.isopass & (1<<2) ) identifiedElectrons = op.select(isolatedElectrons, lambda el : el.idpass & (1<<2) ) cleanedMuons = op.select(muons, lambda mu : op.NOT( op.rng_any(electrons, lambda el : op.deltaR(mu.p4, el.p4) < 0.3 ) )) isolatedMuons = op.select(cleanedMuons, lambda mu : mu.isopass & (1<<2) ) identifiedMuons = op.select(isolatedMuons, lambda mu : mu.idpass & (1<<2) ) InvMassMuMU = op.invariant_mass(identifiedMuons[0].p4, identifiedMuons[1].p4 ) cleanedJets = op.select(t.jetpuppi, lambda j : op.AND( op.NOT(op.rng_any(identifiedElectrons, lambda el : op.deltaR(el.p4, j.p4) < 0.3) ), op.NOT(op.rng_any(identifiedMuons, lambda mu : op.deltaR(mu.p4, j.p4) < 0.3) ) )) cleanedGoodJets = op.select(cleanedJets, lambda j : op.AND( j.pt > 30, op.abs(j.eta) < 2.5 )) btaggedJets = op.select(cleanedGoodJets, lambda j : j.btag & (1<<2)) met = op.select(t.metpuppi) #selections #selection1 : Oppositely charged MuMu selection sel1 = noSel.refine("nmumu", cut = [op.AND( (op.rng_len(identifiedMuons) > 1), (op.product(identifiedMuons[0].charge, identifiedMuons[1].charge) < 0 ))]) #selection2 : Invariant mass selection sel2 = sel1.refine("InvM", cut = [op.NOT(op.in_range(76, InvMassMuMU, 106))]) #selection3 : two jets selection sel3 = sel2.refine("njet", cut = [op.rng_len(cleanedGoodJets) > 1]) #selection4 : at least 1 among two leading jets is b-tagged sel4 = sel3.refine("btag", cut = [op.OR( cleanedGoodJets[0].btag & (1<<2), cleanedGoodJets[1].btag & (1<<2))]) #selection5 : MET > 40 GeV sel5 = sel4.refine("MET", cut = [met[0].pt > 40]) #plots #noSel plots.append(Plot.make1D("nJetsNoSel", op.rng_len(cleanedGoodJets), noSel, EqB(10, 0., 10.), title="nJets")) plots.append(Plot.make1D("nbtaggedJetsNoSel", op.rng_len(btaggedJets), noSel, EqB(10, 0., 10.), title="nbtaggedJets")) plots.append(Plot.make1D("nMuNoSel", op.rng_len(identifiedMuons), noSel, EqB(15, 0., 15.), title="nMuons")) plots.append(Plot.make1D("METptNoSel", met[0].pt, noSel, EqB(50, 0., 250), title="MET_PT")) #sel1 plots.append(Plot.make1D("nJetsSel1", op.rng_len(cleanedGoodJets), sel1, EqB(10, 0., 10.), title="nJets")) plots.append(Plot.make1D("nbtaggedJetsSel1", op.rng_len(btaggedJets), sel1, EqB(10, 0., 10.), title="nbtaggedJets")) plots.append(Plot.make1D("nMuSel1", op.rng_len(identifiedMuons), sel1, EqB(10, 0., 10.), title="nMuons")) plots.append(Plot.make1D("InvMassTwoMuonsSel1", InvMassMuMU, sel1, EqB(30, 0, 300), title="m(ll)")) plots.append(Plot.make1D("LeadingMuonPTSel1", muons[0].pt, sel1, EqB(30, 0., 250.), title=" Leading Muon PT")) plots.append(Plot.make1D("SubLeadingMuonPTSel1", muons[1].pt, sel1, EqB(30, 0., 250.), title="SubLeading Muon PT")) plots.append(Plot.make1D("LeadingMuonEtaSel1", muons[0].eta, sel1, EqB(30, -3, 3), title=" Leading Muon eta")) plots.append(Plot.make1D("SubLeadingMuonEtaSel1", muons[1].eta, sel1, EqB(30, -3, 3), title="SubLeading Muon eta")) plots.append(Plot.make1D("METptSel1", met[0].pt, sel1, EqB(50, 0., 250), title="MET_PT")) #sel2 plots.append(Plot.make1D("nJetsSel2", op.rng_len(cleanedGoodJets), sel2, EqB(10, 0., 10.), title="nJets")) plots.append(Plot.make1D("nbtaggedJetsSel2", op.rng_len(btaggedJets), sel2, EqB(10, 0., 10.), title="nbtaggedJets")) plots.append(Plot.make1D("nMuSel2", op.rng_len(identifiedMuons), sel2, EqB(10, 0., 10.), title="nMuons")) plots.append(Plot.make1D("InvMassTwoMuonsSel2", InvMassMuMU, sel2, EqB(20, 20., 300.), title="m(ll)")) plots.append(Plot.make1D("LeadingMuonPTSel2", muons[0].pt, sel2, EqB(30, 0., 250.), title=" Leading Muon PT")) plots.append(Plot.make1D("SubLeadingMuonPTSel2", muons[1].pt, sel2, EqB(30, 0., 200.), title=" SubLeading Muon PT")) plots.append(Plot.make1D("LeadingMuonEtaSel2", muons[0].eta, sel2, EqB(30, -3, 3), title=" Leading Muon Eta")) plots.append(Plot.make1D("SubLeadingMuonEtaSel2", muons[1].eta, sel2, EqB(30, -3, 3), title=" SubLeading Muon Eta")) plots.append(Plot.make1D("METptSel2", met[0].pt, sel2, EqB(50, 0., 250), title="MET_PT")) #sel3 plots.append(Plot.make1D("nJetsSel3", op.rng_len(cleanedGoodJets), sel3, EqB(10, 0., 10.), title="nJets")) plots.append(Plot.make1D("nbtaggedJetsSel3", op.rng_len(btaggedJets), sel3, EqB(10, 0., 10.), title="nbtaggedJets")) plots.append(Plot.make1D("LeadingJetPTSel3", cleanedGoodJets[0].pt, sel3, EqB(50, 0., 350.), title="Leading jet PT")) plots.append(Plot.make1D("SubLeadingJetPTSel3", cleanedGoodJets[1].pt, sel3, EqB(50, 0., 350.), title="SubLeading jet PT")) plots.append(Plot.make1D("LeadingJetEtaSel3", cleanedGoodJets[0].eta, sel3, EqB(30, -3, 3), title="Leading jet Eta")) plots.append(Plot.make1D("SubLeadingJetEtaSel3", cleanedGoodJets[1].eta, sel3, EqB(30, -3, 3), title="SubLeading jet Eta")) plots.append(Plot.make1D("nMuSel3", op.rng_len(identifiedMuons), sel3, EqB(10, 0., 10.), title="nMuons")) plots.append(Plot.make1D("LeadingMuonPTSel3", muons[0].pt, sel3, EqB(30, 0., 250.), title=" Leading Muon PT")) plots.append(Plot.make1D("SubLeadingMuonPTSel3", muons[1].pt, sel3, EqB(30, 0., 200.), title=" SubLeading Muon PT")) plots.append(Plot.make1D("LeadingMuonEtaSel3", muons[0].eta, sel3, EqB(30, -3, 3), title=" Leading Muon Eta")) plots.append(Plot.make1D("SubLeadingMuonEtaSel3", muons[1].eta, sel3, EqB(30, -3, 3), title=" SubLeading Muon Eta")) plots.append(Plot.make1D("InvMassTwoMuonsSel3", InvMassMuMU, sel3, EqB(30, 0, 300), title="m(ll)")) plots.append(Plot.make1D("METptSel3", met[0].pt, sel3, EqB(50, 0., 250), title="MET_PT")) #sel4 plots.append(Plot.make1D("nJetsSel4", op.rng_len(cleanedGoodJets), sel4, EqB(10, 0, 10), title="nJets")) plots.append(Plot.make1D("nbtaggedJetsSel4", op.rng_len(btaggedJets), sel4, EqB(10, 0., 10.), title="nbtaggedJets")) plots.append(Plot.make1D("LeadingJetPTSel4", cleanedGoodJets[0].pt, sel4, EqB(50, 0., 250.), title="Leading jet PT")) plots.append(Plot.make1D("SubLeadingJetPTSel4", cleanedGoodJets[1].pt, sel4, EqB(50, 0., 250.), title="SubLeading jet PT")) plots.append(Plot.make1D("LeadingJetEtaSel4", cleanedGoodJets[0].eta, sel4, EqB(30, -3, 3.), title="Leading jet Eta")) plots.append(Plot.make1D("SubLeadingJetEtaSel4", cleanedGoodJets[1].eta, sel4, EqB(30, -3, 3.), title="SubLeading jet Eta")) plots.append(Plot.make1D("nMuSel4", op.rng_len(identifiedMuons), sel4, EqB(10, 0., 10.), title="nMuons")) plots.append(Plot.make1D("LeadingMuonPTSel4", muons[0].pt, sel4, EqB(30, 0., 250.), title=" Leading Muon PT")) plots.append(Plot.make1D("SubLeadingMuonPTSel4", muons[1].pt, sel4, EqB(30, 0., 200.), title=" SubLeading Muon PT")) plots.append(Plot.make1D("LeadingMuonEtaSel4", muons[0].eta, sel4, EqB(30, -3, 3), title=" Leading Muon Eta")) plots.append(Plot.make1D("SubLeadingMuonEtaSel4", muons[1].eta, sel4, EqB(30, -3, 3), title=" SubLeading Muon Eta")) plots.append(Plot.make1D("InvMassTwoMuonsSel4", InvMassMuMU, sel4, EqB(30, 0, 300), title="m(ll)")) plots.append(Plot.make1D("METptSel4", met[0].pt, sel4, EqB(50, 0., 250), title="MET_PT")) #sel5 plots.append(Plot.make1D("nJetsSel5", op.rng_len(cleanedGoodJets), sel5, EqB(10, 0, 10), title="nJets")) plots.append(Plot.make1D("nbtaggedJetsSel5", op.rng_len(btaggedJets), sel5, EqB(10, 0., 10.), title="nbtaggedJets")) plots.append(Plot.make1D("LeadingJetPTSel5", cleanedGoodJets[0].pt, sel5, EqB(50, 0., 250.), title="Leading jet PT")) plots.append(Plot.make1D("SubLeadingJetPTSel5", cleanedGoodJets[1].pt, sel5, EqB(50, 0., 250.), title="SubLeading jet PT")) plots.append(Plot.make1D("LeadingJetEtaSel5", cleanedGoodJets[0].eta, sel5, EqB(30, -3, 3.), title="Leading jet Eta")) plots.append(Plot.make1D("SubLeadingJetEtaSel5", cleanedGoodJets[1].eta, sel5, EqB(30, -3, 3.), title="SubLeading jet Eta")) plots.append(Plot.make1D("nMuSel5", op.rng_len(identifiedMuons), sel5, EqB(10, 0., 10.), title="nMuons")) plots.append(Plot.make1D("LeadingMuonPTSel5", muons[0].pt, sel5, EqB(30, 0., 250.), title=" Leading Muon PT")) plots.append(Plot.make1D("SubLeadingMuonPTSel5", muons[1].pt, sel5, EqB(30, 0., 200.), title=" SubLeading Muon PT")) plots.append(Plot.make1D("LeadingMuonEtaSel5", muons[0].eta, sel5, EqB(30, -3, 3), title=" Leading Muon Eta")) plots.append(Plot.make1D("SubLeadingMuonEtaSel5", muons[1].eta, sel5, EqB(30, -3, 3), title=" SubLeading Muon Eta")) plots.append(Plot.make1D("InvMassTwoMuonsSel5", InvMassMuMU, sel5, EqB(30, 0, 300), title="m(ll)")) plots.append(Plot.make1D("METptSel5", met[0].pt, sel5, EqB(50, 0., 250), title="MET_PT > 40")) # Efficiency Report on terminal and the .tex output cfr = CutFlowReport("yields") cfr.add(noSel, "Sel0: No selection") cfr.add(sel1, "Sel1: nMuMu >= 2") cfr.add(sel2, "Sel2: InvM") cfr.add(sel3, "Sel3: nJet >= 2") cfr.add(sel4, "Sel4: btag") cfr.add(sel5, "Sel5: MET") plots.append(cfr) return plots
def definePlots(self, t, noSel, sample=None, sampleCfg=None): from bamboo.analysisutils import forceDefine from bamboo.plots import Plot from bamboo.plots import EquidistantBinning as EqB from bamboo import treefunctions as op era = sampleCfg.get("era") if sampleCfg else None noSel = noSel.refine("passMETFlags", cut=METFilter(t.Flag, era) ) puWeightsFile = None if era == "2016": sfTag="94X" puWeightsFile = os.path.join(os.path.dirname(__file__), "data/PileupFullRunII", "puweights2016.json") elif era == "2017": sfTag="94X" puWeightsFile = os.path.join(os.path.dirname(__file__), "data/PileupFullRunII", "puweights2017.json") elif era == "2018": sfTag="102X" puWeightsFile = os.path.join(os.path.dirname(__file__), "data/PileupFullRunII", "puweights2018.json") if self.isMC(sample) and puWeightsFile is not None: from bamboo.analysisutils import makePileupWeight noSel = noSel.refine("puWeight", weight=makePileupWeight(puWeightsFile, t.Pileup_nTrueInt, systName="pileup")) isMC = self.isMC(sample) plots = [] forceDefine(t._Muon.calcProd, noSel) # Wp // 2016- 2017 -2018 : Muon_mediumId // https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideMuonIdRun2#Muon_Isolation #To suppress nonprompt lep-tons, the impact parameter in three dimensions of the lepton track, with respect to the primaryvertex, is required to be less than 4 times its uncertainty (|SIP3D|<4) sorted_muons = op.sort(t.Muon, lambda mu : -mu.pt) muons = op.select(sorted_muons, lambda mu : op.AND(mu.pt > 10., op.abs(mu.eta) < 2.4, mu.mediumId, mu.pfRelIso04_all<0.15, op.abs(mu.sip3d < 4.))) # i pass 2016 seprate from 2017 &2018 because SFs need to be combined for BCDEF and GH eras ! if era=="2016": doubleMuTrigSF = get_scalefactor("dilepton", ("doubleMuLeg_HHMoriond17_2016"), systName="mumutrig") muMediumIDSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "id_medium"), combine="weight", systName="muid") muMediumISOSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "iso_tight_id_medium"), combine="weight", systName="muiso") else: doubleMuTrigSF = get_scalefactor("dilepton", ("doubleMuLeg_HHMoriond17_2016"), systName="mumutrig") muMediumIDSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "id_medium"), systName="muid") muMediumISOSF = get_scalefactor("lepton", ("muon_{0}_{1}".format(era, sfTag), "iso_tight_id_medium"), systName="muiso") #Wp // 2016: Electron_cutBased_Sum16==3 -> medium // 2017 -2018 : Electron_cutBased ==3 --> medium ( Fall17_V2) # asking for electrons to be in the Barrel region with dz<1mm & dxy< 0.5mm // Endcap region dz<2mm & dxy< 0.5mm # cut-based ID Fall17 V2 the recomended one from POG for the FullRunII sorted_electrons = op.sort(t.Electron, lambda ele : -ele.pt) electrons = op.select(sorted_electrons, lambda ele : op.AND(ele.pt > 15., op.abs(ele.eta) < 2.5 , ele.cutBased>=3, op.abs(ele.sip3d)< 4., op.OR(op.AND(op.abs(ele.dxy) < 0.05, op.abs(ele.dz) < 0.1), op.AND(op.abs(ele.dxy) < 0.05, op.abs(ele.dz) < 0.2) ))) elMediumIDSF = get_scalefactor("lepton", ("electron_{0}_{1}".format(era,sfTag), "id_medium"), systName="elid") doubleEleTrigSF = get_scalefactor("dilepton", ("doubleEleLeg_HHMoriond17_2016"), systName="eleltrig") elemuTrigSF = get_scalefactor("dilepton", ("elemuLeg_HHMoriond17_2016"), systName="elmutrig") mueleTrigSF = get_scalefactor("dilepton", ("mueleLeg_HHMoriond17_2016"), systName="mueltrig") MET = t.MET if era != "2017" else t.METFixEE2017 corrMET=METcorrection(MET,t.PV,sample,era,self.isMC(sample)) ####### select jets ################################## #// 2016 - 2017 - 2018 ( j.jetId &2) -> tight jet ID # For 2017 data, there is the option of "Tight" or "TightLepVeto", depending on how much you want to veto jets that overlap with/are faked by leptons sorted_AK4jets=op.sort(t.Jet, lambda j : -j.pt) AK4jetsSel = op.select(sorted_AK4jets, lambda j : op.AND(j.pt > 20., op.abs(j.eta)< 2.4, (j.jetId &2)))# j.jetId == 6))# oldcut: (j.jetId &2))) # exclude from the jetsSel any jet that happens to include within its reconstruction cone a muon or an electron. AK4jets= op.select(AK4jetsSel, lambda j : op.AND(op.NOT(op.rng_any(electrons, lambda ele : op.deltaR(j.p4, ele.p4) < 0.3 )), op.NOT(op.rng_any(muons, lambda mu : op.deltaR(j.p4, mu.p4) < 0.3 )))) # order jets by *decreasing* deepFlavour cleaned_AK4JetsByDeepFlav = op.sort(AK4jets, lambda j: -j.btagDeepFlavB) cleaned_AK4JetsByDeepB = op.sort(AK4jets, lambda j: -j.btagDeepB) # Boosted Region sorted_AK8jets=op.sort(t.FatJet, lambda j : -j.pt) AK8jetsSel = op.select(sorted_AK8jets, lambda j : op.AND(j.pt > 200., op.abs(j.eta)< 2.4, (j.jetId &2), j.subJet1._idx.result != -1, j.subJet2._idx.result != -1)) AK8jets= op.select(AK8jetsSel, lambda j : op.AND(op.NOT(op.rng_any(electrons, lambda ele : op.deltaR(j.p4, ele.p4) < 0.3 )), op.NOT(op.rng_any(muons, lambda mu : op.deltaR(j.p4, mu.p4) < 0.3 )))) cleaned_AK8JetsByDeepB = op.sort(AK8jets, lambda j: -j.btagDeepB) # Now, let's ask for the jets to be a b-jets # DeepCSV or deepJet Medium b-tag working point btagging = { "DeepCSV":{ # era: (loose, medium, tight) "2016":(0.2217, 0.6321, 0.8953), "2017":(0.1522, 0.4941, 0.8001), "2018":(0.1241, 0.4184, 0.7527) }, "DeepFlavour":{ "2016":(0.0614, 0.3093, 0.7221), "2017":(0.0521, 0.3033, 0.7489), "2018":(0.0494, 0.2770, 0.7264) } } # bjets ={ "DeepFlavour": {"L": jets pass loose , "M": jets pass medium , "T":jets pass tight } # "DeepCSV": {"L": --- , "M": --- , "T": ---- } # } # FIXME bjets_boosted = {} bjets_resolved = {} #WorkingPoints = ["L", "M", "T"] WorkingPoints = ["M"] for tagger in btagging.keys(): bJets_AK4_deepflavour ={} bJets_AK4_deepcsv ={} bJets_AK8_deepcsv ={} # FIXME idx is not propagated properly when i pass only one or two wp !! for wp in sorted(WorkingPoints): suffix = ("loose" if wp=='L' else ("medium" if wp=='M' else "tight")) idx = ( 0 if wp=="L" else ( 1 if wp=="M" else 2)) if tagger=="DeepFlavour": print ("Btagging: Era= {0}, Tagger={1}, Pass_{2}_working_point={3}".format(era, tagger, suffix, btagging[tagger][era][idx] )) print ("***********************************************", idx, wp) print ("btag_{0}_94X".format(era).replace("94X", "102X" if era=="2018" else "94X"), "{0}_{1}".format('DeepJet', suffix)) bJets_AK4_deepflavour[wp] = op.select(cleaned_AK4JetsByDeepFlav, lambda j : j.btagDeepFlavB >= btagging[tagger][era][idx] ) Jet_DeepFlavourBDisc = { "BTagDiscri": lambda j : j.btagDeepFlavB } deepBFlavScaleFactor = get_scalefactor("jet", ("btag_{0}_94X".format(era).replace("94X", "102X" if era=="2018" else "94X"), "{0}_{1}".format('DeepJet', suffix)), additionalVariables=Jet_DeepFlavourBDisc, getFlavour=(lambda j : j.hadronFlavour), systName="btagging{0}".format(era)) bjets_resolved[tagger]=bJets_AK4_deepflavour else: print ("Btagging: Era= {0}, Tagger={1}, Pass_{2}_working_point={3}".format(era, tagger, suffix, btagging[tagger][era][idx] )) print ("***********************************************", idx, wp) print ("btag_{0}_94X".format(era).replace("94X", "102X" if era=="2018" else "94X"), "{0}_{1}".format('DeepCSV', suffix)) bJets_AK4_deepcsv[wp] = op.select(cleaned_AK4JetsByDeepB, lambda j : j.btagDeepB >= btagging[tagger][era][idx] ) bJets_AK8_deepcsv[wp] = op.select(cleaned_AK8JetsByDeepB, lambda j : op.AND(j.subJet1.btagDeepB >= btagging[tagger][era][idx] , j.subJet2.btagDeepB >= btagging[tagger][era][idx])) Jet_DeepCSVBDis = { "BTagDiscri": lambda j : j.btagDeepB } subJet_DeepCSVBDis = { "BTagDiscri": lambda j : op.AND(j.subJet1.btagDeepB, j.subJet2.btagDeepB) } # FIXME for boosted and resolved i will use # tagger need to pass jsons files to scale factors above ! deepB_AK4ScaleFactor = get_scalefactor("jet", ("btag_{0}_94X".format(era).replace("94X", "102X" if era=="2018" else "94X"), "{0}_{1}".format('DeepCSV', suffix)), additionalVariables=Jet_DeepCSVBDis, getFlavour=(lambda j : j.hadronFlavour), systName="btagging{0}".format(era)) # FIXME #deepB_AK8ScaleFactor = get_scalefactor("jet", ("btag_{0}_94X".format(era).replace("94X", "102X" if era=="2018" else "94X"), "subjet_{0}_{1}".format('DeepCSV', suffix)), #additionalVariables=Jet_DeepCSVBDis, #getFlavour=(lambda j : j.subJet1.hadronFlavour), #systName="btagging{0}".format(era)) bjets_resolved[tagger]=bJets_AK4_deepcsv bjets_boosted[tagger]=bJets_AK8_deepcsv bestDeepFlavourPair={} bestDeepCSVPair={} bestJetPairs= {} bjets = {} # For the Resolved only class GetBestJetPair(object): JetsPair={} def __init__(self, JetsPair, tagger, wp): def ReturnHighestDiscriminatorJet(tagger, wp): if tagger=="DeepCSV": return op.sort(safeget(bjets_resolved, tagger, wp), lambda j: - j.btagDeepB) elif tagger=="DeepFlavour": return op.sort(safeget(bjets_resolved, tagger, wp), lambda j: - j.btagDeepFlavB) else: raise RuntimeError("Something went wrong in returning {0} discriminator !".format(tagger)) firstBest=ReturnHighestDiscriminatorJet(tagger, wp)[0] JetsPair[0]=firstBest secondBest=ReturnHighestDiscriminatorJet(tagger, wp)[1] JetsPair[1]=secondBest # bestJetPairs= { "DeepFlavour": bestDeepFlavourPair, # "DeepCSV": bestDeepCSVPair # } ####### Zmass reconstruction : Opposite Sign , Same Flavour leptons ######################################################## # supress quaronika resonances and jets misidentified as leptons LowMass_cut = lambda dilep: op.invariant_mass(dilep[0].p4, dilep[1].p4)>12. ## Dilepton selection: opposite sign leptons in range 70.<mll<120. GeV osdilep_Z = lambda l1,l2 : op.AND(l1.charge != l2.charge, op.in_range(70., op.invariant_mass(l1.p4, l2.p4), 120.)) osLLRng = { "MuMu" : op.combine(muons, N=2, pred= osdilep_Z), "ElEl" : op.combine(electrons, N=2, pred=osdilep_Z), #"ElMu" : op.combine((electrons, muons), pred=lambda ele,mu : op.AND(osdilep_Z(ele,mu), ele.pt > mu.pt )), #"MuEl" : op.combine((muons, electrons), pred=lambda mu,ele : op.AND(osdilep_Z(mu,ele), mu.pt > ele.pt)) } hasOSLL_cmbRng = lambda cmbRng : op.AND(op.rng_len(cmbRng) > 0, cmbRng[0][0].pt > 25.) # TODO The leading pT for the µµ channel should be above 20 Gev ! ## helper selection (OR) to make sure jet calculations are only done once hasOSLL = noSel.refine("hasOSLL", cut=op.OR(*( hasOSLL_cmbRng(rng) for rng in osLLRng.values()))) forceDefine(t._Jet.calcProd, hasOSLL) forceDefine(getattr(t, "_{0}".format("MET" if era != "2017" else "METFixEE2017")).calcProd, hasOSLL) llSFs = { "MuMu" : (lambda ll : [ muMediumIDSF(ll[0]), muMediumIDSF(ll[1]), muMediumISOSF(ll[0]), muMediumISOSF(ll[1]), doubleMuTrigSF(ll) ]), "ElMu" : (lambda ll : [ elMediumIDSF(ll[0]), muMediumIDSF(ll[1]), muMediumISOSF(ll[1]), elemuTrigSF(ll) ]), "MuEl" : (lambda ll : [ muMediumIDSF(ll[0]), muMediumISOSF(ll[0]), elMediumIDSF(ll[1]), mueleTrigSF(ll) ]), "ElEl" : (lambda ll : [ elMediumIDSF(ll[0]), elMediumIDSF(ll[1]), doubleEleTrigSF(ll) ]) } categories = dict((channel, (catLLRng[0], hasOSLL.refine("hasOS{0}".format(channel), cut=hasOSLL_cmbRng(catLLRng), weight=(llSFs[channel](catLLRng[0]) if isMC else None)) )) for channel, catLLRng in osLLRng.items()) ## btagging efficiencies plots #plots.extend(MakeBtagEfficienciesPlots(self, jets, bjets, categories)) for channel, (dilepton, catSel) in categories.items(): #---- Zmass (2Lepton OS && SF ) -------- #plots.extend(MakeControlPlotsForZpic(self, catSel, dilepton, channel)) #---- add Jets selection TwoLeptonsTwoJets_Resolved = catSel.refine("TwoJet_{0}Sel_resolved".format(channel), cut=[ op.rng_len(AK4jets) > 1 ]) TwoLeptonsTwoJets_Boosted = catSel.refine("OneJet_{0}Sel_boosted".format(channel), cut=[ op.rng_len(AK8jets) > 0 ]) #plots.extend(makeJetPlots(self, TwoLeptonsTwoJets_Resolved, AK4jets, channel)) #plots.extend(makeBoostedJetPLots(self, TwoLeptonsTwoJets_Boosted, AK8jets, channel)) # ----- plots : mll, mlljj, mjj, nVX, pT, eta : basic selection plots ------ #plots.extend(MakeControlPlotsForBasicSel(self, TwoLeptonsTwoJets_Resolved, AK4jets, dilepton, channel)) #plots.extend(MakeControlPlotsForBasicSel(self, TwoLeptonsTwoJets_boosted, AK8jets, dilepton, channel)) for wp in WorkingPoints: # Get the best AK4 JETS GetBestJetPair(bestDeepCSVPair,"DeepCSV", wp) GetBestJetPair(bestDeepFlavourPair,"DeepFlavour", wp) bestJetPairs["DeepCSV"]=bestDeepCSVPair bestJetPairs["DeepFlavour"]=bestDeepFlavourPair print ("bestJetPairs AK4--->", bestJetPairs, wp) print ("bestJetPairs_deepcsv AK4--->", bestJetPairs["DeepCSV"][0], bestJetPairs["DeepCSV"][1], wp) print ("bestJetPairs_deepflavour AK4 --->", bestJetPairs["DeepFlavour"][0],bestJetPairs["DeepFlavour"][1], wp) # resolved bJets_resolved_PassdeepflavourWP=safeget(bjets_resolved, "DeepFlavour", wp) bJets_resolved_PassdeepcsvWP=safeget(bjets_resolved, "DeepCSV", wp) # boosted bJets_boosted_PassdeepcsvWP=safeget(bjets_boosted, "DeepCSV", wp) TwoLeptonsTwoBjets_NoMETCut_Res = { "DeepFlavour{0}".format(wp) : TwoLeptonsTwoJets_Resolved.refine("TwoLeptonsTwoBjets_NoMETcut_DeepFlavour{0}_{1}_Resolved".format(wp, channel), cut=[ op.rng_len(bJets_resolved_PassdeepflavourWP) > 1 ], weight=([ deepBFlavScaleFactor(bJets_resolved_PassdeepflavourWP[0]), deepBFlavScaleFactor(bJets_resolved_PassdeepflavourWP[1]) ]if isMC else None)), "DeepCSV{0}".format(wp) : TwoLeptonsTwoJets_Resolved.refine("TwoLeptonsTwoBjets_NoMETcut_DeepCSV{0}_{1}_Resolved".format(wp, channel), cut=[ op.rng_len(bJets_resolved_PassdeepcsvWP) > 1 ], weight=([ deepB_AK4ScaleFactor(bJets_resolved_PassdeepcsvWP[0]), deepB_AK4ScaleFactor(bJets_resolved_PassdeepcsvWP[1]) ]if isMC else None)) } TwoLeptonsTwoBjets_NoMETCut_Boo = { "DeepCSV{0}".format(wp) : TwoLeptonsTwoJets_Boosted.refine("TwoLeptonsTwoBjets_NoMETcut_DeepCSV{0}_{1}_Boosted".format(wp, channel), cut=[ op.rng_len(bJets_boosted_PassdeepcsvWP) > 1 ]), # FIXME ! can't pass boosted jets SFs with current version ---> move to v7 #weight=([ deepB_AK8ScaleFactor(bJets_boosted_PassdeepcsvWP[0]), deepB_AK8ScaleFactor(bJets_boosted_PassdeepcsvWP[1]) ]if isMC else None)) } ## needed to optimize the MET cut # FIXME Rerun again &&& pass signal and bkg # The MET cut is passed to TwoLeptonsTwoBjets selection for the # tagger and for the # wp plots.extend(MakeMETPlots(self, TwoLeptonsTwoBjets_NoMETCut_Res, corrMET, MET, channel, "resolved")) plots.extend(MakeMETPlots(self, TwoLeptonsTwoBjets_NoMETCut_Boo, corrMET, MET, channel, "boosted")) plots.extend(MakeExtraMETPlots(self, TwoLeptonsTwoBjets_NoMETCut_Res, dilepton, MET, channel, "resolved")) plots.extend(MakeExtraMETPlots(self, TwoLeptonsTwoBjets_NoMETCut_Boo, dilepton, MET, channel, "boosted")) TwoLeptonsTwoBjets_Res = dict((key, selNoMET.refine("TwoLeptonsTwoBjets_{0}_{1}_Resolved".format(key, channel), cut=[ corrMET.pt < 80. ])) for key, selNoMET in TwoLeptonsTwoBjets_NoMETCut_Res.items()) TwoLeptonsTwoBjets_Boo = dict((key, selNoMET.refine("TwoLeptonsTwoBjets_{0}_{1}_Boosted".format(key, channel), cut=[ corrMET.pt < 80. ])) for key, selNoMET in TwoLeptonsTwoBjets_NoMETCut_Boo.items()) #plots.extend(MakeDiscriminatorPlots(self, TwoLeptonsTwoBjets_Res, bjets_resolved, wp, channel, "resolved")) #plots.extend(MakeDiscriminatorPlots(self, TwoLeptonsTwoBjets_Boo, bjets_boosted, wp, channel, "boosted")) #plots.extend(makeResolvedBJetPlots(self, TwoLeptonsTwoBjets_Res, bjets_resolved, dilepton, wp, channel)) #plots.extend(makeBoostedBJetPlots(self, TwoLeptonsTwoBjets_NoMETCut_Boo, bjets_boosted, dilepton, wp, channel)) # --- to get the Ellipses plots plots.extend(MakeEllipsesPLots(self, TwoLeptonsTwoBjets_Res, bjets_resolved, dilepton, wp, channel, "resolved")) plots.extend(MakeEllipsesPLots(self, TwoLeptonsTwoBjets_Boo, bjets_boosted, dilepton, wp, channel, "boosted")) return plots
def definePlots(self, tree, noSel, sample=None, sampleCfg=None): plots = [] muons = op.sort(op.select(tree.Muon, lambda mu : op.AND( mu.pt > 5, op.abs(mu.eta) < 2.4, op.abs(mu.pfRelIso04_all) < 0.40, op.abs(mu.dxy) < 0.5, op.abs(mu.dz ) < 1., op.sqrt(mu.dxy**2 + mu.dz**2)/op.sqrt(mu.dxyErr**2+mu.dzErr**2) < 4, ## SIP3D )), lambda mu : -mu.pt) electrons = op.sort(op.select(tree.Electron, lambda el : op.AND( el.pt > 7., op.abs(el.eta) < 2.5, op.abs(el.pfRelIso03_all) < 0.40, op.abs(el.dxy) < 0.5, op.abs(el.dz ) < 1., op.sqrt(el.dxy**2 + el.dz**2)/op.sqrt(el.dxyErr**2+el.dzErr**2) < 4, ## SIP3D )), lambda el : -el.pt) plots += self.controlPlots_2l(noSel, muons, electrons) mZ = 91.1876 def reco_4l(leptons, lName, baseSel): ## select events with four leptons, and find the best Z candidate ## shared between 4el and 4mu has4l = baseSel.refine(f"has4{lName}", cut=[ op.rng_len(leptons) == 4, op.rng_sum(leptons, lambda l : l.charge) == 0, ]) allZcand = op.combine(leptons, N=2, pred=lambda l1,l2 : l1.charge != l2.charge) bestZ = op.rng_min_element_by(allZcand, lambda ll : op.abs(op.invariant_mass(ll[0].p4, ll[1].p4)-mZ)) otherLeptons = op.select(leptons, partial(lambda l,oz=None : op.AND(l.idx != oz[0].idx, l.idx != oz[1].idx), oz=bestZ)) return has4l, bestZ, otherLeptons ## Mixed category: take leading two for each (as in the other implementations def cuts2lMixed(leptons): return [ op.rng_len(leptons) == 2, leptons[0].charge != leptons[1].charge, leptons[0].pt > 20., leptons[1].pt > 10. ] has4lMixed = noSel.refine(f"has4lMixed", cut=cuts2lMixed(muons)+cuts2lMixed(electrons)) mixed_mElEl = op.invariant_mass(electrons[0].p4, electrons[1].p4) mixed_mMuMu = op.invariant_mass(muons[0].p4, muons[1].p4) ## two categories: elel closest to Z or mumu closest to Z has2El2Mu = has4lMixed.refine(f"has2El2Mu", cut=(op.abs(mixed_mElEl-mZ) < op.abs(mixed_mMuMu-mZ))) has2Mu2El = has4lMixed.refine(f"has2Mu2El", cut=(op.abs(mixed_mElEl-mZ) > op.abs(mixed_mMuMu-mZ))) mH_cats = [] for catNm, (has4l, bestZ, otherZ) in { "4Mu" : reco_4l(muons , "Mu", noSel), "4El" : reco_4l(electrons, "El", noSel), "2El2Mu" : (has2El2Mu, electrons, muons), "2Mu2El" : (has2Mu2El, muons, electrons) }.items(): bestZp4 = bestZ[0].p4 + bestZ[1].p4 otherZp4 = otherZ[0].p4 + otherZ[1].p4 hasZZ = has4l.refine(f"{has4l.name}ZZ", cut=[ op.deltaR(bestZ[0].p4 , bestZ[1].p4 ) > 0.02, op.deltaR(otherZ[0].p4, otherZ[1].p4) > 0.02, op.in_range(40., bestZp4.M(), 120.), op.in_range(12., otherZp4.M(), 120.) ]) plots += self.controlPlots_4l(hasZZ, bestZ, otherZ) m4l = (bestZ[0].p4+bestZ[1].p4+otherZ[0].p4+otherZ[1].p4).M() hasZZ_m4l70 = hasZZ.refine(f"{hasZZ.name}m4l70", cut=(m4l > 70.)) p_mH = Plot.make1D(f"H_mass_{catNm}", m4l, hasZZ_m4l70, EqBin(36, 70., 180.), plotopts={"show-overflow": False, "log-y": False, "y-axis-range": [0., 18.]}) mH_cats.append(p_mH) plots.append(p_mH) plots.append(SummedPlot("H_mass", mH_cats)) return plots