6#ifndef PECLET_CORE_DECOMP_BLOCK_DECOMPOSER_HPP
7#define PECLET_CORE_DECOMP_BLOCK_DECOMPOSER_HPP
51 for (
int i = 0;
i <
Dim; ++
i)
64 for (
int i = 0;
i <
Dim; ++
i)
91 for (int i = 0; i < Dim; ++i)
95 "weights array must cover the global grid (x-fastest)");
97 for (
int i = 0;
i <
Dim; ++
i)
128 for (
int k = 0;
k <
Dim; ++
k) {
129 assert(
align[
k] >= 1 &&
"aligned weighted init(): align must be >= 1");
131 "aligned weighted init(): globalSize must be a multiple of align");
138 std::vector<Real>
wc(
static_cast<std::size_t
>(nc), 0.0);
145 for (int i = 0; i < Dim; ++i)
149 "weights array must cover the global grid (x-fastest)");
153 for (
int k = 0;
k <
Dim; ++
k) {
158 const std::size_t
ic =
static_cast<std::size_t
>(
coarse.linearGlobal(c));
171 std::size_t
numBlocks()
const {
return origins_.size(); }
175 const std::vector<IVec<Dim>>&
origins()
const {
return origins_; }
177 const std::vector<IVec<Dim>>&
sizes()
const {
return sizes_; }
185 while (tree_[
node].splitDim != -1) {
188 return static_cast<int>(tree_[
node].splitValue);
197 splitDim.resize(tree_.size());
199 for (std::size_t
i = 0;
i < tree_.size(); ++
i) {
200 splitDim[
i] = tree_[
i].splitDim;
208 for (
int i =
Dim - 2;
i >= 0; --
i) {
209 idx *= globalSize_[
i];
218 for (
int i = 0;
i <
Dim; ++
i) {
219 g[
i] = lin % globalSize_[
i];
220 lin /= globalSize_[
i];
233 for (
int k = 0;
k <
Dim; ++
k) {
235 "coarsened(): global size not divisible by ratio (build the decomposition aligned)");
236 c.globalSize_[
k] = globalSize_[
k] /
ratio[
k];
240 for (
auto&
nd : c.tree_)
241 if (
nd.splitDim != -1) {
243 "coarsened(): split not divisible by ratio (build the decomposition aligned)");
246 c.origins_.resize(origins_.size());
247 c.sizes_.resize(sizes_.size());
248 for (std::size_t b = 0; b < origins_.size(); ++b)
249 for (
int k = 0;
k <
Dim; ++
k) {
251 "coarsened(): block origin/size not divisible by ratio (build aligned)");
252 c.origins_[b][
k] = origins_[b][
k] /
ratio[
k];
253 c.sizes_[b][
k] = sizes_[b][
k] /
ratio[
k];
274 for (
int k = 0;
k <
Dim; ++
k) {
275 assert(
ratio[
k] >= 1 &&
"refined(): ratio must be >= 1");
276 f.globalSize_[
k] = globalSize_[
k] *
ratio[
k];
278 f.cellExtent_[
k] = 1;
281 for (
auto&
nd :
f.tree_)
282 if (
nd.splitDim != -1)
284 f.origins_.resize(origins_.size());
285 f.sizes_.resize(sizes_.size());
286 for (std::size_t b = 0; b < origins_.size(); ++b)
287 for (
int k = 0;
k <
Dim; ++
k) {
288 f.origins_[b][
k] = origins_[b][
k] *
ratio[
k];
289 f.sizes_[b][
k] = sizes_[b][
k] *
ratio[
k];
297 Index splitValue = 0;
305 depthWalk(0, 0,
best);
322 std::vector<int>*
rootOf =
nullptr)
const {
323 assert(depth >= 0 &&
"agglomerated(): depth must be >= 0");
325 a.globalSize_ = globalSize_;
327 a.cellExtent_ = cellExtent_;
328 a.tree_.assign(tree_.size(), TreeNode{});
329 std::vector<int>
gmap(origins_.size(), -1);
330 std::vector<int>
roots;
332 a.tree_.resize(prunedSize(a.tree_));
342 if (
node >=
static_cast<Index>(tree_.size()))
344 if (tree_[
node].splitDim == -1) {
353 void leavesUnder(
Index node, std::vector<int>&
out)
const {
354 if (tree_[
node].splitDim == -1) {
355 out.push_back(
static_cast<int>(tree_[
node].splitValue));
358 leavesUnder(2 *
node + 1,
out);
359 leavesUnder(2 *
node + 2,
out);
363 const TreeNode&
nd = tree_[
node];
364 if (
nd.splitDim == -1 ||
d == depth) {
366 const int newIdx =
static_cast<int>(a.origins_.size());
368 a.origins_.push_back(origin);
369 a.sizes_.push_back(size);
383 lsize[
nd.splitDim] =
nd.splitValue - origin[
nd.splitDim];
385 rsize[
nd.splitDim] = origin[
nd.splitDim] + size[
nd.splitDim] -
nd.splitValue;
389 static std::size_t prunedSize(
const std::vector<TreeNode>&
t) {
392 std::size_t
last = 0;
393 std::vector<Index>
stack{0};
394 while (!
stack.empty()) {
397 if (n >=
static_cast<Index>(
t.size()))
399 if (
static_cast<std::size_t
>(n) >
last)
400 last =
static_cast<std::size_t
>(n);
401 if (
t[n].splitDim != -1) {
402 stack.push_back(2 * n + 1);
403 stack.push_back(2 * n + 2);
420 const std::vector<Real>*
weights)
const;
426 std::vector<IVec<Dim>> origins_;
427 std::vector<IVec<Dim>> sizes_;
428 std::vector<TreeNode> tree_;
432void BlockDecomposer<Dim>::initImpl(std::size_t numBlocks,
IVec<Dim> globalSize,
433 const std::vector<Real>*
weights) {
434 globalSize_ = globalSize;
435 for (
int k = 0;
k <
Dim; ++
k)
436 if (cellExtent_[
k] <= 0)
448 std::stack<StackBlock>
stack;
452 while (!
stack.empty()) {
456 if (
static_cast<std::size_t
>(
cur.treeIndx) >= tree_.size()) {
457 tree_.resize(
cur.treeIndx + 1);
460 if (
cur.numSub > 1) {
467 for (
int k = 1;
k <
Dim; ++
k) {
490 left.treeIndx = 2 *
cur.treeIndx + 1;
496 right.treeIndx = 2 *
cur.treeIndx + 2;
503 origins_.push_back(
cur.origin);
504 sizes_.push_back(
cur.size);
512 const std::vector<Real>*
weights)
const {
517 if (
weights ==
nullptr || n <= 1) {
518 return static_cast<Index>(std::round(
static_cast<double>(n) *
static_cast<double>(
numSub) /
524 std::vector<double>
slab(
static_cast<std::size_t
>(n), 0.0);
526 for (
int i = 0;
i <
Dim; ++
i)
527 end[
i] = origin[
i] + size[
i];
533 for (
double w :
slab)
540 double bestDist = std::numeric_limits<double>::max();
542 for (
Index s = 1; s < n; ++s) {
543 cum +=
slab[
static_cast<std::size_t
>(s - 1)];
563 for (std::size_t b = 0; b <
nb; ++b) {
565 for (
int k = 0;
k <
Dim; ++
k)
572 if (b == 0 || w >
hi)
576 return std::numeric_limits<Real>::infinity();
577 return hi / (
total /
static_cast<double>(
nb));
608 const std::array<Index, N>&
G,
609 const std::vector<Real>&
weights,
611 int aMax = std::numeric_limits<int>::max()) {
613 for (
int k = 0;
k <
Dim; ++
k) {
615 for (
Index g =
G[
k]; g > 0 && g % 2 == 0; g /= 2)
621 const int a =
top + 1;
624 for (
int k = 0;
k <
Dim; ++
k) {
628 cells *=
static_cast<double>(
gk);
630 if (!ok || cells <
static_cast<double>(numBlocks))
634 for (
int a =
top; a >= 1; --a) {
636 for (
int k = 0;
k <
Dim; ++
k)
641 for (
const auto&
sz : c.
dec.sizes())
642 for (
int k = 0;
k <
Dim; ++
k)
Orthogonal recursive bisection of a Dim-dimensional global cell grid into numBlocks axis-aligned bloc...
void flattenTree(std::vector< int > &splitDim, std::vector< Index > &splitVal) const
Flatten the implicit ORB tree into two parallel arrays for a device-callable ownerOf: for node i,...
Block< Dim > block(std::size_t b) const
Block b as (origin, size). Precondition: b < numBlocks() (unchecked).
const std::vector< IVec< Dim > > & sizes() const
Extent in cells of every block, indexed by block.
int treeDepth() const
Depth of the deepest leaf of the ORB tree (root = 0).
void init(std::size_t numBlocks, IVec< Dim > globalSize, const IVec< Dim > &align, const IVec< Dim > &cellExtent)
Anisotropic-cell aligned ORB: cellExtent[k] is how many underlying FINE cells one cell of this grid s...
void init(std::size_t numBlocks, IVec< Dim > globalSize)
Build the decomposition of a globalSize cell grid into numBlocks blocks (equal cell count).
BlockDecomposer(std::size_t numBlocks, IVec< Dim > globalSize, const std::vector< Real > &weights)
Weighted ORB: see init(numBlocks, globalSize, weights).
const std::vector< IVec< Dim > > & origins() const
Inclusive lower corner of every block, in global cell coordinates, indexed by block.
const IVec< Dim > & globalSize() const
Global grid size in cells per axis.
BlockDecomposer< Dim > agglomerated(int depth, std::vector< int > *groupOf=nullptr, std::vector< int > *rootOf=nullptr) const
Coarse-level TELESCOPING: the decomposition obtained by merging ORB siblings — truncate the bisection...
void init(std::size_t numBlocks, IVec< Dim > globalSize, const IVec< Dim > &align)
Aligned ORB: force every split position (and hence every block origin/size) on axis k to be a multipl...
void init(std::size_t numBlocks, IVec< Dim > globalSize, const std::vector< Real > &weights)
Weighted ORB: balance the total weight per block instead of the cell count.
std::size_t numBlocks() const
Number of blocks.
BlockDecomposer()=default
BlockDecomposer(std::size_t numBlocks, IVec< Dim > globalSize)
Equal-cell-count ORB: see init(numBlocks, globalSize).
Index linearGlobal(const IVec< Dim > &g) const
Global multi-index -> global linear index (x-fastest: I = x + y*nx + z*nx*ny).
BlockDecomposer< Dim > refined(const IVec< Dim > &ratio) const
Derive the NESTED fine decomposition: the exact inverse of coarsened() — global size,...
BlockDecomposer(std::size_t numBlocks, IVec< Dim > globalSize, const IVec< Dim > &align)
Aligned ORB (coarsenable): see the aligned init() below.
int ownerOf(const IVec< Dim > &g) const
Owning block index of a global cell coordinate. Caller must wrap into [0, globalSize) first.
BlockDecomposer< Dim > coarsened(const IVec< Dim > &ratio) const
Derive the NESTED coarse decomposition: each block, split value and the global size divided by ratio ...
IVec< Dim > multiGlobal(Index lin) const
Global linear index -> global multi-index (inverse of linearGlobal).
void init(std::size_t numBlocks, IVec< Dim > globalSize, const std::vector< Real > &weights, const IVec< Dim > &align)
Aligned weighted ORB — COARSE-FIRST, never snap-after (amr/docs/amr_mg_core_boundary....
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 ov...
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....
Kokkos::View< T *, MemSpace > View
1D device array.
double Real
Default host floating type. Device kernels may use float; conversions happen at the boundary.
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
What chooseAlignedWeighted returns: the partition, the alignment exponent a (align = 2^a on every axi...
Real imbalance
weightImbalance(dec, weights)
BlockDecomposer< Dim > dec
the chosen partition
int a
alignment exponent: align = 2^a on every axis (0 = unaligned)
A rank-owned axis-aligned block of the global cell grid.
IVec< Dim > size
extent in cells along each axis
IVec< Dim > origin
inclusive lower corner in global cell coordinates