ATLAS Offline Software
Loading...
Searching...
No Matches
JetAnalysisConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3
4
5# AnaAlgorithm import(s):
6from AnalysisAlgorithmsConfig.ConfigBlock import ConfigBlock
7from AnalysisAlgorithmsConfig.ConfigSequence import groupBlocks
8from AnalysisAlgorithmsConfig.ConfigAccumulator import DataType
9from AthenaCommon.SystemOfUnits import GeV
10from AthenaConfiguration.Enums import LHCPeriod
11from AthenaCommon.Logging import logging
12import re
13
14
15class PreJetAnalysisConfig (ConfigBlock) :
16 """the ConfigBlock for the common preprocessing of jet sequences"""
17
18 def __init__ (self) :
19 super (PreJetAnalysisConfig, self).__init__ ()
20 self.addOption ('containerName', '', type=str,
21 noneAction='error',
22 info="the name of the output container after calibration.")
23 self.addOption ('jetCollection', '', type=str,
24 noneAction='error',
25 info="the jet container to run on. It is interpreted to determine "
26 "the correct config blocks to call for small- or large-R jets.")
27 self.addOption('outputTruthLabelIDs', False, type=bool,
28 info='Enable or disable HadronConeExclTruthLabelID and PartonTruthLabelID decorations')
29 # TODO: add info string
30 self.addOption ('runOriginalObjectLink', False, type=bool,
31 info="")
32 self.addOption ('runGhostMuonAssociation', None, type=bool,
33 info="whether to set up the jet-ghost-muon association algorithm "
34 "CP::JetGhostMuonAssociationAlg. The default is True for non-PHYSLITE and False for PHYSLITE.")
35 self.addOption ('runTruthJetTagging', None, type=bool,
36 info="whether to set up the jet truth tagging algorithm "
37 "CP::JetTruthTagAlg. The default is True.")
38
39 def instanceName (self) :
40 """Return the instance name for this block"""
41 return self.containerName
42
43 def makeAlgs (self, config) :
44
45
46 if config.isPhyslite() and self.jetCollection == 'AntiKt4EMPFlowJets' :
47 config.setSourceName (self.containerName, "AnalysisJets", originalName = self.jetCollection)
48 elif config.isPhyslite() and self.jetCollection == 'AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets' :
49 config.setSourceName (self.containerName, "AnalysisLargeRJets", originalName = self.jetCollection)
50 else :
51 config.setSourceName (self.containerName, self.jetCollection, originalName = self.jetCollection)
52
53 # Relink original jets in case of b-tagging calibration
55 alg = config.createAlgorithm( 'CP::AsgOriginalObjectLinkAlg',
56 'JetOriginalObjectLinkAlg',
57 reentrant=True )
58 alg.baseContainerName = self.jetCollection
59 alg.particles = config.readName (self.containerName)
60 if config.wantCopy (self.containerName) :
61 alg.particlesOut = config.copyName (self.containerName)
62 alg.preselection = config.getPreselection (self.containerName, '')
63
64 # Set up the jet ghost muon association algorithm:
65 if (self.runGhostMuonAssociation is None and not config.isPhyslite()) or \
66 (self.runGhostMuonAssociation is True):
67 alg = config.createAlgorithm( 'CP::JetGhostMuonAssociationAlg',
68 'JetGhostMuonAssociationAlg' )
69 alg.jets = config.readName (self.containerName)
70 if config.isPhyslite():
71 alg.muons = "AnalysisMuons"
72 if config.wantCopy (self.containerName) :
73 alg.jetsOut = config.copyName (self.containerName)
74
75 # NB: I'm assuming that the truth tagging is done in PHYSLITE, if not this will
76 # need to change
77 if (self.runTruthJetTagging or (self.runTruthJetTagging is None)
78 ) and config.dataType() is not DataType.Data:
79 # Decorate jets with isHS labels (required to retrieve Jvt SFs)
80 alg = config.createAlgorithm( 'CP::JetDecoratorAlg', 'JetPileupLabelAlg' )
81 config.addPrivateTool( 'decorator', 'JetPileupLabelingTool' )
82 alg.jets = config.readName (self.containerName)
83 alg.jetsOut = config.copyName (self.containerName)
84 alg.decorator.RecoJetContainer = alg.jetsOut.replace ('%SYS%', 'NOSYS')
85 alg.decorator.SuppressOutputDependence=True
86
87 # Set up shallow copy if needed and not yet done
88 if config.wantCopy (self.containerName) :
89 alg = config.createAlgorithm( 'CP::AsgShallowCopyAlg', 'JetShallowCopyAlg' )
90 alg.input = config.readName (self.containerName)
91 alg.output = config.copyName (self.containerName)
92
93 config.addOutputVar (self.containerName, 'pt', 'pt')
94 config.addOutputVar (self.containerName, 'eta', 'eta', noSys=True)
95 config.addOutputVar (self.containerName, 'phi', 'phi', noSys=True)
96 config.addOutputVar (self.containerName, 'charge', 'charge', noSys=True, enabled=False)
97
98 if self.outputTruthLabelIDs and config.dataType() is not DataType.Data:
99 config.addOutputVar (self.containerName, 'HadronConeExclTruthLabelID', 'HadronConeExclTruthLabelID', noSys=True)
100 config.addOutputVar (self.containerName, 'PartonTruthLabelID', 'PartonTruthLabelID', noSys=True)
101
102
103
104class SmallRJetAnalysisConfig (ConfigBlock) :
105 """the ConfigBlock for the small-r jet sequence"""
106
107 def __init__ (self) :
108 super (SmallRJetAnalysisConfig, self).__init__ ()
109 self.addOption ('containerName', '', type=str,
110 noneAction='error',
111 info="the name of the output container after calibration.")
112 self.addOption ('jetCollection', '', type=str,
113 noneAction='error',
114 info="the jet container to run on. It is interpreted to determine "
115 "the correct config blocks to call for small- or large-R jets.")
116 # TODO: add info string
117 self.addOption ('jetInput', '', type=str,
118 noneAction='error',
119 info="")
120 self.addOption ('runJvtUpdate', False, type=bool,
121 info="whether to update the JVT. The default is False.")
122 self.addOption ('runNNJvtUpdate', False, type=bool,
123 info="whether to update the NN-JVT. The default is False.")
124 self.addOption ('runJvtSelection', True, type=bool,
125 info="whether to run JVT selection. The default is True.")
126 self.addOption ('runFJvtSelection', False, type=bool,
127 info="whether to run forward JVT selection. The default is False.")
128 self.addOption ('jvtWP', "FixedEffPt", type=str,
129 info="which Jvt WP to apply. The default is FixedEffPt.")
130 self.addOption ('fJvtWP', "Loose", type=str,
131 info="which fJvt WP to apply. The default is Loose.")
132 self.addOption ('runJvtEfficiency', True, type=bool,
133 info="whether to calculate the JVT efficiency. The default is True.")
134 self.addOption ('runFJvtEfficiency', False, type=bool,
135 info="whether to calculate the forward JVT efficiency. The default is False.")
136 self.addOption ('recalibratePhyslite', True, type=bool,
137 info="whether to run the CP::JetCalibrationAlg on PHYSLITE derivations. "
138 "The default is True.")
139 # Calibration tool options
140 self.addOption ('calibToolConfigFile', None, type=str,
141 info="name (str) of the config file to use for the jet calibration "
142 "tool. Expert option to override JetETmiss recommendations. The "
143 "default is None.",
144 expertMode=True)
145 self.addOption ('calibToolCalibArea', None, type=str,
146 info="name (str) of the CVMFS area to use for the jet calibration "
147 "tool. Expert option to override JetETmiss recommendations. The "
148 "default is None.",
149 expertMode=True)
150 self.addOption ('calibToolCalibSeq', None, type=str,
151 info="name (str) of the sequence to use for the jet calibration "
152 "tool (e.g. 'JetArea_Residual_EtaJES_GSC'). Expert option to override "
153 "JetETmiss recommendations. The default is None.",
154 expertMode=True)
155
156 def instanceName (self) :
157 """Return the instance name for this block"""
158 return self.containerName
159
160 def makeAlgs (self, config) :
161
162 jetCollectionName=self.jetCollection
163 if(self.jetCollection=="AnalysisJets") :
164 jetCollectionName="AntiKt4EMPFlowJets"
165 if(self.jetCollection=="AnalysisLargeRJets") :
166 jetCollectionName="AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets"
167
168 if self.jetInput not in ["EMTopo", "EMPFlow", "HI"]:
169 raise ValueError(
170 "Unsupported input type '{0}' for R=0.4 jets!".format(self.jetInput) )
171
172 if self.jvtWP not in ["FixedEffPt"]:
173 raise ValueError(
174 "Unsupported NNJvt WP '{0}'".format(self.jvtWP) )
175
176 if self.fJvtWP not in ["Loose", "Tight", "Tighter"]:
177 raise ValueError(
178 "Unsupported fJvt WP '{0}'".format(self.fJvtWP) )
179
180 if not config.isPhyslite() or self.recalibratePhyslite:
181 # Prepare the jet calibration algorithm
182 alg = config.createAlgorithm( 'CP::JetCalibrationAlg', 'JetCalibrationAlg' )
183 config.addPrivateTool( 'calibrationTool', 'JetCalibrationTool' )
184 alg.calibrationTool.JetCollection = jetCollectionName[:-4]
185 # Get the correct string to use in the config file name
186 if self.jetInput == "EMPFlow":
187 if config.geometry() is LHCPeriod.Run2:
188 configFile = "PreRec_R22_PFlow_ResPU_EtaJES_GSC_February23_230215.config"
189 alg.calibrationTool.CalibArea = "00-04-82"
190 elif config.geometry() >= LHCPeriod.Run3:
191 configFile = "AntiKt4EMPFlow_MC23a_PreRecR22_Phase2_CalibConfig_ResPU_EtaJES_GSC_241208_InSitu.config"
192 alg.calibrationTool.CalibArea = "00-04-83"
193 elif self.jetInput == "HI":
194 if config.geometry() is LHCPeriod.Run2:
195 configFile = "JES_MC16_HI_Jan2021_5TeV.config"
196 if config.geometry() is LHCPeriod.Run3:
197 configFile = "AntiKt4HI_JES_constants_11-05-2024_13p6TeVFinalConfiguration.config"
198 alg.calibrationTool.CalibArea = "00-04-83"
199 else:
200 if config.dataType() is DataType.FastSim:
201 configFile = "JES_MC16Recommendation_AFII_{0}_Apr2019_Rel21.config"
202 else:
203 configFile = "JES_MC16Recommendation_Consolidated_{0}_Apr2019_Rel21.config"
204 configFile = configFile.format(self.jetInput)
205 if self.calibToolCalibArea is not None:
206 alg.calibrationTool.CalibArea = self.calibToolCalibArea
207 if self.calibToolConfigFile is not None:
208 configFile = self.calibToolConfigFile
209 alg.calibrationTool.ConfigFile = configFile
210 if config.dataType() is DataType.Data:
211 if self.jetInput == "HI":
212 if config.geometry() is LHCPeriod.Run2:
213 alg.calibrationTool.CalibSequence = 'EtaJES_Insitu'
214 if config.geometry() is LHCPeriod.Run3:
215 alg.calibrationTool.CalibSequence = 'EtaJES'
216 else:
217 alg.calibrationTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC_Insitu'
218 else:
219 if self.jetInput == "EMPFlow":
220 alg.calibrationTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC'
221 elif self.jetInput == "HI":
222 alg.calibrationTool.CalibSequence = 'EtaJES'
223 else:
224 alg.calibrationTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC_Smear'
225 if self.calibToolCalibSeq is not None:
226 alg.calibrationTool.CalibSequence = self.calibToolCalibSeq
227 alg.calibrationTool.IsData = (config.dataType() is DataType.Data)
228 alg.jets = config.readName (self.containerName)
229 alg.jetsOut = config.copyName (self.containerName)
230
231 # Set up the JVT update algorithm:
232 if self.runJvtUpdate :
233 alg = config.createAlgorithm( 'CP::JvtUpdateAlg', 'JvtUpdateAlg' )
234 config.addPrivateTool( 'jvtTool', 'JetVertexTaggerTool' )
235 alg.jvtTool.JetContainer = self.jetCollection
236 alg.jvtTool.SuppressInputDependence=True
237 alg.jets = config.readName (self.containerName)
238 alg.jetsOut = config.copyName (self.containerName)
239 alg.preselection = config.getPreselection (self.containerName, '')
240
242 assert self.jetInput=="EMPFlow", "NN JVT only defined for PFlow jets"
243 alg = config.createAlgorithm( 'CP::JetDecoratorAlg', 'NNJvtUpdateAlg' )
244 config.addPrivateTool( 'decorator', 'JetPileupTag::JetVertexNNTagger' )
245 # Set this actually to the *output* collection
246 alg.jets = config.readName (self.containerName)
247 alg.jetsOut = config.copyName (self.containerName)
248 alg.decorator.JetContainer = alg.jetsOut.replace ('%SYS%', 'NOSYS')
249 alg.decorator.SuppressInputDependence=True
250 alg.decorator.SuppressOutputDependence=True
251
252 # Set up the jet efficiency scale factor calculation algorithm
253 # Change the truthJetCollection property to AntiKt4TruthWZJets if preferred
255 assert self.jetInput=="EMPFlow", "NNJvt WPs and SFs only valid for PFlow jets"
256 alg = config.createAlgorithm('CP::AsgSelectionAlg', 'JvtSelectionAlg')
257 config.addPrivateTool('selectionTool', 'CP::NNJvtSelectionTool')
258 alg.selectionTool.JetContainer = config.readName(self.containerName)
259 alg.selectionTool.JvtMomentName = "NNJvt"
260 alg.selectionTool.WorkingPoint = self.jvtWP
261 alg.selectionTool.MaxPtForJvt = 60*GeV
262 alg.selectionDecoration = "jvt_selection,as_char"
263 alg.particles = config.readName(self.containerName)
264
265 if self.runJvtEfficiency and config.dataType() is not DataType.Data:
266 alg = config.createAlgorithm( 'CP::JvtEfficiencyAlg', 'JvtEfficiencyAlg' )
267 config.addPrivateTool( 'efficiencyTool', 'CP::NNJvtEfficiencyTool' )
268 alg.efficiencyTool.JetContainer = config.readName(self.containerName)
269 alg.efficiencyTool.MaxPtForJvt = 60*GeV
270 alg.efficiencyTool.WorkingPoint = self.jvtWP
271 if config.geometry() is LHCPeriod.Run2:
272 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/NNJvtSFFile_Run2_EMPFlow.root"
273 else:
274 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/NNJvtSFFile_Run3_EMPFlow.root"
275 alg.selection = 'jvt_selection,as_char'
276 alg.scaleFactorDecoration = 'jvt_effSF_%SYS%'
277 alg.outOfValidity = 2
278 alg.outOfValidityDeco = 'no_jvt'
279 alg.skipBadEfficiency = False
280 alg.jets = config.readName (self.containerName)
281 alg.preselection = config.getPreselection (self.containerName, '')
282 config.addOutputVar (self.containerName, alg.scaleFactorDecoration, 'jvtEfficiency')
283 config.addSelection (self.containerName, 'baselineJvt', 'jvt_selection,as_char', preselection=False)
284
286 assert self.jetInput=="EMPFlow", "fJvt WPs and SFs only valid for PFlow jets"
287 alg = config.createAlgorithm('CP::AsgSelectionAlg', 'FJvtSelectionAlg')
288 config.addPrivateTool('selectionTool', 'CP::FJvtSelectionTool')
289 alg.selectionTool.JetContainer = config.readName(self.containerName)
290 alg.selectionTool.JvtMomentName = "DFCommonJets_fJvt"
291 alg.selectionTool.WorkingPoint = self.fJvtWP
292 alg.selectionDecoration = "fjvt_selection,as_char"
293 alg.particles = config.readName(self.containerName)
294
295 if self.runFJvtEfficiency and config.dataType() is not DataType.Data:
296 alg = config.createAlgorithm( 'CP::JvtEfficiencyAlg', 'FJvtEfficiencyAlg' )
297 config.addPrivateTool( 'efficiencyTool', 'CP::FJvtEfficiencyTool' )
298 alg.efficiencyTool.JetContainer = config.readName(self.containerName)
299 alg.efficiencyTool.WorkingPoint = self.fJvtWP
300 if config.geometry() is LHCPeriod.Run2:
301 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/fJvtSFFile_Run2_EMPFlow.root"
302 else:
303 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/fJvtSFFile_Run3_EMPFlow.root"
304 alg.selection = 'fjvt_selection,as_char'
305 alg.scaleFactorDecoration = 'fjvt_effSF_%SYS%'
306 alg.outOfValidity = 2
307 alg.outOfValidityDeco = 'no_fjvt'
308 alg.skipBadEfficiency = False
309 alg.jets = config.readName (self.containerName)
310 alg.preselection = config.getPreselection (self.containerName, '')
311 config.addOutputVar (self.containerName, alg.scaleFactorDecoration, 'fjvtEfficiency')
312 config.addSelection (self.containerName, 'baselineFJvt', 'fjvt_selection,as_char', preselection=False)
313
314 # Additional decorations
315 alg = config.createAlgorithm( 'CP::AsgEnergyDecoratorAlg', 'AsgEnergyDecoratorAlg' )
316 alg.particles = config.readName (self.containerName)
317
318 config.addOutputVar (self.containerName, 'e_%SYS%', 'e')
319
320
321class RScanJetAnalysisConfig (ConfigBlock) :
322 """the ConfigBlock for the r-scan jet sequence"""
323
324 def __init__ (self) :
325 super (RScanJetAnalysisConfig, self).__init__ ()
326 self.addOption ('containerName', '', type=str,
327 noneAction='error',
328 info="the name of the output container after calibration.")
329 self.addOption ('jetCollection', '', type=str,
330 noneAction='error',
331 info="the jet container to run on. It is interpreted to determine "
332 "the correct config blocks to call for small- or large-R jets.")
333 # TODO: add info string
334 self.addOption ('jetInput', '', type=str,
335 noneAction='error',
336 info="")
337 # TODO: add info string
338 self.addOption ('radius', None, type=int,
339 noneAction='error',
340 info="")
341 self.addOption ('recalibratePhyslite', True, type=bool,
342 info="whether to run the CP::JetCalibrationAlg on PHYSLITE "
343 "derivations. The default is True.")
344
345 def instanceName (self) :
346 """Return the instance name for this block"""
347 return self.containerName
348
349 def makeAlgs (self, config) :
350
351 log = logging.getLogger('RScanJetAnalysisConfig')
352
353 jetCollectionName=self.jetCollection
354 if(self.jetCollection=="AnalysisJets") :
355 jetCollectionName="AntiKt4EMPFlowJets"
356 if(self.jetCollection=="AnalysisLargeRJets") :
357 jetCollectionName="AntiKt10LCTopoTrimmedPtFrac5SmallR20Jets"
358
359 if not config.isPhyslite() or self.recalibratePhyslite:
360 if self.jetInput != "LCTopo":
361 raise ValueError(
362 "Unsupported input type '{0}' for R-scan jets!".format(self.jetInput) )
363 # Prepare the jet calibration algorithm
364 alg = config.createAlgorithm( 'CP::JetCalibrationAlg', 'JetCalibrationAlg' )
365 config.addPrivateTool( 'calibrationTool', 'JetCalibrationTool' )
366 alg.calibrationTool.JetCollection = jetCollectionName[:-4]
367 alg.calibrationTool.ConfigFile = \
368 "JES_MC16Recommendation_Rscan{0}LC_Feb2022_R21.config".format(self.radius)
369 if config.dataType() is DataType.Data:
370 alg.calibrationTool.CalibSequence = "JetArea_Residual_EtaJES_GSC_Insitu"
371 else:
372 alg.calibrationTool.CalibSequence = "JetArea_Residual_EtaJES_GSC_Smear"
373 alg.calibrationTool.IsData = (config.dataType() is DataType.Data)
374 alg.jets = config.readName (self.containerName)
375 # Logging would be good
376 log.warning("Uncertainties for R-Scan jets are not yet released!")
377
378
379def _largeLCTopoConfigFile(config, self):
380 is_sim = config.dataType() in {DataType.FullSim}
381 if self.largeRMass == "Comb":
382 if config.dataType() is DataType.Data:
383 return "JES_MC16recommendation_FatJet_Trimmed_JMS_comb_March2021.config"
384 if is_sim:
385 return "JES_MC16recommendation_FatJet_Trimmed_JMS_comb_17Oct2018.config"
386 elif self.largeRMass == "Calo":
387 if config.dataType() is DataType.Data:
388 return "JES_MC16recommendation_FatJet_Trimmed_JMS_comb_March2021.config"
389 if is_sim:
390 return "JES_MC16recommendation_FatJet_Trimmed_JMS_calo_12Oct2018.config "
391 elif self.largeRMass == "TA":
392 if config.dataType() is DataType.Data:
393 return "JES_MC16recommendation_FatJet_Trimmed_JMS_comb_March2021.config"
394 if is_sim:
395 return "JES_MC16recommendation_FatJet_Trimmed_JMS_TA_12Oct2018.config"
396 return None
397
398
399class LargeRJetAnalysisConfig (ConfigBlock) :
400 """the ConfigBlock for the large-r jet sequence"""
401
402 def __init__ (self) :
403 super (LargeRJetAnalysisConfig, self).__init__ ()
404 self.addOption ('containerName', '', type=str,
405 noneAction='error',
406 info="the name of the output container after calibration.")
407 self.addOption ('jetCollection', '', type=str,
408 noneAction='error',
409 info="the jet container to run on. It is interpreted to determine "
410 "the correct config blocks to call for small- or large-R jets.")
411 # TODO: add info string
412 self.addOption ('jetInput', '', type=str,
413 noneAction='error',
414 info="")
415 # TODO: add info string
416 self.addOption ('largeRMass', "Comb", type=str,
417 info="")
418 self.addOption ('recalibratePhyslite', True, type=bool,
419 info="whether to run the CP::JetCalibrationAlg on PHYSLITE "
420 "derivations. The default is True.")
421 self.addOption ('systematicsModelJMR', "Full", type=str,
422 info="the NP reduction scheme to use for JMR: Full, Simple. The default is Full.")
423 # Adding these options to override the jet uncertainty config file when we have new recommendations
424 # Calibration tool options
425 self.addOption ('calibToolConfigFile', None, type=str,
426 info="name (str) of the config file to use for the jet calibration "
427 "tool. Expert option to override JetETmiss recommendations. The "
428 "default is None.",
429 expertMode=True)
430 self.addOption ('calibToolCalibArea', None, type=str,
431 info="name (str) of the CVMFS area to use for the jet calibration "
432 "tool. Expert option to override JetETmiss recommendations. The "
433 "default is None.",
434 expertMode=True)
435 self.addOption ('calibToolCalibSeq', None, type=str,
436 info="name (str) of the sequence to use for the jet calibration "
437 "tool (e.g. 'JetArea_Residual_EtaJES_GSC'). Expert option to override "
438 "JetETmiss recommendations. The default is None.",
439 expertMode=True)
440 # Uncertainties tool options
441 self.addOption ('uncertToolConfigPath', None, type=str,
442 info="name (str) of the config file to use for the JES, JER, and JMS uncertainty "
443 "tool. Expert option to override JetETmiss recommendations. The "
444 "default is None.",
445 expertMode=True)
446 self.addOption ('uncertToolConfigPathJMR', None, type=str,
447 info="name (str) of the config file to use for the JMR uncertainty "
448 "tool. Expert option to override JetETmiss recommendations. The "
449 "default is None.",
450 expertMode=True)
451 self.addOption ('minPt', 200.*GeV, type=float,
452 info="the minimum pt cut to apply to calibrated large-R jets. "
453 "The default is 200 GeV.")
454 self.addOption ('maxPt', 3000.*GeV, type=float,
455 info="the maximum pt cut to apply to calibrated large-R jets. "
456 "The default is 3000 GeV.")
457 self.addOption ('maxEta', 0., type=float,
458 info="the maximum |eta| cut to apply to calibrated large-R jets. "
459 "The default is 0.")
460 self.addOption ('maxRapidity', 2., type=float,
461 info="the maximum rapidity cut to apply to calibrated large-R jets. "
462 "The default is 2.")
463 self.addOption ('minMass', 40.*GeV, type=float,
464 info="the minimum mass cut to apply to calibrated large-R jets. "
465 "The default is 40 GeV.")
466 self.addOption ('maxMass', 600.*GeV, type=float,
467 info="the maximum mass cut to apply to calibrated large-R jets. "
468 "The default is 600 GeV.")
469
470 def instanceName (self) :
471 """Return the instance name for this block"""
472 return self.containerName
473
474
475 def createFFSmearingTool(self, jetFFSmearingAlg, config):
476 # Retrieve appropriate large-R jet mass resolution recommendations for the FFJetSmearingTool.
477
478 log = logging.getLogger('LargeRJetAnalysisConfig')
479
480 # Config file:
481 if self.systematicsModelJMR in ["Simple", "Full"]:
482 config_file = f"R10_{self.systematicsModelJMR}JMR.config"
483 else:
484 raise ValueError(
485 f"Invalid request for systematicsModelJMR settings: {self.systematicsModelJMR}"
486 )
487
488 # Expert override for config path:
489 if self.uncertToolConfigPathJMR is not None:
490 config_file = self.uncertToolConfigPathJMR
491 else:
492 if config.geometry() in [LHCPeriod.Run2, LHCPeriod.Run3]:
493 config_file = "rel22/Summer2025_PreRec/" + config_file
494 else:
495 log.warning("Uncertainties for UFO jets are not for Run 4!")
496
497 # MC type:
498 if config.geometry() is LHCPeriod.Run2:
499 if config.dataType() is DataType.FastSim:
500 mc_type = "MC20AF3"
501 else:
502 mc_type = "MC20"
503 elif config.geometry() is LHCPeriod.Run3:
504 if config.dataType() is DataType.FastSim:
505 mc_type = "MC23AF3"
506 else:
507 mc_type = "MC23"
508
509 # Set up the FF smearing tool
510 config.addPrivateTool( 'FFSmearingTool', 'CP::FFJetSmearingTool')
511 jetFFSmearingAlg.FFSmearingTool.MassDef = "UFO"
512 jetFFSmearingAlg.FFSmearingTool.MCType = mc_type
513 jetFFSmearingAlg.FFSmearingTool.ConfigFile = config_file
514
515 def makeAlgs (self, config) :
516
517 configFile = None
518 calibSeq = None
519 calibArea = None
520
521 jetCollectionName=self.jetCollection
522 if(self.jetCollection=="AnalysisJets") :
523 jetCollectionName="AntiKt4EMPFlowJets"
524 if(self.jetCollection=="AnalysisLargeRJets") :
525 jetCollectionName="AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets"
526
527 if self.largeRMass not in ["Comb", "Calo", "TA"]:
528 raise ValueError("Invalid large-R mass defintion {0}!".format(self.largeRMass) )
529
530 if self.jetInput not in ["LCTopo", "TrackCaloCluster", "UFO"]:
531 raise ValueError("Invalid input type '{0}' for large-R jets!".format(self.jetInput) )
532
533 if self.jetInput == "TrackCaloCluster":
534 # Only one mass defintion supported
535 if self.largeRMass != "Calo":
536 raise ValueError("Invalid large-R TCC jet mass '{0}'!".format(self.largeRMass) )
537 configFile = "JES_MC16recommendation_FatJet_TCC_JMS_calo_30Oct2018.config"
538 if self.jetInput == "LCTopo":
539 configFile = _largeLCTopoConfigFile(config, self)
540 if self.jetInput == "UFO":
541 configFile = "JES_MC20PreRecommendation_R10_UFO_CSSK_SoftDrop_JMS_R21Insitu_26Nov2024.config"
542 calibArea = "00-04-83"
543 if self.calibToolConfigFile is not None:
544 configFile = self.calibToolConfigFile
545
546 if self.jetInput == "TrackCaloCluster" or self.jetInput == "UFO" or config.dataType() is DataType.FullSim:
547 calibSeq = "EtaJES_JMS"
548 elif config.dataType() is DataType.Data:
549 calibSeq = "EtaJES_JMS_Insitu"
550 if self.calibToolCalibSeq is not None:
551 calibSeq = self.calibToolCalibSeq
552
553 if self.calibToolCalibArea is not None:
554 calibArea = self.calibToolCalibArea
555
556 if not config.isPhyslite() or self.recalibratePhyslite:
557 # Prepare the jet calibration algorithm
558 alg = config.createAlgorithm( 'CP::JetCalibrationAlg', 'JetCalibrationAlg' )
559 config.addPrivateTool( 'calibrationTool', 'JetCalibrationTool' )
560
561 alg.calibrationTool.JetCollection = jetCollectionName[:-4]
562
563 if configFile is None:
564 raise ValueError(f'Unsupported: {self.jetInput=}, {config.dataType()=}')
565 alg.calibrationTool.ConfigFile = configFile
566
567 if calibSeq is None:
568 raise ValueError(f'Unsupported: {self.jetInput=}, {config.dataType()=}')
569 alg.calibrationTool.CalibSequence = calibSeq
570
571 if calibArea is not None:
572 alg.calibrationTool.CalibArea = calibArea
573
574 alg.calibrationTool.IsData = (config.dataType() is DataType.Data)
575 alg.jets = config.readName(self.containerName)
576
577 if self.jetInput == "UFO" and config.dataType() is not DataType.Data:
578 # set up the FF smearing algorithm
579 alg = config.createAlgorithm( 'CP::JetFFSmearingAlg', 'JetFFSmearingAlg' )
580 self.createFFSmearingTool(alg, config)
581 alg.outOfValidity = 2 # SILENT
582 alg.outOfValidityDeco = 'outOfValidityJMR'
583 alg.jets = config.readName (self.containerName)
584 alg.jetsOut = config.copyName (self.containerName)
585 alg.preselection = config.getPreselection (self.containerName, '')
586
587 if self.minPt > 0 or self.maxPt > 0 or self.maxEta > 0 or self.maxRapidity > 0:
588 # Set up the the pt-eta selection
589 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'JetPtEtaCutAlg' )
590 alg.selectionDecoration = 'selectPtEta,as_bits'
591 config.addPrivateTool( 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
592 alg.selectionTool.minPt = self.minPt
593 alg.selectionTool.maxPt = self.maxPt
594 alg.selectionTool.maxEta = self.maxEta
595 alg.selectionTool.maxRapidity = self.maxRapidity
596 alg.particles = config.readName (self.containerName)
597 alg.preselection = config.getPreselection (self.containerName, '')
598 config.addSelection (self.containerName, '', alg.selectionDecoration,
599 preselection=True)
600
601 if self.minMass > 0 or self.maxMass > 0:
602 # Set up the the mass selection
603 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'JetMassCutAlg' )
604 alg.selectionDecoration = 'selectMass,as_bits'
605 config.addPrivateTool( 'selectionTool', 'CP::AsgMassSelectionTool' )
606 alg.selectionTool.minM = self.minMass
607 alg.selectionTool.maxM = self.maxMass
608 alg.particles = config.readName (self.containerName)
609 alg.preselection = config.getPreselection (self.containerName, '')
610 config.addSelection (self.containerName, '', alg.selectionDecoration,
611 preselection=True)
612
613 config.addOutputVar (self.containerName, 'm', 'm')
614
615# These algorithms set up the jet recommendations as-of 04/02/2019.
616# Jet calibration recommendations
617# https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/ApplyJetCalibrationR21
618# Jet uncertainties recommendations
619# Small-R
620# https://twiki.cern.ch/twiki/bin/view/AtlasProtected/JetUncertaintiesRel21Summer2018SmallR
621# Large-R
622# https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/JetUncertaintiesRel21Moriond2018LargeR
623# JVT recommendations
624# https://twiki.cern.ch/twiki/bin/view/AtlasProtected/JVTCalibrationRel21
625
626@groupBlocks
627def makeJetAnalysisConfig( seq, containerName, jetCollection,
628 runGhostMuonAssociation = None):
629 """Create a jet analysis algorithm sequence
630 The jet collection is interpreted and selects the correct function to call,
631 makeSmallRJetAnalysisConfig, makeRScanJetAnalysisConfig or
632 makeLargeRJetAnalysisConfig
633
634 Keyword arguments
635 jetCollection -- The jet container to run on.
636 """
637
638 # Remove b-tagging calibration from the container name
639 btIndex = jetCollection.find('_BTagging')
640 if btIndex != -1:
641 jetCollection = jetCollection[:btIndex]
642
643 jetCollectionName=jetCollection
644 # needed for PHYSLITE
645 if(jetCollection=="AnalysisJets") :
646 jetCollectionName="AntiKt4EMPFlowJets"
647 if(jetCollection=="AnalysisLargeRJets") :
648 jetCollectionName="AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets"
649
650 # interpret the jet collection
651 collection_pattern = re.compile(
652 r"AntiKt(\d+)(EMTopo|EMPFlow|LCTopo|TrackCaloCluster|UFO|Track|HI)(TrimmedPtFrac5SmallR20|CSSKSoftDropBeta100Zcut10)?Jets")
653 match = collection_pattern.match(jetCollectionName)
654 if not match:
655 raise ValueError(
656 "Jet collection {0} does not match expected pattern!".format(jetCollectionName) )
657 radius = int(match.group(1) )
658 if radius not in [2, 4, 6, 10]:
659 raise ValueError("Jet collection has an unsupported radius '{0}'!".format(radius) )
660 jetInput = match.group(2)
661
662 config = PreJetAnalysisConfig()
663 config.setOptionValue ('containerName', containerName)
664 config.setOptionValue ('jetCollection', jetCollection)
665 config.runOriginalObjectLink = (btIndex != -1)
666 config.setOptionValue ('runGhostMuonAssociation', runGhostMuonAssociation)
667 seq.append (config)
668
669 if radius == 4:
670 makeSmallRJetAnalysisConfig(seq, containerName,
671 jetCollection, jetInput=jetInput)
672 elif radius in [2, 6]:
673 makeRScanJetAnalysisConfig(seq, containerName,
674 jetCollection, jetInput=jetInput, radius=radius)
675 else:
676 trim = match.group(3)
677 if trim == "":
678 raise ValueError("Untrimmed large-R jets are not supported!")
679 makeLargeRJetAnalysisConfig(seq, containerName,
680 jetCollection, jetInput=jetInput)
681
682
683
684def makeSmallRJetAnalysisConfig( seq, containerName, jetCollection, jetInput,
685 runJvtUpdate = None, runNNJvtUpdate = None,
686 runJvtSelection = None, runFJvtSelection = None,
687 jvtWP = None, fJvtWP = None,
688 runJvtEfficiency = None, runFJvtEfficiency = None):
689 """Add algorithms for the R=0.4 jets.
690
691 Keyword arguments
692 seq -- The sequence to add the algorithms to
693 jetCollection -- The jet container to run on.
694 jetInput -- The type of input used, read from the collection name.
695 runJvtUpdate -- Determines whether or not to update JVT on the jets
696 runNNJvtUpdate -- Determines whether or not to update NN JVT on the jets
697 runJvtSelection -- Determines whether or not to run JVT selection on the jets
698 runFJvtSelection -- Determines whether or not to run forward JVT selection on the jets
699 jvtWP -- Defines the NNJvt WP to apply on the jets
700 fJvtWP -- Defines the fJvt WP to apply on the jets
701 runJvtEfficiency -- Determines whether or not to calculate the JVT efficiency
702 runFJvtEfficiency -- Determines whether or not to calculate the forward JVT efficiency
703 """
704
705 if jetInput not in ["EMTopo", "EMPFlow", "HI"]:
706 raise ValueError(
707 "Unsupported input type '{0}' for R=0.4 jets!".format(jetInput) )
708
709 config = SmallRJetAnalysisConfig()
710 config.setOptionValue ('containerName', containerName)
711 config.setOptionValue ('jetCollection', jetCollection)
712 config.setOptionValue ('jetInput', jetInput)
713 config.setOptionValue ('runJvtUpdate', runJvtUpdate)
714 config.setOptionValue ('runNNJvtUpdate', runNNJvtUpdate)
715 config.setOptionValue ('runJvtSelection', runJvtSelection)
716 config.setOptionValue ('runFJvtSelection', runFJvtSelection)
717 config.setOptionValue ('jvtWP', jvtWP)
718 config.setOptionValue ('fJvtWP', fJvtWP)
719 config.setOptionValue ('runJvtEfficiency', runJvtEfficiency)
720 config.setOptionValue ('runFJvtEfficiency', runFJvtEfficiency)
721 seq.append (config)
722
723
724def makeRScanJetAnalysisConfig( seq, containerName, jetCollection,
725 jetInput, radius ):
726 """Add algorithms for the R-scan jets.
727
728 Keyword arguments
729 seq -- The sequence to add the algorithms to
730 jetCollection -- The jet container to run on.
731 jetInput -- The type of input used, read from the collection name.
732 radius -- The radius of the r-scan jets.
733 """
734
735 config = RScanJetAnalysisConfig()
736 config.setOptionValue ('containerName', containerName)
737 config.setOptionValue ('jetCollection', jetCollection)
738 config.setOptionValue ('jetInput', jetInput)
739 config.setOptionValue ('radius', radius)
740 seq.append (config)
741
742
743
744
745def makeLargeRJetAnalysisConfig( seq, containerName, jetCollection,
746 jetInput, largeRMass = None):
747 """Add algorithms for the R=1.0 jets.
748
749 Keyword arguments
750 seq -- The sequence to add the algorithms to
751 jetCollection -- The jet container to run on.
752 jetInput -- The type of input used, read from the collection name.
753 largeRMass -- Which large-R mass definition to use. Ignored if not running on large-R jets ("Comb", "Calo", "TA")
754 """
755 config = LargeRJetAnalysisConfig()
756 config.setOptionValue ('containerName', containerName)
757 config.setOptionValue ('jetCollection', jetCollection)
758 config.setOptionValue ('jetInput', jetInput)
759 config.setOptionValue ('largeRMass', largeRMass)
760 seq.append (config)
761
if(febId1==febId2)
createFFSmearingTool(self, jetFFSmearingAlg, config)
makeJetAnalysisConfig(seq, containerName, jetCollection, runGhostMuonAssociation=None)
makeSmallRJetAnalysisConfig(seq, containerName, jetCollection, jetInput, runJvtUpdate=None, runNNJvtUpdate=None, runJvtSelection=None, runFJvtSelection=None, jvtWP=None, fJvtWP=None, runJvtEfficiency=None, runFJvtEfficiency=None)
makeRScanJetAnalysisConfig(seq, containerName, jetCollection, jetInput, radius)
makeLargeRJetAnalysisConfig(seq, containerName, jetCollection, jetInput, largeRMass=None)