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