4 from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
6 from AthenaConfiguration.Enums
import LHCPeriod
7 from AnalysisAlgorithmsConfig.ConfigAccumulator
import DataType
8 from AthenaCommon.Logging
import logging
13 from xAODEgamma.xAODEgammaParameters
import xAOD
18 """the ConfigBlock for the photon four-momentum correction"""
21 super (PhotonCalibrationConfig, self).__init__ ()
22 self.setBlockName(
'Photons')
23 self.addOption (
'containerName', containerName, type=str,
25 info=
"the name of the output container after calibration.")
26 self.addOption (
'ESModel',
'', type=str,
27 info=
"flag of egamma calibration recommendation.")
28 self.addOption (
'decorrelationModel',
'1NP_v1', type=str,
29 info=
"egamma energy scale decorrelationModel. The default is 1NP_v1. "
30 "Supported Model: 1NP_v1, FULL_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 "
35 self.addOption (
'crackVeto',
False, type=bool,
36 info=
"whether to perform LAr crack veto based on the cluster eta, "
37 "i.e. remove photons within 1.37<|eta|<1.52. "
38 "The default is False.")
39 self.addOption (
'enableCleaning',
True, type=bool,
40 info=
"whether to enable photon cleaning (DFCommonPhotonsCleaning). "
41 "The default is True.")
42 self.addOption (
'cleaningAllowLate',
False, type=bool,
43 info=
"whether to ignore timing information in cleaning "
44 "(DFCommonPhotonsCleaningNoTime). The default is False.")
45 self.addOption (
'recomputeIsEM',
False, type=bool,
46 info=
"whether to recompute the photon shower shape fudge "
47 "corrections (sets up an instance of CP::PhotonShowerShapeFudgeAlg). "
48 "The default is False, i.e. to use derivation variables.")
49 self.addOption (
'recalibratePhyslite',
True, type=bool,
50 info=
"whether to run the CP::EgammaCalibrationAndSmearingAlg on "
51 "PHYSLITE derivations. The default is True.")
52 self.addOption (
'minPt', 10*GeV, type=float,
53 info=
"the minimum pT cut to apply to calibrated photons. "
54 "The default is 10 GeV.")
55 self.addOption (
'maxEta', 2.37, type=float,
56 info=
"maximum photon |eta| (float). The default is 2.37.")
57 self.addOption (
'forceFullSimConfig',
False, type=bool,
58 info=
"whether to force the tool to use the configuration meant for "
59 "full simulation samples. Only for testing purposes. "
60 "The default is False.")
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 self.addOption (
'decorateTruth',
False, type=bool,
69 info=
"decorate truth particle information on the reconstructed one")
70 self.addOption (
'decorateCaloClusterEta',
False, type=bool,
71 info=
"decorate the calo cluster eta on the reconstructed one")
75 """Create the calibration and smearing algorithm
77 Factoring this out into its own function, as we want to
78 instantiate it in multiple places"""
79 log = logging.getLogger(
'PhotonCalibrationConfig')
82 alg = config.createAlgorithm(
'CP::EgammaCalibrationAndSmearingAlg', name + self.postfix )
83 config.addPrivateTool(
'calibrationAndSmearingTool',
84 'CP::EgammaCalibrationAndSmearingTool' )
87 alg.calibrationAndSmearingTool.ESModel = self.ESModel
89 if config.geometry()
is LHCPeriod.Run2:
90 alg.calibrationAndSmearingTool.ESModel =
'es2023_R22_Run2_v1'
91 elif config.geometry()
is LHCPeriod.Run3:
92 alg.calibrationAndSmearingTool.ESModel =
'es2022_R22_PRE'
93 elif config.geometry()
is LHCPeriod.Run4:
94 log.warning(
"No ESModel set for Run4, using Run3 model")
95 alg.calibrationAndSmearingTool.ESModel =
'es2022_R22_PRE'
97 raise ValueError (f
"Can't set up the ElectronCalibrationConfig with {config.geometry().value}, "
98 "there must be something wrong!")
100 alg.calibrationAndSmearingTool.decorrelationModel = self.decorrelationModel
101 alg.calibrationAndSmearingTool.useFastSim = (
102 0
if self.forceFullSimConfig
103 else int( config.dataType()
is DataType.FastSim ))
104 alg.egammas = config.readName (self.containerName)
105 alg.egammasOut = config.copyName (self.containerName)
106 alg.preselection = config.getPreselection (self.containerName,
'')
112 log = logging.getLogger(
'PhotonCalibrationConfig')
114 postfix = self.postfix
115 if postfix !=
'' and postfix[0] !=
'_' :
116 postfix =
'_' + postfix
118 if self.forceFullSimConfig:
119 log.warning(
"You are running PhotonCalibrationConfig forcing full sim config")
120 log.warning(
"This is only intended to be used for testing purposes")
122 if config.isPhyslite() :
123 config.setSourceName (self.containerName,
"AnalysisPhotons")
125 config.setSourceName (self.containerName,
"Photons")
127 cleaningWP =
'NoTime' if self.cleaningAllowLate
else ''
130 if self.decorateCaloClusterEta:
131 alg = config.createAlgorithm(
'CP::EgammaCaloClusterEtaAlg',
'ElectronEgammaCaloClusterEtaAlg' + self.postfix )
132 alg.particles = config.readName(self.containerName)
133 config.addOutputVar (self.containerName,
'caloEta2',
'caloEta2', noSys=
True)
136 if config.wantCopy (self.containerName) :
137 alg = config.createAlgorithm(
'CP::AsgShallowCopyAlg',
'PhotonShallowCopyAlg' + postfix )
138 alg.input = config.readName (self.containerName)
139 alg.output = config.copyName (self.containerName)
142 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PhotonEtaCutAlg' + postfix )
143 alg.selectionDecoration =
'selectEta' + postfix +
',as_bits'
144 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
145 alg.selectionTool.maxEta = self.maxEta
147 alg.selectionTool.etaGapLow = 1.37
148 alg.selectionTool.etaGapHigh = 1.52
149 alg.selectionTool.useClusterEta =
True
150 alg.particles = config.readName (self.containerName)
151 alg.preselection = config.getPreselection (self.containerName,
'')
152 config.addSelection (self.containerName,
'', alg.selectionDecoration)
155 if self.recomputeIsEM
and config.dataType()
is DataType.FullSim:
156 alg = config.createAlgorithm(
'CP::PhotonShowerShapeFudgeAlg',
157 'PhotonShowerShapeFudgeAlg' + postfix )
158 config.addPrivateTool(
'showerShapeFudgeTool',
159 'ElectronPhotonVariableCorrectionTool' )
160 if config.geometry
is LHCPeriod.Run2:
161 alg.showerShapeFudgeTool.ConfigFile = \
162 'EGammaVariableCorrection/TUNE25/ElPhVariableNominalCorrection.conf'
163 if config.geometry
is LHCPeriod.Run3:
164 alg.showerShapeFudgeTool.ConfigFile = \
165 'EGammaVariableCorrection/TUNE23/ElPhVariableNominalCorrection.conf'
166 alg.photons = config.readName (self.containerName)
167 alg.photonsOut = config.copyName (self.containerName)
168 alg.preselection = config.getPreselection (self.containerName,
'')
171 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PhotonObjectQualityAlg' + postfix )
172 alg.selectionDecoration =
'goodOQ,as_bits'
173 config.addPrivateTool(
'selectionTool',
'CP::EgammaIsGoodOQSelectionTool' )
174 alg.selectionTool.Mask = xAOD.EgammaParameters.BADCLUSPHOTON
175 alg.particles = config.readName (self.containerName)
176 alg.preselection = config.getPreselection (self.containerName,
'')
177 config.addSelection (self.containerName,
'', alg.selectionDecoration)
180 if self.enableCleaning:
181 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PhotonCleaningAlg' + postfix)
182 config.addPrivateTool(
'selectionTool',
'CP::AsgFlagSelectionTool' )
183 alg.selectionDecoration =
'isClean,as_bits'
184 alg.selectionTool.selectionFlags = [
'DFCommonPhotonsCleaning' + cleaningWP]
185 alg.particles = config.readName (self.containerName)
186 alg.preselection = config.getPreselection (self.containerName,
'')
187 config.addSelection (self.containerName,
'', alg.selectionDecoration)
192 alg = config.createAlgorithm(
'CP::PhotonOriginCorrectionAlg',
193 'PhotonOriginCorrectionAlg' + postfix )
194 alg.photons = config.readName (self.containerName)
195 alg.photonsOut = config.copyName (self.containerName)
196 alg.preselection = config.getPreselection (self.containerName,
'')
198 if not self.splitCalibrationAndSmearing :
201 if config.isPhyslite()
and not self.recalibratePhyslite :
202 alg.skipNominal =
True
223 alg.noToolSystematics =
True
225 alg.calibrationAndSmearingTool.doSmearing =
False
230 alg.calibrationAndSmearingTool.doScaleCorrection =
False
231 alg.calibrationAndSmearingTool.useMVACalibration =
False
235 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PhotonPtCutAlg' + postfix )
236 alg.selectionDecoration =
'selectPt' + postfix +
',as_bits'
237 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
238 alg.selectionTool.minPt = self.minPt
239 alg.particles = config.readName (self.containerName)
240 alg.preselection = config.getPreselection (self.containerName,
'')
241 config.addSelection (self.containerName,
'', alg.selectionDecoration,
245 alg = config.createAlgorithm(
'CP::EgammaIsolationCorrectionAlg',
246 'PhotonIsolationCorrectionAlg' + postfix )
247 config.addPrivateTool(
'isolationCorrectionTool',
248 'CP::IsolationCorrectionTool' )
249 alg.isolationCorrectionTool.IsMC = config.dataType()
is not DataType.Data
250 alg.isolationCorrectionTool.AFII_corr = (
251 0
if self.forceFullSimConfig
252 else config.dataType()
is DataType.FastSim)
253 alg.egammas = config.readName (self.containerName)
254 alg.egammasOut = config.copyName (self.containerName)
255 alg.preselection = config.getPreselection (self.containerName,
'')
258 alg = config.createAlgorithm(
'CP::AsgEnergyDecoratorAlg',
'EnergyDecorator' + self.containerName + self.postfix )
259 alg.particles = config.readName (self.containerName)
261 config.addOutputVar (self.containerName,
'pt',
'pt')
262 config.addOutputVar (self.containerName,
'eta',
'eta', noSys=
True)
263 config.addOutputVar (self.containerName,
'phi',
'phi', noSys=
True)
264 config.addOutputVar (self.containerName,
'e_%SYS%',
'e')
267 if self.decorateTruth
and config.dataType()
is not DataType.Data:
268 config.addOutputVar (self.containerName,
"truthType",
"truth_type", noSys=
True)
269 config.addOutputVar (self.containerName,
"truthOrigin",
"truth_origin", noSys=
True)
273 """the ConfigBlock for the photon working point
275 This may at some point be split into multiple blocks (29 Aug 22)."""
277 def __init__ (self, containerName='', selectionName='') :
278 super (PhotonWorkingPointConfig, self).__init__ ()
279 self.addOption (
'containerName', containerName, type=str,
281 info=
"the name of the input container.")
282 self.addOption (
'selectionName', selectionName, type=str,
284 info=
"the name of the photon selection to define (e.g. tight or "
286 self.addOption (
'postfix', selectionName, type=str,
287 info=
"a postfix to apply to decorations and algorithm names. "
288 "Typically not needed here as selectionName is used internally.")
289 self.addOption (
'qualityWP',
None, type=str,
290 info=
"the ID WP (string) to use. Supported ID WPs: Tight, Medium and Loose.")
291 self.addOption (
'isolationWP',
None, type=str,
292 info=
"the ID WP (string) to use. Supported isolation WPs: "
293 "FixedCutLoose, FixedCutTight, TightCaloOnly, NonIso.")
294 self.addOption (
'addSelectionToPreselection',
True, type=bool,
295 info=
"whether to retain only photons satisfying the working point "
296 "requirements. The default is True.")
297 self.addOption (
'closeByCorrection',
False, type=bool,
298 info=
"whether to use close-by-corrected isolation working points")
299 self.addOption (
'recomputeIsEM',
False, type=bool,
300 info=
"whether to rerun the cut-based selection. The default is "
301 "False, i.e. to use derivation flags.")
302 self.addOption (
'doFSRSelection',
False, type=bool,
303 info=
"whether to accept additional photons close to muons for the "
304 "purpose of FSR corrections to these muons. Expert feature "
305 "requested by the H4l analysis running on PHYSLITE. "
306 "The default is False.")
307 self.addOption (
'noEffSF',
False, type=bool,
308 info=
"disables the calculation of efficiencies and scale factors. "
309 "Experimental! only useful to test a new WP for which scale "
310 "factors are not available. The default is False.")
311 self.addOption (
'saveDetailedSF',
True, type=bool,
312 info=
"save all the independent detailed object scale factors. "
313 "The default is True.")
314 self.addOption (
'saveCombinedSF',
False, type=bool,
315 info=
"save the combined object scale factor. "
316 "The default is False.")
317 self.addOption (
'forceFullSimConfig',
False, type=bool,
318 info=
"whether to force the tool to use the configuration meant "
319 "for full simulation samples. Only for testing purposes. "
320 "The default is False.")
324 log = logging.getLogger(
'PhotonWorkingPointConfig')
327 if config.geometry()
is LHCPeriod.Run1:
328 raise ValueError (
"Can't set up the PhotonWorkingPointConfig with %s, there must be something wrong!" % config.geometry().value)
330 if self.forceFullSimConfig:
331 log.warning(
"You are running PhotonWorkingPointConfig forcing full sim config")
332 log.warning(
"This is only intended to be used for testing purposes")
334 postfix = self.postfix
335 if postfix !=
'' and postfix[0] !=
'_' :
336 postfix =
'_' + postfix
339 quality = ROOT.egammaPID.PhotonTight
341 quality = ROOT.egammaPID.PhotonMedium
343 quality = ROOT.egammaPID.PhotonLoose
345 raise Exception (
'unknown photon quality working point "' + self.
qualityWP +
'" should be Tight, Medium or Loose')
348 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PhotonIsEMSelectorAlg' + postfix )
349 alg.selectionDecoration =
'selectEM' + postfix +
',as_char'
350 if self.recomputeIsEM:
352 config.addPrivateTool(
'selectionTool',
'AsgPhotonIsEMSelector' )
353 alg.selectionTool.isEMMask = quality
354 if config.geometry()
is LHCPeriod.Run2:
356 alg.selectionTool.ConfigFile =
'ElectronPhotonSelectorTools/offline/mc20_20240510/PhotonIsEMTightSelectorCutDefs_pTdep_mc20_smooth.conf'
358 alg.selectionTool.ConfigFile =
'ElectronPhotonSelectorTools/offline/mc15_20150712/PhotonIsEMLooseSelectorCutDefs.conf'
360 alg.selectionTool.ConfigFile =
'ElectronPhotonSelectorTools/offline/mc20_20240510/PhotonIsEMMediumSelectorCutDefs_pTdep_smooth.conf'
361 if config.geometry()
is LHCPeriod.Run3:
363 alg.selectionTool.ConfigFile =
'ElectronPhotonSelectorTools/offline/20180825/PhotonIsEMTightSelectorCutDefs.conf'
365 alg.selectionTool.ConfigFile =
'ElectronPhotonSelectorTools/offline/mc15_20150712/PhotonIsEMLooseSelectorCutDefs.conf'
367 raise ValueError(
'No Medium menu available for Run-3. Please get in contact with egamma')
370 config.addPrivateTool(
'selectionTool',
'CP::AsgFlagSelectionTool' )
371 dfFlag =
'DFCommonPhotonsIsEM' + self.
qualityWP
372 alg.selectionTool.selectionFlags = [ dfFlag ]
373 alg.particles = config.readName (self.containerName)
374 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
375 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
376 preselection=self.addSelectionToPreselection)
379 if self.doFSRSelection :
381 wpFlag = alg.selectionDecoration.split(
",")[0]
382 alg = config.createAlgorithm(
'CP::EgammaFSRForMuonsCollectorAlg',
'EgammaFSRForMuonsCollectorAlg' + postfix +
'_ph')
383 alg.selectionDecoration = wpFlag
384 alg.ElectronOrPhotonContKey = config.readName (self.containerName)
387 if self.isolationWP !=
'NonIso' :
388 alg = config.createAlgorithm(
'CP::EgammaIsolationSelectionAlg',
389 'PhotonIsolationSelectionAlg' + postfix )
390 alg.selectionDecoration =
'isolated' + postfix +
',as_char'
391 config.addPrivateTool(
'selectionTool',
'CP::IsolationSelectionTool' )
392 alg.selectionTool.PhotonWP = self.isolationWP
393 if self.closeByCorrection:
394 alg.selectionTool.IsoDecSuffix =
"CloseByCorr"
396 alg.egammas = config.readName (self.containerName)
397 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
398 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
399 preselection=self.addSelectionToPreselection)
403 if config.dataType()
is not DataType.Data
and not self.noEffSF:
404 alg = config.createAlgorithm(
'CP::PhotonEfficiencyCorrectionAlg',
405 'PhotonEfficiencyCorrectionAlgID' + postfix )
406 config.addPrivateTool(
'efficiencyCorrectionTool',
407 'AsgPhotonEfficiencyCorrectionTool' )
408 alg.scaleFactorDecoration =
'ph_id_effSF' + postfix +
'_%SYS%'
409 if config.dataType()
is DataType.FastSim:
410 alg.efficiencyCorrectionTool.ForceDataType = (
411 PATCore.ParticleDataType.Full
if self.forceFullSimConfig
else
412 PATCore.ParticleDataType.Fast)
413 elif config.dataType()
is DataType.FullSim:
414 alg.efficiencyCorrectionTool.ForceDataType = \
415 PATCore.ParticleDataType.Full
416 if config.geometry() >= LHCPeriod.Run2:
417 alg.efficiencyCorrectionTool.MapFilePath =
'PhotonEfficiencyCorrection/2015_2025/rel22.2/2024_FinalRun2_Recommendation_v1/map1.txt'
418 alg.outOfValidity = 2
419 alg.outOfValidityDeco =
'ph_id_bad_eff' + postfix
420 alg.photons = config.readName (self.containerName)
421 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
422 if self.saveDetailedSF:
423 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
424 'id_effSF' + postfix)
425 sfList += [alg.scaleFactorDecoration]
428 if config.dataType()
is not DataType.Data
and self.isolationWP !=
'NonIso' and not self.noEffSF:
429 alg = config.createAlgorithm(
'CP::PhotonEfficiencyCorrectionAlg',
430 'PhotonEfficiencyCorrectionAlgIsol' + postfix )
431 config.addPrivateTool(
'efficiencyCorrectionTool',
432 'AsgPhotonEfficiencyCorrectionTool' )
433 alg.scaleFactorDecoration =
'ph_isol_effSF' + postfix +
'_%SYS%'
434 if config.dataType()
is DataType.FastSim:
435 alg.efficiencyCorrectionTool.ForceDataType = (
436 PATCore.ParticleDataType.Full
if self.forceFullSimConfig
else
437 PATCore.ParticleDataType.Fast)
438 elif config.dataType()
is DataType.FullSim:
439 alg.efficiencyCorrectionTool.ForceDataType = \
440 PATCore.ParticleDataType.Full
441 alg.efficiencyCorrectionTool.IsoKey = self.isolationWP.
replace(
"FixedCut",
"")
442 if config.geometry() >= LHCPeriod.Run2:
443 alg.efficiencyCorrectionTool.MapFilePath =
'PhotonEfficiencyCorrection/2015_2025/rel22.2/2022_Summer_Prerecom_v1/map0.txt'
444 alg.outOfValidity = 2
445 alg.outOfValidityDeco =
'ph_isol_bad_eff' + postfix
446 alg.photons = config.readName (self.containerName)
447 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
448 if self.saveDetailedSF:
449 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
450 'isol_effSF' + postfix)
451 sfList += [alg.scaleFactorDecoration]
453 if config.dataType()
is not DataType.Data
and not self.noEffSF
and self.saveCombinedSF:
454 alg = config.createAlgorithm(
'CP::AsgObjectScaleFactorAlg',
455 'PhotonCombinedEfficiencyScaleFactorAlg' + postfix )
456 alg.particles = config.readName (self.containerName)
457 alg.inScaleFactors = sfList
458 alg.outScaleFactor =
'effSF' + postfix +
'_%SYS%'
459 config.addOutputVar (self.containerName, alg.outScaleFactor,
'effSF' + postfix)