Version: SMASH-1.5
listmodus.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2013-2018
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/angles.h"
27 #include "smash/configuration.h"
28 #include "smash/constants.h"
29 #include "smash/distributions.h"
31 #include "smash/fourvector.h"
32 #include "smash/inputfunctions.h"
33 #include "smash/logging.h"
34 #include "smash/macros.h"
35 #include "smash/particles.h"
36 #include "smash/random.h"
37 #include "smash/threevector.h"
38 
39 namespace smash {
40 
123  : shift_id_(modus_config.take({"List", "Shift_Id"})) {
124  std::string fd = modus_config.take({"List", "File_Directory"});
126 
127  std::string fp = modus_config.take({"List", "File_Prefix"});
129 
130  event_id_ = 0;
132 }
133 
134 /* console output on startup of List specific parameters */
135 std::ostream &operator<<(std::ostream &out, const ListModus &m) {
136  out << "-- List Modus\nInput directory for external particle lists:\n"
137  << m.particle_list_file_directory_ << "\n";
138  return out;
139 }
140 
142  /* (1) If particles are already at the same time - don't touch them
143  AND start at the start_time_ from the config. */
144  double earliest_formation_time = DBL_MAX;
145  double formation_time_difference = 0.0;
146  double reference_formation_time = 0.0; // avoid compiler warning
147  bool first_particle = true;
148  for (const auto &particle : particles) {
149  const double t = particle.position().x0();
150  if (t < earliest_formation_time) {
151  earliest_formation_time = t;
152  }
153  if (first_particle) {
154  reference_formation_time = t;
155  first_particle = false;
156  } else {
157  formation_time_difference += std::abs(t - reference_formation_time);
158  }
159  }
160  /* (2) If particles are NOT at the same time -> anti-stream them to
161  the earliest time (Note: not to the start_time_ set by config) */
162  bool anti_streaming_needed = (formation_time_difference > really_small);
163  start_time_ = earliest_formation_time;
164  if (anti_streaming_needed) {
165  for (auto &particle : particles) {
166  /* for hydro output where formation time is different */
167  const double t = particle.position().x0();
168  const double delta_t = t - start_time_;
169  const ThreeVector r =
170  particle.position().threevec() - delta_t * particle.velocity();
171  particle.set_4position(FourVector(start_time_, r));
172  particle.set_formation_time(t);
173  particle.set_cross_section_scaling_factor(0.0);
174  }
175  }
176 }
177 
179  double t, double x, double y, double z,
180  double mass, double E, double px, double py,
181  double pz) {
182  constexpr int max_warns_precision = 10, max_warn_mass_consistency = 10;
183  const auto &log = logger<LogArea::List>();
184  try {
185  ParticleData &particle = particles.create(pdgcode);
186  // SMASH mass versus input mass consistency check
187  if (particle.type().is_stable() &&
188  std::abs(mass - particle.pole_mass()) > really_small) {
189  if (n_warns_precision_ < max_warns_precision) {
190  log.warn() << "Provided mass of " << particle.type().name() << " = "
191  << mass << " [GeV] is inconsistent with SMASH value = "
192  << particle.pole_mass() << ". Forcing E = sqrt(p^2 + m^2)"
193  << ", where m is SMASH mass.";
195  } else if (n_warns_precision_ == max_warns_precision) {
196  log.warn(
197  "Further warnings about SMASH mass versus input mass"
198  " inconsistencies will be suppressed.");
200  }
201  particle.set_4momentum(mass, ThreeVector(px, py, pz));
202  }
203  particle.set_4momentum(FourVector(E, px, py, pz));
204  // On-shell condition consistency check
205  if (std::abs(particle.momentum().sqr() - mass * mass) > really_small) {
206  if (n_warns_mass_consistency_ < max_warn_mass_consistency) {
207  log.warn() << "Provided 4-momentum " << particle.momentum() << " and "
208  << " mass " << mass << " do not satisfy E^2 - p^2 = m^2."
209  << " This may originate from the lack of numerical"
210  << " precision in the input. Setting E to sqrt(p^2 + m^2).";
212  } else if (n_warns_mass_consistency_ == max_warn_mass_consistency) {
213  log.warn(
214  "Further warnings about E != sqrt(p^2 + m^2) will"
215  " be suppressed.");
217  }
218  particle.set_4momentum(mass, ThreeVector(px, py, pz));
219  }
220  // Set spatial coordinates, they will later be backpropagated if needed
221  particle.set_4position(FourVector(t, x, y, z));
222  particle.set_formation_time(t);
223  particle.set_cross_section_scaling_factor(1.0);
225  log.warn() << "SMASH does not recognize pdg code " << pdgcode
226  << " loaded from file. This particle will be ignored.\n";
227  }
228 }
229 
230 /* initial_conditions - sets particle data for @particles */
232  const ExperimentParameters &) {
233  const auto &log = logger<LogArea::List>();
234  std::string particle_list = next_event_();
235 
236  for (const Line &line : line_parser(particle_list)) {
237  std::istringstream lineinput(line.text);
238  double t, x, y, z, mass, E, px, py, pz;
239  int id, charge;
240  std::string pdg_string;
241  lineinput >> t >> x >> y >> z >> mass >> E >> px >> py >> pz >>
242  pdg_string >> id >> charge;
243  if (lineinput.fail()) {
244  throw LoadFailure(
245  build_error_string("While loading external particle lists data:\n"
246  "Failed to convert the input string to the "
247  "expected data types.",
248  line));
249  }
250  PdgCode pdgcode(pdg_string);
251  log.debug("Particle ", pdgcode, " (x,y,z)= (", x, ", ", y, ", ", z, ")");
252 
253  // Charge consistency check
254  if (pdgcode.charge() != charge) {
255  log.error() << "Charge of pdg = " << pdgcode << " != " << charge;
256  throw std::invalid_argument("Inconsistent input (charge).");
257  }
258  try_create_particle(*particles, pdgcode, t, x, y, z, mass, E, px, py, pz);
259  }
260  backpropagate_to_same_time(*particles);
261  event_id_++;
262 
263  return start_time_;
264 }
265 
266 bf::path ListModus::file_path_(const int file_id) {
267  const auto &log = logger<LogArea::List>();
268  std::stringstream fname;
269  fname << particle_list_file_prefix_ << file_id;
270 
271  const bf::path default_path = bf::absolute(particle_list_file_directory_);
272 
273  const bf::path fpath = default_path / fname.str();
274 
275  log.debug() << fpath.filename().native() << '\n';
276 
277  if (!bf::exists(fpath)) {
278  log.fatal() << fpath.filename().native() << " does not exist! \n"
279  << "\n Usage of smash with external particle lists:\n"
280  << "1. Put the external particle lists in file \n"
281  << "File_Directory/File_Prefix{id} where {id} "
282  << "traversal [Shift_Id, Nevent-1]\n"
283  << "2. Particles info: t x y z mass p0 px py pz"
284  << " pdg ID charge\n"
285  << "in units of: fm fm fm fm GeV GeV GeV GeV GeV"
286  << " none none none\n";
287  throw std::runtime_error("External particle list does not exist!");
288  }
289 
290  return fpath;
291 }
292 
293 std::string ListModus::next_event_() {
294  const auto &log = logger<LogArea::List>();
295 
296  const bf::path fpath = file_path_(file_id_);
297  bf::ifstream ifs{fpath};
298  ifs.seekg(last_read_position_);
299 
300  if (!file_has_events_(fpath, last_read_position_)) {
301  // current file out of events. get next file and call this function
302  // recursively.
303  file_id_++;
305  ifs.close();
306  return next_event_();
307  }
308 
309  // read one event. events marked by line # event end i in case of Oscar
310  // output. Assume one event per file for all other output formats
311  std::string event_string;
312  const std::string needle = "end";
313  std::string line;
314  while (getline(ifs, line)) {
315  if (line.find(needle) == std::string::npos) {
316  event_string += line + "\n";
317  } else {
318  break;
319  }
320  }
321 
322  if (!ifs.eof() && (ifs.fail() || ifs.bad())) {
323  log.fatal() << "Error while reading " << fpath.filename().native();
324  throw std::runtime_error("Error while reading external particle list");
325  }
326  // save position for next event read
327  last_read_position_ = ifs.tellg();
328  ifs.close();
329 
330  return event_string;
331 }
332 
333 bool ListModus::file_has_events_(bf::path filepath,
334  std::streampos last_position) {
335  const auto &log = logger<LogArea::List>();
336  bf::ifstream ifs{filepath};
337  std::string line;
338 
339  // last event read read at end of file. we know this because errors are
340  // handled in next_event
341  if (last_position == -1) {
342  return false;
343  }
344  ifs.seekg(last_position);
345  // skip over comment lines, assume that a max. of four consecutive comment
346  // lines can occur
347  int skipped_lines = 0;
348  const int max_comment_lines = 4;
349  while (std::getline(ifs, line) && line[0] != '#' &&
350  skipped_lines++ < max_comment_lines) {
351  }
352 
353  if (ifs.eof()) {
354  return false;
355  }
356 
357  if (!ifs.good()) {
358  log.fatal() << "Error while reading " << filepath.filename().native();
359  throw std::runtime_error("Error while reading external particle list");
360  }
361 
362  ifs.close();
363  return true;
364 }
365 
366 } // namespace smash
std::string particle_list_file_directory_
File directory of the particle list.
Definition: listmodus.h:149
double initial_conditions(Particles *particles, const ExperimentParameters &parameters)
Generates initial state of the particles in the system according to a list.
Definition: listmodus.cc:231
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:30
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:34
int file_id_
file_id_ is the id of the current file
Definition: listmodus.h:164
ListModus()
Construct an empty list. Useful for convenient JetScape connection.
Definition: listmodus.h:72
ListModus: Provides a modus for running SMASH on an external particle list, for example as an afterbu...
Definition: listmodus.h:56
void create(size_t n, PdgCode pdg)
Add n particles of the same type (pdg) to the list.
Definition: particles.cc:66
Collection of useful constants that are known at compile time.
double pole_mass() const
Get the particle&#39;s pole mass ("on-shell").
Definition: particledata.h:96
void backpropagate_to_same_time(Particles &particles)
Judge whether formation times are the same for all the particles; Don&#39;t do anti-freestreaming if all ...
Definition: listmodus.cc:141
const FourVector & momentum() const
Get the particle&#39;s 4-momentum.
Definition: particledata.h:139
Interface to the SMASH configuration files.
int charge() const
The charge of the particle.
Definition: pdgcode.h:470
int n_warns_mass_consistency_
Counter for energy-momentum conservation warnings to avoid spamming.
Definition: listmodus.h:169
void set_formation_time(const double &form_time)
Set the absolute formation time.
Definition: particledata.h:232
double sqr() const
calculate the square of the vector (which is a scalar)
Definition: fourvector.h:437
Used when external particle list cannot be found.
Definition: listmodus.h:139
bool is_stable() const
Definition: particletype.h:226
Generic algorithms on containers and ranges.
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:178
void set_4momentum(const FourVector &momentum_vector)
Set the particle&#39;s 4-momentum directly.
Definition: particledata.h:145
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
double start_time_
Starting time for the List; changed to the earliest formation time.
Definition: listmodus.h:145
int n_warns_precision_
Counter for mass-check warnings to avoid spamming.
Definition: listmodus.h:167
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:333
int event_id_
event_id_ = the unique id of the current event
Definition: listmodus.h:161
build_vector_< Line > line_parser(const std::string &input)
Helper function for parsing particles.txt and decaymodes.txt.
std::string particle_list_file_prefix_
File prefix of the particle list.
Definition: listmodus.h:152
const ParticleType & type() const
Get the type of the particle.
Definition: particledata.h:109
void set_4position(const FourVector &pos)
Set the particle&#39;s 4-position directly.
Definition: particledata.h:190
const int shift_id_
shift_id is the start number of file_id_
Definition: listmodus.h:158
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
Definition: action.h:457
void set_cross_section_scaling_factor(const double &xsec_scal)
Set the particle&#39;s initial cross_section_scaling_factor.
Definition: particledata.h:274
std::string next_event_()
Read the next event.
Definition: listmodus.cc:293
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:32
std::string build_error_string(std::string message, const Line &line)
Builds a meaningful error message.
Helper structure for Experiment.
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:52
Line consists of a line number and the contents of that line.
std::streampos last_read_position_
last read position in current file
Definition: listmodus.h:183
Definition: action.h:24
bf::path file_path_(const int file_id)
Return the absolute file path based on given integer.
Definition: listmodus.cc:266
const std::string & name() const
Definition: particletype.h:131