예제 #1
0
파일: HNLAnalyzer.py 프로젝트: dehuazhu/HNL
    def searchHNL(self, event):
        self.readCollections(event.input)
        self.counters.counter('HNL').inc('all events')
        # make PF candidates
        try:
            pfs = map(PhysicsObject, self.handles['pfcand'].product())
            event.pfs = pfs
        except:
            print(event.eventId, event.run, event.lumi)
            return False  #; set_trace()
        self.counters.counter('HNL').inc('good pf collections')

        #        event.rho = self.handles['rho'].product()[0]

        #####################################################################################
        # primary vertex
        #####################################################################################
        if not len(event.goodVertices):
            return False

        self.counters.counter('HNL').inc('>0 good vtx')

        #####################################################################################
        # produce collections and map our objects to convenient Heppy objects
        #####################################################################################
        # make muon collections
        event.muons = map(Muon, self.handles['muons'].product())
        # event.dsamuons    = self.buildDisplacedMuons(self.handles['dsamuons'].product())
        # event.dgmuons     = self.buildDisplacedMuons(self.handles['dgmuons' ].product())

        for imu in event.muons:
            imu.type = 13
            imu.rho = event.rho
        #        for imu in event.dsamuons: imu.type = 26
        #        for imu in event.dgmuons : imu.type = 39

        # save a flag to know whether the muons is likely OOT
        # FIXME! for displaced too?
        #TODO filter rather saving the flag
        for imu in event.muons:
            imu.isoot = self.isOotMuon(imu)

        event.electrons = map(Electron, self.handles['electrons'].product())

        # prepare the electrons for ID mangling
        for ele in event.electrons:
            ele.event = event.input.object(
            )  # RM: this is needed god knows why to get the eleID
            ele.rho = event.rho

        event.photons = map(Photon, self.handles['photons'].product())
        event.taus = map(Tau, self.handles['taus'].product())

        # make vertex objects
        event.pvs = self.handles['pvs'].product()
        event.svs = self.handles['svs'].product()
        event.beamspot = self.handles['beamspot'].product()

        # make met object
        event.pfmet = self.handles['pfmet'].product().at(0)
        event.puppimet = self.handles['puppimet'].product().at(0)

        # make jet object
        jets = map(Jet, self.handles['jets'].product())

        # assign to the leptons the primary vertex, will be needed to compute a few quantities
        pv = event.goodVertices[0]

        self.assignVtx(event.muons, pv)
        self.assignVtx(event.electrons, pv)

        #####################################################################################
        # filter for events with at least 3 leptons in proper flavor combination
        #####################################################################################

        #check there are enough leptons
        if len(event.muons + event.electrons) < 3:
            return False
        self.counters.counter('HNL').inc('>= 3 leptons')

        #check there are enough leptons in the resp. flavor combination
        if not self.checkLeptonFlavors(event.electrons, event.muons):
            return False

        #save the key numbers
        event.nElectrons = len(event.electrons)
        event.nMuons = len(event.muons)
        event.nLeptons = len(event.electrons) + len(event.muons)

        self.counters.counter('HNL').inc(
            '>= 3 leptons with correct flavor combo')

        #####################################################################################
        # Preselect electrons
        #####################################################################################
        #FIXME: make min electron pt configurable and set the default at 5 GeV
        event.electrons = [
            iele for iele in event.electrons
            if iele.pt() > 5. and abs(iele.eta()) < 2.5
        ]

        #check there are enough leptons in the resp. flavor combination
        if not self.checkLeptonFlavors(event.electrons, event.muons):
            return False

        self.counters.counter('HNL').inc(
            'enough electrons passing preselection')

        #####################################################################################
        # Preselect muons
        #####################################################################################

        event.muons = [
            imu for imu in event.muons
            if imu.pt() > 3. and abs(imu.eta()) < 2.4
        ]
        # event.dsamuons   = [imu for imu in event.dsamuons       if imu.pt()>3. and abs(imu.eta())>2.4]
        # event.dgmuons    = [imu for imu in event.dgmuons        if imu.pt()>3. and abs(imu.eta())>2.4]

        #check there are enough leptons in the resp. flavor combination
        if not self.checkLeptonFlavors(event.electrons, event.muons):
            return False
        self.counters.counter('HNL').inc('enough muons passing preselection')

        #####################################################################################
        # Preselect the prompt leptons
        #####################################################################################
        prompt_mu_cands = sorted(
            [mu for mu in event.muons if self.preselectPromptMuons(mu)],
            key=lambda x: x.pt(),
            reverse=True)
        prompt_ele_cands = sorted([
            ele
            for ele in event.electrons if self.preselectPromptElectrons(ele)
        ],
                                  key=lambda x: x.pt(),
                                  reverse=True)

        if self.cfg_ana.promptLepton == 'mu':
            prompt_leps = prompt_mu_cands
        elif self.cfg_ana.promptLepton == 'ele':
            prompt_leps = prompt_ele_cands
        else:
            print 'ERROR: HNLAnalyzer not supported lepton flavour', self.cfg_ana.promptLepton
            exit(0)
        if not len(prompt_leps):
            return False

        self.counters.counter('HNL').inc('>0 prompt lep')

        #####################################################################################
        # HLT matching
        #####################################################################################

        # match only if the trigger fired and if it is among those we care about
        fired_triggers = [
            info for info in getattr(event, 'trigger_infos', [])
            if info.fired and '_'.join(info.name.split('_')[:-1]) in
            self.cfg_ana.triggersAndFilters.keys()
        ]

        drmax = 0.15

        # loop over the selected prompt leptons
        for ilep in prompt_leps:

            # prepare the HLT obj container, empty
            ilep.matched_hlt_obj = []

            # loop over the final HLT objects of each path
            for info in fired_triggers:

                # get the HLT name w/o version
                hltname = '_'.join(info.name.split('_')[:-1])
                # get the filter name you want to match the offline lepton to
                lastfilter = self.cfg_ana.triggersAndFilters[hltname]
                # get the corresponding HLT objects
                lastobjects = [
                    iobj for iobj in info.objects
                    if lastfilter in [ilab for ilab in iobj.filterLabels()]
                ]
                # match HLT objects and leptons
                matchedobjs = [
                    iobj for iobj in lastobjects if deltaR(iobj, ilep) < drmax
                ]
                # extend the list of matched objects
                ilep.matched_hlt_obj.extend(matchedobjs)

            # remove duplicates through 'set'
            ilep.matched_hlt_obj = [iobj for iobj in set(ilep.matched_hlt_obj)]

        # now filter out non matched leptons
        prompt_leps = [
            ilep for ilep in prompt_leps if len(ilep.matched_hlt_obj) > 0
        ]

        if len(prompt_leps) == 0:
            return False

        self.counters.counter('HNL').inc('>0 trig match prompt lep')

        #####################################################################################
        # Select the prompt lepton candidate and remove it from the collection of leptons
        #####################################################################################

        # the collection is already sorted by pt, just take the first
        prompt_lep = prompt_leps[0]

        # remove the prompt lepton from the corresponding lepton collection that will be later used to find the displaced di-lepton
        event.filtered_muons = [
            mu for mu in event.muons if mu.physObj != prompt_lep.physObj
        ]
        event.filtered_electrons = [
            ele for ele in event.electrons if ele.physObj != prompt_lep.physObj
        ]

        ########################################################################################
        # Preselection for the reco leptons and then create pairs
        ########################################################################################
        # some simple preselection
        event.muons = [
            imu for imu in event.filtered_muons
            if imu.pt() > 3. and abs(imu.eta()) < 2.4
        ]
        # event.dsamuons   = [imu for imu in event.dsamuons       if imu.pt()>3. and abs(imu.eta())>2.4]
        # event.dgmuons    = [imu for imu in event.dgmuons        if imu.pt()>3. and abs(imu.eta())>2.4]
        event.electrons = [
            iele for iele in event.filtered_electrons
            if iele.pt() > 5. and abs(iele.eta()) < 2.5
        ]

        # create all the possible di-lepton pairs out of the different collections
        dileptons = self.makeLeptonPairs(event, event.electrons, event.muons)

        if not len(dileptons):
            return False

        self.counters.counter('HNL').inc('> 0 di-lepton')

        ########################################################################################
        # Vertex Fit: Select only dilepton pairs with mutual vertices
        ########################################################################################
        dileptonsvtx = []
        for index, pair in enumerate(dileptons):
            if pair[0] == pair[1]: continue
            sv = fitVertex(pair, self.cfg_ana.L1L2LeptonType)
            if not sv: continue
            dileptonsvtx.append(DiLepton(pair, sv, pv, event.beamspot))

        event.dileptonsvtx = dileptonsvtx

        if not len(event.dileptonsvtx):
            return False

        self.counters.counter('HNL').inc('> 0 di-lepton + vtx')

        ########################################################################################
        # Select the most promising dilepton candidate
        ########################################################################################
        self.selectDiLepton(event, dileptonsvtx)

        ########################################################################################
        # Create a reco HNL3L object and "harvest" all the relevant eventinfos
        ########################################################################################
        event.the_3lep_cand = HN3L(prompt_lep,
                                   event.displaced_dilepton_reco_cand.lep1(),
                                   event.displaced_dilepton_reco_cand.lep2(),
                                   event.pfmet)

        # save reco secondary vertex
        event.recoSv = event.displaced_dilepton_reco_cand.vtx()

        event.recoSv.disp3DFromBS = ROOT.VertexDistance3D().distance(
            event.recoSv, pv)
        event.recoSv.disp3DFromBS_sig = event.recoSv.disp3DFromBS.significance(
        )

        # create an 'ideal' vertex out of the BS
        point = ROOT.reco.Vertex.Point(
            event.beamspot.position().x(),
            event.beamspot.position().y(),
            event.beamspot.position().z(),
        )
        error = event.beamspot.covariance3D()
        chi2 = 0.
        ndof = 0.
        bsvtx = ROOT.reco.Vertex(point, error, chi2, ndof,
                                 2)  # size? say 3? does it matter?

        event.recoSv.disp2DFromBS = ROOT.VertexDistanceXY().distance(
            event.recoSv, bsvtx)
        event.recoSv.disp2DFromBS_sig = event.recoSv.disp2DFromBS.significance(
        )
        event.recoSv.prob = ROOT.TMath.Prob(event.recoSv.chi2(),
                                            int(event.recoSv.ndof()))

        dilep_p4 = event.displaced_dilepton_reco_cand.lep1().p4(
        ) + event.displaced_dilepton_reco_cand.lep2().p4()

        perp = ROOT.math.XYZVector(dilep_p4.px(), dilep_p4.py(), 0.)

        dxybs = ROOT.GlobalPoint(
            -1 *
            ((event.beamspot.x0() - event.recoSv.x()) +
             (event.recoSv.z() - event.beamspot.z0()) * event.beamspot.dxdz()),
            -1 *
            ((event.beamspot.y0() - event.recoSv.y()) +
             (event.recoSv.z() - event.beamspot.z0()) * event.beamspot.dydz()),
            0)

        vperp = ROOT.math.XYZVector(dxybs.x(), dxybs.y(), 0.)

        cos = vperp.Dot(perp) / (vperp.R() * perp.R())

        event.recoSv.disp2DFromBS_cos = cos

        ########################################################################################
        # Define event.selectedLeptons, will be used by JetAnalyzer.py
        ########################################################################################

        # the selected 3 leptons must be leptons and not jets
        event.selectedLeptons = [
            event.the_3lep_cand.l0(),
            event.the_3lep_cand.l1(),
            event.the_3lep_cand.l2()
        ]

        # plus any isolated electron or muon is also a good lepton rather than a jet
        event.selMuons = [
            mu for mu in event.muons if self.preselectPromptMuons(mu, pt=10)
            and mu.relIsoR(R=0.3, dBetaFactor=0.5, allCharged=0) < 0.15
        ]
        event.selElectrons = [
            ele for ele in event.electrons
            if self.preselectPromptElectrons(ele, pt=10)
            and ele.relIsoR(R=0.3, dBetaFactor=0.5, allCharged=0) < 0.15
        ]
        # RM: what about taus?

        event.selectedLeptons += event.selMuons
        event.selectedLeptons += event.selElectrons

        ########################################################################################
        # Extra prompt and isolated lepton veto
        ########################################################################################
        event.veto_mus = [
            mu for mu in event.selMuons if mu.physObj not in [
                event.the_3lep_cand.l0().physObj,
                event.the_3lep_cand.l1().physObj,
                event.the_3lep_cand.l2().physObj
            ]
        ]
        event.veto_eles = [
            ele for ele in event.selElectrons if ele.physObj not in [
                event.the_3lep_cand.l0().physObj,
                event.the_3lep_cand.l1().physObj,
                event.the_3lep_cand.l2().physObj
            ]
        ]

        #FIXME: Is this step really needed?
        if len(event.veto_eles):
            event.veto_save_ele = sorted([ele for ele in event.veto_eles],
                                         key=lambda x: x.pt,
                                         reverse=True)[0]
        if len(event.veto_mus):
            event.veto_save_mu = sorted([mu for mu in event.veto_mus],
                                        key=lambda x: x.pt,
                                        reverse=True)[0]

        ########################################################################################
        # charged PF isolation
        ########################################################################################

        event.the_3lep_cand.abs_tot_iso03_rhoArea = totIso(
            event, 'rhoArea', 0.3)
        event.the_3lep_cand.abs_tot_iso04_rhoArea = totIso(
            event, 'rhoArea', 0.4)
        event.the_3lep_cand.abs_tot_iso05_rhoArea = totIso(
            event, 'rhoArea', 0.5)

        event.the_3lep_cand.rel_tot_iso03_rhoArea = event.the_3lep_cand.abs_tot_iso03_rhoArea / event.the_3lep_cand.hnVisP4(
        ).pt()
        event.the_3lep_cand.rel_tot_iso04_rhoArea = event.the_3lep_cand.abs_tot_iso04_rhoArea / event.the_3lep_cand.hnVisP4(
        ).pt()
        event.the_3lep_cand.rel_tot_iso05_rhoArea = event.the_3lep_cand.abs_tot_iso05_rhoArea / event.the_3lep_cand.hnVisP4(
        ).pt()

        event.the_3lep_cand.abs_tot_iso03_deltaBeta = totIso(
            event, 'dBeta', 0.3)
        event.the_3lep_cand.abs_tot_iso04_deltaBeta = totIso(
            event, 'dBeta', 0.4)
        event.the_3lep_cand.abs_tot_iso05_deltaBeta = totIso(
            event, 'dBeta', 0.5)

        event.the_3lep_cand.rel_tot_iso03_deltaBeta = event.the_3lep_cand.abs_tot_iso03_deltaBeta / event.the_3lep_cand.hnVisP4(
        ).pt()
        event.the_3lep_cand.rel_tot_iso04_deltaBeta = event.the_3lep_cand.abs_tot_iso04_deltaBeta / event.the_3lep_cand.hnVisP4(
        ).pt()
        event.the_3lep_cand.rel_tot_iso05_deltaBeta = event.the_3lep_cand.abs_tot_iso05_deltaBeta / event.the_3lep_cand.hnVisP4(
        ).pt()

        #####################################################################################
        # After passing all selections and we have an HNL candidate, pass a "true" boolean!
        #####################################################################################
        return True
