Version: SMASH-3.4
isoparticletype.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2022,2024,2026
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
7 
9 
10 #include <filesystem>
11 
12 #include "smash/filelock.h"
13 #include "smash/integrate.h"
14 #include "smash/logging.h"
15 
16 namespace smash {
17 static constexpr int LParticleType = LogArea::ParticleType::id;
18 
19 static IsoParticleTypeList iso_type_list;
20 static std::vector<const IsoParticleType *> iso_baryon_resonances;
21 
22 const std::vector<const IsoParticleType *>
24  if (iso_baryon_resonances.empty()) {
25  // Initialize.
26  for (const auto &res : IsoParticleType::list_all()) {
27  const auto baryon_number = res.states_[0]->pdgcode().baryon_number();
28  if (res.states_[0]->is_stable() || (baryon_number <= 0)) {
29  continue;
30  }
31  iso_baryon_resonances.push_back(&res);
32  }
33  }
34  return iso_baryon_resonances;
35 }
36 
37 IsoParticleType::IsoParticleType(const std::string &n, double m, double w,
38  unsigned int s, Parity p)
39  : name_(n), mass_(m), width_(w), spin_(s), parity_(p) {}
40 
41 const IsoParticleTypeList &IsoParticleType::list_all() { return iso_type_list; }
42 
43 /// Helper function for IsoParticleType::try_find and friends.
44 static IsoParticleType *try_find_private(const std::string &name) {
45  auto found =
46  std::lower_bound(iso_type_list.begin(), iso_type_list.end(), name,
47  [](const IsoParticleType &l, const std::string &r) {
48  return l.name() < r;
49  });
50  if (found == iso_type_list.end() || found->name() != name) {
51  return {}; // The default constructor creates an invalid pointer.
52  }
53  return &*found;
54 }
55 
56 const IsoParticleType *IsoParticleType::try_find(const std::string &name) {
57  return try_find_private(name);
58 }
59 
60 const IsoParticleType &IsoParticleType::find(const std::string &name) {
61  const auto found = try_find_private(name);
62  if (!found) {
63  throw ParticleNotFoundFailure("Isospin multiplet " + name + " not found!");
64  }
65  return *found;
66 }
67 
69  auto found = try_find_private(name);
70  if (!found) {
71  throw ParticleNotFoundFailure("Isospin multiplet " + name +
72  " not found (privately)!");
73  }
74  return *found;
75 }
76 
77 bool IsoParticleType::exists(const std::string &name) {
78  const auto found = try_find_private(name);
79  return found;
80 }
81 
82 /**
83  * Construct the name-string for an isospin multiplet from the given
84  * name-string for the particle.
85  *
86  * \param[in] name name-string of the particle
87  * \return the name-string for an isospin multiplet
88  */
89 static std::string multiplet_name(std::string name) {
90  if (name.find("⁺⁺") != std::string::npos) {
91  return name.substr(0, name.length() - sizeof("⁺⁺") + 1);
92  } else if (name.find("⁺") != std::string::npos) {
93  return name.substr(0, name.length() - sizeof("⁺") + 1);
94  } else if (name.find("⁻⁻") != std::string::npos) {
95  return name.substr(0, name.length() - sizeof("⁻⁻") + 1);
96  } else if (name.find("⁻") != std::string::npos) {
97  return name.substr(0, name.length() - sizeof("⁻") + 1);
98  } else if (name.find("⁰") != std::string::npos) {
99  return name.substr(0, name.length() - sizeof("⁰") + 1);
100  } else {
101  return name;
102  }
103 }
104 
106  if (states_[0]->has_antiparticle()) {
107  ParticleTypePtr anti = states_[0]->get_antiparticle();
108  if (states_[0]->name() != multiplet_name(anti->name())) {
109  return anti->iso_multiplet();
110  } else {
111  return nullptr;
112  }
113  } else {
114  return nullptr;
115  }
116 }
117 
119  return anti_multiplet() != nullptr;
120 }
121 
122 const ParticleTypePtr IsoParticleType::find_state(const std::string &n) {
123  const auto name = multiplet_name(n);
124  const IsoParticleType &multiplet = IsoParticleType::find(name);
125  auto found = std::find_if(multiplet.states_.begin(), multiplet.states_.end(),
126  [&n](ParticleTypePtr p) { return p->name() == n; });
127  if (found == multiplet.states_.end()) {
128  throw std::runtime_error("Isospin state " + n + " not found!");
129  }
130  return *found;
131 }
132 
134  std::string multiname = multiplet_name(type.name());
135  IsoParticleType &multiplet = find_private(multiname);
136  return &multiplet;
137 }
138 
140  states_.push_back(&type);
141 
142  // check if isospin symmetry is fulfilled
143  if (std::abs(mass() - type.mass()) > really_small) {
144  logg[LParticleType].warn()
145  << "Isospin symmetry is broken by mass of " << type.name() << ": "
146  << type.mass() << " vs. " << mass();
147  }
148  if (std::abs(width() - type.width_at_pole()) > really_small) {
149  logg[LParticleType].warn()
150  << "Isospin symmetry is broken by width of " << type.name() << ": "
151  << type.width_at_pole() << " vs. " << width();
152  }
153  if (spin() != type.spin()) {
154  logg[LParticleType].error()
155  << "Isospin symmetry is broken by spin of " << type.name() << ": "
156  << type.spin() << " vs. " << spin();
157  }
158 }
159 
161  // create multiplet if it does not exist yet
162  std::string multiname = multiplet_name(type.name());
163  if (!exists(multiname)) {
164  iso_type_list.emplace_back(multiname, type.mass(), type.width_at_pole(),
165  type.spin(), type.parity());
166  logg[LParticleType].debug()
167  << "Creating isospin multiplet " << multiname
168  << " [ m = " << type.mass() << ", Γ = " << type.width_at_pole() << " ]";
169  }
170 
171  // sort the iso-type list by name
172  std::sort(iso_type_list.begin(), iso_type_list.end(),
173  [](const IsoParticleType &l, const IsoParticleType &r) {
174  return l.name() < r.name();
175  });
176 
177  // add the specific type to the multiplet
178  IsoParticleType &multiplet = find_private(multiname);
179  multiplet.add_state(type);
180 }
181 
184 
185 /**
186  * Tabulation of all N R integrals.
187  *
188  * Keys are the multiplet names (which are unique).
189  */
190 static std::unordered_map<std::string, Tabulation> NR_tabulations;
191 
192 /**
193  * Tabulation of all pi R integrals.
194  *
195  * Keys are the multiplet names (which are unique).
196  */
197 static std::unordered_map<std::string, Tabulation> piR_tabulations;
198 
199 /**
200  * Tabulation of all K R integrals.
201  *
202  * Keys are the multiplet names (which are unique).
203  */
204 static std::unordered_map<std::string, Tabulation> RK_tabulations;
205 
206 /**
207  * Tabulation of all Delta R integrals.
208  *
209  * Keys are the pairs of multiplet names (which are unique).
210  */
211 static std::unordered_map<std::string, Tabulation> DeltaR_tabulations;
212 
213 /**
214  * Tabulation of all rho rho integrals.
215  *
216  * Keys are the pairs of multiplet names (which are unique).
217  */
218 static std::unordered_map<std::string, Tabulation> rhoR_tabulations;
219 
220 static std::filesystem::path generate_tabulation_path(
221  const std::filesystem::path &dir, const std::string &prefix,
222  const std::string &res_name) {
223  return dir / (prefix + res_name + ".bin");
224 }
225 
226 static bool cache_integral(
227  std::unordered_map<std::string, Tabulation> &tabulations,
228  const std::filesystem::path &dir, sha256::Hash hash,
229  const IsoParticleType &part, const IsoParticleType &res,
230  const IsoParticleType *antires, bool unstable) {
231  constexpr double spacing = 2.0;
232  constexpr double spacing2d = 3.0;
233  const auto path = generate_tabulation_path(dir, part.name_filtered_prime(),
234  res.name_filtered_prime());
235  bool loaded_from_file = false;
236  /* This is a static variable to keep track of the length of the previous
237  * status message. It is used to overwrite the previous message with spaces if
238  * the new message is shorter, ensuring that the console output remains clean
239  * and readable also across multiple function calls. */
240  static std::size_t previous_length = 0;
241  const auto print_status = [](std::string_view msg) {
242  std::string output{msg};
243  if (output.size() < previous_length) {
244  output.append(previous_length - output.size(), ' ');
245  }
246  previous_length = output.size();
247  std::cout << output << '\r' << std::flush;
248  };
249  Tabulation integral;
250  if (!dir.empty() && std::filesystem::exists(path)) {
251  std::ifstream file(path.string());
252  integral = Tabulation::from_file(file, hash);
253  }
254  if (integral.is_empty()) {
255  const auto particle_names =
257  print_status("Calculating integral for " + particle_names);
258  if (!unstable) {
259  integral = spectral_integral_semistable(integrate, *res.get_states()[0],
260  *part.get_states()[0], spacing);
261  } else {
262  integral = spectral_integral_unstable(integrate2d, *res.get_states()[0],
263  *part.get_states()[0], spacing2d);
264  }
265 
266  if (!dir.empty()) {
267  // To avoid race conditions, make sure that this is the only instance
268  // writing the tabulation to file.
269  FileLock lock(dir / (particle_names + ".lock"));
270  if (lock.acquire()) {
271  print_status("Caching tabulation to " + path.filename().string());
272  std::ofstream file(path.string());
273  integral.write(file, hash);
274  } else {
275  print_status("Another instance is caching the tabulation to " +
276  path.filename().string() +
277  ", skipping caching for this instance");
278  }
279  }
280  } else {
281  // Only print message if the found tabulation was valid.
282  print_status("Tabulation found at " + path.filename().string());
283  loaded_from_file = true;
284  }
285  tabulations.emplace(std::make_pair(res.name(), integral));
286  if (antires != nullptr) {
287  tabulations.emplace(std::make_pair(antires->name(), integral));
288  }
289  return loaded_from_file;
290 }
291 
293  const std::filesystem::path &dir) {
294  /**
295  * We avoid race conditions by locking each tabulation file separately. This
296  * allows multiple instances of SMASH to run in parallel and tabulate the same
297  * integrals without interfering with each other. Reading them simultaneously
298  * is not a problem, and writing is protected by the lock. The only downside
299  * is that the same integral might be calculated multiple times if several
300  * instances start at the same time and find that the tabulation file does not
301  * yet exist.
302  */
303  const int num_integrals =
305  int num_loaded_integrals = 0;
306  const auto nuc = IsoParticleType::try_find("N");
307  const auto pion = IsoParticleType::try_find("π");
308  const auto kaon = IsoParticleType::try_find("K");
309  const auto delta = IsoParticleType::try_find("Δ");
310  const auto rho = IsoParticleType::try_find("ρ");
311  const auto h1 = IsoParticleType::try_find("h₁(1170)");
312  for (const auto &res : IsoParticleType::list_baryon_resonances()) {
313  const auto antires = res->anti_multiplet();
314  if (nuc) {
315  num_loaded_integrals +=
316  cache_integral(NR_tabulations, dir, hash, *nuc, *res, antires, false);
317  }
318  if (pion) {
319  num_loaded_integrals += cache_integral(piR_tabulations, dir, hash, *pion,
320  *res, antires, false);
321  }
322  if (kaon) {
323  num_loaded_integrals += cache_integral(RK_tabulations, dir, hash, *kaon,
324  *res, antires, false);
325  }
326  if (delta) {
327  num_loaded_integrals += cache_integral(DeltaR_tabulations, dir, hash,
328  *delta, *res, antires, true);
329  }
330  }
331  if (rho) {
332  num_loaded_integrals +=
333  cache_integral(rhoR_tabulations, dir, hash, *rho, *rho, nullptr, true);
334  }
335  if (rho && h1) {
336  num_loaded_integrals +=
337  cache_integral(rhoR_tabulations, dir, hash, *rho, *h1, nullptr, true);
338  }
339  logg[LParticleType].info()
340  << "Tabulation of integrals complete: " << num_loaded_integrals << "/"
341  << num_integrals << " integrals loaded from file, "
342  << num_integrals - num_loaded_integrals << " integrals calculated.";
343 }
344 
345 double IsoParticleType::get_integral_NR(double sqrts) {
346  if (XS_NR_tabulation_ == nullptr) {
347  const auto res = states_[0]->iso_multiplet();
348  XS_NR_tabulation_ = &NR_tabulations.at(res->name());
349  }
350  return XS_NR_tabulation_->get_value_linear(sqrts);
351 }
352 
353 double IsoParticleType::get_integral_piR(double sqrts) {
354  if (XS_piR_tabulation_ == nullptr) {
355  const auto res = states_[0]->iso_multiplet();
356  XS_piR_tabulation_ = &piR_tabulations.at(res->name());
357  }
358  return XS_piR_tabulation_->get_value_linear(sqrts);
359 }
360 
361 double IsoParticleType::get_integral_RK(double sqrts) {
362  if (XS_RK_tabulation_ == nullptr) {
363  const auto res = states_[0]->iso_multiplet();
364  XS_RK_tabulation_ = &RK_tabulations.at(res->name());
365  }
366  return XS_RK_tabulation_->get_value_linear(sqrts);
367 }
368 
370  if (XS_rhoR_tabulation_ == nullptr) {
371  const auto res = states_[0]->iso_multiplet();
372  XS_rhoR_tabulation_ = &rhoR_tabulations.at(res->name());
373  }
374  return XS_rhoR_tabulation_->get_value_linear(sqrts);
375 }
376 
378  double sqrts) {
379  const auto res = states_[0]->iso_multiplet();
380  if (type_res_2->states_[0]->is_Delta()) {
381  if (XS_DeltaR_tabulation_ == nullptr) {
382  XS_DeltaR_tabulation_ = &DeltaR_tabulations.at(res->name());
383  }
385  }
386  if (type_res_2->name() == "ρ") {
387  if (XS_rhoR_tabulation_ == nullptr) {
388  XS_rhoR_tabulation_ = &rhoR_tabulations.at(res->name());
389  }
390  return XS_rhoR_tabulation_->get_value_linear(sqrts);
391  }
392  if (type_res_2->name() == "h₁(1170)") {
393  if (XS_rhoR_tabulation_ == nullptr) {
394  XS_rhoR_tabulation_ = &rhoR_tabulations.at(res->name());
395  }
396  return XS_rhoR_tabulation_->get_value_linear(sqrts);
397  }
398  std::stringstream err;
399  err << "RR=" << name() << type_res_2->name() << " is not implemented";
400  throw std::runtime_error(err.str());
401 }
402 
403 } // namespace smash
Guard to create a file lock.
Definition: filelock.h:30
bool acquire()
Try to acquire the file lock.
Definition: filelock.cc:22
A C++ interface for numerical integration in two dimensions with the Cuba Cuhre integration function.
Definition: integrate.h:219
A C++ interface for numerical integration in one dimension with the GSL CQUAD integration functions.
Definition: integrate.h:106
IsoParticleType is a class to represent isospin multiplets.
void add_state(const ParticleType &type)
Add a new state to an existing multiplet (and check if isospin symmetry is fulfilled).
static const IsoParticleType * try_find(const std::string &name)
Returns the IsoParticleType pointer for the given name.
Tabulation * XS_NR_tabulation_
A tabulation for the NN -> NR cross sections, where R is a resonance from this multiplet.
Tabulation * XS_rhoR_tabulation_
A tabulation for the ρρ integrals.
static bool exists(const std::string &name)
Returns whether the ParticleType with the given pdgcode exists.
double width() const
Returns the (average) multiplet width.
static const IsoParticleType & find(const std::string &name)
Returns the IsoParticleType object for the given name.
double get_integral_RR(IsoParticleType *type_res_2, double sqrts)
Look up the tabulated resonance integral for the XX -> RR cross section.
const std::string name_filtered_prime() const
Returns the name of the multiplet, after replacing "'" with "_prime".
static IsoParticleType & find_private(const std::string &name)
Private version of the 'find' method that returns a non-const reference.
static void tabulate_integrals(sha256::Hash hash, const std::filesystem::path &tabulations_path)
Tabulate all relevant integrals.
Tabulation * XS_piR_tabulation_
A tabulation of the spectral integral for the dpi -> d'pi cross sections.
static void create_multiplet(const ParticleType &type)
Add a new multiplet to the global list of IsoParticleTypes, which contains type.
ParticleTypePtrList states_
list of states that are contained in the multiplet
bool has_anti_multiplet() const
Check if there is a multiplet of antiparticles, which is different from the original multiplet.
IsoParticleType(const std::string &n, double m, double w, unsigned int s, Parity p)
Creates a fully initialized IsoParticleType object.
double get_integral_NR(double sqrts)
Look up the tabulated resonance integral for the XX -> NR cross section.
static const IsoParticleTypeList & list_all()
Returns a list of all IsoParticleTypes.
double mass() const
Returns the (average) multiplet mass.
Tabulation * XS_DeltaR_tabulation_
A tabulation for the NN -> RΔ cross sections, where R is a resonance from this multiplet.
const IsoParticleType * anti_multiplet() const
Return a multiplet of antiparticles, if it is different from the original multiplet.
const std::string & name() const
Returns the name of the multiplet.
double get_integral_rhoR(double sqrts)
Look up the tabulated resonance integral for the XX -> rhoR cross section.
static const std::vector< const IsoParticleType * > list_baryon_resonances()
Returns a list of all IsoParticleTypes that are baryon resonances.
double get_integral_RK(double sqrts)
Look up the tabulated resonance integral for the XX -> RK cross section.
unsigned int spin() const
Returns twice the spin of the multiplet.
ParticleTypePtrList get_states() const
Returns list of states that form part of the multiplet.
Tabulation * XS_RK_tabulation_
A tabulation of the spectral integral for the NK -> RK cross sections.
double get_integral_piR(double sqrts)
Look up the tabulated resonance integral for the XX -> piR cross section.
static const ParticleTypePtr find_state(const std::string &name)
Returns the ParticleType object for the given name, by first finding the correct multiplet and then l...
A pointer-like interface to global references to ParticleType objects.
Definition: particletype.h:731
Particle type contains the static properties of a particle species.
Definition: particletype.h:100
const std::string & name() const
Definition: particletype.h:144
double width_at_pole() const
Definition: particletype.h:153
double mass() const
Definition: particletype.h:147
unsigned int spin() const
Definition: particletype.h:194
IsoParticleType * iso_multiplet() const
Definition: particletype.h:188
Parity parity() const
Definition: particletype.h:156
A class for storing a one-dimensional lookup table of floating-point values.
Definition: tabulation.h:30
double get_value_linear(double x, ExtrapolationType extrapolation=ExtrapolationType::Linear) const
Look up a value from the tabulation using linear interpolation.
Definition: tabulation.cc:40
static Tabulation from_file(std::ifstream &stream, sha256::Hash hash)
Construct a tabulation object by reading binary data from a stream.
Definition: tabulation.cc:176
void write(std::ofstream &stream, sha256::Hash hash) const
Write a binary representation of the tabulation to a stream.
Definition: tabulation.cc:168
bool is_empty() const
Definition: tabulation.h:54
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
Definition: logging.h:245
constexpr Section output
Section for the output information.
Definition: input_keys.h:205
constexpr int p
Proton.
constexpr int h1
h₁(1170).
constexpr int n
Neutron.
std::array< uint8_t, HASH_SIZE > Hash
A SHA256 hash.
Definition: sha256.h:25
Definition: action.h:24
static Integrator integrate
Definition: decaytype.cc:143
static IsoParticleTypeList iso_type_list
static std::unordered_map< std::string, Tabulation > NR_tabulations
Tabulation of all N R integrals.
static std::unordered_map< std::string, Tabulation > RK_tabulations
Tabulation of all K R integrals.
static std::filesystem::path generate_tabulation_path(const std::filesystem::path &dir, const std::string &prefix, const std::string &res_name)
static bool cache_integral(std::unordered_map< std::string, Tabulation > &tabulations, const std::filesystem::path &dir, sha256::Hash hash, const IsoParticleType &part, const IsoParticleType &res, const IsoParticleType *antires, bool unstable)
Tabulation spectral_integral_semistable(Integrator &integrate, const ParticleType &resonance, const ParticleType &stable, double range)
Create a table for the spectral integral of a resonance and a stable particle.
Definition: tabulation.h:198
static Integrator2d integrate2d(1E7)
Parity
Represent the parity of a particle type.
Definition: particletype.h:27
static std::unordered_map< std::string, Tabulation > piR_tabulations
Tabulation of all pi R integrals.
static std::unordered_map< std::string, Tabulation > DeltaR_tabulations
Tabulation of all Delta R integrals.
static std::unordered_map< std::string, Tabulation > rhoR_tabulations
Tabulation of all rho rho integrals.
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
Tabulation spectral_integral_unstable(Integrator2d &integrate2d, const ParticleType &res1, const ParticleType &res2, double range)
Create a table for the spectral integral of two resonances.
Definition: tabulation.h:220
static std::string multiplet_name(std::string name)
Construct the name-string for an isospin multiplet from the given name-string for the particle.
static std::vector< const IsoParticleType * > iso_baryon_resonances
static IsoParticleType * try_find_private(const std::string &name)
Helper function for IsoParticleType::try_find and friends.
static constexpr int LParticleType
Throw when requested particle could not be found.