CMS 3D CMS Logo

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