6#include "G4ParticleTable.hh"
16constexpr size_t LUND_MIN_HEADER_COLUMNS = 10;
17constexpr size_t LUND_MAX_HEADER_COLUMNS = 100;
18constexpr size_t LUND_MIN_PARTICLE_COLUMNS = 14;
19constexpr size_t LUND_MAX_PARTICLE_COLUMNS = 100;
20constexpr int LUND_PROPAGATED_TYPE = 1;
22bool is_blank_line(
const std::string& line) {
23 return line.find_first_not_of(
" \t\r\n") == std::string::npos;
26std::vector<double> parse_lund_header(
const std::string& line) {
27 std::istringstream stream(line);
28 std::vector<double> values;
31 while (stream >> value) { values.emplace_back(value); }
33 if (!stream.eof()) { values.clear(); }
38struct LundParticleLine
56bool parse_lund_particle_line(
const std::string& line, LundParticleLine& particle) {
57 std::istringstream stream(line);
58 std::vector<double> values;
61 while (stream >> value) { values.emplace_back(value); }
64 values.size() < LUND_MIN_PARTICLE_COLUMNS ||
65 values.size() > LUND_MAX_PARTICLE_COLUMNS) {
69 particle.index =
static_cast<int>(values[0]);
70 particle.lifetime = values[1];
71 particle.type =
static_cast<int>(values[2]);
72 particle.pid =
static_cast<int>(values[3]);
73 particle.parent =
static_cast<int>(values[4]);
74 particle.daughter =
static_cast<int>(values[5]);
75 particle.px = values[6];
76 particle.py = values[7];
77 particle.pz = values[8];
78 particle.energy = values[9];
79 particle.mass = values[10];
80 particle.vx = values[11];
81 particle.vy = values[12];
82 particle.vz = values[13];
84 return particle.index == values[0] &&
85 particle.type == values[2] &&
86 particle.pid == values[3] &&
87 particle.parent == values[4] &&
88 particle.daughter == values[5];
91std::string particle_name_from_pid(
int pid,
const std::shared_ptr<GLogger>& logger) {
92 auto particle_table = G4ParticleTable::GetParticleTable();
93 if (particle_table ==
nullptr) {
98 auto particle_definition = particle_table->FindParticle(pid);
99 if (particle_definition ==
nullptr) {
104 return particle_definition->GetParticleName();
107GparticlePtr make_gparticle_from_lund(
const LundParticleLine& particle,
const std::shared_ptr<GLogger>& logger) {
108 const auto particle_name = particle_name_from_pid(particle.pid, logger);
109 if (particle_name.empty()) {
return nullptr; }
111 const double momentum = std::sqrt(
112 particle.px * particle.px +
113 particle.py * particle.py +
114 particle.pz * particle.pz
118 if (momentum > 0) { theta = std::acos(particle.pz / momentum); }
120 const double phi = std::atan2(particle.py, particle.px);
122 return std::make_shared<Gparticle>(
149 const std::shared_ptr<GLogger>& logger) {
152 const double momentum = std::sqrt(
153 particle.px * particle.px +
154 particle.py * particle.py +
155 particle.pz * particle.pz
159 if (momentum > 0) { theta = std::acos(particle.pz / momentum); }
161 std::string particle_name;
162 auto particle_table = G4ParticleTable::GetParticleTable();
163 if (particle_table !=
nullptr) {
164 auto particle_definition = particle_table->FindParticle(particle.pid);
165 if (particle_definition !=
nullptr) { particle_name = particle_definition->GetParticleName(); }
167 if (particle_name.empty()) { particle_name = std::to_string(particle.pid); }
176 std::atan2(particle.py, particle.px),
186 const std::shared_ptr<GLogger>& logger,
187 bool propagated_only) {
189 std::ifstream input(source.
filename);
191 if (!input.is_open()) {
197 while (std::getline(input, line)) {
198 if (is_blank_line(line)) {
continue; }
200 const auto header_values = parse_lund_header(line);
202 if (header_values.size() < LUND_MIN_HEADER_COLUMNS || header_values.size() > LUND_MAX_HEADER_COLUMNS) {
207 const auto particle_count =
static_cast<int>(header_values.front());
208 if (particle_count < 0 || particle_count != header_values.front()) {
210 "Lund event header first column must be a non-negative integer in <",
215 bool have_first_particle_line =
false;
216 if (!std::getline(input, line)) {
218 "Lund event header must be followed by a blank line in <", source.
filename,
">");
221 if (!is_blank_line(line)) { have_first_particle_line =
true; }
224 for (
int i = 0; i < particle_count; i++) {
225 if (have_first_particle_line) {
226 have_first_particle_line =
false;
228 else if (!std::getline(input, line)) {
230 "Lund event declared ", particle_count,
" particles but ended after ",
231 i,
" particle lines in <", source.
filename,
">");
235 if (is_blank_line(line)) {
237 "Unexpected blank line inside Lund particle block in <", source.
filename,
">");
241 LundParticleLine lund_particle;
242 if (!parse_lund_particle_line(line, lund_particle)) {
247 if (lund_particle.index != i + 1) {
249 "Lund particle index must start from 1 and follow particle order in <",
254 if (propagated_only && lund_particle.type != LUND_PROPAGATED_TYPE) {
continue; }
256 auto particle = make_gparticle_from_lund(lund_particle, logger);
257 if (particle !=
nullptr) { event_particles.emplace_back(particle); }
260 events.emplace_back(std::move(event_particles));
263 logger->info(1,
"Loaded ", events.size(),
" Lund events from <", source.
filename,
">");
268 const std::shared_ptr<GLogger>& logger) {
269 std::vector<GparticlePtr> particles;
271 particles.insert(particles.end(),
event.begin(),
event.end());
274 logger->info(1,
"Loaded ", particles.size(),
" propagated particles from Lund file <", source.
filename,
">");
279 const std::shared_ptr<GLogger>& logger) {
281 std::ifstream input(source.
filename);
283 if (!input.is_open()) {
289 while (std::getline(input, line)) {
290 if (is_blank_line(line)) {
continue; }
292 const auto header_values = parse_lund_header(line);
293 if (header_values.size() < LUND_MIN_HEADER_COLUMNS || header_values.size() > LUND_MAX_HEADER_COLUMNS) {
298 const auto particle_count =
static_cast<int>(header_values.front());
299 if (particle_count < 0 || particle_count != header_values.front()) {
301 "Lund event header first column must be a non-negative integer in <",
306 bool have_first_particle_line =
false;
307 if (!std::getline(input, line)) {
309 "Lund event header must be followed by a blank line in <", source.
filename,
">");
312 if (!is_blank_line(line)) { have_first_particle_line =
true; }
315 for (
int i = 0; i < particle_count; i++) {
316 if (have_first_particle_line) {
317 have_first_particle_line =
false;
319 else if (!std::getline(input, line)) {
321 "Lund event declared ", particle_count,
" particles but ended after ",
322 i,
" particle lines in <", source.
filename,
">");
326 if (is_blank_line(line)) {
328 "Unexpected blank line inside Lund particle block in <", source.
filename,
">");
332 LundParticleLine lund_particle;
333 if (!parse_lund_particle_line(line, lund_particle)) {
338 if (lund_particle.index != i + 1) {
340 "Lund particle index must start from 1 and follow particle order in <",
345 event_particles.emplace_back(make_record_from_lund(lund_particle, logger));
348 events.emplace_back(std::move(event_particles));
351 logger->info(1,
"Loaded ", events.size(),
" Lund generated-particle record events from <", source.
filename,
">");
GParticleRecordEvents loadParticleRecordEvents(const GParticleSourceDefinition &source, const std::shared_ptr< GLogger > &logger) override
Loads Lund events as generated-particle records.
GParticleEvents loadParticleEvents(const GParticleSourceDefinition &source, const std::shared_ptr< GLogger > &logger, bool propagated_only=true) override
Loads Lund events as Geant4-shootable particles.
std::vector< GparticlePtr > loadParticles(const GParticleSourceDefinition &source, const std::shared_ptr< GLogger > &logger) override
Loads all propagated Lund particles as one flattened list.
Conventions and error codes for the gparticle module.
#define ERR_GPARTICLEFILEFORMAT
Particle input file contained malformed or unsupported data.
#define ERR_GPARTICLEFILEOPEN
Particle input file could not be opened.
#define ERR_GPARTICLETABLENOTFOUND
G4ParticleTable could not be obtained (unexpected runtime state).
#define ERR_GPARTICLENOTFOUND
Requested particle name was not found in the G4ParticleTable.
std::vector< GParticleEvent > GParticleEvents
Sequence of file-backed generated-particle events.
std::vector< GparticlePtr > GParticleEvent
Event-local list of Geant4-propagated generator particles.
std::vector< GParticleRecordEvent > GParticleRecordEvents
Sequence of generated-particle record events indexed by event number.
std::vector< GParticleRecord > GParticleRecordEvent
Event-local list of generated-particle records for output.
std::shared_ptr< Gparticle > GparticlePtr
Shared pointer type used for Gparticle instances.
Immutable generated-particle metadata used for output banks.
One configured -gparticlefile source.
std::string filename
Source filename.