Example #1
0
def get_scalefactor(objType, key, periods=None, combine=None, additionalVariables=dict(), getFlavour=None, systName=None):
    return scalefactors.get_scalefactor(objType, key, periods=periods, combine=combine, 
                                        additionalVariables=additionalVariables, 
                                        sfLib=all_scalefactors, 
                                        paramDefs=binningVariables, 
                                        getFlavour=getFlavour,
                                        systName=systName)
    def get_scalefactor(self,
                        objType,
                        key,
                        periods=None,
                        combine=None,
                        additionalVariables=dict(),
                        systName=None,
                        defineOnFirstUse=True):
        paramDefs = self.binningVariables
        if additionalVariables is not None:
            paramDefs.update(additionalVariables)

        return scalefactors.get_scalefactor(
            objType=objType,
            key=key,
            periods=periods,
            combine=combine,
            sfLib=self.all_scalefactors,
            paramDefs=paramDefs,
            getFlavour=(lambda j: j.hadronFlavour),
            systName=systName,
            defineOnFirstUse=defineOnFirstUse)
    def definePlots(self, t, noSel, sample=None, sampleCfg=None):
        if 'type' not in sampleCfg.keys() or sampleCfg["type"] != "signal":
            raise RuntimeError("Sample needs to be HH signal LO GGF sample")

        era = sampleCfg.get("era") if sampleCfg else None

        # Select gen level Higgs #
        genh = op.select(
            t.GenPart,
            lambda g: op.AND(g.pdgId == 25, g.statusFlags & (0x1 << 13)))
        HH_p4 = genh[0].p4 + genh[1].p4
        cm = HH_p4.BoostToCM()
        boosted_h = op.extMethod("ROOT::Math::VectorUtil::boost",
                                 returnType=genh[0].p4._typeName)(genh[0].p4,
                                                                  cm)
        mHH = op.invariant_mass(genh[0].p4, genh[1].p4)
        cosHH = op.abs(boosted_h.Pz() / boosted_h.P())

        # Apply reweighting #

        benchmarks = [
            'BenchmarkSM',
            'Benchmark1',
            'Benchmark2',
            'Benchmark3',
            'Benchmark4',
            'Benchmark5',
            'Benchmark6',
            'Benchmark7',
            'Benchmark8',
            'Benchmark8a',
            'Benchmark9',
            'Benchmark10',
            'Benchmark11',
            'Benchmark12',
            'BenchmarkcHHH0',
            'BenchmarkcHHH1',
            'BenchmarkcHHH2p45',
            'BenchmarkcHHH5',
            'Benchmarkcluster1',
            'Benchmarkcluster2',
            'Benchmarkcluster3',
            'Benchmarkcluster4',
            'Benchmarkcluster5',
            'Benchmarkcluster6',
            'Benchmarkcluster7',
        ]
        selections = {'': noSel}
        reweights = {}
        if self.args.reweighting:
            for benchmark in benchmarks:
                json_file = os.path.join(
                    os.path.abspath(os.path.dirname(__file__)), 'data',
                    'ScaleFactors_GGF_LO',
                    '{}_to_{}_{}.json'.format(sample, benchmark, era))
                if os.path.exists(json_file):
                    print("Found file {}".format(json_file))
                    reweightLO = get_scalefactor("lepton",
                                                 json_file,
                                                 paramDefs={
                                                     'Eta': lambda x: mHH,
                                                     'Pt': lambda x: cosHH
                                                 })
                    selections[benchmark] = SelectionWithDataDriven.create(
                        parent=noSel,
                        name='noSel' + benchmark,
                        ddSuffix=benchmark,
                        cut=op.c_bool(True),
                        ddCut=op.c_bool(True),
                        weight=op.c_float(1.),
                        ddWeight=reweightLO(op.c_float(1.)),
                        enable=True)
                    reweights[benchmark] = reweightLO(op.c_float(1.))
                else:
                    print("Could not find file {}".format(json_file))

        # Plots #
        plots = []

        for name, reweight in reweights.items():
            plots.append(
                Plot.make1D("weight_{}".format(name),
                            reweight,
                            noSel,
                            EquidistantBinning(100, 0, 5.),
                            xTitle='weight'))

        for selName, sel in selections.items():
            plots.append(
                Plot.make2D(
                    f"mHHvsCosThetaStar{selName}", [mHH, cosHH],
                    sel, [
                        VariableBinning([
                            250., 270., 290., 310., 330., 350., 370., 390.,
                            410., 430., 450., 470., 490., 510., 530., 550.,
                            570., 590., 610., 630., 650., 670., 700., 750.,
                            800., 850., 900., 950., 1000., 1100., 1200., 1300.,
                            1400., 1500., 1750., 2000., 5000.
                        ]),
                        VariableBinning([0.0, 0.4, 0.6, 0.8, 1.0])
                    ],
                    xTitle='m_{HH}',
                    yTitle='cos(#theta^{*})'))
            plots.append(
                Plot.make1D(f"mHH{selName}",
                            mHH,
                            sel,
                            VariableBinning([
                                250., 270., 290., 310., 330., 350., 370., 390.,
                                410., 430., 450., 470., 490., 510., 530., 550.,
                                570., 590., 610., 630., 650., 670., 700., 750.,
                                800., 850., 900., 950., 1000., 1100., 1200.,
                                1300., 1400., 1500., 1750., 2000., 5000.
                            ]),
                            xTitle='m_{HH}'))
            plots.append(
                Plot.make1D(f"cosThetaStar{selName}",
                            cosHH,
                            sel,
                            VariableBinning([0.0, 0.4, 0.6, 0.8, 1.0]),
                            xTitle='cos(#theta^{*})'))

        return plots
