Exemple #1
0
 def __init__(self, *args, **kwargs):
     super(BKJPsiEEAnalyzer, self).__init__(*args, **kwargs)
     # stuff I need to instantiate only once
     self.vtxfit = VertexFitter()
     # create a std::vector<reco::Track> to be passed to the fitter 
     self.tofit_el = ROOT.std.vector('reco::Track')()
     # create a std::vector<pat::PackedCandidate> to be passed to the fitter 
     self.tofit_pc = ROOT.std.vector('pat::PackedCandidate')()
Exemple #2
0
    def beginLoop(self, setup):
        super(BKJPsiAnalyzer, self).beginLoop(setup)
        self.counters.addCounter('BKJPsiAnalyzer')
        count = self.counters.counter('BKJPsiAnalyzer')
        count.register('all events')
        count.register('>= 2 muons')
        count.register('dimuon mass < 6')
        count.register('good dimuon vtx')
        count.register('B(KLL) mass < 6')

        # stuff I need to instantiate only once
        self.vtxfit = VertexFitter()
        # create a std::vector<reco::RecoChargedCandidate> to be passed to the fitter
        self.tofit_cc = ROOT.std.vector('reco::RecoChargedCandidate')()
        # create a std::vector<pat::PackedCandidate> to be passed to the fitter
        self.tofit_pc = ROOT.std.vector('pat::PackedCandidate')()
Exemple #3
0
    def __init__(self, tk1, tk2, requireVtx=False):
        self.tk1_ = tk1
        self.tk2_ = tk2

        self.arbitrate()

        self.vtx = None
        self.vtxprob = -99.

        if requireVtx:
            # stuff I need to instantiate only once
            self.vtxfit = VertexFitter()
            # create a std::vector<reco::Track> to be passed to the fitter
            self.tofit = ROOT.std.vector('reco::Track')()
            # fill the vector
            self.tofit.push_back(self.tk1_.physObj)
            self.tofit.push_back(self.tk2_.physObj)

            # fit the vertex and save the information
            self.makeVtx_()
