ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HitSmearing.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file HitSmearing.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
17 
19  : BareAlgorithm("HitSmearing", lvl), m_cfg(cfg) {
20  if (m_cfg.inputSimulatedHits.empty()) {
21  throw std::invalid_argument("Missing input simulated hits collection");
22  }
23  if (m_cfg.outputSourceLinks.empty()) {
24  throw std::invalid_argument("Missing output source links collection");
25  }
26  if ((m_cfg.sigmaLoc0 < 0) or (m_cfg.sigmaLoc1 < 0)) {
27  throw std::invalid_argument("Invalid resolution setting");
28  }
29  if (not m_cfg.trackingGeometry) {
30  throw std::invalid_argument("Missing tracking geometry");
31  }
32  if (!m_cfg.randomNumbers) {
33  throw std::invalid_argument("Missing random numbers tool");
34  }
35  // fill the surface map to allow lookup by geometry id only
36  m_cfg.trackingGeometry->visitSurfaces([this](const Acts::Surface* surface) {
37  // for now we just require a valid surface
38  if (not surface) {
39  return;
40  }
41  this->m_surfaces.insert_or_assign(surface->geoID(), surface);
42  });
43 }
44 
46  // setup input and output containers
47  const auto& hits =
48  ctx.eventStore.get<SimHitContainer>(m_cfg.inputSimulatedHits);
49  SimSourceLinkContainer sourceLinks;
50  sourceLinks.reserve(hits.size());
51 
52  // setup random number generator
53  auto rng = m_cfg.randomNumbers->spawnGenerator(ctx);
54  std::normal_distribution<double> stdNormal(0.0, 1.0);
55 
56  // setup local covariance
57  // TODO add support for per volume/layer/module settings
58  Acts::BoundMatrix cov = Acts::BoundMatrix::Zero();
59  cov(Acts::eLOC_0, Acts::eLOC_0) = m_cfg.sigmaLoc0 * m_cfg.sigmaLoc0;
60  cov(Acts::eLOC_1, Acts::eLOC_1) = m_cfg.sigmaLoc1 * m_cfg.sigmaLoc1;
61 
62  for (auto&& [moduleGeoId, moduleHits] : groupByModule(hits)) {
63  // check if we should create hits for this surface
64  const auto is = m_surfaces.find(moduleGeoId);
65  if (is == m_surfaces.end()) {
66  continue;
67  }
68 
69  // smear all truth hits for this module
70  const Acts::Surface* surface = is->second;
71  for (const auto& hit : moduleHits) {
72  // transform global position into local coordinates
73  Acts::Vector2D pos(0, 0);
74  surface->globalToLocal(ctx.geoContext, hit.position(),
75  hit.unitDirection(), pos);
76 
77  // smear truth to create local measurement
78  Acts::BoundVector loc = Acts::BoundVector::Zero();
79  loc[Acts::eLOC_0] = pos[0] + m_cfg.sigmaLoc0 * stdNormal(rng);
80  loc[Acts::eLOC_1] = pos[1] + m_cfg.sigmaLoc1 * stdNormal(rng);
81 
82  // create source link at the end of the container
83  auto it = sourceLinks.emplace_hint(sourceLinks.end(), *surface, hit, 2,
84  loc, cov);
85  // ensure hits and links share the same order to prevent ugly surprises
86  if (std::next(it) != sourceLinks.end()) {
87  ACTS_FATAL("The hit ordering broke. Run for your life.");
88  return ProcessCode::ABORT;
89  }
90  }
91  }
92 
93  ctx.eventStore.add(m_cfg.outputSourceLinks, std::move(sourceLinks));
94  return ProcessCode::SUCCESS;
95 }