Version: SMASH-3.3
smash::OutputFormatter< Converter, > Class Template Reference

#include <outputformatter.h>

template<typename Converter, std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
class smash::OutputFormatter< Converter, >

A general-purpose formatter for output, supporting both ASCII and binary formats.

This class allows the output of particle data in a flexible and configurable manner, either in human-readable ASCII format or compact binary format. It uses a template parameter Converter to determine the desired output format, which must conform to the interface of either ToASCII or ToBinary.

New quantities can be added for output by:

  1. Adding their corresponding getter to the constructor, which extracts the value from a ParticleData instance.
  2. Adding the proper key-value pair to the units_ map, specifying the unit of the quantity.
Template Parameters
ConverterThe desired output format. At the moment it must be either ToASCII or ToBinary.

Definition at line 194 of file outputformatter.h.

Classes

struct  AliasesQuantity
 Thrown when the synonym quantities are used. More...
 
struct  RepeatedQuantity
 Thrown when the same quantity is repeated. More...
 
struct  UnknownQuantity
 Thrown when a not existing quantity is used. More...
 

Public Member Functions

 OutputFormatter (const std::vector< std::string > &in_quantities)
 Creates the formatter. More...
 
std::size_t compute_single_size (const ParticleData &sample) const
 Computes and returns the total size of the formatted representation of a single particle using all registered getters. More...
 
Converter::type single_particle_data (const ParticleData &p) const
 Produces a line of data representing a single particle suitable for writing to an output file. More...
 
template<class Range , std::enable_if_t< std::is_same_v< Range, Particles >||std::is_same_v< Range, ParticleList >, bool > = true>
Converter::type particles_data_chunk (const Range &particles) const
 Builds multiple particle lines for a range of particles by appending the Converter::type representation of each particle into a single buffer. More...
 
Converter::type quantities_line () const
 Produces the line with quantities for the header of the output file. More...
 
Converter::type unit_line () const
 Produces the line with units for the header of the output file. More...
 

Private Member Functions

void validate_quantities ()
 Checks whether the quantities requested are known and unique. More...
 
void append_to_buffer (const ParticleData &particle, typename Converter::type &buffer) const
 Appends the Converter::type representation of a single particle to the provided buffer. More...
 

Private Attributes

Converter converter_ {}
 Member to convert data into the correct output format. More...
 
std::vector< std::string > quantities_ {}
 List of quantities to be written. More...
 
std::vector< std::function< typename Converter::type(const ParticleData &)> > getters_ {}
 List of getters to extract output data from the ParticleData object. More...
 
const std::map< std::string, std::string > units_
 Map with known quantities and corresponding units. More...
 
const std::vector< std::pair< std::string, std::string > > aliases_
 Map with known quantities and corresponding units. More...
 

Constructor & Destructor Documentation

◆ OutputFormatter()

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
smash::OutputFormatter< Converter, >::OutputFormatter ( const std::vector< std::string > &  in_quantities)
inlineexplicit

Creates the formatter.

This reduces the number of literal strings flying around in the codebase, and since this is called only once per output file, in the beginning of the run, there is almost no efficiency lost compared to having fixed strings.

Parameters
[in]in_quantitieslist of quantities to be output.
Exceptions
std::invalid_argumentif the list of quantities is empty
std::invalid_argumentif unknown quantities exist in the list
std::invalid_argumentif incompatible quantities exist in the list
std::invalid_argumentif there are repeated quantities

Definition at line 209 of file outputformatter.h.

