38 static constexpr
int LList = LogArea::List::id;
44 : file_id_{std::nullopt}, event_id_{0} {
53 const bool is_list_box =
56 throw std::logic_error(
57 "Unexpected error in ListModus constructor. Either List or ListBox "
58 "sections must be present in configuration.");
78 const bool file_prefix_used = modus_config.
has_value(file_prefix_key);
79 const bool filename_used = modus_config.
has_value(filename_key);
80 if (file_prefix_used == filename_used) {
81 throw std::invalid_argument(
82 "Either 'Filename' or 'File_Prefix' key must be used in 'Modi' section "
83 "in configuration file. Please, adjust your configuration file.");
85 if (file_prefix_used) {
93 throw std::runtime_error(
"ListModus only makes sense with one ensemble");
102 out <<
"-- List Modus\nInput directory for external particle lists:\n"
110 double earliest_formation_time = DBL_MAX;
111 double formation_time_difference = 0.0;
112 double reference_formation_time = 0.0;
113 bool first_particle =
true;
114 for (
const auto &particle : particles) {
115 const double t = particle.position().x0();
116 if (t < earliest_formation_time) {
117 earliest_formation_time = t;
119 if (first_particle) {
120 reference_formation_time = t;
121 first_particle =
false;
123 formation_time_difference += std::abs(t - reference_formation_time);
128 bool anti_streaming_needed = (formation_time_difference >
really_small);
130 if (anti_streaming_needed) {
137 double z,
double mass,
double E,
double px,
double py,
double pz,
138 const std::vector<std::string> &optional_quantities) {
142 pdgcode, mass, {t, x, y, z}, {E, px, py, pz},
LList,
145 particles.
insert(new_particle);
147 logg[
LList].warn() <<
"SMASH does not recognize pdg code " << pdgcode
148 <<
" loaded from file. This particle will be ignored.\n";
154 const std::vector<std::string> &optional_quantities)
const {
155 if (optional_quantities.empty()) {
158 using namespace std::string_literals;
159 throw std::out_of_range(
"Unexpected size mismatch in "s + __func__ +
160 " between the list of optional quantities values "
161 "passed in and the class member optional_fields_");
164 std::ostringstream error_message{
"", std::ios_base::ate};
169 auto quantity = optional_quantities[i];
173 }
else if (
field ==
"charge") {
174 const PdgCode pdgcode =
p.pdgcode();
175 const int charge = std::stoi(optional_quantities[i], &len);
177 if (pdgcode.
charge() != charge) {
178 error_message <<
"Charge of pdg = " << pdgcode <<
" != " << charge
180 throw std::invalid_argument(
"Inconsistent input (charge).");
182 }
else if (
field ==
"ncoll") {
183 const int ncoll = std::stoi(optional_quantities[i], &len);
185 error_message <<
"ncoll < 0.\n";
188 }
else if (
field ==
"form_time") {
189 p.set_formation_time(std::stod(quantity, &len));
190 }
else if (
field ==
"xsecfac") {
191 const double xsecfac = std::stod(quantity, &len);
192 if (xsecfac < 0 || xsecfac > 1) {
193 error_message <<
"xsecfac < 0 or xsecfac > 1.\n";
195 p.set_cross_section_scaling_factor(xsecfac);
196 }
else if (
field ==
"proc_type") {
197 const int proc_type = std::stoi(quantity, &len);
199 error_message <<
"Invalid proc_type.\n";
202 }
else if (
field ==
"time_last_coll") {
203 const double t_last_coll = std::stod(quantity, &len);
204 if (t_last_coll >
p.position().x0()) {
205 error_message <<
"time_last_coll > particle time.\n";
208 }
else if (
field ==
"pdg_mother1") {
209 if (quantity !=
"0") {
211 error_message <<
"pdg_mother1 cannot be " << quantity <<
".\n";
214 len = quantity.size();
216 }
else if (
field ==
"pdg_mother2") {
217 if (quantity !=
"0") {
219 error_message <<
"pdg_mother2 cannot be " << quantity <<
".\n";
222 len = quantity.size();
224 }
else if (
field ==
"spin0") {
225 const double s0 = std::stod(quantity, &len);
226 p.set_spin_vector_component(0, s0);
227 }
else if (
field ==
"spinx") {
228 const double s1 = std::stod(quantity, &len);
229 p.set_spin_vector_component(1, s1);
230 }
else if (
field ==
"spiny") {
231 const double s2 = std::stod(quantity, &len);
232 p.set_spin_vector_component(2, s2);
233 }
else if (
field ==
"spinz") {
234 const double s3 = std::stod(quantity, &len);
235 p.set_spin_vector_component(3, s3);
236 }
else if (
field ==
"perturbative_weight") {
237 const double weight = std::stod(quantity, &len);
238 if (0 > weight || weight > 1) {
239 error_message <<
"Perturbative weight must be between 0 and 1.\n";
241 p.set_perturbative_weight(weight);
243 error_message <<
" Unknown quantities given in the configuration.\n";
247 if (len != quantity.size()) {
249 <<
field <<
"=" << quantity
250 <<
" not read exactly as written in the input particle list.\n";
254 if (error_message.str().size() > 0) {
256 <<
"The reading-in of optional quantities had the following problems:"
258 << error_message.str();
259 throw std::invalid_argument(
260 "Please fix the list of input particles and/or configuration.");
262 p.set_history(std::move(hist));
269 if (particles->
size() > 0) {
281 const std::vector<Line> event_content =
line_parser(particle_list);
282 if (event_content.empty()) {
285 "Encountered empty event while reading input particle lists data, "
286 "which will result in empty events in the output file!");
290 for (
const Line &line : event_content) {
291 std::istringstream lineinput(line.text);
292 double t, x, y, z, mass, E, px, py, pz;
293 std::string pdg_string;
294 lineinput >> t >> x >> y >> z >> mass >> E >> px >> py >> pz >> pdg_string;
299 optional_quantities[i] = std::move(opt);
301 if (lineinput.fail()) {
304 "Failed to convert the input string to the "
305 "expected data types.",
309 logg[
LList].debug(
"Particle ", pdgcode,
" (x,y,z)= (", x,
", ", y,
", ", z,
312 try_create_particle(particles, pdgcode, t, x, y, z, mass, E, px, py, pz,
313 optional_quantities);
321 const std::filesystem::path default_path =
324 const std::filesystem::path fpath = default_path / fname;
326 logg[
LList].debug() <<
"File: " << std::filesystem::absolute(fpath) <<
'\n';
328 if (!std::filesystem::exists(fpath)) {
331 << fpath.filename().native() <<
" does not exist! \n\n"
332 <<
"Usage of smash with external particle lists:\n"
333 <<
" 1. Put the external particle lists in one or more files\n"
334 <<
" according to the user guide instructions.\n"
335 <<
" 2. Particles info: t x y z mass p0 px py pz pdg ID charge\n"
336 <<
" in units of: fm fm fm fm GeV GeV GeV GeV GeV none none e\n";
338 throw std::runtime_error(
"External particle list does not exist!");
346 std::ifstream ifs{fpath};
357 throw std::runtime_error(
358 "Attempt to read in next event in ListModus object but no further "
359 "data found in single provided file. Please, check your setup.");
365 std::string event_string{};
366 const std::string needle =
" end ";
368 while (getline(ifs, line)) {
369 if (line.find(needle) == std::string::npos) {
370 event_string += line +
"\n";
376 if (!ifs.eof() && (ifs.fail() || ifs.bad())) {
378 logg[
LList].fatal() <<
"Error while reading "
379 << fpath.filename().native();
381 throw std::runtime_error(
"Error while reading external particle list");
391 std::streampos last_position) {
392 std::ifstream ifs{filepath};
397 if (last_position == -1) {
400 ifs.seekg(last_position);
403 int skipped_lines = 0;
404 const int max_comment_lines = 4;
405 while (std::getline(ifs, line) && line[0] !=
'#' &&
406 skipped_lines++ < max_comment_lines) {
415 logg[
LList].fatal() <<
"Error while reading "
416 << filepath.filename().native();
418 throw std::runtime_error(
"Error while reading external particle list");
434 utility_copy.warn_about_mass_discrepancy_ =
false;
435 utility_copy.warn_about_off_shell_particles_ =
false;
436 bool are_there_faulty_events =
false;
440 utility_copy.read_particles_from_next_event_(particles);
442 are_there_faulty_events =
true;
444 utility_copy.event_id_++;
445 }
catch (
const std::exception &) {
449 if (are_there_faulty_events) {
451 "More than 2 particles with the same 4-position have been found in the "
452 "same event.\nPlease, check your particles list file.");
459 std::array<bool, 4> has_spin{{
false,
false,
false,
false}};
461 if (
field ==
"spin0") {
463 }
else if (
field ==
"spinx") {
465 }
else if (
field ==
"spiny") {
467 }
else if (
field ==
"spinz") {
471 for (
int c = 0; c < 4; ++c) {
473 throw std::invalid_argument(
474 "When spin interactions are enabled, all four spin components "
475 "(spin0, spinx, spiny, spinz) must be provided in the config "
499 this->ListModus::operator=(
ListModus(std::move(modus_config), param));
503 const OutputsList &output_list) {
511 data.set_4position(position);
514 std::make_unique<WallcrossingAction>(incoming_particle, data);
515 for (
const auto &output : output_list) {
516 if (!output->is_dilepton_output() && !output->is_photon_output()) {
517 output->at_interaction(*action, 0.);
523 logg[
LList].debug(
"Moved ", wraps,
" particles back into the box.");
546 std::map<std::string, int> checker{};
547 for (
const auto &
p : particles) {
550 bool error_found =
false;
551 for (
const auto &[key, value] : checker) {
553 logg[
LList].error() <<
"Event " <<
event <<
": Found " << value
554 <<
" particles at same position " << key;
Generic algorithms on containers and ranges.
Interface to the SMASH configuration files.
bool has_value(const Key< T > &key) const
Return whether there is a non-empty value behind the requested key (which is supposed not to refer to...
T take(const Key< T > &key)
The default interface for SMASH to read configuration values.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
const double length_
Length of the cube's edge in fm.
int impose_boundary_conditions(Particles *particles, const OutputsList &output_list={})
Enforces that all particles are inside the box at the beginning of an event.
ListBoxModus(Configuration modus_config, const ExperimentParameters ¶meters)
Constructor (This is the same as for the ListModus)
ListModus: Provides a modus for running SMASH on an external particle list, for example as an afterbu...
bool file_has_events_(std::filesystem::path filepath, std::streampos last_position)
Check if the given file has events left after the given position.
std::optional< int > file_id_
The id of the current file.
std::string particle_list_filename_or_prefix_
Prefix of the file(s) containing the particle list.
void backpropagate_to_same_time_if_needed_(Particles &particles)
Judge whether times are the same for all the particles; don't do anti-freestreaming if all particles ...
void validate_optional_fields_() const
Validate the optional fields.
std::filesystem::path file_path_(std::optional< int > file_id)
Return the absolute path of the data file.
SpinInteractionType spin_interaction_type_
Auxiliary flag to indicate the type of spin interaction used.
std::string particle_list_file_directory_
File directory of the particle list.
void validate_list_of_particles_of_all_events_() const
Read and validate all events particles.
void read_particles_from_next_event_(Particles &particles)
Read the next event from file.
double start_time_
Starting time for the List; changed to the earliest formation time.
ListModus()=default
Construct an empty list.
bool verbose_
Flag to suppress some error messages.
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, const std::vector< std::string > &optional_quantities={})
Tries to add a new particle to particles and performs consistency checks: (i) The PDG code is legal a...
std::streampos last_read_position_
Last read position in current file.
bool warn_about_mass_discrepancy_
Auxiliary flag to warn about mass-discrepancies only once per instance.
bool warn_about_off_shell_particles_
Auxiliary flag to warn about off-shell particles only once per instance.
std::string next_event_()
Read the next event.
std::vector< std::string > optional_fields_
Fields with optional quantities to be read.
void insert_optional_quantities_to_(ParticleData &p, const std::vector< std::string > &optional_quantities) const
Sets the optional fields given in the input list into a particle.
double initial_conditions(Particles *particles, const ExperimentParameters ¶meters)
Generates initial state of the particles in the system according to a list.
int event_id_
The unique id of the current event.
ParticleData contains the dynamic information of a certain particle.
static bool exists(PdgCode pdgcode)
The Particles class abstracts the storage and manipulation of particles.
const ParticleData & insert(const ParticleData &p)
Inserts the particle into the list of particles.
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
int charge() const
The charge of the particle.
Collection of useful constants that are known at compile time.
@ Off
No spin interactions.
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
std::basic_ostream< CharT, Traits > & field(std::basic_ostream< CharT, Traits > &s)
Stream modifier to align the next object to a specific width w.
bool is_valid_process_type(int v)
ProcessType
ProcessTypes are used to identify the type of the process.
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.
build_vector_< Line > line_parser(const std::string &input)
Helper function for parsing particles.txt and decaymodes.txt.
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
static constexpr int LList
ParticleData create_valid_smash_particle_matching_provided_quantities(PdgCode pdgcode, double mass, const FourVector &four_position, const FourVector &four_momentum, int log_area, bool &mass_warning, bool &on_shell_warning)
This function creates a SMASH particle validating the provided information.
constexpr double really_small
Numerical error tolerance.
void backpropagate_straight_line(Particles *particles, double to_time)
std::string build_error_string(std::string message, const Line &line)
Builds a meaningful error message.
static bool is_list_of_particles_invalid(const Particles &, int)
Helper structure for Experiment.
int n_ensembles
Number of parallel ensembles.
SpinInteractionType spin_interaction_type
Whether to include spin interactions.
A structure to hold information about the history of the particle, e.g.
double time_last_collision
Time of the last action (excluding walls), time of kinetic freeze_out for HBT analysis this time shou...
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
Line consists of a line number and the contents of that line.
Used when external particle list is invalid.
Used when external particle list cannot be found.