7 from functools
import partial
8 from itertools
import islice
11 logging.basicConfig(level=logging.INFO, format=
"%(filename)s\t%(levelname)s %(message)s")
13 ROOT.PyConfig.IgnoreCommandLineOptions =
True
18 collection = tree.Electrons
19 except AttributeError:
20 collection = tree.ElectronCollection
26 collection = tree.Photons
27 except AttributeError:
28 collection = tree.PhotonCollection
34 min_pt=None, min_abseta=None, max_abseta=None):
35 if event_numbers
is None:
37 elif type(event_numbers)
is int:
38 event_numbers = [event_numbers]
40 for ievent
in range(tree.GetEntries()):
43 event_number = ei.eventNumber()
45 if event_number
not in event_numbers:
47 logging.debug(
"=== event number %d ievent = %d", event_number, ievent)
48 if newevent_function
is not None:
51 collection = collection_getter(tree)
53 for i
in range(collection.size()):
55 if min_pt
is not None and p.pt() < min_pt:
57 if min_abseta
is not None and abs(p.eta()) < min_abseta:
59 if max_abseta
is not None and abs(p.eta()) > max_abseta:
63 if endevent_function
is not None:
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)
71 def main(filename, **args):
72 logging.debug(
"initializing xAOD")
73 if (
not ROOT.xAOD.Init().isSuccess()):
74 raise IOError(
"Failed xAOD.Init()")
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)
86 logging.debug(
"opening file %s", filename)
87 f = ROOT.TFile.Open(filename)
89 logging.error(
"problem opening file %s", filename)
90 tree = ROOT.xAOD.MakeTransientTree(f, args[
'tree_name'])
92 logging.warning(
"cannot find tree in the file")
96 logging.info(
"input has %d entries", tree.GetEntries())
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()
106 if args[
'use_afii']
is not None:
107 tool.setProperty(
"bool")(
"useFastSim",
bool(args[
'use_afii'])).
ignore()
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)
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")
121 logging.debug(
"looping on electron container")
123 def newevent_function():
124 logging.debug(
"executing new event function")
125 tool.beginInputFile()
128 def endevent_function():
129 logging.debug(
"executing end event 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'])
138 _ = ROOT.xAOD.TruthParticle_v1
139 get_truth_particle = ROOT.xAOD.TruthHelpers.getTruthParticle
141 for particle
in islice(generator,
None, args[
'nparticles']):
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")
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)
165 logging.info(
"%d events written", tree_out.GetEntries())
170 if __name__ ==
'__main__':
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)
192 args = parser.parse_args()
194 logging.getLogger().
setLevel(logging.DEBUG)
196 ROOT.xAOD.ClearTransientTrees()