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 
16 
17 #include <cmath>
18 #include <vector>
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  // setup input and output containers
34  const auto& particles =
35  ctx.eventStore.get<SimParticleContainer>(m_cfg.inputParticles);
37  parameters.reserve(particles.size());
38 
39  // setup random number generator and standard gaussian
40  auto rng = m_cfg.randomNumbers->spawnGenerator(ctx);
41  std::normal_distribution<double> stdNormal(0.0, 1.0);
42 
43  for (const auto& particle : particles) {
44  const auto phi = Acts::VectorHelpers::phi(particle.unitDirection());
45  const auto theta = Acts::VectorHelpers::theta(particle.unitDirection());
46  const auto pt = particle.transverseMomentum();
47  const auto p = particle.absMomentum();
48 
49  // compute momentum-dependent resolutions
50  const auto sigmaD0 =
51  m_cfg.sigmaD0 +
52  m_cfg.sigmaD0PtA * std::exp(-1.0 * std::abs(m_cfg.sigmaD0PtB) * pt);
53  const auto sigmaZ0 =
54  m_cfg.sigmaZ0 +
55  m_cfg.sigmaZ0PtA * std::exp(-1.0 * std::abs(m_cfg.sigmaZ0PtB) * pt);
56  const auto sigmaP = m_cfg.sigmaPRel * p;
57  // var(q/p) = (d(1/p)/dp)² * var(p) = (-1/p²)² * var(p)
58  const auto sigmaQOverP = sigmaP / (p * p);
59  // shortcuts for other resolutions
60  const auto sigmaT0 = m_cfg.sigmaT0;
61  const auto sigmaPhi = m_cfg.sigmaPhi;
62  const auto sigmaTheta = m_cfg.sigmaTheta;
63  // converstion from perigee d0,z0 to curvilinear u,v
64  // d0 and u differ only by a sign
65  const auto sigmaU = sigmaD0;
66  // project from z0 to the second axes orthogonal to the track direction
67  const auto sigmaV = sigmaZ0 * std::sin(theta);
68 
69  // draw random noise
70  const auto deltaD0 = sigmaD0 * stdNormal(rng);
71  const auto deltaZ0 = sigmaZ0 * stdNormal(rng);
72  const auto deltaT0 = sigmaT0 * stdNormal(rng);
73  const auto deltaPhi = sigmaPhi * stdNormal(rng);
74  const auto deltaTheta = sigmaTheta * stdNormal(rng);
75  const auto deltaP = sigmaP * stdNormal(rng);
76 
77  // smear the position/time
78  Acts::Vector4D pos4 = particle.position4();
79  pos4[Acts::ePos0] += deltaD0 * std::sin(phi);
80  pos4[Acts::ePos1] += deltaD0 * -std::cos(phi);
81  pos4[Acts::ePos2] += deltaZ0;
82  pos4[Acts::eTime] += deltaT0;
83  // smear direction angles phi,theta ensuring correct bounds
84  const auto [newPhi, newTheta] =
85  Acts::detail::ensureThetaBounds(phi + deltaPhi, theta + deltaTheta);
86  // compute smeared absolute momentum vector
87  const auto newP = p + deltaP;
88 
89  // build the track covariance matrix using the smearing sigmas
90  Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero();
91  cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = sigmaU * sigmaU;
92  cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = sigmaV * sigmaV;
93  cov(Acts::eBoundTime, Acts::eBoundTime) = sigmaT0 * sigmaT0;
94  cov(Acts::eBoundPhi, Acts::eBoundPhi) = sigmaPhi * sigmaPhi;
95  cov(Acts::eBoundTheta, Acts::eBoundTheta) = sigmaTheta * sigmaTheta;
96  cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = sigmaQOverP * sigmaQOverP;
97 
98  parameters.emplace_back(pos4, newPhi, newTheta, newP, particle.charge(),
99  cov);
100  };
101 
102  ctx.eventStore.add(m_cfg.outputTrackParameters, std::move(parameters));
103  return ProcessCode::SUCCESS;
104 }