CMS 3D CMS Logo

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