CMS 3D CMS Logo

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