def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')
    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2),)

    Event    = E.getPrimitives('EVENT'  )
    DSAmuons = E.getPrimitives('DSAMUON')
    Dimuons  = E.getPrimitives('DIMUON' )

    for genMuonPair in genMuonPairs:
        # require genMuonPair to be within acceptance
        genMuonSelection = Selections.AcceptanceSelection(genMuonPair)
        if not genMuonSelection: continue

        # check if any DSA muons match a genMuon
        dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair, Dimuons, DSAmuons, vertex='BS')

        # print if exitcode 1, 2, 3: gen muons matched (or exists next best), but no dimuon found, and Lxy>340
        if exitcode in (1, 2, 3) and genMuonPair[0].Lxy() > 340.:
            dumpInfo(Event, genMuonPair, muonMatches, exitcode, DSAmuons, Dimuons, extramu, PARAMS)
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')

    muons = E.getPrimitives('DSAMUON')

    # apply trigger if --trigger
    # skip events without at least 2 muons with pT > 30
    if self.TRIGGER:
        if not Selections.passedTrigger(E): return

        numPT = 0
        for mu in muons:
            if mu.pt > 30:
                numPT += 1
            if numPT == 2:
                break
        if numPT < 2:
            return

    Event = E.getPrimitives('EVENT')
    dimuons = E.getPrimitives('DIMUON')

    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )

    # loop over genMuonPairs, find dimuon, and do something based on result
    for genMuonPair in genMuonPairs:
        if len(dimuons) > 0:
            dimuonMatches, muonMatches, exitcode = matchedDimuons(
                genMuonPair, dimuons, muons)
            savedDimuon = dimuonMatches[0]['dim'] if len(
                dimuonMatches) > 0 else None
            if savedDimuon is not None:
                for dimuon in dimuons:
                    if dimuon.idx1 == savedDimuon.idx1 and dimuon.idx2 == savedDimuon.idx2:
                        print '1,' + ','.join([
                            '{:.4f}'.format(i)
                            for i in (dimuon.deltaR, dimuon.normChi2,
                                      dimuon.Lxy() / dimuon.LxySig())
                        ])
                    else:
                        print '0,' + ','.join([
                            '{:.4f}'.format(i)
                            for i in (dimuon.deltaR, dimuon.normChi2,
                                      dimuon.Lxy() / dimuon.LxySig())
                        ])
            else:
                for dimuon in dimuons:
                    print '0,' + ','.join([
                        '{:.4f}'.format(i)
                        for i in (dimuon.deltaR, dimuon.normChi2,
                                  dimuon.Lxy() / dimuon.LxySig())
                    ])
Exemple #3
0
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return
    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')
    Event    = E.getPrimitives('EVENT')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjects(E, self.CUTS, Dimuons3, DSAmuons, PATmuons)
    if selectedDimuons is None: return

    for dim in selectedDimuons:
        if dim.composition == 'DSA': continue
        idxList = (dim.idx2,) if dim.composition == 'HYBRID' else dim.ID
        for idx in idxList:
            mu = PATmuons[idx]
            self.HISTS['pT'].Fill(mu.pt)
            if mu.highPurity:
                self.HISTS['pT-HP'].Fill(mu.pt)

    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2),)

        # do the signal matching
        if len(genMuonPairs) == 1:
            genMuonPair = genMuonPairs[0]
            dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair, selectedDimuons)
            if len(dimuonMatches) > 0:
                realMatches = {0:dimuonMatches[0]}
            else:
                realMatches = {}
        else:
            realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(genMuonPairs, selectedDimuons)

        for pairIndex in realMatches:
            genMuon = genMuonPairs[pairIndex][0]
            dim = realMatches[pairIndex]['dim']
            if dim.composition == 'DSA': continue
            idxList = (dim.idx2,) if dim.composition == 'HYBRID' else dim.ID
            for idx in idxList:
                mu = PATmuons[idx]
                self.HISTS['GM-pT'].Fill(mu.pt)
                if mu.highPurity:
                    self.HISTS['GM-pT-HP'].Fill(mu.pt)
Exemple #4
0
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')
    if self.TRIGGER:
        if not Selections.passedTrigger(E): return
    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )
    DSAmuons = E.getPrimitives('DSAMUON')
    Dimuons = E.getPrimitives('DIMUON')

    ALL = True if 'All' in self.CUTS else False

    # require dimuons to pass all selections, and require DSA muons to pass all selections
    if ALL:
        DSASelections = [Selections.MuonSelection(muon) for muon in DSAmuons]
        selectedDSAmuons = [
            mu for idx, mu in enumerate(DSAmuons) if DSASelections[idx]
        ]
        selectedDimuons = [
            dim for idx, dim in enumerate(Dimuons)
            if DSASelections[dim.idx1] and DSASelections[dim.idx2]
        ]

    # don't require dimuons to pass all selections, and don't require DSA muons to pass all selections, either
    else:
        selectedDSAmuons = DSAmuons
        selectedDimuons = Dimuons

    for genMuonPair in genMuonPairs:
        # require genMuonPair to be within acceptance
        genMuonSelection = Selections.AcceptanceSelection(genMuonPair)
        if not genMuonSelection: continue

        dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair,
                                                              selectedDimuons,
                                                              selectedDSAmuons,
                                                              vertex='BS')

        # fill denominator if both gen muons matched, either to different reco muons or, if the same, that there is a next best
        fillDen = exitcode.both and ((not exitcode.same) or
                                     (exitcode.same and exitcode.nextBest))
        fillNum = exitcode.matched

        if fillDen:
            for KEY in CONFIG:
                F = CONFIG[KEY]['LAMBDA']
                if True:
                    self.HISTS[KEY + 'Den'].Fill(F(genMuonPair[0]))
                if fillNum:
                    self.HISTS[KEY + 'Eff'].Fill(F(genMuonPair[0]))
Exemple #5
0
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return
    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')
    Event = E.getPrimitives('EVENT')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjectsReordered(
        E,
        self.CUTS,
        Dimuons3,
        DSAmuons,
        PATmuons,
        keepHybrids=ARGS.HYBRIDS,
        option=ARGS.PCOPTION)
    if selectedDimuons is None: return

    self.COUNTS['events'] += 1
    self.COUNTS['selected'] += len(selectedDimuons)

    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

        # do the signal matching
        if len(genMuonPairs) == 1:
            genMuonPair = genMuonPairs[0]
            dimuonMatches, muonMatches, exitcode = matchedDimuons(
                genMuonPair, selectedDimuons)
            if len(dimuonMatches) > 0:
                realMatches = {0: dimuonMatches[0]}
            else:
                realMatches = {}
        else:
            realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                genMuonPairs, selectedDimuons)

        if len(realMatches) > 0: self.COUNTS['matchEvents'] += 1

        for pairIndex in realMatches:
            self.COUNTS['matches'] += 1
Exemple #6
0
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')
    if self.TRIGGER:
        if not Selections.passedTrigger(E): return
    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )
    DSAmuons = E.getPrimitives('DSAMUON')
    Dimuons = E.getPrimitives('DIMUON')

    for genMuonPair in genMuonPairs:
        genMuonPairSelection = Selections.AcceptanceSelection(genMuonPair)
        if not genMuonPairSelection: continue
        if genMuonPair[0].Lxy() < 100.:
            self.COUNTS['Den'] += 1
            DSAdimuonMatches, DSAmuonMatches, DSAexitcode = matchedDimuons(
                genMuonPair, ('DUMMY', ), DSAmuons, vertex='BS')
            REFdimuonMatches, REFmuonMatches, REFexitcode = matchedDimuons(
                genMuonPair, Dimuons)

            if DSAexitcode in (1, 2, 3):
                self.COUNTS['DSATotal'] += 2
            elif DSAexitcode in (4, 5, 6, 7):
                self.COUNTS['DSATotal'] += 1

            if len(REFdimuonMatches) > 0:
                self.COUNTS['REFTotal'] += 2

            if len(REFdimuonMatches) == 0:
                if DSAexitcode == 8:
                    self.COUNTS['None'] += 1
                elif DSAexitcode in (4, 5, 6, 7):
                    self.COUNTS['One'] += 1
                elif DSAexitcode in (1, 2, 3):
                    self.COUNTS['Both'] += 1
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return
    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')
    Event = E.getPrimitives('EVENT')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

        for pTCut in xrange(31):

            selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjectsReordered(
                E,
                self.CUTS,
                Dimuons3,
                DSAmuons,
                PATmuons,
                keepHybrids=True,
                option=3,
                pTCut=float(pTCut))
            if selectedDimuons is None: continue

            # do the signal matching
            if len(genMuonPairs) == 1:
                genMuonPair = genMuonPairs[0]
                dimuonMatches, muonMatches, exitcode = matchedDimuons(
                    genMuonPair, selectedDimuons)
                if len(dimuonMatches) > 0:
                    realMatches = {0: dimuonMatches[0]}
                else:
                    realMatches = {}
            else:
                realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                    genMuonPairs, selectedDimuons)

            if len(realMatches) > 0:
                self.HISTS['nMatches'].Fill(float(pTCut), eventWeight)
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return

    Event = E.getPrimitives('EVENT')

    CUTSTRING = '_Combined_NS_NH_FPTE_HLT_REP_PT_TRK_NDT_DCA_PC_LXYE_MASS_CHI2_VTX_COSA_NPP_LXYSIG_OS_DPHI'

    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')

    # gen stuff
    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

    # do the selection
    for key in ('before', 'after'):
        selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjects(
            E, CUTSTRING, Dimuons3, DSAmuons, PATmuons, applyDeltaR=key)
        if selectedDimuons is None: continue
        DSADimuons = [
            dim for dim in selectedDimuons if dim.composition == 'DSA'
        ]

        if self.SP is not None:
            if len(genMuonPairs) == 1:
                genMuonPair = genMuonPairs[0]
                dimuonMatches, muonMatches, exitcode = matchedDimuons(
                    genMuonPair, DSADimuons)
                if len(dimuonMatches) > 0:
                    realMatches = {0: dimuonMatches[0]}
                else:
                    realMatches = {}
            else:
                realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                    genMuonPairs, DSADimuons)

            for pairIndex in realMatches:
                genMuon = genMuonPairs[pairIndex][0]
                self.HISTS['Lxy_{}'.format(key)].Fill(genMuon.Lxy())
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')
    if self.TRIGGER:
        if not Selections.passedTrigger(E): return
    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )
    DSAmuons = E.getPrimitives('DSAMUON')
    Dimuons = E.getPrimitives('DIMUON')

    selectedDSAmuons = [
        mu for mu in DSAmuons
        if mu.nDTStations + mu.nCSCStations > 1 and mu.nCSCHits +
        mu.nDTHits > 12 and mu.ptError / mu.pt < 1.
    ]
    selectedOIndices = [mu.idx for mu in selectedDSAmuons]
    selectedDimuons = [
        dim for dim in Dimuons
        if dim.idx1 in selectedOIndices and dim.idx2 in selectedOIndices
    ]

    for genMuonPair in genMuonPairs:
        dimuonMatches, muonMatches, exitcode = matchedDimuons(
            genMuonPair, selectedDimuons)

        matchedIndices = [m['idx'] for m in dimuonMatches]

        for idx, dimuon in enumerate(selectedDimuons):
            CAT = 'Matched' if idx in matchedIndices else 'Junk'
            for Q in CONFIG:
                self.HISTS[Q + '_' + CAT].Fill(CONFIG[Q]['LAMBDA'](dimuon))
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')
    if self.TRIGGER:
        if not Selections.passedTrigger(E): return
    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2),)
    DSAmuons = E.getPrimitives('DSAMUON')
    Dimuons  = E.getPrimitives('DIMUON' )

    TAG = 'ZZ' if self.ARGS.OLD else 'BS'

    # In order for this to work on the "old" nTuples, i.e. previous to the changes to gen muons with BS quantities,
    # the following changes need to be made to Primitives.GenMuon in order to make it backwards-compatible:
    # - wrap the .BS declaration in a try-except: we do not use it here, so the old nTuples will still work
    # - wrap the d0 and dz declarations in a try-except: these only fail for the "extra" gen muons; in the old nTuples,
    #   extra gen muons did not fill the d0 and dz quantities

    for genMuonPair in genMuonPairs:
        dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair, Dimuons, DSAmuons, vertex=None)
        if len(dimuonMatches) > 0:
            dimuon = Dimuons[dimuonMatches[0]['idx']]
            recoMuons = dimuon.mu1, dimuon.mu2
            for QUANTITY in ('Lxy',):
                PRETTY, AXES, RFUNC, GFUNC, RESFUNC = CONFIG[QUANTITY]
                if True:
                    self.HISTS[QUANTITY+'Res{}'.format(TAG)].Fill(RESFUNC(RFUNC(dimuon, 'LIN'), GFUNC(genMuonPair[0], 'LIN')))
            for QUANTITY in ('d0G',):
                PRETTY, AXES, RFUNC, GFUNC, RESFUNC = CONFIG[QUANTITY]
                for recoMuon, genMuon in zip(recoMuons, genMuonPair):
                    self.HISTS[QUANTITY+'Res{}'.format(TAG)].Fill(RESFUNC(RFUNC(recoMuon, 'LIN'), GFUNC(genMuon, 'LIN')))