예제 #2
0
    def process(self, event):
        self.readCollections(event.input)

        self.counters.counter('HNLGenTree').inc('all events')

        # produce collections
        event.genp_pruned = self.mchandles['genp_pruned'].product()
        event.genp_packed = self.mchandles['genp_packed'].product()

        # no point to run this if it's not a HNL signal
        if 'HN3L' not in self.cfg_comp.name:
            return True

#         for pp in event.genp_packed:
#             printer = lambda : 'pat::PackedGenParticle:   %d, pt  %.2f, eta  %.2f, phi  %.2f, mass  %.2f, status  %d' %(pp.pdgId(), pp.pt(), pp.eta(), pp.phi(), pp.mass(), pp.status())
#             import pdb ; pdb.set_trace()
#             pp.__str__ = printer
#             import pdb ; pdb.set_trace()
#
#         import pdb ; pdb.set_trace()

# all gen particles
        event.genp = [ip for ip in event.genp_pruned
                      ] + [ip for ip in event.genp_packed]

        # get the heavy neutrino
        the_hns = [
            ip for ip in event.genp_pruned
            if abs(ip.pdgId()) == 9900012 and ip.isLastCopy()
        ]
        event.the_hn = the_hns[0]  # one per event

        # prompt lepton
        event.the_pl = map(GenParticle, [
            ip for ip in event.genp_pruned if abs(ip.pdgId()) in [11, 13]
            and ip.isPromptFinalState() and not isAncestor(event.the_hn, ip)
        ])[0]

        # get the immediate daughters of the heavy neutrino decay
        event.the_hn.initialdaus = [
            event.the_hn.daughter(jj)
            for jj in range(event.the_hn.numberOfDaughters())
        ]

        event.the_hn.lep1 = max([
            ii
            for ii in event.the_hn.initialdaus if abs(ii.pdgId()) in [11, 13]
        ],
                                key=lambda x: x.pt())
        event.the_hn.lep2 = min([
            ii
            for ii in event.the_hn.initialdaus if abs(ii.pdgId()) in [11, 13]
        ],
                                key=lambda x: x.pt())
        try:
            event.the_hn.neu = [
                ii for ii in event.the_hn.initialdaus
                if abs(ii.pdgId()) in [12, 14]
            ][0]  # there can be only one
        except:
            print(
                '\t<< event.the_hn.neu  = [ii for ii in event.the_hn.initialdaus if abs(ii.pdgId()) in [12, 14]][0] >> crashes\n\tevent:',
                event.eventId, event.run, event.lumi)
            self.counters.counter('HNLGenTree').inc('bad events')
            #            set_trace()
            return False  # FIXME there is some problem with the line above in the new signal samples

        # identify the secondary vertex
        event.the_hn.the_sv = event.the_hn.lep1.vertex()

        # need to analyse the lepton after they radiated / converted
        for ip in [event.the_hn.lep1, event.the_hn.lep2, event.the_pl]:
            finaldaus = []
            for ipp in event.genp_packed:
                #             for ipp in event.genp: # try with all particles, see if it makes sense
                mother = ipp.mother(0)
                if mother and isAncestor(ip, mother):
                    finaldaus.append(ipp)
            ip.finaldaughters = sorted(finaldaus,
                                       key=lambda x: x.pt(),
                                       reverse=True)
            ip.hasConvOrRad = (len(ip.finaldaughters) > 1)
            if len(ip.finaldaughters) > 1:
                try:
                    ip.finallep = max([
                        ii for ii in ip.finaldaughters
                        if ii.pdgId() == ip.pdgId()
                    ],
                                      key=lambda x: x.pt())
                except:
                    try:
                        ip.finallep = max([
                            ii for ii in ip.finaldaughters
                            if abs(ii.pdgId()) in [11, 13]
                        ],
                                          key=lambda x: x.pt())
                    except:
                        return False
