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
21namespace HepMC3 {
22
23
24WriterAscii::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
52WriterAscii::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
75WriterAscii::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
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());
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 }
236}
237
238
239std::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
257void 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
277inline 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);
285 }
286}
287
288
290 std::ptrdiff_t length = m_cursor - m_buffer;
291 m_stream->write(m_buffer, length);
293}
294
295
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
340void 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
347inline 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}
370bool WriterAscii::failed() { return (bool)m_file.rdstate(); }
371
372void 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
381void 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
#define HEPMC3_WARNING(MESSAGE)
Macro for printing HEPMC3_HEPMC3_WARNING messages.
Definition: Errors.h:27
#define HEPMC3_DEBUG(LEVEL, MESSAGE)
Macro for printing debug messages with appropriate debug level.
Definition: Errors.h:33
#define HEPMC3_ERROR(MESSAGE)
Macro for printing error messages.
Definition: Errors.h:24
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:36
double t() const
Time component of position/displacement.
Definition: FourVector.h:102
bool is_zero() const
Check if the length of this vertex is zero.
Definition: FourVector.h:193
double x() const
x-component of position/displacement
Definition: FourVector.h:81
double y() const
y-component of position/displacement
Definition: FourVector.h:88
double z() const
z-component of position/displacement
Definition: FourVector.h:95
Stores event-related information.
Definition: GenEvent.h:41
int event_number() const
Get event number.
Definition: GenEvent.h:148
std::shared_ptr< GenRunInfo > run_info() const
Get a pointer to the the GenRunInfo object.
Definition: GenEvent.h:137
const std::vector< ConstGenVertexPtr > & vertices() const
Get list of vertices (const)
Definition: GenEvent.cc:43
const Units::MomentumUnit & momentum_unit() const
Get momentum unit.
Definition: GenEvent.h:153
const Units::LengthUnit & length_unit() const
Get length unit.
Definition: GenEvent.h:155
const FourVector & event_pos() const
Vertex representing the overall event position.
Definition: GenEvent.cc:412
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
const std::vector< double > & weights() const
Get event weight values as a vector.
Definition: GenEvent.h:98
const std::vector< ConstGenParticlePtr > & particles() const
Get list of particles (const)
Definition: GenEvent.cc:39
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)
Definition: WriterAscii.cc:381
void set_precision(const int &prec)
Set output precision.
Definition: WriterAscii.cc:372
std::string escape(const std::string &s) const
Escape '\' and ' ' characters in string.
Definition: WriterAscii.cc:239
void allocate_buffer()
Attempts to allocate buffer of the chosen size.
Definition: WriterAscii.cc:219
char * m_cursor
Cursor inside stream buffer.
Definition: WriterAscii.h:124
bool failed() override
Return status of the stream.
Definition: WriterAscii.cc:370
char * m_buffer
Stream buffer.
Definition: WriterAscii.h:123
std::string m_float_printf_specifier
the specifier of printf used for floats
Definition: WriterAscii.h:126
~WriterAscii()
Destructor.
Definition: WriterAscii.cc:99
void close() override
Close file stream.
Definition: WriterAscii.cc:362
int precision() const
Return output precision.
Definition: WriterAscii.cc:377
void write_particle(ConstGenParticlePtr p, int second_field)
Write particle.
Definition: WriterAscii.cc:340
int m_precision
Output precision.
Definition: WriterAscii.h:122
std::string m_vertex_short_printf_specifier
the specifier of printf used for zero vertices
Definition: WriterAscii.h:128
std::ofstream m_file
Output file.
Definition: WriterAscii.h:118
void write_string(const std::string &str)
Inline function for writing strings.
Definition: WriterAscii.cc:347
unsigned long m_buffer_size
Buffer size.
Definition: WriterAscii.h:125
std::string m_particle_printf_specifier
the specifier of printf used for floats
Definition: WriterAscii.h:127
void write_event(const GenEvent &evt) override
Write event to file.
Definition: WriterAscii.cc:105
void write_vertex(ConstGenVertexPtr v)
Write vertex.
Definition: WriterAscii.cc:257
WriterAscii(const std::string &filename, std::shared_ptr< GenRunInfo > run=std::shared_ptr< GenRunInfo >())
Constructor.
Definition: WriterAscii.cc:24
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
void write_run_info()
Write the GenRunInfo object to file.
Definition: WriterAscii.cc:296
void forced_flush()
Inline function forcing flush to the output stream.
Definition: WriterAscii.cc:289
std::ostream * m_stream
Output stream.
Definition: WriterAscii.h:120
std::shared_ptr< GenRunInfo > run_info() const
Get the global GenRunInfo object.
Definition: Writer.h:47
std::map< std::string, std::string > m_options
options
Definition: Writer.h:68
void set_run_info(std::shared_ptr< GenRunInfo > run)
Set the global GenRunInfo object.
Definition: Writer.h:42
HepMC3 main namespace.
std::string version()
Get the HepMC library version string.
Definition: Version.h:20