22#ifndef PECLET_CORE_AMR_ADAPT_HPP
23#define PECLET_CORE_AMR_ADAPT_HPP
25#ifdef PECLET_CORE_HAVE_MORTON
39inline double minmod(
double a,
double b) {
42 return (std::fabs(a) < std::fabs(b)) ? a : b;
49template <
int Dim,
unsigned Bits>
51 const std::vector<double>& oldF,
54 using Code =
typename BO::Code;
55 using Coord =
typename BO::Coord;
56 using M =
typename BO::M;
58 auto centroid = [](
const BO& t,
Index i) {
59 auto o = M::from_code(t.code(i)).decode();
60 const double s =
static_cast<double>(Coord(1) << t.level(i));
61 std::array<double, Dim> c{};
62 for (
int d = 0; d < Dim; ++d)
63 c[d] =
static_cast<double>(o[d]) + 0.5 * s;
69 std::vector<std::array<double, Dim>> grad;
71 grad.assign(
static_cast<std::size_t
>(no), std::array<double, Dim>{});
72 for (
Index i = 0; i < no; ++i) {
73 auto ci = centroid(oldT, i);
74 const double ui = oldF[
static_cast<std::size_t
>(i)];
75 for (
int axis = 0; axis < Dim; ++axis) {
80 auto cp = centroid(oldT, jp);
81 auto cm = centroid(oldT, jm);
82 const double sp = (oldF[
static_cast<std::size_t
>(jp)] - ui) / (cp[axis] - ci[axis]);
83 const double sm = (ui - oldF[
static_cast<std::size_t
>(jm)]) / (ci[axis] - cm[axis]);
90 std::vector<double> nf(
static_cast<std::size_t
>(nn), 0.0);
91 std::vector<Index> n2o(
static_cast<std::size_t
>(nn), -1);
92 for (
Index j = 0; j < nn; ++j) {
93 const Code cj = newT.
code(j);
94 const unsigned Lj = newT.
level(j);
98 const unsigned Lo = oldT.
level(o);
100 nf[
static_cast<std::size_t
>(j)] = oldF[
static_cast<std::size_t
>(o)];
101 }
else if (Lo > Lj) {
103 n2o[
static_cast<std::size_t
>(j)] = o;
105 nf[
static_cast<std::size_t
>(j)] = oldF[
static_cast<std::size_t
>(o)];
107 auto co = centroid(oldT, o);
108 auto cn = centroid(newT, j);
109 double v = oldF[
static_cast<std::size_t
>(o)];
110 for (
int d = 0; d < Dim; ++d)
111 v += grad[
static_cast<std::size_t
>(o)][d] * (cn[d] - co[d]);
112 nf[
static_cast<std::size_t
>(j)] = v;
117 auto oj = M::from_code(cj).decode();
118 const Coord sj = Coord(Coord(1) << Lj);
119 double vol = 0.0, acc = 0.0;
120 for (
Index k = o; k < no; ++k) {
121 auto ok = M::from_code(oldT.
code(k)).decode();
123 for (
int d = 0; d < Dim; ++d)
124 if (ok[d] < oj[d] || ok[d] >= oj[d] + sj) {
130 const double w = std::pow(2.0,
static_cast<double>(Dim *
static_cast<int>(oldT.
level(k))));
131 acc += w * oldF[
static_cast<std::size_t
>(k)];
134 nf[
static_cast<std::size_t
>(j)] = (vol > 0.0) ? acc / vol : 0.0;
144 std::vector<double> sv(
static_cast<std::size_t
>(no), 0.0),
145 vv(
static_cast<std::size_t
>(no), 0.0);
146 for (
Index j = 0; j < nn; ++j) {
147 const Index o = n2o[
static_cast<std::size_t
>(j)];
150 const double w = std::pow(2.0,
static_cast<double>(Dim *
static_cast<int>(newT.
level(j))));
151 sv[
static_cast<std::size_t
>(o)] += w * nf[
static_cast<std::size_t
>(j)];
152 vv[
static_cast<std::size_t
>(o)] += w;
154 for (
Index j = 0; j < nn; ++j) {
155 const Index o = n2o[
static_cast<std::size_t
>(j)];
156 if (o < 0 || vv[
static_cast<std::size_t
>(o)] <= 0.0)
158 nf[
static_cast<std::size_t
>(j)] +=
159 oldF[
static_cast<std::size_t
>(o)] -
160 sv[
static_cast<std::size_t
>(o)] / vv[
static_cast<std::size_t
>(o)];
171template <
int Dim,
unsigned Bits>
173 double refineThresh,
double coarsenThresh,
174 unsigned finestLevel = 0) {
176 std::vector<int> f(
static_cast<std::size_t
>(n),
kKeep);
177 for (
Index i = 0; i < n; ++i) {
178 const unsigned L = t.
level(i);
179 const double e = ind[
static_cast<std::size_t
>(i)];
180 if (e > refineThresh && L > finestLevel)
181 f[
static_cast<std::size_t
>(i)] =
kRefine;
182 else if (e < coarsenThresh && L < t.
lmax())
183 f[
static_cast<std::size_t
>(i)] =
kCoarsen;
188template <
int Dim,
unsigned Bits>
198template <
int Dim,
unsigned Bits>
200 const std::vector<int>& flags,
bool linear =
true) {
202 using Code =
typename BO::Code;
203 using M =
typename BO::M;
206 nt.
coarsenIf([&](Code parent,
unsigned pl) {
207 for (
unsigned oct = 0; oct < (1u << Dim); ++oct) {
208 Code cc = M::from_code(parent).child(pl, oct).code();
210 if (ci < 0 || flags[
static_cast<std::size_t
>(ci)] !=
kCoarsen)
216 nt.refineIf([&](Code c,
unsigned) {
218 return ci >= 0 && flags[
static_cast<std::size_t
>(ci)] ==
kRefine;
226template <
int Dim,
unsigned Bits>
228 double refineThresh,
double coarsenThresh,
unsigned finestLevel = 0,
229 double eps = 0.01,
bool linear =
true) {
231 auto flags =
flagByIndicator(t, ind, refineThresh, coarsenThresh, finestLevel);
Per-block adaptive octree over block-local Morton codes.
Index coarsenIf(Pred &&pred)
Merge complete sibling groups (all 2^Dim children present, all at the same level) whose parent satisf...
unsigned level(Index i) const
Index find(Code p) const
Leaf containing Morton code p, or -1. Host wrapper over amrLocate.
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.
double minmod(double a, double b)
std::vector< int > flagByIndicator(const BlockOctree< Dim, Bits > &t, const std::vector< double > &ind, double refineThresh, double coarsenThresh, unsigned finestLevel=0)
AdaptResult< Dim, Bits > adaptField(const BlockOctree< Dim, Bits > &t, const std::vector< double > &f, const std::vector< int > &flags, bool linear=true)
Apply adaptation flags (one level of refine/coarsen) to t carrying field f, then 2:1-balance and rema...
AdaptFlag
Per-leaf adaptation flags from an indicator: refine where ind > refineThresh (and the leaf can go fin...
std::vector< double > transferField(const BlockOctree< Dim, Bits > &oldT, const std::vector< double > &oldF, const BlockOctree< Dim, Bits > &newT, bool linear=true)
Conservative remap of a leaf field from oldT to newT (same domain).
AdaptResult< Dim, Bits > adapt(const BlockOctree< Dim, Bits > &t, const std::vector< double > &f, double refineThresh, double coarsenThresh, unsigned finestLevel=0, double eps=0.01, bool linear=true)
All-in-one solution-adaptive step: Löhner indicator → flags → adaptField.
std::vector< double > lohnerIndicator(const BlockOctree< Dim, Bits > &t, const std::vector< double > &u, double eps=0.01)
Löhner normalized second-difference indicator E_i ∈ [0,1], per leaf, for scalar u (indexed by leaf sl...
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
std::vector< double > field
BlockOctree< Dim, Bits > octree