Block-Structured AMR Software Framework
AMReX_Particle.H
Go to the documentation of this file.
1 #ifndef AMREX_PARTICLE_H_
2 #define AMREX_PARTICLE_H_
3 #include <AMReX_Config.H>
4 
5 #include <AMReX_REAL.H>
6 #include <AMReX_FArrayBox.H>
7 #include <AMReX_IntVect.H>
8 #include <AMReX_RealVect.H>
9 #include <AMReX_ParmParse.H>
10 #include <AMReX_Geometry.H>
11 
12 #include <string>
13 
14 namespace amrex {
15 
17  namespace LongParticleIds {
18  constexpr Long GhostParticleID = 549755813887L; // 2**39-1
19  constexpr Long VirtualParticleID = GhostParticleID - 1;
20  constexpr Long LastParticleID = GhostParticleID - 2;
21  constexpr Long DoSplitParticleID = GhostParticleID - 3;
22  constexpr Long NoSplitParticleID = GhostParticleID - 4;
23  }
24 
25  using namespace LongParticleIds;
26 
30  namespace ParticleIdCpus {
31  constexpr std::uint64_t Invalid = 16777216; // corresponds to id = -1, cpu = 0
32  }
33 
34  using namespace ParticleIdCpus;
35 
37 {
38  uint64_t* m_idata;
39 
40  ~ParticleIDWrapper () noexcept = default;
41 
43  ParticleIDWrapper (uint64_t& idata) noexcept
44  : m_idata(&idata)
45  {}
46 
48  ParticleIDWrapper (const ParticleIDWrapper& rhs) = default;
49 
51 
53  ParticleIDWrapper& operator= (const ParticleIDWrapper& pidw) noexcept
54  {
55  return this->operator=(Long(pidw)); // NOLINT
56  }
57 
59  ParticleIDWrapper& operator= (ParticleIDWrapper&& pidw) noexcept
60  {
61  return this->operator=(Long(pidw)); // NOLINT
62  }
63 
65  ParticleIDWrapper& operator= (const Long id) noexcept
66  {
67  // zero out the 40 leftmost bits, which store the sign and the abs of the id;
68  (*m_idata) &= 0x00FFFFFF;
69 
70  uint64_t val;
71  uint64_t sign = id >= 0;
72  if (sign)
73  {
74  // 2**39-1, the max value representable in this fashion
75  AMREX_ASSERT(id <= 549755813887L);
76  val = id;
77  }
78  else
79  {
80  // -2**39-1, the min value representable in this fashion
81  AMREX_ASSERT(id >= -549755813887L);
82  val = -id;
83  }
84 
85  (*m_idata) |= (sign << 63); // put the sign in the leftmost bit
86  (*m_idata) |= (val << 24); // put the val in the next 39
87  return *this;
88  }
89 
91  operator Long () const noexcept
92  {
93  Long r = 0;
94 
95  uint64_t sign = (*m_idata) >> 63; // extract leftmost sign bit
96  uint64_t val = (((*m_idata) >> 24) & 0x7FFFFFFFFF); // extract next 39 id bits
97 
98  Long lval = static_cast<Long>(val); // bc we take -
99  r = (sign) ? lval : -lval;
100  return r;
101  }
102 
109  void make_invalid () const noexcept
110  {
111  // RHS mask: 0111...
112  (*m_idata) &= ~(uint64_t(1) << 63);
113  }
114 
121  void make_valid () const noexcept
122  {
123  // RHS mask: 1000...
124  (*m_idata) |= uint64_t(1) << 63;
125  }
126 
132  bool is_valid () const noexcept
133  {
134  // the leftmost bit is our id's valid sign
135  return (*m_idata) >> 63;
136  }
137 };
138 
140 {
141  uint64_t* m_idata;
142 
143  ~ParticleCPUWrapper () noexcept = default;
144 
146  ParticleCPUWrapper (uint64_t& idata) noexcept
147  : m_idata(&idata)
148  {}
149 
151  ParticleCPUWrapper (const ParticleCPUWrapper& rhs) = default;
152 
154 
156  ParticleCPUWrapper& operator= (const ParticleCPUWrapper& pcpuw) noexcept
157  {
158  return this->operator=(int(pcpuw)); // NOLINT
159  }
160 
162  ParticleCPUWrapper& operator= (ParticleCPUWrapper&& pcpuw) noexcept
163  {
164  return this->operator=(int(pcpuw)); // NOLINT
165  }
166 
168  ParticleCPUWrapper& operator= (const int cpu) noexcept
169  {
170  // zero out the first 24 bits, which are used to store the cpu number
171  (*m_idata) &= (~ 0x00FFFFFF);
172 
173  AMREX_ASSERT(cpu >= 0);
174  AMREX_ASSERT(cpu <= 16777215); // 2**24-1, the max representable number
175 
176  (*m_idata) |= cpu;
177  return *this;
178  }
179 
181  operator int () const noexcept
182  {
183  return static_cast<int>((*m_idata) & 0x00FFFFFF);
184  }
185 };
186 
188 {
189  const uint64_t* m_idata;
190 
192  ConstParticleIDWrapper (const uint64_t& idata) noexcept
193  : m_idata(&idata)
194  {}
195 
197  operator Long () const noexcept
198  {
199  Long r = 0;
200 
201  uint64_t sign = (*m_idata) >> 63; // extract leftmost sign bit
202  uint64_t val = (((*m_idata) >> 24) & 0x7FFFFFFFFF); // extract next 39 id bits
203 
204  Long lval = static_cast<Long>(val); // bc we take -
205  r = (sign) ? lval : -lval;
206  return r;
207  }
208 
214  bool is_valid () const noexcept
215  {
216  // the leftmost bit is our id's valid sign
217  return (*m_idata) >> 63;
218  }
219 };
220 
222 {
223  const uint64_t* m_idata;
224 
226  ConstParticleCPUWrapper (const uint64_t& idata) noexcept
227  : m_idata(&idata)
228  {}
229 
231  operator int () const noexcept { return static_cast<int>((*m_idata) & 0x00FFFFFF); }
232 };
233 
240 std::uint64_t SetParticleIDandCPU (Long id, int cpu) noexcept{
241  std::uint64_t idcpu = 0;
242  ParticleIDWrapper{idcpu} = id;
243  ParticleCPUWrapper{idcpu} = cpu;
244  return idcpu;
245 }
246 
247 template <typename T, int NReal, int NInt>
249 {
250  T m_pos[AMREX_SPACEDIM];
251  T m_rdata[NReal];
252  uint64_t m_idcpu = 0;
253  int m_idata[NInt];
254 };
255 
256 template <typename T, int NInt>
257 struct ParticleBase<T,0,NInt>
258 {
259  T m_pos[AMREX_SPACEDIM];
260  uint64_t m_idcpu = 0;
261  int m_idata[NInt];
262 };
263 
264 template <typename T, int NReal>
265 struct ParticleBase<T,NReal,0>
266 {
267  T m_pos[AMREX_SPACEDIM];
268  T m_rdata[NReal];
269  uint64_t m_idcpu = 0;
270 };
271 
272 template <typename T>
273 struct ParticleBase<T,0,0>
274 {
275  T m_pos[AMREX_SPACEDIM];
276  uint64_t m_idcpu = 0;
277 };
278 
279 
281 {
282  static constexpr int NReal=0;
283  static constexpr int NInt=0;
284  static constexpr bool is_soa_particle = true;
285 };
286 
292 template <int T_NReal, int T_NInt=0>
293 struct Particle
294  : ParticleBase<ParticleReal,T_NReal,T_NInt>
295 {
296  static constexpr bool is_soa_particle = false;
298  using ConstType = Particle const;
299 
301  static constexpr int NReal = T_NReal;
302 
304  static constexpr int NInt = T_NInt;
305 
307  using RealType = ParticleReal;
308 
309  static Long the_next_id;
310 
312  ParticleCPUWrapper cpu () & { return ParticleCPUWrapper(this->m_idcpu); }
313 
315  ParticleIDWrapper id () & { return ParticleIDWrapper(this->m_idcpu); }
316 
318  ConstParticleCPUWrapper cpu () const & { return ConstParticleCPUWrapper(this->m_idcpu); }
319 
321  ConstParticleIDWrapper id () const & { return ConstParticleIDWrapper(this->m_idcpu); }
322 
324  void atomicSetID (const Long id) {
325  uint64_t tmp = 0;
326  ParticleIDWrapper wrapper(tmp);
327  wrapper = id;
328 #if defined(AMREX_USE_OMP)
329 #pragma omp atomic write
330  this->m_idcpu = wrapper.m_idata;
331 #else
332  auto *old_ptr = reinterpret_cast<unsigned long long*>(&(this->m_idcpu));
333  amrex::Gpu::Atomic::Exch(old_ptr, (unsigned long long) wrapper.m_idata);
334 #endif
335  }
336 
338  RealVect pos () const & {return RealVect(AMREX_D_DECL(this->m_pos[0], this->m_pos[1], this->m_pos[2]));}
339 
341  RealType& pos (int index) &
342  {
343  AMREX_ASSERT(index < AMREX_SPACEDIM);
344  return this->m_pos[index];
345  }
346 
348  RealType pos (int index) const &
349  {
350  AMREX_ASSERT(index < AMREX_SPACEDIM);
351  return this->m_pos[index];
352  }
353 
354  template <int U = T_NReal, std::enable_if_t<U != 0, int> = 0>
356  RealType& rdata (int index) &
357  {
358  AMREX_ASSERT(index < NReal);
359  return this->m_rdata[index];
360  }
361 
362  template <int U = T_NReal, std::enable_if_t<U == 0, int> = 0>
364  RealType& rdata (int /*index*/) &
365  {
366  AMREX_ALWAYS_ASSERT(false);
367  return this->pos(0); // bc we must return something
368  }
369 
370  template <int U = T_NReal, std::enable_if_t<U != 0, int> = 0>
372  const RealType& rdata (int index) const &
373  {
374  AMREX_ASSERT(index < NReal);
375  return this->m_rdata[index];
376  }
377 
378  template <int U = T_NReal, std::enable_if_t<U == 0, int> = 0>
380  RealType rdata (int /*index*/) const &
381  {
382  AMREX_ALWAYS_ASSERT(false);
383  return this->pos(0); // because we must return something
384  }
385 
387  RealType rdata (int /*index*/) && = delete;
388 
389  template <int U = T_NReal, std::enable_if_t<U != 0, int> = 0>
391  RealVect rvec (AMREX_D_DECL(int indx, int indy, int indz)) const &
392  {
393  AMREX_ASSERT(AMREX_D_TERM(indx < NReal, && indy < NReal, && indz < NReal));
394  return RealVect(AMREX_D_DECL(this->m_rdata[indx],
395  this->m_rdata[indy],
396  this->m_rdata[indz]));
397  }
398 
399  template <int U = T_NReal, std::enable_if_t<U == 0, int> = 0>
401  RealVect rvec (AMREX_D_DECL(int /*indx*/, int /*indy*/, int /*indz*/)) const &
402  {
403  AMREX_ALWAYS_ASSERT(false);
404  return RealVect(AMREX_D_DECL(0.0, 0.0, 0.0)); // bc we must return something
405  }
406 
407  template <int U = T_NReal, std::enable_if_t<U != 0, int> = 0>
409  RealVect rvec (const IntVect& indices) const &
410  {
411  AMREX_ASSERT(indices.allLT(NReal));
412  return RealVect(AMREX_D_DECL(this->m_rdata[indices[0]],
413  this->m_rdata[indices[1]],
414  this->m_rdata[indices[2]]));
415  }
416 
417  template <int U = T_NReal, std::enable_if_t<U == 0, int> = 0>
419  RealVect rvec (const IntVect& /*indices*/) const &
420  {
421  AMREX_ALWAYS_ASSERT(false);
422  return RealVect(AMREX_D_DECL(0.0, 0.0, 0.0)); // bc we must return something
423  }
424 
425  template <int U = T_NInt, std::enable_if_t<U != 0, int> = 0>
427  int& idata (int index) &
428  {
429  AMREX_ASSERT(index < NInt);
430  return this->m_idata[index];
431  }
432 
433  template <int U = T_NInt, std::enable_if_t<U == 0, int> = 0>
435  uint64_t& idata (int /*index*/) &
436  {
437  AMREX_ALWAYS_ASSERT(false);
438  return this->m_idcpu; //bc we must return something
439  }
440 
441  template <int U = T_NInt, std::enable_if_t<U != 0, int> = 0>
443  const int& idata (int index) const &
444  {
445  AMREX_ASSERT(index < NInt);
446  return this->m_idata[index];
447  }
448 
449  template <int U = T_NInt, std::enable_if_t<U == 0, int> = 0>
451  int idata (int /*index*/) const &
452  {
453  AMREX_ALWAYS_ASSERT(false);
454  return this->m_idcpu; //bc we must return something
455  }
456 
458  RealType idata (int /*index*/) && = delete;
459 
468  [[nodiscard]] static Long NextID ();
469 
473  [[nodiscard]] static Long UnprotectedNextID ();
474 
480  static void NextID (Long nextid);
481 };
482 
483 template <int NReal, int NInt> Long Particle<NReal, NInt>::the_next_id = 1;
484 
485 template <int NReal, int NInt>
486 Long
488 {
489  Long next;
490 // we should be able to test on _OPENMP < 201107 for capture (version 3.1)
491 // but we must work around a bug in gcc < 4.9
492 #if defined(AMREX_USE_OMP) && defined(_OPENMP) && _OPENMP < 201307
493 #pragma omp critical (amrex_particle_nextid)
494 #elif defined(AMREX_USE_OMP)
495 #pragma omp atomic capture
496 #endif
497  next = the_next_id++;
498 
499  if (next > LongParticleIds::LastParticleID) {
500  amrex::Abort("Particle<NReal, NInt>::NextID() -- too many particles");
501  }
502 
503  return next;
504 }
505 
506 template <int NReal, int NInt>
507 Long
509 {
510  Long next = the_next_id++;
511  if (next > LongParticleIds::LastParticleID) {
512  amrex::Abort("Particle<NReal, NInt>::NextID() -- too many particles");
513  }
514  return next;
515 }
516 
517 template <int NReal, int NInt>
518 void
520 {
521  the_next_id = nextid;
522 }
523 
524 template <int NReal, int NInt>
525 std::ostream&
526 operator<< (std::ostream& os, const Particle<NReal, NInt>& p)
527 {
528  os << p.id() << ' '
529  << p.cpu() << ' ';
530 
531  for (int i = 0; i < AMREX_SPACEDIM; i++) {
532  os << p.pos(i) << ' ';
533  }
534 
535  for (int i = 0; i < NReal; i++) {
536  os << p.rdata(i) << ' ';
537  }
538 
539  for (int i = 0; i < NInt; i++) {
540  os << p.idata(i) << ' ';
541  }
542 
543  if (!os.good()) {
544  amrex::Error("operator<<(ostream&,Particle<NReal, NInt>&) failed");
545  }
546 
547  return os;
548 }
549 
550 template <int NReal>
551 std::ostream&
552 operator<< (std::ostream& os, const Particle<NReal, 0>& p)
553 {
554  os << p.id() << ' '
555  << p.cpu() << ' ';
556 
557  for (int i = 0; i < AMREX_SPACEDIM; i++) {
558  os << p.pos(i) << ' ';
559  }
560 
561  for (int i = 0; i < NReal; i++) {
562  os << p.rdata(i) << ' ';
563  }
564 
565  if (!os.good()) {
566  amrex::Error("operator<<(ostream&,Particle<NReal, NInt>&) failed");
567  }
568 
569  return os;
570 }
571 
572 template <int NInt>
573 std::ostream&
574 operator<< (std::ostream& os, const Particle<0, NInt>& p)
575 {
576  os << p.id() << ' '
577  << p.cpu() << ' ';
578 
579  for (int i = 0; i < AMREX_SPACEDIM; i++) {
580  os << p.pos(i) << ' ';
581  }
582 
583  for (int i = 0; i < NInt; i++) {
584  os << p.idata(i) << ' ';
585  }
586 
587  if (!os.good()) {
588  amrex::Error("operator<<(ostream&,Particle<NReal, NInt>&) failed");
589  }
590 
591  return os;
592 }
593 
594 template <int NReal=0, int NInt=0>
595 std::ostream&
596 operator<< (std::ostream& os, const Particle<0, 0>& p)
597 {
598  os << p.id() << ' '
599  << p.cpu() << ' ';
600 
601  for (int i = 0; i < AMREX_SPACEDIM; i++) {
602  os << p.pos(i) << ' ';
603  }
604 
605  if (!os.good()) {
606  amrex::Error("operator<<(ostream&,Particle<NReal, NInt>&) failed");
607  }
608 
609  return os;
610 }
611 
612 } // namespace amrex
613 
614 #endif // AMREX_PARTICLE_H_
#define AMREX_ASSERT(EX)
Definition: AMReX_BLassert.H:38
#define AMREX_ALWAYS_ASSERT(EX)
Definition: AMReX_BLassert.H:50
#define AMREX_FORCE_INLINE
Definition: AMReX_Extension.H:119
#define AMREX_GPU_HOST_DEVICE
Definition: AMReX_GpuQualifiers.H:20
#define AMREX_D_TERM(a, b, c)
Definition: AMReX_SPACE.H:129
#define AMREX_D_DECL(a, b, c)
Definition: AMReX_SPACE.H:104
A Real vector in SpaceDim-dimensional space.
Definition: AMReX_RealVect.H:32
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T Exch(T *address, T val) noexcept
Definition: AMReX_GpuAtomic.H:485
constexpr Long GhostParticleID
Definition: AMReX_Particle.H:18
constexpr Long NoSplitParticleID
Definition: AMReX_Particle.H:22
constexpr Long VirtualParticleID
Definition: AMReX_Particle.H:19
constexpr Long DoSplitParticleID
Definition: AMReX_Particle.H:21
constexpr Long LastParticleID
Definition: AMReX_Particle.H:20
constexpr std::uint64_t Invalid
Definition: AMReX_Particle.H:31
Definition: AMReX_Amr.cpp:49
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE std::uint64_t SetParticleIDandCPU(Long id, int cpu) noexcept
Definition: AMReX_Particle.H:240
void Error(const std::string &msg)
Print out message to cerr and exit via amrex::Abort().
Definition: AMReX.cpp:219
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition: AMReX.cpp:225
const int[]
Definition: AMReX_BLProfiler.cpp:1664
std::ostream & operator<<(std::ostream &os, AmrMesh const &amr_mesh)
Definition: AMReX_AmrMesh.cpp:1236
Definition: AMReX_Particle.H:222
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ConstParticleCPUWrapper(const uint64_t &idata) noexcept
Definition: AMReX_Particle.H:226
const uint64_t * m_idata
Definition: AMReX_Particle.H:223
Definition: AMReX_Particle.H:188
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ConstParticleIDWrapper(const uint64_t &idata) noexcept
Definition: AMReX_Particle.H:192
const uint64_t * m_idata
Definition: AMReX_Particle.H:189
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool is_valid() const noexcept
Definition: AMReX_Particle.H:214
Definition: AMReX_Particle.H:249
Definition: AMReX_Particle.H:140
ParticleCPUWrapper(ParticleCPUWrapper &&)=delete
~ParticleCPUWrapper() noexcept=default
uint64_t * m_idata
Definition: AMReX_Particle.H:141
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ParticleCPUWrapper(const ParticleCPUWrapper &rhs)=default
Definition: AMReX_Particle.H:37
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ParticleIDWrapper(const ParticleIDWrapper &rhs)=default
uint64_t * m_idata
Definition: AMReX_Particle.H:38
~ParticleIDWrapper() noexcept=default
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool is_valid() const noexcept
Definition: AMReX_Particle.H:132
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void make_valid() const noexcept
Definition: AMReX_Particle.H:121
ParticleIDWrapper(ParticleIDWrapper &&)=delete
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void make_invalid() const noexcept
Definition: AMReX_Particle.H:109
The struct used to store particles.
Definition: AMReX_Particle.H:295
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealType pos(int index) const &
Definition: AMReX_Particle.H:348
ParticleReal RealType
The floating point type used for the particles.
Definition: AMReX_Particle.H:307
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ParticleIDWrapper id() &
Definition: AMReX_Particle.H:315
static Long NextID()
Returns the next particle ID for this processor. Particle IDs start at 1 and are never reused....
Definition: AMReX_Particle.H:487
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealVect rvec(AMREX_D_DECL(int, int, int)) const &
Definition: AMReX_Particle.H:401
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealType rdata(int) const &
Definition: AMReX_Particle.H:380
static Long the_next_id
Definition: AMReX_Particle.H:309
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealType & rdata(int) &
Definition: AMReX_Particle.H:364
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealVect pos() const &
Definition: AMReX_Particle.H:338
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ConstParticleIDWrapper id() const &
Definition: AMReX_Particle.H:321
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealType & rdata(int index) &
Definition: AMReX_Particle.H:356
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealVect rvec(const IntVect &indices) const &
Definition: AMReX_Particle.H:409
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealVect rvec(AMREX_D_DECL(int indx, int indy, int indz)) const &
Definition: AMReX_Particle.H:391
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealType rdata(int) &&=delete
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE const RealType & rdata(int index) const &
Definition: AMReX_Particle.H:372
static Long UnprotectedNextID()
This version can only be used inside omp critical.
Definition: AMReX_Particle.H:508
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealVect rvec(const IntVect &) const &
Definition: AMReX_Particle.H:419
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idata(int) const &
Definition: AMReX_Particle.H:451
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ConstParticleCPUWrapper cpu() const &
Definition: AMReX_Particle.H:318
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealType & pos(int index) &
Definition: AMReX_Particle.H:341
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE RealType idata(int) &&=delete
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int & idata(int index) &
Definition: AMReX_Particle.H:427
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ParticleCPUWrapper cpu() &
Definition: AMReX_Particle.H:312
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void atomicSetID(const Long id)
Definition: AMReX_Particle.H:324
Particle const ConstType
Definition: AMReX_Particle.H:298
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE uint64_t & idata(int) &
Definition: AMReX_Particle.H:435
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE const int & idata(int index) const &
Definition: AMReX_Particle.H:443
Definition: AMReX_Particle.H:281
Definition: AMReX_MakeParticle.H:11