#                         import pdb ; pdb.set_trace()
            else:
                ip.finallep = ip

        # 4-momentum of the visible part of the HN
        event.the_hn.vishn = event.the_hn.lep1.finallep.p4(
        ) + event.the_hn.lep2.finallep.p4()

        # make it into a handy class
        event.the_hnl = HN3L(event.the_pl.finallep, event.the_hn.lep1.finallep,
                             event.the_hn.lep2.finallep, event.the_hn.neu)

        return True
예제 #3
0
파일: HNLAnalyzer.py 프로젝트: rmanzoni/HNL
    def process(self, event):

        # decide whether filter the event or pass through
        # useful to run multiple final states at the same time
        return_statement = getattr(self.cfg_ana, 'pass_through', False)

        # initiate a flag
        setattr(
            event, 'pass_%s' %
            (self.cfg_ana.promptLepton + self.cfg_ana.L1L2LeptonType), False)

        self.readCollections(event.input)
        self.counters.counter('HNL').inc('all events')

        #####################################################################################
        # primary vertex
        #####################################################################################
        if not len(event.goodVertices):
            return return_statement

        self.counters.counter('HNL').inc('>0 good vtx')

        #####################################################################################
        # produce collections and map our objects to convenient Heppy objects
        #####################################################################################
        # make muon collections
        event.muons = map(Muon, self.handles['muons'].product())
        #         event.dsamuons = self.buildDisplacedMuons(self.handles['dsamuons'].product())
        #         event.dgmuons  = self.buildDisplacedMuons(self.handles['dgmuons' ].product())

        for imu in event.muons:
            imu.type = 13
            imu.rho = event.rho
        #        for imu in event.dsamuons: imu.type = 26
        #        for imu in event.dgmuons : imu.type = 39

        # save a flag to know whether the muons is likely OOT
        # FIXME! for displaced too?
        for imu in event.muons:
            imu.isoot = self.isOotMuon(imu)

        event.electrons = map(Electron, self.handles['electrons'].product())
        # prepare the electrons for ID mangling
        for ele in event.electrons:
            ele.event = event.input.object(
            )  # RM: this is needed god knows why to get the eleID
            ele.rho = event.rho

        # assign to the leptons the primary vertex, will be needed to compute a few quantities
        pv = event.goodVertices[0]

        self.assignVtx(event.muons, pv)
        self.assignVtx(event.electrons, pv)

        #####################################################################################
        # filter for events with at least 3 leptons in proper flavor combination
        #####################################################################################
        event.muons = [
            imu for imu in event.muons if self.cfg_ana.muon_preselection(imu)
        ]
        event.electrons = [
            iele for iele in event.electrons
            if self.cfg_ana.ele_preselection(iele)
        ]

        if not self.checkLeptonFlavors(event.electrons, event.muons):
            return return_statement
        self.counters.counter('HNL').inc('>= 3L w/ correct flavours')

        #####################################################################################
        # finish reading collections
        #####################################################################################

        # make vertex objects
        event.beamspot = self.handles['beamspot'].product()

        # make met object
        event.pfmet = self.handles['pfmet'].product().at(0)
        event.puppimet = self.handles['puppimet'].product().at(0)

        #####################################################################################
        # Preselect the prompt leptons
        #####################################################################################
        prompt_mu_cands = sorted([
            mu for mu in event.muons
            if self.preselectPromptMuons(mu, isoAE03cut=0.2)
        ],
                                 key=lambda x: x.pt(),
                                 reverse=True)
        prompt_ele_cands = sorted([
            ele for ele in event.electrons
            if self.preselectPromptElectrons(ele, isoAE03cut=0.2)
        ],
                                  key=lambda x: x.pt(),
                                  reverse=True)

        if self.cfg_ana.promptLepton == 'm':
            prompt_leps = prompt_mu_cands
        elif self.cfg_ana.promptLepton == 'e':
            prompt_leps = prompt_ele_cands
        else:
            print 'ERROR: HNLAnalyzer not supported lepton flavour', self.cfg_ana.promptLepton
            sys.exit(0)
        if not len(prompt_leps):
            return return_statement

        self.counters.counter('HNL').inc('>0 prompt lep')

        #####################################################################################
        # HLT matching
        #####################################################################################

        # match only if the trigger fired and if it is among those we care about
        # set_trace()
        fired_triggers = [
            info for info in getattr(event, 'trigger_infos', [])
            if info.fired and '_'.join(info.name.split('_')[:-1]) in
            self.cfg_ana.triggersAndFilters.keys()
        ]

        drmax = getattr(self.cfg_ana, 'dr_max', 0.15)

        # loop over the selected prompt leptons
        for ilep in prompt_leps:

            # prepare the HLT obj container, empty
            ilep.matched_hlt_obj = []

            # loop over the final HLT objects of each path
            for info in fired_triggers:

                # get the HLT name w/o version
                hltname = '_'.join(info.name.split('_')[:-1])
                # get the filter name you want to match the offline lepton to
                lastfilter = self.cfg_ana.triggersAndFilters[hltname]
                # get the corresponding HLT objects
                lastobjects = [
                    iobj for iobj in info.objects
                    if lastfilter in [ilab for ilab in iobj.filterLabels()]
                ]
                # match HLT objects and leptons
                matchedobjs = [
                    iobj for iobj in lastobjects if deltaR(iobj, ilep) < drmax
                ]
                # extend the list of matched objects
                ilep.matched_hlt_obj.extend(matchedobjs)
                # set_trace()
            # remove duplicates through 'set'
            ilep.matched_hlt_obj = [iobj for iobj in set(ilep.matched_hlt_obj)]

        # now filter out non matched leptons
        prompt_leps = [
            ilep for ilep in prompt_leps if len(ilep.matched_hlt_obj) > 0
        ]

        if len(prompt_leps) == 0:
            return return_statement

        self.counters.counter('HNL').inc('>0 trig match prompt lep')

        #####################################################################################
        # Select the prompt lepton candidate and remove it from the collection of leptons
        #####################################################################################

        # the collection is already sorted by pt, just take the first
        prompt_lep = prompt_leps[0]

        # remove the prompt lepton from the corresponding lepton collection that will be later used to find the displaced di-lepton
        event.filtered_muons = [
            mu for mu in event.muons if mu.physObj != prompt_lep.physObj
        ]
        event.filtered_electrons = [
            ele for ele in event.electrons if ele.physObj != prompt_lep.physObj
        ]

        ########################################################################################
        # Create pairs
        ########################################################################################

        # create all the possible di-lepton pairs out of the different collections
        # AFTER having removed the prompt lepton
        dileptons = self.makeLeptonPairs(event, event.filtered_electrons,
                                         event.filtered_muons)

        if not len(dileptons):
            return return_statement

        self.counters.counter('HNL').inc('> 0 di-lepton')

        ########################################################################################
        # Vertex Fit: Select only dilepton pairs with mutual vertices
        ########################################################################################
        dileptonsvtx = []
        for index, pair in enumerate(dileptons):
            if pair[0] == pair[1]: continue
            sv = fitVertex(pair, self.cfg_ana.L1L2LeptonType)
            if not sv: continue
            dileptonsvtx.append(DiLepton(pair, sv, pv, event.beamspot))

        ########################################################################################
        # skim the dilepton candidates
        ########################################################################################
        dilep_selector = getattr(self.cfg_ana, 'dilepton_selector', True)
        dileptonsvtx = [
            idilep for idilep in dileptonsvtx if dilep_selector(idilep)
        ]

        if not len(dileptonsvtx):
            return return_statement

        event.dileptonsvtx = dileptonsvtx

        final_state = self.cfg_ana.promptLepton + self.cfg_ana.L1L2LeptonType

        if not getattr(event, 'dileptonsvtx_dict', False):
            event.dileptonsvtx_dict = OrderedDict()
        event.dileptonsvtx_dict[final_state] = event.dileptonsvtx

        if not len(event.dileptonsvtx):
            return return_statement

        self.counters.counter('HNL').inc('> 0 di-lepton + vtx')

        ########################################################################################
        # Select the most promising dilepton candidate
        ########################################################################################
        event.displaced_dilepton_reco_cand = self.selectDiLepton(
            event, dileptonsvtx)

        ########################################################################################
        # Create a reco HNL3L object and "harvest" all the relevant eventinfos
        ########################################################################################
        event.the_3lep_cand = HN3L(prompt_lep,
                                   event.displaced_dilepton_reco_cand.lep1(),
                                   event.displaced_dilepton_reco_cand.lep2(),
                                   event.pfmet)

        if not getattr(event, 'the_3lep_cand_dict', False):
            event.the_3lep_cand_dict = OrderedDict()
        event.the_3lep_cand_dict[final_state] = event.the_3lep_cand

        # save reco secondary vertex
        event.recoSv = event.displaced_dilepton_reco_cand.vtx()

        event.recoSv.disp3DFromBS = ROOT.VertexDistance3D().distance(
            event.recoSv, pv)
        event.recoSv.disp3DFromBS_sig = event.recoSv.disp3DFromBS.significance(
        )

        # create an 'ideal' vertex out of the BS
        point = ROOT.reco.Vertex.Point(
            event.beamspot.position().x(),
            event.beamspot.position().y(),
            event.beamspot.position().z(),
        )
        error = event.beamspot.covariance3D()
        chi2 = 0.
        ndof = 0.
        bsvtx = ROOT.reco.Vertex(point, error, chi2, ndof,
                                 2)  # size? say 3? does it matter?

        event.recoSv.disp2DFromBS = ROOT.VertexDistanceXY().distance(
            event.recoSv, bsvtx)
        event.recoSv.disp2DFromBS_sig = event.recoSv.disp2DFromBS.significance(
        )
        event.recoSv.prob = ROOT.TMath.Prob(event.recoSv.chi2(),
                                            int(event.recoSv.ndof()))

        dilep_p4 = event.displaced_dilepton_reco_cand.lep1().p4(
        ) + event.displaced_dilepton_reco_cand.lep2().p4()

        perp = ROOT.math.XYZVector(dilep_p4.px(), dilep_p4.py(), 0.)

        dxybs = ROOT.GlobalPoint(
            -1 *
            ((event.beamspot.x0() - event.recoSv.x()) +
             (event.recoSv.z() - event.beamspot.z0()) * event.beamspot.dxdz()),
            -1 *
            ((event.beamspot.y0() - event.recoSv.y()) +
             (event.recoSv.z() - event.beamspot.z0()) * event.beamspot.dydz()),
            0)

        vperp = ROOT.math.XYZVector(dxybs.x(), dxybs.y(), 0.)

        cos = vperp.Dot(perp) / (vperp.R() * perp.R())

        event.recoSv.disp2DFromBS_cos = cos

        if not getattr(event, 'recoSv_dict', False):
            event.recoSv_dict = OrderedDict()
        event.recoSv_dict[final_state] = event.recoSv

        ########################################################################################
        # Define event.selectedLeptons, will be used by JetAnalyzer.py
        ########################################################################################

        # different selected leptons for different final states
        if not hasattr(event, 'selectedLeptons'):
            event.selectedLeptons = OrderedDict()

        # final state, as configured
        final_state = self.cfg_ana.promptLepton + self.cfg_ana.L1L2LeptonType

        # the selected 3 leptons must be leptons and not jets
        event.selectedLeptons[final_state] = [
            event.the_3lep_cand.l0(),
            event.the_3lep_cand.l1(),
            event.the_3lep_cand.l2()
        ]

        # plus any isolated electron or muon is also a good lepton rather than a jet
        event.selMuons = [
            mu for mu in event.muons if self.preselectPromptMuons(mu, pt=10)
            and mu.relIso(cone_size=0.3,
                          iso_type='dbeta',
                          dbeta_factor=0.5,
                          all_charged=0) < 0.15
            and mu not in event.selectedLeptons[final_state]
        ]
        event.selElectrons = [
            ele for ele in event.electrons
            if self.preselectPromptElectrons(ele, pt=10)
            and ele.relIso(cone_size=0.3,
                           iso_type='dbeta',
                           dbeta_factor=0.5,
                           all_charged=0) < 0.15
            and ele not in event.selectedLeptons[final_state]
        ]
        # RM: what about taus?

        event.selectedLeptons[final_state] += event.selMuons
        event.selectedLeptons[final_state] += event.selElectrons

        ########################################################################################
        # Extra prompt and isolated lepton veto
        ########################################################################################
        event.veto_mus = [
            mu for mu in event.selMuons if mu.physObj not in [
                event.the_3lep_cand.l0().physObj,
                event.the_3lep_cand.l1().physObj,
                event.the_3lep_cand.l2().physObj
            ]
        ]
        event.veto_eles = [
            ele for ele in event.selElectrons if ele.physObj not in [
                event.the_3lep_cand.l0().physObj,
                event.the_3lep_cand.l1().physObj,
                event.the_3lep_cand.l2().physObj
            ]
        ]

        # FIXME!: Is this step really needed?
        if len(event.veto_eles):
            event.veto_save_ele = sorted([ele for ele in event.veto_eles],
                                         key=lambda x: x.pt,
                                         reverse=True)[0]
        if len(event.veto_mus):
            event.veto_save_mu = sorted([mu for mu in event.veto_mus],
                                        key=lambda x: x.pt,
                                        reverse=True)[0]

        #####################################################################################
        # After passing all selections and we have an HNL candidate, pass a "true" boolean!
        #####################################################################################

        # save a flag
        setattr(
            event, 'pass_%s' %
            (self.cfg_ana.promptLepton + self.cfg_ana.L1L2LeptonType), True)

        #         print '\n\n' + '='*50
        #         print 'run %d \t lumi %d events %d' %(event.run, event.lumi, event.eventId)
        #         print '\tmmm candidate charge12', event.the_3lep_cand_dict['mmm'].charge12()
        #         print '\tmmm candidate mass12  ', event.the_3lep_cand_dict['mmm'].mass12()
        #         print '\tmmm candidate cos     ', event.recoSv_dict['mmm'].disp2DFromBS_cos
        #         print '\t\t',event.the_3lep_cand_dict['mmm'].l0()
        #         print '\t\t',event.the_3lep_cand_dict['mmm'].l1()
        #         print '\t\t',event.the_3lep_cand_dict['mmm'].l2()
        #         for ii in map(Muon, self.handles['muons'].product()): print ii
        #         import pdb ; pdb.set_trace()

        return True
