15#include <Pythia8/Pythia.h>
17#include <SHiP/Units.hpp>
31using PythiaTime = mp_units::quantity<ship::units::mm_per_c, double>;
36inline int pythia_seed(std::uint32_t base,
int extra_streams = 0) {
37 if (extra_streams < 0 || extra_streams >= 900000000) {
38 throw std::invalid_argument(
"pythia_seed: extra_streams " +
39 std::to_string(extra_streams) +
40 " must be in [0, 900000000)");
42 auto const range =
static_cast<std::uint32_t
>(900000000 - extra_streams);
43 return static_cast<int>(base % range) + 1;
48template <
typename Pythia>
50 ship::Energy beam_energy) {
51 pythia.readString(
"Beams:idA = " + std::to_string(idA));
52 pythia.readString(
"Beams:idB = " + std::to_string(idB));
53 pythia.readString(
"Beams:frameType = 2");
56 std::to_string(beam_energy.numerical_value_in(ship::units::GeV)));
57 pythia.readString(
"Beams:eB = 0.");
63template <
typename Pythia>
65 double const threshold =
66 tau0_threshold.numerical_value_in(ship::units::mm_per_c);
67 for (
auto it = pythia.particleData.begin(); it != pythia.particleData.end();
69 auto const& entry = it->second;
70 if (entry && entry->tau0() > threshold) {
71 entry->setMayDecay(
false);
81template <
typename Pythia>
82void next_event(Pythia& pythia, std::string_view source_name,
83 int max_attempts = 10) {
84 for (
int attempt = 0; attempt < max_attempts; ++attempt) {
89 throw std::runtime_error(std::string(source_name) +
90 ": Pythia8 event generation failed " +
91 std::to_string(max_attempts) +
" times in a row");
122template <
typename MCParticle>
124 Pythia8::Event
const& event, ship::Length z_offset = ship::Length::zero(),
126 namespace su = ship::units;
127 std::vector<MCParticle> particles;
128 particles.reserve(event.size());
133 std::vector<int> out_index(
static_cast<std::size_t
>(event.size()), -1);
135 for (
int i = 1; i <
event.size(); ++i) {
136 auto const& p =
event[i];
141 out_index[
static_cast<std::size_t
>(i)] =
static_cast<int>(particles.size());
149 mc.vertex = ship::raw(ship::Vec3<ship::Length>{
150 p.xProd() * su::mm, p.yProd() * su::mm, p.zProd() * su::mm + z_offset});
151 mc.momentum = ship::raw(ship::Vec3<ship::Momentum>{p.px() * su::GeV_per_c,
152 p.py() * su::GeV_per_c,
153 p.pz() * su::GeV_per_c});
154 mc.energy = ship::raw(p.e() * su::GeV);
156 mc.time = (p.tProd() * su::mm_per_c).numerical_value_in(su::ns);
157 mc.status = p.statusHepMC();
159 for (
int const m : p.motherList()) {
160 mc.mothers.push_back(m);
162 particles.push_back(mc);
165 for (
auto& mc : particles) {
166 std::vector<std::int32_t> mapped;
167 mapped.reserve(mc.mothers.size());
168 for (
int const m : mc.mothers) {
169 if (m < 0 || std::cmp_greater_equal(m, out_index.size())) {
172 if (
int const out = out_index[
static_cast<std::size_t
>(m)]; out >= 0) {
173 mapped.push_back(out);
176 mc.mothers = std::move(mapped);
177 mc.motherId = mc.mothers.empty() ? -1 : mc.mothers.front();
Definition hepmc_status.hpp:17
record_mode
Definition record_mode.hpp:20
@ final_state
Only particles the generator left undecayed.
void configure_beams(Pythia &pythia, int idA, int idB, ship::Energy beam_energy)
Definition pythia_common.hpp:49
mp_units::quantity< ship::units::mm_per_c, double > PythiaTime
Definition pythia_common.hpp:31
void next_event(Pythia &pythia, std::string_view source_name, int max_attempts=10)
Definition pythia_common.hpp:82
int pythia_seed(std::uint32_t base, int extra_streams=0)
Definition pythia_common.hpp:36
void stabilise_long_lived(Pythia &pythia, PythiaTime tau0_threshold)
Definition pythia_common.hpp:64
std::vector< MCParticle > extract_particles(Pythia8::Event const &event, ship::Length z_offset=ship::Length::zero(), record_mode mode=record_mode::final_state)
Definition pythia_common.hpp:123