Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_ParticleContainerI.H
Go to the documentation of this file.
2
3#include <algorithm>
4#include <iterator>
5#include <set>
6#include <stdexcept>
7#include <string>
8#include <type_traits>
9#include <vector>
10
11namespace amrex {
12
13template <typename ParticleType, int NArrayReal, int NArrayInt,
14 template<class> class Allocator, class CellAssignor>
15void
17{
18 num_real_comm_comps = 0;
19 int comm_comps_start = 0;
20 if constexpr (!ParticleType::is_soa_particle) {
21 comm_comps_start += AMREX_SPACEDIM + NStructReal;
22 }
23 for (int i = comm_comps_start; i < comm_comps_start + NumRealComps(); ++i) {
24 if (h_redistribute_real_comp[i]) {++num_real_comm_comps;}
25 }
26
27 num_int_comm_comps = 0;
28 comm_comps_start = 2 + NStructInt;
29 for (int i = comm_comps_start; i < comm_comps_start + NumIntComps(); ++i) {
30 if (h_redistribute_int_comp[i]) {++num_int_comm_comps;}
31 }
32
33 if constexpr (ParticleType::is_soa_particle) {
34 particle_size = sizeof(uint64_t); // idcpu
35 } else {
36 particle_size = sizeof(ParticleType);
37 }
38 superparticle_size = particle_size +
39 num_real_comm_comps*sizeof(ParticleReal) + num_int_comm_comps*sizeof(int);
40}
41
42template <typename ParticleType, int NArrayReal, int NArrayInt,
43 template<class> class Allocator, class CellAssignor>
44void
46{
47 levelDirectoriesCreated = false;
48 usePrePost = false;
49 doUnlink = true;
50
51 // by default communicate all components
52 if constexpr (ParticleType::is_soa_particle)
53 {
54 h_redistribute_real_comp.resize(NArrayReal, true);
55 } else {
56 h_redistribute_real_comp.resize(AMREX_SPACEDIM + NStructReal + NArrayReal, true);
57 }
58 h_redistribute_int_comp.resize(2 + NStructInt + NArrayInt, true);
59
60 SetParticleSize();
61
62 // add default names for SoA Real and Int compile-time arguments
63 m_soa_rdata_names.clear();
64 for (int i=0; i<NArrayReal; ++i)
65 {
66 m_soa_rdata_names.push_back(getDefaultCompNameReal<ParticleType>(i));
67 }
68 m_soa_idata_names.clear();
69 for (int i=0; i<NArrayInt; ++i)
70 {
71 m_soa_idata_names.push_back(getDefaultCompNameInt<ParticleType>(i));
72 }
73
74 static bool initialized = false;
75 if ( ! initialized)
76 {
77 static_assert(sizeof(ParticleType)%sizeof(RealType) == 0,
78 "sizeof ParticleType is not a multiple of sizeof RealType");
79
80 ParmParse pp("particles");
81 pp.queryAdd("do_tiling", do_tiling);
82 Vector<int> tilesize(AMREX_SPACEDIM);
83 if (pp.queryarr("tile_size", tilesize, 0, AMREX_SPACEDIM)) {
84 for (int i=0; i<AMREX_SPACEDIM; ++i) { tile_size[i] = tilesize[i]; }
85 }
86
87 static_assert(std::is_standard_layout<ParticleType>::value,
88 "Particle type must be standard layout");
89 // && std::is_trivial<ParticleType>::value,
90 // "Particle type must be standard layout and trivial.");
91
92 pp.query("use_prepost", usePrePost);
93 pp.query("do_unlink", doUnlink);
94 pp.queryAdd("do_mem_efficient_sort", memEfficientSort);
95 pp.queryAdd("use_comms_arena", use_comms_arena);
96
97 initialized = true;
98 }
99}
100
101template<
102 typename ParticleType,
103 int NArrayReal,
104 int NArrayInt,
105 template<class> class Allocator,
106 class CellAssignor
107>
108void
110 std::vector<std::string> const & rdata_name, std::vector<std::string> const & idata_name
111)
112{
113 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(rdata_name.size() == NArrayReal, "rdata_name must be equal to NArrayReal");
114 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(idata_name.size() == NArrayInt, "idata_name must be equal to NArrayInt");
115
116 // ensure names for components are unique
117 std::set<std::string> const unique_r_names(rdata_name.begin(), rdata_name.end());
118 std::set<std::string> const unique_i_names(idata_name.begin(), idata_name.end());
119 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(rdata_name.size() == unique_r_names.size(), "SetSoACompileTimeNames: Provided names in rdata_name are not unique!");
120 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(idata_name.size() == unique_i_names.size(), "SetSoACompileTimeNames: Provided names in idata_name are not unique!");
121
122 for (int i=0; i<NArrayReal; ++i)
123 {
124 m_soa_rdata_names.at(i) = rdata_name.at(i);
125 }
126 for (int i=0; i<NArrayInt; ++i)
127 {
128 m_soa_idata_names.at(i) = idata_name.at(i);
129 }
130}
131
132template<
133 typename ParticleType,
134 int NArrayReal,
135 int NArrayInt,
136 template<class> class Allocator,
137 class CellAssignor
138>
139bool
141{
142 return std::find(m_soa_rdata_names.begin(), m_soa_rdata_names.end(), name) != std::end(m_soa_rdata_names);
143}
144
145template <typename ParticleType, int NArrayReal, int NArrayInt,
146 template<class> class Allocator, class CellAssignor>
147bool
149{
150 return std::find(m_soa_idata_names.begin(), m_soa_idata_names.end(), name) != std::end(m_soa_idata_names);
151}
152
153template<
154 typename ParticleType,
155 int NArrayReal,
156 int NArrayInt,
157 template<class> class Allocator,
158 class CellAssignor
159>
160int
162{
163 const auto it = std::find(m_soa_rdata_names.begin(), m_soa_rdata_names.end(), name);
164
165 if (it == m_soa_rdata_names.end())
166 {
167 throw std::runtime_error("GetRealCompIndex: Component " + name + " does not exist!");
168 }
169 else
170 {
171 return std::distance(m_soa_rdata_names.begin(), it);
172 }
173}
174
175template<
176 typename ParticleType,
177 int NArrayReal,
178 int NArrayInt,
179 template<class> class Allocator,
180 class CellAssignor
181>
182int
184{
185 const auto it = std::find(m_soa_idata_names.begin(), m_soa_idata_names.end(), name);
186
187 if (it == m_soa_idata_names.end())
188 {
189 throw std::runtime_error("GetIntCompIndex: Component " + name + " does not exist!");
190 }
191 else
192 {
193 return std::distance(m_soa_idata_names.begin(), it);
194 }
195}
196
197template <typename ParticleType, int NArrayReal, int NArrayInt,
198 template<class> class Allocator, class CellAssignor>
199template <typename P, typename Assignor>
202{
203 const Geometry& geom = Geom(lev);
204 const auto& domain = geom.Domain();
205 const auto& plo = geom.ProbLoArray();
206 const auto& dxi = geom.InvCellSizeArray();
207
208 return Assignor{}(p, plo, dxi, domain);
209}
210
211template <typename ParticleType, int NArrayReal, int NArrayInt,
212 template<class> class Allocator, class CellAssignor>
213template <typename P>
214bool
216::Where (const P& p,
217 ParticleLocData& pld,
218 int lev_min,
219 int lev_max,
220 int nGrow,
221 int local_grid) const
222{
223
224 AMREX_ASSERT(m_gdb != nullptr);
225
226 if (lev_max == -1) {
227 lev_max = finestLevel();
228 }
229
230 AMREX_ASSERT(lev_max <= finestLevel());
231
232 AMREX_ASSERT(nGrow == 0 || (nGrow >= 0 && lev_min == lev_max));
233
234 std::vector< std::pair<int, Box> > isects;
235
236 for (int lev = lev_max; lev >= lev_min; lev--) {
237 const IntVect& iv = Index(p, lev);
238 if (lev == pld.m_lev) {
239 // The fact that we are here means this particle does not belong to any finer grids.
240 if (pld.m_grid >= 0) {
241 if (pld.m_grown_gridbox.contains(iv)) {
242 pld.m_cell = iv;
243 if (!pld.m_tilebox.contains(iv)) {
244 pld.m_tile = getTileIndex(iv, pld.m_gridbox, do_tiling, tile_size, pld.m_tilebox);
245 }
246 return true;
247 }
248 }
249 }
250
251 int grid;
252 const BoxArray& ba = ParticleBoxArray(lev);
254
255 if (local_grid < 0) {
256 bool findfirst = (nGrow == 0) ? true : false;
257 ba.intersections(Box(iv, iv), isects, findfirst, nGrow);
258 grid = isects.empty() ? -1 : isects[0].first;
259 if (nGrow > 0 && isects.size() > 1) {
260 for (auto & isect : isects) {
261 Box bx = ba.getCellCenteredBox(isect.first);
262 for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
263 Box gbx = bx;
265 gr[dir] = nGrow;
266 gbx.grow(gr);
267 if (gbx.contains(iv)) {
268 grid = isect.first;
269 }
270 }
271 }
272 }
273 } else {
274 grid = (*redistribute_mask_ptr)[local_grid](iv, 0);
275 }
276
277 if (grid >= 0) {
278 const Box& bx = ba.getCellCenteredBox(grid);
279 pld.m_lev = lev;
280 pld.m_grid = grid;
281 pld.m_tile = getTileIndex(iv, bx, do_tiling, tile_size, pld.m_tilebox);
282 pld.m_cell = iv;
283 pld.m_gridbox = bx;
284 pld.m_grown_gridbox = amrex::grow(bx, nGrow);
285 return true;
286 }
287 }
288
289 return false;
290}
291
292template <typename ParticleType, int NArrayReal, int NArrayInt,
293 template<class> class Allocator, class CellAssignor>
294template <typename P>
295bool
298 ParticleLocData& pld,
299 int lev_min,
300 int lev_max,
301 int local_grid) const
302{
303
304 AMREX_ASSERT(m_gdb != nullptr);
305
306 if (!Geom(0).isAnyPeriodic()) { return false; }
307
308 if (lev_max == -1) {
309 lev_max = finestLevel();
310 }
311
312 AMREX_ASSERT(lev_max <= finestLevel());
313
314 // Create a copy "dummy" particle to check for periodic outs.
315 Particle<0, 0> p_prime;
316 AMREX_D_TERM(p_prime.pos(0) = p.pos(0);,
317 p_prime.pos(1) = p.pos(1);,
318 p_prime.pos(2) = p.pos(2));
319 if (PeriodicShift(p_prime)) {
320 std::vector< std::pair<int,Box> > isects;
321 for (int lev = lev_max; lev >= lev_min; lev--) {
322
323 int grid;
324 IntVect iv;
325 const BoxArray& ba = ParticleBoxArray(lev);
327
328 if (local_grid < 0) {
329 iv = Index<amrex::Particle<0, 0>, DefaultAssignor>(p_prime, lev);
330 ba.intersections(Box(iv, iv), isects, true, 0);
331 grid = isects.empty() ? -1 : isects[0].first;
332 } else {
333 iv = Index<amrex::Particle<0, 0>, DefaultAssignor>(p_prime, lev);
334 if (ba[local_grid].contains(iv))
335 {
336 grid = local_grid;
337 }
338 else
339 {
340 ba.intersections(Box(iv, iv), isects, true, 0);
341 grid = isects.empty() ? -1 : isects[0].first;
342 if(grid == -1)
343 {
344 grid = (*redistribute_mask_ptr)[local_grid](Index(p, lev), 0);
345 }
346 }
347 }
348
349 if (grid >= 0) {
350 AMREX_D_TERM(p.pos(0) = p_prime.pos(0);,
351 p.pos(1) = p_prime.pos(1);,
352 p.pos(2) = p_prime.pos(2););
353
354 const Box& bx = ba.getCellCenteredBox(grid);
355
356 pld.m_lev = lev;
357 pld.m_grid = grid;
358 pld.m_tile = getTileIndex(iv, bx, do_tiling, tile_size, pld.m_tilebox);
359 pld.m_cell = iv;
360 pld.m_gridbox = bx;
361 pld.m_grown_gridbox = bx;
362 return true;
363 }
364 }
365 }
366
367 return false;
368}
369
370
371template <typename ParticleType, int NArrayReal, int NArrayInt,
372 template<class> class Allocator, class CellAssignor>
373template <typename P>
374bool
376::PeriodicShift (P& p) const
377{
378 const auto& geom = Geom(0);
379 const auto plo = geom.ProbLoArray();
380 const auto phi = geom.ProbHiArray();
381 const auto rlo = geom.ProbLoArrayInParticleReal();
382 const auto rhi = geom.ProbHiArrayInParticleReal();
383 const auto is_per = geom.isPeriodicArray();
384
385 return enforcePeriodic(p, plo, phi, rlo, rhi, is_per);
386}
387
388template <typename ParticleType, int NArrayReal, int NArrayInt,
389 template<class> class Allocator, class CellAssignor>
393 bool /*update*/,
394 bool verbose,
395 ParticleLocData pld) const
396{
397 AMREX_ASSERT(m_gdb != nullptr);
398
399 bool ok = Where(p, pld);
400
401 if (!ok && Geom(0).isAnyPeriodic())
402 {
403 // Attempt to shift the particle back into the domain if it
404 // crossed a periodic boundary.
405 PeriodicShift(p);
406 ok = Where(p, pld);
407 }
408
409 if (!ok) {
410 // invalidate the particle.
411 if (verbose) {
412 amrex::AllPrint()<< "Invalidating out-of-domain particle: " << p << '\n';
413 }
414
415 AMREX_ASSERT(p.id().is_valid());
416
417 p.id().make_invalid();
418 }
419
420 return pld;
421}
422
423template <typename ParticleType, int NArrayReal, int NArrayInt,
424 template<class> class Allocator, class CellAssignor>
425void
431
432template <typename ParticleType, int NArrayReal, int NArrayInt,
433 template<class> class Allocator, class CellAssignor>
434void
436{
438 int nlevs = std::max(0, finestLevel()+1);
439 m_particles.resize(nlevs);
440}
441
442template <typename ParticleType, int NArrayReal, int NArrayInt,
443 template<class> class Allocator, class CellAssignor>
444template <typename P>
445void
447 int lev_min, int lev_max, int nGrow, int local_grid) const
448{
449 bool success;
450 if (Geom(0).outsideRoundoffDomain(AMREX_D_DECL(p.pos(0), p.pos(1), p.pos(2))))
451 {
452 // Note that EnforcePeriodicWhere may shift the particle if it is successful.
453 success = EnforcePeriodicWhere(p, pld, lev_min, lev_max, local_grid);
454 if (!success && lev_min == 0)
455 {
456 // The particle has left the domain; invalidate it.
457 p.id().make_invalid();
458 success = true;
459 }
460 }
461 else
463 success = Where(p, pld, lev_min, lev_max, 0, local_grid);
465
466 if (!success)
467 {
468 success = (nGrow > 0) && Where(p, pld, lev_min, lev_min, nGrow);
469 pld.m_grown_gridbox = pld.m_gridbox; // reset grown box for subsequent calls.
470 }
471
472 if (!success)
473 {
474 amrex::Abort("ParticleContainer::locateParticle(): invalid particle.");
475 }
476}
477
478template <typename ParticleType, int NArrayReal, int NArrayInt,
479 template<class> class Allocator, class CellAssignor>
480Long
482{
483 Long nparticles = 0;
484 for (int lev = 0; lev <= finestLevel(); lev++) {
485 nparticles += NumberOfParticlesAtLevel(lev,only_valid,true);
486 }
487 if (!only_local) {
489 }
490 return nparticles;
491}
492
493template <typename ParticleType, int NArrayReal, int NArrayInt,
494 template<class> class Allocator, class CellAssignor>
497{
498 AMREX_ASSERT(lev >= 0 && lev < int(m_particles.size()));
499
500 LayoutData<Long> np_per_grid_local(ParticleBoxArray(lev),
501 ParticleDistributionMap(lev));
502
503 for (ParConstIterType pti(*this, lev); pti.isValid(); ++pti)
504 {
505 int gid = pti.index();
506 if (only_valid)
507 {
508 const auto& ptile = ParticlesAt(lev, pti);
509 const int np = ptile.numParticles();
510 auto const ptd = ptile.getConstParticleTileData();
511
512 ReduceOps<ReduceOpSum> reduce_op;
513 ReduceData<int> reduce_data(reduce_op);
514 using ReduceTuple = typename decltype(reduce_data)::Type;
515
516 reduce_op.eval(np, reduce_data,
517 [=] AMREX_GPU_DEVICE (int i) -> ReduceTuple
518 {
519 return (ptd.id(i).is_valid()) ? 1 : 0;
520 });
521
522 int np_valid = amrex::get<0>(reduce_data.value(reduce_op));
523 np_per_grid_local[gid] += np_valid;
524 } else
525 {
526 np_per_grid_local[gid] += pti.numParticles();
527 }
528 }
529
530 Vector<Long> nparticles(np_per_grid_local.size(), 0);
531 if (only_local)
532 {
533 for (ParConstIterType pti(*this, lev); pti.isValid(); ++pti)
534 {
535 nparticles[pti.index()] = np_per_grid_local[pti.index()];
536 }
537 }
538 else
539 {
540 ParallelDescriptor::GatherLayoutDataToVector(np_per_grid_local, nparticles,
542 ParallelDescriptor::Bcast(nparticles.data(), nparticles.size(),
544 }
545
546 return nparticles;
547}
549template <typename ParticleType, int NArrayReal, int NArrayInt,
550 template<class> class Allocator, class CellAssignor>
552{
553 Long nparticles = 0;
554
555 if (level < 0 || level >= int(m_particles.size())) { return nparticles; }
556
557 if (only_valid) {
558 ReduceOps<ReduceOpSum> reduce_op;
559 ReduceData<unsigned long long> reduce_data(reduce_op);
560 using ReduceTuple = typename decltype(reduce_data)::Type;
561
562 for (const auto& kv : GetParticles(level)) {
563 const auto& ptile = kv.second;
564 auto const ptd = ptile.getConstParticleTileData();
565
566 reduce_op.eval(ptile.numParticles(), reduce_data,
567 [=] AMREX_GPU_DEVICE (int i) -> ReduceTuple
568 {
569 return (ptd.id(i).is_valid()) ? 1 : 0;
570 });
571 }
572
573 nparticles = static_cast<Long>(amrex::get<0>(reduce_data.value(reduce_op)));
574 }
575 else {
576 for (const auto& kv : GetParticles(level)) {
577 const auto& ptile = kv.second;
578 nparticles += ptile.numParticles();
579 }
581
582 if (!only_local) {
584 }
585
586 return nparticles;
587}
588
589template <typename ParticleType, int NArrayReal, int NArrayInt,
590 template<class> class Allocator, class CellAssignor>
591template <typename I, std::enable_if_t<std::is_integral_v<I> && (sizeof(I) >= sizeof(Long)), int> FOO>
592void
594{
595 AMREX_ASSERT(lev >= 0 && lev < int(m_particles.size()));
597 AMREX_ASSERT(BoxArray::SameRefs(mem.boxArray(), ParticleBoxArray(lev)) &&
598 mem.DistributionMap() == ParticleDistributionMap(lev));
599
600 [[maybe_unused]] Gpu::NoSyncRegion no_sync{};
601 for (ParConstIterType pti(*this, lev); pti.isValid(); ++pti)
602 {
603 int gid = pti.index();
604 mem[gid] += static_cast<I>(pti.capacity());
605 }
607
609// This includes both valid and invalid particles since invalid particles still take up space.
610//
611
612template <typename ParticleType, int NArrayReal, int NArrayInt,
613 template<class> class Allocator, class CellAssignor>
614std::array<Long, 3>
618 Long cnt = 0;
619
620 for (unsigned lev = 0; lev < m_particles.size(); lev++) {
621 const auto& pmap = m_particles[lev];
622 for (const auto& kv : pmap) {
623 const auto& ptile = kv.second;
624 cnt += ptile.numParticles();
625 }
626 }
628 Long mn = cnt, mx = mn;
629
630 const int IOProc = ParallelContext::IOProcessorNumberSub();
631 const Long sz = sizeof(ParticleType)+NumRealComps()*sizeof(ParticleReal)+NumIntComps()*sizeof(int);
632
633#ifdef AMREX_LAZY
634 Lazy::QueueReduction( [=] () mutable {
635#endif
639
640 amrex::Print() << "ParticleContainer spread across MPI nodes - bytes (num particles): [Min: "
641 << mn*sz
642 << " (" << mn << ")"
643 << ", Max: "
644 << mx*sz
645 << " (" << mx << ")"
646 << ", Total: "
647 << cnt*sz
648 << " (" << cnt << ")]\n";
649#ifdef AMREX_LAZY
650 });
651#endif
652
653 return {mn*sz, mx*sz, cnt*sz};
654}
656template <typename ParticleType, int NArrayReal, int NArrayInt,
657 template<class> class Allocator, class CellAssignor>
658std::array<Long, 3>
661{
662 Long cnt = 0;
663
664 for (unsigned lev = 0; lev < m_particles.size(); lev++) {
665 const auto& pmap = m_particles[lev];
666 for (const auto& kv : pmap) {
667 const auto& ptile = kv.second;
668 cnt += ptile.capacity();
669 }
671
672 Long mn = cnt, mx = mn;
673
674 const int IOProc = ParallelContext::IOProcessorNumberSub();
675
676#ifdef AMREX_LAZY
677 Lazy::QueueReduction( [=] () mutable {
678#endif
682
683 amrex::Print() << "ParticleContainer spread across MPI nodes - bytes: [Min: "
684 << mn
685 << ", Max: "
686 << mx
687 << ", Total: "
688 << cnt
689 << "]\n";
690#ifdef AMREX_LAZY
691 });
692#endif
693
694 return {mn, mx, cnt};
695}
696
697template <typename ParticleType, int NArrayReal, int NArrayInt,
698 template<class> class Allocator, class CellAssignor>
699void
701{
702 for (unsigned lev = 0; lev < m_particles.size(); lev++) {
703 auto& pmap = m_particles[lev];
704 for (auto& kv : pmap) {
705 auto& ptile = kv.second;
706 ptile.shrink_to_fit();
707 }
708 }
709}
710
717template <typename ParticleType, int NArrayReal, int NArrayInt,
718 template<class> class Allocator, class CellAssignor>
719void
721{
722 BL_PROFILE("ParticleContainer::Increment");
723
724 AMREX_ASSERT(OK());
725 if (m_particles.empty()) { return; }
726 AMREX_ASSERT(lev >= 0 && lev < int(m_particles.size()));
727 AMREX_ASSERT(numParticlesOutOfRange(*this, 0) == 0);
728
729 const auto& geom = Geom(lev);
730 const auto plo = geom.ProbLoArray();
731 const auto dxi = geom.InvCellSizeArray();
732 const auto domain = geom.Domain();
733 amrex::ParticleToMesh(*this, mf, lev,
734 [=] AMREX_GPU_DEVICE (const typename ParticleTileType::ConstParticleTileDataType& ptd, int ip,
735 amrex::Array4<amrex::Real> const& count)
736 {
737 const auto p = ptd[ip];
738 CellAssignor assignor;
739 IntVect iv = assignor(p, plo, dxi, domain);
740 amrex::Gpu::Atomic::AddNoRet(&count(iv), 1.0_rt);
741 }, false);
742}
743
744template <typename ParticleType, int NArrayReal, int NArrayInt,
745 template<class> class Allocator, class CellAssignor>
746Long
748{
749 BL_PROFILE("ParticleContainer::IncrementWithTotal(lev)");
750 Increment(mf, lev);
751 return TotalNumberOfParticles(true, local);
752}
753
754template <typename ParticleType, int NArrayReal, int NArrayInt,
755 template<class> class Allocator, class CellAssignor>
756void
758{
759 BL_PROFILE("ParticleContainer::RemoveParticlesAtLevel()");
760 if (level >= int(this->m_particles.size())) { return; }
761
762 if (!this->m_particles[level].empty())
763 {
764 ParticleLevel().swap(this->m_particles[level]);
765 }
766}
767
768template <typename ParticleType, int NArrayReal, int NArrayInt,
769 template<class> class Allocator, class CellAssignor>
770void
772{
773 BL_PROFILE("ParticleContainer::RemoveParticlesNotAtFinestLevel()");
774 AMREX_ASSERT(this->finestLevel()+1 == int(this->m_particles.size()));
775
776 Long cnt = 0;
777
778 for (unsigned lev = 0; lev < m_particles.size() - 1; ++lev) {
779 auto& pmap = m_particles[lev];
780 if (!pmap.empty()) {
781 for (auto& kv : pmap) {
782 const auto& pbx = kv.second;
783 cnt += pbx.numParticles();
784 }
785 ParticleLevel().swap(pmap);
786 }
787 }
788
789 //
790 // Print how many particles removed on each processor if any were removed.
791 //
792 if (this->m_verbose > 1 && cnt > 0) {
793 amrex::AllPrint() << "Processor " << ParallelContext::MyProcSub() << " removed " << cnt
794 << " particles not in finest level\n";
795 }
796}
797
799{
800
804
806 const GpuArray<Real, AMREX_SPACEDIM> & dxi, const Box& domain)
807 : m_assign_buffer_grid(assign_buffer_grid), m_plo(plo), m_dxi(dxi), m_domain(domain)
808 {}
809
810 template <typename SrcData>
812 int operator() (const SrcData& src, int src_i) const noexcept
813 {
814 auto iv = getParticleCell(src, src_i, m_plo, m_dxi, m_domain);
815 return (m_assign_buffer_grid(iv)!=-1);
816 }
817};
818
820{
821 template <typename DstData, typename SrcData>
823 void operator() (DstData& dst, const SrcData& src,
824 int src_i, int dst_i) const noexcept
825 {
826 copyParticle(dst, src, src_i, dst_i);
827
829 dst.cpu(dst_i) = 0;
830 }
831};
832
833
834template <typename ParticleType, int NArrayReal, int NArrayInt,
835 template<class> class Allocator, class CellAssignor>
836void
837ParticleContainer_impl<ParticleType, NArrayReal, NArrayInt, Allocator, CellAssignor>
838::CreateVirtualParticles (int level, AoS& virts) const
839{
840 ParticleTileType ptile;
841 CreateVirtualParticles(level, ptile);
842 ptile.GetArrayOfStructs().swap(virts);
843}
844
845template <typename ParticleType, int NArrayReal, int NArrayInt,
846 template<class> class Allocator, class CellAssignor>
847void
850{
851 BL_PROFILE("ParticleContainer::CreateVirtualParticles()");
852 AMREX_ASSERT(level > 0);
853 AMREX_ASSERT(virts.empty());
854
855 if (level >= static_cast<int>(m_particles.size())) {
856 return;
857 }
858
859 std::string aggregation_type = AggregationType();
860 int aggregation_buffer = AggregationBuffer();
861
862 if (aggregation_type == "None")
863 {
864 auto virts_offset = virts.numParticles();
865 for(ParConstIterType pti(*this, level); pti.isValid(); ++pti)
866 {
867 const auto& src_tile = ParticlesAt(level, pti);
868
869 auto np = src_tile.numParticles();
870 virts.resize(virts_offset+np);
871 transformParticles(virts, src_tile, 0, virts_offset, np, TransformerVirt());
872 virts_offset += np;
873 }
874 }
875 if (aggregation_type == "Cell")
876 {
877 //Components would be based on
878 int nComp = AMREX_SPACEDIM + NStructReal + NArrayReal;
879 // NArrayReal, NStructInt, NArrayInt behavior as before
880 int nGhost = 0;
881 MultiFab mf(ParticleBoxArray(level), ParticleDistributionMap(level), nComp, nGhost);
882
883 nComp = 1 + NStructInt + NArrayInt;
884 iMultiFab imf(ParticleBoxArray(level), ParticleDistributionMap(level), nComp, nGhost);
885
886 const auto& geom = Geom(level);
887 const auto plo = geom.ProbLoArray();
888 const auto dxi = geom.InvCellSizeArray();
889 const auto domain = geom.Domain();
890
891 BoxList bl_buffer;
892 bl_buffer.complementIn(Geom(level).Domain(), ParticleBoxArray(level));
893 BoxArray buffer(std::move(bl_buffer));
894 buffer.grow(aggregation_buffer);
895
897 locator.build(buffer, geom);
898 AssignGrid<DenseBinIteratorFactory<Box>> assign_buffer_grid = locator.getGridAssignor();
899
900 amrex::ParticleToMesh(*this, mf, level,
901 [=] AMREX_GPU_DEVICE (const ParticleType& p,
902 amrex::Array4<amrex::Real> const& partData,
905 {
906 auto iv = getParticleCell(p, plo_loc, dxi_loc, domain);
907 if(assign_buffer_grid(iv)==-1)
908 {
909 //Ordering may make this not unique
910 for (int i = 0; i < NArrayReal; ++i)
911 {
912 amrex::Gpu::Atomic::AddNoRet(&partData(iv,AMREX_SPACEDIM+NStructReal+i), partData(iv,AMREX_SPACEDIM)!=0.0 ? static_cast<Real>(0) : static_cast<Real>(p.rdata(NStructReal+i)));
913 }
914 //Add the rdata(0)-weighted sum of position
915 for (int i = 0; i < AMREX_SPACEDIM; ++i)
916 {
917 amrex::Gpu::Atomic::AddNoRet(&partData(iv,i), static_cast<Real>((p.rdata(0)*p.pos(i))));
918 }
919 //Add the rdata(0)-weighted sum of other rdata fields
920 for (int i = 1; i < NStructReal; ++i)
921 {
922 amrex::Gpu::Atomic::AddNoRet(&partData(iv,AMREX_SPACEDIM+i), static_cast<Real>((p.rdata(0)*p.rdata(i))));
923 }
924 //Add the rdata(0) sum
925 for (int i = 0; i < 1; ++i)
926 {
927 amrex::Gpu::Atomic::AddNoRet(&partData(iv,AMREX_SPACEDIM+i), static_cast<Real>(p.rdata(0)));
928 }
929 }
930
931 }); //skipping extra false argument, doing mf.setVal(0) at beginning
932
933 amrex::ParticleToMesh(*this, imf, level,
934 [=] AMREX_GPU_DEVICE (const ParticleType& p,
935 amrex::Array4<int> const& partData,
938 {
939
940 auto iv = getParticleCell(p, plo_loc, dxi_loc, domain);
941 if(assign_buffer_grid(iv)==-1)
942 {
943 //if this cell has no particle id info, do a straight copy to store idata
944 if(partData(iv,0)==0)
945 {
946 //Add 1 to indicate at least 1 particle at cell iv
947 amrex::Gpu::Atomic::AddNoRet(&partData(iv,0), 1);
948 for (int i = 0; i < NStructInt; ++i)
949 {
950 amrex::Gpu::Atomic::AddNoRet(&partData(iv,1+i), p.idata(i));
951 }
952 for (int i = 0; i < NArrayInt; ++i)
953 {
954 amrex::Gpu::Atomic::AddNoRet(&partData(iv,1+NStructInt+i), p.idata(NStructInt+i));
955 }
956 }
957 }
958 });
959
960 //There may be a better way to ensure virts is the right length
961 virts.resize(imf.sum(0));
962
963 int last_offset = 0;
964 for (MFIter mfi(mf); mfi.isValid(); ++mfi)
965 {
966 const auto bx = mfi.tilebox();
967 const auto partData = mf.array(mfi);
968 const auto imf_arr = imf.array(mfi);
969
970 Gpu::DeviceVector<int> offsets(bx.numPts());
971 auto *offsets_ptr = offsets.dataPtr();
972 int next_offset = Scan::ExclusiveSum((int) bx.numPts(),(imf_arr.ptr(bx.smallEnd(),0)),(offsets.dataPtr()),Scan::retSum);
973 auto dst = virts.getParticleTileData();
974 ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
975 {
976 if(imf_arr(i,j,k,0)!=0)
977 {
978 const auto idx = last_offset + offsets_ptr[
979 imf_arr.get_offset(IntVectND<3>{i,j,k})
980 ];
981
982 dst.cpu(idx) = 0;
984
985 auto& p = dst[idx];
986 //Set rdata(0) first so we can normalize the weighted fields
987 //Note that this does not work for soa PC
988 p.rdata(0) = static_cast<ParticleReal>(partData(i,j,k,AMREX_SPACEDIM));;
989 //Set pos with the normalized weighted field
990 for (int n = 0; n < AMREX_SPACEDIM; ++n)
991 {
992 p.pos(n) = static_cast<ParticleReal>(partData(i,j,k,n) / p.rdata(0));
993 }
994 //Set rdata(n>0) with the normalized weighted field for NStructReal
995 for (int n = 1; n < NStructReal; ++n)
996 {
997 p.rdata(n) = static_cast<ParticleReal>(partData(i,j,k,AMREX_SPACEDIM+n) / p.rdata(0));
998 }
999 //Set rdata(n>0) with the normalized weighted field for NArrayReal
1000 for (int n = 0; n < NArrayReal; ++n)
1001 {
1002 dst.rdata(n)[idx] = static_cast<ParticleReal>(partData(i,j,k,AMREX_SPACEDIM+NStructReal+n));
1003 }
1004 //Set idata with the "first" particles idata field for NStructInt
1005 for (int n = 0; n < NStructInt; ++n)
1006 {
1007 p.idata(n) = imf_arr(i,j,k,1+n);
1008 }
1009 //Set idata with the "first" particles idata field for NArrayInt
1010 for (int n = 0; n < NArrayInt; ++n)
1011 {
1012 dst.idata(n)[idx] = imf_arr(i,j,k,1+NStructInt+n);
1013 }
1014 }
1015
1016 });
1017 last_offset+=next_offset;
1019 }
1020
1021 // last_offset should equal virts.numParticles()
1022 auto virts_offset = last_offset;
1023 for(ParConstIterType pti(*this, level); pti.isValid(); ++pti)
1024 {
1025 const auto& src_tile = ParticlesAt(level, pti);
1026
1027 auto np = src_tile.numParticles();
1028 virts.resize(virts_offset+np);
1029 virts_offset += filterAndTransformParticles(virts, src_tile, FilterVirt(assign_buffer_grid,plo,dxi,domain), TransformerVirt(),0,virts_offset);
1031 }
1032 virts.resize(virts_offset);
1034 }
1035}
1036
1038{
1039
1042
1048 : m_lev_min(level), m_lev_max(level+1), m_nGrow(nGrow), m_gid(gid), m_assign_grid(assign_grid)
1049 {}
1050
1051 template <typename SrcData>
1053 int operator() (const SrcData& src, int src_i) const noexcept
1054 {
1055 const auto tup_min = (m_assign_grid)(src[src_i], m_lev_min, m_lev_max, m_nGrow, DefaultAssignor{});
1056 const auto tup_max = (m_assign_grid)(src[src_i], m_lev_max, m_lev_max, m_nGrow, DefaultAssignor{});
1057 const auto p_boxes = amrex::get<0>(tup_min);
1058 const auto p_boxes_max = amrex::get<0>(tup_max);
1059 const auto p_levs_max = amrex::get<1>(tup_max);
1060 return p_boxes_max >=0 && p_boxes == m_gid && p_levs_max == m_lev_max;
1061 }
1062};
1063
1065{
1066
1067 template <typename DstData, typename SrcData>
1069 void operator() (DstData& dst, const SrcData& src,
1070 int src_i, int dst_i) const noexcept
1071 {
1072 copyParticle(dst, src, src_i, dst_i);
1073
1074 dst.id(dst_i) = LongParticleIds::GhostParticleID;
1075 dst.cpu(dst_i) = 0;
1076 }
1077};
1078
1079template <typename ParticleType, int NArrayReal, int NArrayInt,
1080 template<class> class Allocator, class CellAssignor>
1081void
1082ParticleContainer_impl<ParticleType, NArrayReal, NArrayInt, Allocator, CellAssignor>
1083::CreateGhostParticles (int level, int nGrow, AoS& ghosts) const
1084{
1085 ParticleTileType ptile;
1086 CreateGhostParticles(level, nGrow, ptile);
1087 ptile.GetArrayOfStructs().swap(ghosts);
1088}
1089
1090template <typename ParticleType, int NArrayReal, int NArrayInt,
1091 template<class> class Allocator, class CellAssignor>
1092void
1094::CreateGhostParticles (int level, int nGrow, ParticleTileType& ghosts) const
1095{
1096 BL_PROFILE("ParticleContainer::CreateGhostParticles()");
1097 AMREX_ASSERT(ghosts.empty());
1098 AMREX_ASSERT(level < finestLevel());
1099
1100 if (level >= static_cast<int>(m_particles.size())) {
1101 return;
1102 }
1103
1104 if (! m_particle_locator.isValid(GetParGDB())) {
1105 m_particle_locator.build(GetParGDB());
1106 }
1107
1108 m_particle_locator.setGeometry(GetParGDB());
1109 AmrAssignGrid<DenseBinIteratorFactory<Box>> assign_grid = m_particle_locator.getGridAssignor();
1110 auto ghost_offset = ghosts.numParticles();
1111 for(ParConstIterType pti(*this, level); pti.isValid(); ++pti)
1112 {
1113 const auto& src_tile = ParticlesAt(level, pti);
1114 int gid = pti.index();
1115
1116 auto np = src_tile.numParticles();
1117 ghosts.resize(ghost_offset+np);
1118 ghost_offset += filterAndTransformParticles(ghosts, src_tile, AssignGridFilter(assign_grid,gid,level,nGrow), TransformerGhost(),0,ghost_offset);
1119 }
1120 ghosts.resize(ghost_offset);
1122}
1123
1124template <typename ParticleType, int NArrayReal, int NArrayInt,
1125 template<class> class Allocator, class CellAssignor>
1126void
1129{
1130 BL_PROFILE("ParticleContainer::clearParticles()");
1131
1132 for (int lev = 0; lev < static_cast<int>(m_particles.size()); ++lev)
1133 {
1134 for (auto& kv : m_particles[lev]) { kv.second.resize(0); }
1135 particle_detail::clearEmptyEntries(m_particles[lev]);
1136 }
1137}
1138
1139template <typename ParticleType, int NArrayReal, int NArrayInt,
1140 template<class> class Allocator, class CellAssignor>
1141template <class PCType, std::enable_if_t<IsParticleContainer<PCType>::value, int> foo>
1142void
1149
1150template <typename ParticleType, int NArrayReal, int NArrayInt,
1151 template<class> class Allocator, class CellAssignor>
1152template <class PCType, std::enable_if_t<IsParticleContainer<PCType>::value, int> foo>
1153void
1155addParticles (const PCType& other, bool local)
1156{
1158 addParticles(other, [] AMREX_GPU_HOST_DEVICE (const PData& /*data*/, int /*i*/) { return 1; }, local);
1159}
1160
1161template <typename ParticleType, int NArrayReal, int NArrayInt,
1162 template<class> class Allocator, class CellAssignor>
1163template <class F, class PCType,
1164 std::enable_if_t<IsParticleContainer<PCType>::value, int> foo,
1165 std::enable_if_t<! std::is_integral_v<F>, int> bar>
1166void
1168copyParticles (const PCType& other, F&& f, bool local)
1169{
1170 BL_PROFILE("ParticleContainer::copyParticles");
1171 clearParticles();
1172 addParticles(other, std::forward<F>(f), local);
1173}
1174
1175template <typename ParticleType, int NArrayReal, int NArrayInt,
1176 template<class> class Allocator, class CellAssignor>
1177template <class F, class PCType,
1178 std::enable_if_t<IsParticleContainer<PCType>::value, int> foo,
1179 std::enable_if_t<! std::is_integral_v<F>, int> bar>
1180void
1182addParticles (const PCType& other, F const& f, bool local)
1183{
1184 BL_PROFILE("ParticleContainer::addParticles");
1185
1186 // touch all tiles in serial
1187 for (int lev = 0; lev < other.numLevels(); ++lev)
1188 {
1189 [[maybe_unused]] Gpu::NoSyncRegion no_sync{};
1190 const auto& plevel_other = other.GetParticles(lev);
1191 for(MFIter mfi = other.MakeMFIter(lev); mfi.isValid(); ++mfi)
1192 {
1193 auto index = std::make_pair(mfi.index(), mfi.LocalTileIndex());
1194 if(plevel_other.find(index) == plevel_other.end()) { continue; }
1195
1196 DefineAndReturnParticleTile(lev, mfi.index(), mfi.LocalTileIndex());
1197 }
1198 }
1199
1200#ifdef AMREX_USE_OMP
1201#pragma omp parallel if (Gpu::notInLaunchRegion())
1202#endif
1203 for (int lev = 0; lev < other.numLevels(); ++lev)
1204 {
1205 const auto& plevel_other = other.GetParticles(lev);
1206 for(MFIter mfi = other.MakeMFIter(lev); mfi.isValid(); ++mfi)
1207 {
1208 auto index = std::make_pair(mfi.index(), mfi.LocalTileIndex());
1209 if(plevel_other.find(index) == plevel_other.end()) { continue; }
1210
1211 // this has already had define() called above
1212 auto& ptile = ParticlesAt(lev, mfi.index(), mfi.LocalTileIndex());
1213 const auto& ptile_other = plevel_other.at(index);
1214 auto np = ptile_other.numParticles();
1215 if (np == 0) { continue; }
1216
1217 auto dst_index = ptile.numParticles();
1218 ptile.resize(dst_index + np);
1219
1220 auto count = amrex::filterParticles(ptile, ptile_other, f, 0, dst_index, np);
1221
1222 ptile.resize(dst_index + count);
1223 }
1224 }
1226 if (! local) { Redistribute(); }
1227}
1228
1230// This redistributes valid particles and discards invalid ones.
1231//
1232template <typename ParticleType, int NArrayReal, int NArrayInt,
1233 template<class> class Allocator, class CellAssignor>
1234void
1236::Redistribute (int lev_min, int lev_max, int nGrow, int local, bool remove_negative)
1237{
1238 BL_PROFILE_SYNC_START_TIMED("SyncBeforeComms: Redist");
1239
1240#ifdef AMREX_USE_GPU
1241 if ( Gpu::inLaunchRegion() )
1242 {
1243 RedistributeGPU(lev_min, lev_max, nGrow, local, remove_negative);
1244 }
1245 else
1246 {
1247 RedistributeCPU(lev_min, lev_max, nGrow, local, remove_negative);
1248 }
1249#else
1250 RedistributeCPU(lev_min, lev_max, nGrow, local, remove_negative);
1251#endif
1252
1254}
1255
1256template <typename ParticleType, int NArrayReal, int NArrayInt,
1257 template<class> class Allocator, class CellAssignor>
1258template <class index_type>
1259void
1261::ReorderParticles (int lev, const MFIter& mfi, const index_type* permutations)
1262{
1263 auto& ptile = ParticlesAt(lev, mfi);
1264 const size_t np = ptile.numParticles();
1265 const size_t np_total = np + ptile.numNeighborParticles();
1266
1267 if (memEfficientSort) {
1268#if defined(AMREX_USE_CUDA) && defined(_WIN32)
1269 if (!ParticleType::is_soa_particle) {
1270#else
1271 if constexpr (!ParticleType::is_soa_particle) {
1272#endif
1273 static_assert(sizeof(ParticleType)%4 == 0 && sizeof(uint32_t) == 4);
1274 using tmp_t = std::conditional_t<sizeof(ParticleType)%8 == 0,
1275 uint64_t, uint32_t>;
1276 constexpr std::size_t nchunks = sizeof(ParticleType) / sizeof(tmp_t);
1278 auto* ptmp = tmp.data();
1279 auto* paos = (tmp_t*)(ptile.getParticleTileData().m_aos);
1280 for (std::size_t ichunk = 0; ichunk < nchunks; ++ichunk) {
1281 // Do not need to reorder neighbor particles
1283 {
1284 ptmp[i] = paos[permutations[i]*nchunks+ichunk];
1285 });
1287 {
1288 paos[i*nchunks+ichunk] = ptmp[i];
1289 });
1290 }
1292 } else {
1293 typename SoA::IdCPU tmp_idcpu;
1294 if constexpr (has_polymorphic_allocator) {
1295 tmp_idcpu.setArena(arena());
1296 }
1297 tmp_idcpu.resize(np_total);
1298 auto src = ptile.GetStructOfArrays().GetIdCPUData().data();
1299 uint64_t* dst = tmp_idcpu.data();
1300 AMREX_HOST_DEVICE_FOR_1D( np_total, i,
1301 {
1302 dst[i] = i < np ? src[permutations[i]] : src[i];
1303 });
1304
1306
1307 ptile.GetStructOfArrays().GetIdCPUData().swap(tmp_idcpu);
1308 }
1309
1310 { // Create a scope for the temporary vector below
1311 RealVector tmp_real;
1312 if constexpr (has_polymorphic_allocator) {
1313 tmp_real.setArena(arena());
1314 }
1315 tmp_real.resize(np_total);
1316 for (int comp = 0; comp < NArrayReal + m_num_runtime_real; ++comp) {
1317 auto src = ptile.GetStructOfArrays().GetRealData(comp).data();
1318 ParticleReal* dst = tmp_real.data();
1319 AMREX_HOST_DEVICE_FOR_1D( np_total, i,
1320 {
1321 dst[i] = i < np ? src[permutations[i]] : src[i];
1322 });
1323
1325
1326 ptile.GetStructOfArrays().GetRealData(comp).swap(tmp_real);
1327 }
1328 }
1329
1330 IntVector tmp_int;
1331 if constexpr (has_polymorphic_allocator) {
1332 tmp_int.setArena(arena());
1333 }
1334 tmp_int.resize(np_total);
1335 for (int comp = 0; comp < NArrayInt + m_num_runtime_int; ++comp) {
1336 auto src = ptile.GetStructOfArrays().GetIntData(comp).data();
1337 int* dst = tmp_int.data();
1338 AMREX_HOST_DEVICE_FOR_1D( np_total , i,
1339 {
1340 dst[i] = i < np ? src[permutations[i]] : src[i];
1341 });
1342
1344
1345 ptile.GetStructOfArrays().GetIntData(comp).swap(tmp_int);
1346 }
1347 } else {
1348 ParticleTileType ptile_tmp;
1349 ptile_tmp.define(m_num_runtime_real, m_num_runtime_int,
1350 &m_soa_rdata_names, &m_soa_idata_names, arena());
1351 ptile_tmp.resize(np_total);
1352 // copy re-ordered particles
1353 gatherParticles(ptile_tmp, ptile, np, permutations);
1354 // copy neighbor particles
1355 amrex::copyParticles(ptile_tmp, ptile, np, np, np_total-np);
1356 ptile.swap(ptile_tmp);
1357 }
1358}
1359
1360template <typename ParticleType, int NArrayReal, int NArrayInt,
1361 template<class> class Allocator, class CellAssignor>
1362void
1368template <typename ParticleType, int NArrayReal, int NArrayInt,
1369 template<class> class Allocator, class CellAssignor>
1370void
1373{
1374 BL_PROFILE("ParticleContainer::SortParticlesByBin()");
1375
1376 if (bin_size == IntVect::TheZeroVector()) { return; }
1377
1378 for (int lev = 0; lev < numLevels(); ++lev)
1379 {
1380 const Geometry& geom = Geom(lev);
1381 const auto dxi = geom.InvCellSizeArray();
1382 const auto plo = geom.ProbLoArray();
1383 const auto domain = geom.Domain();
1384
1385 for(MFIter mfi = MakeMFIter(lev); mfi.isValid(); ++mfi)
1386 {
1387 auto& ptile = ParticlesAt(lev, mfi);
1388 const size_t np = ptile.numParticles();
1389
1390 const Box& box = mfi.validbox();
1391
1392 int ntiles = numTilesInBox(box, true, bin_size);
1393
1394 m_bins.build(np, ptile.getParticleTileData(), ntiles,
1395 GetParticleBin{plo, dxi, domain, bin_size, box});
1396 ReorderParticles(lev, mfi, m_bins.permutationPtr());
1397 }
1398 }
1399}
1400
1401template <typename ParticleType, int NArrayReal, int NArrayInt,
1402 template<class> class Allocator, class CellAssignor>
1403void
1406{
1407 BL_PROFILE("ParticleContainer::SortParticlesForDeposition()");
1408
1409 for (int lev = 0; lev < numLevels(); ++lev)
1410 {
1411 const Geometry& geom = Geom(lev);
1412
1413 for(MFIter mfi = MakeMFIter(lev); mfi.isValid(); ++mfi)
1414 {
1415 const auto& ptile = ParticlesAt(lev, mfi);
1416 const size_t np = ptile.numParticles();
1417
1418 const Box& box = mfi.validbox();
1419
1420 using index_type = typename decltype(m_bins)::index_type;
1422 PermutationForDeposition<index_type>(perm, np, ptile, box, geom, idx_type);
1423 ReorderParticles(lev, mfi, perm.dataPtr());
1424 }
1425 }
1426}
1427
1428//
1429// The GPU implementation of Redistribute
1430//
1431template <typename ParticleType, int NArrayReal, int NArrayInt,
1432 template<class> class Allocator, class CellAssignor>
1433void
1435::RedistributeGPU (int lev_min, int lev_max, int nGrow, int local, bool remove_negative)
1436{
1437#ifdef AMREX_USE_GPU
1438
1439 if (local) { AMREX_ASSERT(numParticlesOutOfRange(*this, lev_min, lev_max, local) == 0); }
1440
1441 // sanity check
1442 AMREX_ALWAYS_ASSERT(do_tiling == false);
1443
1444 BL_PROFILE("ParticleContainer::RedistributeGPU()");
1445 BL_PROFILE_VAR_NS("Redistribute_partition", blp_partition);
1446
1447 int theEffectiveFinestLevel = m_gdb->finestLevel();
1448 while (!m_gdb->LevelDefined(theEffectiveFinestLevel)) { theEffectiveFinestLevel--; }
1449
1450 if (int(m_particles.size()) < theEffectiveFinestLevel+1) {
1451 if (Verbose()) {
1452 amrex::Print() << "ParticleContainer::Redistribute() resizing containers from "
1453 << m_particles.size() << " to "
1454 << theEffectiveFinestLevel + 1 << '\n';
1455 }
1456 m_particles.resize(theEffectiveFinestLevel+1);
1457 m_dummy_mf.resize(theEffectiveFinestLevel+1);
1458 }
1459
1460 for (int lev = 0; lev < theEffectiveFinestLevel+1; ++lev) { RedefineDummyMF(lev); }
1461
1462 int finest_lev_particles;
1463 if (lev_max == -1) {
1464 lev_max = theEffectiveFinestLevel;
1465 finest_lev_particles = m_particles.size() - 1;
1466 } else {
1467 finest_lev_particles = lev_max;
1468 }
1469 AMREX_ASSERT(lev_max <= finestLevel());
1470
1471 this->defineBufferMap();
1472
1473 if (! m_particle_locator.isValid(GetParGDB())) { m_particle_locator.build(GetParGDB()); }
1474 m_particle_locator.setGeometry(GetParGDB());
1475 auto assign_grid = m_particle_locator.getGridAssignor();
1476
1477 BL_PROFILE_VAR_START(blp_partition);
1478 ParticleCopyOp op;
1479 int num_levels = finest_lev_particles + 1;
1480 op.setNumLevels(num_levels);
1481 Vector<std::map<int, int> > new_sizes(num_levels);
1482 const auto plo = Geom(0).ProbLoArray();
1483 const auto phi = Geom(0).ProbHiArray();
1484 const auto rlo = Geom(0).ProbLoArrayInParticleReal();
1485 const auto rhi = Geom(0).ProbHiArrayInParticleReal();
1486 const auto is_per = Geom(0).isPeriodicArray();
1487 for (int lev = lev_min; lev <= finest_lev_particles; ++lev)
1488 {
1489 auto& plev = m_particles[lev];
1490 for (auto& kv : plev)
1491 {
1492 int gid = kv.first.first;
1493 int tid = kv.first.second;
1494 auto index = std::make_pair(gid, tid);
1495
1496 auto& src_tile = plev[index];
1497 const size_t np = src_tile.numParticles();
1498
1499 int num_stay = partitionParticlesByDest(src_tile, assign_grid,
1500 std::forward<CellAssignor>(CellAssignor{}),
1501 BufferMap(),
1502 plo, phi, rlo, rhi, is_per, lev, gid, tid,
1503 lev_min, lev_max, nGrow, remove_negative);
1504
1505 int num_move = np - num_stay;
1506 new_sizes[lev][gid] = num_stay;
1507 op.resize(gid, lev, num_move);
1508
1509 auto p_boxes = op.m_boxes[lev][gid].dataPtr();
1510 auto p_levs = op.m_levels[lev][gid].dataPtr();
1511 auto p_src_indices = op.m_src_indices[lev][gid].dataPtr();
1512 auto p_periodic_shift = op.m_periodic_shift[lev][gid].dataPtr();
1513 auto ptd = src_tile.getParticleTileData();
1514
1515 AMREX_FOR_1D ( num_move, i,
1516 {
1517 const auto p = ptd[i + num_stay];
1518
1519 if (!p.id().is_valid())
1520 {
1521 p_boxes[i] = -1;
1522 p_levs[i] = -1;
1523 }
1524 else
1525 {
1526 const auto tup = assign_grid(p, lev_min, lev_max, nGrow,
1527 std::forward<CellAssignor>(CellAssignor{}));
1528 p_boxes[i] = amrex::get<0>(tup);
1529 p_levs[i] = amrex::get<1>(tup);
1530 }
1531 p_periodic_shift[i] = IntVect(AMREX_D_DECL(0,0,0));
1532 p_src_indices[i] = i+num_stay;
1533 });
1534 }
1535 }
1536 BL_PROFILE_VAR_STOP(blp_partition);
1537
1538 ParticleCopyPlan plan;
1539
1540 plan.build(*this, op, h_redistribute_int_comp,
1541 h_redistribute_real_comp, local);
1542
1543 // by default, this uses The_Arena();
1546
1547 if (use_comms_arena) {
1548 snd_buffer.setArena(The_Comms_Arena());
1549 rcv_buffer.setArena(The_Comms_Arena());
1550 }
1551
1552 packBuffer(*this, op, plan, snd_buffer);
1553
1554 // clear particles from container
1555 for (int lev = lev_min; lev <= lev_max; ++lev)
1556 {
1557 auto& plev = m_particles[lev];
1558 for (auto& kv : plev)
1559 {
1560 int gid = kv.first.first;
1561 int tid = kv.first.second;
1562 auto index = std::make_pair(gid, tid);
1563 auto& tile = plev[index];
1564 tile.resize(new_sizes[lev][gid]);
1565 }
1566 }
1567
1568 for (int lev = lev_min; lev <= lev_max; lev++)
1569 {
1570 particle_detail::clearEmptyEntries(m_particles[lev]);
1571 }
1572
1573 if (int(m_particles.size()) > theEffectiveFinestLevel+1) {
1574 if (m_verbose > 0) {
1575 amrex::Print() << "ParticleContainer::Redistribute() resizing m_particles from "
1576 << m_particles.size() << " to " << theEffectiveFinestLevel+1 << '\n';
1577 }
1578 AMREX_ASSERT(int(m_particles.size()) >= 2);
1579
1580 m_particles.resize(theEffectiveFinestLevel + 1);
1581 m_dummy_mf.resize(theEffectiveFinestLevel + 1);
1582 }
1583
1585 {
1586 plan.buildMPIFinish(BufferMap());
1587 communicateParticlesStart(*this, plan, snd_buffer, rcv_buffer);
1588 this->ReserveForRedistribute(plan);
1589 unpackBuffer(*this, plan, snd_buffer, RedistributeUnpackPolicy());
1591 unpackRemotes(*this, plan, rcv_buffer, RedistributeUnpackPolicy());
1592 }
1593 else
1594 {
1596 Gpu::PinnedVector<char> pinned_snd_buffer;
1597 Gpu::PinnedVector<char> pinned_rcv_buffer;
1598
1599 if (snd_buffer.arena()->isPinned()) {
1600 plan.buildMPIFinish(BufferMap());
1602 communicateParticlesStart(*this, plan, snd_buffer, pinned_rcv_buffer);
1603 } else {
1604 pinned_snd_buffer.resize(snd_buffer.size());
1605 Gpu::dtoh_memcpy_async(pinned_snd_buffer.dataPtr(), snd_buffer.dataPtr(), snd_buffer.size());
1606 plan.buildMPIFinish(BufferMap());
1608 communicateParticlesStart(*this, plan, pinned_snd_buffer, pinned_rcv_buffer);
1609 }
1610
1611 this->ReserveForRedistribute(plan);
1612
1613 rcv_buffer.resize(pinned_rcv_buffer.size());
1614 unpackBuffer(*this, plan, snd_buffer, RedistributeUnpackPolicy());
1616 Gpu::htod_memcpy_async(rcv_buffer.dataPtr(), pinned_rcv_buffer.dataPtr(), pinned_rcv_buffer.size());
1617 unpackRemotes(*this, plan, rcv_buffer, RedistributeUnpackPolicy());
1618 }
1619
1621 AMREX_ASSERT(numParticlesOutOfRange(*this, lev_min, lev_max, nGrow) == 0);
1622#else
1623 amrex::ignore_unused(lev_min,lev_max,nGrow,local,remove_negative);
1624#endif
1625}
1626
1627template <typename ParticleType, int NArrayReal, int NArrayInt,
1628 template<class> class Allocator, class CellAssignor>
1629void
1630ParticleContainer_impl<ParticleType, NArrayReal, NArrayInt, Allocator, CellAssignor>
1631::ReserveForRedistribute (ParticleCopyPlan const& plan)
1632{
1633 BL_PROFILE("ParticleContainer::ReserveForRedistribute()");
1634
1635 std::map<ParticleTileType*, int> addsizes;
1636
1637 for (int lev = 0; lev < this->BufferMap().numLevels(); ++lev) {
1638 for (MFIter mfi = this->MakeMFIter(lev); mfi.isValid(); ++mfi) {
1639 int gid = mfi.index();
1640 int tid = mfi.LocalTileIndex();
1641 auto& tile = this->DefineAndReturnParticleTile(lev, gid, tid);
1642 int num_copies = plan.m_box_counts_h[this->BufferMap().gridAndLevToBucket(gid, lev)];
1643 if (num_copies > 0) {
1644 addsizes[&tile] += num_copies;
1645 }
1646 }
1647 }
1648
1649 if (plan.m_nrcvs > 0) {
1650 AMREX_ALWAYS_ASSERT(do_tiling == false);
1651 for (int i = 0, N = int(plan.m_rcv_box_counts.size()); i < N; ++i) {
1652 int copy_size = plan.m_rcv_box_counts[i];
1653 int lev = plan.m_rcv_box_levs[i];
1654 int gid = plan.m_rcv_box_ids[i];
1655 int tid = 0; // It's always 0 because this function is for RedistributeGPU only and the tiling is off.
1656 auto& tile = this->DefineAndReturnParticleTile(lev, gid, tid);
1657 addsizes[&tile] += copy_size;
1658 }
1659 }
1660
1661 ParticleTileType::reserve(addsizes);
1662}
1663
1664//
1665// The CPU implementation of Redistribute
1666//
1667template <typename ParticleType, int NArrayReal, int NArrayInt,
1668 template<class> class Allocator, class CellAssignor>
1669void
1671::RedistributeCPU (int lev_min, int lev_max, int nGrow, int local, bool remove_negative)
1672{
1673 BL_PROFILE("ParticleContainer::RedistributeCPU()");
1674
1675 const int MyProc = ParallelContext::MyProcSub();
1676 auto strttime = amrex::second();
1677
1678 if (local > 0) { BuildRedistributeMask(0, local); }
1679
1680 // On startup there are cases where Redistribute() could be called
1681 // with a given finestLevel() where that AmrLevel has yet to be defined.
1682 int theEffectiveFinestLevel = m_gdb->finestLevel();
1683
1684 while (!m_gdb->LevelDefined(theEffectiveFinestLevel)) {
1685 theEffectiveFinestLevel--;
1686 }
1687
1688 if (int(m_particles.size()) < theEffectiveFinestLevel+1) {
1689 if (Verbose()) {
1690 amrex::Print() << "ParticleContainer::Redistribute() resizing containers from "
1691 << m_particles.size() << " to "
1692 << theEffectiveFinestLevel + 1 << '\n';
1693 }
1694 m_particles.resize(theEffectiveFinestLevel+1);
1695 m_dummy_mf.resize(theEffectiveFinestLevel+1);
1696 }
1697
1698 // It is important to do this even if we don't have more levels because we may have changed the
1699 // grids at this level in a regrid.
1700 for (int lev = 0; lev < theEffectiveFinestLevel+1; ++lev) {
1701 RedefineDummyMF(lev);
1702 }
1703
1704 int finest_lev_particles;
1705 if (lev_max == -1) {
1706 lev_max = theEffectiveFinestLevel;
1707 finest_lev_particles = m_particles.size() - 1;
1708 } else {
1709 finest_lev_particles = lev_max;
1710 }
1711 AMREX_ASSERT(lev_max <= finestLevel());
1712
1713 // This will hold the valid particles that go to another process
1714 std::map<int, Vector<char> > not_ours;
1715
1716 int num_threads = OpenMP::get_max_threads();
1717
1718 // these are temporary buffers for each thread
1719 std::map<int, Vector<Vector<char> > > tmp_remote;
1722 tmp_local.resize(theEffectiveFinestLevel+1);
1723 soa_local.resize(theEffectiveFinestLevel+1);
1724
1725 // we resize these buffers outside the parallel region
1726 for (int lev = lev_min; lev <= lev_max; lev++) {
1727 for (MFIter mfi(*m_dummy_mf[lev], this->do_tiling ? this->tile_size : IntVect::TheZeroVector());
1728 mfi.isValid(); ++mfi) {
1729 auto index = std::make_pair(mfi.index(), mfi.LocalTileIndex());
1730 tmp_local[lev][index].resize(num_threads);
1731 soa_local[lev][index].resize(num_threads);
1732 for (int t = 0; t < num_threads; ++t) {
1733 soa_local[lev][index][t].define(m_num_runtime_real, m_num_runtime_int,
1734 &m_soa_rdata_names, &m_soa_idata_names);
1735 if constexpr (has_polymorphic_allocator) {
1736 if constexpr (ParticleType::is_soa_particle) {
1737 soa_local[lev][index][t].GetIdCPUData().setArena(arena());
1738 } else {
1739 tmp_local[lev][index][t].setArena(arena());
1740 }
1741 for (int j = 0; j < soa_local[lev][index][t].NumRealComps(); ++j) {
1742 soa_local[lev][index][t].GetRealData(j).setArena(arena());
1743 }
1744 for (int j = 0; j < soa_local[lev][index][t].NumIntComps(); ++j) {
1745 soa_local[lev][index][t].GetIntData(j).setArena(arena());
1746 }
1747 }
1748 }
1749 }
1750 }
1751 if (local) {
1752 for (int i = 0; i < neighbor_procs.size(); ++i) {
1753 tmp_remote[neighbor_procs[i]].resize(num_threads);
1754 }
1755 } else {
1756 for (int i = 0; i < ParallelContext::NProcsSub(); ++i) {
1757 tmp_remote[i].resize(num_threads);
1758 }
1759 }
1760
1761 // first pass: for each tile in parallel, in each thread copies the particles that
1762 // need to be moved into it's own, temporary buffer.
1763 for (int lev = lev_min; lev <= finest_lev_particles; lev++) {
1764 auto& pmap = m_particles[lev];
1765
1766 Vector<std::pair<int, int> > grid_tile_ids;
1767 Vector<ParticleTileType*> ptile_ptrs;
1768 for (auto& kv : pmap)
1769 {
1770 grid_tile_ids.push_back(kv.first);
1771 ptile_ptrs.push_back(&(kv.second));
1772 }
1773
1774#ifdef AMREX_USE_OMP
1775#pragma omp parallel for
1776#endif
1777 for (int pmap_it = 0; pmap_it < static_cast<int>(ptile_ptrs.size()); ++pmap_it)
1778 {
1779 int thread_num = OpenMP::get_thread_num();
1780 int grid = grid_tile_ids[pmap_it].first;
1781 int tile = grid_tile_ids[pmap_it].second;
1782 auto& soa = ptile_ptrs[pmap_it]->GetStructOfArrays();
1783 auto& aos = ptile_ptrs[pmap_it]->GetArrayOfStructs();
1784
1785 // AMREX_ASSERT_WITH_MESSAGE((NumRealComps() == 0 && NumIntComps() == 0)
1786 // || aos.size() == soa.size(),
1787 // "The AoS and SoA data on this tile are different sizes - "
1788 // "perhaps particles have not been initialized correctly?");
1789 unsigned npart = ptile_ptrs[pmap_it]->numParticles();
1790 ParticleLocData pld;
1791
1792 if constexpr (!ParticleType::is_soa_particle){
1793
1794 if (npart != 0) {
1795 Long last = npart - 1;
1796 Long pindex = 0;
1797 while (pindex <= last) {
1798 ParticleType& p = aos[pindex];
1799
1800 if ((remove_negative == false) && (!p.id().is_valid())) {
1801 ++pindex;
1802 continue;
1803 }
1804
1805 if (!p.id().is_valid())
1806 {
1807 aos[pindex] = aos[last];
1808 for (int comp = 0; comp < NumRealComps(); comp++) {
1809 soa.GetRealData(comp)[pindex] = soa.GetRealData(comp)[last];
1810 }
1811 for (int comp = 0; comp < NumIntComps(); comp++) {
1812 soa.GetIntData(comp)[pindex] = soa.GetIntData(comp)[last];
1813 }
1814 correctCellVectors(last, pindex, grid, aos[pindex]);
1815 --last;
1816 continue;
1817 }
1818
1819 locateParticle(p, pld, lev_min, lev_max, nGrow, local ? grid : -1);
1820
1821 particlePostLocate(p, pld, lev);
1822
1823 if (!p.id().is_valid())
1824 {
1825 aos[pindex] = aos[last];
1826 for (int comp = 0; comp < NumRealComps(); comp++) {
1827 soa.GetRealData(comp)[pindex] = soa.GetRealData(comp)[last];
1828 }
1829 for (int comp = 0; comp < NumIntComps(); comp++) {
1830 soa.GetIntData(comp)[pindex] = soa.GetIntData(comp)[last];
1831 }
1832 correctCellVectors(last, pindex, grid, aos[pindex]);
1833 --last;
1834 continue;
1835 }
1836
1837 const int who = ParallelContext::global_to_local_rank(ParticleDistributionMap(pld.m_lev)[pld.m_grid]);
1838 if (who == MyProc) {
1839 if (pld.m_lev != lev || pld.m_grid != grid || pld.m_tile != tile) {
1840 // We own it but must shift it to another place.
1841 auto index = std::make_pair(pld.m_grid, pld.m_tile);
1842 AMREX_ASSERT(tmp_local[pld.m_lev][index].size() == num_threads);
1843 tmp_local[pld.m_lev][index][thread_num].push_back(p);
1844 for (int comp = 0; comp < NumRealComps(); ++comp) {
1845 RealVector& arr = soa_local[pld.m_lev][index][thread_num].GetRealData(comp);
1846 arr.push_back(soa.GetRealData(comp)[pindex]);
1847 }
1848 for (int comp = 0; comp < NumIntComps(); ++comp) {
1849 IntVector& arr = soa_local[pld.m_lev][index][thread_num].GetIntData(comp);
1850 arr.push_back(soa.GetIntData(comp)[pindex]);
1851 }
1852
1853 p.id().make_invalid(); // Invalidate the particle
1854 }
1855 }
1856 else {
1857 auto& particles_to_send = tmp_remote[who][thread_num];
1858 auto old_size = particles_to_send.size();
1859 auto new_size = old_size + superparticle_size;
1860 particles_to_send.resize(new_size);
1861 std::memcpy(&particles_to_send[old_size], &p, particle_size);
1862 char* dst = &particles_to_send[old_size] + particle_size;
1863 int array_comp_start = 0;
1864 if constexpr (!ParticleType::is_soa_particle) {
1865 array_comp_start = AMREX_SPACEDIM + NStructReal;
1866 }
1867 for (int comp = 0; comp < NumRealComps(); comp++) {
1868 if (h_redistribute_real_comp[array_comp_start + comp]) {
1869 std::memcpy(dst, &soa.GetRealData(comp)[pindex], sizeof(ParticleReal));
1870 dst += sizeof(ParticleReal);
1871 }
1872 }
1873 array_comp_start = 2 + NStructInt;
1874 for (int comp = 0; comp < NumIntComps(); comp++) {
1875 if (h_redistribute_int_comp[array_comp_start + comp]) {
1876 std::memcpy(dst, &soa.GetIntData(comp)[pindex], sizeof(int));
1877 dst += sizeof(int);
1878 }
1879 }
1880
1881 p.id().make_invalid(); // Invalidate the particle
1882 }
1883
1884 if (!p.id().is_valid())
1885 {
1886 aos[pindex] = aos[last];
1887 for (int comp = 0; comp < NumRealComps(); comp++) {
1888 soa.GetRealData(comp)[pindex] = soa.GetRealData(comp)[last];
1889 }
1890 for (int comp = 0; comp < NumIntComps(); comp++) {
1891 soa.GetIntData(comp)[pindex] = soa.GetIntData(comp)[last];
1892 }
1893 correctCellVectors(last, pindex, grid, aos[pindex]);
1894 --last;
1895 continue;
1896 }
1897
1898 ++pindex;
1899 }
1900
1901 aos().erase(aos().begin() + last + 1, aos().begin() + npart);
1902 for (int comp = 0; comp < NumRealComps(); comp++) {
1903 RealVector& rdata = soa.GetRealData(comp);
1904 rdata.erase(rdata.begin() + last + 1, rdata.begin() + npart);
1905 }
1906 for (int comp = 0; comp < NumIntComps(); comp++) {
1907 IntVector& idata = soa.GetIntData(comp);
1908 idata.erase(idata.begin() + last + 1, idata.begin() + npart);
1909 }
1910 }
1911
1912 } else { // soa particle
1913
1914 auto particle_tile = ptile_ptrs[pmap_it];
1915 if (npart != 0) {
1916 Long last = npart - 1;
1917 Long pindex = 0;
1918 auto ptd = particle_tile->getParticleTileData();
1919 while (pindex <= last) {
1920 ParticleType p = ptd[pindex];
1921
1922 if ((remove_negative == false) && (!ptd.id(pindex).is_valid())) {
1923 ++pindex;
1924 continue;
1925 }
1926
1927 if (!ptd.id(pindex).is_valid()){
1928 soa.GetIdCPUData()[pindex] = soa.GetIdCPUData()[last];
1929 for (int comp = 0; comp < NumRealComps(); comp++) {
1930 soa.GetRealData(comp)[pindex] = soa.GetRealData(comp)[last];
1931 }
1932 for (int comp = 0; comp < NumIntComps(); comp++) {
1933 soa.GetIntData(comp)[pindex] = soa.GetIntData(comp)[last];
1934 }
1935 correctCellVectors(last, pindex, grid, ptd[pindex]);
1936 --last;
1937 continue;
1938 }
1939
1940 locateParticle(p, pld, lev_min, lev_max, nGrow, local ? grid : -1);
1941
1942 particlePostLocate(p, pld, lev);
1943
1944 if (!ptd.id(pindex).is_valid()) {
1945 soa.GetIdCPUData()[pindex] = soa.GetIdCPUData()[last];
1946 for (int comp = 0; comp < NumRealComps(); comp++) {
1947 soa.GetRealData(comp)[pindex] = soa.GetRealData(comp)[last];
1948 }
1949 for (int comp = 0; comp < NumIntComps(); comp++) {
1950 soa.GetIntData(comp)[pindex] = soa.GetIntData(comp)[last];
1951 }
1952 correctCellVectors(last, pindex, grid, ptd[pindex]);
1953 --last;
1954 continue;
1955 }
1956
1957 const int who = ParallelContext::global_to_local_rank(ParticleDistributionMap(pld.m_lev)[pld.m_grid]);
1958 if (who == MyProc) {
1959 if (pld.m_lev != lev || pld.m_grid != grid || pld.m_tile != tile) {
1960 // We own it but must shift it to another place.
1961 auto index = std::make_pair(pld.m_grid, pld.m_tile);
1962 AMREX_ASSERT(soa_local[pld.m_lev][index].size() == num_threads);
1963 {
1964 auto& arr = soa_local[pld.m_lev][index][thread_num].GetIdCPUData();
1965 arr.push_back(soa.GetIdCPUData()[pindex]);
1966 }
1967 for (int comp = 0; comp < NumRealComps(); ++comp) {
1968 RealVector& arr = soa_local[pld.m_lev][index][thread_num].GetRealData(comp);
1969 arr.push_back(soa.GetRealData(comp)[pindex]);
1970 }
1971 for (int comp = 0; comp < NumIntComps(); ++comp) {
1972 IntVector& arr = soa_local[pld.m_lev][index][thread_num].GetIntData(comp);
1973 arr.push_back(soa.GetIntData(comp)[pindex]);
1974 }
1975
1976 ptd.id(pindex).make_invalid(); // Invalidate the particle
1977 }
1978 }
1979 else {
1980 auto& particles_to_send = tmp_remote[who][thread_num];
1981 auto old_size = particles_to_send.size();
1982 auto new_size = old_size + superparticle_size;
1983 particles_to_send.resize(new_size);
1984
1985 char* dst = &particles_to_send[old_size];
1986 {
1987 std::memcpy(dst, &soa.GetIdCPUData()[pindex], sizeof(uint64_t));
1988 dst += sizeof(uint64_t);
1989 }
1990 int array_comp_start = 0;
1991 if constexpr (!ParticleType::is_soa_particle) {
1992 array_comp_start = AMREX_SPACEDIM + NStructReal;
1993 }
1994 for (int comp = 0; comp < NumRealComps(); comp++) {
1995 if (h_redistribute_real_comp[array_comp_start + comp]) {
1996 std::memcpy(dst, &soa.GetRealData(comp)[pindex], sizeof(ParticleReal));
1997 dst += sizeof(ParticleReal);
1998 }
1999 }
2000 array_comp_start = 2 + NStructInt;
2001 for (int comp = 0; comp < NumIntComps(); comp++) {
2002 if (h_redistribute_int_comp[array_comp_start + comp]) {
2003 std::memcpy(dst, &soa.GetIntData(comp)[pindex], sizeof(int));
2004 dst += sizeof(int);
2005 }
2006 }
2007 ptd.id(pindex).make_invalid(); // Invalidate the particle
2008 }
2009
2010 if (!ptd.id(pindex).is_valid()){
2011 soa.GetIdCPUData()[pindex] = soa.GetIdCPUData()[last];
2012 for (int comp = 0; comp < NumRealComps(); comp++) {
2013 soa.GetRealData(comp)[pindex] = soa.GetRealData(comp)[last];
2014 }
2015 for (int comp = 0; comp < NumIntComps(); comp++) {
2016 soa.GetIntData(comp)[pindex] = soa.GetIntData(comp)[last];
2017 }
2018 correctCellVectors(last, pindex, grid, ptd[pindex]);
2019 --last;
2020 continue;
2021 }
2022
2023 ++pindex;
2024 }
2025
2026 {
2027 auto& iddata = soa.GetIdCPUData();
2028 iddata.erase(iddata.begin() + last + 1, iddata.begin() + npart);
2029 }
2030 for (int comp = 0; comp < NumRealComps(); comp++) {
2031 RealVector& rdata = soa.GetRealData(comp);
2032 rdata.erase(rdata.begin() + last + 1, rdata.begin() + npart);
2033 }
2034 for (int comp = 0; comp < NumIntComps(); comp++) {
2035 IntVector& idata = soa.GetIntData(comp);
2036 idata.erase(idata.begin() + last + 1, idata.begin() + npart);
2037 }
2038 }
2039 }
2040 }
2041 }
2042
2043 for (int lev = lev_min; lev <= lev_max; lev++) {
2044 particle_detail::clearEmptyEntries(m_particles[lev]);
2045 }
2046
2047 // Second pass - for each tile in parallel, collect the particles we are owed from all thread's buffers.
2048 for (int lev = lev_min; lev <= lev_max; lev++) {
2049 typename std::map<std::pair<int, int>, Vector<ParticleVector > >::iterator pmap_it;
2050
2051 if constexpr(!ParticleType::is_soa_particle) {
2052 Vector<std::pair<int, int> > grid_tile_ids;
2053 Vector<Vector<ParticleVector>* > pvec_ptrs;
2054
2055 // we need to create any missing map entries in serial here
2056 for (pmap_it=tmp_local[lev].begin(); pmap_it != tmp_local[lev].end(); pmap_it++)
2057 {
2058 DefineAndReturnParticleTile(lev, pmap_it->first.first, pmap_it->first.second);
2059 grid_tile_ids.push_back(pmap_it->first);
2060 pvec_ptrs.push_back(&(pmap_it->second));
2061 }
2062
2063#ifdef AMREX_USE_OMP
2064#pragma omp parallel for
2065#endif
2066 for (int pit = 0; pit < static_cast<int>(pvec_ptrs.size()); ++pit)
2067 {
2068 auto index = grid_tile_ids[pit];
2069 auto& ptile = ParticlesAt(lev, index.first, index.second);
2070 auto& aos = ptile.GetArrayOfStructs();
2071 auto& soa = ptile.GetStructOfArrays();
2072 auto& aos_tmp = *(pvec_ptrs[pit]);
2073 auto& soa_tmp = soa_local[lev][index];
2074 for (int i = 0; i < num_threads; ++i) {
2075 aos.insert(aos.end(), aos_tmp[i].begin(), aos_tmp[i].end());
2076 aos_tmp[i].erase(aos_tmp[i].begin(), aos_tmp[i].end());
2077 for (int comp = 0; comp < NumRealComps(); ++comp) {
2078 RealVector& arr = soa.GetRealData(comp);
2079 RealVector& tmp = soa_tmp[i].GetRealData(comp);
2080 arr.insert(arr.end(), tmp.begin(), tmp.end());
2081 tmp.erase(tmp.begin(), tmp.end());
2082 }
2083 for (int comp = 0; comp < NumIntComps(); ++comp) {
2084 IntVector& arr = soa.GetIntData(comp);
2085 IntVector& tmp = soa_tmp[i].GetIntData(comp);
2086 arr.insert(arr.end(), tmp.begin(), tmp.end());
2087 tmp.erase(tmp.begin(), tmp.end());
2088 }
2089 }
2090 }
2091 } else { // soa particle
2092 Vector<std::pair<int, int> > grid_tile_ids;
2093
2094 // we need to create any missing map entries in serial here
2095 for (auto soa_map_it=soa_local[lev].begin(); soa_map_it != soa_local[lev].end(); soa_map_it++)
2096 {
2097 DefineAndReturnParticleTile(lev, soa_map_it->first.first, soa_map_it->first.second);
2098 grid_tile_ids.push_back(soa_map_it->first);
2099 }
2100
2101#ifdef AMREX_USE_OMP
2102#pragma omp parallel for
2103#endif
2104 for (int pit = 0; pit < static_cast<int>(grid_tile_ids.size()); ++pit) // NOLINT(modernize-loop-convert)
2105 {
2106 auto index = grid_tile_ids[pit];
2107 auto& ptile = ParticlesAt(lev, index.first, index.second);
2108 auto& soa = ptile.GetStructOfArrays();
2109 auto& soa_tmp = soa_local[lev][index];
2110 for (int i = 0; i < num_threads; ++i) {
2111 {
2112 auto& arr = soa.GetIdCPUData();
2113 auto& tmp = soa_tmp[i].GetIdCPUData();
2114 arr.insert(arr.end(), tmp.begin(), tmp.end());
2115 tmp.erase(tmp.begin(), tmp.end());
2116 }
2117 for (int comp = 0; comp < NumRealComps(); ++comp) {
2118 RealVector& arr = soa.GetRealData(comp);
2119 RealVector& tmp = soa_tmp[i].GetRealData(comp);
2120 arr.insert(arr.end(), tmp.begin(), tmp.end());
2121 tmp.erase(tmp.begin(), tmp.end());
2122 }
2123 for (int comp = 0; comp < NumIntComps(); ++comp) {
2124 IntVector& arr = soa.GetIntData(comp);
2125 IntVector& tmp = soa_tmp[i].GetIntData(comp);
2126 arr.insert(arr.end(), tmp.begin(), tmp.end());
2127 tmp.erase(tmp.begin(), tmp.end());
2128 }
2129 }
2130 }
2131 }
2132 }
2133
2134 for (auto& map_it : tmp_remote) {
2135 int who = map_it.first;
2136 not_ours[who];
2137 }
2138
2139 Vector<int> dest_proc_ids;
2140 Vector<Vector<Vector<char> >* > pbuff_ptrs;
2141 for (auto& kv : tmp_remote)
2142 {
2143 dest_proc_ids.push_back(kv.first);
2144 pbuff_ptrs.push_back(&(kv.second));
2145 }
2146
2147#ifdef AMREX_USE_OMP
2148#pragma omp parallel for
2149#endif
2150 for (int pmap_it = 0; pmap_it < static_cast<int>(pbuff_ptrs.size()); ++pmap_it)
2151 {
2152 int who = dest_proc_ids[pmap_it];
2153 Vector<Vector<char> >& tmp = *(pbuff_ptrs[pmap_it]);
2154 for (int i = 0; i < num_threads; ++i) {
2155 not_ours[who].insert(not_ours[who].end(), tmp[i].begin(), tmp[i].end());
2156 tmp[i].erase(tmp[i].begin(), tmp[i].end());
2157 }
2158 }
2159
2160 particle_detail::clearEmptyEntries(not_ours);
2161
2162 if (int(m_particles.size()) > theEffectiveFinestLevel+1) {
2163 // Looks like we lost an AmrLevel on a regrid.
2164 if (m_verbose > 0) {
2165 amrex::Print() << "ParticleContainer::Redistribute() resizing m_particles from "
2166 << m_particles.size() << " to " << theEffectiveFinestLevel+1 << '\n';
2167 }
2168 AMREX_ASSERT(int(m_particles.size()) >= 2);
2169
2170 m_particles.resize(theEffectiveFinestLevel + 1);
2171 m_dummy_mf.resize(theEffectiveFinestLevel + 1);
2172 }
2173
2174 if (ParallelContext::NProcsSub() == 1) {
2175 AMREX_ASSERT(not_ours.empty());
2176 }
2177 else {
2178 RedistributeMPI(not_ours, lev_min, lev_max, nGrow, local);
2179 }
2180
2181 AMREX_ASSERT(OK(lev_min, lev_max, nGrow));
2182
2183 if (m_verbose > 0) {
2184 auto stoptime = amrex::second() - strttime;
2185
2186 ByteSpread();
2187
2188#ifdef AMREX_LAZY
2189 Lazy::QueueReduction( [=] () mutable {
2190#endif
2193
2194 amrex::Print() << "ParticleContainer::Redistribute() time: " << stoptime << "\n\n";
2195#ifdef AMREX_LAZY
2196 });
2197#endif
2198 }
2199}
2200
2201template <typename ParticleType, int NArrayReal, int NArrayInt,
2202 template<class> class Allocator, class CellAssignor>
2203void
2205RedistributeMPI (std::map<int, Vector<char> >& not_ours,
2206 int lev_min, int lev_max, int nGrow, int local)
2207{
2208 BL_PROFILE("ParticleContainer::RedistributeMPI()");
2209 BL_PROFILE_VAR_NS("RedistributeMPI_locate", blp_locate);
2210 BL_PROFILE_VAR_NS("RedistributeMPI_copy", blp_copy);
2211
2212#ifdef AMREX_USE_MPI
2213
2214 using buffer_type = unsigned long long;
2215
2216 std::map<int, Vector<buffer_type> > mpi_snd_data;
2217 for (const auto& kv : not_ours)
2218 {
2219 auto nbt = (kv.second.size() + sizeof(buffer_type)-1)/sizeof(buffer_type);
2220 mpi_snd_data[kv.first].resize(nbt);
2221 std::memcpy((char*) mpi_snd_data[kv.first].data(), kv.second.data(), kv.second.size());
2222 }
2223
2224 const int NProcs = ParallelContext::NProcsSub();
2225 const int NNeighborProcs = neighbor_procs.size();
2226
2227 // We may now have particles that are rightfully owned by another CPU.
2228 Vector<Long> Snds(NProcs, 0), Rcvs(NProcs, 0); // bytes!
2229
2230 Long NumSnds = 0;
2231 if (local > 0)
2232 {
2233 AMREX_ALWAYS_ASSERT(lev_min == 0);
2234 AMREX_ALWAYS_ASSERT(lev_max == 0);
2235 BuildRedistributeMask(0, local);
2236 NumSnds = doHandShakeLocal(not_ours, neighbor_procs, Snds, Rcvs);
2237 }
2238 else
2239 {
2240 NumSnds = doHandShake(not_ours, Snds, Rcvs);
2241 }
2242
2243 const int SeqNum = ParallelDescriptor::SeqNum();
2244
2245 if ((! local) && NumSnds == 0) {
2246 return; // There's no parallel work to do.
2247 }
2248
2249 if (local)
2250 {
2251 Long tot_snds_this_proc = 0;
2252 Long tot_rcvs_this_proc = 0;
2253 for (int i = 0; i < NNeighborProcs; ++i) {
2254 tot_snds_this_proc += Snds[neighbor_procs[i]];
2255 tot_rcvs_this_proc += Rcvs[neighbor_procs[i]];
2256 }
2257 if ( (tot_snds_this_proc == 0) && (tot_rcvs_this_proc == 0) ) {
2258 return; // There's no parallel work to do.
2259 }
2260 }
2261
2262 Vector<int> RcvProc;
2263 Vector<std::size_t> rOffset; // Offset (in bytes) in the receive buffer
2264
2265 std::size_t TotRcvInts = 0;
2266 std::size_t TotRcvBytes = 0;
2267 for (int i = 0; i < NProcs; ++i) {
2268 if (Rcvs[i] > 0) {
2269 RcvProc.push_back(i);
2270 rOffset.push_back(TotRcvInts);
2271 TotRcvBytes += Rcvs[i];
2272 auto nbt = (Rcvs[i] + sizeof(buffer_type)-1)/sizeof(buffer_type);
2273 TotRcvInts += nbt;
2274 }
2275 }
2276
2277 const auto nrcvs = static_cast<int>(RcvProc.size());
2278 Vector<MPI_Status> stats(nrcvs);
2279 Vector<MPI_Request> rreqs(nrcvs);
2280
2281 // Allocate data for rcvs as one big chunk.
2282 Vector<unsigned long long> recvdata(TotRcvInts);
2283
2284 // Post receives.
2285 for (int i = 0; i < nrcvs; ++i) {
2286 const auto Who = RcvProc[i];
2287 const auto offset = rOffset[i];
2288 const auto Cnt = (Rcvs[Who] + sizeof(buffer_type)-1)/sizeof(buffer_type);
2289 AMREX_ASSERT(Cnt > 0);
2290 AMREX_ASSERT(Cnt < size_t(std::numeric_limits<int>::max()));
2291 AMREX_ASSERT(Who >= 0 && Who < NProcs);
2292
2293 rreqs[i] = ParallelDescriptor::Arecv(&recvdata[offset], Cnt, Who, SeqNum,
2295 }
2296
2297 // Send.
2298 for (const auto& kv : mpi_snd_data) {
2299 const auto Who = kv.first;
2300 const auto Cnt = kv.second.size();
2301
2302 AMREX_ASSERT(Cnt > 0);
2303 AMREX_ASSERT(Who >= 0 && Who < NProcs);
2304 AMREX_ASSERT(Cnt < std::numeric_limits<int>::max());
2305
2306 ParallelDescriptor::Send(kv.second.data(), Cnt, Who, SeqNum,
2308 }
2309
2310 if (nrcvs > 0) {
2311 ParallelDescriptor::Waitall(rreqs, stats);
2312
2313 BL_PROFILE_VAR_START(blp_locate);
2314
2315 int npart = TotRcvBytes / superparticle_size;
2316
2317 Vector<int> rcv_levs(npart);
2318 Vector<int> rcv_grid(npart);
2319 Vector<int> rcv_tile(npart);
2320
2321 int ipart = 0;
2322 ParticleLocData pld;
2323 for (int j = 0; j < nrcvs; ++j)
2324 {
2325 const auto offset = rOffset[j];
2326 const auto Who = RcvProc[j];
2327 const auto Cnt = Rcvs[Who] / superparticle_size;
2328 for (int i = 0; i < int(Cnt); ++i)
2329 {
2330 char* pbuf = ((char*) &recvdata[offset]) + i*superparticle_size;
2331
2332 Particle<NStructReal, NStructInt> p;
2333
2334 if constexpr (ParticleType::is_soa_particle) {
2335 std::memcpy(&p.m_idcpu, pbuf, sizeof(uint64_t));
2336
2337 ParticleReal pos[AMREX_SPACEDIM];
2338 std::memcpy(&pos[0], pbuf + sizeof(uint64_t), AMREX_SPACEDIM*sizeof(ParticleReal));
2339 AMREX_D_TERM(p.pos(0) = pos[0];,
2340 p.pos(1) = pos[1];,
2341 p.pos(2) = pos[2]);
2342 } else {
2343 std::memcpy(&p, pbuf, sizeof(ParticleType));
2344 }
2345
2346 bool success = Where(p, pld, lev_min, lev_max, 0);
2347 if (!success)
2348 {
2349 success = (nGrow > 0) && Where(p, pld, lev_min, lev_min, nGrow);
2350 pld.m_grown_gridbox = pld.m_gridbox; // reset grown box for subsequent calls.
2351 }
2352 if (!success)
2353 {
2354 amrex::Abort("RedistributeMPI_locate:: invalid particle.");
2355 }
2356
2357 rcv_levs[ipart] = pld.m_lev;
2358 rcv_grid[ipart] = pld.m_grid;
2359 rcv_tile[ipart] = pld.m_tile;
2360
2361 ++ipart;
2362 }
2363 }
2364
2365 BL_PROFILE_VAR_STOP(blp_locate);
2366
2367 BL_PROFILE_VAR_START(blp_copy);
2368
2369#ifndef AMREX_USE_GPU
2370 ipart = 0;
2371 for (int i = 0; i < nrcvs; ++i)
2372 {
2373 const auto offset = rOffset[i];
2374 const auto Who = RcvProc[i];
2375 const auto Cnt = Rcvs[Who] / superparticle_size;
2376 for (int j = 0; j < int(Cnt); ++j)
2377 {
2378 auto& ptile = m_particles[rcv_levs[ipart]][std::make_pair(rcv_grid[ipart],
2379 rcv_tile[ipart])];
2380 char* pbuf = ((char*) &recvdata[offset]) + j*superparticle_size;
2381
2382 if constexpr (ParticleType::is_soa_particle) {
2383 uint64_t idcpudata;
2384 std::memcpy(&idcpudata, pbuf, sizeof(uint64_t));
2385 pbuf += sizeof(uint64_t);
2386 ptile.GetStructOfArrays().GetIdCPUData().push_back(idcpudata);
2387 } else {
2388 ParticleType p;
2389 std::memcpy(&p, pbuf, sizeof(ParticleType));
2390 pbuf += sizeof(ParticleType);
2391 ptile.push_back(p);
2392 }
2393
2394 int array_comp_start = 0;
2395 if constexpr (!ParticleType::is_soa_particle) {
2396 array_comp_start = AMREX_SPACEDIM + NStructReal;
2397 }
2398 for (int comp = 0; comp < NumRealComps(); ++comp) {
2399 if (h_redistribute_real_comp[array_comp_start + comp]) {
2400 ParticleReal rdata;
2401 std::memcpy(&rdata, pbuf, sizeof(ParticleReal));
2402 pbuf += sizeof(ParticleReal);
2403 ptile.push_back_real(comp, rdata);
2404 } else {
2405 ptile.push_back_real(comp, 0.0);
2406 }
2407 }
2408
2409 array_comp_start = 2 + NStructInt;
2410 for (int comp = 0; comp < NumIntComps(); ++comp) {
2411 if (h_redistribute_int_comp[array_comp_start + comp]) {
2412 int idata;
2413 std::memcpy(&idata, pbuf, sizeof(int));
2414 pbuf += sizeof(int);
2415 ptile.push_back_int(comp, idata);
2416 } else {
2417 ptile.push_back_int(comp, 0);
2418 }
2419 }
2420 ++ipart;
2421 }
2422 }
2423
2424#else
2425 Vector<std::map<std::pair<int, int>, Gpu::HostVector<ParticleType> > > host_particles;
2426 host_particles.reserve(15);
2427 host_particles.resize(finestLevel()+1);
2428
2429 Vector<std::map<std::pair<int, int>,
2430 std::vector<Gpu::HostVector<ParticleReal> > > > host_real_attribs;
2431 host_real_attribs.reserve(15);
2432 host_real_attribs.resize(finestLevel()+1);
2433
2434 Vector<std::map<std::pair<int, int>,
2435 std::vector<Gpu::HostVector<int> > > > host_int_attribs;
2436 host_int_attribs.reserve(15);
2437 host_int_attribs.resize(finestLevel()+1);
2438
2439 Vector<std::map<std::pair<int, int>, Gpu::HostVector<uint64_t> > > host_idcpu;
2440 host_idcpu.reserve(15);
2441 host_idcpu.resize(finestLevel()+1);
2442
2443 ipart = 0;
2444 for (int i = 0; i < nrcvs; ++i)
2445 {
2446 const auto offset = rOffset[i];
2447 const auto Who = RcvProc[i];
2448 const auto Cnt = Rcvs[Who] / superparticle_size;
2449 for (auto j = decltype(Cnt)(0); j < Cnt; ++j)
2450 {
2451 int lev = rcv_levs[ipart];
2452 std::pair<int, int> ind(std::make_pair(rcv_grid[ipart], rcv_tile[ipart]));
2453
2454 char* pbuf = ((char*) &recvdata[offset]) + j*superparticle_size;
2455
2456 host_real_attribs[lev][ind].resize(NumRealComps());
2457 host_int_attribs[lev][ind].resize(NumIntComps());
2458
2459 if constexpr (ParticleType::is_soa_particle) {
2460 uint64_t idcpudata;
2461 std::memcpy(&idcpudata, pbuf, sizeof(uint64_t));
2462 pbuf += sizeof(uint64_t);
2463 host_idcpu[lev][ind].push_back(idcpudata);
2464 } else {
2465 ParticleType p;
2466 std::memcpy(&p, pbuf, sizeof(ParticleType));
2467 pbuf += sizeof(ParticleType);
2468 host_particles[lev][ind].push_back(p);
2469 }
2470
2471 host_real_attribs[lev][ind].resize(NumRealComps());
2472 host_int_attribs[lev][ind].resize(NumIntComps());
2473
2474 // add the real...
2475 int array_comp_start = 0;
2476 if constexpr (!ParticleType::is_soa_particle) {
2477 array_comp_start = AMREX_SPACEDIM + NStructReal;
2478 }
2479 for (int comp = 0; comp < NumRealComps(); ++comp) {
2480 if (h_redistribute_real_comp[array_comp_start + comp]) {
2481 Real rdata;
2482 std::memcpy(&rdata, pbuf, sizeof(Real));
2483 pbuf += sizeof(Real);
2484 host_real_attribs[lev][ind][comp].push_back(rdata);
2485 } else {
2486 host_real_attribs[lev][ind][comp].push_back(0.0);
2487 }
2488 }
2489
2490 // ... and int array data
2491 array_comp_start = 2 + NStructInt;
2492 for (int comp = 0; comp < NumIntComps(); ++comp) {
2493 if (h_redistribute_int_comp[array_comp_start + comp]) {
2494 int idata;
2495 std::memcpy(&idata, pbuf, sizeof(int));
2496 pbuf += sizeof(int);
2497 host_int_attribs[lev][ind][comp].push_back(idata);
2498 } else {
2499 host_int_attribs[lev][ind][comp].push_back(0);
2500 }
2501 }
2502 ++ipart;
2503 }
2504 }
2505
2506 for (int host_lev = 0; host_lev < static_cast<int>(host_particles.size()); ++host_lev)
2507 {
2508 for (auto& kv : host_particles[host_lev]) {
2509 auto grid = kv.first.first;
2510 auto tile = kv.first.second;
2511 const auto& src_tile = kv.second;
2512
2513 auto& dst_tile = GetParticles(host_lev)[std::make_pair(grid,tile)];
2514 auto old_size = dst_tile.size();
2515 auto new_size = old_size + src_tile.size();
2516 dst_tile.resize(new_size);
2517
2518 if constexpr (ParticleType::is_soa_particle) {
2520 host_idcpu[host_lev][std::make_pair(grid,tile)].begin(),
2521 host_idcpu[host_lev][std::make_pair(grid,tile)].end(),
2522 dst_tile.GetStructOfArrays().GetIdCPUData().begin() + old_size);
2523 } else {
2525 src_tile.begin(), src_tile.end(),
2526 dst_tile.GetArrayOfStructs().begin() + old_size);
2527 }
2528
2529 for (int i = 0; i < NumRealComps(); ++i) {
2531 host_real_attribs[host_lev][std::make_pair(grid,tile)][i].begin(),
2532 host_real_attribs[host_lev][std::make_pair(grid,tile)][i].end(),
2533 dst_tile.GetStructOfArrays().GetRealData(i).begin() + old_size);
2534 }
2535
2536 for (int i = 0; i < NumIntComps(); ++i) {
2538 host_int_attribs[host_lev][std::make_pair(grid,tile)][i].begin(),
2539 host_int_attribs[host_lev][std::make_pair(grid,tile)][i].end(),
2540 dst_tile.GetStructOfArrays().GetIntData(i).begin() + old_size);
2541 }
2542 }
2543 }
2544
2546#endif
2547
2548 BL_PROFILE_VAR_STOP(blp_copy);
2549 }
2550#else
2551 amrex::ignore_unused(not_ours,lev_min,lev_max,nGrow,local);
2552#endif
2553}
2554
2555template <typename ParticleType, int NArrayReal, int NArrayInt,
2556 template<class> class Allocator, class CellAssignor>
2557bool
2559{
2560 BL_PROFILE("ParticleContainer::OK()");
2561
2562 if (lev_max == -1) {
2563 lev_max = finestLevel();
2564 }
2565
2566 return (numParticlesOutOfRange(*this, lev_min, lev_max, nGrow) == 0);
2567}
2568
2569template <typename ParticleType, int NArrayReal, int NArrayInt,
2570 template<class> class Allocator, class CellAssignor>
2571void
2573::AddParticlesAtLevel (AoS& particles, int level, int nGrow)
2574{
2575 ParticleTileType ptile;
2576 ptile.GetArrayOfStructs().swap(particles);
2577 AddParticlesAtLevel(ptile, level, nGrow);
2578}
2579
2580template <typename ParticleType, int NArrayReal, int NArrayInt,
2581 template<class> class Allocator, class CellAssignor>
2582void
2584::AddParticlesAtLevel (ParticleTileType& particles, int level, int nGrow)
2585{
2586 BL_PROFILE("ParticleContainer::AddParticlesAtLevel()");
2587
2588 if (int(m_particles.size()) < level+1)
2589 {
2590 if (Verbose())
2591 {
2592 amrex::Print() << "ParticleContainer::AddParticlesAtLevel resizing m_particles from "
2593 << m_particles.size()
2594 << " to "
2595 << level+1 << '\n';
2596 }
2597 m_particles.resize(level+1);
2598 m_dummy_mf.resize(level+1);
2599 for (int lev = 0; lev < level+1; ++lev) {
2600 RedefineDummyMF(lev);
2601 }
2602 }
2603
2604 auto& ptile = DefineAndReturnParticleTile(level, 0, 0);
2605 int old_np = ptile.size();
2606 int num_to_add = particles.size();
2607 int new_np = old_np + num_to_add;
2608 ptile.resize(new_np);
2609 amrex::copyParticles(ptile, particles, 0, old_np, num_to_add);
2610 Redistribute(level, level, nGrow);
2611 particles.resize(0);
2612}
2613
2614// This is the single-level version for cell-centered density
2615template <typename ParticleType, int NArrayReal, int NArrayInt,
2616 template<class> class Allocator, class CellAssignor>
2617void
2619AssignCellDensitySingleLevel (int rho_index,
2620 MultiFab& mf_to_be_filled,
2621 int lev,
2622 int ncomp,
2623 int particle_lvl_offset) const
2624{
2625 BL_PROFILE("ParticleContainer::AssignCellDensitySingleLevel()");
2626
2627 if (rho_index != 0) { amrex::Abort("AssignCellDensitySingleLevel only works if rho_index = 0"); }
2628
2629 MultiFab* mf_pointer;
2630
2631 if (OnSameGrids(lev, mf_to_be_filled)) {
2632 // If we are already working with the internal mf defined on the
2633 // particle_box_array, then we just work with this.
2634 mf_pointer = &mf_to_be_filled;
2635 }
2636 else {
2637 // If mf_to_be_filled is not defined on the particle_box_array, then we need
2638 // to make a temporary here and copy into mf_to_be_filled at the end.
2639 mf_pointer = new MultiFab(ParticleBoxArray(lev),
2640 ParticleDistributionMap(lev),
2641 ncomp, mf_to_be_filled.nGrow());
2642 }
2643
2644 // We must have ghost cells for each FAB so that a particle in one grid can spread
2645 // its effect to an adjacent grid by first putting the value into ghost cells of its
2646 // own grid. The mf->SumBoundary call then adds the value from one grid's ghost cell
2647 // to another grid's valid region.
2648 if (mf_pointer->nGrow() < 1) {
2649 amrex::Error("Must have at least one ghost cell when in AssignCellDensitySingleLevel");
2650 }
2651
2652 const auto strttime = amrex::second();
2653
2654 const auto dxi = Geom(lev).InvCellSizeArray();
2655 const auto plo = Geom(lev).ProbLoArray();
2656 const auto pdxi = Geom(lev + particle_lvl_offset).InvCellSizeArray();
2657
2658 if (Geom(lev).isAnyPeriodic() && ! Geom(lev).isAllPeriodic())
2659 {
2660 amrex::Error("AssignCellDensitySingleLevel: problem must be periodic in no or all directions");
2661 }
2662
2663 mf_pointer->setVal(0);
2664
2666#ifdef AMREX_USE_OMP
2667#pragma omp parallel if (Gpu::notInLaunchRegion())
2668#endif
2669 {
2670 FArrayBox local_rho;
2671 for (ParConstIter pti(*this, lev); pti.isValid(); ++pti) {
2672 const Long np = pti.numParticles();
2673 auto ptd = pti.GetParticleTile().getConstParticleTileData();
2674 FArrayBox& fab = (*mf_pointer)[pti];
2675 auto rhoarr = fab.array();
2676#ifdef AMREX_USE_OMP
2677 Box tile_box;
2679 {
2680 tile_box = pti.tilebox();
2681 tile_box.grow(mf_pointer->nGrow());
2682 local_rho.resize(tile_box,ncomp);
2683 local_rho.setVal<RunOn::Host>(0.0);
2684 rhoarr = local_rho.array();
2685 }
2686#endif
2687
2688 if (particle_lvl_offset == 0)
2689 {
2691 {
2692 auto p = ptd[i];
2693 amrex_deposit_cic(p, ncomp, rhoarr, plo, dxi);
2694 });
2695 }
2696 else
2697 {
2699 {
2700 auto p = ptd[i];
2701 amrex_deposit_particle_dx_cic(p, ncomp, rhoarr, plo, dxi, pdxi);
2702 });
2703 }
2704
2705#ifdef AMREX_USE_OMP
2707 {
2708 fab.atomicAdd<RunOn::Host>(local_rho, tile_box, tile_box, 0, 0, ncomp);
2709 }
2710#endif
2711 }
2712 }
2713
2714 mf_pointer->SumBoundary(Geom(lev).periodicity());
2715
2716 // If ncomp > 1, first divide the momenta (component n)
2717 // by the mass (component 0) in order to get velocities.
2718 // Be careful not to divide by zero.
2719 for (int n = 1; n < ncomp; n++)
2720 {
2721 for (MFIter mfi(*mf_pointer); mfi.isValid(); ++mfi)
2722 {
2723 (*mf_pointer)[mfi].protected_divide<RunOn::Device>((*mf_pointer)[mfi],0,n,1);
2724 }
2725 }
2726
2727 // Only multiply the first component by (1/vol) because this converts mass
2728 // to density. If there are additional components (like velocity), we don't
2729 // want to divide those by volume.
2730 const Real* dx = Geom(lev).CellSize();
2731 const Real vol = AMREX_D_TERM(dx[0], *dx[1], *dx[2]);
2732
2733 mf_pointer->mult(Real(1.0)/vol, 0, 1, mf_pointer->nGrow());
2734
2735 // If mf_to_be_filled is not defined on the particle_box_array, then we need
2736 // to copy here from mf_pointer into mf_to_be_filled.
2737 if (mf_pointer != &mf_to_be_filled)
2738 {
2739 mf_to_be_filled.ParallelCopy(*mf_pointer,0,0,ncomp,0,0);
2740 delete mf_pointer;
2741 }
2742
2743 if (m_verbose > 1)
2744 {
2745 auto stoptime = amrex::second() - strttime;
2746
2749
2750 amrex::Print() << "ParticleContainer::AssignCellDensitySingleLevel) time: "
2751 << stoptime << '\n';
2752 }
2753}
2754
2755template <typename ParticleType, int NArrayReal, int NArrayInt,
2756 template<class> class Allocator, class CellAssignor>
2757void
2759ResizeRuntimeRealComp (int new_size, bool communicate)
2760{
2761 int old_size = m_num_runtime_real;
2762
2763 m_runtime_comps_defined = (new_size > 0);
2764 m_num_runtime_real = new_size;
2765 int cur_size = h_redistribute_real_comp.size();
2766 h_redistribute_real_comp.resize(cur_size-old_size+new_size, communicate);
2767 SetParticleSize();
2768
2769 for (int lev = 0; lev < numLevels(); ++lev) {
2770 for (ParIterType pti(*this,lev); pti.isValid(); ++pti) {
2771 auto& tile = DefineAndReturnParticleTile(lev, pti);
2772 auto np = tile.numParticles();
2773 if (np > 0 && new_size > old_size) {
2774 auto& soa = tile.GetStructOfArrays();
2775 soa.resize(np);
2776 }
2777 }
2778 }
2779}
2780
2781template <typename ParticleType, int NArrayReal, int NArrayInt,
2782 template<class> class Allocator, class CellAssignor>
2783void
2785ResizeRuntimeIntComp (int new_size, bool communicate)
2786{
2787 int old_size = m_num_runtime_int;
2788
2789 m_runtime_comps_defined = (new_size > 0);
2790 m_num_runtime_int = new_size;
2791 int cur_size = h_redistribute_int_comp.size();
2792 h_redistribute_int_comp.resize(cur_size-old_size+new_size, communicate);
2793 SetParticleSize();
2794
2795 for (int lev = 0; lev < numLevels(); ++lev) {
2796 for (ParIterType pti(*this,lev); pti.isValid(); ++pti) {
2797 auto& tile = DefineAndReturnParticleTile(lev, pti);
2798 auto np = tile.numParticles();
2799 if (np > 0 && new_size > old_size) {
2800 auto& soa = tile.GetStructOfArrays();
2801 soa.resize(np);
2802 }
2803 }
2804 }
2805}
2806
2807}
#define BL_PROFILE_VAR_START(vname)
Definition AMReX_BLProfiler.H:562
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:551
#define BL_PROFILE_VAR_STOP(vname)
Definition AMReX_BLProfiler.H:563
#define BL_PROFILE_SYNC_STOP()
Definition AMReX_BLProfiler.H:645
#define BL_PROFILE_SYNC_START_TIMED(fname)
Definition AMReX_BLProfiler.H:644
#define BL_PROFILE_VAR_NS(fname, vname)
Definition AMReX_BLProfiler.H:561
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#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_FOR_1D(...)
Definition AMReX_GpuLaunchMacrosC.nolint.H:97
#define AMREX_HOST_DEVICE_FOR_1D(...)
Definition AMReX_GpuLaunchMacrosC.nolint.H:105
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
#define AMREX_GPU_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
amrex::ParmParse pp
Input file parser instance for the given namespace.
Definition AMReX_HypreIJIface.cpp:15
Array4< int const > offset
Definition AMReX_HypreMLABecLap.cpp:1089
#define AMREX_D_TERM(a, b, c)
Definition AMReX_SPACE.H:172
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
Print on all processors of the default communicator.
Definition AMReX_Print.H:117
BaseFab< T > & atomicAdd(const BaseFab< T > &x) noexcept
Atomic FAB addition (a[i] <- a[i] + b[i]).
Definition AMReX_BaseFab.H:2484
Array4< T const > array() const noexcept
Definition AMReX_BaseFab.H:381
void setVal(T const &x, const Box &bx, int dcomp, int ncomp) noexcept
The setVal functions set sub-regions in the BaseFab to a constant value. This most general form speci...
Definition AMReX_BaseFab.H:1399
A collection of Boxes stored in an Array.
Definition AMReX_BoxArray.H:567
IndexType ixType() const noexcept
Return index type of this BoxArray.
Definition AMReX_BoxArray.H:857
BoxArray & grow(int n)
Grow each Box in the BoxArray by the specified amount.
Definition AMReX_BoxArray.cpp:706
std::vector< std::pair< int, Box > > intersections(const Box &bx) const
Return intersections of Box and BoxArray.
Definition AMReX_BoxArray.cpp:1186
Box getCellCenteredBox(int index) const noexcept
Return cell-centered box at element index of this BoxArray.
Definition AMReX_BoxArray.H:747
static bool SameRefs(const BoxArray &lhs, const BoxArray &rhs)
whether two BoxArrays share the same data
Definition AMReX_BoxArray.H:840
A class for managing a List of Boxes that share a common IndexType. This class implements operations ...
Definition AMReX_BoxList.H:52
BoxList & complementIn(const Box &b, const BoxList &bl)
Definition AMReX_BoxList.cpp:307
__host__ __device__ BoxND & grow(int i) noexcept
Definition AMReX_Box.H:641
__host__ __device__ bool contains(const IntVectND< dim > &p) const noexcept
Return true if argument is contained within BoxND.
Definition AMReX_Box.H:212
GpuArray< Real, 3 > InvCellSizeArray() const noexcept
Definition AMReX_CoordSys.H:87
A Fortran Array of REALs.
Definition AMReX_FArrayBox.H:231
void resize(const Box &b, int N=1, Arena *ar=nullptr)
For debugging purposes we hide BaseFab version and do some extra work.
Definition AMReX_FArrayBox.cpp:178
int size() const noexcept
Return the number of FABs in the FabArray.
Definition AMReX_FabArrayBase.H:110
int nGrow(int direction=0) const noexcept
Return the grow factor that defines the region of definition.
Definition AMReX_FabArrayBase.H:78
const DistributionMapping & DistributionMap() const noexcept
Return constant reference to associated DistributionMapping.
Definition AMReX_FabArrayBase.H:131
const BoxArray & boxArray() const noexcept
Return a constant reference to the BoxArray that defines the valid region associated with this FabArr...
Definition AMReX_FabArrayBase.H:95
void ParallelCopy(const FabArray< FAB > &src, const Periodicity &period=Periodicity::NonPeriodic(), CpOp op=FabArrayBase::COPY)
Definition AMReX_FabArray.H:847
Array4< typename FabArray< FAB >::value_type const > array(const MFIter &mfi) const noexcept
Definition AMReX_FabArray.H:563
void setVal(value_type val)
Set all components in the entire region of each FAB to val.
Definition AMReX_FabArray.H:2652
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:74
const Box & Domain() const noexcept
Returns our rectangular domain.
Definition AMReX_Geometry.H:211
GpuArray< Real, 3 > ProbLoArray() const noexcept
Definition AMReX_Geometry.H:187
static void streamSynchronize() noexcept
Definition AMReX_GpuDevice.cpp:757
__host__ __device__ bool cellCentered() const noexcept
True if the IndexTypeND is CELL based in all directions.
Definition AMReX_IndexType.H:104
__host__ static __device__ constexpr IntVectND< dim > TheZeroVector() noexcept
This static member function returns a reference to a constant IntVectND object, all of whose dim argu...
Definition AMReX_IntVect.H:679
a one-thingy-per-box distributed object
Definition AMReX_LayoutData.H:13
Iterator for looping ever tiles and boxes of amrex::FabArray based containers.
Definition AMReX_MFIter.H:85
int LocalTileIndex() const noexcept
The current local tile index in the current grid;.
Definition AMReX_MFIter.H:178
bool isValid() const noexcept
Is the iterator valid i.e. is it associated with a FAB?
Definition AMReX_MFIter.H:169
Box validbox() const noexcept
Return the valid Box in which the current tile resides.
Definition AMReX_MFIter.H:160
int index() const noexcept
The index into the underlying BoxArray of the current FAB.
Definition AMReX_MFIter.H:172
A collection (stored as an array) of FArrayBox objects.
Definition AMReX_MultiFab.H:40
void mult(Real val, int comp, int num_comp, int nghost=0)
Scales the value of each cell in the specified subregion of the MultiFab by the scalar val (a[i] <- a...
Definition AMReX_MultiFab.cpp:1417
Dynamically allocated vector for trivially copyable data.
Definition AMReX_PODVector.H:308
size_type size() const noexcept
Definition AMReX_PODVector.H:648
void resize(size_type a_new_size, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:728
T * dataPtr() noexcept
Definition AMReX_PODVector.H:670
Definition AMReX_ParIter.H:144
Definition AMReX_ParIter.H:115
MPI_Request req() const
Definition AMReX_ParallelDescriptor.H:74
int queryAdd(std::string_view name, T &ref)
If name is found, the value in the ParmParse database will be stored in the ref argument....
Definition AMReX_ParmParse.H:1040
int queryarr(std::string_view name, std::vector< int > &ref, int start_ix=FIRST, int num_val=ALL) const
Same as queryktharr() but searches for last occurrence of name.
Definition AMReX_ParmParse.cpp:1536
int query(std::string_view name, bool &ref, int ival=FIRST) const
Same as querykth() but searches for the last occurrence of name.
Definition AMReX_ParmParse.cpp:1450
virtual void reserveData()
Definition AMReX_ParticleContainerBase.cpp:41
virtual void resizeData()
Definition AMReX_ParticleContainerBase.cpp:46
A distributed container for Particles sorted onto the levels, grids, and tiles of a block-structured ...
Definition AMReX_ParticleContainer.H:148
void addParticles(const PCType &other, bool local=false)
Add particles from other to this ParticleContainer. local controls whether or not to call Redistribut...
Definition AMReX_ParticleContainerI.H:1155
IntVect Index(const P &p, int lev) const
Definition AMReX_ParticleContainerI.H:201
void ResizeRuntimeIntComp(int new_size, bool communicate)
Definition AMReX_ParticleContainerI.H:2785
bool OK(int lev_min=0, int lev_max=-1, int nGrow=0) const
OK checks that all particles are in the right places (for some value of right)
Definition AMReX_ParticleContainerI.H:2558
std::map< std::pair< int, int >, ParticleTileType > ParticleLevel
Definition AMReX_ParticleContainer.H:189
void SetSoACompileTimeNames(std::vector< std::string > const &rdata_name, std::vector< std::string > const &idata_name)
Definition AMReX_ParticleContainerI.H:109
typename ParticleTileType::AoS AoS
Definition AMReX_ParticleContainer.H:192
typename SoA::RealVector RealVector
Definition AMReX_ParticleContainer.H:195
void SetParticleSize()
Definition AMReX_ParticleContainerI.H:16
void RemoveParticlesAtLevel(int level)
The Following methods are for managing Virtual and Ghost Particles.
Definition AMReX_ParticleContainerI.H:757
void clearParticles()
Clear all the particles in this container. This does not free memory.
Definition AMReX_ParticleContainerI.H:1128
void Increment(MultiFab &mf, int level)
Definition AMReX_ParticleContainerI.H:720
void AssignCellDensitySingleLevel(int rho_index, MultiFab &mf, int level, int ncomp=1, int particle_lvl_offset=0) const
Definition AMReX_ParticleContainerI.H:2619
bool HasIntComp(std::string const &name)
Definition AMReX_ParticleContainerI.H:148
void ShrinkToFit()
Definition AMReX_ParticleContainerI.H:700
bool HasRealComp(std::string const &name)
Definition AMReX_ParticleContainerI.H:140
void resizeData() override
This resizes the vector of dummy MultiFabs used by the ParticleContainer for the current number of le...
Definition AMReX_ParticleContainerI.H:435
void ResizeRuntimeRealComp(int new_size, bool communicate)
Definition AMReX_ParticleContainerI.H:2759
Long IncrementWithTotal(MultiFab &mf, int level, bool local=false)
Definition AMReX_ParticleContainerI.H:747
Long NumberOfParticlesAtLevel(int level, bool only_valid=true, bool only_local=false) const
Returns # of particles at specified the level.
Definition AMReX_ParticleContainerI.H:551
void SortParticlesByCell()
Sort the particles on each tile by cell, using Fortran ordering.
Definition AMReX_ParticleContainerI.H:1363
int GetRealCompIndex(std::string const &name)
Definition AMReX_ParticleContainerI.H:161
int GetIntCompIndex(std::string const &name)
Definition AMReX_ParticleContainerI.H:183
void RemoveParticlesNotAtFinestLevel()
Definition AMReX_ParticleContainerI.H:771
Vector< Long > NumberOfParticlesInGrid(int level, bool only_valid=true, bool only_local=false) const
Definition AMReX_ParticleContainerI.H:496
typename SoA::IntVector IntVector
Definition AMReX_ParticleContainer.H:196
void copyParticles(const PCType &other, bool local=false)
Copy particles from other to this ParticleContainer. Will clear all the particles from this container...
Definition AMReX_ParticleContainerI.H:1144
ParticleLocData Reset(ParticleType &prt, bool update, bool verbose=true, ParticleLocData pld=ParticleLocData()) const
Updates a particle's location (Where), tries to periodic shift any particles that have left the domai...
Definition AMReX_ParticleContainerI.H:392
void CapacityOfParticlesInGrid(LayoutData< I > &mem, int lev) const
Return capacity of memory for particles at specific grid.
Definition AMReX_ParticleContainerI.H:593
Long TotalNumberOfParticles(bool only_valid=true, bool only_local=false) const
Returns # of particles at all levels.
Definition AMReX_ParticleContainerI.H:481
void reserveData() override
This reserves data in the vector of dummy MultiFabs used by the ParticleContainer for the maximum num...
Definition AMReX_ParticleContainerI.H:426
T_ParticleType ParticleType
Definition AMReX_ParticleContainer.H:150
Definition AMReX_ParticleLocator.H:104
AssignGrid< BinIteratorFactory > getGridAssignor() const noexcept
Definition AMReX_ParticleLocator.H:183
void build(const BoxArray &ba, const Geometry &geom)
Definition AMReX_ParticleLocator.H:111
This class provides the user with a few print options.
Definition AMReX_Print.H:35
Definition AMReX_Reduce.H:257
Type value()
Definition AMReX_Reduce.H:289
Definition AMReX_Reduce.H:389
std::enable_if_t< IsFabArray< MF >::value > eval(MF const &mf, IntVect const &nghost, D &reduce_data, F &&f)
Definition AMReX_Reduce.H:458
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:28
Long size() const noexcept
Definition AMReX_Vector.H:53
A Collection of IArrayBoxes.
Definition AMReX_iMultiFab.H:34
Long sum(int comp, int nghost=0, bool local=false) const
Returns the sum in component comp.
Definition AMReX_iMultiFab.cpp:454
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:79
amrex_particle_real ParticleReal
Floating Point Type for Particles.
Definition AMReX_REAL.H:90
amrex_long Long
Definition AMReX_INT.H:30
T ExclusiveSum(N n, T const *in, T *out, RetSum a_ret_sum=retSum)
Exclusive sum.
Definition AMReX_Scan.H:1290
void SumBoundary(const Periodicity &period=Periodicity::NonPeriodic(), bool deterministic=false)
Sum values in overlapped cells.
Definition AMReX_FabArray.H:3583
__host__ __device__ BoxND< dim > grow(const BoxND< dim > &b, int i) noexcept
Grow BoxND in all directions by given amount.
Definition AMReX_Box.H:1280
Arena * The_Comms_Arena()
Definition AMReX_Arena.cpp:843
void Min(KeyValuePair< K, V > &vi, int root, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:287
void Max(KeyValuePair< K, V > &vi, int root, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:254
void Sum(T &v, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:221
void Sum(T &v, int root, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:352
__host__ __device__ AMREX_FORCE_INLINE void AddNoRet(T *sum, T value) noexcept
Definition AMReX_GpuAtomic.H:283
void copyAsync(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
A host-to-device copy routine. Note this is just a wrapper around memcpy, so it assumes contiguous st...
Definition AMReX_GpuContainers.H:228
static constexpr HostToDevice hostToDevice
Definition AMReX_GpuContainers.H:105
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:263
void dtoh_memcpy_async(void *p_h, const void *p_d, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:315
bool inLaunchRegion() noexcept
Definition AMReX_GpuControl.H:92
bool notInLaunchRegion() noexcept
Definition AMReX_GpuControl.H:93
void htod_memcpy_async(void *p_d, const void *p_h, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:301
void QueueReduction(Func f)
Definition AMReX_Lazy.cpp:7
constexpr Long GhostParticleID
Definition AMReX_Particle.H:19
constexpr Long VirtualParticleID
Definition AMReX_Particle.H:20
int NProcs()
Process ID in MPI_COMM_WORLD.
Definition AMReX_MPMD.cpp:122
constexpr int get_thread_num()
Definition AMReX_OpenMP.H:37
constexpr int get_max_threads()
Definition AMReX_OpenMP.H:36
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int MyProcSub() noexcept
my sub-rank in current frame
Definition AMReX_ParallelContext.H:76
int global_to_local_rank(int rank) noexcept
Definition AMReX_ParallelContext.H:98
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
int IOProcessorNumberSub() noexcept
IO sub-rank in current frame.
Definition AMReX_ParallelContext.H:78
bool UseGpuAwareMpi()
Definition AMReX_ParallelDescriptor.H:113
void Waitall(Vector< MPI_Request > &, Vector< MPI_Status > &)
Definition AMReX_ParallelDescriptor.cpp:1308
Message Send(const T *buf, size_t n, int dst_pid, int tag)
Definition AMReX_ParallelDescriptor.H:1193
void Bcast(void *, int, MPI_Datatype, int, MPI_Comm)
Definition AMReX_ParallelDescriptor.cpp:1295
int SeqNum() noexcept
Returns sequential message sequence numbers, usually used as tags for send/recv.
Definition AMReX_ParallelDescriptor.H:696
void GatherLayoutDataToVector(const LayoutData< T > &sendbuf, Vector< T > &recvbuf, int root)
Gather LayoutData values to a vector on root.
Definition AMReX_ParallelDescriptor.H:1295
Message Arecv(T *, size_t n, int pid, int tag)
Definition AMReX_ParallelDescriptor.H:1214
static constexpr RetSum retSum
Definition AMReX_Scan.H:32
Definition AMReX_Amr.cpp:49
__host__ __device__ void ignore_unused(const Ts &...)
This shuts up the compiler about unused variables.
Definition AMReX.H:138
int nComp(FabArrayBase const &fa)
Definition AMReX_FabArrayBase.cpp:2854
__host__ __device__ int getTileIndex(const IntVect &iv, const Box &box, const bool a_do_tiling, const IntVect &a_tile_size, Box &tbx)
Definition AMReX_ParticleUtil.H:184
void communicateParticlesStart(const PC &pc, ParticleCopyPlan &plan, const SndBuffer &snd_buffer, RcvBuffer &rcv_buffer)
Definition AMReX_ParticleCommunication.H:500
std::enable_if_t< std::is_integral_v< T > > ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:193
__host__ __device__ void copyParticle(const ParticleTileData< T_ParticleType, NAR, NAI > &dst, const ConstParticleTileData< T_ParticleType, NAR, NAI > &src, int src_i, int dst_i) noexcept
A general single particle copying routine that can run on the GPU.
Definition AMReX_ParticleTransformation.H:31
void unpackRemotes(PC &pc, const ParticleCopyPlan &plan, Buffer &rcv_buffer, UnpackPolicy const &policy)
Definition AMReX_ParticleCommunication.H:600
void copyParticles(DstTile &dst, const SrcTile &src) noexcept
Copy particles from src to dst. This version copies all the particles, writing them to the beginning ...
Definition AMReX_ParticleTransformation.H:161
Long doHandShake(const std::map< int, Vector< char > > &not_ours, Vector< Long > &Snds, Vector< Long > &Rcvs)
Definition AMReX_ParticleMPIUtil.cpp:25
Index filterAndTransformParticles(DstTile &dst, const SrcTile &src, Index *mask, F const &f, Index src_start, Index dst_start) noexcept
Conditionally copy particles from src to dst based on the value of mask. A transformation will also b...
Definition AMReX_ParticleTransformation.H:456
__host__ __device__ bool enforcePeriodic(P &p, amrex::GpuArray< amrex::Real, 3 > const &plo, amrex::GpuArray< amrex::Real, 3 > const &phi, amrex::GpuArray< amrex::ParticleReal, 3 > const &rlo, amrex::GpuArray< amrex::ParticleReal, 3 > const &rhi, amrex::GpuArray< int, 3 > const &is_per) noexcept
Definition AMReX_ParticleUtil.H:421
Long doHandShakeLocal(const std::map< int, Vector< char > > &not_ours, const Vector< int > &neighbor_procs, Vector< Long > &Snds, Vector< Long > &Rcvs)
Definition AMReX_ParticleMPIUtil.cpp:50
__host__ __device__ int numTilesInBox(const Box &box, const bool a_do_tiling, const IntVect &a_tile_size)
Definition AMReX_ParticleUtil.H:232
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:30
__host__ __device__ Dim3 begin(BoxND< dim > const &box) noexcept
Definition AMReX_Box.H:2006
double second() noexcept
Definition AMReX_Utility.cpp:940
void communicateParticlesFinish(const ParticleCopyPlan &plan)
Definition AMReX_ParticleCommunication.cpp:384
Index filterParticles(DstTile &dst, const SrcTile &src, const Index *mask) noexcept
Conditionally copy particles from src to dst based on the value of mask.
Definition AMReX_ParticleTransformation.H:330
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:33
void ParticleToMesh(PC const &pc, const Vector< MultiFab * > &mf, int lev_min, int lev_max, F &&f, bool zero_out_input=true, bool vol_weight=true)
Definition AMReX_AmrParticles.H:156
void Error(const std::string &msg)
Print out message to cerr and exit via amrex::Abort().
Definition AMReX.cpp:224
void gatherParticles(PTile &dst, const PTile &src, N np, const Index *inds)
Gather particles copies particles into contiguous order from an arbitrary order. Specifically,...
Definition AMReX_ParticleTransformation.H:674
int numParticlesOutOfRange(Iterator const &pti, int nGrow)
Returns the number of particles that are more than nGrow cells from the box correspond to the input i...
Definition AMReX_ParticleUtil.H:34
int Verbose() noexcept
Definition AMReX.cpp:169
int partitionParticlesByDest(PTile &ptile, const PLocator &ploc, CellAssignor const &assignor, const ParticleBufferMap &pmap, const GpuArray< Real, 3 > &plo, const GpuArray< Real, 3 > &phi, const GpuArray< ParticleReal, 3 > &rlo, const GpuArray< ParticleReal, 3 > &rhi, const GpuArray< int, 3 > &is_per, int lev, int gid, int, int lev_min, int lev_max, int nGrow, bool remove_negative)
Definition AMReX_ParticleUtil.H:654
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition AMReX.cpp:230
const int[]
Definition AMReX_BLProfiler.cpp:1664
void transformParticles(DstTile &dst, const SrcTile &src, F &&f) noexcept
Apply the function f to all the particles in src, writing the result to dst. This version does all th...
Definition AMReX_ParticleTransformation.H:213
__host__ __device__ Dim3 end(BoxND< dim > const &box) noexcept
Definition AMReX_Box.H:2015
void unpackBuffer(PC &pc, const ParticleCopyPlan &plan, const Buffer &snd_buffer, UnpackPolicy const &policy)
Definition AMReX_ParticleCommunication.H:435
void packBuffer(const PC &pc, const ParticleCopyOp &op, const ParticleCopyPlan &plan, Buffer &snd_buffer)
Definition AMReX_ParticleCommunication.H:336
__host__ __device__ IntVect getParticleCell(P const &p, amrex::GpuArray< amrex::Real, 3 > const &plo, amrex::GpuArray< amrex::Real, 3 > const &dxi) noexcept
Returns the cell index for a given particle using the provided lower bounds and cell sizes.
Definition AMReX_ParticleUtil.H:336
Definition AMReX_ParticleLocator.H:216
A multidimensional array accessor.
Definition AMReX_Array4.H:224
Definition AMReX_ParticleContainerI.H:1038
amrex::AmrAssignGrid< amrex::DenseBinIteratorFactory< amrex::Box > > m_assign_grid
Definition AMReX_ParticleContainerI.H:1041
int m_lev_max
Definition AMReX_ParticleContainerI.H:1040
AssignGridFilter(amrex::AmrAssignGrid< amrex::DenseBinIteratorFactory< amrex::Box > > assign_grid, int gid, int level, int nGrow)
This filters based on matching grids.
Definition AMReX_ParticleContainerI.H:1047
int m_nGrow
Definition AMReX_ParticleContainerI.H:1040
int m_lev_min
Definition AMReX_ParticleContainerI.H:1040
AMREX_GPU_HOST_DEVICE int operator()(const SrcData &src, int src_i) const noexcept
Definition AMReX_ParticleContainerI.H:1053
int m_gid
Definition AMReX_ParticleContainerI.H:1040
Definition AMReX_ParticleLocator.H:14
Definition AMReX_ParticleTile.H:514
Definition AMReX_ParticleUtil.H:394
Definition AMReX_DenseBins.H:32
Definition AMReX_ParticleContainerI.H:799
Box m_domain
Definition AMReX_ParticleContainerI.H:803
GpuArray< Real, 3 > m_dxi
Definition AMReX_ParticleContainerI.H:802
FilterVirt(const amrex::AssignGrid< amrex::DenseBinIteratorFactory< amrex::Box > > &assign_buffer_grid, const GpuArray< Real, 3 > &plo, const GpuArray< Real, 3 > &dxi, const Box &domain)
Definition AMReX_ParticleContainerI.H:805
AMREX_GPU_HOST_DEVICE int operator()(const SrcData &src, int src_i) const noexcept
Definition AMReX_ParticleContainerI.H:812
amrex::AssignGrid< amrex::DenseBinIteratorFactory< amrex::Box > > m_assign_buffer_grid
Definition AMReX_ParticleContainerI.H:801
GpuArray< Real, 3 > m_plo
Definition AMReX_ParticleContainerI.H:802
Definition AMReX_ParticleUtil.H:303
Fixed-size array that can be used on GPU.
Definition AMReX_Array.H:41
Definition AMReX_GpuControl.H:184
Definition AMReX_ParticleCommunication.H:58
void setNumLevels(int num_levels)
Definition AMReX_ParticleCommunication.cpp:14
Vector< std::map< int, Gpu::DeviceVector< IntVect > > > m_periodic_shift
Definition AMReX_ParticleCommunication.H:62
Vector< std::map< int, Gpu::DeviceVector< int > > > m_boxes
Definition AMReX_ParticleCommunication.H:59
Vector< std::map< int, Gpu::DeviceVector< int > > > m_levels
Definition AMReX_ParticleCommunication.H:60
Vector< std::map< int, Gpu::DeviceVector< int > > > m_src_indices
Definition AMReX_ParticleCommunication.H:61
void resize(int gid, int lev, int size)
Definition AMReX_ParticleCommunication.cpp:22
Definition AMReX_ParticleCommunication.H:81
Vector< int > m_rcv_box_ids
Definition AMReX_ParticleCommunication.H:90
Vector< int > m_rcv_box_counts
Definition AMReX_ParticleCommunication.H:88
Vector< int > m_rcv_box_levs
Definition AMReX_ParticleCommunication.H:92
int m_nrcvs
Definition AMReX_ParticleCommunication.H:95
Gpu::HostVector< unsigned int > m_box_counts_h
Definition AMReX_ParticleCommunication.H:85
A struct used for storing a particle's position in the AMR hierarchy.
Definition AMReX_ParticleContainer.H:92
Box m_grown_gridbox
Definition AMReX_ParticleContainer.H:99
IntVect m_cell
Definition AMReX_ParticleContainer.H:96
int m_grid
Definition AMReX_ParticleContainer.H:94
int m_tile
Definition AMReX_ParticleContainer.H:95
int m_lev
Definition AMReX_ParticleContainer.H:93
Box m_tilebox
Definition AMReX_ParticleContainer.H:98
Box m_gridbox
Definition AMReX_ParticleContainer.H:97
Definition AMReX_ParticleTile.H:721
std::size_t size() const
Returns the total number of particles (real and neighbor)
Definition AMReX_ParticleTile.H:890
ParticleTileDataType getParticleTileData()
Definition AMReX_ParticleTile.H:1203
int numParticles() const
Returns the number of real particles (excluding neighbors)
Definition AMReX_ParticleTile.H:903
void resize(std::size_t count, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_ParticleTile.H:969
AoS & GetArrayOfStructs()
Definition AMReX_ParticleTile.H:878
bool empty() const
Definition AMReX_ParticleTile.H:884
The struct used to store particles.
Definition AMReX_Particle.H:404
__host__ __device__ RealVect pos() const &
Definition AMReX_Particle.H:454
Definition AMReX_ParticleContainerI.H:1065
AMREX_GPU_HOST_DEVICE void operator()(DstData &dst, const SrcData &src, int src_i, int dst_i) const noexcept
Definition AMReX_ParticleContainerI.H:1069
Definition AMReX_ParticleContainerI.H:820
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void operator()(DstData &dst, const SrcData &src, int src_i, int dst_i) const noexcept
Definition AMReX_ParticleContainerI.H:823