Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ParametricParticleGenerator.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ParametricParticleGenerator.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2020 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 <limits>
18 #include <random>
19 #include <utility>
20 
22  const Config& cfg)
23  : m_cfg(cfg),
24  m_charge(cfg.charge.value_or(Acts::findCharge(m_cfg.pdg).value_or(0))),
25  m_mass(cfg.mass.value_or(Acts::findMass(m_cfg.pdg).value_or(0))),
26  // since we want to draw the direction uniform on the unit sphere, we must
27  // draw from cos(theta) instead of theta. see e.g.
28  // https://mathworld.wolfram.com/SpherePointPicking.html
29  m_cosThetaMin(std::cos(m_cfg.thetaMin)),
30  // ensure upper bound is included. see e.g.
31  // https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution
32  m_cosThetaMax(std::nextafter(std::cos(m_cfg.thetaMax),
33  std::numeric_limits<double>::max())),
34  // in case we force uniform eta generation
35  m_etaMin(-std::log(std::tan(0.5 * m_cfg.thetaMin))),
36  m_etaMax(-std::log(std::tan(0.5 * m_cfg.thetaMax))) {}
37 
40  using UniformIndex = std::uniform_int_distribution<unsigned int>;
41  using UniformReal = std::uniform_real_distribution<double>;
42 
43  // choose between particle/anti-particle if requested
44  // the upper limit of the distribution is inclusive
45  UniformIndex particleTypeChoice(0u, m_cfg.randomizeCharge ? 1u : 0u);
46  // (anti-)particle choice is one random draw but defines two properties
47  const Acts::PdgParticle pdgChoices[] = {
48  m_cfg.pdg,
49  static_cast<Acts::PdgParticle>(-m_cfg.pdg),
50  };
51  const double qChoices[] = {
52  m_charge,
53  -m_charge,
54  };
55  UniformReal phiDist(m_cfg.phiMin, m_cfg.phiMax);
56  UniformReal cosThetaDist(m_cosThetaMin, m_cosThetaMax);
57  UniformReal etaDist(m_etaMin, m_etaMax);
58  UniformReal pDist(m_cfg.pMin, m_cfg.pMax);
59 
61  particles.reserve(m_cfg.numParticles);
62 
63  // counter will be reused as barcode particle number which must be non-zero.
64  for (size_t ip = 1; ip <= m_cfg.numParticles; ++ip) {
65  // all particles are treated as originating from the same primary vertex
66  const auto pid = ActsFatras::Barcode(0u).setParticle(ip);
67 
68  // draw parameters
69  const unsigned int type = particleTypeChoice(rng);
70  const Acts::PdgParticle pdg = pdgChoices[type];
71  const double q = qChoices[type];
72  const double phi = phiDist(rng);
73  double p = pDist(rng);
74 
75  // we already have sin/cos theta. they can be used directly to
76  Acts::Vector3 dir;
77  double cosTheta = 0.;
78  double sinTheta = 0.;
79  if (not m_cfg.etaUniform) {
80  cosTheta = cosThetaDist(rng);
81  sinTheta = std::sqrt(1 - cosTheta * cosTheta);
82  } else {
83  const double eta = etaDist(rng);
84  const double theta = 2 * std::atan(std::exp(-eta));
85  sinTheta = std::sin(theta);
86  cosTheta = std::cos(theta);
87  }
88  dir[Acts::eMom0] = sinTheta * std::cos(phi);
89  dir[Acts::eMom1] = sinTheta * std::sin(phi);
90  dir[Acts::eMom2] = cosTheta;
91 
92  // construct the particle;
93  ActsFatras::Particle particle(pid, pdg, q, m_mass);
94  particle.setDirection(dir);
95  p *= m_cfg.pTransverse ? 1. / sinTheta : 1.;
96  particle.setAbsoluteMomentum(p);
97 
98  // generated particle ids are already ordered and should end up at the end
99  particles.insert(particles.end(), std::move(particle));
100  }
101 
102  return particles;
103 }