CMS 3D CMS Logo

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