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 
20  : BareAlgorithm("HitSmearing", lvl), m_cfg(cfg) {
21  if (m_cfg.inputSimulatedHits.empty()) {
22  throw std::invalid_argument("Missing input simulated hits collection");
23  }
24  if (m_cfg.outputSourceLinks.empty()) {
25  throw std::invalid_argument("Missing output source links collection");
26  }
27  if ((m_cfg.sigmaLoc0 < 0) or (m_cfg.sigmaLoc1 < 0)) {
28  throw std::invalid_argument("Invalid resolution setting");
29  }
30  if (not m_cfg.trackingGeometry) {
31  throw std::invalid_argument("Missing tracking geometry");
32  }
33  if (!m_cfg.randomNumbers) {
34  throw std::invalid_argument("Missing random numbers tool");
35  }
36  // fill the surface map to allow lookup by geometry id only
37  m_cfg.trackingGeometry->visitSurfaces([this](const Acts::Surface* surface) {
38  // for now we just require a valid surface
39  if (not surface) {
40  return;
41  }
42  this->m_surfaces.insert_or_assign(surface->geometryId(), surface);
43  });
44 }
45 
47  const AlgorithmContext& ctx) const {
48  // setup input and output containers
49  const auto& hits =
50  ctx.eventStore.get<SimHitContainer>(m_cfg.inputSimulatedHits);
51  SimSourceLinkContainer sourceLinks;
52  sourceLinks.reserve(hits.size());
53 
54  // setup random number generator
55  auto rng = m_cfg.randomNumbers->spawnGenerator(ctx);
56  std::normal_distribution<double> stdNormal(0.0, 1.0);
57 
58  // setup local covariance
59  // TODO add support for per volume/layer/module settings
60  Acts::BoundMatrix cov = Acts::BoundMatrix::Zero();
61  cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_cfg.sigmaLoc0 * m_cfg.sigmaLoc0;
62  cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_cfg.sigmaLoc1 * m_cfg.sigmaLoc1;
63 
64  for (auto&& [moduleGeoId, moduleHits] : groupByModule(hits)) {
65  // check if we should create hits for this surface
66  const auto is = m_surfaces.find(moduleGeoId);
67  if (is == m_surfaces.end()) {
68  continue;
69  }
70 
71  // smear all truth hits for this module
72  const Acts::Surface* surface = is->second;
73  for (const auto& hit : moduleHits) {
74  // transform global position into local coordinates
75  auto lpResult = surface->globalToLocal(ctx.geoContext, hit.position(),
76  hit.unitDirection());
77  Acts::Vector2D lp{0., 0.};
78  if (not lpResult.ok()) {
79  ACTS_ERROR("Global to local transformation did not succeed.");
80  return ProcessCode::ABORT;
81  } else {
82  lp = lpResult.value();
83  }
84 
85  // smear truth to create local measurement
86  Acts::BoundVector loc = Acts::BoundVector::Zero();
87  loc[Acts::eBoundLoc0] = lp[0] + m_cfg.sigmaLoc0 * stdNormal(rng);
88  loc[Acts::eBoundLoc1] = lp[1] + m_cfg.sigmaLoc1 * stdNormal(rng);
89 
90  // create source link at the end of the container
91  auto it = sourceLinks.emplace_hint(sourceLinks.end(), *surface, hit, 2,
92  loc, cov);
93  // ensure hits and links share the same order to prevent ugly surprises
94  if (std::next(it) != sourceLinks.end()) {
95  ACTS_FATAL("The hit ordering broke. Run for your life.");
96  return ProcessCode::ABORT;
97  }
98  }
99  }
100 
101  ctx.eventStore.add(m_cfg.outputSourceLinks, std::move(sourceLinks));
102  return ProcessCode::SUCCESS;
103 }