210  : quantities_(in_quantities) {
212  for (const std::string& quantity : quantities_) {
213  if (quantity == "t") {
214  getters_.push_back([this](const ParticleData& in) {
215  return this->converter_.as_double(in.position()[0]);
216  });
217  } else if (quantity == "x") {
218  getters_.push_back([this](const ParticleData& in) {
219  return this->converter_.as_double(in.position()[1]);
220  });
221  } else if (quantity == "y") {
222  getters_.push_back([this](const ParticleData& in) {
223  return this->converter_.as_double(in.position()[2]);
224  });
225  } else if (quantity == "z") {
226  getters_.push_back([this](const ParticleData& in) {
227  return this->converter_.as_double(in.position()[3]);
228  });
229  } else if (quantity == "mass") {
230  getters_.push_back([this](const ParticleData& in) {
231  return this->converter_.as_double(in.effective_mass());
232  });
233  } else if (quantity == "p0") {
234  getters_.push_back([this](const ParticleData& in) {
235  return this->converter_.as_precise_double(in.momentum()[0]);
236  });
237  } else if (quantity == "px") {
238  getters_.push_back([this](const ParticleData& in) {
239  return this->converter_.as_precise_double(in.momentum()[1]);
240  });
241  } else if (quantity == "py") {
242  getters_.push_back([this](const ParticleData& in) {
243  return this->converter_.as_precise_double(in.momentum()[2]);
244  });
245  } else if (quantity == "pz") {
246  getters_.push_back([this](const ParticleData& in) {
247  return this->converter_.as_precise_double(in.momentum()[3]);
248  });
249  } else if (quantity == "pdg") {
250  getters_.push_back([this](const ParticleData& in) {
251  return this->converter_.as_integer(in.pdgcode().get_decimal());
252  });
253  } else if (quantity == "ID" || quantity == "id") {
254  getters_.push_back([this](const ParticleData& in) {
255  return this->converter_.as_integer(in.id());
256  });
257  } else if (quantity == "charge") {
258  getters_.push_back([this](const ParticleData& in) {
259  return this->converter_.as_integer(in.type().charge());
260  });
261  } else if (quantity == "ncoll") {
262  getters_.push_back([this](const ParticleData& in) {
263  return this->converter_.as_integer(
264  in.get_history().collisions_per_particle);
265  });
266  } else if (quantity == "form_time") {
267  getters_.push_back([this](const ParticleData& in) {
268  return this->converter_.as_double(in.formation_time());
269  });
270  } else if (quantity == "xsecfac") {
271  getters_.push_back([this](const ParticleData& in) {
272  return this->converter_.as_double(in.xsec_scaling_factor());
273  });
274  } else if (quantity == "proc_id_origin") {
275  getters_.push_back([this](const ParticleData& in) {
276  return this->converter_.as_integer(in.get_history().id_process);
277  });
278  } else if (quantity == "proc_type_origin") {
279  getters_.push_back([this](const ParticleData& in) {
280  return this->converter_.as_integer(
281  static_cast<int>(in.get_history().process_type));
282  });
283  } else if (quantity == "time_last_coll") {
284  getters_.push_back([this](const ParticleData& in) {
285  return this->converter_.as_double(
286  in.get_history().time_last_collision);
287  });
288  } else if (quantity == "pdg_mother1") {
289  getters_.push_back([this](const ParticleData& in) {
290  return this->converter_.as_integer(in.get_history().p1.get_decimal());
291  });
292  } else if (quantity == "pdg_mother2") {
293  getters_.push_back([this](const ParticleData& in) {
294  return this->converter_.as_integer(in.get_history().p2.get_decimal());
295  });
296  } else if (quantity == "baryon_number") {
297  getters_.push_back([this](const ParticleData& in) {
298  return this->converter_.as_integer(in.pdgcode().baryon_number());
299  });
300  } else if (quantity == "strangeness") {
301  getters_.push_back([this](const ParticleData& in) {
302  return this->converter_.as_integer(in.pdgcode().strangeness());
303  });
304  } else if (quantity == "spin0") {
305  getters_.push_back([this](const ParticleData& in) {
306  return this->converter_.as_double(in.spin_vector()[0]);
307  });
308  } else if (quantity == "spinx") {
309  getters_.push_back([this](const ParticleData& in) {
310  return this->converter_.as_double(in.spin_vector()[1]);
311  });
312  } else if (quantity == "spiny") {
313  getters_.push_back([this](const ParticleData& in) {
314  return this->converter_.as_double(in.spin_vector()[2]);
315  });
316  } else if (quantity == "spinz") {
317  getters_.push_back([this](const ParticleData& in) {
318  return this->converter_.as_double(in.spin_vector()[3]);
319  });
320  } else if (quantity == "0") { // for OSCAR1999
321  getters_.push_back([this]([[maybe_unused]] const ParticleData& in) {
322  return this->converter_.as_integer(0);
323  });
324  } else if (quantity == "tau") {
325  getters_.push_back([this](const ParticleData& in) {
326  return this->converter_.as_double(in.hyperbolic_time());
327  });
328  } else if (quantity == "eta" || quantity == "eta_s") {
329  getters_.push_back([this](const ParticleData& in) {
330  return this->converter_.as_double(in.spatial_rapidity());
331  });
332  } else if (quantity == "mt") {
333  getters_.push_back([this](const ParticleData& in) {
334  return this->converter_.as_double(in.transverse_mass());
335  });
336  } else if (quantity == "Rap" || quantity == "y_rap") {
337  // "Rap" is used for compatibility with vHLLE
338  getters_.push_back([this](const ParticleData& in) {
339  return this->converter_.as_double(in.rapidity());
340  });
341  } else if (quantity == "perturbative_weight") {
342  getters_.push_back([this](const ParticleData& in) {
343  return this->converter_.as_double(in.perturbative_weight());
344  });
345  }
346  }
347  }
Converter converter_
Member to convert data into the correct output format.
std::vector< std::string > quantities_
List of quantities to be written.
std::vector< std::function< typename Converter::type(const ParticleData &)> > getters_
List of getters to extract output data from the ParticleData object.
void validate_quantities()
Checks whether the quantities requested are known and unique.

