gparticle
Loading...
Searching...
No Matches
gparticle_lund_reader.cc
Go to the documentation of this file.
1// gparticle
4
5// geant4
6#include "G4ParticleTable.hh"
7
8// c++
9#include <cmath>
10#include <fstream>
11#include <sstream>
12#include <utility>
13#include <vector>
14
15namespace {
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;
21
22bool is_blank_line(const std::string& line) {
23 return line.find_first_not_of(" \t\r\n") == std::string::npos;
24}
25
26std::vector<double> parse_lund_header(const std::string& line) {
27 std::istringstream stream(line);
28 std::vector<double> values;
29 double value = 0;
30
31 while (stream >> value) { values.emplace_back(value); }
32 stream >> std::ws;
33 if (!stream.eof()) { values.clear(); }
34
35 return values;
36}
37
38struct LundParticleLine
39{
40 int index = 0;
41 double lifetime = 0;
42 int type = 0;
43 int pid = 0;
44 int parent = 0;
45 int daughter = 0;
46 double px = 0;
47 double py = 0;
48 double pz = 0;
49 double energy = 0;
50 double mass = 0;
51 double vx = 0;
52 double vy = 0;
53 double vz = 0;
54};
55
56bool parse_lund_particle_line(const std::string& line, LundParticleLine& particle) {
57 std::istringstream stream(line);
58 std::vector<double> values;
59 double value = 0;
60
61 while (stream >> value) { values.emplace_back(value); }
62 stream >> std::ws;
63 if (!stream.eof() ||
64 values.size() < LUND_MIN_PARTICLE_COLUMNS ||
65 values.size() > LUND_MAX_PARTICLE_COLUMNS) {
66 return false;
67 }
68
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];
83
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];
89}
90
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) {
94 logger->error(
95 gparticle::ERR_GPARTICLETABLENOTFOUND, "G4ParticleTable not found while reading Lund particles");
96 return {};
97 }
98
99 auto particle_definition = particle_table->FindParticle(pid);
100 if (particle_definition == nullptr) {
101 logger->error(gparticle::ERR_GPARTICLENOTFOUND, "Lund pid <%1> was not found in G4ParticleTable", pid);
102 return {};
103 }
104
105 return particle_definition->GetParticleName();
106}
107
108GparticlePtr make_gparticle_from_lund(const LundParticleLine& particle, const std::shared_ptr<GLogger>& logger) {
109 const auto particle_name = particle_name_from_pid(particle.pid, logger);
110 if (particle_name.empty()) { return nullptr; }
111
112 const double momentum = std::sqrt(
113 particle.px * particle.px +
114 particle.py * particle.py +
115 particle.pz * particle.pz
116 );
117
118 double theta = 0;
119 if (momentum > 0) { theta = std::acos(particle.pz / momentum); }
120
121 const double phi = std::atan2(particle.py, particle.px);
122
123 return std::make_shared<Gparticle>(
124 particle_name,
125 1,
126 gutilities::getG4Number(momentum, "GeV"),
127 0,
128 "uniform",
129 gutilities::getG4Number(theta, "rad"),
130 0,
131 "uniform",
132 gutilities::getG4Number(phi, "rad"),
133 0,
134 gutilities::getG4Number(particle.vx, "cm"),
135 gutilities::getG4Number(particle.vy, "cm"),
136 gutilities::getG4Number(particle.vz, "cm"),
137 0,
138 0,
139 0,
140 "uniform",
141 logger,
142 particle.type
143 );
144}
145
146GParticleRecord make_record_from_lund(const LundParticleLine& particle,
147 const std::shared_ptr<GLogger>& logger) {
148 (void)logger;
149
150 const double momentum = std::sqrt(
151 particle.px * particle.px +
152 particle.py * particle.py +
153 particle.pz * particle.pz
154 );
155
156 double theta = 0;
157 if (momentum > 0) { theta = std::acos(particle.pz / momentum); }
158
159 std::string particle_name;
160 auto particle_table = G4ParticleTable::GetParticleTable();
161 if (particle_table != nullptr) {
162 auto particle_definition = particle_table->FindParticle(particle.pid);
163 if (particle_definition != nullptr) { particle_name = particle_definition->GetParticleName(); }
164 }
165 if (particle_name.empty()) { particle_name = std::to_string(particle.pid); }
166
167 return {
168 particle_name,
169 particle.pid,
170 particle.type,
171 1,
172 momentum,
173 theta,
174 std::atan2(particle.py, particle.px),
175 particle.vx,
176 particle.vy,
177 particle.vz
178 };
179}
180
181}
182
184 const std::shared_ptr<GLogger>& logger,
185 bool propagated_only) {
186 GParticleEvents events;
187 std::ifstream input(source.filename);
188
189 if (!input.is_open()) {
190 logger->error(
191 gparticle::ERR_GPARTICLEFILEOPEN, "Could not open Lund particle file <%1>", source.filename);
192 return events;
193 }
194
195 std::string line;
196 while (std::getline(input, line)) {
197 if (is_blank_line(line)) { continue; }
198
199 const auto header_values = parse_lund_header(line);
200
201 if (header_values.size() < LUND_MIN_HEADER_COLUMNS || header_values.size() > LUND_MAX_HEADER_COLUMNS) {
202 logger->error(
203 gparticle::ERR_GPARTICLEFILEFORMAT, "Malformed Lund event header in <%1>: %2", source.filename,
204 line);
205 continue;
206 }
207
208 const auto particle_count = static_cast<int>(header_values.front());
209 if (particle_count < 0 || particle_count != header_values.front()) {
210 logger->error(
212 "Lund event header first column must be a non-negative integer in <%1>: %2", source.filename,
213 line);
214 continue;
215 }
216
217 bool have_first_particle_line = false;
218 if (!std::getline(input, line)) {
219 logger->error(
221 "Lund event header must be followed by a blank line in <%1>", source.filename);
222 continue;
223 }
224 if (!is_blank_line(line)) { have_first_particle_line = true; }
225
226 GParticleEvent event_particles;
227 for (int i = 0; i < particle_count; i++) {
228 if (have_first_particle_line) {
229 have_first_particle_line = false;
230 }
231 else if (!std::getline(input, line)) {
232 logger->error(
234 "Lund event declared %1 particles but ended after %2 particle lines in <%3>",
235 particle_count, i, source.filename);
236 break;
237 }
238
239 if (is_blank_line(line)) {
240 logger->error(
242 "Unexpected blank line inside Lund particle block in <%1>", source.filename);
243 continue;
244 }
245
246 LundParticleLine lund_particle;
247 if (!parse_lund_particle_line(line, lund_particle)) {
248 logger->error(
249 gparticle::ERR_GPARTICLEFILEFORMAT, "Malformed Lund particle line in <%1>: %2",
250 source.filename, line);
251 continue;
252 }
253
254 if (lund_particle.index != i + 1) {
255 logger->error(
257 "Lund particle index must start from 1 and follow particle order in <%1>: %2",
258 source.filename, line);
259 continue;
260 }
261
262 if (propagated_only && lund_particle.type != LUND_PROPAGATED_TYPE) { continue; }
263
264 auto particle = make_gparticle_from_lund(lund_particle, logger);
265 if (particle != nullptr) { event_particles.emplace_back(particle); }
266 }
267
268 events.emplace_back(std::move(event_particles));
269 }
270
271 logger->info(1, "Loaded %1 Lund events from <%2>", events.size(), source.filename);
272 return events;
273}
274
275std::vector<GparticlePtr> GParticleLundReader::loadParticles(const GParticleSourceDefinition& source,
276 const std::shared_ptr<GLogger>& logger) {
277 std::vector<GparticlePtr> particles;
278 for (const auto& event : loadParticleEvents(source, logger)) {
279 particles.insert(particles.end(), event.begin(), event.end());
280 }
281
282 logger->info(1, "Loaded %1 propagated particles from Lund file <%2>", particles.size(), source.filename);
283 return particles;
284}
285
287 const std::shared_ptr<GLogger>& logger) {
289 std::ifstream input(source.filename);
290
291 if (!input.is_open()) {
292 logger->error(
293 gparticle::ERR_GPARTICLEFILEOPEN, "Could not open Lund particle file <%1>", source.filename);
294 return events;
295 }
296
297 std::string line;
298 while (std::getline(input, line)) {
299 if (is_blank_line(line)) { continue; }
300
301 const auto header_values = parse_lund_header(line);
302 if (header_values.size() < LUND_MIN_HEADER_COLUMNS || header_values.size() > LUND_MAX_HEADER_COLUMNS) {
303 logger->error(
304 gparticle::ERR_GPARTICLEFILEFORMAT, "Malformed Lund event header in <%1>: %2", source.filename,
305 line);
306 continue;
307 }
308
309 const auto particle_count = static_cast<int>(header_values.front());
310 if (particle_count < 0 || particle_count != header_values.front()) {
311 logger->error(
313 "Lund event header first column must be a non-negative integer in <%1>: %2", source.filename,
314 line);
315 continue;
316 }
317
318 bool have_first_particle_line = false;
319 if (!std::getline(input, line)) {
320 logger->error(
322 "Lund event header must be followed by a blank line in <%1>", source.filename);
323 continue;
324 }
325 if (!is_blank_line(line)) { have_first_particle_line = true; }
326
327 GParticleRecordEvent event_particles;
328 for (int i = 0; i < particle_count; i++) {
329 if (have_first_particle_line) {
330 have_first_particle_line = false;
331 }
332 else if (!std::getline(input, line)) {
333 logger->error(
335 "Lund event declared %1 particles but ended after %2 particle lines in <%3>",
336 particle_count, i, source.filename);
337 break;
338 }
339
340 if (is_blank_line(line)) {
341 logger->error(
343 "Unexpected blank line inside Lund particle block in <%1>", source.filename);
344 continue;
345 }
346
347 LundParticleLine lund_particle;
348 if (!parse_lund_particle_line(line, lund_particle)) {
349 logger->error(
350 gparticle::ERR_GPARTICLEFILEFORMAT, "Malformed Lund particle line in <%1>: %2",
351 source.filename, line);
352 continue;
353 }
354
355 if (lund_particle.index != i + 1) {
356 logger->error(
358 "Lund particle index must start from 1 and follow particle order in <%1>: %2",
359 source.filename, line);
360 continue;
361 }
362
363 event_particles.emplace_back(make_record_from_lund(lund_particle, logger));
364 }
365
366 events.emplace_back(std::move(event_particles));
367 }
368
369 logger->info(
370 1, "Loaded %1 Lund generated-particle record events from <%2>", events.size(), source.filename);
371 return events;
372}
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.
event
Conventions and error codes for the gparticle module.
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.
Definition gparticle.h:431
constexpr int ERR_GPARTICLETABLENOTFOUND
G4ParticleTable could not be obtained (unexpected runtime state).
constexpr int ERR_GPARTICLEFILEFORMAT
Particle input file contained malformed or unsupported data.
constexpr int ERR_GPARTICLEFILEOPEN
Particle input file could not be opened.
constexpr int ERR_GPARTICLENOTFOUND
Requested particle name was not found in the G4ParticleTable.
double getG4Number(const string &v, bool warnIfNotUnit=false)
Immutable generated-particle metadata used for output banks.
One configured -gparticlefile source.
std::string filename
Source filename.