CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
GeneratorAnalyzer.py
Go to the documentation of this file.
1 import operator
2 import itertools
3 import copy
4 
5 from ROOT import TLorentzVector
6 
7 from PhysicsTools.Heppy.analyzers.core.Analyzer import Analyzer
8 from PhysicsTools.HeppyCore.framework.event import Event
9 from PhysicsTools.HeppyCore.statistics.counter import Counter, Counters
10 from PhysicsTools.Heppy.analyzers.core.AutoHandle import AutoHandle
11 from PhysicsTools.Heppy.physicsobjects.Lepton import Lepton
12 from PhysicsTools.Heppy.physicsobjects.Photon import Photon
13 from PhysicsTools.Heppy.physicsobjects.Electron import Electron
14 from PhysicsTools.Heppy.physicsobjects.Muon import Muon
15 from PhysicsTools.Heppy.physicsobjects.Jet import Jet
16 from PhysicsTools.Heppy.physicsobjects.PhysicsObjects import GenParticle
17 
18 from PhysicsTools.HeppyCore.utils.deltar import deltaR,deltaPhi
21 
22 
24  """Do generator-level analysis of a ttH->leptons decay:
25 
26  Creates in the event:
27  event.genParticles = the gen particles (pruned, as default)
28  event.genHiggsDecayMode = 0 for non-Higgs
29  15 for H -> tau tau
30  23 for H -> Z Z
31  24 for H -> W W
32  xx for H -> xx yy zzz
33 
34  event.gentauleps = [ gen electrons and muons from hard scattering not from tau decays ]
35  event.gentaus = [ gen taus from from hard scattering ]
36  event.genleps = [ gen electrons and muons from hard scattering not from tau decays ]
37  event.genbquarks = [ gen b quarks from top quark decays ]
38  event.genwzquarks = [ gen quarks from hadronic W,Z decays ]
39 
40  If filterHiggsDecays is set to a list of Higgs decay modes,
41  it will filter events that have those decay modes.
42  e.g. [0, 15, 23, 24] will keep data, non-Higgs MC and Higgs decays to (tau, Z, W)
43  but will drop Higgs decays to other particles (e.g. bb).
44 
45  """
46  def __init__(self, cfg_ana, cfg_comp, looperName ):
47  super(GeneratorAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName)
48  self.doPDFWeights = hasattr(self.cfg_ana, "PDFWeights") and len(self.cfg_ana.PDFWeights) > 0
49  if self.doPDFWeights:
50  self.pdfWeightInit = False
51  #---------------------------------------------
52  # DECLARATION OF HANDLES OF GEN LEVEL OBJECTS
53  #---------------------------------------------
54 
55 
56  def declareHandles(self):
57  super(GeneratorAnalyzer, self).declareHandles()
58 
59  #mc information
60  self.mchandles['genParticles'] = AutoHandle( 'prunedGenParticles',
61  'std::vector<reco::GenParticle>' )
62  if self.doPDFWeights:
63  self.mchandles['pdfstuff'] = AutoHandle( 'generator', 'GenEventInfoProduct' )
64 
65  def beginLoop(self):
66  super(GeneratorAnalyzer,self).beginLoop()
67 
68  def fillGenLeptons(self, event, particle, isTau=False, sourceId=25):
69  """Get the gen level light leptons (prompt and/or from tau decays)"""
70 
71  for i in xrange( particle.numberOfDaughters() ):
72  dau = GenParticle(particle.daughter(i))
73  dau.sourceId = sourceId
74  dau.isTau = isTau
75  id = abs(dau.pdgId())
76  moid = abs(dau.mother().pdgId())
77  if id in [11,13]:
78  if isTau: event.gentauleps.append(dau)
79  else: event.genleps.append(dau)
80  elif id == 15:
81  if moid in [22,23,24]:
82  event.gentaus.append(dau)
83  self.fillGenLeptons(event, dau, True, sourceId)
84  elif id in [22,23,24]:
85  self.fillGenLeptons(event, dau, False, sourceId)
86 
87  def fillWZQuarks(self, event, particle, isWZ=False, sourceId=25):
88  """Descend daughters of 'particle', and add quarks from W,Z to event.genwzquarks
89  isWZ is set to True if already processing daughters of W,Z's, to False before it"""
90 
91  for i in xrange( particle.numberOfDaughters() ):
92  dau = GenParticle(particle.daughter(i))
93  dau.sourceId = sourceId
94  id = abs(dau.pdgId())
95  if id <= 5 and isWZ:
96  event.genwzquarks.append(dau)
97  elif id in [22,23,24]:
98  self.fillWZQuarks(event, dau, True, sourceId)
99 
100  def fillTopQuarks(self, event):
101  """Get the b quarks from top decays into event.genbquarks"""
102 
103  event.gentopquarks = [ p for p in event.genParticles if abs(p.pdgId()) == 6 and p.numberOfDaughters() > 0 and abs(p.daughter(0).pdgId()) != 6 ]
104  #if len(event.gentopquarks) != 2:
105  # print "Not two top quarks? \n%s\n" % event.gentopquarks
106 
107  for tq in event.gentopquarks:
108  for i in xrange( tq.numberOfDaughters() ):
109  dau = GenParticle(tq.daughter(i))
110  if abs(dau.pdgId()) == 5:
111  dau.sourceId = 6
112  event.genbquarks.append( dau )
113  elif abs(dau.pdgId()) == 24:
114  self.fillGenLeptons( event, dau, sourceId=6 )
115  self.fillWZQuarks( event, dau, True, sourceId=6 )
116 
117  def makeMCInfo(self, event):
118  event.genParticles = map( GenParticle, self.mchandles['genParticles'].product() )
119 
120  if False:
121  for i,p in enumerate(event.genParticles):
122  print " %5d: pdgId %+5d status %3d pt %6.1f " % (i, p.pdgId(),p.status(),p.pt()),
123  if p.numberOfMothers() > 0:
124  imom, mom = p.motherRef().key(), p.mother()
125  print " | mother %5d pdgId %+5d status %3d pt %6.1f " % (imom, mom.pdgId(),mom.status(),mom.pt()),
126  else:
127  print " | no mother particle ",
128 
129  for j in xrange(min(3, p.numberOfDaughters())):
130  idau, dau = p.daughterRef(j).key(), p.daughter(j)
131  print " | dau[%d] %5d pdgId %+5d status %3d pt %6.1f " % (j,idau,dau.pdgId(),dau.status(),dau.pt()),
132  print ""
133 
134  event.genHiggsBoson = None
135  event.genleps = []
136  event.gentauleps = []
137  event.gentaus = []
138  event.genbquarks = []
139  event.genwzquarks = []
140  event.gentopquarks = []
141 
142  higgsBosons = [ p for p in event.genParticles if (p.pdgId() == 25) and p.numberOfDaughters() > 0 and abs(p.daughter(0).pdgId()) != 25 ]
143 
144  if len(higgsBosons) == 0:
145  event.genHiggsDecayMode = 0
146 
147  ## Matching that can be done also on non-Higgs events
148  ## First, top quarks
149  self.fillTopQuarks( event )
150  self.countBPartons( event )
151 
152  ## Then W,Z,gamma from hard scattering and that don't come from a top and don't rescatter
153  def hasAncestor(particle, filter):
154  for i in xrange(particle.numberOfMothers()):
155  mom = particle.mother(i)
156  if filter(mom) or hasAncestor(mom, filter):
157  return True
158  return False
159  def hasDescendent(particle, filter):
160  for i in xrange(particle.numberOfDaughters()):
161  dau = particle.daughter(i)
162  if filter(dau) or hasDescendent(dau, filter):
163  return True
164  return False
165 
166  bosons = [ gp for gp in event.genParticles if gp.status() > 2 and abs(gp.pdgId()) in [22,23,24] ]
167  for b in bosons:
168  if hasAncestor(b, lambda gp : abs(gp.pdgId()) == 6): continue
169  if hasDescendent(b, lambda gp : abs(gp.pdgId()) in [22,23,24] and gp.status() > 2): continue
170  self.fillGenLeptons(event, b, sourceId=abs(b.pdgId()))
171  self.fillWZQuarks(event, b, isWZ=True, sourceId=abs(b.pdgId()))
172  else:
173  if len(higgsBosons) > 1:
174  print "More than one higgs? \n%s\n" % higgsBosons
175 
176  event.genHiggsBoson = GenParticle(higgsBosons[-1])
177  event.genHiggsDecayMode = abs( event.genHiggsBoson.daughter(0).pdgId() )
178  self.fillTopQuarks( event )
179  self.countBPartons( event )
180  self.fillWZQuarks( event, event.genHiggsBoson )
181  self.fillGenLeptons( event, event.genHiggsBoson, sourceId=25 )
182  if self.cfg_ana.verbose:
183  print "Higgs boson decay mode: ", event.genHiggsDecayMode
184  print "Generator level prompt light leptons:\n", "\n".join(["\t%s" % p for p in event.genleps])
185  print "Generator level light leptons from taus:\n", "\n".join(["\t%s" % p for p in event.gentauleps])
186  print "Generator level prompt tau leptons:\n", "\n".join(["\t%s" % p for p in event.gentaus])
187  print "Generator level b quarks from top:\n", "\n".join(["\t%s" % p for p in event.genbquarks])
188  print "Generator level quarks from W, Z decays:\n", "\n".join(["\t%s" % p for p in event.genwzquarks])
189  # make sure prompt leptons have a non-zero sourceId
190  for p in event.genParticles:
191  if isPromptLepton(p, True, includeTauDecays=True, includeMotherless=False):
192  if getattr(p, 'sourceId', 0) == 0:
193  p.sourceId = 99
194 
195  def countBPartons(self,event):
196  event.allBPartons = [ q for q in event.genParticles if abs(q.pdgId()) == 5 and abs(q.status()) == 2 and abs(q.pt()) > 15 ]
197  event.allBPartons.sort(key = lambda q : q.pt(), reverse = True)
198  event.bPartons = []
199  for q in event.allBPartons:
200  duplicate = False
201  for q2 in event.bPartons:
202  if deltaR(q.eta(),q.phi(),q2.eta(),q2.phi()) < 0.5:
203  duplicate = True
204  continue
205  if not duplicate: event.bPartons.append(q)
206 
207  def initPDFWeights(self):
208  from ROOT import PdfWeightProducerTool
209  self.pdfWeightInit = True
210  self.pdfWeightTool = PdfWeightProducerTool()
211  for pdf in self.cfg_ana.PDFWeights:
212  self.pdfWeightTool.addPdfSet(pdf+".LHgrid")
213  self.pdfWeightTool.beginJob()
214 
215  def makePDFWeights(self, event):
216  if not self.pdfWeightInit: self.initPDFWeights()
217  self.pdfWeightTool.processEvent(self.mchandles['pdfstuff'].product())
218  event.pdfWeights = {}
219  for pdf in self.cfg_ana.PDFWeights:
220  ws = self.pdfWeightTool.getWeights(pdf+".LHgrid")
221  event.pdfWeights[pdf] = [w for w in ws]
222  #print "Produced %d weights for %s: %s" % (len(ws),pdf,event.pdfWeights[pdf])
223 
224  def process(self, iEvent, event):
225  self.readCollections( iEvent )
226 
227  ## creating a "sub-event" for this analyzer
228  #myEvent = Event(event.iEv)
229  #setattr(event, self.name, myEvent)
230  #event = myEvent
231 
232  # if not MC, nothing to do
233  if not self.cfg_comp.isMC:
234  return True
235 
236  # do MC level analysis
237  self.makeMCInfo(event)
238 
239  # if MC and filtering on the Higgs decay mode,
240  # them do filter events
241  if self.cfg_ana.filterHiggsDecays:
242  if event.genHiggsDecayMode not in self.cfg_ana.filterHiggsDecays:
243  return False
244 
245  # do PDF weights, if requested
246  if self.doPDFWeights:
247  self.makePDFWeights(event)
248  return True
249 
250 setattr(GeneratorAnalyzer,"defaultConfig",cfg.Analyzer(
251  class_object=GeneratorAnalyzer,
252  filterHiggsDecays = False,
253  verbose = False,
254  PDFWeights = []
255  )
256 )
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
T min(T a, T b)
Definition: MathUtil.h:58
double deltaR(double eta1, double eta2, double phi1, double phi2)
Definition: TreeUtility.cc:17
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
bool hasAncestor(const reco::GenParticle *particle, int pdgId, int status)
does the particle have an ancestor with this pdgId and this status?
list key
Definition: combine.py:13
def isPromptLepton
Definition: genutils.py:49