1 |
#! /usr/bin/env python2
|
2 |
# -*- coding: utf-8 -*-
|
3 |
from treeFunctions import *
|
4 |
import Styles
|
5 |
Styles.tdrStyle2D()
|
6 |
import numpy
|
7 |
import ROOT
|
8 |
import argparse
|
9 |
import ConfigParser
|
10 |
import sys
|
11 |
|
12 |
def deltaPhi( phi1, phi2):
|
13 |
"""Computes delta phi.
|
14 |
Due to the zylindrical form of CMS, it has be be corrected by a diffenence
|
15 |
of 2pi.
|
16 |
"""
|
17 |
import math
|
18 |
result = phi1 - phi2
|
19 |
while result > math.pi:
|
20 |
result -= 2*math.pi
|
21 |
while result <= -math.pi:
|
22 |
result += 2*math.pi
|
23 |
return result
|
24 |
|
25 |
def deltaR( object1, object2 ):
|
26 |
"""Compute delta R of two objects.
|
27 |
Both objects must have eta and phi as member variables.
|
28 |
"""
|
29 |
import math
|
30 |
return math.sqrt( (object1.eta-object2.eta)**2 + (deltaPhi(object1.phi,object2.phi))**2 )
|
31 |
|
32 |
def gammaSelectionClone( tree, newTreeName, weight, type_="tree::Photon", name="photon" ):
|
33 |
"""Clones a tree and get access to photon vector"""
|
34 |
newTree = tree.CloneTree(0)
|
35 |
newTree.SetName( newTreeName )
|
36 |
photons = ROOT.std.vector(type_)()
|
37 |
newTree.SetBranchAddress( name, photons )
|
38 |
newTree.SetBranchAddress("weight", weight )
|
39 |
return newTree, photons, weight
|
40 |
|
41 |
def histoDefinition():
|
42 |
"""All histograms are defined here and put into an directory."""
|
43 |
from random import randint
|
44 |
histos = {}
|
45 |
histos["dEtadPhiLarge"] = ROOT.TH2F( "%x"%randint(0,100000), ";#Delta#eta;#Delta#phi", 100, -4, 4, 100, -3.3, 3.3 )
|
46 |
histos["dEtadPhiSmall"] = ROOT.TH2F( "%x"%randint(0,1000000), ";|#Delta#eta|;|#Delta#phi|", 100, 0, .012, 100, 0, .1 )
|
47 |
histos["dEtadPhiSmallPhoton"] = ROOT.TH2F( "%x"%randint(0,1000000), ";|#Delta#eta|;|#Delta#phi|", 100, 0, .012, 100, 0, .1 )
|
48 |
histos["dEtadPhiSmallElectron"] = ROOT.TH2F( "%x"%randint(0,1000000), ";|#Delta#eta|;|#Delta#phi|", 100, 0, .012, 100, 0, .1 )
|
49 |
histos["nGenEnRec"] = ROOT.TH2F( "%x"%randint(0,10000000), ";generated e;reco EM-Objects", 5, -0.5, 4.5, 5, -0.5, 4.5 )
|
50 |
histos["dPtdR"] = ROOT.TH2F( "%x"%randint(0,10000000), ";|(p_{T}-p_{T gen} )/ p_{T gen}|;#DeltaR", 100, 0, 1, 100, 0, .5 )
|
51 |
return histos
|
52 |
|
53 |
def draw_histogram_dict( histograms, suffix="new" ):
|
54 |
"""Draw all histograms in this directory and save it as pdf."""
|
55 |
can = ROOT.TCanvas()
|
56 |
can.cd()
|
57 |
dataset = ROOT.TPaveText(.4,.9,.6,.98, "ndc")
|
58 |
dataset.SetFillColor(0)
|
59 |
dataset.SetBorderSize(0)
|
60 |
dataset.AddText( suffix )
|
61 |
for name, histo in histograms.iteritems():
|
62 |
name = name.replace(".","")
|
63 |
histo.Draw("colz")
|
64 |
dataset.Draw()
|
65 |
can.SaveAs("plots/%s_%s.pdf"%(name,suffix))
|
66 |
|
67 |
def generalMatching( objects1, objects2, hist):
|
68 |
"""Matches for each object in objects1 an object in objects2.
|
69 |
'hists' is a dict containing ROOT.TH* objects which will be filled and returned.
|
70 |
The gen information will be storend in first list and returned.
|
71 |
"""
|
72 |
hist["nGenEnRec"].Fill( objects1.size(), objects2.size() )
|
73 |
for o1 in objects1:
|
74 |
match = False
|
75 |
minDeltaPt = sys.maxint
|
76 |
minIndex = -1
|
77 |
for i, o2 in enumerate(objects2):
|
78 |
DeltaEta = o1.eta - o2.eta
|
79 |
DeltaPhi = deltaPhi( o1.phi, o2.phi)
|
80 |
absDeltaEta = abs( DeltaEta )
|
81 |
absDeltaPhi = abs( DeltaPhi )
|
82 |
absDeltaPt = 2*abs( o1.pt - o2.pt ) / ( o1.pt + o2.pt )
|
83 |
hist["dEtadPhiLarge"].Fill( DeltaEta, DeltaPhi )
|
84 |
hist["dEtadPhiSmall"].Fill( absDeltaEta, absDeltaPhi )
|
85 |
if hasattr( o1, "pixelseed" ):
|
86 |
if o1.pixelseed:
|
87 |
hist["dEtadPhiSmallElectron"].Fill( absDeltaEta, absDeltaPhi )
|
88 |
else:
|
89 |
hist["dEtadPhiSmallPhoton"].Fill( absDeltaEta, absDeltaPhi )
|
90 |
|
91 |
if absDeltaEta < .008 and absDeltaPhi < .08 and absDeltaPt < .1:
|
92 |
match = True
|
93 |
if absDeltaPt < minDeltaPt:
|
94 |
minDeltaPt = absDeltaPt
|
95 |
minIndex = i
|
96 |
|
97 |
if match:
|
98 |
if hasattr( o1, "genInformation" ):
|
99 |
o1.genInformation = 1
|
100 |
else: # use phi variable for gen information. TODO: fix that
|
101 |
# only fill gen matching for photons matching a gen electrons.
|
102 |
# Electrons are not needed in fake rate
|
103 |
if not objects2[minIndex].pixelseed:
|
104 |
o1.phi = 5
|
105 |
return objects1, hist
|
106 |
|
107 |
def splitCandidates( inputFileName, shortName, nExpected, processNEvents=-1, genMatching=False ):
|
108 |
print "Processing file {}".format(inputFileName)
|
109 |
|
110 |
#genMatching = not shortName in ["WJets", "DY", "TTJets"]
|
111 |
if genMatching:
|
112 |
print "Match generated objects"
|
113 |
|
114 |
tree = readTree( inputFileName )
|
115 |
eventHisto = readHisto( inputFileName )
|
116 |
if processNEvents == -1:
|
117 |
processNEvents = eventHisto.GetBinContent(1)
|
118 |
|
119 |
weight = numpy.zeros(1, dtype=float)
|
120 |
photonTree, photons, weight = gammaSelectionClone( tree, "photonTree", weight )
|
121 |
photonJetTree, photonJets, weight = gammaSelectionClone( tree, "photonJetTree", weight )
|
122 |
photonElectronTree, photonElectrons, weight = gammaSelectionClone( tree, "photonElectronTree", weight )
|
123 |
if genMatching:
|
124 |
genElectronTree, genElectrons, weight = gammaSelectionClone( tree, "genElectronTree", weight, "tree::Particle","genElectron" )
|
125 |
histograms = histoDefinition()
|
126 |
|
127 |
emObjects = ROOT.std.vector("tree::Photon")()
|
128 |
|
129 |
for event in tree:
|
130 |
if not event.GetReadEntry()%100000:
|
131 |
print '{0}%\r'.format(100*event.GetReadEntry()/event.GetEntries())
|
132 |
|
133 |
if event.GetReadEntry() > processNEvents:
|
134 |
break
|
135 |
|
136 |
weight[0] = event.weight * nExpected / processNEvents
|
137 |
emObjects.clear()
|
138 |
photons.clear()
|
139 |
photonElectrons.clear()
|
140 |
photonJets.clear()
|
141 |
if genMatching:
|
142 |
genElectrons.clear()
|
143 |
|
144 |
for gamma in event.photon:
|
145 |
|
146 |
# cuts for every object to rject spikes
|
147 |
if gamma.r9 < 1 \
|
148 |
and gamma.sigmaIetaIeta > 0.001 \
|
149 |
and abs(gamma.eta) < 1.4442 \
|
150 |
and gamma.pt > 20:
|
151 |
|
152 |
# look for gamma and electrons
|
153 |
if gamma.hadTowOverEm < 0.05 \
|
154 |
and gamma.sigmaIetaIeta < 0.012 \
|
155 |
and gamma.chargedIso < 2.6 \
|
156 |
and gamma.neutralIso < 3.5 + 0.04*gamma.pt \
|
157 |
and gamma.photonIso < 1.3 + 0.005*gamma.pt:
|
158 |
emObjects.push_back( gamma )
|
159 |
|
160 |
# QCD fake object definition
|
161 |
if gamma.ptJet > 75 \
|
162 |
and gamma.hadTowOverEm < 0.05 \
|
163 |
and gamma.sigmaIetaIeta < 0.014 \
|
164 |
and gamma.chargedIso < 15 \
|
165 |
and gamma.neutralIso < 3.5 + 0.04*gamma.pt \
|
166 |
and gamma.photonIso < 1.3 + 0.005*gamma.pt \
|
167 |
and not gamma.pixelseed \
|
168 |
and ( gamma.sigmaIetaIeta>=0.012 or gamma.chargedIso>=2.6):
|
169 |
photonJets.push_back( gamma )
|
170 |
|
171 |
if genMatching:
|
172 |
emObjects, histograms = generalMatching( emObjects, event.genElectron, histograms )
|
173 |
for genE in event.genElectron:
|
174 |
if abs(genE.eta) < 1.4442:
|
175 |
genElectrons.push_back( genE )
|
176 |
genElectrons, histograms = generalMatching( genElectrons, emObjects, histograms )
|
177 |
|
178 |
for emObject in emObjects:
|
179 |
if emObject.pixelseed:
|
180 |
photonElectrons.push_back( emObject )
|
181 |
else:
|
182 |
photons.push_back( emObject )
|
183 |
|
184 |
if photons.size() > 0:
|
185 |
photonTree.Fill()
|
186 |
else:
|
187 |
if photonElectrons.size() > 0:
|
188 |
photonElectronTree.Fill()
|
189 |
if photonJets.size() > 0:
|
190 |
photonJetTree.Fill()
|
191 |
if genMatching and genElectrons.size() > 0:
|
192 |
genElectronTree.Fill()
|
193 |
|
194 |
|
195 |
outputFileName = "slim"+inputFileName
|
196 |
f = ROOT.TFile( outputFileName, "recreate" )
|
197 |
f.cd()
|
198 |
photonTree.Write()
|
199 |
photonJetTree.Write()
|
200 |
photonElectronTree.Write()
|
201 |
if genMatching:
|
202 |
genElectronTree.Write()
|
203 |
draw_histogram_dict( histograms, shortName )
|
204 |
f.Close()
|
205 |
|
206 |
|
207 |
if __name__ == "__main__":
|
208 |
# include knowledge about objects saved in the tree
|
209 |
ROOT.gSystem.Load("libTreeObjects.so")
|
210 |
|
211 |
arguments = argparse.ArgumentParser( description="Slim tree" )
|
212 |
arguments.add_argument("--input", default=["WJets_V01.12_tree.root"], nargs="+" )
|
213 |
arguments.add_argument("--test", action="store_true" )
|
214 |
arguments.add_argument("--genMatching", action="store_true" )
|
215 |
opts = arguments.parse_args()
|
216 |
|
217 |
processNEvents = 10000 if opts.test else -1
|
218 |
|
219 |
|
220 |
# disable open canvas
|
221 |
ROOT.gROOT.SetBatch()
|
222 |
|
223 |
datasetConfigName = "dataset.cfg"
|
224 |
datasetConf = ConfigParser.SafeConfigParser()
|
225 |
datasetConf.read( datasetConfigName )
|
226 |
|
227 |
integratedLumi = 19300 #pb
|
228 |
|
229 |
for inName in opts.input:
|
230 |
shortName = None
|
231 |
for configName in datasetConf.sections():
|
232 |
if inName.count( configName ):
|
233 |
shortName = configName
|
234 |
crosssection = datasetConf.getfloat( configName, "crosssection" )
|
235 |
if not shortName:
|
236 |
print "No configuration for input file {} defined in '{}'".format(
|
237 |
inName, datasetConfigName )
|
238 |
continue
|
239 |
|
240 |
# N = L * sigma
|
241 |
nExpected = integratedLumi * crosssection
|
242 |
|
243 |
splitCandidates( inName, shortName, nExpected, processNEvents, opts.genMatching )
|
244 |
|