18#ifndef CD_NEARESTNEIGHBORPARTICLEMERGE_H
19#define CD_NEARESTNEIGHBORPARTICLEMERGE_H
27#include <unordered_set>
28#include <unordered_map>
37#include <EBGeometry.hpp>
43#include <CD_NamespaceHeader.H>
62template <
typename Packed>
113template <
typename Packed>
161template <
typename Packed>
210template <
typename Packed>
250template <
typename Packed>
252 Packed(
const Packed& a_first,
const Real a_firstWeight,
const Packed& a_second,
const Real a_secondWeight)>;
291template <
typename Packed>
313cellKeyOf(
const RealVect& a_position,
const RealVect& a_probLo,
const RealVect& a_dx)
noexcept;
346 hash ^=
static_cast<std::size_t
>(
static_cast<unsigned int>(a_key.first)) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
392 m_minBudget = std::min(m_minBudget, std::max(0, m_uniform - count));
405 reserveOne(
const int a_level,
const RealVect& a_position,
const RealVect& a_probLo,
const RealVect& a_dx)
418 if (m_reserved.empty()) {
422 const auto it = m_reserved.find(a_key);
424 return (it == m_reserved.end()) ? m_uniform : std::max(0, m_uniform - it->second);
437 return m_reserved.empty() ? m_uniform : std::min(m_uniform, m_minBudget);
449 int m_minBudget = std::numeric_limits<int>::max();
454 std::unordered_map<detail::NNCellKey, int, detail::NNCellKeyHasher> m_reserved;
467using NNWalkCell = IntVect;
486template <
typename Packed,
typename Cloud = EBGeometry::Po
intCloudBVH<Real, ParticleID>>
494 std::shared_ptr<Cloud> pointCloud;
501 std::size_t pointCloudNLocal = 0;
510 std::vector<typename Cloud::Hit> pointCloudGraph;
552template <
typename Packed,
typename Cloud = EBGeometry::Po
intCloudBVH<Real, ParticleID>>
554buildNNSpatialIndex(NNSpatialIndex<Packed, Cloud>& a_index,
555 const std::vector<MergeParticle<Packed>>& a_localValid,
556 const std::vector<MergeParticle<Packed>>& a_ghosts,
557 const RealVect& a_probLo,
558 const RealVect& a_dx,
559 const NNCellBudget& a_cellBudget,
560 const int a_kNearest)
noexcept;
630template <
typename Packed,
typename Cloud = EBGeometry::Po
intCloudBVH<Real, ParticleID>>
632findNearestNeighborCandidates(std::vector<NNMergeEdge<Packed>>& a_edges,
633 const std::vector<MergeParticle<Packed>>& a_localValid,
634 const std::vector<MergeParticle<Packed>>& a_ghosts,
635 const std::unordered_set<ParticleID>& a_consumedIDs,
636 const NNSpatialIndex<Packed, Cloud>& a_spatialIndex,
637 const std::unordered_map<NNCellKey, int, NNCellKeyHasher>& a_liveCellCount,
638 const RealVect& a_probLo,
639 const RealVect& a_dx,
640 const NNCellBudget& a_cellBudget,
641 const int a_maxFallbackCandidates = 0,
642 const std::optional<int> a_maxCellDistance = std::nullopt)
noexcept;
678using NNCellCloud = EBGeometry::PointCloudBVH<Real, NNCellMeta>;
686using NNCellSpatialIndex = std::unordered_map<NNWalkCell, std::shared_ptr<NNCellCloud>,
LevelTiles::TileHasher>;
705template <
typename Packed>
707buildNNCellSpatialIndex(NNCellSpatialIndex& a_index,
708 const std::vector<MergeParticle<Packed>>& a_localValid,
709 const std::vector<MergeParticle<Packed>>& a_ghosts,
710 const RealVect& a_probLo,
711 const RealVect& a_dx,
712 const NNCellBudget& a_cellBudget)
noexcept;
753template <
typename Packed>
755findNearestNeighborCandidatesOneCell(std::vector<NNMergeEdge<Packed>>& a_edges,
756 const std::vector<MergeParticle<Packed>>& a_localValid,
757 const std::unordered_set<ParticleID>& a_consumedIDs,
758 const NNCellSpatialIndex& a_cellIndex,
759 const std::unordered_map<NNCellKey, int, NNCellKeyHasher>& a_liveCellCount,
760 const RealVect& a_probLo,
761 const RealVect& a_dx,
762 const std::vector<RealVect>& a_dxByLevel,
763 const NNCellBudget& a_cellBudget,
764 const int a_maxFallbackCandidates = 0) noexcept;
864template <typename Packed, typename Combine, typename PosValid, typename Allocator, typename OnMerge>
867 std::unordered_map<
NNCellKey,
int, NNCellKeyHasher>& a_liveCellCount,
868 std::unordered_set<
ParticleID>& a_consumedIDs,
869 std::unordered_set<
ParticleID>& a_hasOutgoingCommitment,
870 std::vector<NNMergeResult<Packed>>& a_results,
871 const std::vector<NNMergeEdge<Packed>>& a_edges,
872 const std::unordered_map<
ParticleID, NNPooledParticle<Packed>>& a_particlesByID,
873 const Combine& a_combine,
874 const NNCellBudget& a_cellBudget,
875 const RealVect& a_probLo,
876 const std::vector<RealVect>& a_dxByLevel,
877 const PosValid& a_isPositionValid,
878 const Allocator& a_allocateID,
879 const
int a_maxFallbackCandidates = 0,
880 const std::optional<
int> a_maxCellDistance = std::nullopt,
881 unsigned long long* a_crossLevelMergeCount =
nullptr,
882 const OnMerge& a_onMergeCommitted =
883 [](const MergeParticle<Packed>&, const MergeParticle<Packed>&, const MergeParticle<Packed>&) {
909template <
typename Packed>
911generateProposals(std::vector<std::vector<NNMergeProposal<Packed>>>& a_proposalsByDestRank,
912 const std::vector<NNMergeEdge<Packed>>& a_edges,
913 const std::unordered_set<ParticleID>& a_hasOutgoingCommitment,
914 const std::unordered_map<
ParticleID, NNPooledParticle<Packed>>& a_particlesByID,
915 const int a_numRanks)
noexcept;
999template <
typename Packed,
typename Combine,
typename PosVal
id,
typename Allocator,
typename OnMerge>
1002 std::unordered_map<NNCellKey, int, NNCellKeyHasher>& a_liveCellCount,
1003 std::vector<NNMergeResult<Packed>>& a_results,
1004 std::vector<std::vector<NNMergeVerdict>>& a_verdictsByDestRank,
1005 const std::vector<NNMergeProposal<Packed>>& a_incomingProposals,
1006 const std::unordered_map<
ParticleID, NNPooledParticle<Packed>>& a_particlesByID,
1007 const std::unordered_set<ParticleID>& a_consumedIDs,
1008 const std::unordered_set<ParticleID>& a_hasOutgoingCommitment,
1009 const std::map<ParticleID, ParticleID>& a_outgoingTargetOf,
1010 const Combine& a_combine,
1011 const NNCellBudget& a_cellBudget,
1012 const RealVect& a_probLo,
1013 const std::vector<RealVect>& a_dxByLevel,
1014 const PosValid& a_isPositionValid,
1015 const Allocator& a_allocateID,
1016 const std::optional<int> a_maxCellDistance = std::nullopt,
1017 unsigned long long* a_crossLevelMergeCount =
nullptr,
1018 const OnMerge& a_onMergeCommitted =
1019 [](
const MergeParticle<Packed>&,
const MergeParticle<Packed>&,
const MergeParticle<Packed>&) {
1034applyVerdicts(std::unordered_set<ParticleID>& a_consumedIDs,
1035 const std::vector<NNMergeVerdict>& a_incomingVerdicts)
noexcept;
1074template <
typename Packed>
1076placeMergedParticles(std::map<std::pair<int, unsigned int>, std::vector<MergeParticle<Packed>>>& a_localByPatch,
1077 std::vector<std::vector<MergeParticle<Packed>>>& a_scatterByDestRank,
1078 const std::vector<NNMergeResult<Packed>>& a_results,
1079 const PositionLocator& a_locate,
1080 const int a_thisRank)
noexcept;
1136template <
typename P,
typename Packed,
typename Traits,
typename Gather>
1139 std::vector<NNPatchWork>& a_patchWork,
1140 std::vector<std::vector<MergeParticle<Packed>>>& a_patchLocalValid,
1141 std::vector<std::vector<MergeParticle<Packed>>>& a_patchGhosts,
1142 std::unordered_map<
ParticleID, NNPooledParticle<Packed>>& a_particlesByID,
1143 std::unordered_map<NNCellKey, int, NNCellKeyHasher>& a_liveCellCount,
1145 const std::string& a_realm,
1146 const int a_finestLevel,
1147 const RealVect& a_probLo,
1148 const std::vector<RealVect>& a_dxByLevel,
1149 const int a_ghostWidth,
1150 const Gather& a_gather)
noexcept;
1195template <
typename P,
1205 std::unordered_map<
ParticleID, NNPooledParticle<Packed>>& a_particlesByID,
1206 std::unordered_set<ParticleID>& a_consumedIDs,
1207 std::unordered_map<NNCellKey, int, NNCellKeyHasher>& a_liveCellCount,
1208 std::vector<NNMergeResult<Packed>>& a_allResults,
1209 unsigned long long* a_crossLevelMergeCount,
1211 const std::string& a_realm,
1212 const NNCellBudget& a_cellBudget,
1213 const Combine& a_combine,
1214 const Scatter& a_scatter,
1215 const Allocator& a_allocateID,
1216 const std::optional<int> a_maxCellDistance,
1217 const PosValid& a_isPositionValid,
1218 const RealVect& a_probLo,
1219 const std::vector<RealVect>& a_dxByLevel,
1220 const std::vector<NNPatchWork>& a_patchWork,
1221 const std::vector<NNMergeEdge<Packed>>& a_pooledEdges,
1222 const std::unordered_set<ParticleID>& a_hasOutgoingCommitment,
1223 const OnMerge& a_onMergeCommitted)
noexcept;
1241template <
typename P,
1253 unsigned long long* a_crossLevelMergeCount,
1255 const NNCellBudget& a_cellBudget,
1256 const Gather& a_gather,
1257 const Combine& a_combine,
1258 const Scatter& a_scatter,
1259 const Allocator& a_allocateID,
1260 const bool a_iterateLocalTierToConvergence,
1261 const int a_maxFallbackCandidates,
1262 const std::optional<int> a_maxCellDistance,
1263 const int a_ghostWidth,
1264 const PosValid& a_isPositionValid,
1265 const OnMerge& a_onMergeCommitted);
1354template <
typename P,
1361 typename PosValid = std::function<bool(
const RealVect&)>,
1362 typename OnMerge = std::function<
1363 void(
const MergeParticle<Packed>&,
const MergeParticle<Packed>&,
const MergeParticle<Packed>&)>>
1368 const NNCellBudget& a_cellBudget,
1369 const Gather& a_gather,
1370 const Combine& a_combine,
1371 const Scatter& a_scatter,
1372 const Allocator& a_allocateID,
1373 const bool a_iterateLocalTierToConvergence =
false,
1374 const int a_maxFallbackCandidates = 0,
1375 const std::optional<int> a_maxCellDistance = std::nullopt,
1376 const int a_ghostWidth = 1,
1377 const PosValid& a_isPositionValid =
1378 [](
const RealVect&) {
1381 unsigned long long* a_crossLevelMergeCount =
nullptr,
1382 const OnMerge& a_onMergeCommitted =
1383 [](
const MergeParticle<Packed>&,
const MergeParticle<Packed>&,
const MergeParticle<Packed>&) {
1402template <
typename P,
1409 typename PosValid = std::function<bool(
const RealVect&)>,
1410 typename OnMerge = std::function<
1411 void(
const MergeParticle<Packed>&,
const MergeParticle<Packed>&,
const MergeParticle<Packed>&)>>
1416 const NNCellBudget& a_cellBudget,
1417 const Gather& a_gather,
1418 const Combine& a_combine,
1419 const Scatter& a_scatter,
1420 const Allocator& a_allocateID,
1421 const bool a_iterateLocalTierToConvergence =
false,
1422 const int a_maxFallbackCandidates = 0,
1423 const std::optional<int> a_maxCellDistance = std::nullopt,
1424 const int a_ghostWidth = 1,
1425 const PosValid& a_isPositionValid =
1426 [](
const RealVect&) {
1429 unsigned long long* a_crossLevelMergeCount =
nullptr,
1430 const OnMerge& a_onMergeCommitted =
1431 [](
const MergeParticle<Packed>&,
const MergeParticle<Packed>&,
const MergeParticle<Packed>&) {
1473template <
typename P,
1480 typename PosValid = std::function<bool(
const RealVect&)>,
1481 typename OnMerge = std::function<
1482 void(
const MergeParticle<Packed>&,
const MergeParticle<Packed>&,
const MergeParticle<Packed>&)>>
1487 const NNCellBudget& a_cellBudget,
1488 const Gather& a_gather,
1489 const Combine& a_combine,
1490 const Scatter& a_scatter,
1491 const Allocator& a_allocateID,
1492 const bool a_iterateLocalTierToConvergence =
false,
1493 const int a_maxFallbackCandidates = 0,
1494 const PosValid& a_isPositionValid =
1495 [](
const RealVect&) {
1498 unsigned long long* a_crossLevelMergeCount =
nullptr,
1499 const OnMerge& a_onMergeCommitted =
1500 [](
const MergeParticle<Packed>&,
const MergeParticle<Packed>&,
const MergeParticle<Packed>&) {
1505#include <CD_NamespaceFooter.H>
Implementation of CD_NearestNeighborParticleMerge.H.
Declaration of an AMR-hierarchy container that owns per-patch ParticleSoA leaves.
Namespace containing various particle management utilities.
Declaration of ParticleSoA, an arena-backed Struct-of-Arrays particle container.
std::int64_t ParticleID
Global particle identifier type (container-owned metadata column; fixed-width for I/O).
Definition CD_ParticleSoA.H:161
Class for handling spatial operations.
Definition CD_AmrMesh.H:45
AMR-hierarchy container of computational particles, stored per patch in Struct-of-Arrays form.
Definition CD_ParticleContainer.H:123
The per-cell particle count this merge drains each cell down to.
Definition CD_NearestNeighborParticleMerge.H:372
void reserveOne(const int a_level, const IntVect &a_cell)
Reserve one slot in a cell, lowering that cell's budget by one.
Definition CD_NearestNeighborParticleMerge.H:388
int operator()(const detail::NNCellKey &a_key) const noexcept
The budget for one cell: the uniform count less that cell's reservations, floored at 0.
Definition CD_NearestNeighborParticleMerge.H:416
NNCellBudget(const int a_uniform) noexcept
Construct a uniform budget. Deliberately implicit – a bare count is the common case.
Definition CD_NearestNeighborParticleMerge.H:378
void reserveOne(const int a_level, const RealVect &a_position, const RealVect &a_probLo, const RealVect &a_dx)
Reserve one slot in the cell a position falls in.
Definition CD_NearestNeighborParticleMerge.H:405
int minimum() const noexcept
The smallest budget any cell has.
Definition CD_NearestNeighborParticleMerge.H:435
IntVect cellKeyOf(const RealVect &a_position, const RealVect &a_probLo, const RealVect &a_dx) noexcept
The unclamped, position-derived cell index a given physical position falls in.
Definition CD_NearestNeighborParticleMergeImplem.H:254
std::pair< int, IntVect > NNCellKey
A cell key together with the AMR level it was computed on – see cellKeyOf()'s warning.
Definition CD_NearestNeighborParticleMerge.H:323
Namespace for various particle management tools.
Definition CD_KDParticleMerge.H:33
std::function< ParticleID()> IDAllocator
Illustrative signature of the fresh-id allocator: produce one globally-unique id for a newly created ...
Definition CD_NearestNeighborParticleMerge.H:278
std::function< void(const MergeParticle< Packed > &a_first, const MergeParticle< Packed > &a_second, const MergeParticle< Packed > &a_merged)> MergeCommittedCallback
Optional per-merge diagnostic callback: observe every individual merge as it commits.
Definition CD_NearestNeighborParticleMerge.H:294
void mergeNearestNeighborsOneCell(ParticleContainer< P, Traits > &a_particles, const AmrMesh &a_amr, const NNCellBudget &a_cellBudget, const Gather &a_gather, const Combine &a_combine, const Scatter &a_scatter, const Allocator &a_allocateID, const bool a_iterateLocalTierToConvergence=false, const int a_maxFallbackCandidates=0, const PosValid &a_isPositionValid=[](const RealVect &) { return true;}, unsigned long long *a_crossLevelMergeCount=nullptr, const OnMerge &a_onMergeCommitted=[](const MergeParticle< Packed > &, const MergeParticle< Packed > &, const MergeParticle< Packed > &) { })
Run one full round of the one-cell nearest-neighbor merge: the same distributed propose/judge/verdict...
Definition CD_NearestNeighborParticleMergeImplem.H:1876
void mergeNearestNeighborsHash(ParticleContainer< P, Traits > &a_particles, const AmrMesh &a_amr, const NNCellBudget &a_cellBudget, const Gather &a_gather, const Combine &a_combine, const Scatter &a_scatter, const Allocator &a_allocateID, const bool a_iterateLocalTierToConvergence=false, const int a_maxFallbackCandidates=0, const std::optional< int > a_maxCellDistance=std::nullopt, const int a_ghostWidth=1, const PosValid &a_isPositionValid=[](const RealVect &) { return true;}, unsigned long long *a_crossLevelMergeCount=nullptr, const OnMerge &a_onMergeCommitted=[](const MergeParticle< Packed > &, const MergeParticle< Packed > &, const MergeParticle< Packed > &) { })
Run one full round of the nearest-neighbor merge algorithm, identical in every respect to mergeNeares...
Definition CD_NearestNeighborParticleMergeImplem.H:1832
std::function< Packed(const Packed &a_first, const Real a_firstWeight, const Packed &a_second, const Real a_secondWeight)> PayloadCombine
Illustrative signature of the combine callback: produce a merged particle's opaque payload from its t...
Definition CD_NearestNeighborParticleMerge.H:252
void mergeNearestNeighborsTree(ParticleContainer< P, Traits > &a_particles, const AmrMesh &a_amr, const NNCellBudget &a_cellBudget, const Gather &a_gather, const Combine &a_combine, const Scatter &a_scatter, const Allocator &a_allocateID, const bool a_iterateLocalTierToConvergence=false, const int a_maxFallbackCandidates=0, const std::optional< int > a_maxCellDistance=std::nullopt, const int a_ghostWidth=1, const PosValid &a_isPositionValid=[](const RealVect &) { return true;}, unsigned long long *a_crossLevelMergeCount=nullptr, const OnMerge &a_onMergeCommitted=[](const MergeParticle< Packed > &, const MergeParticle< Packed > &, const MergeParticle< Packed > &) { })
Run one full round (one timestep's worth) of the nearest-neighbor merge algorithm.
Definition CD_NearestNeighborParticleMergeImplem.H:1788
std::function< bool(const RealVect &a_mergedPosition)> PositionValid
Illustrative signature of the position-validity predicate for a would-be merged particle.
Definition CD_NearestNeighborParticleMerge.H:266
Result of a point->block query. See findDestination.
Definition CD_LevelTiles.H:123
Hash functor for using IntVect tiles as unordered_map keys.
Definition CD_LevelTiles.H:55
Minimal, payload-agnostic description of one particle as input to a distributed merge.
Definition CD_ParticleManagement.H:430
Hash functor for NNCellKey – REQUIRED whenever NNCellKey is used as a hash-map key; NNCellKey must ne...
Definition CD_NearestNeighborParticleMerge.H:336
std::size_t operator()(const NNCellKey &a_key) const noexcept
Hash operator.
Definition CD_NearestNeighborParticleMerge.H:343
One additional ranked candidate beyond a query's primary nearest neighbor.
Definition CD_NearestNeighborParticleMerge.H:86
ParticleID candidateID
Global id of this candidate.
Definition CD_NearestNeighborParticleMerge.H:90
bool candidateIsLocal
True iff this candidate is a locally-valid particle in the SAME patch as the query (i....
Definition CD_NearestNeighborParticleMerge.H:101
Real distanceSquared
Squared distance between the query particle and this candidate.
Definition CD_NearestNeighborParticleMerge.H:95
One candidate merge edge: a single particle's own nearest-neighbor query result.
Definition CD_NearestNeighborParticleMerge.H:115
ParticleID candidateID
Global id of the candidate (query's nearest neighbor). May be a local valid particle (same patch) or ...
Definition CD_NearestNeighborParticleMerge.H:131
bool candidateIsLocal
True iff the candidate is a locally-valid particle in the SAME patch as the query (i....
Definition CD_NearestNeighborParticleMerge.H:139
Real distanceSquared
Squared distance between the query particle and its candidate.
Definition CD_NearestNeighborParticleMerge.H:119
std::vector< NNFallbackCandidate > fallbackCandidates
Next-nearest candidates beyond candidateID, in ascending distanceSquared order.
Definition CD_NearestNeighborParticleMerge.H:149
ParticleID queryID
Global id of the query particle (always locally valid/owned – ghosts never initiate a query).
Definition CD_NearestNeighborParticleMerge.H:125
A cross-patch merge proposal: one particle's own nearest-neighbor query result, bundled as a self-con...
Definition CD_NearestNeighborParticleMerge.H:163
ParticleID targetID
Global id of the particle being proposed to. Owned by the receiving (judge) rank.
Definition CD_NearestNeighborParticleMerge.H:173
MergeParticle< Packed > source
The proposer's own particle (full data) – always locally valid/owned by the sending rank.
Definition CD_NearestNeighborParticleMerge.H:168
Real distanceSquared
Squared distance between source and the target. Duplicated from the originating NNMergeEdge so the ju...
Definition CD_NearestNeighborParticleMerge.H:179
One resolved merge: the two consumed particles' ids and the newly created merged particle (not yet pl...
Definition CD_NearestNeighborParticleMerge.H:212
ParticleID secondID
Global id of the second consumed particle. For a trivial-tier result, this is the local candidate....
Definition CD_NearestNeighborParticleMerge.H:223
MergeParticle< Packed > merged
The newly created merged particle: weighted-centroid position, weighted-average opaque payload (compu...
Definition CD_NearestNeighborParticleMerge.H:231
ParticleID firstID
Global id of the first consumed particle. For a trivial-tier result, this is the query particle....
Definition CD_NearestNeighborParticleMerge.H:217
The judge's reply to one proposal.
Definition CD_NearestNeighborParticleMerge.H:190
bool accepted
True iff the judge accepted this specific proposal (i.e. it was the winning candidate for its target ...
Definition CD_NearestNeighborParticleMerge.H:202
ParticleID proposerID
Global id of the proposer this verdict is a reply to (i.e. NNMergeProposal::source's id)....
Definition CD_NearestNeighborParticleMerge.H:196
Pooled per-round record for one particle: the particle plus its cached boundary-exposure flag.
Definition CD_NearestNeighborParticleMerge.H:64
MergeParticle< Packed > particle
The pooled particle (position/weight/ids/level/payload).
Definition CD_NearestNeighborParticleMerge.H:68
bool exposed
Whether this local valid particle's cell touches a patch boundary (has ghost targets)....
Definition CD_NearestNeighborParticleMerge.H:74
Traits class that a user specializes to describe the PAYLOAD columns of a particle type....
Definition CD_ParticleSoA.H:192