Exemple #4
0
class BKJPsiEEAnalyzer(Analyzer):
    '''
    '''
    def __init__(self, *args, **kwargs):
        super(BKJPsiEEAnalyzer, self).__init__(*args, **kwargs)
        # stuff I need to instantiate only once
        self.vtxfit = VertexFitter()
        # create a std::vector<reco::Track> to be passed to the fitter 
        self.tofit_el = ROOT.std.vector('reco::Track')()
        # create a std::vector<pat::PackedCandidate> to be passed to the fitter 
        self.tofit_pc = ROOT.std.vector('pat::PackedCandidate')()

    def declareHandles(self):
        super(BKJPsiEEAnalyzer, self).declareHandles()

        # miniAOD collections
        self.handles['electrons' ] = AutoHandle('slimmedElectrons'             , 'std::vector<pat::Electron>'       )
        self.handles['muons'     ] = AutoHandle('slimmedMuons'                 , 'std::vector<pat::Muon>'           )
        self.handles['losttracks'] = AutoHandle('lostTracks'                   , 'std::vector<pat::PackedCandidate>')
        self.handles['pfcands'   ] = AutoHandle('packedPFCandidates'           , 'std::vector<pat::PackedCandidate>')
        self.handles['pvs'       ] = AutoHandle('offlineSlimmedPrimaryVertices', 'std::vector<reco::Vertex>'        )
        
        # enriched miniAOD collections
        self.handles['eletrackMap'] = AutoHandle(('ttk', 'eleTtkMap', 'TTK'), 'std::vector<pair<edm::Ptr<pat::Electron>,reco::Track> >')
        
        # AOD collections
        self.handles['beamspot'  ] = AutoHandle('offlineBeamSpot', 'reco::BeamSpot')

    def beginLoop(self, setup):
        super(BKJPsiEEAnalyzer, self).beginLoop(setup)
        self.counters.addCounter('BKJPsiEEAnalyzer')
        count = self.counters.counter('BKJPsiEEAnalyzer')
        count.register('all events')
        count.register('>= 2 electrons')
        count.register('diele mass < 6')
        count.register('diele dz < 1')
        count.register('good diele vtx')
        count.register('B(KLL) mass < 6')

    def process(self, event):
        self.readCollections(event.input)

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

        # vertex stuff
        event.pvs         = self.handles['pvs'     ].product()
        event.beamspot    = self.handles['beamspot'].product()

        # get the tracks
        allpf      = map(PhysicsObject, self.handles['pfcands'   ].product())
        losttracks = map(PhysicsObject, self.handles['losttracks'].product())

        # merge the track collections
        event.alltracks = sorted([tt for tt in allpf + losttracks if tt.charge() != 0 and abs(tt.pdgId()) not in (11,13)], key = lambda x : x.pt(), reverse = True)
        
        # get the offline electrons and muons
        event.electrons = map(Electron, self.handles['electrons'].product())
        event.muons     = map(Muon    , self.handles['muons'    ].product())

        # get the electron-track map BEFORE selections
        eletrks = self.handles['eletrackMap'].product()

        # check consistency between electron-track map and electrons
        if len(event.electrons) != len(eletrks):
            print 'run %d \tlumi %d \tevent %d' %(event.run, event.lumi, event.eventId)
            print 'different number of electrons and ele tracks, %d and %d respectively' %(len(event.electrons), len(eletrks))
            for ii in event.electrons:
                print ii, ii.gsfTrack().pt()
            for ii in eletrks:
                print ii.first.pt(), ii.first.eta(), ii.first.phi(), ii.second.pt()
            set_trace()
        
        for jj in range(len(event.electrons)):
            event.electrons[jj].trackFromGsfTrack = eletrks[jj].second
            event.electrons[jj].ptr = eletrks[jj].first
            if event.electrons[jj].gsfTrack().pt() != eletrks[jj].second.pt():
                set_trace()

        # preselect electrons
        event.electrons = [ele for ele in event.electrons if self.testEle(ele)]

        # at least two electrons  
        if len(event.electrons)<2: return False
        self.counters.counter('BKJPsiEEAnalyzer').inc('>= 2 electrons')

        # build all di-ele pairs
        dieles = [(ele1, ele2) for ele1, ele2 in combinations(event.electrons, 2)]

        # opposite sign di-muon
        dieles = [(ele1, ele2) for ele1, ele2 in dieles if ele1.charge() != ele2.charge()]

        # SAVE THEM ALL, ALSO NON RESONANT!
        # invariant mass http://cmslxr.fnal.gov/source/DataFormats/EgammaCandidates/interface/GsfElectron.h#0795
        # dieles = [(ele1, ele2) for ele1, ele2 in dieles if (ele1.p4(1) + ele2.p4(1)).mass() < 6.]
        dieles = [(ele1, ele2) for ele1, ele2 in dieles if (ele1.p4() + ele2.p4()).mass() < 6.]
        if not len(dieles): return False
        self.counters.counter('BKJPsiEEAnalyzer').inc('diele mass < 6')

        # select by dz
        dieles = [(ele1, ele2) for ele1, ele2 in dieles if abs(ele1.vz() - ele2.vz()) < 1.]
        if not len(dieles): return False
        self.counters.counter('BKJPsiEEAnalyzer').inc('diele dz < 1')
        
        selDieles = []
        
        # dieles with a good vertex
        for diele in dieles:
            # clear the vectors
            self.tofit_el.clear()
            self.tofit_pc.clear()
            # create the vector of bla bla FIXME!
            for il in diele:
                # set_trace()
                self.tofit_el.push_back(il.trackFromGsfTrack)
            # fit it!
            # set_trace()
            svtree = self.vtxfit.Fit(self.tofit_el, self.tofit_pc) # actual vertex fitting
            # check that the vertex is good
            if not svtree.get().isEmpty() and svtree.get().isValid():
                svtree.movePointerToTheTop()
                sv = svtree.currentDecayVertex().get()
                recoSv = makeRecoVertex(sv, kinVtxTrkSize=2) # need to do some gymastics
                selDieles.append(diele)
        
        if len(selDieles)==0: return False
        self.counters.counter('BKJPsiEEAnalyzer').inc('good diele vtx')

        cands = []
        
        # set_trace()

        # add a track
        for diele, tk in product(selDieles, event.alltracks):
            # try to fit a vertex only if the track's close to the di-ele cand
            if max([abs(ee.vz() - tk.vz()) for ee in diele]) > 1.5:
                continue
            # remove double countings 
            if deltaR(tk, diele[0])<0.01 or deltaR(tk, diele[1])<0.01:
                continue
            # pt and sanity checks on the track
            # set_trace()
            if not tk.bestTrack():
                continue
            if tk.pt()<0.8:
                continue

            # kaon mass
            tk.setMass(0.493677)
            # clear the vectors
            self.tofit_el.clear()
            self.tofit_pc.clear()
            # create a RecoChargedCandidate for each reconstructed lepton and flush it into the vector
            for il in diele:
                self.tofit_el.push_back(il.trackFromGsfTrack)
            
            # push the track into the vector
            self.tofit_pc.push_back(tk.physObj)

            # fit it!
            svtree = self.vtxfit.Fit(self.tofit_el, self.tofit_pc) # actual vertex fitting
            # check that the vertex is good
            if not svtree.get().isEmpty() and svtree.get().isValid():
                svtree.movePointerToTheTop()
                sv = svtree.currentDecayVertex().get()
                recoSv = makeRecoVertex(sv, kinVtxTrkSize=3) # need to do some gymastics
                cands.append(BKLL(diele[0], diele[1], tk, recoSv, event.beamspot))

        if not len(cands): return False
        self.counters.counter('BKJPsiEEAnalyzer').inc('good diele vtx')

        cands = [cand for cand in cands if cand.b().mass()>4 and cand.b().mass()<6]
        if not len(cands): return False
        self.counters.counter('BKJPsiEEAnalyzer').inc('B(KLL) mass < 6')

