Version: SMASH-3.0
listmodus.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2015-2023
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/listmodus.h"
11 
12 #include <cmath>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <filesystem>
16 #include <fstream>
17 #include <list>
18 #include <map>
19 #include <sstream>
20 #include <utility>
21 #include <vector>
22 
23 #include "smash/algorithms.h"
24 #include "smash/boxmodus.h"
25 #include "smash/configuration.h"
26 #include "smash/constants.h"
28 #include "smash/fourvector.h"
29 #include "smash/inputfunctions.h"
30 #include "smash/logging.h"
31 #include "smash/particledata.h"
32 #include "smash/threevector.h"
34 
35 namespace smash {
36 static constexpr int LList = LogArea::List::id;
37 
39  const ExperimentParameters &param)
40  : shift_id_(modus_config.take({"List", "Shift_Id"})) {
41  std::string fd = modus_config.take({"List", "File_Directory"});
43 
44  std::string fp = modus_config.take({"List", "File_Prefix"});
46 
47  event_id_ = 0;
49 
50  if (param.n_ensembles > 1) {
51  throw std::runtime_error("ListModus only makes sense with one ensemble");
52  }
53 }
54 
55 /* console output on startup of List specific parameters */
56 std::ostream &operator<<(std::ostream &out, const ListModus &m) {
57  out << "-- List Modus\nInput directory for external particle lists:\n"
58  << m.particle_list_file_directory_ << "\n";
59  return out;
60 }
61 
63  /* (1) If particles are already at the same time - don't touch them
64  AND start at the start_time_ from the config. */
65  double earliest_formation_time = DBL_MAX;
66  double formation_time_difference = 0.0;
67  double reference_formation_time = 0.0; // avoid compiler warning
68  bool first_particle = true;
69  for (const auto &particle : particles) {
70  const double t = particle.position().x0();
71  if (t < earliest_formation_time) {
72  earliest_formation_time = t;
73  }
74  if (first_particle) {
75  reference_formation_time = t;
76  first_particle = false;
77  } else {
78  formation_time_difference += std::abs(t - reference_formation_time);
79  }
80  }
81  /* (2) If particles are NOT at the same time -> anti-stream them to
82  the earliest time (Note: not to the start_time_ set by config) */
83  bool anti_streaming_needed = (formation_time_difference > really_small);
84  start_time_ = earliest_formation_time;
85  if (anti_streaming_needed) {
86  for (auto &particle : particles) {
87  /* for hydro output where formation time is different */
88  const double t = particle.position().x0();
89  const double delta_t = t - start_time_;
90  const ThreeVector r =
91  particle.position().threevec() - delta_t * particle.velocity();
92  particle.set_4position(FourVector(start_time_, r));
93  particle.set_formation_time(t);
94  particle.set_cross_section_scaling_factor(0.0);
95  }
96  }
97 }
98 
100  double t, double x, double y, double z,
101  double mass, double E, double px, double py,
102  double pz) {
103  try {
104  ParticleData new_particle =
106  pdgcode, mass, {E, px, py, pz}, LList, warn_about_mass_discrepancy_,
108  // Set spatial coordinates, they will later be backpropagated if needed
109  new_particle.set_4position(FourVector(t, x, y, z));
110  new_particle.set_formation_time(t);
111  new_particle.set_cross_section_scaling_factor(1.0);
112  particles.insert(new_particle);
114  logg[LList].warn() << "SMASH does not recognize pdg code " << pdgcode
115  << " loaded from file. This particle will be ignored.\n";
116  }
117 }
118 
119 /* initial_conditions - sets particle data for @particles */
121  const ExperimentParameters &) {
122  std::string particle_list = next_event_();
123  for (const Line &line : line_parser(particle_list)) {
124  std::istringstream lineinput(line.text);
125  double t, x, y, z, mass, E, px, py, pz;
126  int id, charge;
127  std::string pdg_string;
128  lineinput >> t >> x >> y >> z >> mass >> E >> px >> py >> pz >>
129  pdg_string >> id >> charge;
130  if (lineinput.fail()) {
131  throw LoadFailure(
132  build_error_string("While loading external particle lists data:\n"
133  "Failed to convert the input string to the "
134  "expected data types.",
135  line));
136  }
137  PdgCode pdgcode(pdg_string);
138  logg[LList].debug("Particle ", pdgcode, " (x,y,z)= (", x, ", ", y, ", ", z,
139  ")");
140 
141  // Charge consistency check
142  if (pdgcode.charge() != charge) {
143  logg[LList].error() << "Charge of pdg = " << pdgcode << " != " << charge;
144  throw std::invalid_argument("Inconsistent input (charge).");
145  }
146  try_create_particle(*particles, pdgcode, t, x, y, z, mass, E, px, py, pz);
147  }
148  if (particles->size() > 0) {
149  backpropagate_to_same_time(*particles);
150  } else {
151  start_time_ = 0.0;
152  }
153  event_id_++;
154 
155  return start_time_;
156 }
157 
158 std::filesystem::path ListModus::file_path_(const int file_id) {
159  std::stringstream fname;
160  fname << particle_list_file_prefix_ << file_id;
161 
162  const std::filesystem::path default_path =
163  std::filesystem::absolute(particle_list_file_directory_);
164 
165  const std::filesystem::path fpath = default_path / fname.str();
166 
167  logg[LList].debug() << fpath.filename().native() << '\n';
168 
169  if (!std::filesystem::exists(fpath)) {
170  logg[LList].fatal() << fpath.filename().native() << " does not exist! \n"
171  << "\n Usage of smash with external particle lists:\n"
172  << "1. Put the external particle lists in file \n"
173  << "File_Directory/File_Prefix{id} where {id} "
174  << "traversal [Shift_Id, Nevent-1]\n"
175  << "2. Particles info: t x y z mass p0 px py pz"
176  << " pdg ID charge\n"
177  << "in units of: fm fm fm fm GeV GeV GeV GeV GeV"
178  << " none none e\n";
179  throw std::runtime_error("External particle list does not exist!");
180  }
181 
182  return fpath;
183 }
184 
185 std::string ListModus::next_event_() {
186  const std::filesystem::path fpath = file_path_(file_id_);
187  std::ifstream ifs{fpath};
188  ifs.seekg(last_read_position_);
189 
190  if (!file_has_events_(fpath, last_read_position_)) {
191  // current file out of events. get next file and call this function
192  // recursively.
193  file_id_++;
195  ifs.close();
196  return next_event_();
197  }
198 
199  // read one event. events marked by line # event end i in case of Oscar
200  // output. Assume one event per file for all other output formats
201  std::string event_string;
202  const std::string needle = "end";
203  std::string line;
204  while (getline(ifs, line)) {
205  if (line.find(needle) == std::string::npos) {
206  event_string += line + "\n";
207  } else {
208  break;
209  }
210  }
211 
212  if (!ifs.eof() && (ifs.fail() || ifs.bad())) {
213  logg[LList].fatal() << "Error while reading " << fpath.filename().native();
214  throw std::runtime_error("Error while reading external particle list");
215  }
216  // save position for next event read
217  last_read_position_ = ifs.tellg();
218  ifs.close();
219 
220  return event_string;
221 }
222 
223 bool ListModus::file_has_events_(std::filesystem::path filepath,
224  std::streampos last_position) {
225  std::ifstream ifs{filepath};
226  std::string line;
227 
228  // last event read read at end of file. we know this because errors are
229  // handled in next_event
230  if (last_position == -1) {
231  return false;
232  }
233  ifs.seekg(last_position);
234  // skip over comment lines, assume that a max. of four consecutive comment
235  // lines can occur
236  int skipped_lines = 0;
237  const int max_comment_lines = 4;
238  while (std::getline(ifs, line) && line[0] != '#' &&
239  skipped_lines++ < max_comment_lines) {
240  }
241 
242  if (ifs.eof()) {
243  return false;
244  }
245 
246  if (!ifs.good()) {
247  logg[LList].fatal() << "Error while reading "
248  << filepath.filename().native();
249  throw std::runtime_error("Error while reading external particle list");
250  }
251 
252  ifs.close();
253  return true;
254 }
255 
257  const ExperimentParameters &param)
258  : shift_id_(modus_config.take({"ListBox", "Shift_Id"})),
259  length_(modus_config.take({"ListBox", "Length"})) {
260  std::string fd = modus_config.take({"ListBox", "File_Directory"});
261  particle_list_file_directory_ = fd;
262 
263  std::string fp = modus_config.take({"ListBox", "File_Prefix"});
264  particle_list_file_prefix_ = fp;
265 
266  event_id_ = 0;
267  file_id_ = shift_id_;
268 
269  // Set specific values in the ListModus class
270  ListModus::set_file_id(file_id_);
271  ListModus::set_particle_list_file_directory(particle_list_file_directory_);
272  ListModus::set_particle_list_file_prefix(particle_list_file_prefix_);
273  ListModus::set_event_id(event_id_);
274 
275  if (param.n_ensembles > 1) {
276  throw std::runtime_error("ListModus only makes sense with one ensemble");
277  }
278 }
279 
281  const OutputsList &output_list) {
282  int wraps = 0;
283  for (ParticleData &data : *particles) {
284  FourVector position = data.position();
285  bool wall_hit = enforce_periodic_boundaries(position.begin() + 1,
286  position.end(), length_);
287  if (wall_hit) {
288  const ParticleData incoming_particle(data);
289  data.set_4position(position);
290  ++wraps;
291  ActionPtr action =
292  std::make_unique<WallcrossingAction>(incoming_particle, data);
293  for (const auto &output : output_list) {
294  if (!output->is_dilepton_output() && !output->is_photon_output()) {
295  output->at_interaction(*action, 0.);
296  }
297  }
298  }
299  }
300 
301  logg[LList].debug("Moved ", wraps, " particles back into the box.");
302  return wraps;
303 }
304 
305 } // namespace smash
Generic algorithms on containers and ranges.
Interface to the SMASH configuration files.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
iterator end()
Definition: fourvector.h:294
iterator begin()
Definition: fourvector.h:291
const double length_
Length of the cube's edge in fm.
Definition: listmodus.h:316
int impose_boundary_conditions(Particles *particles, const OutputsList &output_list={})
Enforces that all particles are inside the box at the beginning of an event.
Definition: listmodus.cc:280
ListBoxModus(Configuration modus_config, const ExperimentParameters &parameters)
Constructor (This is the same as for the ListModus)
Definition: listmodus.cc:256
ListModus: Provides a modus for running SMASH on an external particle list, for example as an afterbu...
Definition: listmodus.h:56
void set_particle_list_file_directory(std::string particle_list_file_directory_inh)
set the particle_list_directory when ListBoxModus is used
Definition: listmodus.h:149
void backpropagate_to_same_time(Particles &particles)
Judge whether formation times are the same for all the particles; Don't do anti-freestreaming if all ...
Definition: listmodus.cc:62
bool file_has_events_(std::filesystem::path filepath, std::streampos last_position)
Check if the file given by filepath has events left after streampos last_position.
Definition: listmodus.cc:223
void set_file_id(const double file_id_inh)
set the file id when ListBoxModus is used
Definition: listmodus.h:146
std::string particle_list_file_directory_
File directory of the particle list.
Definition: listmodus.h:200
std::string particle_list_file_prefix_
File prefix of the particle list.
Definition: listmodus.h:203
int file_id_
file_id_ is the id of the current file
Definition: listmodus.h:215
ListModus()
Construct an empty list. Useful for convenient JetScape connection.
Definition: listmodus.h:72
double start_time_
Starting time for the List; changed to the earliest formation time.
Definition: listmodus.h:165
void try_create_particle(Particles &particles, PdgCode pdgcode, double t, double x, double y, double z, double mass, double E, double px, double py, double pz)
Tries to add a new particle to particles and performs consistency checks: (i) The PDG code is legal a...
Definition: listmodus.cc:99
std::filesystem::path file_path_(const int file_id)
Return the absolute file path based on given integer.
Definition: listmodus.cc:158
void set_particle_list_file_prefix(std::string particle_list_file_prefix_inh)
set the particle_list_prefix when ListBoxModus is used
Definition: listmodus.h:155
std::streampos last_read_position_
last read position in current file
Definition: listmodus.h:223
bool warn_about_mass_discrepancy_
Auxiliary flag to warn about mass-discrepancies only once per instance.
Definition: listmodus.h:218
const int shift_id_
shift_id is the start number of file_id_
Definition: listmodus.h:209
bool warn_about_off_shell_particles_
Auxiliary flag to warn about off-shell particles only once per instance.
Definition: listmodus.h:220
std::string next_event_()
Read the next event.
Definition: listmodus.cc:185
double initial_conditions(Particles *particles, const ExperimentParameters &parameters)
Generates initial state of the particles in the system according to a list.
Definition: listmodus.cc:120
int event_id_
event_id_ = the unique id of the current event
Definition: listmodus.h:212
void set_event_id(int event_id_inh)
set the event_id when ListBoxModus is used
Definition: listmodus.h:161
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:58
void set_4position(const FourVector &pos)
Set the particle's 4-position directly.
Definition: particledata.h:209
void set_cross_section_scaling_factor(const double &xsec_scal)
Set the particle's initial cross_section_scaling_factor.
Definition: particledata.h:293
void set_formation_time(const double &form_time)
Set the absolute formation time.
Definition: particledata.h:251
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
size_t size() const
Definition: particles.h:87
const ParticleData & insert(const ParticleData &p)
Inserts the particle into the list of particles.
Definition: particles.cc:50
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:110
int charge() const
The charge of the particle.
Definition: pdgcode.h:566
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
Collection of useful constants that are known at compile time.
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
Definition: action.h:537
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
Definition: action.h:24
ParticleData create_valid_smash_particle_matching_provided_quantities(PdgCode pdgcode, double mass, const FourVector &four_momentum, int log_area, bool &mass_warning, bool &on_shell_warning)
This function creates a SMASH particle validating the provided information.
static bool enforce_periodic_boundaries(Iterator begin, const Iterator &end, typename std::iterator_traits< Iterator >::value_type length)
Enforces periodic boundaries on the given collection of values.
Definition: algorithms.h:53
build_vector_< Line > line_parser(const std::string &input)
Helper function for parsing particles.txt and decaymodes.txt.
static constexpr int LList
Definition: listmodus.cc:36
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
std::string build_error_string(std::string message, const Line &line)
Builds a meaningful error message.
Helper structure for Experiment.
Line consists of a line number and the contents of that line.
Used when external particle list cannot be found.
Definition: listmodus.h:138