|
core 1.5.0
Shared MPI block decomposition, asynchronous ghost-layer exchange, SDF geometry, load balancing (header-only C++20)
|
Namespaces | |
| namespace | detail |
Classes | |
| struct | AlignedWeightedChoice |
What chooseAlignedWeighted returns: the partition, the alignment exponent a (align = 2^a on every axis; 0 = the plain weighted ORB) and that partition's weightImbalance, for logging. More... | |
| struct | Block |
| A rank-owned axis-aligned block of the global cell grid. More... | |
| class | BlockDecomposer |
Orthogonal recursive bisection of a Dim-dimensional global cell grid into numBlocks axis-aligned blocks; by the suite's convention block b is owned by rank b. More... | |
| class | BlockIndexer |
| class | MortonIndexer |
| Z-order (Morton) indexer over an axis-origin-relative cell block. More... | |
| class | RedistributeTopology |
| The planned, repeatable movement of a multigrid level's fields onto a stage target and back (the file comment has the per-kind collectives and the layout contract). More... | |
| struct | SiblingMergeChoice |
A sibling merge the search chose: the tree depth it truncates at, the merged decomposition, and its maps (agglomerated(depth, &groupOf, &ownerOf)). More... | |
| struct | StageComm |
The communicators of one coarse-level multigrid stage, made by makeStageComm (the file comment spells out group and sub per StageKind). More... | |
| struct | StageTarget |
| Where a level goes: the result of chooseStageTarget / repartitionTarget. More... | |
Enumerations | |
| enum class | StageKind { InPlace , SiblingMerge , Repartition , Replicated } |
| How a multigrid level moves when it can no longer coarsen in place (see chooseStageTarget and the file comment for the movement each kind implies). More... | |
Functions | |
| template<int Dim> | |
| Real | weightImbalance (const BlockDecomposer< Dim > &dec, const std::vector< Real > &weights) |
Weight imbalance of a decomposition — the balancer's own metric: the heaviest block's total weight over the mean, max_b W(b) / (W_total / numBlocks). | |
| template<std::size_t N, int Dim = static_cast<int>(N)> | |
| AlignedWeightedChoice< Dim > | chooseAlignedWeighted (std::size_t numBlocks, const std::array< Index, N > &G, const std::vector< Real > &weights, Real budget=1.05, int aMax=std::numeric_limits< int >::max()) |
Choose the alignment of a weighted ORB from an imbalance budget (amr/docs/ amr_mg_core_boundary.md §11.4): the LARGEST a whose coarse-first aligned weighted ORB (init(numBlocks, G, weights, {2^a,…})) has weightImbalance <= budget, else a = 0 with today's partition, init(numBlocks, G, weights), bit for bit — never worse than now. | |
| template<class T > | |
| void | gatherByGlobalId (const std::vector< long long > &ids, const std::vector< T > &vals, long long nGlobal, std::vector< T > &out, MPI_Comm comm) |
ids[i] is the global id of vals[i] on this rank. | |
| template<class T > | |
| void | redistributeGridFields (const BlockDecomposer< 3 > &oldDec, const BlockDecomposer< 3 > &newDec, int rank, int g, const std::vector< const T * > &oldFields, const std::vector< T * > &newFields, MPI_Comm comm) |
Redistribute nFields grid fields from oldDec to newDec (this rank = rank). | |
| template<int Dim> | |
| StageComm | makeStageComm (MPI_Comm parent, const StageTarget< Dim > &t) |
Build the stage communicators for t on parent. | |
| template<int Dim> | |
| Index | minBlockExtent (const BlockDecomposer< Dim > &d) |
| Smallest block extent over every block and axis — replicated, like the decomposition. | |
| template<int Dim> | |
| Index | largestBlockCells (const BlockDecomposer< Dim > &d) |
| Cell count of the largest block — replicated, like the decomposition. | |
| template<int Dim, class Liftable > | |
| std::optional< SiblingMergeChoice< Dim > > | shallowestLiftableMerge (const BlockDecomposer< Dim > &cur, Liftable &&liftable, int minExtent) |
| The sibling-merge SEARCH on its own, with no trigger: the shallowest merge — fewest merges, i.e. | |
| template<int Dim, class Liftable > | |
| std::optional< StageTarget< Dim > > | repartitionTarget (const BlockDecomposer< Dim > &cur, const std::type_identity_t< IVec< Dim > > &levelGrid, Liftable &&liftable, int minExtent, Index maxBlockCells) |
| The Repartition candidate (design §11.2): a fresh proportional, unweighted, unaligned ORB of the level grid on the first np_L parent ranks, or std::nullopt when none lifts. | |
| template<int Dim, class Liftable > | |
| StageTarget< Dim > | chooseStageTarget (const BlockDecomposer< Dim > &cur, const std::type_identity_t< IVec< Dim > > &levelGrid, Liftable &&liftable, int minExtent, Index maxBlockCells=0) |
Choose the stage target of a level whose current decomposition is cur over the level grid levelGrid (which must equal cur.globalSize()). | |
How a multigrid level moves when it can no longer coarsen in place (see chooseStageTarget and the file comment for the movement each kind implies).
Definition at line 43 of file stage_target.hpp.
| Real peclet::core::decomp::weightImbalance | ( | const BlockDecomposer< Dim > & | dec, |
| const std::vector< Real > & | weights | ||
| ) |
Weight imbalance of a decomposition — the balancer's own metric: the heaviest block's total weight over the mean, max_b W(b) / (W_total / numBlocks).
Each block's weight is summed over its box x-fastest and W_total is the sum of the block weights in block order, so the value is a pure function of (dec, weights). A field whose total is not positive has no defined imbalance and returns +infinity (no budget can be certified against it). Precondition: weights covers dec.globalSize() x-fastest (unchecked). No communication; replicated when its inputs are.
Definition at line 560 of file block_decomposer.hpp.
References peclet::core::decomp::BlockDecomposer< Dim >::linearGlobal(), peclet::core::decomp::BlockDecomposer< Dim >::numBlocks(), peclet::core::decomp::BlockDecomposer< Dim >::origins(), and peclet::core::decomp::BlockDecomposer< Dim >::sizes().
Referenced by chooseAlignedWeighted().
| AlignedWeightedChoice< Dim > peclet::core::decomp::chooseAlignedWeighted | ( | std::size_t | numBlocks, |
| const std::array< Index, N > & | G, | ||
| const std::vector< Real > & | weights, | ||
| Real | budget = 1.05, |
||
| int | aMax = std::numeric_limits<int>::max() |
||
| ) |
Choose the alignment of a weighted ORB from an imbalance budget (amr/docs/ amr_mg_core_boundary.md §11.4): the LARGEST a whose coarse-first aligned weighted ORB (init(numBlocks, G, weights, {2^a,…})) has weightImbalance <= budget, else a = 0 with today's partition, init(numBlocks, G, weights), bit for bit — never worse than now.
A pure function of its arguments (weights is the global field on every rank), so every rank returns the same answer without communicating.
Candidates run from aMax down to 1, where aMax is capped by the caller's value, by every axis's factors of two (G[k] % 2^a == 0), and by the coarse grid still holding the blocks: Π_k G[k]/2^a >= numBlocks and every G[k]/2^a >= 2. The default aMax imposes no cap of its own. A candidate with an empty block is rejected whatever its imbalance (an empty block weighs nothing, so the metric alone would not see it). (G is spelled as the std::array that IVec<Dim> is, so Dim deduces from it.)
Preconditions (as the aligned weighted init, assert-checked only): weights covers G x-fastest. A budget below 1 can never be met (for non-negative weights the imbalance is >= 1) and always yields a = 0.
Definition at line 607 of file block_decomposer.hpp.
References peclet::core::decomp::AlignedWeightedChoice< Dim >::a, peclet::core::decomp::AlignedWeightedChoice< Dim >::dec, peclet::core::decomp::AlignedWeightedChoice< Dim >::imbalance, and weightImbalance().
| void peclet::core::decomp::gatherByGlobalId | ( | const std::vector< long long > & | ids, |
| const std::vector< T > & | vals, | ||
| long long | nGlobal, | ||
| std::vector< T > & | out, | ||
| MPI_Comm | comm | ||
| ) |
ids[i] is the global id of vals[i] on this rank.
On return out (size nGlobal, on every rank) holds out[id] = the value some rank contributed for id. The ids over all ranks must be a permutation of [0, nGlobal) — each id exactly once — or this throws (on every rank). Collective on comm: one Allgather of the counts, one Allgatherv each of ids and values. T must be trivially copyable (it travels as raw bytes).
Throws std::invalid_argument when the ids are not such a permutation — decided on the gathered, replicated data, so on every rank alike — and std::overflow_error when the global vector exceeds INT_MAX entries or bytes (also every rank alike). Two checks are rank-LOCAL and run before the first collective: ids.size() != vals.size() (std::invalid_argument) and a single rank's contribution exceeding INT_MAX bytes (std::overflow_error); a throw there leaves the other ranks waiting in the Allgather, so treat it as fatal.
Definition at line 31 of file gather_by_global_id.hpp.
References MPI_BYTE, MPI_Comm_size(), and MPI_INT.
| void peclet::core::decomp::redistributeGridFields | ( | const BlockDecomposer< 3 > & | oldDec, |
| const BlockDecomposer< 3 > & | newDec, | ||
| int | rank, | ||
| int | g, | ||
| const std::vector< const T * > & | oldFields, | ||
| const std::vector< T * > & | newFields, | ||
| MPI_Comm | comm | ||
| ) |
Redistribute nFields grid fields from oldDec to newDec (this rank = rank).
oldFields[f] is the old padded local buffer, newFields[f] the (caller-allocated) new padded local buffer, both with ghost width g (layout in the file comment). Dim == 3. Only inner cells move; ghosts of the new buffers are not written, so refill them with a halo exchange.
Collective on comm (one NBX round): every rank calls it, with the same replicated oldDec and newDec. Preconditions: rank < oldDec.numBlocks() (every rank sends its old block). newDec may have FEWER blocks than ranks — a rank without a new block only sends, and its newFields are not touched (may be empty). Pure copies: every value arrives bitwise.
Definition at line 83 of file grid_redistribute.hpp.
References peclet::core::decomp::detail::boxCellCount(), and peclet::core::decomp::detail::forBox().
| StageComm peclet::core::decomp::makeStageComm | ( | MPI_Comm | parent, |
| const StageTarget< Dim > & | t | ||
| ) |
Build the stage communicators for t on parent.
Collective on parent, whose size must equal the number of current blocks (t.groupOf.size() for SiblingMerge); every rank passes the same replicated t (chooseStageTarget's result). Parent rank r is taken to own current block r.
Throws std::invalid_argument for an InPlace target (there is no stage), a SiblingMerge groupOf that does not map one block per rank, or a malformed Repartition target (not 1..size blocks, owners not the identity, or a non-empty groupOf); std::logic_error when a merge group's owner is not its lowest rank. The std::invalid_argument checks read only t and the size of parent, so with a replicated t they fire on every rank alike, before any communication. The std::logic_error (a broken agglomerated invariant, not a caller error) fires after the splits and on the offending group's ranks only: treat it as fatal.
Definition at line 105 of file stage_comm.hpp.
References peclet::core::decomp::StageComm::active, peclet::core::decomp::StageComm::group, InPlace, peclet::core::decomp::StageComm::kind, peclet::core::decomp::StageComm::members, MPI_Comm_rank(), MPI_Comm_size(), MPI_UNDEFINED, peclet::core::decomp::StageComm::myGroup, peclet::core::decomp::StageComm::myTargetBlock, peclet::core::decomp::StageComm::parent, Repartition, SiblingMerge, and peclet::core::decomp::StageComm::sub.
|
inline |
Smallest block extent over every block and axis — replicated, like the decomposition.
Definition at line 69 of file stage_target.hpp.
Referenced by chooseStageTarget(), and shallowestLiftableMerge().
|
inline |
Cell count of the largest block — replicated, like the decomposition.
Definition at line 79 of file stage_target.hpp.
Referenced by chooseStageTarget().
| std::optional< SiblingMergeChoice< Dim > > peclet::core::decomp::shallowestLiftableMerge | ( | const BlockDecomposer< Dim > & | cur, |
| Liftable && | liftable, | ||
| int | minExtent | ||
| ) |
The sibling-merge SEARCH on its own, with no trigger: the shallowest merge — fewest merges, i.e.
the LARGEST depth d in [0, treeDepth) — whose agglomerated(d)
liftable, the method's predicate),cur, andchooseStageTarget calls it behind the trigger. A caller that must merge whatever the trigger says calls it directly: that is how flow's test-only forced telescope (teleForce_ == L, which runs the search even where in-place coarsening is legal) maps onto core, so the policy's own signature carries no test hook.
Pure: no communication, replicated whenever cur and liftable are. Throws nothing of its own; an exception from liftable propagates.
Definition at line 115 of file stage_target.hpp.
References minBlockExtent().
Referenced by chooseStageTarget().
| std::optional< StageTarget< Dim > > peclet::core::decomp::repartitionTarget | ( | const BlockDecomposer< Dim > & | cur, |
| const std::type_identity_t< IVec< Dim > > & | levelGrid, | ||
| Liftable && | liftable, | ||
| int | minExtent, | ||
| Index | maxBlockCells | ||
| ) |
The Repartition candidate (design §11.2): a fresh proportional, unweighted, unaligned ORB of the level grid on the first np_L parent ranks, or std::nullopt when none lifts.
np_L starts at as many ranks as the level's size justifies at maxBlockCells cells per rank, n = ceil(cells(levelGrid) / maxBlockCells), capped, when the extent rule is on (minExtent > 0), at prod_k max(1, floor(levelGrid[k] / (2*minExtent))) — blocks fat enough to survive the halving that follows (no cap at minExtent == 0) — and is then ROUNDED UP to a power of two and clamped to the current rank count: np_L = min(cur.numBlocks(), nextPow2(n)). Rounding up never violates the invariant (more ranks, smaller blocks), and a power-of-two block count on a grid with factors of two keeps lifting level after level instead of only once (np_L = 5 or 6 on the §6 heap / flat-bed fixtures lifted once and staged again at the next level; they now get 8). The round-up never overshoots the extent cap: if it would (a cap that is not a power of two), np_L drops to the largest power of two within the cap, since the cap is what keeps blocks fat enough. Then np_L, the largest power of two <= np_L (when np_L is not one — a non-power-of-two rank count) and its halvings down to 1 are tried in turn, and the first proportional ORB that lifts is returned. Owners are the identity on [0, n); groupOf is empty. A pure function, replicated on every rank.
Preconditions: levelGrid == cur.globalSize() (checked by chooseStageTarget, NOT here) and maxBlockCells > 0 — throws std::invalid_argument otherwise.
Definition at line 153 of file stage_target.hpp.
References Repartition.
Referenced by chooseStageTarget().
| StageTarget< Dim > peclet::core::decomp::chooseStageTarget | ( | const BlockDecomposer< Dim > & | cur, |
| const std::type_identity_t< IVec< Dim > > & | levelGrid, | ||
| Liftable && | liftable, | ||
| int | minExtent, | ||
| Index | maxBlockCells = 0 |
||
| ) |
Choose the stage target of a level whose current decomposition is cur over the level grid levelGrid (which must equal cur.globalSize()).
liftable(const BlockDecomposer<Dim>&) -> bool is the METHOD's predicate: "every block can
coarsen in place one more time". minExtent is the economic trigger (0 disables it): a level whose smallest block extent is below it is staged even when it could still coarsen in place, and a merged candidate with more than one block must keep an extent of at least 2*minExtent. maxBlockCells is the caller's "a rank never holds more cells of a coarse level than it holds
of its finest level" — the finest level's largest block, replicated; 0 disables Repartition.
Order (design §11.1):
cur has one block, or when liftable(cur) and no block is below minExtent;Note what stays with the CALLER, because it is the method's rule, not core's: flow stages only when telescoping is enabled and some axis of the level grid can still coarsen at all. With no coarsenable axis flow's predicate is vacuously true, and a level below minExtent would otherwise be sent to step 2. flow's forced telescope calls shallowestLiftableMerge directly.
What also stays in flow at S4: the outflow ghost-plane gathers (teleGatherOutflowPlanes / teleGatherPlane, WO-R2) — they move the plane beyond the inner block on the global outflow face, which the inner-cell RedistributeTopology does not describe.
Pure: no communication. Every rank passing the same (replicated) cur, minExtent and maxBlockCells, and a liftable that answers alike, gets the same target — which is what makeStageComm and RedistributeTopology::build rely on. Throws std::invalid_argument when levelGrid != cur.globalSize() or maxBlockCells < 0; since both are replicated inputs, it throws on every rank alike.
Definition at line 246 of file stage_target.hpp.
References InPlace, largestBlockCells(), minBlockExtent(), repartitionTarget(), Replicated, shallowestLiftableMerge(), and SiblingMerge.