예제 #4
0
    def process(self, event):
        self.readCollections(event.input)

        self.counters.counter('HNLGenTree').inc('all events')

        # produce collections
        event.genp_pruned = self.mchandles['genp_pruned'].product()
        event.genp_packed = self.mchandles['genp_packed'].product()

        # all gen particles
        event.genp = [ip for ip in event.genp_pruned
                      ] + [ip for ip in event.genp_packed]

        # get the heavy neutrino
        the_hns = [
            ip for ip in event.genp_pruned
            if abs(ip.pdgId()) == 9900012 and ip.isLastCopy()
        ]
        event.the_hn = the_hns[0]  # one per event

        # prompt lepton
        event.the_pl = map(GenParticle, [
            ip for ip in event.genp_pruned if abs(ip.pdgId()) in [11, 13]
            and ip.isPromptFinalState() and not isAncestor(event.the_hn, ip)
        ])[0]

        # get the immediate daughters of the heavy neutrino decay
        event.the_hn.initialdaus = [
            event.the_hn.daughter(jj)
            for jj in range(event.the_hn.numberOfDaughters())
        ]

        event.the_hn.lep1 = max([
            ii
            for ii in event.the_hn.initialdaus if abs(ii.pdgId()) in [11, 13]
        ],
                                key=lambda x: x.pt())
        event.the_hn.lep2 = min([
            ii
            for ii in event.the_hn.initialdaus if abs(ii.pdgId()) in [11, 13]
        ],
                                key=lambda x: x.pt())
        event.the_hn.neu = [
            ii for ii in event.the_hn.initialdaus
            if abs(ii.pdgId()) in [12, 14]
        ][0]  # there can be only one

        # identify the secondary vertex
        event.the_hn.the_sv = event.the_hn.lep1.vertex()

        # need to analyse the lepton after they radiated / converted
        for ip in [event.the_hn.lep1, event.the_hn.lep2, event.the_pl]:
            finaldaus = []
            for ipp in event.genp_packed:
                #             for ipp in event.genp: # try with all particles, see if it makes sense
                mother = ipp.mother(0)
                if mother and isAncestor(ip, mother):
                    finaldaus.append(ipp)
            ip.finaldaughters = sorted(finaldaus,
                                       key=lambda x: x.pt(),
                                       reverse=True)
            ip.hasConvOrRad = (len(ip.finaldaughters) > 1)
            if len(ip.finaldaughters) > 1:
                try:
                    ip.finallep = max([
                        ii for ii in ip.finaldaughters
                        if ii.pdgId() == ip.pdgId()
                    ],
                                      key=lambda x: x.pt())
                except:
                    try:
                        ip.finallep = max([
                            ii for ii in ip.finaldaughters
                            if abs(ii.pdgId()) in [11, 13]
                        ],
                                          key=lambda x: x.pt())
                    except:
                        return False
