HepMC3 event record library
WriterAscii.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // This file is part of HepMC
4 // Copyright (C) 2014-2021 The HepMC collaboration (see AUTHORS for details)
5 //
6 ///
7 /// @file WriterAscii.cc
8 /// @brief Implementation of \b class WriterAscii
9 ///
10 #include <cstring>
11 #include <algorithm>//min max for VS2017
12 
13 #include "HepMC3/WriterAscii.h"
14 
15 #include "HepMC3/Version.h"
16 #include "HepMC3/GenEvent.h"
17 #include "HepMC3/GenParticle.h"
18 #include "HepMC3/GenVertex.h"
19 #include "HepMC3/Units.h"
20 
21 namespace HepMC3 {
22 
23 
24 WriterAscii::WriterAscii(const std::string &filename, std::shared_ptr<GenRunInfo> run)
25  : m_file(filename),
26  m_stream(&m_file),
27  m_precision(16),
28  m_buffer(nullptr),
29  m_cursor(nullptr),
30  m_buffer_size(256*1024)
31 {
32  set_run_info(run);
33  if ( !m_file.is_open() ) {
34  HEPMC3_ERROR("WriterAscii: could not open output file: " << filename)
35  } else {
36  const std::string header = "HepMC::Version " + version() + "\nHepMC::Asciiv3-START_EVENT_LISTING\n";
37  m_file.write(header.data(), header.length());
38  if ( run_info() ) write_run_info();
39  }
40  m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
41  m_particle_printf_specifier = "P %i %i %i"
46  + m_float_printf_specifier + " %i\n";
47  m_vertex_short_printf_specifier = "V %i %i [%s]\n";
49 }
50 
51 
52 WriterAscii::WriterAscii(std::ostream &stream, std::shared_ptr<GenRunInfo> run)
53  : m_file(),
54  m_stream(&stream),
55  m_precision(16),
56  m_buffer(nullptr),
57  m_cursor(nullptr),
58  m_buffer_size(256*1024)
59 {
60  set_run_info(run);
61  const std::string header = "HepMC::Version " + version() + "\nHepMC::Asciiv3-START_EVENT_LISTING\n";
62  m_stream->write(header.data(), header.length());
63  if ( run_info() ) write_run_info();
64  m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
65  m_particle_printf_specifier = "P %i %i %i"
70  + m_float_printf_specifier + " %i\n";
71  m_vertex_short_printf_specifier = "V %i %i [%s]\n";
73 }
74 
75 WriterAscii::WriterAscii(std::shared_ptr<std::ostream> s_stream, std::shared_ptr<GenRunInfo> run)
76  : m_file(),
77  m_shared_stream(s_stream),
78  m_stream(s_stream.get()),
79  m_precision(16),
80  m_buffer(nullptr),
81  m_cursor(nullptr),
82  m_buffer_size(256*1024)
83 {
84  set_run_info(run);
85  const std::string header = "HepMC::Version " + version() + "\nHepMC::Asciiv3-START_EVENT_LISTING\n";
86  m_stream->write(header.data(), header.length());
87  if ( run_info() ) write_run_info();
88  m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
89  m_particle_printf_specifier = "P %i %i %i"
94  + m_float_printf_specifier + " %i\n";
95  m_vertex_short_printf_specifier = "V %i %i [%s]\n";
97 }
98 
100  close();
101  if ( m_buffer ) delete[] m_buffer;
102 }
103 
104 
106  allocate_buffer();
107  if ( !m_buffer ) return;
108  auto float_printf_specifier_option = m_options.find("float_printf_specifier");
109  std::string letter=(float_printf_specifier_option != m_options.end())?float_printf_specifier_option->second.substr(0,2):"e";
110  if (letter != "e" && letter != "E" && letter != "G" && letter != "g" && letter != "f" && letter != "F" ) letter = "e";
111  m_float_printf_specifier = " %." + std::to_string(m_precision) + letter;
112 
113 
114  m_particle_printf_specifier = "P %i %i %i"
119  + m_float_printf_specifier + " %i\n";
120  m_vertex_short_printf_specifier = "V %i %i [%s]\n";
122 
123  // Make sure nothing was left from previous event
124  flush();
125 
126  if ( !run_info() ) {
127  set_run_info(evt.run_info());
128  write_run_info();
129  } else {
130  if ( evt.run_info() && (run_info() != evt.run_info()) ) {
131  HEPMC3_WARNING("WriterAscii::write_event: GenEvents contain "
132  "different GenRunInfo objects from - only the "
133  "first such object will be serialized.")
134  }
135  }
136 
137  // Write event info
138  flush();
139  std::string especifier = "E " + std::to_string(evt.event_number()) + " "
140  + std::to_string(evt.vertices().size()) + " "
141  + std::to_string(evt.particles().size());
142  // Write event position if not zero
143  const FourVector &pos = evt.event_pos();
144  if ( !pos.is_zero() ) {
146  m_cursor += sprintf(m_cursor, especifier.c_str(), pos.x(), pos.y(), pos.z(), pos.t());
147  } else {
148  m_cursor += sprintf(m_cursor, "%s\n", especifier.c_str());
149  }
150  flush();
151 
152  // Write units
153  m_cursor += sprintf(m_cursor, "U %s %s\n", Units::name(evt.momentum_unit()).c_str(), Units::name(evt.length_unit()).c_str());
154  flush();
155 
156  // Write weight values if present
157  if ( evt.weights().size() ) {
158  m_cursor += sprintf(m_cursor, "W");
159  for (auto w: evt.weights())
160  {
161  m_cursor += sprintf(m_cursor, " %.*e", std::min(3*m_precision, 22), w);
162  flush();
163  }
164  m_cursor += sprintf(m_cursor, "\n");
165  flush();
166  }
167 
168  // Write attributes
169  for ( auto vt1: evt.attributes() ) {
170  for ( auto vt2: vt1.second ) {
171  std::string st;
172  bool status = vt2.second->to_string(st);
173 
174  if ( !status ) {
175  HEPMC3_WARNING("WriterAscii::write_event: problem serializing attribute: " << vt1.first)
176  }
177  else {
178  m_cursor += sprintf(m_cursor, "A %i ", vt2.first);
179  write_string(escape(vt1.first));
180  flush();
181  m_cursor += sprintf(m_cursor, " ");
182  write_string(escape(st));
183  m_cursor += sprintf(m_cursor, "\n");
184  flush();
185  }
186  }
187  }
188 
189 
190  // Print particles
191  std::map<int, bool> alreadywritten;
192  for (ConstGenParticlePtr p: evt.particles()) {
193  // Check to see if we need to write a vertex first
194  ConstGenVertexPtr v = p->production_vertex();
195  int parent_object = 0;
196 
197  if (v) {
198  // Check if we need this vertex at all
199  // Yes, use vertex as parent object
200  if ( v->particles_in().size() > 1 || !v->data().is_zero() ) parent_object = v->id();
201  // No, use particle as parent object
202  // Add check for attributes of this vertex
203  else if ( v->particles_in().size() == 1 ) parent_object = v->particles_in().front()->id();
204  else if ( v->particles_in().size() == 0 ) HEPMC3_DEBUG(30, "WriterAscii::write_event - found a vertex without incoming particles: " << v->id());
205  // Usage of map instead of simple counter helps to deal with events with random ids of vertices.
206  if (alreadywritten.count(v->id()) == 0 && parent_object < 0)
207  { write_vertex(v); alreadywritten[v->id()] = true; }
208  }
209 
210  write_particle(p, parent_object);
211  }
212  alreadywritten.clear();
213 
214  // Flush rest of the buffer to file
215  forced_flush();
216 }
217 
218 
220  if ( m_buffer ) return;
221  while ( m_buffer == nullptr && m_buffer_size >= 512 ) {
222  try {
223  m_buffer = new char[ m_buffer_size ]();
224  } catch (const std::bad_alloc& e) {
225  delete[] m_buffer;
226  m_buffer_size /= 2;
227  HEPMC3_WARNING("WriterAscii::allocate_buffer:" << e.what() << " buffer size too large. Dividing by 2. New size: " << m_buffer_size)
228  }
229  }
230 
231  if ( !m_buffer ) {
232  HEPMC3_ERROR("WriterAscii::allocate_buffer: could not allocate buffer!")
233  return;
234  }
235  m_cursor = m_buffer;
236 }
237 
238 
239 std::string WriterAscii::escape(const std::string& s) const {
240  std::string ret;
241  ret.reserve(s.length()*2);
242  for ( std::string::const_iterator it = s.begin(); it != s.end(); ++it ) {
243  switch ( *it ) {
244  case '\\':
245  ret += "\\\\";
246  break;
247  case '\n':
248  ret += "\\|";
249  break;
250  default:
251  ret += *it;
252  }
253  }
254  return ret;
255 }
256 
257 void WriterAscii::write_vertex(ConstGenVertexPtr v) {
258  flush();
259  std::string vlist;
260  std::vector<int> pids;
261  pids.reserve(v->particles_in().size());
262  for (ConstGenParticlePtr p: v->particles_in()) pids.push_back(p->id());
263  //We order pids to be able to compare ascii files
264  std::sort(pids.begin(), pids.end());
265  for (auto p: pids) vlist.append( std::to_string(p).append(",") );
266  if ( pids.size() ) vlist.pop_back();
267  const FourVector &pos = v->position();
268  if ( !pos.is_zero() ) {
269  m_cursor += sprintf(m_cursor, m_vertex_long_printf_specifier.c_str(), v->id(), v->status(), vlist.c_str(), pos.x(), pos.y(), pos.z(), pos.t() );
270  } else {
271  m_cursor += sprintf(m_cursor, m_vertex_short_printf_specifier.c_str(), v->id(), v->status(), vlist.c_str());
272  }
273  flush();
274 }
275 
276 
277 inline void WriterAscii::flush() {
278  // The maximum size of single add to the buffer (other than by
279  // using WriterAscii::write_string) should not be larger than 256. This is a safe value as
280  // we will not allow precision larger than 24 anyway
281  if ( m_buffer + m_buffer_size < m_cursor + 512 ) {
282  std::ptrdiff_t length = m_cursor - m_buffer;
283  m_stream->write(m_buffer, length);
284  m_cursor = m_buffer;
285  }
286 }
287 
288 
290  std::ptrdiff_t length = m_cursor - m_buffer;
291  m_stream->write(m_buffer, length);
292  m_cursor = m_buffer;
293 }
294 
295 
297  allocate_buffer();
298 
299  // If no run info object set, create a dummy one.
300  if ( !run_info() ) set_run_info(std::make_shared<GenRunInfo>());
301 
302  const std::vector<std::string> names = run_info()->weight_names();
303 
304  if ( !names.empty() ) {
305  std::string out = names[0];
306  for ( int i = 1, N = names.size(); i < N; ++i )
307  out += "\n" + names[i];
308  m_cursor += sprintf(m_cursor, "W ");
309  flush();
310  write_string(escape(out));
311  m_cursor += sprintf(m_cursor, "\n");
312  }
313 
314  for (int i = 0, N = run_info()->tools().size(); i < N; ++i) {
315  std::string out = "T " + run_info()->tools()[i].name + "\n"
316  + run_info()->tools()[i].version + "\n"
317  + run_info()->tools()[i].description;
318  write_string(escape(out));
319  m_cursor += sprintf(m_cursor, "\n");
320  }
321 
322 
323  for ( auto att: run_info()->attributes() ) {
324  std::string st;
325  if ( !att.second->to_string(st) ) {
326  HEPMC3_WARNING("WriterAscii::write_run_info: problem serializing attribute: " << att.first)
327  }
328  else {
329  m_cursor += sprintf(m_cursor, "A ");
330  write_string(att.first);
331  flush();
332  m_cursor += sprintf(m_cursor, " ");
333  write_string(escape(st));
334  m_cursor += sprintf(m_cursor, "\n");
335  flush();
336  }
337  }
338 }
339 
340 void WriterAscii::write_particle(ConstGenParticlePtr p, int second_field) {
341  flush();
342  m_cursor += sprintf(m_cursor, m_particle_printf_specifier.c_str(), p->id(), second_field, p->pid(), p->momentum().px(), p->momentum().py(), p->momentum().pz(), p->momentum().e(), p->generated_mass(), p->status());
343  flush();
344 }
345 
346 
347 inline void WriterAscii::write_string(const std::string &str) {
348  // First let's check if string will fit into the buffer
349  if ( m_buffer + m_buffer_size > m_cursor + str.length() ) {
350  strncpy(m_cursor, str.data(), str.length());
351  m_cursor += str.length();
352  flush();
353  }
354  // If not, flush the buffer and write the string directly
355  else {
356  forced_flush();
357  m_stream->write(str.data(), str.length());
358  }
359 }
360 
361 
363  std::ofstream* ofs = dynamic_cast<std::ofstream*>(m_stream);
364  if (ofs && !ofs->is_open()) return;
365  forced_flush();
366  const std::string footer("HepMC::Asciiv3-END_EVENT_LISTING\n\n");
367  if (m_stream) m_stream->write(footer.data(),footer.length());
368  if (ofs) ofs->close();
369 }
370 bool WriterAscii::failed() { return (bool)m_file.rdstate(); }
371 
372 void WriterAscii::set_precision(const int& prec ) {
373  if (prec < 2 || prec > 24) return;
374  m_precision = prec;
375 }
376 
378  return m_precision;
379 }
380 
381 void WriterAscii::set_buffer_size(const size_t& size ) {
382  if (m_buffer) return;
383  if (size < 1024) return;
384  m_buffer_size = size;
385 }
386 
387 
388 } // namespace HepMC3
int event_number() const
Get event number.
Definition: GenEvent.h:148
const Units::MomentumUnit & momentum_unit() const
Get momentum unit.
Definition: GenEvent.h:153
void write_string(const std::string &str)
Inline function for writing strings.
Definition: WriterAscii.cc:347
void forced_flush()
Inline function forcing flush to the output stream.
Definition: WriterAscii.cc:289
HepMC3 main namespace.
const Units::LengthUnit & length_unit() const
Get length unit.
Definition: GenEvent.h:155
int m_precision
Output precision.
Definition: WriterAscii.h:122
#define HEPMC3_WARNING(MESSAGE)
Macro for printing HEPMC3_HEPMC3_WARNING messages.
Definition: Errors.h:27
std::ostream * m_stream
Output stream.
Definition: WriterAscii.h:120
void set_buffer_size(const size_t &size)
Set buffer size (in bytes)
Definition: WriterAscii.cc:381
Definition of class GenParticle.
const std::vector< ConstGenVertexPtr > & vertices() const
Get list of vertices (const)
Definition: GenEvent.cc:43
Definition of class GenVertex.
char * m_cursor
Cursor inside stream buffer.
Definition: WriterAscii.h:124
Definition of class WriterAscii.
#define HEPMC3_DEBUG(LEVEL, MESSAGE)
Macro for printing debug messages with appropriate debug level.
Definition: Errors.h:33
std::string version()
Get the HepMC library version string.
Definition: Version.h:20
void allocate_buffer()
Attempts to allocate buffer of the chosen size.
Definition: WriterAscii.cc:219
WriterAscii(const std::string &filename, std::shared_ptr< GenRunInfo > run=std::shared_ptr< GenRunInfo >())
Constructor.
Definition: WriterAscii.cc:24
static std::string name(MomentumUnit u)
Get name of momentum unit.
Definition: Units.h:56
bool is_zero() const
Check if the length of this vertex is zero.
Definition: FourVector.h:193
void write_particle(ConstGenParticlePtr p, int second_field)
Write particle.
Definition: WriterAscii.cc:340
double x() const
x-component of position/displacement
Definition: FourVector.h:81
const std::vector< double > & weights() const
Get event weight values as a vector.
Definition: GenEvent.h:98
const FourVector & event_pos() const
Vertex representing the overall event position.
Definition: GenEvent.cc:412
unsigned long m_buffer_size
Buffer size.
Definition: WriterAscii.h:125
std::string m_float_printf_specifier
the specifier of printf used for floats
Definition: WriterAscii.h:126
void set_precision(const int &prec)
Set output precision.
Definition: WriterAscii.cc:372
std::string m_particle_printf_specifier
the specifier of printf used for floats
Definition: WriterAscii.h:127
bool failed() override
Return status of the stream.
Definition: WriterAscii.cc:370
Stores event-related information.
Definition: GenEvent.h:41
Generic 4-vector.
Definition: FourVector.h:36
char * m_buffer
Stream buffer.
Definition: WriterAscii.h:123
std::string escape(const std::string &s) const
Escape &#39;\&#39; and &#39; &#39; characters in string.
Definition: WriterAscii.cc:239
void write_vertex(ConstGenVertexPtr v)
Write vertex.
Definition: WriterAscii.cc:257
double y() const
y-component of position/displacement
Definition: FourVector.h:88
double t() const
Time component of position/displacement.
Definition: FourVector.h:102
int precision() const
Return output precision.
Definition: WriterAscii.cc:377
const std::vector< ConstGenParticlePtr > & particles() const
Get list of particles (const)
Definition: GenEvent.cc:39
Definition of class Units.
std::string m_vertex_short_printf_specifier
the specifier of printf used for zero vertices
Definition: WriterAscii.h:128
~WriterAscii()
Destructor.
Definition: WriterAscii.cc:99
void set_run_info(std::shared_ptr< GenRunInfo > run)
Set the global GenRunInfo object.
Definition: Writer.h:42
std::shared_ptr< GenRunInfo > run_info() const
Get a pointer to the the GenRunInfo object.
Definition: GenEvent.h:137
void write_run_info()
Write the GenRunInfo object to file.
Definition: WriterAscii.cc:296
void write_event(const GenEvent &evt) override
Write event to file.
Definition: WriterAscii.cc:105
#define HEPMC3_ERROR(MESSAGE)
Macro for printing error messages.
Definition: Errors.h:24
std::shared_ptr< GenRunInfo > run_info() const
Get the global GenRunInfo object.
Definition: Writer.h:47
std::ofstream m_file
Output file.
Definition: WriterAscii.h:118
Definition of class GenEvent.
std::map< std::string, std::string > m_options
options
Definition: Writer.h:68
void close() override
Close file stream.
Definition: WriterAscii.cc:362
std::map< std::string, std::map< int, std::shared_ptr< Attribute > > > attributes() const
Get a copy of the list of attributes.
Definition: GenEvent.h:257
std::string m_vertex_long_printf_specifier
the specifier of printf used for vertices
Definition: WriterAscii.h:129
void flush()
Inline function flushing buffer to output stream when close to buffer capacity.
Definition: WriterAscii.cc:277
double z() const
z-component of position/displacement
Definition: FourVector.h:95