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(ERR_GPARTICLETABLENOTFOUND, "G4ParticleTable not found while reading Lund particles");
95 return {};
96 }
97
98 auto particle_definition = particle_table->FindParticle(pid);
99 if (particle_definition == nullptr) {
100 logger->error(ERR_GPARTICLENOTFOUND, "Lund pid <", pid, "> was not found in G4ParticleTable");
101 return {};
102 }
103
104 return particle_definition->GetParticleName();
105}
106
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; }
110
111 const double momentum = std::sqrt(
112 particle.px * particle.px +
113 particle.py * particle.py +
114 particle.pz * particle.pz
115 );
116
117 double theta = 0;
118 if (momentum > 0) { theta = std::acos(particle.pz / momentum); }
119
120 const double phi = std::atan2(particle.py, particle.px);
121
122 return std::make_shared<Gparticle>(
123 particle_name,
124 1,
125 momentum,
126 0,
127 "GeV",
128 "uniform",
129 theta,
130 0,
131 "uniform",
132 phi,
133 0,
134 "rad",
135 particle.vx,
136 particle.vy,
137 particle.vz,
138 0,
139 0,
140 0,
141 "cm",
142 "uniform",
143 logger,
144 particle.type
145 );
146}
147
148GParticleRecord make_record_from_lund(const LundParticleLine& particle,
149 const std::shared_ptr<GLogger>& logger) {
150 (void)logger;
151
152 const double momentum = std::sqrt(
153 particle.px * particle.px +
154 particle.py * particle.py +
155 particle.pz * particle.pz
156 );
157
158 double theta = 0;
159 if (momentum > 0) { theta = std::acos(particle.pz / momentum); }
160
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(); }
166 }
167 if (particle_name.empty()) { particle_name = std::to_string(particle.pid); }
168
169 return {
170 particle_name,
171 particle.pid,
172 particle.type,
173 1,
174 momentum,
175 theta,
176 std::atan2(particle.py, particle.px),
177 particle.vx,
178 particle.vy,
179 particle.vz
180 };
181}
182
183}
184
186 const std::shared_ptr<GLogger>& logger,
187 bool propagated_only) {
188 GParticleEvents events;
189 std::ifstream input(source.filename);
190
191 if (!input.is_open()) {
192 logger->error(ERR_GPARTICLEFILEOPEN, "Could not open Lund particle file <", source.filename, ">");
193 return events;
194 }
195
196 std::string line;
197 while (std::getline(input, line)) {
198 if (is_blank_line(line)) { continue; }
199
200 const auto header_values = parse_lund_header(line);
201
202 if (header_values.size() < LUND_MIN_HEADER_COLUMNS || header_values.size() > LUND_MAX_HEADER_COLUMNS) {
203 logger->error(ERR_GPARTICLEFILEFORMAT, "Malformed Lund event header in <", source.filename, ">: ", line);
204 continue;
205 }
206
207 const auto particle_count = static_cast<int>(header_values.front());
208 if (particle_count < 0 || particle_count != header_values.front()) {
209 logger->error(ERR_GPARTICLEFILEFORMAT,
210 "Lund event header first column must be a non-negative integer in <",
211 source.filename, ">: ", line);
212 continue;
213 }
214
215 bool have_first_particle_line = false;
216 if (!std::getline(input, line)) {
217 logger->error(ERR_GPARTICLEFILEFORMAT,
218 "Lund event header must be followed by a blank line in <", source.filename, ">");
219 continue;
220 }
221 if (!is_blank_line(line)) { have_first_particle_line = true; }
222
223 GParticleEvent event_particles;
224 for (int i = 0; i < particle_count; i++) {
225 if (have_first_particle_line) {
226 have_first_particle_line = false;
227 }
228 else if (!std::getline(input, line)) {
229 logger->error(ERR_GPARTICLEFILEFORMAT,
230 "Lund event declared ", particle_count, " particles but ended after ",
231 i, " particle lines in <", source.filename, ">");
232 break;
233 }
234
235 if (is_blank_line(line)) {
236 logger->error(ERR_GPARTICLEFILEFORMAT,
237 "Unexpected blank line inside Lund particle block in <", source.filename, ">");
238 continue;
239 }
240
241 LundParticleLine lund_particle;
242 if (!parse_lund_particle_line(line, lund_particle)) {
243 logger->error(ERR_GPARTICLEFILEFORMAT, "Malformed Lund particle line in <", source.filename, ">: ", line);
244 continue;
245 }
246
247 if (lund_particle.index != i + 1) {
248 logger->error(ERR_GPARTICLEFILEFORMAT,
249 "Lund particle index must start from 1 and follow particle order in <",
250 source.filename, ">: ", line);
251 continue;
252 }
253
254 if (propagated_only && lund_particle.type != LUND_PROPAGATED_TYPE) { continue; }
255
256 auto particle = make_gparticle_from_lund(lund_particle, logger);
257 if (particle != nullptr) { event_particles.emplace_back(particle); }
258 }
259
260 events.emplace_back(std::move(event_particles));
261 }
262
263 logger->info(1, "Loaded ", events.size(), " Lund events from <", source.filename, ">");
264 return events;
265}
266
267std::vector<GparticlePtr> GParticleLundReader::loadParticles(const GParticleSourceDefinition& source,
268 const std::shared_ptr<GLogger>& logger) {
269 std::vector<GparticlePtr> particles;
270 for (const auto& event : loadParticleEvents(source, logger)) {
271 particles.insert(particles.end(), event.begin(), event.end());
272 }
273
274 logger->info(1, "Loaded ", particles.size(), " propagated particles from Lund file <", source.filename, ">");
275 return particles;
276}
277
279 const std::shared_ptr<GLogger>& logger) {
281 std::ifstream input(source.filename);
282
283 if (!input.is_open()) {
284 logger->error(ERR_GPARTICLEFILEOPEN, "Could not open Lund particle file <", source.filename, ">");
285 return events;
286 }
287
288 std::string line;
289 while (std::getline(input, line)) {
290 if (is_blank_line(line)) { continue; }
291
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) {
294 logger->error(ERR_GPARTICLEFILEFORMAT, "Malformed Lund event header in <", source.filename, ">: ", line);
295 continue;
296 }
297
298 const auto particle_count = static_cast<int>(header_values.front());
299 if (particle_count < 0 || particle_count != header_values.front()) {
300 logger->error(ERR_GPARTICLEFILEFORMAT,
301 "Lund event header first column must be a non-negative integer in <",
302 source.filename, ">: ", line);
303 continue;
304 }
305
306 bool have_first_particle_line = false;
307 if (!std::getline(input, line)) {
308 logger->error(ERR_GPARTICLEFILEFORMAT,
309 "Lund event header must be followed by a blank line in <", source.filename, ">");
310 continue;
311 }
312 if (!is_blank_line(line)) { have_first_particle_line = true; }
313
314 GParticleRecordEvent event_particles;
315 for (int i = 0; i < particle_count; i++) {
316 if (have_first_particle_line) {
317 have_first_particle_line = false;
318 }
319 else if (!std::getline(input, line)) {
320 logger->error(ERR_GPARTICLEFILEFORMAT,
321 "Lund event declared ", particle_count, " particles but ended after ",
322 i, " particle lines in <", source.filename, ">");
323 break;
324 }
325
326 if (is_blank_line(line)) {
327 logger->error(ERR_GPARTICLEFILEFORMAT,
328 "Unexpected blank line inside Lund particle block in <", source.filename, ">");
329 continue;
330 }
331
332 LundParticleLine lund_particle;
333 if (!parse_lund_particle_line(line, lund_particle)) {
334 logger->error(ERR_GPARTICLEFILEFORMAT, "Malformed Lund particle line in <", source.filename, ">: ", line);
335 continue;
336 }
337
338 if (lund_particle.index != i + 1) {
339 logger->error(ERR_GPARTICLEFILEFORMAT,
340 "Lund particle index must start from 1 and follow particle order in <",
341 source.filename, ">: ", line);
342 continue;
343 }
344
345 event_particles.emplace_back(make_record_from_lund(lund_particle, logger));
346 }
347
348 events.emplace_back(std::move(event_particles));
349 }
350
351 logger->info(1, "Loaded ", events.size(), " Lund generated-particle record events from <", source.filename, ">");
352 return events;
353}
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.
#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.
Definition gparticle.h:415
Immutable generated-particle metadata used for output banks.
One configured -gparticlefile source.
std::string filename
Source filename.