Version: SMASH-2.2
listmodus.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2013-2021
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 <fstream>
16 #include <list>
17 #include <map>
18 #include <sstream>
19 #include <utility>
20 #include <vector>
21 
22 #include <boost/filesystem.hpp>
23 #include <boost/filesystem/fstream.hpp>
24 
25 #include "smash/algorithms.h"
26 #include "smash/boxmodus.h"
27 #include "smash/configuration.h"
28 #include "smash/constants.h"
30 #include "smash/fourvector.h"
31 #include "smash/inputfunctions.h"
32 #include "smash/logging.h"
33 #include "smash/threevector.h"
35 
36 namespace smash {
37 static constexpr int LList = LogArea::List::id;
38 
139  const ExperimentParameters &param)
140  : shift_id_(modus_config.take({"List", "Shift_Id"})) {
141  std::string fd = modus_config.take({"List", "File_Directory"});
143 
144  std::string fp = modus_config.take({"List", "File_Prefix"});
146 
147  event_id_ = 0;
149 
150  if (param.n_ensembles > 1) {
151  throw std::runtime_error("ListModus only makes sense with one ensemble");
152  }
153 }
154 
155 /* console output on startup of List specific parameters */
156 std::ostream &operator<<(std::ostream &out, const ListModus &m) {
157  out << "-- List Modus\nInput directory for external particle lists:\n"
158  << m.particle_list_file_directory_ << "\n";
159  return out;
160 }
161 
163  /* (1) If particles are already at the same time - don't touch them
164  AND start at the start_time_ from the config. */
165  double earliest_formation_time = DBL_MAX;
166  double formation_time_difference = 0.0;
167  double reference_formation_time = 0.0; // avoid compiler warning
168  bool first_particle = true;
169  for (const auto &particle : particles) {
170  const double t = particle.position().x0();
171  if (t < earliest_formation_time) {
172  earliest_formation_time = t;
173  }
174  if (first_particle) {
175  reference_formation_time = t;
176  first_particle = false;
177  } else {
178  formation_time_difference += std::abs(t - reference_formation_time);
179  }
180  }
181  /* (2) If particles are NOT at the same time -> anti-stream them to
182  the earliest time (Note: not to the start_time_ set by config) */
183  bool anti_streaming_needed = (formation_time_difference > really_small);
184  start_time_ = earliest_formation_time;
185  if (anti_streaming_needed) {
186  for (auto &particle : particles) {
187  /* for hydro output where formation time is different */
188  const double t = particle.position().x0();
189  const double delta_t = t - start_time_;
190  const ThreeVector r =
191  particle.position().threevec() - delta_t * particle.velocity();
192  particle.set_4position(FourVector(start_time_, r));
193  particle.set_formation_time(t);
194  particle.set_cross_section_scaling_factor(0.0);
195  }
196  }
197 }
198 
200  double t, double x, double y, double z,
201  double mass, double E, double px, double py,
202  double pz) {
203  constexpr int max_warns_precision = 10, max_warn_mass_consistency = 10;
204  try {
205  ParticleData &particle = particles.create(pdgcode);
206  // SMASH mass versus input mass consistency check
207  if (particle.type().is_stable() &&
208  std::abs(mass - particle.pole_mass()) > really_small) {
209  if (n_warns_precision_ < max_warns_precision) {
210  logg[LList].warn() << "Provided mass of " << particle.type().name()
211  << " = " << mass
212  << " [GeV] is inconsistent with SMASH value = "
213  << particle.pole_mass()
214  << ". Forcing E = sqrt(p^2 + m^2)"
215  << ", where m is SMASH mass.";
217  } else if (n_warns_precision_ == max_warns_precision) {
218  logg[LList].warn(
219  "Further warnings about SMASH mass versus input mass"
220  " inconsistencies will be suppressed.");
222  }
223  particle.set_4momentum(mass, ThreeVector(px, py, pz));
224  }
225  particle.set_4momentum(FourVector(E, px, py, pz));
226  // On-shell condition consistency check
227  if (std::abs(particle.momentum().sqr() - mass * mass) > really_small) {
228  if (n_warns_mass_consistency_ < max_warn_mass_consistency) {
229  logg[LList].warn()
230  << "Provided 4-momentum " << particle.momentum() << " and "
231  << " mass " << mass << " do not satisfy E^2 - p^2 = m^2."
232  << " This may originate from the lack of numerical"
233  << " precision in the input. Setting E to sqrt(p^2 + m^2).";
235  } else if (n_warns_mass_consistency_ == max_warn_mass_consistency) {
236  logg[LList].warn(
237  "Further warnings about E != sqrt(p^2 + m^2) will"
238  " be suppressed.");
240  }
241  particle.set_4momentum(mass, ThreeVector(px, py, pz));
242  }
243  // Set spatial coordinates, they will later be backpropagated if needed
244  particle.set_4position(FourVector(t, x, y, z));
245  particle.set_formation_time(t);
246  particle.set_cross_section_scaling_factor(1.0);
248  logg[LList].warn() << "SMASH does not recognize pdg code " << pdgcode
249  << " loaded from file. This particle will be ignored.\n";
250  }
251 }
252 
253 /* initial_conditions - sets particle data for @particles */
255  const ExperimentParameters &) {
256  std::string particle_list = next_event_();
257  for (const Line &line : line_parser(particle_list)) {
258  std::istringstream lineinput(line.text);
259  double t, x, y, z, mass, E, px, py, pz;
260  int id, charge;
261  std::string pdg_string;
262  lineinput >> t >> x >> y >> z >> mass >> E >> px >> py >> pz >>
263  pdg_string >> id >> charge;
264  if (lineinput.fail()) {
265  throw LoadFailure(
266  build_error_string("While loading external particle lists data:\n"
267  "Failed to convert the input string to the "
268  "expected data types.",
269  line));
270  }
271  PdgCode pdgcode(pdg_string);
272  logg[LList].debug("Particle ", pdgcode, " (x,y,z)= (", x, ", ", y, ", ", z,
273  ")");
274 
275  // Charge consistency check
276  if (pdgcode.charge() != charge) {
277  logg[LList].error() << "Charge of pdg = " << pdgcode << " != " << charge;
278  throw std::invalid_argument("Inconsistent input (charge).");
279  }
280  try_create_particle(*particles, pdgcode, t, x, y, z, mass, E, px, py, pz);
281  }
282  if (particles->size() > 0) {
283  backpropagate_to_same_time(*particles);
284  } else {
285  start_time_ = 0.0;
286  }
287  event_id_++;
288 
289  return start_time_;
290 }
291 
292 bf::path ListModus::file_path_(const int file_id) {
293  std::stringstream fname;
294  fname << particle_list_file_prefix_ << file_id;
295 
296  const bf::path default_path = bf::absolute(particle_list_file_directory_);
297 
298  const bf::path fpath = default_path / fname.str();
299 
300  logg[LList].debug() << fpath.filename().native() << '\n';
301 
302  if (!bf::exists(fpath)) {
303  logg[LList].fatal() << fpath.filename().native() << " does not exist! \n"
304  << "\n Usage of smash with external particle lists:\n"
305  << "1. Put the external particle lists in file \n"
306  << "File_Directory/File_Prefix{id} where {id} "
307  << "traversal [Shift_Id, Nevent-1]\n"
308  << "2. Particles info: t x y z mass p0 px py pz"
309  << " pdg ID charge\n"
310  << "in units of: fm fm fm fm GeV GeV GeV GeV GeV"
311  << " none none e\n";
312  throw std::runtime_error("External particle list does not exist!");
313  }
314 
315  return fpath;
316 }
317 
318 std::string ListModus::next_event_() {
319  const bf::path fpath = file_path_(file_id_);
320  bf::ifstream ifs{fpath};
321  ifs.seekg(last_read_position_);
322 
323  if (!file_has_events_(fpath, last_read_position_)) {
324  // current file out of events. get next file and call this function
325  // recursively.
326  file_id_++;
328  ifs.close();
329  return next_event_();
330  }
331 
332  // read one event. events marked by line # event end i in case of Oscar
333  // output. Assume one event per file for all other output formats
334  std::string event_string;
335  const std::string needle = "end";
336  std::string line;
337  while (getline(ifs, line)) {
338  if (line.find(needle) == std::string::npos) {
339  event_string += line + "\n";
340  } else {
341  break;
342  }
343  }
344 
345  if (!ifs.eof() && (ifs.fail() || ifs.bad())) {
346  logg[LList].fatal() << "Error while reading " << fpath.filename().native();
347  throw std::runtime_error("Error while reading external particle list");
348  }
349  // save position for next event read
350  last_read_position_ = ifs.tellg();
351  ifs.close();
352 
353  return event_string;
354 }
355 
356 bool ListModus::file_has_events_(bf::path filepath,
357  std::streampos last_position) {
358  bf::ifstream ifs{filepath};
359  std::string line;
360 
361  // last event read read at end of file. we know this because errors are
362  // handled in next_event
363  if (last_position == -1) {
364  return false;
365  }
366  ifs.seekg(last_position);
367  // skip over comment lines, assume that a max. of four consecutive comment
368  // lines can occur
369  int skipped_lines = 0;
370  const int max_comment_lines = 4;
371  while (std::getline(ifs, line) && line[0] != '#' &&
372  skipped_lines++ < max_comment_lines) {
373  }
374 
375  if (ifs.eof()) {
376  return false;
377  }
378 
379  if (!ifs.good()) {
380  logg[LList].fatal() << "Error while reading "
381  << filepath.filename().native();
382  throw std::runtime_error("Error while reading external particle list");
383  }
384 
385  ifs.close();
386  return true;
387 }
388 
390  const ExperimentParameters &param)
391  : shift_id_(modus_config.take({"ListBox", "Shift_Id"})),
392  length_(modus_config.take({"ListBox", "Length"})) {
393  std::string fd = modus_config.take({"ListBox", "File_Directory"});
394  particle_list_file_directory_ = fd;
395 
396  std::string fp = modus_config.take({"ListBox", "File_Prefix"});
397  particle_list_file_prefix_ = fp;
398 
399  event_id_ = 0;
400  file_id_ = shift_id_;
401 
402  // Set specific values in the ListModus class
403  ListModus::set_file_id(file_id_);
404  ListModus::set_particle_list_file_directory(particle_list_file_directory_);
405  ListModus::set_particle_list_file_prefix(particle_list_file_prefix_);
406  ListModus::set_event_id(event_id_);
407 
408  if (param.n_ensembles > 1) {
409  throw std::runtime_error("ListModus only makes sense with one ensemble");
410  }
411 }
412 
414  const OutputsList &output_list) {
415  int wraps = 0;
416  for (ParticleData &data : *particles) {
417  FourVector position = data.position();
418  bool wall_hit = enforce_periodic_boundaries(position.begin() + 1,
419  position.end(), length_);
420  if (wall_hit) {
421  const ParticleData incoming_particle(data);
422  data.set_4position(position);
423  ++wraps;
424  ActionPtr action =
425  make_unique<WallcrossingAction>(incoming_particle, data);
426  for (const auto &output : output_list) {
427  if (!output->is_dilepton_output() && !output->is_photon_output()) {
428  output->at_interaction(*action, 0.);
429  }
430  }
431  }
432  }
433 
434  logg[LList].debug("Moved ", wraps, " particles back into the box.");
435  return wraps;
436 }
437 
438 } // 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
double sqr() const
calculate the square of the vector (which is a scalar)
Definition: fourvector.h:455
iterator end()
Definition: fourvector.h:289
iterator begin()
Definition: fourvector.h:286
const double length_
Length of the cube's edge in fm/c.
Definition: listmodus.h:315
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:413
ListBoxModus(Configuration modus_config, const ExperimentParameters &parameters)
Constructor (This is the same as for the ListModus)
Definition: listmodus.cc:389
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:162
bf::path file_path_(const int file_id)
Return the absolute file path based on given integer.
Definition: listmodus.cc:292
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:199
std::string particle_list_file_prefix_
File prefix of the particle list.
Definition: listmodus.h:202
int file_id_
file_id_ is the id of the current file
Definition: listmodus.h:214
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:199
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:222
const int shift_id_
shift_id is the start number of file_id_
Definition: listmodus.h:208
bool file_has_events_(bf::path filepath, std::streampos last_position)
Check if the file given by filepath has events left after streampos last_position.
Definition: listmodus.cc:356
std::string next_event_()
Read the next event.
Definition: listmodus.cc:318
double initial_conditions(Particles *particles, const ExperimentParameters &parameters)
Generates initial state of the particles in the system according to a list.
Definition: listmodus.cc:254
int event_id_
event_id_ = the unique id of the current event
Definition: listmodus.h:211
void set_event_id(int event_id_inh)
set the event_id when ListBoxModus is used
Definition: listmodus.h:161
int n_warns_precision_
Counter for mass-check warnings to avoid spamming.
Definition: listmodus.h:217
int n_warns_mass_consistency_
Counter for energy-momentum conservation warnings to avoid spamming.
Definition: listmodus.h:219
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:58
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
Definition: particledata.h:164
const ParticleType & type() const
Get the type of the particle.
Definition: particledata.h:128
void set_4position(const FourVector &pos)
Set the particle's 4-position directly.
Definition: particledata.h:209
const FourVector & momentum() const
Get the particle's 4-momentum.
Definition: particledata.h:158
void set_cross_section_scaling_factor(const double &xsec_scal)
Set the particle's initial cross_section_scaling_factor.
Definition: particledata.h:293
double pole_mass() const
Get the particle's pole mass ("on-shell").
Definition: particledata.h:115
void set_formation_time(const double &form_time)
Set the absolute formation time.
Definition: particledata.h:251
const std::string & name() const
Definition: particletype.h:141
bool is_stable() const
Definition: particletype.h:242
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
size_t size() const
Definition: particles.h:87
void create(size_t n, PdgCode pdg)
Add n particles of the same type (pdg) to the list.
Definition: particles.cc:66
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
int charge() const
The charge of the particle.
Definition: pdgcode.h:488
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:532
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
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:37
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