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
19namespace HepMC3 {
20
21
22WriterAscii::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(nullptr),
27 m_cursor(nullptr),
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 " << version() << std::endl;
35 m_file << "HepMC::Asciiv3-START_EVENT_LISTING" << std::endl;
36 if ( run_info() ) write_run_info();
37 }
38}
39
40
41WriterAscii::WriterAscii(std::ostream &stream, 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() ) {
75 } else {
76 if ( evt.run_info() && (run_info() != evt.run_info()) ) {
77 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 string st;
124 bool status = vt2.second->to_string(st);
125
126 if( !status ) {
127 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 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 ERROR( "WriterAscii::allocate_buffer: could not allocate buffer!" )
184 return;
185 }
187}
188
189
190string WriterAscii::escape(const string& s) const {
191 string ret;
192 ret.reserve( s.length()*2 );
193 for ( 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
208void 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
247inline 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 );
256 }
257}
258
259
261 // m_file.write( m_buffer, m_cursor-m_buffer );
262 m_stream->write( m_buffer, m_cursor - m_buffer );
264}
265
266
268
270
271 // If no run info object set, create a dummy one.
272 if ( !run_info() ) set_run_info(make_shared<GenRunInfo>());
273
274 vector<string> names = run_info()->weight_names();
275
276 if ( !names.empty() ) {
277 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 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 string st;
297 if ( ! att.second->to_string(st) ) {
298 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
311void 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
335inline void WriterAscii::write_string( const 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" << endl << endl;
359 if (ofs) ofs->close();
360}
361bool WriterAscii::failed() { return (bool)m_file.rdstate(); }
362
363void 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
372void 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
#define WARNING(MESSAGE)
Macro for printing warning messages.
Definition Errors.h:26
#define 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 Units.
Definition of class WriterAscii.
Generic 4-vector.
Definition FourVector.h:35
double t() const
Time component of position/displacement.
Definition FourVector.h:83
bool is_zero() const
Check if the length of this vertex is zero.
Definition FourVector.h:174
double x() const
x-component of position/displacement
Definition FourVector.h:62
double y() const
y-component of position/displacement
Definition FourVector.h:69
double z() const
z-component of position/displacement
Definition FourVector.h:76
Stores event-related information.
Definition GenEvent.h:42
int event_number() const
Get event number.
Definition GenEvent.h:136
const std::vector< ConstGenVertexPtr > & vertices() const
Get list of vertices (const)
Definition GenEvent.cc:44
const Units::MomentumUnit & momentum_unit() const
Get momentum unit.
Definition GenEvent.h:141
const Units::LengthUnit & length_unit() const
Get length unit.
Definition GenEvent.h:143
shared_ptr< GenRunInfo > run_info() const
Get a pointer to the the GenRunInfo object.
Definition GenEvent.h:125
const FourVector & event_pos() const
Vertex representing the overall event position.
Definition GenEvent.cc:417
const std::vector< double > & weights() const
Get event weight values as a vector.
Definition GenEvent.h:87
const std::vector< ConstGenParticlePtr > & particles() const
Get list of particles (const)
Definition GenEvent.cc:40
std::map< string, std::map< int, shared_ptr< Attribute > > > attributes() const
Get a copy of the list of attributes.
Definition GenEvent.h:236
static std::string name(MomentumUnit u)
Get name of momentum unit.
Definition Units.h:56
void set_buffer_size(const size_t &size)
Set buffer size (in bytes)
void set_precision(const int &prec)
Set output precision.
void allocate_buffer()
Attempts to allocate buffer of the chosen size.
char * m_cursor
Cursor inside stream buffer.
char * m_buffer
Stream buffer.
void close()
Close file stream.
~WriterAscii()
Destructor.
std::string escape(const std::string &s) const
Escape '\' and ' ' characters in string.
int precision() const
Return output precision.
void write_particle(ConstGenParticlePtr p, int second_field)
Write particle.
int m_precision
Output precision.
std::ofstream m_file
Output file.
void write_string(const std::string &str)
Inline function for writing strings.
bool failed()
Return status of the stream.
unsigned long m_buffer_size
Buffer size.
void write_event(const GenEvent &evt)
Write event to file.
void write_vertex(ConstGenVertexPtr v)
Write vertex.
void flush()
Inline function flushing buffer to output stream when close to buffer capacity.
void write_run_info()
Write the GenRunInfo object to file.
void forced_flush()
Inline function forcing flush to the output stream.
std::ostream * m_stream
Output stream.
WriterAscii(const std::string &filename, shared_ptr< GenRunInfo > run=shared_ptr< GenRunInfo >())
Constructor.
void set_run_info(shared_ptr< GenRunInfo > run)
Set the global GenRunInfo object.
Definition Writer.h:39
shared_ptr< GenRunInfo > run_info() const
Get the global GenRunInfo object.
Definition Writer.h:44
HepMC3 main namespace.
Definition ReaderGZ.h:28
std::string version()
Get the HepMC library version string.
Definition Version.h:20