ATLAS Offline Software
Loading...
Searching...
No Matches
TrigJetMonitorAlgorithm.py
Go to the documentation of this file.
2# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3#
4
5'''@file MTMonitoring.py
6@authors P-A. Delsart, Jona Bossio
7@date 03/04/2020
8@brief Python configuration for the Run III Trigger Jet Monitoring
9'''
10
11from AthenaCommon.Logging import logging
12logger = logging.getLogger(__name__)
13
14from TrigDecisionTool.TrigDecisionToolConfig import getRun3NavigationContainerFromInput
15
16import math
17import re
18import copy
19
20
21
24
25copySuffix = "copied" # suffix for jet containters that are duplicated for monitoring
26
27
30
31OfflineJetCollections = dict()
32
33OfflineJetCollections['pp'] = {
34 'AntiKt4EMTopoJets' : { 'MatchTo' : 'AntiKt4EMPFlowJets' },
35 'AntiKt4EMPFlowJets' : { 'MatchTo' : 'NONE' },
36 #'AntiKt10LCTopoTrimmedPtFrac5SmallR20Jets' : { 'MatchTo' : 'NONE' }, # Remove until ATR-25800 is fixed
37}
38
39OfflineJetCollections['HI'] = {
40 'AntiKt4HIJets' : { 'MatchTo' : 'AntiKt4HIJets' },
41}
42
43
46
47# The MatchedTo list must be either empty of length 2, and contain the names of an offline collection
48# and an HLT collection. These names can be the empty string.
49
50# the strings in L1JetCollections are jet container names.
51L1JetCollections = dict()
52
53match_smallRL1_OfflineJets_List = ['AntiKt4EMPFlowJets', 'HLT_AntiKt4EMPFlowJets_subresjesgscIS_ftf']
54# temporarily modified to use small-R offline jet in turn-on to fix tier0 jet mon crash ATR-25800!! - throws exception if < 2 jet collections provided
55match_largeRL1_OfflineJets_List = ['AntiKt4EMPFlowJets', 'HLT_AntiKt10EMPFlowCSSKSoftDropBeta100Zcut10Jets_jes_ftf']
56match_HIL1_OfflineJets_List = ['AntiKt4HIJets', 'HLT_AntiKt4HIJets']
57
58L1JetCollections['pp'] = {
59 'L1_jFexSRJetRoI': {'MatchTo': match_smallRL1_OfflineJets_List},
60 'L1_gFexSRJetRoI': {'MatchTo': match_smallRL1_OfflineJets_List},
61 'L1_gFexLRJetRoI': {'MatchTo': match_largeRL1_OfflineJets_List},
62}
63
64L1JetCollections['HI'] = {
65 'L1_jFexSRJetRoI': {'MatchTo': match_HIL1_OfflineJets_List},
66 'L1_gFexSRJetRoI': {'MatchTo': match_HIL1_OfflineJets_List},
67}
68
69for case in L1JetCollections.keys():
70 try:
71 items = L1JetCollections[case].items()
72 except (AttributeError, TypeError):
73 raise RuntimeError('L1JetCollections for %s is not a mapping type'%case)
74
75 for k, d in items:
76 try:
77 d_items = d.items()
78 except (AttributeError, TypeError):
79 raise RuntimeError('L1JetCollections value for %s is not a mapping type'%case)
80
81 if 'MatchTo' not in d:
82 errmsg = 'L1Collections entry %s has no (possibly empty) MatchType list' % (
83 str(k))
84 raise RuntimeError(errmsg)
85
86# Now seeing new L1 containers of differing types. These types
87# are explicit in the C++ JetMatcher algorithm, and correspond
88# top different attributes of that algorithm.
89#
90# l1Coll2MatcherKey supplies the python name of
91# C++ component attribute.
92
93l1Coll2MatcherKey = {
94 'L1_jFexSRJetRoI': 'L1jFexSRJetRoIContainerName',
95 'L1_gFexSRJetRoI': 'L1gFexJetRoIContainerName',
96 'L1_gFexLRJetRoI': 'L1gFexJetRoIContainerName',
97}
98
99for case in L1JetCollections.keys():
100 for k, d in L1JetCollections[case].items():
101 if d['MatchTo']: # exists by previous checks. check if empty.
102 if k not in l1Coll2MatcherKey:
103 errmsg = 'Match(es) to an L1 container requested entry '\
104 '%s but no C++ MatcherAlg attribute name provided' % (str(k),)
105 raise RuntimeError(errmsg)
106
107
108# the values of Chain2L1JetCollDict are keys of L1JetCollections.
109# the keys of Chain2L1JetCollDict are used to select events before histograms are filled
110
111Chain2L1JetCollDict = dict()
112
113Chain2L1JetCollDict['pp'] = { # set L1 jet collection name for L1 jet chains
114
115 'L1_jJ40': ['L1_jFexSRJetRoI'],
116 'L1_jJ50': ['L1_jFexSRJetRoI'],
117 'L1_jJ160': ['L1_jFexSRJetRoI'],
118 'L1_jJ85p0ETA21_3jJ40p0ETA25': ['L1_jFexSRJetRoI'],
119 'L1_3jJ70p0ETA23': ['L1_jFexSRJetRoI'],
120 'L1_4jJ40': ['L1_jFexSRJetRoI'],
121
122
123 'L1_gJ20p0ETA25': ['L1_gFexSRJetRoI'],
124 'L1_gJ50p0ETA25': ['L1_gFexSRJetRoI'],
125 'L1_gJ100p0ETA25': ['L1_gFexSRJetRoI'],
126 'L1_gJ400p0ETA25': ['L1_gFexSRJetRoI'],
127
128 'L1_gLJ80p0ETA25': ['L1_gFexLRJetRoI'],
129 'L1_gLJ100p0ETA25': ['L1_gFexLRJetRoI'],
130 'L1_gLJ140p0ETA25': ['L1_gFexLRJetRoI'],
131 'L1_gLJ160p0ETA25': ['L1_gFexLRJetRoI'],
132
133 'L1_SC111-CjJ40': ['L1_jFexSRJetRoI'],
134 'L1_HT190-jJ40s5pETA21': ['L1_jFexSRJetRoI'],
135}
136
137Chain2L1JetCollDict['HI'] = {
138
139 'L1_jJ40': ['L1_jFexSRJetRoI'],
140 'L1_jJ55': ['L1_jFexSRJetRoI'],
141 'L1_jJ80': ['L1_jFexSRJetRoI'],
142
143 'L1_jJ40p30ETA49': ['L1_jFexSRJetRoI'],
144}
145
146
149
150# List of HLT jet collections (stating
151# which should be matched and to which offline jet collection
152
153JetCollections = dict()
154
155JetCollections['pp'] = {
156 'HLT_AntiKt4EMTopoJets_subjesIS' : { 'MatchTo' : 'AntiKt4EMPFlowJets'}, # default small-R EM
157 'HLT_AntiKt4EMTopoJets_subjesIS_fastftag' : { 'MatchTo' : 'NONE'}, # small-R EM jets with RoI tracking & fast flavour tagging
158 'HLT_AntiKt4EMTopoJets_subresjesgscIS_ftf' : { 'MatchTo' : 'AntiKt4EMPFlowJets'}, # a4 calo jet w/ FTF
159 'HLT_AntiKt4EMTopoJets_subjesgscIS_ftf' : { 'MatchTo' : 'AntiKt4EMPFlowJets'}, # a4 calo jet w/ calo+track GSC, reconstructed by MET
160 'HLT_AntiKt4EMPFlowJets_subjesgscIS_ftf' : { 'MatchTo' : 'AntiKt4EMPFlowJets'}, # a4 pflow w/ calo+track GSC, reconstructed by MET
161 'HLT_AntiKt4EMPFlowJets_subresjesgscIS_ftf' : { 'MatchTo' : 'AntiKt4EMPFlowJets'}, # a4 pflow w/ residual + calo+track GSC
162 'HLT_AntiKt4EMPFlowJets_nojcalib_ftf' : { 'MatchTo' : 'NONE'}, # a4 pflow nojcalib
163 'HLT_AntiKt10EMTopoRCJets_subjesIS' : { 'MatchTo' : 'NONE'}, # a10r
164 'HLT_AntiKt10LCTopoJets_subjes' : { 'MatchTo' : 'NONE'}, # a10
165 'HLT_AntiKt10LCTopoTrimmedPtFrac4SmallR20Jets_jes' : { 'MatchTo' : 'NONE'}, # a10t
166 'HLT_AntiKt10EMPFlowCSSKSoftDropBeta100Zcut10Jets_nojcalib_ftf' : { 'MatchTo' : 'NONE'}, # a10sd pflow cssk nojcalib
167 'HLT_AntiKt10EMPFlowCSSKSoftDropBeta100Zcut10Jets_jes_ftf' : { 'MatchTo' : 'NONE'}, # a10sd pflow cssk jes
168}
169
170JetCollections['HI'] = {
171 'HLT_AntiKt4HIJets' : {'MatchTo': 'AntiKt4HIJets'},
172 'HLT_AntiKt4EMPFlowJets_jes_ftf' : {'MatchTo': 'AntiKt4HIJets'},
173}
174
175
176def getChains2Monitor(inputFlags, monMode):
177
178 Chains2Monitor = dict()
179 from TrigConfigSvc.TriggerConfigAccess import getHLTMonitoringAccess
180 monAccess = getHLTMonitoringAccess(inputFlags)
181
182 # set HLT jet collection, reference chain and offline jet collection
183 # for turn-on curves
184 ListOfMonChains = monAccess.monitoredChains(signatures="jetMon", monLevels = ["shifter","t0"])
185
186 default_dict = {"HLTColl": "NONE", "RefChain": "NONE" ,"OfflineColl": "NONE"}
187 Chains2Monitor[monMode] = dict((chain, default_dict.copy()) for chain in ListOfMonChains)
188
189 if monMode == 'HI':
190 for chainName in Chains2Monitor['HI']:
191 if '_ion_' in chainName:
192 Chains2Monitor['HI'][chainName]["HLTColl"] = "HLT_AntiKt4HIJets"
193 Chains2Monitor['HI'][chainName]["OfflineColl"] = "AntiKt4HIJets"
194 else:
195 Chains2Monitor['HI'][chainName]["HLTColl"] = "HLT_AntiKt4EMPFlowJets_jes_ftf"
196 Chains2Monitor['HI'][chainName]["OfflineColl"] = "AntiKt4EMPFlowJets"
197
198 # only HLT_noalg get efficiency curves by default, so...
199 # these are additional hard-coded chains for efficiency monitoring
200 #Standard HI chains (obsolete for O+O)
201 if Chains2Monitor['HI'].get('HLT_j60_ion_L1jJ40'): Chains2Monitor['HI']['HLT_j60_ion_L1jJ40'].update({"RefChain": "HLT_noalg_L1jTE50", "OfflineColl": "AntiKt4HIJets"})
202 if Chains2Monitor['HI'].get('HLT_j75_ion_L1jJ55'): Chains2Monitor['HI']['HLT_j75_ion_L1jJ55'].update({"RefChain": "HLT_noalg_L1jTE50", "OfflineColl": "AntiKt4HIJets"})
203 if Chains2Monitor['HI'].get('HLT_j85_ion_L1jJ55'): Chains2Monitor['HI']['HLT_j85_ion_L1jJ55'].update({"RefChain": "HLT_noalg_L1jTE50", "OfflineColl": "AntiKt4HIJets"})
204 if Chains2Monitor['HI'].get('HLT_j150_ion_L1jJ80'): Chains2Monitor['HI']['HLT_j150_ion_L1jJ80'].update({"RefChain": "HLT_noalg_L1jTE50", "OfflineColl": "AntiKt4HIJets"})
205 if Chains2Monitor['HI'].get('HLT_j200_ion_L1jJ80'): Chains2Monitor['HI']['HLT_j200_ion_L1jJ80'].update({"RefChain": "HLT_noalg_L1jTE50", "OfflineColl": "AntiKt4HIJets"})
206
207 if Chains2Monitor['HI'].get('HLT_j50f_ion_L1jJ40p30ETA49'): Chains2Monitor['HI']['HLT_j50f_ion_L1jJ40p30ETA49'].update({"RefChain": "HLT_noalg_L1jTE50", "OfflineColl": "AntiKt4HIJets"})
208 if Chains2Monitor['HI'].get('HLT_j60f_ion_L1jJ40p30ETA49'): Chains2Monitor['HI']['HLT_j60f_ion_L1jJ40p30ETA49'].update({"RefChain": "HLT_noalg_L1jTE50", "OfflineColl": "AntiKt4HIJets"})
209
210 elif monMode == "pp":
211 # logic to define HLTColl, RefChain, OfflineColl
212 for chainName in Chains2Monitor['pp']:
213 Chains2Monitor['pp'][chainName]["HLTColl"] = "HLT_AntiKt4EMTopoJets_subjesIS"
214 if '_pf_' in chainName and 'a10' not in chainName:
215 Chains2Monitor['pp'][chainName]["HLTColl"] = "HLT_AntiKt4EMPFlowJets_subresjesgscIS_ftf"
216 Chains2Monitor['pp'][chainName]["OfflineColl"] = "AntiKt4EMPFlowJets"
217 elif 'a10' in chainName:
218 if 'a10t' in chainName: Chains2Monitor['pp'][chainName]["HLTColl"] = "HLT_AntiKt10LCTopoTrimmedPtFrac4SmallR20Jets_jes"
219 elif 'sd_cssk_pf' in chainName: Chains2Monitor['pp'][chainName]["HLTColl"] = "HLT_AntiKt10EMPFlowCSSKSoftDropBeta100Zcut10Jets_jes_ftf"
220 elif 'a10r' in chainName: Chains2Monitor['pp'][chainName]["HLTColl"] = "HLT_AntiKt10EMTopoRCJets_subjesIS"
221 else: Chains2Monitor['pp'][chainName]["HLTColl"] = "HLT_AntiKt10LCTopoJets_subjes"
222 elif '_noalg_' in chainName:
223 Chains2Monitor['pp'][chainName]["RefChain"] = "HLT_j45_pf_ftf_preselj20_L1jJ40" # temporarily modify to using small-R jet in turn-on for both small and large-R jets to fix tier0 jet mon crash ATR-25800!!
224 Chains2Monitor['pp'][chainName]["OfflineColl"] = "AntiKt4EMPFlowJets"
225 if 'gLJ' in chainName: Chains2Monitor['pp'][chainName]["HLTColl"] = "HLT_AntiKt10EMPFlowCSSKSoftDropBeta100Zcut10Jets_jes_ftf"
226 else: continue
227
228
229 if Chains2Monitor['pp'].get('HLT_j420_L1jJ160'): Chains2Monitor['pp']['HLT_j420_L1jJ160'].update({"RefChain": "HLT_j85_L1jJ50", "OfflineColl": "AntiKt4EMPFlowJets"})
230 if Chains2Monitor['pp'].get('HLT_3j200_L1jJ160'): Chains2Monitor['pp']['HLT_3j200_L1jJ160'].update({"RefChain": "HLT_j85_L1jJ50", "OfflineColl": "AntiKt4EMPFlowJets"})
231 if Chains2Monitor['pp'].get('HLT_4j120_L13jJ90'): Chains2Monitor['pp']['HLT_4j120_L13jJ90'].update({"RefChain": "HLT_j85_L1jJ50", "OfflineColl": "AntiKt4EMPFlowJets"})
232 if Chains2Monitor['pp'].get('HLT_5j80_pf_ftf_presel5j50_L14jJ40'): Chains2Monitor['pp']['HLT_5j80_pf_ftf_presel5j50_L14jJ40'].update({"RefChain": "HLT_j45_pf_ftf_preselj20_L1jJ40", "OfflineColl": "AntiKt4EMPFlowJets"})
233 if Chains2Monitor['pp'].get('HLT_j400_pf_ftf_L1jJ160'): Chains2Monitor['pp']['HLT_j400_pf_ftf_L1jJ160'].update({"RefChain": "HLT_j85_pf_ftf_preselj50_L1jJ50", "OfflineColl": "AntiKt4EMPFlowJets"})
234 if Chains2Monitor['pp'].get('HLT_j400_pf_ftf_preselj225_L1jJ160'): Chains2Monitor['pp']['HLT_j400_pf_ftf_preselj225_L1jJ160'].update({"RefChain": "HLT_j85_pf_ftf_preselj50_L1jJ50", "OfflineColl": "AntiKt4EMPFlowJets"})
235
236 else:
237 errmsg = 'Returned empty Chains2Monitor due to invalid monMode'
238 raise RuntimeError(errmsg)
239 return Chains2Monitor
240
241
244
245def getEtaRange(chain):
246 etaMin,etaMax = 0,2.5 # central jets by default
247
248 if 'eta490_j' in chain: #workaround for the UPC (ultra-peripheral) trigger chains
249 etaMin,etaMax = 0,4.9
250 elif 'eta' in chain:
251 etaParts = chain.split('eta')
252 etaMinTemp = etaParts[0].split('_')
253 etaMin = etaMinTemp[len(etaMinTemp)-1]
254 etaMin = int(etaMin)/10
255 etaMax = etaParts[1].split('_')[0]
256 etaMax = int(etaMax)/10
257
258 # Check for 2-3 digit number before f_ for forward triggers
259 if re.search(r'\d{2,3}f_', chain): #workaround for the HLT forward triggers with 2-3 digit numbers
260 etaMin,etaMax = 3.2,4.9
261
262 if 'a_' in chain: #new full eta range triggers
263 etaMin,etaMax = 0,4.9
264
265 return etaMin,etaMax
266
267def getBinningFromThreshold(chain,varname):
268 #default binning if nothing below applies
269 xbins, xmin, xmax = 160,0.,800000.
270 #pt and et binning based on threshold
271 if varname == "pt" or varname == "et":
272 if 'noalg' in chain:
273 if 'jJ500' in chain or 'J400' in chain: return 160,xmin,800000
274 else: return 100,xmin,500000 # good enough for L1 jJ40 & jJ100
275 else:
276 #threshold = int(chain.split("_")[1].split('j')[1])
277 threshold = int(re.search(r'\d+',chain.split("_")[1].split('j')[1]).group())
278 if threshold < 50:
279 return 40, 0., 100000.
280 if threshold < 120:
281 return 36, 20000., 200000.
282
283 xbins = 40
284 xmin = 50000.+100000.*(int(threshold/100)-1) #example: threshold = 330 -> 250 to 450; threshold = 420 -> 350 to 550
285 if threshold % 100 == 0: #gives enough low bins if threshold is an exact divider of 100 GeV such as 3j200
286 xmin = 1000.*(threshold - 100.)
287 xmax = xmin + 200000.
288 if "a10" in chain: # efficiency curve broader for large-R jets
289 xmin = xmin - 50000.
290 xmax = xmax + 50000.
291 if "pf" in chain:
292 xmax = xmax + 50000. # needed to include efficiency plateau for large-R PFlow chains
293 if "smc" in chain:
294 xmax = xmax + 50000. # efficiency plateau even higher for a10 pdf smc chains due to imperfect calibration
295 #mass binning for large-R smc chains
296 elif varname == "m":
297 xbins, xmin, xmax = 35, 30000., 100000.
298 return xbins, xmin, xmax
299
300def getHTBinning(chain,binwidth):
301 parts = chain.split('HT')
302 threshold = parts[1].split('_')[0]
303 if 'XX' in threshold:
304 threshold = threshold.split('XX')[0]
305 xmin = int(0.9 * int(threshold)) # xmin to make the threshold visible
306 xmax = xmin + 500
307 xbins = int((xmax-xmin)/binwidth)-1
308 return xbins, xmin, xmax
309
310# Add fast flavour-tag monitoring.
311# Adds a 20 GeV jet pT cut to avoid FPE WARNINGS from jets below min jet pT for RoI track association
312def addFlavourTagVariables(conf, network_prefix, flavs="cub"):
313 cutname='pt20'
314 fillerTools = []
315 for f in flavs:
316 xvar = f"{network_prefix}_p{f}"
317 varname = f"ftag_p{f}"
318 fillerTools += [HistoSpec(varname, xvar=xvar, bins=(70, -0.2, 1.2), title=f"{varname};{varname};;Entries")]
319 fastDipsSelectSpec = SelectSpec(f"{network_prefix}_{cutname}", '20<pt:GeV&|eta|<3.2', path='NoTriggerSelection/'+cutname, FillerTools=fillerTools)
320 conf.appendHistos(fastDipsSelectSpec)
321
322
325from JetMonitoring.JetMonitoringConfig import JetMonAlgSpec, HistoSpec, EventHistoSpec, SelectSpec, ToolSpec #VarSpec can be added to define specific/custom variables
326from AthenaConfiguration.ComponentFactory import CompFactory
327
328# All offline jet collections
329ExtraOfflineHists = [
330 "EMFrac",
331 "HECFrac",
332 "Jvt",
333 "JVFCorr",
334 "JvtRpt",
335 "NumTrkPt1000[0]",
336 "TrackWidthPt1000[0]",
337 "SumPtTrkPt500[0]",
338]
339
340# All online small-R jet collections
341ExtraSmallROnlineHists = [
342 HistoSpec('et:GeV;eta', (100,0,750, 50,-5,5) , title='#eta vs E_{T};E_{T} [GeV];#eta;Entries'),
343 "EMFrac",
344 "HECFrac",
345 "DetectorEta",
346 "ActiveArea",
347 "EM3Frac",
348 "Tile0Frac",
349 "LooseBad",
350]
351
352# All online large-R jet collections
353ExtraLargeROnlineHists = [
354]
355
356ExtraOnlineNJetHists = [
357 "njets",
358]
359
360# Kinematics at different scales for offline and small-R online jet collections
361OfflineScaleMomenta = [ "ConstitScale", "EMScale", "PileupScale", "EtaJESScale"]
362OnlineScaleMomenta = [ "ConstitScale" ]
363for var in [ "pt", "eta", "m" ]:
364 for offlinescale in OfflineScaleMomenta:
365 ExtraOfflineHists.append("Jet"+offlinescale+"Momentum_"+var)
366 for onlinescale in OnlineScaleMomenta:
367 ExtraSmallROnlineHists.append("Jet"+onlinescale+"Momentum_"+var)
368
369OnlineScaleMomenta.append("") #Adding this for convenience in the jet matching loop below
370OfflineScaleMomenta.append("")
371
372
373def getJetCopyAlg(injets,outjets):
374 '''
375 Schedules JetCopier tool to make a shallow copy of
376 the original offline/HLT jet container, for the JetMatcherAlg to decorate.
377 This prevents our jet monitoring from decorating
378 the original jet containers, which may end up being
379 persistified in AOD/ESD (ATLASRECTS-7168,ATR-27980,ATR-26076)
380 '''
381 jcopy = CompFactory.JetCopier(
382 "copier",
383 InputJets = injets,
384 DecorDeps=[],
385 ShallowCopy=True,
386 ShallowIO=True)
387
388 jprovider = CompFactory.JetRecAlg(
389 "jetalg_copy_"+outjets,
390 Provider = jcopy,
391 Modifiers = [],
392 OutputContainer = outjets,
393 MonTool = None)
394
395 return jprovider
396
397def getL1JetCopyAlg(injets,outjets):
398 '''
399 Schedules L1JetCopyAlgorithm to make a shallow copy of
400 the original L1 jet container, for the JetMatcherAlg to decorate.
401 This prevents our jet monitoring from decorating
402 the original jet containers, which may end up being
403 persistified in AOD/ESD (ATLASRECTS-7168,ATR-27980,ATR-26076).
404 The L1JetCopyAlgorithm is a templated class (e.g. L1JetCopyAlgorithm<JTM_JetRoIContainer>).
405 The python class name is what is generated by Athena during build time.
406 The template types are defined in JTMContainers.h.
407 '''
408 jcopy_alg = None
409 jcopy_alg_name = "l1jetcopy_alg_"+injets
410 if injets == "L1_jFexSRJetRoI":
411 jcopy_alg = CompFactory.L1JetCopyAlgorithm_JTM_jFexSRJetRoIContainer_(jcopy_alg_name)
412 elif injets in ["L1_gFexSRJetRoI", "L1_gFexLRJetRoI"]:
413 jcopy_alg = CompFactory.L1JetCopyAlgorithm_JTM_gFexJetRoIContainer_(jcopy_alg_name)
414 else:
415 raise ValueError(f"L1 jet container {injets} not recognised")
416 jcopy_alg.JetInContainerName = injets
417 jcopy_alg.JetOutContainerName = outjets
418
419 return jcopy_alg
420
421def TrigJetMonConfig(inputFlags):
422
423 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
424 cfg = ComponentAccumulator()
425
426 monMode = 'pp'
427 if inputFlags.Reco.EnableHI: monMode = 'HI'
428
429 Chains2Monitor = getChains2Monitor(inputFlags, monMode)
430
431 # Protections
432 # Add missing jet collections to JetCollections dict
433 # (this can happen if a given chain uses a jet collection that is not listed in JetCollections)
434 # TODO: make more general
435 for chain,chaindict in Chains2Monitor[monMode].items():
436 if chaindict['HLTColl'] not in JetCollections[case]: # chain will not be monitored unless HLT collection is present in JetCollections
437 JetCollections[case][chaindict['HLTColl']] = {'MatchTo': 'NONE'}
438
439 # Match HLT jets to offline jets
440 CopiedJetCollections = copy.deepcopy(JetCollections)
441 for hltColl,collDict in JetCollections[monMode].items():
442 if collDict['MatchTo'] != 'NONE':
443 copiedhltColl = f'{hltColl}_{copySuffix}'
444 CopiedJetCollections[monMode][copiedhltColl] = CopiedJetCollections[monMode].pop(hltColl)
445 jetcopyalg = getJetCopyAlg(hltColl,copiedhltColl)
446 jetcopyalg.ExtraInputs.add(('xAOD::TrigCompositeContainer',
447 'StoreGateSvc+%s' % getRun3NavigationContainerFromInput(inputFlags)))
448 cfg.addEventAlgo(jetcopyalg)
449 for jetcalibscale in OnlineScaleMomenta:
450 scalestring = "_"+jetcalibscale if jetcalibscale != "" else ""
451 name = 'Matching_{}{}_{}'.format(hltColl,scalestring,collDict['MatchTo'])
452 alg = CompFactory.JetMatcherAlg(name,
453 JetContainerName1=copiedhltColl,
454 JetContainerName2=collDict['MatchTo'],
455 JetCalibScale=jetcalibscale)
456
457 alg.ExtraInputs.add(('xAOD::TrigCompositeContainer',
458 'StoreGateSvc+%s' % getRun3NavigationContainerFromInput(inputFlags)))
459 cfg.addEventAlgo(alg)
460
461 # Match offline to offline jets
462 CopiedOfflineJetCollections = copy.deepcopy(OfflineJetCollections)
463 for offjetColl,collDict in OfflineJetCollections[monMode].items():
464 if collDict['MatchTo'] != 'NONE':
465 copiedjetcoll = f'{offjetColl}_{copySuffix}'
466 CopiedOfflineJetCollections[monMode][copiedjetcoll] = CopiedOfflineJetCollections[monMode].pop(offjetColl)
467 jetcopyalg = getJetCopyAlg(offjetColl,copiedjetcoll)
468 cfg.addEventAlgo(jetcopyalg)
469 for jetcalibscale in OfflineScaleMomenta:
470 scalestring = "_"+jetcalibscale if jetcalibscale != "" else ""
471 name = 'Matching_{}{}_{}'.format(offjetColl,scalestring,collDict['MatchTo'])
472 alg = CompFactory.JetMatcherAlg(name,
473 JetContainerName1=copiedjetcoll,
474 JetContainerName2=collDict['MatchTo'],
475 JetCalibScale=jetcalibscale)
476
477 alg.ExtraInputs.add(('xAOD::TrigCompositeContainer',
478 'StoreGateSvc+%s' % getRun3NavigationContainerFromInput(inputFlags)))
479 cfg.addEventAlgo(alg)
480
481 # Make copy of every L1 jet collection
482 # Then match L1 to offline as well as HLT jets
483 CopiedL1JetCollections = copy.deepcopy(L1JetCollections)
484 for l1jetColl,collDict in L1JetCollections[monMode].items():
485 copiedl1jetColl = f'{l1jetColl}_{copySuffix}'
486 CopiedL1JetCollections[monMode][copiedl1jetColl] = CopiedL1JetCollections[monMode].pop(l1jetColl)
487 l1jetcopyalg = getL1JetCopyAlg(l1jetColl,copiedl1jetColl)
488 l1jetcopyalg.ExtraInputs.add(('xAOD::TrigCompositeContainer',
489 'StoreGateSvc+%s' % getRun3NavigationContainerFromInput(inputFlags)))
490 cfg.addEventAlgo(l1jetcopyalg)
491 for matchjetcoll in collDict['MatchTo']:
492
493 kwds = {'name': 'Matching_{}_{}'.format(l1jetColl,matchjetcoll),
494 l1Coll2MatcherKey[l1jetColl]: copiedl1jetColl,
495 'JetContainerName2': matchjetcoll,
496 'MatchL1': True
497 }
498
499 alg = CompFactory.JetMatcherAlg(**kwds)
500 alg.ExtraInputs.add(('xAOD::TrigCompositeContainer',
501 'StoreGateSvc+%s' % getRun3NavigationContainerFromInput(inputFlags)))
502 cfg.addEventAlgo(alg)
503
504 # The following class will make a sequence, configure algorithms, and link
505 # them to GenericMonitoringTools
506 from AthenaMonitoring import AthMonitorCfgHelper
507 helper = AthMonitorCfgHelper(inputFlags,'TrigJetMonitorAlgorithm')
508 # Configure filter tools
509 from AthenaMonitoring.EventFlagFilterToolConfig import EventFlagFilterToolCfg
510 from AthenaMonitoring.BadLBFilterToolConfig import LArBadLBFilterToolCfg
511 # Loop over L1 jet collections
512 for jetcoll in CopiedL1JetCollections[monMode]:
513 l1jetconf = l1JetMonitoringConfig(inputFlags,jetcoll,CopiedL1JetCollections,monMode,'',True)
514 alg=l1jetconf.toAlg(helper)
515 alg.FilterTools = [ EventFlagFilterToolCfg(inputFlags),helper.resobj.popToolsAndMerge(LArBadLBFilterToolCfg(inputFlags))]
516
517 # Loop over L1 jet chains
518 for chain,jetcolls in Chain2L1JetCollDict[monMode].items():
519 for jetcoll in jetcolls:
520 l1chainconf = l1JetMonitoringConfig(inputFlags,jetcoll,L1JetCollections,monMode,chain)
521 alg=l1chainconf.toAlg(helper)
522 alg.FilterTools = [ EventFlagFilterToolCfg(inputFlags),helper.resobj.popToolsAndMerge(LArBadLBFilterToolCfg(inputFlags))]
523
524 # Loop over offline jet collections
525 for jetcoll in CopiedOfflineJetCollections[monMode]:
526 offlineMonitorConf = jetMonitoringConfig(inputFlags,jetcoll,CopiedOfflineJetCollections,monMode)
527 alg=offlineMonitorConf.toAlg(helper)
528 alg.FilterTools = [ EventFlagFilterToolCfg(inputFlags),helper.resobj.popToolsAndMerge(LArBadLBFilterToolCfg(inputFlags))]
529
530 # Loop over HLT jet collections
531 for jetcoll in CopiedJetCollections[monMode]:
532 monitorConf = jetMonitoringConfig(inputFlags,jetcoll,CopiedJetCollections,monMode)
533 # then we turn the full specification into properly configured algorithm and tools.
534 # we use the method 'toAlg()' defined for the specialized dictionnary 'JetMonAlgSpec'
535 monitorConf.toAlg(helper)
536
537 # Loop over HLT jet chains
538 for chain,chainDict in Chains2Monitor[monMode].items():
539 jetcoll = chainDict['HLTColl']
540 # kinematic plots
541 # only use passing jets
542 # skip for noalg chains
543 if 'noalg' not in chain:
544 chainMonitorConfT = jetChainMonitoringConfig(inputFlags,jetcoll,chain,True)
545 alg=chainMonitorConfT.toAlg(helper)
546 alg.FilterTools = [ EventFlagFilterToolCfg(inputFlags),helper.resobj.popToolsAndMerge(LArBadLBFilterToolCfg(inputFlags))]
547 # all jets
548 chainMonitorConfF = jetChainMonitoringConfig(inputFlags,jetcoll,chain,False)
549 alg=chainMonitorConfF.toAlg(helper)
550 alg.FilterTools = [ EventFlagFilterToolCfg(inputFlags),helper.resobj.popToolsAndMerge(LArBadLBFilterToolCfg(inputFlags))]
551 # efficiency plots
552 if chainDict['RefChain'] != 'NONE' and chainDict['OfflineColl'] != 'NONE':
553 effMonitorConf = jetEfficiencyMonitoringConfig(inputFlags,jetcoll,chainDict['OfflineColl'],chain,chainDict['RefChain'])
554 effMonitorConf.toAlg(helper)
555
556 cfg.merge(helper.result())
557 return cfg
558
559
560# Basic selection of histograms common for online and offline jets
561def basicJetMonAlgSpec(jetcoll,isOnline):
562 # we use a specialized dictionnary (JetMonAlgSpec) which will be translated into the final C++ tool
563 path = 'NoTriggerSelection' if isOnline else 'standardHistos/'
564 minNjetBin = 1 if isOnline else 0
565
566 TopLevelDir = 'HLT/JetMon/'
567 TopLevelDir += 'Online/' if isOnline else 'Offline/'
568
569 jetcollFolder = jetcoll
570 jetcollFolder=jetcoll.replace(f"_{copySuffix}","")
571 Conf = JetMonAlgSpec(jetcoll+"Mon",JetContainerName = jetcoll, defaultPath = path, topLevelDir=TopLevelDir, bottomLevelDir=jetcollFolder, failureOnMissingContainer=False)
572
573 # Now start filling the histo spec list
574 Conf.appendHistos(
575
576 #See knownHistos in JetStandardHistoSpecs.py for the list of standard specification.
577 #or we can directly add our custom histo specification in the form of a HistoSpec:
578 #the basic call is : HistoSpec( variable, histobins, title='histotile;xtitle,ytitle')
579
580 #Say we want a 2nd 'pt' plot but with a different binning than in the standard spec.
581 #WARNING : we can not re-use the same spec name in a given JetMonitoringAlg !!!
582 #so we give a new name AND we specify the actual variable with the argument 'xvar'
583 #(the ':GeV' means the variable is to be set at GeV scale)
584 #HistoSpec( 'lowpt', (100,0,150) , title='p_{T};p_{T} [GeV];', xvar='pt:GeV'),
585 #An equivalent solution would have been to clone the existing spec like in :
586 #knownHistos.pt.clone('lowpt',bins= (100,0,200) ),
587
588 #2D histos are usually refered to by concatenating vars with a ';' as in 'varx;vary'
589 #if the 'vax;vary' alias doesn't exist in knownHistos but 'varx' and 'vary'
590 #do exist, then a spec fot 'vax;vary' will be automatically generated.
591
592
593 #Jet multiplicity histograms can be added by using an EventHistoSpec
594 #Their specifications (pT cut, ET cut, eta cuts) must be defined in the knownEventVar dictionary within JetStandardHistoSpecs.py
595 #The following line is an example for a jet multiplicity histogram with ET>40 GeV, 1.0<|eta|<2.0, and binning of (10,0,10):
596 #EventHistoSpec('njetsEt40Eta1_2', (10,0,10), title='NJetsEt40Eta1_2;NJetsEt40Eta1_2;Entries' ),
597
598 #To select on multiple variables simultaneously, simply combine the selection strings via &
599 #Example below to select on ET > 100 GeV and |eta| > 3.2:
600 #SelectSpec( 'ETeta', '100<et:GeV&|eta|<3.2', path, FillerTools = ["pt","et","m","eta"] )
601
602 #TProfile2D : just use 3 variables. For now the sytem will automatically
603 #interpret it as a TProfile2D (the 3rd variable being profiled)
604 #"phi;eta;e", --> Average Energy vs pt and eta
605
606 #another possible selections : only sub-leading jets and highJVF
607 #SelectSpec( 'subleading',
608 # '', # no selection on variables
609 # SelectedIndex=1, # force 2nd (sub-leading) jet (we would set 0 for leading jets)
610 # path='standardHistos', # force the path where the histos are saved in the final ROOT file
611 # FillerTools = [
612 # "pt",
613 # "m",
614 # ] ),
615 #SelectSpec( 'highJVF',
616 # '0.3<JVF[0]', # JVF is a vector<float> for each jets. Here we cut on the 0th entry of this vector
617 # FillerTools = [
618 # "pt",
619 # ] ),
620
621 #1D histos
622 "pt",
623 "m",
624 "eta",
625 "phi",
626 "e",
627 "et",
628
629 #2D histos
630 "pt;m", # mass vs pt
631 "eta;phi", # phi vs eta
632 "eta;e", # energy vs eta
633 "phi;e", # energy vs phi
634
635 #Event selection
636 SelectSpec( 'central', '|eta|<3.2', path, FillerTools = ["pt","et","m"] ),
637 SelectSpec( 'forward', '3.2<|eta|', path, FillerTools = ["pt","et","m"] ),
638 SelectSpec( 'lowmu', 'avgMu<30', path, isEventVariable=True, FillerTools = ["pt","et","m","phi","eta"]),
639 SelectSpec( 'highmu', '30<avgMu', path, isEventVariable=True, FillerTools = ["pt","et","m","phi","eta"]),
640
641 EventHistoSpec('njets', (25,minNjetBin,25), title='NJets;NJets;Entries' ),
642 EventHistoSpec('njetsPt20', (25,minNjetBin,25), title='NJetsPt20;NJetsPt20;Entries' ),
643 EventHistoSpec('njetsPt50', (25,minNjetBin,25), title='NJetsPt50;NJetsPt50;Entries' ),
644
645 )
646
647 return Conf
648
649# Basic selection of histograms common for heavy ion online and offline jets
650def basicHIJetMonAlgSpec(jetcoll,isOnline):
651 # we use a specialized dictionnary (JetMonAlgSpec) which will be translated into the final C++ tool
652 path = 'NoTriggerSelection' if isOnline else 'standardHistos/'
653
654 TopLevelDir = 'HLT/JetMon/'
655 TopLevelDir += 'Online/' if isOnline else 'Offline/'
656
657 jetcollFolder = jetcoll
658 jetcollFolder=jetcoll.replace(f"_{copySuffix}","")
659 Conf = JetMonAlgSpec(jetcoll+"Mon",JetContainerName = jetcoll, defaultPath = path, topLevelDir=TopLevelDir, bottomLevelDir=jetcollFolder, failureOnMissingContainer=False)
660
661 # Now start filling the histo spec list
662 Conf.appendHistos(
663
664 #See knownHistos in JetStandardHistoSpecs.py for the list of standard specification.
665 #or we can directly add our custom histo specification in the form of a HistoSpec:
666 #the basic call is : HistoSpec( variable, histobins, title='histotile;xtitle,ytitle')
667
668 #Say we want a 2nd 'pt' plot but with a different binning than in the standard spec.
669 #WARNING : we can not re-use the same spec name in a given JetMonitoringAlg !!!
670 #so we give a new name AND we specify the actual variable with the argument 'xvar'
671 #(the ':GeV' means the variable is to be set at GeV scale)
672 #HistoSpec( 'lowpt', (100,0,150) , title='p_{T};p_{T} [GeV];', xvar='pt:GeV'),
673 #An equivalent solution would have been to clone the existing spec like in :
674 #knownHistos.pt.clone('lowpt',bins= (100,0,200) ),
675
676 #2D histos are usually refered to by concatenating vars with a ';' as in 'varx;vary'
677 #if the 'vax;vary' alias doesn't exist in knownHistos but 'varx' and 'vary'
678 #do exist, then a spec fot 'vax;vary' will be automatically generated.
679
680 #Jet multiplicity histograms can be added by using an EventHistoSpec
681 #Their specifications (pT cut, ET cut, eta cuts) must be defined in the knownEventVar dictionary within JetStandardHistoSpecs.py
682 #The following line is an example for a jet multiplicity histogram with ET>40 GeV, 1.0<|eta|<2.0, and binning of (10,0,10):
683 #EventHistoSpec('njetsEt40Eta1_2', (10,0,10), title='NJetsEt40Eta1_2;NJetsEt40Eta1_2;Entries' ),
684
685 #To select on multiple variables simultaneously, simply combine the selection strings via &
686 #Example below to select on ET > 100 GeV and |eta| > 3.2:
687 #SelectSpec( 'ETeta', '100<et:GeV&|eta|<3.2', path, FillerTools = ["pt","et","m","eta"] )
688
689 #TProfile2D : just use 3 variables. For now the sytem will automatically
690 #interpret it as a TProfile2D (the 3rd variable being profiled)
691 #"phi;eta;e", --> Average Energy vs pt and eta
692
693 #another possible selections : only sub-leading jets and highJVF
694 #SelectSpec( 'subleading',
695 # '', # no selection on variables
696 # SelectedIndex=1, # force 2nd (sub-leading) jet (we would set 0 for leading jets)
697 # path='standardHistos', # force the path where the histos are saved in the final ROOT file
698 # FillerTools = [
699 # "pt",
700 # "m",
701 # ] ),
702 #SelectSpec( 'highJVF',
703 # '0.3<JVF[0]', # JVF is a vector<float> for each jets. Here we cut on the 0th entry of this vector
704 # FillerTools = [
705 # "pt",
706 # ] ),
707
708 #1D histos
709 "pt",
710 "m",
711 "eta",
712 "phi",
713 "et",
714
715 #2D histos
716 "eta;phi", # phi vs eta
717 HistoSpec( 'pt:GeV;m:GeV', (100,0,400, 100,0,400) , title='p_{T} vs mass;p_{T} [GeV];m [GeV];Entries'),
718 HistoSpec( 'eta;et:GeV', (100,-5,5, 100,0,400) , title='#eta vs e_{T};#eta;E_{T} [GeV];Entries'),
719 HistoSpec( 'phi;et:GeV', (60,-math.pi,math.pi, 100,0,400) , title='#phi vs E_{T};#phi;E_{T} [GeV];Entries'),
720
721 #Event selection
722 SelectSpec( 'central', '|eta|<3.2', path, FillerTools = ["pt","et","m"] ),
723 SelectSpec( 'forward', '3.2<|eta|', path, FillerTools = ["pt","et","m"] ),
724 SelectSpec( 'pt60', '60<pt:GeV', path, FillerTools = ["m","phi","eta","eta;phi"]),
725
726 )
727
728 return Conf
729
730def jetMonitoringConfig(inputFlags,jetcoll,jetCollDict,monMode):
731 '''Function to configures some algorithms in the monitoring system.'''
732
733 isOnline = True if 'HLT' in jetcoll else False
734
735 if monMode == 'HI': # Heavy ion jet monitoring histos
736 conf = basicHIJetMonAlgSpec(jetcoll,isOnline)
737 else:
738 conf = basicJetMonAlgSpec(jetcoll,isOnline)
739
740 jetCollMonDetails = jetCollDict[monMode][jetcoll]
741
742 # Declare a configuration dictionnary for a JetContainer
743 if isOnline:
744 if 'AntiKt4' in jetcoll or 'a4tcem' in jetcoll:
745 if monMode == 'pp': #Use extra histos for pp only
746 for hist in ExtraSmallROnlineHists: conf.appendHistos(hist)
747 if 'ftf' in jetcoll: # dedicated histograms for FTF chains
748 conf.appendHistos("Jvt")
749 conf.appendHistos("JVFCorr")
750 conf.appendHistos("JvtRpt")
751 conf.appendHistos("SumPtTrkPt500[0]")
752 conf.appendHistos("NumTrkPt1000[0]")
753 conf.appendHistos("TrackWidthPt1000[0]")
754 if 'PF' in jetcoll: # dedicated histograms for online PFlow jets
755 conf.appendHistos("SumPtChargedPFOPt500[0]")
756 conf.appendHistos("fCharged")
757 if "subresjesgscIS" in jetcoll:
758 addFlavourTagVariables(conf,"fastDIPS20211215")
759 addFlavourTagVariables(conf,"GN120230331")
760 addFlavourTagVariables(conf,"tlaGN220240122")
761 if 'fastftag' in jetcoll:
762 addFlavourTagVariables(conf,"fastDips")
763 addFlavourTagVariables(conf, "fastGN120230327")
764 addFlavourTagVariables(conf,"fastGN220240122")
765 addFlavourTagVariables(conf,"fastGNTau20240216", flavs=["tau", "u"])
766 if 'EMTopo' in jetcoll: #dedicated histograms for online EMTopo jets
767 conf.appendHistos("Timing")
768 else:
769 for hist in ExtraLargeROnlineHists: conf.appendHistos(hist)
770 # Add matched jets plots
771 if jetCollMonDetails['MatchTo'] != 'NONE':
772 def defineHistoForHLTJetMatch(conf, parentAlg, monhelper , path):
773 # create a monitoring group with the histo path starting from the parentAlg
774 group = monhelper.addGroup(parentAlg, conf.Group, conf.topLevelDir+'/'+conf.bottomLevelDir+'/NoTriggerSelection/')
775 # define the histograms
776 for histname in [ 'ptdiff', 'energydiff', 'massdiff' ]: #defines which variable difference will be plotted
777 group.defineHistogram(histname,title=histname, type="TH1F",
778 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
779 xbins=100 , xmin=-100000., xmax=100000. ,)
780
781 for histname in [ 'ptresp', 'energyresp', 'massresp' ]:
782 group.defineHistogram(histname,title=histname, type="TH1F",
783 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
784 xbins=100 , xmin=-2., xmax=2. ,)
785
786 group.defineHistogram('ptresp,ptref;ptresp_vs_ptRef',title='ptresponse vs ptRef', type="TH2F",
787 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
788 xbins=10 , xmin=-2., xmax=2., ybins=10, ymin=0., ymax=500000.,)
789
790 group.defineHistogram('ptresp,etaref;ptresp_vs_etaRef',title='ptresponse vs etaRef', type="TH2F",
791 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
792 xbins=10 , xmin=-2., xmax=2., ybins=10, ymin=-5., ymax=5.,)
793
794 group.defineHistogram('ptref,ptresp;ptRef_vs_ptresp',title='ptRef vs ptresponse', type="TH2F",
795 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
796 xbins=100 , xmin=0., xmax=400000., ybins=80, ymin=-2., ymax=2.,)
797
798 group.defineHistogram('etaref,ptresp;etaRef_vs_ptresp',title='etaRef vs ptresponse', type="TH2F",
799 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
800 xbins=100 , xmin=-5., xmax=5., ybins=80, ymin=-2., ymax=2.,)
801
802 matchedJetColl = jetCollMonDetails['MatchTo']
803
804 # we can get specific calibration scales by adding e.g. '_EtaJESScale' to the strings
805 jetmatchKey = '{}.matched_{}'.format(jetcoll,matchedJetColl)
806 jetptdiffKey = '{}.ptdiff_{}'.format(jetcoll,matchedJetColl)
807 jetenergydiffKey = '{}.energydiff_{}'.format(jetcoll,matchedJetColl)
808 jetmassdiffKey = '{}.massdiff_{}'.format(jetcoll,matchedJetColl)
809 jetptrespKey = '{}.ptresp_{}'.format(jetcoll,matchedJetColl)
810 jetenergyrespKey = '{}.energyresp_{}'.format(jetcoll,matchedJetColl)
811 jetmassrespKey = '{}.massresp_{}'.format(jetcoll,matchedJetColl)
812 jetptrefKey = '{}.ptRef_{}'.format(jetcoll,matchedJetColl)
813 jetetarefKey = '{}.etaRef_{}'.format(jetcoll,matchedJetColl)
814 name = 'jetMatched_{}_{}'.format(jetcoll,matchedJetColl)
815 conf.appendHistos(ToolSpec('JetHistoMatchedFiller', name,
816 JetMatchedKey=jetmatchKey, JetPtDiffKey=jetptdiffKey,
817 JetEnergyDiffKey=jetenergydiffKey,
818 JetMassDiffKey=jetmassdiffKey, JetPtRespKey=jetptrespKey,
819 JetEnergyRespKey=jetenergyrespKey, JetMassRespKey=jetmassrespKey,
820 JetPtRefKey=jetptrefKey,JetEtaRefKey=jetetarefKey,
821 defineHistoFunc=defineHistoForHLTJetMatch,Group='matchedJets_'+jetcoll)
822 )
823 else: # offline
824 for hist in ExtraOfflineHists: conf.appendHistos(hist)
825 if 'AntiKt4' in jetcoll and monMode=="pp":
826 conf.appendHistos(SelectSpec('LooseBadFailedJets', 'LooseBad',
827 InverseJetSel=True,
828 FillerTools = ["pt",
829 "phi",
830 "eta"])) #cleaning variables not applicable for large-R collections
831
832 if 'PF' in jetcoll: # dedicated histograms for offline PFlow jets
833 conf.appendHistos("SumPtChargedPFOPt500[0]")
834 conf.appendHistos("fCharged")
835 elif 'EMTopo' in jetcoll:
836 conf.appendHistos("Timing")
837 if jetCollMonDetails['MatchTo'] != 'NONE':
838 def defineHistoForOfflineJetMatch(conf, parentAlg, monhelper , path):
839 # create a monitoring group with the histo path starting from the parentAlg
840 group = monhelper.addGroup(parentAlg, conf.Group, conf.topLevelDir+'/'+conf.bottomLevelDir+'/standardHistos/')
841 # define the histograms
842 for histname in [ 'ptdiff', 'energydiff', 'massdiff' ]: #defines which variable difference will be plotted
843 group.defineHistogram(histname,title=histname, type="TH1F",
844 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
845 xbins=100 , xmin=-100000., xmax=100000. ,)
846
847 for histname in [ 'ptresp', 'energyresp', 'massresp' ]:
848 group.defineHistogram(histname,title=histname, type="TH1F",
849 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
850 xbins=100 , xmin=-2., xmax=2. ,)
851
852 group.defineHistogram('ptresp,ptref;ptresp_vs_ptRef',title='ptresp vs ptRef', type="TH2F",
853 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
854 xbins=10 , xmin=-2., xmax=2., ybins=10, ymin=0., ymax=500000.,)
855
856 group.defineHistogram('ptresp,etaref;ptresp_vs_etaRef',title='ptresp vs etaRef', type="TH2F",
857 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
858 xbins=10 , xmin=-2., xmax=2., ybins=10, ymin=-5., ymax=5.,)
859
860 group.defineHistogram('ptref,ptresp;ptRef_vs_ptresp',title='ptRef vs ptresponse', type="TH2F",
861 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
862 xbins=100 , xmin=0., xmax=400000., ybins=80, ymin=-2., ymax=2.,)
863
864 group.defineHistogram('etaref,ptresp;etaRef_vs_ptresp',title='etaRef vs ptresponse', type="TH2F",
865 path='MatchedJets_{}'.format(jetCollMonDetails['MatchTo']),
866 xbins=100 , xmin=-5., xmax=5., ybins=80, ymin=-2., ymax=2.,)
867
868 matchedJetColl = jetCollMonDetails['MatchTo']
869 jetmatchKey = '{}.matched_{}'.format(jetcoll,matchedJetColl)
870 jetptdiffKey = '{}.ptdiff_{}'.format(jetcoll,matchedJetColl)
871 jetenergydiffKey = '{}.energydiff_{}'.format(jetcoll,matchedJetColl)
872 jetmassdiffKey = '{}.massdiff_{}'.format(jetcoll,matchedJetColl)
873 jetptrespKey = '{}.ptresp_{}'.format(jetcoll,matchedJetColl)
874 jetenergyrespKey = '{}.energyresp_{}'.format(jetcoll,matchedJetColl)
875 jetmassrespKey = '{}.massresp_{}'.format(jetcoll,matchedJetColl)
876 jetptrefKey = '{}.ptRef_{}'.format(jetcoll,matchedJetColl)
877 jetetarefKey = '{}.etaRef_{}'.format(jetcoll,matchedJetColl)
878 name = 'jetMatched_{}_{}'.format(jetcoll,matchedJetColl)
879 conf.appendHistos(ToolSpec('JetHistoMatchedFiller',name,
880 JetMatchedKey=jetmatchKey, JetPtDiffKey=jetptdiffKey,
881 JetEnergyDiffKey=jetenergydiffKey,
882 JetMassDiffKey=jetmassdiffKey, JetPtRespKey=jetptrespKey,
883 JetEnergyRespKey=jetenergyrespKey,
884 JetMassRespKey=jetmassrespKey,
885 JetPtRefKey=jetptrefKey, JetEtaRefKey=jetetarefKey,
886 defineHistoFunc=defineHistoForOfflineJetMatch,Group='matchedJets_'+jetcoll)
887 )
888
889 return conf
890
891def l1JetMonitoringConfig(inputFlags,jetColl, jetDict, monMode,chain='',matched=False):
892
893 from TrigJetMonitoring.L1JetMonitoringConfig import L1JetMonAlg
894 name = jetColl if chain=='' else jetColl+'_'+chain
895
896 jetCollKey = jetColl
897 jetColl = jetColl.replace(f"_{copySuffix}","")
898
899 if not jetDict[monMode][jetCollKey]['MatchTo']:
900 conf = L1JetMonAlg(name,jetColl,jetCollKey,chain)
901 else:
902 assert len(jetDict[monMode][jetCollKey]['MatchTo']) == 2
903
904 conf = L1JetMonAlg(name,jetColl,jetCollKey,chain,
905 matched,jetDict[monMode][jetCollKey]['MatchTo'][0],
906 jetDict[monMode][jetCollKey]['MatchTo'][1])
907
908 return conf
909
910def jetChainMonitoringConfig(inputFlags,jetcoll,chain,onlyUsePassingJets=True):
911 '''Function to configures some algorithms in the monitoring system.'''
912
913 jetcollFolder = jetcoll
914 chainFolder = chain
915
916 #if not athenaMT:
917 # onlyUsePassingJets = False #does not work for legacy samples yet
918 jetMonAlgSpecName = chain+"TrigMon"
919 if not onlyUsePassingJets:
920 chainFolder = chainFolder + "/ExpertHistos"
921 jetMonAlgSpecName = jetMonAlgSpecName + "_ExpertHistos"
922
923 # Define helper functions to automatize ET & eta selection strings for NJet histograms of chains
924 def getThreshold(parts):
925 return parts[1].split('_')[0]
926
927 def getEtaRangeString(chain):
928 etaMin, etaMax = 0, 32
929 if 'eta490_j' in chain: #workaround for the upc chains
930 etaMin, etaMax = 0, 49
931 elif 'eta' in chain:
932 etaParts = chain.split('eta')
933 etaMinTemp = etaParts[0].split('_')
934 etaMin = etaMinTemp[len(etaMinTemp)-1]
935 etaMax = etaParts[1].split('_')[0]
936 if int(etaMin) > 0 : etaMin = str(int(int(etaMin)/10))
937 if int(etaMax) > 0 : etaMax = str(int(int(etaMax)/10))
938 if 'f_ion' in chain:
939 etaMin, etaMax = 32, 49
940 return 'Eta{}_{}'.format(etaMin,etaMax)
941
942 def getNjetHistName(chain):
943 NjetHistName = 'NONE'
944 parts = chain.split('j')
945 # check if it is a multi-threshold multijet chain or a single-threshold multijet chain
946 multiplicity = parts[0].split('_')[1] # for single-threshold multijet chains
947 if (chain.count('_j')-chain.count('_jes')) > 1 or multiplicity != '':
948 NjetHistName = 'njetsEt{}{}'.format(getThreshold(parts),getEtaRangeString(chain))
949 return NjetHistName
950
951
952 trigConf = JetMonAlgSpec( # the usual JetMonAlgSpec
953 jetMonAlgSpecName,
954 JetContainerName = jetcoll,
955 TriggerChain = chain,
956 defaultPath = chainFolder,
957 topLevelDir="HLT/JetMon/Online/",
958 bottomLevelDir=jetcollFolder,
959 failureOnMissingContainer=True,
960 onlyPassingJets=onlyUsePassingJets,
961 isExpressStreamJob=inputFlags.Common.doExpressProcessing,
962 )
963
964 trigConf.appendHistos(
965 "pt",
966 "m",
967 "eta",
968 "et",
969 "phi",
970 )
971 for hist in ExtraOnlineNJetHists: trigConf.appendHistos(EventHistoSpec(hist, (20,0,25), title=hist+';'+hist+';Entries'))
972 # Add NjetEt and NjetPt histograms for simple scenarios
973 if 'ht' not in chain and 'HT' not in chain and 'dijet' not in chain and 'DIJET' not in chain and 'fbdj' not in chain and 'noalg' not in chain:
974 NjetHistName = getNjetHistName(chain)
975 from JetMonitoring.JetStandardHistoSpecs import knownEventVar
976 if knownEventVar.get(NjetHistName,None) is not None and NjetHistName not in ExtraOnlineNJetHists: #avoids duplication warnings for some chains
977 trigConf.appendHistos(
978 EventHistoSpec(NjetHistName, (25,0,25), title=NjetHistName+';'+NjetHistName+';Entries' ),
979 )
980 NjetHistName = NjetHistName.replace('Et','Pt')
981 if knownEventVar.get(NjetHistName,None) is not None and NjetHistName not in ExtraOnlineNJetHists:
982 trigConf.appendHistos(
983 EventHistoSpec(NjetHistName, (25,0,25), title=NjetHistName+';'+NjetHistName+';Entries' ),
984 )
985 if 'ftf' in chain and 'a10' not in chain: # track-based JVT variables for FTF chains
986 trigConf.appendHistos("Jvt")
987 trigConf.appendHistos("JVFCorr")
988 trigConf.appendHistos("JvtRpt")
989
990 if 'ht' in chain or 'HT' in chain:
991 def defineHistoForHTChain(conf, parentAlg, monhelper , path):
992 # create a monitoring group with the histo path starting from the parentAlg
993 group = monhelper.addGroup(parentAlg, conf.Group, conf.topLevelDir+jetcollFolder+'/')
994 # define the histograms
995 xbins, xmin, xmax = getHTBinning(chain,25) # bin width in GeV
996 group.defineHistogram("jetHT;HT",title="Jet HT;H_{T} [GeV];Entries", type="TH1F", path=chainFolder, xbins=xbins , xmin=xmin, xmax=xmax ,)
997 trigConf.appendHistos(ToolSpec('JetHistoHTFiller','JetHistoHTFiller_'+chain,MinPt=30.,MaxEta=3.2,FailureOnMissingContainer=False,
998 defineHistoFunc=defineHistoForHTChain,Group='jetHT_'+jetcoll))
999
1000 return trigConf
1001
1002def jetEfficiencyMonitoringConfig(inputFlags,onlinejetcoll,offlinejetcoll,chain,refChain):
1003 '''Function to configures some algorithms in the monitoring system.'''
1004
1005 jetcollFolder = onlinejetcoll
1006 chainFolder = chain
1007
1008 # We schedule a new JetAlg which will be acting only when a TriggerChain fired (using the TriggerChain from the base classes).
1009 # We'll plot 1 histo build by a dedicated JetHistoTriggEfficiency tool.
1010 # So we'll have to explicitely give a specification via the generic dicionnary 'ToolSpec'
1011 # This implies defining a little function which declares to the monitoring framework which variables to histogram and how.
1012 # this is done here.
1013 def defineHistoForJetTrigg(conf, parentAlg, monhelper , path):
1014 # create a monitoring group with the histo path starting from the parentAlg
1015 group = monhelper.addGroup(parentAlg, conf.Group, conf.topLevelDir+jetcollFolder+'/')
1016 # define the histogram, give them individual names so they don't overwrite each other
1017 append = "offlineCut_"+conf.name.split("_")[-1] if "offlineCut" in conf.name else "noOfflineCut"
1018 histname = "trigEff_vs_"+conf.Var.Name+"_"+append
1019 xbins, xmin, xmax = getBinningFromThreshold(chain,conf.Var.Name)
1020 group.defineHistogram('trigPassed,jetVar;'+histname, title=histname, type="TEfficiency",
1021 path=chainFolder,
1022 xbins=xbins , xmin=xmin, xmax=xmax,)
1023
1024 # Get jet index and eta selection for offline jets
1025 validchain = chain.replace('noalg','j0')
1026 parts = validchain.split('j')
1027 multiplicity = parts[0].split('_')[1]
1028 if multiplicity != '': index = int(multiplicity) - 1 # single-threhold multijet chains
1029 else: index = 0 # single-jet chain
1030 etaMin,etaMax = getEtaRange(chain)
1031
1032 from JetMonitoring.JetMonitoringConfig import retrieveVarToolConf
1033 trigConf = JetMonAlgSpec( # the usual JetMonAlgSpec
1034 chain+"TrigEffMon",
1035 JetContainerName = offlinejetcoll,
1036 TriggerChain = refChain, # reference chain
1037 defaultPath = chainFolder,
1038 topLevelDir = "HLT/JetMon/Online/",
1039 bottomLevelDir = jetcollFolder,
1040 failureOnMissingContainer = True,
1041 onlyPassingJets = False,
1042 )
1043 trigConf.appendHistos(
1044 SelectSpec( 'eff', '{}<|eta|<{}'.format(etaMin,etaMax), chainFolder, SelectedIndex=index, FillerTools = [
1045 # we pass directly the ToolSpec
1046 ToolSpec('JetHistoTriggEfficiency', chain,
1047 # below we pass the Properties of this JetHistoTriggEfficiency tool :
1048 Group='jetTrigGroup_'+chain,
1049 Var=retrieveVarToolConf("pt"), # In this context we can not just pass a str alias to describe a histo variable
1050 # so we use retrieveVarToolConf("pt") which returns a full specification for the "pt" histo variable.
1051 ProbeTrigChain=chain,defineHistoFunc=defineHistoForJetTrigg),
1052 ] ),
1053 )
1054
1055 if 'smc' in chain:
1056 trigConf.appendHistos(
1057 SelectSpec( 'm50', '50<m:GeV&{}<|eta|<{}'.format(etaMin,etaMax), chainFolder, SelectedIndex=index, FillerTools = [
1058 ToolSpec('JetHistoTriggEfficiency', chain+'_offlineCut_m50',
1059 Group='jetTrigGroup_'+chain+'_m50',
1060 Var=retrieveVarToolConf("pt"), # In this context we can not just pass a str alias to describe a histo variable
1061 ProbeTrigChain=chain,defineHistoFunc=defineHistoForJetTrigg
1062 ),
1063 ] ),
1064 SelectSpec( 'et500', '500<et:GeV&{}<|eta|<{}'.format(etaMin,etaMax), chainFolder, SelectedIndex=index, FillerTools = [
1065 ToolSpec('JetHistoTriggEfficiency', chain+'_offlineCut_et500',
1066 Group='jetTrigGroup_'+chain+'_et500',
1067 Var=retrieveVarToolConf("m"), # In this context we can not just pass a str alias to describe a histo variable
1068 SortJets=True,
1069 ProbeTrigChain=chain,defineHistoFunc=defineHistoForJetTrigg
1070 ),
1071 ] ),
1072 )
1073
1074 return trigConf
1075
1076if __name__=='__main__':
1077
1078 import sys,argparse
1079
1080 # Read arguments
1081 parser = argparse.ArgumentParser()
1082 parser.add_argument('--runTruthReco', action='store_true', dest='runTruthReco', default=False)
1083 parser.add_argument('--genOfflineR10PF', action='store_true', dest='genOfflineR10PF', default=False)
1084 parser.add_argument('--printDetailedConfig', action='store_true', dest='printDetailedConfig', default=False)
1085 parser.add_argument('--input', action='store', dest='inputFile')
1086 args = parser.parse_args()
1087 RunTruth = args.runTruthReco
1088 GenOfflineR10PF = args.genOfflineR10PF
1089 PrintDetailedConfig = args.printDetailedConfig
1090
1091 # Input file
1092 if args.inputFile is not None: inputFile = args.inputFile
1093 else:
1094 logger.error('ERROR: No input file provided, exiting')
1095 sys.exit(0)
1096
1097 # Setup logs
1098 from AthenaCommon.Logging import log
1099 from AthenaCommon.Constants import INFO #,DEBUG
1100 log.setLevel(INFO)
1101
1102 # Set the Athena configuration flags
1103 from AthenaConfiguration.AllConfigFlags import initConfigFlags
1104 flags = initConfigFlags()
1105 flags.Input.Files = [inputFile]
1106 flags.Input.isMC = True
1107 flags.Output.HISTFileName = 'AthenaMTMonitorOutput.root'
1108 flags.lock()
1109
1110 monMode = 'pp'
1111 if flags.Reco.EnableHI: monMode = 'HI'
1112
1113 Chains2Monitor = getChains2Monitor(flags, monMode)
1114
1115 # Protections
1116 # Add missing jet collections to JetCollections dict
1117 # (this can happen if a given chain uses a jet collection that is not listed in JetCollections)
1118 # TODO: make more general
1119 for chain,chaindict in Chains2Monitor[monMode].items():
1120 if chaindict['HLTColl'] not in JetCollections[case]: # chain will not be monitored unless HLT collection is present in JetCollections
1121 JetCollections[case][chaindict['HLTColl']] = {'MatchTo': 'NONE'}
1122
1123 # Initialize configuration object, add accumulator, merge, and run.
1124 from AthenaConfiguration.MainServicesConfig import MainServicesCfg
1125 from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
1126 cfg = MainServicesCfg(flags)
1127
1128 # Define the output list
1129 outputlist = ["xAOD::EventInfo#*","xAOD::VertexContainer#*","xAOD::JetContainer#AntiKt4*Jets","xAOD::JetAuxContainer#AntiKt4*JetsAux.-PseudoJet","xAOD::JetContainer#HLT_*","xAOD::JetAuxContainer#HLT_*Aux.-PseudoJet","xAOD::ShallowAuxContainer#HLT_*Aux.-PseudoJet"]
1130 # Reconstruct small-R truth jets
1131 if RunTruth:
1132 from JetRecConfig.StandardSmallRJets import AntiKt4Truth # import the standard definitions
1133 # Add the components from our jet reconstruction job
1134 from JetRecConfig.JetRecConfig import JetRecCfg
1135 comp = JetRecCfg(AntiKt4Truth,flags)
1136 cfg.merge(comp)
1137 # add jets to the output list
1138 key = "{0}Jets".format(AntiKt4Truth.basename)
1139 outputlist += ["xAOD::JetContainer#"+key,"xAOD::JetAuxContainer#"+key+"Aux.-PseudoJet"]
1140
1141 # Reconstruct offline large-R PFlow CSSK+SD jets
1142 if GenOfflineR10PF:
1143 from JetRecConfig.JetDefinition import JetConstitSeq, JetDefinition, xAODType
1144 EMPFlowCSSK = JetConstitSeq("EMPFlowCSSK", xAODType.ParticleFlow, ["CorrectPFO","CS","SK","CHS"], "JetETMissParticleFlowObjects", "CSSKParticleFlowObjects", label="EMPFlowCSSK")
1145 AntiKt10EMPFlowCSSK = JetDefinition("AntiKt",1.0,EMPFlowCSSK,ptmin=2e3,)
1146 AntiKt10EMPFlowCSSK.modifiers = ["ConstitFourMom","Sort","Filter:2000"]
1147 from JetRecConfig.JetGrooming import JetSoftDrop
1148 from JetRecConfig.StandardLargeRJets import standardrecomods,substrmods
1149 AntiKt10EMPFlowCSSKSoftDrop = JetSoftDrop(AntiKt10EMPFlowCSSK,modifiers=standardrecomods+substrmods,ZCut=0.1,Beta=1.0) # standard SoftDrop
1150 # Add the components from our jet reconstruction job
1151 from JetRecConfig.JetRecConfig import JetRecCfg
1152 comp = JetRecCfg(AntiKt10EMPFlowCSSKSoftDrop,flags)
1153 cfg.merge(comp)
1154 # add jets to the output list
1155 key = "{0}Jets".format(AntiKt10EMPFlowCSSKSoftDrop.basename)
1156 outputlist += ["xAOD::JetContainer#"+key,"xAOD::JetAuxContainer#"+key+"Aux.-PseudoJet"]
1157
1158 # Write new jet collections to AOD
1159 if RunTruth or GenOfflineR10PF:
1160 # Get the output stream components
1161 from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
1162 cfg.merge(OutputStreamCfg(flags,"xAOD",ItemList=outputlist))
1163
1164 cfg.merge(PoolReadCfg(flags))
1165
1166 # The following class will make a sequence, configure algorithms, and link
1167 # them to GenericMonitoringTools
1168 from AthenaMonitoring import AthMonitorCfgHelper
1169 helper = AthMonitorCfgHelper(flags,'TrigJetMonitorAlgorithm')
1170 cfg.merge(helper.result()) # merge it to add the sequence needed to add matchers
1171
1172 # Match HLT jets to offline jets
1173 for hltColl,collDict in JetCollections[monMode].items():
1174 if collDict['MatchTo'] != 'NONE':
1175 for jetcalibscale in OnlineScaleMomenta:
1176 scalestring = "_"+jetcalibscale if jetcalibscale != "" else ""
1177 name = 'Matching_{}{}_{}'.format(hltColl,scalestring,collDict['MatchTo'])
1178 alg = CompFactory.JetMatcherAlg(name, JetContainerName1=hltColl,JetContainerName2=collDict['MatchTo'],JetCalibScale=jetcalibscale)
1179 alg.ExtraInputs.add(('xAOD::TrigCompositeContainer','StoreGateSvc+%s' % getRun3NavigationContainerFromInput(flags)))
1180 cfg.addEventAlgo(alg,sequenceName='AthMonSeq_TrigJetMonitorAlgorithm') # Add matchers to monitoring alg sequence
1181
1182 # Match offline to offline jets
1183 for offjetColl,collDict in OfflineJetCollections[monMode].items():
1184 if collDict['MatchTo'] != 'NONE':
1185 for jetcalibscale in OfflineScaleMomenta:
1186 scalestring = "_"+jetcalibscale if jetcalibscale != "" else ""
1187 name = 'Matching_{}{}_{}'.format(offjetColl,scalestring,collDict['MatchTo'])
1188 alg = CompFactory.JetMatcherAlg(name, JetContainerName1=offjetColl,JetContainerName2=collDict['MatchTo'],JetCalibScale=jetcalibscale)
1189 alg.ExtraInputs.add(('xAOD::TrigCompositeContainer','StoreGateSvc+%s' % getRun3NavigationContainerFromInput(flags)))
1190 cfg.addEventAlgo(alg,sequenceName='AthMonSeq_TrigJetMonitorAlgorithm')
1191
1192 # Match L1 to offline as well as HLT jets
1193 for l1jetColl,collDict in L1JetCollections[monMode].items():
1194 for matchjetcoll in collDict['MatchTo']:
1195 if matchjetcoll != 'NONE':
1196 name = 'Matching_{}_{}'.format(l1jetColl,matchjetcoll)
1197 alg = CompFactory.JetMatcherAlg(name, L1JetContainerName1=l1jetColl,JetContainerName2=matchjetcoll,MatchL1=True)
1198 alg.ExtraInputs.add(('xAOD::TrigCompositeContainer','StoreGateSvc+%s' % getRun3NavigationContainerFromInput(flags)))
1199 cfg.addEventAlgo(alg,sequenceName='AthMonSeq_TrigJetMonitorAlgorithm')
1200
1201 # Loop over L1 jet collectoins
1202 for jetcoll in L1JetCollections[monMode]:
1203 l1jetconf = l1JetMonitoringConfig(flags,jetcoll,L1JetCollections,monMode,'',True)
1204 l1jetconf.toAlg(helper)
1205
1206 # Loop over L1 jet chains
1207 for chain,jetcoll in Chain2L1JetCollDict[monMode].items():
1208 l1chainconf = l1JetMonitoringConfig(flags,jetcoll,L1JetCollections,monMode,chain)
1209 l1chainconf.toAlg(helper)
1210
1211 # Loop over offline jet collections
1212 for jetcoll in OfflineJetCollections[monMode]:
1213 offlineMonitorConf = jetMonitoringConfig(flags,jetcoll,OfflineJetCollections,monMode)
1214 offlineMonitorConf.toAlg(helper)
1215
1216 # Loop over HLT jet collections
1217 for jetcoll in JetCollections[monMode]:
1218 monitorConf = jetMonitoringConfig(flags,jetcoll,JetCollections,monMode)
1219 # then we turn the full specification into properly configured algorithm and tools.
1220 # we use the method 'toAlg()' defined for the specialized dictionnary 'JetMonAlgSpec'
1221 monitorConf.toAlg(helper)
1222
1223 # Loop over HLT jet chains
1224 for chain,chainDict in Chains2Monitor[monMode].items():
1225 jetcoll = chainDict['HLTColl']
1226 # kinematic plots
1227 # only passing jets
1228 # skip for noalg chains
1229 if 'noalg' not in chain:
1230 chainMonitorConfT = jetChainMonitoringConfig(flags,jetcoll,chain,True)
1231 chainMonitorConfT.toAlg(helper)
1232 # all jets
1233 chainMonitorConfF = jetChainMonitoringConfig(flags,jetcoll,chain,False)
1234 chainMonitorConfF.toAlg(helper)
1235 # efficiency plots
1236 if chainDict['RefChain'] != 'NONE' and chainDict['OfflineColl'] != 'NONE':
1237 effMonitorConf = jetEfficiencyMonitoringConfig(flags, jetcoll,
1238 chainDict['OfflineColl'], chain,
1239 chainDict['RefChain'])
1240 effMonitorConf.toAlg(helper)
1241
1242 cfg.merge(helper.result())
1243
1244 # Print config
1245 cfg.printConfig(withDetails=PrintDetailedConfig)
1246
1247 cfg.run()
CP::CorrectionCode getThreshold(Int_t &threshold, const std::string &trigger)
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
getEtaRange(chain)
Helpful functions.
basicJetMonAlgSpec(jetcoll, isOnline)
jetMonitoringConfig(inputFlags, jetcoll, jetCollDict, monMode)
jetChainMonitoringConfig(inputFlags, jetcoll, chain, onlyUsePassingJets=True)
l1JetMonitoringConfig(inputFlags, jetColl, jetDict, monMode, chain='', matched=False)
getChains2Monitor(inputFlags, monMode)
basicHIJetMonAlgSpec(jetcoll, isOnline)
jetEfficiencyMonitoringConfig(inputFlags, onlinejetcoll, offlinejetcoll, chain, refChain)
addFlavourTagVariables(conf, network_prefix, flavs="cub")