CMS 3D CMS Logo

ntupleDataFormat.py
Go to the documentation of this file.
1 from builtins import range
2 import math
3 import collections
4 
5 import ROOT
6 
9 
11  """Adaptor class representing a collection of objects.
12 
13  Concrete collection classes should inherit from this class.
14 
15  """
16  def __init__(self, tree, sizeBranch, objclass):
17  """Constructor.
18 
19  Arguments:
20  tree -- TTree object
21  sizeBranch -- Name of the branch to be used in size()
22  objclass -- Class to be used for the objects in __getitem__()
23  """
24  super(_Collection, self).__init__()
25  self._tree = tree
26  self._sizeBranch = sizeBranch
27  self._objclass = objclass
28 
29  def size(self):
30  """Number of objects in the collection."""
31  return int(getattr(self._tree, self._sizeBranch).size())
32 
33  def __len__(self):
34  """Number of objects in the collection."""
35  return self.size()
36 
37  def __getitem__(self, index):
38  """Get object 'index' in the collection."""
39  return self._objclass(self._tree, index)
40 
41  def __iter__(self):
42  """Returns generator for the objects."""
43  for index in range(self.size()):
44  yield self._objclass(self._tree, index)
45 
46 class _Object(object):
47  """Adaptor class representing a single object in a collection.
48 
49  The member variables of the object are obtained from the branches
50  with common prefix and a given index.
51 
52  Concrete object classes should inherit from this class.
53  """
54  def __init__(self, tree, index, prefix):
55  """Constructor.
56 
57  Arguments:
58  tree -- TTree object
59  index -- Index for this object
60  prefix -- Prefix of the branchs
61  """
62  super(_Object, self).__init__()
63  self._tree = tree
64  self._index = index
65  self._prefix = prefix
66 
67  def __getattr__(self, attr):
68  """Return object member variable.
69 
70  'attr' is translated as a branch in the TTree (<prefix>_<attr>).
71  """
72  self._checkIsValid()
73  val = getattr(self._tree, self._prefix+"_"+attr)[self._index]
74  return lambda: val
75 
76  def _checkIsValid(self):
77  """Raise an exception if the object index is not valid."""
78  if not self.isValid():
79  raise Exception("%s is not valid" % self.__class__.__name__)
80 
81  def isValid(self):
82  """Check if object index is valid."""
83  return self._index != -1
84 
85  def index(self):
86  """Return object index."""
87  return self._index
88 
90  """Adaptor class for objects containgin DetId (hits)."""
91  def __init__(self):
92  super(_DetIdStrAdaptor, self).__init__()
93 
94  def layerStr(self):
95  """Returns a string describing the layer of the hit."""
96  self._checkIsValid()
97  get = lambda name: getattr(self._tree, self._prefix+"_"+name)[self._index]
98  subdet = get("subdet")
99  side = ""
100  isPhase2OTBarrel = (subdet == SubDet.TOB and hasattr(self._tree, self._prefix+"_isLower"))
101  if subdet in [SubDet.FPix, SubDet.TID, SubDet.TEC] or isPhase2OTBarrel:
102  sideNum = get("side")
103  if sideNum == 1:
104  side = "-"
105  elif sideNum == 2:
106  side = "+"
107  elif isPhase2OTBarrel and sideNum == 3:
108  side = ""
109  else:
110  side = "?"
111  return "%s%d%s" % (SubDet.toString(subdet),
112  getattr(self._tree, self._prefix+"_layer")[self._index],
113  side)
114 
115  def detIdStr(self):
116  """Returns a string describing the DetId fields."""
117  self._checkIsValid
118  get = lambda name: getattr(self._tree, self._prefix+"_"+name)[self._index]
119  isPhase2 = hasattr(self._tree, self._prefix+"_isLower")
120  def stereo():
121  if isPhase2:
122  if get("isLower"):
123  return " isLower"
124  if get("isUpper"):
125  return " isUpper"
126  if get("isStack"):
127  return " isStack"
128  else:
129  if get("isStereo"):
130  return " isStereo"
131  if get("isRPhi"):
132  return " isRPhi"
133  if get("isGlued"):
134  return " isGlued"
135  return ""
136 
137  subdet = get("subdet")
138  if subdet == SubDet.BPix:
139  return "ladder {} module {}".format(get("ladder"), get("module"))
140  if subdet == SubDet.FPix:
141  return "blade {} panel {} module {}".format(get("blade"), get("panel"), get("module"))
142  if subdet == SubDet.TIB:
143  return "side {} order {} string {} module {}{}".format(get("side"), get("order"), get("string"), get("module"), stereo())
144  if subdet == SubDet.TID:
145  return "ring {} order {} module {}{}".format(get("ring"), get("order"), get("module"), stereo())
146  if subdet == SubDet.TOB:
147  if isPhase2:
148  return "rod {} module {}{}".format(get("rod"), get("module"), stereo())
149  else:
150  return "side {} rod {} module {}{}".format(get("side"), get("rod"), get("module"), stereo())
151  if subdet == SubDet.TEC:
152  return "order {} petal {} ring {} module {}{}".format(get("order"), get("petalNumber"), get("ring"), get("module"), stereo())
153  raise Exception("Unknown subdet %d" % subdet)
154 
156  """Adaptor class for pixel/strip hit objects."""
157  def __init__(self, tree, index, prefix):
158  """Constructor.
159 
160  Arguments:
161  tree -- TTree object
162  index -- Index for this object
163  prefix -- Prefix of the branchs
164  """
165  """Constructor
166  """
167  super(_HitObject, self).__init__(tree, index, prefix)
168 
169  def ntracks(self):
170  """Returns number of tracks containing this hit."""
171  self._checkIsValid()
172  return getattr(self._tree, self._prefix+"_trkIdx")[self._index].size()
173 
174  def tracks(self):
175  """Returns generator for tracks containing this hit.
176 
177  The generator returns Track objects
178  """
179  self._checkIsValid()
180  for itrack in getattr(self._tree, self._prefix+"_trkIdx")[self._index]:
181  yield Track(self._tree, itrack)
182 
183  def nseeds(self):
184  """Returns number of seeds containing this hit."""
185  self._checkIsValid()
186  return getattr(self._tree, self._prefix+"_seeIdx")[self._index].size()
187 
188  def seeds(self):
189  """Returns generator for tracks containing this hit.
190 
191  The generator returns Seed objects
192  """
193  self._checkIsValid()
194  for iseed in getattr(self._tree, self._prefix+"_seeIdx")[self._index]:
195  yield Seed(self._tree, iseed)
196 
197  def r(self):
198  return math.sqrt(self.x()**2 + self.y()**2)
199 
200  def r3D(self):
201  return math.sqrt(self.x()**2 + self.y()**2 + self.z()**2)
202 
204  """Adaptor class for objects containing hits (e.g. tracks)"""
205  def __init__(self):
206  super(_RecoHitAdaptor, self).__init__()
207 
208  def _hits(self):
209  """Internal method to generate pairs of hit index and type."""
210  for ihit, hitType in zip(self.hitIdx(), self.hitType()):
211  yield (ihit, hitType)
212 
213  def hits(self):
214  """Returns generator for hits.
215 
216  Generator returns PixelHit/StripHit/GluedHit/Phase2OT depending on the
217  hit type.
218 
219  """
220  for ihit, hitType in self._hits():
221  if hitType == 0:
222  yield PixelHit(self._tree, ihit)
223  elif hitType == 1:
224  yield StripHit(self._tree, ihit)
225  elif hitType == 2:
226  yield GluedHit(self._tree, ihit)
227  elif hitType == 3:
228  yield InvalidHit(self._tree, ihit)
229  elif hitType == 4:
230  yield Phase2OTHit(self._tree, ihit)
231  else:
232  raise Exception("Unknown hit type %d" % hitType)
233 
234  def pixelHits(self):
235  """Returns generator for pixel hits."""
236  self._checkIsValid()
237  for ihit, hitType in self._hits():
238  if hitType != 0:
239  continue
240  yield PixelHit(self._tree, ihit)
241 
242  def stripHits(self):
243  """Returns generator for strip hits."""
244  self._checkIsValid()
245  for ihit, hitType in self._hits():
246  if hitType != 1:
247  continue
248  yield StripHit(self._tree, ihit)
249 
250  def gluedHits(self):
251  """Returns generator for matched strip hits."""
252  self._checkIsValid()
253  for ihit, hitType in self._hits():
254  if hitType != 2:
255  continue
256  yield GluedHit(self._tree, ihit)
257 
258  def invalidHits(self):
259  """Returns generator for invalid hits."""
260  self._checkIsValid()
261  for ihit, hitType in self._hits():
262  if hitType != 3:
263  continue
264  yield InvalidHit(self._tree, ihit)
265 
266  def phase2OTHits(self):
267  """Returns generator for phase2 outer tracker hits."""
268  self._checkIsValid()
269  for ihit, hitType in self._hits():
270  if hitType != 4:
271  continue
272  yield Phase2OTHit(self._tree, ihit)
273 
275  """Adaptor class for objects containing or matched to SimHits (e.g. reco hits)."""
276  def __init__(self):
277  super(_SimHitMatchAdaptor, self).__init__()
278 
279  def _nMatchedSimHits(self):
280  """Internal method to get the number of matched SimHits."""
281  return getattr(self._tree, self._prefix+"_simHitIdx")[self._index].size()
282 
283  def nMatchedSimHits(self):
284  """Returns the number of matched SimHits."""
285  self._checkIsValid()
286  return self._nMatchedSimHits()
287 
289  """Returns a generator for matched SimHits.
290 
291  The generator returns SimHitMatchInfo objects.
292  """
293  self._checkIsValid()
294  for imatch in range(self._nMatchedSimHits()):
295  yield SimHitMatchInfo(self._tree, self._index, imatch, self._prefix)
296 
298  """Adaptor class for objects matched to TrackingParticles."""
299  def __init__(self):
300  super(_TrackingParticleMatchAdaptor, self).__init__()
301 
303  """Internal method to get the number of matched TrackingParticles."""
304  return getattr(self._tree, self._prefix+"_simTrkIdx")[self._index].size()
305 
307  """Returns the number of matched TrackingParticles."""
308  self._checkIsValid()
309  return self._nMatchedTrackingParticles()
310 
312  """Returns a generator for matched TrackingParticles.
313 
314  The generator returns TrackingParticleMatchInfo objects.
315 
316  """
317  self._checkIsValid()
318  for imatch in range(self._nMatchedTrackingParticles()):
319  yield TrackingParticleMatchInfo(self._tree, self._index, imatch, self._prefix)
320 
322  """Returns best-matching TrackingParticle, even for fake tracks, or None if there is no best-matching TrackingParticle.
323 
324  Best-matching is defined as the one with largest number of
325  hits matched to the hits of a track (>= 3). If there are many
326  fulfilling the same number of hits, the one inducing the
327  innermost hit of the track is chosen.
328  """
329  idx = self.bestSimTrkIdx()
330  if idx < 0:
331  return None
332  return TrackingParticle(self._tree, idx)
333 
335  """Fraction of shared hits with reco hits as denominator for best-matching TrackingParticle."""
336  return self.bestSimTrkShareFrac()
337 
339  """Fraction of shared hits with TrackingParticle::numberOfTrackerHits() as denominator for best-matching TrackingParticle."""
340  return self.bestSimTrkShareFracSimDenom()
341 
343  """Fraction of shared hits with number of reco clusters associated to a TrackingParticle as denominator for best-matching TrackingParticle."""
344  return self.bestSimTrkShareFracSimClusterDenom()
345 
347  """Normalized chi2 calculated from track parameters+covariance matrix and TrackingParticle parameters for best-matching TrackingParticle."""
348  return self.bestSimTrkNChi2()
349 
351  """Returns best-matching TrackingParticle, even for fake tracks, or None if there is no best-matching TrackingParticle.
352 
353  Best-matching is defined as the one with largest number of
354  hits matched to the hits of a track (>= 3) starting from the
355  beginning of the track. If there are many fulfilling the same
356  number of hits, "a first TP" is chosen (a bit arbitrary, but
357  should be rare".
358  """
359  idx = self.bestFromFirstHitSimTrkIdx()
360  if idx < 0:
361  return None
362  return TrackingParticle(self._tree, idx)
363 
365  """Fraction of shared hits with reco hits as denominator for best-matching TrackingParticle starting from the first hit of a track."""
366  return self.bestFromFirstHitSimTrkShareFrac()
367 
369  """Fraction of shared hits with TrackingParticle::numberOfTrackerHits() as denominator for best-matching TrackingParticle starting from the first hit of a track."""
370  return self.bestFromFirstHitSimTrkShareFracSimDenom()
371 
373  """Fraction of shared hits with number of reco clusters associated to a TrackingParticle as denominator for best-matching TrackingParticle starting from the first hit of a track."""
374  return self.bestFromFirstHitSimTrkShareFracSimClusterDenom()
375 
377  """Normalized chi2 calculated from track parameters+covariance matrix and TrackingParticle parameters for best-matching TrackingParticle starting from the first hit of a track."""
378  return self.bestFromFirstHitSimTrkNChi2()
379 
380 
382  """Class abstracting the whole ntuple/TTree.
383 
384  Main benefit is to provide nice interface for
385  - iterating over events
386  - querying whether hit/seed information exists
387 
388  Note that to iteratate over the evets with zip(), you should use
389  itertools.izip() instead.
390  """
391  def __init__(self, fileName, tree="trackingNtuple/tree"):
392  """Constructor.
393 
394  Arguments:
395  fileName -- String for path to the ROOT file
396  tree -- Name of the TTree object inside the ROOT file (default: 'trackingNtuple/tree')
397  """
398  super(TrackingNtuple, self).__init__()
399  self._file = ROOT.TFile.Open(fileName)
400  self._tree = self._file.Get(tree)
401  self._entries = self._tree.GetEntriesFast()
402 
403  def file(self):
404  return self._file
405 
406  def tree(self):
407  return self._tree
408 
409  def nevents(self):
410  return self._entries
411 
412  def hasHits(self):
413  """Returns true if the ntuple has hit information."""
414  return hasattr(self._tree, "pix_isBarrel")
415 
416  def hasSeeds(self):
417  """Returns true if the ntuple has seed information."""
418  return hasattr(self._tree, "see_fitok")
419 
420  def __iter__(self):
421  """Returns generator for iterating over TTree entries (events)
422 
423  Generator returns Event objects.
424 
425  """
426  for jentry in range(self._entries):
427  # get the next tree in the chain and verify
428  ientry = self._tree.LoadTree( jentry )
429  if ientry < 0: break
430  # copy next entry into memory and verify
431  nb = self._tree.GetEntry( jentry )
432  if nb <= 0: continue
433 
434  yield Event(self._tree, jentry)
435 
436  def getEvent(self, index):
437  """Returns Event for a given index"""
438  ientry = self._tree.LoadTree(index)
439  if ientry < 0: return None
440  nb = self._tree.GetEntry(ientry) # ientry or jentry?
441  if nb <= 0: None
442 
443  return Event(self._tree, ientry) # ientry of jentry?
444 
445 
446 class Event(object):
447  """Class abstracting a single event.
448 
449  Main benefit is to provide nice interface to get various objects
450  or collections of objects.
451  """
452  def __init__(self, tree, entry):
453  """Constructor.
454 
455  Arguments:
456  tree -- TTree object
457  entry -- Entry number in the tree
458  """
459  super(Event, self).__init__()
460  self._tree = tree
461  self._entry = entry
462 
463  def entry(self):
464  return self._entry
465 
466  def event(self):
467  """Returns event number."""
468  return self._tree.event
469 
470  def lumi(self):
471  """Returns lumisection number."""
472  return self._tree.lumi
473 
474  def run(self):
475  """Returns run number."""
476  return self._tree.run
477 
478  def eventId(self):
479  """Returns (run, lumi, event) tuple."""
480  return (self._tree.run, self._tree.lumi, self._tree.event)
481 
482  def eventIdStr(self):
483  """Returns 'run:lumi:event' string."""
484  return "%d:%d:%d" % self.eventId()
485 
486  def beamspot(self):
487  """Returns BeamSpot object."""
488  return BeamSpot(self._tree)
489 
490  def tracks(self):
491  """Returns Tracks object."""
492  return Tracks(self._tree)
493 
494  def pixelHits(self):
495  """Returns PixelHits object."""
496  return PixelHits(self._tree)
497 
498  def stripHits(self):
499  """Returns StripHits object."""
500  return StripHits(self._tree)
501 
502  def gluedHits(self):
503  """Returns GluedHits object."""
504  return GluedHits(self._tree)
505 
506  def phase2OTHits(self):
507  """Returns Phase2OTHits object."""
508  return Phase2OTHits(self._tree)
509 
510  def seeds(self):
511  """Returns Seeds object."""
512  return Seeds(self._tree)
513 
514  def trackingParticles(self):
515  """Returns TrackingParticles object."""
516  return TrackingParticles(self._tree)
517 
518  def vertices(self):
519  """Returns Vertices object."""
520  return Vertices(self._tree)
521 
522  def trackingVertices(self):
523  """Returns TrackingVertices object."""
524  return TrackingVertices(self._tree)
525 
526 
528  """Class representing the beam spot."""
529  def __init__(self, tree):
530  """Constructor.
531 
532  Arguments:
533  tree -- TTree object
534  """
535  super(BeamSpot, self).__init__()
536  self._tree = tree
537  self._prefix = "bsp"
538 
539  def __getattr__(self, attr):
540  """Return object member variable.
541 
542  'attr' is translated as a branch in the TTree (bsp_<attr>).
543  """
544  val = getattr(self._tree, self._prefix+"_"+attr)
545  return lambda: val
546 
547 
549  """Class representing a match to a SimHit.
550 
551  The point of this class is to provide, in addition to the matched
552  SimHit, also other information about the match (e.g. fraction of
553  charge from this SimHit).
554  """
555  def __init__(self, tree, index, shindex, prefix):
556  """Constructor.
557 
558  Arguments:
559  tree -- TTree object
560  index -- Index of the hit matched to SimHit
561  shindex -- Index of the SimHit match (second index in _simHitIdx branch)
562  prefix -- String for prefix of the object (track/seed/hit) matched to TrackingParticle
563  """
564  super(SimHitMatchInfo, self).__init__(tree, index, prefix)
565  self._shindex = shindex
566 
567  def __getattr__(self, attr):
568  """Custom __getattr__ because of the second index needed to access the branch."""
569  val = super(SimHitMatchInfo, self).__getattr__(attr)()[self._shindex]
570  return lambda: val
571 
572  def simHit(self):
573  """Returns matched SimHit."""
574  self._checkIsValid()
575  return SimHit(self._tree, getattr(self._tree, self._prefix+"_simHitIdx")[self._index][self._shindex])
576 
578 
579  """Class representing a match to a TrackingParticle.
580 
581  The point of this class is to provide, in addition to the matched
582  TrackingParticle, also other information about the match (e.g.
583  shared hit fraction for tracks/seeds).
584  """
585  def __init__(self, tree, index, tpindex, prefix):
586  """Constructor.
587 
588  Arguments:
589  tree -- TTree object
590  index -- Index of the object (track/seed) matched to TrackingParticle
591  tpindex -- Index of the TrackingParticle match (second index in _simTrkIdx branch)
592  prefix -- String for prefix of the object (track/seed) matched to TrackingParticle
593  """
594  super(TrackingParticleMatchInfo, self).__init__(tree, index, prefix)
595  self._tpindex = tpindex
596 
597  def __getattr__(self, attr):
598  """Custom __getattr__ because of the second index needed to access the branch.
599 
600  Note that when mapping the 'attr' to a branch, a 'simTrk' is
601  prepended and the first letter of 'attr' is turned to upper
602  case.
603  """
604  val = super(TrackingParticleMatchInfo, self).__getattr__("simTrk"+attr[0].upper()+attr[1:])()[self._tpindex]
605  return lambda: val
606 
607  def trackingParticle(self):
608  """Returns matched TrackingParticle."""
609  return TrackingParticle(self._tree, self.idx())
610 
612  """Class representing a match to a Track.
613 
614  The point of this class is to provide, in addition to the matched
615  Track, also other information about the match (e.g. shared hit fraction.
616  """
617  def __init__(self, tree, index, trkindex, prefix):
618  """Constructor.
619 
620  Arguments:
621  tree -- TTree object
622  index -- Index of the object (TrackingParticle) matched to track
623  trkindex -- Index of the track match (second index in _trkIdx branch)
624  prefix -- String for prefix of the object (TrackingParticle) matched to track
625  """
626  super(TrackMatchInfo, self).__init__(tree, index, prefix)
627  self._trkindex = trkindex
628 
629  def __getattr__(self, attr):
630  """Custom __getattr__ because of the second index needed to access the branch.
631 
632  Note that when mapping the 'attr' to a branch, a 'trk' is
633  prepended and the first letter of 'attr' is turned to upper
634  case.
635  """
636  val = super(TrackMatchInfo, self).__getattr__("trk"+attr[0].upper()+attr[1:])()[self._trkindex]
637  return lambda: val
638 
639  def track(self):
640  """Returns matched Track."""
641  return Track(self._tree, self.idx())
642 
644  """Class representing a match to a Seed.
645 
646  The point of this class is to provide an interface compatible with
647  all other "MatchInfo" classes
648 
649  """
650  def __init__(self, tree, index, seedindex, prefix):
651  """Constructor.
652 
653  Arguments:
654  tree -- TTree object
655  index -- Index of the object (TrackingParticle) matched to seed
656  seedindex -- Index of the seed match (second index in _trkIdx branch)
657  prefix -- String for prefix of the object (TrackingParticle) matched to seed
658  """
659  super(SeedMatchInfo, self).__init__(tree, index, prefix)
660  self._seedindex = seedindex
661 
662  def seed(self):
663  """Returns matched Seed."""
664  self._checkIsValid()
665  return Seed(self._tree, getattr(self._tree, self._prefix+"_seedIdx")[self._index][self._seedindex])
666 
667 
669  """Class presenting a track."""
670  def __init__(self, tree, index):
671  """Constructor.
672 
673  Arguments:
674  tree -- TTree object
675  index -- Index of the track
676  """
677  super(Track, self).__init__(tree, index, "trk")
678 
679  def seed(self):
680  """Returns Seed of the track."""
681  self._checkIsValid()
682  return Seed(self._tree, self._tree.trk_seedIdx[self._index])
683 
684  def vertex(self):
685  """Returns Vertex that used this track in its fit."""
686  self._checkIsValid()
687  return Vertex(self._tree, self._tree.trk_vtxIdx[self._index])
688 
689  def ptPull(self):
690  tp = self.bestMatchingTrackingParticle()
691  if tp is None:
692  return None
693  return (self.pt() - tp.pca_pt())/self.ptErr()
694 
695  def thetaPull(self):
696  tp = self.bestMatchingTrackingParticle()
697  if tp is None:
698  return None
699  return (getattr(self, "lambda")() - tp.pca_lambda())/self.lambdaErr() # as in MTV
700 
701  def phiPull(self):
702  tp = self.bestMatchingTrackingParticle()
703  if tp is None:
704  return None
705  return (self.phi() - tp.pca_phi())/self.phiErr()
706 
707  def dxyPull(self):
708  tp = self.bestMatchingTrackingParticle()
709  if tp is None:
710  return None
711  return (self.dxy() - tp.pca_dxy())/self.dxyErr()
712 
713  def dzPull(self):
714  tp = self.bestMatchingTrackingParticle()
715  if tp is None:
716  return None
717  return (self.dz() - tp.pca_dz())/self.dzErr()
718 
720  """Class presenting a collection of tracks."""
721  def __init__(self, tree):
722  """Constructor.
723 
724  Arguments:
725  tree -- TTree object
726  """
727  super(Tracks, self).__init__(tree, "trk_pt", Track)
728 
729 
731  """Class representing a pixel hit."""
732  def __init__(self, tree, index):
733  """Constructor.
734 
735  Arguments:
736  tree -- TTree object
737  index -- Index of the hit
738  """
739  super(PixelHit, self).__init__(tree, index, "pix")
740 
741  def isValidHit(self):
742  return True
743 
745  """Class presenting a collection of pixel hits."""
746  def __init__(self, tree):
747  """Constructor.
748 
749  Arguments:
750  tree -- TTree object
751  """
752  super(PixelHits, self).__init__(tree, "pix_isBarrel", PixelHit)
753 
754 
756  """Class representing a strip hit."""
757  def __init__(self, tree, index):
758  """Constructor.
759 
760  Arguments:
761  tree -- TTree object
762  index -- Index of the hit
763  """
764  super(StripHit, self).__init__(tree, index, "str")
765 
766  def isValidHit(self):
767  return True
768 
770  """Class presenting a collection of strip hits."""
771  def __init__(self, tree):
772  """Constructor.
773 
774  Arguments:
775  tree -- TTree object
776  """
777  super(StripHits, self).__init__(tree, "str_isBarrel", StripHit)
778 
779 
781  """Class representing a matched strip hit."""
782  def __init__(self, tree, index):
783  """Constructor.
784 
785  Arguments:
786  tree -- TTree object
787  index -- Index of the hit
788  """
789  super(GluedHit, self).__init__(tree, index, "glu")
790 
791  def isValidHit(self):
792  return True
793 
794  def monoHit(self):
795  """Returns a StripHit for the mono hit."""
796  self._checkIsValid()
797  return StripHit(self._tree, self._tree.glu_monoIdx[self._index])
798 
799  def stereoHit(self):
800  """Returns a StripHit for the stereo hit."""
801  self._checkIsValid()
802  return StripHit(self._tree, self._tree.glu_stereoIdx[self._index])
803 
804  def nseeds(self):
805  """Returns the number of seeds containing this hit."""
806  self._checkIsValid()
807  return self._tree.glu_seeIdx[self._index].size()
808 
809  def seeds(self):
810  """Returns generator for seeds containing this hit.
811 
812  The generator returns Seed objects
813  """
814  self._checkIsValid()
815  for iseed in self._tree.glu_seeIdx[self._index]:
816  yield Seed(self._tree, iseed)
817 
819  """Class presenting a collection of matched strip hits."""
820  def __init__(self, tree):
821  """Constructor.
822 
823  Arguments:
824  tree -- TTree object
825  """
826  super(GluedHits, self).__init__(tree, "glu_isBarrel", GluedHit)
827 
828 
830  # repeating TrackingRecHit::Type
831  Type = _Enum(
832  missing = 1,
833  inactive = 2,
834  bad = 3,
835  missing_inner = 4,
836  missing_outer = 5
837  )
838 
839  """Class representing an invalid hit."""
840  def __init__(self, tree, index):
841  """Constructor.
842 
843  Arguments:
844  tree -- TTree object
845  index -- Index of the hit
846  """
847  super(InvalidHit, self).__init__(tree, index, "inv")
848 
849  def isValidHit(self):
850  return False
851 
852  def layerStr(self):
853  """Returns a string describing the layer of the hit."""
854  invalid_type = self._tree.inv_type[self._index]
855  return super(InvalidHit, self).layerStr() + " (%s)"%InvalidHit.Type.toString(invalid_type)
856 
857 
859  """Class representing a phase2 OT hit."""
860  def __init__(self, tree, index):
861  """Constructor.
862 
863  Arguments:
864  tree -- TTree object
865  index -- Index of the hit
866  """
867  super(Phase2OTHit, self).__init__(tree, index, "ph2")
868 
869  def isValidHit(self):
870  return True
871 
873  """Class presenting a collection of phase2 OT hits."""
874  def __init__(self, tree):
875  """Constructor.
876 
877  Arguments:
878  tree -- TTree object
879  """
880  super(Phase2OTHits, self).__init__(tree, "ph2_isBarrel", Phase2OTHit)
881 
882 
883 def _seedOffsetForAlgo(tree, algo):
884  """Internal function for returning a pair of indices for the beginning of seeds of a given 'algo', and the one-beyond-last index of the seeds."""
885  for ioffset, offset in enumerate(tree.see_offset):
886  if tree.see_algo[offset] == algo:
887  next_offset = tree.see_offset[ioffset+1] if ioffset < tree.see_offset.size()-1 else tree.see_algo.size()
888  return (offset, next_offset)
889  return (-1, -1)
890 
892  """Class presenting a seed."""
893  def __init__(self, tree, index):
894  """Constructor.
895 
896  Arguments:
897  tree -- TTree object
898  index -- Index of the seed
899  """
900  super(Seed, self).__init__(tree, index, "see")
901 
902  def indexWithinAlgo(self):
903  """Returns the seed index within the seeds of the same algo.
904 
905  In case of errors, -1 is returned.
906  """
907  self._checkIsValid()
908  algo = self._tree.see_algo[self._index]
909  (offset, next_offset) = _seedOffsetForAlgo(self._tree, algo)
910  if offset == -1: # algo not found
911  return -1
912  return self._index - offset
913 
914  def track(self):
915  """Returns Track that was made from this seed."""
916  self._checkIsValid()
917  return Track(self._tree, self._tree.see_trkIdx[self._index])
918 
920  """Class presenting a collection of seeds."""
921  def __init__(self, tree):
922  """Constructor.
923 
924  Arguments:
925  tree -- TTree object
926  """
927  super(Seeds, self).__init__(tree, "see_pt", Seed)
928 
929  def nSeedsForAlgo(self, algo):
930  """Returns the number of seeds for a given 'algo'."""
931  (offset, next_offset) = _seedOffsetForAlgo(self._tree, algo)
932  return next_offset - offset
933 
934  def seedsForAlgo(self, algo):
935  """Returns generator iterating over the seeds of a given 'algo'.
936 
937  Generator returns Seed object.
938  """
939  (offset, next_offset) = _seedOffsetForAlgo(self._tree, algo)
940  for isee in range(offset, next_offset):
941  yield Seed(self._tree, isee)
942 
943  def seedForAlgo(self, algo, iseed):
944  """Returns Seed of index 'iseed' for 'algo'."""
945  (offset, next_offset) = _seedOffsetForAlgo(self._tree, algo)
946  if iseed >= (next_offset-offset):
947  raise Exception("Seed index %d is larger than the number of seeds %d for algo %d (%s)" % (iseed, next_offset-offset, algo, Algo.toString(algo)))
948  return Seed(self._tree, offset+iseed)
949 
950 
952  """Class representing a SimHit which has not induced a RecHit."""
953  def __init__(self, tree, index):
954  """Constructor.
955 
956  Arguments:
957  tree -- TTree object
958  index -- Index of the SimHit
959  """
960  super(SimHit, self).__init__(tree, index, "simhit")
961 
962  def nRecHits(self):
963  self._checkIsValid()
964  return self._tree.simhit_hitIdx[self._index].size()
965 
966  def trackingParticle(self):
967  self._checkIsValid()
968  return TrackingParticle(self._tree, getattr(self._tree, self._prefix+"_simTrkIdx")[self._index])
969 
970 
972  """Class representing a TrackingParticle."""
973  def __init__(self, tree, index):
974  """Constructor.
975 
976  Arguments:
977  tree -- TTree object
978  index -- Index of the TrackingParticle
979  """
980  super(TrackingParticle, self).__init__(tree, index, "sim")
981 
982  def _nMatchedTracks(self):
983  """Internal function to get the number of matched tracks."""
984  return self._tree.sim_trkIdx[self._index].size()
985 
986  def nMatchedTracks(self):
987  """Returns the number of matched tracks."""
988  self._checkIsValid()
989  return self._nMatchedTracks()
990 
991  def matchedTrackInfos(self):
992  """Returns a generator for matched tracks.
993 
994  The generator returns TrackMatchInfo objects.
995  """
996  self._checkIsValid()
997  for imatch in range(self._nMatchedTracks()):
998  yield TrackMatchInfo(self._tree, self._index, imatch, self._prefix)
999 
1001  """Returns best-matching track, even for non-reconstructed TrackingParticles, or None, if there is no best-matching track.
1002 
1003  Best-matching is defined as the one with largest number of
1004  hits matched to the hits of a TrackingParticle (>= 3). If
1005  there are many fulfilling the same number of hits, the one
1006  inducing the innermost hit of the TrackingParticle is chosen.
1007  """
1008  self._checkIsValid()
1009  if self._nMatchedTracks() == 1:
1010  return next(self.matchedTrackInfos()).track()
1011 
1012  tracks = collections.OrderedDict()
1013  for hit in self.simHits():
1014  for recHit in hit.hits():
1015  for track in recHit.tracks():
1016  if track.index() in tracks:
1017  tracks[track.index()] += 1
1018  else:
1019  tracks[track.index()] = 1
1020 
1021  best = (None, 2)
1022  for trackIndex, nhits in tracks.items():
1023  if nhits > best[1]:
1024  best = (trackIndex, nhits)
1025  if best[0] is None:
1026  return None
1027  return Tracks(self._tree)[best[0]]
1028 
1029  def _nMatchedSeeds(self):
1030  """Internal function to get the number of matched seeds."""
1031  return self._tree.sim_seedIdx[self._index].size()
1032 
1033  def nMatchedSeeds(self):
1034  """Returns the number of matched seeds."""
1035  self._checkIsValid()
1036  return self._nMatchedSeeds()
1037 
1038  def matchedSeedInfos(self):
1039  """Returns a generator for matched tracks.
1040 
1041  The generator returns SeedMatchInfo objects.
1042  """
1043  self._checkIsValid()
1044  for imatch in range(self._nMatchedSeeds()):
1045  yield SeedMatchInfo(self._tree, self._index, imatch, self._prefix)
1046 
1047  def nSimHits(self):
1048  self._checkIsValid()
1049  return self.simHitIdx().size()
1050 
1051  def simHits(self):
1052  """Returns generator for SimHits."""
1053  self._checkIsValid()
1054  for ihit in self.simHitIdx():
1055  yield SimHit(self._tree, ihit)
1056 
1057  def parentVertex(self):
1058  """Returns the parent TrackingVertex."""
1059  self._checkIsValid()
1060  return TrackingVertex(self._tree, self._tree.sim_parentVtxIdx[self._index])
1061 
1062  def decayVertices(self):
1063  """Returns a generator for decay vertices.
1064 
1065  The generator returns TrackingVertex objects.
1066  """
1067  self._checkIsValid()
1068  for ivtx in self._tree.sim_decayVtxIdx[self._index]:
1069  yield TrackingVertex(self._tree, ivtx)
1070 
1071  def isLooper(self):
1072  """Returns True if this TrackingParticle is a looper.
1073 
1074  Note that the check involves looping over the SimHits, so it is not too cheap."""
1075  self._checkIsValid()
1076  prevr = 0
1077  for ihit in self.simHitIdx():
1078  hit = SimHit(self._tree, ihit)
1079  r = hit.x()**2 + hit.y()**2
1080  if r < prevr:
1081  return True
1082  prevr = r
1083  return False
1084 
1085 
1087  """Class presenting a collection of TrackingParticles."""
1088  def __init__(self, tree):
1089  """Constructor.
1090 
1091  Arguments:
1092  tree -- TTree object
1093  """
1094  super(TrackingParticles, self).__init__(tree, "sim_pt", TrackingParticle)
1095 
1096 
1098  """Class presenting a primary vertex."""
1099  def __init__(self, tree, index):
1100  """Constructor.
1101 
1102  Arguments:
1103  tree -- TTree object
1104  index -- Index of the vertex
1105  """
1106  super(Vertex, self).__init__(tree, index, "vtx")
1107 
1108  def nTracks(self):
1109  """Returns the number of tracks used in the vertex fit."""
1110  self._checkIsValid()
1111  return self._tree.vtx_trkIdx[self._index].size()
1112 
1113  def tracks(self):
1114  """Returns a generator for the tracks used in the vertex fit.
1115 
1116  The generator returns Track object.
1117  """
1118  self._checkIsValid()
1119  for itrk in self._tree.vtx_trkIdx[self._index]:
1120  yield Track(self._tree, itrk)
1121 
1123  """Class presenting a collection of vertices."""
1124  def __init__(self, tree):
1125  """Constructor.
1126 
1127  Arguments:
1128  tree -- TTree object
1129  """
1130  super(Vertices, self).__init__(tree, "vtx_valid", Vertex)
1131 
1132 
1134  """Class representing a TrackingVertex."""
1135  def __init__(self, tree, index):
1136  """Constructor.
1137 
1138  Arguments:
1139  tree -- TTree object
1140  index -- Index of the TrackingVertex
1141  """
1142  super(TrackingVertex, self).__init__(tree, index, "simvtx")
1143 
1145  """Returns the number of source TrackingParticles."""
1146  self._checkIsValid()
1147  return self._tree.simvtx_sourceSimIdx[self._index].size()
1148 
1150  """Returns the number of daughter TrackingParticles."""
1151  self._checkIsValid()
1152  return self._tree.simvtx_daughterSimIdx[self._index].size()
1153 
1155  """Returns a generator for the source TrackingParticles."""
1156  self._checkIsValid()
1157  for isim in self._tree.simvtx_sourceSimIdx[self._index]:
1158  yield TrackingParticle(self._tree, isim)
1159 
1161  """Returns a generator for the daughter TrackingParticles."""
1162  self._checkIsValid()
1163  for isim in self._tree.simvtx_daughterSimIdx[self._index]:
1164  yield TrackingParticle(self._tree, isim)
1165 
1167  """Class presenting a collection of TrackingVertices."""
1168  def __init__(self, tree):
1169  """Constructor.
1170 
1171  Arguments:
1172  tree -- TTree object
1173  """
1174  super(TrackingVertex, self).__init__(tree, "simvtx_x")
size
Write out results.
def __init__(self, tree, index, trkindex, prefix)
def __init__(self, tree, index)
def __init__(self, tree, index)
def __init__(self, tree)
def __init__(self, fileName, tree="trackingNtuple/tree")
def seedsForAlgo(self, algo)
def __init__(self, tree, index)
def __init__(self, tree, index, shindex, prefix)
def __init__(self, tree, entry)
def __init__(self, tree, index)
def __init__(self, tree, index, seedindex, prefix)
def seedForAlgo(self, algo, iseed)
def __init__(self, tree, index, tpindex, prefix)
OutputIterator zip(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp)
def __init__(self, tree, index)
def __init__(self, tree, index)
def __init__(self, tree, index)
def nSeedsForAlgo(self, algo)
def __init__(self, tree, index, prefix)
def __getattr__(self, attr)
def __init__(self, tree, index, prefix)
def __init__(self, tree, sizeBranch, objclass)
def __init__(self, tree, index)
def __init__(self, tree, index)
def __init__(self, tree, index)
def _seedOffsetForAlgo(tree, algo)