#         set_trace()
#         for jj in cands: print jj.b().mass(), jj.b().pt(), jj.b().eta(), jj.b().phi(), jj.ll().mass(), jj.ls2d(), jj.vtxprob(), jj.llcone(), jj.bcone()

        event.myB = sorted(cands, key = lambda x : x.vtxprob(), reverse=True)[0]
        
        return True

    
    def testEle(self, ele):
        return ele.pt()>2.        and \
               abs(ele.eta())<2.5 
Exemple #5
0
class Kst(object):
    '''
    Builds a K*(892) candidate out of two tracks.
    Assigns \pi and K mass hypothesis, find the assignment that returns the
    invariant mass closer to the nominal K*(892) mass.
    As an option, it can be required that the two tracks make a vertex.
    '''
    def __init__(self, tk1, tk2, requireVtx=False):
        self.tk1_ = tk1
        self.tk2_ = tk2

        self.arbitrate()

        self.vtx = None
        self.vtxprob = -99.

        if requireVtx:
            # stuff I need to instantiate only once
            self.vtxfit = VertexFitter()
            # create a std::vector<reco::Track> to be passed to the fitter
            self.tofit = ROOT.std.vector('reco::Track')()
            # fill the vector
            self.tofit.push_back(self.tk1_.physObj)
            self.tofit.push_back(self.tk2_.physObj)

            # fit the vertex and save the information
            self.makeVtx_()

    def makeVtx_(self):
        # fit it!
        svtree = self.vtxfit.Fit(self.tofit)  # actual vertex fitting
        # check that the vertex is good
        if not svtree.get().isEmpty() and svtree.get().isValid():
            svtree.movePointerToTheTop()
            sv = svtree.currentDecayVertex().get()
            recoSv = makeRecoVertex(
                sv, kinVtxTrkSize=2)  # need to do some gymastics
        self.vtx = recoSv
        self.vtxprob = ROOT.TMath.Prob(self.vtx.chi2(), int(self.vtx().ndof()))

    def arbitrate(self):
        pi1 = ROOT.Math.LorentzVector('<ROOT::Math::PxPyPzM4D<double> >')(
            self.tk1_.px(), self.tk1_.py(), self.tk1_.pz(), m_pi_ch)
        pi2 = ROOT.Math.LorentzVector('<ROOT::Math::PxPyPzM4D<double> >')(
            self.tk2_.px(), self.tk2_.py(), self.tk2_.pz(), m_pi_ch)
        k1 = ROOT.Math.LorentzVector('<ROOT::Math::PxPyPzM4D<double> >')(
            self.tk1_.px(), self.tk1_.py(), self.tk1_.pz(), m_k_ch)
        k2 = ROOT.Math.LorentzVector('<ROOT::Math::PxPyPzM4D<double> >')(
            self.tk2_.px(), self.tk2_.py(), self.tk2_.pz(), m_k_ch)

        # assign the mass hypotheses
        if abs((pi1 + k2).mass() - m_k_st_zero) < abs((pi2 + k1).mass() -
                                                      m_k_st_zero):
            self.pi_ = PhysicsObject(
                ROOT.pat.PackedCandidate(self.tk1_.physObj))
            self.k_ = PhysicsObject(ROOT.pat.PackedCandidate(
                self.tk2_.physObj))
        else:
            self.pi_ = PhysicsObject(
                ROOT.pat.PackedCandidate(self.tk2_.physObj))
            self.k_ = PhysicsObject(ROOT.pat.PackedCandidate(
                self.tk1_.physObj))

        self.pi_.setMass(m_pi_ch)
        self.k_.setMass(m_k_ch)

        self.pi_.setPdgId(self.pi_.charge() * 211)
        self.k_.setPdgId(self.k_.charge() * 321)

    def charge(self):
        return self.tk1_.charge() + self.tk2_.charge()

    def pi(self):
        return self.pi_

    def k(self):
        return self.k_

    def p4(self):
        return self.pi().p4() + self.k().p4()

    def mass(self):
        return self.p4().mass()

    def eta(self):
        return self.p4().eta()

    def phi(self):
        return self.p4().phi()

    def e(self):
        return self.p4().e()

    def pt(self):
        return self.p4().pt()

    def p(self):
        return math.sqrt(self.p4().px()**2 + self.p4().py()**2 +
                         self.p4().pz()**2)

    def px(self):
        return self.p4().px()

    def py(self):
        return self.p4().py()

    def pz(self):
        return self.p4().pz()

    def pdgId():
        # FIXME! get the correct pdgId based on the kaon an pion charges
        return 313 if self.k().charge() > 0 else -313
