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