peclet-amr 0.2.0
Block-local-Morton AMR octree + collocated cut-cell Navier–Stokes solver (header-only C++20, Kokkos + MPI)
Loading...
Searching...
No Matches
facegeom_assembly.hpp
Go to the documentation of this file.
1// core — device assembly of the collocated-projection FACE-GEOMETRY tables (D4).
2//
3// buildFaceGeom (flow.hpp) walks AmrPoisson::forEachFaceFull on the host to produce the
4// per-(sub)face geometry CSR the collocated divergence / gradient / ABC face-field / FOU advection
5// kernels consume: neighbour, axis, dir, α·area, raw area, distance, openness α, and the two SOU
6// upstream-probe leaves. It is pure per-face geometry — embarrassingly parallel — so for a moving
7// boundary it should rebuild on device rather than re-walk the host and re-upload. This header does
8// that, reusing the D2 FvFaceEmit traversal helpers (decode / wrap / areaOf / openness / locate)
9// and the S1 offsets primitive.
10//
11// Bit-exactness: same forEachFaceFull enumeration (axis-major, dir −1/+1, 2:1 sub-faces), same
12// per-face formulas, each cell fills its own slice — so on OpenMP the device FaceGeom == host
13// buildFaceGeom bit-for-bit (test_amr_facegeom). GPU is tolerance-not-bit-exact (FMA), per the
14// convention.
15//
16#ifndef PECLET_AMR_FACEGEOM_ASSEMBLY_HPP
17#define PECLET_AMR_FACEGEOM_ASSEMBLY_HPP
18
19#include <array>
20
21#include "peclet/amr/assembly.hpp" // FvFaceEmit (shared geometry traversal helpers)
23#include "peclet/amr/common.hpp"
24#include "peclet/amr/csr.hpp" // scanOffsets
25#include "peclet/amr/face_geom.hpp" // FaceGeom (the produced type)
27#include "peclet/core/common/view.hpp"
28
29namespace peclet::amr {
30
34template <unsigned Bits = 21u>
39
42 std::array<Coord, 3> lo = M::from_code(g.ov.codes(i)).decode();
43 const Coord si = Coord(Coord(1) << g.ov.levels(i));
44 const long pc = (dir > 0) ? static_cast<long>(lo[axis]) + static_cast<long>(si)
45 : static_cast<long>(lo[axis]) - 1;
46 std::array<Coord, 3> p = lo;
47 p[axis] = g.wrap(pc, axis);
48 return g.ov.locate(M::encode(p).code());
49 }
50
53 template <class CB>
55 std::array<Coord, 3> lo = M::from_code(g.ov.codes(i)).decode();
56 const unsigned Li = g.ov.levels(i);
57 const Coord si = Coord(Coord(1) << Li);
58 for (int axis = 0; axis < 3; ++axis)
59 for (int dir = -1; dir <= 1; dir += 2) {
60 const long pc = (dir > 0) ? static_cast<long>(lo[axis]) + static_cast<long>(si)
61 : static_cast<long>(lo[axis]) - 1;
62 std::array<Coord, 3> p = lo;
63 p[axis] = g.wrap(pc, axis);
64 const Index j = g.ov.locate(M::encode(p).code());
65 const unsigned Lj = g.ov.levels(j);
66 if (Lj >= Li) {
67 const Coord sj = Coord(Coord(1) << Lj);
68 cb(j, axis, dir, g.areaOf(si, axis),
69 0.5 * (static_cast<Real>(si) + static_cast<Real>(sj)) * g.h0[axis],
70 g.openness(i, axis, dir));
71 } else {
72 const Coord sj = Coord(si >> 1);
73 const int nsub = 1 << 2; // 2^(Dim-1), Dim=3
74 for (int k = 0; k < nsub; ++k) {
75 std::array<Coord, 3> q = lo;
76 q[axis] = g.wrap(pc, axis);
77 int bit = 0;
78 for (int t = 0; t < 3; ++t) {
79 if (t == axis)
80 continue;
81 const Coord off = ((k >> bit) & 1) ? sj : Coord(0);
82 q[t] = g.wrap(static_cast<long>(lo[t]) + static_cast<long>(off), t);
83 ++bit;
84 }
85 const Index jj = g.ov.locate(M::encode(q).code());
86 cb(jj, axis, dir, g.areaOf(sj, axis),
87 0.5 * (static_cast<Real>(si) + static_cast<Real>(sj)) * g.h0[axis],
88 g.openness(jj, axis, -dir));
89 }
90 }
91 }
92 }
93
95 struct CountCB {
96 Index c = 0;
97 KOKKOS_INLINE_FUNCTION void operator()(Index, int, int, double, double, double) { ++c; }
98 } cb;
100 return cb.c;
101 }
102};
103
106template <unsigned Bits>
107FaceGeom assembleFaceGeom(const AmrPoisson<3, Bits>& ap, const std::vector<char>& fluidHost,
108 const BlockOctreeView<3, Bits>& ov) {
110 emit.g.ov = ov;
111 for (int d = 0; d < 3; ++d)
112 emit.g.h0[d] = ap.h0()[d];
113 emit.g.periodic = ap.periodic();
114 emit.g.hasOpen = ap.hasOpenness();
115 for (int d = 0; d < 3; ++d)
116 emit.g.fineExt[d] = ap.fineExt()[d];
117 if (ap.hasOpenness())
118 emit.g.alpha = toDevice(ap.opennessRaw(), "fg::alpha");
119
120 const Index n = ov.numLeaves();
121 Index nf = 0;
122 View<Index> start = scanOffsets(n, KOKKOS_LAMBDA(const Index i) { return emit.count(i); }, nf);
123
124 FaceGeom fg;
125 fg.n = n;
126 fg.start = start;
127 // NB: pass the label as std::string — a const char* *variable* is read by view_alloc as a
128 // pointer-to-memory (only string literals are special-cased as labels).
129 auto mk = [&](const char* lbl, std::size_t m) {
130 return View<double>(Kokkos::view_alloc(std::string(lbl), Kokkos::WithoutInitializing), m);
131 };
132 auto mkI = [&](const char* lbl, std::size_t m) {
133 return View<Index>(Kokkos::view_alloc(std::string(lbl), Kokkos::WithoutInitializing), m);
134 };
135 const std::size_t F = static_cast<std::size_t>(nf);
136 fg.nbr = mkI("fg::nbr", F);
137 fg.axis = View<int>(Kokkos::view_alloc("fg::axis", Kokkos::WithoutInitializing), F);
138 fg.dir = View<int>(Kokkos::view_alloc("fg::dir", Kokkos::WithoutInitializing), F);
139 fg.alphaArea = mk("fg::aArea", F);
140 fg.rawArea = mk("fg::rArea", F);
141 fg.dist = mk("fg::dist", F);
142 fg.alpha = mk("fg::alpha", F);
143 fg.upupI = mkI("fg::upupI", F);
144 fg.upupJ = mkI("fg::upupJ", F);
145 fg.invVol = mk("fg::invVol", static_cast<std::size_t>(n));
146 fg.fluid = View<char>(Kokkos::view_alloc("fg::fluid", Kokkos::WithoutInitializing),
147 static_cast<std::size_t>(n));
148
149 View<char> fluidDev = toDevice(fluidHost, "fg::fluidIn");
150 FaceGeom out = fg; // copy of the View handles for capture
151 const FaceGeomEmit<Bits> e = emit;
152 Kokkos::parallel_for(
153 "amr::facegeom_fill", n, KOKKOS_LAMBDA(const Index i) {
154 out.invVol(i) = 1.0 / e.g.cellVolume(i);
155 out.fluid(i) = fluidDev(i);
156 // own-slice fill cursor; cb writes one (sub)face per call (forEachFaceFull order).
157 struct FillCB {
158 const FaceGeomEmit<Bits>* e;
159 const FaceGeom* o; // captured-by-value FaceGeom is const; View element writes still work
160 Index i;
161 Index k;
162 KOKKOS_INLINE_FUNCTION void operator()(Index j, int axis, int dir, double area,
163 double dist, double alpha) {
164 o->nbr(k) = j;
165 o->axis(k) = axis;
166 o->dir(k) = dir;
167 o->alphaArea(k) = alpha * area;
168 o->rawArea(k) = area;
169 o->dist(k) = dist;
170 o->alpha(k) = alpha;
171 o->upupI(k) = e->periodicNeighbor(i, axis, -dir);
172 o->upupJ(k) = e->periodicNeighbor(j, axis, dir);
173 ++k;
174 }
175 } cb{&e, &out, i, out.start(i)};
176 e.forEachFaceFull(i, cb);
177 });
178 return fg;
179}
180
181} // namespace peclet::amr
182
183#endif // PECLET_AMR_FACEGEOM_ASSEMBLY_HPP
Cell-centered FV Poisson operator on one (periodic) block octree.
Definition poisson.hpp:43
const std::array< Coord, Dim > & fineExt() const
Per-axis fine-grid extent (brick·2^lmax) — the periodic wrap modulus.
Definition poisson.hpp:592
const Vec< Dim > & h0() const
Definition poisson.hpp:587
bool hasOpenness() const
Definition poisson.hpp:156
bool periodic() const
Definition poisson.hpp:212
const std::vector< double > & opennessRaw() const
Definition poisson.hpp:157
View< Index > scanOffsets(Index n, const CountFn &countFn, Index &nTotal)
CSR row offsets (size n+1) from a per-cell count functor, via one exclusive prefix scan,...
Definition csr.hpp:55
FaceGeom assembleFaceGeom(const AmrPoisson< 3, Bits > &ap, const std::vector< char > &fluidHost, const BlockOctreeView< 3, Bits > &ov)
Assemble the collocated FaceGeom entirely on device from a built AmrPoisson (openness set) + a per-ce...
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,...
Definition adapt.hpp:51
Device mirror of a BlockOctree's leaf arrays + device-callable queries.
The device face-geometry walker: replicates AmrPoisson::forEachFaceFull + periodicNeighbor over the d...
Index periodicNeighbor(Index i, int axis, int dir) const
Single-leaf periodic face neighbour (AmrPoisson::periodicNeighbor) — the SOU upstream probe.
typename BlockOctreeView< 3, Bits >::M M
void forEachFaceFull(Index i, CB &cb) const
Visit each (sub)face of leaf i: cb(neighbour, axis, dir, area, dist, alpha) in forEachFaceFull order.
typename BlockOctreeView< 3, Bits >::Coord Coord
View< Index > nbr
neighbour leaf per face, size nFaces
Definition face_geom.hpp:25
Device-callable reproduction of AmrPoisson's per-cell face walk + geometry.
Definition assembly.hpp:36