#                         import pdb ; pdb.set_trace()
            else:
                ip.finallep = ip

        # 4-momentum of the visible part of the HN
        event.the_hn.vishn = event.the_hn.lep1.finallep.p4(
        ) + event.the_hn.lep2.finallep.p4()

        # make it into a handy class
        event.the_hnl = HN3L(event.the_pl.finallep, event.the_hn.lep1.finallep,
                             event.the_hn.lep2.finallep, event.the_hn.neu)

        return True
예제 #5
0
    def process(self, event):
        self.readCollections(event.input)
        self.counters.counter('HNL').inc('all events')
        # make PF candidates
        try:
            pfs = map(PhysicsObject, self.handles['pfcand'].product())
#            set_trace()
#            return False
        except: print(event.eventId, event.run, event.lumi); return False#; set_trace()
        self.counters.counter('HNL').inc('good collections')

        #####################################################################################
        # primary vertex
        #####################################################################################
        if not len(event.goodVertices):
            return False

        self.counters.counter('HNL').inc('>0 good vtx')

        #####################################################################################
        # produce collections and map our objects to convenient Heppy objects
        #####################################################################################

        # make muon collections
        event.muons       = map(Muon, self.handles['muons'].product())
#        event.dsamuons    = self.buildDisplacedMuons(self.handles['dsamuons'].product())
#        event.dgmuons     = self.buildDisplacedMuons(self.handles['dgmuons' ].product())

        for imu in event.muons   : imu.type = 13
