13#ifndef CD_PARTICLECONTAINERIMPLEM_H
14#define CD_PARTICLECONTAINERIMPLEM_H
24#include <unordered_map>
32#include <BoxIterator.H>
38#include <CD_NamespaceHeader.H>
40template <
typename P,
typename Traits>
47template <
typename P,
typename Traits>
50 const Vector<DisjointBoxLayout>& a_sourceGrids)
52 CH_TIME(
"ParticleContainer::gatherToPool");
60 auto binLeaf = [
this](
MoverPool& a_target,
const Leaf& a_leaf) ->
unsigned long long {
61 unsigned long long outcast = 0;
63 for (std::size_t i = 0; i < a_leaf.size(); i++) {
64 const RealVect pos = a_leaf.position(i);
65 const auto dst = this->findDestination(pos);
72 Leaf& bin = a_target[dst.rank][
PoolKey(dst.level, dst.gridIndex)];
74 bin.
append(pos, a_leaf.weight(i), a_leaf.gather(i));
76 const std::size_t k = bin.
size() - 1;
85 unsigned long long numOutcast = 0;
87 for (
int lvl = 0; lvl < a_source.size(); lvl++) {
89 const DataIterator& dit = a_sourceGrids[lvl].dataIterator();
90 const int nbox = dit.size();
93#pragma omp parallel reduction(+ : numOutcast)
97#pragma omp for schedule(runtime)
98 for (
int mybox = 0; mybox < nbox; mybox++) {
99 Leaf& leaf = level[dit[mybox]];
101 numOutcast += binLeaf(threadPool, leaf);
114#pragma omp critical(ParticleContainer_gatherMerge)
116 for (
int r = 0; r < numProc(); r++) {
117 for (
auto& kv : threadPool[r]) {
118 pool[r][kv.first].catenate(kv.second);
124 for (
int mybox = 0; mybox < nbox; mybox++) {
125 Leaf& leaf = level[dit[mybox]];
127 numOutcast += binLeaf(pool, leaf);
136 m_numOutcastLocal = numOutcast;
141template <
typename P,
typename Traits>
145 CH_TIME(
"ParticleContainer::gatherMoversToPool");
147 CH_assert(m_validCells !=
nullptr);
150 unsigned long long numOutcast = 0;
152 for (
int lvl = 0; lvl <= m_finestLevel; lvl++) {
154 const LevelData<BaseFab<bool>>* maskLevel = (*m_validCells)[lvl].isNull() ? nullptr : &(*(*m_validCells)[lvl]);
155 const DataIterator& dit = m_grids[lvl].dataIterator();
156 const int nbox = dit.size();
163 auto partitionLeaf = [
this, lvl](
MoverPool& a_target,
164 [[maybe_unused]]
const DataIndex& a_din,
166 const BaseFab<bool>* a_mask) ->
unsigned long long {
167 unsigned long long outcast = 0;
169 const Box maskBox = (a_mask !=
nullptr) ? a_mask->box() : Box();
173 while (i < a_leaf.size()) {
174 const RealVect pos = a_leaf.position(i);
175 if (a_mask !=
nullptr) {
176 const IntVect iv = this->cellIndex(lvl, pos);
178 if (maskBox.contains(iv) && (*a_mask)(iv, 0)) {
183 const auto chk = this->findDestination(pos);
184 CH_assert(chk.valid && chk.level == lvl && chk.rank == procID() &&
185 m_levelTiles[lvl]->getMyGrids().at(chk.gridIndex) == a_din);
193 const auto dst = this->findDestination(pos);
196 Leaf& bin = a_target[dst.rank][
PoolKey(dst.level, dst.gridIndex)];
198 bin.
append(pos, a_leaf.weight(i), a_leaf.gather(i));
200 const std::size_t k = bin.
size() - 1;
216#pragma omp parallel reduction(+ : numOutcast)
220#pragma omp for schedule(runtime)
221 for (
int mybox = 0; mybox < nbox; mybox++) {
222 const DataIndex& din = dit[mybox];
223 const BaseFab<bool>* mask = (maskLevel !=
nullptr) ? &(*maskLevel)[din] :
nullptr;
225 if (mask !=
nullptr && !mask->isUsable()) {
229 numOutcast += partitionLeaf(threadPool, din, level[din], mask);
232#pragma omp critical(ParticleContainer_gatherMerge)
234 for (
int r = 0; r < numProc(); r++) {
235 for (
auto& kv : threadPool[r]) {
236 pool[r][kv.first].catenate(kv.second);
242 for (
int mybox = 0; mybox < nbox; mybox++) {
243 const DataIndex& din = dit[mybox];
244 const BaseFab<bool>* mask = (maskLevel !=
nullptr) ? &(*maskLevel)[din] :
nullptr;
246 if (mask !=
nullptr && !mask->isUsable()) {
250 numOutcast += partitionLeaf(pool, din, level[din], mask);
255 m_numOutcastLocal = numOutcast;
260template <
typename P,
typename Traits>
264 CH_TIME(
"ParticleContainer::distributeFromPool");
266 const int myRank = procID();
267 const int numRanks = numProc();
274 for (
auto& kv : a_pool[myRank]) {
275 const int lvl = kv.first.first;
276 const unsigned int gidx = kv.first.second;
277 const DataIndex din = m_levelTiles[lvl]->getMyGrids().at(gidx);
279 (*m_particles[lvl])[din].catenate(kv.second);
284 constexpr std::size_t pp = Leaf::bytesPerParticle();
285 constexpr std::size_t headerLen = 2 *
sizeof(std::uint32_t) +
sizeof(std::uint64_t);
292 std::vector<int> sendCounts(numRanks, 0);
293 std::vector<int> recvCounts(numRanks, 0);
294 std::vector<std::int64_t> sendBytes(numRanks, 0);
296 std::int64_t stot = 0;
298 for (
int r = 0; r < numRanks; r++) {
303 std::int64_t bytes = 0;
305 for (
const auto& kv : a_pool[r]) {
306 bytes +=
static_cast<std::int64_t
>(headerLen + kv.second.size() * pp);
309 sendBytes[r] = bytes;
318 if (stot >
static_cast<std::int64_t
>(std::numeric_limits<int>::max())) {
319 MayDay::Abort(
"ParticleContainer::distributeFromPool - outbound particle bytes exceed MPI's int limit");
322 for (
int r = 0; r < numRanks; r++) {
323 sendCounts[r] =
static_cast<int>(sendBytes[r]);
326 MPI_Alltoall(sendCounts.data(), 1, MPI_INT, recvCounts.data(), 1, MPI_INT, Chombo_MPI::comm);
328 std::vector<int> sdispl(numRanks, 0);
329 std::vector<int> rdispl(numRanks, 0);
331 std::int64_t sacc = 0;
332 std::int64_t rtot = 0;
334 for (
int r = 0; r < numRanks; r++) {
335 sdispl[r] =
static_cast<int>(sacc);
336 sacc += sendCounts[r];
338 rdispl[r] =
static_cast<int>(rtot);
339 rtot += recvCounts[r];
342 if (rtot >
static_cast<std::int64_t
>(std::numeric_limits<int>::max())) {
343 MayDay::Abort(
"ParticleContainer::distributeFromPool - inbound particle bytes exceed MPI's int limit");
346 std::vector<char> sflat(stot);
347 std::vector<char> rflat(rtot);
353 const std::size_t flatBytes =
static_cast<std::size_t
>(stot) +
static_cast<std::size_t
>(rtot);
363#pragma omp parallel for schedule(runtime)
365 for (
int r = 0; r < numRanks; r++) {
370 char* p = sflat.data() + sdispl[r];
372 for (
auto& kv : a_pool[r]) {
373 Leaf& src = kv.second;
375 const std::uint32_t lvl =
static_cast<std::uint32_t
>(kv.first.first);
376 const std::uint32_t gidx =
static_cast<std::uint32_t
>(kv.first.second);
377 const std::uint64_t count =
static_cast<std::uint64_t
>(src.
size());
379 std::memcpy(p, &lvl,
sizeof(std::uint32_t));
380 p +=
sizeof(std::uint32_t);
382 std::memcpy(p, &gidx,
sizeof(std::uint32_t));
383 p +=
sizeof(std::uint32_t);
385 std::memcpy(p, &count,
sizeof(std::uint64_t));
386 p +=
sizeof(std::uint64_t);
388 for (std::size_t i = 0; i < count; i++) {
398 MPI_Alltoallv(sflat.data(),
420 unsigned int gridIndex;
422 std::vector<RecvChunk> chunks;
425 std::vector<DestGroup> groups;
426 std::map<PoolKey, std::size_t> keyToGroup;
428 const char* p = rflat.data();
429 const char* end = p + rtot;
436 std::memcpy(&lvl, p,
sizeof(std::uint32_t));
437 p +=
sizeof(std::uint32_t);
439 std::memcpy(&gidx, p,
sizeof(std::uint32_t));
440 p +=
sizeof(std::uint32_t);
442 std::memcpy(&count, p,
sizeof(std::uint64_t));
443 p +=
sizeof(std::uint64_t);
445 const PoolKey key(
static_cast<int>(lvl), gidx);
446 const auto it = keyToGroup.find(key);
448 if (it == keyToGroup.end()) {
449 keyToGroup.emplace(key, groups.size());
450 groups.push_back(DestGroup{
static_cast<int>(lvl), gidx, count, {RecvChunk{p, count}}});
453 DestGroup& g = groups[it->second];
455 g.chunks.push_back(RecvChunk{p, count});
462 const int numGroups =
static_cast<int>(groups.size());
465#pragma omp parallel for schedule(runtime)
467 for (
int d = 0; d < numGroups; d++) {
468 const DestGroup& g = groups[d];
469 const DataIndex din = m_levelTiles[g.level]->getMyGrids().at(g.gridIndex);
471 Leaf& tgt = (*m_particles[g.level])[din];
474 for (
const RecvChunk& chunk : g.chunks) {
475 const char* q = chunk.payload;
477 for (std::uint64_t c = 0; c < chunk.count; c++) {
480 if (a_setOwnerToReceiver) {
492template <
typename P,
typename Traits>
496 CH_TIME(
"ParticleContainer::remap");
498 CH_assert(m_isDefined);
501 this->clearGhostParticles();
503 if (m_validCells !=
nullptr &&
static_cast<int>(m_validCells->size()) >= m_finestLevel + 1) {
507 MoverPool pool = this->gatherMoversToPool();
509 this->distributeFromPool(pool,
true);
514 MoverPool pool = this->gatherToPool(m_particles, m_grids);
516 this->clearParticles();
517 this->distributeFromPool(pool,
true);
520 m_isOrganizedByCell =
false;
523template <
typename P,
typename Traits>
527 CH_TIME(
"ParticleContainer::preRegrid");
529 CH_assert(m_isDefined);
532 this->clearGhostParticles();
534 m_cacheParticles = m_particles;
535 m_cacheGrids = m_grids;
538template <
typename P,
typename Traits>
541 const Vector<ProblemDomain>& a_domains,
542 const Vector<Real>& a_dx,
543 const Vector<int>& a_refRat,
544 const int a_minBlockSize,
545 const Vector<RefCountedPtr<LevelTiles>>& a_levelTiles,
546 const int a_newFinestLevel)
548 CH_TIME(
"ParticleContainer::regrid");
550 CH_assert(m_isDefined);
551 CH_assert(a_levelTiles.size() > a_newFinestLevel);
555 m_domains = a_domains;
557 m_minBlockSize = a_minBlockSize;
558 m_finestLevel = a_newFinestLevel;
561 m_levelTiles = a_levelTiles;
563 m_dx.resize(a_newFinestLevel + 1);
564 for (
int lvl = 0; lvl <= a_newFinestLevel; lvl++) {
565 m_dx[lvl] = a_dx[lvl] * RealVect::Unit;
569 m_particles.resize(a_newFinestLevel + 1);
570 m_maskParticles.resize(a_newFinestLevel + 1);
572 for (
int lvl = 0; lvl <= a_newFinestLevel; lvl++) {
573 m_particles[lvl] = RefCountedPtr<LevelParticles>(
new LevelParticles(a_grids[lvl]));
574 m_maskParticles[lvl] = RefCountedPtr<LevelParticles>(
new LevelParticles(a_grids[lvl]));
577 this->setupGrownGrids();
579 m_bufferParticles.resize(a_newFinestLevel + 1);
581 for (
int lvl = 0; lvl <= a_newFinestLevel; lvl++) {
582 m_bufferParticles[lvl] = RefCountedPtr<LevelParticles>(
new LevelParticles(m_grownGrids[lvl]));
586 MoverPool pool = this->gatherToPool(m_cacheParticles, m_cacheGrids);
587 this->distributeFromPool(pool,
true);
590 m_cacheParticles.resize(0);
591 m_cacheGrids.resize(0);
593 m_isOrganizedByCell =
false;
596template <
typename P,
typename Traits>
600 CH_TIME(
"ParticleContainer::clearGhostParticles");
602 CH_assert(m_isDefined);
604 for (
int lvl = 0; lvl <= m_finestLevel; lvl++) {
606 const DisjointBoxLayout& dbl = m_grids[lvl];
607 const DataIterator& dit = dbl.dataIterator();
609 const int nbox = dit.size();
611#pragma omp parallel for schedule(runtime)
612 for (
int mybox = 0; mybox < nbox; mybox++) {
613 const DataIndex& din = dit[mybox];
614 Leaf& leaf = level[din];
618 while (i < leaf.
size()) {
629 m_isOrganizedByCell =
false;
632template <
typename P,
typename Traits>
636 CH_TIME(
"ParticleContainer::claimOwnership");
638 CH_assert(m_isDefined);
645 for (
int lvl = 0; lvl <= m_finestLevel; lvl++) {
647 const DisjointBoxLayout& dbl = m_grids[lvl];
648 const DataIterator& dit = dbl.dataIterator();
649 const int nbox = dit.size();
651#pragma omp parallel for schedule(runtime)
652 for (
int mybox = 0; mybox < nbox; mybox++) {
653 const DataIndex& din = dit[mybox];
654 const Box box = dbl[din];
655 Leaf& leaf = level[din];
657 for (std::size_t i = 0; i < leaf.
size(); i++) {
661 if (!a_onlyValidRegion || this->inValidBox(lvl, box, leaf.
position(i))) {
669template <
typename P,
typename Traits>
673 CH_TIME(
"ParticleContainer::resetParticleIDs");
675 CH_assert(m_isDefined);
682 std::vector<std::pair<int, DataIndex>> boxes;
683 for (
int lvl = 0; lvl <= m_finestLevel; lvl++) {
684 const DataIterator& dit = m_grids[lvl].dataIterator();
685 const int nbox = dit.size();
686 for (
int mybox = 0; mybox < nbox; mybox++) {
687 boxes.emplace_back(lvl, dit[mybox]);
690 const int numBoxes =
static_cast<int>(boxes.size());
693 std::vector<long long> boxCount(numBoxes, 0);
694#pragma omp parallel for schedule(runtime)
695 for (
int b = 0; b < numBoxes; b++) {
696 const int lvl = boxes[b].first;
697 const DataIndex& din = boxes[b].second;
698 const Box box = m_grids[lvl][din];
699 const Leaf& leaf = (*m_particles[lvl])[din];
702 for (std::size_t i = 0; i < leaf.
size(); i++) {
703 if (!leaf.
isGhost(i) && (!a_onlyValidRegion || this->inValidBox(lvl, box, leaf.
position(i)))) {
711 std::vector<long long> boxLocalOffset(numBoxes, 0);
712 long long localTotal = 0;
713 for (
int b = 0; b < numBoxes; b++) {
714 boxLocalOffset[b] = localTotal;
715 localTotal += boxCount[b];
722 for (
int r = 0; r < procID(); r++) {
723 rankOffset += perRankCount[r];
728#pragma omp parallel for schedule(runtime)
729 for (
int b = 0; b < numBoxes; b++) {
730 const int lvl = boxes[b].first;
731 const DataIndex& din = boxes[b].second;
732 const Box box = m_grids[lvl][din];
733 Leaf& leaf = (*m_particles[lvl])[din];
736 for (std::size_t i = 0; i < leaf.
size(); i++) {
740 if (!a_onlyValidRegion || this->inValidBox(lvl, box, leaf.
position(i))) {
752template <
typename P,
typename Traits>
758 CH_TIME(
"ParticleContainer::gatherGhostsFromMasks");
766 auto binLeaf = [&](
MoverPool& a_target,
const Leaf& a_leaf,
const int a_srcLvl,
const DataIndex& a_din) {
767 const bool haveSame = (a_srcLvl < a_maskSame.size()) && !a_maskSame[a_srcLvl].isNull();
768 const bool haveC2F = (a_srcLvl < m_finestLevel) && (a_srcLvl < a_maskCoarToFine.size()) &&
769 !a_maskCoarToFine[a_srcLvl].isNull();
770 const bool haveF2C = (a_srcLvl >= 1) && (a_srcLvl < a_maskFineToCoar.size()) &&
771 !a_maskFineToCoar[a_srcLvl].isNull();
773 const ParticleGhostMask* same = haveSame ? &((*a_maskSame[a_srcLvl])[a_din]) :
nullptr;
774 const ParticleGhostMask* c2f = haveC2F ? &((*a_maskCoarToFine[a_srcLvl])[a_din]) :
nullptr;
775 const ParticleGhostMask* f2c = haveF2C ? &((*a_maskFineToCoar[a_srcLvl])[a_din]) :
nullptr;
777 if (same ==
nullptr && c2f ==
nullptr && f2c ==
nullptr) {
781 for (std::size_t i = 0; i < a_leaf.size(); i++) {
782 const RealVect pos = a_leaf.position(i);
783 const IntVect iv = this->cellIndex(a_srcLvl, pos);
787 if (a_mask ==
nullptr || !a_mask->
box().contains(iv)) {
795 const IntVect dstCell = a_pruneByTargetBox ? this->cellIndex(a_dstLvl, pos) : IntVect::Zero;
797 for (
int k = 0; k < nt; k++) {
798 if (a_pruneByTargetBox && !a_mask->
targetBox(iv, k).contains(dstCell)) {
804 bin.
append(pos, a_leaf.weight(i), a_leaf.gather(i));
806 const std::size_t j = bin.
size() - 1;
820 for (
int lvl = 0; lvl <= m_finestLevel; lvl++) {
822 const DataIterator& dit = m_grids[lvl].dataIterator();
823 const int nbox = dit.size();
830#pragma omp for schedule(runtime)
831 for (
int mybox = 0; mybox < nbox; mybox++) {
832 binLeaf(threadPool, level[dit[mybox]], lvl, dit[mybox]);
835#pragma omp critical(ParticleContainer_gatherGhostsFromMasksMerge)
837 for (
int r = 0; r < numProc(); r++) {
838 for (
auto& kv : threadPool[r]) {
839 pool[r][kv.first].catenate(kv.second);
845 for (
int mybox = 0; mybox < nbox; mybox++) {
846 binLeaf(pool, level[dit[mybox]], lvl, dit[mybox]);
854template <
typename P,
typename Traits>
860 CH_TIME(
"ParticleContainer::fillGhostParticles");
862 CH_assert(m_isDefined);
865 this->clearGhostParticles();
867 MoverPool pool = this->gatherGhostsFromMasks(a_maskSame, a_maskCoarToFine, a_maskFineToCoar);
870 this->distributeFromPool(pool,
false);
872 m_isOrganizedByCell =
false;
875template <
typename P,
typename Traits>
879 CH_TIME(
"ParticleContainer::setupGrownGrids");
881 m_grownGrids.resize(m_finestLevel + 1);
882 for (
int lvl = 0; lvl <= m_finestLevel; lvl++) {
883 const DisjointBoxLayout& dbl = m_grids[lvl];
885 Vector<Box> boxes = dbl.boxArray();
888 const Box domainBox = m_domains[lvl].domainBox();
889 for (
int i = 0; i < boxes.size(); i++) {
890 boxes[i].grow(m_refRat[lvl - 1]);
891 boxes[i] &= domainBox;
895 m_grownGrids[lvl] = BoxLayout(boxes, dbl.procIDs());
899template <
typename P,
typename Traits>
903 CH_TIME(
"ParticleContainer::copyMaskParticles(amr)");
905 CH_assert(m_isDefined);
907 for (
int lvl = 0; lvl <= m_finestLevel; lvl++) {
908 if (!a_mask[lvl].isNull()) {
909 this->copyMaskParticles(lvl, *a_mask[lvl]);
914template <
typename P,
typename Traits>
918 CH_TIME(
"ParticleContainer::copyMaskParticles(level)");
920 CH_assert(m_isDefined);
925 const DisjointBoxLayout& dbl = m_grids[a_level];
926 const DataIterator& dit = dbl.dataIterator();
928 const int nbox = dit.size();
930#pragma omp parallel for schedule(runtime)
931 for (
int mybox = 0; mybox < nbox; mybox++) {
932 const DataIndex& din = dit[mybox];
934 maskLevel[din].clear();
936 const BaseFab<bool>& mask = a_mask[din];
937 if (!mask.isUsable()) {
940 const Box maskBox = mask.box();
942 const Leaf& src = srcLevel[din];
943 Leaf& dst = maskLevel[din];
945 for (std::size_t i = 0; i < src.size(); i++) {
946 const IntVect iv = this->cellIndex(a_level, src.position(i));
948 if (maskBox.contains(iv) && mask(iv, 0)) {
949 dst.append(src.position(i), src.weight(i), src.gather(i));
951 const std::size_t k = dst.size() - 1;
953 dst.particleID(k) = src.particleID(i);
954 dst.rankID(k) = src.rankID(i);
960template <
typename P,
typename Traits>
964 CH_TIME(
"ParticleContainer::transferMaskParticles(amr)");
966 CH_assert(m_isDefined);
968 for (
int lvl = 0; lvl <= m_finestLevel; lvl++) {
969 if (!a_mask[lvl].isNull()) {
970 this->transferMaskParticles(lvl, *a_mask[lvl]);
975template <
typename P,
typename Traits>
979 CH_TIME(
"ParticleContainer::transferMaskParticles(level)");
981 CH_assert(m_isDefined);
986 const DisjointBoxLayout& dbl = m_grids[a_level];
987 const DataIterator& dit = dbl.dataIterator();
989 const int nbox = dit.size();
991#pragma omp parallel for schedule(runtime)
992 for (
int mybox = 0; mybox < nbox; mybox++) {
993 const DataIndex& din = dit[mybox];
995 const BaseFab<bool>& mask = a_mask[din];
996 if (!mask.isUsable()) {
999 const Box maskBox = mask.box();
1001 Leaf& src = srcLevel[din];
1002 Leaf& dst = maskLevel[din];
1005 while (i < src.
size()) {
1006 const IntVect iv = this->cellIndex(a_level, src.
position(i));
1008 if (maskBox.contains(iv) && mask(iv, 0)) {
1011 const std::size_t k = dst.
size() - 1;
1025#include <CD_NamespaceFooter.H>
Declaration of an AMR-hierarchy container that owns per-patch ParticleSoA leaves.
Vector< RefCountedPtr< LayoutData< ParticleSoA< P, Traits > > > > AMRParticlesSoA
Per-level holder vector: one ParticleSoA leaf container per box, per level.
Definition CD_ParticleContainer.H:56
Vector< RefCountedPtr< LayoutData< ParticleGhostMask > > > AMRParticleGhostMask
AMR-wide particle ghost-target lookup: one per-box CSR table per level, indexed by SOURCE level.
Definition CD_ParticleGhostMask.H:210
Process-wide accounting of the memory held by particle data.
std::int32_t RankID
Owning-rank identifier type (container-owned metadata column; fixed-width for I/O).
Definition CD_ParticleSoA.H:166
GhostType
Ghost designation of a particle (container-owned metadata column).
Definition CD_ParticleSoA.H:177
@ SameLevel
Ghost from an adjacent patch on the same level.
@ Coarse
Ghost from the next-coarser level (level l-1).
@ Fine
Ghost from the next-finer level (level l+1).
std::int64_t ParticleID
Global particle identifier type (container-owned metadata column; fixed-width for I/O).
Definition CD_ParticleSoA.H:161
static LevelAndBox findDestination(const RealVect &a_pos, const RealVect &a_probLo, const Vector< RealVect > &a_dx, const int a_minBlockSize, const Vector< RefCountedPtr< LevelTiles > > &a_levelTiles, const int a_finestLevel) noexcept
Map a physical position to its owning (level, grid index, rank) via the finest containing tile.
Definition CD_LevelTiles.H:161
void fillGhostParticles(const AMRParticleGhostMask &a_maskSame, const AMRParticleGhostMask &a_maskCoarToFine, const AMRParticleGhostMask &a_maskFineToCoar)
Fill each patch's ghost halo from prebuilt Realm particle ghost masks.
Definition CD_ParticleContainerImplem.H:856
void regrid(const Vector< DisjointBoxLayout > &a_grids, const Vector< ProblemDomain > &a_domains, const Vector< Real > &a_dx, const Vector< int > &a_refRat, const int a_minBlockSize, const Vector< RefCountedPtr< LevelTiles > > &a_levelTiles, const int a_newFinestLevel)
Rebuild over a new AMR layout and redistribute the preRegrid()-cached particles onto it.
Definition CD_ParticleContainerImplem.H:540
void transferMaskParticles(const Vector< RefCountedPtr< LevelData< BaseFab< bool > > > > &a_mask)
Move the valid particles selected by a per-cell mask into the mask holder, all levels.
Definition CD_ParticleContainerImplem.H:962
void setupGrownGrids()
Build the grown grids (buffer-particle layout): boxes grown by the refinement factor.
Definition CD_ParticleContainerImplem.H:877
MoverPool gatherMoversToPool()
Mask fast path for remap(): pool ONLY the movers, leaving stayers in place.
Definition CD_ParticleContainerImplem.H:143
void clearGhostParticles()
Remove every ghost particle (any non-Valid GhostType) from all levels and patches.
Definition CD_ParticleContainerImplem.H:598
std::vector< std::map< PoolKey, Leaf > > MoverPool
Per-rank pool of movers: pool[rank] maps a destination patch to a small SoA of particles.
Definition CD_ParticleContainer.H:911
void preRegrid()
Cache the current valid particles ahead of a regrid.
Definition CD_ParticleContainerImplem.H:525
void claimOwnership(const bool a_onlyValidRegion)
Claim ownership of this rank's particles by stamping their owner rank (rankID = procID()).
Definition CD_ParticleContainerImplem.H:634
void distributeFromPool(MoverPool &a_pool, const bool a_setOwnerToReceiver)
Assign a pool into the valid holders: local appends + MPI scatter.
Definition CD_ParticleContainerImplem.H:262
long long resetParticleIDs(const bool a_onlyValidRegion, const ParticleID a_startID)
Assign globally-unique, contiguous particle IDs to the owned particles.
Definition CD_ParticleContainerImplem.H:671
void remap()
Redistribute every valid particle to the patch/level/rank that owns its cell.
Definition CD_ParticleContainerImplem.H:494
MoverPool gatherToPool(AMRParticlesSoA< P, Traits > &a_source, const Vector< DisjointBoxLayout > &a_sourceGrids)
Gather every particle of a source holder into a per-rank, per-destination-patch pool.
Definition CD_ParticleContainerImplem.H:49
LayoutData< Leaf > LevelParticles
The per-level holder type (one Leaf per box on the level's DisjointBoxLayout).
Definition CD_ParticleContainer.H:133
LevelTiles::LevelAndBox findDestination(const RealVect &a_pos) const
Map a position to its owning (level, grid index, rank) via the finest containing tile.
Definition CD_ParticleContainerImplem.H:42
void copyMaskParticles(const Vector< RefCountedPtr< LevelData< BaseFab< bool > > > > &a_mask)
Copy the valid particles selected by a per-cell mask into the mask holder, all levels.
Definition CD_ParticleContainerImplem.H:901
std::pair< int, unsigned int > PoolKey
Pool key identifying a destination patch: (level, grid index within the level).
Definition CD_ParticleContainer.H:906
MoverPool gatherGhostsFromMasks(const AMRParticleGhostMask &a_maskSame, const AMRParticleGhostMask &a_maskCoarToFine, const AMRParticleGhostMask &a_maskFineToCoar)
Gather ghost copies into a per-rank pool using prebuilt particle ghost masks.
Definition CD_ParticleContainerImplem.H:754
Per-box CSR lookup from a source cell to the destination boxes whose ghosted region covers it.
Definition CD_ParticleGhostMask.H:53
const Box & box() const noexcept
Get the box that the source cells live on.
Definition CD_ParticleGhostMaskImplem.H:90
unsigned int targetGridIndex(const IntVect &a_iv, const int a_i) const noexcept
Get the destination grid index of the i-th target for a cell.
Definition CD_ParticleGhostMaskImplem.H:116
const Box & targetBox(const IntVect &a_iv, const int a_i) const noexcept
Get the acceptance box of the i-th target for a cell.
Definition CD_ParticleGhostMaskImplem.H:128
int numTargets(const IntVect &a_iv) const noexcept
Get the number of scatter targets for a cell.
Definition CD_ParticleGhostMaskImplem.H:100
unsigned int targetRank(const IntVect &a_iv, const int a_i) const noexcept
Get the receiving rank of the i-th target for a cell.
Definition CD_ParticleGhostMaskImplem.H:122
Arena-backed Struct-of-Arrays particle container for a single grid patch.
Definition CD_ParticleSoA.H:655
RankID & rankID(const std::size_t a_index) noexcept
Owning rank of particle i (container-owned metadata).
Definition CD_ParticleSoA.H:1279
void append(const RealVect &a_position, const double a_weight)
Append one particle with a default-constructed payload.
Definition CD_ParticleSoA.H:955
void shrinkToFit()
Reclaim unused capacity by reallocating the arena down to the current size.
Definition CD_ParticleSoAImplem.H:187
bool isGhost(const std::size_t a_index) const noexcept
Whether particle i is a ghost particle (any non-Valid designation).
Definition CD_ParticleSoA.H:1331
void delinearizeAndAppend(const void *a_buffer)
Append a particle delinearized from a byte buffer (all columns, for MPI receive).
Definition CD_ParticleSoAImplem.H:243
void linearizeParticle(void *a_buffer, const std::size_t a_index) const noexcept
Linearize particle i into a byte buffer (all columns, for MPI send).
Definition CD_ParticleSoAImplem.H:232
RealVect position(const std::size_t a_index) const noexcept
Position of particle i as a RealVect (by value, assembled from the scalar columns).
Definition CD_ParticleSoA.H:1188
GhostType & ghost(const std::size_t a_index) noexcept
Ghost designation of particle i (container-owned metadata).
Definition CD_ParticleSoA.H:1305
double & weight(const std::size_t a_index) noexcept
Weight of particle i.
Definition CD_ParticleSoA.H:1222
std::size_t size() const noexcept
Number of particles currently stored.
Definition CD_ParticleSoA.H:882
P gather(const std::size_t a_index) const
Gather particle i's payload back into the AoS payload view.
Definition CD_ParticleSoA.H:1021
ParticleID & particleID(const std::size_t a_index) noexcept
Global id of particle i (container-owned metadata).
Definition CD_ParticleSoA.H:1253
void remove(const std::size_t a_index) noexcept
Remove particle i using swap-and-pop (O(1), does NOT preserve order).
Definition CD_ParticleSoA.H:1033
void clear() noexcept
Drop all particles (keeps the arena; invalidates the cell sort).
Definition CD_ParticleSoA.H:911
void reserve(const std::size_t a_capacity)
Ensure capacity for at least a_capacity particles (reallocates + moves on growth).
Definition CD_ParticleSoAImplem.H:88
Vector< int > gather(const int &a_localValue) noexcept
Gather local values – return a vector of local values.
Definition CD_ParallelOpsImplem.H:540
Real sum(const Real &a_value) noexcept
Compute the sum across all MPI ranks.
Definition CD_ParallelOpsImplem.H:354
void removeBytes(const Kind a_kind, const std::size_t a_bytes) noexcept
Record a release.
Definition CD_ParticleMemory.H:140
void addBytes(const Kind a_kind, const std::size_t a_bytes) noexcept
Record an allocation.
Definition CD_ParticleMemory.H:124
@ Buffer
Flat exchange buffers: payload in flight.
Result of a point->block query. See findDestination.
Definition CD_LevelTiles.H:123