CMS 3D CMS Logo

TrackingTruthAccumulator.cc
Go to the documentation of this file.
1 
32 
47 
55 
56 //Turn on integrity checking
57 //#define DO_DEBUG_TESTING
58 
59 
60 //---------------------------------------------------------------------------------
61 //---------------------------------------------------------------------------------
62 //---------------------------------------------------------------------------------
63 //------ ------
64 //------ Declarations for utility classes and functions in the unnamed ------
65 //------ namespace. The definitions are right at the bottom of the file. ------
66 //------ ------
67 //---------------------------------------------------------------------------------
68 //---------------------------------------------------------------------------------
69 //---------------------------------------------------------------------------------
70 
71 namespace
72 {
77  struct DecayChainTrack
78  {
79  int simTrackIndex;
80  struct DecayChainVertex* pParentVertex;
81  // Some things have multiple decay vertices. Not sure how that works but it seems to be mostly electrons and some photons.
82  std::vector<struct DecayChainVertex*> daughterVertices;
83  DecayChainTrack* pMergedBremSource;
84  DecayChainTrack() : simTrackIndex(-1), pParentVertex(NULL), pMergedBremSource(NULL) {}
85  DecayChainTrack( int newSimTrackIndex ) : simTrackIndex(newSimTrackIndex), pParentVertex(NULL), pMergedBremSource() {}
86  };
87 
92  struct DecayChainVertex
93  {
94  int simVertexIndex;
95  DecayChainTrack* pParentTrack;
96  std::vector<DecayChainTrack*> daughterTracks;
97  DecayChainVertex* pMergedBremSource;
98  DecayChainVertex() : simVertexIndex(-1), pParentTrack(NULL), pMergedBremSource(NULL) {}
99  DecayChainVertex( int newIndex ) : simVertexIndex(newIndex), pParentTrack(NULL), pMergedBremSource(NULL) {}
100  };
101 
112  struct DecayChain
113  {
114  public:
115  DecayChain( const std::vector<SimTrack>& trackCollection, const std::vector<SimVertex>& vertexCollection );
116  const size_t decayTracksSize;
117  const size_t decayVerticesSize;
118 
119 #if defined(DO_DEBUG_TESTING)
120 
124  void integrityCheck();
125 #endif
126  const SimTrack& getSimTrack( const ::DecayChainTrack* pDecayTrack ) const { return simTrackCollection_.at( pDecayTrack->simTrackIndex ); }
127  const SimVertex& getSimVertex( const ::DecayChainVertex* pDecayVertex ) const { return simVertexCollection_.at( pDecayVertex->simVertexIndex ); }
128  private:
129  void findBrem( const std::vector<SimTrack>& trackCollection, const std::vector<SimVertex>& vertexCollection );
130  std::unique_ptr< ::DecayChainTrack[]> decayTracks_;
131  std::unique_ptr< ::DecayChainVertex[]> decayVertices_;
132 
134  std::vector< ::DecayChainVertex*> rootVertices_;
135 
136  // Keep a record of the constructor parameters
137  const std::vector<SimTrack>& simTrackCollection_;
138  const std::vector<SimVertex>& simVertexCollection_;
139  public:
140  const std::unique_ptr< ::DecayChainTrack[]>& decayTracks;
141  const std::unique_ptr< ::DecayChainVertex[]>& decayVertices;
142  const std::vector< ::DecayChainVertex*>& rootVertices;
143  };
144 
149  class TrackingParticleFactory
150  {
151  public:
152  TrackingParticleFactory( const ::DecayChain& decayChain, const edm::Handle< std::vector<reco::GenParticle> >& hGenParticles,
153  const edm::Handle< edm::HepMCProduct >& hepMCproduct, const edm::Handle< std::vector<int> >& hHepMCGenParticleIndices,
154  const std::vector<const PSimHit*>& simHits, double volumeRadius, double volumeZ, double vertexDistanceCut, bool allowDifferentProcessTypes );
155  TrackingParticle createTrackingParticle( const DecayChainTrack* pTrack, const TrackerTopology *tTopo ) const;
156  TrackingVertex createTrackingVertex( const DecayChainVertex* pVertex) const;
157  bool vectorIsInsideVolume( const math::XYZTLorentzVectorD& vector ) const;
158  private:
159  const ::DecayChain& decayChain_;
160  const edm::Handle< std::vector<reco::GenParticle> >& hGenParticles_;
161  const edm::Handle< edm::HepMCProduct >& hepMCproduct_;
162  std::vector<int> genParticleIndices_;
163  const std::vector<const PSimHit*>& simHits_;
164  const double volumeRadius_;
165  const double volumeZ_;
166  const double vertexDistanceCut2_; // distance based on which HepMC::GenVertexs are added to SimVertexs
167  std::multimap<unsigned int, size_t> trackIdToHitIndex_;
168  bool allowDifferentProcessTypeForDifferentDetectors_;
169  };
170 
175  class OutputCollectionWrapper
176  {
177  public:
178  OutputCollectionWrapper( const DecayChain& decayChain, TrackingTruthAccumulator::OutputCollections& outputCollections );
179  TrackingParticle* addTrackingParticle( const ::DecayChainTrack* pDecayTrack, const TrackingParticle& trackingParticle );
180  TrackingVertex* addTrackingVertex( const ::DecayChainVertex* pDecayVertex, const TrackingVertex& trackingVertex );
181  TrackingParticle* getTrackingParticle( const ::DecayChainTrack* pDecayTrack );
183  void setProxy( const ::DecayChainTrack* pOriginalTrack, const ::DecayChainTrack* pProxyTrack );
184  void setProxy( const ::DecayChainVertex* pOriginalVertex, const ::DecayChainVertex* pProxyVertex );
185  TrackingVertex* getTrackingVertex( const ::DecayChainVertex* pDecayVertex );
186  TrackingParticleRef getRef( const ::DecayChainTrack* pDecayTrack );
187  TrackingVertexRef getRef( const ::DecayChainVertex* pDecayVertex );
188  private:
189  void associateToExistingObjects( const ::DecayChainVertex* pChainVertex );
190  void associateToExistingObjects( const ::DecayChainTrack* pChainTrack );
192  std::vector<int> trackingParticleIndices_;
193  std::vector<int> trackingVertexIndices_;
194  };
195 
200  TrackingParticle* addTrackAndParentVertex( ::DecayChainTrack* pDecayTrack, const TrackingParticle& trackingParticle, ::OutputCollectionWrapper* pOutput );
201 
206  void addTrack( ::DecayChainTrack* pDecayChainTrack, const TrackingParticleSelector* pSelector, ::OutputCollectionWrapper* pUnmergedOutput, ::OutputCollectionWrapper* pMergedOutput, const ::TrackingParticleFactory& objectFactory, bool addAncestors, const TrackerTopology *tTopo);
207 
208 } // end of the unnamed namespace
209 
210 
211 
212 
213 //---------------------------------------------------------------------------------
214 //---------------------------------------------------------------------------------
215 //---------------------------------------------------------------------------------
216 //------ ------
217 //------ Definitions for the TrackingTruthAccumulator methods ------
218 //------ are below. ------
219 //------ ------
220 //---------------------------------------------------------------------------------
221 //---------------------------------------------------------------------------------
222 //---------------------------------------------------------------------------------
223 
225  messageCategory_("TrackingTruthAccumulator"),
226  volumeRadius_( config.getParameter<double>("volumeRadius") ),
227  volumeZ_( config.getParameter<double>("volumeZ") ),
228  vertexDistanceCut_( config.getParameter<double>("vertexDistanceCut") ),
229  ignoreTracksOutsideVolume_( config.getParameter<bool>("ignoreTracksOutsideVolume") ),
230  maximumPreviousBunchCrossing_( config.getParameter<unsigned int>("maximumPreviousBunchCrossing") ),
231  maximumSubsequentBunchCrossing_( config.getParameter<unsigned int>("maximumSubsequentBunchCrossing") ),
232  createUnmergedCollection_( config.getParameter<bool>("createUnmergedCollection") ),
233  createMergedCollection_(config.getParameter<bool>("createMergedBremsstrahlung") ),
234  createInitialVertexCollection_(config.getParameter<bool>("createInitialVertexCollection") ),
235  addAncestors_( config.getParameter<bool>("alwaysAddAncestors") ),
236  removeDeadModules_( config.getParameter<bool>("removeDeadModules") ),
237  simTrackLabel_( config.getParameter<edm::InputTag>("simTrackCollection") ),
238  simVertexLabel_( config.getParameter<edm::InputTag>("simVertexCollection") ),
239  collectionTags_( ),
240  genParticleLabel_( config.getParameter<edm::InputTag>("genParticleCollection") ),
241  hepMCproductLabel_( config.getParameter<edm::InputTag>("HepMCProductLabel") ),
242  allowDifferentProcessTypeForDifferentDetectors_( config.getParameter<bool>("allowDifferentSimHitProcesses") )
243 {
244  //
245  // Make sure at least one of the merged and unmerged collections have been set
246  // to be created.
247  //
249  edm::LogError(messageCategory_) << "Both \"createUnmergedCollection\" and \"createMergedBremsstrahlung\" have been"
250  << "set to false, which means no collections will be created";
251 
252  // Initialize selection for building TrackingParticles
253  //
254  if( config.exists( "select" ) )
255  {
256  edm::ParameterSet param=config.getParameter<edm::ParameterSet>("select");
257  selector_=TrackingParticleSelector( param.getParameter<double>( "ptMinTP" ),
258  param.getParameter<double>( "ptMaxTP" ),
259  param.getParameter<double>( "minRapidityTP" ),
260  param.getParameter<double>( "maxRapidityTP" ),
261  param.getParameter<double>( "tipTP" ),
262  param.getParameter<double>( "lipTP" ),
263  param.getParameter<int>( "minHitTP" ),
264  param.getParameter<bool>( "signalOnlyTP" ),
265  param.getParameter<bool>( "intimeOnlyTP" ),
266  param.getParameter<bool>( "chargedOnlyTP" ),
267  param.getParameter<bool>( "stableOnlyTP" ),
268  param.getParameter<std::vector<int> >("pdgIdTP") );
269  selectorFlag_=true;
270 
271  // Also set these two variables, which are used to drop out early if the SimTrack doesn't conform.
272  // The selector_ requires a full TrackingParticle object, but these two variables can veto things early.
273  chargedOnly_=param.getParameter<bool>( "chargedOnlyTP" );
274  signalOnly_=param.getParameter<bool>( "signalOnlyTP" );
275  }
276  else
277  {
278  selectorFlag_=false;
279  chargedOnly_=false;
280  signalOnly_=false;
281  }
282 
283  //
284  // Need to state what collections are going to be added to the event. This
285  // depends on which of the merged and unmerged collections have been configured
286  // to be created.
287  //
289  {
290  mixMod.produces<TrackingVertexCollection>();
291  mixMod.produces<TrackingParticleCollection>();
292  }
293 
295  {
296  mixMod.produces<TrackingParticleCollection>("MergedTrackTruth");
297  mixMod.produces<TrackingVertexCollection>("MergedTrackTruth");
298  }
299 
301  {
302  mixMod.produces<TrackingVertexCollection>("InitialVertices");
303  }
304 
305  iC.consumes<std::vector<SimTrack> >(simTrackLabel_);
306  iC.consumes<std::vector<SimVertex> >(simVertexLabel_);
307  iC.consumes<std::vector<reco::GenParticle> >(genParticleLabel_);
308  iC.consumes<std::vector<int> >(genParticleLabel_);
309  iC.consumes<std::vector<int> >(hepMCproductLabel_);
310 
311  // Fill the collection tags
312  const edm::ParameterSet& simHitCollectionConfig=config.getParameterSet("simHitCollections");
313  std::vector<std::string> parameterNames=simHitCollectionConfig.getParameterNames();
314 
315  for( const auto& parameterName : parameterNames )
316  {
317  std::vector<edm::InputTag> tags=simHitCollectionConfig.getParameter<std::vector<edm::InputTag> >(parameterName);
318  collectionTags_.insert(collectionTags_.end(), tags.begin(), tags.end());
319  }
320 
321  for( const auto& collectionTag : collectionTags_ ) {
322  iC.consumes<std::vector<PSimHit> >(collectionTag);
323  }
324 
325 }
326 
328 {
330  {
333  unmergedOutput_.refTrackingParticles=const_cast<edm::Event&>( event ).getRefBeforePut<TrackingParticleCollection>();
334  unmergedOutput_.refTrackingVertexes=const_cast<edm::Event&>( event ).getRefBeforePut<TrackingVertexCollection>();
335  }
336 
338  {
341  mergedOutput_.refTrackingParticles=const_cast<edm::Event&>( event ).getRefBeforePut<TrackingParticleCollection>("MergedTrackTruth");
342  mergedOutput_.refTrackingVertexes=const_cast<edm::Event&>( event ).getRefBeforePut<TrackingVertexCollection>("MergedTrackTruth");
343  }
344 
346  {
348  }
349 }
350 
355 
357 {
358  // Call the templated version that does the same for both signal and pileup events
359 
361  event.getByLabel(hepMCproductLabel_, hepmc);
362 
363  accumulateEvent( event, setup, hepmc );
364 }
365 
367 {
368  // If this bunch crossing is outside the user configured limit, don't do anything.
369  if( event.bunchCrossing()>=-static_cast<int>(maximumPreviousBunchCrossing_) && event.bunchCrossing()<=static_cast<int>(maximumSubsequentBunchCrossing_) )
370  {
371  //edm::LogInfo(messageCategory_) << "Analysing pileup event for bunch crossing " << event.bunchCrossing();
372 
373  //simply create empty handle as we do not have a HepMCProduct in PU anyway
375  accumulateEvent( event, setup, hepmc );
376  }
377  else edm::LogInfo(messageCategory_) << "Skipping pileup event for bunch crossing " << event.bunchCrossing();
378 }
379 
381 {
382 
384  {
385  edm::LogInfo("TrackingTruthAccumulator") << "Adding " << unmergedOutput_.pTrackingParticles->size() << " TrackingParticles and " << unmergedOutput_.pTrackingVertices->size()
386  << " TrackingVertexs to the event.";
387 
390  }
391 
393  {
394  edm::LogInfo("TrackingTruthAccumulator") << "Adding " << mergedOutput_.pTrackingParticles->size() << " merged TrackingParticles and " << mergedOutput_.pTrackingVertices->size()
395  << " merged TrackingVertexs to the event.";
396 
397  event.put(std::move(mergedOutput_.pTrackingParticles), "MergedTrackTruth" );
398  event.put(std::move(mergedOutput_.pTrackingVertices), "MergedTrackTruth" );
399  }
400 
402  {
403  edm::LogInfo("TrackingTruthAccumulator") << "Adding " << pInitialVertices_->size() << " initial TrackingVertexs to the event.";
404 
405  event.put(std::move(pInitialVertices_), "InitialVertices" );
406  }
407 }
408 
409 template<class T> void TrackingTruthAccumulator::accumulateEvent( const T& event, const edm::EventSetup& setup, const edm::Handle< edm::HepMCProduct >& hepMCproduct)
410 {
411  //
412  // Get the collections
413  //
415  edm::Handle<std::vector<SimVertex> > hSimVertices;
417  edm::Handle< std::vector<int> > hGenParticleIndices;
418 
419  event.getByLabel( simTrackLabel_, hSimTracks );
420  event.getByLabel( simVertexLabel_, hSimVertices );
421 
422  try
423  {
424  event.getByLabel( genParticleLabel_, hGenParticles );
425  event.getByLabel( genParticleLabel_, hGenParticleIndices );
426  }
427  catch( cms::Exception& exception )
428  {
429  //
430  // The Monte Carlo is not always available, e.g. for pileup events. The information
431  // is only used if it's available, but for some reason the PileUpEventPrincipal
432  // wrapper throws an exception here rather than waiting to see if the handle is
433  // used (as is the case for edm::Event). So I just want to catch this exception
434  // and use the normal handle checking later on.
435  //
436  }
437 
438  //Retrieve tracker topology from geometry
439  edm::ESHandle<TrackerTopology> tTopoHandle;
440  setup.get<TrackerTopologyRcd>().get(tTopoHandle);
441  const TrackerTopology* const tTopo = tTopoHandle.product();
442 
443 
444  // Run through the collections and work out the decay chain of each track/vertex. The
445  // information in SimTrack and SimVertex only allows traversing upwards, but this will
446  // allow traversal in both directions. This is required for things like grouping electrons
447  // that bremsstrahlung as one TrackingParticle if "mergedBremsstrahlung" is set in the
448  // config file.
449  DecayChain decayChain( *hSimTracks, *hSimVertices );
450 
451  // I only want to create these collections if they're actually required
452  std::unique_ptr< ::OutputCollectionWrapper> pUnmergedCollectionWrapper;
453  std::unique_ptr< ::OutputCollectionWrapper> pMergedCollectionWrapper;
454  if( createUnmergedCollection_ ) pUnmergedCollectionWrapper.reset( new ::OutputCollectionWrapper( decayChain, unmergedOutput_ ) );
455  if( createMergedCollection_ ) pMergedCollectionWrapper.reset( new ::OutputCollectionWrapper( decayChain, mergedOutput_ ) );
456 
457  std::vector<const PSimHit*> simHitPointers;
458  fillSimHits( simHitPointers, event, setup );
459  TrackingParticleFactory objectFactory( decayChain, hGenParticles, hepMCproduct, hGenParticleIndices, simHitPointers, volumeRadius_, volumeZ_, vertexDistanceCut_, allowDifferentProcessTypeForDifferentDetectors_ );
460 
461 #if defined(DO_DEBUG_TESTING)
462  // While I'm testing, perform some checks.
463  // TODO - drop this call once I'm happy it works in all situations.
464  decayChain.integrityCheck();
465 #endif
466 
467  TrackingParticleSelector* pSelector=NULL;
468  if( selectorFlag_ ) pSelector=&selector_;
469 
470  // Run over all of the SimTracks, but because I'm interested in the decay hierarchy
471  // do it through the DecayChainTrack objects. These are looped over in sequence here
472  // but they have the hierarchy information for the functions called to traverse the
473  // decay chain.
474 
475  for( size_t index=0; index<decayChain.decayTracksSize; ++index )
476  {
477  ::DecayChainTrack* pDecayTrack=&decayChain.decayTracks[index];
478  const SimTrack& simTrack=hSimTracks->at(pDecayTrack->simTrackIndex);
479 
480 
481  // Perform some quick checks to see if we can drop out early. Note that these are
482  // a subset of the cuts in the selector_ so the created TrackingParticle could still
483  // fail. The selector_ requires the full TrackingParticle to be made however, which
484  // can be computationally expensive.
485  if( chargedOnly_ && simTrack.charge()==0 ) continue;
486  if( signalOnly_ && (simTrack.eventId().bunchCrossing()!=0 || simTrack.eventId().event()!=0) ) continue;
487 
488  // Also perform a check to see if the production vertex is inside the tracker volume (if required).
490  {
491  const SimVertex& simVertex=hSimVertices->at( pDecayTrack->pParentVertex->simVertexIndex );
492  if( !objectFactory.vectorIsInsideVolume( simVertex.position() ) ) continue;
493  }
494 
495 
496  // This function creates the TrackinParticle and adds it to the collection if it
497  // passes the selection criteria specified in the configuration. If the config
498  // specifies adding ancestors, the function is called recursively to do that.
499  ::addTrack( pDecayTrack, pSelector, pUnmergedCollectionWrapper.get(), pMergedCollectionWrapper.get(), objectFactory, addAncestors_, tTopo );
500  }
501 
502  // If configured to create a collection of initial vertices, add them from this bunch
503  // crossing. No selection is applied on this collection, but it also has no links to
504  // the TrackingParticle decay products.
505  // There are a lot of "initial vertices", I'm not entirely sure what they all are
506  // (nuclear interactions in the detector maybe?), but the one for the main event is
507  // the one with vertexId==0.
509  {
510  // Pretty sure the one with vertexId==0 is always the first one, but doesn't hurt to check
511  for( const auto& pRootVertex : decayChain.rootVertices )
512  {
513  const SimVertex& vertex=hSimVertices->at(decayChain.rootVertices[0]->simVertexIndex);
514  if( vertex.vertexId()!=0 ) continue;
515 
516  pInitialVertices_->push_back( objectFactory.createTrackingVertex(pRootVertex) );
517  break;
518  }
519  }
520 }
521 
522 template<class T> void TrackingTruthAccumulator::fillSimHits( std::vector<const PSimHit*>& returnValue, const T& event, const edm::EventSetup& setup )
523 {
524  // loop over the collections
525  for( const auto& collectionTag : collectionTags_ )
526  {
528  event.getByLabel( collectionTag, hSimHits );
529 
530  // TODO - implement removing the dead modules
531  for( const auto& simHit : *hSimHits )
532  {
533  returnValue.push_back( &simHit );
534  }
535 
536  } // end of loop over InputTags
537 
538  // sort the SimHits according to their time of flight,
539  // necessary for looping over them "in order" in
540  // TrackingParticleFactory::createTrackingParticle()
541  std::sort(returnValue.begin(), returnValue.end(), [](const PSimHit *a, const PSimHit *b) {
542  const auto atof = edm::isFinite(a->timeOfFlight()) ? a->timeOfFlight() : std::numeric_limits<decltype(a->timeOfFlight())>::max();
543  const auto btof = edm::isFinite(b->timeOfFlight()) ? b->timeOfFlight() : std::numeric_limits<decltype(b->timeOfFlight())>::max();
544  return atof < btof;
545  });
546 }
547 
548 
549 //---------------------------------------------------------------------------------
550 //---------------------------------------------------------------------------------
551 //---------------------------------------------------------------------------------
552 //------ ------
553 //------ End of the definitions for the TrackingTruthAccumulator methods. ------
554 //------ Definitions for the functions and classes declared in the unnamed ------
555 //------ namespace are below. Documentation for those is above, where ------
556 //------ they're declared. ------
557 //------ ------
558 //---------------------------------------------------------------------------------
559 //---------------------------------------------------------------------------------
560 //---------------------------------------------------------------------------------
561 
562 
563 namespace // Unnamed namespace for things only used in this file
564 {
565  //---------------------------------------------------------------------------------
566  //---------------------------------------------------------------------------------
567  //---- TrackingParticleFactory methods ----------------------------------------
568  //---------------------------------------------------------------------------------
569  //---------------------------------------------------------------------------------
570 
571  ::TrackingParticleFactory::TrackingParticleFactory( const ::DecayChain& decayChain, const edm::Handle< std::vector<reco::GenParticle> >& hGenParticles,
572  const edm::Handle< edm::HepMCProduct >& hepMCproduct, const edm::Handle< std::vector<int> >& hHepMCGenParticleIndices, const std::vector<const PSimHit*>& simHits,
573  double volumeRadius, double volumeZ, double vertexDistanceCut, bool allowDifferentProcessTypes )
574  : decayChain_(decayChain), hGenParticles_(hGenParticles), hepMCproduct_(hepMCproduct), simHits_(simHits), volumeRadius_(volumeRadius),
575  volumeZ_(volumeZ), vertexDistanceCut2_(vertexDistanceCut*vertexDistanceCut), allowDifferentProcessTypeForDifferentDetectors_(allowDifferentProcessTypes)
576  {
577  // Need to create a multimap to get from a SimTrackId to all of the hits in it. The SimTrackId
578  // is an unsigned int.
579  for( size_t index=0; index<simHits_.size(); ++index )
580  {
581  trackIdToHitIndex_.insert( std::make_pair( simHits_[index]->trackId(), index ) );
582  }
583 
584  if( hHepMCGenParticleIndices.isValid() ) // Monte Carlo might not be available for the pileup events
585  {
586  genParticleIndices_.resize( hHepMCGenParticleIndices->size()+1 );
587 
588  // What I need is the reverse mapping of this vector. The sizes are already equivalent because I set
589  // the size in the initialiser list.
590  for( size_t recoGenParticleIndex=0; recoGenParticleIndex<hHepMCGenParticleIndices->size(); ++recoGenParticleIndex )
591  {
592  size_t hepMCGenParticleIndex=(*hHepMCGenParticleIndices)[recoGenParticleIndex];
593 
594  // They should be the same size, give or take a fencepost error, so this should never happen - but just in case
595  if( genParticleIndices_.size()<=hepMCGenParticleIndex ) genParticleIndices_.resize(hepMCGenParticleIndex+1);
596 
597  genParticleIndices_[ hepMCGenParticleIndex ]=recoGenParticleIndex;
598  }
599  }
600  }
601 
602  TrackingParticle TrackingParticleFactory::createTrackingParticle( const ::DecayChainTrack* pChainTrack, const TrackerTopology *tTopo ) const
603  {
605  typedef math::XYZPoint Vector;
606 
607  const SimTrack& simTrack=decayChain_.getSimTrack( pChainTrack );
608  const SimVertex& parentSimVertex=decayChain_.getSimVertex( pChainTrack->pParentVertex );
609 
610  LorentzVector position( 0, 0, 0, 0 );
611  if( !simTrack.noVertex() ) position=parentSimVertex.position();
612 
613  int pdgId=simTrack.type();
614 
615  TrackingParticle returnValue;
616  // N.B. The sim track is added a few lines below, the parent and decay vertices are added in
617  // another function later on.
618 
619  //
620  // If there is some valid Monte Carlo for this track, take some information from that.
621  // Only do so if it is from the signal event however. Not sure why but that's what the
622  // old code did.
623  //
624  if( simTrack.eventId().event()==0 && simTrack.eventId().bunchCrossing()==0 ) // if this is a track in the signal event
625  {
626  int hepMCGenParticleIndex=simTrack.genpartIndex();
627  if( hepMCGenParticleIndex>=0 && hepMCGenParticleIndex<static_cast<int>(genParticleIndices_.size()) && hGenParticles_.isValid() )
628  {
629  int recoGenParticleIndex=genParticleIndices_[hepMCGenParticleIndex];
630  reco::GenParticleRef generatorParticleRef( hGenParticles_, recoGenParticleIndex );
631  pdgId=generatorParticleRef->pdgId();
632  returnValue.addGenParticle( generatorParticleRef );
633  }
634  }
635 
636  returnValue.addG4Track( simTrack );
637 
638  // I need to run over the sim hits and count up the different types of hits. To be honest
639  // I don't fully understand this next section of code, I copied it from the old TrackingTruthProducer
640  // to provide the same results. The different types of hits that I need to count are:
641  size_t matchedHits=0; // As far as I can tell, this is the number of tracker layers with hits on them, i.e. taking account of overlaps.
642  size_t numberOfHits=0; // The total number of hits not taking account of overlaps.
643  size_t numberOfTrackerHits=0; // The number of tracker hits not taking account of overlaps.
644 
645  bool init=true;
646  int processType=0;
647  int particleType=0;
648  int oldLayer = 0;
649  int newLayer = 0;
650  DetId oldDetector;
651  DetId newDetector;
652 
653  // Loop over the SimHits associated to this SimTrack
654  // in the order defined by time of flight, which is
655  // probably the best quantity available for going
656  // through the hits "in order" (ok, most important is
657  // to get the first hit right because processType and
658  // particleType are taken from it)
659  for( auto iHitIndex=trackIdToHitIndex_.lower_bound( simTrack.trackId() ), end=trackIdToHitIndex_.upper_bound( simTrack.trackId() );
660  iHitIndex!=end;
661  ++iHitIndex )
662  {
663  const auto& pSimHit=simHits_[ iHitIndex->second ];
664 
665  // Skip hits with particle type different from SimTrack pdgId
666  if(pSimHit->particleType() != pdgId)
667  continue;
668 
669  // Initial condition for consistent simhit selection
670  if( init )
671  {
672  processType=pSimHit->processType();
673  particleType=pSimHit->particleType();
674  newDetector=DetId( pSimHit->detUnitId() );
675  init=false;
676  }
677 
678  oldDetector=newDetector;
679  newDetector=DetId( pSimHit->detUnitId() );
680 
681  // Fast sim seems to have different processType between tracker and muons, so if this flag
682  // has been set allow the processType to change if the detector changes.
683  if( allowDifferentProcessTypeForDifferentDetectors_ && newDetector.det()!=oldDetector.det() ) processType=pSimHit->processType();
684 
685  // Check for delta and interaction products discards
686  if( processType==pSimHit->processType() && particleType==pSimHit->particleType() )
687  {
688  ++numberOfHits;
689  oldLayer=newLayer;
690  newLayer=0;
691  if( newDetector.det() == DetId::Tracker ) {
692  ++numberOfTrackerHits;
693 
694  newLayer=tTopo->layer( newDetector );
695 
696  // Count hits using layers for glued detectors
697  if( (oldLayer!=newLayer || (oldLayer==newLayer && oldDetector.subdetId()!=newDetector.subdetId())) ) ++matchedHits;
698  }
699  }
700  } // end of loop over the sim hits for this sim track
701 
702  returnValue.setNumberOfTrackerLayers( matchedHits );
703  returnValue.setNumberOfHits( numberOfHits );
704  returnValue.setNumberOfTrackerHits( numberOfTrackerHits );
705 
706  return returnValue;
707  }
708 
709  TrackingVertex TrackingParticleFactory::createTrackingVertex( const ::DecayChainVertex* pChainVertex) const
710  {
711 
713  typedef math::XYZPoint Vector;
715 
716  const SimVertex& simVertex=decayChain_.getSimVertex( pChainVertex );
717 
718  bool isInVolume=this->vectorIsInsideVolume( simVertex.position() );
719 
720  TrackingVertex returnValue( simVertex.position(), isInVolume, simVertex.eventId() );
721 
722  // add the SimVertex to the TrackingVertex
723  returnValue.addG4Vertex(simVertex);
724 
725  // also add refs to nearby HepMC::GenVertexs; the way this is done (i.e. based on the position) is transcribed over from the old TrackingTruthProducer
726  if( simVertex.eventId().event()==0 && simVertex.eventId().bunchCrossing()==0 && hepMCproduct_.isValid()) // if this is a track in the signal event
727  {
728  const HepMC::GenEvent* genEvent = hepMCproduct_->GetEvent();
729 
730  if (genEvent != NULL)
731  {
732  Vector tvPosition(returnValue.position().x(), returnValue.position().y(), returnValue.position().z());
733 
734  for (HepMC::GenEvent::vertex_const_iterator iGenVertex = genEvent->vertices_begin(); iGenVertex != genEvent->vertices_end(); ++iGenVertex)
735  {
736  HepMC::ThreeVector rawPosition = (*iGenVertex)->position();
737 
738  Vector genPosition(rawPosition.x()*0.1, rawPosition.y()*0.1, rawPosition.z()*0.1);
739 
740  auto distance2 = (tvPosition - genPosition).mag2();
741 
742  if (distance2 < vertexDistanceCut2_)
743  returnValue.addGenVertex( GenVertexRef(hepMCproduct_, (*iGenVertex)->barcode()) );
744  }
745  }
746  }
747 
748  return returnValue;
749  }
750 
751  bool ::TrackingParticleFactory::vectorIsInsideVolume( const math::XYZTLorentzVectorD& vector ) const
752  {
753  return ( vector.Pt()<volumeRadius_ && std::abs( vector.z() )<volumeZ_ );
754  }
755 
756  //---------------------------------------------------------------------------------
757  //---------------------------------------------------------------------------------
758  //---- DecayChain methods -----------------------------------------------------
759  //---------------------------------------------------------------------------------
760  //---------------------------------------------------------------------------------
761 
762  ::DecayChain::DecayChain( const std::vector<SimTrack>& trackCollection, const std::vector<SimVertex>& vertexCollection )
763  : decayTracksSize( trackCollection.size() ),
764  decayVerticesSize( vertexCollection.size() ),
765  decayTracks_( new DecayChainTrack[decayTracksSize] ),
766  decayVertices_( new DecayChainVertex[decayVerticesSize] ),
767  simTrackCollection_( trackCollection ),
768  simVertexCollection_( vertexCollection ),
769  decayTracks( decayTracks_ ), // These const references map onto the actual members for public const access
770  decayVertices( decayVertices_ ),
771  rootVertices( rootVertices_ )
772  {
773  // I need some maps to be able to get object pointers from the track/vertex ID
774  std::map<int,::DecayChainTrack*> trackIdToDecayTrack;
775  std::map<int,::DecayChainVertex*> vertexIdToDecayVertex;
776 
777  // First create a DecayChainTrack for every SimTrack and make a note of the
778  // trackIds in the map. Also add a pointer to the daughter list of the parent
779  // DecayChainVertex, which might include creating the vertex object if it
780  // doesn't already exist.
781  size_t decayVertexIndex=0; // The index of the next free slot in the DecayChainVertex array.
782  for( size_t index=0; index<trackCollection.size(); ++index )
783  {
784  ::DecayChainTrack* pDecayTrack=&decayTracks_[index]; // Get a pointer for ease of use
785 
786  // This is the array index of the SimTrack that this DecayChainTrack corresponds to. At
787  // the moment this is a 1 to 1 relationship with the DecayChainTrack index, but they won't
788  // necessarily be accessed through the array later so it's still required to store it.
789  pDecayTrack->simTrackIndex=index;
790 
791  trackIdToDecayTrack[ trackCollection[index].trackId() ]=pDecayTrack;
792 
793  int parentVertexIndex=trackCollection[index].vertIndex();
794  if( parentVertexIndex>=0 )
795  {
796  // Get the DecayChainVertex corresponding to this SimVertex, or initialise it if it hasn't been done already.
797  ::DecayChainVertex*& pParentVertex=vertexIdToDecayVertex[parentVertexIndex];
798  if( pParentVertex==NULL )
799  {
800  // Note that I'm using a reference, so changing pParentVertex will change the entry in the map too.
801  pParentVertex=&decayVertices_[decayVertexIndex];
802  ++decayVertexIndex;
803  pParentVertex->simVertexIndex=parentVertexIndex;
804  }
805  pParentVertex->daughterTracks.push_back(pDecayTrack);
806  pDecayTrack->pParentVertex=pParentVertex;
807  }
808  else throw std::runtime_error( "TrackingTruthAccumulator: Found a track with an invalid parent vertex index." );
809  }
810 
811  // This assert was originally in to check the internal consistency of the decay chain. Fast sim
812  // pileup seems to have a load of vertices with no tracks pointing to them though, so fast sim fails
813  // this assert if pileup is added. I don't think the problem is vital however, so if the assert is
814  // taken out these extra vertices are ignored.
815  //assert( vertexIdToDecayVertex.size()==vertexCollection.size() && vertexCollection.size()==decayVertexIndex );
816 
817  // I still need to set DecayChainTrack::daughterVertices and DecayChainVertex::pParentTrack.
818  // The information to do this comes from SimVertex::parentIndex. I couldn't do this before
819  // because I need all of the DecayChainTracks initialised.
820  for( auto& decayVertexMapPair : vertexIdToDecayVertex )
821  {
822  ::DecayChainVertex* pDecayVertex=decayVertexMapPair.second;
823  int parentTrackIndex=vertexCollection[pDecayVertex->simVertexIndex].parentIndex();
824  if( parentTrackIndex!=-1 )
825  {
826  std::map<int,::DecayChainTrack*>::iterator iParentTrackMapPair=trackIdToDecayTrack.find(parentTrackIndex);
827  if( iParentTrackMapPair==trackIdToDecayTrack.end() )
828  {
829  std::stringstream errorStream;
830  errorStream << "TrackingTruthAccumulator: Something has gone wrong with the indexing. Parent track index is " << parentTrackIndex << ".";
831  throw std::runtime_error( errorStream.str() );
832  }
833 
834  ::DecayChainTrack* pParentTrackHierarchy=iParentTrackMapPair->second;
835 
836  pParentTrackHierarchy->daughterVertices.push_back( pDecayVertex );
837  pDecayVertex->pParentTrack=pParentTrackHierarchy;
838  }
839  else rootVertices_.push_back(pDecayVertex); // Has no parent so is at the top of the decay chain.
840  } // end of loop over the vertexIdToDecayVertex map
841 
842  findBrem( trackCollection, vertexCollection );
843 
844  } // end of ::DecayChain constructor
845 
846 #if defined(DO_DEBUG_TESTING)
847  // Function documentation is with the declaration above. This function is only used for testing.
848  void ::DecayChain::integrityCheck()
849  {
850  //
851  // Start off checking the tracks
852  //
853  for( size_t index=0; index<decayTracksSize; ++index )
854  {
855  const auto& decayTrack=decayTracks[index];
856  //
857  // Tracks should always have a production vertex
858  //
859  if( decayTrack.pParentVertex==NULL ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack with no parent vertex." );
860 
861  //
862  // Make sure the parent has this as a child. Also make sure it's only listed once.
863  //
864  size_t numberOfTimesListed=0;
865  for( const auto pSiblingTrack : decayTrack.pParentVertex->daughterTracks )
866  {
867  if( pSiblingTrack==&decayTrack ) ++numberOfTimesListed;
868  }
869  if( numberOfTimesListed!=1 ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack whose parent does not have it listed once and only once as a child." );
870 
871  //
872  // Make sure all of the children have this listed as a parent.
873  //
874  for( const auto pDaughterVertex : decayTrack.daughterVertices )
875  {
876  if( pDaughterVertex->pParentTrack!=&decayTrack ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack whose child does not have it listed as the parent." );
877  }
878 
879  //
880  // Follow the chain up to the root vertex, and make sure that is listed in rootVertices
881  //
882  const DecayChainVertex* pAncestorVertex=decayTrack.pParentVertex;
883  while( pAncestorVertex->pParentTrack!=NULL )
884  {
885  if( pAncestorVertex->pParentTrack->pParentVertex==NULL ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack with no parent vertex higher in the decay chain." );
886  pAncestorVertex=pAncestorVertex->pParentTrack->pParentVertex;
887  }
888  if( std::find( rootVertices.begin(), rootVertices.end(), pAncestorVertex )==rootVertices.end() )
889  {
890  throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack whose root vertex is not recorded anywhere." );
891  }
892  } // end of loop over decayTracks
893 
894  //
895  // Now check the vertices
896  //
897  for( size_t index=0; index<decayVerticesSize; ++index )
898  {
899  const auto& decayVertex=decayVertices[index];
900 
901  //
902  // Make sure this, or a vertex higher in the chain, is in the list of root vertices.
903  //
904  const DecayChainVertex* pAncestorVertex=&decayVertex;
905  while( pAncestorVertex->pParentTrack!=NULL )
906  {
907  if( pAncestorVertex->pParentTrack->pParentVertex==NULL ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack with no parent vertex higher in the vertex decay chain." );
908  pAncestorVertex=pAncestorVertex->pParentTrack->pParentVertex;
909  }
910  if( std::find( rootVertices.begin(), rootVertices.end(), pAncestorVertex )==rootVertices.end() )
911  {
912  throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack whose root vertex is not recorded anywhere." );
913  }
914 
915  //
916  // Make sure the parent has this listed in its daughters once and only once.
917  //
918  if( decayVertex.pParentTrack!=NULL )
919  {
920  size_t numberOfTimesListed=0;
921  for( const auto pSibling : decayVertex.pParentTrack->daughterVertices )
922  {
923  if( pSibling==&decayVertex ) ++numberOfTimesListed;
924  }
925  if( numberOfTimesListed!=1 ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainVertex whose parent does not have it listed once and only once as a child." );
926  }
927 
928  //
929  // Make sure all of the children have this listed as the parent
930  //
931  for( const auto pDaughter : decayVertex.daughterTracks )
932  {
933  if( pDaughter->pParentVertex!=&decayVertex ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainVertex whose child does not have it listed as the parent." );
934  }
935  } // end of loop over decay vertices
936 
937  std::cout << "TrackingTruthAccumulator.cc integrityCheck() completed successfully" << std::endl;
938  } // end of ::DecayChain::integrityCheck()
939 #endif
940 
941  void ::DecayChain::findBrem( const std::vector<SimTrack>& trackCollection, const std::vector<SimVertex>& vertexCollection )
942  {
943  for( size_t index=0; index<decayVerticesSize; ++index )
944  {
945  auto& vertex=decayVertices_[index];
946 
947  // Make sure parent is an electron
948  if( vertex.pParentTrack==NULL ) continue;
949  int parentTrackPDG=trackCollection[vertex.pParentTrack->simTrackIndex].type();
950  if( std::abs( parentTrackPDG )!=11 ) continue;
951 
952  size_t numberOfElectrons=0;
953  size_t numberOfNonElectronsOrPhotons=0;
954  for( auto& pDaughterTrack : vertex.daughterTracks )
955  {
956  const auto& simTrack=trackCollection[pDaughterTrack->simTrackIndex];
957  if( simTrack.type()==11 || simTrack.type()==-11 ) ++numberOfElectrons;
958  else if( simTrack.type()!=22 ) ++numberOfNonElectronsOrPhotons;
959  }
960  if( numberOfElectrons==1 && numberOfNonElectronsOrPhotons==0 )
961  {
962  // This is a valid brem, run through and tell all daughters to use the parent
963  // as the brem
964  for( auto& pDaughterTrack : vertex.daughterTracks ) pDaughterTrack->pMergedBremSource=vertex.pParentTrack;
965  vertex.pMergedBremSource=vertex.pParentTrack->pParentVertex;
966  }
967  }
968  } // end of ::DecayChain::findBrem()
969 
970 
971  //---------------------------------------------------------------------------------
972  //---------------------------------------------------------------------------------
973  //---- OutputCollectionWrapper methods ----------------------------------------
974  //---------------------------------------------------------------------------------
975  //---------------------------------------------------------------------------------
976 
977  ::OutputCollectionWrapper::OutputCollectionWrapper( const ::DecayChain& decayChain, TrackingTruthAccumulator::OutputCollections& outputCollections )
978  : output_(outputCollections),
979  trackingParticleIndices_(decayChain.decayTracksSize,-1),
980  trackingVertexIndices_(decayChain.decayVerticesSize,-1)
981  {
982  // No operation besides the initialiser list
983  }
984 
985  TrackingParticle* ::OutputCollectionWrapper::addTrackingParticle( const ::DecayChainTrack* pDecayTrack, const TrackingParticle& trackingParticle )
986  {
987  if( trackingParticleIndices_[pDecayTrack->simTrackIndex]!=-1 ) throw std::runtime_error( "OutputCollectionWrapper::addTrackingParticle - trying to add a particle twice" );
988 
989  trackingParticleIndices_[pDecayTrack->simTrackIndex]=output_.pTrackingParticles->size();
990  output_.pTrackingParticles->push_back( trackingParticle );
991 
992  // Clear any associations in case there were any beforehand
993  output_.pTrackingParticles->back().clearDecayVertices();
994  output_.pTrackingParticles->back().clearParentVertex();
995 
996  // Associate to the objects that are already in the output collections
997  associateToExistingObjects( pDecayTrack );
998 
999  return &output_.pTrackingParticles->back();
1000  }
1001 
1002  TrackingVertex* ::OutputCollectionWrapper::addTrackingVertex( const ::DecayChainVertex* pDecayVertex, const TrackingVertex& trackingVertex )
1003  {
1004  if( trackingVertexIndices_[pDecayVertex->simVertexIndex]!=-1 ) throw std::runtime_error( "OutputCollectionWrapper::addTrackingVertex - trying to add a vertex twice" );
1005 
1006  trackingVertexIndices_[pDecayVertex->simVertexIndex]=output_.pTrackingVertices->size();
1007  output_.pTrackingVertices->push_back( trackingVertex );
1008 
1009  // Associate the new vertex to any parents or children that are already in the output collections
1010  associateToExistingObjects( pDecayVertex );
1011 
1012  return &output_.pTrackingVertices->back();
1013  }
1014 
1015  TrackingParticle* ::OutputCollectionWrapper::getTrackingParticle( const ::DecayChainTrack* pDecayTrack )
1016  {
1017  const int index=trackingParticleIndices_[pDecayTrack->simTrackIndex];
1018  if( index==-1 ) return NULL;
1019  else return &(*output_.pTrackingParticles)[index];
1020  }
1021 
1022  TrackingVertex* ::OutputCollectionWrapper::getTrackingVertex( const ::DecayChainVertex* pDecayVertex )
1023  {
1024  const int index=trackingVertexIndices_[pDecayVertex->simVertexIndex];
1025  if( index==-1 ) return NULL;
1026  else return &(*output_.pTrackingVertices)[index];
1027  }
1028 
1029  TrackingParticleRef OutputCollectionWrapper::getRef( const ::DecayChainTrack* pDecayTrack )
1030  {
1031  const int index=trackingParticleIndices_[pDecayTrack->simTrackIndex];
1032  if( index==-1 ) throw std::runtime_error( "OutputCollectionWrapper::getRefTrackingParticle - ref requested for a non existent TrackingParticle" );
1033  else return TrackingParticleRef( output_.refTrackingParticles, index );
1034  }
1035 
1036  TrackingVertexRef OutputCollectionWrapper::getRef( const ::DecayChainVertex* pDecayVertex )
1037  {
1038  const int index=trackingVertexIndices_[pDecayVertex->simVertexIndex];
1039  if( index==-1 ) throw std::runtime_error( "OutputCollectionWrapper::getRefTrackingParticle - ref requested for a non existent TrackingVertex" );
1040  else return TrackingVertexRef( output_.refTrackingVertexes, index );
1041  }
1042 
1043  void ::OutputCollectionWrapper::setProxy( const ::DecayChainTrack* pOriginalTrack, const ::DecayChainTrack* pProxyTrack )
1044  {
1045  int& index=trackingParticleIndices_[pOriginalTrack->simTrackIndex];
1046  if( index!=-1 ) throw std::runtime_error( "OutputCollectionWrapper::setProxy() was called for a TrackingParticle that has already been created" );
1047  // Note that index is a reference so this call changes the value in the vector too
1048  index=trackingParticleIndices_[pProxyTrack->simTrackIndex];
1049  }
1050 
1051  void ::OutputCollectionWrapper::setProxy( const ::DecayChainVertex* pOriginalVertex, const ::DecayChainVertex* pProxyVertex )
1052  {
1053  int& index=trackingVertexIndices_[pOriginalVertex->simVertexIndex];
1054  const int newIndex=trackingVertexIndices_[pProxyVertex->simVertexIndex];
1055 
1056  if( index!=-1 && index!=newIndex ) throw std::runtime_error( "OutputCollectionWrapper::setProxy() was called for a TrackingVertex that has already been created" );
1057 
1058  // Note that index is a reference so this call changes the value in the vector too
1059  index=newIndex;
1060  }
1061 
1062  void ::OutputCollectionWrapper::associateToExistingObjects( const ::DecayChainVertex* pChainVertex )
1063  {
1064  // First make sure the DecayChainVertex supplied has been turned into a TrackingVertex
1065  TrackingVertex* pTrackingVertex=getTrackingVertex( pChainVertex );
1066  if( pTrackingVertex==NULL ) throw std::runtime_error( "associateToExistingObjects was passed a non existent TrackingVertex" );
1067 
1068  //
1069  // Associate to the parent track (if there is one)
1070  //
1071  ::DecayChainTrack* pParentChainTrack=pChainVertex->pParentTrack;
1072  if( pParentChainTrack!=NULL ) // Make sure there is a parent track first
1073  {
1074  // There is a parent track, but it might not have been turned into a TrackingParticle yet
1075  TrackingParticle* pParentTrackingParticle=getTrackingParticle(pParentChainTrack);
1076  if( pParentTrackingParticle!=NULL )
1077  {
1078  pParentTrackingParticle->addDecayVertex( getRef(pChainVertex) );
1079  pTrackingVertex->addParentTrack( getRef(pParentChainTrack) );
1080  }
1081  // Don't worry about the "else" case - the parent track might not necessarily get added
1082  // to the output collection at all. A check is done on daughter vertices when tracks
1083  // are added, so the association will be picked up then.
1084  }
1085 
1086  //
1087  // A parent TrackingVertex is always associated to a daughter TrackingParticle when
1088  // the TrackingParticle is created. Hence there is no need to check the list of
1089  // daughter tracks.
1090  //
1091  }
1092 
1093  void ::OutputCollectionWrapper::associateToExistingObjects( const ::DecayChainTrack* pChainTrack )
1094  {
1095  //
1096  // First make sure this DecayChainTrack has been turned into a TrackingParticle
1097  //
1098  TrackingParticle* pTrackingParticle=getTrackingParticle( pChainTrack );
1099  if( pTrackingParticle==NULL ) throw std::runtime_error( "associateToExistingObjects was passed a non existent TrackingParticle" );
1100 
1101  // Get the parent vertex. This should always already have been turned into a TrackingVertex, and
1102  // there should always be a parent DecayChainVertex.
1103  ::DecayChainVertex* pParentChainVertex=pChainTrack->pParentVertex;
1104  TrackingVertex* pParentTrackingVertex=getTrackingVertex( pParentChainVertex );
1105 
1106  //
1107  // First associate to the parent vertex.
1108  //
1109  pTrackingParticle->setParentVertex( getRef(pParentChainVertex) );
1110  pParentTrackingVertex->addDaughterTrack( getRef(pChainTrack) );
1111 
1112  // If there are any daughter vertices that have already been made into a TrackingVertex
1113  // make sure they know about each other. If the daughter vertices haven't been made into
1114  // TrackingVertexs yet, I won't do anything and create the association when the vertex is
1115  // made.
1116  for( auto pDaughterChainVertex : pChainTrack->daughterVertices )
1117  {
1118  TrackingVertex* pDaughterTrackingVertex=getTrackingVertex( pDaughterChainVertex );
1119  if( pDaughterTrackingVertex!=NULL )
1120  {
1121  pTrackingParticle->addDecayVertex( getRef(pDaughterChainVertex) );
1122  pDaughterTrackingVertex->addParentTrack( getRef(pChainTrack) );
1123  }
1124  }
1125  }
1126 
1127 
1128  TrackingParticle* addTrackAndParentVertex( ::DecayChainTrack* pDecayTrack, const TrackingParticle& trackingParticle, ::OutputCollectionWrapper* pOutput )
1129  {
1130  // See if this TrackingParticle has already been created (could be if the DecayChainTracks are
1131  // looped over in a funny order). If it has then there's no need to do anything.
1132  TrackingParticle* pTrackingParticle=pOutput->getTrackingParticle( pDecayTrack );
1133  if( pTrackingParticle==NULL )
1134  {
1135  // Need to make sure the production vertex has been created first
1136  if( pOutput->getTrackingVertex( pDecayTrack->pParentVertex ) == nullptr )
1137  {
1138  // TrackingVertex doesn't exist in the output collection yet. However, it's already been
1139  // created in the addTrack() function and a temporary reference to it set in the TrackingParticle.
1140  // I'll use that reference to create a copy in the output collection. When the TrackingParticle
1141  // is added to the output collection a few lines below the temporary reference to the parent
1142  // vertex will be cleared, and the correct one referring to the output collection will be set.
1143  pOutput->addTrackingVertex( pDecayTrack->pParentVertex, *trackingParticle.parentVertex() );
1144  }
1145 
1146 
1147  pTrackingParticle=pOutput->addTrackingParticle( pDecayTrack, trackingParticle );
1148  }
1149 
1150  return pTrackingParticle;
1151  }
1152 
1153  void addTrack( ::DecayChainTrack* pDecayChainTrack, const TrackingParticleSelector* pSelector, ::OutputCollectionWrapper* pUnmergedOutput, ::OutputCollectionWrapper* pMergedOutput, const ::TrackingParticleFactory& objectFactory, bool addAncestors, const TrackerTopology *tTopo )
1154  {
1155  if( pDecayChainTrack==NULL ) return; // This is required for when the addAncestors_ recursive call reaches the top of the chain
1156 
1157  // Check to see if this particle has already been processed while traversing up the parents
1158  // of another split in the decay chain. The check in the line above only stops when the top
1159  // of the chain is reached, whereas this will stop when a previously traversed split is reached.
1160  { // block to limit the scope of temporary variables
1161  bool alreadyProcessed=true;
1162  if( pUnmergedOutput!=NULL )
1163  {
1164  if( pUnmergedOutput->getTrackingParticle( pDecayChainTrack )==NULL ) alreadyProcessed=false;
1165  }
1166  if( pMergedOutput!=NULL )
1167  {
1168  if( pMergedOutput->getTrackingParticle( pDecayChainTrack )==NULL ) alreadyProcessed=false;
1169  }
1170  if( alreadyProcessed ) return;
1171  }
1172 
1173  // Create a TrackingParticle.
1174  TrackingParticle newTrackingParticle=objectFactory.createTrackingParticle( pDecayChainTrack, tTopo );
1175 
1176  // The selector checks the impact parameters from the vertex, so I need to have a valid reference
1177  // to the parent vertex in the TrackingParticle before that can be called. TrackingParticle needs
1178  // an edm::Ref for the parent TrackingVertex though. I still don't know if this is going to be
1179  // added to the collection so I can't take it from there, so I need to create a temporary one.
1180  // When the addTrackAndParentVertex() is called (assuming it passes selection) it will use the
1181  // temporary reference to create a copy of the parent vertex, put that in the output collection,
1182  // and then set the reference in the TrackingParticle properly.
1183  TrackingVertexCollection dummyCollection; // Only needed to create an edm::Ref
1184  dummyCollection.push_back( objectFactory.createTrackingVertex( pDecayChainTrack->pParentVertex) );
1185  TrackingVertexRef temporaryRef( &dummyCollection, 0 );
1186  newTrackingParticle.setParentVertex( temporaryRef );
1187 
1188  // If a selector has been supplied apply it on the new TrackingParticle and return if it fails.
1189  if( pSelector )
1190  {
1191  if( !(*pSelector)( newTrackingParticle ) ) return; // Return if the TrackingParticle fails selection
1192  }
1193 
1194  // Add the ancestors first (if required) so that the collection has some kind of chronological
1195  // order. I don't know how important that is but other code might assume chronological order.
1196  // If adding ancestors, no selection is applied. Note that I've already checked that all
1197  // DecayChainTracks have a pParentVertex.
1198  if( addAncestors ) addTrack( pDecayChainTrack->pParentVertex->pParentTrack, NULL, pUnmergedOutput, pMergedOutput, objectFactory, addAncestors, tTopo );
1199 
1200  // If creation of the unmerged collection has been turned off in the config this pointer
1201  // will be null.
1202  if( pUnmergedOutput!=NULL ) addTrackAndParentVertex( pDecayChainTrack, newTrackingParticle, pUnmergedOutput );
1203 
1204  // If creation of the merged collection has been turned off in the config this pointer
1205  // will be null.
1206  if( pMergedOutput!=NULL )
1207  {
1208  ::DecayChainTrack* pBremParentChainTrack=pDecayChainTrack;
1209  while( pBremParentChainTrack->pMergedBremSource!=NULL ) pBremParentChainTrack=pBremParentChainTrack->pMergedBremSource;
1210 
1211  if( pBremParentChainTrack!=pDecayChainTrack )
1212  {
1213  TrackingParticle* pBremParentTrackingParticle=addTrackAndParentVertex( pBremParentChainTrack, newTrackingParticle, pMergedOutput );
1214  // The original particle in the bremsstrahlung decay chain has been
1215  // created (or retrieved if it already existed), now copy in the
1216  // extra information.
1217  // TODO - copy extra information.
1218 
1219  if( std::abs( newTrackingParticle.pdgId() ) == 22 )
1220  {
1221  // Photons are added as separate TrackingParticles, but with the production
1222  // vertex changed to be the production vertex of the original electron.
1223 
1224  // Set up a proxy, so that all requests for the parent TrackingVertex get
1225  // redirected to the brem parent's TrackingVertex.
1226  pMergedOutput->setProxy( pDecayChainTrack->pParentVertex, pBremParentChainTrack->pParentVertex );
1227 
1228  // Now that pMergedOutput thinks the parent vertex is the brem parent's vertex I can
1229  // call this and it will set the TrackingParticle parent vertex correctly to the brem
1230  // parent vertex.
1231  addTrackAndParentVertex( pDecayChainTrack, newTrackingParticle, pMergedOutput );
1232  }
1233  else if( std::abs( newTrackingParticle.pdgId() ) == 11 )
1234  {
1235  // Electrons have their G4 tracks and SimHits copied to the parent TrackingParticle.
1236  for( const auto& trackSegment : newTrackingParticle.g4Tracks() )
1237  {
1238  pBremParentTrackingParticle->addG4Track( trackSegment );
1239  }
1240 
1241  // Also copy the generator particle references
1242  for( const auto& genParticleRef : newTrackingParticle.genParticles() )
1243  {
1244  pBremParentTrackingParticle->addGenParticle( genParticleRef );
1245  }
1246 
1247  pBremParentTrackingParticle->setNumberOfHits(pBremParentTrackingParticle->numberOfHits()+newTrackingParticle.numberOfHits());
1248  pBremParentTrackingParticle->setNumberOfTrackerHits(pBremParentTrackingParticle->numberOfTrackerHits()+newTrackingParticle.numberOfTrackerHits());
1249  pBremParentTrackingParticle->setNumberOfTrackerLayers(pBremParentTrackingParticle->numberOfTrackerLayers()+newTrackingParticle.numberOfTrackerLayers());
1250 
1251  // Set a proxy in the output collection wrapper so that any attempt to get objects for
1252  // this DecayChainTrack again get redirected to the brem parent.
1253  pMergedOutput->setProxy( pDecayChainTrack, pBremParentChainTrack );
1254  }
1255  }
1256  else
1257  {
1258  // This is not the result of bremsstrahlung so add to the collection as normal.
1259  addTrackAndParentVertex( pDecayChainTrack, newTrackingParticle, pMergedOutput );
1260  }
1261  } // end of "if( pMergedOutput!=NULL )", i.e. end of "if bremsstrahlung merging is turned on"
1262 
1263  } // end of addTrack function
1264 
1265 } // end of the unnamed namespace
1266 
1267 // Register with the framework
helper::MatcherGetRef< C >::ref_type getRef(const Handle< C > &c, size_t k)
Definition: getRef.h:28
EDGetTokenT< ProductType > consumes(edm::InputTag const &tag)
T getParameter(std::string const &) const
std::unique_ptr< TrackingParticleCollection > pTrackingParticles
std::unique_ptr< TrackingVertexCollection > pInitialVertices_
EncodedEventId eventId() const
Definition: CoreSimTrack.h:31
int event() const
get the contents of the subdetector field (should be protected?)
const std::vector< SimTrack > & g4Tracks() const
ROOT::Math::LorentzVector< ROOT::Math::PxPyPzE4D< double > > XYZTLorentzVectorD
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:14
virtual void initializeEvent(const edm::Event &event, const edm::EventSetup &setup)
std::unique_ptr< TrackingVertexCollection > pTrackingVertices
std::vector< TrackingParticle > TrackingParticleCollection
const reco::GenParticleRefVector & genParticles() const
ROOT::Math::Plane3D::Vector Vector
Definition: EcalHitMaker.cc:29
int pdgId() const
PDG ID.
const bool addAncestors_
Whether or not to add the full parentage of any TrackingParticle that is inserted in the collection...
int init
Definition: HydjetWrapper.h:67
bool exists(std::string const &parameterName) const
checks if a parameter exists
void addDaughterTrack(const TrackingParticleRef &)
def setup(process, global_tag, zero_tesla=False)
Definition: GeneralSetup.py:1
const double vertexDistanceCut_
maximum distance for HepMC::GenVertex to be added to SimVertex
#define NULL
Definition: scimark2.h:8
Definition: config.py:1
#define nullptr
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:20
void addParentTrack(const TrackingParticleRef &)
float charge() const
charge
Definition: CoreSimTrack.cc:18
bool signalOnly_
Uses the same config as selector_, but can be used to drop out early since selector_ requires the Tra...
genEvent
Definition: MCTruth.py:33
void fillSimHits(std::vector< const PSimHit * > &returnValue, const T &event, const edm::EventSetup &setup)
Fills the supplied vector with pointers to the SimHits, checking for bad modules if required...
bool isFinite(T x)
const unsigned int maximumSubsequentBunchCrossing_
void addG4Vertex(const SimVertex &)
void setParentVertex(const TrackingVertexRef &ref)
void addGenParticle(const reco::GenParticleRef &ref)
SingleObjectSelector< TrackingParticleCollection,::TrackingParticleSelector > TrackingParticleSelector
void accumulateEvent(const T &event, const edm::EventSetup &setup, const edm::Handle< edm::HepMCProduct > &hepMCproduct)
Both forms of accumulate() delegate to this templated method.
float timeOfFlight() const
Definition: PSimHit.h:69
simTrack
per collection params
int bunchCrossing() const
get the detector field from this detid
void addG4Track(const SimTrack &t)
int genpartIndex() const
index of the corresponding Generator particle in the Event container (-1 if no Genpart) ...
Definition: SimTrack.h:33
int numberOfTrackerLayers() const
The number of tracker layers with a hit.
virtual void finalizeEvent(edm::Event &event, const edm::EventSetup &setup)
T mag2() const
The vector magnitude squared. Equivalent to vec.dot(vec)
const std::string messageCategory_
The message category used to send messages to MessageLogger.
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
bool noVertex() const
Definition: SimTrack.h:30
virtual void accumulate(const edm::Event &event, const edm::EventSetup &setup)
const math::XYZTLorentzVectorD & position() const
Definition: CoreSimVertex.h:26
unsigned int vertexId() const
Definition: SimVertex.h:37
#define end
Definition: vmac.h:37
std::vector< std::string > getParameterNames() const
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger but the state exists so we define the behavior If all triggers are the negative crieriion will lead to accepting the event(this again matches the behavior of"!*"before the partial wildcard feature was incorporated).The per-event"cost"of each negative criterion with multiple relevant triggers is about the same as!*was in the past
int subdetId() const
get the contents of the subdetector field (not cast into any detector&#39;s numbering enum) ...
Definition: DetId.h:37
const TrackingVertexRef & parentVertex() const
bool allowDifferentProcessTypeForDifferentDetectors_
When counting hits, allows hits in different detectors to have a different process type...
edm::Ref< TrackingVertexCollection > TrackingVertexRef
Definition: DetId.h:18
edm::Ref< edm::HepMCProduct, HepMC::GenVertex > GenVertexRef
unsigned int trackId() const
Definition: CoreSimTrack.h:34
const bool createInitialVertexCollection_
Whether or not to create a separate collection for just the initial interaction vertices.
ParameterSet const & getParameterSet(std::string const &) const
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
void addDecayVertex(const TrackingVertexRef &ref)
std::vector< TrackingVertex > TrackingVertexCollection
const T & get() const
Definition: EventSetup.h:55
double b
Definition: hdecay.h:120
int numberOfHits() const
Gives the total number of hits, including muon hits. Hits on overlaps in the same layer count separat...
const unsigned int maximumPreviousBunchCrossing_
unsigned int layer(const DetId &id) const
void setNumberOfTrackerHits(int numberOfTrackerHits)
int type() const
particle type (HEP PDT convension)
Definition: CoreSimTrack.h:25
HLT enums.
EncodedEventId eventId() const
Definition: CoreSimVertex.h:30
#define DEFINE_DIGI_ACCUMULATOR(type)
double a
Definition: hdecay.h:121
static int position[264][3]
Definition: ReadPGInfo.cc:509
bool chargedOnly_
Uses the same config as selector_, but can be used to drop out early since selector_ requires the Tra...
const bool createUnmergedCollection_
If bremsstrahlung merging, whether to also add the unmerged collection to the event or not...
TrackingParticleSelector selector_
Monte Carlo truth information used for tracking validation.
TrackingTruthAccumulator(const edm::ParameterSet &config, edm::stream::EDProducerBase &mixMod, edm::ConsumesCollector &iC)
int numberOfTrackerHits() const
The number of hits in the tracker. Hits on overlaps in the same layer count separately.
void setNumberOfTrackerLayers(const int numberOfTrackerLayers)
Replacement for TrackingTruthProducer in the new pileup mixing setup.
Detector det() const
get the detector field from this detid
Definition: DetId.h:35
long double T
T const * product() const
Definition: ESHandle.h:86
edm::Ref< TrackingParticleCollection > TrackingParticleRef
def move(src, dest)
Definition: eostools.py:510
edm::InputTag hepMCproductLabel_
Needed to add HepMC::GenVertex to SimVertex.
Definition: event.py:1
math::PtEtaPhiELorentzVectorF LorentzVector
void setNumberOfHits(int numberOfHits)
std::vector< edm::InputTag > collectionTags_