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