#        for imu in event.dsamuons: imu.type = 26
#        for imu in event.dgmuons : imu.type = 39

        # save a flag to know whether the muons is likely OOT
        # FIXME! for displaced too?
        for imu in event.muons:
            imu.isoot = self.isOotMuon(imu)

        event.electrons   = map(Electron, self.handles['electrons'].product())
        
        # prepare the electrons for ID mangling
        for ele in event.electrons:
            ele.event = event.input.object() # RM: this is needed god knows why to get the eleID
            ele.rho = event.rho

        event.photons     = map(Photon  , self.handles['photons'  ].product())
        event.taus        = map(Tau     , self.handles['taus'     ].product())

        # make vertex objects 
        event.pvs         = self.handles['pvs'     ].product()
        event.svs         = self.handles['svs'     ].product()
        event.beamspot    = self.handles['beamspot'].product()

        # make met object
        event.pfmet       = self.handles['pfmet'   ].product().at(0)
        event.puppimet    = self.handles['puppimet'].product().at(0)

        # make jet object
        jets = map(Jet, self.handles['jets'].product())        

        # assign to the leptons the primary vertex, will be needed to compute a few quantities
        pv = event.goodVertices[0]
        
        self.assignVtx(event.muons    , pv)
        self.assignVtx(event.electrons, pv)

        #####################################################################################
        # Preselect the prompt leptons
        #####################################################################################
        
        prompt_mu_cands  = sorted([mu  for mu  in event.muons     if self.preselectPromptMuons    (mu) ], key = lambda x : x.pt(), reverse = True)
        prompt_ele_cands = sorted([ele for ele in event.electrons if self.preselectPromptElectrons(ele)], key = lambda x : x.pt(), reverse = True)

        if   self.cfg_ana.promptLepton=='mu':
            prompt_leps = prompt_mu_cands       
        elif self.cfg_ana.promptLepton=='ele':
            prompt_leps = prompt_ele_cands
        else:
            print 'ERROR: HNLAnalyzer not supported lepton flavour', self.cfg_ana.promptLepton
            exit(0) 

        if not len(prompt_leps):
            return False

        self.counters.counter('HNL').inc('>0 prompt lep')

        #####################################################################################
        # HLT matching
        #####################################################################################
        
        # match only if the trigger fired and if it is among those we care about
        fired_triggers = [info for info in getattr(event, 'trigger_infos', []) if info.fired and '_'.join(info.name.split('_')[:-1]) in self.cfg_ana.triggersAndFilters.keys()]
    
        drmax=0.15
        
        # loop over the selected prompt leptons
        for ilep in prompt_leps:
        
            # prepare the HLT obj container, empty
            ilep.matched_hlt_obj = []
            
            # loop over the final HLT objects of each path
            for info in fired_triggers:
            
                # get the HLT name w/o version
                hltname     = '_'.join(info.name.split('_')[:-1])          
                # get the filter name you want to match the offline lepton to
                lastfilter  = self.cfg_ana.triggersAndFilters[hltname]
                # get the corresponding HLT objects
                lastobjects = [iobj for iobj in info.objects if lastfilter in [ilab for ilab in iobj.filterLabels()]]
                # match HLT objects and leptons
                matchedobjs = [iobj for iobj in lastobjects if deltaR(iobj, ilep)<drmax]
                # extend the list of matched objects
                ilep.matched_hlt_obj.extend(matchedobjs)
            
            # remove duplicates through 'set'
            ilep.matched_hlt_obj = [iobj for iobj in set(ilep.matched_hlt_obj)]
        
        # now filter out non matched leptons
        prompt_leps = [ilep for ilep in prompt_leps if len(ilep.matched_hlt_obj)>0]
        
        if len(prompt_leps)==0:
            return False
        
        self.counters.counter('HNL').inc('>0 trig match prompt lep')
        
        #####################################################################################
        # Select the prompt lepton candidate and remove it from the collection of leptons
        #####################################################################################

        # the collection is already sorted by pt, just take the first
        prompt_lep = prompt_leps[0]

        # remove the prompt lepton from the corresponding lepton collection that will be later used to find the displaced di-lepton
        event.filtered_muons     = [mu  for mu  in event.muons     if mu.physObj  != prompt_lep.physObj]
        event.filtered_electrons = [ele for ele in event.electrons if ele.physObj != prompt_lep.physObj]
         
        ########################################################################################
        # Preselection for the reco muons before pairing them
        ########################################################################################
        # some simple preselection
        event.muons    = [imu for imu in event.filtered_muons if imu.pt()>3. and abs(imu.eta())<2.4]
