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