ATLAS Offline Software
run_xAOD_ElectronPhotonFourMomentumCorrection.py
Go to the documentation of this file.
1 #!/bin/env python
2 
3 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
4 
5 import ROOT
6 import math
7 from functools import partial
8 from itertools import islice
9 
10 import logging
11 logging.basicConfig(level=logging.INFO, format="%(filename)s\t%(levelname)s %(message)s")
12 
13 ROOT.PyConfig.IgnoreCommandLineOptions = True
14 
15 
17  try:
18  collection = tree.Electrons
19  except AttributeError:
20  collection = tree.ElectronCollection
21  return collection
22 
23 
25  try:
26  collection = tree.Photons
27  except AttributeError:
28  collection = tree.PhotonCollection
29  return collection
30 
31 
32 def xAOD_particle_generator(tree, collection_getter, newevent_function=None, endevent_function=None,
33  event_numbers=None,
34  min_pt=None, min_abseta=None, max_abseta=None):
35  if event_numbers is None:
36  event_numbers = []
37  elif type(event_numbers) is int:
38  event_numbers = [event_numbers]
39 
40  for ievent in range(tree.GetEntries()):
41  tree.GetEntry(ievent)
42  ei = tree.EventInfo
43  event_number = ei.eventNumber()
44  if event_numbers:
45  if event_number not in event_numbers:
46  continue
47  logging.debug("=== event number %d ievent = %d", event_number, ievent)
48  if newevent_function is not None:
49  newevent_function()
50 
51  collection = collection_getter(tree)
52 
53  for i in range(collection.size()):
54  p = collection.at(i)
55  if min_pt is not None and p.pt() < min_pt:
56  continue
57  if min_abseta is not None and abs(p.eta()) < min_abseta:
58  continue
59  if max_abseta is not None and abs(p.eta()) > max_abseta:
60  continue
61  yield p
62 
63  if endevent_function is not None:
64  endevent_function()
65 
66 
67 xAOD_photon_generator = partial(xAOD_particle_generator, collection_getter=get_photon_collection)
68 xAOD_electron_generator = partial(xAOD_particle_generator, collection_getter=get_electron_collection)
69 
70 
71 def main(filename, **args):
72  logging.debug("initializing xAOD")
73  if (not ROOT.xAOD.Init().isSuccess()):
74  raise IOError("Failed xAOD.Init()")
75 
76 
77  tree = None
78  if ".txt" in filename:
79  logging.debug("filename is a list of files")
80  chain = ROOT.TChain(args['tree_name'])
81  for line in islice(open(filename), 10):
82  logging.debug("adding %s", line.strip())
83  chain.Add(line.strip())
84  tree = ROOT.xAOD.MakeTransientTree(chain)
85  else:
86  logging.debug("opening file %s", filename)
87  f = ROOT.TFile.Open(filename)
88  if not f:
89  logging.error("problem opening file %s", filename)
90  tree = ROOT.xAOD.MakeTransientTree(f, args['tree_name'])
91  if not tree:
92  logging.warning("cannot find tree in the file")
93  f.Print()
94  return
95 
96  logging.info("input has %d entries", tree.GetEntries())
97 
98  logging.debug("initializing tool")
99  tool = ROOT.CP.EgammaCalibrationAndSmearingTool("tool")
100  tool.setProperty("ESModel", args["esmodel"]).ignore()
101  tool.setProperty("decorrelationModel", args["decorrelation"]).ignore()
102  if args["no_smearing"]:
103  tool.setProperty("int")("doSmearing", 0).ignore()
104  if args['debug']:
105  tool.msg().setLevel(0)
106  if args['use_afii'] is not None:
107  tool.setProperty("bool")("useFastSim", bool(args['use_afii'])).ignore()
108 
109  tool.initialize()
110 
111  if args['variation'] is not None:
112  logging.info("applying systematic variation %s", args['variation'])
113  sys_set = ROOT.CP.SystematicSet()
114  sys_set.insert(ROOT.CP.SystematicVariation(args['variation'], args['variation_sigma']))
115  tool.applySystematicVariation(sys_set)
116 
117  logging.debug("creating output tree")
118  fout = ROOT.TFile("output.root", "recreate")
119  tree_out = ROOT.TNtuple(args["tree_name"], args["tree_name"], "eventNumber:eta:phi:true_e:pdgId:e:xAOD_e:raw_e:raw_ps")
120 
121  logging.debug("looping on electron container")
122 
123  def newevent_function():
124  logging.debug("executing new event function")
125  tool.beginInputFile()
126  tool.beginEvent()
127 
128  def endevent_function():
129  logging.debug("executing end event function")
130  tool.endInputFile()
131 
132  generator = xAOD_photon_generator(tree, newevent_function = newevent_function,
133  endevent_function = endevent_function,
134  min_pt=args['min_pt'],
135  min_abseta=args['min_abseta'], max_abseta=args['max_abseta'],
136  event_numbers=args['event_number'])
137 
138  _ = ROOT.xAOD.TruthParticle_v1 # this is needed to run the next line, don't know why, dictionary stuff...
139  get_truth_particle = ROOT.xAOD.TruthHelpers.getTruthParticle
140 
141  for particle in islice(generator, None, args['nparticles']):
142  ei = tree.EventInfo
143  logging.debug(" === new photon eventNumber|eta|phi|e| = |%d|%.2f|%.2f|%.2f|", ei.eventNumber(), particle.eta(), particle.phi(), particle.e())
144  if not particle.caloCluster():
145  logging.warning("particle has no calo cluster")
146  continue
147  logging.debug(" |rawe0|raweAcc|TileGap3| = |%.2f|%.2f|%.2f|",
148  particle.caloCluster().energyBE(0),
149  particle.caloCluster().energyBE(1) + particle.caloCluster().energyBE(2) + particle.caloCluster().energyBE(3),
150  particle.caloCluster().eSample(17))
151  xAOD_energy = particle.e()
152  cluster = particle.caloCluster()
153  raw_e = cluster.energyBE(1) + cluster.energyBE(2) + cluster.energyBE(3)
154  raw_ps = cluster.energyBE(0)
155  true_particle = get_truth_particle(particle)
156  true_e = true_particle.e() if true_particle else 0
157  pdgId = true_particle.pdgId() if true_particle else 0
158  calibrated_energy = tool.getEnergy(particle)
159  tree_out.Fill(ei.eventNumber(), cluster.eta(), cluster.phi(),
160  true_e, pdgId, calibrated_energy, xAOD_energy, raw_e, raw_ps)
161  if math.isnan(calibrated_energy) or math.isnan(calibrated_energy) or calibrated_energy < 1:
162  print("==>", particle.author(), particle.eta(), particle.phi(), xAOD_energy, calibrated_energy)
163 
164 
165  logging.info("%d events written", tree_out.GetEntries())
166 
167  tree_out.Write()
168  fout.Close()
169 
170 if __name__ == '__main__':
171  import argparse
172 
173  parser = argparse.ArgumentParser(description='Run on xAOD and dump calibrated energy for electron and photons',
174  formatter_class=argparse.RawTextHelpFormatter,
175  epilog='example: ./run_xAOD_ElectronPhotonFourMomentumCorrection.py root://eosatlas.cern.ch//eos/atlas/user/t/turra/Hgamgam_20.7/mc15_13TeV:AOD.07922786._000014.pool.root.1')
176  parser.add_argument('filename', type=str, help='path to xAOD')
177  parser.add_argument('--nparticles', type=int, help='number of particles')
178  parser.add_argument('--tree-name', type=str, default='CollectionTree')
179  parser.add_argument('--min-pt', type=float, help='minimum pT')
180  parser.add_argument('--min-abseta', type=float, help='minimum |eta|')
181  parser.add_argument('--max-abseta', type=float, help='maximum |eta|')
182  parser.add_argument('--event-number', type=int)
183  parser.add_argument('--debug', action='store_true', default=False)
184  parser.add_argument('--no-layer-correction', action='store_true', default=False)
185  parser.add_argument('--no-smearing', action='store_true')
186  parser.add_argument('--esmodel', default="es2015c_summer")
187  parser.add_argument('--decorrelation', default='1NP_v1')
188  parser.add_argument('--variation', type=str, help='variation to apply (optional)')
189  parser.add_argument('--variation-sigma', type=int, default=1, help='number of sigma for the variation (+1 or -1)')
190  parser.add_argument('--use-afii', type=int)
191 
192  args = parser.parse_args()
193  if args.debug:
194  logging.getLogger().setLevel(logging.DEBUG)
195  main(**vars(args))
196  ROOT.xAOD.ClearTransientTrees()
run_xAOD_ElectronPhotonFourMomentumCorrection.type
type
Definition: run_xAOD_ElectronPhotonFourMomentumCorrection.py:176
run_xAOD_ElectronPhotonFourMomentumCorrection.xAOD_particle_generator
def xAOD_particle_generator(tree, collection_getter, newevent_function=None, endevent_function=None, event_numbers=None, min_pt=None, min_abseta=None, max_abseta=None)
Definition: run_xAOD_ElectronPhotonFourMomentumCorrection.py:32
pool::DbPrintLvl::setLevel
void setLevel(MsgLevel l)
Definition: DbPrint.h:32
DiTauMassTools::ignore
void ignore(T &&)
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:54
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
run_xAOD_ElectronPhotonFourMomentumCorrection.xAOD_photon_generator
xAOD_photon_generator
Definition: run_xAOD_ElectronPhotonFourMomentumCorrection.py:67
run_xAOD_ElectronPhotonFourMomentumCorrection.get_electron_collection
def get_electron_collection(tree)
Definition: run_xAOD_ElectronPhotonFourMomentumCorrection.py:16
Trk::open
@ open
Definition: BinningType.h:40
run_xAOD_ElectronPhotonFourMomentumCorrection.get_photon_collection
def get_photon_collection(tree)
Definition: run_xAOD_ElectronPhotonFourMomentumCorrection.py:24
run_xAOD_ElectronPhotonFourMomentumCorrection.main
def main(filename, **args)
Definition: run_xAOD_ElectronPhotonFourMomentumCorrection.py:71
Muon::print
std::string print(const MuPatSegment &)
Definition: MuonTrackSteering.cxx:28
xAOD::bool
setBGCode setTAP setLVL2ErrorBits bool
Definition: TrigDecision_v1.cxx:60