ATLAS Offline Software
TrackingAnalysisConfig.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.ConfigBlock import ConfigBlock
5 from AthenaCommon.SystemOfUnits import GeV
6 from AnalysisAlgorithmsConfig.ConfigAccumulator import DataType
7 from AthenaConfiguration.Enums import LHCPeriod
8 from Campaigns.Utils import Campaign
9 from AthenaCommon.Logging import logging
10 
11 
12 class InDetTrackCalibrationConfig (ConfigBlock):
13  """the ConfigBlock for the track impact parameter correction"""
14 
15  def __init__ (self) :
16  super (InDetTrackCalibrationConfig, self).__init__ ()
17  self.setBlockName ('InDetTracks')
18  self.addOption ('inputContainer', '', type=str,
19  info="select track input container, by default set to InDetTrackParticles")
20  self.addOption ('containerName', '', type=str,
21  noneAction='error',
22  info="the name of the output container after calibration.")
23  self.addOption ('postfix', '', type=str,
24  info="a postfix to apply to decorations and algorithm names. Typically "
25  "not needed here since the calibration is common to all tracks.")
26  self.addOption ('runBiasing', True, type=bool,
27  info="whether to run the InDetTrackBiasingTool. Allows the user to "
28  "disable the tool if no recommendations are available. This should "
29  "not be used in an analysis. The default is True.")
30  self.addOption ('biasD0', None, type=float,
31  info="a manual bias (float) to d0 in mm. Will be applied by the "
32  "InDetTrackBiasingTool. Expert option in addition to the "
33  "recommendations. The default is 0.")
34  self.addOption ('biasZ0', None, type=float,
35  info="a manual bias (float) to z0 in mm. Will be applied by the "
36  "InDetTrackBiasingTool. Expert option in addition to the "
37  "recommendations. The default is 0.")
38  self.addOption ('biasQoverPsagitta', None, type=float,
39  info="a manual bias (float) to QoverP in TeV^-1. Will be applied "
40  "by the InDetTrackBiasingTool. Expert option in addition to the "
41  "recommendations. The default is 0.")
42  self.addOption ('customRunNumber', None, type=int,
43  info="manually sets the runNumber (int) in the InDetTrackBiasingTool. "
44  "Expert option leads to use of different recommendations. Default is "
45  "retrieved from EventInfo")
46  self.addOption ('calibFile', None, type=str,
47  info="name (str) of the calibration file to use for the CTIDE "
48  "calibration. Expert option to override the recommendations "
49  "based on the campaign. The default is None.")
50  self.addOption ('smearingToolSeed', None, type=int,
51  info="random seed (int) to be used by the InDetTrackSmearingTool. "
52  "Expert option. The default is 0.")
53  self.addOption ('minPt', 0.5*GeV, type=float,
54  info="the minimum pT cut to apply to calibrated tracks. "
55  "The default is 0.5 GeV.")
56  self.addOption ('maxEta', 2.5, type=float,
57  info="maximum track |eta| (float). The default is 2.5.")
58  self.addOption ('outputTrackSummaryInfo', False, type=bool,
59  info="decorate track summary information on the reconstructed object")
60 
61  def instanceName (self) :
62  """Return the instance name for this block"""
63  return self.containerName + self.postfix
64 
65  def makeAlgs (self, config) :
66  log = logging.getLogger('InDetTrackCalibrationConfig')
67 
68  inputContainer = "InDetTrackParticles"
69  if self.inputContainer:
70  inputContainer = self.inputContainer
71  config.setSourceName (self.containerName, inputContainer)
72 
73  # Set up a shallow copy to decorate
74  if config.wantCopy (self.containerName) :
75  alg = config.createAlgorithm( 'CP::AsgShallowCopyAlg', 'InDetTrackShallowCopyAlg' )
76  alg.input = config.readName (self.containerName)
77  alg.output = config.copyName (self.containerName)
78 
79  # Set up the eta-cut on all tracks prior to everything else
80  alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'InDetTrackEtaCutAlg' )
81  alg.selectionDecoration = 'selectEta' + self.postfix + ',as_bits'
82  config.addPrivateTool( 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
83  alg.selectionTool.maxEta = self.maxEta
84  alg.particles = config.readName (self.containerName)
85  alg.preselection = config.getPreselection (self.containerName, '')
86  config.addSelection (self.containerName, '', alg.selectionDecoration)
87 
88  # Set up the biasing algorithm. The recommendations is to bias MC instead of unbiasing Data:
89  if config.dataType() is not DataType.Data:
90  if not self.runBiasing:
91  log.warning('Disabling the biasing tool for now. This should not '
92  'be used in an analysis.')
93  else:
94  if config.geometry() is LHCPeriod.Run3:
95  raise ValueError ('Recommendations are not yet available in Run 3.')
96  elif config.geometry() is not LHCPeriod.Run2:
97  raise ValueError ('No recommendations found for geometry \"'
98  + config.geometry().value + '\". Please check '
99  'the configuration.')
100  alg = config.createAlgorithm( 'CP::InDetTrackBiasingAlg', 'InDetTrackBiasingAlg' )
101  config.addPrivateTool( 'biasingTool', 'InDet::InDetTrackBiasingTool' )
102  if self.biasD0:
103  alg.biasingTool.biasD0 = self.biasD0
104  if self.biasZ0:
105  alg.biasingTool.biasZ0 = self.biasZ0
106  if self.biasQoverPsagitta:
107  alg.biasingTool.biasQoverPsagitta = self.biasQoverPsagitta
108  if self.customRunNumber:
109  alg.biasingTool.runNumber = self.customRunNumber
110  alg.inDetTracks = config.readName (self.containerName)
111  alg.inDetTracksOut = config.copyName (self.containerName)
112  alg.preselection = config.getPreselection (self.containerName, '')
113 
114  # Set up the smearing algorithm:
115  if config.dataType() is not DataType.Data:
116  alg = config.createAlgorithm( 'CP::InDetTrackSmearingAlg', 'InDetTrackSmearingAlg' )
117  config.addPrivateTool( 'smearingTool', 'InDet::InDetTrackSmearingTool' )
118  if self.smearingToolSeed:
119  alg.smearingTool.Seed = self.smearingToolSeed
120  if self.calibFile:
121  alg.smearingTool.calibFileIP_CTIDE = self.calibFile
122  else:
123  if config.geometry() is LHCPeriod.Run2:
124  # Run 2 recommendations (MC20)
125  alg.smearingTool.calibFileIP_CTIDE = "InDetTrackSystematicsTools/CalibData_22.0_2022-v00/d0z0_smearing_factors_Run2_v2.root"
126  elif config.geometry() is LHCPeriod.Run3:
127  if config.campaign() is Campaign.MC23a:
128  # 2022 recommendations (MC23a)
129  alg.smearingTool.calibFileIP_CTIDE = "InDetTrackSystematicsTools/CalibData_25.2_2025-v00/2022_d0z0_smearing_factors_v2.root"
130  elif config.campaign() is Campaign.MC23d:
131  # 2023 recommendations (MC23d)
132  alg.smearingTool.calibFileIP_CTIDE = "InDetTrackSystematicsTools/CalibData_25.2_2025-v00/2023_d0z0_smearing_factors_v2.root"
133  elif config.campaign() is Campaign.MC23e:
134  # 2024 recommendations (MC23e)
135  alg.smearingTool.calibFileIP_CTIDE = "InDetTrackSystematicsTools/CalibData_25.2_2025-v00/2024_d0z0_smearing_factors.root"
136  else:
137  raise ValueError ('No recommendations found for capaign \"'
138  + config.campaign().value + '\" in Run 3. '
139  'Please check that the recommendations exist.')
140  else:
141  raise ValueError ('No recommendations found for geometry \"'
142  + config.geometry().value + '\". Please check '
143  'the configuration.')
144  alg.inDetTracks = config.readName (self.containerName)
145  alg.inDetTracksOut = config.copyName (self.containerName)
146  alg.preselection = config.getPreselection (self.containerName, '')
147 
148  if self.minPt > 0 : # Set up the the pt selection
149  alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'InDetTrackPtCutAlg' )
150  alg.selectionDecoration = 'selectPt' + self.postfix + ',as_bits'
151  config.addPrivateTool( 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
152  alg.selectionTool.minPt = self.minPt
153  alg.particles = config.readName (self.containerName)
154  alg.preselection = config.getPreselection (self.containerName, '')
155  config.addSelection (self.containerName, '', alg.selectionDecoration,
156  preselection=True)
157 
158  alg = config.createAlgorithm( 'CP::InDetTrackMomentumDecoratorAlg', 'MomentumDecorator' )
159  alg.inDetTracks = config.readName(self.containerName)
160 
161  config.addOutputVar (self.containerName, 'pt_%SYS%', 'pt')
162  config.addOutputVar (self.containerName, 'eta', 'eta', noSys=True)
163  config.addOutputVar (self.containerName, 'phi', 'phi', noSys=True)
164  config.addOutputVar (self.containerName, 'charge', 'charge', noSys=True)
165  config.addOutputVar (self.containerName, 'qOverP', 'qOverP')
166  config.addOutputVar (self.containerName, 'd0', 'd0')
167  config.addOutputVar (self.containerName, 'z0', 'z0')
168  config.addOutputVar (self.containerName, 'vz', 'vz', noSys=True)
169 
170  # decorate track summary information on the reconstructed object:
171  if self.outputTrackSummaryInfo and config.dataType() is not DataType.Data:
172  config.addOutputVar (self.containerName, 'numberOfInnermostPixelLayerHits', 'numberOfInnermostPixelLayerHits', noSys=True)
173  config.addOutputVar (self.containerName, 'numberOfPixelDeadSensors', 'numberOfPixelDeadSensors', noSys=True)
174  config.addOutputVar (self.containerName, 'numberOfPixelHits', 'numberOfPixelHits', noSys=True)
175  config.addOutputVar (self.containerName, 'numberOfPixelHoles', 'numberOfPixelHoles', noSys=True)
176  config.addOutputVar (self.containerName, 'numberOfPixelSharedHits', 'numberOfPixelSharedHits', noSys=True)
177  config.addOutputVar (self.containerName, 'numberOfSCTDeadSensors', 'numberOfSCTDeadSensors', noSys=True)
178  config.addOutputVar (self.containerName, 'numberOfSCTHits', 'numberOfSCTHits', noSys=True)
179  config.addOutputVar (self.containerName, 'numberOfSCTHoles', 'numberOfSCTHoles', noSys=True)
180  config.addOutputVar (self.containerName, 'numberOfSCTSharedHits', 'numberOfSCTSharedHits', noSys=True)
181  config.addOutputVar (self.containerName, 'numberOfTRTHits', 'numberOfTRTHits', noSys=True)
182  config.addOutputVar (self.containerName, 'numberOfTRTOutliers', 'numberOfTRTOutliers', noSys=True)
183 
184 
185 class InDetTrackWorkingPointConfig (ConfigBlock):
186  """the ConfigBlock for the track working point"""
187 
188  def __init__ (self) :
189  super (InDetTrackWorkingPointConfig, self).__init__ ()
190  self.addOption ('containerName', '', type=str,
191  noneAction='error',
192  info="the name of the input container.")
193  self.addOption ('selectionName', '', type=str,
194  noneAction='error',
195  info="the name of the track selection to define (e.g. tightPrimary "
196  "or loose).")
197  self.addOption ('postfix', None, type=str,
198  info="a postfix to apply to decorations and algorithm names. "
199  "Typically not needed here as selectionName is used internally.")
200  self.addOption ('cutLevel', None, type=str,
201  noneAction='error',
202  info="the selection WP (str) to use. Supported WPs for general "
203  "use: `Loose` and `TightPrimary`. For expert studies, further "
204  "WPs are available: `NoCut`, `LoosePrimary`, `LooseElectron`, "
205  "`LooseMuon`, `LooseTau`, `MinBias`, `HILoose`, `HITight`, "
206  "`HILooseOptimized`, `HITightOptimized`.")
207  self.addOption ('additionalCuts', None, type=None,
208  info="additional cuts to modify the selection WP. Only meant for "
209  "expert studies of track selection. Passed as pairs of `cutName: value`. "
210  "For an overview of available cuts, see twiki.cern.ch/twiki/bin/viewauth/"
211  "AtlasProtected/InDetTrackSelectionTool#List_of_possible_cuts.")
212  self.addOption ('runTruthFilter', True, type=bool,
213  info="whether to run the TruthFilterTool. This tool is only compatible "
214  "with the cut levels 'Loose' and 'TightPrimary'.")
215  self.addOption ('calibFile', None, type=str,
216  info="name (str) of the calibration file to use for efficiencies "
217  "in the TruthFilter tool. Expert option to override the "
218  "recommendations based on the campaign. The default is None.")
219  self.addOption ('filterToolSeed', None, type=int,
220  info="random seed (int) to be used by the InDetTrackTruthFilterTool. "
221  "Expert option. The default is 0.")
222  self.addOption ('fFakeLoose', None, type=float,
223  info="the fraction of fake tracks (float) in the Loose working point. "
224  "Will be used by the InDetTrackTruthFilterTool. Expert option to "
225  "override the recommendations.")
226  self.addOption ('fFakeTight', None, type=float,
227  info="the fraction of fake tracks (float) in the TightPrimary working "
228  "point. Will be used by the InDetTrackTruthFilterTool. Expert option "
229  "to override the recommendations.")
230  self.addOption ('trkEffSystScale', None, type=float,
231  info="the track efficiency systematic scale (float). Will be used "
232  "by the InDetTrackTruthFilterTool. Expert option to override the "
233  "recommendations. Default is 1.0")
234  self.addOption ('addSelectionToPreselection', True, type=bool,
235  info="whether to retain only tracks satisfying the cutLevel "
236  "requirements. The default is True.")
237 
238  def instanceName (self) :
239  """Return the instance name for this block"""
240  if self.postfix is not None:
241  return self.containerName + self.selectionName + self.postfix
242  else:
243  return self.containerName + self.selectionName
244 
245  def makeAlgs (self, config) :
246  log = logging.getLogger('InDetTrackWorkingPointConfig')
247 
248  selectionPostfix = self.selectionName
249  if selectionPostfix != '' and selectionPostfix[0] != '_' :
250  selectionPostfix = '_' + selectionPostfix
251 
252  postfix = self.postfix
253  if postfix is None :
254  postfix = self.selectionName
255  if postfix != '' and postfix[0] != '_' :
256  postfix = '_' + postfix
257 
258  cutLevels = ["NoCut", "Loose", "LoosePrimary", "TightPrimary", "LooseMuon",
259  "LooseElectron", "LooseTau", "MinBias", "HILoose", "HITight",
260  "HILooseOptimized", "HITightOptimized"]
261  alg = config.createAlgorithm( 'CP::InDetTrackSelectionAlg', 'InDetTrackSelectionAlg' )
262  alg.selectionDecoration = 'selectTrack' + postfix + '_%SYS%,as_bits'
263  config.addPrivateTool( 'selectionTool', 'InDet::InDetTrackSelectionTool')
264  if self.cutLevel is None:
265  log.warning("No selection WP chosen, not setting up InDetTrackSelectionTool.")
266  elif self.cutLevel not in cutLevels:
267  raise ValueError ('Invalid cut level: \"' + self.cutLevel + '\", has '
268  'to be one of: ' + ', '.join(cutLevels))
269  elif self.cutLevel in ["Loose", "TightPrimary"]:
270  alg.selectionTool.CutLevel = self.cutLevel
271  else:
272  log.warning('Using cut level: \"' + self.cutLevel + '\" that is not '
273  'meant for general use, but only expert studies.')
274  alg.selectionTool.CutLevel = self.cutLevel
275  if self.additionalCuts:
276  for cutName, value in self.additionalCuts.items():
277  setattr(alg.selectionTool, cutName, value)
278  # Set up the truth filtering algorithm:
279  if config.dataType() is not DataType.Data:
280  if not self.runTruthFilter:
281  log.warning('Disabling the TruthFilterTool.')
282  else:
283  config.addPrivateTool( 'filterTool', 'InDet::InDetTrackTruthFilterTool' )
284  config.addPrivateTool( 'filterTool.trackOriginTool', 'InDet::InDetTrackTruthOriginTool' )
285  # Set working point based on cut level
286  if self.cutLevel == "Loose":
287  alg.filterWP = "LOOSE"
288  elif self.cutLevel == "TightPrimary":
289  alg.filterWP = "TIGHT"
290  else:
291  raise ValueError ('Attempting to set TruthFilter WP based on cut level: \"'
292  + self.efficiencyWP + '\" that is not supported.')
293  # Set calibFile and fake rates based on campaign
294  if config.geometry() is LHCPeriod.Run2:
295  # Run 2 recommendations (MC20)
296  alg.filterTool.calibFileNomEff = "InDetTrackSystematicsTools/CalibData_22.0_2022-v00/TrackingRecommendations_prelim_rel22.root"
297  alg.filterTool.fFakeLoose = 0.10
298  alg.filterTool.fFakeTight = 1.00
299  elif config.geometry() is LHCPeriod.Run3:
300  if config.campaign() is Campaign.MC23a:
301  # 2022 recommendations (MC23a)
302  alg.filterTool.calibFileNomEff = "InDetTrackSystematicsTools/CalibData_22.0_2022-v00/TrackingRecommendations_prelim_rel22.root"
303  alg.filterTool.fFakeLoose = 0.40
304  alg.filterTool.fFakeTight = 1.00
305  elif config.campaign() is Campaign.MC23d:
306  # 2023 recommendations (MC23d)
307  alg.filterTool.calibFileNomEff = "InDetTrackSystematicsTools/CalibData_22.0_2022-v00/TrackingRecommendations_prelim_rel22.root"
308  alg.filterTool.fFakeLoose = 0.40
309  alg.filterTool.fFakeTight = 1.00
310  elif not (self.calibFile and self.fFakeLoose and self.fFakeTight):
311  raise ValueError ('No efficiency recommendations found for capaign \"'
312  + config.campaign().value + '\" in Run 3. '
313  'Please check that the recommendations exist.')
314  elif not (self.calibFile and self.fFakeLoose and self.fFakeTight):
315  raise ValueError ('No efficiency recommendations found for geometry \"'
316  + config.geometry().value + '\". Please check '
317  'the configuration.')
318  # Set custom calibFile, fake rates, or random seed
319  if self.calibFile:
320  alg.filterTool.calibFileNomEff = self.calibFile
321  if self.fFakeLoose:
322  alg.filterTool.fFakeLoose = self.fFakeLoose
323  if self.fFakeTight:
324  alg.filterTool.fFakeTight = self.fFakeTight
325  if self.filterToolSeed:
326  alg.filterTool.Seed = self.filterToolSeed
327  if self.trkEffSystScale:
328  alg.filterTool.trkEffSystScale = self.trkEffSystScale
329  alg.inDetTracks = config.readName (self.containerName)
330  alg.preselection = config.getPreselection (self.containerName, '')
331  config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
332  preselection=self.addSelectionToPreselection)
TrackingAnalysisConfig.InDetTrackCalibrationConfig.makeAlgs
def makeAlgs(self, config)
Definition: TrackingAnalysisConfig.py:65
SystemOfUnits
TrackingAnalysisConfig.InDetTrackCalibrationConfig.__init__
def __init__(self)
Definition: TrackingAnalysisConfig.py:15
TrackingAnalysisConfig.InDetTrackWorkingPointConfig.cutLevel
cutLevel
Definition: TrackingAnalysisConfig.py:286
TrackingAnalysisConfig.InDetTrackWorkingPointConfig.__init__
def __init__(self)
Definition: TrackingAnalysisConfig.py:188
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
TrackingAnalysisConfig.InDetTrackWorkingPointConfig.makeAlgs
def makeAlgs(self, config)
Definition: TrackingAnalysisConfig.py:245
TrackingAnalysisConfig.InDetTrackWorkingPointConfig.instanceName
def instanceName(self)
Definition: TrackingAnalysisConfig.py:238
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:71
TrackingAnalysisConfig.InDetTrackCalibrationConfig.instanceName
def instanceName(self)
Definition: TrackingAnalysisConfig.py:61
TrackingAnalysisConfig.InDetTrackCalibrationConfig
Definition: TrackingAnalysisConfig.py:12
TrackingAnalysisConfig.InDetTrackWorkingPointConfig
Definition: TrackingAnalysisConfig.py:185