def analyze(self, E, PARAMS=None):

    Event = E.getPrimitives('EVENT')

    # take 10% of data: event numbers ending in 7
    if 'DoubleMuon' in self.NAME:
        if Event.event % 10 != 7: return

    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')

    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )

    genMuonPair = genMuonPairs[0]
    genLxy = genMuonPair[0].Lxy()

    TRIG = Selections.passedTrigger(E)

    ACC = Selections.AcceptanceSelection(genMuonPair)

    RECO = False
    dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair,
                                                          Dimuons3,
                                                          DSAmuons,
                                                          vertex='BS',
                                                          doDimuons=False)
    genMuonMatches = exitcode.getBestGenMuonMatches(muonMatches)
    if genMuonMatches[0] is not None and genMuonMatches[1] is not None:
        RECO = True

    SEL = False
    CUTS = '_Combined_NS_NH_FPTE_HLT_REP_PT_DCA_PC_LXYE_MASS_CHI2_VTX_COSA_NPP_LXYSIG_TRK_NDT_DPHI'
    selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjects(
        E, CUTS, Dimuons3, DSAmuons, PATmuons)
    if selectedDimuons is not None:

        selectedDimuons = [
            dim for dim in selectedDimuons if dim.composition == 'DSA'
        ]

        dimuonMatches, muonMatches, exitcode = matchedDimuons(
            genMuonPair, selectedDimuons)
        if len(dimuonMatches) > 0:
            realMatches = {0: dimuonMatches[0]}
        else:
            realMatches = {}

        if len(realMatches) > 0:
            SEL = True

    KEY = 'Trig{}-Acc{}-Reco{}-Sel{}'.format(
        *[int(bool(x)) for x in (TRIG, ACC, RECO, SEL)])

    genLxy = genMuonPair[0].Lxy()
    self.HISTS['Lxy-' + KEY].Fill(genLxy)
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return
    Event = E.getPrimitives('EVENT')
    DSAmuons = E.getPrimitives('DSAMUON')
    Dimuons = E.getPrimitives('DIMUON')
    Vertex = E.getPrimitives('VERTEX')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    # decide what set of cuts to apply based on self.CUTS cut string
    ALL = 'All' in self.CUTS
    PROMPT = '_Prompt' in self.CUTS
    NOPROMPT = '_NoPrompt' in self.CUTS
    NSTATIONS = '_NS' in self.CUTS
    NMUONHITS = '_NH' in self.CUTS
    FPTERR = '_FPTE' in self.CUTS
    PT = '_PT' in self.CUTS
    HLT = '_HLT' in self.CUTS
    PC = '_PC' in self.CUTS
    LXYERR = '_LXYE' in self.CUTS
    MASS = '_M' in self.CUTS

    def boolsToMuonCutList(NSTATIONS, NMUONHITS, FPTERR, PT):
        cutList = []
        if NSTATIONS:
            cutList.append('b_nStations')
        if NMUONHITS:
            cutList.append('b_nMuonHits')
        if FPTERR:
            cutList.append('b_FPTE')
        if PT:
            cutList.append('b_pT')
        return cutList

    def boolsToDimuonCutList(LXYERR, MASS):
        cutList = []
        if LXYERR:
            cutList.append('b_LxyErr')
        if MASS:
            cutList.append('b_mass')
        return cutList

    # require DSA muons to pass all selections, and require dimuons to pass all selections except LxySig and deltaPhi
    if ALL:
        DSASelections = [Selections.MuonSelection(muon) for muon in DSAmuons]
        DimuonSelections = [
            Selections.DimuonSelection(dimuon) for dimuon in Dimuons
        ]
        selectedDSAmuons = [
            mu for idx, mu in enumerate(DSAmuons) if DSASelections[idx]
        ]
        selectedDimuons = [
            dim for idx, dim in enumerate(Dimuons)
            if DimuonSelections[idx].allExcept('LxySig', 'deltaPhi')
            and DSASelections[dim.idx1] and DSASelections[dim.idx2]
        ]

    # no cuts
    else:
        selectedDSAmuons = DSAmuons
        selectedDimuons = Dimuons

    # for PROMPT and NOPROMPT event selections
    if PROMPT or NOPROMPT:
        highLxySigExists = False
        for dimuon in Dimuons:
            if dimuon.LxySig() > 3.:
                highLxySigExists = True
                break

        # return if there are LxySig > 3
        if PROMPT:
            if highLxySigExists:
                return
        # return if there are NO LxySig > 3 -- that's category 1
        elif NOPROMPT:
            if not highLxySigExists:
                return

    if PROMPT or NOPROMPT:
        # compute all the baseline selection booleans
        DSASelections = [
            Selections.MuonSelection(muon, cutList='BaselineMuonCutList')
            for muon in DSAmuons
        ]

        # figure out which cuts we actually care about
        cutList = boolsToMuonCutList(NSTATIONS, NMUONHITS, FPTERR, PT)

        # no selection
        if len(cutList) == 0:
            selectedDSAmuons = DSAmuons
            selectedDimuons = Dimuons
        # cutList is some nonzero list, meaning keep only the muons that pass the cut keys in cutList
        else:
            selectedDSAmuons = [
                mu for i, mu in enumerate(DSAmuons)
                if DSASelections[i].allOf(*cutList)
            ]
            selectedOIndices = [mu.idx for mu in selectedDSAmuons]
            selectedDimuons = [
                dim for dim in Dimuons if dim.idx1 in selectedOIndices
                and dim.idx2 in selectedOIndices
            ]

    # apply HLT RECO matching
    if HLT:
        HLTPaths, HLTMuons, L1TMuons = E.getPrimitives('TRIGGER')
        DSAMuonsForHLTMatch = [
            mu for mu in selectedDSAmuons if abs(mu.eta) < 2.
        ]
        HLTMuonMatches = matchedTrigger(HLTMuons, DSAMuonsForHLTMatch)
        if not any([HLTMuonMatches[ij]['matchFound']
                    for ij in HLTMuonMatches]):
            return

    # apply pairing criteria and transform selectedDimuons
    if PC:
        selectedDimuons = applyPairingCriteria(selectedDSAmuons,
                                               selectedDimuons)

    if PROMPT or NOPROMPT:
        # compute all the baseline selection booleans
        DimuonSelections = {
            dim.ID: Selections.DimuonSelection(dim,
                                               cutList='BaselineDimuonCutList')
            for dim in selectedDimuons
        }

        # figure out which cuts we actually care about
        cutList = boolsToDimuonCutList(LXYERR, MASS)

        # cutList is some nonzero list, meaning keep only the muons that pass the cut keys in cutList
        if len(cutList) > 0:
            selectedDimuons = [
                dim for dim in selectedDimuons
                if DimuonSelections[dim.ID].allOf(*cutList)
            ]

    # for the MC/Data events, skip events with no dimuons, but not for "no selection"
    if (PROMPT or NOPROMPT) and NSTATIONS:
        if len(selectedDimuons) == 0: return

    # also filter selectedDSAmuons to only be of those indices that are in the final dimuons
    if PROMPT or NOPROMPT:
        selectedOIndices = []
        for dim in selectedDimuons:
            selectedOIndices.append(dim.idx1)
            selectedOIndices.append(dim.idx2)
        selectedOIndices = list(set(selectedOIndices))
        selectedDSAmuons = [
            mu for mu in selectedDSAmuons if mu.idx in selectedOIndices
        ]

    # fill histograms for every dimuon
    for dimuon in selectedDimuons:
        for KEY in CONFIG:
            self.HISTS['Dim_' + KEY].Fill(CONFIG[KEY]['LAMBDA'](dimuon),
                                          eventWeight)

        for KEY in EXTRACONFIG:
            if EXTRACONFIG[KEY]['LAMBDA'] is None: continue
            F1 = EXTRACONFIG[KEY]['LAMBDA'][0]
            F2 = EXTRACONFIG[KEY]['LAMBDA'][1]
            self.HISTS['Dim_' + KEY].Fill(F1(dimuon), F2(dimuon), eventWeight)
    self.HISTS['Dim_nDimuon'].Fill(len(selectedDimuons), eventWeight)

    # get gen particles if this is a signal sample
    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

        # fill histograms only for matched reco muons
        for genMuonPair in genMuonPairs:
            # require genMuonPair to be within acceptance
            # don't do it for now
            #genMuonSelection = Selections.AcceptanceSelection(genMuonPair)

            # find the matching dimuon, if any, and fill
            dimuonMatches, muonMatches, exitcode = matchedDimuons(
                genMuonPair, selectedDimuons)

            if len(dimuonMatches) > 0:
                for match in dimuonMatches:
                    dimuon = match['dim']
                    for KEY in CONFIG:
                        self.HISTS['Dim_' + KEY + '_Matched'].Fill(
                            CONFIG[KEY]['LAMBDA'](dimuon), eventWeight)
                    for KEY in EXTRACONFIG:
                        if EXTRACONFIG[KEY]['LAMBDA'] is None: continue
                        F1 = EXTRACONFIG[KEY]['LAMBDA'][0]
                        F2 = EXTRACONFIG[KEY]['LAMBDA'][1]
                        self.HISTS['Dim_' + KEY + '_Matched'].Fill(
                            F1(dimuon), F2(dimuon), eventWeight)
            self.HISTS['Dim_nDimuon_Matched'].Fill(len(dimuonMatches))
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')

    if self.TRIGGER:
        if not Selections.passedTrigger(E): return

    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )
    Event = E.getPrimitives('EVENT')
    dimuons = E.getPrimitives('DIMUON')
    muons = E.getPrimitives('DSAMUON')

    baseMuons = [
        mu for mu in muons
        if mu.nDTStations + mu.nCSCStations > 1 and mu.nCSCHits +
        mu.nDTHits > 12 and mu.ptError / mu.pt < 1.
    ]
    baseOIndices = [mu.idx for mu in baseMuons]
    baseDimuons = [
        dim for dim in dimuons
        if dim.idx1 in baseOIndices and dim.idx2 in baseOIndices
    ]

    for pTCut in PTCUTS:
        selectedMuons = [mu for mu in baseMuons if mu.pt > pTCut]
        selectedOIndices = [mu.idx for mu in selectedMuons]
        selectedDimuons = [
            dim for dim in baseDimuons
            if dim.idx1 in selectedOIndices and dim.idx2 in selectedOIndices
        ]

        # for a few special pT cut values, fill multiplicity histograms: all, and split by matched or not matched
        if pTCut in MULTCUTS:
            sPTCut = str(pTCut)
            self.HISTS['nMuon_' + sPTCut].Fill(len(selectedMuons))
            self.HISTS['nDimuon_' + sPTCut].Fill(len(selectedDimuons))

            # fill split muon histograms; len(0) goes directly to not matched
            matches = []
            if len(selectedMuons) > 0:
                for genMuonPair in genMuonPairs:
                    for genMuon in genMuonPair:
                        matches.extend(
                            matchedMuons(genMuon, selectedMuons, vertex='BS'))
                matches = list(set([m['oidx'] for m in matches]))
                self.HISTS['nMuon_Matched_' + sPTCut].Fill(len(matches))
                self.HISTS['nMuon_NotMatched_' +
                           sPTCut].Fill(len(selectedMuons) - len(matches))
            else:
                self.HISTS['nMuon_Matched_' + sPTCut].Fill(0)
                self.HISTS['nMuon_NotMatched_' + sPTCut].Fill(0)

            # fill split dimuon histograms; len(0) goes directly to not matched
            matches = []
            if len(selectedDimuons) > 0:
                for genMuonPair in genMuonPairs:
                    dimuonMatches, muonMatches, exitcode = matchedDimuons(
                        genMuonPair, selectedDimuons)
                    for m in dimuonMatches:
                        matches.append(m['idx'])
                matches = list(set(matches))
                self.HISTS['nDimuon_Matched_' + sPTCut].Fill(len(matches))
                self.HISTS['nDimuon_NotMatched_' +
                           sPTCut].Fill(len(selectedDimuons) - len(matches))
            else:
                self.HISTS['nDimuon_Matched_' + sPTCut].Fill(0)
                self.HISTS['nDimuon_NotMatched_' + sPTCut].Fill(0)

        #for i in range(len(selectedMuons  )): self.HISTS['nMuon'  ].Fill(pTCut)
        #for i in range(len(selectedDimuons)): self.HISTS['nDimuon'].Fill(pTCut)
        #for i in range(len(genMuonPairs   )): self.HISTS['nPair'  ].Fill(pTCut)

        if len(selectedDimuons) > 0:
            for genMuonPair in genMuonPairs:
                dimuonMatches, muonMatches, exitcode = matchedDimuons(
                    genMuonPair, selectedDimuons)
                if len(dimuonMatches) > 0:
                    self.HISTS['nMatch'].Fill(pTCut)

                    # best matched dimuon
                    matchedDimuon = dimuonMatches[0]['dim']

                    # fill nCorrectChi2 : chi^2/dof criterion, i.e. dimuon with lowest vertex chi2/dof
                    sortedDimuons = sorted(selectedDimuons,
                                           key=lambda dim: dim.normChi2)
                    bestDimuon = sortedDimuons[0]
                    if bestDimuon.idx1 == matchedDimuon.idx1 and bestDimuon.idx2 == matchedDimuon.idx2:
                        self.HISTS['nCorrectChi2'].Fill(pTCut)

                    # fill nCorrectHPD : pT criterion, i.e. dimuon made of highest 2 pT
                    sortedMuons = sorted(selectedMuons,
                                         key=lambda mu: mu.pt,
                                         reverse=True)
                    bestTwo = (sortedMuons[0].idx, sortedMuons[1].idx)
                    bestDimuon = None
                    for dim in selectedDimuons:
                        if dim.idx1 in bestTwo and dim.idx2 in bestTwo:
                            bestDimuon = dim
                            break
                    if bestDimuon is not None:
                        if bestDimuon.idx1 == matchedDimuon.idx1 and bestDimuon.idx2 == matchedDimuon.idx2:
                            self.HISTS['nCorrectHPD'].Fill(pTCut)

                    # test the 3mu and 4mu criteria on 2mu samples
                    bestDimuons = {}
                    if len(sortedMuons) == 3:
                        self.HISTS['nMatch3'].Fill(pTCut)

                        # I have not overwritten bestDimuon yet. It's still the HPD.
                        if bestDimuon is not None:
                            bestDimuons['HPD3'] = (bestDimuon.ID, )
                        else:
                            bestDimuons['HPD3'] = []
                        # Chi2 among all dimuons
                        bestDimuons['Chi23'] = (sortedDimuons[0].ID, )

                        for tag in ('Chi2', 'HPD'):
                            if matchedDimuon.ID in bestDimuons[tag + '3']:
                                self.HISTS['nCorrect' + tag + '3'].Fill(pTCut)

                    elif len(sortedMuons) >= 4:
                        self.HISTS['nMatch4'].Fill(pTCut)

                        highestPTMuons = sortedMuons[:4]
                        highestIndices = [mu.idx for mu in highestPTMuons]
                        bestDimuons['HPD'] = {
                            d.ID: d
                            for d in selectedDimuons
                            if d.idx1 in highestIndices
                            and d.idx2 in highestIndices
                        }

                        pairings = {}
                        for tag in ('HPD', ):
                            pairings[tag] = []
                            dimuonList = bestDimuons[tag].values()
                            for dim1 in dimuonList:
                                for dim2 in dimuonList:
                                    if dim1.ID == dim2.ID: continue
                                    muonIDs = set(dim1.ID + dim2.ID)
                                    if len(muonIDs) == 4:
                                        pairings[tag].append((dim1, dim2))

                        def AMD(pairing):
                            return abs(pairing[0].mass - pairing[1].mass)

                        def FMD(pairing):
                            return abs(pairing[0].mass - pairing[1].mass) / (
                                pairing[0].mass + pairing[1].mass)

                        def C2S(pairing):
                            return pairing[0].normChi2 + pairing[1].normChi2

                        functions = {'AMD4': AMD, 'C2S4': C2S}

                        # if there are pairings, use sortedPairings[0]
                        for tag in ('HPD', ):
                            if len(pairings[tag]) > 0:

                                for fkey in functions:
                                    sortedPairings = sorted(
                                        pairings[tag], key=functions[fkey])
                                    bestDimuons[fkey] = []
                                    if len(sortedPairings) > 0:
                                        for dim in sortedPairings[0]:
                                            bestDimuons[fkey].append(dim.ID)

                            else:
                                for fkey in functions:
                                    bestDimuons[fkey] = []

                        # I have not overwritten bestDimuon yet. It's still the HPD.
                        if bestDimuon is not None:
                            bestDimuons['HPD4'] = (bestDimuon.ID, )
                        else:
                            bestDimuons['HPD4'] = []
                        # Chi2 among all dimuons
                        bestDimuons['Chi24'] = (sortedDimuons[0].ID, )
                        # Chi2 among HPDs only
                        if len(bestDimuons['HPD']) > 0:
                            bestDimuons['LCD4'] = (sorted(
                                bestDimuons['HPD'].values(),
                                key=lambda dim: dim.normChi2)[0].ID, )
                        else:
                            bestDimuons['LCD4'] = []

                        for tag in ('Chi2', 'HPD', 'LCD', 'AMD', 'C2S'):
                            if matchedDimuon.ID in bestDimuons[tag + '4']:
                                self.HISTS['nCorrect' + tag + '4'].Fill(pTCut)
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return

    Event = E.getPrimitives('EVENT')

    # take 10% of data: event numbers ending in 7
    if 'DoubleMuon' in self.NAME:
        if Event.event % 10 != 7: return

    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjects(E, self.CUTS, Dimuons3, DSAmuons, PATmuons)
    if selectedDimuons is None: return
    selectedDimuons = [dim for dim in selectedDimuons if dim.composition == 'DSA']

    def getOriginalMuons(dim):
        if dim.composition == 'PAT':
            return PATmuons[dim.idx1], PATmuons[dim.idx2]
        elif dim.composition == 'DSA':
            return DSAmuons[dim.idx1], DSAmuons[dim.idx2]
        else:
            return DSAmuons[dim.idx1], PATmuons[dim.idx2]

    for dim in selectedDimuons:
        for val in self.COUNTS:
            if dim.normChi2 < val:
                self.COUNTS[val] += 1

    if len(selectedDimuons) == 0: return

    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2),)

    # do the signal matching
    if len(genMuonPairs) == 1:
        genMuonPair = genMuonPairs[0]
        dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair, selectedDimuons)
        if len(dimuonMatches) > 0:
            realMatches = {0:dimuonMatches[0]}
        else:
            realMatches = {}
    else:
        realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(genMuonPairs, selectedDimuons)

    for pairIndex in realMatches:
        genMuon = genMuonPairs[pairIndex][0]
        dim = realMatches[pairIndex]['dim']

        for val in self.COUNTS:
            if dim.normChi2 < val:
                self.MATCH[val] += 1
