ATLAS Offline Software
Loading...
Searching...
No Matches
JetAnalysisConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 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 (
9 DataType, ConfigDeprecationWarning, JetUncertaintyWarning)
10from AthenaCommon.SystemOfUnits import GeV
11from AthenaConfiguration.Enums import LHCPeriod
12import re
13import warnings
14
15
16def _parseJetCollection(jetCollection):
17 """Parse a jet collection name into its components.
18
19 Returns (radius, jetInput, trim, hasBTag) where:
20 radius -- the jet radius parameter (2, 4, 6, or 10)
21 jetInput -- the input type string (e.g. 'EMPFlow', 'UFO', ...)
22 trim -- the trimming suffix string, or None
23 hasBTag -- whether the original collection name had a '_BTagging' suffix
24 """
25 hasBTag = False
26 btIndex = jetCollection.find('_BTagging')
27 if btIndex != -1:
28 jetCollection = jetCollection[:btIndex]
29 hasBTag = True
30
31 jetCollectionName = jetCollection
32 if jetCollection == "AnalysisJets":
33 jetCollectionName = "AntiKt4EMPFlowJets"
34 elif jetCollection == "AnalysisLargeRJets":
35 jetCollectionName = "AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets"
36
37 collection_pattern = re.compile(
38 r"AntiKt(\d+)(EMTopo|EMPFlow|LCTopo|TrackCaloCluster|UFO|Track|HI)"
39 r"(TrimmedPtFrac5SmallR20|CSSKSoftDropBeta100Zcut10)?Jets")
40 match = collection_pattern.match(jetCollectionName)
41 if not match:
42 raise ValueError(
43 "Jet collection {0} does not match expected pattern!".format(jetCollectionName))
44 radius = int(match.group(1))
45 if radius not in [2, 4, 6, 10]:
46 raise ValueError(
47 "Jet collection has unsupported radius '{0}'!".format(radius))
48 jetInput = match.group(2)
49 trim = match.group(3)
50 return radius, jetInput, trim, hasBTag
51
52
53class PreJetAnalysisConfig (ConfigBlock) :
54 """the ConfigBlock for the common preprocessing of jet sequences"""
55
56 def __init__ (self) :
57 super (PreJetAnalysisConfig, self).__init__ ()
58 self.addOption ('containerName', '', type=str,
59 noneAction='error',
60 info="the name of the output container after calibration.")
61 self.addOption ('jetCollection', '', type=str,
62 noneAction='error',
63 info="the jet container to run on. It is interpreted to determine "
64 "the correct config blocks to call for small- or large-R jets.")
65 self.addOption('outputTruthLabelIDs', False, type=bool,
66 info='enable or disable `HadronConeExclTruthLabelID` and `PartonTruthLabelID` decorations.')
67 self.addOption ('runOriginalObjectLink', False, type=bool,
68 info='sets up an instance of `CP::AsgOriginalObjectLinkAlg` to link systematically-varied containers to the base one.')
69 self.addOption ('runGhostMuonAssociation', None, type=bool,
70 info="whether to set up the jet-ghost-muon association algorithm "
71 "`CP::JetGhostMuonAssociationAlg`. If left empty, automatically defaults to `False` for PHYSLITE and `True` otherwise.")
72 self.addOption ('runTruthJetTagging', True, type=bool,
73 info="whether to set up the jet truth tagging algorithm "
74 "`CP::JetTruthTagAlg`.")
75
76 def instanceName (self) :
77 """Return the instance name for this block"""
78 return self.containerName
79
80 def makeAlgs (self, config) :
81
82
83 if config.isPhyslite() and self.jetCollection == 'AntiKt4EMPFlowJets' :
84 config.setSourceName (self.containerName, "AnalysisJets", originalName = self.jetCollection)
85 elif config.isPhyslite() and self.jetCollection == 'AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets' :
86 config.setSourceName (self.containerName, "AnalysisLargeRJets", originalName = self.jetCollection)
87 else :
88 config.setSourceName (self.containerName, self.jetCollection, originalName = self.jetCollection)
89
90 # Parse and store jet collection metadata for downstream blocks
91 radius, jetInput, trim, hasBTag = _parseJetCollection(self.jetCollection)
92 config.setContainerMeta(self.containerName, 'jetRadius', radius)
93 config.setContainerMeta(self.containerName, 'jetInput', jetInput)
94 config.setContainerMeta(self.containerName, 'jetTrim', trim)
95 config.setContainerMeta(self.containerName, 'hasBTag', hasBTag)
96
97 # Relink original jets in case of b-tagging calibration
98 if self.runOriginalObjectLink or hasBTag :
99 alg = config.createAlgorithm( 'CP::AsgOriginalObjectLinkAlg',
100 'JetOriginalObjectLinkAlg',
101 reentrant=True )
102 alg.baseContainerName = self.jetCollection
103 alg.particles = config.readName (self.containerName)
104 if config.wantCopy (self.containerName) :
105 alg.particlesOut = config.copyName (self.containerName)
106 alg.preselection = config.getPreselection (self.containerName, '')
107
108 # Set up the jet ghost muon association algorithm:
109 if (self.runGhostMuonAssociation is None and not config.isPhyslite()) or \
110 (self.runGhostMuonAssociation is True):
111 alg = config.createAlgorithm( 'CP::JetGhostMuonAssociationAlg',
112 'JetGhostMuonAssociationAlg' )
113 alg.jets = config.readName (self.containerName)
114 if config.isPhyslite():
115 alg.muons = "AnalysisMuons"
116 if config.wantCopy (self.containerName) :
117 alg.jetsOut = config.copyName (self.containerName)
118 taggerName = "GN2HLv01" if config.geometry() >= LHCPeriod.Run4 else "GN2v01"
119 extraInputs = [
120 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.DFCommonJets_jetClean_LooseBad".format(baseName=self.jetCollection)),
121 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.DFCommonJets_jetClean_TightBad".format(baseName=self.jetCollection)),
122 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.{tagger}_pb".format(baseName=self.jetCollection, tagger=taggerName)),
123 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.{tagger}_pc".format(baseName=self.jetCollection, tagger=taggerName)),
124 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.{tagger}_ptau".format(baseName=self.jetCollection, tagger=taggerName)),
125 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.{tagger}_pu".format(baseName=self.jetCollection, tagger=taggerName))]
126 config.setExtraInputs (extraInputs)
127
128 if self.runTruthJetTagging and config.dataType() is not DataType.Data:
129 # Decorate jets with isHS labels (required to retrieve Jvt SFs)
130 alg = config.createAlgorithm( 'CP::JetDecoratorAlg', 'JetPileupLabelAlg' )
131 config.addPrivateTool( 'decorator', 'JetPileupLabelingTool' )
132 alg.jets = config.readName (self.containerName)
133 alg.jetsOut = config.copyName (self.containerName)
134 alg.decorator.RecoJetContainer = alg.jetsOut.replace ('%SYS%', 'NOSYS')
135 alg.decorator.SuppressOutputDependence=True
136 if self.jetCollection == 'AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets' :
137 extraInputs = [
138 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.GN2Xv01_phbb".format(baseName= self.jetCollection)),
139 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.GN2Xv01_phcc".format(baseName= self.jetCollection)),
140 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.GN2Xv01_pqcd".format(baseName= self.jetCollection)),
141 ( 'xAOD::JetContainer' , "StoreGateSvc+{baseName}.GN2Xv01_ptop".format(baseName= self.jetCollection))]
142 config.setExtraInputs (extraInputs)
143
144 # Set up shallow copy if needed and not yet done
145 if config.wantCopy (self.containerName) :
146 alg = config.createAlgorithm( 'CP::AsgShallowCopyAlg', 'JetShallowCopyAlg' )
147 alg.input = config.readName (self.containerName)
148 alg.output = config.copyName (self.containerName)
149 alg.outputType = 'xAOD::JetContainer'
150 if self.jetCollection == 'AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets' :
151 alg.declareDecorations = ['GN2Xv01_phbb', 'GN2Xv01_phcc',
152 'GN2Xv01_pqcd', 'GN2Xv01_ptop']
153
154 config.addOutputVar (self.containerName, 'pt', 'pt')
155 config.addOutputVar (self.containerName, 'eta', 'eta', noSys=True)
156 config.addOutputVar (self.containerName, 'phi', 'phi', noSys=True)
157 config.addOutputVar (self.containerName, 'charge', 'charge', noSys=True, enabled=False)
158
159
160 if self.outputTruthLabelIDs and config.dataType() is not DataType.Data:
161 config.addOutputVar (self.containerName, 'HadronConeExclTruthLabelID', 'HadronConeExclTruthLabelID', noSys=True, auxType="int")
162 config.addOutputVar (self.containerName, 'PartonTruthLabelID', 'PartonTruthLabelID', noSys=True, auxType="int")
163
164
165
166class SmallRJetAnalysisConfig (ConfigBlock) :
167 """the ConfigBlock for the small-r jet sequence"""
168
169 def __init__ (self) :
170 super (SmallRJetAnalysisConfig, self).__init__ ()
171 self.addOption ('containerName', '', type=str,
172 noneAction='error',
173 info="the name of the output container after calibration.")
174 self.addOption ('jetCollection', '', type=str,
175 noneAction='error',
176 info="the jet container to run on. It is interpreted to determine "
177 "the correct config blocks to call for small- or large-R jets.")
178 self.addOption ('runJvtUpdate', False, type=bool,
179 info="whether to update the JVT.")
180 self.addOption ('runNNJvtUpdate', False, type=bool,
181 info="whether to update the NN-JVT.")
182 self.addOption ('runJvtSelection', True, type=bool,
183 info="whether to run JVT selection.")
184 self.addOption ('runFJvtSelection', False, type=bool,
185 info="whether to run forward JVT selection.")
186 self.addOption ('jvtWP', "FixedEffPt", type=str,
187 info="which Jvt WP to apply.")
188 self.addOption ('fJvtWP', "Loose", type=str,
189 info="which fJvt WP to apply.")
190 self.addOption ('runJvtEfficiency', True, type=bool,
191 info="whether to calculate the JVT efficiency.")
192 self.addOption ('runFJvtEfficiency', False, type=bool,
193 info="whether to calculate the forward JVT efficiency.")
194 self.addOption ('runUncertainties', True, type=bool,
195 info="whether to configure JetUncertaintiesTool.", expertMode=True)
196 self.addOption ('systematicsModelJES', "Category", type=str,
197 info="the NP reduction scheme to use for JES: All, Global, Category, "
198 "Scenario. The default is Category.")
199 self.addOption ('systematicsModelJER', "Full", type=str,
200 info="the NP reduction scheme to use for JER: All, Full, Simple. The "
201 "default is Full.")
202 self.addOption ('runJERsystematicsOnData', False, type=bool,
203 info="whether to run the All/Full JER model variations also on data samples. Expert option!",
204 expertMode=True)
205 self.addOption ('recalibratePhyslite', True, type=bool,
206 info="whether to run the `CP::JetCalibrationAlg` on PHYSLITE derivations.")
207 # Calibration tool options
208 self.addOption ('calibToolConfigFile', None, type=str,
209 info="the name of the config file to use for the jet calibration "
210 "tool. Expert option to override JetETmiss recommendations.",
211 expertMode=True)
212 self.addOption ('calibToolCalibArea', None, type=str,
213 info="name of the CVMFS area to use for the jet calibration "
214 "tool. Expert option to override JetETmiss recommendations.",
215 expertMode=True)
216 self.addOption ('calibToolCalibSeq', None, type=str,
217 info="name of the sequence to use for the jet calibration "
218 "tool (e.g. `JetArea_Residual_EtaJES_GSC`). Expert option to override "
219 "JetETmiss recommendations.",
220 expertMode=True)
221 # Uncertainties tool options
222 self.addOption ('uncertToolConfigPath', None, type=str,
223 info="name (str) of the config file to use for the jet uncertainty "
224 "tool. Expert option to override JetETmiss recommendations. The "
225 "default is None.",
226 expertMode=True)
227 self.addOption ('uncertToolCalibArea', None, type=str,
228 info="name (str) of the CVMFS area to use for the jet uncertainty "
229 "tool. Expert option to override JetETmiss recommendations. The "
230 "default is None.",
231 expertMode=True)
232 self.addOption ('uncertToolMCType', None, type=str,
233 info="data type (str) to use for the jet uncertainty tool (e.g. "
234 "'AF3' or 'MC16'). Expert option to override JetETmiss "
235 "recommendations. The default is None.",
236 expertMode=True)
237
238 def instanceName (self) :
239 """Return the instance name for this block"""
240 return self.containerName
241
242 def getUncertaintyToolSettings(self, config):
243
244 # Retrieve appropriate JES/JER recommendations for the JetUncertaintiesTool.
245 # We do this separately from the tool declaration, as we may need to set uo
246 # two such tools, but they have to be private.
247
248 jetInput = config.getContainerMeta(self.containerName, 'jetInput', failOnMiss=True)
249 # Config file:
250 config_file = None
251 if self.systematicsModelJES == "All" and self.systematicsModelJER == "All":
252 config_file = "R4_AllNuisanceParameters_AllJERNP.config"
253 elif "Scenario" in self.systematicsModelJES:
254 if self.systematicsModelJER != "Simple":
255 raise ValueError(
256 "Invalid uncertainty configuration - Scenario* systematicsModelJESs can "
257 "only be used together with the Simple systematicsModelJER")
258 config_file = "R4_{0}_SimpleJER.config".format(self.systematicsModelJES)
259 elif self.systematicsModelJES in ["Global", "Category"] and self.systematicsModelJER in ["Simple", "Full"]:
260 config_file = "R4_{0}Reduction_{1}JER.config".format(self.systematicsModelJES, self.systematicsModelJER)
261 else:
262 raise ValueError(
263 "Invalid combination of systematicsModelJES and systematicsModelJER settings: "
264 "systematicsModelJES: {0}, systematicsModelJER: {1}".format(self.systematicsModelJES, self.systematicsModelJER) )
265
266 # Calibration area:
267 calib_area = None
268 if self.uncertToolCalibArea is not None:
269 calib_area = self.uncertToolCalibArea
270
271 # Expert override for config path:
272 if self.uncertToolConfigPath is not None:
273 config_file = self.uncertToolConfigPath
274 else:
275 if config.geometry() is LHCPeriod.Run2:
276 if config.dataType() is DataType.FastSim:
277 config_file = "rel22/Fall2024_PreRec/" + config_file
278 else:
279 if jetInput == "HI":
280 config_file = "HIJetUncertainties/Spring2023/HI" + config_file
281 else:
282 config_file = "rel22/Summer2023_PreRec/" + config_file
283 else:
284 if config.dataType() is DataType.FastSim:
285 config_file = "rel22/Winter2025_AF3_PreRec/" + config_file
286 else:
287 if jetInput == "HI":
288 config_file = "HIJetUncertainties/Spring2023/HI" + config_file
289 else:
290 config_file = "rel22/Winter2025_PreRec/" + config_file
291
292 # MC type:
293 mc_type = None
294 if self.uncertToolMCType is not None:
295 mc_type = self.uncertToolMCType
296 else:
297 if config.geometry() is LHCPeriod.Run2:
298 if config.dataType() is DataType.FastSim:
299 mc_type = "AF3"
300 else:
301 mc_type = "MC20"
302 else:
303 if config.dataType() is DataType.FastSim:
304 mc_type = "MC23AF3"
305 else:
306 if jetInput == "HI":
307 mc_type = "MC16"
308 else:
309 mc_type = "MC23"
310
311 return config_file, calib_area, mc_type
312
313
314 def createUncertaintyTool(self, jetUncertaintiesAlg, config, jetCollectionName, doPseudoData=False):
315
316 # Create an instance of JetUncertaintiesTool, following JetETmiss recommendations.
317 # To run Jet Energy Resolution (JER) uncertainties in the "Full" or "All" schemes,
318 # we need two sets of tools: one configured as normal (MC), the other with the
319 # exact same settings but pretending to run on data (pseudo-data).
320 # This is achieved by passing "isPseudoData=True" to the arguments.
321
322 # Retrieve the common configuration settings
323 configFile, calibArea, mcType = self.getUncertaintyToolSettings(config)
324
325 # The main tool for all JES+JER combinations
326 config.addPrivateTool( 'uncertaintiesTool', 'JetUncertaintiesTool' )
327 jetUncertaintiesAlg.uncertaintiesTool.JetDefinition = jetCollectionName[:-4]
328 jetUncertaintiesAlg.uncertaintiesTool.ConfigFile = configFile
329 if calibArea is not None:
330 jetUncertaintiesAlg.uncertaintiesTool.CalibArea = calibArea
331 jetUncertaintiesAlg.uncertaintiesTool.MCType = mcType
332 jetUncertaintiesAlg.uncertaintiesTool.IsData = (config.dataType() is DataType.Data)
333 jetUncertaintiesAlg.uncertaintiesTool.PseudoDataJERsmearingMode = False
334
335 if config.dataType() is DataType.Data and not (doPseudoData and self.runJERsystematicsOnData):
336 # we don't want any systematics on data if we're not using the right JER model!
337 jetUncertaintiesAlg.affectingSystematicsFilter = '.*'
338 if config.dataType() is not DataType.Data and doPseudoData and not self.runJERsystematicsOnData:
339 # The secondary tool for pseudo-data JER smearing
340 config.addPrivateTool( 'uncertaintiesToolPD', 'JetUncertaintiesTool' )
341 jetUncertaintiesAlg.uncertaintiesToolPD.JetDefinition = jetCollectionName[:-4]
342 jetUncertaintiesAlg.uncertaintiesToolPD.ConfigFile = configFile
343 if calibArea is not None:
344 jetUncertaintiesAlg.uncertaintiesToolPD.CalibArea = calibArea
345 jetUncertaintiesAlg.uncertaintiesToolPD.MCType = mcType
346
347 # This is the part that is different!
348 jetUncertaintiesAlg.uncertaintiesToolPD.IsData = True
349 jetUncertaintiesAlg.uncertaintiesToolPD.PseudoDataJERsmearingMode = True
350
351
352 def makeAlgs (self, config) :
353
354 # Self-select: only run for radius-4 jets
355 if config.getContainerMeta(self.containerName, 'jetRadius', failOnMiss=True) != 4:
356 return
357
358
359 jetCollectionName=self.jetCollection
360 if(self.jetCollection=="AnalysisJets") :
361 jetCollectionName="AntiKt4EMPFlowJets"
362 if(self.jetCollection=="AnalysisLargeRJets") :
363 jetCollectionName="AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets"
364
365 jetInput = config.getContainerMeta(self.containerName, 'jetInput', failOnMiss=True)
366
367 if jetInput not in ["EMTopo", "EMPFlow", "HI"]:
368 raise ValueError(
369 "Unsupported input type '{0}' for R=0.4 jets!".format(jetInput) )
370
371 if self.jvtWP not in ["FixedEffPt"]:
372 raise ValueError(
373 "Unsupported NNJvt WP '{0}'".format(self.jvtWP) )
374
375 if self.fJvtWP not in ["Loose", "Tight", "Tighter"]:
376 raise ValueError(
377 "Unsupported fJvt WP '{0}'".format(self.fJvtWP) )
378
379 if not config.isPhyslite() or self.recalibratePhyslite:
380 # Create calibration tool as public so it can be shared
381 # (e.g. with FTAG1LITE's JetCalibratedPtDecoratorAlg).
382 # Must be created before the algorithm so EventLoop
383 # initialises the tool first.
384 calibToolName = 'JetCalibTool_' + jetCollectionName[:-4]
385 calibTool = config.createPublicTool( 'JetCalibrationTool', calibToolName )
386 calibTool.JetCollection = jetCollectionName[:-4]
387 # Get the correct string to use in the config file name
388 if jetInput == "EMPFlow":
389 if config.geometry() is LHCPeriod.Run2:
390 configFile = "PreRec_R22_PFlow_ResPU_EtaJES_GSC_February23_230215.config"
391 calibTool.CalibArea = "00-04-82"
392 elif config.geometry() >= LHCPeriod.Run3:
393 configFile = "AntiKt4EMPFlow_MC23a_PreRecR22_Phase2_CalibConfig_ResPU_EtaJES_GSC_241208_InSitu.config"
394 calibTool.CalibArea = "00-04-83"
395 elif jetInput == "HI":
396 if config.geometry() is LHCPeriod.Run2:
397 configFile = "JES_MC16_HI_Jan2021_5TeV.config"
398 if config.geometry() is LHCPeriod.Run3:
399 configFile = "AntiKt4HI_MC23_EtaJES_Run3PreRec_Run2VJet_Run3EtaInt_5p36TeV.config"
400 calibTool.CalibArea = "00-04-83"
401 else:
402 if config.dataType() is DataType.FastSim:
403 configFile = "JES_MC16Recommendation_AFII_{0}_Apr2019_Rel21.config"
404 else:
405 configFile = "JES_MC16Recommendation_Consolidated_{0}_Apr2019_Rel21.config"
406 configFile = configFile.format(jetInput)
407 if self.calibToolCalibArea is not None:
408 calibTool.CalibArea = self.calibToolCalibArea
409 if self.calibToolConfigFile is not None:
410 configFile = self.calibToolConfigFile
411 calibTool.ConfigFile = configFile
412 if config.dataType() is DataType.Data:
413 if jetInput == "HI":
414 calibTool.CalibSequence = 'EtaJES_Insitu'
415 else:
416 calibTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC_Insitu'
417 else:
418 if jetInput == "EMPFlow":
419 calibTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC'
420 elif jetInput == "HI":
421 calibTool.CalibSequence = 'EtaJES'
422 else:
423 calibTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC_Smear'
424 if self.calibToolCalibSeq is not None:
425 calibTool.CalibSequence = self.calibToolCalibSeq
426 calibTool.IsData = (config.dataType() is DataType.Data)
427 # Prepare the jet calibration algorithm
428 alg = config.createAlgorithm( 'CP::JetCalibrationAlg', 'JetCalibrationAlg' )
429 alg.HIsetup = jetInput == "HI"
430 alg.calibrationTool = f'{calibTool.getType()}/{calibTool.getName()}'
431 alg.jets = config.readName (self.containerName)
432 alg.jetsOut = config.copyName (self.containerName)
433
434 # Jet uncertainties
436 alg = config.createAlgorithm( 'CP::JetUncertaintiesAlg', 'JetUncertaintiesAlg' )
437 self.createUncertaintyTool(alg, config, jetCollectionName, doPseudoData=( self.systematicsModelJER in ["Full","All"] ))
438 alg.jets = config.readName (self.containerName)
439 alg.jetsOut = config.copyName (self.containerName)
440 alg.preselection = config.getPreselection (self.containerName, '')
441
442 # Set up the JVT update algorithm:
443 if self.runJvtUpdate :
444 alg = config.createAlgorithm( 'CP::JvtUpdateAlg', 'JvtUpdateAlg' )
445 config.addPrivateTool( 'jvtTool', 'JetVertexTaggerTool' )
446 alg.jvtTool.JetContainer = self.jetCollection
447 alg.jvtTool.SuppressInputDependence=True
448 alg.jets = config.readName (self.containerName)
449 alg.jetsOut = config.copyName (self.containerName)
450 alg.preselection = config.getPreselection (self.containerName, '')
451
453 assert jetInput=="EMPFlow", "NN JVT only defined for PFlow jets"
454 alg = config.createAlgorithm( 'CP::JetDecoratorAlg', 'NNJvtUpdateAlg' )
455 config.addPrivateTool( 'decorator', 'JetPileupTag::JetVertexNNTagger' )
456 alg.jets = config.readName (self.containerName)
457 alg.jetsOut = config.copyName (self.containerName)
458 # Set this actually to the *output* collection
459 alg.decorator.JetContainer = alg.jetsOut.replace ('%SYS%', 'NOSYS')
460 alg.decorator.SuppressInputDependence=True
461 alg.decorator.SuppressOutputDependence=True
462
463 # Set up the jet efficiency scale factor calculation algorithm
464 # Change the truthJetCollection property to AntiKt4TruthWZJets if preferred
466 assert jetInput=="EMPFlow", "NNJvt WPs and SFs only valid for PFlow jets"
467 warnings.warn_explicit(
468 "jvtWP, runJvtSelection and runJvtEfficiency"
469 " are deprecated - please use a"
470 " JVTWorkingPoint block instead.",
471 ConfigDeprecationWarning, filename='', lineno=0)
472
473 alg = config.createAlgorithm('CP::AsgSelectionAlg', 'JvtSelectionAlg')
474 config.addPrivateTool('selectionTool', 'CP::NNJvtSelectionTool')
475 alg.selectionTool.JetContainer = config.readName(self.containerName)
476 alg.selectionTool.JvtMomentName = "NNJvt"
477 alg.selectionTool.WorkingPoint = self.jvtWP
478 alg.selectionTool.MaxPtForJvt = 60*GeV
479 alg.selectionDecoration = "jvt_selection,as_char"
480 alg.particles = config.readName(self.containerName)
481
482 if self.runJvtEfficiency and config.dataType() is not DataType.Data:
483 alg = config.createAlgorithm( 'CP::JvtEfficiencyAlg', 'JvtEfficiencyAlg' )
484 config.addPrivateTool( 'efficiencyTool', 'CP::NNJvtEfficiencyTool' )
485 alg.efficiencyTool.JetContainer = config.readName(self.containerName)
486 alg.efficiencyTool.MaxPtForJvt = 60*GeV
487 alg.efficiencyTool.WorkingPoint = self.jvtWP
488 if config.geometry() is LHCPeriod.Run2:
489 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/NNJvtSFFile_Run2_EMPFlow.root"
490 else:
491 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/NNJvtSFFile_Run3_EMPFlow.root"
492 alg.selection = 'jvt_selection,as_char'
493 alg.scaleFactorDecoration = 'jvt_effSF_%SYS%'
494 alg.outOfValidity = 2
495 alg.outOfValidityDeco = 'no_jvt'
496 alg.skipBadEfficiency = False
497 alg.jets = config.readName (self.containerName)
498 alg.preselection = config.getPreselection (self.containerName, '')
499 config.addOutputVar (self.containerName, alg.scaleFactorDecoration, 'jvtEfficiency')
500 config.addSelection (self.containerName, 'baselineJvt', 'jvt_selection,as_char', preselection=False)
501
503 assert jetInput=="EMPFlow", "fJvt WPs and SFs only valid for PFlow jets"
504 warnings.warn_explicit(
505 "fJvtWP, runFJvtSelection and runFJvtEfficiency"
506 " are deprecated - please use a"
507 " FJVTWorkingPoint block instead.",
508 ConfigDeprecationWarning, filename='', lineno=0)
509
510 alg = config.createAlgorithm('CP::AsgSelectionAlg', 'FJvtSelectionAlg')
511 config.addPrivateTool('selectionTool', 'CP::FJvtSelectionTool')
512 alg.selectionTool.JetContainer = config.readName(self.containerName)
513 alg.selectionTool.JvtMomentName = "DFCommonJets_fJvt"
514 alg.selectionTool.WorkingPoint = self.fJvtWP
515 alg.selectionDecoration = "fjvt_selection,as_char"
516 alg.particles = config.readName(self.containerName)
517
518 if self.runFJvtEfficiency and config.dataType() is not DataType.Data:
519 alg = config.createAlgorithm( 'CP::JvtEfficiencyAlg', 'FJvtEfficiencyAlg' )
520 config.addPrivateTool( 'efficiencyTool', 'CP::FJvtEfficiencyTool' )
521 alg.efficiencyTool.JetContainer = config.readName(self.containerName)
522 alg.efficiencyTool.WorkingPoint = self.fJvtWP
523 if config.geometry() is LHCPeriod.Run2:
524 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/fJvtSFFile_Run2_EMPFlow.root"
525 else:
526 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/fJvtSFFile_Run3_EMPFlow.root"
527 alg.selection = 'fjvt_selection,as_char'
528 alg.scaleFactorDecoration = 'fjvt_effSF_%SYS%'
529 alg.outOfValidity = 2
530 alg.outOfValidityDeco = 'no_fjvt'
531 alg.skipBadEfficiency = False
532 alg.jets = config.readName (self.containerName)
533 alg.preselection = config.getPreselection (self.containerName, '')
534 config.addOutputVar (self.containerName, alg.scaleFactorDecoration, 'fjvtEfficiency')
535 config.addSelection (self.containerName, 'baselineFJvt', 'fjvt_selection,as_char', preselection=False)
536
537 # Additional decorations
538 alg = config.createAlgorithm( 'CP::AsgEnergyDecoratorAlg', 'AsgEnergyDecoratorAlg' )
539 alg.particles = config.readName (self.containerName)
540
541 config.addOutputVar (self.containerName, 'e_%SYS%', 'e')
542
543
544class RScanJetAnalysisConfig (ConfigBlock) :
545 """the ConfigBlock for the r-scan jet sequence"""
546
547 def __init__ (self) :
548 super (RScanJetAnalysisConfig, self).__init__ ()
549 self.addOption ('containerName', '', type=str,
550 noneAction='error',
551 info="the name of the output container after calibration.")
552 self.addOption ('jetCollection', '', type=str,
553 noneAction='error',
554 info="the jet container to run on. It is interpreted to determine "
555 "the correct config blocks to call for small- or large-R jets.")
556 self.addOption ('recalibratePhyslite', True, type=bool,
557 info="whether to run the CP::JetCalibrationAlg on PHYSLITE "
558 "derivations. The default is True.")
559
560 def instanceName (self) :
561 """Return the instance name for this block"""
562 return self.containerName
563
564 def makeAlgs (self, config) :
565
566 # Self-select: only run for r-scan jets (radius 2 or 6)
567 radius = config.getContainerMeta(self.containerName, 'jetRadius', failOnMiss=True)
568 if radius not in [2, 6]:
569 return
570
571 jetCollectionName=self.jetCollection
572 if(self.jetCollection=="AnalysisJets") :
573 jetCollectionName="AntiKt4EMPFlowJets"
574 if(self.jetCollection=="AnalysisLargeRJets") :
575 jetCollectionName="AntiKt10LCTopoTrimmedPtFrac5SmallR20Jets"
576
577 jetInput = config.getContainerMeta(self.containerName, 'jetInput', failOnMiss=True)
578
579 if not config.isPhyslite() or self.recalibratePhyslite:
580 if jetInput not in ["LCTopo", "HI"]:
581 raise ValueError(
582 "Unsupported input type '{0}' for R-scan jets!".format(jetInput) )
583 # Create calibration tool before algorithm (EventLoop ordering)
584 calibToolName = 'JetCalibTool_' + jetCollectionName[:-4]
585 calibTool = config.createPublicTool( 'JetCalibrationTool', calibToolName )
586 calibTool.JetCollection = jetCollectionName[:-4]
587 if jetInput=="LCTopo":
588 calibTool.ConfigFile = \
589 "JES_MC16Recommendation_Rscan{0}LC_Feb2022_R21.config".format(radius)
590 if config.dataType() is DataType.Data:
591 calibTool.CalibSequence = "JetArea_Residual_EtaJES_GSC_Insitu"
592 else:
593 calibTool.CalibSequence = "JetArea_Residual_EtaJES_GSC_Smear"
594 elif jetInput=="HI":
595 calibTool.ConfigFile = \
596 "JES_MC16_HI_Jan2021_5TeV.config"
597 if config.dataType() is DataType.Data:
598 calibTool.CalibSequence = "EtaJES_Insitu"
599 else:
600 calibTool.CalibSequence = "EtaJES"
601 calibTool.IsData = (config.dataType() is DataType.Data)
602 # Prepare the jet calibration algorithm
603 alg = config.createAlgorithm( 'CP::JetCalibrationAlg', 'JetCalibrationAlg' )
604 alg.HIsetup = jetInput == "HI"
605 alg.calibrationTool = f'{calibTool.getType()}/{calibTool.getName()}'
606 alg.jets = config.readName (self.containerName)
607 warnings.warn_explicit(
608 "Uncertainties for R-Scan jets are not yet released!",
609 JetUncertaintyWarning, filename='', lineno=0)
610
611
612class LargeRJetAnalysisConfig (ConfigBlock) :
613 """the ConfigBlock for the large-r jet sequence"""
614
615 def __init__ (self) :
616 super (LargeRJetAnalysisConfig, self).__init__ ()
617 self.addOption ('containerName', '', type=str,
618 noneAction='error',
619 info="the name of the output container after calibration.")
620 self.addOption ('jetCollection', '', type=str,
621 noneAction='error',
622 info="the jet container to run on. It is interpreted to determine "
623 "the correct config blocks to call for small- or large-R jets.")
624 self.addOption ('jetInput', '', type=str,
625 noneAction='error',
626 info="the type of jet input. Supported options are: `UFO`.")
627 self.addOption ('recalibratePhyslite', True, type=bool,
628 info="whether to run the CP::JetCalibrationAlg on PHYSLITE "
629 "derivations. The default is True.")
630 self.addOption ('runUncertainties', True, type=bool,
631 info="whether to configure JetUncertaintiesTool.", expertMode=True )
632 self.addOption ('systematicsModelJER', "Full", type=str)
633 self.addOption ('systematicsModelJMS', "Full", type=str)
634 self.addOption ('systematicsModelJMR', "Full", type=str,
635 info="the NP reduction scheme to use for JMR: Full, Simple. The default is Full.")
636 self.addOption ('runJERsystematicsOnData', False, type=bool,
637 info="whether to run the All/Full JER model variations also on data samples. Expert option!",
638 expertMode=True)
639 # Adding these options to override the jet uncertainty config file when we have new recommendations
640 # Calibration tool options
641 self.addOption ('calibToolConfigFile', None, type=str,
642 info="name of the config file to use for the jet calibration "
643 "tool. Expert option to override JetETmiss recommendations.",
644 expertMode=True)
645 self.addOption ('calibToolCalibArea', None, type=str,
646 info="name of the CVMFS area to use for the jet calibration "
647 "tool. Expert option to override JetETmiss recommendations.",
648 expertMode=True)
649 self.addOption ('calibToolCalibSeq', None, type=str,
650 info="name of the sequence to use for the jet calibration "
651 "tool (e.g. `JetArea_Residual_EtaJES_GSC`). Expert option to override "
652 "JetETmiss recommendations.",
653 expertMode=True)
654 # Uncertainties tool options
655 self.addOption ('uncertToolConfigPath', None, type=str,
656 info="name of the config file to use for the JES, JER, and JMS uncertainty "
657 "tool. Expert option to override JetETmiss recommendations.",
658 expertMode=True)
659 self.addOption ('uncertToolConfigPathJMR', None, type=str,
660 info="name of the config file to use for the JMR uncertainty "
661 "tool. Expert option to override JetETmiss recommendations.",
662 expertMode=True)
663 self.addOption ('uncertToolCalibArea', None, type=str,
664 info="name (str) of the CVMFS area to use for the jet uncertainty "
665 "tool. Expert option to override JetETmiss recommendations. The "
666 "default is None.",
667 expertMode=True)
668 self.addOption ('uncertToolMCType', None, type=str,
669 info="data type (str) to use for the jet uncertainty tool (e.g. "
670 "'AF3' or 'MC16'). Expert option to override JetETmiss "
671 "recommendations. The default is None.",
672 expertMode=True)
673 self.addOption ('minPt', 200.*GeV, type=float,
674 info=r"the minimum $p_\mathrm{T}$ cut (in MeV) to apply to calibrated large-R jets.")
675 self.addOption ('maxPt', 3000.*GeV, type=float,
676 info=r"the maximum $p_\mathrm{T}$ cut (in MeV) to apply to calibrated large-R jets.")
677 self.addOption ('maxEta', 0., type=float,
678 info=r"the maximum $\vert\eta\vert$ cut to apply to calibrated large-R jets.")
679 self.addOption ('maxRapidity', 2., type=float,
680 info="the maximum rapidity cut to apply to calibrated large-R jets.")
681 self.addOption ('minMass', 40.*GeV, type=float,
682 info="the minimum mass cut (in MeV) to apply to calibrated large-R jets.")
683 self.addOption ('maxMass', 600.*GeV, type=float,
684 info="the maximum mass cut (in MeV) to apply to calibrated large-R jets.")
685
686 def instanceName (self) :
687 """Return the instance name for this block"""
688 return self.containerName
689
690 def getUncertaintyToolSettings(self, config):
691 # Retrieve appropriate JES/JER recommendations for the JetUncertaintiesTool.
692 # We do this separately from the tool declaration, as we may need to set uo
693 # two such tools, but they have to be private.
694
695
696 # Config file:
697 config_file = None
698 if self.systematicsModelJER in ["Simple", "Full"] and self.systematicsModelJMS in ["Simple", "Full"]:
699 config_file = "R10_CategoryJES_{0}JER_{1}JMS.config".format(self.systematicsModelJER, self.systematicsModelJMS)
700 else:
701 raise ValueError(
702 "Invalid request for systematicsModelJER/JMS settings: "
703 "systematicsModelJER = '{0}', "
704 "systematicsModelJMS = '{1}'".format(self.systematicsModelJER, self.systematicsModelJMS) )
705 if self.uncertToolConfigPath is not None:
706 # Expert override
707 config_file = self.uncertToolConfigPath
708 else:
709 if config.geometry() in [LHCPeriod.Run2, LHCPeriod.Run3]:
710 config_file = "rel22/Summer2025_PreRec/" + config_file
711 else:
712 warnings.warn_explicit(
713 "Uncertainties for UFO jets are not for Run 4!"
714 " are deprecated - please use a"
715 " JVTWorkingPoint block instead.",
716 JetUncertaintyWarning, filename='', lineno=0)
717
718
719 # Calibration area:
720 calib_area = None
721 if self.uncertToolCalibArea is not None:
722 calib_area = self.uncertToolCalibArea
723
724 # MC type:
725 if self.uncertToolMCType is not None:
726 mc_type = self.uncertToolMCType
727 else:
728 if config.dataType() is DataType.FastSim:
729 if config.geometry() is LHCPeriod.Run2:
730 mc_type = "MC20AF3"
731 else:
732 mc_type = "MC23AF3"
733 else:
734 if config.geometry() is LHCPeriod.Run2:
735 mc_type = "MC20"
736 else:
737 mc_type = "MC23"
738
739 return config_file, calib_area, mc_type
740
741 def createUncertaintyTool(self, jetUncertaintiesAlg, config, jetCollectionName, doPseudoData=False):
742 '''
743 Create instance(s) of JetUncertaintiesTool following JetETmiss recommendations.
744
745 JER uncertainties under the "Full" scheme must be run on MC samples twice:
746 1. Normal (MC) mode,
747 2. Pseudodata (PD) mode, as if the events are Data.
748 '''
749
750 # Retrieve the common configuration settings
751 configFile, calibArea, mcType = self.getUncertaintyToolSettings(config)
752
753 # The main tool for all JER combinations
754 config.addPrivateTool( 'uncertaintiesTool', 'JetUncertaintiesTool' )
755 jetUncertaintiesAlg.uncertaintiesTool.JetDefinition = jetCollectionName[:-4]
756 jetUncertaintiesAlg.uncertaintiesTool.ConfigFile = configFile
757 if calibArea is not None:
758 jetUncertaintiesAlg.uncertaintiesTool.CalibArea = calibArea
759 jetUncertaintiesAlg.uncertaintiesTool.MCType = mcType
760 jetUncertaintiesAlg.uncertaintiesTool.IsData = (config.dataType() is DataType.Data)
761 jetUncertaintiesAlg.uncertaintiesTool.PseudoDataJERsmearingMode = False
762
763 # JER smearing on data
764 if config.dataType() is DataType.Data and not (config.isPhyslite() and doPseudoData and self.runJERsystematicsOnData):
765 # we don't want any systematics on data if we're not using the right JER model!
766 jetUncertaintiesAlg.affectingSystematicsFilter = '.*'
767
768 if config.dataType() is not (DataType.Data and config.isPhyslite()) and doPseudoData and not self.runJERsystematicsOnData:
769 # The secondary tool for pseudo-data JER smearing
770 config.addPrivateTool( 'uncertaintiesToolPD', 'JetUncertaintiesTool' )
771 jetUncertaintiesAlg.uncertaintiesToolPD.JetDefinition = jetCollectionName[:-4]
772 jetUncertaintiesAlg.uncertaintiesToolPD.ConfigFile = configFile
773 if calibArea is not None:
774 jetUncertaintiesAlg.uncertaintiesToolPD.CalibArea = calibArea
775 jetUncertaintiesAlg.uncertaintiesToolPD.MCType = mcType
776 jetUncertaintiesAlg.uncertaintiesToolPD.IsData = True
777 jetUncertaintiesAlg.uncertaintiesToolPD.PseudoDataJERsmearingMode = True
778
779 def createFFSmearingTool(self, jetFFSmearingAlg, config):
780 # Retrieve appropriate large-R jet mass resolution recommendations for the FFJetSmearingTool.
781
782 # Config file:
783 if self.systematicsModelJMR in ["Simple", "Full"]:
784 config_file = f"R10_{self.systematicsModelJMR}JMR.config"
785 else:
786 raise ValueError(
787 f"Invalid request for systematicsModelJMR settings: {self.systematicsModelJMR}"
788 )
789
790 # Expert override for config path:
791 if self.uncertToolConfigPathJMR is not None:
792 config_file = self.uncertToolConfigPathJMR
793 else:
794 config_file = "rel22/Summer2025_PreRec/" + config_file
795 if config.geometry() is LHCPeriod.Run4:
796 warnings.warn_explicit(
797 "Uncertainties for UFO jets are not for Run 4!",
798 JetUncertaintyWarning, filename='', lineno=0)
799
800 # MC type:
801 if config.geometry() is LHCPeriod.Run2:
802 if config.dataType() is DataType.FastSim:
803 mc_type = "MC20AF3"
804 else:
805 mc_type = "MC20"
806 elif config.geometry() >= LHCPeriod.Run3:
807 if config.dataType() is DataType.FastSim:
808 mc_type = "MC23AF3"
809 else:
810 mc_type = "MC23"
811
812 # Set up the FF smearing tool
813 config.addPrivateTool( 'FFSmearingTool', 'CP::FFJetSmearingTool')
814 jetFFSmearingAlg.FFSmearingTool.MassDef = "UFO"
815 jetFFSmearingAlg.FFSmearingTool.MCType = mc_type
816 jetFFSmearingAlg.FFSmearingTool.ConfigFile = config_file
817
818 def makeAlgs (self, config) :
819
820 # Self-select: only run for large-R (radius 10) jets
821 if config.getContainerMeta(self.containerName, 'jetRadius', failOnMiss=True) != 10:
822 return
823
824 configFile = None
825 calibSeq = None
826 calibArea = None
827
828 jetCollectionName=self.jetCollection
829 if(self.jetCollection=="AnalysisJets") :
830 jetCollectionName="AntiKt4EMPFlowJets"
831 if(self.jetCollection=="AnalysisLargeRJets") :
832 jetCollectionName="AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets"
833
834 jetInput = config.getContainerMeta(self.containerName, 'jetInput', failOnMiss=True)
835 trim = config.getContainerMeta(self.containerName, 'jetTrim', failOnMiss=True)
836
837 if jetInput not in ["UFO"]:
838 raise ValueError("Invalid input type '{0}' for large-R jets!".format(jetInput) )
839
840 if not trim:
841 raise ValueError("Untrimmed large-R jets are not supported!")
842
843 configFile = "JES_MC20PreRecommendation_R10_UFO_CSSK_SoftDrop_JMS_R21Insitu_26Nov2024.config"
844 calibArea = "00-04-83"
845 if self.calibToolConfigFile is not None:
846 configFile = self.calibToolConfigFile
847
848 if config.dataType() is not DataType.Data:
849 calibSeq = "EtaJES_JMS"
850 elif config.dataType() is DataType.Data:
851 calibSeq = "EtaJES_JMS_Insitu"
852 if self.calibToolCalibSeq is not None:
853 calibSeq = self.calibToolCalibSeq
854
855 if self.calibToolCalibArea is not None:
856 calibArea = self.calibToolCalibArea
857
858 if not config.isPhyslite() or self.recalibratePhyslite:
859 # Create calibration tool before algorithm (EventLoop ordering)
860 calibToolName = 'JetCalibTool_' + jetCollectionName[:-4]
861 calibTool = config.createPublicTool( 'JetCalibrationTool', calibToolName )
862
863 calibTool.JetCollection = jetCollectionName[:-4]
864
865 if configFile is None:
866 raise ValueError(f'Unsupported: {jetInput=}, {config.dataType()=}')
867 calibTool.ConfigFile = configFile
868
869 if calibSeq is None:
870 raise ValueError(f'Unsupported: {jetInput=}, {config.dataType()=}')
871 calibTool.CalibSequence = calibSeq
872
873 if calibArea is not None:
874 calibTool.CalibArea = calibArea
875
876 calibTool.IsData = (config.dataType() is DataType.Data)
877 # Prepare the jet calibration algorithm
878 alg = config.createAlgorithm( 'CP::JetCalibrationAlg', 'JetCalibrationAlg' )
879 alg.calibrationTool = f'{calibTool.getType()}/{calibTool.getName()}'
880 alg.jets = config.readName(self.containerName)
881 alg.jetsOut = config.copyName(self.containerName)
882
883 # Jet uncertainties
884 if jetInput == "UFO" and config.dataType() in [DataType.FullSim, DataType.FastSim] and self.runUncertainties:
885 alg = config.createAlgorithm( 'CP::JetUncertaintiesAlg', 'JetUncertaintiesAlg' )
886 self.createUncertaintyTool(alg, config, jetCollectionName, doPseudoData=( self.systematicsModelJER in ["Full","All"] ))
887
888 alg.uncertaintiesTool.JetDefinition = jetCollectionName[:-4]
889
890 # R=1.0 jets have a validity range
891 alg.outOfValidity = 2 # SILENT
892 alg.outOfValidityDeco = 'outOfValidity'
893
894 alg.jets = config.readName (self.containerName)
895 alg.jetsOut = config.copyName (self.containerName)
896 alg.preselection = config.getPreselection (self.containerName, '')
897
898 if jetInput != "UFO" and self.runUncertainties:
899 alg = config.createAlgorithm( 'CP::JetUncertaintiesAlg', 'JetUncertaintiesAlg' )
900
901 # R=1.0 jets have a validity range
902 alg.outOfValidity = 2 # SILENT
903 alg.outOfValidityDeco = 'outOfValidity'
904 config.addPrivateTool( 'uncertaintiesTool', 'JetUncertaintiesTool' )
905
906 alg.uncertaintiesTool.JetDefinition = jetCollectionName[:-4]
907 alg.uncertaintiesTool.ConfigFile = \
908 "rel21/Moriond2018/R10_{0}Mass_all.config".format(self.largeRMass)
909 alg.uncertaintiesTool.MCType = "MC16a"
910 alg.uncertaintiesTool.IsData = (config.dataType() is DataType.Data)
911
912 alg.jets = config.readName (self.containerName)
913 alg.jetsOut = config.copyName (self.containerName)
914 alg.preselection = config.getPreselection (self.containerName, '')
915 config.addSelection (self.containerName, '', 'outOfValidity')
916
917 if jetInput == "UFO" and config.dataType() is not DataType.Data:
918 # set up the FF smearing algorithm
919 alg = config.createAlgorithm( 'CP::JetFFSmearingAlg', 'JetFFSmearingAlg' )
920 self.createFFSmearingTool(alg, config)
921 alg.outOfValidity = 2 # SILENT
922 alg.outOfValidityDeco = 'outOfValidityJMR'
923 alg.jets = config.readName (self.containerName)
924 alg.jetsOut = config.copyName (self.containerName)
925 alg.preselection = config.getPreselection (self.containerName, '')
926
927 if self.minPt > 0 or self.maxPt > 0 or self.maxEta > 0 or self.maxRapidity > 0:
928 # Set up the the pt-eta selection
929 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'JetPtEtaCutAlg' )
930 alg.selectionDecoration = 'selectPtEta,as_bits'
931 config.addPrivateTool( 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
932 alg.selectionTool.minPt = self.minPt
933 alg.selectionTool.maxPt = self.maxPt
934 alg.selectionTool.maxEta = self.maxEta
935 alg.selectionTool.maxRapidity = self.maxRapidity
936 alg.particles = config.readName (self.containerName)
937 alg.preselection = config.getPreselection (self.containerName, '')
938 config.addSelection (self.containerName, '', alg.selectionDecoration,
939 preselection=True)
940
941 if self.minMass > 0 or self.maxMass > 0:
942 # Set up the the mass selection
943 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'JetMassCutAlg' )
944 alg.selectionDecoration = 'selectMass,as_bits'
945 config.addPrivateTool( 'selectionTool', 'CP::AsgMassSelectionTool' )
946 alg.selectionTool.minM = self.minMass
947 alg.selectionTool.maxM = self.maxMass
948 alg.particles = config.readName (self.containerName)
949 alg.preselection = config.getPreselection (self.containerName, '')
950 config.addSelection (self.containerName, '', alg.selectionDecoration,
951 preselection=True)
952
953 config.addOutputVar (self.containerName, 'm', 'm')
954
956 """the ConfigBlock for the Jvt working point selection"""
957
958 def __init__ (self) :
959 super (JvtWorkingPointSelectionConfig, self).__init__ ()
960 self.setBlockName('JvtWorkingPointSelectionConfig')
961 self.addOption ('containerName', '', type=str,
962 noneAction='error',
963 info="the name of the input container.")
964 self.addOption ('selectionName', '', type=str,
965 noneAction='error',
966 info="the name of the jet selection to define (e.g. `tight` or `loose`).")
967 self.addOption ('jvtWP', '', type=str,
968 noneAction='error',
969 info="the NNJvt WP to use. Supported WPs: `FixedEffPt`.")
970 self.addOption ('useSuffix', True, type=bool,
971 info="whether the working point name is to be used as suffix ."
972 "Not to be disabled if multiple working points are scheduled.")
973
974 def instanceName (self) :
975 return self.containerName + '_' + self.selectionName
976
977 def makeAlgs (self, config) :
978
979 suffix = f"_{self.jvtWP}" if self.useSuffix else ""
980 decorationName = f"jvt_selection{suffix},as_char"
981 selectionName = self.selectionName
982
983 alg = config.createAlgorithm('CP::AsgSelectionAlg', f'JvtSelectionAlg_{self.jvtWP}')
984 config.addPrivateTool('selectionTool', 'CP::NNJvtSelectionTool')
985 alg.selectionTool.JetContainer = config.readName(self.containerName)
986 alg.selectionTool.JvtMomentName = "NNJvt"
987 alg.selectionTool.WorkingPoint = self.jvtWP
988 alg.selectionTool.MaxPtForJvt = 60*GeV
989 alg.selectionDecoration = decorationName
990 alg.particles = config.readName(self.containerName)
991
992 config.addSelection (self.containerName, selectionName, decorationName, preselection=False)
993
994
996 """the ConfigBlock for the Jvt working point efficiency"""
997
998 def __init__ (self) :
999 super (JvtWorkingPointEfficiencyConfig, self).__init__ ()
1000 self.setBlockName('JvtWorkingPointEfficiencyConfig')
1001 self.addDependency('EventSelection', required=False)
1002 self.addDependency('EventSelectionMerger', required=False)
1003 self.addOption ('containerName', '', type=str,
1004 noneAction='error',
1005 info="the name of the input container.")
1006 self.addOption ('selectionName', '', type=str,
1007 noneAction='error',
1008 info="the name of the jet selection to define (e.g. `tight` or `loose`).")
1009 self.addOption ('jvtWP', '', type=str,
1010 noneAction='error',
1011 info="the NNJvt WP to use. Supported WPs: `FixedEffPt`.")
1012 self.addOption ('useSuffix', True, type=bool,
1013 info="whether the working point name is to be used as suffix ."
1014 "Not to be disabled if multiple working points are scheduled.")
1015 self.addOption ('noEffSF', False, type=bool,
1016 info="disables the calculation of efficiencies and scale factors. "
1017 "Only useful to test a new WP for which scale factors are not available.",
1018 expertMode=True)
1019
1020 def instanceName (self) :
1021 return self.containerName + '_' + self.selectionName
1022
1023 def makeAlgs (self, config) :
1024
1025 suffix = f"_{self.jvtWP}" if self.useSuffix else ""
1026 decorationName = f"jvt_selection{suffix},as_char"
1027
1028 if not self.noEffSF and config.dataType() is not DataType.Data:
1029 alg = config.createAlgorithm( 'CP::JvtEfficiencyAlg', f'JvtEfficiencyAlg_{self.jvtWP}' )
1030 config.addPrivateTool( 'efficiencyTool', 'CP::NNJvtEfficiencyTool' )
1031 alg.efficiencyTool.JetContainer = config.readName(self.containerName)
1032 alg.efficiencyTool.MaxPtForJvt = 60*GeV
1033 alg.efficiencyTool.WorkingPoint = self.jvtWP
1034 if config.geometry() is LHCPeriod.Run2:
1035 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/NNJvtSFFile_Run2_EMPFlow.root"
1036 else:
1037 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/NNJvtSFFile_Run3_EMPFlow.root"
1038 alg.selection = decorationName
1039 alg.scaleFactorDecoration = f'jvt_effSF{suffix}_%SYS%'
1040 alg.outOfValidity = 2
1041 alg.outOfValidityDeco = f'no_jvt{suffix}'
1042 alg.skipBadEfficiency = False
1043 alg.jets = config.readName (self.containerName)
1044 alg.preselection = config.getPreselection (self.containerName, '')
1045
1046 config.addOutputVar (self.containerName, alg.scaleFactorDecoration, f'jvtEfficiency{suffix}')
1047
1048
1050 """the ConfigBlock for the event Jvt working point efficiency"""
1051
1052 def __init__ (self) :
1053 super (JvtWorkingPointEventEfficiencyConfig, self).__init__ ()
1054 self.setBlockName('JvtWorkingPointEventEfficiencyConfig')
1055 self.addDependency('JvtWorkingPointEfficiencyConfig', required=True)
1056 self.addDependency('OverlapRemoval', required=False)
1057 self.addDependency('EventSelection', required=False)
1058 self.addDependency('EventSelectionMerger', required=False)
1059 self.addOption ('containerName', '', type=str,
1060 noneAction='error',
1061 info="the name of the input container.")
1062 self.addOption ('selectionName', '', type=str,
1063 noneAction='error',
1064 info="the name of the jet selection to define (e.g. `tight` or `loose`).")
1065 self.addOption ('jvtWP', '', type=str,
1066 noneAction='error',
1067 info="the NNJvt WP to use. Supported WPs: `FixedEffPt`.")
1068 self.addOption ('useSuffix', True, type=bool,
1069 info="whether the working point name is to be used as suffix ."
1070 "Not to be disabled if multiple working points are scheduled.")
1071 self.addOption ('noEffSF', False, type=bool,
1072 info="disables the calculation of efficiencies and scale factors. "
1073 "Only useful to test a new WP for which scale factors are not available.",
1074 expertMode=True)
1075 self.addOption ('eventSF', True, type=bool,
1076 info="add calculation of event-level efficiency SF.")
1077
1078 def instanceName (self) :
1079 return self.containerName + '_' + self.selectionName
1080
1081 def makeAlgs (self, config) :
1082
1083 if (not self.noEffSF and self.eventSF and
1084 config.dataType() is not DataType.Data):
1085 suffix = f"_{self.jvtWP}" if self.useSuffix else ""
1086 alg = config.createAlgorithm( 'CP::AsgEventScaleFactorAlg', f'JvtEventScaleFactorAlg_{self.jvtWP}' )
1087 preselection = config.getFullSelection (self.containerName, '')
1088 alg.preselection = preselection + f'&&no_jvt{suffix}' if preselection else f'no_jvt{suffix}'
1089 alg.scaleFactorInputDecoration = f'jvt_effSF{suffix}_%SYS%'
1090 alg.scaleFactorOutputDecoration = f'jvt_effSF{suffix}_%SYS%'
1091 alg.particles = config.readName (self.containerName)
1092
1093 config.addOutputVar('EventInfo', alg.scaleFactorOutputDecoration, f'weight_jvt_effSF{suffix}')
1094
1095
1097 """the ConfigBlock for the fJvt working point selection"""
1098
1099 def __init__ (self) :
1100 super (FJvtWorkingPointSelectionConfig, self).__init__ ()
1101 self.setBlockName('FJvtWorkingPointSelectionConfig')
1102 self.addOption ('containerName', '', type=str,
1103 noneAction='error',
1104 info="the name of the input container.")
1105 self.addOption ('selectionName', '', type=str,
1106 noneAction='error',
1107 info="the name of the jet selection to define (e.g. `tight` or `loose`).")
1108 self.addOption ('fjvtWP', '', type=str,
1109 noneAction='error',
1110 info="the fJvt WP to use. Supported WPs: `Loose`, `Tight`, `Tighter`.")
1111 self.addOption ('useSuffix', True, type=bool,
1112 info="whether the working point name is to be used as suffix ."
1113 "Not to be disabled if multiple working points are scheduled.")
1114
1115 def instanceName (self) :
1116 return self.containerName + '_' + self.selectionName
1117
1118 def makeAlgs (self, config) :
1119
1120 suffix = f"_{self.fjvtWP}" if self.useSuffix else ""
1121 decorationName = f"fjvt_selection{suffix},as_char"
1122 selectionName = self.selectionName
1123
1124 alg = config.createAlgorithm('CP::AsgSelectionAlg', f'FJvtSelectionAlg_{self.fjvtWP}')
1125 config.addPrivateTool('selectionTool', 'CP::FJvtSelectionTool')
1126 alg.selectionTool.JetContainer = config.readName(self.containerName)
1127 alg.selectionTool.JvtMomentName = "DFCommonJets_fJvt"
1128 alg.selectionTool.WorkingPoint = self.fjvtWP
1129 alg.selectionDecoration = decorationName
1130 alg.particles = config.readName(self.containerName)
1131
1132 config.addSelection (self.containerName, selectionName, decorationName, preselection=False)
1133
1134
1136 """the ConfigBlock for the fJvt working point efficiency"""
1137
1138 def __init__ (self) :
1139 super (FJvtWorkingPointEfficiencyConfig, self).__init__ ()
1140 self.setBlockName('FJvtWorkingPointEfficiencyConfig')
1141 self.addDependency('EventSelection', required=False)
1142 self.addDependency('EventSelectionMerger', required=False)
1143 self.addOption ('containerName', '', type=str,
1144 noneAction='error',
1145 info="the name of the input container.")
1146 self.addOption ('selectionName', '', type=str,
1147 noneAction='error',
1148 info="the name of the jet selection to define (e.g. `tight` or `loose`).")
1149 self.addOption ('fjvtWP', '', type=str,
1150 noneAction='error',
1151 info="the fJvt WP to use. Supported WPs: `Loose`, `Tight`, `Tighter`.")
1152 self.addOption ('useSuffix', True, type=bool,
1153 info="whether the working point name is to be used as suffix ."
1154 "Not to be disabled if multiple working points are scheduled.")
1155 self.addOption ('noEffSF', False, type=bool,
1156 info="disables the calculation of efficiencies and scale factors. "
1157 "Only useful to test a new WP for which scale factors are not available.",
1158 expertMode=True)
1159
1160 def instanceName (self) :
1161 return self.containerName + '_' + self.selectionName
1162
1163 def makeAlgs (self, config) :
1164
1165 suffix = f"_{self.fjvtWP}" if self.useSuffix else ""
1166 decorationName = f"fjvt_selection{suffix},as_char"
1167
1168 if not self.noEffSF and config.dataType() is not DataType.Data:
1169 alg = config.createAlgorithm( 'CP::JvtEfficiencyAlg', f'FJvtEfficiencyAlg_{self.fjvtWP}' )
1170 config.addPrivateTool( 'efficiencyTool', 'CP::FJvtEfficiencyTool' )
1171 alg.efficiencyTool.JetContainer = config.readName(self.containerName)
1172 alg.efficiencyTool.WorkingPoint = self.fjvtWP
1173 if config.geometry() is LHCPeriod.Run2:
1174 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/fJvtSFFile_Run2_EMPFlow.root"
1175 else:
1176 alg.efficiencyTool.SFFile = "JetJvtEfficiency/May2024/fJvtSFFile_Run3_EMPFlow.root"
1177 alg.selection = decorationName
1178 alg.scaleFactorDecoration = f'fjvt_effSF{suffix}_%SYS%'
1179 alg.outOfValidity = 2
1180 alg.outOfValidityDeco = f'no_fjvt{suffix}'
1181 alg.skipBadEfficiency = False
1182 alg.jets = config.readName (self.containerName)
1183 alg.preselection = config.getPreselection (self.containerName, '')
1184
1185 config.addOutputVar (self.containerName, alg.scaleFactorDecoration, f'fjvtEfficiency{suffix}')
1186
1187
1189 """the ConfigBlock for the event fJvt working point efficiency"""
1190
1191 def __init__ (self) :
1192 super (FJvtWorkingPointEventEfficiencyConfig, self).__init__ ()
1193 self.setBlockName('FJvtWorkingPointEventEfficiencyConfig')
1194 self.addDependency('FJvtWorkingPointEfficiencyConfig', required=True)
1195 self.addDependency('OverlapRemoval', required=False)
1196 self.addDependency('EventSelection', required=False)
1197 self.addDependency('EventSelectionMerger', required=False)
1198 self.addOption ('containerName', '', type=str,
1199 noneAction='error',
1200 info="the name of the input container.")
1201 self.addOption ('selectionName', '', type=str,
1202 noneAction='error',
1203 info="the name of the jet selection to define (e.g. `tight` or `loose`).")
1204 self.addOption ('fjvtWP', '', type=str,
1205 noneAction='error',
1206 info="the fJvt WP to use. Supported WPs: `Loose`, `Tight`, `Tighter`.")
1207 self.addOption ('useSuffix', True, type=bool,
1208 info="whether the working point name is to be used as suffix ."
1209 "Not to be disabled if multiple working points are scheduled.")
1210 self.addOption ('noEffSF', False, type=bool,
1211 info="disables the calculation of efficiencies and scale factors. "
1212 "Only useful to test a new WP for which scale factors are not available.",
1213 expertMode=True)
1214 self.addOption ('eventSF', True, type=bool,
1215 info="add calculation of event-level efficiency SF.")
1216
1217 def instanceName (self) :
1218 return self.containerName + '_' + self.selectionName
1219
1220 def makeAlgs (self, config) :
1221
1222 if (not self.noEffSF and self.eventSF and
1223 config.dataType() is not DataType.Data):
1224 suffix = f"_{self.fjvtWP}" if self.useSuffix else ""
1225 alg = config.createAlgorithm( 'CP::AsgEventScaleFactorAlg', f'ForwardJvtEventScaleFactorAlg_{self.fjvtWP}' )
1226 preselection = config.getFullSelection (self.containerName, '')
1227 alg.preselection = preselection + f'&&no_fjvt{suffix}' if preselection else f'no_fjvt{suffix}'
1228 alg.scaleFactorInputDecoration = f'fjvt_effSF{suffix}_%SYS%'
1229 alg.scaleFactorOutputDecoration = f'fjvt_effSF{suffix}_%SYS%'
1230 alg.particles = config.readName (self.containerName)
1231
1232 config.addOutputVar('EventInfo', alg.scaleFactorOutputDecoration, f'weight_fjvt_effSF{suffix}')
1233
1234
1235@groupBlocks
1236def Jets(seq):
1237 seq.append(PreJetAnalysisConfig())
1238 seq.append(SmallRJetAnalysisConfig())
1239 seq.append(RScanJetAnalysisConfig())
1240 seq.append(LargeRJetAnalysisConfig())
1241
1242@groupBlocks
1244 seq.append(JvtWorkingPointSelectionConfig())
1247
1248@groupBlocks
if(pathvar)
createFFSmearingTool(self, jetFFSmearingAlg, config)
createUncertaintyTool(self, jetUncertaintiesAlg, config, jetCollectionName, doPseudoData=False)
createUncertaintyTool(self, jetUncertaintiesAlg, config, jetCollectionName, doPseudoData=False)
Definition Jets.py:1
_parseJetCollection(jetCollection)