Exemple #6
0
class BKJPsiAnalyzer(Analyzer):
    '''
    '''
    def declareHandles(self):
        super(BKJPsiAnalyzer, self).declareHandles()

        self.handles['electrons'] = AutoHandle('slimmedElectrons',
                                               'std::vector<pat::Electron>')
        self.handles['muons'] = AutoHandle('slimmedMuons',
                                           'std::vector<pat::Muon>')
        self.handles['losttracks'] = AutoHandle(
            'lostTracks', 'std::vector<pat::PackedCandidate>')
        self.handles['pfcands'] = AutoHandle(
            'packedPFCandidates', 'std::vector<pat::PackedCandidate>')
        self.handles['pvs'] = AutoHandle(
            ('offlineSlimmedPrimaryVertices', '', 'PAT'),
            'std::vector<reco::Vertex>')
        self.handles['beamspot'] = AutoHandle(('offlineBeamSpot', '', 'RECO'),
                                              'reco::BeamSpot')

    def beginLoop(self, setup):
        super(BKJPsiAnalyzer, self).beginLoop(setup)
        self.counters.addCounter('BKJPsiAnalyzer')
        count = self.counters.counter('BKJPsiAnalyzer')
        count.register('all events')
        count.register('>= 2 muons')
        count.register('dimuon mass < 6')
        count.register('good dimuon vtx')
        count.register('B(KLL) mass < 6')

        # stuff I need to instantiate only once
        self.vtxfit = VertexFitter()
        # create a std::vector<reco::RecoChargedCandidate> to be passed to the fitter
        self.tofit_cc = ROOT.std.vector('reco::RecoChargedCandidate')()
        # create a std::vector<pat::PackedCandidate> to be passed to the fitter
        self.tofit_pc = ROOT.std.vector('pat::PackedCandidate')()

    def process(self, event):
        self.readCollections(event.input)

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

        # vertex stuff
        event.pvs = self.handles['pvs'].product()
        event.beamspot = self.handles['beamspot'].product()

        # get the tracks
        allpf = map(PhysicsObject, self.handles['pfcands'].product())
        losttracks = map(PhysicsObject, self.handles['losttracks'].product())

        # merge the track collections
        event.alltracks = sorted([
            tt for tt in allpf + losttracks
            if tt.charge() != 0 and abs(tt.pdgId()) not in (11, 13)
        ],
                                 key=lambda x: x.pt(),
                                 reverse=True)

        # get the offline electrons and muons
        event.electrons = map(Electron, self.handles['electrons'].product())
        event.muons = map(Muon, self.handles['muons'].product())

        # preselect muons
        event.muons = [muon for muon in event.muons if self.testMuon(muon)]

        if len(event.muons) < 2: return False
        self.counters.counter('BKJPsiAnalyzer').inc('>= 2 muons')

        # build all di-muon pairs
        dimuons = [(mu1, mu2) for mu1, mu2 in combinations(event.muons, 2)]

        # opposite sign di-muon
        dimuons = [(mu1, mu2) for mu1, mu2 in dimuons
                   if mu1.charge() != mu2.charge()]

        # SAVE THEM ALL, ALSO NON RESONANT!
        # invariant mass
        dimuons = [(mu1, mu2) for mu1, mu2 in dimuons
                   if (mu1.p4() + mu2.p4()).mass() < 6.]
        if not len(dimuons): return False
        self.counters.counter('BKJPsiAnalyzer').inc('dimuon mass < 6')

        selDimuons = []

        # dimuons with a good vertex
        for dimuon in dimuons:
            # clear the vectors
            self.tofit_cc.clear()
            self.tofit_pc.clear()
            # create a RecoChargedCandidate for each reconstructed lepton and flush it into the vector
            for il in dimuon:
                # if the reco particle is a displaced thing, it does not have the p4() method, so let's build it
                myp4 = ROOT.Math.LorentzVector(
                    '<ROOT::Math::PxPyPzE4D<double> >')(
                        il.px(), il.py(), il.pz(),
                        math.sqrt(il.mass()**2 + il.px()**2 + il.py()**2 +
                                  il.pz()**2))
                ic = ROOT.reco.RecoChargedCandidate(
                )  # instantiate a dummy RecoChargedCandidate
                ic.setCharge(il.charge())  # assign the correct charge
                ic.setP4(myp4)  # assign the correct p4
                ic.setTrack(il.track())  # set the correct TrackRef
                if ic.track().isNonnull():  # check that the track is valid
                    self.tofit_cc.push_back(ic)

            # further sanity check: two *distinct* tracks
            if self.tofit_cc.size(
            ) == 2 and self.tofit_cc[0].track() != self.tofit_cc[1].track():
                # fit it!
                svtree = self.vtxfit.Fit(
                    self.tofit_cc, self.tofit_pc)  # actual vertex fitting
                # check that the vertex is good
                if not svtree.get().isEmpty() and svtree.get().isValid():
                    svtree.movePointerToTheTop()
                    sv = svtree.currentDecayVertex().get()
                    recoSv = makeRecoVertex(
                        sv, kinVtxTrkSize=2)  # need to do some gymastics
                    selDimuons.append(dimuon)

        if len(selDimuons) == 0: return False
        self.counters.counter('BKJPsiAnalyzer').inc('good dimuon vtx')

        cands = []

        # add a track
        for dimu, tk in product(selDimuons, event.alltracks):
            # remove double countings
            if deltaR(tk, dimu[0]) < 0.01 or deltaR(tk, dimu[1]) < 0.01:
                continue
            # pt and sanity checks on the track