Exemple #15
0
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return
    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')
    Event = E.getPrimitives('EVENT')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    selectedDimuonsOld, selectedDSAmuonsOld = Selector.SelectObjects(
        E, self.CUTS, [dim for dim in Dimuons3 if dim.composition == 'DSA'],
        DSAmuons)
    if selectedDimuonsOld is None: return

    selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjectsReordered(
        E, self.CUTS, Dimuons3, DSAmuons, PATmuons)

    selectedDimuonsHyb, selectedDSAmuonsHyb, selectedPATmuonsHyb = Selector.SelectObjectsReordered(
        E,
        self.CUTS,
        Dimuons3,
        DSAmuons,
        PATmuons,
        keepHybrids=True,
        option=ARGS.PCOPTION)

    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

        realMatches = {}
        if selectedDimuons is not None:
            # do the signal matching
            if len(genMuonPairs) == 1:
                genMuonPair = genMuonPairs[0]
                dimuonMatches, muonMatches, exitcode = matchedDimuons(
                    genMuonPair, selectedDimuons)
                if len(dimuonMatches) > 0:
                    realMatches = {0: dimuonMatches[0]}
                else:
                    realMatches = {}
            else:
                realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                    genMuonPairs, selectedDimuons)

        if len(realMatches) == 0:
            if len(genMuonPairs) == 1:
                genMuonPair = genMuonPairs[0]
                dimuonMatches, muonMatches, exitcode = matchedDimuons(
                    genMuonPair, selectedDimuonsOld)
                if len(dimuonMatches) > 0:
                    realMatchesOld = {0: dimuonMatches[0]}
                else:
                    realMatchesOld = {}
            else:
                realMatchesOld, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                    genMuonPairs, selectedDimuonsOld)

            if len(realMatchesOld) > 0:
                # huzzah!
                self.COUNTS['huzzah'] += 1
                HybridDimuons = [
                    dim for dim in Dimuons3 if dim.composition == 'HYBRID'
                ]
                HybridIDs = [dim.ID for dim in HybridDimuons]

                # defines a SegMatch, returns a pair of indices (called candidate)
                def lookForSegMatch(DSAmuon):
                    candidate = None
                    if DSAmuon.idx_SegMatch is None:
                        pass
                    elif len(DSAmuon.idx_SegMatch) > 1:
                        if DSAmuon.idx_ProxMatch in DSAmuon.idx_SegMatch:
                            candidate = DSAmuon.idx_ProxMatch
                        else:
                            # take first entry
                            # which is the smallest index = largest pT
                            candidate = DSAmuon.idx_SegMatch[0]
                    else:
                        candidate = DSAmuon.idx_SegMatch[0]
                    return candidate

                # check whether the DSA dimuons have hybrid replacements
                for dim in selectedDimuonsOld:
                    candidates = map(lookForSegMatch,
                                     (DSAmuons[dim.idx1], DSAmuons[dim.idx2]))

                    if candidates.count(None) == 1:
                        PATIndex = candidates[0] if candidates[
                            0] is not None else candidates[1]
                        DSAIndex = dim.idx2 if candidates[
                            1] is None else dim.idx1
                        testID = (DSAIndex, PATIndex)
                        if testID in HybridIDs:
                            self.COUNTS['hybfound'] += 1
                        else:
                            self.COUNTS['hybnot'] += 1
                    elif candidates.count(None) == 2:
                        self.COUNTS['nomatch'] += 1
                    elif candidates.count(None) == 0:
                        self.COUNTS['bothmatch'] += 1
                        PATDim = None
                        for pd in Dimuons3:
                            if pd.composition == 'PAT' and set(
                                    candidates).issubset(pd.ID):
                                PATDim = pd
                                break
                        if PATDim is None:
                            self.COUNTS['failedDim'] += 1
                            continue
                        elif PATmuons[PATDim.idx1].pt < 10. or PATmuons[
                                PATDim.idx2].pt < 10.:
                            self.COUNTS['failedPT'] += 1
                            continue
                        elif PATDim.LxyErr() > 99.:
                            self.COUNTS['failedLxyE'] += 1
                            continue
                        elif PATDim.mass < 5.:
                            self.COUNTS['failedM'] += 1
                            continue
                        else:
                            self.COUNTS['failedMatch'] += 1
                    else:
                        print 'What?'

                # see if gen muons matched with hybrid selection
                if selectedDimuonsHyb is not None:
                    if len(genMuonPairs) == 1:
                        genMuonPair = genMuonPairs[0]
                        dimuonMatches, muonMatches, exitcode = matchedDimuons(
                            genMuonPair, selectedDimuonsHyb)
                        if len(dimuonMatches) > 0:
                            realMatchesHyb = {0: dimuonMatches[0]}
                        else:
                            realMatchesHyb = {}
                    else:
                        realMatchesHyb, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                            genMuonPairs, selectedDimuonsHyb)

                    if len(realMatchesHyb) > 0:
                        self.COUNTS['recovered'] += 1
Exemple #16
0
def analyze(self, E, PARAMS=None):

#    print(E)

    event = E.getPrimitives('EVENT')
