Version: SMASH-3.3
oscaroutput.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2025
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/oscaroutput.h"
11 
12 #include <filesystem>
13 #include <string>
14 
15 #include "smash/action.h"
16 #include "smash/clock.h"
17 #include "smash/config.h"
19 
20 namespace smash {
21 
22 template <OscarOutputFormat Format, int Contents>
24  const std::filesystem::path &path, const std::string &name,
25  const std::vector<std::string> quantities)
26  : OutputInterface(name),
27  file_{path / (name + ((Format == ASCII) ? ".dat" : ".oscar") +
28  ((Format == OscarFormat1999) ? "1999" : "")),
29  "w"},
30  formatter_{Format == ASCII ? quantities
31  : (Format == OscarFormat2013)
32  ? OutputDefaultQuantities::oscar2013
33  : (Format == OscarFormat2013Extended)
34  ? OutputDefaultQuantities::oscar2013extended
35  : OutputDefaultQuantities::oscar1999} {
85  if (Format != ASCII && !quantities.empty()) {
86  throw std::logic_error(
87  "Non-empty Quantities given alongside format other than ASCII.");
88  }
89  std::string format_name;
90  if (Format == ASCII) {
91  format_name = "ASCII";
92  } else if (Format == OscarFormat2013) {
93  format_name = "OSCAR2013";
94  } else if (Format == OscarFormat2013Extended) {
95  format_name = "OSCAR2013Extended";
96  } else {
97  format_name = "OSC1999A";
98  }
99  if (Format == ASCII || Format == OscarFormat2013 ||
100  Format == OscarFormat2013Extended) {
101  std::fprintf(file_.get(), "#!%s %s %s", format_name.c_str(), name.c_str(),
102  formatter_.quantities_line().c_str());
103  std::fprintf(file_.get(), "# Units: %s", formatter_.unit_line().c_str());
104  std::fprintf(file_.get(), "# %s\n", SMASH_VERSION);
105  } else {
106  const std::string &oscar_name =
107  name == "particle_lists" ? "final_id_p_x" : name;
108  // This is necessary because OSCAR1999A requires
109  // this particular string for particle output.
110 
111  std::fprintf(file_.get(), "# %s\n# %s\n# %s\n", format_name.c_str(),
112  oscar_name.c_str(), SMASH_VERSION);
113  std::fprintf(file_.get(), "# Block format:\n");
114  if (oscar_name == "full_event_history") {
115  std::fprintf(file_.get(),
116  "# nin nout density tot_weight part_weight proc_type\n");
117  } else {
118  std::fprintf(file_.get(), "# nin nout event_number ensemble_number\n");
119  }
120  std::fprintf(file_.get(), "# %s", formatter_.quantities_line().c_str());
121  std::fprintf(
122  file_.get(),
123  "# End of event: 0 0 event_number ensemble_number impact_parameter\n");
124  std::fprintf(file_.get(), "#\n");
125  }
126 }
127 
128 template <OscarOutputFormat Format, int Contents>
129 inline void OscarOutput<Format, Contents>::write(const Particles &particles) {
130  write_in_chunk<ToASCII>(
131  particles, formatter_,
132  [this](const ToASCII::type &buf) { this->write(buf); });
133 }
134 
135 template <OscarOutputFormat Format, int Contents>
137  const EventLabel &event_label,
138  const EventInfo &) {
139  // We do not want the inital particle list or number to be printed in case of
140  // IC output
141  if (Contents & OscarAtEventstart && !(Contents & OscarParticlesIC)) {
142  if (Format == ASCII || Format == OscarFormat2013 ||
143  Format == OscarFormat2013Extended) {
144  std::fprintf(file_.get(), "# event %i ensemble %i in %zu\n",
145  event_label.event_number, event_label.ensemble_number,
146  particles.size());
147  } else {
148  /* OSCAR line prefix : initial particles; final particles; event id
149  * First block of an event: initial = 0, final = number of particles
150  */
151  const size_t zero = 0;
152  std::fprintf(file_.get(), "%zu %zu %i %i\n", zero, particles.size(),
153  event_label.event_number, event_label.ensemble_number);
154  }
155  write(particles);
156  } else if (Contents & OscarParticlesIC) {
157  if (Format == ASCII || Format == OscarFormat2013 ||
158  Format == OscarFormat2013Extended) {
159  std::fprintf(file_.get(), "# event %i ensemble %i start\n",
160  event_label.event_number, event_label.ensemble_number);
161  } else if (Format == OscarFormat1999) {
162  const size_t zero = 0;
163  std::fprintf(file_.get(), "%zu %zu %i %i\n", zero, zero,
164  event_label.event_number, event_label.ensemble_number);
165  }
166  }
167 }
168 
169 template <OscarOutputFormat Format, int Contents>
171  const EventLabel &event_label,
172  const EventInfo &event) {
173  if (Format == ASCII || Format == OscarFormat2013 ||
174  Format == OscarFormat2013Extended) {
175  if (Contents & OscarParticlesAtEventend ||
176  (Contents & OscarParticlesAtEventendIfNotEmpty && !event.empty_event)) {
177  std::fprintf(file_.get(), "# event %i ensemble %i out %zu\n",
178  event_label.event_number, event_label.ensemble_number,
179  particles.size());
180  write(particles);
181  }
182  // Comment end of an event
183  if (!(Contents & OscarParticlesIC)) {
184  const char *empty_event_str = event.empty_event ? "no" : "yes";
185  std::fprintf(file_.get(),
186  "# event %i ensemble %i end 0 impact %7.3f "
187  "scattering_projectile_target %s\n",
188  event_label.event_number, event_label.ensemble_number,
189  event.impact_parameter, empty_event_str);
190  } else {
191  std::fprintf(file_.get(), "# event %i ensemble %i end\n",
192  event_label.event_number, event_label.ensemble_number);
193  }
194  } else {
195  /* OSCAR line prefix : initial particles; final particles; event id
196  * Last block of an event: initial = number of particles, final = 0
197  * Block ends with null interaction. */
198  const size_t zero = 0;
199  if (Contents & OscarParticlesAtEventend ||
200  (Contents & OscarParticlesAtEventendIfNotEmpty && !event.empty_event)) {
201  std::fprintf(file_.get(), "%zu %zu %i %i\n", particles.size(), zero,
202  event_label.event_number, event_label.ensemble_number);
203  write(particles);
204  }
205  // Null interaction marks the end of an event
206  std::fprintf(file_.get(), "%zu %zu %i %i %7.3f\n", zero, zero,
207  event_label.event_number, event_label.ensemble_number,
208  event.impact_parameter);
209  }
210  // Flush to disk
211  std::fflush(file_.get());
212 }
213 
214 template <OscarOutputFormat Format, int Contents>
216  const double density) {
217  if (Contents & OscarInteractions) {
218  if (Format == ASCII || Format == OscarFormat2013 ||
219  Format == OscarFormat2013Extended) {
220  std::fprintf(file_.get(),
221  "# interaction in %zu out %zu rho %12.7f weight %12.7g"
222  " partial %12.7f type %5i\n",
223  action.incoming_particles().size(),
224  action.outgoing_particles().size(), density,
225  action.get_total_weight(), action.get_partial_weight(),
226  static_cast<int>(action.get_type()));
227  } else {
228  /* OSCAR line prefix : initial final
229  * particle creation: 0 1
230  * particle 2<->2 collision: 2 2
231  * resonance formation: 2 1
232  * resonance decay: 1 2
233  * etc.*/
234  std::fprintf(file_.get(), "%zu %zu %12.7f %12.7f %12.7f %5i\n",
235  action.incoming_particles().size(),
236  action.outgoing_particles().size(), density,
237  action.get_total_weight(), action.get_partial_weight(),
238  static_cast<int>(action.get_type()));
239  }
240  for (const auto &p : action.incoming_particles()) {
241  write_particledata(p);
242  }
243  for (const auto &p : action.outgoing_particles()) {
244  write_particledata(p);
245  }
246  } else if (Contents & OscarParticlesIC) {
247  for (const auto &p : action.incoming_particles()) {
248  write_particledata(p);
249  }
250  }
251 }
252 
253 template <OscarOutputFormat Format, int Contents>
255  const Particles &particles, const std::unique_ptr<Clock> &,
256  const DensityParameters &, const EventLabel &event_label,
257  const EventInfo &) {
258  if (Contents & OscarTimesteps) {
259  if (Format == ASCII || Format == OscarFormat2013 ||
260  Format == OscarFormat2013Extended) {
261  std::fprintf(file_.get(), "# event %i ensemble %i out %zu\n",
262  event_label.event_number, event_label.ensemble_number,
263  particles.size());
264  } else {
265  const size_t zero = 0;
266  std::fprintf(file_.get(), "%zu %zu %i %i\n", particles.size(), zero,
267  event_label.event_number, event_label.ensemble_number);
268  }
269  write(particles);
270  }
271 }
272 
862 template <OscarOutputFormat Format, int Contents>
864  const ParticleData &data) {
865  std::fprintf(file_.get(), "%s",
866  formatter_.single_particle_data(data).c_str());
867 }
868 
869 template <OscarOutputFormat Format, int Contents>
871  std::fprintf(file_.get(), "%s", buffer.c_str());
872 }
873 
874 namespace {
889 template <int Contents>
890 std::unique_ptr<OutputInterface> create_selected_format(
891  const std::filesystem::path &path, const std::string &name,
892  bool modern_format, bool extended_format, bool custom_format,
893  const std::vector<std::string> &quantities) {
894  if (custom_format) {
895  return std::make_unique<OscarOutput<ASCII, Contents>>(path, name,
896  quantities);
897  } else {
898  if (modern_format && extended_format) {
899  return std::make_unique<OscarOutput<OscarFormat2013Extended, Contents>>(
900  path, name);
901  } else if (modern_format && !extended_format) {
902  return std::make_unique<OscarOutput<OscarFormat2013, Contents>>(path,
903  name);
904  } else if (!modern_format && !extended_format) {
905  return std::make_unique<OscarOutput<OscarFormat1999, Contents>>(path,
906  name);
907  } else {
908  // Only remaining possibility: (!modern_format && extended_format)
909  logg[LOutput].warn() << "There is no extended Oscar1999 format, creating "
910  "a regular Oscar1999 output instead.";
911  return std::make_unique<OscarOutput<OscarFormat1999, Contents>>(path,
912  name);
913  }
914  }
915 }
916 } // unnamed namespace
917 
918 std::unique_ptr<OutputInterface> create_oscar_output(
919  const std::string &format, const std::string &content,
920  const std::filesystem::path &path, const OutputParameters &out_par) {
921  if (format != "Oscar2013" && format != "Oscar1999" && format != "ASCII") {
922  throw std::invalid_argument("Creating Oscar output: unknown format");
923  }
924  const bool modern_format = (format == "Oscar2013");
925  const bool custom_format = (format == "ASCII");
926  const auto &quantities = custom_format ? out_par.quantities.at(content)
927  : std::vector<std::string>{};
928 
929  if (content == "Particles") {
930  if (out_par.part_only_final == OutputOnlyFinal::Yes) {
931  return create_selected_format<OscarParticlesAtEventend>(
932  path, "particle_lists", modern_format, out_par.part_extended,
933  custom_format, quantities);
934  } else if (out_par.part_only_final == OutputOnlyFinal::IfNotEmpty) {
935  return create_selected_format<OscarParticlesAtEventendIfNotEmpty>(
936  path, "particle_lists", modern_format, out_par.part_extended,
937  custom_format, quantities);
938  } else { // out_par.part_only_final == OutputOnlyFinal::No
941  path, "particle_lists", modern_format, out_par.part_extended,
942  custom_format, quantities);
943  }
944  } else if (content == "Collisions") {
945  if (out_par.coll_printstartend) {
948  path, "full_event_history", modern_format, out_par.coll_extended,
949  custom_format, quantities);
950  } else {
951  return create_selected_format<OscarInteractions>(
952  path, "full_event_history", modern_format, out_par.coll_extended,
953  custom_format, quantities);
954  }
955  } else if (content == "Dileptons") {
956  return create_selected_format<OscarInteractions>(
957  path, "Dileptons", modern_format, out_par.dil_extended, custom_format,
958  quantities);
959  } else if (content == "Photons") {
960  return create_selected_format<OscarInteractions>(
961  path, "Photons", modern_format, out_par.photons_extended, custom_format,
962  quantities);
963  } else if (content == "Initial_Conditions") {
964  return create_selected_format<OscarParticlesIC | OscarAtEventstart>(
965  path, "SMASH_IC", modern_format, out_par.ic_extended, custom_format,
966  quantities);
967  }
968 
969  throw std::invalid_argument("Create_oscar_output got unknown content.");
970 }
971 
972 } // namespace smash
Action is the base class for a generic process that takes a number of incoming particles and transfor...
Definition: action.h:35
virtual ProcessType get_type() const
Get the process type.
Definition: action.h:131
virtual double get_total_weight() const =0
Return the total weight value, which is mainly used for the weight output entry.
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
Definition: action.cc:58
virtual double get_partial_weight() const =0
Return the specific weight for the chosen outgoing channel, which is mainly used for the partial weig...
const ParticleList & outgoing_particles() const
Get the list of particles that resulted from the action.
Definition: action.h:247
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:92
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
size_t size() const
Definition: particles.h:87
@ IfNotEmpty
Print only final-state particles, and those only if the event is not empty.
@ Yes
Print only final-state particles.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:40
FormattingHelper< T > format(const T &value, const char *unit, int width=-1, int precision=-1)
Acts as a stream modifier for std::ostream to output an object with an optional suffix string and wit...
Definition: logging.h:217
OscarOutput(const std::filesystem::path &path, const std::string &name, const std::vector< std::string > quantities={})
Create oscar output.
std::unique_ptr< OutputInterface > create_oscar_output(const std::string &format, const std::string &content, const std::filesystem::path &path, const OutputParameters &out_par)
Definition: oscaroutput.cc:918
@ OscarParticlesAtEventend
store the state at the end of each event (at_eventend)
Definition: oscaroutput.h:53
@ OscarParticlesAtEventendIfNotEmpty
store the state at the end of each event if it is not empty (at_eventend)
Definition: oscaroutput.h:55
@ OscarAtEventstart
store the state at the start of each event (at_eventstart)
Definition: oscaroutput.h:51
@ OscarInteractions
store interaction information (write_interaction)
Definition: oscaroutput.h:47
@ OscarParticlesIC
store the particles that are removed on the hypersurface
Definition: oscaroutput.h:57
@ OscarTimesteps
store the state after N timesteps (after_Nth_timestep)
Definition: oscaroutput.h:49
@ OscarFormat1999
Definition: oscaroutput.h:34
@ OscarFormat2013Extended
Definition: oscaroutput.h:33
@ ASCII
Definition: oscaroutput.h:35
@ OscarFormat2013
Definition: oscaroutput.h:32
std::unique_ptr< OutputInterface > create_selected_format(const std::filesystem::path &path, const std::string &name, bool modern_format, bool extended_format, bool custom_format, const std::vector< std::string > &quantities)
Helper function that creates the oscar output with the format selected by create_oscar_output.
Definition: oscaroutput.cc:890
constexpr int p
Proton.
Definition: action.h:24
static constexpr int LOutput
Structure to contain custom data for output.
bool empty_event
True if no collisions happened.
double impact_parameter
Impact parameter for collider modus, otherwise dummy.
Structure to contain information about the event and ensemble numbers.
int32_t ensemble_number
The number of the ensemble.
int32_t event_number
The number of the event.
Helper structure for Experiment to hold output options and parameters.
bool dil_extended
Extended format for dilepton output.
bool coll_extended
Extended format for collisions output.
bool part_extended
Extended format for particles output.
bool photons_extended
Extended format for photon output.
std::map< std::string, std::vector< std::string > > quantities
Map of quantities to be printed in the output.
OutputOnlyFinal part_only_final
Print only final particles in event.
bool ic_extended
Extended initial conditions output.
bool coll_printstartend
Print initial and final particles in event into collision output.
std::string type
Return type of this converter.