Member Function Documentation

◆ compute_single_size()

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
std::size_t smash::OutputFormatter< Converter, >::compute_single_size ( const ParticleData sample) const
inline

Computes and returns the total size of the formatted representation of a single particle using all registered getters.

The total size consists of:

  • the sum of the sizes of all field strings (from each getter),
  • (n - 1) separator characters if a separator is defined, since separators appear only between fields, not after the last one,
  • one end-of-line character if an end-of-line marker is defined.
Parameters
[in]sampleA representative particle used to compute the size.
Returns
Total size of the formatted representation of one particle.

Definition at line 362 of file outputformatter.h.

362  {
363  const std::size_t n = getters_.size();
364  if (n == 0) {
365  return 0;
366  }
367  std::size_t size = 0;
368  for (const auto& getter : getters_) {
369  const typename Converter::type tmp = getter(sample);
370  size += tmp.size();
371  }
372 
373  if (Converter::separator.has_value()) {
374  size += (n - 1);
375  }
376 
377  if (Converter::end_of_line.has_value()) {
378  size += 1;
379  }
380 
381  return size;
382  }
constexpr int n
Neutron.

◆ single_particle_data()

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
Converter::type smash::OutputFormatter< Converter, >::single_particle_data ( const ParticleData p) const
inline

Produces a line of data representing a single particle suitable for writing to an output file.

Parameters
[in]pParticle whose information is to be written.
Returns
A buffer containing the formatted data.
See also
append_to_buffer

Definition at line 392 of file outputformatter.h.

392  {
393  typename Converter::type chunk{};
394  append_to_buffer(p, chunk);
395  return chunk;
396  }
void append_to_buffer(const ParticleData &particle, typename Converter::type &buffer) const
Appends the Converter::type representation of a single particle to the provided buffer.
constexpr int p
Proton.

◆ particles_data_chunk()

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
template<class Range , std::enable_if_t< std::is_same_v< Range, Particles >||std::is_same_v< Range, ParticleList >, bool > = true>
Converter::type smash::OutputFormatter< Converter, >::particles_data_chunk ( const Range &  particles) const
inline

Builds multiple particle lines for a range of particles by appending the Converter::type representation of each particle into a single buffer.

The resulting buffer reflects exactly what the Converter defines( per-record separators and end-of-line markers, if any). No additional formatting is applied beyond what the Converter specifies.

Template Parameters
RangeContainer type — constrained to Particles or ParticleList.
Parameters
[in]particlesContainer of particles whose data should be formatted and added to the buffer
Returns
Converter::type A buffer containing the concatenated representation of all particles in the block.
Note
Capacity is reserved using a size estimate based on the first element.
See also
append_to_buffer
Returns
Converter::type

Definition at line 424 of file outputformatter.h.

424  {
425  typename Converter::type chunk{};
426  if (particles.size() == 0)
427  return chunk;
428 
429  chunk.reserve(particles.size() * compute_single_size(particles.front()));
430 
431  for (const ParticleData& p : particles) {
432  append_to_buffer(p, chunk);
433  }
434  return chunk;
435  }
std::size_t compute_single_size(const ParticleData &sample) const
Computes and returns the total size of the formatted representation of a single particle using all re...

◆ quantities_line()

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
Converter::type smash::OutputFormatter< Converter, >::quantities_line ( ) const
inline

Produces the line with quantities for the header of the output file.

Appends each quantity name to the output buffer, separating them by the separator character if it is defined in the Converter. End of line character is added last if defined.

Returns
Converter::type

Definition at line 446 of file outputformatter.h.

446  {
447  typename Converter::type out{};
448 
449  // Educated size guess to reduce the number of reallocations in push_backs:
450  out.reserve(quantities_.size() * 5);
451 
452  for (const auto& string_name : quantities_) {
453  if constexpr (Converter::separator) {
454  if (!out.empty()) {
455  out.push_back(*Converter::separator);
456  }
457  }
458  typename Converter::type name = converter_.as_string(string_name);
459  out.insert(out.end(), name.begin(), name.end());
460  }
461  if constexpr (Converter::end_of_line) {
462  out.push_back(*Converter::end_of_line);
463  }
464  return out;
465  }

◆ unit_line()

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
Converter::type smash::OutputFormatter< Converter, >::unit_line ( ) const
inline

Produces the line with units for the header of the output file.

Looks up each quantity’s unit in the units_ map and appends it to the output buffer. Each unit is separated by the separator character if defined. End of line character is added last if defined.

Returns
Converter::type

Definition at line 476 of file outputformatter.h.

