HepMC3 event record library
ReaderAscii.cc
Go to the documentation of this file.
1// -*- C++ -*-
2//
3// This file is part of HepMC
4// Copyright (C) 2014-2019 The HepMC collaboration (see AUTHORS for details)
5//
6///
7/// @file ReaderAscii.cc
8/// @brief Implementation of \b class ReaderAscii
9///
10#include "HepMC3/ReaderAscii.h"
11
12#include "HepMC3/GenEvent.h"
13#include "HepMC3/GenParticle.h"
14#include "HepMC3/GenVertex.h"
15#include "HepMC3/Units.h"
16#include <cstring>
17#include <sstream>
18
19namespace HepMC3 {
20
21
22ReaderAscii::ReaderAscii(const std::string &filename)
23 : m_file(filename), m_stream(0), m_isstream(false)
24{
25 if( !m_file.is_open() ) {
26 HEPMC3_ERROR( "ReaderAscii: could not open input file: "<<filename )
27 }
28 set_run_info(std::make_shared<GenRunInfo>());
29}
30
31
32// Ctor for reading from stdin
33ReaderAscii::ReaderAscii(std::istream & stream)
34 : m_stream(&stream), m_isstream(true)
35{
36 if( !m_stream->good() ) {
37 HEPMC3_ERROR( "ReaderAscii: could not open input stream " )
38 }
39 set_run_info(std::make_shared<GenRunInfo>());
40}
41
42
43
45
46bool ReaderAscii::skip(const int n)
47{
48 const size_t max_buffer_size=512*512;
49 char buf[max_buffer_size];
50 int nn=n;
51 char peek;
52 while(!failed()) {
53 if ( (!m_file.is_open()) && (!m_isstream) ) return false;
54 m_isstream ? peek = m_stream->peek() : peek = m_file.peek();
55 if( peek=='E' ) nn--;
56 if (nn<0) return true;
57 m_isstream ? m_stream->getline(buf,max_buffer_size) : m_file.getline(buf,max_buffer_size);
58 }
59 return true;
60}
61
62
64 if ( (!m_file.is_open()) && (!m_isstream) ) return false;
65
66 char peek;
67 const size_t max_buffer_size=512*512;
68 char buf[max_buffer_size];
69 bool parsed_event_header = false;
70 bool is_parsing_successful = true;
71 std::pair<int,int> vertices_and_particles(0,0);
72
73 evt.clear();
75 m_forward_daughters.clear();
76 m_forward_mothers.clear();
77 //
78 // Parse event, vertex and particle information
79 //
80 while(!failed()) {
81
82 m_isstream ? m_stream->getline(buf,max_buffer_size) : m_file.getline(buf,max_buffer_size);
83
84 if( strlen(buf) == 0 ) continue;
85
86 // Check for ReaderAscii header/footer
87 if( strncmp(buf,"HepMC",5) == 0 ) {
88 if( strncmp(buf,"HepMC::Version",14) != 0 && strncmp(buf,"HepMC::Asciiv3",14)!=0 )
89 {
90 HEPMC3_WARNING( "ReaderAscii: found unsupported expression in header. Will close the input." )
91 std::cout<<buf<<std::endl;
92 m_isstream ? m_stream->clear(std::ios::eofbit) : m_file.clear(std::ios::eofbit);
93 }
94 if(parsed_event_header) {
95 is_parsing_successful = true;
96 break;
97 }
98 continue;
99 }
100
101 switch(buf[0]) {
102 case 'E':
103 vertices_and_particles = parse_event_information(evt,buf);
104 if (vertices_and_particles.second < 0) {
105 is_parsing_successful = false;
106 } else {
107 is_parsing_successful = true;
108 parsed_event_header = true;
109 }
110 break;
111 case 'V':
112 is_parsing_successful = parse_vertex_information(evt,buf);
113 break;
114 case 'P':
115 is_parsing_successful = parse_particle_information(evt,buf);
116 break;
117 case 'W':
118 if ( parsed_event_header )
119 is_parsing_successful = parse_weight_values(evt,buf);
120 else
121 is_parsing_successful = parse_weight_names(buf);
122 break;
123 case 'U':
124 is_parsing_successful = parse_units(evt,buf);
125 break;
126 case 'T':
127 is_parsing_successful = parse_tool(buf);
128 break;
129 case 'A':
130 if ( parsed_event_header )
131 is_parsing_successful = parse_attribute(evt,buf);
132 else
133 is_parsing_successful = parse_run_attribute(buf);
134 break;
135 default:
136 HEPMC3_WARNING( "ReaderAscii: skipping unrecognised prefix: " << buf[0] )
137 is_parsing_successful = true;
138 break;
139 }
140
141 if( !is_parsing_successful ) break;
142
143 // Check for next event
144 m_isstream ? peek = m_stream->peek() : peek = m_file.peek();
145 if( parsed_event_header && peek=='E' ) break;
146 }
147
148
149 // Check if all particles and vertices were parsed
150 if ((int)evt.particles().size() > vertices_and_particles.second ) {
151 HEPMC3_ERROR( "ReaderAscii: too many particles were parsed" )
152 printf("%zu vs %i expected\n",evt.particles().size(),vertices_and_particles.second );
153 is_parsing_successful = false;
154 }
155 if ((int)evt.particles().size() < vertices_and_particles.second ) {
156 HEPMC3_ERROR( "ReaderAscii: too few particles were parsed" )
157 printf("%zu vs %i expected\n",evt.particles().size(),vertices_and_particles.second );
158 is_parsing_successful = false;
159 }
160
161 if ((int)evt.vertices().size() > vertices_and_particles.first) {
162 HEPMC3_ERROR( "ReaderAscii: too many vertices were parsed" )
163 printf("%zu vs %i expected\n",evt.vertices().size(),vertices_and_particles.first );
164 is_parsing_successful = false;
165 }
166
167 if ((int)evt.vertices().size() < vertices_and_particles.first) {
168 HEPMC3_ERROR( "ReaderAscii: too few vertices were parsed" )
169 printf("%zu vs %i expected\n",evt.vertices().size(),vertices_and_particles.first );
170 is_parsing_successful = false;
171 }
172 // Check if there were HEPMC3_ERRORs during parsing
173 if( !is_parsing_successful ) {
174 HEPMC3_ERROR( "ReaderAscii: event parsing failed. Returning empty event" )
175 HEPMC3_DEBUG( 1, "Parsing failed at line:" << std::endl << buf )
176
177 evt.clear();
178 m_isstream ? m_stream->clear(std::ios::badbit) : m_file.clear(std::ios::badbit);
179
180 return false;
181 }
182 for ( auto p : m_forward_daughters )
183 for (auto v: evt.vertices())
184 if (p.second==v->id())
185 v->add_particle_out(p.first);
186 for ( auto v : m_forward_mothers ) for ( auto idpm : v.second ) v.first->add_particle_in(evt.particles()[idpm-1]);
187
188 /* restore ids of vertices using a bank of available ids*/
189 std::vector<int> all_ids;
190 std::vector<int> filled_ids;
191 std::vector<int> diff;
192 for (auto v: evt.vertices()) if (v->id()!=0) filled_ids.push_back(v->id());
193 for (int i=-((long)evt.vertices().size()); i<0; i++) all_ids.push_back(i);
194 std::sort(all_ids.begin(),all_ids.end());
195 std::sort(filled_ids.begin(),filled_ids.end());
196 //The bank of available ids is created as a difference between all range of ids and the set of used ids
197 std::set_difference(all_ids.begin(), all_ids.end(), filled_ids.begin(), filled_ids.end(), std::inserter(diff, diff.begin()));
198 auto it= diff.rbegin();
199 //Set available ids to vertices sequentially.
200 for (auto v: evt.vertices()) if (v->id()==0) { v->set_id(*it); it++;}
201
202 return true;
203}
204
205
206std::pair<int,int> ReaderAscii::parse_event_information(GenEvent &evt, const char *buf) {
207 static const std::pair<int,int> err(-1,-1);
208 std::pair<int,int> ret(-1,-1);
209 const char *cursor = buf;
210 int event_no = 0;
211 FourVector position;
212
213 // event number
214 if( !(cursor = strchr(cursor+1,' ')) ) return err;
215 event_no = atoi(cursor);
216 evt.set_event_number(event_no);
217
218 // num_vertices
219 if( !(cursor = strchr(cursor+1,' ')) ) return err;
220 ret.first = atoi(cursor);
221
222 // num_particles
223 if( !(cursor = strchr(cursor+1,' ')) ) return err;
224 ret.second = atoi(cursor);
225
226 // check if there is position information
227 if( (cursor = strchr(cursor+1,'@')) ) {
228
229 // x
230 if( !(cursor = strchr(cursor+1,' ')) ) return err;
231 position.setX(atof(cursor));
232
233 // y
234 if( !(cursor = strchr(cursor+1,' ')) ) return err;
235 position.setY(atof(cursor));
236
237 // z
238 if( !(cursor = strchr(cursor+1,' ')) ) return err;
239 position.setZ(atof(cursor));
240
241 // t
242 if( !(cursor = strchr(cursor+1,' ')) ) return err;
243 position.setT(atof(cursor));
244 evt.shift_position_to( position );
245 }
246
247 HEPMC3_DEBUG( 10, "ReaderAscii: E: "<<event_no<<" ("<<ret.first<<"V, "<<ret.second<<"P)" )
248
249 return ret;
250}
251
252
253bool ReaderAscii::parse_weight_values(GenEvent &evt, const char *buf) {
254
255 std::istringstream iss(buf + 1);
256 std::vector<double> wts;
257 double w;
258 while ( iss >> w ) wts.push_back(w);
259 if ( run_info() && run_info()->weight_names().size()
260 && run_info()->weight_names().size() != wts.size() )
261 throw std::logic_error("ReaderAscii::parse_weight_values: "
262 "The number of weights ("+std::to_string((long long int)(wts.size()))+") does not match "
263 "the number weight names("+std::to_string((long long int)(run_info()->weight_names().size()))+") in the GenRunInfo object");
264 evt.weights() = wts;
265
266 return true;
267}
268
269
270bool ReaderAscii::parse_units(GenEvent &evt, const char *buf) {
271 const char *cursor = buf;
272
273 // momentum
274 if( !(cursor = strchr(cursor+1,' ')) ) return false;
275 ++cursor;
276 Units::MomentumUnit momentum_unit = Units::momentum_unit(cursor);
277
278 // length
279 if( !(cursor = strchr(cursor+1,' ')) ) return false;
280 ++cursor;
281 Units::LengthUnit length_unit = Units::length_unit(cursor);
282
283 evt.set_units(momentum_unit,length_unit);
284
285 HEPMC3_DEBUG( 10, "ReaderAscii: U: " << Units::name(evt.momentum_unit()) << " " << Units::name(evt.length_unit()) )
286
287 return true;
288}
289
290
292 GenVertexPtr data = std::make_shared<GenVertex>();
293 FourVector position;
294 const char *cursor = buf;
295 const char *cursor2 = nullptr;
296 int id = 0;
297 int highest_id = evt.particles().size();
298
299 // id
300 if( !(cursor = strchr(cursor+1,' ')) ) return false;
301 id = atoi(cursor);
302
303 // status
304 if( !(cursor = strchr(cursor+1,' ')) ) return false;
305 data->set_status( atoi(cursor) );
306
307 // skip to the list of particles
308 if( !(cursor = strchr(cursor+1,'[')) ) return false;
309
310 while(true) {
311 ++cursor; // skip the '[' or ',' character
312 cursor2 = cursor; // save cursor position
313 int particle_in = atoi(cursor);
314
315 // add incoming particle to the vertex
316 if( particle_in > 0) {
317//Particles are always ordered, so id==position in event.
318 if (particle_in <= highest_id)
319 data->add_particle_in( evt.particles()[particle_in-1] );
320//If the particle has not been red yet, we store its id to add the particle later.
321 else m_forward_mothers[data].insert(particle_in);
322 }
323
324 // check for next particle or end of particle list
325 if( !(cursor = strchr(cursor+1,',')) ) {
326 if( !(cursor = strchr(cursor2+1,']')) ) return false;
327 break;
328 }
329 }
330
331 // check if there is position information
332 if( (cursor = strchr(cursor+1,'@')) ) {
333
334 // x
335 if( !(cursor = strchr(cursor+1,' ')) ) return false;
336 position.setX(atof(cursor));
337
338 // y
339 if( !(cursor = strchr(cursor+1,' ')) ) return false;
340 position.setY(atof(cursor));
341
342 // z
343 if( !(cursor = strchr(cursor+1,' ')) ) return false;
344 position.setZ(atof(cursor));
345
346 // t
347 if( !(cursor = strchr(cursor+1,' ')) ) return false;
348 position.setT(atof(cursor));
349 data->set_position( position );
350
351 }
352
353 HEPMC3_DEBUG( 10, "ReaderAscii: V: "<<id<<" with "<<data->particles_in().size()<<" particles)" )
354
355 evt.add_vertex(data);
356//Restore vertex id, as it is used to build connections inside event.
357 data->set_id(id);
358
359 return true;
360}
361
362
364 GenParticlePtr data = std::make_shared<GenParticle>();
365 FourVector momentum;
366 const char *cursor = buf;
367 int mother_id = 0;
368
369 // verify id
370 if( !(cursor = strchr(cursor+1,' ')) ) return false;
371
372 if( atoi(cursor) != (int)evt.particles().size() + 1 ) {
373 /// @todo Should be an exception
374 HEPMC3_ERROR( "ReaderAscii: particle ID mismatch" )
375 return false;
376 }
377
378 // mother id
379 if( !(cursor = strchr(cursor+1,' ')) ) return false;
380 mother_id = atoi(cursor);
381
382 // Parent object is a particle. Particleas are always ordered id==position in event.
383 if( mother_id > 0 && mother_id <= (int)evt.particles().size() ) {
384
385 GenParticlePtr mother = evt.particles()[ mother_id-1 ];
386 GenVertexPtr vertex = mother->end_vertex();
387
388 // create new vertex if needed
389 if( !vertex ) {
390 vertex = std::make_shared<GenVertex>();
391 vertex->add_particle_in(mother);
392 }
393
394 vertex->add_particle_out(data);
395 evt.add_vertex(vertex);
396//ID of this vertex is not explicitely set in the input. We set it to zero to prevent overlap with other ids. It will be restored later.
397 vertex->set_id(0);
398 }
399 // Parent object is vertex
400 else if( mother_id < 0 )
401 {
402 //Vertices are not always ordered, e.g. when one reads HepMC2 event, so we check their ids.
403 bool found=false;
404 for (auto v: evt.vertices()) if (v->id()==mother_id) {v->add_particle_out(data); found=true; break; }
405 if (!found)
406 {
407//This should happen in case of unordered event.
408// WARNING("ReaderAscii: Unordered event, id of mother vertex is out of range of known ids: " <<mother_id<<" evt.vertices().size()="<<evt.vertices().size() )
409//Save the mother id to reconnect later.
410 m_forward_daughters[data]=mother_id;
411 }
412 }
413
414 // pdg id
415 if( !(cursor = strchr(cursor+1,' ')) ) return false;
416 data->set_pid( atoi(cursor) );
417
418 // px
419 if( !(cursor = strchr(cursor+1,' ')) ) return false;
420 momentum.setPx(atof(cursor));
421
422 // py
423 if( !(cursor = strchr(cursor+1,' ')) ) return false;
424 momentum.setPy(atof(cursor));
425
426 // pz
427 if( !(cursor = strchr(cursor+1,' ')) ) return false;
428 momentum.setPz(atof(cursor));
429
430 // pe
431 if( !(cursor = strchr(cursor+1,' ')) ) return false;
432 momentum.setE(atof(cursor));
433 data->set_momentum(momentum);
434
435 // m
436 if( !(cursor = strchr(cursor+1,' ')) ) return false;
437 data->set_generated_mass( atof(cursor) );
438
439 // status
440 if( !(cursor = strchr(cursor+1,' ')) ) return false;
441 data->set_status( atoi(cursor) );
442
443 evt.add_particle(data);
444
445 HEPMC3_DEBUG( 10, "ReaderAscii: P: "<<data->id()<<" ( mother: "<<mother_id<<", pid: "<<data->pid()<<")" )
446
447 return true;
448}
449
450
451bool ReaderAscii::parse_attribute(GenEvent &evt, const char *buf) {
452 const char *cursor = buf;
453 const char *cursor2 = buf;
454 char name[64];
455 int id = 0;
456
457 if( !(cursor = strchr(cursor+1,' ')) ) return false;
458 id = atoi(cursor);
459
460 if( !(cursor = strchr(cursor+1,' ')) ) return false;
461 ++cursor;
462
463 if( !(cursor2 = strchr(cursor,' ')) ) return false;
464 sprintf(name,"%.*s", (int)(cursor2-cursor), cursor);
465
466 cursor = cursor2+1;
467
468 std::shared_ptr<Attribute> att =
469 std::make_shared<StringAttribute>( StringAttribute(unescape(cursor)) );
470
471 evt.add_attribute(std::string(name), att, id);
472
473 return true;
474}
475
476bool ReaderAscii::parse_run_attribute(const char *buf) {
477 const char *cursor = buf;
478 const char *cursor2 = buf;
479 char name[64];
480
481 if( !(cursor = strchr(cursor+1,' ')) ) return false;
482 ++cursor;
483
484 if( !(cursor2 = strchr(cursor,' ')) ) return false;
485 sprintf(name,"%.*s", (int)(cursor2-cursor), cursor);
486
487 cursor = cursor2+1;
488
489 std::shared_ptr<StringAttribute> att =
490 std::make_shared<StringAttribute>( StringAttribute(unescape(cursor)) );
491
492 run_info()->add_attribute(std::string(name), att);
493
494 return true;
495
496}
497
498
499bool ReaderAscii::parse_weight_names(const char *buf) {
500 const char *cursor = buf;
501
502 if( !(cursor = strchr(cursor+1,' ')) ) return false;
503 ++cursor;
504
505 std::istringstream iss(unescape(cursor));
506 std::vector<std::string> names;
507 std::string name;
508 while ( iss >> name ) names.push_back(name);
509
510 run_info()->set_weight_names(names);
511
512 return true;
513
514}
515
516bool ReaderAscii::parse_tool(const char *buf) {
517 const char *cursor = buf;
518
519 if( !(cursor = strchr(cursor+1,' ')) ) return false;
520 ++cursor;
521 std::string line = unescape(cursor);
523 std::string::size_type pos = line.find("\n");
524 tool.name = line.substr(0, pos);
525 line = line.substr(pos + 1);
526 pos = line.find("\n");
527 tool.version = line.substr(0, pos);
528 tool.description = line.substr(pos + 1);
529 run_info()->tools().push_back(tool);
530
531 return true;
532
533}
534
535
536std::string ReaderAscii::unescape(const std::string& s) {
537 std::string ret;
538 ret.reserve(s.length());
539 for ( std::string::const_iterator it = s.begin(); it != s.end(); ++it ) {
540 if ( *it == '\\' ) {
541 ++it;
542 if ( *it == '|' )
543 ret += '\n';
544 else
545 ret += *it;
546 } else
547 ret += *it;
548 }
549
550 return ret;
551}
552
553bool ReaderAscii::failed() { return m_isstream ? (bool)m_stream->rdstate() :(bool)m_file.rdstate(); }
554
556 if( !m_file.is_open()) return;
557 m_file.close();
558}
559
560
561} // namespace HepMC3
#define HEPMC3_WARNING(MESSAGE)
Macro for printing HEPMC3_HEPMC3_WARNING messages.
Definition: Errors.h:26
#define HEPMC3_DEBUG(LEVEL, MESSAGE)
Macro for printing debug messages with appropriate debug level.
Definition: Errors.h:32
#define HEPMC3_ERROR(MESSAGE)
Macro for printing error messages.
Definition: Errors.h:23
Definition of class GenEvent.
Definition of class GenParticle.
Definition of class GenVertex.
Definition of class ReaderAscii.
Definition of class Units.
Generic 4-vector.
Definition: FourVector.h:35
void setE(double ee)
Definition: FourVector.h:134
void setT(double tt)
Definition: FourVector.h:105
void setPz(double pzz)
Definition: FourVector.h:127
void setY(double yy)
Definition: FourVector.h:91
void setPy(double pyy)
Definition: FourVector.h:120
void setX(double xx)
Definition: FourVector.h:84
void setPx(double pxx)
Definition: FourVector.h:113
void setZ(double zz)
Definition: FourVector.h:98
Stores event-related information.
Definition: GenEvent.h:41
void add_vertex(GenVertexPtr v)
Add vertex.
Definition: GenEvent.cc:97
void shift_position_to(const FourVector &newpos)
Shift position of all vertices in the event to op.
Definition: GenEvent.h:187
void add_particle(GenParticlePtr p)
Add particle.
Definition: GenEvent.cc:49
void set_units(Units::MomentumUnit new_momentum_unit, Units::LengthUnit new_length_unit)
Change event units Converts event from current units to new ones.
Definition: GenEvent.cc:395
void set_event_number(const int &num)
Set event number.
Definition: GenEvent.h:137
void set_run_info(std::shared_ptr< GenRunInfo > run)
Set the GenRunInfo object by smart pointer.
Definition: GenEvent.h:128
const std::vector< ConstGenVertexPtr > & vertices() const
Get list of vertices (const)
Definition: GenEvent.cc:43
const Units::MomentumUnit & momentum_unit() const
Get momentum unit.
Definition: GenEvent.h:140
const Units::LengthUnit & length_unit() const
Get length unit.
Definition: GenEvent.h:142
void add_attribute(const std::string &name, const std::shared_ptr< Attribute > &att, const int &id=0)
Add event attribute to event.
Definition: GenEvent.h:208
const std::vector< double > & weights() const
Get event weight values as a vector.
Definition: GenEvent.h:86
void clear()
Remove contents of this event.
Definition: GenEvent.cc:608
const std::vector< ConstGenParticlePtr > & particles() const
Get list of particles (const)
Definition: GenEvent.cc:39
bool parse_tool(const char *buf)
Parse run-level tool information.
Definition: ReaderAscii.cc:516
bool m_isstream
toggles usage of m_file or m_stream
Definition: ReaderAscii.h:160
bool parse_weight_values(GenEvent &evt, const char *buf)
Parse weight value lines.
Definition: ReaderAscii.cc:253
std::map< GenParticlePtr, int > m_forward_daughters
Temp storage for prod vertex ids.
Definition: ReaderAscii.h:169
bool read_event(GenEvent &evt) override
Load event from file.
Definition: ReaderAscii.cc:63
std::string unescape(const std::string &s)
Unsecape '\' and ' ' characters in string.
Definition: ReaderAscii.cc:536
bool failed() override
Return status of the stream.
Definition: ReaderAscii.cc:553
bool skip(const int) override
skip events
Definition: ReaderAscii.cc:46
std::ifstream m_file
Input file.
Definition: ReaderAscii.h:158
bool parse_units(GenEvent &evt, const char *buf)
Parse units.
Definition: ReaderAscii.cc:270
bool parse_particle_information(GenEvent &evt, const char *buf)
Parse particle.
Definition: ReaderAscii.cc:363
std::map< GenVertexPtr, std::set< int > > m_forward_mothers
Temp storage for outgoing particle ids.
Definition: ReaderAscii.h:167
bool parse_attribute(GenEvent &evt, const char *buf)
Parse attribute.
Definition: ReaderAscii.cc:451
void close() override
Close file stream.
Definition: ReaderAscii.cc:555
bool parse_vertex_information(GenEvent &evt, const char *buf)
Parse vertex.
Definition: ReaderAscii.cc:291
~ReaderAscii()
Destructor.
Definition: ReaderAscii.cc:44
bool parse_weight_names(const char *buf)
Parse run-level weight names.
Definition: ReaderAscii.cc:499
ReaderAscii(const std::string &filename)
Constructor.
Definition: ReaderAscii.cc:22
std::istream * m_stream
For ctor when reading from stdin.
Definition: ReaderAscii.h:159
bool parse_run_attribute(const char *buf)
Parse run-level attribute.
Definition: ReaderAscii.cc:476
std::pair< int, int > parse_event_information(GenEvent &evt, const char *buf)
Parse event.
Definition: ReaderAscii.cc:206
std::shared_ptr< GenRunInfo > run_info() const
Get the global GenRunInfo object.
Definition: Reader.h:44
void set_run_info(std::shared_ptr< GenRunInfo > run)
Set the global GenRunInfo object.
Definition: Reader.h:64
Attribute that holds a string.
Definition: Attribute.h:337
static LengthUnit length_unit(const std::string &name)
Get length unit based on its name.
Definition: Units.h:46
LengthUnit
Position units.
Definition: Units.h:32
static std::string name(MomentumUnit u)
Get name of momentum unit.
Definition: Units.h:56
MomentumUnit
Momentum units.
Definition: Units.h:29
static MomentumUnit momentum_unit(const std::string &name)
Get momentum unit based on its name.
Definition: Units.h:36
HepMC3 main namespace.
Interrnal struct for keeping track of tools.
Definition: GenRunInfo.h:38
std::string description
Other information about how the tool was used in the run.
Definition: GenRunInfo.h:48
std::string version
The version of the tool.
Definition: GenRunInfo.h:44
std::string name
The name of the tool.
Definition: GenRunInfo.h:41