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