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