10 #ifndef SRC_INCLUDE_SMASH_OUTPUTFORMATTER_H_
11 #define SRC_INCLUDE_SMASH_OUTPUTFORMATTER_H_
36 static constexpr std::optional<char>
separator{
' '};
65 constexpr
size_t kBufferSize = 13;
66 char buffer[kBufferSize];
67 const auto length = std::snprintf(buffer, kBufferSize,
"%g", value);
68 assert(
static_cast<size_t>(length) < kBufferSize);
70 return std::string{buffer, buffer + length};
88 constexpr
size_t kBufferSize = 16;
89 char buffer[kBufferSize];
90 const auto length = std::snprintf(buffer, kBufferSize,
"%.9g", value);
91 assert(
static_cast<size_t>(length) < kBufferSize);
93 return std::string{buffer, buffer + length};
112 using type = std::vector<char>;
115 static constexpr std::optional<char>
separator = std::nullopt;
154 return type(str.begin(), str.end());
164 template <
typename T>
166 type binary_data(
sizeof(T));
167 std::memcpy(binary_data.data(), &value,
sizeof(T));
190 template <
typename Converter,
191 std::enable_if_t<std::is_same_v<Converter, ToASCII> ||
192 std::is_same_v<Converter, ToBinary>,
213 if (quantity ==
"t") {
217 }
else if (quantity ==
"x") {
221 }
else if (quantity ==
"y") {
225 }
else if (quantity ==
"z") {
229 }
else if (quantity ==
"mass") {
233 }
else if (quantity ==
"p0") {
237 }
else if (quantity ==
"px") {
241 }
else if (quantity ==
"py") {
245 }
else if (quantity ==
"pz") {
249 }
else if (quantity ==
"pdg") {
253 }
else if (quantity ==
"ID" || quantity ==
"id") {
257 }
else if (quantity ==
"charge") {
261 }
else if (quantity ==
"ncoll") {
266 }
else if (quantity ==
"form_time") {
270 }
else if (quantity ==
"xsecfac") {
274 }
else if (quantity ==
"proc_id_origin") {
278 }
else if (quantity ==
"proc_type_origin") {
283 }
else if (quantity ==
"time_last_coll") {
288 }
else if (quantity ==
"pdg_mother1") {
292 }
else if (quantity ==
"pdg_mother2") {
296 }
else if (quantity ==
"baryon_number") {
300 }
else if (quantity ==
"strangeness") {
304 }
else if (quantity ==
"spin0") {
308 }
else if (quantity ==
"spinx") {
312 }
else if (quantity ==
"spiny") {
316 }
else if (quantity ==
"spinz") {
320 }
else if (quantity ==
"0") {
324 }
else if (quantity ==
"tau") {
328 }
else if (quantity ==
"eta" || quantity ==
"eta_s") {
332 }
else if (quantity ==
"mt") {
336 }
else if (quantity ==
"Rap" || quantity ==
"y_rap") {
341 }
else if (quantity ==
"perturbative_weight") {
367 std::size_t size = 0;
368 for (
const auto& getter :
getters_) {
369 const typename Converter::type tmp = getter(sample);
373 if (Converter::separator.has_value()) {
377 if (Converter::end_of_line.has_value()) {
393 typename Converter::type chunk{};
420 template <
class Range,
421 std::enable_if_t<std::is_same_v<Range, Particles> ||
422 std::is_same_v<Range, ParticleList>,
425 typename Converter::type chunk{};
426 if (particles.size() == 0)
447 typename Converter::type out{};
453 if constexpr (Converter::separator) {
455 out.push_back(*Converter::separator);
458 typename Converter::type name =
converter_.as_string(string_name);
459 out.insert(out.end(), name.begin(), name.end());
461 if constexpr (Converter::end_of_line) {
462 out.push_back(*Converter::end_of_line);
477 typename Converter::type out{};
483 if constexpr (Converter::separator) {
485 out.push_back(*Converter::separator);
489 out.insert(out.end(), unit.begin(), unit.end());
491 if constexpr (Converter::end_of_line) {
492 out.push_back(*Converter::end_of_line);
502 using std::invalid_argument::invalid_argument;
510 using std::invalid_argument::invalid_argument;
518 using std::invalid_argument::invalid_argument;
529 std::vector<std::function<
typename Converter::type(
const ParticleData&)>>
533 const std::map<std::string, std::string>
units_ = {
550 {
"proc_id_origin",
"none"},
551 {
"proc_type_origin",
"none"},
552 {
"time_last_coll",
"fm"},
553 {
"pdg_mother1",
"none"},
554 {
"pdg_mother2",
"none"},
555 {
"baryon_number",
"none"},
556 {
"strangeness",
"none"},
568 {
"perturbative_weight",
"none"}};
571 const std::vector<std::pair<std::string, std::string>>
aliases_ = {
572 {
"ID",
"id"}, {
"eta_s",
"eta"}, {
"y_rap",
"Rap"}};
577 throw std::invalid_argument(
578 "OutputFormatter: Empty quantities handed over to the class.");
580 std::string repeated{};
583 repeated +=
"'" + quantity +
"',";
586 if (!repeated.empty()) {
588 " please fix the configuration file.\n");
590 std::string unknown{};
592 if (
units_.count(quantity) == 0) {
593 unknown +=
"'" + quantity +
"',";
596 if (!unknown.empty()) {
598 " please fix the configuration file.\n");
600 for (
const auto& alias :
aliases_) {
601 const bool first_quantity_is_given =
604 const bool second_quantity_is_given =
607 if (first_quantity_is_given && second_quantity_is_given) {
609 "Both '" + alias.first +
"' and '" + alias.second +
610 "' cannot be provided in the \"Quantities\" key together. Please, "
611 "fix the configuration file.");
629 typename Converter::type& buffer)
const {
630 for (std::size_t i = 0; i <
getters_.size(); ++i) {
631 if constexpr (Converter::separator) {
633 buffer.push_back(*Converter::separator);
636 buffer.insert(buffer.end(), std::make_move_iterator(data.begin()),
637 std::make_move_iterator(data.end()));
639 if constexpr (Converter::end_of_line) {
640 buffer.push_back(*Converter::end_of_line);
691 template <
typename Converter,
class Range,
692 std::enable_if_t<std::is_same_v<Range, Particles> ||
693 std::is_same_v<Range, ParticleList>,
697 std::function<
void(
const typename Converter::type&)> write,
698 std::size_t max_buffer_bytes = 1'000'000'000) {
699 if (particles.size() == 0)
702 const std::size_t bytes_per_particle =
705 if (2.0 * bytes_per_particle > max_buffer_bytes) {
706 throw std::runtime_error(
707 "write_in_chunk_impl: the estimated size of a single particle line "
708 "exceeds half of the configured max_buffer_bytes.\n"
709 "This effectively means only one particle would fit per chunk, "
710 "which defeats the purpose of chunked writing.\n"
711 "Increase max_buffer_bytes to at least twice the particle line size "
712 "to use this function correctly.");
715 if (particles.size() * bytes_per_particle <= max_buffer_bytes) {
720 using Buffer =
typename Converter::type;
722 buffer.reserve(max_buffer_bytes);
723 std::size_t current_size = 0;
725 for (
const auto& particle : particles) {
727 const std::size_t line_size = line.size();
728 if (current_size + line_size > max_buffer_bytes) {
733 buffer.insert(buffer.end(), std::make_move_iterator(line.begin()),
734 std::make_move_iterator(line.end()));
735 current_size += line_size;
738 if (!buffer.empty()) {
751 template <
typename Converter,
class Range,
752 std::enable_if_t<std::is_same_v<Range, Particles> ||
753 std::is_same_v<Range, ParticleList>,
757 std::function<
void(
const typename Converter::type&)> write) {
ParticleData contains the dynamic information of a certain particle.
PdgCode pdgcode() const
Get the pdgcode of the particle.
const ParticleType & type() const
Get the type of the particle.
double xsec_scaling_factor(double delta_time=0.) const
Return the cross section scaling factor at a given time.
double hyperbolic_time() const
Particle (hyperbolic time)
const FourVector & momentum() const
Get the particle's 4-momentum.
double formation_time() const
Get the absolute formation time of the particle.
double effective_mass() const
Get the particle's effective mass.
int32_t id() const
Get the id of the particle.
const FourVector & spin_vector() const
Get the mean spin 4-vector (Pauli–Lubanski vector) of the particle (const reference,...
double perturbative_weight() const
Get the perturbative weight.
HistoryData get_history() const
Get history information.
double rapidity() const
Particle momentum rapidity .
double transverse_mass() const
Particle .
double spatial_rapidity() const
Particle spacetime rapidity .
const FourVector & position() const
Get the particle's position in Minkowski space.
int32_t charge() const
The charge of the particle.
int baryon_number() const
int32_t get_decimal() const
Structure to convert a given value into binary format, such that all methods return a std::vector<cha...
type as_binary_data(T value) const
Template method to convert numbers into binary format.
type as_double(double value) const
Converts a double to binary format.
type as_precise_double(double value) const
Converts a double to binary format, intended for precise representation.
static constexpr std::optional< char > end_of_line
Endline char is not needed for Binary format.
static constexpr std::optional< char > separator
separator char is not needed for Binary format
type as_integer(int32_t value) const
Converts an integer to binary format.
std::vector< char > type
Return type of this converter.
type as_string(const std::string &str) const
Converts a string to binary format.
void write_in_chunk_impl(const Range &particles, const OutputFormatter< Converter > &formatter, std::function< void(const typename Converter::type &)> write, std::size_t max_buffer_bytes=1 '000 '000 '000)
Writes particle data in multiple chunks if the total buffer size exceeds a predefined maximum.
void write_in_chunk(const Range &particles, const OutputFormatter< Converter > &formatter, std::function< void(const typename Converter::type &)> write)
User-facing wrapper for chunked particle writing.
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
double time_last_collision
Time of the last action (excluding walls), time of kinetic freeze_out for HBT analysis this time shou...
int32_t id_process
id of the last action
PdgCode p2
PdgCode of the second parent particles.
PdgCode p1
PdgCode of the first parent particles.
int32_t collisions_per_particle
Collision counter per particle, zero only for initially present particles.
ProcessType process_type
type of the last action
Structure to convert a given value into ASCII format, such that all methods return a std::string.
type as_integer(int value) const
Converts an integer.
std::string type
Return type of this converter.
static constexpr std::optional< char > end_of_line
Character used to mark the end of a record in ASCII output.
static constexpr std::optional< char > separator
Character used to separate fields in ASCII output.
type as_double(double value)
Converts a double with 6 digits of precision.
type as_precise_double(double value)
Converts a double with 9 digits of precision.
type as_string(const std::string &str) const
Because ToASCII converts into strings, this simply returns the string itself.