#    print(event)

    # require that the trigger has fired
    if not Selections.passedTrigger(E): return

    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')
    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2),)

    # original DSA muons
    DSAMuons = E.getPrimitives('DSAMUON')

    # all dimuons and dimuons made of muons passing quality cuts
    allDimuons = E.getPrimitives('DIMUON')
    selectedDSAmuons  = [mu for mu in DSAMuons if mu.nDTStations+mu.nCSCStations>1 and mu.nCSCHits+mu.nDTHits>12 and mu.ptError/mu.pt<1.]
    DSAmuons_formatch = [mu for mu in DSAMuons if mu.nDTStations+mu.nCSCStations>1 and mu.nCSCHits+mu.nDTHits>12 and mu.ptError/mu.pt<1. and abs(mu.eta) < 2.0 and mu.pt > 5.]
    selectedOIndices = [mu.idx for mu in selectedDSAmuons]
    selectedDimuons  = [dim for dim in allDimuons if dim.idx1 in selectedOIndices and dim.idx2 in selectedOIndices]

    # studies of matching between HLT and DSA muons
    HLTPaths, HLTMuons, L1TMuons = E.getPrimitives('TRIGGER')
#    print "List of HLT muons:"
#    for hltmuon in HLTMuons:
#        print(hltmuon)
    for muon in DSAMuons:
        print muon

    match_found = False
    HLTDSAMatches = matchedTrigger(HLTMuons, DSAmuons_formatch, saveDeltaR=True, threshold=0.4, printAllMatches=True)
    for i, j in HLTDSAMatches:
        imatch = 0
        for match in HLTDSAMatches[(i,j)]['bestMatches']:
            if   imatch == 0: print 'best match:', i, j, match
            elif imatch == 1: print '2nd best:',   i, j, match
            imatch += 1
            dR = match['deltaR']
            self.HISTS['dR_HLT_DSA'].Fill(dR)
        if HLTDSAMatches[(i,j)]['matchFound'] == True:
            match_found = True

    # check for how many events a DSA-HLT match was found
    self.HISTS['matches_HLT_DSA'].Fill(0)
    if match_found:
        self.HISTS['matches_HLT_DSA'].Fill(1)
    else:
        self.HISTS['matches_HLT_DSA'].Fill(2)

        print 'match not found'
        print(E)

        # check if there were any matching dimuons
        for genMuonPair in genMuonPairs:
            dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair, allDimuons)
            if len(dimuonMatches) > 0:
                self.HISTS['matches_HLT_DSA'].Fill(3)
            else:
                for i, j in HLTDSAMatches:
                    imatch = 0
                    for match in HLTDSAMatches[(i,j)]['bestMatches']:
                        dR = match['deltaR']
                        if   imatch == 0: self.HISTS['dR1_HLT_DSA_BadEvent'].Fill(dR)
                        elif imatch == 1: self.HISTS['dR2_HLT_DSA_BadEvent'].Fill(dR)
                        imatch += 1

            # more detailed diagnostics for cases when a good-quality
            # signal dimuon is lost
            dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair, selectedDimuons)
            if len(dimuonMatches) > 0:
                print "Lose good event!"
                self.HISTS['matches_HLT_DSA'].Fill(4)
                for i, j in HLTDSAMatches:
                    imatch = 0
                    for match in HLTDSAMatches[(i,j)]['bestMatches']:
                        dR = match['deltaR']
                        if   imatch == 0: self.HISTS['dR1_HLT_DSA_GoodEvent'].Fill(dR)
                        elif imatch == 1: self.HISTS['dR2_HLT_DSA_GoodEvent'].Fill(dR)
                        imatch += 1

                gen_dim = genMuonPair[0].p4 + genMuonPair[1].p4
                gen_invm = gen_dim.M()
                for dimuonMatch in dimuonMatches:
                    dimuon = dimuonMatch['dim']
                    rec_invm = dimuon.p4.M()
                    print "gen_mass = ", gen_invm, "rec_mass = ", rec_invm
                    print "gen_Lxy = ", genMuonPair[0].Lxy_, "rec_Lxy = ", dimuon.Lxy(), "+/-", dimuon.LxyErr()
                    print(dimuon)
                    unmatched_invm_res = (rec_invm - gen_invm)/gen_invm
                    self.HISTS['unmatched_invm_res'].Fill(unmatched_invm_res)
                    for muonMatch in muonMatches:
                        recmu_idx = muonMatch[0]['oidx']
                        muon_found = False
                        for i, j in HLTDSAMatches:
                            for hltMatch in HLTDSAMatches[(i,j)]['bestMatches']:
                                if hltMatch['rec_idx'] == recmu_idx and hltMatch['deltaR'] < 0.4:
                                    muon_found = True
                                    break
                        if muon_found == False:
                            print "DSA muon not matched to HLT muon:", recmu_idx
                            recmu_p4 = muonMatch[0]['muon'].p4
                            recmu_pt = muonMatch[0]['muon'].pt
                            for genmu in genMuonPair:
                                genmu_p4 = genmu.p4
                                dr = recmu_p4.DeltaR(genmu_p4)
                                if dr < 0.2:
                                    genmu_pt = genmu.pt
                                    unmatched_pt_res = (recmu_pt - genmu_pt)/genmu_pt
                                    print "muon pT = ", recmu_pt, "pt of matched gen muon = ", genmu_pt, "pt_res =", unmatched_pt_res
                                    self.HISTS['unmatched_pt_res'].Fill(unmatched_pt_res)
                                    self.HISTS['unmatched_pt_rec_vs_pt_gen'].Fill(genmu_pt, recmu_pt)
                                    self.HISTS['unmatched_pt_rec_vs_pt_gen_zoomed'].Fill(genmu_pt, recmu_pt)

    # studies of single-muon variables
    # loop over genMuons and fill histograms
    # for genMuon in genMuons:
    for gen_idx, genMuon in enumerate(genMuons):
#        print(genMuon)
        matches = matchedMuons(genMuon, DSAMuons, vertex='BS')
        if len(matches) > 0:
            for match in matches:

                muon = match['muon']

                # number of hits
                nDTCSCHits = muon.nDTHits + muon.nCSCHits
                nRPCHits   = muon.nMuonHits - nDTCSCHits
                self.HISTS['nMuonHits'].Fill(muon.nMuonHits)
                self.HISTS['nDTCSCHits'].Fill(nDTCSCHits)
                self.HISTS['nDTHits'].Fill(muon.nDTHits)
                self.HISTS['nCSCHits'].Fill(muon.nCSCHits)
                self.HISTS['nRPCHits'].Fill(nRPCHits)

                # number of hits for various numbers of stations
                nStations = muon.nDTStations + muon.nCSCStations
                self.HISTS['CSC_vs_DT_Stations'].Fill(muon.nDTStations, muon.nCSCStations)
                if nStations >= 1 and nStations <= 4:
                    self.HISTS['nMuonHits_%dStat'%nStations]. Fill(muon.nMuonHits)
                    self.HISTS['nDTCSCHits_%dStat'%nStations].Fill(nDTCSCHits)
                    if muon.nDTHits > 0:
                        self.HISTS['nDTHits_%dStat'%nStations]. Fill(muon.nDTHits)
                    if muon.nCSCHits > 0:
                        self.HISTS['nCSCHits_%dStat'%nStations].Fill(muon.nCSCHits)
                    self.HISTS['nRPCHits_%dStat'%nStations].  Fill(nRPCHits)
                    self.HISTS['nCSCHits_vs_nDTHits_%dStat'%nStations].Fill(muon.nDTHits, muon.nCSCHits)
                elif nStations < 1 or nStations > 4:
                    print '+++ Warning: no histo filled; N(stat) = ', nStations

                # pT and 1/pT resolutions
                pt_res    = (muon.pt - genMuon.BS.pt)/genMuon.BS.pt
                invpt_res = (1./muon.pt - 1./genMuon.BS.pt)/(1./genMuon.BS.pt)
                # (rec-gen) charge and d0
                q_dif     = muon.charge - genMuon.BS.charge
                d0_dif    = muon.d0(extrap=None) - genMuon.d0(extrap=None)
#                print 'gen idx', gen_idx, 'muon idx = ', muon.idx, ' pT res = ', pt_res, 'd0 dif = ', d0_dif

                # sigma(pT)/pT and chi2/dof
                sigmapt_over_pt = muon.ptError/muon.pt
                chi2_over_ndof  = muon.chi2/muon.ndof

                # resolutions for groups of 3 DT+CSC hits
                ihist = nDTCSCHits//3
                self.HISTS['pTres_DTCSChits_hist%d'%ihist].Fill(pt_res)
                self.HISTS['invpTres_DTCSChits_hist%d'%ihist].Fill(invpt_res)
                self.HISTS['qdif_DTCSChits_hist%d'%ihist].Fill(q_dif)
                self.HISTS['d0dif_DTCSChits_hist%d'%ihist].Fill(d0_dif)

                # ditto for Nstat > 1
                if nStations > 1:
                    self.HISTS['pTres_DTCSChits_Stat234_hist%d'%ihist].Fill(pt_res)
                    self.HISTS['invpTres_DTCSChits_Stat234_hist%d'%ihist].Fill(invpt_res)
                    self.HISTS['qdif_DTCSChits_Stat234_hist%d'%ihist].Fill(q_dif)
                    self.HISTS['d0dif_DTCSChits_Stat234_hist%d'%ihist].Fill(d0_dif)

                    # fine scan for Nhits between 12 and 19
                    if nDTCSCHits >= 12 and nDTCSCHits <= 19:
                        self.HISTS['pTres_Stat234_%dDTCSChits'%nDTCSCHits].Fill(pt_res)
                        self.HISTS['invpTres_Stat234_%dDTCSChits'%nDTCSCHits].Fill(pt_res)
                        self.HISTS['qdif_Stat234_%dDTCSChits'%nDTCSCHits].Fill(q_dif)

                # sigma(pT)/pT and chi2/dof for groups of 3 DT+CSC hits
                self.HISTS['dpt_over_pt_DTCSChits_hist%d'%ihist].Fill(sigmapt_over_pt)
                self.HISTS['chi2_over_ndof_DTCSChits_hist%d'%ihist].Fill(chi2_over_ndof)

                # ditto for Nstat > 1
                if nStations > 1:
                    self.HISTS['dpt_over_pt_DTCSChits_Stat234_hist%d'%ihist].Fill(sigmapt_over_pt)
                    self.HISTS['chi2_over_ndof_DTCSChits_Stat234_hist%d'%ihist].Fill(chi2_over_ndof)

                # resolutions in barrel, endcap, and overlap
                if muon.nDTStations > 0 and muon.nCSCStations == 0:
                    ihist = muon.nDTHits//6
#                    print 'barrel: ', muon.nDTHits, ihist
                    self.HISTS['pTres_DThits_barrel_hist%d'%ihist].Fill(pt_res)
                    self.HISTS['d0dif_DThits_barrel_hist%d'%ihist].Fill(d0_dif)
                elif muon.nDTStations == 0 and muon.nCSCStations > 0:
                    ihist = muon.nCSCHits//3
                    # overlapping chambers?
                    if ihist > 9:
                        print "CSCs: > 29 hits", muon.nCSCHits
                        ihist = 8
#                    print 'endcap: ', muon.nCSCHits, ihist
                    self.HISTS['pTres_CSChits_endcap_hist%d'%ihist].Fill(pt_res)
                    self.HISTS['d0dif_CSChits_endcap_hist%d'%ihist].Fill(d0_dif)
                elif muon.nDTStations > 0 and muon.nCSCStations > 0:
                    ihist = nDTCSCHits//6
#                    print 'overlap: ', nDTCSCHits, ihist
                    self.HISTS['pTres_DTCSChits_overlap_hist%d'%ihist].Fill(pt_res)
                    self.HISTS['d0dif_DTCSChits_overlap_hist%d'%ihist].Fill(d0_dif)

                # make sure that the nDTCSCHits > 12 cut supersedes the nStations > 1 one
                if nDTCSCHits > 12 and nStations <= 1:
                    print "+++ Mismatch between nStations and nHits: nStations = ", nStations, "nDTCSCHits = ", nDTCSCHits, "+++"

                # sigma(pT)/pT and chi2/dof
                self.HISTS['dpt_over_pt_vs_chi2_over_ndof'].Fill(chi2_over_ndof, sigmapt_over_pt)
                if nStations >= 1 and nStations <= 4:
                    self.HISTS['dpt_over_pt_%dStat'%nStations].Fill(sigmapt_over_pt)
                    self.HISTS['chi2_over_ndof_%dStat'%nStations].Fill(chi2_over_ndof)

                # pT resolution in slices of sigma(pT)/pT
                ihist = 0
                while sigmapt_over_pt >= SLICE_EDGES[ihist]: ihist += 1
                self.HISTS['pTres_for_dpt_over_pt_hist%d'%ihist].Fill(pt_res)
                if nDTCSCHits > 12:
                    self.HISTS['pTres_for_dpt_over_pt_passed_hist%d'%ihist].Fill(pt_res)

                # pT pull in slices of sigma(pT)/pT
                pt_pull = (muon.pt - genMuon.BS.pt)/muon.ptError
                self.HISTS['pTpull_for_dpt_over_pt_hist%d'%ihist].Fill(pt_pull)

                # Refitted muons for DSA muons failing dpT/pT cut
                if sigmapt_over_pt > 1.:
                    self.HISTS['eta_for_dpt_over_pt_gt_1'].Fill(muon.eta)
                    for genMuonPair in genMuonPairs:
                        dimuonMatches, muonMatches, exitcode = matchedDimuons(genMuonPair, allDimuons)
                        for match in dimuonMatches:
                            dimuon = match['dim']
                            for refmu in (dimuon.mu1, dimuon.mu2):
                                if refmu.idx == muon.idx:
#                                    print "Found refitted muon", refmu.idx, refmu.pt
                                    pt_res_ref          = (refmu.pt - genMuon.pt)/genMuon.pt
                                    sigmapt_over_pt_ref = refmu.ptError/refmu.pt
                                    self.HISTS['pTres_ref_for_dpt_over_pt_gt_1'].Fill(pt_res_ref)
                                    self.HISTS['dpt_over_pt_ref_for_dpt_over_pt_gt_1'].Fill(sigmapt_over_pt_ref)
                                    if sigmapt_over_pt_ref < 1:
                                        self.HISTS['pTres_ref_for_dpt_over_pt_gt_1_ref_lt_1'].Fill(pt_res_ref)


                # pT resolution in slices of chi2/ndof
                ihist = 0
                while chi2_over_ndof >= SLICE_EDGES[ihist]: ihist += 1
                self.HISTS['pTres_for_chi2_over_ndof_hist%d'%ihist].Fill(pt_res)
                if nDTCSCHits > 12:
                    self.HISTS['pTres_for_chi2_over_ndof_passed_hist%d'%ihist].Fill(pt_res)
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return

    Event = E.getPrimitives('EVENT')

    # take 10% of data: event numbers ending in 7
    if 'DoubleMuon' in self.NAME and '_IDPHI' not in self.CUTS:
        self.DATACOUNTER['all'] += 1
        if Event.event % 10 != 7: return
        self.DATACOUNTER['selected'] += 1

    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjects(
        E, self.CUTS, Dimuons3, DSAmuons, PATmuons)
    if selectedDimuons is None: return

    for dim in selectedDimuons:
        if dim.composition == 'DSA':
            self.HISTS['nDimuon'].Fill(len(selectedDimuons), eventWeight)
            self.HISTS['nDSA'].Fill(len(DSAmuons), eventWeight)
            self.HISTS['nDSA12'].Fill(
                len([d for d in DSAmuons if d.nCSCHits + d.nDTHits > 12]),
                eventWeight)
            self.HISTS['nDSA12-pT'].Fill(
                len([
                    d for d in DSAmuons
                    if d.nCSCHits + d.nDTHits > 12 and d.pt > 5.
                ]), eventWeight)
            self.HISTS['nDSA-DT'].Fill(
                len([d for d in DSAmuons if d.nCSCHits == 0]), eventWeight)
            break

    def getOriginalMuons(dim):
        if dim.composition == 'PAT':
            return PATmuons[dim.idx1], PATmuons[dim.idx2]
        elif dim.composition == 'DSA':
            return DSAmuons[dim.idx1], DSAmuons[dim.idx2]
        else:
            return DSAmuons[dim.idx1], PATmuons[dim.idx2]

    for dim in selectedDimuons:
        RTYPE = dim.composition[:3]
        for QKEY in DIMQUANTITIES:
            KEY = RTYPE + '-' + QKEY
            if QKEY not in ('mind0Sig', 'minNHits', 'qsum'):
                self.HISTS[KEY].Fill(DIMQUANTITIES[QKEY]['LAMBDA'](dim),
                                     eventWeight)
            elif QKEY in ('mind0Sig', 'minNHits'):
                self.HISTS[KEY].Fill(
                    DIMQUANTITIES[QKEY]['LAMBDA'](*getOriginalMuons(dim)),
                    eventWeight,
                )  # ew
            else:
                self.HISTS[KEY].Fill(
                    DIMQUANTITIES[QKEY]['LAMBDA'](dim.mu1, dim.mu2),
                    eventWeight)

        if RTYPE == 'DSA':
            for QKEY in DSAQUANTITIES:
                KEY = RTYPE + '-' + QKEY
                for mu in getOriginalMuons(dim):
                    self.HISTS[KEY].Fill(DSAQUANTITIES[QKEY]['LAMBDA'](mu),
                                         eventWeight)

        if RTYPE == 'PAT':
            for QKEY in PATQUANTITIES:
                KEY = RTYPE + '-' + QKEY
                for mu in getOriginalMuons(dim):
                    self.HISTS[KEY].Fill(PATQUANTITIES[QKEY]['LAMBDA'](mu),
                                         eventWeight)

        if RTYPE == 'HYB':
            DSAmu, PATmu = getOriginalMuons(dim)

            for QKEY in DSAQUANTITIES:
                KEY = 'HYB-DSA' + '-' + QKEY
                self.HISTS[KEY].Fill(DSAQUANTITIES[QKEY]['LAMBDA'](DSAmu),
                                     eventWeight)

            for QKEY in PATQUANTITIES:
                KEY = 'HYB-PAT' + '-' + QKEY
                self.HISTS[KEY].Fill(PATQUANTITIES[QKEY]['LAMBDA'](PATmu),
                                     eventWeight)

        self.HISTS[RTYPE + '-LxySigVSdeltaPhi'].Fill(
            DIMQUANTITIES['deltaPhi']['LAMBDA'](dim),
            DIMQUANTITIES['LxySig']['LAMBDA'](dim), eventWeight)

        # temporary 2D histograms
        if dim.composition != 'DSA':
            mu1, mu2 = getOriginalMuons(dim)
            FC2, FMED = PAT2DQUANTITIES['normChi2']['LAMBDA'], PAT2DQUANTITIES[
                'isMedium']['LAMBDA']

            for mu in (mu1, mu2) if RTYPE == 'PAT' else (mu2, ):
                self.HISTS['PAT-normChi2VSisMedium'].Fill(
                    FMED(mu), FC2(mu), eventWeight)

        if dim.composition == 'DSA':
            mu1, mu2 = getOriginalMuons(dim)
            for QKEY in DSA2DQUANTITIES:
                KEY = 'DSA-12-' + QKEY
                F = DSA2DQUANTITIES[QKEY]['LAMBDA']
                self.HISTS[KEY].Fill(F(mu1), F(mu2), eventWeight)

            F = DSAQUANTITIES['FPTE']['LAMBDA']
            self.HISTS['REF-DSA-FPTE'].Fill(F(dim.mu1), eventWeight)
            self.HISTS['REF-DSA-FPTE'].Fill(F(dim.mu2), eventWeight)

        if self.SP is None and dim.LxySig() > 20.:
            mu1, mu2 = getOriginalMuons(dim)
            if dim.composition == 'PAT':
                for QKEY in PAT2DQUANTITIES:
                    KEY = 'PAT-12-' + QKEY
                    F = PAT2DQUANTITIES[QKEY]['LAMBDA']
                    if QKEY in ('hitsBeforeVtx', 'missingHitsAfterVtx'):
                        self.HISTS[KEY].Fill(F(dim.mu1), F(dim.mu2),
                                             eventWeight)
                    else:
                        self.HISTS[KEY].Fill(F(mu1), F(mu2), eventWeight)

                print '{:13s} {:d} {:7d} {:10d} {:2d} ::: {:3s} {:2d} {:2d} ::: {:6.2f} {:2d} {:1d} {:1d} {:1d} {:1d} {:6.2f} {:2d} {:1d} {:1d} {:1d} {:1d} ::: {:9.4f} {:8.4f} {:5.2f} {:6.2f} {:6.2f}'.format(
                    self.NAME, Event.run, Event.lumi, Event.event,
                    int(eventWeight), dim.composition[:3], dim.idx1, dim.idx2,
                    mu1.normChi2, mu1.nTrackerLayers, mu1.nPixelHits,
                    int(mu1.highPurity), int(mu1.isGlobal), int(mu1.isMedium),
                    mu2.normChi2, mu2.nTrackerLayers, mu2.nPixelHits,
                    int(mu2.highPurity), int(mu2.isGlobal), int(mu2.isMedium),
                    dim.LxySig(), dim.Lxy(), dim.normChi2, mu1.d0Sig(),
                    mu2.d0Sig())
            elif dim.composition == 'DSA':
                print '{:13s} {:d} {:7d} {:10d} {:2d} ::: {:3s} {:2d} {:2d} ::: {:6.2f} {:2s} {:1s} {:1s} {:1s} {:1s} {:6.2f} {:2s} {:1s} {:1s} {:1s} {:1s} ::: {:9.4f} {:8.4f} {:5.2f} {:6.2f} {:6.2f}'.format(
                    self.NAME, Event.run, Event.lumi, Event.event,
                    int(eventWeight), dim.composition[:3], dim.idx1, dim.idx2,
                    mu1.normChi2, '-', '-', '-', '-', '-', mu2.normChi2, '-',
                    '-', '-', '-', '-', dim.LxySig(), dim.Lxy(), dim.normChi2,
                    mu1.d0Sig(), mu2.d0Sig())
            else:
                print '{:13s} {:d} {:7d} {:10d} {:2d} ::: {:3s} {:2d} {:2d} ::: {:6.2f} {:2s} {:1s} {:1s} {:1s} {:1s} {:6.2f} {:2d} {:1d} {:1d} {:1d} {:1d} ::: {:9.4f} {:8.4f} {:5.2f} {:6.2f} {:6.2f}'.format(
                    self.NAME, Event.run, Event.lumi, Event.event,
                    int(eventWeight), dim.composition[:3], dim.idx1, dim.idx2,
                    mu1.normChi2, '-', '-', '-', '-', '-', mu2.normChi2,
                    mu2.nTrackerLayers, mu2.nPixelHits, int(mu2.highPurity),
                    int(mu2.isGlobal), int(mu2.isMedium), dim.LxySig(),
                    dim.Lxy(), dim.normChi2, mu1.d0Sig(), mu2.d0Sig())

    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

        # do the signal matching
        if len(genMuonPairs) == 1:
            genMuonPair = genMuonPairs[0]
            dimuonMatches, muonMatches, exitcode = matchedDimuons(
                genMuonPair, selectedDimuons)
            if len(dimuonMatches) > 0:
                realMatches = {0: dimuonMatches[0]}
            else:
                realMatches = {}
        else:
            realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                genMuonPairs, selectedDimuons)

        for pairIndex in realMatches:
            genMuon = genMuonPairs[pairIndex][0]
            dim = realMatches[pairIndex]['dim']
            self.HISTS['GEN-Lxy'].Fill(genMuon.Lxy(), eventWeight)

            RTYPE = dim.composition[:3]
            KEY = 'GEN-Lxy-' + RTYPE
            self.HISTS[KEY].Fill(genMuon.Lxy(), eventWeight)

            KEY = RTYPE + '-' + 'LxyRes'
            self.HISTS[KEY].Fill(dim.Lxy() - genMuon.Lxy(), eventWeight)

            KEY = RTYPE + '-' + 'LxyRes' + 'VSGEN-Lxy'
            self.HISTS[KEY].Fill(genMuon.Lxy(),
                                 dim.Lxy() - genMuon.Lxy(), eventWeight)

            KEY = RTYPE + '-' + 'LxyPull'
            self.HISTS[KEY].Fill((dim.Lxy() - genMuon.Lxy()) / dim.LxyErr(),
                                 eventWeight)

            KEY = RTYPE + '-' + 'LxyRes' + 'VS' + RTYPE + '-' + 'LxyErr'
            self.HISTS[KEY].Fill(dim.LxyErr(),
                                 dim.Lxy() - genMuon.Lxy(), eventWeight)

            # temporary 2D histograms
            if RTYPE == 'DSA': continue

            mu1, mu2 = getOriginalMuons(dim)
            FC2, FMED = PAT2DQUANTITIES['normChi2']['LAMBDA'], PAT2DQUANTITIES[
                'isMedium']['LAMBDA']

            for mu in (mu1, mu2) if RTYPE == 'PAT' else (mu2, ):
                self.HISTS['PAT-normChi2VSGEN-Lxy'].Fill(
                    genMuon.Lxy(), FC2(mu), eventWeight)
                self.HISTS['PAT-isMediumVSGEN-Lxy'].Fill(
                    genMuon.Lxy(), FMED(mu), eventWeight)

            # permanent
            if RTYPE != 'PAT': continue
            mu1, mu2 = PATmuons[dim.idx1], PATmuons[dim.idx2]
            for QKEY in PAT2DQUANTITIES:
                KEY = RTYPE + '-' + '12' + '-' + QKEY
                F = PAT2DQUANTITIES[QKEY]['LAMBDA']
                if QKEY in ('hitsBeforeVtx', 'missingHitsAfterVtx'):
                    self.HISTS[KEY].Fill(F(dim.mu1), F(dim.mu2), eventWeight)
                else:
                    self.HISTS[KEY].Fill(F(mu1), F(mu2), eventWeight)