Example #4
0
    def definePlots(self, t, noSel, sample=None, sampleCfg=None):
        from bamboo.plots import Plot, CutFlowReport, SummedPlot
        from bamboo.plots import EquidistantBinning as EqB
        from bamboo import treefunctions as op

        isMC = self.isMC(sample)
        trigCut, trigWeight = None, None
        if isMC:
            noSel = noSel.refine("mcWeight", weight=[ t.genWeight, t.puWeight, t.PrefireWeight ])
            trigCut = op.OR(t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ, t.HLT.HIL3DoubleMu0, t.HLT.HIL3Mu20, t.HLT.HIEle20_WPLoose_Gsf)
            ## TODO add a correction for prescaled triggers
        else:
            ## suggested trigger order: dielectron, dimuon or single muon, single electron (to minimise loss due to prescales). Electron triggered-events should be taken from the HighEGJet primary datasets, muon-triggered events from the SingleMuon primary datset
            pd = sample.split("_")[0]
            if pd == "SingleMuon":
                ## TODO fill trigger cut
            elif pd == "HighEGJet":
                ## TODO fill trigger cut
        noSel = noSel.refine("trig", cut=trigCut, weight=trigWeight)

        plots = []

        goodLeptons = {
            "el" : op.select(t.Electron, partial(isGoodElectron, ptCut=15.)),
            "mu" : op.select(t.Muon, partial(isGoodMuon, ptCut=15.))
            }
        plots += [
            Plot.make1D("trig_nLeptons15", op.rng_len(goodLeptons["el"])+op.rng_len(goodLeptons["mu"]), noSel, EqB(15, 0., 15.)),
            Plot.make1D("trig_nEl15", op.rng_len(goodLeptons["el"]), noSel, EqB(15, 0., 15.)),
            Plot.make1D("trig_nMu15", op.rng_len(goodLeptons["mu"]), noSel, EqB(15, 0., 15.)) 
            ]
        from bamboo.scalefactors import get_scalefactor
        sf_loose = {
            "mu": get_scalefactor("lepton", "Muon_RecoToLoose", sfLib=scalefactors_lepMVA, paramDefs=binningVariables_nano_noScaleSyst, systName="muLoose"),
            "el": get_scalefactor("lepton", "Electron_RecoToLoose", sfLib=scalefactors_lepMVA, paramDefs=binningVariables_nano_noScaleSyst, systName="elLoose")
            }
        sf_tight = {
            "mu": get_scalefactor("lepton", "Muon_LooseToTight", sfLib=scalefactors_lepMVA, paramDefs=binningVariables_nano_noScaleSyst, systName="muTight"),
            "el": get_scalefactor("lepton", "Electron_LooseToTight", sfLib=scalefactors_lepMVA, paramDefs=binningVariables_nano_noScaleSyst, systName="elTight")
            }

        nGoodLeptons = op.rng_len(goodLeptons["el"])+op.rng_len(goodLeptons["mu"])
        hasTwoGoodLeptons = noSel.refine("has2Lep", cut=(nGoodLeptons > 1)) # avoid overlap with 1l
        jets = op.sort(op.select(t.Jet, lambda j : op.AND(
            j.pt > 25., ## you decide...
            op.abs(j.eta) < 2.4,
            j.jetId & 0x2, ## tight JetID
            op.AND( ## lepton-jet cross-cleaning
                op.NOT(op.rng_any(goodLeptons["el"], lambda l : op.deltaR(l.p4, j.p4) < 0.4)),
                op.NOT(op.rng_any(goodLeptons["mu"], lambda l : op.deltaR(l.p4, j.p4) < 0.4)))
            )), lambda j : -j.pt)
        for fl1,fl2 in product(*repeat(goodLeptons.keys(), 2)):
            dilepSel = lambda l1,l2 : op.AND(
                    l1.charge != l2.charge,
                    (l1.p4+l2.p4).M() > 12.
                    )
            if fl1 == fl2:
                lGood = op.sort(goodLeptons[fl1], lambda l : -l.pt)
                dilep = op.combine(lGood, N=2, pred=dilepSel)
            else:
                l1Good = op.sort(goodLeptons[fl1], lambda l : -l.pt)
                l2Good = op.sort(goodLeptons[fl2], lambda l : -l.pt)
                dilep = op.combine((l1Good, l2Good), pred=dilepSel)
            ll = dilep[0]
            hasDilep = hasTwoGoodLeptons.refine(f"hasDilep{fl1}{fl2}", cut=(op.rng_len(dilep) > 0, ll[0].pt > 25.),
                    weight=([ sf_loose[fl1](ll[0]), sf_loose[fl2](ll[1]), sf_tight[fl1](ll[0]), sf_tight[fl2](ll[1]) ] if isMC else None))
            plots += [
                Plot.make1D(f"dilepton_{fl1}{fl2}_Mll", (ll[0].p4+ll[1].p4).M(), hasDilep, EqB(50, 70, 120.), title="Dilepton mass"),
                ]
            for il,ifl in enumerate((fl1, fl2)):
                plots += [
                    Plot.make1D(f"dilepton_{fl1}{fl2}_L{il:d}PT", ll[il].pt, hasDilep, EqB(50, 0., 100.), title=f"Lepton {il:d} PT"),
                    Plot.make1D(f"dilepton_{fl1}{fl2}_L{il:d}ETA", ll[il].eta, hasDilep, EqB(50, -2.5, 2.5), title=f"Lepton {il:d} ETA"),
                    ]
            plots += [
                Plot.make1D(f"dilepton_{fl1}{fl2}_nJets", op.rng_len(jets), hasDilep, EqB(15, 0, 15.), title="Jet multiplicity"),
                ]

        return plots
    def definePlots(self, t, noSel, sample=None, sampleCfg=None):
        from bamboo.plots import Plot, CutFlowReport, SummedPlot
        from bamboo.plots import EquidistantBinning as EqB
        from bamboo import treefunctions as op

        isMC = self.isMC(sample)

        if sampleCfg.get("alt-syst"):
            noSel = noSel.refine("withoutsyst", autoSyst=False)

        plots = []

        trigCut, trigWeight = None, None
        if isMC:
            muR = op.systematic(op.c_float(1.),
                                name="muR",
                                up=t.PSWeight[2],
                                down=t.PSWeight[0])
            muF = op.systematic(op.c_float(1.),
                                name="muF",
                                up=t.PSWeight[3],
                                down=t.PSWeight[1])

            noSel = noSel.refine(
                "mcWeight",
                weight=[t.genWeight, t.puWeight, t.PrefireWeight, muR, muF])

            trigCut = op.OR(t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ,
                            t.HLT.HIL3DoubleMu0, t.HLT.HIL3Mu20,
                            t.HLT.HIEle20_WPLoose_Gsf)
            trigWeight = op.switch(
                op.OR(t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ,
                      t.HLT.HIL3DoubleMu0), op.c_float(1.),
                op.switch(t.HLT.HIL3Mu20, op.c_float(306.913 / 308.545),
                          op.c_float(264.410 / 308.545))
            )  ## FIXME these are wrong - you will get the final values from team A

        else:
            ## trigger order: dielectron, dimuon or single muon, single electron
            pd = sample.split("_")[0]
            if pd == "SingleMuon":
                trigCut = op.AND(
                    op.NOT(t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ),
                    op.OR(t.HLT.HIL3DoubleMu0, t.HLT.HIL3Mu20))
            elif pd == "HighEGJet":
                trigCut = op.OR(
                    t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ,
                    op.AND(op.NOT(op.OR(t.HLT.HIL3DoubleMu0, t.HLT.HIL3Mu20)),
                           t.HLT.HIEle20_WPLoose_Gsf))

        noSel = noSel.refine("trig", cut=trigCut, weight=trigWeight)
        #plots += [Plot.make1D("nTotalEvents", op.rng_len([1]), noSel , EqB(1, 0, 1.), title="nTotalEvents")]
        plots.append(
            Plot.make1D("nTotalJets",
                        op.rng_len(t.Jet),
                        noSel,
                        EqB(15, 0, 15.),
                        title="Initial Jet multiplicity"))
        #noSel = noSel.refine("trig", cut=op.OR(t.HLT.HIL3DoubleMu0, t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ))

        # plots = []
        goodLeptons = {
            "el":
            op.select(
                t.Electron, lambda el: op.AND(el.pt > 15.,
                                              op.abs(el.p4.Eta()) < 2.5)
            ),  # op.select(t.Electron, partial(isGoodElectron, ptCut=15.)),
            "mu":
            op.select(t.Muon, lambda mu: mu.pt > 20.
                      )  # op.select(t.Muon, partial(isGoodMuon, ptCut=15.))
        }
        plots += [
            Plot.make1D(
                "trig_nLeptons15",
                op.rng_len(goodLeptons["el"]) + op.rng_len(goodLeptons["mu"]),
                noSel, EqB(15, 0., 15.)),
            Plot.make1D("trig_nEl15", op.rng_len(goodLeptons["el"]), noSel,
                        EqB(15, 0., 15.)),
            Plot.make1D("trig_nMu15", op.rng_len(goodLeptons["mu"]), noSel,
                        EqB(15, 0., 15.))
        ]
        from bamboo.scalefactors import get_scalefactor
        sf_loose = {
            "mu":
            get_scalefactor("lepton",
                            "Muon_RecoToLoose",
                            sfLib=scalefactors_lepMVA,
                            paramDefs=binningVariables_nano_noScaleSyst,
                            systName="muLoose"),
            "el":
            get_scalefactor("lepton",
                            "Electron_RecoToLoose",
                            sfLib=scalefactors_lepMVA,
                            paramDefs=binningVariables_nano_noScaleSyst,
                            systName="elLoose")
        }
        sf_tight = {
            "mu":
            get_scalefactor("lepton",
                            "Muon_LooseToTight",
                            sfLib=scalefactors_lepMVA,
                            paramDefs=binningVariables_nano_noScaleSyst,
                            systName="muTight"),
            "el":
            get_scalefactor("lepton",
                            "Electron_LooseToTight",
                            sfLib=scalefactors_lepMVA,
                            paramDefs=binningVariables_nano_noScaleSyst,
                            systName="elTight")
        }

        nGoodLeptons = op.rng_len(goodLeptons["el"]) + op.rng_len(
            goodLeptons["mu"])
        hasTwoGoodLeptons = noSel.refine(
            "has2Lep", cut=(nGoodLeptons > 1))  # avoid overlap with 1l
        jets = op.sort(
            op.select(
                t.Jet, lambda j: op.AND(
                    j.pt > 25.,
                    op.abs(j.eta) < 2.4, j.jetId & 0x2,
                    op.AND(
                        op.NOT(
                            op.rng_any(goodLeptons["el"], lambda l: op.deltaR(
                                l.p4, j.p4) < 0.4)),
                        op.NOT(
                            op.rng_any(goodLeptons["mu"], lambda l: op.deltaR(
                                l.p4, j.p4) < 0.4))))), lambda j: -j.pt)
        ## WP: see https://twiki.cern.ch/twiki/bin/viewauth/CMS/BtagRecommendation94X
        loosebjets = op.select(jets, lambda j: j.btagDeepB > 0.1522)
        mediumbjets = op.select(jets, lambda j: j.btagDeepB > 0.4941)
        for fl1, fl2 in product(*repeat(goodLeptons.keys(), 2)):
            dilepSel = lambda l1, l2: op.AND(l1.charge != l2.charge,
                                             (l1.p4 + l2.p4).M() > 12.)
            if fl1 == fl2:
                lGood = op.sort(goodLeptons[fl1], lambda l: -l.pt)
                dilep = op.combine(lGood, N=2, pred=dilepSel)
            else:
                l1Good = op.sort(goodLeptons[fl1], lambda l: -l.pt)
                l2Good = op.sort(goodLeptons[fl2], lambda l: -l.pt)
                dilep = op.combine((l1Good, l2Good), pred=dilepSel)
            ll = dilep[0]
            hasDilep = hasTwoGoodLeptons.refine(
                f"hasDilep{fl1}{fl2}",
                cut=(op.rng_len(dilep) > 0, ll[0].pt > 25.),
                weight=([
                    sf_loose[fl1](ll[0]), sf_loose[fl2](ll[1]), sf_tight[fl1](
                        ll[0]), sf_tight[fl2](ll[1])
                ] if isMC else None))
            plots += [
                Plot.make1D(f"dilepton_{fl1}{fl2}_Mll",
                            (ll[0].p4 + ll[1].p4).M(),
                            hasDilep,
                            EqB(50, 70, 120.),
                            title="Dilepton mass"),
            ]
            for il, ifl in enumerate((fl1, fl2)):
                plots += [
                    Plot.make1D(f"dilepton_{fl1}{fl2}_L{il:d}PT",
                                ll[il].pt,
                                hasDilep,
                                EqB(50, 0., 100.),
                                title=f"Lepton {il:d} PT"),
                    Plot.make1D(f"dilepton_{fl1}{fl2}_L{il:d}ETA",
                                ll[il].eta,
                                hasDilep,
                                EqB(50, -2.5, 2.5),
                                title=f"Lepton {il:d} ETA"),
                ]
            plots += [
                Plot.make1D(f"dilepton_{fl1}{fl2}_nJets",
                            op.rng_len(jets),
                            hasDilep,
                            EqB(15, 0, 15.),
                            title="Jet multiplicity"),
                Plot.make1D(f"dilepton_{fl1}{fl2}_nLooseBJets",
                            op.rng_len(loosebjets),
                            hasDilep,
                            EqB(15, 0, 15.),
                            title="Loose b-jet multiplicity"),
                Plot.make1D(f"dilepton_{fl1}{fl2}_nMediumBJets",
                            op.rng_len(mediumbjets),
                            hasDilep,
                            EqB(15, 0, 15.),
                            title="Medium b-jet multiplicity"),
                #Plot.make1D(f"dilepton_{fl1}{fl2}_nSelectedEvents", 1, hasDilep, EqB(1, 0, 1.), title="nSelectedEvents")
            ]

        #muons = op.select(t.Muon, lambda mu : mu.pt > 20.)
        #twoMuSel = noSel.refine("twoMuons", cut=[ op.rng_len(muons) > 1 ])

        #electrons = op.select(t.Electron, lambda el : op.AND(el.pt > 15. , op.abs(el.p4.Eta()) < 2.5))
        #twoElSel = noSel.refine("twoElectrons", cut=[ op.rng_len(electrons) > 1 ])

        #oselmu = op.combine((electrons, muons))
        #leptons = oselmu[0]
        #twoLepSel = noSel.refine("twoLeptons", cut=[ op.rng_len(electrons) == 1 , op.rng_len(muons) == 1 ])

        #jets = op.select(t.Jet, lambda j : j.pt > 30.)

        #bjets = op.select(jets, lambda j : j.btagDeepFlavB > 0.2217)

        #plots.append(Plot.make1D("dimu_M",
        #    op.invariant_mass(muons[0].p4, muons[1].p4), twoMuSel, EqB(100, 20., 120.),
        #    title="Dimuon invariant mass", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))
        #plots.append(Plot.make1D("diel_M",
        #    op.invariant_mass(electrons[0].p4, electrons[1].p4), twoElSel, EqB(100, 20., 120.),
        #    title="Dielectron invariant mass", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))
        #plots.append(Plot.make1D("dilep_M",
        #    op.invariant_mass(leptons[0].p4, leptons[1].p4) , twoLepSel, EqB(100, 20., 120.),
        #    title="Dimuon invariant mass", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))
        #plots.append(SummedPlot("Mjj", plots, title="m(jj)"))

        #plots.append(Plot.make1D("nJets_dimu",op.rng_len(jets), twoMuSel, EqB(10, -0.5, 9.5),
        #    title="Jet multiplicity", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))

        #plots.append(Plot.make1D("nBJets_dimu",op.rng_len(bjets), twoMuSel, EqB(10, -0.5, 9.5),
        #    title="Jet multiplicity", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))

        #plots.append(Plot.make1D("nJets_diel",op.rng_len(jets), twoElSel, EqB(10, -0.5, 9.5),
        #    title="Jet multiplicity", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))

        #plots.append(Plot.make1D("nBJets_diel",op.rng_len(bjets), twoElSel, EqB(10, -0.5, 9.5),
        #    title="Jet multiplicity", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))

        #plots.append(Plot.make1D("nJets_elmu",op.rng_len(jets), twoLepSel, EqB(10, -0.5, 9.5),
        #    title="Jet multiplicity", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))

        #plots.append(Plot.make1D("nBJets_elmu",op.rng_len(bjets), twoLepSel, EqB(10, -0.5, 9.5),
        #    title="Jet multiplicity", plotopts={"show-overflow":False,
        #    "legend-position": [0.2, 0.6, 0.5, 0.9]}))

        return plots
