EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Pythia8ProcessGenerator.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file Pythia8ProcessGenerator.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-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 <algorithm>
12 #include <iterator>
13 #include <random>
14 
15 #include <Pythia8/Pythia.h>
16 
17 namespace {
18 struct FrameworkRndmEngine : public Pythia8::RndmEngine {
20 
21  FrameworkRndmEngine(ActsExamples::RandomEngine& rng_) : rng(rng_) {}
22  double flat() {
23  return std::uniform_real_distribution<double>(0.0, 1.0)(rng);
24  }
25 };
26 } // namespace
27 
28 std::function<ActsExamples::SimParticleContainer(ActsExamples::RandomEngine&)>
31  auto gen = std::make_shared<Pythia8Generator>(cfg, lvl);
32  return [=](RandomEngine& rng) { return (*gen)(rng); };
33 }
34 
37  : m_cfg(cfg),
38  m_logger(Acts::getDefaultLogger("Pythia8Generator", lvl)),
39  m_pythia8(std::make_unique<Pythia8::Pythia>("", false)) {
40  // disable all output by default but allow reenable via config
41  m_pythia8->settings.flag("Print:quiet", true);
42  for (const auto& setting : m_cfg.settings) {
43  ACTS_VERBOSE("use Pythia8 setting '" << setting << "'");
44  m_pythia8->readString(setting.c_str());
45  }
46  m_pythia8->settings.mode("Beams:idA", m_cfg.pdgBeam0);
47  m_pythia8->settings.mode("Beams:idB", m_cfg.pdgBeam1);
48  m_pythia8->settings.mode("Beams:frameType", 1);
49  m_pythia8->settings.parm("Beams:eCM",
51  m_pythia8->init();
52 }
53 
54 // needed to allow unique_ptr of forward-declared Pythia class
56 
58  RandomEngine& rng) {
59  using namespace Acts::UnitLiterals;
60 
61  SimParticleContainer::sequence_type generated;
62  std::vector<SimParticle::Vector4> vertexPositions;
63 
64  // pythia8 is not thread safe and generation needs to be protected
65  std::lock_guard<std::mutex> lock(m_pythia8Mutex);
66  // use per-thread random engine also in pythia
67  FrameworkRndmEngine rndmEngine(rng);
68  m_pythia8->rndm.rndmEnginePtr(&rndmEngine);
69  m_pythia8->next();
70 
71  // convert generated final state particles into internal format
72  for (int ip = 0; ip < m_pythia8->event.size(); ++ip) {
73  const auto& genParticle = m_pythia8->event[ip];
74 
75  // ignore beam particles
76  if (genParticle.statusHepMC() == 4) {
77  continue;
78  }
79  // only interested in final, visible particles
80  if (not genParticle.isFinal()) {
81  continue;
82  }
83  if (not genParticle.isVisible()) {
84  continue;
85  }
86 
87  // production vertex. Pythia8 time uses units mm/c, and we use c=1
89  genParticle.xProd() * 1_mm, genParticle.yProd() * 1_mm,
90  genParticle.zProd() * 1_mm, genParticle.tProd() * 1_mm);
91 
92  // define the particle identifier including possible secondary vertices
93  ActsFatras::Barcode particleId(0u);
94  // ensure particle identifier component is non-zero
95  particleId.setParticle(1u + generated.size());
96  // only secondaries have a defined vertex position
97  if (genParticle.hasVertex()) {
98  // either add to existing secondary vertex if exists or create new one
99  // TODO can we do this w/o the manual search and position check?
100  auto it = std::find_if(
101  vertexPositions.begin(), vertexPositions.end(),
102  [=](const SimParticle::Vector4& pos) { return (pos == pos4); });
103  if (it == vertexPositions.end()) {
104  // no matching secondary vertex exists -> create new one
105  vertexPositions.emplace_back(pos4);
106  particleId.setVertexSecondary(vertexPositions.size());
107  ACTS_VERBOSE("created new secondary vertex " << pos4.transpose());
108  } else {
109  particleId.setVertexSecondary(
110  1u + std::distance(vertexPositions.begin(), it));
111  }
112  }
113 
114  // construct internal particle
115  const auto pdg = static_cast<Acts::PdgParticle>(genParticle.id());
116  const auto charge = genParticle.charge() * 1_e;
117  const auto mass = genParticle.m0() * 1_GeV;
119  particle.setPosition4(pos4);
120  // normalization/ units are not import for the direction
121  particle.setDirection(genParticle.px(), genParticle.py(), genParticle.pz());
122  particle.setAbsMomentum(
123  std::hypot(genParticle.px(), genParticle.py(), genParticle.pz()) *
124  1_GeV);
125 
126  generated.push_back(std::move(particle));
127  }
128 
130  out.adopt_sequence(std::move(generated));
131  return out;
132 }