#        event.dsamuons = [imu for imu in event.dsamuons       if imu.pt()>3. and abs(imu.eta())>2.4]
#        event.dgmuons  = [imu for imu in event.dgmuons        if imu.pt()>3. and abs(imu.eta())>2.4]

        # create all the possible di-muon pairs out of the three different collections
        
        # FIXME! configure which collections to use
        # dimuons = combinations(event.muons + event.dsamuons + event.dgmuons, 2)
        dimuons = combinations(event.muons, 2)
        
        dimuons = [(mu1, mu2) for mu1, mu2 in dimuons if deltaR(mu1, mu2)>0.01]
        
        if not len(dimuons):
            return False
        self.counters.counter('HNL').inc('> 0 di-muon')

        ########################################################################################
        # Vertex Fit: Select only dimuon pairs with mutual vertices
        ########################################################################################
        dimuonsvtx = []
        for index, pair in enumerate(dimuons):
            if pair[0]==pair[1]: continue
            sv = fitVertex(pair)
            if not sv: continue
            dimuonsvtx.append(DiLepton(pair, sv, pv, event.beamspot))

        event.dimuonsvtx = dimuonsvtx
        
        if not len(event.dimuonsvtx):
            return False 
        
        self.counters.counter('HNL').inc('> 0 di-muon + vtx')

        ########################################################################################
        # candidate choice by different criteria
        ########################################################################################
        
        which_candidate = getattr(self.cfg_ana, 'candidate_selection', 'maxpt')
        
        if which_candidate == 'minmass'    : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(),  x.mass()                        ), reverse=False)[0]
        if which_candidate == 'minchi2'    : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(),  x.chi2()                        ), reverse=False)[0]
        if which_candidate == 'mindr'      : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(),  x.dr()                          ), reverse=False)[0]
        if which_candidate == 'maxdphi'    : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.dphi()                        ), reverse=False)[0]
        if which_candidate == 'mindeta'    : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(),  x.deta()                        ), reverse=False)[0]
        if which_candidate == 'maxdisp2dbs': event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.disp2DFromBS()                ), reverse=False)[0]
        if which_candidate == 'maxdisp2dpv': event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.disp2DFromPV()                ), reverse=False)[0]
        if which_candidate == 'maxdisp3dpv': event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.disp3DFromPV()                ), reverse=False)[0]
        if which_candidate == 'maxdls2dbs' : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.disp2DFromBSSignificance()    ), reverse=False)[0]
        if which_candidate == 'maxdls2dpv' : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.disp2DFromPVSignificance()    ), reverse=False)[0]
        if which_candidate == 'maxdls3dpv' : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.disp3DFromPVSignificance()    ), reverse=False)[0]
        if which_candidate == 'maxcos'     : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.cosTransversePointingAngleBS()), reverse=False)[0]
        if which_candidate == 'maxpt'      : event.displaced_dilepton_reco_cand = None if not len(dimuonsvtx) else sorted(dimuonsvtx, key = lambda x : (x.isSS(), -x.pt()                          ), reverse=False)[0]

        ########################################################################################
        # Create a reco HNL3L object
        ########################################################################################
        event.the_3lep_cand = HN3L(prompt_lep, 
                                   event.displaced_dilepton_reco_cand.lep1(), 
                                   event.displaced_dilepton_reco_cand.lep2(), 
                                   event.pfmet)
        
        # save reco secondary vertex
        event.recoSv = event.displaced_dilepton_reco_cand.vtx()

        event.recoSv.disp3DFromBS      = ROOT.VertexDistance3D().distance(event.recoSv, pv)
        event.recoSv.disp3DFromBS_sig  = event.recoSv.disp3DFromBS.significance()
        
        # create an 'ideal' vertex out of the BS
        point = ROOT.reco.Vertex.Point(
            event.beamspot.position().x(),
            event.beamspot.position().y(),
            event.beamspot.position().z(),
        )
        error = event.beamspot.covariance3D()
        chi2 = 0.
        ndof = 0.
        bsvtx = ROOT.reco.Vertex(point, error, chi2, ndof, 2) # size? say 3? does it matter?
                                        
        event.recoSv.disp2DFromBS      = ROOT.VertexDistanceXY().distance(event.recoSv, bsvtx)
        event.recoSv.disp2DFromBS_sig  = event.recoSv.disp2DFromBS.significance()
        event.recoSv.prob              = ROOT.TMath.Prob(event.recoSv.chi2(), int(event.recoSv.ndof()))
        
        dilep_p4 = event.displaced_dilepton_reco_cand.lep1().p4() + event.displaced_dilepton_reco_cand.lep2().p4()

        perp = ROOT.math.XYZVector(dilep_p4.px(),
                                   dilep_p4.py(),
                                   0.)
        
        dxybs = ROOT.GlobalPoint(-1*((event.beamspot.x0() - event.recoSv.x()) + (event.recoSv.z() - event.beamspot.z0()) * event.beamspot.dxdz()), 
                                 -1*((event.beamspot.y0() - event.recoSv.y()) + (event.recoSv.z() - event.beamspot.z0()) * event.beamspot.dydz()),
                                  0)
        
        vperp = ROOT.math.XYZVector(dxybs.x(), dxybs.y(), 0.)
        
        cos = vperp.Dot(perp)/(vperp.R()*perp.R())
        
        event.recoSv.disp2DFromBS_cos = cos

        ########################################################################################
        # Define event.selectedLeptons, will be used by JetAnalyzer.py
        ########################################################################################

        # the selected 3 leptons must be leptons and not jets
        event.selectedLeptons = [event.the_3lep_cand.l0(),
                                 event.the_3lep_cand.l1(),
                                 event.the_3lep_cand.l2()]

        # plus any isolated electron or muon is also a good lepton rather than a jet
        event.selMuons     = [mu  for mu  in event.muons     if self.preselectPromptMuons    (mu , pt=10) and mu .relIsoR(R=0.3, dBetaFactor=0.5, allCharged=0)<0.15]
        event.selElectrons = [ele for ele in event.electrons if self.preselectPromptElectrons(ele, pt=10) and ele.relIsoR(R=0.3, dBetaFactor=0.5, allCharged=0)<0.15]
        # RM: what about taus?

        event.selectedLeptons += event.selMuons
        event.selectedLeptons += event.selElectrons

        ########################################################################################
        # Extra prompt and isolated lepton veto
        ########################################################################################        
        event.veto_mus   = [ele for ele in event.selMuons     if ele.physObj not in [event.the_3lep_cand.l0().physObj, event.the_3lep_cand.l1().physObj, event.the_3lep_cand.l2().physObj] ]
        event.veto_eles  = [mu  for mu  in event.selElectrons if mu .physObj not in [event.the_3lep_cand.l0().physObj, event.the_3lep_cand.l1().physObj, event.the_3lep_cand.l2().physObj] ]

        if len(event.veto_eles): event.veto_save_ele = sorted([ele for ele in event.veto_eles], key = lambda x : x.pt, reverse = True)[0] 
        if len(event.veto_mus ): event.veto_save_mu  = sorted([mu  for mu  in event.veto_mus ], key = lambda x : x.pt, reverse = True)[0] 

        ########################################################################################
        # charged PF isolation
        ########################################################################################        
        chargedpfs = [ipf for ipf in pfs if ipf.charge()!=0 and abs(ipf.pdgId())!=11 and abs(ipf.pdgId())!=13]
        chargedpfs = [ipf for ipf in chargedpfs if ipf.pt()>0.6 and abs(ipf.eta())<2.5]
        chargedpfs = [ipf for ipf in chargedpfs if abs(ipf.dxy(event.recoSv.position()))<0.1 and abs(ipf.dz(event.recoSv.position()))<0.5]

        chisopfs = [ipf for ipf in chargedpfs if deltaR(ipf, event.the_3lep_cand.hnP4())<0.5]

        event.the_3lep_cand.abs_ch_iso = sum([ipf.pt() for ipf in chisopfs]) #FIXME MAYBE WE WANNA CHANGE HERE TO E INSTEAD OF pT
        event.the_3lep_cand.rel_ch_iso = event.the_3lep_cand.abs_ch_iso/event.the_3lep_cand.hnP4().pt()

        for mu in event.muons:
            print event.eventId, mu, mu.simType()
