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