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