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