HepMC3 event record library: WriterAscii.cc Source File

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),
27 m_stream(&m_file)
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"
39 + m_float_printf_specifier
40 + m_float_printf_specifier
41 + m_float_printf_specifier
42 + m_float_printf_specifier
43 + m_float_printf_specifier + " %i\n";
44 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
45 m_vertex_long_printf_specifier = "V %i %i [%s] @"+ m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + "\n";
46}
47
48
49 WriterAscii::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"
58 + m_float_printf_specifier
59 + m_float_printf_specifier
60 + m_float_printf_specifier
61 + m_float_printf_specifier
62 + m_float_printf_specifier + " %i\n";
63 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
64 m_vertex_long_printf_specifier = "V %i %i [%s] @"+ m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + "\n";
65}
66
67 WriterAscii::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"
77 + m_float_printf_specifier
78 + m_float_printf_specifier
79 + m_float_printf_specifier
80 + m_float_printf_specifier
81 + m_float_printf_specifier + " %i\n";
82 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
83 m_vertex_long_printf_specifier = "V %i %i [%s] @"+ m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + "\n";
84}
85
86WriterAscii::~WriterAscii() {
87 close();
88 delete[] m_buffer;
89}
90
91
92 void WriterAscii::write_event(const GenEvent &evt) {
93 allocate_buffer();
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"
102 + m_float_printf_specifier
103 + m_float_printf_specifier
104 + m_float_printf_specifier
105 + m_float_printf_specifier
106 + m_float_printf_specifier + " %i\n";
107 m_vertex_short_printf_specifier = "V %i %i [%s]\n";
108 m_vertex_long_printf_specifier = "V %i %i [%s] @"+ m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + "\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());
115 write_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() ) {
130 especifier += ( " @" + m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + m_float_printf_specifier + "\n" );
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
206 void WriterAscii::allocate_buffer() {
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 }
222 m_cursor = m_buffer;
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
244 void 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
264 inline 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);
271 m_cursor = m_buffer;
272 }
273}
274
275
276 inline void WriterAscii::forced_flush() {
277 std::ptrdiff_t length = m_cursor - m_buffer;
278 m_stream->write(m_buffer, length);
279 m_cursor = m_buffer;
280}
281
282
283 void WriterAscii::write_run_info() {
284 allocate_buffer();
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
326 void 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
333 inline 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
348 void WriterAscii::close() {
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}
358 bool WriterAscii::failed() { return static_cast<bool> (m_file.rdstate()); }
359
360 void WriterAscii::set_precision(const int& prec ) {
361 if (prec < 2 || prec > 24) return;
362 m_precision = prec;
363}
364
365 int WriterAscii::precision() const {
366 return m_precision;
367}
368
369 void 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
HEPMC3_WARNING_LEVEL
#define HEPMC3_WARNING_LEVEL(LEVEL, MESSAGE)
Macro for printing HEPMC3_HEPMC3_WARNING messages.
Definition Errors.h:34
HEPMC3_ERROR_LEVEL
#define HEPMC3_ERROR_LEVEL(LEVEL, MESSAGE)
Macro for printing error messages.
Definition Errors.h:27
HEPMC3_DEBUG
#define HEPMC3_DEBUG(LEVEL, MESSAGE)
Macro for printing debug messages with appropriate debug level.
Definition Errors.h:41
GenEvent.h
Definition of class GenEvent.
GenParticle.h
Definition of class GenParticle.
GenVertex.h
Definition of class GenVertex.
Units.h
Definition of class Units.
Version.h
Declaration of the Verrion functions and some macros.
WriterAscii.h
Definition of class WriterAscii.
HepMC3::FourVector
Generic 4-vector.
Definition FourVector.h:36
HepMC3::FourVector::t
double t() const
Time component of position/displacement.
Definition FourVector.h:106
HepMC3::FourVector::is_zero
bool is_zero() const
Check if the length of this vertex is zero.
Definition FourVector.h:206
HepMC3::FourVector::x
double x() const
x-component of position/displacement
Definition FourVector.h:85
HepMC3::FourVector::y
double y() const
y-component of position/displacement
Definition FourVector.h:92
HepMC3::FourVector::z
double z() const
z-component of position/displacement
Definition FourVector.h:99
HepMC3::GenEvent
Stores event-related information.
Definition GenEvent.h:47
HepMC3::GenEvent::event_number
int event_number() const
Get event number.
Definition GenEvent.h:155
HepMC3::GenEvent::run_info
std::shared_ptr< GenRunInfo > run_info() const
Get a pointer to the the GenRunInfo object.
Definition GenEvent.h:144
HepMC3::GenEvent::vertices
const std::vector< ConstGenVertexPtr > & vertices() const
Get list of vertices (const).
Definition GenEvent.cc:43
HepMC3::GenEvent::momentum_unit
const Units::MomentumUnit & momentum_unit() const
Get momentum unit.
Definition GenEvent.h:160
HepMC3::GenEvent::length_unit
const Units::LengthUnit & length_unit() const
Get length unit.
Definition GenEvent.h:162
HepMC3::GenEvent::event_pos
const FourVector & event_pos() const
Vertex representing the overall event position.
Definition GenEvent.cc:418
HepMC3::GenEvent::attributes
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
HepMC3::GenEvent::weights
const std::vector< double > & weights() const
Get event weight values as a vector.
Definition GenEvent.h:105
HepMC3::GenEvent::particles
const std::vector< ConstGenParticlePtr > & particles() const
Get list of particles (const).
Definition GenEvent.cc:39
HepMC3::Units::name
static std::string name(MomentumUnit u)
Get name of momentum unit.
Definition Units.h:56
HepMC3::WriterAscii::set_buffer_size
void set_buffer_size(const size_t &size)
Set buffer size (in bytes).
Definition WriterAscii.cc:369
HepMC3::WriterAscii::set_precision
void set_precision(const int &prec)
Set output precision.
Definition WriterAscii.cc:360
HepMC3::WriterAscii::allocate_buffer
void allocate_buffer()
Attempts to allocate buffer of the chosen size.
Definition WriterAscii.cc:206
HepMC3::WriterAscii::m_cursor
char * m_cursor
Cursor inside stream buffer.
Definition WriterAscii.h:124
HepMC3::WriterAscii::failed
bool failed() override
Return status of the stream.
Definition WriterAscii.cc:358
HepMC3::WriterAscii::m_buffer
char * m_buffer
Stream buffer.
Definition WriterAscii.h:123
HepMC3::WriterAscii::m_float_printf_specifier
std::string m_float_printf_specifier
the specifier of printf used for floats
Definition WriterAscii.h:126
HepMC3::WriterAscii::~WriterAscii
~WriterAscii()
Destructor.
Definition WriterAscii.cc:86
HepMC3::WriterAscii::close
void close() override
Close file stream.
Definition WriterAscii.cc:348
HepMC3::WriterAscii::precision
int precision() const
Return output precision.
Definition WriterAscii.cc:365
HepMC3::WriterAscii::m_precision
int m_precision
Output precision.
Definition WriterAscii.h:122
HepMC3::WriterAscii::write_particle
void write_particle(const ConstGenParticlePtr &p, int second_field)
Write particle.
Definition WriterAscii.cc:326
HepMC3::WriterAscii::m_vertex_short_printf_specifier
std::string m_vertex_short_printf_specifier
the specifier of printf used for zero vertices
Definition WriterAscii.h:128
HepMC3::WriterAscii::write_vertex
void write_vertex(const ConstGenVertexPtr &v)
Write vertex.
Definition WriterAscii.cc:244
HepMC3::WriterAscii::m_shared_stream
std::shared_ptr< std::ostream > m_shared_stream
Output temp. stream.
Definition WriterAscii.h:119
HepMC3::WriterAscii::m_file
std::ofstream m_file
Output file.
Definition WriterAscii.h:118
HepMC3::WriterAscii::escape
static std::string escape(const std::string &s)
Escape '\' and ' ' characters in string.
Definition WriterAscii.cc:226
HepMC3::WriterAscii::write_string
void write_string(const std::string &str)
Inline function for writing strings.
Definition WriterAscii.cc:333
HepMC3::WriterAscii::m_buffer_size
unsigned long m_buffer_size
Buffer size.
Definition WriterAscii.h:125
HepMC3::WriterAscii::m_particle_printf_specifier
std::string m_particle_printf_specifier
the specifier of printf used for floats
Definition WriterAscii.h:127
HepMC3::WriterAscii::write_event
void write_event(const GenEvent &evt) override
Write event to file.
Definition WriterAscii.cc:92
HepMC3::WriterAscii::WriterAscii
WriterAscii(const std::string &filename, std::shared_ptr< GenRunInfo > run=std::shared_ptr< GenRunInfo >())
Constructor.
Definition WriterAscii.cc:25
HepMC3::WriterAscii::m_vertex_long_printf_specifier
std::string m_vertex_long_printf_specifier
the specifier of printf used for vertices
Definition WriterAscii.h:129
HepMC3::WriterAscii::flush
void flush()
Inline function flushing buffer to output stream when close to buffer capacity.
Definition WriterAscii.cc:264
HepMC3::WriterAscii::write_run_info
void write_run_info()
Write the GenRunInfo object to file.
Definition WriterAscii.cc:283
HepMC3::WriterAscii::forced_flush
void forced_flush()
Inline function forcing flush to the output stream.
Definition WriterAscii.cc:276
HepMC3::WriterAscii::m_stream
std::ostream * m_stream
Output stream.
Definition WriterAscii.h:120
HepMC3::Writer::set_run_info
virtual void set_run_info(std::shared_ptr< GenRunInfo > run)
Set the global GenRunInfo object.
Definition Writer.h:42
HepMC3::Writer::run_info
virtual std::shared_ptr< GenRunInfo > run_info() const
Get the global GenRunInfo object.
Definition Writer.h:45
HepMC3::Writer::m_options
std::map< std::string, std::string > m_options
options
Definition Writer.h:59
HepMC3
HepMC3 main namespace.
Definition AnalysisExample.h:24
HepMC3::version
std::string version()
Get the HepMC library version string.
Definition Version.h:25