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