#             set_trace()
            if not tk.bestTrack():
                continue
            if tk.pt() < 0.8:
                continue
            # clear the vectors
            self.tofit_cc.clear()
            self.tofit_pc.clear()
            # create a RecoChargedCandidate for each reconstructed lepton and flush it into the vector
            for il in dimu:
                # if the reco particle is a displaced thing, it does not have the p4() method, so let's build it
                myp4 = ROOT.Math.LorentzVector(
                    '<ROOT::Math::PxPyPzE4D<double> >')(
                        il.px(), il.py(), il.pz(),
                        math.sqrt(il.mass()**2 + il.px()**2 + il.py()**2 +
                                  il.pz()**2))
                ic = ROOT.reco.RecoChargedCandidate(
                )  # instantiate a dummy RecoChargedCandidate
                ic.setCharge(il.charge())  # assign the correct charge
                ic.setP4(myp4)  # assign the correct p4
                ic.setTrack(il.track())  # set the correct TrackRef
                if ic.track().isNonnull():  # check that the track is valid
                    self.tofit_cc.push_back(ic)

            set_trace()
            m_k = 0.493677
            # push the track into the vector
            self.tofit_pc.push_back(tk.physObj)

            # fit it!
            try:
                svtree = self.vtxfit.Fit(
                    self.tofit_cc, self.tofit_pc)  # actual vertex fitting
            except:
                set_trace()
            # check that the vertex is good
            if not svtree.get().isEmpty() and svtree.get().isValid():
                svtree.movePointerToTheTop()
                sv = svtree.currentDecayVertex().get()
                recoSv = makeRecoVertex(
                    sv, kinVtxTrkSize=3)  # need to do some gymastics
                cands.append(BKLL(dimu[0], dimu[1], tk, recoSv,
                                  event.beamspot))

        if not len(cands): return False
        self.counters.counter('BKJPsiAnalyzer').inc('good dimuon vtx')

        cands = [cand for cand in cands if cand.b().mass() < 6]
        if not len(cands): return False
        self.counters.counter('BKJPsiAnalyzer').inc('B(KLL) mass < 6')

        #         set_trace()
        #         for jj in cands: print jj.b().mass(), jj.b().pt(), jj.b().eta(), jj.b().phi(), jj.ll().mass(), jj.ls2d(), jj.vtxprob(), jj.llcone(), jj.bcone()

        event.myB = sorted(cands, key=lambda x: x.vtxprob(), reverse=True)[0]

        return True

    def testMuon(self, muon):
        return muon.pt()>1.        and \
               abs(muon.eta())<2.5 and \
               muon.isGlobalMuon()