476  {
477  typename Converter::type out{};
478 
479  // Educated size guess to reduce the number of reallocations in push_backs:
480  out.reserve(quantities_.size() * 5);
481 
482  for (const auto& key : quantities_) {
483  if constexpr (Converter::separator) {
484  if (!out.empty()) {
485  out.push_back(*Converter::separator);
486  }
487  }
488  const auto& unit = converter_.as_string(units_.at(key));
489  out.insert(out.end(), unit.begin(), unit.end());
490  }
491  if constexpr (Converter::end_of_line) {
492  out.push_back(*Converter::end_of_line);
493  }
494  return out;
495  }
const std::map< std::string, std::string > units_
Map with known quantities and corresponding units.

◆ validate_quantities()

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
void smash::OutputFormatter< Converter, >::validate_quantities ( )
inlineprivate

Checks whether the quantities requested are known and unique.

Definition at line 575 of file outputformatter.h.

575  {
576  if (quantities_.empty()) {
577  throw std::invalid_argument(
578  "OutputFormatter: Empty quantities handed over to the class.");
579  }
580  std::string repeated{};
581  for (const std::string& quantity : quantities_) {
582  if (std::count(quantities_.begin(), quantities_.end(), quantity) > 1) {
583  repeated += "'" + quantity + "',";
584  }
585  }
586  if (!repeated.empty()) {
587  throw RepeatedQuantity("Repeated \"Quantities\": " + repeated +
588  " please fix the configuration file.\n");
589  }
590  std::string unknown{};
591  for (const std::string& quantity : quantities_) {
592  if (units_.count(quantity) == 0) {
593  unknown += "'" + quantity + "',";
594  }
595  }
596  if (!unknown.empty()) {
597  throw UnknownQuantity("Unknown \"Quantities\": " + unknown +
598  " please fix the configuration file.\n");
599  }
600  for (const auto& alias : aliases_) {
601  const bool first_quantity_is_given =
602  std::find(quantities_.begin(), quantities_.end(), alias.first) !=
603  quantities_.end();
604  const bool second_quantity_is_given =
605  std::find(quantities_.begin(), quantities_.end(), alias.second) !=
606  quantities_.end();
607  if (first_quantity_is_given && second_quantity_is_given) {
608  throw AliasesQuantity(
609  "Both '" + alias.first + "' and '" + alias.second +
610  "' cannot be provided in the \"Quantities\" key together. Please, "
611  "fix the configuration file.");
612  }
613  }
614  }
const std::vector< std::pair< std::string, std::string > > aliases_
Map with known quantities and corresponding units.

◆ append_to_buffer()

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
void smash::OutputFormatter< Converter, >::append_to_buffer ( const ParticleData particle,
typename Converter::type &  buffer 
) const
inlineprivate

Appends the Converter::type representation of a single particle to the provided buffer.

The buffer is used exactly as provided by the caller; no assumptions or modifications are made to its initial state or capacity.

Parameters
[in]particleParticle whose information is to be appended.
[out]bufferDestination buffer to which the converted data is appended.

Definition at line 628 of file outputformatter.h.

629  {
630  for (std::size_t i = 0; i < getters_.size(); ++i) {
631  if constexpr (Converter::separator) {
632  if (i > 0)
633  buffer.push_back(*Converter::separator);
634  }
635  auto data = getters_[i](particle);
636  buffer.insert(buffer.end(), std::make_move_iterator(data.begin()),
637  std::make_move_iterator(data.end()));
638  }
639  if constexpr (Converter::end_of_line) {
640  buffer.push_back(*Converter::end_of_line);
641  }
642  }

Member Data Documentation

◆ converter_

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
Converter smash::OutputFormatter< Converter, >::converter_ {}
private

Member to convert data into the correct output format.

Definition at line 523 of file outputformatter.h.

◆ quantities_

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
std::vector<std::string> smash::OutputFormatter< Converter, >::quantities_ {}
private

List of quantities to be written.

Definition at line 526 of file outputformatter.h.

◆ getters_

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
std::vector<std::function<typename Converter::type(const ParticleData&)> > smash::OutputFormatter< Converter, >::getters_ {}
private

List of getters to extract output data from the ParticleData object.

Definition at line 530 of file outputformatter.h.

◆ units_

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
const std::map<std::string, std::string> smash::OutputFormatter< Converter, >::units_
private

Map with known quantities and corresponding units.

Definition at line 533 of file outputformatter.h.

◆ aliases_

template<typename Converter , std::enable_if_t< std::is_same_v< Converter, ToASCII >||std::is_same_v< Converter, ToBinary >, bool > = true>
const std::vector<std::pair<std::string, std::string> > smash::OutputFormatter< Converter, >::aliases_
private
Initial value:
= {
{"ID", "id"}, {"eta_s", "eta"}, {"y_rap", "Rap"}}

Map with known quantities and corresponding units.

Definition at line 571 of file outputformatter.h.


The documentation for this class was generated from the following file: