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