CMS 3D CMS Logo

MtdTruthAccumulator.cc
Go to the documentation of this file.
1 // Author: Aurora Perego, Fabio Cossutti - aurora.perego@cern.ch, fabio.cossutti@ts.infn.it
2 // Date: 05/2023
3 
4 #define DEBUG false
5 
6 #if DEBUG
7 #pragma GCC diagnostic pop
8 #endif
9 
10 #include <algorithm>
11 #include <iterator>
12 #include <exception>
13 #include <memory>
14 
15 #include <numeric> // for std::accumulate
16 #include <unordered_map>
17 
26 
33 
45 
51 
59 
60 namespace {
61  using Index_t = unsigned;
62  using Barcode_t = int;
63  const std::string messageCategoryGraph_("MtdTruthAccumulatorGraphProducer");
64 } // namespace
65 
67 public:
69 
70 private:
71  void initializeEvent(const edm::Event &event, const edm::EventSetup &setup) override;
72  void accumulate(const edm::Event &event, const edm::EventSetup &setup) override;
73  void accumulate(const PileUpEventPrincipal &event, const edm::EventSetup &setup, edm::StreamID const &) override;
74  void finalizeEvent(edm::Event &event, const edm::EventSetup &setup) override;
75 
77  template <class T>
78  void accumulateEvent(const T &event,
79  const edm::EventSetup &setup,
80  const edm::Handle<edm::HepMCProduct> &hepMCproduct);
81 
84  template <class T>
85  void fillSimHits(std::vector<std::pair<uint64_t, const PSimHit *>> &returnValue,
86  std::unordered_map<int, std::map<uint64_t, float>> &simTrackDetIdEnergyMap,
87  std::unordered_map<int, std::map<uint64_t, float>> &simTrackDetIdTimeMap,
88  const T &event,
89  const edm::EventSetup &setup);
90 
92 
93  std::unordered_map<uint64_t, float> m_detIdToTotalSimEnergy; // keep track of cell normalizations
94  std::unordered_multimap<Barcode_t, Index_t> m_simHitBarcodeToIndex;
95 
101  const unsigned int maximumPreviousBunchCrossing_;
108 
109  const unsigned int bunchSpacing_;
110 
115 
116  std::vector<edm::InputTag> collectionTags_;
122  // edm::ESWatcher<MTDDigiGeometryRecord> geomWatcher_;
123 
125 
127  const bool premixStage1_;
128 
129  bool isEtl_;
130 
131 public:
133  std::unique_ptr<MtdSimClusterCollection> pSimClusters;
134  std::unique_ptr<MtdCaloParticleCollection> pCaloParticles;
135  std::unique_ptr<MtdSimLayerClusterCollection> pMtdSimLayerClusters;
136  std::unique_ptr<MtdSimTracksterCollection> pMtdSimTracksters;
137  };
138 
139  struct calo_particles {
140  std::vector<uint32_t> sc_start_;
141  std::vector<uint32_t> sc_stop_;
142 
143  void swap(calo_particles &oth) {
144  sc_start_.swap(oth.sc_start_);
145  sc_stop_.swap(oth.sc_stop_);
146  }
147 
148  void clear() {
149  sc_start_.clear();
150  sc_stop_.clear();
151  }
152  };
153 
154 private:
155  const MTDGeometry *geom = nullptr;
156  const MTDTopology *topology = nullptr;
159 };
160 
161 /* Graph utility functions */
162 
163 namespace {
164  class CaloParticle_dfs_visitor : public boost::default_dfs_visitor {
165  public:
166  CaloParticle_dfs_visitor(MtdTruthAccumulator::OutputCollections &output,
168  std::unordered_multimap<Barcode_t, Index_t> &simHitBarcodeToIndex,
169  std::unordered_map<int, std::map<uint64_t, float>> &simTrackDetIdEnergyMap,
170  std::unordered_map<int, std::map<uint64_t, float>> &simTrackDetIdTimeMap,
171  std::unordered_map<uint32_t, float> &vertex_time_map,
172  Selector selector)
173  : output_(output),
174  caloParticles_(caloParticles),
175  simHitBarcodeToIndex_(simHitBarcodeToIndex),
176  simTrackDetIdEnergyMap_(simTrackDetIdEnergyMap),
177  simTrackDetIdTimeMap_(simTrackDetIdTimeMap),
178  vertex_time_map_(vertex_time_map),
179  selector_(selector) {}
180  template <typename Vertex, typename Graph>
181  void discover_vertex(Vertex u, const Graph &g) {
182  // If we reach the vertex 0, it means that we are backtracking with respect
183  // to the first generation of stable particles: simply return;
184  // if (u == 0) return;
185  print_vertex(u, g);
186  auto const vertex_property = get(vertex_name, g, u);
187  if (!vertex_property.simTrack)
188  return;
189  auto trackIdx = vertex_property.simTrack->trackId();
190  IfLogDebug(DEBUG, messageCategoryGraph_)
191  << " Found " << simHitBarcodeToIndex_.count(trackIdx) << " associated simHits" << std::endl;
192  if (simHitBarcodeToIndex_.count(trackIdx)) {
193  output_.pSimClusters->emplace_back(*vertex_property.simTrack);
194  auto &simcluster = output_.pSimClusters->back();
195  std::unordered_map<uint64_t, float> acc_energy;
196  for (auto const &hit_and_energy : simTrackDetIdEnergyMap_[trackIdx]) {
197  acc_energy[hit_and_energy.first] += hit_and_energy.second;
198  }
199  for (auto const &hit_and_energy : acc_energy) {
200  simcluster.addHitAndFraction(hit_and_energy.first, hit_and_energy.second);
201  simcluster.addHitEnergy(hit_and_energy.second);
202  simcluster.addHitTime(simTrackDetIdTimeMap_[simcluster.g4Tracks()[0].trackId()][hit_and_energy.first]);
203  }
204  }
205  }
206  template <typename Edge, typename Graph>
207  void examine_edge(Edge e, const Graph &g) {
208  auto src = source(e, g);
209  auto vertex_property = get(vertex_name, g, src);
210  if (src == 0 or (vertex_property.simTrack == nullptr)) {
211  auto edge_property = get(edge_weight, g, e);
212  IfLogDebug(DEBUG, messageCategoryGraph_) << "Considering CaloParticle: " << edge_property.simTrack->trackId();
213  if (selector_(edge_property)) {
214  IfLogDebug(DEBUG, messageCategoryGraph_) << "Adding CaloParticle: " << edge_property.simTrack->trackId();
215  output_.pCaloParticles->emplace_back(*(edge_property.simTrack));
216  output_.pCaloParticles->back().addSimTime(vertex_time_map_[(edge_property.simTrack)->vertIndex()]);
217  caloParticles_.sc_start_.push_back(output_.pSimClusters->size());
218  }
219  }
220  }
221 
222  template <typename Edge, typename Graph>
223  void finish_edge(Edge e, const Graph &g) {
224  auto src = source(e, g);
225  auto vertex_property = get(vertex_name, g, src);
226  if (src == 0 or (vertex_property.simTrack == nullptr)) {
227  auto edge_property = get(edge_weight, g, e);
228  if (selector_(edge_property)) {
229  caloParticles_.sc_stop_.push_back(output_.pSimClusters->size());
230  }
231  }
232  }
233 
234  private:
236  MtdTruthAccumulator::calo_particles &caloParticles_;
237  std::unordered_multimap<Barcode_t, Index_t> &simHitBarcodeToIndex_;
238  std::unordered_map<int, std::map<uint64_t, float>> &simTrackDetIdEnergyMap_;
239  std::unordered_map<int, std::map<uint64_t, float>> &simTrackDetIdTimeMap_;
240  std::unordered_map<uint32_t, float> &vertex_time_map_;
241  Selector selector_;
242  };
243 } // namespace
244 
246  edm::ProducesCollector producesCollector,
248  : messageCategory_("MtdTruthAccumulator"),
249  maximumPreviousBunchCrossing_(config.getParameter<unsigned int>("maximumPreviousBunchCrossing")),
250  maximumSubsequentBunchCrossing_(config.getParameter<unsigned int>("maximumSubsequentBunchCrossing")),
251  bunchSpacing_(config.getParameter<unsigned int>("bunchspace")),
252  simTrackLabel_(config.getParameter<edm::InputTag>("simTrackCollection")),
253  simVertexLabel_(config.getParameter<edm::InputTag>("simVertexCollection")),
254  collectionTags_(),
255  genParticleLabel_(config.getParameter<edm::InputTag>("genParticleCollection")),
256  hepMCproductLabel_(config.getParameter<edm::InputTag>("HepMCProductLabel")),
257  geomToken_(iC.esConsumes<MTDGeometry, MTDDigiGeometryRecord>()),
258  mtdtopoToken_(iC.esConsumes<MTDTopology, MTDTopologyRcd>()),
259  minEnergy_(config.getParameter<double>("MinEnergy")),
260  maxPseudoRapidity_(config.getParameter<double>("MaxPseudoRapidity")),
261  premixStage1_(config.getParameter<bool>("premixStage1")) {
262  iC.consumes<std::vector<SimTrack>>(simTrackLabel_);
263  iC.consumes<std::vector<SimVertex>>(simVertexLabel_);
264  iC.consumes<std::vector<reco::GenParticle>>(genParticleLabel_);
265  iC.consumes<std::vector<int>>(genParticleLabel_);
266  iC.consumes<std::vector<int>>(hepMCproductLabel_);
267 
268  // Fill the collection tags
269  const edm::ParameterSet &simHitCollectionConfig = config.getParameterSet("simHitCollections");
270  std::vector<std::string> parameterNames = simHitCollectionConfig.getParameterNames();
271 
272  for (auto const &parameterName : parameterNames) {
273  std::vector<edm::InputTag> tags = simHitCollectionConfig.getParameter<std::vector<edm::InputTag>>(parameterName);
274  collectionTags_.insert(collectionTags_.end(), tags.begin(), tags.end());
275  }
276 
277  for (auto const &collectionTag : collectionTags_) {
278  iC.consumes<std::vector<PSimHit>>(collectionTag);
279  isEtl_ = (collectionTag.instance().find("FastTimerHitsEndcap") != std::string::npos);
280  }
281 
282  producesCollector.produces<MtdSimClusterCollection>("MergedMtdTruth");
283  producesCollector.produces<MtdSimLayerClusterCollection>("MergedMtdTruthLC");
284  producesCollector.produces<MtdSimTracksterCollection>("MergedMtdTruthST");
285  producesCollector.produces<MtdCaloParticleCollection>("MergedMtdTruth");
286  if (premixStage1_) {
287  producesCollector.produces<std::vector<std::pair<uint64_t, float>>>("MergedMtdTruth");
288  }
289 }
290 
292  output_.pSimClusters = std::make_unique<MtdSimClusterCollection>();
293  output_.pCaloParticles = std::make_unique<MtdCaloParticleCollection>();
294 
295  output_.pMtdSimLayerClusters = std::make_unique<MtdSimLayerClusterCollection>();
296  output_.pMtdSimTracksters = std::make_unique<MtdSimTracksterCollection>();
297 
298  m_detIdToTotalSimEnergy.clear();
299 
300  auto geometryHandle = setup.getTransientHandle(geomToken_);
301  geom = geometryHandle.product();
302 
303  auto topologyHandle = setup.getTransientHandle(mtdtopoToken_);
304  topology = topologyHandle.product();
305 
308 }
309 
319  event.getByLabel(hepMCproductLabel_, hepmc);
320 
321  edm::LogInfo(messageCategory_) << " MtdTruthAccumulator::accumulate (signal)";
322  accumulateEvent(event, setup, hepmc);
323 }
324 
326  edm::EventSetup const &setup,
327  edm::StreamID const &) {
328  if (event.bunchCrossing() >= -static_cast<int>(maximumPreviousBunchCrossing_) &&
329  event.bunchCrossing() <= static_cast<int>(maximumSubsequentBunchCrossing_)) {
330  // simply create empty handle as we do not have a HepMCProduct in PU anyway
332  edm::LogInfo(messageCategory_) << " MtdTruthAccumulator::accumulate (pileup) bunchCrossing="
333  << event.bunchCrossing();
334  accumulateEvent(event, setup, hepmc);
335  } else {
336  edm::LogInfo(messageCategory_) << "Skipping pileup event for bunch crossing " << event.bunchCrossing();
337  }
338 }
339 
341  using namespace geant_units::operators;
342 
343  edm::LogInfo(messageCategory_) << "Adding " << output_.pSimClusters->size() << " SimParticles and "
344  << output_.pCaloParticles->size() << " CaloParticles to the event.";
345 
346  // We need to normalize the hits and energies into hits and fractions (since
347  // we have looped over all pileup events)
348  // For premixing stage1 we keep the energies, they will be normalized to
349  // fractions in stage2
350 
351  if (premixStage1_) {
352  auto totalEnergies = std::make_unique<std::vector<std::pair<uint64_t, float>>>();
353  totalEnergies->reserve(m_detIdToTotalSimEnergy.size());
354  std::copy(m_detIdToTotalSimEnergy.begin(), m_detIdToTotalSimEnergy.end(), std::back_inserter(*totalEnergies));
355  std::sort(totalEnergies->begin(), totalEnergies->end());
356  event.put(std::move(totalEnergies), "MergedMtdTruth");
357  } else {
358  for (auto &sc : *(output_.pSimClusters)) {
359  auto hitsAndEnergies = sc.hits_and_fractions();
360  sc.clearHitsAndFractions();
361  sc.clearHitsEnergy();
362  for (auto &hAndE : hitsAndEnergies) {
363  const float totalenergy = m_detIdToTotalSimEnergy[hAndE.first];
364  float fraction = 0.;
365  if (totalenergy > 0)
366  fraction = hAndE.second / totalenergy;
367  else
369  << "TotalSimEnergy for hit " << hAndE.first << " is 0! The fraction for this hit cannot be computed.";
370  sc.addHitAndFraction(hAndE.first, fraction);
371  sc.addHitEnergy(hAndE.second);
372  }
373  }
374  }
375 
376 #ifdef PRINT_DEBUG
377  IfLogDebug(DEBUG, messageCategory_) << "SIMCLUSTERS LIST:" << std::endl;
378  for (const auto &sc : *(output_.pSimClusters)) {
379  IfLogDebug(DEBUG, messageCategory_) << std::fixed << std::setprecision(3) << "SimCluster from CP with:"
380  << "\n charge " << sc.charge() << "\n pdgId " << sc.pdgId() << "\n energy "
381  << sc.energy() << " GeV\n eta " << sc.eta() << "\n phi " << sc.phi()
382  << "\n number of cells = " << sc.hits_and_fractions().size() << std::endl;
383  for (unsigned int i = 0; i < sc.hits_and_fractions().size(); ++i) {
384  DetId id(sc.detIds_and_rows()[i].first);
386  << std::fixed << std::setprecision(3) << " hit " << id.rawId() << " on layer " << geomTools_.layer(id)
387  << " module " << geomTools_.module(id) << " row " << (unsigned int)(sc.detIds_and_rows()[i].second).first
388  << " col " << (unsigned int)(sc.detIds_and_rows()[i].second).second << " at time "
389  << sc.hits_and_times()[i].second << " ns" << std::endl;
390  }
391  IfLogDebug(DEBUG, messageCategory_) << "--------------\n";
392  }
393  IfLogDebug(DEBUG, messageCategory_) << std::endl;
394 #endif
395 
396  // save the SimCluster orphan handle so we can fill the calo particles
397  auto scHandle = event.put(std::move(output_.pSimClusters), "MergedMtdTruth");
398 
399  // reserve for the best case scenario: already splitted
400  output_.pMtdSimLayerClusters->reserve(scHandle->size());
401  output_.pMtdSimTracksters->reserve(scHandle->size());
402 
403  uint32_t SC_index = 0;
404  uint32_t LC_index = 0;
405  for (const auto &sc : *scHandle) {
406  auto const &hAndF = sc.hits_and_fractions();
407  auto const &hAndE = sc.hits_and_energies();
408  auto const &hAndT = sc.hits_and_times();
409  auto const &hAndR = sc.detIds_and_rows();
410  // create a vector with the indices of the hits in the simCluster
411  std::vector<int> indices(hAndF.size());
412  std::iota(indices.begin(), indices.end(), 0);
413  // sort the hits indices based on the unique indices created before
414  std::sort(indices.begin(), indices.end(), [&](int a, int b) { return hAndF[a].first < hAndF[b].first; });
415 
416  // now split the sc: loop on the sorted indices and save the first hit in a
417  // temporary simCluster. If the following hit is in the same module and row (column),
418  // but next column (row) put it in the temporary simcluster as well, otherwise
419  // put the temporary simcluster in the collection and start creating a new one
420  std::vector<uint32_t> LC_indices;
421  MtdSimLayerCluster tmpLC(sc.g4Tracks()[0]);
422  int prev = indices[0];
423  DetId prevId(hAndR[prev].first);
424 
425  float SimLCenergy = 0.;
426  float SimLCx = 0., SimLCy = 0., SimLCz = 0.;
427 
428  auto push_back_hit = [&](const int &ind) {
429  tmpLC.addHitAndFraction(hAndF[ind].first, hAndF[ind].second);
430  tmpLC.addHitEnergy(hAndE[ind].second);
431  tmpLC.addHitTime(hAndT[ind].second);
432  };
433 
434  auto update_clu_info = [&](const int &ind) {
435  double energy = hAndE[ind].second;
436  auto position =
437  geomTools_.position((DetId)hAndR[ind].first, (hAndR[ind].second).first, (hAndR[ind].second).second).first;
438  SimLCenergy += energy;
439  SimLCx += position.x() * energy;
440  SimLCy += position.y() * energy;
441  SimLCz += position.z() * energy;
442  };
443 
444  auto push_back_clu = [&](const uint32_t &SC_index, uint32_t &LC_index) {
445  tmpLC.addCluEnergy(SimLCenergy);
446  LocalPoint SimLCpos(SimLCx / SimLCenergy, SimLCy / SimLCenergy, SimLCz / SimLCenergy);
447  tmpLC.addCluLocalPos(SimLCpos);
448  SimLCenergy = 0.;
449  SimLCx = 0.;
450  SimLCy = 0.;
451  SimLCz = 0.;
452  tmpLC.addCluIndex(SC_index);
453  tmpLC.computeClusterTime();
454  output_.pMtdSimLayerClusters->push_back(tmpLC);
455  LC_indices.push_back(LC_index);
456  LC_index++;
457  tmpLC.clear();
458  };
459 
460  // fill tmpLC with the first hit
461  push_back_hit(prev);
462  update_clu_info(prev);
463  for (const auto &ind : indices) {
464  if (ind == indices[0])
465  continue;
466  DetId id(hAndR[ind].first);
467  if (geomTools_.isETL(id) != geomTools_.isETL(prevId) or geomTools_.layer(id) != geomTools_.layer(prevId) or
468  geomTools_.module(id) != geomTools_.module(prevId) or
469  ((hAndR[ind].second).first == (hAndR[prev].second).first and
470  (hAndR[ind].second).second != (hAndR[prev].second).second + 1) or
471  ((hAndR[ind].second).second == (hAndR[prev].second).second and
472  (hAndR[ind].second).first != (hAndR[prev].second).first + 1)) {
473  // the next hit is not adjacent to the previous one, put the current temporary cluster in the collection
474  // and the hit will be put in an empty temporary cluster
475  push_back_clu(SC_index, LC_index);
476  }
477  // add the hit to the temporary cluster
478  push_back_hit(ind);
479  update_clu_info(ind);
480  prev = ind;
481  DetId newId(hAndR[prev].first);
482  prevId = newId;
483  }
484  // add the remaining temporary cluster to the collection
485  push_back_clu(SC_index, LC_index);
486 
487  // now the simTrackster: find position and time of the first simHit
488  // bc right now there is no method to ask the simTrack for pos/time
489  // at MTD entrance
490  float timeAtEntrance = 99.;
491  uint32_t idAtEntrance = 0;
492  for (uint32_t i = 0; i < (uint32_t)hAndT.size(); i++) {
493  if (hAndT[i].second < timeAtEntrance) {
494  timeAtEntrance = hAndT[i].second;
495  idAtEntrance = i;
496  }
497  }
498 
499  // sort LCs in the SimTrackster by time
500  auto &MtdSimLayerClusters = output_.pMtdSimLayerClusters;
501  std::sort(LC_indices.begin(), LC_indices.end(), [&MtdSimLayerClusters](int i, int j) {
502  return (*MtdSimLayerClusters)[i].simLCTime() < (*MtdSimLayerClusters)[j].simLCTime();
503  });
504 
505  GlobalPoint posAtEntrance = geomTools_
506  .position((DetId)hAndR[idAtEntrance].first,
507  (hAndR[idAtEntrance].second).first,
508  (hAndR[idAtEntrance].second).second)
509  .second;
510  output_.pMtdSimTracksters->emplace_back(sc, LC_indices, timeAtEntrance, posAtEntrance);
511  SC_index++;
512  }
513 
514 #ifdef PRINT_DEBUG
515  IfLogDebug(DEBUG, messageCategory_) << "SIMLAYERCLUSTERS LIST: \n";
516  for (auto &sc : *output_.pMtdSimLayerClusters) {
517  IfLogDebug(DEBUG, messageCategory_) << std::fixed << std::setprecision(3) << "SimLayerCluster with:"
518  << "\n CP charge " << sc.charge() << "\n CP pdgId " << sc.pdgId()
519  << "\n CP energy " << sc.energy() << " GeV\n CP eta " << sc.eta()
520  << "\n CP phi " << sc.phi()
521  << "\n number of cells = " << sc.hits_and_fractions().size() << std::endl;
522  for (unsigned int i = 0; i < sc.hits_and_fractions().size(); ++i) {
523  DetId id(sc.detIds_and_rows()[i].first);
525  << std::fixed << std::setprecision(3) << " hit " << sc.detIds_and_rows()[i].first << " on layer "
526  << geomTools_.layer(id) << " at time " << sc.hits_and_times()[i].second << " ns" << std::endl;
527  }
528  IfLogDebug(DEBUG, messageCategory_) << std::fixed << std::setprecision(3) << " Cluster time " << sc.simLCTime()
529  << " ns \n Cluster pos" << sc.simLCPos() << " cm\n"
530  << std::fixed << std::setprecision(6) << " Cluster energy "
531  << convertUnitsTo(0.001_MeV, sc.simLCEnergy()) << " MeV" << std::endl;
532  IfLogDebug(DEBUG, messageCategory_) << "--------------\n";
533  }
534  IfLogDebug(DEBUG, messageCategory_) << std::endl;
535 
536  IfLogDebug(DEBUG, messageCategory_) << "SIMTRACKSTERS LIST: \n";
537  for (auto &sc : *output_.pMtdSimTracksters) {
538  IfLogDebug(DEBUG, messageCategory_) << std::fixed << std::setprecision(3) << "SimTrackster with:"
539  << "\n CP charge " << sc.charge() << "\n CP pdgId " << sc.pdgId()
540  << "\n CP energy " << sc.energy() << " GeV\n CP eta " << sc.eta()
541  << "\n CP phi " << sc.phi()
542  << "\n number of layer clusters = " << sc.numberOfClusters()
543  << "\n time of first simhit " << sc.time() << " ns\n position of first simhit"
544  << sc.position() << "cm" << std::endl;
545  IfLogDebug(DEBUG, messageCategory_) << " LCs indices: ";
546  for (const auto &lc : sc.clusters())
547  IfLogDebug(DEBUG, messageCategory_) << lc << ", ";
548  IfLogDebug(DEBUG, messageCategory_) << "\n--------------\n";
549  }
550  IfLogDebug(DEBUG, messageCategory_) << std::endl;
551 #endif
552 
553  event.put(std::move(output_.pMtdSimLayerClusters), "MergedMtdTruthLC");
554  event.put(std::move(output_.pMtdSimTracksters), "MergedMtdTruthST");
555 
556  // now fill the calo particles
557  for (unsigned i = 0; i < output_.pCaloParticles->size(); ++i) {
558  auto &cp = (*output_.pCaloParticles)[i];
559  for (unsigned j = m_caloParticles.sc_start_[i]; j < m_caloParticles.sc_stop_[i]; ++j) {
560  edm::Ref<MtdSimClusterCollection> ref(scHandle, j);
561  cp.addSimCluster(ref);
562  }
563  }
564  event.put(std::move(output_.pCaloParticles), "MergedMtdTruth");
565 
567 
568  std::unordered_map<uint64_t, float>().swap(m_detIdToTotalSimEnergy);
569  std::unordered_multimap<Barcode_t, Index_t>().swap(m_simHitBarcodeToIndex);
570 }
571 
572 template <class T>
574  const edm::EventSetup &setup,
575  const edm::Handle<edm::HepMCProduct> &hepMCproduct) {
577  edm::Handle<std::vector<int>> hGenParticleIndices;
578 
579  event.getByLabel(simTrackLabel_, hSimTracks);
580  event.getByLabel(simVertexLabel_, hSimVertices);
581 
582  event.getByLabel(genParticleLabel_, hGenParticles);
583  event.getByLabel(genParticleLabel_, hGenParticleIndices);
584 
585  std::vector<std::pair<uint64_t, const PSimHit *>> simHitPointers;
586  std::unordered_map<int, std::map<uint64_t, float>> simTrackDetIdEnergyMap;
587  std::unordered_map<int, std::map<uint64_t, float>> simTrackDetIdTimeMap;
588  fillSimHits(simHitPointers, simTrackDetIdEnergyMap, simTrackDetIdTimeMap, event, setup);
589 
590  // Clear maps from previous event fill them for this one
591  m_simHitBarcodeToIndex.clear();
592  for (unsigned int i = 0; i < simHitPointers.size(); ++i) {
593  m_simHitBarcodeToIndex.emplace(simHitPointers[i].second->trackId(), i);
594  }
595 
596  auto const &tracks = *hSimTracks;
597  auto const &vertices = *hSimVertices;
598  std::unordered_map<int, int> trackid_to_track_index;
599  std::unordered_map<uint32_t, float> vertex_time_map;
601 
602  for (uint32_t i = 0; i < vertices.size(); i++) {
603  vertex_time_map[i] = vertices[i].position().t() * 1e9 + event.bunchCrossing() * bunchSpacing_;
604  }
605 
606  IfLogDebug(DEBUG, messageCategory_) << " TRACKS" << std::endl;
607  int idx = 0;
608  for (auto const &t : tracks) {
609  IfLogDebug(DEBUG, messageCategory_) << " " << idx << "\t" << t.trackId() << "\t" << t << std::endl;
610  trackid_to_track_index[t.trackId()] = idx;
611  idx++;
612  }
613 
640  idx = 0;
641  std::vector<int> used_sim_tracks(tracks.size(), 0);
642  std::vector<int> collapsed_vertices(vertices.size(), 0);
643  IfLogDebug(DEBUG, messageCategory_) << " VERTICES" << std::endl;
644  for (auto const &v : vertices) {
645  IfLogDebug(DEBUG, messageCategory_) << " " << idx++ << "\t" << v << std::endl;
646  if (v.parentIndex() != -1) {
647  auto const trk_idx = trackid_to_track_index[v.parentIndex()];
648  auto origin_vtx = tracks[trk_idx].vertIndex();
649  if (used_sim_tracks[trk_idx]) {
650  // collapse the vertex into the original first vertex we saw associated
651  // to this track. Omit adding the edge in order to avoid double
652  // counting of the very same particles and its associated hits.
653  collapsed_vertices[v.vertexId()] = used_sim_tracks[trk_idx];
654  continue;
655  }
656  // Perform the actual vertex collapsing, if needed.
657  if (collapsed_vertices[origin_vtx])
658  origin_vtx = collapsed_vertices[origin_vtx];
659  add_edge(origin_vtx,
660  v.vertexId(),
661  EdgeProperty(&tracks[trk_idx], simTrackDetIdEnergyMap[v.parentIndex()].size(), 0),
662  decay);
663  used_sim_tracks[trk_idx] = v.vertexId();
664  }
665  }
666  // Build the motherParticle property to each vertex
667  auto const &vertexMothersProp = get(vertex_name, decay);
668  // Now recover the particles that did not decay. Append them with an index
669  // bigger than the size of the generated vertices.
670  int offset = vertices.size();
671  for (size_t i = 0; i < tracks.size(); ++i) {
672  if (!used_sim_tracks[i]) {
673  auto origin_vtx = tracks[i].vertIndex();
674  // Perform the actual vertex collapsing, if needed.
675  if (collapsed_vertices[origin_vtx])
676  origin_vtx = collapsed_vertices[origin_vtx];
677  add_edge(
678  origin_vtx, offset, EdgeProperty(&tracks[i], simTrackDetIdEnergyMap[tracks[i].trackId()].size(), 0), decay);
679  // The properties for "fake" vertices associated to stable particles have
680  // to be set inside this loop, since they do not belong to the vertices
681  // collection and would be skipped by that loop (coming next)
682  put(vertexMothersProp, offset, VertexProperty(&tracks[i], 0));
683  offset++;
684  }
685  }
686  for (auto const &v : vertices) {
687  if (v.parentIndex() != -1) {
688  // Skip collapsed_vertices
689  if (collapsed_vertices[v.vertexId()])
690  continue;
691  put(vertexMothersProp, v.vertexId(), VertexProperty(&tracks[trackid_to_track_index[v.parentIndex()]], 0));
692  }
693  }
694  SimHitsAccumulator_dfs_visitor vis;
695  depth_first_search(decay, visitor(vis));
696  CaloParticle_dfs_visitor caloParticleCreator(
697  output_,
700  simTrackDetIdEnergyMap,
701  simTrackDetIdTimeMap,
702  vertex_time_map,
703  [&](EdgeProperty &edge_property) -> bool {
704  // Apply selection on SimTracks in order to promote them to be
705  // CaloParticles. The function returns TRUE if the particle satisfies
706  // the selection, FALSE otherwise. Therefore the correct logic to select
707  // the particle is to ask for TRUE as return value.
708  return (edge_property.cumulative_simHits != 0 and !edge_property.simTrack->noGenpart() and
709  edge_property.simTrack->momentum().E() > minEnergy_ and
710  std::abs(edge_property.simTrack->momentum().Eta()) < maxPseudoRapidity_);
711  });
712  depth_first_search(decay, visitor(caloParticleCreator));
713 
714 #if DEBUG
715  boost::write_graphviz(std::cout,
716  decay,
717  make_label_writer(make_transform_value_property_map(&graphviz_vertex, get(vertex_name, decay))),
718  make_label_writer(make_transform_value_property_map(&graphviz_edge, get(edge_weight, decay))));
719 #endif
720 }
721 
722 template <class T>
723 void MtdTruthAccumulator::fillSimHits(std::vector<std::pair<uint64_t, const PSimHit *>> &returnValue,
724  std::unordered_map<int, std::map<uint64_t, float>> &simTrackDetIdEnergyMap,
725  std::unordered_map<int, std::map<uint64_t, float>> &simTrackDetIdTimeMap,
726  const T &event,
727  const edm::EventSetup &setup) {
728  using namespace geant_units::operators;
729  using namespace angle_units::operators;
730  for (auto const &collectionTag : collectionTags_) {
732  event.getByLabel(collectionTag, hSimHits);
733 
734  for (auto const &simHit : *hSimHits) {
735  DetId id(0);
736 
737  // --- Use only hits compatible with the in-time bunch-crossing
738  if (simHit.tof() < 0 || simHit.tof() > 25.)
739  continue;
740 
741  id = simHit.detUnitId();
742 
743  if (id == DetId(0)) {
744  edm::LogWarning(messageCategory_) << "Invalid DetId for the current simHit!";
745  continue;
746  }
747 
748  if (simHit.trackId() == 0) {
749  continue;
750  }
751 
752  returnValue.emplace_back(id, &simHit);
753 
754  // get an unique id: for BTL the detId is unique (one for each crystal), for ETL the detId is not enough
755  // also row and column are needed. An unique number is created from detId, row, col
756  // Get row and column
757  const auto &position = simHit.localPosition();
759  std::pair<uint8_t, uint8_t> pixel = geomTools_.pixelInModule(id, simscaled);
760  // create the unique id
761  uint64_t uniqueId = static_cast<uint64_t>(id.rawId()) << 32;
762  uniqueId |= pixel.first << 16;
763  uniqueId |= pixel.second;
764 
765  simTrackDetIdEnergyMap[simHit.trackId()][uniqueId] += simHit.energyLoss();
766  m_detIdToTotalSimEnergy[uniqueId] += simHit.energyLoss();
767  // --- Get the time of the first SIM hit in the cell
768  if (simTrackDetIdTimeMap[simHit.trackId()][uniqueId] == 0. ||
769  simHit.tof() < simTrackDetIdTimeMap[simHit.trackId()][uniqueId]) {
770  simTrackDetIdTimeMap[simHit.trackId()][uniqueId] = simHit.tof();
771  }
772 
773 #ifdef PRINT_DEBUG
775  << "hitId " << id.rawId() << " from track " << simHit.trackId() << " in layer " << geomTools_.layer(id)
776  << ", module " << geomTools_.module(id) << ", pixel ( " << (int)geomTools_.pixelInModule(id, simscaled).first
777  << ", " << (int)geomTools_.pixelInModule(id, simscaled).second << " )\n global pos(cm) "
778  << geomTools_.globalPosition(id, simscaled) << ", time(ns) " << simHit.tof() << ", energy(MeV) "
779  << convertUnitsTo(0.001_MeV, simHit.energyLoss()) << std::endl;
780 #endif
781  } // end of loop over simHits
782  } // end of loop over InputTags
783 }
784 
785 // Register with the framework
size
Write out results.
void initializeEvent(const edm::Event &event, const edm::EventSetup &setup) override
std::vector< MtdSimLayerCluster > MtdSimLayerClusterCollection
EDGetTokenT< ProductType > consumes(edm::InputTag const &tag)
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
const edm::ESGetToken< MTDTopology, MTDTopologyRcd > mtdtopoToken_
const edm::InputTag simVertexLabel_
GlobalPoint globalPosition(const DetId &id, const LocalPoint &local_point) const
Definition: MTDGeomUtil.cc:58
std::vector< MtdCaloParticle > MtdCaloParticleCollection
ProductRegistryHelper::BranchAliasSetterT< ProductType > produces()
MtdTruthAccumulator(const edm::ParameterSet &config, edm::ProducesCollector, edm::ConsumesCollector &iC)
std::pair< float, float > pixelInModule(const DetId &id, const int row, const int column) const
Definition: MTDGeomUtil.cc:111
edm::InputTag genParticleLabel_
std::unique_ptr< MtdCaloParticleCollection > pCaloParticles
const edm::InputTag simTrackLabel_
const edm::ESGetToken< MTDGeometry, MTDDigiGeometryRecord > geomToken_
const std::string messageCategory_
const unsigned int maximumSubsequentBunchCrossing_
const MTDGeometry * geom
#define DEBUG
const MTDTopology * topology
Definition: config.py:1
void fillSimHits(std::vector< std::pair< uint64_t, const PSimHit *>> &returnValue, std::unordered_map< int, std::map< uint64_t, float >> &simTrackDetIdEnergyMap, std::unordered_map< int, std::map< uint64_t, float >> &simTrackDetIdTimeMap, const T &event, const edm::EventSetup &setup)
Fills the supplied vector with pointers to the SimHits, checking for bad modules if required...
std::unique_ptr< MtdSimTracksterCollection > pMtdSimTracksters
void accumulateEvent(const T &event, const edm::EventSetup &setup, const edm::Handle< edm::HepMCProduct > &hepMCproduct)
Both forms of accumulate() delegate to this templated method.
const unsigned int bunchSpacing_
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
Definition: Activities.doc:4
void swap(Association< C > &lhs, Association< C > &rhs)
Definition: Association.h:117
const math::XYZTLorentzVectorD & momentum() const
Definition: CoreSimTrack.h:19
void setTopology(MTDTopology const *topo)
Definition: MTDGeomUtil.cc:12
constexpr NumType convertUnitsTo(double desiredUnits, NumType val)
Definition: GeantUnits.h:73
void put(edm::Event &evt, double value, const char *instanceName)
const SimTrack * simTrack
Definition: DecayGraph.h:61
U second(std::pair< T, U > const &p)
#define IfLogDebug(cond, cat)
std::unique_ptr< MtdSimLayerClusterCollection > pMtdSimLayerClusters
adjacency_list< listS, vecS, directedS, VertexMotherParticleProperty, EdgeParticleClustersProperty > DecayChain
Definition: DecayGraph.h:77
unsigned int layer(const DetId &) const
Definition: MTDGeomUtil.cc:89
int cumulative_simHits
Definition: DecayGraph.h:63
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
std::unordered_multimap< Barcode_t, Index_t > m_simHitBarcodeToIndex
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
OutputCollections output_
std::pair< LocalPoint, GlobalPoint > position(const DetId &id, int row=0, int column=0) const
Definition: MTDGeomUtil.cc:27
std::unique_ptr< MtdSimClusterCollection > pSimClusters
Functor that operates on <T>
Definition: Selector.h:22
void setGeometry(MTDGeometry const *geom)
Definition: MTDGeomUtil.cc:10
calo_particles m_caloParticles
const unsigned int maximumPreviousBunchCrossing_
Log< level::Info, false > LogInfo
Definition: DetId.h:17
constexpr NumType convertMmToCm(NumType millimeters)
Definition: angle_units.h:44
unsigned long long uint64_t
Definition: Time.h:13
bool isETL(const DetId &) const
Definition: MTDGeomUtil.cc:14
double b
Definition: hdecay.h:120
edm::Handle< std::vector< SimVertex > > hSimVertices
std::vector< edm::InputTag > collectionTags_
bool noGenpart() const
Definition: SimTrack.h:38
std::unordered_map< uint64_t, float > m_detIdToTotalSimEnergy
HLT enums.
#define DEFINE_DIGI_ACCUMULATOR(type)
double a
Definition: hdecay.h:121
static int position[264][3]
Definition: ReadPGInfo.cc:289
void accumulate(const edm::Event &event, const edm::EventSetup &setup) override
std::vector< MtdSimCluster > MtdSimClusterCollection
int module(const DetId &) const
Definition: MTDGeomUtil.cc:98
edm::Handle< std::vector< SimTrack > > hSimTracks
Log< level::Warning, false > LogWarning
long double T
void finalizeEvent(edm::Event &event, const edm::EventSetup &setup) override
static std::string const source
Definition: EdmProvDump.cc:49
mtd::MTDGeomUtil geomTools_
std::vector< MtdSimTrackster > MtdSimTracksterCollection
def move(src, dest)
Definition: eostools.py:511
edm::InputTag hepMCproductLabel_
Needed to add HepMC::GenVertex to SimVertex.
Definition: event.py:1