ATLAS Offline Software
PhotonAnalysisSequence.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 # Framework import(s):
4 import ROOT
5 
6 # AnaAlgorithm import(s):
7 from AsgAnalysisAlgorithms.AnalysisObjectSharedSequence import makeSharedObjectSequence
8 from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence
9 from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool
10 
11 # E/gamma import(s).
12 from xAODEgamma.xAODEgammaParameters import xAOD
13 
15 
16 def makePhotonAnalysisSequence( dataType, workingPoint,
17  deepCopyOutput = False,
18  shallowViewOutput = True,
19  postfix = '',
20  crackVeto = False,
21  enableCleaning = True,
22  cleaningAllowLate = False,
23  recomputeIsEM = False,
24  ptSelectionOutput = False,
25  enableCutflow = False,
26  enableKinematicHistograms = False,
27  defineSystObjectLinks = False,
28  forceFullSimConfig = False):
29  """Create a photon analysis algorithm sequence
30 
31  Keywrod arguments:
32  dataType -- The data type to run on ("data", "mc" or "afii")
33  workingPoint -- The working point to use
34  deepCopyOutput -- If set to 'True', the output containers will be
35  standalone, deep copies (slower, but needed for xAOD
36  output writing)
37  shallowViewOutput -- Create a view container if required
38  postfix -- a postfix to apply to decorations and algorithm
39  names. this is mostly used/needed when using this
40  sequence with multiple working points to ensure all
41  names are unique.
42  crackVeto -- Whether or not to perform eta crack veto
43  enableCleaning -- Enable photon cleaning
44  cleaningAllowLate -- Whether to ignore timing information in cleaning.
45  recomputeIsEM -- Whether to rerun the cut-based selection. If not, use derivation flags
46  ptSelectionOutput -- Whether or not to apply pt selection when creating
47  output containers.
48  enableCutflow -- Whether or not to dump the cutflow
49  enableKinematicHistograms -- Whether or not to dump the kinematic histograms
50  """
51 
52  # Make sure we received a valid data type.
53  if dataType not in [ 'data', 'mc', 'afii' ]:
54  raise ValueError( 'Invalid data type: %s' % dataType )
55 
56  if postfix != '' :
57  postfix = '_' + postfix
58  pass
59 
60  # Create the analysis algorithm sequence object:
61  seq = AnaAlgSequence( "PhotonAnalysisSequence" + postfix )
62 
63  seq.addMetaConfigDefault ("selectionDecorNames", [])
64  seq.addMetaConfigDefault ("selectionDecorNamesOutput", [])
65  seq.addMetaConfigDefault ("selectionDecorCount", [])
66 
67  makePhotonCalibrationSequence (seq, dataType, postfix = postfix,
68  crackVeto = crackVeto,
69  enableCleaning = enableCleaning, cleaningAllowLate = cleaningAllowLate,
70  recomputeIsEM = recomputeIsEM,
71  ptSelectionOutput = ptSelectionOutput,
72  forceFullSimConfig = forceFullSimConfig)
73  makePhotonWorkingPointSequence (seq, dataType, workingPoint, postfix = postfix,
74  recomputeIsEM = recomputeIsEM,
75  forceFullSimConfig = forceFullSimConfig)
76  makeSharedObjectSequence (seq, deepCopyOutput = deepCopyOutput,
77  shallowViewOutput = shallowViewOutput,
78  postfix = '_Photon' + postfix,
79  enableCutflow = enableCutflow,
80  enableKinematicHistograms = enableKinematicHistograms,
81  defineSystObjectLinks = defineSystObjectLinks )
82 
83  # Return the sequence:
84  return seq
85 
86 
87 
88 
89 
90 def makePhotonCalibrationSequence( seq, dataType,
91  postfix = '',
92  crackVeto = False,
93  enableCleaning = True,
94  cleaningAllowLate = False,
95  recomputeIsEM = False,
96  ptSelectionOutput = False,
97  forceFullSimConfig = False):
98  """Create photon calibration analysis algorithms
99 
100  This makes all the algorithms that need to be run first befor
101  all working point specific algorithms and that can be shared
102  between the working points.
103 
104  Keywrod arguments:
105  dataType -- The data type to run on ("data", "mc" or "afii")
106  postfix -- a postfix to apply to decorations and algorithm
107  names. this is mostly used/needed when using this
108  sequence with multiple working points to ensure all
109  names are unique.
110  crackVeto -- Whether or not to perform eta crack veto
111  enableCleaning -- Enable photon cleaning
112  cleaningAllowLate -- Whether to ignore timing information in cleaning.
113  recomputeIsEM -- Whether to rerun the cut-based selection. If not, use derivation flags
114  ptSelectionOutput -- Whether or not to apply pt selection when creating
115  output containers.
116  """
117 
118  # Make sure we received a valid data type.
119  if dataType not in [ 'data', 'mc', 'afii' ]:
120  raise ValueError( 'Invalid data type: %s' % dataType )
121 
122  if forceFullSimConfig:
123  print("WARNING! You are running makePhotonCalibrationSequence forcing full sim config")
124  print("WARNING! This is only intended to be used for testing purposes")
125 
126  cleaningWP = 'NoTime' if cleaningAllowLate else ''
127 
128  # Set up a shallow copy to decorate
129  alg = createAlgorithm( 'CP::AsgShallowCopyAlg', 'PhotonShallowCopyAlg' + postfix )
130  seq.append( alg, inputPropName = 'input',
131  outputPropName = 'output',
132  stageName = 'prepare')
133 
134  # Set up the eta-cut on all photons prior to everything else
135  alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonEtaCutAlg' + postfix )
136  alg.selectionDecoration = 'selectEta' + postfix + ',as_bits'
137  addPrivateTool( alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
138  alg.selectionTool.maxEta = 2.37
139  if crackVeto:
140  alg.selectionTool.etaGapLow = 1.37
141  alg.selectionTool.etaGapHigh = 1.52
142  alg.selectionTool.useClusterEta = True
143  seq.append( alg, inputPropName = 'particles',
144  stageName = 'calibration',
145  metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
146  'selectionDecorNamesOutput' : [alg.selectionDecoration],
147  'selectionDecorCount' : [5 if crackVeto else 4]},
148  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
149 
150  # Setup shower shape fudge
151  if recomputeIsEM and dataType == 'mc':
152  alg = createAlgorithm( 'CP::PhotonShowerShapeFudgeAlg',
153  'PhotonShowerShapeFudgeAlg' + postfix )
154  addPrivateTool( alg, 'showerShapeFudgeTool',
155  'ElectronPhotonVariableCorrectionTool' )
156  alg.showerShapeFudgeTool.ConfigFile = \
157  'EGammaVariableCorrection/TUNE23/ElPhVariableNominalCorrection.conf'
158  seq.append( alg, inputPropName = 'photons', outputPropName = 'photonsOut',
159  stageName = 'calibration',
160  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
161  pass
162 
163  # Select photons only with good object quality.
164  alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonObjectQualityAlg' + postfix )
165  alg.selectionDecoration = 'goodOQ,as_bits'
166  addPrivateTool( alg, 'selectionTool', 'CP::EgammaIsGoodOQSelectionTool' )
167  alg.selectionTool.Mask = xAOD.EgammaParameters.BADCLUSPHOTON
168  seq.append( alg, inputPropName = 'particles',
169  stageName = 'calibration',
170  metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
171  'selectionDecorNamesOutput' : [alg.selectionDecoration],
172  'selectionDecorCount' : [1]},
173  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
174 
175  # Select clean photons
176  if enableCleaning:
177  alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonCleaningAlg' + postfix)
178  addPrivateTool( alg, 'selectionTool', 'CP::AsgFlagSelectionTool' )
179  alg.selectionDecoration = 'isClean,as_bits'
180  alg.selectionTool.selectionFlags = ['DFCommonPhotonsCleaning' + cleaningWP]
181  seq.append( alg, inputPropName = 'particles',
182  stageName = 'calibration',
183  metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
184  'selectionDecorNamesOutput' : [alg.selectionDecoration],
185  'selectionDecorCount' : [1]},
186  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
187 
188  # Change the origin of Photons from (0,0,0) to (0,0,z)
189  # where z comes from the position of a vertex
190  # Default the one tagged as Primary
191  alg = createAlgorithm( 'CP::PhotonOriginCorrectionAlg',
192  'PhotonOriginCorrectionAlg' + postfix)
193  seq.append( alg, inputPropName = 'photons', outputPropName = 'photonsOut',
194  stageName = 'calibration',
195  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
196 
197  # Do calibration
198  alg = createAlgorithm( 'CP::EgammaCalibrationAndSmearingAlg',
199  'PhotonCalibrationAndSmearingAlg' + postfix )
200  addPrivateTool( alg, 'calibrationAndSmearingTool',
201  'CP::EgammaCalibrationAndSmearingTool' )
202  alg.calibrationAndSmearingTool.ESModel = 'es2022_R22_PRE'
203  alg.calibrationAndSmearingTool.decorrelationModel = '1NP_v1'
204  alg.calibrationAndSmearingTool.useFastSim = (0 if forceFullSimConfig
205  else int(dataType == 'afii'))
206  seq.append( alg, inputPropName = 'egammas', outputPropName = 'egammasOut',
207  stageName = 'calibration',
208  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
209 
210  # Set up the the pt selection
211  alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonPtCutAlg' + postfix )
212  alg.selectionDecoration = 'selectPt' + postfix + ',as_bits'
213  addPrivateTool( alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
214  alg.selectionTool.minPt = 10e3
215  seq.append( alg, inputPropName = 'particles',
216  stageName = 'selection',
217  metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
218  'selectionDecorNamesOutput' : [alg.selectionDecoration] if ptSelectionOutput else [],
219  'selectionDecorCount' : [2]},
220  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
221 
222  # Set up the isolation correction algorithm.
223  alg = createAlgorithm( 'CP::EgammaIsolationCorrectionAlg',
224  'PhotonIsolationCorrectionAlg' + postfix )
225  addPrivateTool( alg, 'isolationCorrectionTool',
226  'CP::IsolationCorrectionTool' )
227  alg.isolationCorrectionTool.IsMC = int(dataType != 'data')
228  alg.isolationCorrectionTool.AFII_corr = (0 if forceFullSimConfig
229  else dataType == 'afii')
230  seq.append( alg, inputPropName = 'egammas', outputPropName = 'egammasOut',
231  stageName = 'selection',
232  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
233  pass
234 
235 
236 
237 
238 
239 def makePhotonWorkingPointSequence( seq, dataType, workingPoint, postfix = '',
240  recomputeIsEM = False,
241  forceFullSimConfig = False):
242  """Create photon analysis algorithms for a single working point
243 
244  Keywrod arguments:
245  dataType -- The data type to run on ("data", "mc" or "afii")
246  workingPoint -- The working point to use
247  postfix -- a postfix to apply to decorations and algorithm
248  names. this is mostly used/needed when using this
249  sequence with multiple working points to ensure all
250  names are unique.
251  recomputeIsEM -- Whether to rerun the cut-based selection. If not, use derivation flags
252  """
253 
254  # Make sure we received a valid data type.
255  if dataType not in [ 'data', 'mc', 'afii' ]:
256  raise ValueError( 'Invalid data type: %s' % dataType )
257 
258  if forceFullSimConfig:
259  print("WARNING! You are running makePhotonWorkingPointSequence forcing full sim config")
260  print("WARNING! This is only intended to be used for testing purposes")
261 
262  splitWP = workingPoint.split ('.')
263  if len (splitWP) != 2 :
264  raise ValueError ('working point should be of format "quality.isolation", not ' + workingPoint)
265 
266  qualityWP = splitWP[0]
267  isolationWP = splitWP[1]
268 
269  if qualityWP == 'Tight' :
270  quality = ROOT.egammaPID.PhotonTight
271  pass
272  elif qualityWP == 'Loose' :
273  quality = ROOT.egammaPID.PhotonLoose
274  pass
275  else :
276  raise Exception ('unknown photon quality working point "' + qualityWP + '" should be Tight or Loose')
277 
278  # Set up the photon selection algorithm:
279  alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonIsEMSelectorAlg' + postfix )
280  alg.selectionDecoration = 'selectEM,as_bits'
281  if recomputeIsEM:
282  # Rerun the cut-based ID
283  addPrivateTool( alg, 'selectionTool', 'AsgPhotonIsEMSelector' )
284  alg.selectionTool.isEMMask = quality
285  alg.selectionTool.ConfigFile = \
286  'ElectronPhotonSelectorTools/offline/20180116/PhotonIsEMTightSelectorCutDefs.conf'
287  else:
288  # Select from Derivation Framework flags
289  addPrivateTool( alg, 'selectionTool', 'CP::AsgFlagSelectionTool' )
290  dfFlag = 'DFCommonPhotonsIsEM' + qualityWP
291  alg.selectionTool.selectionFlags = [ dfFlag ]
292  pass
293  seq.append( alg, inputPropName = 'particles',
294  stageName = 'calibration',
295  metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
296  'selectionDecorNamesOutput' : [alg.selectionDecoration],
297  'selectionDecorCount' : [32 if recomputeIsEM else 1]},
298  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
299 
300  # Set up the isolation selection algorithm:
301  if isolationWP != 'NonIso' :
302  alg = createAlgorithm( 'CP::EgammaIsolationSelectionAlg',
303  'PhotonIsolationSelectionAlg' + postfix )
304  alg.selectionDecoration = 'isolated' + postfix + ',as_bits'
305  addPrivateTool( alg, 'selectionTool', 'CP::IsolationSelectionTool' )
306  alg.selectionTool.PhotonWP = isolationWP
307  alg.isPhoton = True
308  seq.append( alg, inputPropName = 'egammas',
309  stageName = 'selection',
310  metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
311  'selectionDecorNamesOutput' : [alg.selectionDecoration],
312  'selectionDecorCount' : [1]},
313  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
314  pass
315 
316  # Set up the photon efficiency correction algorithm.
317  alg = createAlgorithm( 'CP::PhotonEfficiencyCorrectionAlg',
318  'PhotonEfficiencyCorrectionAlg' + postfix )
319  addPrivateTool( alg, 'efficiencyCorrectionTool',
320  'AsgPhotonEfficiencyCorrectionTool' )
321  alg.scaleFactorDecoration = 'ph_effSF' + postfix + '_%SYS%'
322  if dataType == 'afii':
323  print("WARNING! No AFII ID SFs are available for now for photon efficiency")
324  alg.efficiencyCorrectionTool.ForceDataType = \
325  PATCore.ParticleDataType.Full
326  elif dataType == 'mc':
327  alg.efficiencyCorrectionTool.ForceDataType = \
328  PATCore.ParticleDataType.Full
329  pass
330  alg.outOfValidity = 2 #silent
331  alg.outOfValidityDeco = 'bad_eff' + postfix
332  if dataType != 'data':
333  seq.append( alg, inputPropName = 'photons',
334  stageName = 'efficiency',
335  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNamesOutput"])} )
336  pass
337 
338  pass
339 
340  # Set up an algorithm used for decorating baseline photon selection:
341  alg = createAlgorithm( 'CP::AsgSelectionAlg',
342  'PhotonSelectionSummary' + postfix )
343  alg.selectionDecoration = 'baselineSelection' + postfix + ',as_char'
344  seq.append( alg, inputPropName = 'particles',
345  stageName = 'selection',
346  dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
python.PhotonAnalysisSequence.makePhotonAnalysisSequence
def makePhotonAnalysisSequence(dataType, workingPoint, deepCopyOutput=False, shallowViewOutput=True, postfix='', crackVeto=False, enableCleaning=True, cleaningAllowLate=False, recomputeIsEM=False, ptSelectionOutput=False, enableCutflow=False, enableKinematicHistograms=False, defineSystObjectLinks=False, forceFullSimConfig=False)
Definition: PhotonAnalysisSequence.py:16
PATCore::ParticleDataType
Definition: PATCoreEnums.h:21
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.DualUseConfig.addPrivateTool
def addPrivateTool(alg, toolName, typeName)
Definition: DualUseConfig.py:180
python.PhotonAnalysisSequence.makePhotonWorkingPointSequence
def makePhotonWorkingPointSequence(seq, dataType, workingPoint, postfix='', recomputeIsEM=False, forceFullSimConfig=False)
Definition: PhotonAnalysisSequence.py:239
python.DualUseConfig.createAlgorithm
def createAlgorithm(typeName, instanceName)
Definition: DualUseConfig.py:56
python.PhotonAnalysisSequence.makePhotonCalibrationSequence
def makePhotonCalibrationSequence(seq, dataType, postfix='', crackVeto=False, enableCleaning=True, cleaningAllowLate=False, recomputeIsEM=False, ptSelectionOutput=False, forceFullSimConfig=False)
Definition: PhotonAnalysisSequence.py:90
Muon::print
std::string print(const MuPatSegment &)
Definition: MuonTrackSteering.cxx:28