ATLAS Offline Software
Loading...
Searching...
No Matches
PhotonAnalysisConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3# AnaAlgorithm import(s):
4from AnalysisAlgorithmsConfig.ConfigBlock import ConfigBlock
5from AnalysisAlgorithmsConfig.ConfigSequence import groupBlocks
6from AthenaCommon.SystemOfUnits import GeV
7from AthenaConfiguration.Enums import LHCPeriod
8from AnalysisAlgorithmsConfig.ConfigAccumulator import (
9 DataType, Run4FallbackWarning, TestingOnlyWarning)
10import warnings
11
12import ROOT
13
14# E/gamma import(s).
15from xAODEgamma.xAODEgammaParameters import xAOD
16
18
19class PhotonCalibrationConfig (ConfigBlock) :
20 """the ConfigBlock for the photon four-momentum correction"""
21
22 def __init__ (self) :
23 super (PhotonCalibrationConfig, self).__init__ ()
24 self.setBlockName('Photons')
25 self.addOption ('containerName', '', type=str,
26 noneAction='error',
27 info="the name of the output container after calibration.")
28 self.addOption ('ESModel', '', type=str,
29 info="flag for EGamma calibration. If left empty, uses the current recommendations.")
30 self.addOption ('decorrelationModel', '1NP_v1', type=str,
31 info="decorrelation model for the EGamma energy scale. Supported choices are: `FULL_v1`, `1NP_v1`.")
32 self.addOption ('postfix', '', type=str,
33 info="a postfix to apply to decorations and algorithm names. "
34 "Typically not needed here since the calibration is common to "
35 "all photons.")
36 self.addOption ('crackVeto', False, type=bool,
37 info=r"whether to perform LAr crack veto based on the cluster $\eta$, "
38 r"i.e. remove photons within $1.37<\vert\eta\vert<1.52$.")
39 self.addOption ('enableCleaning', True, type=bool,
40 info="whether to enable photon cleaning (`DFCommonPhotonsCleaning`).")
41 self.addOption ('cleaningAllowLate', False, type=bool,
42 info="whether to ignore timing information in cleaning "
43 "(`DFCommonPhotonsCleaningNoTime`).")
44 self.addOption ('recomputeIsEM', False, type=bool,
45 info="whether to recompute the photon shower shape fudge "
46 "corrections (sets up an instance of `CP::PhotonShowerShapeFudgeAlg`) or rely on derivation flags.")
47 self.addOption ('recalibratePhyslite', True, type=bool,
48 info="whether to run the `CP::EgammaCalibrationAndSmearingAlg` on "
49 "PHYSLITE derivations.")
50 self.addOption ('minPt', 10*GeV, type=float,
51 info=r"the minimum $p_\mathrm{T}$ cut (in MeV) to apply to calibrated photons.")
52 self.addOption ('maxEta', 2.37, type=float,
53 info=r"maximum photon $\vert\eta\vert$.")
54 self.addOption ('forceFullSimConfigForP4', False, type=bool,
55 info="whether to force the tool to use the configuration meant for "
56 "full simulation samples for 4-vector corrections. Only for testing purposes.")
57 self.addOption ('forceFullSimConfigForIso', False, type=bool,
58 info="whether to force the tool to use the configuration meant for "
59 "full simulation samples for isolation corrections. Only for testing purposes.")
60 self.addOption ('applyIsolationCorrection', True, type=bool,
61 info="whether to apply the isolation corrections.")
62 self.addOption ('splitCalibrationAndSmearing', False, type=bool,
63 info="EXPERIMENTAL: This splits the `EgammaCalibrationAndSmearingTool` "
64 " into two steps. The first step applies a baseline calibration that "
65 "is not affected by systematics. The second step then applies the "
66 "systematics dependent corrections. The net effect is that the "
67 "slower first step only has to be run once, while the second is run "
68 "once per systematic. ATLASG-2358.",
69 expertMode=True)
70 self.addOption ('decorateTruth', False, type=bool,
71 info="decorate the truth particle information on the reconstructed one.")
72 self.addOption ('decorateCaloClusterEta', False, type=bool,
73 info=r"decorate the calo-cluster $\eta$.")
74 self.addOption ('decorateEmva', False, type=bool,
75 info="decorate `E_mva_only` on the photons (needed for columnar tools/PHYSLITE).")
76 self.addOption ('addGlobalFELinksDep', False, type=bool,
77 info="whether to add dependencies for the global FE links (needed for PHYSLITE production)",
78 expertMode=True)
79
80 def instanceName (self) :
81 """Return the instance name for this block"""
82 return self.containerName + self.postfix
83
84
85 def makeCalibrationAndSmearingAlg (self, config, name) :
86 """Create the calibration and smearing algorithm
87
88 Factoring this out into its own function, as we want to
89 instantiate it in multiple places"""
90
91 # Set up the calibration and smearing algorithm:
92 alg = config.createAlgorithm( 'CP::EgammaCalibrationAndSmearingAlg', name )
93 config.addPrivateTool( 'calibrationAndSmearingTool',
94 'CP::EgammaCalibrationAndSmearingTool' )
95 # Set default ESModel per period
96 if self.ESModel:
97 alg.calibrationAndSmearingTool.ESModel = self.ESModel
98 else:
99 if config.geometry() is LHCPeriod.Run2:
100 alg.calibrationAndSmearingTool.ESModel = 'es2023_R22_Run2_v1'
101 elif config.geometry() is LHCPeriod.Run3:
102 alg.calibrationAndSmearingTool.ESModel = 'es2024_Run3_v0'
103 elif config.geometry() is LHCPeriod.Run4:
104 warnings.warn_explicit(
105 "No ESModel set for Run4, using Run3 model",
106 Run4FallbackWarning, filename='', lineno=0)
107 alg.calibrationAndSmearingTool.ESModel = 'es2024_Run3_v0'
108 else:
109 raise ValueError (f"Can't set up the ElectronCalibrationConfig with {config.geometry().value}, "
110 "there must be something wrong!")
111
112 alg.calibrationAndSmearingTool.decorrelationModel = self.decorrelationModel
113 alg.calibrationAndSmearingTool.useFastSim = (
115 else int( config.dataType() is DataType.FastSim ))
116 alg.calibrationAndSmearingTool.decorateEmva = self.decorateEmva
117 alg.egammas = config.readName (self.containerName)
118 alg.egammasOut = config.copyName (self.containerName)
119 alg.preselection = config.getPreselection (self.containerName, '')
120 return alg
121
122
123 def makeAlgs (self, config) :
124
125 postfix = self.postfix
126 if postfix != '' and postfix[0] != '_' :
127 postfix = '_' + postfix
128
130 warnings.warn_explicit(
131 "You are running PhotonCalibrationConfig forcing"
132 " full sim config for P4 corrections."
133 " This is only intended to be used for testing purposes.",
134 TestingOnlyWarning, filename='', lineno=0)
135
136 if config.isPhyslite() :
137 config.setSourceName (self.containerName, "AnalysisPhotons")
138 else :
139 config.setSourceName (self.containerName, "Photons")
140
141 cleaningWP = 'NoTime' if self.cleaningAllowLate else ''
142
143 # Decorate calo cluster eta if required
145 alg = config.createAlgorithm( 'CP::EgammaCaloClusterEtaAlg',
146 'ElectronEgammaCaloClusterEtaAlg',
147 reentrant=True )
148 alg.particles = config.readName(self.containerName)
149 config.addOutputVar (self.containerName, 'caloEta2', 'caloEta2', noSys=True)
150
151 # Set up a shallow copy to decorate
152 if config.wantCopy (self.containerName) :
153 alg = config.createAlgorithm( 'CP::AsgShallowCopyAlg', 'PhotonShallowCopyAlg' )
154 alg.input = config.readName (self.containerName)
155 alg.output = config.copyName (self.containerName)
156 alg.outputType = 'xAOD::PhotonContainer'
157 decorationList = ['DFCommonPhotonsCleaning',
158 'ptcone20_CloseByCorr',
159 'topoetcone20_CloseByCorr',
160 'topoetcone40_CloseByCorr']
162 decorationList += ['neutralGlobalFELinks', 'chargedGlobalFELinks']
163 if config.dataType() is not DataType.Data:
164 decorationList += ['TruthLink']
165 alg.declareDecorations = decorationList
166
167 # Set up the eta-cut on all photons prior to everything else
168 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonEtaCutAlg' )
169 alg.selectionDecoration = 'selectEta' + postfix + ',as_bits'
170 config.addPrivateTool( 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
171 alg.selectionTool.maxEta = self.maxEta
172 if self.crackVeto:
173 alg.selectionTool.etaGapLow = 1.37
174 alg.selectionTool.etaGapHigh = 1.52
175 alg.selectionTool.useClusterEta = True
176 alg.particles = config.readName (self.containerName)
177 alg.preselection = config.getPreselection (self.containerName, '')
178 config.addSelection (self.containerName, '', alg.selectionDecoration)
179
180 # Setup shower shape fudge
181 if self.recomputeIsEM and config.dataType() is DataType.FullSim:
182 alg = config.createAlgorithm( 'CP::PhotonShowerShapeFudgeAlg',
183 'PhotonShowerShapeFudgeAlg' )
184 config.addPrivateTool( 'showerShapeFudgeTool',
185 'ElectronPhotonVariableCorrectionTool' )
186 if config.geometry() is LHCPeriod.Run2:
187 alg.showerShapeFudgeTool.ConfigFile = \
188 'EGammaVariableCorrection/TUNE25/ElPhVariableNominalCorrection.conf'
189 if config.geometry() is LHCPeriod.Run3:
190 alg.showerShapeFudgeTool.ConfigFile = \
191 'EGammaVariableCorrection/TUNE23/ElPhVariableNominalCorrection.conf'
192 alg.photons = config.readName (self.containerName)
193 alg.photonsOut = config.copyName (self.containerName)
194 alg.preselection = config.getPreselection (self.containerName, '')
195
196 # Select photons only with good object quality.
197 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonObjectQualityAlg' )
198 config.setExtraInputs ({('xAOD::EventInfo', 'EventInfo.RandomRunNumber')})
199 alg.selectionDecoration = 'goodOQ,as_bits'
200 config.addPrivateTool( 'selectionTool', 'CP::EgammaIsGoodOQSelectionTool' )
201 alg.selectionTool.Mask = xAOD.EgammaParameters.BADCLUSPHOTON
202 alg.particles = config.readName (self.containerName)
203 alg.preselection = config.getPreselection (self.containerName, '')
204 config.addSelection (self.containerName, '', alg.selectionDecoration)
205
206 # Select clean photons
208 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonCleaningAlg' )
209 config.addPrivateTool( 'selectionTool', 'CP::AsgFlagSelectionTool' )
210 alg.selectionDecoration = 'isClean,as_bits'
211 alg.selectionTool.selectionFlags = ['DFCommonPhotonsCleaning' + cleaningWP]
212 alg.particles = config.readName (self.containerName)
213 alg.preselection = config.getPreselection (self.containerName, '')
214 config.addSelection (self.containerName, '', alg.selectionDecoration)
215
216 # Change the origin of Photons from (0,0,0) to (0,0,z)
217 # where z comes from the position of a vertex
218 # Default the one tagged as Primary
219 alg = config.createAlgorithm( 'CP::PhotonOriginCorrectionAlg',
220 'PhotonOriginCorrectionAlg',
221 reentrant=True )
222 alg.photons = config.readName (self.containerName)
223 alg.photonsOut = config.copyName (self.containerName)
224 alg.preselection = config.getPreselection (self.containerName, '')
225
227 # Set up the calibration and smearing algorithm:
228 alg = self.makeCalibrationAndSmearingAlg (config, 'PhotonCalibrationAndSmearingAlg')
229 if config.isPhyslite() and not self.recalibratePhyslite :
230 alg.skipNominal = True
231 else:
232 # This splits the EgammaCalibrationAndSmearingTool into two
233 # steps. The first step applies a baseline calibration that
234 # is not affected by systematics. The second step then
235 # applies the systematics dependent corrections. The net
236 # effect is that the slower first step only has to be run
237 # once, while the second is run once per systematic.
238 #
239 # For now (22 May 24) this has to happen in the same job, as
240 # the output of the first step is not part of PHYSLITE, and
241 # even for the nominal the output of the first and second
242 # step are different. In the future the plan is to put both
243 # the output of the first and second step into PHYSLITE,
244 # allowing to skip the first step when running on PHYSLITE.
245 #
246 # WARNING: All of this is experimental, see: ATLASG-2358
247
248 # Set up the calibration algorithm:
249 alg = self.makeCalibrationAndSmearingAlg (config, 'PhotonBaseCalibrationAlg')
250 # turn off systematics for the calibration step
251 alg.noToolSystematics = True
252 # turn off smearing for the calibration step
253 alg.calibrationAndSmearingTool.doSmearing = False
254
255 # Set up the smearing algorithm:
256 alg = self.makeCalibrationAndSmearingAlg (config, 'PhotonCalibrationSystematicsAlg')
257 # turn off scale corrections for the smearing step
258 alg.calibrationAndSmearingTool.doScaleCorrection = False
259 alg.calibrationAndSmearingTool.useMVACalibration = False
260 alg.calibrationAndSmearingTool.decorateEmva = False
261
263 warnings.warn_explicit(
264 "You are not applying the isolation corrections."
265 " This is only intended to be used for testing purposes.",
266 TestingOnlyWarning, filename='', lineno=0)
267
268 if self.minPt > 0:
269
270 # Set up the the pt selection
271 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonPtCutAlg' )
272 alg.selectionDecoration = 'selectPt' + postfix + ',as_bits'
273 config.addPrivateTool( 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
274 alg.selectionTool.minPt = self.minPt
275 alg.particles = config.readName (self.containerName)
276 alg.preselection = config.getPreselection (self.containerName, '')
277 config.addSelection (self.containerName, '', alg.selectionDecoration,
278 preselection=True)
279
280 # Set up the isolation correction algorithm.
282
284 warnings.warn_explicit(
285 "You are running PhotonCalibrationConfig forcing"
286 " full sim config for isolation corrections."
287 " This is only intended to be used for testing purposes.",
288 TestingOnlyWarning, filename='', lineno=0)
289
290 alg = config.createAlgorithm( 'CP::EgammaIsolationCorrectionAlg',
291 'PhotonIsolationCorrectionAlg' )
292 config.addPrivateTool( 'isolationCorrectionTool',
293 'CP::IsolationCorrectionTool' )
294 alg.isolationCorrectionTool.IsMC = config.dataType() is not DataType.Data
295 alg.isolationCorrectionTool.AFII_corr = (
297 else config.dataType() is DataType.FastSim)
298 alg.isolationCorrectionTool.FixTimingIssueInCore = True
299 alg.egammas = config.readName (self.containerName)
300 alg.egammasOut = config.copyName (self.containerName)
301 alg.preselection = config.getPreselection (self.containerName, '')
302
303 # Additional decorations
304 alg = config.createAlgorithm( 'CP::AsgEnergyDecoratorAlg', 'EnergyDecorator' )
305 alg.particles = config.readName (self.containerName)
306
307 config.addOutputVar (self.containerName, 'pt', 'pt')
308 config.addOutputVar (self.containerName, 'eta', 'eta', noSys=True)
309 config.addOutputVar (self.containerName, 'phi', 'phi', noSys=True)
310 config.addOutputVar (self.containerName, 'e_%SYS%', 'e')
311 config.addOutputVar (self.containerName, 'caloClusterEnergyReso_%SYS%', 'caloClusterEnergyReso', noSys=True)
312
313 # decorate truth information on the reconstructed object:
314 if self.decorateTruth and config.dataType() is not DataType.Data:
315 config.addOutputVar (self.containerName, "truthType", "truth_type", noSys=True)
316 config.addOutputVar (self.containerName, "truthOrigin", "truth_origin", noSys=True)
317
318
320 """the ConfigBlock for the photon working point selection"""
321
322 def __init__ (self) :
323 super (PhotonWorkingPointSelectionConfig, self).__init__ ()
324 self.setBlockName('PhotonWorkingPointSelection')
325 self.addOption ('containerName', '', type=str,
326 noneAction='error',
327 info="the name of the input container.")
328 self.addOption ('selectionName', '', type=str,
329 noneAction='error',
330 info="the name of the photon selection to define (e.g. `tight` or "
331 "`loose`).")
332 self.addOption ('postfix', None, type=str,
333 info="a postfix to apply to decorations and algorithm names. "
334 "Typically not needed here as `selectionName` is used internally.")
335 self.addOption ('qualityWP', None, type=str,
336 info="the ID WP to use. Supported ID WPs: `Tight`, `Medium`, `Loose`.")
337 self.addOption ('isolationWP', None, type=str,
338 info="the isolation WP to use. Supported isolation WPs: "
339 "`FixedCutLoose`, `FixedCutTight`, `TightCaloOnly`, `NonIso`.")
340 self.addOption ('addSelectionToPreselection', True, type=bool,
341 info="whether to retain only photons satisfying the working point "
342 "requirements.")
343 self.addOption ('closeByCorrection', False, type=bool,
344 info="whether to use close-by-corrected isolation working points.")
345 self.addOption ('recomputeIsEM', False, type=bool,
346 info="whether to rerun the cut-based selection (`True`), or rely on derivation flags (`False`).")
347 self.addOption ('doFSRSelection', False, type=bool,
348 info="whether to accept additional photons close to muons for the "
349 "purpose of FSR corrections to these muons. Expert feature "
350 "requested by the H4l analysis running on PHYSLITE.",
351 expertMode=True)
352 self.addOption ('muonsForFSRSelection', None, type=str,
353 info="the name of the muon container to use for the FSR selection. "
354 "If not specified, AnalysisMuons is used.",
355 expertMode=True)
356
357 def instanceName (self) :
358 """Return the instance name for this block"""
359 if self.postfix is not None :
360 return self.containerName + '_' + self.selectionName + self.postfix
361 return self.containerName + '_' + self.selectionName
362
363 def makeAlgs (self, config) :
364
365 # The setup below is inappropriate for Run 1
366 if config.geometry() is LHCPeriod.Run1:
367 raise ValueError ("Can't set up the PhotonWorkingPointConfig with %s, there must be something wrong!" % config.geometry().value)
368
369 postfix = self.postfix
370 if postfix is None :
371 postfix = self.selectionName
372 if postfix != '' and postfix[0] != '_' :
373 postfix = '_' + postfix
374
375 if self.qualityWP == 'Tight' :
376 quality = ROOT.egammaPID.PhotonTight
377 elif self.qualityWP == 'Medium' :
378 quality = ROOT.egammaPID.PhotonMedium
379 elif self.qualityWP == 'Loose' :
380 quality = ROOT.egammaPID.PhotonLoose
381 else :
382 raise Exception ('unknown photon quality working point "' + self.qualityWP + '" should be Tight, Medium or Loose')
383
384 # Set up the photon selection algorithm:
385 alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonIsEMSelectorAlg' )
386 alg.selectionDecoration = 'selectEM' + postfix + ',as_char'
388 # Rerun the cut-based ID
389 config.addPrivateTool( 'selectionTool', 'AsgPhotonIsEMSelector' )
390 alg.selectionTool.isEMMask = quality
391 if config.geometry() is LHCPeriod.Run2:
392 if self.qualityWP == 'Tight':
393 alg.selectionTool.ConfigFile = 'ElectronPhotonSelectorTools/offline/mc20_20240510/PhotonIsEMTightSelectorCutDefs_pTdep_mc20_smooth.conf'
394 elif self.qualityWP == 'Loose':
395 alg.selectionTool.ConfigFile = 'ElectronPhotonSelectorTools/offline/mc15_20150712/PhotonIsEMLooseSelectorCutDefs.conf'
396 elif self.qualityWP == 'Medium':
397 alg.selectionTool.ConfigFile = 'ElectronPhotonSelectorTools/offline/mc20_20240510/PhotonIsEMMediumSelectorCutDefs_pTdep_smooth.conf'
398 if config.geometry() is LHCPeriod.Run3:
399 if self.qualityWP == 'Tight':
400 alg.selectionTool.ConfigFile = 'ElectronPhotonSelectorTools/offline/20180825/PhotonIsEMTightSelectorCutDefs.conf'
401 elif self.qualityWP == 'Loose':
402 alg.selectionTool.ConfigFile = 'ElectronPhotonSelectorTools/offline/mc15_20150712/PhotonIsEMLooseSelectorCutDefs.conf'
403 elif self.qualityWP == 'Medium':
404 raise ValueError('No Medium menu available for Run-3. Please get in contact with egamma')
405 else:
406 # Select from Derivation Framework flags
407 config.addPrivateTool( 'selectionTool', 'CP::AsgFlagSelectionTool' )
408 dfFlag = 'DFCommonPhotonsIsEM' + self.qualityWP
409 alg.selectionTool.selectionFlags = [ dfFlag ]
410 alg.particles = config.readName (self.containerName)
411 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
412
413 # Set up the FSR selection
415 # wpSelection needs the ',as_char' suffix so SysReadSelectionHandle knows the type
416 wpDecoration = alg.selectionDecoration
417 wpDecorationName = wpDecoration.split(',')[0]
418 # Insert FSR before the postfix (e.g., selectEM_loose -> selectEMFSR_loose)
419 underscorePos = wpDecorationName.index('_')
420 outputDecorationName = wpDecorationName[:underscorePos] + 'FSR' + wpDecorationName[underscorePos:]
421
422 alg = config.createAlgorithm( 'CP::EgammaFSRForMuonsCollectorAlg', 'EgammaFSRForMuonsCollectorAlg')
423 alg.wpSelection = wpDecoration # Input: read the WP selection (with type suffix)
424 alg.selectionDecoration = outputDecorationName # Output: combined WP||FSR (name only for SysWriteDecorHandle)
425 alg.ElectronOrPhotonContKey = config.readName (self.containerName)
426 if self.muonsForFSRSelection is not None:
427 alg.MuonContKey = config.readName (self.muonsForFSRSelection)
428
429 # Register the FSR COMBINED selection
430 config.addSelection (self.containerName, self.selectionName,
431 alg.selectionDecoration + ',as_char',
432 preselection=self.addSelectionToPreselection)
433 else:
434 # No FSR - register the WP selection directly
435 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
436 preselection=self.addSelectionToPreselection)
437
438 # Set up the isolation selection algorithm:
439 if self.isolationWP != 'NonIso' :
440 alg = config.createAlgorithm( 'CP::EgammaIsolationSelectionAlg',
441 'PhotonIsolationSelectionAlg' )
442 alg.selectionDecoration = 'isolated' + postfix + ',as_char'
443 config.addPrivateTool( 'selectionTool', 'CP::IsolationSelectionTool' )
444 alg.selectionTool.PhotonWP = self.isolationWP
446 alg.selectionTool.IsoDecSuffix = "CloseByCorr"
447 alg.isPhoton = True
448 alg.egammas = config.readName (self.containerName)
449 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
450 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
451 preselection=self.addSelectionToPreselection)
452
453
455 """the ConfigBlock for the photon working point efficiency computation"""
456
457 def __init__ (self) :
458 super (PhotonWorkingPointEfficiencyConfig, self).__init__ ()
459 self.setBlockName('PhotonWorkingPointEfficiency')
460 self.addDependency('PhotonWorkingPointSelection', required=True)
461 self.addDependency('EventSelection', required=False)
462 self.addDependency('EventSelectionMerger', required=False)
463 self.addOption ('containerName', '', type=str,
464 noneAction='error',
465 info="the name of the input container.")
466 self.addOption ('selectionName', '', type=str,
467 noneAction='error',
468 info="the name of the photon selection to define (e.g. `tight` or "
469 "`loose`).")
470 self.addOption ('postfix', None, type=str,
471 info="a postfix to apply to decorations and algorithm names. "
472 "Typically not needed here as `selectionName` is used internally.")
473 self.addOption ('qualityWP', None, type=str,
474 info="the ID WP to use. Supported ID WPs: `Tight`, `Medium`, `Loose`.")
475 self.addOption ('isolationWP', None, type=str,
476 info="the isolation WP to use. Supported isolation WPs: "
477 "`FixedCutLoose`, `FixedCutTight`, `TightCaloOnly`, `NonIso`.")
478 self.addOption ('noEffSFForID', False, type=bool,
479 info="disables the calculation of ID efficiencies and scale factors. "
480 "Experimental! only useful to test a new WP for which scale "
481 "factors are not available.",
482 expertMode=True)
483 self.addOption ('noEffSFForIso', False, type=bool,
484 info="disables the calculation of isolation efficiencies and scale factors. "
485 "Experimental! only useful to test a new WP for which scale "
486 "factors are not available.",
487 expertMode=True)
488 self.addOption ('saveDetailedSF', True, type=bool,
489 info="save all the independent detailed object scale factors.")
490 self.addOption ('saveCombinedSF', False, type=bool,
491 info="save the combined object scale factor.")
492 self.addOption ('forceFullSimConfigForID', False, type=bool,
493 info="whether to force the ID tool to use the configuration meant "
494 "for full simulation samples. Only for testing purposes.")
495 self.addOption ('forceFullSimConfigForIso', False, type=bool,
496 info="whether to force the isolation tool to use the configuration meant "
497 "for full simulation samples. Only for testing purposes.")
498
499 def instanceName (self) :
500 """Return the instance name for this block"""
501 if self.postfix is not None :
502 return self.containerName + '_' + self.selectionName + self.postfix
503 return self.containerName + '_' + self.selectionName
504
505 def makeAlgs (self, config) :
506
507 # The setup below is inappropriate for Run 1
508 if config.geometry() is LHCPeriod.Run1:
509 raise ValueError ("Can't set up the PhotonWorkingPointConfig with %s, there must be something wrong!" % config.geometry().value)
510
512 warnings.warn_explicit(
513 "You are running PhotonWorkingPointConfig forcing"
514 " full sim config for ID."
515 " This is only intended to be used for testing purposes.",
516 TestingOnlyWarning, filename='', lineno=0)
517
519 warnings.warn_explicit(
520 "You are running PhotonWorkingPointConfig forcing"
521 " full sim config for Iso."
522 " This is only intended to be used for testing purposes.",
523 TestingOnlyWarning, filename='', lineno=0)
524
525 postfix = self.postfix
526 if postfix is None :
527 postfix = self.selectionName
528 if postfix != '' and postfix[0] != '_' :
529 postfix = '_' + postfix
530
531 sfList = []
532 # Set up the ID/reco photon efficiency correction algorithm:
533 if config.dataType() is not DataType.Data and not self.noEffSFForID:
534 alg = config.createAlgorithm( 'CP::PhotonEfficiencyCorrectionAlg',
535 'PhotonEfficiencyCorrectionAlgID' )
536 config.addPrivateTool( 'efficiencyCorrectionTool',
537 'AsgPhotonEfficiencyCorrectionTool' )
538 alg.scaleFactorDecoration = 'ph_id_effSF' + postfix + '_%SYS%'
539 if config.dataType() is DataType.FastSim:
540 alg.efficiencyCorrectionTool.ForceDataType = (
541 PATCore.ParticleDataType.Full if self.forceFullSimConfigForID else
542 PATCore.ParticleDataType.Fast)
543 elif config.dataType() is DataType.FullSim:
544 alg.efficiencyCorrectionTool.ForceDataType = \
545 PATCore.ParticleDataType.Full
546 if config.geometry() >= LHCPeriod.Run2:
547 alg.efficiencyCorrectionTool.MapFilePath = 'PhotonEfficiencyCorrection/2015_2025/rel22.2/2024_FinalRun2_Recommendation_v1/map1.txt'
548 alg.outOfValidity = 2 #silent
549 alg.outOfValidityDeco = 'ph_id_bad_eff' + postfix
550 alg.photons = config.readName (self.containerName)
551 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
553 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
554 'id_effSF' + postfix)
555 sfList += [alg.scaleFactorDecoration]
556
557 # Set up the ISO photon efficiency correction algorithm:
558 if config.dataType() is not DataType.Data and self.isolationWP != 'NonIso' and not self.noEffSFForIso:
559 alg = config.createAlgorithm( 'CP::PhotonEfficiencyCorrectionAlg',
560 'PhotonEfficiencyCorrectionAlgIsol' )
561 config.addPrivateTool( 'efficiencyCorrectionTool',
562 'AsgPhotonEfficiencyCorrectionTool' )
563 alg.scaleFactorDecoration = 'ph_isol_effSF' + postfix + '_%SYS%'
564 if config.dataType() is DataType.FastSim:
565 alg.efficiencyCorrectionTool.ForceDataType = (
566 PATCore.ParticleDataType.Full if self.forceFullSimConfigForIso else
567 PATCore.ParticleDataType.Fast)
568 elif config.dataType() is DataType.FullSim:
569 alg.efficiencyCorrectionTool.ForceDataType = \
570 PATCore.ParticleDataType.Full
571 alg.efficiencyCorrectionTool.IsoKey = self.isolationWP.replace("FixedCut","")
572 if config.geometry() >= LHCPeriod.Run2:
573 alg.efficiencyCorrectionTool.MapFilePath = 'PhotonEfficiencyCorrection/2015_2025/rel22.2/2022_Summer_Prerecom_v1/map1.txt'
574 alg.outOfValidity = 2 #silent
575 alg.outOfValidityDeco = 'ph_isol_bad_eff' + postfix
576 alg.photons = config.readName (self.containerName)
577 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
578 if self.saveDetailedSF:
579 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
580 'isol_effSF' + postfix)
581 sfList += [alg.scaleFactorDecoration]
582
583 doCombEffSF = not self.noEffSFForID or not self.noEffSFForIso
584 if config.dataType() is not DataType.Data and doCombEffSF and self.saveCombinedSF:
585 alg = config.createAlgorithm( 'CP::AsgObjectScaleFactorAlg',
586 'PhotonCombinedEfficiencyScaleFactorAlg' )
587 alg.particles = config.readName (self.containerName)
588 alg.inScaleFactors = sfList
589 alg.outScaleFactor = 'effSF' + postfix + '_%SYS%'
590 config.addOutputVar (self.containerName, alg.outScaleFactor, 'effSF' + postfix)
591
592
593@groupBlocks
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:312