Exemple #18
0
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')
    if self.TRIGGER:
        if not Selections.passedTrigger(E): return
    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2),)
    DSAmuons = E.getPrimitives('DSAMUON')
    RSAmuons = E.getPrimitives('RSAMUON')
    Dimuons  = E.getPrimitives('DIMUON' )

    ALL = True if 'All' in self.CUTS else False
    # require reco muons to pass all selections
    if ALL:
        DSASelections = [Selections.MuonSelection(muon) for muon in DSAmuons]
        RSASelections = [Selections.MuonSelection(muon) for muon in RSAmuons]
        selectedDSAmuons = [mu  for idx,mu  in enumerate(DSAmuons) if DSASelections   [idx]]
        selectedRSAmuons = [mu  for idx,mu  in enumerate(RSAmuons) if RSASelections   [idx]]
        selectedDimuons  = Dimuons

    # don't require reco muons to pass all selections
    else:
        selectedDSAmuons = DSAmuons
        selectedRSAmuons = RSAmuons
        selectedDimuons  = Dimuons

    # loop over genMuons and fill histograms based on matches
    for genMuonPair in genMuonPairs:
        # genMuonMatches are a dictionary of the return tuple of length 3
        # DSA and RSA get a doDimuons=False argument so that no dimuon matching will be done
        genMuonMatches = {'DSA':None, 'RSA':None, 'REF':None}
        for MUON, recoMuons in (('DSA', selectedDSAmuons), ('RSA', selectedRSAmuons)):
            genMuonMatches[MUON]  = matchedDimuons(genMuonPair, selectedDimuons, recoMuons, vertex='BS', doDimuons=False)
        for MUON in ('REF',):
            genMuonMatches['REF'] = matchedDimuons(genMuonPair, selectedDimuons)

        # now figure out the closest match, or None if they overlap
        # exitcode helps to make sure that both gen muons never match the same reco muon
        genMuonMatch = [{'DSA': None, 'RSA': None, 'REF': None}, {'DSA': None, 'RSA': None, 'REF': None}]
        for MUON in ('DSA', 'RSA'):
            dimuonMatches, muonMatches, exitcode = genMuonMatches[MUON]
            genMuonMatch[0][MUON], genMuonMatch[1][MUON] = exitcode.getBestGenMuonMatches(muonMatches)

        # matched refitted muons if there was at least one dimuon
        for MUON in ('REF',):
            dimuonMatches, muonMatches, exitcode = genMuonMatches['REF']
            if len(dimuonMatches) > 0:
                genMuonMatch[0]['REF'] = muonMatches[0][0]
                genMuonMatch[1]['REF'] = muonMatches[1][0]

        # now loop over the quantities and fill. split by whether it's a mu plot or a mumu plot
        genMuonPairSelection = Selections.AcceptanceSelection(genMuonPair)
        genMuonSelections    = [Selections.AcceptanceSelection(genMuonPair[0]), Selections.AcceptanceSelection(genMuonPair[1])]
        for KEY in CONFIG:
            F = CONFIG[KEY]['LAMBDA']
            AF = CONFIG[KEY]['ACC_LAMBDA']

            # mumu plots: check if pair in acceptance, fill den, fill num if both match
            if KEY == 'dphi' or KEY == 'dR':
                if AF(genMuonPairSelection):
                    self.HISTS[       KEY+'Den'].Fill(F(genMuonPair))
                    self.HISTS['REF_'+KEY+'Den'].Fill(F(genMuonPair))

                    for MUON in ('DSA', 'RSA', 'REF'):
                        if genMuonMatch[0][MUON] is not None and genMuonMatch[1][MUON] is not None:
                            self.EffPairFill(MUON, KEY, genMuonPair, genMuonMatch, F)

            # mu plots: for DSA and RSA, check if gen muon in acceptance, fill den, fill num if match
            # for REF, check if pair in acceptance, fill den, full num if both match
            else:
                for idx, genMuon in enumerate(genMuonPair):
                    if AF(genMuonSelections[idx]):
                        self.HISTS[KEY+'Den'].Fill(F(genMuon))

                        for MUON in ('DSA', 'RSA'):
                            if genMuonMatch[idx][MUON] is not None:
                                self.EffSingleFill(MUON, KEY, genMuon, genMuonMatch, F, idx)

                    if AF(genMuonPairSelection):
                        self.HISTS['REF_'+KEY+'Den'].Fill(F(genMuon))

                        for MUON in ('REF',):
                            if genMuonMatch[0][MUON] is not None and genMuonMatch[1][MUON] is not None:
                                self.EffSingleFill(MUON, KEY, genMuon, genMuonMatch, F, idx)
