def process_shift(self, events, shift_name): dataset = events.metadata['dataset'] isRealData = not hasattr(events, "genWeight") selection = PackedSelection() weights = Weights(len(events), storeIndividual=True) output = self.make_output() if shift_name is None and not isRealData: output['sumw'] = ak.sum(events.genWeight) if isRealData or self._newTrigger: trigger = np.zeros(len(events), dtype='bool') for t in self._triggers[self._year]: if t in events.HLT.fields: trigger = trigger | events.HLT[t] selection.add('trigger', trigger) del trigger else: selection.add('trigger', np.ones(len(events), dtype='bool')) if isRealData: selection.add( 'lumimask', lumiMasks[self._year](events.run, events.luminosityBlock)) else: selection.add('lumimask', np.ones(len(events), dtype='bool')) if isRealData and self._skipRunB and self._year == '2017': selection.add('dropB', events.run > 299329) else: selection.add('dropB', np.ones(len(events), dtype='bool')) if isRealData: trigger = np.zeros(len(events), dtype='bool') for t in self._muontriggers[self._year]: if t in events.HLT.fields: trigger |= np.array(events.HLT[t]) selection.add('muontrigger', trigger) del trigger else: selection.add('muontrigger', np.ones(len(events), dtype='bool')) metfilter = np.ones(len(events), dtype='bool') for flag in self._met_filters[ self._year]['data' if isRealData else 'mc']: metfilter &= np.array(events.Flag[flag]) selection.add('metfilter', metfilter) del metfilter fatjets = events.FatJet fatjets['msdcorr'] = corrected_msoftdrop(fatjets) fatjets['qcdrho'] = 2 * np.log(fatjets.msdcorr / fatjets.pt) fatjets['n2ddt'] = fatjets.n2b1 - n2ddt_shift(fatjets, year=self._year) fatjets['msdcorr_full'] = fatjets['msdcorr'] * self._msdSF[self._year] candidatejet = fatjets[ # https://github.com/DAZSLE/BaconAnalyzer/blob/master/Analyzer/src/VJetLoader.cc#L269 (fatjets.pt > 200) & (abs(fatjets.eta) < 2.5) & fatjets.isTight # this is loose in sampleContainer ] candidatejet = candidatejet[:, : 2] # Only consider first two to match generators if self._jet_arbitration == 'pt': candidatejet = ak.firsts(candidatejet) elif self._jet_arbitration == 'mass': candidatejet = ak.firsts(candidatejet[ak.argmax( candidatejet.msdcorr, axis=1, keepdims=True)]) elif self._jet_arbitration == 'n2': candidatejet = ak.firsts(candidatejet[ak.argmin(candidatejet.n2ddt, axis=1, keepdims=True)]) elif self._jet_arbitration == 'ddb': candidatejet = ak.firsts(candidatejet[ak.argmax( candidatejet.btagDDBvLV2, axis=1, keepdims=True)]) elif self._jet_arbitration == 'ddc': candidatejet = ak.firsts(candidatejet[ak.argmax( candidatejet.btagDDCvLV2, axis=1, keepdims=True)]) else: raise RuntimeError("Unknown candidate jet arbitration") if self._tagger == 'v1': bvl = candidatejet.btagDDBvL cvl = candidatejet.btagDDCvL cvb = candidatejet.btagDDCvB elif self._tagger == 'v2': bvl = candidatejet.btagDDBvLV2 cvl = candidatejet.btagDDCvLV2 cvb = candidatejet.btagDDCvBV2 elif self._tagger == 'v3': bvl = candidatejet.particleNetMD_Xbb cvl = candidatejet.particleNetMD_Xcc / ( 1 - candidatejet.particleNetMD_Xbb) cvb = candidatejet.particleNetMD_Xcc / ( candidatejet.particleNetMD_Xcc + candidatejet.particleNetMD_Xbb) elif self._tagger == 'v4': bvl = candidatejet.particleNetMD_Xbb cvl = candidatejet.btagDDCvLV2 cvb = candidatejet.particleNetMD_Xcc / ( candidatejet.particleNetMD_Xcc + candidatejet.particleNetMD_Xbb) else: raise ValueError("Not an option") selection.add('minjetkin', (candidatejet.pt >= 450) & (candidatejet.pt < 1200) & (candidatejet.msdcorr >= 40.) & (candidatejet.msdcorr < 201.) & (abs(candidatejet.eta) < 2.5)) selection.add('_strict_mass', (candidatejet.msdcorr > 85) & (candidatejet.msdcorr < 130)) selection.add('_high_score', cvl > 0.8) selection.add('minjetkinmu', (candidatejet.pt >= 400) & (candidatejet.pt < 1200) & (candidatejet.msdcorr >= 40.) & (candidatejet.msdcorr < 201.) & (abs(candidatejet.eta) < 2.5)) selection.add('minjetkinw', (candidatejet.pt >= 200) & (candidatejet.pt < 1200) & (candidatejet.msdcorr >= 40.) & (candidatejet.msdcorr < 201.) & (abs(candidatejet.eta) < 2.5)) selection.add('jetid', candidatejet.isTight) selection.add('n2ddt', (candidatejet.n2ddt < 0.)) if not self._tagger == 'v2': selection.add('ddbpass', (bvl >= 0.89)) selection.add('ddcpass', (cvl >= 0.83)) selection.add('ddcvbpass', (cvb >= 0.2)) else: selection.add('ddbpass', (bvl >= 0.7)) selection.add('ddcpass', (cvl >= 0.45)) selection.add('ddcvbpass', (cvb >= 0.03)) jets = events.Jet jets = jets[(jets.pt > 30.) & (abs(jets.eta) < 2.5) & jets.isTight] # only consider first 4 jets to be consistent with old framework jets = jets[:, :4] dphi = abs(jets.delta_phi(candidatejet)) selection.add( 'antiak4btagMediumOppHem', ak.max(jets[dphi > np.pi / 2][self._ak4tagBranch], axis=1, mask_identity=False) < BTagEfficiency.btagWPs[self._ak4tagger][self._year]['medium']) ak4_away = jets[dphi > 0.8] selection.add( 'ak4btagMedium08', ak.max(ak4_away[self._ak4tagBranch], axis=1, mask_identity=False) > BTagEfficiency.btagWPs[self._ak4tagger][self._year]['medium']) met = events.MET selection.add('met', met.pt < 140.) goodmuon = ((events.Muon.pt > 10) & (abs(events.Muon.eta) < 2.4) & (events.Muon.pfRelIso04_all < 0.25) & events.Muon.looseId) nmuons = ak.sum(goodmuon, axis=1) leadingmuon = ak.firsts(events.Muon[goodmuon]) if self._looseTau: goodelectron = ((events.Electron.pt > 10) & (abs(events.Electron.eta) < 2.5) & (events.Electron.cutBased >= events.Electron.VETO)) nelectrons = ak.sum(goodelectron, axis=1) ntaus = ak.sum( ((events.Tau.pt > 20) & (abs(events.Tau.eta) < 2.3) & events.Tau.idDecayMode & ((events.Tau.idMVAoldDM2017v2 & 2) != 0) & ak.all(events.Tau.metric_table(events.Muon[goodmuon]) > 0.4, axis=2) & ak.all(events.Tau.metric_table( events.Electron[goodelectron]) > 0.4, axis=2)), axis=1, ) else: goodelectron = ( (events.Electron.pt > 10) & (abs(events.Electron.eta) < 2.5) & (events.Electron.cutBased >= events.Electron.LOOSE)) nelectrons = ak.sum(goodelectron, axis=1) ntaus = ak.sum( (events.Tau.pt > 20) & events.Tau.idDecayMode # bacon iso looser than Nano selection & ak.all(events.Tau.metric_table(events.Muon[goodmuon]) > 0.4, axis=2) & ak.all(events.Tau.metric_table(events.Electron[goodelectron]) > 0.4, axis=2), axis=1, ) selection.add('noleptons', (nmuons == 0) & (nelectrons == 0) & (ntaus == 0)) selection.add('onemuon', (nmuons == 1) & (nelectrons == 0) & (ntaus == 0)) selection.add('muonkin', (leadingmuon.pt > 55.) & (abs(leadingmuon.eta) < 2.1)) selection.add('muonDphiAK8', abs(leadingmuon.delta_phi(candidatejet)) > 2 * np.pi / 3) # W-Tag (Tag and Probe) # tag side selection.add( 'ak4btagMediumOppHem', ak.max(jets[dphi > np.pi / 2][self._ak4tagBranch], axis=1, mask_identity=False) > BTagEfficiency.btagWPs[self._ak4tagger][self._year]['medium']) selection.add('met40p', met.pt > 40.) selection.add('tightMuon', (leadingmuon.tightId) & (leadingmuon.pt > 53.)) # selection.add('ptrecoW', (leadingmuon + met).pt > 250.) selection.add('ptrecoW200', (leadingmuon + met).pt > 200.) selection.add( 'ak4btagNearMu', leadingmuon.delta_r(leadingmuon.nearest(ak4_away, axis=None)) < 2.0) _bjets = jets[self._ak4tagBranch] > BTagEfficiency.btagWPs[ self._ak4tagger][self._year]['medium'] # _nearAK8 = jets.delta_r(candidatejet) < 0.8 # _nearMu = jets.delta_r(ak.firsts(events.Muon)) < 0.3 # selection.add('ak4btagOld', ak.sum(_bjets & ~_nearAK8 & ~_nearMu, axis=1) >= 1) _nearAK8 = jets.delta_r(candidatejet) < 0.8 _nearMu = jets.delta_r(leadingmuon) < 0.3 selection.add('ak4btagOld', ak.sum(_bjets & ~_nearAK8 & ~_nearMu, axis=1) >= 1) # _nearAK8 = jets.delta_r(candidatejet) < 0.8 # _nearMu = jets.delta_r(candidatejet.nearest(events.Muon[goodmuon], axis=None)) < 0.3 # selection.add('ak4btagNew', ak.sum(_bjets & ~_nearAK8 & ~_nearMu, axis=1) >= 1) # probe side selection.add('minWjetpteta', (candidatejet.pt >= 200) & (abs(candidatejet.eta) < 2.4)) # selection.add('noNearMuon', candidatejet.delta_r(candidatejet.nearest(events.Muon[goodmuon], axis=None)) > 1.0) selection.add('noNearMuon', candidatejet.delta_r(leadingmuon) > 1.0) ##### if isRealData: genflavor = ak.zeros_like(candidatejet.pt) else: if 'HToCC' in dataset or 'HToBB' in dataset: if self._ewkHcorr: add_HiggsEW_kFactors(weights, events.GenPart, dataset) weights.add('genweight', events.genWeight) if "PSWeight" in events.fields: add_ps_weight(weights, events.PSWeight) else: add_ps_weight(weights, None) if "LHEPdfWeight" in events.fields: add_pdf_weight(weights, events.LHEPdfWeight) else: add_pdf_weight(weights, None) if "LHEScaleWeight" in events.fields: add_scalevar_7pt(weights, events.LHEScaleWeight) add_scalevar_3pt(weights, events.LHEScaleWeight) else: add_scalevar_7pt(weights, []) add_scalevar_3pt(weights, []) add_pileup_weight(weights, events.Pileup.nPU, self._year, dataset) bosons = getBosons(events.GenPart) matchedBoson = candidatejet.nearest(bosons, axis=None, threshold=0.8) if self._tightMatch: match_mask = ( (candidatejet.pt - matchedBoson.pt) / matchedBoson.pt < 0.5) & ((candidatejet.msdcorr - matchedBoson.mass) / matchedBoson.mass < 0.3) selmatchedBoson = ak.mask(matchedBoson, match_mask) genflavor = bosonFlavor(selmatchedBoson) else: genflavor = bosonFlavor(matchedBoson) genBosonPt = ak.fill_none(ak.firsts(bosons.pt), 0) if self._newVjetsKfactor: add_VJets_kFactors(weights, events.GenPart, dataset) else: add_VJets_NLOkFactor(weights, genBosonPt, self._year, dataset) if shift_name is None: output['btagWeight'].fill(val=self._btagSF.addBtagWeight( weights, ak4_away, self._ak4tagBranch)) if self._nnlops_rew and dataset in [ 'GluGluHToCC_M125_13TeV_powheg_pythia8' ]: weights.add('minlo_rew', powheg_to_nnlops(ak.to_numpy(genBosonPt))) if self._newTrigger: add_jetTriggerSF( weights, ak.firsts(fatjets), self._year if not self._skipRunB else f'{self._year}CDEF', selection) else: add_jetTriggerWeight(weights, candidatejet.msdcorr, candidatejet.pt, self._year) add_mutriggerSF(weights, leadingmuon, self._year, selection) add_mucorrectionsSF(weights, leadingmuon, self._year, selection) if self._year in ("2016", "2017"): weights.add("L1Prefiring", events.L1PreFiringWeight.Nom, events.L1PreFiringWeight.Up, events.L1PreFiringWeight.Dn) logger.debug("Weight statistics: %r" % weights.weightStatistics) msd_matched = candidatejet.msdcorr * self._msdSF[self._year] * ( genflavor > 0) + candidatejet.msdcorr * (genflavor == 0) regions = { 'signal': [ 'noleptons', 'minjetkin', 'met', 'metfilter', 'jetid', 'antiak4btagMediumOppHem', 'n2ddt', 'trigger', 'lumimask' ], 'signal_noddt': [ 'noleptons', 'minjetkin', 'met', 'jetid', 'antiak4btagMediumOppHem', 'trigger', 'lumimask', 'metfilter' ], # 'muoncontrol': ['minjetkinmu', 'jetid', 'n2ddt', 'ak4btagMedium08', 'onemuon', 'muonkin', 'muonDphiAK8', 'muontrigger', 'lumimask', 'metfilter'], 'muoncontrol': [ 'onemuon', 'muonkin', 'muonDphiAK8', 'metfilter', 'minjetkinmu', 'jetid', 'ak4btagMedium08', 'n2ddt', 'muontrigger', 'lumimask' ], 'muoncontrol_noddt': [ 'onemuon', 'muonkin', 'muonDphiAK8', 'jetid', 'metfilter', 'minjetkinmu', 'jetid', 'ak4btagMedium08', 'muontrigger', 'lumimask' ], 'wtag': [ 'onemuon', 'tightMuon', 'minjetkinw', 'jetid', 'met40p', 'metfilter', 'ptrecoW200', 'ak4btagOld', 'muontrigger', 'lumimask' ], 'wtag0': [ 'onemuon', 'tightMuon', 'met40p', 'metfilter', 'ptrecoW200', 'ak4btagOld', 'muontrigger', 'lumimask' ], 'wtag2': [ 'onemuon', 'tightMuon', 'minjetkinw', 'jetid', 'ak4btagMediumOppHem', 'met40p', 'metfilter', 'ptrecoW200', 'ak4btagOld', 'muontrigger', 'lumimask' ], 'noselection': [], } def normalize(val, cut): if cut is None: ar = ak.to_numpy(ak.fill_none(val, np.nan)) return ar else: ar = ak.to_numpy(ak.fill_none(val[cut], np.nan)) return ar import time tic = time.time() if shift_name is None: for region, cuts in regions.items(): allcuts = set([]) cut = selection.all(*allcuts) output['cutflow_msd'].fill(region=region, genflavor=normalize( genflavor, None), cut=0, weight=weights.weight(), msd=normalize(msd_matched, None)) output['cutflow_eta'].fill(region=region, genflavor=normalize(genflavor, cut), cut=0, weight=weights.weight()[cut], eta=normalize( candidatejet.eta, cut)) output['cutflow_pt'].fill(region=region, genflavor=normalize(genflavor, cut), cut=0, weight=weights.weight()[cut], pt=normalize(candidatejet.pt, cut)) for i, cut in enumerate(cuts + ['ddcvbpass', 'ddcpass']): allcuts.add(cut) cut = selection.all(*allcuts) output['cutflow_msd'].fill(region=region, genflavor=normalize( genflavor, cut), cut=i + 1, weight=weights.weight()[cut], msd=normalize(msd_matched, cut)) output['cutflow_eta'].fill( region=region, genflavor=normalize(genflavor, cut), cut=i + 1, weight=weights.weight()[cut], eta=normalize(candidatejet.eta, cut)) output['cutflow_pt'].fill( region=region, genflavor=normalize(genflavor, cut), cut=i + 1, weight=weights.weight()[cut], pt=normalize(candidatejet.pt, cut)) if self._evtVizInfo and 'ddcpass' in allcuts and isRealData and region == 'signal': if 'event' not in events.fields: continue _cut = selection.all(*allcuts, '_strict_mass', '_high_score') # _cut = selection.all('_strict_mass'') output['to_check'][ 'mass'] += processor.column_accumulator( normalize(msd_matched, _cut)) nfatjet = ak.sum( ((fatjets.pt > 200) & (abs(fatjets.eta) < 2.5) & fatjets.isTight), axis=1) output['to_check'][ 'njet'] += processor.column_accumulator( normalize(nfatjet, _cut)) output['to_check'][ 'fname'] += processor.column_accumulator( np.array([events.metadata['filename']] * len(normalize(msd_matched, _cut)))) output['to_check'][ 'event'] += processor.column_accumulator( normalize(events.event, _cut)) output['to_check'][ 'luminosityBlock'] += processor.column_accumulator( normalize(events.luminosityBlock, _cut)) output['to_check'][ 'run'] += processor.column_accumulator( normalize(events.run, _cut)) if shift_name is None: systematics = [None] + list(weights.variations) else: systematics = [shift_name] def fill(region, systematic, wmod=None): selections = regions[region] cut = selection.all(*selections) sname = 'nominal' if systematic is None else systematic if wmod is None: if systematic in weights.variations: weight = weights.weight(modifier=systematic)[cut] else: weight = weights.weight()[cut] else: weight = weights.weight()[cut] * wmod[cut] output['templates'].fill( region=region, systematic=sname, runid=runmap(events.run)[cut], genflavor=normalize(genflavor, cut), pt=normalize(candidatejet.pt, cut), msd=normalize(msd_matched, cut), ddb=normalize(bvl, cut), ddc=normalize(cvl, cut), ddcvb=normalize(cvb, cut), weight=weight, ) if region in [ 'wtag', 'wtag0', 'wtag2', 'wtag3', 'wtag4', 'wtag5', 'wtag6', 'wtag7', 'noselection' ]: # and sname in ['nominal', 'pileup_weightDown', 'pileup_weightUp', 'jet_triggerDown', 'jet_triggerUp']: output['wtag'].fill( region=region, systematic=sname, genflavor=normalize(genflavor, cut), pt=normalize(candidatejet.pt, cut), msd=normalize(msd_matched, cut), n2ddt=normalize(candidatejet.n2ddt, cut), ddc=normalize(cvl, cut), ddcvb=normalize(cvb, cut), weight=weight, ) # if region in ['signal', 'noselection']: # output['etaphi'].fill( # region=region, # systematic=sname, # runid=runmap(events.run)[cut], # genflavor=normalize(genflavor, cut), # pt=normalize(candidatejet.pt, cut), # eta=normalize(candidatejet.eta, cut), # phi=normalize(candidatejet.phi, cut), # ddc=normalize(cvl, cut), # ddcvb=normalize(cvb, cut), # ), if not isRealData: if wmod is not None: _custom_weight = events.genWeight[cut] * wmod[cut] else: _custom_weight = np.ones_like(weight) output['genresponse_noweight'].fill( region=region, systematic=sname, pt=normalize(candidatejet.pt, cut), genpt=normalize(genBosonPt, cut), weight=_custom_weight, ) output['genresponse'].fill( region=region, systematic=sname, pt=normalize(candidatejet.pt, cut), genpt=normalize(genBosonPt, cut), weight=weight, ) if systematic is None: output['signal_opt'].fill( region=region, genflavor=normalize(genflavor, cut), ddc=normalize(cvl, cut), ddcvb=normalize(cvb, cut), msd=normalize(msd_matched, cut), weight=weight, ) output['signal_optb'].fill( region=region, genflavor=normalize(genflavor, cut), ddb=normalize(bvl, cut), msd=normalize(msd_matched, cut), weight=weight, ) for region in regions: cut = selection.all(*(set(regions[region]) - {'n2ddt'})) if shift_name is None: output['nminus1_n2ddt'].fill( region=region, n2ddt=normalize(candidatejet.n2ddt, cut), weight=weights.weight()[cut], ) for systematic in systematics: if isRealData and systematic is not None: continue fill(region, systematic) if shift_name is None and 'GluGluH' in dataset and 'LHEWeight' in events.fields: for i in range(9): fill(region, 'LHEScale_%d' % i, events.LHEScaleWeight[:, i]) for c in events.LHEWeight.fields[1:]: fill(region, 'LHEWeight_%s' % c, events.LHEWeight[c]) toc = time.time() output["filltime"] = toc - tic if shift_name is None: output["weightStats"] = weights.weightStatistics return {dataset: output}
def process(self, events): # get meta infos dataset = events.metadata["dataset"] isRealData = not hasattr(events, "genWeight") n_events = len(events) selection = processor.PackedSelection() weights = processor.Weights(n_events) output = self.accumulator.identity() # weights if not isRealData: output['sumw'][dataset] += awkward1.sum(events.genWeight) # trigger triggers = {} for channel in ["e","mu"]: trigger = np.zeros(len(events), dtype='bool') for t in self._trigger[channel]: try: trigger = trigger | events.HLT[t] except: warnings.warn("Missing trigger %s" % t, RuntimeWarning) triggers[channel] = trigger # met filter met_filters = ["goodVertices", "globalSuperTightHalo2016Filter", "HBHENoiseFilter", "HBHENoiseIsoFilter", "EcalDeadCellTriggerPrimitiveFilter", "BadPFMuonFilter", ] met_filters_mask = np.ones(len(events), dtype='bool') for t in met_filters: met_filters_mask = met_filters_mask & events.Flag[t] selection.add("met_filter", awkward1.to_numpy(met_filters_mask)) # load objects muons = events.Muon electrons = events.Electron jets = events.Jet fatjets = events.FatJet subjets = events.SubJet fatjetsLS = events.FatJetLS met = events.MET # muons goodmuon = ( (muons.mediumId) & (muons.miniPFRelIso_all <= 0.2) & (muons.pt >= 27) & (abs(muons.eta) <= 2.4) & (abs(muons.dz) < 0.1) & (abs(muons.dxy) < 0.05) & (muons.sip3d < 4) ) good_muons = muons[goodmuon] ngood_muons = awkward1.sum(goodmuon, axis=1) # electrons goodelectron = ( (electrons.mvaFall17V2noIso_WP90) & (electrons.pt >= 30) & (abs(electrons.eta) <= 1.479) & (abs(electrons.dz) < 0.1) & (abs(electrons.dxy) < 0.05) & (electrons.sip3d < 4) ) good_electrons = electrons[goodelectron] ngood_electrons = awkward1.sum(goodelectron, axis=1) # good leptons good_leptons = awkward1.concatenate([good_muons, good_electrons], axis=1) good_leptons = good_leptons[awkward1.argsort(good_leptons.pt)] # lepton candidate candidatelep = awkward1.firsts(good_leptons) # lepton channel selection selection.add("ch_e", awkward1.to_numpy((triggers["e"]) & (ngood_electrons==1) & (ngood_muons==0))) # not sure if need to require 0 muons or 0 electrons in the next line selection.add("ch_mu", awkward1.to_numpy((triggers["mu"]) & (ngood_electrons==0) & (ngood_muons==1))) # jets ht = awkward1.sum(jets[jets.pt > 30].pt,axis=1) selection.add("ht_400", awkward1.to_numpy(ht>=400)) goodjet = ( (jets.isTight) & (jets.pt > 30) & (abs(jets.eta) <= 2.5) ) good_jets = jets[goodjet] # fat jets jID = "isTight" # TODO: add mass correction # a way to get the first two subjets # cart = awkward1.cartesian([fatjets, subjets], nested=True) # idxes = awkward1.pad_none(awkward1.argsort(cart['0'].delta_r(cart['1'])), 2, axis=2) # sj1 = subjets[idxes[:,:,0]] # sj2 = subjets[idxes[:,:,1]] good_fatjet = ( (getattr(fatjets, jID)) & (abs(fatjets.eta) <= 2.4) & (fatjets.pt > 50) & (fatjets.msoftdrop > 30) & (fatjets.msoftdrop < 210) #& (fatjets.pt.copy(content=fatjets.subjets.content.counts) == 2) # TODO: require 2 subjets? # this can probably be done w FatJet_subJetIdx1 or FatJet_subJetIdx2 & (awkward1.all(fatjets.subjets.pt >= 20)) & (awkward1.all(abs(fatjets.subjets.eta) <= 2.4)) ) good_fatjets = fatjets[good_fatjet] # hbb candidate mask_hbb = ( (good_fatjets.pt > 200) & (good_fatjets.delta_r(candidatelep) > 2.0) ) candidateHbb = awkward1.firsts(good_fatjets[mask_hbb]) # b-tag #& (good_fatjets.particleNetMD_Xbb > 0.9) selection.add('hbb_btag',awkward1.to_numpy(candidateHbb.deepTagMD_ZHbbvsQCD >= 0.8)) # score would be larger for tight category (0.97) # No AK4 b-tagged jets away from bb jet jets_HbbV = jets[good_jets.delta_r(candidateHbb) >= 1.2] selection.add('hbb_vetobtagaway', awkward1.to_numpy(awkward1.max(jets_HbbV.btagDeepB, axis=1, mask_identity=False) > BTagEfficiency.btagWPs[self._year]['medium'])) # fat jets Lepton Subtracted # wjj candidate mask_wjj = ( (fatjetsLS.pt > 50) & (fatjetsLS.delta_r(candidatelep) > 1.2) # need to add 2 subjets w pt > 20 & eta<2.4 # need to add ID? ) candidateWjj = awkward1.firsts(fatjetsLS[mask_wjj][awkward1.argmin(fatjetsLS[mask_wjj].delta_r(candidatelep),axis=1,keepdims=True)]) # add t2/t1 <= 0.75 (0.45 HP) selection.add('hww_mass', awkward1.to_numpy(candidateWjj.mass >= 10)) print('met ',met) # wjjlnu info #HSolverLiInfo hwwInfoLi; # qqSDmass = candidateWjj.msoftdrop # hwwLi = hSolverLi->minimize(candidatelep.p4(), met.p4(), wjjcand.p4(), qqSDmass, hwwInfoLi) #neutrino = hwwInfoLi.neutrino; #wlnu = hwwInfoLi.wlnu; #wqq = hwwInfoLi.wqqjet; #hWW = hwwInfoLi.hWW; #wwDM = PhysicsUtilities::deltaR( wlnu,wqq) * hWW.pt()/2.0; # add dlvqq <= 11 (2.5 HP) # in the meantime let's add the mass ''' mm = (candidatejet - candidatelep).mass2 jmass = (mm>0)*np.sqrt(np.maximum(0, mm)) + (mm<0)*candidatejet.mass joffshell = jmass < 62.5 massassumption = 80.*joffshell + (125 - 80.)*~joffshell x = massassumption**2/(2*candidatelep.pt*met.pt) + np.cos(candidatelep.phi - met.phi) met_eta = ( (x < 1)*np.arcsinh(x*np.sinh(candidatelep.eta)) + (x > 1)*( candidatelep.eta - np.sign(candidatelep.eta)*np.arccosh(candidatelep.eta) ) ) met_p4 = TLorentzVectorArray.from_ptetaphim(np.array([0.]),np.array([0.]),np.array([0.]),np.array([0.])) if met.size > 0: met_p4 = TLorentzVectorArray.from_ptetaphim(met.pt, met_eta.fillna(0.), met.phi, np.zeros(met.size)) # hh system candidateHH = candidateWjj + met_p4 + candidateHbb selection.add('hh_mass', candidateHH.mass >= 700) selection.add('hh_centrality', candidateHH.pt/candidateHH.mass >= 0.3) ''' channels = {"e": ["met_filter","ch_e","ht_400","hbb_btag","hbb_vetobtagaway","hww_mass"], #,"hh_mass","hh_centrality"], "mu": ["met_filter","ch_mu","ht_400","hbb_btag","hbb_vetobtagaway","hww_mass"] #,"hh_mass","hh_centrality"], } # need to add gen info if not isRealData: weights.add('genweight', events.genWeight) add_pileup_weight(weights, events.Pileup.nPU, self._year, dataset) for channel, cuts in channels.items(): allcuts = set() output['cutflow'].fill(dataset=dataset, channel=channel, cut=0, weight=weights.weight()) for i, cut in enumerate(cuts): allcuts.add(cut) cut = selection.all(*allcuts) output['cutflow'].fill(dataset=dataset, channel=channel, cut=i + 1, weight=weights.weight()[cut]) return output
def process(self, events): dataset = events.metadata['dataset'] print('process dataset', dataset) isRealData = 'genWeight' not in events.columns selection = processor.PackedSelection() weights = processor.Weights(len(events)) output = self.accumulator.identity() if (len(events) == 0): return output if not isRealData: output['sumw'][dataset] += events.genWeight.sum() # trigger paths if isRealData: trigger_fatjet = np.zeros(events.size, dtype='bool') for t in self._triggers[self._year]: try: trigger_fatjet = trigger_fatjet | events.HLT[t] except: print('trigger %s not available' % t) continue trigger_muon = np.zeros(events.size, dtype='bool') for t in self._muontriggers[self._year]: trigger_muon = trigger_muon | events.HLT[t] else: trigger_fatjet = np.ones(events.size, dtype='bool') trigger_muon = np.ones(events.size, dtype='bool') selection.add('fatjet_trigger', trigger_fatjet) selection.add('muon_trigger', trigger_muon) #jet corrected kinematics gru = events.GRU IN = events.IN fatjets = events.FatJet fatjets['msdcorr'] = corrected_msoftdrop(fatjets) fatjets['rhocorr'] = 2 * np.log(fatjets.msdcorr / fatjets.pt) fatjets['gruddt'] = gru.v25 - shift( fatjets, algo='gruddt', year=self._year) fatjets['gru'] = gru.v25 fatjets['in_v3'] = IN.v3 fatjets['in_v3_ddt'] = IN.v3 - shift( fatjets, algo='inddt', year=self._year) fatjets['in_v3_ddt_90pctl'] = IN.v3 - shift( fatjets, algo='inddt90pctl', year=self._year) fatjets['n2ddt'] = fatjets.n2b1 - n2ddt_shift(fatjets, year=self._year) fatjets["genMatchFull"] = genmatch(events, dataset) #else: fatjets["genMatchFull"] = fatjets.pt.zeros_like() #np.zeros(events.size, dtype='bool') candidatejet = fatjets[:, :1] candidatemuon = events.Muon[:, :5] # run model on PFCands associated to FatJet (FatJetPFCands) #events.FatJet.array.content["PFCands"] = type(events.FatJetPFCands.array).fromcounts(events.FatJet.nPFConstituents.flatten(), events.FatJetPFCands.flatten()) #events.FatJet.array.content["twoProngGru"] = run_model(events.FatJet.flatten()) selection.add('pt', (candidatejet.pt > 525).any()) selection.add('msdcorr', (candidatejet.msdcorr > 40).any()) # basic jet selection goodjet_sel = ((candidatejet.pt > 525) & (abs(candidatejet.eta) < 2.5) & (candidatejet.msoftdrop > 40.) & (candidatejet.rhocorr > -5.5) & (candidatejet.rhocorr < -2) & (candidatejet.genMatchFull if ('WJetsToQQ' in dataset or 'ZJetsToQQ' in dataset) else (1 == 1))).any() vselection_goodjet_sel = ((candidatejet.pt > 200) & (abs(candidatejet.eta) < 2.5) & (candidatejet.msoftdrop > 40.)).any() #& (candidatejet.genMatchFull if ('TTTo' in dataset) else (1==1))).any() #& (candidatejet.rhocorr > -5.5) #& (candidatejet.rhocorr < -2)).any() selection.add('vselection_jetkin', vselection_goodjet_sel) #goodmuon sel for muon CR (lep vetos below) goodmuon_sel = ((candidatemuon.pt > 55) & (abs(candidatemuon.eta) < 2.1) & (candidatemuon.looseId).astype(bool) & (candidatemuon.pfRelIso04_all < 0.15)).any() vselection_goodmuon_sel = ((candidatemuon.pt > 53) & (abs(candidatemuon.eta) < 2.1) & (candidatemuon.tightId).astype(bool)) #& (candidatemuon.pfRelIso04_all < 0.15)) vselection_goodmuon_sel_loose = ((candidatemuon.pt > 20) & (candidatemuon.looseId).astype(bool) & (abs(candidatemuon.eta) < 2.4)) selection.add('vselection_muonkin', vselection_goodmuon_sel.any()) selection.add('vselection_onetightmuon', vselection_goodmuon_sel.sum() == 1) selection.add('vselection_oneloosemuon', vselection_goodmuon_sel_loose.sum() == 1) candidatemuon = candidatemuon[:, 0:1] selection.add('muonkin', goodmuon_sel) selection.add('jetkin', goodjet_sel) selection.add('n2ddt', (candidatejet.n2ddt < 0.).any()) selection.add('jetid', candidatejet.isTight.any()) selection.add('met', events.MET.pt > 40.) muon_ak8_pair = candidatemuon.cross(candidatejet, nested=True) selection.add('muonDphiAK8', (abs(muon_ak8_pair.i0.delta_phi(muon_ak8_pair.i1)) > 2 * np.pi / 3).all().all()) selection.add('vselection_muonDphiAK8', (abs( muon_ak8_pair.i0.delta_phi(muon_ak8_pair.i1)) > 1).all().all()) #ak4 puppi jet for CR jets = events.Jet[((events.Jet.pt > 50.) & (abs(events.Jet.eta) < 2.5))][:, :10] # only consider first 4 jets to be consistent with old framework ak4_ak8_pair = jets.cross(candidatejet, nested=True) dr = abs(ak4_ak8_pair.i0.delta_r(ak4_ak8_pair.i1)) dphi = abs(ak4_ak8_pair.i0.delta_phi(ak4_ak8_pair.i1)) ak4_away = jets[(dr > 0.8).all()] selection.add('ak4btagMedium08', ak4_away.btagCSVV2.max() > 0.8838) ak4_opposite = jets[(dphi > np.pi / 2).all()] selection.add('antiak4btagMediumOppHem', ak4_opposite.btagCSVV2.max() < 0.8838) mu_p4 = TLorentzVectorArray.from_ptetaphim( candidatemuon.pt.fillna(0), candidatemuon.eta.fillna(0), candidatemuon.phi.fillna(0), candidatemuon.mass.fillna(0)) met_p4 = TLorentzVectorArray.from_ptetaphim( awkward.JaggedArray.fromiter([[v] for v in events.MET.pt]), awkward.JaggedArray.fromiter([[v] for v in np.zeros(events.size)]), awkward.JaggedArray.fromiter([[v] for v in events.MET.phi]), awkward.JaggedArray.fromiter([[v] for v in np.zeros(events.size)])) met_candidatemuon_pair = met_p4.cross(mu_p4) Wleptoniccandidate = met_candidatemuon_pair.i0 + met_candidatemuon_pair.i1 selection.add('Wleptonic_candidate', (Wleptoniccandidate.pt > 200).any()) vselection_jets = events.Jet[((events.Jet.pt > 30.) & (abs(events.Jet.eta) < 2.4))] vselection_ak4_ak8_pair = vselection_jets.cross(candidatejet, nested=True) muon_ak4_pair = vselection_jets.cross(candidatemuon, nested=True) dr_ak8 = abs( vselection_ak4_ak8_pair.i0.delta_r(vselection_ak4_ak8_pair.i1)) dr_muon = abs(muon_ak4_pair.i0.delta_r(muon_ak4_pair.i1)) ak4_away = vselection_jets[(dr_ak8 > 0.8).all()] selection.add('vselection_ak4btagMedium08', ak4_away.btagCSVV2.max() > 0.8838) ak4_away = vselection_jets[(dr_muon > 0.3).all()] selection.add('vselection_muonDphiAK4', ak4_away.btagCSVV2.max() > 0.8838) nelectrons = (( (events.Electron.pt > 10.) & (abs(events.Electron.eta) < 2.5) #& (events.Electron.cutBased >= events.Electron.LOOSE)) #& (events.Electron.cutBased_Fall17_V1 >= 1)) & (events.Electron.cutBased >= 2))).sum() nmuons = (((events.Muon.pt > 10) & (abs(events.Muon.eta) < 2.1) #& (events.Muon.pfRelIso04_all < 0.4) & (events.Muon.looseId).astype(bool))).sum() ntaus = (((events.Tau.pt > 20.) #& (events.Tau.idMVAnewDM2017v2 >=4)) & (events.Tau.idDecayMode).astype(bool) & (events.Tau.rawIso < 5) & (abs(events.Tau.eta) < 2.3))).sum() selection.add('noleptons', (nmuons == 0) & (nelectrons == 0) & (ntaus == 0)) selection.add('noelectron_notau', (nelectrons == 0) & (ntaus == 0)) #weights.add('metfilter', events.Flag.METFilters) if isRealData: genflavor = candidatejet.pt.zeros_like().pad( 1, clip=True).fillna(-1).flatten() if not isRealData: weights.add('genweight', events.genWeight) add_pileup_weight(weights, events.Pileup.nPU, self._year, dataset) #add_jetTriggerWeight(weights, candidatejet.msdcorr, candidatejet.pt, self._year) #signal region only #add_singleMuTriggerWeight(weights, abs(candidatemuon.eta), candidatemuon.pt, self._year) bosons = getBosons(events) genBosonPt = bosons.pt.pad(1, clip=True).fillna(0) add_VJets_NLOkFactor(weights, genBosonPt, self._year, dataset) genflavor = matchedBosonFlavor(candidatejet, bosons).pad( 1, clip=True).fillna(-1).flatten() #b-tag weights regions = { 'signal': [ 'fatjet_trigger', 'jetkin', 'noleptons', 'jetid', 'antiak4btagMediumOppHem', ], 'ttbar_muoncontrol': [ 'muon_trigger', 'pt', 'msdcorr', 'jetid', 'jetkin', 'muonkin', 'muonDphiAK8', 'ak4btagMedium08', 'noelectron_notau', ], 'vselection': [ 'muon_trigger', 'vselection_jetkin', 'vselection_muonkin', 'vselection_onetightmuon', 'vselection_oneloosemuon', 'vselection_muonDphiAK8', 'vselection_ak4btagMedium08', 'vselection_muonDphiAK4', 'Wleptonic_candidate', 'met' ], 'noselection': [], #'vselection_muoncontrol' : ['muon_trigger', 'v_selection_jetkin', 'genmatch', 'jetid', 'ak4btagMedium08', 'muonkin','met'], } allcuts_signal = set() output['cutflow_signal'][dataset]['none'] += float( weights.weight().sum()) allcuts_ttbar_muoncontrol = set() output['cutflow_ttbar_muoncontrol'][dataset]['none'] += float( weights.weight().sum()) allcuts_vselection = set() output['cutflow_vselection'][dataset]['none'] += float( weights.weight().sum()) for cut in regions['signal']: allcuts_signal.add(cut) output['cutflow_signal'][dataset][cut] += float( weights.weight()[selection.all(*allcuts_signal)].sum()) for cut in regions['ttbar_muoncontrol']: allcuts_ttbar_muoncontrol.add(cut) output['cutflow_ttbar_muoncontrol'][dataset][cut] += float( weights.weight()[selection.all( *allcuts_ttbar_muoncontrol)].sum()) for cut in regions['vselection']: allcuts_vselection.add(cut) output['cutflow_vselection'][dataset][cut] += float( weights.weight()[selection.all(*allcuts_vselection)].sum()) def normalize(val, cut): return val[cut].pad(1, clip=True).fillna(0).flatten() def fill(region, systematic=None, wmod=None): print('filling %s' % region) selections = regions[region] cut = selection.all(*selections) weight = weights.weight()[cut] output['templates'].fill( dataset=dataset, region=region, pt=normalize(candidatejet.pt, cut), msd=normalize(candidatejet.msdcorr, cut), n2ddt=normalize(candidatejet.n2ddt, cut), gruddt=normalize(candidatejet.gruddt, cut), in_v3_ddt=normalize(candidatejet.in_v3_ddt_90pctl, cut), weight=weight, ), output['event'].fill( dataset=dataset, region=region, MET=events.MET.pt[cut], nJet=fatjets.counts[cut], nPFConstituents=normalize(candidatejet.nPFConstituents, cut), weight=weight, ), output['muon'].fill( dataset=dataset, region=region, mu_pt=normalize(candidatemuon.pt, cut), mu_pfRelIso04_all=normalize(candidatemuon.pfRelIso04_all, cut), weight=weight, ), output['deepAK8'].fill( dataset=dataset, region=region, deepTagMDWqq=normalize(candidatejet.deepTagMDWqq, cut), deepTagMDZqq=normalize(candidatejet.deepTagMDZqq, cut), msd=normalize(candidatejet.msdcorr, cut), genflavor=genflavor[cut], weight=weight, ), output['in_v3'].fill( dataset=dataset, region=region, genflavor=genflavor[cut], in_v3=normalize(candidatejet.in_v3, cut), n2=normalize(candidatejet.n2b1, cut), gru=normalize(candidatejet.gru, cut), weight=weight, ) for region in regions: fill(region) return output
def process(self, df): dataset = df.metadata['dataset'] isRealData = 'genWeight' not in df.columns output = self.accumulator.identity() selection = processor.PackedSelection() output = self.accumulator.identity() good = False goodMuon = ((df.Muon.pt > 27.) & (np.abs(df.Muon.eta) < 2.4)) nmuons = goodMuon.sum() goodElectron = ((df.Electron.pt > 30.) & (np.abs(df.Electron.eta) < 2.5)) nelectrons = goodElectron.sum() df.FatJet['msdcorr'] = corrected_msoftdrop(df.FatJet) goodFatJet = ((df.FatJet.pt > 300.) & (np.abs(df.FatJet.eta) < 2.4) & (df.FatJet.msdcorr > 10.) & (df.FatJet.isTight)) nfatjets = goodFatJet.sum() if self._channel == 'muon': good = ((nmuons >= 1) & (nfatjets >= 1)) else: good = ((nelectrons >= 1) & (nfatjets >= 1)) events = df[good] if not isRealData: output['sumw'][dataset] += events.genWeight.sum() # trigger trigger = np.zeros(df.size, dtype='bool') for t in self._triggers[self._year + '_' + self._trigger]: try: trigger = trigger | df.HLT[t] except: warnings.warn("Missing trigger %s" % t, RuntimeWarning) selection.add('trigger', trigger[good]) # Muons candidatemuon = events.Muon[:, 0:1] nmuons = events.Muon.counts # Electrons candidateelectron = events.Electron[:, 0:1] nelectrons = events.Electron.counts if self._channel == 'muon': candidatelep = candidatemuon selection.add('nootherlepton', (nelectrons == 0)) else: candidatelep = candidateelectron selection.add('nootherlepton', (nmuons == 0)) selection.add('iplepton', ((np.abs(candidatelep.dz) < 0.1) & (np.abs(candidatelep.dxy) < 0.05)).any()) # FatJets ak8_lep_pair = candidatelep.cross(events.FatJet) ak8_lep_dR = ak8_lep_pair.i0.delta_r(ak8_lep_pair.i1) candidatejet = events.FatJet[ak8_lep_dR.argmin()] leadingjet = events.FatJet[:, 0:1] ak8_lep_dR_closest = candidatelep.delta_r(candidatejet) selection.add('jetkin', (candidatejet.pt > self._fjetptMIN).any()) selection.add('jetmsd', (candidatejet.msdcorr > 20).any()) selection.add('LSF3medium', (candidatejet.lsf3 > 0.7).any()) selection.add('LSF3tight', (candidatejet.lsf3 > 0.78).any()) selection.add('lepnearjet', (ak8_lep_dR.min() < 1.5)) selection.add('lepinjet', (ak8_lep_dR.min() < 0.8)) # FatJet substracted Lepton # sj1_sj2_btagDeepB_pair = candidatejet.LSsubJet1btagDeepB.cross(candidatejet.LSsubJet2btagDeepB) # fls_btagDeepB_max = max(sj1_sj2_btagDeepB_pair.i0,sj1_sj2_btagDeepB_pair.i1) # Jets jets = events.Jet[(events.Jet.pt > 30.) & (abs(events.Jet.eta) < 2.5) & (events.Jet.isTight)] ak4_ak8_pair = jets.cross(candidatejet, nested=True) ak4_ak8_dphi = abs(ak4_ak8_pair.i0.delta_phi(ak4_ak8_pair.i1)) ak4_opposite = jets[(ak4_ak8_dphi > np.pi / 2).all()] ak4_away = jets[(ak4_ak8_dphi > 0.8).all()] selection.add( 'antiak4btagMediumOppHem', ak4_opposite.btagDeepB.max() < self._btagWPs['med'][self._year]) selection.add( 'ak4btagMedium08', ak4_away.btagDeepB.max() < self._btagWPs['med'][self._year]) # MET met = events.MET # MET eta with mass assumption mm = (candidatejet - candidatelep).mass2 jmass = (mm > 0) * np.sqrt(np.maximum( 0, mm)) + (mm < 0) * candidatejet.mass joffshell = jmass < 62.5 massassumption = 80. * joffshell + (125 - 80.) * ~joffshell x = massassumption**2 / (2 * candidatelep.pt * met.pt) + np.cos(candidatelep.phi - met.phi) met_eta = ((x < 1) * np.arcsinh(x * np.sinh(candidatelep.eta)) + (x > 1) * (candidatelep.eta - np.sign(candidatelep.eta) * np.arccosh(candidatelep.eta))) met_p4 = TLorentzVectorArray.from_ptetaphim(np.array([0.]), np.array([0.]), np.array([0.]), np.array([0.])) if met.size > 0: met_p4 = TLorentzVectorArray.from_ptetaphim( met.pt, met_eta.fillna(0.), met.phi, np.zeros(met.size)) hmass = (candidatejet + met_p4).mass else: hmass = candidatejet.pt.zeros_like() # weights weights = processor.Weights(len(events), storeIndividual=True) if isRealData: genflavor = candidatejet.pt.zeros_like() else: try: weights.add('genweight', events.genWeight) add_pileup_weight(weights, events.Pileup.nPU, self._year) #print("Weight statistics: %r" % weights._weightStats) except: print('no gen weight') if 'TTTo' in dataset: genW, genW_idx = getParticles( events, 24, ['fromHardProcess', 'isLastCopy']) genb, genb_idx = getParticles( events, 5, ['fromHardProcess', 'isLastCopy']) genflavorW = matchedParticleFlavor(candidatelep, genW, 'child', 0.4) genflavorb = matchedParticleFlavor(candidatelep, genb, 'mom', 0.4) genflavor = getFlavor(genflavorW, genflavorb) elif (('hww_2017' in dataset) or ('GluGluHToWW' in dataset)): genH, genH_idx = getParticles( events, 25, ['fromHardProcess', 'isLastCopy']) genW, genW_idx = getParticles( events, 24, ['fromHardProcess', 'isLastCopy']) genE, genE_idx = getParticles( events, 11, ['fromHardProcess', 'isFirstCopy'], 1) genM, genM_idx = getParticles( events, 13, ['fromHardProcess', 'isFirstCopy'], 1) genT, genT_idx = getParticles( events, 15, ['fromHardProcess', 'isFirstCopy'], 1) genQ, genQ_idx = getParticles( events, [0, 5], ['fromHardProcess', 'isFirstCopy']) ishWW_qqelev = (genH.counts == 1) & (genW.counts == 2) & ( genE.counts == 1) & (genM.counts == 0) & (genT.counts == 0) ishWW_qqmuv = (genH.counts == 1) & (genW.counts == 2) & ( genM.counts == 1) & (genE.counts == 0) & (genT.counts == 0) ishWW_qqtauv = (genH.counts == 1) & (genW.counts == 2) & ( genT.counts == 1) & (genM.counts == 0) & (genE.counts == 0) ishWW_qqqq = (genH.counts == 1) & (genW.counts == 2) & ( genQ.counts == 4) & (genM.counts == 0) & (genE.counts == 0) ishWW_muvelev = (genH.counts == 1) & (genW.counts == 2) & ( genE.counts == 1) & (genM.counts == 1) ishWW_elevelev = (genH.counts == 1) & (genW.counts == 2) & ( genE.counts == 2) & (genM.counts == 0) ishWW_tauvtauv = (genH.counts == 1) & (genW.counts == 2) & ( genT.counts == 2) & (genM.counts == 0) & (genE.counts == 0) ishWW_muvmuv = (genH.counts == 1) & (genW.counts == 2) & ( genE.counts == 0) & (genM.counts == 2) genflavor = ((ishWW_qqelev) * 8 + (ishWW_qqmuv) * 9) else: genflavor = candidatejet.pt.zeros_like() # fill cutflow cutflow = [ 'trigger', 'jetkin', 'jetmsd', 'lepnearjet', 'lepinjet', 'antiak4btagMediumOppHem', 'nootherlepton', 'iplepton', 'LSF3medium', 'LSF3tight' ] allcuts = set() output['cutflow']['none'] += len(events) for cut in cutflow: allcuts.add(cut) output['cutflow'][cut] += selection.all(*allcuts).sum() regions = {} regions['presel'] = {'trigger', 'jetkin', 'jetmsd', 'lepinjet'} regions['antibtag'] = { 'trigger', 'jetkin', 'jetmsd', 'antiak4btagMediumOppHem' } regions['noinjet'] = { 'trigger', 'jetkin', 'jetmsd', 'lepnearjet', 'antiak4btagMediumOppHem' } regions['nolsf'] = { 'trigger', 'jetkin', 'jetmsd', 'lepinjet', 'antiak4btagMediumOppHem' } #,'nootherlepton'} regions['lsf'] = { 'trigger', 'jetkin', 'jetmsd', 'lepinjet', 'LSF3tight' } regions['bopp'] = { 'trigger', 'jetkin', 'jetmsd', 'lepinjet', 'LSF3tight', 'antiak4btagMediumOppHem' } regions['lep'] = { 'trigger', 'jetkin', 'jetmsd', 'lepinjet', 'LSF3tight', 'antiak4btagMediumOppHem', 'nootherlepton', 'iplepton' } for region in self._regions: selections = regions[region] cut = selection.all(*selections) weight = weights.weight()[cut] def normalize(val): try: return val[cut].pad(1, clip=True).fillna(0).flatten() except: try: return val[cut].flatten() except: return val[cut] # output['%s_fjetprop'%region].fill(#fjet_pt = normalize(candidatejet.pt), # fjet_msd = normalize(candidatejet.msdcorr), # fjet_lsf3 = normalize(candidatejet.lsf3), # #jet_oppbtag = normalize(ak4_opposite.btagDeepB.max()), # genflavor = normalize(genflavor), # dataset=dataset, # weight=weight # ) # output['%s_fjetextraprop'%region].fill(fjet_t41 = normalize(candidatejet.tau4/candidatejet.tau1), # fjet_t42 = normalize(candidatejet.tau4/candidatejet.tau2), # fjet_t31 = normalize(candidatejet.tau3/candidatejet.tau1), # dataset=dataset, # weight=weight # ) # output['%s_jetprop'%region].fill(jet_oppbtag = normalize(ak4_opposite.btagDeepB.max()), # genflavor = normalize(genflavor), # dataset=dataset, # weight=weight # ) output['%s_fmmjetprop' % region].fill( fjet_pt=normalize(candidatejet.pt), #fjet_mmass = normalize(jmass), #fjet_hmass = normalize(hmass), lep_pt=normalize(candidatelep.pt), fjet_lsf3=normalize(candidatejet.lsf3), genflavor=normalize(genflavor), dataset=dataset, weight=weight) output['%s_fmmjetprop2' % region].fill( fjet_mmass=normalize(jmass), fjet_lsf3=normalize(candidatejet.lsf3), genflavor=normalize(genflavor), dataset=dataset, weight=weight) # output['%s_flsjetprop'%region].fill(#flsjet_pt = normalize(candidatejet.LSpt), # flsjet_msd = normalize(candidatejet.LSmsoftdrop), # #flsjet_n2b1 = normalize(candidatejet.LSn2b1), # #flsjet_n3b1 = normalize(candidatejet.LSn3b1), # #flsjet_t21 = normalize(candidatejet.LStau2/candidatejet.LStau1), # #flsjet_t32 = normalize(candidatejet.LStau3/candidatejet.LStau2), # genflavor = normalize(genflavor), # dataset=dataset, # weight=weight) #output['%s_metprop'%region].fill(met_pt = normalize(met.pt), # met_phi = normalize(met.phi), # dataset=dataset, # weight=weight) # output['%s_weight'%region].fill(puweight=weights.partial_weight(include=["pileup_weight"])[cut], # genweight=weights.partial_weight(include=["genweight"])[cut], # dataset=dataset, # ) # if self._channel=='muon': # output['%s_muonprop'%region].fill(muon_pt = normalize(candidatemuon.pt), # muon_miso = normalize(candidatemuon.miniPFRelIso_all), # muon_sip = normalize(candidatemuon.sip3d), # dataset=dataset, # weight=weight) # output['%s_muonextraprop'%region].fill(nmuons = normalize(nmuons), # nelectrons = normalize(nelectrons), # muon_dz = normalize(candidatemuon.dz), # muon_dxy = normalize(candidatemuon.dxy), # dataset=dataset, # weight=weight) # else: # output['%s_electronprop'%region].fill(electron_pt = normalize(candidateelectron.pt), # electron_miso = normalize(candidateelectron.miniPFRelIso_all), # electron_sip = normalize(candidateelectron.sip3d), # dataset=dataset, # weight=weight) # output['%s_electronextraprop'%region].fill(nmuons = normalize(nmuons), # nelectrons = normalize(nelectrons), # electron_dz = normalize(candidateelectron.dz), # electron_dxy = normalize(candidateelectron.dxy), # dataset=dataset, # weight=weight) return output
def process(self, events): dataset = events.metadata['dataset'] isRealData = 'genWeight' not in events.columns selection = processor.PackedSelection() weights = processor.Weights(len(events)) output = self.accumulator.identity() if not isRealData: output['sumw'][dataset] += events.genWeight.sum() if isRealData: trigger = np.zeros(events.size, dtype='bool') for t in self._triggers[self._year]: trigger = trigger | events.HLT[t] else: trigger = np.ones(events.size, dtype='bool') selection.add('trigger', trigger) if isRealData: trigger = np.zeros(events.size, dtype='bool') for t in self._muontriggers[self._year]: trigger = trigger | events.HLT[t] else: trigger = np.ones(events.size, dtype='bool') selection.add('muontrigger', trigger) try: fatjets = events.FatJet except AttributeError: # early pancakes fatjets = events.CustomAK8Puppi fatjets['msdcorr'] = corrected_msoftdrop(fatjets) fatjets['rho'] = 2 * np.log(fatjets.msdcorr / fatjets.pt) fatjets['n2ddt'] = fatjets.n2b1 - n2ddt_shift(fatjets, year=self._year) fatjets['msdcorr_full'] = fatjets['msdcorr'] * self._msdSF[self._year] candidatejet = fatjets[ # https://github.com/DAZSLE/BaconAnalyzer/blob/master/Analyzer/src/VJetLoader.cc#L269 (fatjets.pt > 200) & (abs(fatjets.eta) < 2.5) # & fatjets.isLoose # not always available ][:, 0:1] selection.add('minjetkin', ( (candidatejet.pt >= 450) & (candidatejet.msdcorr >= 47.) & (abs(candidatejet.eta) < 2.5) ).any()) selection.add('jetacceptance', ( (candidatejet.msdcorr >= 47.) & (candidatejet.pt < 1200) & (candidatejet.msdcorr < 201.) ).any()) selection.add('jetid', candidatejet.isTight.any()) selection.add('n2ddt', (candidatejet.n2ddt < 0.).any()) selection.add('ddbpass', (candidatejet.btagDDBvL >= 0.89).any()) jets = events.Jet[ (events.Jet.pt > 30.) & (abs(events.Jet.eta) < 2.5) & events.Jet.isTight ] # only consider first 4 jets to be consistent with old framework jets = jets[:, :4] ak4_ak8_pair = jets.cross(candidatejet, nested=True) dphi = abs(ak4_ak8_pair.i0.delta_phi(ak4_ak8_pair.i1)) ak4_opposite = jets[(dphi > np.pi / 2).all()] selection.add('antiak4btagMediumOppHem', ak4_opposite.btagDeepB.max() < BTagEfficiency.btagWPs[self._year]['medium']) ak4_away = jets[(dphi > 0.8).all()] selection.add('ak4btagMedium08', ak4_away.btagDeepB.max() > BTagEfficiency.btagWPs[self._year]['medium']) selection.add('met', events.MET.pt < 140.) goodmuon = ( (events.Muon.pt > 10) & (abs(events.Muon.eta) < 2.4) & (events.Muon.pfRelIso04_all < 0.25) & (events.Muon.looseId).astype(bool) ) nmuons = goodmuon.sum() leadingmuon = events.Muon[goodmuon][:, 0:1] muon_ak8_pair = leadingmuon.cross(candidatejet, nested=True) nelectrons = ( (events.Electron.pt > 10) & (abs(events.Electron.eta) < 2.5) & (events.Electron.cutBased >= events.Electron.LOOSE) ).sum() ntaus = ( (events.Tau.pt > 20) & (events.Tau.idDecayMode).astype(bool) # bacon iso looser than Nano selection ).sum() selection.add('noleptons', (nmuons == 0) & (nelectrons == 0) & (ntaus == 0)) selection.add('onemuon', (nmuons == 1) & (nelectrons == 0) & (ntaus == 0)) selection.add('muonkin', ( (leadingmuon.pt > 55.) & (abs(leadingmuon.eta) < 2.1) ).all()) selection.add('muonDphiAK8', ( abs(muon_ak8_pair.i0.delta_phi(muon_ak8_pair.i1)) > 2*np.pi/3 ).all().all()) if isRealData: genflavor = candidatejet.pt.zeros_like() else: weights.add('genweight', events.genWeight) add_pileup_weight(weights, events.Pileup.nPU, self._year, dataset) bosons = getBosons(events) genBosonPt = bosons.pt.pad(1, clip=True).fillna(0) add_VJets_NLOkFactor(weights, genBosonPt, self._year, dataset) genflavor = matchedBosonFlavor(candidatejet, bosons).pad(1, clip=True).fillna(-1).flatten() add_jetTriggerWeight(weights, candidatejet.msdcorr, candidatejet.pt, self._year) output['btagWeight'].fill(dataset=dataset, val=self._btagSF.addBtagWeight(weights, ak4_away)) logger.debug("Weight statistics: %r" % weights._weightStats) msd_matched = candidatejet.msdcorr * self._msdSF[self._year] * (genflavor > 0) + candidatejet.msdcorr * (genflavor == 0) regions = { 'signal': ['trigger','minjetkin',],#'noleptons','jetacceptance', 'noleptons','jetid',],#'jetid', 'noleptons',],# 'n2ddt','antiak4btagMediumOppHem'],#, 'met',], 'muoncontrol': ['muontrigger','minjetkin', 'jetid','muonDphiAK8','muonkin', 'ak4btagMedium08', 'onemuon',],# 'muonkin', 'muonDphiAK8'], 'noselection': [], } for region, cuts in regions.items(): allcuts = set() logger.debug(f"Filling cutflow with: {dataset}, {region}, {genflavor}, {weights.weight()}") #output['cutflow'].fill(dataset=dataset, region=region, genflavor=genflavor, cut=0, weight=weights.weight()) #for i, cut in enumerate(cuts + ['ddbpass']): # allcuts.add(cut) # cut = selection.all(*allcuts) # output['cutflow'].fill(dataset=dataset, region=region, genflavor=genflavor[cut], cut=i + 1, weight=weights.weight()[cut]) systematics = [ None, 'jet_triggerUp', 'jet_triggerDown', 'btagWeightUp', 'btagWeightDown', 'btagEffStatUp', 'btagEffStatDown', ] def normalize(val, cut): return val[cut].pad(1, clip=True).fillna(0).flatten() def fill(region, systematic=None, wmod=None): selections = regions[region] cut = selection.all(*selections) sname = 'nominal' if systematic is None else systematic if wmod is None: weight = weights.weight(modifier=systematic)[cut] else: weight = weights.weight()[cut] * wmod[cut] output['templates'].fill( dataset=dataset, region=region, #systematic=sname, #genflavor=genflavor[cut], pt=normalize(candidatejet.pt, cut), msd=normalize(msd_matched, cut), #ddb=normalize(candidatejet.btagDDBvL, cut), weight=weight, ) if wmod is not None: output['genresponse_noweight'].fill( dataset=dataset, region=region, systematic=sname, pt=normalize(candidatejet.pt, cut), genpt=normalize(genBosonPt, cut), weight=events.genWeight[cut] * wmod[cut], ) output['genresponse'].fill( dataset=dataset, region=region, systematic=sname, pt=normalize(candidatejet.pt, cut), genpt=normalize(genBosonPt, cut), weight=weight, ) for region in regions: cut = selection.all(*(set(regions[region]) - {'n2ddt'})) output['nminus1_n2ddt'].fill( dataset=dataset, region=region, n2ddt=normalize(candidatejet.n2ddt, cut), weight=weights.weight()[cut], ) #for systematic in systematics: fill(region)#, systematic) if 'GluGluHToBB' in dataset: for i in range(9): fill(region, 'LHEScale_%d' % i, events.LHEScaleWeight[:, i]) for c in events.LHEWeight.columns[1:]: fill(region, 'LHEWeight_%s' % c, events.LHEWeight[c]) return output
def process(self, events): dataset = events.metadata['dataset'] isRealData = not hasattr(events, "genWeight") selection = PackedSelection() weights = Weights(len(events)) output = self.accumulator.identity() if not isRealData: output['sumw'][dataset] += ak.sum(events.genWeight) if isRealData: trigger = np.zeros(len(events), dtype='bool') for t in self._triggers[self._year]: trigger = trigger | events.HLT[t] else: trigger = np.ones(len(events), dtype='bool') selection.add('trigger', trigger) if isRealData: trigger = np.zeros(len(events), dtype='bool') for t in self._muontriggers[self._year]: trigger = trigger | events.HLT[t] else: trigger = np.ones(len(events), dtype='bool') selection.add('muontrigger', trigger) fatjets = events.FatJet fatjets['msdcorr'] = corrected_msoftdrop(fatjets) fatjets['qcdrho'] = 2 * np.log(fatjets.msdcorr / fatjets.pt) fatjets['n2ddt'] = fatjets.n2b1 - n2ddt_shift(fatjets, year=self._year) fatjets['msdcorr_full'] = fatjets['msdcorr'] * self._msdSF[self._year] candidatejet = fatjets[ # https://github.com/DAZSLE/BaconAnalyzer/blob/master/Analyzer/src/VJetLoader.cc#L269 (fatjets.pt > 200) & (abs(fatjets.eta) < 2.5) & fatjets.isTight # this is loose in sampleContainer ] if self._jet_arbitration == 'pt': candidatejet = ak.firsts(candidatejet) elif self._jet_arbitration == 'mass': candidatejet = candidatejet[ak.argmax(candidatejet.msdcorr)] elif self._jet_arbitration == 'n2': candidatejet = candidatejet[ak.argmin(candidatejet.n2ddt)] elif self._jet_arbitration == 'ddb': candidatejet = candidatejet[ak.argmax(candidatejet.btagDDBvL)] else: raise RuntimeError("Unknown candidate jet arbitration") selection.add('minjetkin', (candidatejet.pt >= 450) & (candidatejet.msdcorr >= 40.) & (abs(candidatejet.eta) < 2.5)) selection.add('jetacceptance', (candidatejet.msdcorr >= 47.) & (candidatejet.pt < 1200) & (candidatejet.msdcorr < 201.)) selection.add('jetid', candidatejet.isTight) selection.add('n2ddt', (candidatejet.n2ddt < 0.)) selection.add('ddbpass', (candidatejet.btagDDBvL >= 0.89)) jets = events.Jet[(events.Jet.pt > 30.) & (abs(events.Jet.eta) < 2.5) & events.Jet.isTight] # only consider first 4 jets to be consistent with old framework jets = jets[:, :4] dphi = abs(jets.delta_phi(candidatejet)) selection.add( 'antiak4btagMediumOppHem', ak.max( jets[dphi > np.pi / 2].btagDeepB, axis=1, mask_identity=False) < BTagEfficiency.btagWPs[self._year]['medium']) ak4_away = jets[dphi > 0.8] selection.add( 'ak4btagMedium08', ak.max(ak4_away.btagDeepB, axis=1, mask_identity=False) > BTagEfficiency.btagWPs[self._year]['medium']) selection.add('met', events.MET.pt < 140.) goodmuon = ((events.Muon.pt > 10) & (abs(events.Muon.eta) < 2.4) & (events.Muon.pfRelIso04_all < 0.25) & events.Muon.looseId) nmuons = ak.sum(goodmuon, axis=1) leadingmuon = ak.firsts(events.Muon[goodmuon]) nelectrons = ak.sum( (events.Electron.pt > 10) & (abs(events.Electron.eta) < 2.5) & (events.Electron.cutBased >= events.Electron.LOOSE), axis=1, ) ntaus = ak.sum( (events.Tau.pt > 20) & events.Tau.idDecayMode, # bacon iso looser than Nano selection axis=1, ) selection.add('noleptons', (nmuons == 0) & (nelectrons == 0) & (ntaus == 0)) selection.add('onemuon', (nmuons == 1) & (nelectrons == 0) & (ntaus == 0)) selection.add('muonkin', (leadingmuon.pt > 55.) & (abs(leadingmuon.eta) < 2.1)) selection.add('muonDphiAK8', abs(leadingmuon.delta_phi(candidatejet)) > 2 * np.pi / 3) if isRealData: genflavor = 0 else: weights.add('genweight', events.genWeight) add_pileup_weight(weights, events.Pileup.nPU, self._year, dataset) bosons = getBosons(events.GenPart) matchedBoson = candidatejet.nearest(bosons, axis=None, threshold=0.8) genflavor = bosonFlavor(matchedBoson) genBosonPt = ak.fill_none(ak.firsts(bosons.pt), 0) add_VJets_NLOkFactor(weights, genBosonPt, self._year, dataset) add_jetTriggerWeight(weights, candidatejet.msdcorr, candidatejet.pt, self._year) output['btagWeight'].fill(dataset=dataset, val=self._btagSF.addBtagWeight( weights, ak4_away)) logger.debug("Weight statistics: %r" % weights.weightStatistics) msd_matched = candidatejet.msdcorr * self._msdSF[self._year] * ( genflavor > 0) + candidatejet.msdcorr * (genflavor == 0) regions = { 'signal': [ 'trigger', 'minjetkin', 'jetacceptance', 'jetid', 'n2ddt', 'antiak4btagMediumOppHem', 'met', 'noleptons' ], 'muoncontrol': [ 'muontrigger', 'minjetkin', 'jetacceptance', 'jetid', 'n2ddt', 'ak4btagMedium08', 'onemuon', 'muonkin', 'muonDphiAK8' ], 'noselection': [], } for region, cuts in regions.items(): allcuts = set() output['cutflow'].fill(dataset=dataset, region=region, genflavor=genflavor, cut=0, weight=weights.weight()) for i, cut in enumerate(cuts + ['ddbpass']): allcuts.add(cut) cut = selection.all(*allcuts) output['cutflow'].fill(dataset=dataset, region=region, genflavor=genflavor[cut], cut=i + 1, weight=weights.weight()[cut]) systematics = [ None, 'jet_triggerUp', 'jet_triggerDown', 'btagWeightUp', 'btagWeightDown', 'btagEffStatUp', 'btagEffStatDown', ] def normalize(val, cut): return ak.to_numpy(ak.fill_none(val[cut], np.nan)) def fill(region, systematic, wmod=None): selections = regions[region] cut = selection.all(*selections) sname = 'nominal' if systematic is None else systematic if wmod is None: weight = weights.weight(modifier=systematic)[cut] else: weight = weights.weight()[cut] * wmod[cut] output['templates'].fill( dataset=dataset, region=region, systematic=sname, genflavor=genflavor[cut], pt=normalize(candidatejet.pt, cut), msd=normalize(msd_matched, cut), ddb=normalize(candidatejet.btagDDBvL, cut), weight=weight, ) if wmod is not None: output['genresponse_noweight'].fill( dataset=dataset, region=region, systematic=sname, pt=normalize(candidatejet.pt, cut), genpt=normalize(genBosonPt, cut), weight=events.genWeight[cut] * wmod[cut], ) output['genresponse'].fill( dataset=dataset, region=region, systematic=sname, pt=normalize(candidatejet.pt, cut), genpt=normalize(genBosonPt, cut), weight=weight, ) for region in regions: cut = selection.all(*(set(regions[region]) - {'n2ddt'})) output['nminus1_n2ddt'].fill( dataset=dataset, region=region, n2ddt=normalize(candidatejet.n2ddt, cut), weight=weights.weight()[cut], ) for systematic in systematics: fill(region, systematic) if 'GluGluHToBB' in dataset: for i in range(9): fill(region, 'LHEScale_%d' % i, events.LHEScaleWeight[:, i]) for c in events.LHEWeight.columns[1:]: fill(region, 'LHEWeight_%s' % c, events.LHEWeight[c]) output["weightStats"] = weights.weightStatistics return output