#        if (abs(event.the_3lep_cand.l1().simType()) > 100 or abs(event.the_3lep_cand.l2().simType()) > 100): set_trace()
        return True
예제 #6
0
    def process(self, event):
        self.readCollections(event.input)

        self.counters.counter('HNLGenTree').inc('all events')

        # produce collections
        event.genp_pruned = self.mchandles['genp_pruned'].product()
        event.genp_packed = self.mchandles['genp_packed'].product()

        # no point to run this if it's not a HNL signal
        if 'HN3L' not in self.cfg_comp.name:
            return True

#         for pp in event.genp_packed:
#             printer = lambda : 'pat::PackedGenParticle:   %d, pt  %.2f, eta  %.2f, phi  %.2f, mass  %.2f, status  %d' %(pp.pdgId(), pp.pt(), pp.eta(), pp.phi(), pp.mass(), pp.status())
#             import pdb ; pdb.set_trace()
#             pp.__str__ = printer
#             import pdb ; pdb.set_trace()
#
#         import pdb ; pdb.set_trace()

# all gen particles
        event.genp = [ip for ip in event.genp_pruned
                      ] + [ip for ip in event.genp_packed]

        # get the heavy neutrino
        the_hns = [
            ip for ip in event.genp_pruned
            if abs(ip.pdgId()) in [9900012, 9990012] and ip.isLastCopy()
        ]  # 9900012 is Majorana, 9990012 is Dirac. Dirac comes in two species, particle and anti-particle!
        event.the_hn = the_hns[0]  # one per event

        # RM FIXME! for the tau case, we might want to save the tau daughters as well...
        # prompt lepton
        #         import pdb ; pdb.set_trace()
        # treat light leptons and taus differently, as the former are stable. the latter decay
        pl_candidates = [
            ip for ip in event.genp_pruned if abs(ip.pdgId()) in [11, 13]
            and ip.isPromptFinalState() and not isAncestor(event.the_hn, ip)
        ]
        pl_candidates += [
            ip for ip in event.genp_pruned if abs(ip.pdgId()) in [15]
            and ip.isPromptDecayed() and not isAncestor(event.the_hn, ip)
        ]
        event.the_pl = map(GenParticle, pl_candidates)[0]
        #         import pdb ; pdb.set_trace()
        #         event.the_pl = map(GenParticle, [ip for ip in event.genp_pruned if abs(ip.pdgId()) in [11,13,15] and ip.isPromptFinalState() and not isAncestor(event.the_hn, ip)])[0]

        # get the immediate daughters of the heavy neutrino decay
        event.the_hn.initialdaus = [
            event.the_hn.daughter(jj)
            for jj in range(event.the_hn.numberOfDaughters())
        ]

        event.the_hn.lep1 = max([
            ii for ii in event.the_hn.initialdaus
            if abs(ii.pdgId()) in [11, 13, 15]
        ],
                                key=lambda x: x.pt())
        event.the_hn.lep2 = min([
            ii for ii in event.the_hn.initialdaus
            if abs(ii.pdgId()) in [11, 13, 15]
        ],
                                key=lambda x: x.pt())
        event.the_hn.neu = [
            ii for ii in event.the_hn.initialdaus
            if abs(ii.pdgId()) in [12, 14, 16]
        ][0]  # there can be only one

        # identify the secondary vertex
        event.the_hn.the_sv = event.the_hn.lep1.vertex()

        # need to analyse the lepton after they radiated / converted
        for ip in [event.the_hn.lep1, event.the_hn.lep2, event.the_pl]:
            finaldaus = []
            for ipp in event.genp_packed:
                #             for ipp in event.genp: # try with all particles, see if it makes sense
                mother = ipp.mother(0)
                if mother and isAncestor(ip, mother):
                    finaldaus.append(ipp)
            ip.finaldaughters = sorted(finaldaus,
                                       key=lambda x: x.pt(),
                                       reverse=True)
            ip.hasConvOrRad = (len(ip.finaldaughters) > 1)
            if len(ip.finaldaughters) > 1:
                try:
                    ip.finallep = max([
                        ii for ii in ip.finaldaughters
                        if ii.pdgId() == ip.pdgId()
                    ],
                                      key=lambda x: x.pt())
                except:
                    try:
                        ip.finallep = max([
                            ii for ii in ip.finaldaughters
                            if abs(ii.pdgId()) in [11, 13]
                        ],
                                          key=lambda x: x.pt())
                    except:
                        return False
#                         import pdb ; pdb.set_trace()
            else:
                ip.finallep = ip

        # 4-momentum of the visible part of the HN
        event.the_hn.vishn = event.the_hn.lep1.finallep.p4(
        ) + event.the_hn.lep2.finallep.p4()

        # make it into a handy class
        event.the_hnl = HN3L(event.the_pl.finallep, event.the_hn.lep1.finallep,
                             event.the_hn.lep2.finallep, event.the_hn.neu)

        return True