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 ('recalibratePhyslite', True, type=bool,
139  info="whether to run the CP::JetCalibrationAlg on PHYSLITE derivations. "
140  "The default is True.")
141  # Calibration tool options
142  self.addOption ('calibToolConfigFile', None, type=str,
143  info="name (str) of the config file to use for the jet calibration "
144  "tool. Expert option to override JetETmiss recommendations. The "
145  "default is None.",
146  expertMode=True)
147  self.addOption ('calibToolCalibArea', None, type=str,
148  info="name (str) of the CVMFS area to use for the jet calibration "
149  "tool. Expert option to override JetETmiss recommendations. The "
150  "default is None.",
151  expertMode=True)
152  self.addOption ('calibToolCalibSeq', None, type=str,
153  info="name (str) of the sequence to use for the jet calibration "
154  "tool (e.g. 'JetArea_Residual_EtaJES_GSC'). Expert option to override "
155  "JetETmiss recommendations. The default is None.",
156  expertMode=True)
157 
158  def instanceName (self) :
159  """Return the instance name for this block"""
160  return self.containerName
161 
162  def makeAlgs (self, config) :
163 
164  jetCollectionName=self.jetCollection
165  if(self.jetCollection=="AnalysisJets") :
166  jetCollectionName="AntiKt4EMPFlowJets"
167  if(self.jetCollection=="AnalysisLargeRJets") :
168  jetCollectionName="AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets"
169 
170  if self.jetInput not in ["EMTopo", "EMPFlow", "HI"]:
171  raise ValueError(
172  "Unsupported input type '{0}' for R=0.4 jets!".format(self.jetInput) )
173 
174  if self.jvtWP not in ["FixedEffPt"]:
175  raise ValueError(
176  "Unsupported NNJvt WP '{0}'".format(self.jvtWP) )
177 
178  if self.fJvtWP not in ["Loose", "Tight", "Tighter"]:
179  raise ValueError(
180  "Unsupported fJvt WP '{0}'".format(self.fJvtWP) )
181 
182  if not config.isPhyslite() or self.recalibratePhyslite:
183  # Prepare the jet calibration algorithm
184  alg = config.createAlgorithm( 'CP::JetCalibrationAlg', 'JetCalibrationAlg' )
185  config.addPrivateTool( 'calibrationTool', 'JetCalibrationTool' )
186  alg.calibrationTool.JetCollection = jetCollectionName[:-4]
187  # Get the correct string to use in the config file name
188  if self.jetInput == "EMPFlow":
189  if config.geometry() is LHCPeriod.Run2:
190  configFile = "PreRec_R22_PFlow_ResPU_EtaJES_GSC_February23_230215.config"
191  alg.calibrationTool.CalibArea = "00-04-82"
192  elif config.geometry() >= LHCPeriod.Run3:
193  configFile = "AntiKt4EMPFlow_MC23a_PreRecR22_Phase2_CalibConfig_ResPU_EtaJES_GSC_241208_InSitu.config"
194  alg.calibrationTool.CalibArea = "00-04-83"
195  elif self.jetInput == "HI":
196  if config.geometry() is LHCPeriod.Run2:
197  configFile = "JES_MC16_HI_Jan2021_5TeV.config"
198  if config.geometry() is LHCPeriod.Run3:
199  configFile = "AntiKt4HI_JES_constants_11-05-2024_13p6TeVFinalConfiguration.config"
200  alg.calibrationTool.CalibArea = "00-04-83"
201  else:
202  if config.dataType() is DataType.FastSim:
203  configFile = "JES_MC16Recommendation_AFII_{0}_Apr2019_Rel21.config"
204  else:
205  configFile = "JES_MC16Recommendation_Consolidated_{0}_Apr2019_Rel21.config"
206  configFile = configFile.format(self.jetInput)
207  if self.calibToolCalibArea is not None:
208  alg.calibrationTool.CalibArea = self.calibToolCalibArea
209  if self.calibToolConfigFile is not None:
210  configFile = self.calibToolConfigFile
211  alg.calibrationTool.ConfigFile = configFile
212  if config.dataType() is DataType.Data:
213  if self.jetInput == "HI":
214  if config.geometry() is LHCPeriod.Run2:
215  alg.calibrationTool.CalibSequence = 'EtaJES_Insitu'
216  if config.geometry() is LHCPeriod.Run3:
217  alg.calibrationTool.CalibSequence = 'EtaJES'
218  else:
219  alg.calibrationTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC_Insitu'
220  else:
221  if self.jetInput == "EMPFlow":
222  alg.calibrationTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC'
223  elif self.jetInput == "HI":
224  alg.calibrationTool.CalibSequence = 'EtaJES'
225  else:
226  alg.calibrationTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC_Smear'
227  if self.calibToolCalibSeq is not None:
228  alg.calibrationTool.CalibSequence = self.calibToolCalibSeq
229  alg.calibrationTool.IsData = (config.dataType() is DataType.Data)
230  alg.jets = config.readName (self.containerName)
231  alg.jetsOut = config.copyName (self.containerName)
232 
233  # Set up the JVT update algorithm:
234  if self.runJvtUpdate :
235  alg = config.createAlgorithm( 'CP::JvtUpdateAlg', 'JvtUpdateAlg' )
236  config.addPrivateTool( 'jvtTool', 'JetVertexTaggerTool' )
237  alg.jvtTool.JetContainer = self.jetCollection
238  alg.jvtTool.SuppressInputDependence=True
239  alg.jets = config.readName (self.containerName)
240  alg.jetsOut = config.copyName (self.containerName)
241  alg.preselection = config.getPreselection (self.containerName, '')
242 
243  if self.runNNJvtUpdate:
244  assert self.jetInput=="EMPFlow", "NN JVT only defined for PFlow jets"
245  alg = config.createAlgorithm( 'CP::JetDecoratorAlg', 'NNJvtUpdateAlg' )
246  config.addPrivateTool( 'decorator', 'JetPileupTag::JetVertexNNTagger' )
247  # Set this actually to the *output* collection
248  alg.jets = config.readName (self.containerName)
249  alg.jetsOut = config.copyName (self.containerName)
250  alg.decorator.JetContainer = alg.jetsOut.replace ('%SYS%', 'NOSYS')
251  alg.decorator.SuppressInputDependence=True
252  alg.decorator.SuppressOutputDependence=True
253 
254  # Set up the jet efficiency scale factor calculation algorithm
255  # Change the truthJetCollection property to AntiKt4TruthWZJets if preferred
256  if self.runJvtSelection :
257  assert self.jetInput=="EMPFlow", "NNJvt WPs and SFs only valid for PFlow jets"
258  alg = config.createAlgorithm('CP::AsgSelectionAlg', 'JvtSelectionAlg')
259  config.addPrivateTool('selectionTool', 'CP::NNJvtSelectionTool')
260  alg.selectionTool.JetContainer = config.readName(self.containerName)
261  alg.selectionTool.WorkingPoint = self.jvtWP
262  alg.selectionTool.MaxPtForJvt = 60*GeV
263  alg.selectionDecoration = "jvt_selection,as_char"
264  alg.particles = config.readName(self.containerName)
265 
266  if self.runJvtEfficiency and config.dataType() is not DataType.Data:
267  alg = config.createAlgorithm( 'CP::JvtEfficiencyAlg', 'JvtEfficiencyAlg' )
268  config.addPrivateTool( 'efficiencyTool', 'CP::NNJvtEfficiencyTool' )
269  alg.efficiencyTool.JetContainer = config.readName(self.containerName)
270  alg.efficiencyTool.MaxPtForJvt = 60*GeV
271  alg.efficiencyTool.WorkingPoint = self.jvtWP
272  if config.geometry() is LHCPeriod.Run2:
273  alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/NNJvtSFFile_Run2_EMPFlow.root"
274  else:
275  alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/NNJvtSFFile_Run3_EMPFlow.root"
276  alg.selection = 'jvt_selection,as_char'
277  alg.scaleFactorDecoration = 'jvt_effSF_%SYS%'
278  alg.outOfValidity = 2
279  alg.outOfValidityDeco = 'no_jvt'
280  alg.skipBadEfficiency = False
281  alg.jets = config.readName (self.containerName)
282  alg.preselection = config.getPreselection (self.containerName, '')
283  config.addOutputVar (self.containerName, alg.scaleFactorDecoration, 'jvtEfficiency')
284  config.addSelection (self.containerName, 'baselineJvt', 'jvt_selection,as_char', preselection=False)
285 
286  if self.runFJvtSelection :
287  assert self.jetInput=="EMPFlow", "fJvt WPs and SFs only valid for PFlow jets"
288  alg = config.createAlgorithm('CP::AsgSelectionAlg', 'FJvtSelectionAlg')
289  config.addPrivateTool('selectionTool', 'CP::FJvtSelectionTool')
290  alg.selectionTool.JetContainer = config.readName(self.containerName)
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 
321 class 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 
379 def _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 
399 class 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
627 def 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 
684 def 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 
724 def 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 
745 def 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 
python.JetAnalysisConfig.LargeRJetAnalysisConfig.instanceName
def instanceName(self)
Definition: JetAnalysisConfig.py:470
python.JetAnalysisConfig._largeLCTopoConfigFile
def _largeLCTopoConfigFile(config, self)
Definition: JetAnalysisConfig.py:379
SystemOfUnits
vtune_athena.format
format
Definition: vtune_athena.py:14
python.JetAnalysisConfig.LargeRJetAnalysisConfig.createFFSmearingTool
def createFFSmearingTool(self, jetFFSmearingAlg, config)
Definition: JetAnalysisConfig.py:475
python.JetAnalysisConfig.PreJetAnalysisConfig.jetCollection
jetCollection
Definition: JetAnalysisConfig.py:46
python.JetAnalysisConfig.PreJetAnalysisConfig.makeAlgs
def makeAlgs(self, config)
Definition: JetAnalysisConfig.py:43
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)
Definition: JetAnalysisConfig.py:684
python.JetAnalysisConfig.PreJetAnalysisConfig
Definition: JetAnalysisConfig.py:15
python.JetAnalysisConfig.SmallRJetAnalysisConfig.jetInput
jetInput
Definition: JetAnalysisConfig.py:188
python.JetAnalysisConfig.LargeRJetAnalysisConfig
Definition: JetAnalysisConfig.py:399
python.JetAnalysisConfig.RScanJetAnalysisConfig
Definition: JetAnalysisConfig.py:321
python.JetAnalysisConfig.RScanJetAnalysisConfig.makeAlgs
def makeAlgs(self, config)
Definition: JetAnalysisConfig.py:349
python.JetAnalysisConfig.RScanJetAnalysisConfig.jetCollection
jetCollection
Definition: JetAnalysisConfig.py:354
python.JetAnalysisConfig.makeLargeRJetAnalysisConfig
def makeLargeRJetAnalysisConfig(seq, containerName, jetCollection, jetInput, largeRMass=None)
Definition: JetAnalysisConfig.py:745
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:162
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:402
python.JetAnalysisConfig.SmallRJetAnalysisConfig.instanceName
def instanceName(self)
Definition: JetAnalysisConfig.py:158
python.JetAnalysisConfig.makeRScanJetAnalysisConfig
def makeRScanJetAnalysisConfig(seq, containerName, jetCollection, jetInput, radius)
Definition: JetAnalysisConfig.py:724
python.JetAnalysisConfig.SmallRJetAnalysisConfig.jetCollection
jetCollection
Definition: JetAnalysisConfig.py:165
python.JetAnalysisConfig.SmallRJetAnalysisConfig
Definition: JetAnalysisConfig.py:106
python.JetAnalysisConfig.makeJetAnalysisConfig
def makeJetAnalysisConfig(seq, containerName, jetCollection, runGhostMuonAssociation=None)
Definition: JetAnalysisConfig.py:627
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:567
python.JetAnalysisConfig.LargeRJetAnalysisConfig.jetCollection
jetCollection
Definition: JetAnalysisConfig.py:522
python.JetAnalysisConfig.LargeRJetAnalysisConfig.jetInput
jetInput
Definition: JetAnalysisConfig.py:533
python.JetAnalysisConfig.LargeRJetAnalysisConfig.makeAlgs
def makeAlgs(self, config)
Definition: JetAnalysisConfig.py:515
python.JetAnalysisConfig.RScanJetAnalysisConfig.instanceName
def instanceName(self)
Definition: JetAnalysisConfig.py:345
python.JetAnalysisConfig.RScanJetAnalysisConfig.__init__
def __init__(self)
Definition: JetAnalysisConfig.py:324