Example #6
0
    def definePlots(self, t, noSel, sample=None, sampleCfg=None):
        from bamboo.plots import CutFlowReport, SummedPlot
        from bamboo.plots import EquidistantBinning as EqB
        from bamboo import treefunctions as op

        isMC = self.isMC(sample)
        trigCut, trigWeight = None, None
        if isMC:
            trigCut = op.OR(t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ, t.HLT.HIL3DoubleMu0, t.HLT.HIL3Mu20, t.HLT.HIEle20_WPLoose_Gsf)
            trigWeight = op.switch(op.OR(t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ, t.HLT.HIL3DoubleMu0), op.c_float(1.),
                    op.switch(t.HLT.HIL3Mu20, op.c_float(306.913/308.545), op.c_float(264.410/308.545))) ## FIXME these are wrong - you will get the final values from team A
        else:
            ## trigger order: dielectron, dimuon or single muon, single electron
            pd = sample.split("_")[0]
            if pd == "SingleMuon":
                trigCut = op.AND(op.NOT(t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ),
                    op.OR(t.HLT.HIL3DoubleMu0, t.HLT.HIL3Mu20))
            elif pd == "HighEGJet":
                trigCut = op.OR(t.HLT.HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ,
                    op.AND(op.NOT(op.OR(t.HLT.HIL3DoubleMu0, t.HLT.HIL3Mu20)),
                        t.HLT.HIEle20_WPLoose_Gsf))
        noSel = noSel.refine("trig", cut=trigCut, weight=trigWeight)

        plots = []

        def isGoodElectron(el, ptCut=10.):
            return op.AND(
                el.pt > ptCut,
                op.abs(el.eta) < 2.5,
                el.lostHits == 0, ## do you want this?
                op.abs(el.sip3d) < 8.,
                op.abs(el.dxy) < .05,
                op.abs(el.dz ) < .1,
                el.miniPFRelIso_all < 0.085,
                el.mvaTTH > 0.125,
                op.NOT(op.AND(el.jet.isValid, op.OR(el.jet.btagDeepB > .1522, el.jet.btagDeepB <= -999.)))
                )
        def isGoodMuon(mu, ptCut=10.):
            return op.AND(
                mu.pt > ptCut,
                op.abs(mu.eta) < 2.4,
                mu.mediumPromptId,
                op.abs(mu.sip3d) < 8.,
                op.abs(mu.dxy) < .05,
                op.abs(mu.dz ) < .1,
                mu.miniPFRelIso_all < 0.325,
                mu.mvaTTH > 0.55,
                op.NOT(op.AND(mu.jet.isValid, op.OR(mu.jet.btagDeepB > .1522, mu.jet.btagDeepB <= -999.)))
                )

        goodLeptons = {
            "el" : op.select(t.Electron, partial(isGoodElectron, ptCut=15.)),
            "mu" : op.select(t.Muon, partial(isGoodMuon, ptCut=15.))
            }
        plots += [
            Plot.make1D("trig_nLeptons15", op.rng_len(goodLeptons["el"])+op.rng_len(goodLeptons["mu"]), noSel, EqB(15, 0., 15.)),
            Plot.make1D("trig_nEl15", op.rng_len(goodLeptons["el"]), noSel, EqB(15, 0., 15.)),
            Plot.make1D("trig_nMu15", op.rng_len(goodLeptons["mu"]), noSel, EqB(15, 0., 15.)) 
            ]
        from bamboo.scalefactors import get_scalefactor
        sf_loose = {
            "mu": get_scalefactor("lepton", "Muon_RecoToLoose", sfLib=scalefactors_lepMVA, paramDefs=binningVariables_nano_noScaleSyst, systName="muLoose"),
            "el": get_scalefactor("lepton", "Electron_RecoToLoose", sfLib=scalefactors_lepMVA, paramDefs=binningVariables_nano_noScaleSyst, systName="elLoose")
            }
        sf_tight = {
            "mu": get_scalefactor("lepton", "Muon_LooseToTight", sfLib=scalefactors_lepMVA, paramDefs=binningVariables_nano_noScaleSyst, systName="muTight"),
            "el": get_scalefactor("lepton", "Electron_LooseToTight", sfLib=scalefactors_lepMVA, paramDefs=binningVariables_nano_noScaleSyst, systName="elTight")
            }

        nGoodLeptons = op.rng_len(goodLeptons["el"])+op.rng_len(goodLeptons["mu"])
        hasTwoGoodLeptons = noSel.refine("has2Lep", cut=(nGoodLeptons > 1)) # avoid overlap with 1l
        jets = op.sort(op.select(t.Jet, lambda j : op.AND(
            j.pt > 25.,
            op.abs(j.eta) < 2.4,
            j.jetId & 0x2,
            op.AND(
                op.NOT(op.rng_any(goodLeptons["el"], lambda l : op.deltaR(l.p4, j.p4) < 0.4)),
                op.NOT(op.rng_any(goodLeptons["mu"], lambda l : op.deltaR(l.p4, j.p4) < 0.4)))
            )), lambda j : -j.pt)
        ## WP: see https://twiki.cern.ch/twiki/bin/viewauth/CMS/BtagRecommendation94X
        loosebjets = op.select(jets, lambda j : j.btagDeepB > 0.1522)
        mediumbjets = op.select(jets, lambda j : j.btagDeepB > 0.4941)
        for fl1,fl2 in product(*repeat(goodLeptons.keys(), 2)):
            dilepSel = lambda l1,l2 : op.AND(
                    l1.charge != l2.charge,
                    (l1.p4+l2.p4).M() > 12.
                    )
            if fl1 == fl2:
                lGood = op.sort(goodLeptons[fl1], lambda l : -l.pt)
                dilep = op.combine(lGood, N=2, pred=dilepSel)
            else:
                l1Good = op.sort(goodLeptons[fl1], lambda l : -l.pt)
                l2Good = op.sort(goodLeptons[fl2], lambda l : -l.pt)
                dilep = op.combine((l1Good, l2Good), pred=dilepSel)
            ll = dilep[0]
            hasDilep = hasTwoGoodLeptons.refine(f"hasDilep{fl1}{fl2}", cut=(op.rng_len(dilep) > 0, ll[0].pt > 25.),
                    weight=([ sf_loose[fl1](ll[0]), sf_loose[fl2](ll[1]), sf_tight[fl1](ll[0]), sf_tight[fl2](ll[1]) ] if isMC else None))
            plots += [
                Plot.make1D(f"dilepton_{fl1}{fl2}_Mll", (ll[0].p4+ll[1].p4).M(), hasDilep, EqB(50, 70, 120.), title="Dilepton mass"),
                ]
#            for il,ifl in enumerate((fl1, fl2)):
##                plots += [
#                    Plot.make1D(f"dilepton_{fl1}{fl2}_L{il:d}PT", ll[il].pt, hasDilep, EqB(50, 0., 100.), title=f"Lepton {il:d} PT"),
#                    Plot.make1D(f"dilepton_{fl1}{fl2}_L{il:d}ETA", ll[il].eta, hasDilep, EqB(50, -2.5, 2.5), title=f"Lepton {il:d} ETA"),
#                    ]
#            plots += [
#                Plot.make1D(f"dilepton_{fl1}{fl2}_nJets", op.rng_len(jets), hasDilep, EqB(15, 0, 15.), title="Jet multiplicity"),
#                Plot.make1D(f"dilepton_{fl1}{fl2}_nLooseBJets", op.rng_len(loosebjets), hasDilep, EqB(15, 0, 15.), title="Loose b-jet multiplicity"),
#                Plot.make1D(f"dilepton_{fl1}{fl2}_nMediumBJets", op.rng_len(mediumbjets), hasDilep, EqB(15, 0, 15.), title="Medium b-jet multiplicity")
#                ]

        return plots