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{
29 set_run_info(run);
30 if ( !m_file.is_open() ) {
31 HEPMC3_ERROR_LEVEL(200,"WriterAscii: could not open output file: " << filename)
32 } else {
33 const std::string header = "HepMC::Version " + version() + "\nHepMC::Asciiv3-START_EVENT_LISTING\n";
34 m_file.write(header.data(), header.length());
35 if ( run_info() ) write_run_info();
36 }
37 m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
38 m_particle_printf_specifier = "P %i %i %i"
43 + m_float_printf_specifier + " %i\n";
44 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
46}
47
48
49WriterAscii::WriterAscii(std::ostream &stream, std::shared_ptr<GenRunInfo> run)
50 : m_stream(&stream)
51{
52 set_run_info(run);
53 const std::string header = "HepMC::Version " + version() + "\nHepMC::Asciiv3-START_EVENT_LISTING\n";
54 m_stream->write(header.data(), header.length());
55 if ( run_info() ) write_run_info();
56 m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
57 m_particle_printf_specifier = "P %i %i %i"
62 + m_float_printf_specifier + " %i\n";
63 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
65}
66
67WriterAscii::WriterAscii(std::shared_ptr<std::ostream> s_stream, std::shared_ptr<GenRunInfo> run)
68 : m_shared_stream(s_stream),
69 m_stream(s_stream.get())
70{
71 set_run_info(run);
72 const std::string header = "HepMC::Version " + version() + "\nHepMC::Asciiv3-START_EVENT_LISTING\n";
73 m_stream->write(header.data(), header.length());
74 if ( run_info() ) write_run_info();
75 m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
76 m_particle_printf_specifier = "P %i %i %i"
81 + m_float_printf_specifier + " %i\n";
82 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
84}
85
87 close();
88 delete[] m_buffer;
89}
90
91
94 if ( !m_buffer ) return;
95 auto float_printf_specifier_option = m_options.find("float_printf_specifier");
96 std::string letter=(float_printf_specifier_option != m_options.end())?float_printf_specifier_option->second.substr(0,2):"e";
97 if (letter != "e" && letter != "E" && letter != "G" && letter != "g" && letter != "f" && letter != "F" ) letter = "e";
98 m_float_printf_specifier = " %." + std::to_string(m_precision) + letter;
99
100
101 m_particle_printf_specifier = "P %i %i %i"
106 + m_float_printf_specifier + " %i\n";
107 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
109
110 // Make sure nothing was left from previous event
111 flush();
112
113 if ( !run_info() ) {
114 set_run_info(evt.run_info());
116 } else {
117 if ( evt.run_info() && (run_info() != evt.run_info()) ) {
118 HEPMC3_WARNING_LEVEL(600,"WriterAscii::write_event: GenEvents contain different GenRunInfo objects from - only the first such object will be serialized.")
119 }
120 }
121
122 // Write event info
123 flush();
124 std::string especifier = "E " + std::to_string(evt.event_number()) + " "
125 + std::to_string(evt.vertices().size()) + " "
126 + std::to_string(evt.particles().size());
127 // Write event position if not zero
128 const FourVector &pos = evt.event_pos();
129 if ( !pos.is_zero() ) {
131 m_cursor += sprintf(m_cursor, especifier.c_str(), pos.x(), pos.y(), pos.z(), pos.t());
132 } else {
133 m_cursor += sprintf(m_cursor, "%s\n", especifier.c_str());
134 }
135 flush();
136
137 // Write units
138 m_cursor += sprintf(m_cursor, "U %s %s\n", Units::name(evt.momentum_unit()).c_str(), Units::name(evt.length_unit()).c_str());
139 flush();
140
141 // Write weight values if present
142 if ( !evt.weights().empty() ) {
143 m_cursor += sprintf(m_cursor, "W");
144 for (const auto& w: evt.weights())
145 {
146 m_cursor += sprintf(m_cursor, " %.*e", std::min(3*m_precision, 22), w);
147 flush();
148 }
149 m_cursor += sprintf(m_cursor, "\n");
150 flush();
151 }
152
153 // Write attributes
154 for ( const auto& vt1: evt.attributes() ) {
155 for ( const auto& vt2: vt1.second ) {
156 std::string st;
157 bool status = vt2.second->to_string(st);
158
159 if ( !status ) {
160 HEPMC3_WARNING_LEVEL(300,"WriterAscii::write_event: problem serializing attribute: " << vt1.first)
161 }
162 else {
163 m_cursor += sprintf(m_cursor, "A %i ", vt2.first);
164 write_string(escape(vt1.first));
165 flush();
166 m_cursor += sprintf(m_cursor, " ");
167 write_string(escape(st));
168 m_cursor += sprintf(m_cursor, "\n");
169 flush();
170 }
171 }
172 }
173
174
175 // Print particles
176 std::map<int, bool> alreadywritten;
177 for (const ConstGenParticlePtr& p: evt.particles()) {
178 // Check to see if we need to write a vertex first
179 ConstGenVertexPtr v = p->production_vertex();
180 int parent_object = 0;
181
182 if (v) {
183 // Check if we need this vertex at all
184 // Yes, use vertex as parent object
185 if ( v->particles_in().size() > 1 || !v->data().is_zero() ) { parent_object = v->id(); }
186 // No, use particle as parent object
187 // Add check for attributes of this vertex
188 else {
189 if ( v->particles_in().size() == 1 ) { parent_object = v->particles_in().front()->id();}
190 else {if ( v->particles_in().empty() ) {HEPMC3_DEBUG(30, "WriterAscii::write_event - found a vertex without incoming particles: " << v->id());}}
191 }
192 // Usage of map instead of simple counter helps to deal with events with random ids of vertices.
193 if (alreadywritten.count(v->id()) == 0 && parent_object < 0)
194 { write_vertex(v); alreadywritten[v->id()] = true; }
195 }
196
197 write_particle(p, parent_object);
198 }
199 alreadywritten.clear();
200
201 // Flush rest of the buffer to file
202 forced_flush();
203}
204
205
207 if ( m_buffer ) return;
208 while ( m_buffer == nullptr && m_buffer_size >= 512 ) {
209 try {
210 m_buffer = new char[ m_buffer_size ]();
211 } catch (const std::bad_alloc& e) {
212 delete[] m_buffer;
213 m_buffer_size /= 2;
214 HEPMC3_WARNING_LEVEL(200,"WriterAscii::allocate_buffer:" << e.what() << " buffer size too large. Dividing by 2. New size: " << m_buffer_size)
215 }
216 }
217
218 if ( !m_buffer ) {
219 HEPMC3_ERROR_LEVEL(200,"WriterAscii::allocate_buffer: could not allocate buffer!")
220 return;
221 }
223}
224
225
226std::string WriterAscii::escape(const std::string& s) {
227 std::string ret;
228 ret.reserve(s.length()*2);
229 for ( std::string::const_iterator it = s.begin(); it != s.end(); ++it ) {
230 switch ( *it ) {
231 case '\\':
232 ret += "\\\\";
233 break;
234 case '\n':
235 ret += "\\|";
236 break;
237 default:
238 ret += *it;
239 }
240 }
241 return ret;
242}
243
244void WriterAscii::write_vertex(const ConstGenVertexPtr& v) {
245 flush();
246 std::string vlist;
247 std::vector<int> pids;
248 pids.reserve(v->particles_in().size());
249 for (const ConstGenParticlePtr& p: v->particles_in()) pids.emplace_back(p->id());
250 //We order pids to be able to compare ascii files
251 std::sort(pids.begin(), pids.end());
252 for (const auto& p: pids) vlist.append( std::to_string(p).append(",") );
253 if ( !pids.empty() ) vlist.pop_back();
254 const FourVector &pos = v->position();
255 if ( !pos.is_zero() ) {
256 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() );
257 } else {
258 m_cursor += sprintf(m_cursor, m_vertex_short_printf_specifier.c_str(), v->id(), v->status(), vlist.c_str());
259 }
260 flush();
261}
262
263
264inline void WriterAscii::flush() {
265 // The maximum size of single add to the buffer (other than by
266 // using WriterAscii::write_string) should not be larger than 256. This is a safe value as
267 // we will not allow precision larger than 24 anyway
268 if ( m_buffer + m_buffer_size < m_cursor + 512 ) {
269 std::ptrdiff_t length = m_cursor - m_buffer;
270 m_stream->write(m_buffer, length);
272 }
273}
274
275
277 std::ptrdiff_t length = m_cursor - m_buffer;
278 m_stream->write(m_buffer, length);
280}
281
282
285
286 // If no run info object set, create a dummy one.
287 if ( !run_info() ) set_run_info(std::make_shared<GenRunInfo>());
288
289 const std::vector<std::string> names = run_info()->weight_names();
290
291 if ( !names.empty() ) {
292 std::string out = names[0];
293 for ( int i = 1, N = names.size(); i < N; ++i ) {
294 out += "\n" + names[i];
295 }
296 m_cursor += sprintf(m_cursor, "W ");
297 flush();
298 write_string(escape(out));
299 m_cursor += sprintf(m_cursor, "\n");
300 }
301
302 for (const auto& tool: run_info()->tools()) {
303 std::string out = "T " + tool.name + "\n" + tool.version + "\n" + tool.description;
304 write_string(escape(out));
305 m_cursor += sprintf(m_cursor, "\n");
306 }
307
308
309 for ( const auto& att: run_info()->attributes() ) {
310 std::string st;
311 if ( !att.second->to_string(st) ) {
312 HEPMC3_WARNING_LEVEL(300,"WriterAscii::write_run_info: problem serializing attribute: " << att.first)
313 }
314 else {
315 m_cursor += sprintf(m_cursor, "A ");
316 write_string(att.first);
317 flush();
318 m_cursor += sprintf(m_cursor, " ");
319 write_string(escape(st));
320 m_cursor += sprintf(m_cursor, "\n");
321 flush();
322 }
323 }
324}
325
326void WriterAscii::write_particle(const ConstGenParticlePtr& p, int second_field) {
327 flush();
328 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());
329 flush();
330}
331
332
333inline void WriterAscii::write_string(const std::string &str) {
334 // First let's check if string will fit into the buffer
335 if ( m_buffer + m_buffer_size > m_cursor + str.length() ) {
336 strncpy(m_cursor, str.data(), str.length());
337 m_cursor += str.length();
338 flush();
339 }
340 // If not, flush the buffer and write the string directly
341 else {
342 forced_flush();
343 m_stream->write(str.data(), str.length());
344 }
345}
346
347
349 if (!m_stream) return;
350 auto* ofs = dynamic_cast<std::ofstream*>(m_stream);
351 if (ofs && !ofs->is_open()) return;
352 forced_flush();
353 const std::string footer("HepMC::Asciiv3-END_EVENT_LISTING\n\n");
354 if (m_stream) m_stream->write(footer.data(),footer.length());
355 m_stream = nullptr;
356 if (ofs) ofs->close();
357}
358bool WriterAscii::failed() { return static_cast<bool> (m_file.rdstate()); }
359
360void WriterAscii::set_precision(const int& prec ) {
361 if (prec < 2 || prec > 24) return;
362 m_precision = prec;
363}
364
366 return m_precision;
367}
368
369void WriterAscii::set_buffer_size(const size_t& size ) {
370 if (m_buffer) return;
371 if (size < 1024) return;
372 m_buffer_size = size;
373}
374
375
376} // namespace HepMC3
#define HEPMC3_WARNING_LEVEL(LEVEL, MESSAGE)
Macro for printing HEPMC3_HEPMC3_WARNING messages.
Definition Errors.h:34
#define HEPMC3_ERROR_LEVEL(LEVEL, MESSAGE)
Macro for printing error messages.
Definition Errors.h:27
#define HEPMC3_DEBUG(LEVEL, MESSAGE)
Macro for printing debug messages with appropriate debug level.
Definition Errors.h:41
Definition of class GenEvent.
Definition of class GenParticle.
Definition of class GenVertex.
Definition of class Units.
Declaration of the Verrion functions and some macros.
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:206
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:47
int event_number() const
Get event number.
Definition GenEvent.h:155
std::shared_ptr< GenRunInfo > run_info() const
Get a pointer to the the GenRunInfo object.
Definition GenEvent.h:144
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:160
const Units::LengthUnit & length_unit() const
Get length unit.
Definition GenEvent.h:162
const FourVector & event_pos() const
Vertex representing the overall event position.
Definition GenEvent.cc:418
std::map< std::string, std::map< int, std::shared_ptr< Attribute > > > attributes() const
Get a copy of the list of attributes.
Definition GenEvent.h:270
const std::vector< double > & weights() const
Get event weight values as a vector.
Definition GenEvent.h:105
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.
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.
static std::string escape(const std::string &s)
Escape '\' and ' ' characters in string.
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:25