29#ifndef PECLET_AMR_BLOCK_OCTREE_HPP
30#define PECLET_AMR_BLOCK_OCTREE_HPP
38#include "morton/morton.hpp"
40#include "peclet/core/common/types.hpp"
52 Index n,
typename M::code_type
p) {
66 if (M::from_code(
p).
ancestor(levels[idx]).code() == codes[idx])
76template <
int Dim,
unsigned Bits = (Dim == 2 ? 32u : (Dim == 3 ? 21u : 16u))>
79 using M = morton::Morton<Dim, Bits>;
80 using Code =
typename M::code_type;
81 using Coord =
typename M::coord_type;
82 static constexpr unsigned octants = M::octants;
104 std::array<Coord, Dim>
o{};
105 for (
int i = 0;
i < Dim; ++
i)
106 o[
i] =
static_cast<Coord>(
r[
i]) * rootSpan;
107 codes_.push_back(M::encode(
o).
code());
108 levels_.push_back(
static_cast<std::uint8_t
>(lmax_));
119 std::vector<std::uint8_t>
levels) {
123 codes_ = std::move(
codes);
124 levels_ = std::move(
levels);
130 unsigned lmax()
const {
return lmax_; }
135 unsigned level(
Index i)
const {
return levels_[
static_cast<std::size_t
>(
i)]; }
136 const std::vector<Code>&
codes()
const {
return codes_; }
137 const std::vector<std::uint8_t>&
levels()
const {
return levels_; }
148 std::array<std::array<Coord, Dim>, 2> b{};
149 auto o = M::from_code(codes_[
static_cast<std::size_t
>(
i)]).decode();
150 Coord extent =
Coord((
Coord(1) << levels_[
static_cast<std::size_t
>(
i)]) - 1);
151 for (
int d = 0; d < Dim; ++d) {
153 b[1][d] =
Coord(
o[d] + extent);
162 M probe = M::from_code(codes_[
static_cast<std::size_t
>(
i)]);
165 if (!
probe.try_add(
static_cast<unsigned>(axis), step))
168 if (!
probe.try_sub(
static_cast<unsigned>(axis), 1))
181 template <
class Pred>
183 std::vector<Code>
nc;
184 std::vector<std::uint8_t>
nl;
185 nc.reserve(codes_.size());
186 nl.reserve(levels_.size());
188 for (std::size_t k = 0; k < codes_.size(); ++k) {
189 const unsigned L = levels_[k];
190 const Code c = codes_[k];
195 nl.push_back(
static_cast<std::uint8_t
>(
L - 1));
200 nl.push_back(
static_cast<std::uint8_t
>(
L));
210 const Code target = codes_[
static_cast<std::size_t
>(
i)];
217 template <
class Pred>
219 std::vector<Code>
nc;
220 std::vector<std::uint8_t>
nl;
221 nc.reserve(codes_.size());
222 nl.reserve(levels_.size());
225 while (k < codes_.size()) {
226 const unsigned L = levels_[k];
228 if (
L < lmax_ && k +
octants <= codes_.size()) {
229 const Code parent = M::from_code(codes_[k]).ancestor(
L + 1).code();
233 M::from_code(codes_[k +
oct]).ancestor(
L + 1).code() ==
parent &&
234 M::from_code(
parent).child(
L + 1,
oct).code() == codes_[k +
oct];
238 nl.push_back(
static_cast<std::uint8_t
>(
L + 1));
245 nc.push_back(codes_[k]);
246 nl.push_back(
static_cast<std::uint8_t
>(
L));
265 for (
int d = 0; d < Dim; ++d)
266 if ((brick_[d] % 2) != 0 || (globalOrigin_[d] % 2) != 0)
284 for (
int d = 0; d < Dim; ++d) {
286 globalOrigin_[d] /= 2;
300 for (std::size_t k = 0; k < codes_.size(); ++k) {
301 const unsigned Lf = levels_[k];
302 for (
int axis = 0; axis < Dim; ++axis) {
303 for (
int dir = -1; dir <= 1; dir += 2) {
305 if (
nb >= 0 && levels_[
static_cast<std::size_t
>(
nb)] >=
Lf + 2)
306 toRefine.push_back(codes_[
static_cast<std::size_t
>(
nb)]);
324 for (std::size_t k = 0; k < codes_.size(); ++k) {
325 const unsigned Lf = levels_[k];
326 for (
int axis = 0; axis < Dim; ++axis)
327 for (
int dir = -1; dir <= 1; dir += 2) {
330 unsigned Ln = levels_[
static_cast<std::size_t
>(
nb)];
342 std::vector<Index>
ord(codes_.size());
343 for (std::size_t
i = 0;
i <
ord.size(); ++
i)
345 std::sort(
ord.begin(),
ord.end(), [&](
Index a,
Index b) { return codes_[a] < codes_[b]; });
346 std::vector<Code>
nc(codes_.size());
347 std::vector<std::uint8_t>
nl(levels_.size());
348 for (std::size_t
i = 0;
i <
ord.size(); ++
i) {
349 nc[
i] = codes_[
static_cast<std::size_t
>(
ord[
i])];
350 nl[
i] = levels_[
static_cast<std::size_t
>(
ord[
i])];
359 std::vector<Code> codes_;
360 std::vector<std::uint8_t> levels_;
Per-block adaptive octree over block-local Morton codes.
static constexpr unsigned bits()
Index find(const std::array< Coord, Dim > &fine) const
Leaf containing fine-unit coordinates, or -1.
Index balance2to1()
Enforce 2:1 (graded) balance within this block: no two face-adjacent leaves differ by more than one l...
bool isBalanced() const
True iff the leaves form a valid 2:1-balanced partition: every face neighbour differs by at most one ...
Index refineIf(Pred &&pred)
Split every leaf for which pred(code, level) is true (and level > 0) into its 2^Dim children one leve...
void assign(IVec< Dim > brick, unsigned lmax, IVec< Dim > globalOrigin, std::vector< Code > codes, std::vector< std::uint8_t > levels)
Replace the entire leaf set directly (used by load-balancing migration, which rebuilds a block from l...
bool refineLeaf(Index i)
Refine a single leaf by index. Returns true if it was split.
const IVec< Dim > & brick() const
morton::Morton< Dim, Bits > M
void liftRoot()
Lift the root one level: halve the root brick (and the block's global root origin) on every axis and ...
unsigned level(Index i) const
const IVec< Dim > & globalOrigin() const
BlockOctree(IVec< Dim > brick, unsigned lmax, IVec< Dim > globalOrigin=IVec< Dim >{})
Build a uniform block: a brick (in root cells) of leaves at level lmax.
Index coarsenIf(Pred &&pred)
Merge complete sibling groups (all 2^Dim children present, all at the same level) whose parent satisf...
Index find(Code p) const
Leaf containing Morton code p, or -1. Host wrapper over amrLocate.
const std::vector< std::uint8_t > & levels() const
void init(IVec< Dim > brick, unsigned lmax, IVec< Dim > globalOrigin=IVec< Dim >{})
const std::vector< Code > & codes() const
std::array< std::array< Coord, Dim >, 2 > bounds(Index i) const
Inclusive integer bounds [lo, hi] of leaf i in fine units.
typename M::coord_type Coord
typename M::code_type Code
static constexpr unsigned octants
bool canLiftRoot() const
True iff the root brick can be halved on every axis: brick() and globalOrigin() both even everywhere.
Index faceNeighbor(Index i, int axis, int dir) const
The leaf across leaf i's face on axis in direction dir (±1), or -1 if it lies outside the block.
Index amrLocate(const typename M::code_type *codes, const std::uint8_t *levels, Index n, typename M::code_type p)
Locate the leaf containing Morton code p in sorted leaf arrays.
std::vector< std::array< double, Dim > > transferFieldGradients(const BlockOctree< Dim, Bits > &oldT, const std::vector< double > &oldF)
Per-old-leaf minmod prolongation gradients (per fine-coordinate unit) — transferField's stencil,...