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-2023 The HepMC collaboration (see AUTHORS for details)
5//
6///
7/// @file WriterAscii.cc
8/// @brief Implementation of \b class WriterAscii
9///
10
11#include <algorithm>//min max for VS2017
12#include <cstring>
13
14
15#include "HepMC3/GenEvent.h"
16#include "HepMC3/GenParticle.h"
17#include "HepMC3/GenVertex.h"
18#include "HepMC3/Units.h"
19#include "HepMC3/Version.h"
20#include "HepMC3/WriterAscii.h"
21
22namespace HepMC3 {
23
24
25WriterAscii::WriterAscii(const std::string &filename, std::shared_ptr<GenRunInfo> run)
26 : m_file(filename),
28 m_precision(16),
29 m_buffer(nullptr),
30 m_cursor(nullptr),
31 m_buffer_size(262144)
32{
33 set_run_info(run);
34 if ( !m_file.is_open() ) {
35 HEPMC3_ERROR("WriterAscii: could not open output file: " << filename)
36 } else {
37 const std::string header = "HepMC::Version " + version() + "\nHepMC::Asciiv3-START_EVENT_LISTING\n";
38 m_file.write(header.data(), header.length());
39 if ( run_info() ) write_run_info();
40 }
41 m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
42 m_particle_printf_specifier = "P %i %i %i"
47 + m_float_printf_specifier + " %i\n";
48 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
50}
51
52
53WriterAscii::WriterAscii(std::ostream &stream, std::shared_ptr<GenRunInfo> run)
54 : m_stream(&stream),
55 m_precision(16),
56 m_buffer(nullptr),
57 m_cursor(nullptr),
58 m_buffer_size(262144)
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_shared_stream(s_stream),
77 m_stream(s_stream.get()),
78 m_precision(16),
79 m_buffer(nullptr),
80 m_cursor(nullptr),
81 m_buffer_size(262144)
82{
83 set_run_info(run);
84 const std::string header = "HepMC::Version " + version() + "\nHepMC::Asciiv3-START_EVENT_LISTING\n";
85 m_stream->write(header.data(), header.length());
86 if ( run_info() ) write_run_info();
87 m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
88 m_particle_printf_specifier = "P %i %i %i"
93 + m_float_printf_specifier + " %i\n";
94 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
96}
97
99 close();
100 if ( m_buffer ) delete[] m_buffer;
101}
102
103
106 if ( !m_buffer ) return;
107 auto float_printf_specifier_option = m_options.find("float_printf_specifier");
108 std::string letter=(float_printf_specifier_option != m_options.end())?float_printf_specifier_option->second.substr(0,2):"e";
109 if (letter != "e" && letter != "E" && letter != "G" && letter != "g" && letter != "f" && letter != "F" ) letter = "e";
110 m_float_printf_specifier = " %." + std::to_string(m_precision) + letter;
111
112
113 m_particle_printf_specifier = "P %i %i %i"
118 + m_float_printf_specifier + " %i\n";
119 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
121
122 // Make sure nothing was left from previous event
123 flush();
124
125 if ( !run_info() ) {
126 set_run_info(evt.run_info());
128 } else {
129 if ( evt.run_info() && (run_info() != evt.run_info()) ) {
130 HEPMC3_WARNING("WriterAscii::write_event: GenEvents contain "
131 "different GenRunInfo objects from - only the "
132 "first such object will be serialized.")
133 }
134 }
135
136 // Write event info
137 flush();
138 std::string especifier = "E " + std::to_string(evt.event_number()) + " "
139 + std::to_string(evt.vertices().size()) + " "
140 + std::to_string(evt.particles().size());
141 // Write event position if not zero
142 const FourVector &pos = evt.event_pos();
143 if ( !pos.is_zero() ) {
145 m_cursor += sprintf(m_cursor, especifier.c_str(), pos.x(), pos.y(), pos.z(), pos.t());
146 } else {
147 m_cursor += sprintf(m_cursor, "%s\n", especifier.c_str());
148 }
149 flush();
150
151 // Write units
152 m_cursor += sprintf(m_cursor, "U %s %s\n", Units::name(evt.momentum_unit()).c_str(), Units::name(evt.length_unit()).c_str());
153 flush();
154
155 // Write weight values if present
156 if ( !evt.weights().empty() ) {
157 m_cursor += sprintf(m_cursor, "W");
158 for (const auto& w: evt.weights())
159 {
160 m_cursor += sprintf(m_cursor, " %.*e", std::min(3*m_precision, 22), w);
161 flush();
162 }
163 m_cursor += sprintf(m_cursor, "\n");
164 flush();
165 }
166
167 // Write attributes
168 for ( const auto& vt1: evt.attributes() ) {
169 for ( const auto& vt2: vt1.second ) {
170 std::string st;
171 bool status = vt2.second->to_string(st);
172
173 if ( !status ) {
174 HEPMC3_WARNING("WriterAscii::write_event: problem serializing attribute: " << vt1.first)
175 }
176 else {
177 m_cursor += sprintf(m_cursor, "A %i ", vt2.first);
178 write_string(escape(vt1.first));
179 flush();
180 m_cursor += sprintf(m_cursor, " ");
181 write_string(escape(st));
182 m_cursor += sprintf(m_cursor, "\n");
183 flush();
184 }
185 }
186 }
187
188
189 // Print particles
190 std::map<int, bool> alreadywritten;
191 for (const ConstGenParticlePtr& p: evt.particles()) {
192 // Check to see if we need to write a vertex first
193 ConstGenVertexPtr v = p->production_vertex();
194 int parent_object = 0;
195
196 if (v) {
197 // Check if we need this vertex at all
198 // Yes, use vertex as parent object
199 if ( v->particles_in().size() > 1 || !v->data().is_zero() ) { parent_object = v->id(); }
200 // No, use particle as parent object
201 // Add check for attributes of this vertex
202 else {
203 if ( v->particles_in().size() == 1 ) { parent_object = v->particles_in().front()->id();}
204 else {if ( v->particles_in().empty() ) {HEPMC3_DEBUG(30, "WriterAscii::write_event - found a vertex without incoming particles: " << v->id());}}
205 }
206 // Usage of map instead of simple counter helps to deal with events with random ids of vertices.
207 if (alreadywritten.count(v->id()) == 0 && parent_object < 0)
208 { write_vertex(v); alreadywritten[v->id()] = true; }
209 }
210
211 write_particle(p, parent_object);
212 }
213 alreadywritten.clear();
214
215 // Flush rest of the buffer to file
216 forced_flush();
217}
218
219
221 if ( m_buffer ) return;
222 while ( m_buffer == nullptr && m_buffer_size >= 512 ) {
223 try {
224 m_buffer = new char[ m_buffer_size ]();
225 } catch (const std::bad_alloc& e) {
226 delete[] m_buffer;
227 m_buffer_size /= 2;
228 HEPMC3_WARNING("WriterAscii::allocate_buffer:" << e.what() << " buffer size too large. Dividing by 2. New size: " << m_buffer_size)
229 }
230 }
231
232 if ( !m_buffer ) {
233 HEPMC3_ERROR("WriterAscii::allocate_buffer: could not allocate buffer!")
234 return;
235 }
237}
238
239
240std::string WriterAscii::escape(const std::string& s) const {
241 std::string ret;
242 ret.reserve(s.length()*2);
243 for ( std::string::const_iterator it = s.begin(); it != s.end(); ++it ) {
244 switch ( *it ) {
245 case '\\':
246 ret += "\\\\";
247 break;
248 case '\n':
249 ret += "\\|";
250 break;
251 default:
252 ret += *it;
253 }
254 }
255 return ret;
256}
257
258void WriterAscii::write_vertex(const ConstGenVertexPtr& v) {
259 flush();
260 std::string vlist;
261 std::vector<int> pids;
262 pids.reserve(v->particles_in().size());
263 for (const ConstGenParticlePtr& p: v->particles_in()) pids.emplace_back(p->id());
264 //We order pids to be able to compare ascii files
265 std::sort(pids.begin(), pids.end());
266 for (const auto& p: pids) vlist.append( std::to_string(p).append(",") );
267 if ( !pids.empty() ) vlist.pop_back();
268 const FourVector &pos = v->position();
269 if ( !pos.is_zero() ) {
270 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() );
271 } else {
272 m_cursor += sprintf(m_cursor, m_vertex_short_printf_specifier.c_str(), v->id(), v->status(), vlist.c_str());
273 }
274 flush();
275}
276
277
278inline void WriterAscii::flush() {
279 // The maximum size of single add to the buffer (other than by
280 // using WriterAscii::write_string) should not be larger than 256. This is a safe value as
281 // we will not allow precision larger than 24 anyway
282 if ( m_buffer + m_buffer_size < m_cursor + 512 ) {
283 std::ptrdiff_t length = m_cursor - m_buffer;
284 m_stream->write(m_buffer, length);
286 }
287}
288
289
291 std::ptrdiff_t length = m_cursor - m_buffer;
292 m_stream->write(m_buffer, length);
294}
295
296
299
300 // If no run info object set, create a dummy one.
301 if ( !run_info() ) set_run_info(std::make_shared<GenRunInfo>());
302
303 const std::vector<std::string> names = run_info()->weight_names();
304
305 if ( !names.empty() ) {
306 std::string out = names[0];
307 for ( int i = 1, N = names.size(); i < N; ++i ) {
308 out += "\n" + names[i];
309 }
310 m_cursor += sprintf(m_cursor, "W ");
311 flush();
312 write_string(escape(out));
313 m_cursor += sprintf(m_cursor, "\n");
314 }
315
316 for (const auto& tool: run_info()->tools()) {
317 std::string out = "T " + tool.name + "\n" + tool.version + "\n" + tool.description;
318 write_string(escape(out));
319 m_cursor += sprintf(m_cursor, "\n");
320 }
321
322
323 for ( const 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(const 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 auto* 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:106
bool is_zero() const
Check if the length of this vertex is zero.
Definition FourVector.h:197
double x() const
x-component of position/displacement
Definition FourVector.h:85
double y() const
y-component of position/displacement
Definition FourVector.h:92
double z() const
z-component of position/displacement
Definition FourVector.h:99
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:261
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)
void set_precision(const int &prec)
Set output precision.
std::string escape(const std::string &s) const
Escape '\' and ' ' characters in string.
void allocate_buffer()
Attempts to allocate buffer of the chosen size.
char * m_cursor
Cursor inside stream buffer.
bool failed() override
Return status of the stream.
char * m_buffer
Stream buffer.
std::string m_float_printf_specifier
the specifier of printf used for floats
~WriterAscii()
Destructor.
void close() override
Close file stream.
int precision() const
Return output precision.
int m_precision
Output precision.
void write_particle(const ConstGenParticlePtr &p, int second_field)
Write particle.
std::string m_vertex_short_printf_specifier
the specifier of printf used for zero vertices
void write_vertex(const ConstGenVertexPtr &v)
Write vertex.
std::shared_ptr< std::ostream > m_shared_stream
Output temp. stream.
std::ofstream m_file
Output file.
void write_string(const std::string &str)
Inline function for writing strings.
unsigned long m_buffer_size
Buffer size.
std::string m_particle_printf_specifier
the specifier of printf used for floats
void write_event(const GenEvent &evt) override
Write event to file.
WriterAscii(const std::string &filename, std::shared_ptr< GenRunInfo > run=std::shared_ptr< GenRunInfo >())
Constructor.
std::string m_vertex_long_printf_specifier
the specifier of printf used for vertices
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.
virtual void set_run_info(std::shared_ptr< GenRunInfo > run)
Set the global GenRunInfo object.
Definition Writer.h:42
virtual std::shared_ptr< GenRunInfo > run_info() const
Get the global GenRunInfo object.
Definition Writer.h:45
std::map< std::string, std::string > m_options
options
Definition Writer.h:59
HepMC3 main namespace.
std::string version()
Get the HepMC library version string.
Definition Version.h:20