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 #define PRINT_DEBUG true
6 
7 #if DEBUG
8 #pragma GCC diagnostic pop
9 #endif
10 
11 #include <algorithm>
12 #include <iterator>
13 #include <exception>
14 #include <memory>
15 
16 #include <numeric> // for std::accumulate
17 #include <unordered_map>
18 
27 
34 
46 
52 
60 
61 namespace {
62  using Index_t = unsigned;
63  using Barcode_t = int;
64  const std::string messageCategoryGraph_("MtdTruthAccumulatorGraphProducer");
65 } // namespace
66 
68 public:
70 
71 private:
72  void initializeEvent(const edm::Event &event, const edm::EventSetup &setup) override;
73  void accumulate(const edm::Event &event, const edm::EventSetup &setup) override;
74  void accumulate(const PileUpEventPrincipal &event, const edm::EventSetup &setup, edm::StreamID const &) override;
75  void finalizeEvent(edm::Event &event, const edm::EventSetup &setup) override;
76 
78  template <class T>
79  void accumulateEvent(const T &event,
80  const edm::EventSetup &setup,
81  const edm::Handle<edm::HepMCProduct> &hepMCproduct);
82 
85  template <class T>
86  void fillSimHits(std::vector<std::pair<uint64_t, const PSimHit *>> &returnValue,
87  std::unordered_map<int, std::map<uint64_t, std::tuple<float, float, LocalPoint>>> &simTrackDetIdMap,
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(
169  std::unordered_multimap<Barcode_t, Index_t> &simHitBarcodeToIndex,
170  std::unordered_map<int, std::map<uint64_t, std::tuple<float, float, LocalPoint>>> &simTrackDetIdMap,
171  std::unordered_map<uint32_t, float> &vertex_time_map,
173  : output_(output),
174  caloParticles_(caloParticles),
175  simHitBarcodeToIndex_(simHitBarcodeToIndex),
176  simTrackDetIdMap_(simTrackDetIdMap),
177  vertex_time_map_(vertex_time_map),
178  selector_(selector) {}
179  template <typename Vertex, typename Graph>
180  void discover_vertex(Vertex u, const Graph &g) {
181  // If we reach the vertex 0, it means that we are backtracking with respect
182  // to the first generation of stable particles: simply return;
183  // if (u == 0) return;
184  print_vertex(u, g);
185  auto const vertex_property = get(vertex_name, g, u);
186  if (!vertex_property.simTrack)
187  return;
188  // -- loop over possible trackIdOffsets to save also sim clusters from non-direct hits
189  for (unsigned int offset = 0; offset < 4; offset++) {
190  auto trackIdx = vertex_property.simTrack->trackId();
191  trackIdx += offset * (static_cast<int>(PSimHit::k_tidOffset));
192  IfLogDebug(DEBUG, messageCategoryGraph_)
193  << " Found " << simHitBarcodeToIndex_.count(trackIdx) << " associated simHits" << std::endl;
194  if (simHitBarcodeToIndex_.count(trackIdx)) {
195  output_.pSimClusters->emplace_back(*vertex_property.simTrack);
196  auto &simcluster = output_.pSimClusters->back();
197  std::unordered_map<uint64_t, float> acc_energy;
198  for (auto const &hit_and_energy : simTrackDetIdMap_[trackIdx]) {
199  acc_energy[hit_and_energy.first] += std::get<0>(hit_and_energy.second);
200  }
201  for (auto const &hit_and_energy : acc_energy) {
202  simcluster.addHitAndFraction(hit_and_energy.first, hit_and_energy.second);
203  simcluster.addHitEnergy(hit_and_energy.second);
204  simcluster.addHitTime(std::get<1>(
205  simTrackDetIdMap_[simcluster.g4Tracks()[0].trackId() +
206  offset * (static_cast<int>(PSimHit::k_tidOffset))][hit_and_energy.first]));
207  simcluster.addHitPosition(std::get<2>(
208  simTrackDetIdMap_[simcluster.g4Tracks()[0].trackId() +
209  offset * (static_cast<int>(PSimHit::k_tidOffset))][hit_and_energy.first]));
210  simcluster.setTrackIdOffset(offset);
211  }
212  }
213  }
214  }
215 
216  template <typename Edge, typename Graph>
217  void examine_edge(Edge e, const Graph &g) {
218  auto src = source(e, g);
219  auto vertex_property = get(vertex_name, g, src);
220  if (src == 0 or (vertex_property.simTrack == nullptr)) {
221  auto edge_property = get(edge_weight, g, e);
222  IfLogDebug(DEBUG, messageCategoryGraph_) << "Considering CaloParticle: " << edge_property.simTrack->trackId();
223  if (selector_(edge_property)) {
224  IfLogDebug(DEBUG, messageCategoryGraph_) << "Adding CaloParticle: " << edge_property.simTrack->trackId();
225  output_.pCaloParticles->emplace_back(*(edge_property.simTrack));
226  output_.pCaloParticles->back().addSimTime(vertex_time_map_[(edge_property.simTrack)->vertIndex()]);
227  caloParticles_.sc_start_.push_back(output_.pSimClusters->size());
228  }
229  }
230  }
231 
232  template <typename Edge, typename Graph>
233  void finish_edge(Edge e, const Graph &g) {
234  auto src = source(e, g);
235  auto vertex_property = get(vertex_name, g, src);
236  if (src == 0 or (vertex_property.simTrack == nullptr)) {
237  auto edge_property = get(edge_weight, g, e);
238  if (selector_(edge_property)) {
239  caloParticles_.sc_stop_.push_back(output_.pSimClusters->size());
240  }
241  }
242  }
243 
244  private:
246  MtdTruthAccumulator::calo_particles &caloParticles_;
247  std::unordered_multimap<Barcode_t, Index_t> &simHitBarcodeToIndex_;
248  std::unordered_map<int, std::map<uint64_t, std::tuple<float, float, LocalPoint>>> &simTrackDetIdMap_;
249  std::unordered_map<uint32_t, float> &vertex_time_map_;
250  Selector selector_;
251  };
252 } // Namespace
253 
255  edm::ProducesCollector producesCollector,
257  : messageCategory_("MtdTruthAccumulator"),
258  maximumPreviousBunchCrossing_(config.getParameter<unsigned int>("maximumPreviousBunchCrossing")),
259  maximumSubsequentBunchCrossing_(config.getParameter<unsigned int>("maximumSubsequentBunchCrossing")),
260  bunchSpacing_(config.getParameter<unsigned int>("bunchspace")),
261  simTrackLabel_(config.getParameter<edm::InputTag>("simTrackCollection")),
262  simVertexLabel_(config.getParameter<edm::InputTag>("simVertexCollection")),
263  collectionTags_(),
264  genParticleLabel_(config.getParameter<edm::InputTag>("genParticleCollection")),
265  hepMCproductLabel_(config.getParameter<edm::InputTag>("HepMCProductLabel")),
266  geomToken_(iC.esConsumes<MTDGeometry, MTDDigiGeometryRecord>()),
267  mtdtopoToken_(iC.esConsumes<MTDTopology, MTDTopologyRcd>()),
268  minEnergy_(config.getParameter<double>("MinEnergy")),
269  maxPseudoRapidity_(config.getParameter<double>("MaxPseudoRapidity")),
270  premixStage1_(config.getParameter<bool>("premixStage1")) {
271  iC.consumes<std::vector<SimTrack>>(simTrackLabel_);
272  iC.consumes<std::vector<SimVertex>>(simVertexLabel_);
273  iC.consumes<std::vector<reco::GenParticle>>(genParticleLabel_);
274  iC.consumes<std::vector<int>>(genParticleLabel_);
275  iC.consumes<std::vector<int>>(hepMCproductLabel_);
276 
277  // Fill the collection tags
278  const edm::ParameterSet &simHitCollectionConfig = config.getParameterSet("simHitCollections");
279  std::vector<std::string> parameterNames = simHitCollectionConfig.getParameterNames();
280 
281  for (auto const &parameterName : parameterNames) {
282  std::vector<edm::InputTag> tags = simHitCollectionConfig.getParameter<std::vector<edm::InputTag>>(parameterName);
283  collectionTags_.insert(collectionTags_.end(), tags.begin(), tags.end());
284  }
285 
286  for (auto const &collectionTag : collectionTags_) {
287  iC.consumes<std::vector<PSimHit>>(collectionTag);
288  isEtl_ = (collectionTag.instance().find("FastTimerHitsEndcap") != std::string::npos);
289  }
290 
291  producesCollector.produces<MtdSimClusterCollection>("MergedMtdTruth");
292  producesCollector.produces<MtdSimLayerClusterCollection>("MergedMtdTruthLC");
293  producesCollector.produces<MtdSimTracksterCollection>("MergedMtdTruthST");
294  producesCollector.produces<MtdCaloParticleCollection>("MergedMtdTruth");
295  if (premixStage1_) {
296  producesCollector.produces<std::vector<std::pair<uint64_t, float>>>("MergedMtdTruth");
297  }
298 }
299 
301  output_.pSimClusters = std::make_unique<MtdSimClusterCollection>();
302  output_.pCaloParticles = std::make_unique<MtdCaloParticleCollection>();
303 
304  output_.pMtdSimLayerClusters = std::make_unique<MtdSimLayerClusterCollection>();
305  output_.pMtdSimTracksters = std::make_unique<MtdSimTracksterCollection>();
306 
307  m_detIdToTotalSimEnergy.clear();
308 
309  auto geometryHandle = setup.getTransientHandle(geomToken_);
310  geom = geometryHandle.product();
311 
312  auto topologyHandle = setup.getTransientHandle(mtdtopoToken_);
313  topology = topologyHandle.product();
314 
317 }
318 
328  event.getByLabel(hepMCproductLabel_, hepmc);
329 
330  edm::LogInfo(messageCategory_) << " MtdTruthAccumulator::accumulate (signal)";
331  accumulateEvent(event, setup, hepmc);
332 }
333 
335  edm::EventSetup const &setup,
336  edm::StreamID const &) {
337  if (event.bunchCrossing() >= -static_cast<int>(maximumPreviousBunchCrossing_) &&
338  event.bunchCrossing() <= static_cast<int>(maximumSubsequentBunchCrossing_)) {
339  // simply create empty handle as we do not have a HepMCProduct in PU anyway
341  edm::LogInfo(messageCategory_) << " MtdTruthAccumulator::accumulate (pileup) bunchCrossing="
342  << event.bunchCrossing();
343  accumulateEvent(event, setup, hepmc);
344  } else {
345  edm::LogInfo(messageCategory_) << "Skipping pileup event for bunch crossing " << event.bunchCrossing();
346  }
347 }
348 
350  using namespace geant_units::operators;
351 
352  edm::LogInfo(messageCategory_) << "Adding " << output_.pSimClusters->size() << " SimParticles and "
353  << output_.pCaloParticles->size() << " CaloParticles to the event.";
354 
355  // We need to normalize the hits and energies into hits and fractions (since
356  // we have looped over all pileup events)
357  // For premixing stage1 we keep the energies, they will be normalized to
358  // fractions in stage2
359 
360  if (premixStage1_) {
361  auto totalEnergies = std::make_unique<std::vector<std::pair<uint64_t, float>>>();
362  totalEnergies->reserve(m_detIdToTotalSimEnergy.size());
363  std::copy(m_detIdToTotalSimEnergy.begin(), m_detIdToTotalSimEnergy.end(), std::back_inserter(*totalEnergies));
364  std::sort(totalEnergies->begin(), totalEnergies->end());
365  event.put(std::move(totalEnergies), "MergedMtdTruth");
366  } else {
367  for (auto &sc : *(output_.pSimClusters)) {
368  auto hitsAndEnergies = sc.hits_and_fractions();
369  sc.clearHitsAndFractions();
370  sc.clearHitsEnergy();
371  for (auto &hAndE : hitsAndEnergies) {
372  const float totalenergy = m_detIdToTotalSimEnergy[hAndE.first];
373  float fraction = 0.;
374  if (totalenergy > 0)
375  fraction = hAndE.second / totalenergy;
376  else
378  << "TotalSimEnergy for hit " << hAndE.first << " is 0! The fraction for this hit cannot be computed.";
379  sc.addHitAndFraction(hAndE.first, fraction);
380  sc.addHitEnergy(hAndE.second);
381  }
382  }
383  }
384 
385 #ifdef PRINT_DEBUG
386  IfLogDebug(DEBUG, messageCategory_) << "SIMCLUSTERS LIST:" << std::endl;
387  for (const auto &sc : *(output_.pSimClusters)) {
388  IfLogDebug(DEBUG, messageCategory_) << std::fixed << std::setprecision(3) << "SimCluster from CP with:"
389  << "\n charge " << sc.charge() << "\n pdgId " << sc.pdgId() << "\n energy "
390  << sc.energy() << " GeV\n eta " << sc.eta() << "\n phi " << sc.phi()
391  << "\n number of cells = " << sc.hits_and_fractions().size() << std::endl;
392  for (unsigned int i = 0; i < sc.hits_and_fractions().size(); ++i) {
393  DetId id(sc.detIds_and_rows()[i].first);
395  << std::fixed << std::setprecision(3) << " hit " << id.rawId() << " on layer " << geomTools_.layer(id)
396  << " module " << geomTools_.module(id) << " row " << (unsigned int)(sc.detIds_and_rows()[i].second).first
397  << " col " << (unsigned int)(sc.detIds_and_rows()[i].second).second << " at time "
398  << sc.hits_and_times()[i].second << " ns" << std::endl;
399  }
400  IfLogDebug(DEBUG, messageCategory_) << "--------------\n";
401  }
402  IfLogDebug(DEBUG, messageCategory_) << std::endl;
403 #endif
404 
405  // save the SimCluster orphan handle so we can fill the calo particles
406  auto scHandle = event.put(std::move(output_.pSimClusters), "MergedMtdTruth");
407 
408  // reserve for the best case scenario: already splitted
409  output_.pMtdSimLayerClusters->reserve(scHandle->size());
410  output_.pMtdSimTracksters->reserve(scHandle->size());
411 
412  uint32_t SC_index = 0;
413  uint32_t LC_index = 0;
414  for (const auto &sc : *scHandle) {
415  auto const &hAndF = sc.hits_and_fractions();
416  auto const &hAndE = sc.hits_and_energies();
417  auto const &hAndT = sc.hits_and_times();
418  auto const &hAndP = sc.hits_and_positions();
419  auto const &hAndR = sc.detIds_and_rows();
420  // create a vector with the indices of the hits in the simCluster
421  std::vector<int> indices(hAndF.size());
422  std::iota(indices.begin(), indices.end(), 0);
423  // sort the hits indices based on the unique indices created before
424  std::sort(indices.begin(), indices.end(), [&](int a, int b) { return hAndF[a].first < hAndF[b].first; });
425 
426  // now split the sc: loop on the sorted indices and save the first hit in a
427  // temporary simCluster. If the following hit is in the same module and row (column),
428  // but next column (row) put it in the temporary simcluster as well, otherwise
429  // put the temporary simcluster in the collection and start creating a new one
430  std::vector<uint32_t> LC_indices;
431  MtdSimLayerCluster tmpLC(sc.g4Tracks()[0]);
432  int prev = indices[0];
433  DetId prevId(hAndR[prev].first);
434 
435  float SimLCenergy = 0.;
436  float SimLCx = 0., SimLCy = 0., SimLCz = 0.;
437 
438  auto push_back_hit = [&](const int &ind) {
439  tmpLC.addHitAndFraction(hAndF[ind].first, hAndF[ind].second);
440  tmpLC.addHitEnergy(hAndE[ind].second);
441  tmpLC.addHitTime(hAndT[ind].second);
442  tmpLC.addHitPosition(hAndP[ind].second);
443  };
444 
445  auto update_clu_info = [&](const int &ind) {
446  double energy = hAndE[ind].second;
447  auto position = hAndP[ind].second;
448  if (geomTools_.isBTL((DetId)hAndR[ind].first)) {
449  BTLDetId detId{(DetId)hAndR[ind].first};
451  const MTDGeomDet *thedet = geom->idToDet(geoId);
452  const ProxyMTDTopology &topoproxy = static_cast<const ProxyMTDTopology &>(thedet->topology());
453  const RectangularMTDTopology &topo = static_cast<const RectangularMTDTopology &>(topoproxy.specificTopology());
454  position =
455  topo.pixelToModuleLocalPoint(hAndP[ind].second, (hAndR[ind].second).first, (hAndR[ind].second).second);
456  }
457  SimLCenergy += energy;
458  SimLCx += position.x() * energy;
459  SimLCy += position.y() * energy;
460  SimLCz += position.z() * energy;
461  };
462 
463  auto push_back_clu = [&](const uint32_t &SC_index, uint32_t &LC_index) {
464  tmpLC.addCluEnergy(SimLCenergy);
465  LocalPoint SimLCpos(SimLCx / SimLCenergy, SimLCy / SimLCenergy, SimLCz / SimLCenergy);
466  tmpLC.addCluLocalPos(SimLCpos);
467  SimLCenergy = 0.;
468  SimLCx = 0.;
469  SimLCy = 0.;
470  SimLCz = 0.;
471  tmpLC.addCluIndex(SC_index);
472  tmpLC.computeClusterTime();
473  tmpLC.setTrackIdOffset(sc.trackIdOffset()); // add trackIdoffset
474  output_.pMtdSimLayerClusters->push_back(tmpLC);
475  LC_indices.push_back(LC_index);
476  LC_index++;
477  tmpLC.clear();
478  };
479 
480  // fill tmpLC with the first hit
481  push_back_hit(prev);
482  update_clu_info(prev);
483  for (const auto &ind : indices) {
484  if (ind == indices[0])
485  continue;
486  DetId id(hAndR[ind].first);
487  if (geomTools_.isETL(id) != geomTools_.isETL(prevId) or geomTools_.layer(id) != geomTools_.layer(prevId) or
488  geomTools_.module(id) != geomTools_.module(prevId) or
489  ((hAndR[ind].second).first == (hAndR[prev].second).first and
490  (hAndR[ind].second).second != (hAndR[prev].second).second + 1) or
491  ((hAndR[ind].second).second == (hAndR[prev].second).second and
492  (hAndR[ind].second).first != (hAndR[prev].second).first + 1)) {
493  // the next hit is not adjacent to the previous one, put the current temporary cluster in the collection
494  // and the hit will be put in an empty temporary cluster
495  push_back_clu(SC_index, LC_index);
496  }
497  // add the hit to the temporary cluster
498  push_back_hit(ind);
499  update_clu_info(ind);
500  prev = ind;
501  DetId newId(hAndR[prev].first);
502  prevId = newId;
503  }
504  // add the remaining temporary cluster to the collection
505  push_back_clu(SC_index, LC_index);
506 
507  // now the simTrackster: find position and time of the first simHit
508  // bc right now there is no method to ask the simTrack for pos/time
509  // at MTD entrance
510  float timeAtEntrance = 99.;
511  uint32_t idAtEntrance = 0;
512  for (uint32_t i = 0; i < (uint32_t)hAndT.size(); i++) {
513  if (hAndT[i].second < timeAtEntrance) {
514  timeAtEntrance = hAndT[i].second;
515  idAtEntrance = i;
516  }
517  }
518 
519  // sort LCs in the SimTrackster by time
520  auto &MtdSimLayerClusters = output_.pMtdSimLayerClusters;
521  std::sort(LC_indices.begin(), LC_indices.end(), [&MtdSimLayerClusters](int i, int j) {
522  return (*MtdSimLayerClusters)[i].simLCTime() < (*MtdSimLayerClusters)[j].simLCTime();
523  });
524 
525  GlobalPoint posAtEntrance = geomTools_
526  .position((DetId)hAndR[idAtEntrance].first,
527  (hAndR[idAtEntrance].second).first,
528  (hAndR[idAtEntrance].second).second)
529  .second;
530  output_.pMtdSimTracksters->emplace_back(sc, LC_indices, timeAtEntrance, posAtEntrance);
531  SC_index++;
532  }
533 
534 #ifdef PRINT_DEBUG
535  IfLogDebug(DEBUG, messageCategory_) << "SIMLAYERCLUSTERS LIST: \n";
536  for (auto &sc : *output_.pMtdSimLayerClusters) {
537  IfLogDebug(DEBUG, messageCategory_) << std::fixed << std::setprecision(3) << "SimLayerCluster with:"
538  << "\n CP charge " << sc.charge() << "\n CP pdgId " << sc.pdgId()
539  << "\n CP energy " << sc.energy() << " GeV\n CP eta " << sc.eta()
540  << "\n CP phi " << sc.phi()
541  << "\n number of cells = " << sc.hits_and_fractions().size() << std::endl;
542  for (unsigned int i = 0; i < sc.hits_and_fractions().size(); ++i) {
543  DetId id(sc.detIds_and_rows()[i].first);
545  << std::fixed << std::setprecision(3) << " hit " << sc.detIds_and_rows()[i].first << " on layer "
546  << geomTools_.layer(id) << " at time " << sc.hits_and_times()[i].second << " ns" << std::endl;
547  }
548  IfLogDebug(DEBUG, messageCategory_) << std::fixed << std::setprecision(3) << " Cluster time " << sc.simLCTime()
549  << " ns \n Cluster pos" << sc.simLCPos() << " cm\n"
550  << std::fixed << std::setprecision(6) << " Cluster energy "
551  << convertUnitsTo(0.001_MeV, sc.simLCEnergy()) << " MeV" << std::endl;
552  IfLogDebug(DEBUG, messageCategory_) << "--------------\n";
553  }
554  IfLogDebug(DEBUG, messageCategory_) << std::endl;
555 
556  IfLogDebug(DEBUG, messageCategory_) << "SIMTRACKSTERS LIST: \n";
557  for (auto &sc : *output_.pMtdSimTracksters) {
558  IfLogDebug(DEBUG, messageCategory_) << std::fixed << std::setprecision(3) << "SimTrackster with:"
559  << "\n CP charge " << sc.charge() << "\n CP pdgId " << sc.pdgId()
560  << "\n CP energy " << sc.energy() << " GeV\n CP eta " << sc.eta()
561  << "\n CP phi " << sc.phi()
562  << "\n number of layer clusters = " << sc.numberOfClusters()
563  << "\n time of first simhit " << sc.time() << " ns\n position of first simhit"
564  << sc.position() << "cm" << std::endl;
565  IfLogDebug(DEBUG, messageCategory_) << " LCs indices: ";
566  for (const auto &lc : sc.clusters())
567  IfLogDebug(DEBUG, messageCategory_) << lc << ", ";
568  IfLogDebug(DEBUG, messageCategory_) << "\n--------------\n";
569  }
570  IfLogDebug(DEBUG, messageCategory_) << std::endl;
571 #endif
572 
573  event.put(std::move(output_.pMtdSimLayerClusters), "MergedMtdTruthLC");
574  event.put(std::move(output_.pMtdSimTracksters), "MergedMtdTruthST");
575 
576  // now fill the calo particles
577  for (unsigned i = 0; i < output_.pCaloParticles->size(); ++i) {
578  auto &cp = (*output_.pCaloParticles)[i];
579  for (unsigned j = m_caloParticles.sc_start_[i]; j < m_caloParticles.sc_stop_[i]; ++j) {
580  edm::Ref<MtdSimClusterCollection> ref(scHandle, j);
581  cp.addSimCluster(ref);
582  }
583  }
584  event.put(std::move(output_.pCaloParticles), "MergedMtdTruth");
585 
587 
588  std::unordered_map<uint64_t, float>().swap(m_detIdToTotalSimEnergy);
589  std::unordered_multimap<Barcode_t, Index_t>().swap(m_simHitBarcodeToIndex);
590 }
591 
592 template <class T>
594  const edm::EventSetup &setup,
595  const edm::Handle<edm::HepMCProduct> &hepMCproduct) {
597  edm::Handle<std::vector<int>> hGenParticleIndices;
598 
599  event.getByLabel(simTrackLabel_, hSimTracks);
600  event.getByLabel(simVertexLabel_, hSimVertices);
601 
602  event.getByLabel(genParticleLabel_, hGenParticles);
603  event.getByLabel(genParticleLabel_, hGenParticleIndices);
604 
605  std::vector<std::pair<uint64_t, const PSimHit *>> simHitPointers;
606  std::unordered_map<int, std::map<uint64_t, std::tuple<float, float, LocalPoint>>> simTrackDetIdMap;
607  fillSimHits(simHitPointers, simTrackDetIdMap, event, setup);
608 
609  // Clear maps from previous event fill them for this one
610  m_simHitBarcodeToIndex.clear();
611  for (unsigned int i = 0; i < simHitPointers.size(); ++i) {
612  m_simHitBarcodeToIndex.emplace(simHitPointers[i].second->trackId(), i);
613  }
614 
615  auto const &tracks = *hSimTracks;
616  auto const &vertices = *hSimVertices;
617  std::unordered_map<int, int> trackid_to_track_index;
618  std::unordered_map<uint32_t, float> vertex_time_map;
620 
621  for (uint32_t i = 0; i < vertices.size(); i++) {
622  vertex_time_map[i] = vertices[i].position().t() * 1e9 + event.bunchCrossing() * static_cast<int>(bunchSpacing_);
623  }
624 
625  IfLogDebug(DEBUG, messageCategory_) << " TRACKS" << std::endl;
626  int idx = 0;
627  for (auto const &t : tracks) {
628  IfLogDebug(DEBUG, messageCategory_) << " " << idx << "\t" << t.trackId() << "\t" << t << std::endl;
629  trackid_to_track_index[t.trackId()] = idx;
630  idx++;
631  }
632 
659  idx = 0;
660  std::vector<int> used_sim_tracks(tracks.size(), 0);
661  std::vector<int> collapsed_vertices(vertices.size(), 0);
662  IfLogDebug(DEBUG, messageCategory_) << " VERTICES" << std::endl;
663  for (auto const &v : vertices) {
664  IfLogDebug(DEBUG, messageCategory_) << " " << idx++ << "\t" << v << std::endl;
665  if (v.parentIndex() != -1) {
666  auto const trk_idx = trackid_to_track_index[v.parentIndex()];
667  auto origin_vtx = tracks[trk_idx].vertIndex();
668  if (used_sim_tracks[trk_idx]) {
669  // collapse the vertex into the original first vertex we saw associated
670  // to this track. Omit adding the edge in order to avoid double
671  // counting of the very same particles and its associated hits.
672  collapsed_vertices[v.vertexId()] = used_sim_tracks[trk_idx];
673  continue;
674  }
675  // Perform the actual vertex collapsing, if needed.
676  if (collapsed_vertices[origin_vtx])
677  origin_vtx = collapsed_vertices[origin_vtx];
678  add_edge(
679  origin_vtx, v.vertexId(), EdgeProperty(&tracks[trk_idx], simTrackDetIdMap[v.parentIndex()].size(), 0), decay);
680  used_sim_tracks[trk_idx] = v.vertexId();
681  }
682  }
683  // Build the motherParticle property to each vertex
684  auto const &vertexMothersProp = get(vertex_name, decay);
685  // Now recover the particles that did not decay. Append them with an index
686  // bigger than the size of the generated vertices.
687  int offset = vertices.size();
688  for (size_t i = 0; i < tracks.size(); ++i) {
689  if (!used_sim_tracks[i]) {
690  auto origin_vtx = tracks[i].vertIndex();
691  // Perform the actual vertex collapsing, if needed.
692  if (collapsed_vertices[origin_vtx])
693  origin_vtx = collapsed_vertices[origin_vtx];
694  add_edge(origin_vtx, offset, EdgeProperty(&tracks[i], simTrackDetIdMap[tracks[i].trackId()].size(), 0), decay);
695  // The properties for "fake" vertices associated to stable particles have
696  // to be set inside this loop, since they do not belong to the vertices
697  // collection and would be skipped by that loop (coming next)
698  put(vertexMothersProp, offset, VertexProperty(&tracks[i], 0));
699  offset++;
700  }
701  }
702  for (auto const &v : vertices) {
703  if (v.parentIndex() != -1) {
704  // Skip collapsed_vertices
705  if (collapsed_vertices[v.vertexId()])
706  continue;
707  put(vertexMothersProp, v.vertexId(), VertexProperty(&tracks[trackid_to_track_index[v.parentIndex()]], 0));
708  }
709  }
710  SimHitsAccumulator_dfs_visitor vis;
711  depth_first_search(decay, visitor(vis));
712  CaloParticle_dfs_visitor caloParticleCreator(
713  output_,
716  simTrackDetIdMap,
717  vertex_time_map,
718  [&](EdgeProperty &edge_property) -> bool {
719  // Apply selection on SimTracks in order to promote them to be
720  // CaloParticles. The function returns TRUE if the particle satisfies
721  // the selection, FALSE otherwise. Therefore the correct logic to select
722  // the particle is to ask for TRUE as return value.
723  return (edge_property.cumulative_simHits != 0 and !edge_property.simTrack->noGenpart() and
724  edge_property.simTrack->momentum().E() > minEnergy_ and
725  std::abs(edge_property.simTrack->momentum().Eta()) < maxPseudoRapidity_);
726  });
727  depth_first_search(decay, visitor(caloParticleCreator));
728 
729 #if DEBUG
730  boost::write_graphviz(std::cout,
731  decay,
732  make_label_writer(make_transform_value_property_map(&graphviz_vertex, get(vertex_name, decay))),
733  make_label_writer(make_transform_value_property_map(&graphviz_edge, get(edge_weight, decay))));
734 #endif
735 }
736 
737 template <class T>
739  std::vector<std::pair<uint64_t, const PSimHit *>> &returnValue,
740  std::unordered_map<int, std::map<uint64_t, std::tuple<float, float, LocalPoint>>> &simTrackDetIdMap,
741  const T &event,
742  const edm::EventSetup &setup) {
743  using namespace geant_units::operators;
744  using namespace angle_units::operators;
745  for (auto const &collectionTag : collectionTags_) {
747  event.getByLabel(collectionTag, hSimHits);
748 
749  for (auto const &simHit : *hSimHits) {
750  DetId id(0);
751 
752  // --- Use only hits compatible with the in-time bunch-crossing
753  if (simHit.tof() < 0 || simHit.tof() > 25.)
754  continue;
755 
756  id = simHit.detUnitId();
757 
758  if (id == DetId(0)) {
759  edm::LogWarning(messageCategory_) << "Invalid DetId for the current simHit!";
760  continue;
761  }
762 
763  if (simHit.trackId() == 0) {
764  continue;
765  }
766 
767  returnValue.emplace_back(id, &simHit);
768 
769  // get an unique id: for BTL the detId is unique (one for each crystal), for ETL the detId is not enough
770  // also row and column are needed. An unique number is created from detId, row, col
771  // Get row and column
772  const auto &position = simHit.localPosition();
773 
775  std::pair<uint8_t, uint8_t> pixel = geomTools_.pixelInModule(id, simscaled);
776  // create the unique id
777  uint64_t uniqueId = static_cast<uint64_t>(id.rawId()) << 32;
778  uniqueId |= pixel.first << 16;
779  uniqueId |= pixel.second;
780 
781  std::get<0>(simTrackDetIdMap[simHit.trackId()][uniqueId]) += simHit.energyLoss();
782  m_detIdToTotalSimEnergy[uniqueId] += simHit.energyLoss();
783  // --- Get the time of the first SIM hit in the cell
784  if (std::get<1>(simTrackDetIdMap[simHit.trackId()][uniqueId]) == 0. ||
785  simHit.tof() < std::get<1>(simTrackDetIdMap[simHit.trackId()][uniqueId])) {
786  std::get<1>(simTrackDetIdMap[simHit.trackId()][uniqueId]) = simHit.tof();
787  }
788 
789  float xSim = std::get<2>(simTrackDetIdMap[simHit.trackId()][uniqueId]).x() + simscaled.x() * simHit.energyLoss();
790  float ySim = std::get<2>(simTrackDetIdMap[simHit.trackId()][uniqueId]).y() + simscaled.y() * simHit.energyLoss();
791  float zSim = std::get<2>(simTrackDetIdMap[simHit.trackId()][uniqueId]).z() + simscaled.z() * simHit.energyLoss();
792  LocalPoint posSim(xSim, ySim, zSim);
793  std::get<2>(simTrackDetIdMap[simHit.trackId()][uniqueId]) = posSim;
794 
795 #ifdef PRINT_DEBUG
797  << "hitId " << id.rawId() << " from track " << simHit.trackId() << " in layer " << geomTools_.layer(id)
798  << ", module " << geomTools_.module(id) << ", pixel ( " << (int)geomTools_.pixelInModule(id, simscaled).first
799  << ", " << (int)geomTools_.pixelInModule(id, simscaled).second << " )\n global pos(cm) "
800  << geomTools_.globalPosition(id, simscaled) << ", time(ns) " << simHit.tof() << ", energy(MeV) "
801  << convertUnitsTo(0.001_MeV, simHit.energyLoss()) << std::endl;
802 #endif
803  } // end of loop over simHits
804 
805  } // End of loop over InputTags
806 
807  for (auto &tkIt : simTrackDetIdMap) {
808  for (auto &uIt : tkIt.second) {
809  float accEnergy = std::get<0>(uIt.second);
810  float xSim = std::get<2>(uIt.second).x() / accEnergy;
811  float ySim = std::get<2>(uIt.second).y() / accEnergy;
812  float zSim = std::get<2>(uIt.second).z() / accEnergy;
813  LocalPoint posSim(xSim, ySim, zSim);
814  std::get<2>(uIt.second) = posSim;
815  }
816  }
817 }
818 
819 // 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)
int getMTDTopologyMode() const
Definition: MTDTopology.h:27
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()
T z() const
Definition: PV3DBase.h:61
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
virtual const Topology & topology() const
Definition: GeomDet.cc:67
virtual const PixelTopology & specificTopology() const
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
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.
LocalPoint pixelToModuleLocalPoint(const LocalPoint &plp, int row, int col) const
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:112
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
T x() const
Definition: PV3DBase.h:59
T y() const
Definition: PV3DBase.h:60
adjacency_list< listS, vecS, directedS, VertexMotherParticleProperty, EdgeParticleClustersProperty > DecayChain
Definition: DecayGraph.h:75
unsigned int layer(const DetId &) const
Definition: MTDGeomUtil.cc:89
bool isBTL(const DetId &) const
Definition: MTDGeomUtil.cc:24
int cumulative_simHits
Definition: DecayGraph.h:63
static constexpr unsigned int k_tidOffset
Definition: PSimHit.h:17
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
const MTDGeomDet * idToDet(DetId) const override
Definition: MTDGeometry.cc:171
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
void fillSimHits(std::vector< std::pair< uint64_t, const PSimHit *>> &returnValue, std::unordered_map< int, std::map< uint64_t, std::tuple< float, float, LocalPoint >>> &simTrackDetIdMap, const T &event, const edm::EventSetup &setup)
Fills the supplied vector with pointers to the SimHits, checking for bad modules if required...
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
Detector identifier class for the Barrel Timing Layer. The crystal count must start from 0...
Definition: BTLDetId.h:19
void accumulate(const edm::Event &event, const edm::EventSetup &setup) override
Definition: output.py:1
std::vector< MtdSimCluster > MtdSimClusterCollection
BTLDetId::CrysLayout crysLayoutFromTopoMode(const int &topoMode)
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