Version: SMASH-3.4
particles.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2018,2020,2022-2023
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
7 #ifndef SRC_INCLUDE_SMASH_PARTICLES_H_
8 #define SRC_INCLUDE_SMASH_PARTICLES_H_
9 
10 #include <memory>
11 #include <type_traits>
12 #include <vector>
13 
14 #include "macros.h"
15 #include "particledata.h"
16 #include "particletype.h"
17 #include "pdgcode.h"
18 
19 namespace smash {
20 
21 /**
22  * \ingroup data
23  *
24  * The Particles class abstracts the storage and manipulation of particles.
25  *
26  * There is one Particles object per Experiment. It stores
27  * the data about all existing particles in the experiment (ParticleData).
28  *
29  * \note
30  * The Particles object cannot be copied, because it does not make sense
31  * semantically. Move semantics make sense and can be implemented when needed.
32  */
33 class Particles {
34  public:
35  /// Creates a new (empty) Particles object.
36  Particles();
37 
38  /// Cannot be copied
39  Particles(const Particles &) = delete;
40  /// Cannot be copied
41  Particles &operator=(const Particles &) = delete;
42 
43  /// \return a copy of all particles as a std::vector<ParticleData>.
44  ParticleList copy_to_vector() const {
45  if (dirty_.empty()) {
46  return {&data_[0], &data_[data_size_]};
47  }
48  return {begin(), end()};
49  }
50 
51  /**
52  * Inserts the particle \p into the list of particles.
53  * The argument \p will afterwards not be a valid copy of a particle of the
54  * internal list. I.e.
55  * \code
56  * ParticleData particle(type);
57  * particles.insert(particle);
58  * particles.is_valid(particle); // returns false
59  * \endcode
60  *
61  * \param[in] p The data to be added. The id will not be copied. Instead a new
62  * unique id is generated by the function.
63  *
64  * \return An immutable reference to the new ParticleData object in the
65  * Particles list. This is a valid copy (i.e. Particles::is_valid returns
66  * true).
67  */
68  const ParticleData &insert(const ParticleData &p);
69 
70  /**
71  * Add \p n particles of the same type (\p pdg) to the list.
72  *
73  * \param[in] n The number of the added particles
74  * \param[in] pdg PDG code of the added particles
75  */
76  void create(size_t n, PdgCode pdg);
77 
78  /**
79  * Add one particle of the given \p pdg code
80  *
81  * \param[in] pdg PDG code of the added particle
82  * \return a reference to the added particle
83  */
84  ParticleData &create(const PdgCode pdg);
85 
86  /// \return the number of particles in the list.
87  size_t size() const { return data_size_ - dirty_.size(); }
88 
89  /// \return whether the list of particles is empty.
90  bool is_empty() const { return data_size_ == 0; }
91 
92  /**
93  * Returns the time of the computational frame.
94  *
95  * \return computation time which is reduced by the start up time
96  *
97  * \note This function may only be called if the list of particles is not
98  * empty.
99  */
100  double time() const {
101  assert(!is_empty());
102  return front().position().x0();
103  }
104 
105  /**
106  * Reset the state of the Particles object to an empty list and a new id
107  * counter. The object is thus in the same state as right after construction.
108  */
109  void reset();
110 
111  /**
112  * Check whether the ParticleData copy is still a valid copy of the one
113  * stored in the Particles object.
114  *
115  * \param[in] copy ParticleData copy whose validity is going to be checked
116  * \return whether ParticleData copy is still valid. If not, then the
117  * particle either never was a valid copy or it has interacted
118  * (e.g. scatter, decay) since it was copied.
119  */
120  bool is_valid(const ParticleData &copy) const {
121  if (data_size_ <= copy.index_) {
122  return false;
123  }
124  /* Check if the particles still exists. If it decayed
125  * or scattered inelastically it is gone. */
126  return data_[copy.index_].id() == copy.id()
127  /* If the particle has scattered
128  * elastically, its id_process has
129  * changed and we consider it invalid. */
130  && data_[copy.index_].id_process() == copy.id_process();
131  }
132 
133  /**
134  * Remove the given particle \p p from the list. The argument \p p must be a
135  * valid copy obtained from Particles, i.e. a call to \ref is_valid must
136  * return \c true.
137  *
138  * \param[in] p Particle which is going to be removed
139  * \note The validity of \p p is only enforced in DEBUG builds.
140  */
141  void remove(const ParticleData &p);
142 
143  /**
144  * Replace the particles in \p to_remove with the particles in \p to_add in
145  * the list of current particles. The particles in \p to_remove must be valid
146  * copies obtained from Particles. The particles in \p to_add are adjusted
147  * to be valid copies of the new particles in the Particles list.
148  *
149  * \param[in] to_remove A list of particles which are valid copies out of the
150  * Particles list. They identify the entries in Particles to be
151  * replaced.
152  * \param[in] to_add A list of (invalid) ParticleData objects to be placed
153  * into the Particles list.
154  *
155  * \note The validity of \p to_remove is only enforced in DEBUG builds.
156  */
157  void replace(const ParticleList &to_remove, ParticleList &to_add);
158 
159  /**
160  * Updates the particle identified by \p p with the state stored in \p
161  * new_state. A reference to the resulting ParticleData object in the list is
162  * subsequently returned.
163  *
164  * The state update copies the id_process, momentum, and position from \p
165  * new_state.
166  *
167  * This function expects \p p to be a valid copy (i.e. is_valid returns \c
168  * true) and it expects the ParticleType of \p p and \p new_state to be
169  * equal. This is enforced in DEBUG builds.
170  *
171  * \param[in] p The particle which is going to be updated.
172  * \param[in] new_state The new state of the particle.
173  * \return Updated particle
174  */
176  const ParticleData &new_state) {
177  assert(is_valid(p));
178  assert(p.type() == new_state.type());
179  ParticleData &original = data_[p.index_];
180  new_state.copy_to(original);
181  return original;
182  }
183 
184  /**
185  * Updates the Particles object, replacing the particles in \p old_state with
186  * the particles in \p new_state.
187  *
188  * The third parameter \p do_replace determines whether the particles are
189  * actually replaced (so that they get new IDs etc) or if the old particles
190  * are kept and just updated with new properties (e.g. in an elastic
191  * collision).
192  *
193  * This function expects \p old_state to be a valid copy (i.e. is_valid
194  * returns \c true). This is enforced in DEBUG builds.
195  *
196  * \param[in] old_state Particles of old states
197  * \param[in] new_state New states of these particles
198  * \param[in] do_replace Whether to replace the old states by the new ones
199  */
200  void update(const ParticleList &old_state, ParticleList &new_state,
201  bool do_replace) {
202  if (do_replace) {
203  replace(old_state, new_state);
204  } else {
205  for (std::size_t i = 0; i < old_state.size(); ++i) {
206  new_state[i] = update_particle(old_state[i], new_state[i]);
207  }
208  }
209  }
210 
211  /**
212  * Returns the particle that is currently stored in this object given an old
213  * copy of that particle.
214  *
215  * This function expects \p old_state to be a valid copy (i.e. is_valid
216  * returns \c true). This is enforced in DEBUG builds.
217  *
218  * \param[in] old_state A copy of old state particle. We need its index to
219  * know where it's stored in the particles list.
220  * \return The currrent state of the particle which is searched.
221  */
222  const ParticleData &lookup(const ParticleData &old_state) const {
223  assert(is_valid(old_state));
224  return data_[old_state.index_];
225  }
226 
227  /**
228  * \internal
229  * Iterator type that skips over the holes in `data_`. It implements a
230  * standard bidirectional iterator over the ParticleData objects in Particles.
231  * <b>Each iterator must expose 5 types to correctly interact with the
232  * STL</b>:
233  * - \c iterator_category
234  * - \c value_type
235  * - \c difference_type
236  * - \c pointer
237  * - \c reference
238  *
239  * Prior to C++17 it was common habit to inherit from \c std::iterator to
240  * simplify the implementation of user-defined iterators, but this turned out
241  * not to be the most readable choice and this habit has been deprecated in
242  * C++17. It is simply better to explicitly expose the 5 types.
243  */
244  template <typename T>
246  friend class Particles;
247 
248  public:
249  /// <b>Required by STL:</b> expose iterator_category
250  using iterator_category = std::bidirectional_iterator_tag;
251  /// <b>Required by STL:</b> expose value_type removing const qualification
252  using value_type = std::remove_const_t<T>;
253  /// <b>Required by STL:</b> expose difference_type
254  using difference_type = std::ptrdiff_t;
255  /// <b>Required by STL:</b> expose pointer (of a reference)
256  using pointer = std::add_pointer_t<T>;
257  /// <b>Required by STL:</b> expose reference (lvalue)
258  using reference = std::add_lvalue_reference_t<T>;
259  /// add const qualification to a pointer
260  using const_pointer = std::add_const_t<pointer>;
261  /// add const qualification to a reference
262  using const_reference = std::add_const_t<reference>;
263 
264  private:
265  /**
266  * Constructs an iterator pointing to the ParticleData pointed to by \p p.
267  * This constructor may only be called from the Particles class.
268  *
269  * \param[in] p The particle which is pointed by the iterator.
270  */
271  GenericIterator(pointer p) : ptr_(p) {} // NOLINT(runtime/explicit)
272 
273  /// The entry in Particles this iterator points to.
275 
276  public:
277  /**
278  * Advance the iterator to the next valid (not a hole) entry in Particles.
279  * Holes are identified by the ParticleData::hole_ member and thus the
280  * internal pointer is incremented until all holes are skipped. It is
281  * important that the Particles entry pointed to by Particles::end() is not
282  * identified as a hole as otherwise the iterator would advance too far.
283  *
284  * \return the iterator to the next valid particle.
285  */
287  do {
288  ++ptr_;
289  } while (ptr_->hole_);
290  return *this;
291  }
292  /**
293  * Postfix variant of the above prefix increment operator.
294  *
295  * \return the iterator before increment.
296  */
298  GenericIterator old = *this;
299  operator++();
300  return old;
301  }
302 
303  /**
304  * Advance the iterator to the previous valid (not a hole) entry in
305  * Particles.
306  * Holes are identified by the ParticleData::hole_ member and thus the
307  * internal pointer is decremented until all holes are skipped. It is
308  * irrelevant whether Particles::data_[0] is a hole because the iteration
309  * typically ends at Particles::begin(), which points to a non-hole entry in
310  * Particles::data_.
311  *
312  * \return the iterator to the previous valid particle.
313  */
315  do {
316  --ptr_;
317  } while (ptr_->hole_);
318  return *this;
319  }
320  /**
321  * Postfix variant of the above prefix decrement operator.
322  *
323  * \return the iterator before decrement.
324  */
326  GenericIterator old = *this;
327  operator--();
328  return old;
329  }
330 
331  /// \return the dereferenced iterator.
332  reference operator*() { return *ptr_; }
333  /// \return the dereferenced iterator.
334  const_reference operator*() const { return *ptr_; }
335 
336  /// \return the dereferenced iterator.
337  pointer operator->() { return ptr_; }
338  /// \return the dereferenced iterator.
339  const_pointer operator->() const { return ptr_; }
340 
341  /// \return whether two iterators point to the same object.
342  bool operator==(const GenericIterator &rhs) const {
343  return ptr_ == rhs.ptr_;
344  }
345  /// \return whether two iterators point to different objects.
346  bool operator!=(const GenericIterator &rhs) const {
347  return ptr_ != rhs.ptr_;
348  }
349  /// \return whether this iterator comes before the iterator \p rhs.
350  bool operator<(const GenericIterator &rhs) const { return ptr_ < rhs.ptr_; }
351  /// \return whether this iterator comes after the iterator \p rhs.
352  bool operator>(const GenericIterator &rhs) const { return ptr_ > rhs.ptr_; }
353  /**
354  * \return whether this iterator comes before the iterator \p rhs or points
355  * to the same object.
356  */
357  bool operator<=(const GenericIterator &rhs) const {
358  return ptr_ <= rhs.ptr_;
359  }
360  /**
361  * \return whether this iterator comes after the iterator \p rhs or points
362  * to the same object.
363  */
364  bool operator>=(const GenericIterator &rhs) const {
365  return ptr_ >= rhs.ptr_;
366  }
367  };
368  /// An alias to the GenericIterator class of ParticleData
370  /// An alias to the GenericIterator class of const ParticleData
372 
373  /// \return a reference to the first particle in the list.
374  ParticleData &front() { return *begin(); }
375  /**
376  * const overload of &front()
377  *
378  * \return a reference to the first particle in the list.
379  */
380  const ParticleData &front() const { return *begin(); }
381 
382  /// \return a reference to the last particle in the list.
383  ParticleData &back() { return *(--end()); }
384  /**
385  * const overload of &back()
386  *
387  * \return a reference to the last particle in the list.
388  */
389  const ParticleData &back() const { return *(--end()); }
390 
391  /**
392  * \return an iterator pointing to the first particle in the list. Use it to
393  * iterate over all particles in the list.
394  */
396  ParticleData *first = &data_[0];
397  while (first->hole_) {
398  ++first;
399  }
400  return first;
401  }
402  /**
403  * const overload of begin()
404  *
405  * \return an iterator pointing to the first particle in the list.
406  */
408  ParticleData *first = &data_[0];
409  while (first->hole_) {
410  ++first;
411  }
412  return first;
413  }
414 
415  /**
416  * \return an iterator pointing behind the last particle in the list. Use it
417  * to iterate over all particles in the list.
418  */
419  iterator end() { return &data_[data_size_]; }
420  /**
421  * const overload of end()
422  *
423  * \return an iterator pointing behind the last particle in the list.
424  */
425  const_iterator end() const { return &data_[data_size_]; }
426 
427  /// \return a const begin iterator.
428  const_iterator cbegin() const { return begin(); }
429  /// \return a const end iterator.
430  const_iterator cend() const { return end(); }
431 
432  /**
433  * \ingroup logging
434  * Print effective mass and type name for all particles to the stream.
435  * \param[in] out The ostream into which to output
436  * \param[in] particles The Particles object to write into out
437  */
438  friend std::ostream &operator<<(std::ostream &out,
439  const Particles &particles);
440 
441  private:
442  /**
443  * Highest id of a given particle. The first particle added to data_ will
444  * have id 0.
445  */
446  int id_max_ = -1;
447 
448  /**
449  * \internal
450  * Increases the capacity of data_ to \p new_capacity.
451  *
452  * \param[in] new_capacity new capacity which is expected to be larger than
453  * data_capacity_. This is enforced in DEBUG builds.
454  */
455  void increase_capacity(unsigned new_capacity);
456  /**
457  * \internal
458  * Ensure that the capacity of data_ is large enough to hold \p to_add more
459  * entries. If the capacity does not sufficient increase_capacity is called.
460  *
461  * \param[in] to_add Number of particles which is going to be added to the
462  * list.
463  */
464  inline void ensure_capacity(unsigned to_add);
465  /**
466  * \internal
467  * Common implementation for copying the relevant data of a ParticleData
468  * object into data_. This does not implement a 1:1 copy, instead:
469  * \li The particle id in data_ is set to the next id for a new particle.
470  * \li The id_process, type, momentum, and position are copied from \p from.
471  * \li The ParticleData::index_ members is not modified since it already has
472  * the correct value
473  * \li The ParticleData::hole_ member is not modified and might need
474  * adjustment in the calling code.
475  *
476  * \param[out] to The copied version of the particle added to the end of the
477  * to particle list.
478  * \param[in] from the original particle that will be copied.
479  */
480  inline void copy_in(ParticleData &to, const ParticleData &from);
481 
482  /**
483  * \internal
484  * The number of elements in data_ (including holes, but excluding entries
485  * behind the last valid particle)
486  */
487  unsigned data_size_ = 0u;
488  /**
489  * \internal
490  * The capacity of the memory pointed to by data_.
491  */
492  unsigned data_capacity_ = 100u;
493  /**
494  * Points to a dynamically allocated array of ParticleData objects. The
495  * allocated size is stored in data_capacity_ and the used range (starting
496  * from index 0) is stored in data_size_.
497  */
498  std::unique_ptr<ParticleData[]> data_;
499 
500  /**
501  * Stores the indexes in data_ that do not hold valid particle data and should
502  * be reused when new particles are added.
503  */
504  std::vector<unsigned> dirty_;
505 };
506 
507 } // namespace smash
508 
509 #endif // SRC_INCLUDE_SMASH_PARTICLES_H_
double x0() const
Definition: fourvector.h:313
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
unsigned index_
Internal index in the Particles list.
Definition: particledata.h:515
const ParticleType & type() const
Get the type of the particle.
Definition: particledata.h:132
bool hole_
If true, the object is an entry in Particles::data_ and does not hold valid particle data.
Definition: particledata.h:535
uint32_t id_process() const
Get the id of the last action.
Definition: particledata.h:138
void copy_to(ParticleData &dst) const
Copies some information of the particle to the given particle dst.
Definition: particledata.h:484
int32_t id() const
Get the id of the particle.
Definition: particledata.h:77
const FourVector & position() const
Get the particle's position in Minkowski space.
Definition: particledata.h:217
bool operator>(const GenericIterator &rhs) const
Definition: particles.h:352
bool operator==(const GenericIterator &rhs) const
Definition: particles.h:342
std::add_const_t< pointer > const_pointer
add const qualification to a pointer
Definition: particles.h:260
std::add_lvalue_reference_t< T > reference
Required by STL: expose reference (lvalue)
Definition: particles.h:258
bool operator<(const GenericIterator &rhs) const
Definition: particles.h:350
std::ptrdiff_t difference_type
Required by STL: expose difference_type
Definition: particles.h:254
std::remove_const_t< T > value_type
Required by STL: expose value_type removing const qualification
Definition: particles.h:252
GenericIterator & operator--()
Advance the iterator to the previous valid (not a hole) entry in Particles.
Definition: particles.h:314
const_reference operator*() const
Definition: particles.h:334
GenericIterator operator--(int)
Postfix variant of the above prefix decrement operator.
Definition: particles.h:325
const_pointer operator->() const
Definition: particles.h:339
GenericIterator operator++(int)
Postfix variant of the above prefix increment operator.
Definition: particles.h:297
bool operator<=(const GenericIterator &rhs) const
Definition: particles.h:357
bool operator!=(const GenericIterator &rhs) const
Definition: particles.h:346
pointer ptr_
The entry in Particles this iterator points to.
Definition: particles.h:274
GenericIterator & operator++()
Advance the iterator to the next valid (not a hole) entry in Particles.
Definition: particles.h:286
GenericIterator(pointer p)
Constructs an iterator pointing to the ParticleData pointed to by p.
Definition: particles.h:271
std::add_pointer_t< T > pointer
Required by STL: expose pointer (of a reference)
Definition: particles.h:256
std::bidirectional_iterator_tag iterator_category
Required by STL: expose iterator_category
Definition: particles.h:250
bool operator>=(const GenericIterator &rhs) const
Definition: particles.h:364
std::add_const_t< reference > const_reference
add const qualification to a reference
Definition: particles.h:262
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
double time() const
Returns the time of the computational frame.
Definition: particles.h:100
std::unique_ptr< ParticleData[]> data_
Points to a dynamically allocated array of ParticleData objects.
Definition: particles.h:498
const ParticleData & update_particle(const ParticleData &p, const ParticleData &new_state)
Updates the particle identified by p with the state stored in new_state.
Definition: particles.h:175
size_t size() const
Definition: particles.h:87
void update(const ParticleList &old_state, ParticleList &new_state, bool do_replace)
Updates the Particles object, replacing the particles in old_state with the particles in new_state.
Definition: particles.h:200
const_iterator cend() const
Definition: particles.h:430
ParticleList copy_to_vector() const
Definition: particles.h:44
void reset()
Reset the state of the Particles object to an empty list and a new id counter.
Definition: particles.cc:139
bool is_valid(const ParticleData &copy) const
Check whether the ParticleData copy is still a valid copy of the one stored in the Particles object.
Definition: particles.h:120
std::vector< unsigned > dirty_
Stores the indexes in data_ that do not hold valid particle data and should be reused when new partic...
Definition: particles.h:504
const ParticleData & front() const
const overload of &front()
Definition: particles.h:380
ParticleData & front()
Definition: particles.h:374
unsigned data_size_
Definition: particles.h:487
Particles(const Particles &)=delete
Cannot be copied.
iterator begin()
Definition: particles.h:395
bool is_empty() const
Definition: particles.h:90
const_iterator end() const
const overload of end()
Definition: particles.h:425
void copy_in(ParticleData &to, const ParticleData &from)
Definition: particles.cc:44
Particles & operator=(const Particles &)=delete
Cannot be copied.
int id_max_
Highest id of a given particle.
Definition: particles.h:446
const ParticleData & lookup(const ParticleData &old_state) const
Returns the particle that is currently stored in this object given an old copy of that particle.
Definition: particles.h:222
void ensure_capacity(unsigned to_add)
Definition: particles.cc:23
Particles()
Creates a new (empty) Particles object.
Definition: particles.cc:17
ParticleData & back()
Definition: particles.h:383
void replace(const ParticleList &to_remove, ParticleList &to_add)
Replace the particles in to_remove with the particles in to_add in the list of current particles.
Definition: particles.cc:120
unsigned data_capacity_
Definition: particles.h:492
const ParticleData & insert(const ParticleData &p)
Inserts the particle into the list of particles.
Definition: particles.cc:50
void create(size_t n, PdgCode pdg)
Add n particles of the same type (pdg) to the list.
Definition: particles.cc:66
void increase_capacity(unsigned new_capacity)
Definition: particles.cc:30
const_iterator cbegin() const
Definition: particles.h:428
const_iterator begin() const
const overload of begin()
Definition: particles.h:407
const ParticleData & back() const
const overload of &back()
Definition: particles.h:389
void remove(const ParticleData &p)
Remove the given particle p from the list.
Definition: particles.cc:108
iterator end()
Definition: particles.h:419
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
friend std::ostream & operator<<(std::ostream &out, const Particles &particles)
Print effective mass and type name for all particles to the stream.
Definition: particles.cc:148
constexpr int p
Proton.
constexpr int n
Neutron.
Definition: action.h:24