CMS 3D CMS Logo

CaloTruthAccumulator.cc
Go to the documentation of this file.
1 #define DEBUG false
2 #if DEBUG
3 // boost optional (used by boost graph) results in some false positives with
4 // -Wmaybe-uninitialized
5 #pragma GCC diagnostic push
6 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
7 #endif
8 
9 // BOOST GRAPH LIBRARY
10 #include <boost/graph/adjacency_list.hpp>
11 #include <boost/graph/breadth_first_search.hpp>
12 #include <boost/graph/depth_first_search.hpp>
13 #include <boost/graph/graphviz.hpp>
14 
15 #if DEBUG
16 #pragma GCC diagnostic pop
17 #endif
18 
19 #include <iterator>
20 #include <memory>
21 
22 #include <numeric> // for std::accumulate
23 #include <unordered_map>
24 
33 
40 
49 
54 
60 
61 namespace {
62  using Index_t = unsigned;
63  using Barcode_t = int;
64  const std::string messageCategoryGraph_("CaloTruthAccumulatorGraphProducer");
65 } // namespace
66 
67 using boost::add_edge;
68 using boost::adjacency_list;
69 using boost::directedS;
70 using boost::edge;
71 using boost::edge_weight;
72 using boost::edge_weight_t;
73 using boost::listS;
74 using boost::property;
75 using boost::vecS;
76 using boost::vertex;
77 using boost::vertex_name;
78 using boost::vertex_name_t;
79 
80 /* GRAPH DEFINITIONS
81 
82  The graphs represent the full decay chain.
83 
84  The parent-child relationship is the natural one, following "time".
85 
86  Each edge has a property (edge_weight_t) that holds a const pointer to the
87  SimTrack that connects the 2 vertices of the edge, the number of simHits
88  associated to that simTrack and the cumulative number of simHits of itself
89  and of all its children. Only simHits within the selected detectors are
90  taken into account. The cumulative property is filled during the dfs
91  exploration of the graph: if not explored the number is 0.
92 
93  Each vertex has a property (vertex_name_t) that holds a const pointer to the
94  SimTrack that originated that vertex and the cumulative number of simHits of
95  all its outgoing edges. The cumulative property is filled during the dfs
96  exploration of the graph: if not explored the number is 0.
97 
98  Stable particles are recovered/added in a second iterations and are linked
99  to ghost vertices with an offset starting from the highest generated vertex.
100 
101  Multiple decays of a single particle that retains its original trackId are
102  merged into one unique vertex (the first encountered) in order to avoid
103  multiple counting of its associated simHits (if any).
104 
105 */
106 struct EdgeProperty {
109  int simHits;
111 };
112 
120 };
121 
122 using EdgeParticleClustersProperty = property<edge_weight_t, EdgeProperty>;
123 using VertexMotherParticleProperty = property<vertex_name_t, VertexProperty>;
124 using DecayChain = adjacency_list<listS, vecS, directedS, VertexMotherParticleProperty, EdgeParticleClustersProperty>;
125 
127 public:
129 
130 private:
131  void initializeEvent(const edm::Event &event, const edm::EventSetup &setup) override;
132  void accumulate(const edm::Event &event, const edm::EventSetup &setup) override;
133  void accumulate(const PileUpEventPrincipal &event, const edm::EventSetup &setup, edm::StreamID const &) override;
134  void finalizeEvent(edm::Event &event, const edm::EventSetup &setup) override;
135 
137  template <class T>
138  void accumulateEvent(const T &event,
139  const edm::EventSetup &setup,
140  const edm::Handle<edm::HepMCProduct> &hepMCproduct);
141 
144  template <class T>
145  void fillSimHits(std::vector<std::pair<DetId, const PCaloHit *>> &returnValue,
146  std::unordered_map<int, std::map<int, float>> &simTrackDetIdEnergyMap,
147  const T &event,
148  const edm::EventSetup &setup);
149 
151 
152  std::unordered_map<Index_t, float> m_detIdToTotalSimEnergy; // keep track of cell normalizations
153  std::unordered_multimap<Barcode_t, Index_t> m_simHitBarcodeToIndex;
154 
160  const unsigned int maximumPreviousBunchCrossing_;
167 
172 
173  std::vector<edm::InputTag> collectionTags_;
179 
181  const bool premixStage1_;
182 
183 public:
185  std::unique_ptr<SimClusterCollection> pSimClusters;
186  std::unique_ptr<CaloParticleCollection> pCaloParticles;
187  };
188 
189  struct calo_particles {
190  std::vector<uint32_t> sc_start_;
191  std::vector<uint32_t> sc_stop_;
192 
193  void swap(calo_particles &oth) {
194  sc_start_.swap(oth.sc_start_);
195  sc_stop_.swap(oth.sc_stop_);
196  }
197 
198  void clear() {
199  sc_start_.clear();
200  sc_stop_.clear();
201  }
202  };
203 
204 private:
205  const HGCalTopology *hgtopo_[3] = {nullptr, nullptr, nullptr};
206  const HGCalDDDConstants *hgddd_[3] = {nullptr, nullptr, nullptr};
207  const HcalDDDRecConstants *hcddd_ = nullptr;
210  // geometry type (0 pre-TDR; 1 TDR)
212  bool doHGCAL;
213 };
214 
215 /* Graph utility functions */
216 
217 namespace {
218  template <typename Edge, typename Graph, typename Visitor>
219  void accumulateSimHits_edge(Edge &e, const Graph &g, Visitor *v) {
220  auto const edge_property = get(edge_weight, g, e);
221  v->total_simHits += edge_property.simHits;
222  IfLogDebug(DEBUG, messageCategoryGraph_)
223  << " Examining edges " << e << " --> particle " << edge_property.simTrack->type() << "("
224  << edge_property.simTrack->trackId() << ")"
225  << " with SimClusters: " << edge_property.simHits << " Accumulated SimClusters: " << v->total_simHits
226  << std::endl;
227  }
228  template <typename Vertex, typename Graph>
229  void print_vertex(Vertex &u, const Graph &g) {
230  auto const vertex_property = get(vertex_name, g, u);
231  IfLogDebug(DEBUG, messageCategoryGraph_) << " At " << u;
232  // The Mother of all vertices has **no** SimTrack associated.
233  if (vertex_property.simTrack)
234  IfLogDebug(DEBUG, messageCategoryGraph_) << " [" << vertex_property.simTrack->type() << "]"
235  << "(" << vertex_property.simTrack->trackId() << ")";
236  IfLogDebug(DEBUG, messageCategoryGraph_) << std::endl;
237  }
238 
239 // Graphviz output functions will only be generated in DEBUG mode
240 #if DEBUG
241  std::string graphviz_vertex(const VertexProperty &v) {
242  std::ostringstream oss;
243  oss << "{id: " << (v.simTrack ? v.simTrack->trackId() : 0) << ",\\ntype: " << (v.simTrack ? v.simTrack->type() : 0)
244  << ",\\nchits: " << v.cumulative_simHits << "}";
245  return oss.str();
246  }
247 
248  std::string graphviz_edge(const EdgeProperty &e) {
249  std::ostringstream oss;
250  oss << "[" << (e.simTrack ? e.simTrack->trackId() : 0) << "," << (e.simTrack ? e.simTrack->type() : 0) << ","
251  << e.simHits << "," << e.cumulative_simHits << "]";
252  return oss.str();
253  }
254 #endif
255 
256  class SimHitsAccumulator_dfs_visitor : public boost::default_dfs_visitor {
257  public:
258  int total_simHits = 0;
259  template <typename Edge, typename Graph>
260  void examine_edge(Edge e, const Graph &g) {
261  accumulateSimHits_edge(e, g, this);
262  }
263  template <typename Edge, typename Graph>
264  void finish_edge(Edge e, const Graph &g) {
265  auto const edge_property = get(edge_weight, g, e);
266  auto src = source(e, g);
267  auto trg = target(e, g);
268  auto cumulative = edge_property.simHits + get(vertex_name, g, trg).cumulative_simHits +
269  (get(vertex_name, g, src).simTrack ? get(vertex_name, g, src).cumulative_simHits
270  : 0); // when we hit the root vertex we have to stop
271  // adding back its contribution.
272  auto const src_vertex_property = get(vertex_name, g, src);
273  put(get(vertex_name, const_cast<Graph &>(g)), src, VertexProperty(src_vertex_property.simTrack, cumulative));
274  put(get(edge_weight, const_cast<Graph &>(g)),
275  e,
276  EdgeProperty(edge_property.simTrack, edge_property.simHits, cumulative));
277  IfLogDebug(DEBUG, messageCategoryGraph_)
278  << " Finished edge: " << e << " Track id: " << get(edge_weight, g, e).simTrack->trackId()
279  << " has accumulated " << cumulative << " hits" << std::endl;
280  IfLogDebug(DEBUG, messageCategoryGraph_) << " SrcVtx: " << src << "\t" << get(vertex_name, g, src).simTrack
281  << "\t" << get(vertex_name, g, src).cumulative_simHits << std::endl;
282  IfLogDebug(DEBUG, messageCategoryGraph_) << " TrgVtx: " << trg << "\t" << get(vertex_name, g, trg).simTrack
283  << "\t" << get(vertex_name, g, trg).cumulative_simHits << std::endl;
284  }
285  };
286 
287  using Selector = std::function<bool(EdgeProperty &)>;
288 
289  class CaloParticle_dfs_visitor : public boost::default_dfs_visitor {
290  public:
291  CaloParticle_dfs_visitor(CaloTruthAccumulator::OutputCollections &output,
293  std::unordered_multimap<Barcode_t, Index_t> &simHitBarcodeToIndex,
294  std::unordered_map<int, std::map<int, float>> &simTrackDetIdEnergyMap,
295  Selector selector)
296  : output_(output),
297  caloParticles_(caloParticles),
298  simHitBarcodeToIndex_(simHitBarcodeToIndex),
299  simTrackDetIdEnergyMap_(simTrackDetIdEnergyMap),
300  selector_(selector) {}
301  template <typename Vertex, typename Graph>
302  void discover_vertex(Vertex u, const Graph &g) {
303  // If we reach the vertex 0, it means that we are backtracking with respect
304  // to the first generation of stable particles: simply return;
305  // if (u == 0) return;
306  print_vertex(u, g);
307  auto const vertex_property = get(vertex_name, g, u);
308  if (!vertex_property.simTrack)
309  return;
310  auto trackIdx = vertex_property.simTrack->trackId();
311  IfLogDebug(DEBUG, messageCategoryGraph_)
312  << " Found " << simHitBarcodeToIndex_.count(trackIdx) << " associated simHits" << std::endl;
313  if (simHitBarcodeToIndex_.count(trackIdx)) {
314  output_.pSimClusters->emplace_back(*vertex_property.simTrack);
315  auto &simcluster = output_.pSimClusters->back();
316  std::unordered_map<uint32_t, float> acc_energy;
317  for (auto const &hit_and_energy : simTrackDetIdEnergyMap_[trackIdx]) {
318  acc_energy[hit_and_energy.first] += hit_and_energy.second;
319  }
320  for (auto const &hit_and_energy : acc_energy) {
321  simcluster.addRecHitAndFraction(hit_and_energy.first, hit_and_energy.second);
322  }
323  }
324  }
325  template <typename Edge, typename Graph>
326  void examine_edge(Edge e, const Graph &g) {
327  auto src = source(e, g);
328  auto vertex_property = get(vertex_name, g, src);
329  if (src == 0 or (vertex_property.simTrack == nullptr)) {
330  auto edge_property = get(edge_weight, g, e);
331  IfLogDebug(DEBUG, messageCategoryGraph_) << "Considering CaloParticle: " << edge_property.simTrack->trackId();
332  if (selector_(edge_property)) {
333  IfLogDebug(DEBUG, messageCategoryGraph_) << "Adding CaloParticle: " << edge_property.simTrack->trackId();
334  output_.pCaloParticles->emplace_back(*(edge_property.simTrack));
335  caloParticles_.sc_start_.push_back(output_.pSimClusters->size());
336  }
337  }
338  }
339 
340  template <typename Edge, typename Graph>
341  void finish_edge(Edge e, const Graph &g) {
342  auto src = source(e, g);
343  auto vertex_property = get(vertex_name, g, src);
344  if (src == 0 or (vertex_property.simTrack == nullptr)) {
345  auto edge_property = get(edge_weight, g, e);
346  if (selector_(edge_property)) {
347  caloParticles_.sc_stop_.push_back(output_.pSimClusters->size());
348  }
349  }
350  }
351 
352  private:
354  CaloTruthAccumulator::calo_particles &caloParticles_;
355  std::unordered_multimap<Barcode_t, Index_t> &simHitBarcodeToIndex_;
356  std::unordered_map<int, std::map<int, float>> &simTrackDetIdEnergyMap_;
357  Selector selector_;
358  };
359 } // namespace
360 
362  edm::ProducesCollector producesCollector,
364  : messageCategory_("CaloTruthAccumulator"),
365  maximumPreviousBunchCrossing_(config.getParameter<unsigned int>("maximumPreviousBunchCrossing")),
366  maximumSubsequentBunchCrossing_(config.getParameter<unsigned int>("maximumSubsequentBunchCrossing")),
367  simTrackLabel_(config.getParameter<edm::InputTag>("simTrackCollection")),
368  simVertexLabel_(config.getParameter<edm::InputTag>("simVertexCollection")),
369  collectionTags_(),
370  genParticleLabel_(config.getParameter<edm::InputTag>("genParticleCollection")),
371  hepMCproductLabel_(config.getParameter<edm::InputTag>("HepMCProductLabel")),
372  geomToken_(iC.esConsumes()),
373  minEnergy_(config.getParameter<double>("MinEnergy")),
374  maxPseudoRapidity_(config.getParameter<double>("MaxPseudoRapidity")),
375  premixStage1_(config.getParameter<bool>("premixStage1")),
376  geometryType_(-1),
377  doHGCAL(config.getParameter<bool>("doHGCAL")) {
378  producesCollector.produces<SimClusterCollection>("MergedCaloTruth");
379  producesCollector.produces<CaloParticleCollection>("MergedCaloTruth");
380  if (premixStage1_) {
381  producesCollector.produces<std::vector<std::pair<unsigned int, float>>>("MergedCaloTruth");
382  }
383 
384  iC.consumes<std::vector<SimTrack>>(simTrackLabel_);
385  iC.consumes<std::vector<SimVertex>>(simVertexLabel_);
386  iC.consumes<std::vector<reco::GenParticle>>(genParticleLabel_);
387  iC.consumes<std::vector<int>>(genParticleLabel_);
388  iC.consumes<std::vector<int>>(hepMCproductLabel_);
389 
390  // Fill the collection tags
391  const edm::ParameterSet &simHitCollectionConfig = config.getParameterSet("simHitCollections");
392  std::vector<std::string> parameterNames = simHitCollectionConfig.getParameterNames();
393 
394  for (auto const &parameterName : parameterNames) {
395  std::vector<edm::InputTag> tags = simHitCollectionConfig.getParameter<std::vector<edm::InputTag>>(parameterName);
396  collectionTags_.insert(collectionTags_.end(), tags.begin(), tags.end());
397  }
398 
399  for (auto const &collectionTag : collectionTags_) {
400  iC.consumes<std::vector<PCaloHit>>(collectionTag);
401  }
402 }
403 
405  output_.pSimClusters = std::make_unique<SimClusterCollection>();
406  output_.pCaloParticles = std::make_unique<CaloParticleCollection>();
407 
408  m_detIdToTotalSimEnergy.clear();
409 
410  if (geomWatcher_.check(setup)) {
411  auto const &geom = setup.getData(geomToken_);
412  const HGCalGeometry *eegeom = nullptr, *fhgeom = nullptr, *bhgeomnew = nullptr;
413  const HcalGeometry *bhgeom = nullptr;
414  bhgeom = static_cast<const HcalGeometry *>(geom.getSubdetectorGeometry(DetId::Hcal, HcalEndcap));
415 
416  if (doHGCAL) {
417  eegeom = static_cast<const HGCalGeometry *>(
418  geom.getSubdetectorGeometry(DetId::HGCalEE, ForwardSubdetector::ForwardEmpty));
419  // check if it's the new geometry
420  if (eegeom) {
421  geometryType_ = 1;
422  fhgeom = static_cast<const HGCalGeometry *>(
423  geom.getSubdetectorGeometry(DetId::HGCalHSi, ForwardSubdetector::ForwardEmpty));
424  bhgeomnew = static_cast<const HGCalGeometry *>(
425  geom.getSubdetectorGeometry(DetId::HGCalHSc, ForwardSubdetector::ForwardEmpty));
426  } else {
427  geometryType_ = 0;
428  eegeom = static_cast<const HGCalGeometry *>(geom.getSubdetectorGeometry(DetId::Forward, HGCEE));
429  fhgeom = static_cast<const HGCalGeometry *>(geom.getSubdetectorGeometry(DetId::Forward, HGCHEF));
430  bhgeom = static_cast<const HcalGeometry *>(geom.getSubdetectorGeometry(DetId::Hcal, HcalEndcap));
431  }
432  hgtopo_[0] = &(eegeom->topology());
433  hgtopo_[1] = &(fhgeom->topology());
434  if (bhgeomnew)
435  hgtopo_[2] = &(bhgeomnew->topology());
436 
437  for (unsigned i = 0; i < 3; ++i) {
438  if (hgtopo_[i])
439  hgddd_[i] = &(hgtopo_[i]->dddConstants());
440  }
441  }
442 
443  if (bhgeom) {
444  hcddd_ = bhgeom->topology().dddConstants();
445  }
446  }
447 }
448 
458  event.getByLabel(hepMCproductLabel_, hepmc);
459 
460  edm::LogInfo(messageCategory_) << " CaloTruthAccumulator::accumulate (signal)";
461  accumulateEvent(event, setup, hepmc);
462 }
463 
465  edm::EventSetup const &setup,
466  edm::StreamID const &) {
467  if (event.bunchCrossing() >= -static_cast<int>(maximumPreviousBunchCrossing_) &&
468  event.bunchCrossing() <= static_cast<int>(maximumSubsequentBunchCrossing_)) {
469  // simply create empty handle as we do not have a HepMCProduct in PU anyway
471  edm::LogInfo(messageCategory_) << " CaloTruthAccumulator::accumulate (pileup) bunchCrossing="
472  << event.bunchCrossing();
473  accumulateEvent(event, setup, hepmc);
474  } else {
475  edm::LogInfo(messageCategory_) << "Skipping pileup event for bunch crossing " << event.bunchCrossing();
476  }
477 }
478 
480  edm::LogInfo(messageCategory_) << "Adding " << output_.pSimClusters->size() << " SimParticles and "
481  << output_.pCaloParticles->size() << " CaloParticles to the event.";
482 
483  // We need to normalize the hits and energies into hits and fractions (since
484  // we have looped over all pileup events)
485  // For premixing stage1 we keep the energies, they will be normalized to
486  // fractions in stage2
487 
488  if (premixStage1_) {
489  auto totalEnergies = std::make_unique<std::vector<std::pair<unsigned int, float>>>();
490  totalEnergies->reserve(m_detIdToTotalSimEnergy.size());
491  std::copy(m_detIdToTotalSimEnergy.begin(), m_detIdToTotalSimEnergy.end(), std::back_inserter(*totalEnergies));
492  std::sort(totalEnergies->begin(), totalEnergies->end());
493  event.put(std::move(totalEnergies), "MergedCaloTruth");
494  } else {
495  for (auto &sc : *(output_.pSimClusters)) {
496  auto hitsAndEnergies = sc.hits_and_fractions();
497  sc.clearHitsAndFractions();
498  sc.clearHitsEnergy();
499  for (auto &hAndE : hitsAndEnergies) {
500  const float totalenergy = m_detIdToTotalSimEnergy[hAndE.first];
501  float fraction = 0.;
502  if (totalenergy > 0)
503  fraction = hAndE.second / totalenergy;
504  else
506  << "TotalSimEnergy for hit " << hAndE.first << " is 0! The fraction for this hit cannot be computed.";
507  sc.addRecHitAndFraction(hAndE.first, fraction);
508  sc.addHitEnergy(hAndE.second);
509  }
510  }
511  }
512 
513  // save the SimCluster orphan handle so we can fill the calo particles
514  auto scHandle = event.put(std::move(output_.pSimClusters), "MergedCaloTruth");
515 
516  // now fill the calo particles
517  for (unsigned i = 0; i < output_.pCaloParticles->size(); ++i) {
518  auto &cp = (*output_.pCaloParticles)[i];
519  for (unsigned j = m_caloParticles.sc_start_[i]; j < m_caloParticles.sc_stop_[i]; ++j) {
520  edm::Ref<SimClusterCollection> ref(scHandle, j);
521  cp.addSimCluster(ref);
522  }
523  }
524 
525  event.put(std::move(output_.pCaloParticles), "MergedCaloTruth");
526 
528 
529  std::unordered_map<Index_t, float>().swap(m_detIdToTotalSimEnergy);
530  std::unordered_multimap<Barcode_t, Index_t>().swap(m_simHitBarcodeToIndex);
531 }
532 
533 template <class T>
535  const edm::EventSetup &setup,
536  const edm::Handle<edm::HepMCProduct> &hepMCproduct) {
538  edm::Handle<std::vector<int>> hGenParticleIndices;
539 
540  event.getByLabel(simTrackLabel_, hSimTracks);
541  event.getByLabel(simVertexLabel_, hSimVertices);
542 
543  event.getByLabel(genParticleLabel_, hGenParticles);
544  event.getByLabel(genParticleLabel_, hGenParticleIndices);
545 
546  std::vector<std::pair<DetId, const PCaloHit *>> simHitPointers;
547  std::unordered_map<int, std::map<int, float>> simTrackDetIdEnergyMap;
548  fillSimHits(simHitPointers, simTrackDetIdEnergyMap, event, setup);
549 
550  // Clear maps from previous event fill them for this one
551  m_simHitBarcodeToIndex.clear();
552  for (unsigned int i = 0; i < simHitPointers.size(); ++i) {
553  m_simHitBarcodeToIndex.emplace(simHitPointers[i].second->geantTrackId(), i);
554  }
555 
556  auto const &tracks = *hSimTracks;
557  auto const &vertices = *hSimVertices;
558  std::unordered_map<int, int> trackid_to_track_index;
560  int idx = 0;
561 
562  IfLogDebug(DEBUG, messageCategory_) << " TRACKS" << std::endl;
563  for (auto const &t : tracks) {
564  IfLogDebug(DEBUG, messageCategory_) << " " << idx << "\t" << t.trackId() << "\t" << t << std::endl;
565  trackid_to_track_index[t.trackId()] = idx;
566  idx++;
567  }
568 
595  idx = 0;
596  std::vector<int> used_sim_tracks(tracks.size(), 0);
597  std::vector<int> collapsed_vertices(vertices.size(), 0);
598  IfLogDebug(DEBUG, messageCategory_) << " VERTICES" << std::endl;
599  for (auto const &v : vertices) {
600  IfLogDebug(DEBUG, messageCategory_) << " " << idx++ << "\t" << v << std::endl;
601  if (v.parentIndex() != -1) {
602  auto trk_idx = trackid_to_track_index[v.parentIndex()];
603  auto origin_vtx = tracks[trk_idx].vertIndex();
604  if (used_sim_tracks[trk_idx]) {
605  // collapse the vertex into the original first vertex we saw associated
606  // to this track. Omit adding the edge in order to avoid double
607  // counting of the very same particles and its associated hits.
608  collapsed_vertices[v.vertexId()] = used_sim_tracks[trk_idx];
609  continue;
610  }
611  // Perform the actual vertex collapsing, if needed.
612  if (collapsed_vertices[origin_vtx])
613  origin_vtx = collapsed_vertices[origin_vtx];
614  add_edge(origin_vtx,
615  v.vertexId(),
616  EdgeProperty(&tracks[trk_idx], simTrackDetIdEnergyMap[v.parentIndex()].size(), 0),
617  decay);
618  used_sim_tracks[trk_idx] = v.vertexId();
619  }
620  }
621  // Build the motherParticle property to each vertex
622  auto const &vertexMothersProp = get(vertex_name, decay);
623  // Now recover the particles that did not decay. Append them with an index
624  // bigger than the size of the generated vertices.
625  int offset = vertices.size();
626  for (size_t i = 0; i < tracks.size(); ++i) {
627  if (!used_sim_tracks[i]) {
628  auto origin_vtx = tracks[i].vertIndex();
629  // Perform the actual vertex collapsing, if needed.
630  if (collapsed_vertices[origin_vtx])
631  origin_vtx = collapsed_vertices[origin_vtx];
632  add_edge(
633  origin_vtx, offset, EdgeProperty(&tracks[i], simTrackDetIdEnergyMap[tracks[i].trackId()].size(), 0), decay);
634  // The properties for "fake" vertices associated to stable particles have
635  // to be set inside this loop, since they do not belong to the vertices
636  // collection and would be skipped by that loop (coming next)
637  put(vertexMothersProp, offset, VertexProperty(&tracks[i], 0));
638  offset++;
639  }
640  }
641  for (auto const &v : vertices) {
642  if (v.parentIndex() != -1) {
643  // Skip collapsed_vertices
644  if (collapsed_vertices[v.vertexId()])
645  continue;
646  put(vertexMothersProp, v.vertexId(), VertexProperty(&tracks[trackid_to_track_index[v.parentIndex()]], 0));
647  }
648  }
649  SimHitsAccumulator_dfs_visitor vis;
650  depth_first_search(decay, visitor(vis));
651  CaloParticle_dfs_visitor caloParticleCreator(
652  output_,
655  simTrackDetIdEnergyMap,
656  [&](EdgeProperty &edge_property) -> bool {
657  // Apply selection on SimTracks in order to promote them to be
658  // CaloParticles. The function returns TRUE if the particle satisfies
659  // the selection, FALSE otherwise. Therefore the correct logic to select
660  // the particle is to ask for TRUE as return value.
661  return (edge_property.cumulative_simHits != 0 and !edge_property.simTrack->noGenpart() and
662  edge_property.simTrack->momentum().E() > minEnergy_ and
663  std::abs(edge_property.simTrack->momentum().Eta()) < maxPseudoRapidity_);
664  });
665  depth_first_search(decay, visitor(caloParticleCreator));
666 
667 #if DEBUG
668  boost::write_graphviz(std::cout,
669  decay,
670  make_label_writer(make_transform_value_property_map(&graphviz_vertex, get(vertex_name, decay))),
671  make_label_writer(make_transform_value_property_map(&graphviz_edge, get(edge_weight, decay))));
672 #endif
673 }
674 
675 template <class T>
676 void CaloTruthAccumulator::fillSimHits(std::vector<std::pair<DetId, const PCaloHit *>> &returnValue,
677  std::unordered_map<int, std::map<int, float>> &simTrackDetIdEnergyMap,
678  const T &event,
679  const edm::EventSetup &setup) {
680  for (auto const &collectionTag : collectionTags_) {
682  const bool isHcal = (collectionTag.instance().find("HcalHits") != std::string::npos);
683  event.getByLabel(collectionTag, hSimHits);
684 
685  for (auto const &simHit : *hSimHits) {
686  DetId id(0);
687 
688  //Relabel as necessary for HGCAL
689  if (doHGCAL) {
690  const uint32_t simId = simHit.id();
691  if (geometryType_ == 1) {
692  // no test numbering in new geometry
693  id = simId;
694  } else if (isHcal) {
696  if (hid.subdet() == HcalEndcap)
697  id = hid;
698  } else {
699  int subdet, layer, cell, sec, subsec, zp;
700  HGCalTestNumbering::unpackHexagonIndex(simId, subdet, zp, layer, sec, subsec, cell);
701  const HGCalDDDConstants *ddd = hgddd_[subdet - 3];
702  std::pair<int, int> recoLayerCell = ddd->simToReco(cell, layer, sec, hgtopo_[subdet - 3]->detectorType());
703  cell = recoLayerCell.first;
704  layer = recoLayerCell.second;
705  // skip simhits with bad barcodes or non-existant layers
706  if (layer == -1 || simHit.geantTrackId() == 0)
707  continue;
708  id = HGCalDetId((ForwardSubdetector)subdet, zp, layer, subsec, sec, cell);
709  }
710  } else {
711  id = simHit.id();
712  //Relabel all HCAL hits
713  if (isHcal) {
715  id = hid;
716  }
717  }
718 
719  if (id == DetId(0)) {
720  continue;
721  }
722  if (simHit.geantTrackId() == 0) {
723  continue;
724  }
725 
726  returnValue.emplace_back(id, &simHit);
727  simTrackDetIdEnergyMap[simHit.geantTrackId()][id.rawId()] += simHit.energy();
728  m_detIdToTotalSimEnergy[id.rawId()] += simHit.energy();
729  }
730  } // end of loop over InputTags
731 }
732 
733 // Register with the framework
size
Write out results.
EDGetTokenT< ProductType > consumes(edm::InputTag const &tag)
std::unordered_multimap< Barcode_t, Index_t > m_simHitBarcodeToIndex
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
edm::Handle< std::vector< SimVertex > > hSimVertices
void fillSimHits(std::vector< std::pair< DetId, const PCaloHit *>> &returnValue, std::unordered_map< int, std::map< int, float >> &simTrackDetIdEnergyMap, const T &event, const edm::EventSetup &setup)
Fills the supplied vector with pointers to the SimHits, checking for bad modules if required...
void initializeEvent(const edm::Event &event, const edm::EventSetup &setup) override
ProductRegistryHelper::BranchAliasSetterT< ProductType > produces()
const HGCalTopology * hgtopo_[3]
const unsigned int maximumSubsequentBunchCrossing_
std::vector< edm::InputTag > collectionTags_
Definition: config.py:1
ForwardSubdetector
EdgeProperty(const SimTrack *t, int h, int c)
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
const SimTrack * simTrack
void put(edm::Event &evt, double value, const char *instanceName)
constexpr std::array< uint8_t, layerIndexSize< TrackerTraits > > layer
edm::ESWatcher< CaloGeometryRecord > geomWatcher_
U second(std::pair< T, U > const &p)
const SimTrack * simTrack
constexpr HcalSubdetector subdet() const
get the subdetector
Definition: HcalDetId.h:138
edm::InputTag hepMCproductLabel_
Needed to add HepMC::GenVertex to SimVertex.
#define IfLogDebug(cond, cat)
const std::string messageCategory_
void accumulate(const edm::Event &event, const edm::EventSetup &setup) override
const edm::ESGetToken< CaloGeometry, CaloGeometryRecord > geomToken_
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
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
std::pair< int, int > simToReco(int cell, int layer, int mod, bool half) const
property< edge_weight_t, EdgeProperty > EdgeParticleClustersProperty
CaloTruthAccumulator(const edm::ParameterSet &config, edm::ProducesCollector, edm::ConsumesCollector &iC)
std::unordered_map< Index_t, float > m_detIdToTotalSimEnergy
const edm::InputTag simVertexLabel_
DetId relabel(const uint32_t testId) const
Functor that operates on <T>
Definition: Selector.h:22
const HGCalDDDConstants * hgddd_[3]
VertexProperty(const VertexProperty &other)
const edm::InputTag simTrackLabel_
Log< level::Info, false > LogInfo
VertexProperty(const SimTrack *t, int c)
edm::Handle< std::vector< SimTrack > > hSimTracks
Definition: DetId.h:17
void accumulateEvent(const T &event, const edm::EventSetup &setup, const edm::Handle< edm::HepMCProduct > &hepMCproduct)
Both forms of accumulate() delegate to this templated method.
std::unique_ptr< CaloParticleCollection > pCaloParticles
bool noGenpart() const
Definition: SimTrack.h:38
const HcalDDDRecConstants * hcddd_
void finalizeEvent(edm::Event &event, const edm::EventSetup &setup) override
bool check(const edm::EventSetup &iSetup)
Definition: ESWatcher.h:57
HLT enums.
#define DEFINE_DIGI_ACCUMULATOR(type)
std::vector< CaloParticle > CaloParticleCollection
property< vertex_name_t, VertexProperty > VertexMotherParticleProperty
const HcalDDDRecConstants * dddConstants() const
Definition: HcalTopology.h:164
std::unique_ptr< SimClusterCollection > pSimClusters
Log< level::Warning, false > LogWarning
std::vector< SimCluster > SimClusterCollection
Definition: SimClusterFwd.h:8
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
long double T
adjacency_list< listS, vecS, directedS, VertexMotherParticleProperty, EdgeParticleClustersProperty > DecayChain
static std::string const source
Definition: EdmProvDump.cc:49
const HGCalDDDConstants & dddConstants() const
Definition: HGCalTopology.h:98
static void unpackHexagonIndex(const uint32_t &idx, int &subdet, int &z, int &lay, int &wafer, int &celltyp, int &cell)
def move(src, dest)
Definition: eostools.py:511
Definition: event.py:1
const unsigned int maximumPreviousBunchCrossing_
#define DEBUG
const HcalTopology & topology() const
Definition: HcalGeometry.h:111