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