File indexing completed on 2025-07-08 08:10:25
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Generators/Pythia8ProcessGenerator.hpp"
0010
0011 #include "Acts/Plugins/FpeMonitoring/FpeMonitor.hpp"
0012 #include "Acts/Utilities/MathHelpers.hpp"
0013 #include "ActsExamples/EventData/SimVertex.hpp"
0014 #include "ActsFatras/EventData/Barcode.hpp"
0015 #include "ActsFatras/EventData/Particle.hpp"
0016
0017 #include <algorithm>
0018 #include <iterator>
0019 #include <ostream>
0020 #include <random>
0021 #include <utility>
0022
0023 #include <HepMC3/WriterAscii.h>
0024 #include <Pythia8/Pythia.h>
0025 #include <Pythia8Plugins/HepMC3.h>
0026
0027 namespace ActsExamples {
0028
0029 struct Pythia8RandomEngineWrapper : public Pythia8::RndmEngine {
0030 RandomEngine* rng{nullptr};
0031
0032 struct {
0033 std::size_t numUniformRandomNumbers = 0;
0034 double first = std::numeric_limits<double>::quiet_NaN();
0035 double last = std::numeric_limits<double>::quiet_NaN();
0036 } statistics;
0037
0038 Pythia8RandomEngineWrapper() = default;
0039
0040 double flat() override {
0041 if (rng == nullptr) {
0042 throw std::runtime_error(
0043 "Pythia8RandomEngineWrapper: no random engine set");
0044 }
0045
0046 double value = std::uniform_real_distribution<double>(0.0, 1.0)(*rng);
0047 if (statistics.numUniformRandomNumbers == 0) {
0048 statistics.first = value;
0049 }
0050 statistics.last = value;
0051 statistics.numUniformRandomNumbers++;
0052 return value;
0053 }
0054
0055 void setRandomEngine(RandomEngine& rng_) { rng = &rng_; }
0056 void clearRandomEngine() { rng = nullptr; }
0057 };
0058
0059 struct Pythia8GeneratorImpl {
0060 std::unique_ptr<HepMC3::Writer> m_hepMC3Writer;
0061 std::unique_ptr<HepMC3::Pythia8ToHepMC3> m_hepMC3Converter;
0062 std::shared_ptr<Pythia8RandomEngineWrapper> m_pythia8RndmEngine;
0063 };
0064
0065 Pythia8Generator::Pythia8Generator(const Config& cfg, Acts::Logging::Level lvl)
0066 : m_cfg(cfg),
0067 m_logger(Acts::getDefaultLogger("Pythia8Generator", lvl)),
0068 m_pythia8(std::make_unique<Pythia8::Pythia>("", false)) {
0069 ACTS_INFO("Pythia8Generator: init");
0070
0071 m_pythia8->settings.flag("Print:quiet", true);
0072 for (const auto& setting : m_cfg.settings) {
0073 ACTS_VERBOSE("use Pythia8 setting '" << setting << "'");
0074 m_pythia8->readString(setting.c_str());
0075 }
0076 m_pythia8->settings.mode("Beams:idA", m_cfg.pdgBeam0);
0077 m_pythia8->settings.mode("Beams:idB", m_cfg.pdgBeam1);
0078 m_pythia8->settings.mode("Beams:frameType", 1);
0079 m_pythia8->settings.parm("Beams:eCM",
0080 m_cfg.cmsEnergy / Acts::UnitConstants::GeV);
0081
0082 m_impl = std::make_unique<Pythia8GeneratorImpl>();
0083
0084 m_impl->m_pythia8RndmEngine = std::make_shared<Pythia8RandomEngineWrapper>();
0085
0086 #if PYTHIA_VERSION_INTEGER >= 8310
0087 m_pythia8->setRndmEnginePtr(m_impl->m_pythia8RndmEngine);
0088 #else
0089 m_pythia8->setRndmEnginePtr(m_impl->m_pythia8RndmEngine.get());
0090 #endif
0091
0092 RandomEngine rng{m_cfg.initializationSeed};
0093 m_impl->m_pythia8RndmEngine->setRandomEngine(rng);
0094 m_pythia8->init();
0095 m_impl->m_pythia8RndmEngine->clearRandomEngine();
0096
0097 m_impl->m_hepMC3Converter = std::make_unique<HepMC3::Pythia8ToHepMC3>();
0098 if (m_cfg.writeHepMC3.has_value()) {
0099 ACTS_DEBUG("Initializing HepMC3 output to: " << m_cfg.writeHepMC3.value());
0100 m_impl->m_hepMC3Writer =
0101 std::make_unique<HepMC3::WriterAscii>(m_cfg.writeHepMC3.value());
0102 }
0103 }
0104
0105
0106 Pythia8Generator::~Pythia8Generator() {
0107 if (m_impl->m_hepMC3Writer) {
0108 m_impl->m_hepMC3Writer->close();
0109 }
0110
0111 ACTS_DEBUG("Pythia8Generator produced "
0112 << m_impl->m_pythia8RndmEngine->statistics.numUniformRandomNumbers
0113 << " uniform random numbers");
0114 ACTS_DEBUG(" first = "
0115 << m_impl->m_pythia8RndmEngine->statistics.first);
0116 ACTS_DEBUG(" last = "
0117 << m_impl->m_pythia8RndmEngine->statistics.last);
0118 }
0119
0120 std::shared_ptr<HepMC3::GenEvent> Pythia8Generator::operator()(
0121 RandomEngine& rng) {
0122 using namespace Acts::UnitLiterals;
0123
0124
0125 std::lock_guard<std::mutex> lock(m_pythia8Mutex);
0126
0127
0128 m_impl->m_pythia8RndmEngine->setRandomEngine(rng);
0129
0130 {
0131 Acts::FpeMonitor mon{0};
0132 m_pythia8->next();
0133 }
0134
0135 if (m_cfg.printShortEventListing) {
0136 m_pythia8->process.list();
0137 }
0138 if (m_cfg.printLongEventListing) {
0139 m_pythia8->event.list();
0140 }
0141
0142 auto genEvent = std::make_shared<HepMC3::GenEvent>();
0143 genEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM);
0144
0145 assert(m_impl->m_hepMC3Converter != nullptr);
0146 m_impl->m_hepMC3Converter->fill_next_event(*m_pythia8, genEvent.get(),
0147 genEvent->event_number());
0148
0149 if (m_impl->m_hepMC3Converter && m_impl->m_hepMC3Writer) {
0150 m_impl->m_hepMC3Writer->write_event(*genEvent);
0151 }
0152
0153 m_impl->m_pythia8RndmEngine->clearRandomEngine();
0154
0155 return genEvent;
0156 }
0157
0158 }