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