CMS 3D CMS Logo

QuickTrackAssociatorByHitsImpl.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <fstream>
3 
5 
7 
11 
13 
14 //
15 // Use the unnamed namespace for utility functions only used in this file
16 //
17 namespace {
18  //
19  // All of these functions are pretty straightforward but the implementation is type dependent.
20  // The templated methods call these for the type specific parts and the compiler will resolve
21  // the type and call the correct overload.
22  //
23 
24  template <class T_element>
25  size_t collectionSize(const edm::RefToBaseVector<T_element>& collection) {
26  return collection.size();
27  }
28 
29  template <class T_element>
30  size_t collectionSize(const edm::Handle<T_element>& hCollection) {
31  return hCollection->size();
32  }
33 
34  template <class T_element>
35  size_t collectionSize(const edm::RefVector<T_element>& collection) {
36  return collection.size();
37  }
38 
39  const reco::Track* getTrackAt(const edm::RefToBaseVector<reco::Track>& trackCollection, size_t index) {
40  return &*trackCollection[index]; // pretty obscure dereference
41  }
42 
43  const reco::Track* getTrackAt(const edm::Handle<edm::View<reco::Track> >& pTrackCollection, size_t index) {
44  return &(*pTrackCollection.product())[index];
45  }
46 
47  const TrackingParticle* getTrackingParticleAt(const edm::Handle<TrackingParticleCollection>& pCollection,
48  size_t index) {
49  return &(*pCollection.product())[index];
50  }
51 
52  const TrackingParticle* getTrackingParticleAt(const edm::RefVector<TrackingParticleCollection>& collection,
53  size_t index) {
54  return &*collection[index];
55  }
56 
58  return trackCollection[index];
59  }
60 
61  edm::RefToBase<reco::Track> getRefToTrackAt(const edm::Handle<edm::View<reco::Track> >& pTrackCollection,
62  size_t index) {
63  return edm::RefToBase<reco::Track>(pTrackCollection, index);
64  }
65 
66  edm::Ref<TrackingParticleCollection> getRefToTrackingParticleAt(
67  const edm::Handle<TrackingParticleCollection>& pCollection, size_t index) {
68  return edm::Ref<TrackingParticleCollection>(pCollection, index);
69  }
70 
71  edm::Ref<TrackingParticleCollection> getRefToTrackingParticleAt(
72  const edm::RefVector<TrackingParticleCollection>& collection, size_t index) {
73  return collection[index];
74  }
75 
76  void fillKeys(edm::IndexSet& keys, const edm::RefVector<TrackingParticleCollection>& collection) {
77  keys.reserve(collection.size());
78  for (const auto& ref : collection) {
79  keys.insert(ref.key());
80  }
81  }
82 
83  template <typename Coll>
84  void checkClusterMapProductID(const ClusterTPAssociation& clusterToTPMap, const Coll& collection) {
85  clusterToTPMap.checkMappedProductID(collection.id());
86  }
87 
88  template <typename Coll>
89  void checkClusterMapProductID(const TrackerHitAssociator& hitAssociator, const Coll& collection) {}
90 
91 } // namespace
92 
94  std::unique_ptr<const TrackerHitAssociator> hitAssoc,
95  const ClusterTPAssociation* clusterToTPMap,
96 
97  bool absoluteNumberOfHits,
98  double qualitySimToReco,
99  double puritySimToReco,
100  double pixelHitWeight,
101  double cutRecoToSim,
102  bool threeHitTracksAreSpecial,
103  SimToRecoDenomType simToRecoDenominator)
104  : productGetter_(&productGetter),
105  hitAssociator_(std::move(hitAssoc)),
106  clusterToTPMap_(clusterToTPMap),
107  qualitySimToReco_(qualitySimToReco),
108  puritySimToReco_(puritySimToReco),
109  pixelHitWeight_(pixelHitWeight),
110  cutRecoToSim_(cutRecoToSim),
111  simToRecoDenominator_(simToRecoDenominator),
112  threeHitTracksAreSpecial_(threeHitTracksAreSpecial),
113  absoluteNumberOfHits_(absoluteNumberOfHits) {}
114 
116  const edm::Handle<edm::View<reco::Track> >& trackCollectionHandle,
117  const edm::Handle<TrackingParticleCollection>& trackingParticleCollectionHandle) const {
118  // Only pass the one that was successfully created to the templated method.
119  if (not clusterToTPMap_)
121  trackCollectionHandle, trackingParticleCollectionHandle, nullptr, *hitAssociator_);
122  else
124  trackCollectionHandle, trackingParticleCollectionHandle, nullptr, *clusterToTPMap_);
125 }
126 
128  const edm::Handle<edm::View<reco::Track> >& trackCollectionHandle,
129  const edm::Handle<TrackingParticleCollection>& trackingParticleCollectionHandle) const {
130  // Only pass the one that was successfully created to the templated method.
131  if (not clusterToTPMap_)
133  trackCollectionHandle, trackingParticleCollectionHandle, nullptr, *hitAssociator_);
134  else
136  trackCollectionHandle, trackingParticleCollectionHandle, nullptr, *clusterToTPMap_);
137 }
138 
142  // Only pass the one that was successfully created to the templated method.
143  if (not clusterToTPMap_)
144  return associateRecoToSimImplementation(trackCollection, trackingParticleCollection, nullptr, *hitAssociator_);
145  else {
147  fillKeys(tpKeys, trackingParticleCollection);
148  return associateRecoToSimImplementation(trackCollection, trackingParticleCollection, &tpKeys, *clusterToTPMap_);
149  }
150 }
151 
155  // Only pass the one that was successfully created to the templated method.
156  if (not clusterToTPMap_)
157  return associateSimToRecoImplementation(trackCollection, trackingParticleCollection, nullptr, *hitAssociator_);
158  else {
160  fillKeys(tpKeys, trackingParticleCollection);
161  return associateSimToRecoImplementation(trackCollection, trackingParticleCollection, &tpKeys, *clusterToTPMap_);
162  }
163 }
164 
165 template <class T_TrackCollection, class T_TrackingParticleCollection, class T_hitOrClusterAssociator>
167  const T_TrackCollection& trackCollection,
168  const T_TrackingParticleCollection& trackingParticleCollection,
169  const TrackingParticleRefKeySet* trackingParticleKeys,
170  T_hitOrClusterAssociator hitOrClusterAssociator) const {
172  if (::collectionSize(trackingParticleCollection) == 0)
173  return returnValue;
174 
175  checkClusterMapProductID(hitOrClusterAssociator, trackingParticleCollection);
176 
177  size_t collectionSize = ::collectionSize(trackCollection); // Delegate away type specific part
178 
179  for (size_t i = 0; i < collectionSize; ++i) {
180  const reco::Track* pTrack = ::getTrackAt(
181  trackCollection, i); // Get a normal pointer for ease of use. This part is type specific so delegate.
182 
183  // The return of this function has first as the index and second as the number of associated hits
184  std::vector<std::pair<edm::Ref<TrackingParticleCollection>, double> > trackingParticleQualityPairs =
185  associateTrack(hitOrClusterAssociator,
186  trackingParticleCollection,
187  trackingParticleKeys,
188  pTrack->recHitsBegin(),
189  pTrack->recHitsEnd());
190 
191  // int nt = 0;
192  for (auto iTrackingParticleQualityPair = trackingParticleQualityPairs.begin();
193  iTrackingParticleQualityPair != trackingParticleQualityPairs.end();
194  ++iTrackingParticleQualityPair) {
195  const edm::Ref<TrackingParticleCollection>& trackingParticleRef = iTrackingParticleQualityPair->first;
196  double numberOfSharedClusters = iTrackingParticleQualityPair->second;
197  double numberOfValidTrackClusters = weightedNumberOfTrackClusters(*pTrack, hitOrClusterAssociator);
198 
199  if (numberOfSharedClusters == 0.0)
200  continue; // No point in continuing if there was no association
201 
202  //if electron subtract double counting
203  if (abs(trackingParticleRef->pdgId()) == 11 &&
204  (trackingParticleRef->g4Track_end() - trackingParticleRef->g4Track_begin()) > 1) {
205  numberOfSharedClusters -=
206  getDoubleCount(hitOrClusterAssociator, pTrack->recHitsBegin(), pTrack->recHitsEnd(), trackingParticleRef);
207  }
208 
209  double quality;
211  quality = numberOfSharedClusters;
212  else if (numberOfValidTrackClusters != 0.0)
213  quality = numberOfSharedClusters / numberOfValidTrackClusters;
214  else
215  quality = 0;
216  if (quality > cutRecoToSim_ &&
217  !(threeHitTracksAreSpecial_ && pTrack->numberOfValidHits() == 3 && numberOfSharedClusters < 3.0)) {
218  // Getting the RefToBase is dependent on the type of trackCollection, so delegate that to an overload.
219  returnValue.insert(::getRefToTrackAt(trackCollection, i), std::make_pair(trackingParticleRef, quality));
220  }
221  }
222  }
223  returnValue.post_insert();
224  return returnValue;
225 }
226 
227 template <class T_TrackCollection, class T_TrackingParticleCollection, class T_hitOrClusterAssociator>
229  const T_TrackCollection& trackCollection,
230  const T_TrackingParticleCollection& trackingParticleCollection,
231  const TrackingParticleRefKeySet* trackingParticleKeys,
232  T_hitOrClusterAssociator hitOrClusterAssociator) const {
234  if (::collectionSize(trackingParticleCollection) == 0)
235  return returnValue;
236 
237  checkClusterMapProductID(hitOrClusterAssociator, trackingParticleCollection);
238 
239  size_t collectionSize = ::collectionSize(trackCollection); // Delegate away type specific part
240 
241  for (size_t i = 0; i < collectionSize; ++i) {
242  const reco::Track* pTrack = ::getTrackAt(
243  trackCollection, i); // Get a normal pointer for ease of use. This part is type specific so delegate.
244 
245  // The return of this function has first as an edm:Ref to the associated TrackingParticle, and second as the number of associated hits
246  std::vector<std::pair<edm::Ref<TrackingParticleCollection>, double> > trackingParticleQualityPairs =
247  associateTrack(hitOrClusterAssociator,
248  trackingParticleCollection,
249  trackingParticleKeys,
250  pTrack->recHitsBegin(),
251  pTrack->recHitsEnd());
252 
253  // int nt = 0;
254  for (auto iTrackingParticleQualityPair = trackingParticleQualityPairs.begin();
255  iTrackingParticleQualityPair != trackingParticleQualityPairs.end();
256  ++iTrackingParticleQualityPair) {
257  const edm::Ref<TrackingParticleCollection>& trackingParticleRef = iTrackingParticleQualityPair->first;
258  double numberOfSharedClusters = iTrackingParticleQualityPair->second;
259  double numberOfValidTrackClusters = weightedNumberOfTrackClusters(*pTrack, hitOrClusterAssociator);
260  size_t numberOfSimulatedHits = 0; // Set a few lines below, but only if required.
261 
262  if (numberOfSharedClusters == 0.0)
263  continue; // No point in continuing if there was no association
264 
266  (numberOfSharedClusters < 3.0 &&
267  threeHitTracksAreSpecial_)) // the numberOfSimulatedHits is not always required, so can skip counting in some circumstances
268  {
269  // Note that in the standard TrackAssociatorByHits, all of the hits in associatedTrackingParticleHits are checked for
270  // various things. I'm not sure what these checks are for but they depend on the UseGrouping and UseSplitting settings.
271  // This associator works as though both UseGrouping and UseSplitting were set to true, i.e. just counts the number of
272  // hits in the tracker.
273  numberOfSimulatedHits = trackingParticleRef->numberOfTrackerHits();
274  }
275 
276  //if electron subtract double counting
277  if (abs(trackingParticleRef->pdgId()) == 11 &&
278  (trackingParticleRef->g4Track_end() - trackingParticleRef->g4Track_begin()) > 1) {
279  numberOfSharedClusters -=
280  getDoubleCount(hitOrClusterAssociator, pTrack->recHitsBegin(), pTrack->recHitsEnd(), trackingParticleRef);
281  }
282 
283  double purity = numberOfSharedClusters / numberOfValidTrackClusters;
284  double quality;
286  quality = numberOfSharedClusters;
287  else if (simToRecoDenominator_ == denomsim && numberOfSimulatedHits != 0)
288  quality = numberOfSharedClusters / static_cast<double>(numberOfSimulatedHits);
289  else if (simToRecoDenominator_ == denomreco && numberOfValidTrackClusters != 0)
290  quality = purity;
291  else
292  quality = 0;
293 
294  if (quality > qualitySimToReco_ &&
295  !(threeHitTracksAreSpecial_ && numberOfSimulatedHits == 3 && numberOfSharedClusters < 3.0) &&
296  (absoluteNumberOfHits_ || (purity > puritySimToReco_))) {
297  // Getting the RefToBase is dependent on the type of trackCollection, so delegate that to an overload.
298  returnValue.insert(trackingParticleRef, std::make_pair(::getRefToTrackAt(trackCollection, i), quality));
299  }
300  }
301  }
302  returnValue.post_insert();
303  return returnValue;
304 }
305 
306 template <typename T_TPCollection, typename iter>
307 std::vector<std::pair<edm::Ref<TrackingParticleCollection>, double> > QuickTrackAssociatorByHitsImpl::associateTrack(
309  const T_TPCollection& trackingParticles,
310  const TrackingParticleRefKeySet* trackingParticleKeys,
311  iter begin,
312  iter end) const {
313  // The pairs in this vector have a Ref to the associated TrackingParticle as "first" and the weighted number of associated hits as "second"
314  std::vector<std::pair<edm::Ref<TrackingParticleCollection>, double> > returnValue;
315 
316  // The pairs in this vector have first as the sim track identifiers, and second the number of reco hits associated to that sim track.
317  // Most reco hits will probably have come from the same sim track, so the number of entries in this vector should be fewer than the
318  // number of reco hits. The pair::second entries should add up to the total number of reco hits though.
319  std::vector<std::pair<SimTrackIdentifiers, double> > hitIdentifiers =
320  getAllSimTrackIdentifiers(hitAssociator, begin, end);
321 
322  // Loop over the TrackingParticles
323  size_t collectionSize = ::collectionSize(trackingParticles);
324 
325  for (size_t i = 0; i < collectionSize; ++i) {
326  const TrackingParticle* pTrackingParticle = getTrackingParticleAt(trackingParticles, i);
327 
328  // Historically there was a requirement that pTrackingParticle->numberOfHits() > 0
329  // However, in TrackingTruthAccumulator, the numberOfHits is calculated from a subset
330  // of the SimHits of the SimTracks of a TrackingParticle (essentially limiting the
331  // processType and particleType to those of the "first" hit, and particleType to the pdgId of the SimTrack).
332  // But, here the association between tracks and TrackingParticles is done with *all* the hits of
333  // TrackingParticle, so we should not rely on the numberOfHits() calculated with a subset of SimHits.
334 
335  double numberOfAssociatedHits = 0;
336  // Loop over all of the sim track identifiers and see if any of them are part of this TrackingParticle. If they are, add
337  // the number of reco hits associated to that sim track to the total number of associated hits.
338  for (const auto& identifierCountPair : hitIdentifiers) {
339  if (trackingParticleContainsIdentifier(pTrackingParticle, identifierCountPair.first))
340  numberOfAssociatedHits += identifierCountPair.second;
341  }
342 
343  if (numberOfAssociatedHits > 0) {
344  returnValue.push_back(std::make_pair(getRefToTrackingParticleAt(trackingParticles, i), numberOfAssociatedHits));
345  }
346  }
347 
348  return returnValue;
349 }
350 
351 template <typename T_TPCollection, typename iter>
352 std::vector<std::pair<edm::Ref<TrackingParticleCollection>, double> > QuickTrackAssociatorByHitsImpl::associateTrack(
353  const ClusterTPAssociation& clusterToTPMap,
354  const T_TPCollection& trackingParticles,
355  const TrackingParticleRefKeySet* trackingParticleKeys,
356  iter begin,
357  iter end) const {
358  // Note that the trackingParticles parameter is not actually required since all the information is in clusterToTPMap,
359  // but the method signature has to match the other overload because it is called from a templated method.
360 
361  // Note further, that we can't completely ignore the
362  // trackingParticles parameter, in case it is a subset of those
363  // TrackingParticles used to construct clusterToTPMap (via the
364  // TrackingParticleRefVector overloads). The trackingParticles
365  // parameter is still ignored since looping over it on every call
366  // would be expensive, but the keys of the TrackingParticleRefs are
367  // cached to an IndexSet (trackingParticleKeys) which is used
368  // as a fast search structure.
369 
370  // The pairs in this vector have a Ref to the associated TrackingParticle as "first" and the weighted number of associated clusters as "second"
371  // Note: typedef edm::Ref<TrackingParticleCollection> TrackingParticleRef;
372  std::vector<std::pair<edm::Ref<TrackingParticleCollection>, double> > returnValue;
373  if (clusterToTPMap.empty())
374  return returnValue;
375 
376  // The pairs in this vector have first as the TP, and second the number of reco clusters associated to that TP.
377  // Most reco clusters will probably have come from the same sim track (i.e TP), so the number of entries in this
378  // vector should be fewer than the number of clusters. The pair::second entries should add up to the total
379  // number of reco clusters though.
380  std::vector<OmniClusterRef> oClusters = track_associator::hitsToClusterRefs(begin, end);
381 
382  std::map<TrackingParticleRef, double> lmap;
383  for (std::vector<OmniClusterRef>::const_iterator it = oClusters.begin(); it != oClusters.end(); ++it) {
384  auto range = clusterToTPMap.equal_range(*it);
385  const double weight = it->isPixel() ? pixelHitWeight_ : 1.0;
386  if (range.first != range.second) {
387  for (auto ip = range.first; ip != range.second; ++ip) {
388  const TrackingParticleRef trackingParticle = (ip->second);
389 
390  if (trackingParticleKeys && !trackingParticleKeys->has(trackingParticle.key()))
391  continue;
392 
393  // Historically there was a requirement that pTrackingParticle->numberOfHits() > 0
394  // However, in TrackingTruthAccumulator, the numberOfHits is calculated from a subset
395  // of the SimHits of the SimTracks of a TrackingParticle (essentially limiting the
396  // processType and particleType to those of the "first" hit, and particleType to the pdgId of the SimTrack).
397  // But, here the association between tracks and TrackingParticles is done with *all* the hits of
398  // TrackingParticle, so we should not rely on the numberOfHits() calculated with a subset of SimHits.
399 
400  /* Alternative implementation to avoid the use of lmap... memory slightly improved but slightly slower...
401  std::pair<edm::Ref<TrackingParticleCollection>,size_t> tpIntPair(trackingParticle, 1);
402  auto tp_range = std::equal_range(returnValue.begin(), returnValue.end(), tpIntPair, tpIntPairGreater);
403  if ((tp_range.second-tp_range.first)>1) {
404  edm::LogError("TrackAssociator") << ">>> Error in counting TPs!" << " file: " << __FILE__ << " line: " << __LINE__;
405  }
406  if(tp_range.first != tp_range.second) {
407  tp_range.first->second++;
408  } else {
409  returnValue.push_back(tpIntPair);
410  std::sort(returnValue.begin(), returnValue.end(), tpIntPairGreater);
411  }
412  */
413  auto jpos = lmap.find(trackingParticle);
414  if (jpos != lmap.end())
415  jpos->second += weight;
416  else
417  lmap.insert(std::make_pair(trackingParticle, weight));
418  }
419  }
420  }
421  // now copy the map to returnValue
422  for (auto ip = lmap.begin(); ip != lmap.end(); ++ip) {
423  returnValue.push_back(std::make_pair(ip->first, ip->second));
424  }
425  return returnValue;
426 }
427 
428 template <typename iter>
429 std::vector<std::pair<QuickTrackAssociatorByHitsImpl::SimTrackIdentifiers, double> >
431  iter begin,
432  iter end) const {
433  // The pairs in this vector have first as the sim track identifiers, and second the number of reco hits associated to that sim track.
434  std::vector<std::pair<SimTrackIdentifiers, double> > returnValue;
435 
436  std::vector<SimTrackIdentifiers> simTrackIdentifiers;
437  // Loop over all of the rec hits in the track
438  //iter tRHIterBeginEnd = getTRHIterBeginEnd( pTrack );
439  for (iter iRecHit = begin; iRecHit != end; ++iRecHit) {
440  if (track_associator::getHitFromIter(iRecHit)->isValid()) {
441  simTrackIdentifiers.clear();
442 
443  // Get the identifiers for the sim track that this hit came from. There should only be one entry unless clusters
444  // have merged (as far as I know).
445  hitAssociator.associateHitId(*(track_associator::getHitFromIter(iRecHit)),
446  simTrackIdentifiers); // This call fills simTrackIdentifiers
447 
448  const auto subdetId = track_associator::getHitFromIter(iRecHit)->geographicalId().subdetId();
449  const double weight = (subdetId == PixelSubdetector::PixelBarrel || subdetId == PixelSubdetector::PixelEndcap)
451  : 1.0;
452 
453  // Loop over each identifier, and add it to the return value only if it's not already in there
454  for (std::vector<SimTrackIdentifiers>::const_iterator iIdentifier = simTrackIdentifiers.begin();
455  iIdentifier != simTrackIdentifiers.end();
456  ++iIdentifier) {
457  std::vector<std::pair<SimTrackIdentifiers, double> >::iterator iIdentifierCountPair;
458  for (auto iIdentifierCountPair = returnValue.begin(); iIdentifierCountPair != returnValue.end();
459  ++iIdentifierCountPair) {
460  if (iIdentifierCountPair->first.first == iIdentifier->first &&
461  iIdentifierCountPair->first.second == iIdentifier->second) {
462  // This sim track identifier is already in the list, so increment the count of how many hits it relates to.
463  iIdentifierCountPair->second += weight;
464  break;
465  }
466  }
467  if (iIdentifierCountPair == returnValue.end())
468  returnValue.push_back(std::make_pair(*iIdentifier, 1.0));
469  // This identifier wasn't found, so add it
470  }
471  }
472  }
473  return returnValue;
474 }
475 
477  const SimTrackIdentifiers& identifier) const {
478  // Loop over all of the g4 tracks in the tracking particle
479  for (std::vector<SimTrack>::const_iterator iSimTrack = pTrackingParticle->g4Track_begin();
480  iSimTrack != pTrackingParticle->g4Track_end();
481  ++iSimTrack) {
482  // And see if the sim track identifiers match
483  if (iSimTrack->eventId() == identifier.second && iSimTrack->trackId() == identifier.first) {
484  return true;
485  }
486  }
487 
488  // If control has made it this far then none of the identifiers were found in
489  // any of the g4 tracks, so return false.
490  return false;
491 }
492 
493 template <typename iter>
495  iter startIterator,
496  iter endIterator,
497  TrackingParticleRef associatedTrackingParticle) const {
498  // This method is largely copied from the standard TrackAssociatorByHits. Once I've tested how much difference
499  // it makes I'll go through and comment it properly.
500 
501  // FIXME: It may be that this piece is not fully correct for
502  // counting how many times a single *cluster* is matched to many
503  // SimTracks of a single TrackingParticle (see comments in
504  // getDoubleCount(ClusterTPAssociation) overload). To be verified
505  // some time.
506 
507  double doubleCount = 0.0;
508  std::vector<SimHitIdpr> SimTrackIdsDC;
509 
510  for (iter iHit = startIterator; iHit != endIterator; iHit++) {
511  int idcount = 0;
512 
513  SimTrackIdsDC.clear();
514  hitAssociator.associateHitId(*(track_associator::getHitFromIter(iHit)), SimTrackIdsDC);
515  if (SimTrackIdsDC.size() > 1) {
516  for (TrackingParticle::g4t_iterator g4T = associatedTrackingParticle->g4Track_begin();
517  g4T != associatedTrackingParticle->g4Track_end();
518  ++g4T) {
519  if (find(SimTrackIdsDC.begin(),
520  SimTrackIdsDC.end(),
521  SimHitIdpr((*g4T).trackId(), SimTrackIdsDC.begin()->second)) != SimTrackIdsDC.end()) {
522  idcount++;
523  }
524  }
525  }
526  if (idcount > 1) {
527  const auto subdetId = track_associator::getHitFromIter(iHit)->geographicalId().subdetId();
528  const double weight = (subdetId == PixelSubdetector::PixelBarrel || subdetId == PixelSubdetector::PixelEndcap)
530  : 1.0;
531  doubleCount += weight * (idcount - 1);
532  }
533  }
534 
535  return doubleCount;
536 }
537 
538 template <typename iter>
540  iter startIterator,
541  iter endIterator,
542  TrackingParticleRef associatedTrackingParticle) const {
543  // This code here was written by Subir Sarkar. I'm just splitting it off into a
544  // separate method. - Grimes 01/May/2014
545 
546  // The point here is that the electron TrackingParticles may contain
547  // multiple SimTracks (from the bremsstrahling), and (historically)
548  // the each matched hit/cluster has been multiplied by "how many
549  // SimTracks from the TrackingParticle" it contains charge from.
550  // Here the amount of this double counting is calculated, so that it
551  // can be subtracted by the calling code.
552  //
553  // Note that recently (hence "historically" in the paragraph above)
554  // the ClusterTPAssociationProducer was changed to remove the
555  // duplicate cluster->TP associations (hence making this function
556  // obsolete), but there is more recent proof that there is some
557  // duplication left (to be investigated).
558 
559  double doubleCount = 0;
560  std::vector<SimHitIdpr> SimTrackIdsDC;
561 
562  for (iter iHit = startIterator; iHit != endIterator; iHit++) {
563  std::vector<OmniClusterRef> oClusters =
564  track_associator::hitsToClusterRefs(iHit, iHit + 1); //only for the cluster being checked
565  for (std::vector<OmniClusterRef>::const_iterator it = oClusters.begin(); it != oClusters.end(); ++it) {
566  int idcount = 0;
567 
568  auto range = clusterToTPList.equal_range(*it);
569  if (range.first != range.second) {
570  for (auto ip = range.first; ip != range.second; ++ip) {
571  const TrackingParticleRef trackingParticle = (ip->second);
572  if (associatedTrackingParticle == trackingParticle) {
573  idcount++;
574  }
575  }
576  }
577 
578  if (idcount > 1) {
579  const auto subdetId = track_associator::getHitFromIter(iHit)->geographicalId().subdetId();
580  const double weight = (subdetId == PixelSubdetector::PixelBarrel || subdetId == PixelSubdetector::PixelEndcap)
582  : 1.0;
583  doubleCount += weight * (idcount - 1);
584  }
585  }
586  }
587 
588  return doubleCount;
589 }
590 
592  const edm::Handle<edm::View<TrajectorySeed> >& pSeedCollectionHandle_,
593  const edm::Handle<TrackingParticleCollection>& trackingParticleCollectionHandle) const {
594  edm::LogVerbatim("TrackAssociator") << "Starting TrackAssociatorByHitsImpl::associateRecoToSim - #seeds="
595  << pSeedCollectionHandle_->size()
596  << " #TPs=" << trackingParticleCollectionHandle->size();
597 
599 
600  size_t collectionSize = pSeedCollectionHandle_->size();
601 
602  for (size_t i = 0; i < collectionSize; ++i) {
603  const TrajectorySeed* pSeed = &(*pSeedCollectionHandle_)[i];
604 
605  // The return of this function has first as the index and second as the number of associated hits
606  std::vector<std::pair<edm::Ref<TrackingParticleCollection>, double> > trackingParticleQualityPairs =
608  trackingParticleCollectionHandle,
609  nullptr,
610  pSeed->recHits().first,
611  pSeed->recHits().second)
613  trackingParticleCollectionHandle,
614  nullptr,
615  pSeed->recHits().first,
616  pSeed->recHits().second);
617  for (auto iTrackingParticleQualityPair = trackingParticleQualityPairs.begin();
618  iTrackingParticleQualityPair != trackingParticleQualityPairs.end();
619  ++iTrackingParticleQualityPair) {
620  const edm::Ref<TrackingParticleCollection>& trackingParticleRef = iTrackingParticleQualityPair->first;
621  double numberOfSharedClusters = iTrackingParticleQualityPair->second;
622  double numberOfValidTrackClusters = clusterToTPMap_ ? weightedNumberOfTrackClusters(*pSeed, *clusterToTPMap_)
624 
625  if (numberOfSharedClusters == 0.0)
626  continue; // No point in continuing if there was no association
627 
628  //if electron subtract double counting
629  if (abs(trackingParticleRef->pdgId()) == 11 &&
630  (trackingParticleRef->g4Track_end() - trackingParticleRef->g4Track_begin()) > 1) {
631  if (clusterToTPMap_)
632  numberOfSharedClusters -=
633  getDoubleCount(*clusterToTPMap_, pSeed->recHits().first, pSeed->recHits().second, trackingParticleRef);
634  else
635  numberOfSharedClusters -=
636  getDoubleCount(*hitAssociator_, pSeed->recHits().first, pSeed->recHits().second, trackingParticleRef);
637  }
638 
639  double quality;
641  quality = numberOfSharedClusters;
642  else if (numberOfValidTrackClusters != 0.0)
643  quality = numberOfSharedClusters / numberOfValidTrackClusters;
644  else
645  quality = 0;
646 
647  if (quality > cutRecoToSim_ &&
648  !(threeHitTracksAreSpecial_ && pSeed->nHits() == 3 && numberOfSharedClusters < 3.0)) {
649  returnValue.insert(edm::RefToBase<TrajectorySeed>(pSeedCollectionHandle_, i),
650  std::make_pair(trackingParticleRef, quality));
651  }
652  }
653  }
654 
655  LogTrace("TrackAssociator") << "% of Assoc Seeds="
656  << ((double)returnValue.size()) / ((double)pSeedCollectionHandle_->size());
657  returnValue.post_insert();
658  return returnValue;
659 }
660 
662  const edm::Handle<edm::View<TrajectorySeed> >& pSeedCollectionHandle_,
663  const edm::Handle<TrackingParticleCollection>& trackingParticleCollectionHandle) const {
664  edm::LogVerbatim("TrackAssociator") << "Starting TrackAssociatorByHitsImpl::associateSimToReco - #seeds="
665  << pSeedCollectionHandle_->size()
666  << " #TPs=" << trackingParticleCollectionHandle->size();
667 
669  if (trackingParticleCollectionHandle->empty())
670  return returnValue;
671 
672  if (clusterToTPMap_) {
673  checkClusterMapProductID(*clusterToTPMap_, trackingParticleCollectionHandle);
674  }
675 
676  size_t collectionSize = pSeedCollectionHandle_->size();
677 
678  for (size_t i = 0; i < collectionSize; ++i) {
679  const TrajectorySeed* pSeed = &(*pSeedCollectionHandle_)[i];
680 
681  // The return of this function has first as an edm:Ref to the associated TrackingParticle, and second as the number of associated hits
682  std::vector<std::pair<edm::Ref<TrackingParticleCollection>, double> > trackingParticleQualityPairs =
684  trackingParticleCollectionHandle,
685  nullptr,
686  pSeed->recHits().first,
687  pSeed->recHits().second)
689  trackingParticleCollectionHandle,
690  nullptr,
691  pSeed->recHits().first,
692  pSeed->recHits().second);
693  for (auto iTrackingParticleQualityPair = trackingParticleQualityPairs.begin();
694  iTrackingParticleQualityPair != trackingParticleQualityPairs.end();
695  ++iTrackingParticleQualityPair) {
696  const edm::Ref<TrackingParticleCollection>& trackingParticleRef = iTrackingParticleQualityPair->first;
697  double numberOfSharedClusters = iTrackingParticleQualityPair->second;
698  double numberOfValidTrackClusters = clusterToTPMap_ ? weightedNumberOfTrackClusters(*pSeed, *clusterToTPMap_)
700  size_t numberOfSimulatedHits = 0; // Set a few lines below, but only if required.
701 
702  if (numberOfSharedClusters == 0.0)
703  continue; // No point in continuing if there was no association
704 
705  //if electron subtract double counting
706  if (abs(trackingParticleRef->pdgId()) == 11 &&
707  (trackingParticleRef->g4Track_end() - trackingParticleRef->g4Track_begin()) > 1) {
708  if (clusterToTPMap_)
709  numberOfSharedClusters -=
710  getDoubleCount(*clusterToTPMap_, pSeed->recHits().first, pSeed->recHits().second, trackingParticleRef);
711  else
712  numberOfSharedClusters -=
713  getDoubleCount(*hitAssociator_, pSeed->recHits().first, pSeed->recHits().second, trackingParticleRef);
714  }
715 
717  (numberOfSharedClusters < 3.0 &&
718  threeHitTracksAreSpecial_)) // the numberOfSimulatedHits is not always required, so can skip counting in some circumstances
719  {
720  // Note that in the standard TrackAssociatorByHits, all of the hits in associatedTrackingParticleHits are checked for
721  // various things. I'm not sure what these checks are for but they depend on the UseGrouping and UseSplitting settings.
722  // This associator works as though both UseGrouping and UseSplitting were set to true, i.e. just counts the number of
723  // hits in the tracker.
724  numberOfSimulatedHits = trackingParticleRef->numberOfTrackerHits();
725  }
726 
727  double purity = numberOfSharedClusters / numberOfValidTrackClusters;
728  double quality;
730  quality = numberOfSharedClusters;
731  else if (simToRecoDenominator_ == denomsim && numberOfSimulatedHits != 0)
732  quality = numberOfSharedClusters / static_cast<double>(numberOfSimulatedHits);
733  else if (simToRecoDenominator_ == denomreco && numberOfValidTrackClusters != 0.0)
734  quality = purity;
735  else
736  quality = 0;
737 
738  if (quality > qualitySimToReco_ &&
739  !(threeHitTracksAreSpecial_ && numberOfSimulatedHits == 3 && numberOfSharedClusters < 3.0) &&
740  (absoluteNumberOfHits_ || (purity > puritySimToReco_))) {
741  returnValue.insert(trackingParticleRef,
742  std::make_pair(edm::RefToBase<TrajectorySeed>(pSeedCollectionHandle_, i), quality));
743  }
744  }
745  }
746 
747  LogTrace("TrackAssociator") << "% of Assoc TPs="
748  << ((double)returnValue.size()) / ((double)trackingParticleCollectionHandle->size());
749  returnValue.post_insert();
750  return returnValue;
751 }
752 
753 // count hits
755  const TrackerHitAssociator&) const {
756  const reco::HitPattern& p = track.hitPattern();
757  const auto pixelHits = p.numberOfValidPixelHits();
758  const auto otherHits = p.numberOfValidHits() - pixelHits;
759  return pixelHits * pixelHitWeight_ + otherHits;
760 }
761 
763  const TrackerHitAssociator&) const {
764  double sum = 0.0;
765  for (auto iHit = seed.recHits().first; iHit != seed.recHits().second; ++iHit) {
766  const auto subdetId = track_associator::getHitFromIter(iHit)->geographicalId().subdetId();
767  const double weight = (subdetId == PixelSubdetector::PixelBarrel || subdetId == PixelSubdetector::PixelEndcap)
769  : 1.0;
770  sum += weight;
771  }
772  return sum;
773 }
774 
775 // count clusters
777  const ClusterTPAssociation&) const {
778  return weightedNumberOfTrackClusters(track.recHitsBegin(), track.recHitsEnd());
779 }
781  const ClusterTPAssociation&) const {
782  const auto& hitRange = seed.recHits();
783  return weightedNumberOfTrackClusters(hitRange.first, hitRange.second);
784 }
785 
786 template <typename iter>
788  double weightedClusters = 0.0;
789  for (iter iRecHit = begin; iRecHit != end; ++iRecHit) {
790  const auto subdetId = track_associator::getHitFromIter(iRecHit)->geographicalId().subdetId();
791  const double weight = (subdetId == PixelSubdetector::PixelBarrel || subdetId == PixelSubdetector::PixelEndcap)
793  : 1.0;
794  LogTrace("QuickTrackAssociatorByHitsImpl")
795  << " detId: " << track_associator::getHitFromIter(iRecHit)->geographicalId().rawId();
796  LogTrace("QuickTrackAssociatorByHitsImpl") << " weight: " << weight;
797  std::vector<OmniClusterRef> oClusters =
798  track_associator::hitsToClusterRefs(iRecHit, iRecHit + 1); //only for the cluster being checked
799  for (std::vector<OmniClusterRef>::const_iterator it = oClusters.begin(); it != oClusters.end(); ++it) {
800  weightedClusters += weight;
801  }
802  }
803  LogTrace("QuickTrackAssociatorByHitsImpl") << " total weighted clusters: " << weightedClusters;
804 
805  return weightedClusters;
806 }
reco::SimToRecoCollection associateSimToReco(const edm::Handle< edm::View< reco::Track > > &trackCollectionHandle, const edm::Handle< TrackingParticleCollection > &trackingParticleCollectionHandle) const override
std::pair< uint32_t, EncodedEventId > SimTrackIdentifiers
This is enough information to uniquely identify a sim track.
reco::RecoToSimCollection associateRecoToSimImplementation(const T_TrackCollection &trackCollection, const T_TrackingParticleCollection &trackingParticleCollection, const TrackingParticleRefKeySet *trackingParticleKeys, T_hitOrClusterAssociator hitOrClusterAssociator) const
The method that does the work for both overloads of associateRecoToSim.
std::vector< std::pair< edm::Ref< TrackingParticleCollection >, double > > associateTrack(const TrackerHitAssociator &hitAssociator, const T_TPCollection &trackingParticles, const TrackingParticleRefKeySet *trackingParticleKeys, iter begin, iter end) const
Returns the TrackingParticle that has the most associated hits to the given track.
g4t_iterator g4Track_begin() const
int numberOfValidHits() const
Definition: HitPattern.h:787
constexpr uint32_t rawId() const
get the raw id
Definition: DetId.h:57
std::vector< OmniClusterRef > hitsToClusterRefs(iter begin, iter end)
Definition: weight.py:1
key_type key() const
Accessor for product key.
Definition: Ref.h:250
edm::EDProductGetter const * productGetter_
creates either a ClusterTPAssociation OR a TrackerHitAssociator and stores it in the provided unique_...
const ClusterTPAssociation * clusterToTPMap_
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
QuickTrackAssociatorByHitsImpl(edm::EDProductGetter const &productGetter, std::unique_ptr< const TrackerHitAssociator > hitAssoc, const ClusterTPAssociation *clusterToTPMap, bool absoluteNumberOfHits, double qualitySimToReco, double puritySimToReco, double cutRecoToSim, double pixelHitWeight, bool threeHitTracksAreSpecial, SimToRecoDenomType simToRecoDenominator)
EDProductGetter const * productGetter(std::atomic< void const * > const &iCache)
reco::SimToRecoCollection associateSimToRecoImplementation(const T_TrackCollection &trackCollection, const T_TrackingParticleCollection &trackingParticleCollection, const TrackingParticleRefKeySet *trackingParticleKeys, T_hitOrClusterAssociator hitOrClusterAssociator) const
The method that does the work for both overloads of associateSimToReco.
bool has(unsigned int index) const
Check if an element (=index) is in the set.
Definition: IndexSet.h:54
void post_insert()
post insert action
constexpr int subdetId() const
get the contents of the subdetector field (not cast into any detector&#39;s numbering enum) ...
Definition: DetId.h:48
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
reco::RecoToSimCollection associateRecoToSim(const edm::Handle< edm::View< reco::Track > > &trackCollectionHandle, const edm::Handle< TrackingParticleCollection > &trackingParticleCollectionHandle) const override
range equal_range(const OmniClusterRef &key) const
unsigned short numberOfValidHits() const
number of valid hits found
Definition: TrackBase.h:740
#define end
Definition: vmac.h:39
size_type size() const
trackingRecHit_iterator recHitsBegin() const
Iterator to first hit on the track.
Definition: Track.h:88
#define LogTrace(id)
double getDoubleCount(const TrackerHitAssociator &hitAssociator, iter begin, iter end, TrackingParticleRef associatedTrackingParticle) const
This method was copied almost verbatim from the standard TrackAssociatorByHits.
std::vector< SimTrack >::const_iterator g4t_iterator
std::pair< uint32_t, EncodedEventId > SimHitIdpr
size_type size() const
map size
T const * product() const
Definition: Handle.h:69
void insert(const key_type &k, const data_type &v)
insert an association
const HitPattern & hitPattern() const
Access the hit pattern, indicating in which Tracker layers the track has hits.
Definition: TrackBase.h:483
range recHits() const
const TrackingRecHit * getHitFromIter(trackingRecHit_iterator iter)
void checkMappedProductID(const edm::HandleBase &mappedHandle) const
std::vector< SimHitIdpr > associateHitId(const TrackingRecHit &thit) const
unsigned int nHits() const
#define begin
Definition: vmac.h:32
double weightedNumberOfTrackClusters(const reco::Track &track, const TrackerHitAssociator &) const
int numberOfValidPixelHits() const
Definition: HitPattern.h:801
size_type size() const
Size of the RefVector.
Definition: RefVector.h:102
Monte Carlo truth information used for tracking validation.
void insert(unsigned int index)
Insert an element (=index) to the set.
Definition: IndexSet.h:47
DetId geographicalId() const
g4t_iterator g4Track_end() const
void reserve(unsigned int size)
Reserve memory for the set.
Definition: IndexSet.h:34
std::vector< std::pair< SimTrackIdentifiers, double > > getAllSimTrackIdentifiers(const TrackerHitAssociator &hitAssociator, iter begin, iter end) const
Returns a vector of pairs where first is a SimTrackIdentifiers (see typedef above) and second is the ...
def move(src, dest)
Definition: eostools.py:511
bool trackingParticleContainsIdentifier(const TrackingParticle *pTrackingParticle, const SimTrackIdentifiers &identifier) const
Returns true if the supplied TrackingParticle has the supplied g4 track identifiers.
std::unique_ptr< const TrackerHitAssociator > hitAssociator_
trackingRecHit_iterator recHitsEnd() const
Iterator to last hit on the track.
Definition: Track.h:91