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()) ])
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)
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]))
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
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
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
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)
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)
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)
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])
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)