Exemple #19
0
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return

    Event = E.getPrimitives('EVENT')

    # no Lxy sig
    CUTSTRING = '_Combined_NS_NH_FPTE_HLT_REP_PT_TRK_NDT_DCA_PC_LXYE_MASS_CHI2_VTX_COSA_NPP_OS'
    if 'DoubleMuon' in self.NAME:
        CUTSTRING += '_IDPHI'
    else:
        CUTSTRING += '_DPHI'

    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    # do the selection
    selectedDimuons, selectedDSAmuons, selectedPATmuons = Selector.SelectObjects(
        E, CUTSTRING, Dimuons3, DSAmuons, PATmuons)
    if selectedDimuons is None:
        DSADimuons = []
        return
    DSADimuons = [dim for dim in selectedDimuons if dim.composition == 'DSA']

    def getOriginalMuons(dim, DSAmuons):
        if dim.composition == 'PAT':
            return PATmuons[dim.idx1], PATmuons[dim.idx2]
        elif dim.composition == 'DSA':
            return DSAmuons[dim.idx1], DSAmuons[dim.idx2]
        else:
            return DSAmuons[dim.idx1], PATmuons[dim.idx2]

    def modifiedName(name):
        if 'DoubleMuon' in name:
            return 'Data' + name[17]
        if 'QCD' in name:
            return 'QCD'
        if 'HTo2X' in name:
            return '{:4d} {:3d} {:4d}'.format(*self.SP.SP)
        return name

    # gen stuff
    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

        if len(genMuonPairs) == 1:
            genMuonPair = genMuonPairs[0]
            dimuonMatches, muonMatches, exitcode = matchedDimuons(
                genMuonPair, selectedDimuons)  #DSADimuons)
            if len(dimuonMatches) > 0:
                realMatches = {0: dimuonMatches[0]}
            else:
                realMatches = {}
        else:
            realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                genMuonPairs, selectedDimuons)  # DSADimuons)

    # the other plots
    for dim in DSADimuons:

        matched = None
        if self.SP is not None and dim.ID in [
                realMatches[pIdx]['dim'].ID for pIdx in realMatches
        ]:
            matched = True

        mu1, mu2 = getOriginalMuons(dim, DSAmuons)

        for mu in (mu1, mu2):
            for matchType in ('Prox', 'Seg'):
                for vectorType in ('PD', 'PP'):
                    match = getattr(mu,
                                    '{}Match{}'.format(matchType, vectorType))
                    if match.idx is not None:
                        if matchType == 'Prox':
                            iterables = [(match.idx, match.deltaR, match.nSeg,
                                          mu.nSegments)]
                        else:
                            iterables = [
                                (a, b, c, mu.nSegments) for a, b, c in zip(
                                    match.idx, match.deltaR, match.nSeg)
                            ]

                        for idx, deltaR, nSeg, nDSASeg in iterables:
                            self.HISTS['{}_{}_deltaR'.format(
                                matchType, vectorType)].Fill(deltaR)
                            self.HISTS['{}_{}_fSeg'.format(
                                matchType, vectorType)].Fill(
                                    float(nSeg) /
                                    nDSASeg if nDSASeg != 0 else 0.)

                            if matched is not None:
                                self.HISTS['{}_{}_deltaR_Matched'.format(
                                    matchType, vectorType)].Fill(deltaR)
                                self.HISTS['{}_{}_fSeg_Matched'.format(
                                    matchType, vectorType)].Fill(
                                        float(nSeg) /
                                        nDSASeg if nDSASeg != 0 else 0.)
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return
    Event = E.getPrimitives('EVENT')
    DSAmuons = E.getPrimitives('DSAMUON')
    Dimuons = E.getPrimitives('DIMUON')

    Primitives.CopyExtraRecoMuonInfo(Dimuons, DSAmuons)

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    # decide what set of cuts to apply based on self.CUTS cut string
    ALL = 'All' in self.CUTS
    PROMPT = '_Prompt' in self.CUTS
    NOPROMPT = '_NoPrompt' in self.CUTS
    NSTATIONS = '_NS' in self.CUTS
    NMUONHITS = '_NH' in self.CUTS
    FPTERR = '_FPTE' in self.CUTS
    PT = '_PT' in self.CUTS
    HLT = '_HLT' in self.CUTS
    PC = '_PC' in self.CUTS
    LXYERR = '_LXYE' in self.CUTS
    MASS = '_M' in self.CUTS

    def boolsToMuonCutList(NSTATIONS, NMUONHITS, FPTERR, PT):
        cutList = []
        if NSTATIONS:
            cutList.append('b_nStations')
        if NMUONHITS:
            cutList.append('b_nMuonHits')
        if FPTERR:
            cutList.append('b_FPTE')
        if PT:
            cutList.append('b_pT')
        return cutList

    def boolsToDimuonCutList(LXYERR, MASS):
        cutList = []
        if LXYERR:
            cutList.append('b_LxyErr')
        if MASS:
            cutList.append('b_mass')
        return cutList

    # require muons to pass all selections
    if ALL:
        DSASelections = [Selections.MuonSelection(muon) for muon in DSAmuons]
        selectedDSAmuons = [
            mu for idx, mu in enumerate(DSAmuons) if DSASelections[idx]
        ]
        selectedDimuons = Dimuons

    # don't require reco muons to pass all selections
    else:
        selectedDSAmuons = DSAmuons
        selectedDimuons = Dimuons

    # for PROMPT and NOPROMPT event selections
    if PROMPT or NOPROMPT:
        highLxySigExists = False
        for dimuon in Dimuons:
            if dimuon.LxySig() > 3.:
                highLxySigExists = True
                break

        # return if there are LxySig > 3
        if PROMPT:
            if highLxySigExists:
                return
        # return if there are NO LxySig > 3 -- that's category 1
        elif NOPROMPT:
            if not highLxySigExists:
                return

    if PROMPT or NOPROMPT:
        # compute all the baseline selection booleans
        DSASelections = [
            Selections.MuonSelection(muon, cutList='BaselineMuonCutList')
            for muon in DSAmuons
        ]

        # figure out which cuts we actually care about
        cutList = boolsToMuonCutList(NSTATIONS, NMUONHITS, FPTERR, PT)

        # no selection
        if len(cutList) == 0:
            selectedDSAmuons = DSAmuons
            selectedDimuons = Dimuons
        # cutList is some nonzero list, meaning keep only the muons that pass the cut keys in cutList
        else:
            selectedDSAmuons = [
                mu for i, mu in enumerate(DSAmuons)
                if DSASelections[i].allOf(*cutList)
            ]
            selectedOIndices = [mu.idx for mu in selectedDSAmuons]
            selectedDimuons = [
                dim for dim in Dimuons if dim.idx1 in selectedOIndices
                and dim.idx2 in selectedOIndices
            ]

    # apply HLT RECO matching
    if HLT:
        HLTPaths, HLTMuons, L1TMuons = E.getPrimitives('TRIGGER')
        DSAMuonsForHLTMatch = [
            mu for mu in selectedDSAmuons if abs(mu.eta) < 2.
        ]
        HLTMuonMatches = matchedTrigger(HLTMuons, DSAMuonsForHLTMatch)
        if not any([HLTMuonMatches[ij]['matchFound']
                    for ij in HLTMuonMatches]):
            return

    # apply pairing criteria and transform selectedDimuons
    if PC:
        selectedDimuons = applyPairingCriteria(selectedDSAmuons,
                                               selectedDimuons)

    if PROMPT or NOPROMPT:
        # compute all the baseline selection booleans
        DimuonSelections = {
            dim.ID: Selections.DimuonSelection(dim,
                                               cutList='BaselineDimuonCutList')
            for dim in selectedDimuons
        }

        # figure out which cuts we actually care about
        cutList = boolsToDimuonCutList(LXYERR, MASS)

        # cutList is some nonzero list, meaning keep only the muons that pass the cut keys in cutList
        if len(cutList) > 0:
            selectedDimuons = [
                dim for dim in selectedDimuons
                if DimuonSelections[dim.ID].allOf(*cutList)
            ]

    # for the MC/Data events, skip events with no dimuons, but not for "no selection"
    if (PROMPT or NOPROMPT) and NSTATIONS:
        if len(selectedDimuons) == 0: return

    # also filter selectedDSAmuons to only be of those indices that are in the final dimuons
    if PROMPT or NOPROMPT:
        selectedOIndices = []
        for dim in selectedDimuons:
            selectedOIndices.append(dim.idx1)
            selectedOIndices.append(dim.idx2)
        selectedOIndices = list(set(selectedOIndices))
        selectedDSAmuons = [
            mu for mu in selectedDSAmuons if mu.idx in selectedOIndices
        ]

    # all refitted muons
    allRefittedMuons = []
    for dimuon in selectedDimuons:
        allRefittedMuons.append(dimuon.mu1)
        allRefittedMuons.append(dimuon.mu2)

    # fill histograms for every reco muon
    for MUON, recoMuons in (('DSA', selectedDSAmuons), ('REF',
                                                        allRefittedMuons)):
        self.HISTS[MUON + '_nMuon'].Fill(len(recoMuons), eventWeight)
        for muon in recoMuons:
            for KEY in CONFIG:
                self.HISTS[MUON + '_' + KEY].Fill(CONFIG[KEY]['LAMBDA'](muon),
                                                  eventWeight)
            for KEY in EXTRACONFIG:
                F1 = EXTRACONFIG[KEY]['LAMBDA'][0]
                F2 = EXTRACONFIG[KEY]['LAMBDA'][1]
                self.HISTS[MUON + '_' + KEY].Fill(F1(muon), F2(muon),
                                                  eventWeight)

    # get gen particles if this is a signal sample
    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

        MuonMatches = {'DSA': [], 'REF': []}
        # get matched reco muons
        for genMuon in genMuons:
            # cut genMuons outside the detector acceptance
            # don't do it for now
            #genMuonSelection = Selections.AcceptanceSelection(genMuon)

            for MUON, recoMuons in (('DSA', selectedDSAmuons), ):
                MuonMatches[MUON].append(
                    matchedMuons(genMuon, recoMuons, vertex='BS'))

        # and for refitted muons for matched dimuons
        for genMuonPair in genMuonPairs:
            for MUON in ('REF', ):
                dimuonMatches, muonMatches, exitcode = matchedDimuons(
                    genMuonPair, selectedDimuons)
                MuonMatches[MUON].append(muonMatches[0])
                MuonMatches[MUON].append(muonMatches[1])

        # fill histograms
        # for each major muon type,
        # MuonMatches contains 2 lists of matches corresponding to each gen muon
        # Each match in each of those 2 lists is a list of individual muon matches
        for MUON in ('DSA', 'REF'):
            for matches in MuonMatches[MUON]:
                for match in matches:
                    muon = match['muon']
                    deltaR = match['deltaR']
                    for KEY in CONFIG:
                        self.HISTS[MUON + '_' + KEY + '_Matched'].Fill(
                            CONFIG[KEY]['LAMBDA'](muon), eventWeight)
                    for KEY in EXTRACONFIG:
                        F1 = EXTRACONFIG[KEY]['LAMBDA'][0]
                        F2 = EXTRACONFIG[KEY]['LAMBDA'][1]
                        self.HISTS[MUON + '_' + KEY + '_Matched'].Fill(
                            F1(muon), F2(muon), eventWeight)
                    self.HISTS[MUON + '_deltaRGR_Matched'].Fill(
                        deltaR, eventWeight)
                self.HISTS[MUON + '_nMuon_Matched'].Fill(
                    len(matches), eventWeight)
                if len(matches) > 0:
                    self.HISTS[MUON + '_deltaRGR_Closest'].Fill(
                        matches[0]['deltaR'], eventWeight)
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')

    if self.TRIGGER:
        if not Selections.passedTrigger(E): return

    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )
    Event = E.getPrimitives('EVENT')
    dimuons = E.getPrimitives('DIMUON')
    muons = E.getPrimitives('DSAMUON')

    baseMuons = [
        mu for mu in muons
        if mu.nDTStations + mu.nCSCStations > 1 and mu.nCSCHits +
        mu.nDTHits > 12 and mu.ptError / mu.pt < 1.
    ]

    for pTCut in PTCUTS:
        for nMuons in ('All', '2', '3', '4'):
            self.fillHist(nMuons, 'Triggers', pTCut)

        selectedMuons = [mu for mu in baseMuons if mu.pt > pTCut]
        selectedOIndices = [mu.idx for mu in selectedMuons]
        selectedDimuons = [
            dim for dim in dimuons
            if dim.idx1 in selectedOIndices and dim.idx2 in selectedOIndices
        ]

        if len(selectedMuons) > 0:
            nMuons = nToStr(len(selectedMuons))
            self.fillHist(nMuons, 'Events', pTCut)

            if len(selectedDimuons) > 0:
                # follow the recipe to find the best 1 or 2 dimuons
                if len(selectedMuons) >= 3:
                    sortedDimuons = sorted(selectedDimuons,
                                           key=lambda dim: dim.normChi2)

                if len(selectedMuons) >= 4:
                    sortedMuons = sorted(selectedMuons,
                                         key=lambda mu: mu.pt,
                                         reverse=True)
                    highestPTMuons = sortedMuons[:4]
                    highestIndices = [mu.idx for mu in highestPTMuons]
                    HPDs = {
                        d.ID: d
                        for d in selectedDimuons if d.idx1 in highestIndices
                        and d.idx2 in highestIndices
                    }

                    # find all unique non-overlapping pairs of dimuons
                    pairings = []
                    dimuonList = HPDs.values()
                    for dim1 in dimuonList:
                        for dim2 in dimuonList:
                            if dim1.ID == dim2.ID: continue
                            muonIDs = set(dim1.ID + dim2.ID)
                            if len(muonIDs) == 4:
                                pairings.append((dim1, dim2))

                    def C2S(pairing):
                        return pairing[0].normChi2 + pairing[1].normChi2

                    def AMD(pairing):
                        return abs(pairing[0].mass - pairing[1].mass)

                    funcs = {'C2S': C2S, 'AMD': AMD}

                    # sort the pairings by a pairing criteria
                    if len(pairings) > 0:
                        candidateBestDimuons = {fkey: {} for fkey in funcs}
                        sortedPairings = {}
                        for fkey in funcs:
                            sortedPairings[fkey] = sorted(pairings,
                                                          key=funcs[fkey])
                            for d in sortedPairings[fkey][0]:
                                candidateBestDimuons[fkey][d.ID] = d

                        # try to use AMD for low Lxy
                        if ARGS.CUTS == '_AMD':
                            dims = candidateBestDimuons['AMD'].values()
                            if dims[0].Lxy() < 30. and dims[1].Lxy() < 30.:
                                bestDimuons = candidateBestDimuons['AMD']
                            else:
                                bestDimuons = candidateBestDimuons['C2S']
                        else:
                            bestDimuons = candidateBestDimuons['C2S']

                    # if there were NO pairings, there had to have been <=3 dimuons
                    # because any 4 dimuons can always make at least 1 pair
                    # this means 1 of the 4 muons formed no dimuons at all
                    # so treat this case like the 3 mu case
                    else:
                        sortedDimuons = sorted(selectedDimuons,
                                               key=lambda dim: dim.normChi2)
                        bestDimuons = {sortedDimuons[0].ID: sortedDimuons[0]}

                # do the signal matching
                if len(genMuonPairs) == 1:
                    genMuonPair = genMuonPairs[0]
                    dimuonMatches, muonMatches, exitcode = matchedDimuons(
                        genMuonPair, selectedDimuons)
                    if len(dimuonMatches) > 0:
                        realMatches = {0: dimuonMatches[0]}
                    else:
                        realMatches = {}
                else:
                    realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                        genMuonPairs, selectedDimuons)

                # loop over matches and fill if correct by some criteria
                for genPairIndex, dimuonMatches in realMatches.iteritems():
                    if len(dimuonMatches) > 0:
                        self.fillHist(nMuons, 'Matches', pTCut)
                        self.fillLxyHist(nMuons, 'Matches', pTCut,
                                         genMuonPairs[genPairIndex][0].Lxy())

                        # best matched dimuon
                        matchedDimuon = dimuonMatches['dim']

                        # if we have 2 muons, take the dimuon made from them
                        if len(selectedMuons) == 2:
                            # strictly speaking this if is not necessary because
                            # if there was a match, then with 2 muons it will be the only dimuon in the list
                            bestDimuon = selectedDimuons[0]
                            if matchedDimuon.ID == bestDimuon.ID:
                                self.fillHist(nMuons, 'Correct', pTCut)
                                self.fillLxyHist(
                                    nMuons, 'Correct', pTCut,
                                    genMuonPairs[genPairIndex][0].Lxy())

                        # if we have 3 muons, take the dimuon with the lowest chi^2/dof
                        elif len(selectedMuons) == 3:
                            bestDimuon = sortedDimuons[0]
                            if matchedDimuon.ID == bestDimuon.ID:
                                self.fillHist(nMuons, 'Correct', pTCut)
                                self.fillLxyHist(
                                    nMuons, 'Correct', pTCut,
                                    genMuonPairs[genPairIndex][0].Lxy())

                        # if we have 4+ muons, take the pair of dimuons with the lowest sum of chi^2/dof
                        elif len(selectedMuons) >= 4:
                            if matchedDimuon.ID in bestDimuons:
                                self.fillHist(nMuons, 'Correct', pTCut)
                                self.fillLxyHist(
                                    nMuons, 'Correct', pTCut,
                                    genMuonPairs[genPairIndex][0].Lxy())
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')

    if self.TRIGGER:
        if not Selections.passedTrigger(E): return

    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )

    Event = E.getPrimitives('EVENT')
    dimuons = E.getPrimitives('DIMUON')
    muons = E.getPrimitives('DSAMUON')

    baseMuons = [
        mu for mu in muons
        if mu.nDTStations + mu.nCSCStations > 1 and mu.nCSCHits +
        mu.nDTHits > 12 and mu.ptError / mu.pt < 1.
    ]
    baseOIndices = [mu.idx for mu in baseMuons]
    baseDimuons = [
        dim for dim in dimuons
        if dim.idx1 in baseOIndices and dim.idx2 in baseOIndices
    ]

    if len(baseDimuons) > 0:
        sortedMuons = sorted(baseMuons, key=lambda mu: mu.pt, reverse=True)
        bestTwo = (sortedMuons[0].idx, sortedMuons[1].idx)
        bestDimuon = None
        for dim in baseDimuons:
            if dim.idx1 in bestTwo and dim.idx2 in bestTwo:
                bestDimuon = dim
                break
        # Highest pT Dimuon (HPD) found
        if bestDimuon is not None:
            self.fillBoth('All', bestDimuon)

            # split HPD found into 3 pieces and 4 histograms:
            # - no matches (Hopeless)
            # - matches, and one of the matches is the HPD (Matched)
            # - matches, and none of the matches is the HPD (Wrong = HPD pT, Right = all matches' pT)
            dimuonMatches, muonMatches, exitcode = matchedDimuons(
                genMuonPairs[0], baseDimuons)
            if len(dimuonMatches) > 0:
                for match in dimuonMatches:
                    matchedDimuon = match['dim']
                    if matchedDimuon.idx1 == bestDimuon.idx1 and matchedDimuon.idx2 == bestDimuon.idx2:
                        self.fillBoth('Matched', bestDimuon)
                        break
                else:
                    self.fillBoth('Wrong', bestDimuon)
                    for match in dimuonMatches:
                        matchedDimuon = match['dim']
                        self.fillBoth('Right', matchedDimuon)
            else:
                self.fillBoth('Hopeless', bestDimuon)

        # HPD not found
        else:
            dimuonMatches, muonMatches, exitcode = matchedDimuons(
                genMuonPairs[0], baseDimuons)
            if len(dimuonMatches) > 0:
                for match in dimuonMatches:
                    matchedDimuon = match['dim']
                    self.fillBoth('Lost', matchedDimuon)
