ATLAS Offline Software
Loading...
Searching...
No Matches
TauAnalysisConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3# AnaAlgorithm import(s):
4from AnalysisAlgorithmsConfig.ConfigAccumulator import DataType
5from AnalysisAlgorithmsConfig.ConfigSequence import groupBlocks
6from AnalysisAlgorithmsConfig.ConfigBlock import ConfigBlock
7from AthenaCommon.Logging import logging
8from AthenaConfiguration.Enums import LHCPeriod
9from Campaigns.Utils import Campaign
10
11from TriggerAnalysisAlgorithms.TriggerAnalysisSFConfig import trigger_set
12
13
14class TauCalibrationConfig (ConfigBlock):
15 """the ConfigBlock for the tau four-momentum correction"""
16
17 def __init__ (self) :
18 super (TauCalibrationConfig, self).__init__ ()
19 self.setBlockName('Taus')
20 self.addOption ('inputContainer', '', type=str,
21 info="the name of the input tau-jet container. If left empty, automatically defaults "
22 "to `'AnalysisTauJets'` for PHYSLITE and `'TauJets'` otherwise.")
23 self.addOption ('containerName', '', type=str,
24 noneAction='error',
25 info="the name of the output container after calibration.")
26 self.addOption ('postfix', '', type=str,
27 info="a postfix to apply to decorations and algorithm names. "
28 "Typically not needed here since the calibration is common to "
29 "all tau-jets.")
30 self.addOption ('rerunTruthMatching', True, type=bool,
31 info="whether to rerun truth matching (sets up an instance of "
32 "`CP::TauTruthMatchingAlg`).")
33 self.addOption ('decorateTruth', False, type=bool,
34 info="decorate the truth particle information on the reconstructed one.")
35 self.addOption ('decorateExtraVariables', True, type=bool,
36 info="decorate extra variables for the reconstructed tau-jet.")
37 self.addOption ('addGlobalFELinksDep', False, type=bool,
38 info="whether to add dependencies for the global FE links (needed for PHYSLITE production)",
39 expertMode=True)
40
41 def instanceName (self) :
42 """Return the instance name for this block"""
43 return self.containerName + self.postfix
44
45 def makeAlgs (self, config) :
46
47 # protection for EleRM taus, which are available only from 2024 onward
48 if 'EleRM' in self.inputContainer:
49 if config.dataType() is DataType.Data and config.dataYear() <= 2023:
50 raise RuntimeError("EleRM taus are only available from 2024 dataset onward")
51 elif config.dataType() is not DataType.Data and config.campaign() <= Campaign.MC23d:
52 raise RuntimeError("EleRM taus are only available from 2024 dataset onward")
53
54 postfix = self.postfix
55 if postfix != '' and postfix[0] != '_' :
56 postfix = '_' + postfix
57
58 inputContainer = "AnalysisTauJets" if config.isPhyslite() else "TauJets"
59 if self.inputContainer:
60 inputContainer = self.inputContainer
61 config.setSourceName (self.containerName, inputContainer)
62
63 # Set up a shallow copy to decorate
64 if config.wantCopy (self.containerName) :
65 alg = config.createAlgorithm( 'CP::AsgShallowCopyAlg', 'TauShallowCopyAlg' )
66 alg.input = config.readName (self.containerName)
67 alg.output = config.copyName (self.containerName)
68 alg.outputType = 'xAOD::TauJetContainer'
70 alg.declareDecorations = ['neutralGlobalFELinks', 'chargedGlobalFELinks']
71
72 # Set up the tau truth matching algorithm:
73 if self.rerunTruthMatching and config.dataType() is not DataType.Data:
74 alg = config.createAlgorithm( 'CP::TauTruthMatchingAlg',
75 'TauTruthMatchingAlg' )
76 config.addPrivateTool( 'matchingTool',
77 'TauAnalysisTools::TauTruthMatchingTool' )
78 alg.matchingTool.TruthJetContainerName = 'AntiKt4TruthDressedWZJets'
79 alg.taus = config.readName (self.containerName)
80 alg.preselection = config.getPreselection (self.containerName, '')
81
82 # decorate truth tau information on the reconstructed object:
83 if self.decorateTruth and config.dataType() is not DataType.Data:
84 alg = config.createAlgorithm( 'CP::TauTruthDecorationsAlg',
85 'TauTruthDecorationsAlg',
86 reentrant=True )
87 alg.taus = config.readName (self.containerName, nominal=True)
88 alg.doubleDecorations = ['pt_vis', 'pt_invis', 'eta_vis', 'eta_invis', 'phi_vis', 'phi_invis', 'm_vis', 'm_invis']
89 alg.floatDecorations = []
90 alg.intDecorations = ['pdgId']
91 alg.unsignedIntDecorations = ['classifierParticleOrigin', 'classifierParticleType']
92 alg.charDecorations = ['IsHadronicTau']
93 alg.prefix = 'truth_'
94
95 # these are "_ListHelper" objects, and not "list", need to copy to lists to allow concatenate
96 for var in ['DecayMode', 'ParticleType', 'PartonTruthLabelID'] + alg.doubleDecorations[:] + alg.floatDecorations[:] + alg.intDecorations[:] + alg.unsignedIntDecorations[:] + alg.charDecorations[:]:
97 branchName = alg.prefix + var
98 if 'classifierParticle' in var:
99 branchOutput = alg.prefix + var.replace('classifierParticle', '').lower()
100 else:
101 branchOutput = branchName
102 config.addOutputVar (self.containerName, branchName, branchOutput, noSys=True)
103
104 # Decorate extra variables
106 alg = config.createAlgorithm( 'CP::TauExtraVariablesAlg',
107 'TauExtraVariablesAlg',
108 reentrant=True )
109 alg.taus = config.readName (self.containerName, nominal=True)
110
111 # Set up the tau 4-momentum smearing algorithm:
112 alg = config.createAlgorithm( 'CP::TauSmearingAlg', 'TauSmearingAlg' )
113 config.addPrivateTool( 'smearingTool', 'TauAnalysisTools::TauSmearingTool' )
114 alg.smearingTool.useFastSim = config.dataType() is DataType.FastSim
115 alg.smearingTool.Campaign = "mc23" if config.geometry() is LHCPeriod.Run3 else "mc20"
116 alg.taus = config.readName (self.containerName)
117 alg.tausOut = config.copyName (self.containerName)
118 config.setExtraOutputs ({('xAOD::IParticleContainer' , 'StoreGateSvc+' + config.readName(self.containerName, nominal=True) + '.RNNEleScoreSigTrans_v1')})
119 alg.preselection = config.getPreselection (self.containerName, '')
120
121 # Additional decorations
122 alg = config.createAlgorithm( 'CP::AsgEnergyDecoratorAlg', 'EnergyDecorator' )
123 alg.particles = config.readName (self.containerName)
124
125 config.addOutputVar (self.containerName, 'pt', 'pt')
126 config.addOutputVar (self.containerName, 'eta', 'eta', noSys=True)
127 config.addOutputVar (self.containerName, 'phi', 'phi', noSys=True)
128 config.addOutputVar (self.containerName, 'e_%SYS%', 'e')
129 config.addOutputVar (self.containerName, 'charge', 'charge', noSys=True)
130 config.addOutputVar (self.containerName, 'NNDecayMode', 'NNDecayMode', noSys=True, auxType='int')
131 config.addOutputVar (self.containerName, 'passTATTauMuonOLR', 'passTATTauMuonOLR', noSys=True, auxType='char')
132 config.addOutputVar (self.containerName, 'TESCompatibility', 'TESCompatibility')
134 config.addOutputVar (self.containerName, 'nTracksCharged', 'nTracksCharged', noSys=True)
135
136
138 """the ConfigBlock for the tau working point selection"""
139
140 def __init__ (self) :
141 super (TauWorkingPointSelectionConfig, self).__init__ ()
142 self.setBlockName('TauWorkingPointSelection')
143 self.addOption ('containerName', '', type=str,
144 noneAction='error',
145 info="the name of the input container.")
146 self.addOption ('selectionName', '', type=str,
147 noneAction='error',
148 info="the name of the tau-jet selection to define (e.g. `tight` or "
149 "`loose`).")
150 self.addOption ('postfix', None, type=str,
151 info="a postfix to apply to decorations and algorithm names. "
152 "Typically not needed here as selectionName is used internally.")
153 self.addOption ('quality', None, type=str,
154 info="the ID WP to use. Supported ID WPs: `Tight`, `Medium`, "
155 "`Loose`, `VeryLoose`, `Baseline`, `BaselineForFakes`.")
156 self.addOption ('use_eVeto', False, type=bool,
157 info="use selection with or without eVeto combined with TauID. "
158 "Recommendations: set it to `True` if electrons mis-reconstructed as tau-jets are a large background for your analysis.")
159 self.addOption ('use_muonOLR', False, type=bool,
160 info="use selection with or without muonOLR with TauID. "
161 "Recommendations: set it to `True` if muons mis-reconstructed as tau-jets are a large background for your analysis.")
162 self.addOption ('useGNTau', False, type=bool,
163 info="use GNTau-based ID instead of RNNTau ID. "
164 "Recommendations: experimental feature and might become default soon.",
165 expertMode=True)
166 self.addOption ('dropPtCut', False, type=bool,
167 info=r"select tau-jets without an explicit minimum $p_\mathrm{T}$ cut. For PHYS/PHYSLITE, this would mean selecting tau-jets starting from 13 GeV. "
168 "Recommendations: experimental feature and not supported for all combinations of ID/eVeto WPs.",
169 expertMode=True)
170 self.addOption ('useLowPt', False, type=bool,
171 info="select taus starting from 15 GeV instead of the default 20 GeV cut "
172 "recommendations: experimental feature and not supported for all combinations of ID/eVeto WPs.",
173 expertMode=True)
174 self.addOption ('useSelectionConfigFile', True, type=bool,
175 info="use pre-defined configuration files for selecting tau-jets. "
176 "Recommendations: set this to `False` only if you want to test/optimise the tau-jet selection for selections not already provided through config files.")
177 self.addOption ('manual_sel_minpt', 20.0, type=float,
178 info=r"minimum $p_\mathrm{T}$ cut (in GeV) used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
179 self.addOption ('manual_sel_absetaregion', [0, 1.37, 1.52, 2.5], type=list,
180 info=r"$\vert\eta\vert$ regions cut used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
181 self.addOption ('manual_sel_abscharges', [1,], type=list,
182 info="charge of the tau-jet cut used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
183 self.addOption ('manual_sel_ntracks', [1,3], type=list,
184 info="number of tau-jet tracks used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
185 self.addOption ('manual_sel_minrnnscore', -1, type=float,
186 info="minimum RNN score cut used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
187 self.addOption ('manual_sel_mingntauscore', -1, type=float,
188 info="minimum GNTau score selection when `useSelectionConfigFile` is set to `False`.")
189 self.addOption ('manual_sel_rnnwp', None, type=str,
190 info="RNN working point used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
191 self.addOption ('manual_sel_gntauwp', None, type=str,
192 info="GNTau working point used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
193 self.addOption ('manual_sel_evetowp', None, type=str,
194 info="eveto working point used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
195 self.addOption ('manual_sel_muonolr', False, type=bool,
196 info="use `muonolr` for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
197 self.addOption ('addSelectionToPreselection', True, type=bool,
198 info="whether to retain only tau-jets satisfying the working point "
199 "requirements.")
200
201 def instanceName (self) :
202 """Return the instance name for this block"""
203 if self.postfix is not None:
204 return self.containerName + '_' + self.selectionName + self.postfix
205 else:
206 return self.containerName + '_' + self.selectionName
207
208 def makeAlgs (self, config) :
209
210 selectionPostfix = self.selectionName
211 if selectionPostfix != '' and selectionPostfix[0] != '_' :
212 selectionPostfix = '_' + selectionPostfix
213
214 postfix = self.postfix
215 if postfix is None :
216 postfix = self.selectionName
217 if postfix != '' and postfix[0] != '_' :
218 postfix = '_' + postfix
219
220 # do tau seletion through external txt config file
222 nameFormat = 'TauAnalysisAlgorithms/tau_selection_'
223 if self.dropPtCut:
224 nameFormat = nameFormat + 'nopt_'
225 if self.useLowPt:
226 nameFormat = nameFormat + 'lowpt_'
227 if self.useGNTau:
228 nameFormat = nameFormat + 'gntau_'
229 nameFormat = nameFormat + '{}_'
230 if self.use_eVeto:
231 nameFormat = nameFormat + 'eleid'
232 else:
233 nameFormat = nameFormat + 'noeleid'
234 if self.use_muonOLR:
235 nameFormat = nameFormat + '_muonolr'
236 nameFormat = nameFormat + '.conf'
237
238 if self.quality not in ['Tight', 'Medium', 'Loose', 'VeryLoose', 'Baseline', 'BaselineForFakes'] :
239 raise ValueError ("invalid tau quality: \"" + self.quality +
240 "\", allowed values are Tight, Medium, Loose, " +
241 "VeryLoose, Baseline, BaselineForFakes")
242
243 # Set up the algorithm selecting taus:
244 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'TauSelectionAlg' )
245 config.addPrivateTool( 'selectionTool', 'TauAnalysisTools::TauSelectionTool' )
246 alg.selectionTool.TauContainerName = config.readName (self.containerName, nominal=True)
248 inputfile = nameFormat.format(self.quality.lower())
249 alg.selectionTool.ConfigPath = inputfile
250 else:
251 #build selection from user handmade selection
252 from ROOT import TauAnalysisTools
253 selectioncuts = TauAnalysisTools.SelectionCuts
254 alg.selectionTool.ConfigPath = ""
255 alg.selectionTool.SelectionCuts = int(selectioncuts.CutPt |
256 selectioncuts.CutAbsEta |
257 selectioncuts.CutAbsCharge |
258 selectioncuts.CutNTrack |
259 selectioncuts.CutJetRNNScoreSigTrans |
260 selectioncuts.CutGNTauScoreSigTrans |
261 selectioncuts.CutJetIDWP |
262 selectioncuts.CutEleIDWP |
263 selectioncuts.CutMuonOLR)
264
265 alg.selectionTool.PtMin = self.manual_sel_minpt
266 alg.selectionTool.AbsEtaRegion = self.manual_sel_absetaregion
267 alg.selectionTool.AbsCharges = self.manual_sel_abscharges
268 alg.selectionTool.NTracks = self.manual_sel_ntracks
269 alg.selectionTool.JetRNNSigTransMin = self.manual_sel_minrnnscore
270 alg.selectionTool.GNTauSigTransMin = self.manual_sel_mingntauscore
271 #cross-check that min rnn score and min gntau score are not both set at the same time
272 if self.manual_sel_minrnnscore != -1 and self.manual_sel_mingntauscore != -1:
273 raise RuntimeError("manual_sel_minrnnscore and manual_sel_mingntauscore have been both set; please choose only one type of ID: RNN or GNTau, not both")
274 # working point following the Enums from https://gitlab.cern.ch/atlas/athena/-/blob/main/PhysicsAnalysis/TauID/TauAnalysisTools/TauAnalysisTools/Enums.h
275 if self.manual_sel_rnnwp is None:
276 alg.selectionTool.JetIDWP = 1
277 elif self.manual_sel_rnnwp == "veryloose":
278 alg.selectionTool.JetIDWP = 6
279 elif self.manual_sel_rnnwp == "loose":
280 alg.selectionTool.JetIDWP = 7
281 elif self.manual_sel_rnnwp == "medium":
282 alg.selectionTool.JetIDWP = 8
283 elif self.manual_sel_rnnwp == "tight":
284 alg.selectionTool.JetIDWP = 9
285 else:
286 raise ValueError ("invalid RNN TauID WP: \"" + self.manual_sel_rnnwp + "\". Allowed values are None, veryloose, loose, medium, tight")
287
288 # cross-check that min rnn score and RNN WPs are not set at the same time
289 if self.manual_sel_minrnnscore != -1 and self.manual_sel_rnnwp is not None:
290 raise RuntimeError("manual_sel_minrnnscore and manual_sel_rnnwp have been both set; please set only one of them")
291
292 # working point following the Enums from https://gitlab.cern.ch/atlas/athena/-/blob/main/PhysicsAnalysis/TauID/TauAnalysisTools/TauAnalysisTools/Enums.h
293 if self.manual_sel_gntauwp is None:
294 alg.selectionTool.JetIDWP = 1
295 elif self.manual_sel_gntauwp == "veryloose":
296 alg.selectionTool.JetIDWP = 10
297 elif self.manual_sel_gntauwp == "loose":
298 alg.selectionTool.JetIDWP = 11
299 elif self.manual_sel_gntauwp == "medium":
300 alg.selectionTool.JetIDWP = 12
301 elif self.manual_sel_gntauwp == "tight":
302 alg.selectionTool.JetIDWP = 13
303 else:
304 raise ValueError ("invalid GNN Tau ID WP: \"" + self.manual_sel_gntauwp + "\". Allowed values are None, veryloose, loose, medium, tight")
305
306 # cross-check that min gntau score and GNTau WPs are not set at the same time
307 if self.manual_sel_mingntauscore != -1 and self.manual_sel_gntauwp is not None:
308 raise RuntimeError("manual_sel_mingntauscore and manual_sel_gntauwp have been both set; please set only one of them")
309
310 # working point following the Enums from https://gitlab.cern.ch/atlas/athena/-/blob/main/PhysicsAnalysis/TauID/TauAnalysisTools/TauAnalysisTools/Enums.h
311 if self.manual_sel_evetowp is None:
312 alg.selectionTool.EleIDWP = 1
313 elif self.manual_sel_evetowp == "loose":
314 alg.selectionTool.EleIDWP = 2
315 elif self.manual_sel_evetowp == "medium":
316 alg.selectionTool.EleIDWP = 3
317 elif self.manual_sel_evetowp == "tight":
318 alg.selectionTool.EleIDWP = 4
319 else:
320 raise ValueError ("invalid eVeto WP: \"" + self.manual_sel_evetowp + "\". Allowed values are None, loose, medium, tight")
321
322 # set MuonOLR option:
323 alg.selectionTool.MuonOLR = self.manual_sel_muonolr
324
325 alg.selectionDecoration = 'selected_tau' + selectionPostfix + ',as_char'
326 alg.particles = config.readName (self.containerName)
327 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
328 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
329 preselection=self.addSelectionToPreselection)
330
331
333 """the ConfigBlock for the tau working point efficiency computation"""
334
335 def __init__ (self) :
336 super (TauWorkingPointEfficiencyConfig, self).__init__ ()
337 self.setBlockName('TauWorkingPointEfficiency')
338 self.addDependency('TauWorkingPointSelection', required=True)
339 self.addDependency('EventSelection', required=False)
340 self.addDependency('EventSelectionMerger', required=False)
341 self.addOption ('containerName', '', type=str,
342 noneAction='error',
343 info="the name of the input container.")
344 self.addOption ('selectionName', '', type=str,
345 noneAction='error',
346 info="the name of the tau-jet selection to define (e.g. `tight` or "
347 "`loose`).")
348 self.addOption ('postfix', None, type=str,
349 info="a postfix to apply to decorations and algorithm names. "
350 "Typically not needed here as selectionName is used internally.")
351 self.addOption ('quality', None, type=str,
352 info="the ID WP to use. Supported ID WPs: `Tight`, `Medium`, "
353 "`Loose`, `VeryLoose`, `Baseline`, `BaselineForFakes`.")
354 self.addOption ('use_eVeto', False, type=bool,
355 info="use selection with or without eVeto combined with TauID. "
356 "Recommendations: set it to `True` if electrons mis-reconstructed as tau-jets are a large background for your analysis.")
357 self.addOption ('useGNTau', False, type=bool,
358 info="use GNTau-based ID instead of RNNTau ID. "
359 "Recommendations: experimental feature and might become default soon.",
360 expertMode=True)
361 self.addOption ('manual_sel_rnnwp', None, type=str,
362 info="RNN working point used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
363 self.addOption ('manual_sel_evetowp', None, type=str,
364 info="eveto working point used for tau-jet selection when `useSelectionConfigFile` is set to `False`.")
365 self.addOption ('noEffSF', False, type=bool,
366 info="disables the calculation of efficiencies and scale factors. "
367 "Experimental! only useful to test a new WP for which scale "
368 "factors are not available.",
369 expertMode=True)
370 self.addOption ('saveDetailedSF', True, type=bool,
371 info="save all the independent detailed object scale factors.")
372 self.addOption ('saveCombinedSF', False, type=bool,
373 info="save the combined object scale factor.")
374
375 def instanceName (self) :
376 """Return the instance name for this block"""
377 if self.postfix is not None:
378 return self.containerName + '_' + self.selectionName + self.postfix
379 else:
380 return self.containerName + '_' + self.selectionName
381
382 def makeAlgs (self, config) :
383
384 selectionPostfix = self.selectionName
385 if selectionPostfix != '' and selectionPostfix[0] != '_' :
386 selectionPostfix = '_' + selectionPostfix
387
388 postfix = self.postfix
389 if postfix is None :
390 postfix = self.selectionName
391 if postfix != '' and postfix[0] != '_' :
392 postfix = '_' + postfix
393
394 if self.quality is not None and self.quality not in ['Tight', 'Medium', 'Loose', 'VeryLoose', 'Baseline', 'BaselineForFakes'] :
395 raise ValueError ("invalid tau quality: \"" + self.quality +
396 "\", allowed values are Tight, Medium, Loose, " +
397 "VeryLoose, Baseline, BaselineForFakes")
398
399 sfList = []
400 # Set up the algorithm calculating the efficiency scale factors for the
401 # taus:
402 if config.dataType() is not DataType.Data and not self.noEffSF:
403 log = logging.getLogger('TauJetSFConfig')
404 # need multiple instances of the TauEfficiencyCorrectionTool
405 # 1) Reco 2) TauID, 3) eVeto for fake tau 4) eVeto for true tau
406 # 3) and 4) are optional if eVeto is used in TauSelectionTool
407
408 # TauEfficiencyCorrectionTool for Reco, this should be always enabled
409 alg = config.createAlgorithm( 'CP::TauEfficiencyCorrectionsAlg',
410 'TauEfficiencyCorrectionsAlgReco' )
411 config.addPrivateTool( 'efficiencyCorrectionsTool',
412 'TauAnalysisTools::TauEfficiencyCorrectionsTool' )
413 alg.efficiencyCorrectionsTool.EfficiencyCorrectionTypes = [0]
414 alg.efficiencyCorrectionsTool.Campaign = "mc23" if config.geometry() is LHCPeriod.Run3 else "mc20"
415 alg.efficiencyCorrectionsTool.useFastSim = config.dataType() is DataType.FastSim
416 alg.scaleFactorDecoration = 'tau_Reco_effSF' + selectionPostfix + '_%SYS%'
417 alg.outOfValidity = 2 #silent
418 alg.outOfValidityDeco = 'bad_Reco_eff' + selectionPostfix
419 alg.taus = config.readName (self.containerName)
420 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
422 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
423 'Reco_effSF' + postfix)
424 sfList += [alg.scaleFactorDecoration]
425
426 # TauEfficiencyCorrectionTool for Identification, use only in case TauID is requested in TauSelectionTool
427 if self.quality not in ('VeryLoose','Baseline','BaselineForFakes'):
428 if not self.useGNTau: # current recommendations are for RNN ID, so don't use in case of GNTau
429
430 alg = config.createAlgorithm( 'CP::TauEfficiencyCorrectionsAlg',
431 'TauEfficiencyCorrectionsAlgID' )
432 config.addPrivateTool( 'efficiencyCorrectionsTool',
433 'TauAnalysisTools::TauEfficiencyCorrectionsTool' )
434 alg.efficiencyCorrectionsTool.EfficiencyCorrectionTypes = [4]
435 if self.quality=="Loose" or self.manual_sel_rnnwp == "loose":
436 JetIDLevel = 7
437 elif self.quality=="Medium" or self.manual_sel_rnnwp == "medium":
438 JetIDLevel = 8
439 elif self.quality=="Tight" or self.manual_sel_rnnwp == "tight":
440 JetIDLevel = 9
441 else:
442 raise ValueError ("invalid tauID: \"" + self.quality + "\". Allowed values are loose, medium, tight")
443
444 alg.efficiencyCorrectionsTool.JetIDLevel = JetIDLevel
445 alg.efficiencyCorrectionsTool.useFastSim = config.dataType() is DataType.FastSim
446 alg.efficiencyCorrectionsTool.Campaign = "mc23" if config.geometry() is LHCPeriod.Run3 else "mc20"
447 alg.scaleFactorDecoration = 'tau_ID_effSF' + selectionPostfix + '_%SYS%'
448 alg.outOfValidity = 2 #silent
449 alg.outOfValidityDeco = 'bad_ID_eff' + selectionPostfix
450 alg.taus = config.readName (self.containerName)
451 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
452 if self.saveDetailedSF:
453 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
454 'ID_effSF' + postfix)
455 sfList += [alg.scaleFactorDecoration]
456
457 # TauEfficiencyCorrectionTool for eVeto both on true tau and fake tau, use only in case eVeto is requested in TauSelectionTool
458 if self.use_eVeto:
459 if not self.useGNTau: # eVeto correction for fake tau are for RNN ID, so don't use them for GNTau
460 # correction for fake tau
461 alg = config.createAlgorithm( 'CP::TauEfficiencyCorrectionsAlg',
462 'TauEfficiencyCorrectionsAlgEvetoFakeTau' )
463 config.addPrivateTool( 'efficiencyCorrectionsTool',
464 'TauAnalysisTools::TauEfficiencyCorrectionsTool' )
465 alg.efficiencyCorrectionsTool.EfficiencyCorrectionTypes = [10]
466 # since all TauSelectionTool config files have loose eRNN, code only this option for now
467 alg.efficiencyCorrectionsTool.EleIDLevel = 2
468 #overwrite decision in case user selects a WP manually
469 if self.manual_sel_evetowp == "loose":
470 alg.efficiencyCorrectionsTool.EleIDLevel = 2
471 elif self.manual_sel_evetowp == "medium":
472 alg.efficiencyCorrectionsTool.EleIDLevel = 3
473
474 alg.efficiencyCorrectionsTool.useFastSim = config.dataType() is DataType.FastSim
475 alg.efficiencyCorrectionsTool.Campaign = "mc23" if config.geometry() is LHCPeriod.Run3 else "mc20"
476 alg.scaleFactorDecoration = 'tau_EvetoFakeTau_effSF' + selectionPostfix + '_%SYS%'
477 # for 2025-prerec, eVeto recommendations are given separately for Loose and Medium RNN
478 if self.quality=="Loose" or self.manual_sel_rnnwp == "loose":
479 JetIDLevel = 7
480 elif self.quality=="Medium" or self.manual_sel_rnnwp == "medium":
481 JetIDLevel = 8
482 elif self.quality=="Tight" or self.manual_sel_rnnwp == "tight":
483 log.warning("eVeto SFs are not available for Tight WP -> fallback to Medium WP")
484 JetIDLevel = 8
485 alg.efficiencyCorrectionsTool.JetIDLevel = JetIDLevel
486 alg.outOfValidity = 2 #silent
487 alg.outOfValidityDeco = 'bad_EvetoFakeTau_eff' + selectionPostfix
488 alg.taus = config.readName (self.containerName)
489 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
490 if self.saveDetailedSF:
491 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
492 'EvetoFakeTau_effSF' + postfix)
493 sfList += [alg.scaleFactorDecoration]
494
495 # correction for true tau
496 alg = config.createAlgorithm( 'CP::TauEfficiencyCorrectionsAlg',
497 'TauEfficiencyCorrectionsAlgEvetoTrueTau' )
498 config.addPrivateTool( 'efficiencyCorrectionsTool',
499 'TauAnalysisTools::TauEfficiencyCorrectionsTool' )
500 alg.efficiencyCorrectionsTool.EfficiencyCorrectionTypes = [8]
501 alg.efficiencyCorrectionsTool.useFastSim = config.dataType() is DataType.FastSim
502 alg.efficiencyCorrectionsTool.Campaign = "mc23" if config.geometry() is LHCPeriod.Run3 else "mc20"
503 alg.scaleFactorDecoration = 'tau_EvetoTrueTau_effSF' + selectionPostfix + '_%SYS%'
504 # since all TauSelectionTool config files have loose eRNN, code only this option for now
505 alg.efficiencyCorrectionsTool.EleIDLevel = 2
506 #overwrite decision in case user selects a WP manually
507 if self.manual_sel_evetowp == "loose":
508 alg.efficiencyCorrectionsTool.EleIDLevel = 2
509 elif self.manual_sel_evetowp == "medium":
510 alg.efficiencyCorrectionsTool.EleIDLevel = 3
511 alg.outOfValidity = 2 #silent
512 alg.outOfValidityDeco = 'bad_EvetoTrueTau_eff' + selectionPostfix
513 alg.taus = config.readName (self.containerName)
514 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
515 if self.saveDetailedSF:
516 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
517 'EvetoTrueTau_effSF' + postfix)
518 sfList += [alg.scaleFactorDecoration]
519
521 alg = config.createAlgorithm( 'CP::AsgObjectScaleFactorAlg',
522 'TauCombinedEfficiencyScaleFactorAlg' )
523 alg.particles = config.readName (self.containerName)
524 alg.inScaleFactors = sfList
525 alg.outScaleFactor = 'effSF' + postfix + '_%SYS%'
526 config.addOutputVar (self.containerName, alg.outScaleFactor,
527 'effSF' + postfix)
528
529
531 def __init__ (self) :
532 super (EXPERIMENTAL_TauCombineMuonRemovalConfig, self).__init__ ()
533 self.addOption (
534 'inputTaus', 'TauJets', type=str,
535 noneAction='error',
536 info="the name of the input tau container."
537 )
538 self.addOption (
539 'inputTausMuRM', 'TauJets_MuonRM', type=str,
540 noneAction='error',
541 info="the name of the input tau container with muon removal applied."
542 )
543 self.addOption (
544 'outputTaus', 'TauJets_MuonRmCombined', type=str,
545 noneAction='error',
546 info="the name of the output tau container."
547 )
548
549 def instanceName (self) :
550 """Return the instance name for this block"""
551 return self.outputTaus
552
553 def makeAlgs (self, config) :
554
555 if config.isPhyslite() :
556 raise(RuntimeError("Muon removal taus is not available in Physlite mode"))
557
558 alg = config.createAlgorithm( 'CP::TauCombineMuonRMTausAlg', 'TauCombineMuonRMTausAlg' )
559 alg.taus = self.inputTaus
560 alg.muonrm_taus = self.inputTausMuRM
561 alg.combined_taus = self.outputTaus
562
563class TauTriggerAnalysisSFBlock (ConfigBlock):
564
565 def __init__ (self) :
566 super (TauTriggerAnalysisSFBlock, self).__init__ ()
567 self.addDependency('EventSelection', required=False)
568 self.addDependency('EventSelectionMerger', required=False)
569 self.addOption ('triggerChainsPerYear', {}, type=dict,
570 info="a dictionary with key (string) the year and value (list of "
571 "strings) the trigger chains.")
572 self.addOption ('tauID', '', type=str,
573 info="the tau-jet quality WP to use.")
574 self.addOption ('prefixSF', 'trigEffSF', type=str,
575 info="the decoration prefix for trigger scale factors.")
576 self.addOption ('includeAllYearsPerRun', False, type=bool,
577 info="all configured years in the LHC run will "
578 "be included in all jobs.")
579 self.addOption ('removeHLTPrefix', True, type=bool,
580 info="remove the HLT prefix from trigger chain names.")
581 self.addOption ('containerName', '', type=str,
582 info="the input tau-jet container, with a possible selection, in "
583 "the format `container` or `container.selection`.")
584
585 def instanceName (self) :
586 """Return the instance name for this block"""
587 return self.containerName + '_' + self.prefixSF + '_' + self.tauID
588
589 def makeAlgs (self, config) :
590
591 if config.dataType() is not DataType.Data:
592 log = logging.getLogger('TauTriggerAnalysisSF')
593
594 # Temporary skip for MC23e until SFs are available
595 if config.campaign() is Campaign.MC23e:
596 log.warning("Tau trigger scale factors are not available yet for MC23e")
597 return
598
599 triggers = trigger_set(config, self.triggerChainsPerYear,
600 self.includeAllYearsPerRun)
601 for chain in triggers:
602 chain_noHLT = chain.replace("HLT_", "")
603 chain_out = chain_noHLT if self.removeHLTPrefix else chain
604 alg = config.createAlgorithm( 'CP::TauEfficiencyCorrectionsAlg',
605 'TauTrigEfficiencyCorrectionsAlg_' + chain )
606 config.addPrivateTool( 'efficiencyCorrectionsTool',
607 'TauAnalysisTools::TauEfficiencyCorrectionsTool' )
608 # SFTriggerHadTau correction type from
609 # https://gitlab.cern.ch/atlas/athena/-/blob/main/PhysicsAnalysis/TauID/TauAnalysisTools/TauAnalysisTools/Enums.h#L79
610 alg.efficiencyCorrectionsTool.EfficiencyCorrectionTypes = [12]
611 if config.geometry() is LHCPeriod.Run2:
612 alg.efficiencyCorrectionsTool.Campaign = "mc20"
613 else:
614 alg.efficiencyCorrectionsTool.Campaign = config.campaign().value
615 alg.efficiencyCorrectionsTool.TriggerName = chain
616
617 # JetIDLevel from
618 # https://gitlab.cern.ch/atlas/athena/-/blob/main/PhysicsAnalysis/TauID/TauAnalysisTools/TauAnalysisTools/Enums.h#L79
619 if self.tauID=="Loose":
620 JetIDLevel = 7
621 elif self.tauID=="Medium":
622 JetIDLevel = 8
623 elif self.tauID=="Tight":
624 JetIDLevel = 9
625 else:
626 raise ValueError ("invalid tauID: \"" + self.tauID + "\". Allowed values are loose, medium, tight")
627 alg.efficiencyCorrectionsTool.JetIDLevel = JetIDLevel
628 alg.efficiencyCorrectionsTool.TriggerSFMeasurement = "combined"
629 alg.efficiencyCorrectionsTool.useFastSim = config.dataType() is DataType.FastSim
630
631 alg.scaleFactorDecoration = f"tau_{self.prefixSF}_{chain_out}_%SYS%"
632 alg.outOfValidity = 2 #silent
633 alg.outOfValidityDeco = f"bad_eff_tautrig_{chain_out}"
634 alg.taus = config.readName (self.containerName)
635 alg.preselection = config.getPreselection (self.containerName, self.tauID)
636 config.addOutputVar (self.containerName, alg.scaleFactorDecoration, f"{self.prefixSF}_{chain_out}")
637
638@groupBlocks
# current recommendations are for RNN ID, so donCPTauEfficiencyCorrectionsAlgTauEfficiencyCorrectionsAlgIDefficiencyCorrectionsToolTauAnalysisToolsTauEfficiencyCorrectionsTooltau_ID_effSF_%SYS%bad_ID_effID_effSFt use them for GNTau useGNTau