ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ParticleSmearing.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ParticleSmearing.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 
11 #include <cmath>
12 #include <vector>
13 
19 
22  : BareAlgorithm("ParticleSmearing", lvl), m_cfg(cfg) {
23  if (m_cfg.inputParticles.empty()) {
24  throw std::invalid_argument("Missing input truth particles collection");
25  }
26  if (m_cfg.outputTrackParameters.empty()) {
27  throw std::invalid_argument("Missing output tracks parameters collection");
28  }
29 }
30 
32  const AlgorithmContext& ctx) const {
33  namespace vh = Acts::VectorHelpers;
34 
35  // setup input and output containers
36  const auto& particles =
37  ctx.eventStore.get<SimParticleContainer>(m_cfg.inputParticles);
39  parameters.reserve(particles.size());
40 
41  // setup random number generator and standard gaussian
42  auto rng = m_cfg.randomNumbers->spawnGenerator(ctx);
43  std::normal_distribution<double> stdNormal(0.0, 1.0);
44 
45  for (const auto& particle : particles) {
46  const auto pt = particle.transverseMomentum();
47  const auto p = particle.absMomentum();
48  const auto theta = vh::theta(particle.unitDirection());
49  const auto phi = vh::phi(particle.unitDirection());
50 
51  // compute momentum-dependent resolutions
52  const auto sigmaD0 =
53  m_cfg.sigmaD0 +
54  m_cfg.sigmaD0PtA * std::exp(-1.0 * std::abs(m_cfg.sigmaD0PtB) * pt);
55  const auto sigmaZ0 =
56  m_cfg.sigmaZ0 +
57  m_cfg.sigmaZ0PtA * std::exp(-1.0 * std::abs(m_cfg.sigmaZ0PtB) * pt);
58  const auto sigmaP = m_cfg.sigmaPRel * p;
59  // var(q/p) = (d(1/p)/dp)² * var(p) = (-1/p²)² * var(p)
60  const auto sigmaQOverP = sigmaP / (p * p);
61  // shortcuts for other resolutions
62  const auto sigmaT0 = m_cfg.sigmaT0;
63  const auto sigmaPhi = m_cfg.sigmaPhi;
64  const auto sigmaTheta = m_cfg.sigmaTheta;
65  // converstion from perigee d0,z0 to curvilinear u,v
66  // d0 and u differ only by a sign
67  const auto sigmaU = sigmaD0;
68  // project from z0 to the second axes orthogonal to the track direction
69  const auto sigmaV = sigmaZ0 * std::sin(theta);
70 
71  // draw random noise
72  const auto deltaD0 = sigmaD0 * stdNormal(rng);
73  const auto deltaZ0 = sigmaZ0 * stdNormal(rng);
74  const auto deltaT0 = sigmaT0 * stdNormal(rng);
75  const auto deltaPhi = sigmaPhi * stdNormal(rng);
76  const auto deltaTheta = sigmaTheta * stdNormal(rng);
77  const auto deltaP = sigmaP * stdNormal(rng);
78 
79  // smear the position
80  const Acts::Vector3D pos =
81  particle.position() + Acts::Vector3D(deltaD0 * std::sin(phi),
82  deltaD0 * -std::cos(phi), deltaZ0);
83  // smear the time
84  const auto time = particle.time() + deltaT0;
85  // smear direction angles phi,theta ensuring correct bounds
86  const auto angles =
87  Acts::detail::ensureThetaBounds(phi + deltaPhi, theta + deltaTheta);
88  // compute smeared direction vector
89  const Acts::Vector3D dir(std::sin(angles.second) * std::cos(angles.first),
90  std::sin(angles.second) * std::sin(angles.first),
91  std::cos(angles.second));
92  // compute smeared momentum vector
93  const Acts::Vector3D mom = (p + deltaP) * dir;
94 
95  // build the track covariance matrix using the smearing sigmas
96  Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero();
97  cov(Acts::eLOC_0, Acts::eLOC_0) = sigmaU * sigmaU;
98  cov(Acts::eLOC_1, Acts::eLOC_1) = sigmaV * sigmaV;
99  cov(Acts::ePHI, Acts::ePHI) = sigmaPhi * sigmaPhi;
100  cov(Acts::eTHETA, Acts::eTHETA) = sigmaTheta * sigmaTheta;
101  cov(Acts::eQOP, Acts::eQOP) = sigmaQOverP * sigmaQOverP;
102  cov(Acts::eT, Acts::eT) = sigmaT0 * sigmaT0;
103 
104  parameters.emplace_back(std::make_optional(std::move(cov)), pos, mom,
105  particle.charge(), time);
106  };
107 
108  ctx.eventStore.add(m_cfg.outputTrackParameters, std::move(parameters));
109  return ProcessCode::SUCCESS;
110 }