Exemple #23
0
def analyze(self, E, PARAMS=None):
    if self.TRIGGER and self.SP is not None:
        if not Selections.passedTrigger(E): return

    Event = E.getPrimitives('EVENT')

    # no Lxy sig
    CUTSTRING = '_Combined_NS_NH_FPTE_HLT_REP_PT_TRK_NDT_DCA_PC_LXYE_MASS_CHI2_VTX_COSA_NPP_OS'
    if 'DoubleMuon' in self.NAME:
        CUTSTRING += '_IDPHI'
    else:
        CUTSTRING += '_DPHI'

    DSAmuons = E.getPrimitives('DSAMUON')
    PATmuons = E.getPrimitives('PATMUON')
    Dimuons3 = E.getPrimitives('DIMUON')

    eventWeight = 1.
    try:
        eventWeight = 1. if Event.weight > 0. else -1.
    except:
        pass

    # gen stuff
    if self.SP is not None:
        if '4Mu' in self.NAME:
            mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives(
                'GEN')
            genMuons = (mu11, mu12, mu21, mu22)
            genMuonPairs = ((mu11, mu12), (mu21, mu22))
        elif '2Mu2J' in self.NAME:
            mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
            genMuons = (mu1, mu2)
            genMuonPairs = ((mu1, mu2), )

    # do the selection
    selectedDimuons, selectedDSAmuons, selectedPATmuons, DSADimuons = {}, {}, {}, {}
    for deltaR in DELTARS:
        # deltaR was a keyword here controlling the deltaR parameter, now 0.1 with PP
        selectedDimuons[deltaR], selectedDSAmuons[deltaR], selectedPATmuons[
            deltaR] = Selector.SelectObjects(E,
                                             CUTSTRING,
                                             Dimuons3,
                                             DSAmuons,
                                             PATmuons,
                                             deltaR=deltaR)
        if selectedDimuons[deltaR] is None:
            DSADimuons[deltaR] = []
            continue
        DSADimuons[deltaR] = [
            dim for dim in selectedDimuons[deltaR] if dim.composition == 'DSA'
        ]

    def getOriginalMuons(dim, DSAmuons):
        if dim.composition == 'PAT':
            return PATmuons[dim.idx1], PATmuons[dim.idx2]
        elif dim.composition == 'DSA':
            return DSAmuons[dim.idx1], DSAmuons[dim.idx2]
        else:
            return DSAmuons[dim.idx1], PATmuons[dim.idx2]

    def modifiedName(name):
        if 'DoubleMuon' in name:
            return 'Data' + name[17]
        if 'QCD' in name:
            return 'QCD'
        if 'HTo2X' in name:
            return '{:4d} {:3d} {:4d}'.format(*self.SP.SP)
        return name

    # meh
    for deltaR in DELTARS:

        # do the signal matching
        if self.SP is not None:
            if len(genMuonPairs) == 1:
                genMuonPair = genMuonPairs[0]
                dimuonMatches, muonMatches, exitcode = matchedDimuons(
                    genMuonPair, DSADimuons[deltaR])
                if len(dimuonMatches) > 0:
                    realMatches = {0: dimuonMatches[0]}
                else:
                    realMatches = {}
            else:
                realMatches, dimuonMatches, muon0Matches, muon1Matches = matchedDimuonPairs(
                    genMuonPairs, DSADimuons[deltaR])

            for pairIndex in realMatches:
                genMuon = genMuonPairs[pairIndex][0]
                self.HISTS['Lxy_{}'.format(DELTARS[deltaR]['tag'])].Fill(
                    genMuon.Lxy())

        else:
            self.COUNTS[deltaR] += len(DSADimuons[deltaR])
Exemple #24
0
def analyze(self, E, PARAMS=None):
    if self.SP is None:
        raise Exception('[ANALYZER ERROR]: This script runs on signal only.')
    if self.TRIGGER:
        if not Selections.passedTrigger(E): return
    if '4Mu' in self.NAME:
        mu11, mu12, mu21, mu22, X1, X2, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu11, mu12, mu21, mu22)
        genMuonPairs = ((mu11, mu12), (mu21, mu22))
    elif '2Mu2J' in self.NAME:
        mu1, mu2, j1, j2, X, XP, H, P, extramu = E.getPrimitives('GEN')
        genMuons = (mu1, mu2)
        genMuonPairs = ((mu1, mu2), )
    Event = E.getPrimitives('EVENT')
    DSAmuons = E.getPrimitives('DSAMUON')
    RSAmuons = E.getPrimitives('RSAMUON')
    Dimuons = E.getPrimitives('DIMUON')

    ALL = True if 'All' in self.CUTS else False
    # require dimuons and muons to pass all selections
    if ALL:
        DSASelections = [Selections.MuonSelection(muon) for muon in DSAmuons]
        RSASelections = [Selections.MuonSelection(muon) for muon in RSAmuons]
        DimuonSelections = [
            Selections.DimuonSelection(dimuon) for dimuon in Dimuons
        ]

        selectedDSAmuons = [
            mu for idx, mu in enumerate(DSAmuons) if DSASelections[idx]
        ]
        selectedRSAmuons = [
            mu for idx, mu in enumerate(RSAmuons) if RSASelections[idx]
        ]
        selectedDimuons = [
            dim for idx, dim in enumerate(Dimuons) if DimuonSelections[idx]
            and DSASelections[dim.idx1] and DSASelections[dim.idx2]
        ]

    # don't require dimuons and muons to pass all selections
    else:
        selectedDSAmuons = DSAmuons
        selectedRSAmuons = RSAmuons
        selectedDimuons = Dimuons

    for genMuonPair in genMuonPairs:
        # no acceptance selection for now
        # genMuonSelection = Selections.AcceptanceSelection(genMuonPair)
        # if not genMuonSelection: continue

        # genMuonMatches are a dictionary of the return tuple of length 3
        # DSA and RSA get a doDimuons=False argument so that no dimuon matching will be done
        genMuonMatches = {'DSA': None, 'RSA': None, 'REF': None}
        for MUON, recoMuons in zip(SHORTRECOMUONLIST,
                                   (selectedDSAmuons, selectedRSAmuons)):
            genMuonMatches[MUON] = matchedDimuons(genMuonPair,
                                                  selectedDimuons,
                                                  recoMuons,
                                                  vertex='BS',
                                                  doDimuons=False)
        for MUON in REFMUONLIST:
            genMuonMatches[MUON] = matchedDimuons(genMuonPair, selectedDimuons)

        # now figure out the closest match, or None if they overlap
        # exitcode helps to make sure that both gen muons never match the same reco muon
        genMuonMatch = [{MUON: None
                         for MUON in FULLMUONLIST},
                        {MUON: None
                         for MUON in FULLMUONLIST}]
        for MUON in SHORTRECOMUONLIST:
            dimuonMatches, muonMatches, exitcode = genMuonMatches[MUON]
            genMuonMatch[0][MUON], genMuonMatch[1][
                MUON] = exitcode.getBestGenMuonMatches(muonMatches)

        fillDSADim = False

        # matched refitted muons if there was at least one dimuon
        for MUON in REFMUONLIST:
            dimuonMatches, muonMatches, exitcode = genMuonMatches['REF']
            if len(dimuonMatches) > 0:
                genMuonMatch[0]['REF'] = muonMatches[0][0]
                genMuonMatch[1]['REF'] = muonMatches[1][0]

                # when there's a dimuon match, pick out the original DSA muons
                # muonMatches[whichGenMuon][0=closest] is a dictionary with oidx as a field
                # This is the position in DSAmuons (NOT selectedDSAmuons!), so we can get the original DSA muon from that
                fillDSADim = True
                genMuonMatch[0]['DSADim'] = {
                    'muon': DSAmuons[muonMatches[0][0]['oidx']]
                }
                genMuonMatch[1]['DSADim'] = {
                    'muon': DSAmuons[muonMatches[1][0]['oidx']]
                }

        # loop over muon types, over quantities, compute the quantities, fill
        for MUON in FULLMUONLIST:
            # DSADim is only filled when REF is
            if MUON == 'DSADim' and not fillDSADim: continue
            for Q in QUANTITIES:
                if Q == 'qm': continue
                if Q == 'Lxy' and MUON in RECOMUONLIST: continue

                # gen, reco, and res functions
                GF = QUANTITIES[Q]['GENLAMBDA']
                RF = QUANTITIES[Q]['RECOLAMBDA']
                RESF = QUANTITIES[Q]['RESLAMBDA']

                # gen, reco, res, and gen2 quantities
                # if the code below succeeds, these should all be lists of length 2
                # corresponding to g0 and g1 exactly
                # gq2[0] will additionally be a dictionary storing the q2 values
                GQ = []
                RQ = []
                RESQ = []
                GQ2 = [{}, {}]

                # loop over gen muons individually
                # if there was a match
                # if this is a muon quantity use the closest muon
                # if this is a dimuon quantity (e.g. Lxy) use the dimuon
                # compute the gen, reco, and res quantities
                # loop over Q2, get the function, apply it
                # if Q2 is QM, need recoMuon to be passed to it
                for which, genMuon in enumerate(genMuonPair):
                    # in case we decide later that Lxy should only be filled once
                    # make sure the logic for QM below this loop is changed as well
                    # if Q == 'Lxy' and which == 1: continue

                    # handle gen pT and eta quantity in a somewhat unnatural way
                    if Q in ('pT', 'eta') and MUON in RECOMUONLIST:
                        genObj = genMuon.BS
                    else:
                        genObj = genMuon

                    if genMuonMatch[which][MUON] is not None:
                        # 'dim' does not exist for DSADim, but this shouldn't matter
                        # because Lxy is skipped for DSADim anyway
                        if Q == 'Lxy':
                            recoObj = genMuonMatches[MUON][0][0]['dim']
                            recoMuon = genMuonMatch[which][MUON]['muon']
                        else:
                            recoObj = genMuonMatch[which][MUON]['muon']
                            recoMuon = genMuonMatch[which][MUON]['muon']
                        GQ.append(GF(genObj))
                        RQ.append(RF(recoObj))
                        # in a few pathological cases, REF matches to genSV, but
                        # when we try to compute the res for the corresponding DSA wrt genBS
                        # the genBS quantity is 0. Set the res to inf in these cases.
                        try:
                            RESQ.append(RESF(RF(recoObj), GF(genObj)))
                        except:
                            print 'Haha {} {} {} in {} {} {} {}, you\'re not crashing me! {} = inf'.format(
                                Event.run, Event.lumi, Event.event,
                                '4Mu' if '4Mu' in self.NAME else '2Mu2J',
                                self.SP.mH, self.SP.mX, self.SP.cTau,
                                GF(genObj))
                            RESQ.append(float('inf'))
                        for Q2 in Q2LIST:
                            G2F = QUANTITIES[Q2]['GENLAMBDA']
                            if Q2 != 'qm':
                                # again, handle gen pT and eta quantity in a somewhat unnatural way
                                if Q2 in ('pT',
                                          'eta') and MUON in RECOMUONLIST:
                                    GQ2[which][Q2] = G2F(genMuon.BS)
                                else:
                                    GQ2[which][Q2] = G2F(genMuon)
                            else:
                                GQ2[which][Q2] = G2F(recoMuon, genMuon)
                    else:
                        GQ.append(None)
                        RQ.append(None)
                        RESQ.append(None)
                        for Q2 in Q2LIST:
                            GQ2[which][Q2] = None

                # for QM, define for Lxy as the && of the two. This will result in either True, False, or None
                if Q == 'Lxy':
                    realChargeMatchBool = GQ2[0]['qm'] and GQ2[1]['qm']
                    GQ2[0]['qm'], GQ2[1][
                        'qm'] = realChargeMatchBool, realChargeMatchBool

                # now all the quantities are computed (or are None). this loop of is length 2, one for each gen muon
                for which, (gq, rq, resq,
                            gq2) in enumerate(zip(GQ, RQ, RESQ, GQ2)):
                    if True:
                        if resq is not None:
                            self.HISTS['{M}_{Q}Res'.format(M=MUON,
                                                           Q=Q)].Fill(resq)
                        if gq is not None and rq is not None:
                            self.HISTS['{M}_{Q}VS{Q}'.format(M=MUON,
                                                             Q=Q)].Fill(
                                                                 gq, rq)
                    for Q2 in gq2:
                        gq2val = gq2[Q2]
                        if gq2val is not None:
                            self.HISTS['{M}_{Q}ResVS{Q2}'.format(M=MUON,
                                                                 Q=Q,
                                                                 Q2=Q2)].Fill(
                                                                     gq2val,
                                                                     resq)