HepMC3 event record library
WriterAsciiHepMC2.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 WriterAsciiHepMC2.cc
8/// @brief Implementation of \b class WriterAsciiHepMC2
9///
10#include <cstring>
11
12
13#include "HepMC3/GenEvent.h"
14#include "HepMC3/GenParticle.h"
15#include "HepMC3/GenVertex.h"
16#include "HepMC3/Units.h"
17#include "HepMC3/Version.h"
19
20namespace HepMC3
21{
22
23
24WriterAsciiHepMC2::WriterAsciiHepMC2(const std::string &filename, std::shared_ptr<GenRunInfo> run)
25 : m_file(filename),
27{
28 HEPMC3_WARNING_LEVEL(900,"WriterAsciiHepMC2::WriterAsciiHepMC2: HepMC2 IO_GenEvent format is outdated. Please use HepMC3 Asciiv3 format instead.")
29 set_run_info(run);
30 if ( !run_info() ) set_run_info(std::make_shared<GenRunInfo>());
31 if ( !m_file.is_open() )
32 {
33 HEPMC3_ERROR_LEVEL(100,"WriterAsciiHepMC2: could not open output file: " << filename )
34 }
35 else
36 {
37 const std::string header = "HepMC::Version " + version() + "\nHepMC::IO_GenEvent-START_EVENT_LISTING\n";
38 m_file.write(header.data(), header.length());
39 }
40 m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
41}
42
43WriterAsciiHepMC2::WriterAsciiHepMC2(std::ostream &stream, std::shared_ptr<GenRunInfo> run)
44 : m_stream(&stream)
45{
46 HEPMC3_WARNING_LEVEL(900,"WriterAsciiHepMC2::WriterAsciiHepMC2: HepMC2 IO_GenEvent format is outdated. Please use HepMC3 Asciiv3 format instead.")
47 set_run_info(run);
48 if ( !run_info() ) set_run_info(std::make_shared<GenRunInfo>());
49 const std::string header = "HepMC::Version " + version() + "\nHepMC::IO_GenEvent-START_EVENT_LISTING\n";
50 m_stream->write(header.data(), header.length());
51 m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
52}
53
54WriterAsciiHepMC2::WriterAsciiHepMC2(std::shared_ptr<std::ostream> s_stream, std::shared_ptr<GenRunInfo> run)
55 : m_shared_stream(s_stream),
56 m_stream(s_stream.get())
57{
58 HEPMC3_WARNING_LEVEL(900,"WriterAsciiHepMC2::WriterAsciiHepMC2: HepMC2 IO_GenEvent format is outdated. Please use HepMC3 Asciiv3 format instead.")
59 set_run_info(run);
60 if ( !run_info() ) set_run_info(std::make_shared<GenRunInfo>());
61 const std::string header = "HepMC::Version " + version() + "\nHepMC::IO_GenEvent-START_EVENT_LISTING\n";
62 m_stream->write(header.data(), header.length());
63 m_float_printf_specifier = " %." + std::to_string(m_precision) + "e";
64}
65
66
72
73
75{
77 if ( !m_buffer ) return;
78 auto float_printf_specifier_option = m_options.find("float_printf_specifier");
79 std::string letter=(float_printf_specifier_option != m_options.end())?float_printf_specifier_option->second.substr(0,2):"e";
80 if (letter != "e" && letter != "E" && letter != "G" && letter != "g" && letter != "f" && letter != "F" ) letter = "e";
81 m_float_printf_specifier = " %." + std::to_string(m_precision) + letter;
82 // Make sure nothing was left from previous event
83 flush();
84
85 if ( !run_info() ) set_run_info(evt.run_info());
86 if ( evt.run_info() && run_info() != evt.run_info() ) set_run_info(evt.run_info());
87
88
89 std::shared_ptr<DoubleAttribute> A_event_scale = evt.attribute<DoubleAttribute>("event_scale");
90 std::shared_ptr<DoubleAttribute> A_alphaQED = evt.attribute<DoubleAttribute>("alphaQED");
91 std::shared_ptr<DoubleAttribute> A_alphaQCD = evt.attribute<DoubleAttribute>("alphaQCD");
92 std::shared_ptr<IntAttribute> A_signal_process_id = evt.attribute<IntAttribute>("signal_process_id");
93 std::shared_ptr<IntAttribute> A_mpi = evt.attribute<IntAttribute>("mpi");
94 std::shared_ptr<IntAttribute> A_signal_process_vertex = evt.attribute<IntAttribute>("signal_process_vertex");
95
96 double event_scale = A_event_scale?(A_event_scale->value()):0.0;
97 double alphaQED = A_alphaQED?(A_alphaQED->value()):0.0;
98 double alphaQCD = A_alphaQCD?(A_alphaQCD->value()):0.0;
99 int signal_process_id = A_signal_process_id?(A_signal_process_id->value()):0;
100 int mpi = A_mpi?(A_mpi->value()):0;
101 int signal_process_vertex = A_signal_process_vertex?(A_signal_process_vertex->value()):0;
102
103 std::vector<long> m_random_states;
104 std::shared_ptr<VectorLongIntAttribute> random_states_a = evt.attribute<VectorLongIntAttribute>("random_states");
105 if (random_states_a) {
106 m_random_states = random_states_a->value();
107 } else {
108 m_random_states.reserve(100);
109 for (int i = 0; i < 100; i++)
110 {
111 std::shared_ptr<LongAttribute> rs = evt.attribute<LongAttribute>("random_states"+std::to_string(static_cast<long long unsigned int>(i)));
112 if (!rs) break;
113 m_random_states.emplace_back(rs->value());
114 }
115 }
116 // Write event info
117 //Find beam particles
118 std::vector<int> beams;
119 beams.reserve(2);
120 int idbeam = 0;
121 for (const ConstGenVertexPtr& v: evt.vertices())
122 {
123 for (const ConstGenParticlePtr& p: v->particles_in())
124 {
125 if (!p->production_vertex()) { if (p->status() == 4) beams.emplace_back(idbeam); idbeam++; }
126 else {if (p->production_vertex()->id() == 0) { if (p->status() == 4) beams.emplace_back(idbeam); idbeam++; }}
127 }
128 for (const ConstGenParticlePtr& p: v->particles_out()) { if (p->status() == 4) beams.push_back(idbeam); idbeam++; }
129 }
130 //
131 int idbeam1 = 10000;
132 int idbeam2 = 10000;
133 if (!beams.empty()) idbeam1 += beams[0] + 1;
134 if (beams.size() > 1) idbeam2 += beams[1] + 1;
135 m_cursor += sprintf(m_cursor, "E %d %d %e %e %e %d %d %zu %i %i",
136 evt.event_number(),
137 mpi,
138 event_scale,
139 alphaQCD,
140 alphaQED,
141 signal_process_id,
142 signal_process_vertex,
143 evt.vertices().size(),
144 idbeam1, idbeam2);
145
146 // This should be the largest single add to the buffer. Its size 11+4*11+3*22+2*11+10=153
147 flush();
148 m_cursor += sprintf(m_cursor, " %zu", m_random_states.size());
149 for (size_t q = 0; q < m_random_states.size(); q++)
150 {
151 m_cursor += sprintf(m_cursor, " %i", static_cast<int> (q));
152 flush();
153 }
154 flush();
155 m_cursor += sprintf(m_cursor, " %zu", evt.weights().size());
156 if ( !evt.weights().empty() )
157 {
158 for (const double& w: evt.weights()) {
159 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), w);
160 flush();
161 }
162 m_cursor += sprintf(m_cursor, "\n");
163 flush();
164 m_cursor += sprintf(m_cursor, "N %zu", evt.weights().size());
165 const std::vector<std::string> names = run_info()->weight_names();
166 for (size_t q = 0; q < evt.weights().size(); q++)
167 {
168 if (q < names.size()) {
169 write_string(" \""+names[q]+"\"");
170 } else {
171 write_string(" \""+std::to_string(q)+"\"");
172 }
173 flush();
174 }
175 }
176 m_cursor += sprintf(m_cursor, "\n");
177 flush();
178 // Write units
179 m_cursor += sprintf(m_cursor, "U %s %s\n", Units::name(evt.momentum_unit()).c_str(), Units::name(evt.length_unit()).c_str());
180 flush();
181 std::shared_ptr<GenCrossSection> cs = evt.attribute<GenCrossSection>("GenCrossSection");
182 if (cs) {
183 m_cursor += sprintf(m_cursor, ("C" + m_float_printf_specifier + m_float_printf_specifier + "\n").c_str(), cs->xsec(), cs->xsec_err() );
184 flush();
185 }
186
187 std::shared_ptr<GenHeavyIon> hi = evt.attribute<GenHeavyIon>("GenHeavyIon");
188 if (hi) {
189 m_cursor += sprintf(m_cursor, "H %i %i %i %i %i %i %i %i %i %e %e %e %e\n",
190 hi->Ncoll_hard,
191 hi->Npart_proj,
192 hi->Npart_targ,
193 hi->Ncoll,
194 hi->spectator_neutrons,
195 hi->spectator_protons,
196 hi->N_Nwounded_collisions,
197 hi->Nwounded_N_collisions,
198 hi->Nwounded_Nwounded_collisions,
199 hi->impact_parameter,
200 hi->event_plane_angle,
201 hi->eccentricity,
202 hi->sigma_inel_NN);
203 flush();
204 }
205
206 std::shared_ptr<GenPdfInfo> pi = evt.attribute<GenPdfInfo>("GenPdfInfo");
207 if (pi) {
208 std::string st;
209 // We use it here because the HepMC3 GenPdfInfo has the same format as in HepMC2 IO_GenEvent and get error handeling for free.
210 bool status = pi->to_string(st);
211 if ( !status )
212 {
213 HEPMC3_WARNING_LEVEL(300,"WriterAsciiHepMC2::write_event: problem serializing GenPdfInfo attribute")
214 } else {
215 m_cursor += sprintf(m_cursor, "F ");
216 flush();
217 write_string(escape(st));
218 m_cursor += sprintf(m_cursor, "\n");
219 flush();
220 }
221 }
222
223
225 for (const ConstGenVertexPtr& v: evt.vertices() )
226 {
227 int production_vertex = 0;
228 production_vertex = v->id();
229 write_vertex(v);
230 for (const ConstGenParticlePtr& p: v->particles_in())
231 {
232 if (!p->production_vertex()) { write_particle( p, production_vertex ); }
233 else
234 {
235 if (p->production_vertex()->id() == 0) write_particle( p, production_vertex );
236 }
237 }
238 for (const ConstGenParticlePtr& p: v->particles_out()) {
239 write_particle(p, production_vertex);
240 }
241 }
242
243 // Flush rest of the buffer to file
244 forced_flush();
245}
246
247
249{
250 if ( m_buffer ) return;
251 while ( m_buffer == nullptr && m_buffer_size >= 512 ) {
252 try {
253 m_buffer = new char[ m_buffer_size ]();
254 } catch (const std::bad_alloc& e) {
255 delete[] m_buffer;
256 m_buffer_size /= 2;
257 HEPMC3_WARNING_LEVEL(200,"WriterAsciiHepMC2::allocate_buffer:" << e.what() << " buffer size too large. Dividing by 2. New size: " << m_buffer_size)
258 }
259 }
260
261 if ( !m_buffer )
262 {
263 HEPMC3_ERROR_LEVEL(200,"WriterAsciiHepMC2::allocate_buffer: could not allocate buffer!")
264 return;
265 }
266
268}
269
270
271std::string WriterAsciiHepMC2::escape(const std::string& s)
272{
273 std::string ret;
274 ret.reserve(s.length()*2);
275 for ( std::string::const_iterator it = s.begin(); it != s.end(); ++it )
276 {
277 switch ( *it )
278 {
279 case '\\':
280 ret += "\\\\";
281 break;
282 case '\n':
283 ret += "\\|";
284 break;
285 default:
286 ret += *it;
287 }
288 }
289 return ret;
290}
291
292void WriterAsciiHepMC2::write_vertex(const ConstGenVertexPtr& v)
293{
294 std::vector<double> weights;
295 std::shared_ptr<VectorDoubleAttribute> weights_a = v->attribute<VectorDoubleAttribute>("weights");
296 if (weights_a) {
297 weights = weights_a->value();
298 } else {
299 weights.reserve(100);
300 for (int i = 0; i < 100; i++)
301 {
302 std::shared_ptr<DoubleAttribute> rs = v->attribute<DoubleAttribute>("weight"+std::to_string(static_cast<long long unsigned int>(i)));
303 if (!rs) break;
304 weights.emplace_back(rs->value());
305 }
306 }
307 flush();
308 m_cursor += sprintf(m_cursor, "V %i %i", v->id(), v->status());
309 int orph = 0;
310 for (const ConstGenParticlePtr& p: v->particles_in())
311 {
312 if (!p->production_vertex()) { orph++;}
313 else
314 {
315 if (p->production_vertex()->id() == 0) orph++;
316 }
317 }
318 const FourVector &pos = v->position();
319 if (pos.is_zero())
320 {
321 m_cursor += sprintf(m_cursor, " 0 0 0 0");
322 }
323 else
324 {
325 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), pos.x());
326 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), pos.y());
327 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), pos.z());
328 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), pos.t());
329 }
330 m_cursor += sprintf(m_cursor, " %i %zu %zu", orph, v->particles_out().size(), weights.size());
331 flush();
332 for (size_t i = 0; i < weights.size(); i++) { m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), weights[i]); flush(); }
333 m_cursor += sprintf(m_cursor, "\n");
334 flush();
335}
336
337
339{
340 // The maximum size of single add to the buffer should not be larger than 256. This is a safe value as
341 // we will not allow precision larger than 24 anyway
342 if ( m_buffer + m_buffer_size < m_cursor + 512 )
343 {
344 std::ptrdiff_t length = m_cursor - m_buffer;
345 m_stream->write(m_buffer, length);
347 }
348}
349
350
352{
353 std::ptrdiff_t length = m_cursor - m_buffer;
354 m_stream->write(m_buffer, length);
356}
357
358
360
361void WriterAsciiHepMC2::write_particle(const ConstGenParticlePtr& p, int /*second_field*/)
362{
363 flush();
364 m_cursor += sprintf(m_cursor, "P %i", int(10001+m_particle_counter));
366 m_cursor += sprintf(m_cursor, " %i", p->pid() );
367 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), p->momentum().px() );
368 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), p->momentum().py());
369 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), p->momentum().pz() );
370 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), p->momentum().e() );
371 m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), p->generated_mass() );
372 m_cursor += sprintf(m_cursor, " %i", p->status() );
373 flush();
374 int ev = 0;
375 if (p->end_vertex()) {
376 if (p->end_vertex()->id() != 0)
377 { ev = p->end_vertex()->id(); }
378 }
379 std::shared_ptr<DoubleAttribute> A_theta = p->attribute<DoubleAttribute>("theta");
380 std:: shared_ptr<DoubleAttribute> A_phi = p->attribute<DoubleAttribute>("phi");
381 if (A_theta) { m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), A_theta->value()); }
382 else { m_cursor += sprintf(m_cursor, " 0");}
383 if (A_phi) { m_cursor += sprintf(m_cursor, m_float_printf_specifier.c_str(), A_phi->value()); }
384 else { m_cursor += sprintf(m_cursor, " 0");}
385 m_cursor += sprintf(m_cursor, " %i", ev);
386 flush();
387 std::shared_ptr<VectorIntAttribute> A_flows = p->attribute<VectorIntAttribute>("flows");
388 if (A_flows)
389 {
390 std::vector<int> flowsv = A_flows->value();
391 std::string flowss = " " + std::to_string(flowsv.size());
392 for (size_t k = 0; k < flowsv.size(); k++) { flowss += ( " " + std::to_string(k+1) + " " + std::to_string(flowsv.at(k))); }
393 flowss += "\n";
394 write_string(flowss);
395 } else {
396 std::shared_ptr<IntAttribute> A_flow1 = p->attribute<IntAttribute>("flow1");
397 std::shared_ptr<IntAttribute> A_flow2 = p->attribute<IntAttribute>("flow2");
398 std::shared_ptr<IntAttribute> A_flow3 = p->attribute<IntAttribute>("flow3");
399 int flowsize = 0;
400 if (A_flow1) flowsize++;
401 if (A_flow2) flowsize++;
402 if (A_flow3) flowsize++;
403 std::string flowss = " " + std::to_string(flowsize);
404 if (A_flow1) flowss += ( " 1 " + std::to_string(A_flow1->value()));
405 if (A_flow2) flowss += ( " 2 " + std::to_string(A_flow2->value()));
406 if (A_flow3) flowss += ( " 3 " + std::to_string(A_flow3->value()));
407 flowss += "\n";
408 write_string(flowss);
409 }
410 flush();
411}
412
413
414inline void WriterAsciiHepMC2::write_string(const std::string &str)
415{
416 // First let's check if string will fit into the buffer
417 if ( m_buffer + m_buffer_size > m_cursor + str.length() )
418 {
419 strncpy(m_cursor, str.data(), str.length());
420 m_cursor += str.length();
421 flush();
422 }
423 // If not, flush the buffer and write the string directly
424 else
425 {
426 forced_flush();
427 m_stream->write(str.data(), str.length());
428 }
429}
430
431
433{
434 if (!m_stream) return;
435 auto* ofs = dynamic_cast<std::ofstream*>(m_stream);
436 if (ofs && !ofs->is_open()) return;
437 forced_flush();
438 const std::string footer("HepMC::IO_GenEvent-END_EVENT_LISTING\n\n");
439 if (m_stream) m_stream->write(footer.data(),footer.length());
440 m_stream = nullptr;
441 if (ofs) ofs->close();
442}
443bool WriterAsciiHepMC2::failed() { return static_cast<bool>(m_file.rdstate()); }
444
445void WriterAsciiHepMC2::set_precision(const int& prec ) {
446 if (prec < 2 || prec > 24) return;
447 m_precision = prec;
448}
449
451 return m_precision;
452}
453
454void WriterAsciiHepMC2::set_buffer_size(const size_t& size ) {
455 if (m_buffer) return;
456 if (size < 1024) return;
457 m_buffer_size = size;
458}
459} // 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
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 WriterAsciiHepMC2.
Attribute that holds a real number as a double.
Definition Attribute.h:245
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 additional information about cross-section.
Stores event-related information.
Definition GenEvent.h:47
std::shared_ptr< T > attribute(const std::string &name, const int &id=0) const
Get attribute of type T.
Definition GenEvent.h:420
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 std::vector< double > & weights() const
Get event weight values as a vector.
Definition GenEvent.h:105
Stores additional information about Heavy Ion generator.
Definition GenHeavyIon.h:26
Stores additional information about PDFs.
Definition GenPdfInfo.h:32
Attribute that holds an Integer implemented as an int.
Definition Attribute.h:157
Attribute that holds an Integer implemented as a long int.
Definition Attribute.h:200
static std::string name(MomentumUnit u)
Get name of momentum unit.
Definition Units.h:56
Attribute that holds a vector of real numbers of type double.
Definition Attribute.h:1134
Attribute that holds a vector of integers of type int.
Definition Attribute.h:1039
Attribute that holds a vector of integers of type long int.
Definition Attribute.h:1087
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
void close() override
Close file stream.
int precision() const
Return output precision.
int m_precision
Output precision.
WriterAsciiHepMC2(const std::string &filename, std::shared_ptr< GenRunInfo > run=std::shared_ptr< GenRunInfo >())
Constructor.
void write_particle(const ConstGenParticlePtr &p, int second_field)
Write particle.
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.
unsigned long m_particle_counter
Used to set bar codes.
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.
void write_event(const GenEvent &evt) override
Write event to file.
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