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
csr.hpp
Go to the documentation of this file.
1// core — device CSR-fill primitive (S1 / D1): the reusable count → scan → fill backbone
2// for assembling a face-CSR sparse operator on the device.
3//
4// Every AMR operator (the FV pressure Laplacian, the cut-cell momentum operator, the face-geometry
5// tables) is a per-cell list of faces with a neighbour index and a coefficient. Assembling such a
6// CSR in parallel is the standard three-step pattern:
7// 1. count — each cell counts its faces (parallel_for)
8// 2. scan — exclusive prefix-sum the counts into row offsets (parallel_scan)
9// 3. fill — each cell writes its faces into its OWN slice (parallel_for, atomic-free)
10// Step 3 is deterministic (own-slice, no atomics, fixed emit order), so on the OpenMP backend the
11// device-assembled CSR is bit-for-bit identical to the host serial assembler — the suite's
12// anti-drift contract. (GPU is tolerance-not-bit-exact by the documented FMA convention.)
13//
14// The per-cell face traversal is supplied by the caller as an `Emit` functor with a templated
15// `operator()(Index i, Sink& s)` that calls `s(neighbourLeaf, coef)` once per face in a fixed
16// order. The same functor drives both the count pass (a counting sink) and the fill pass (a writing
17// sink), so the emit order is guaranteed identical between the two — exactly as the host assembler
18// reuses one `forEachFaceNeighbor` lambda for both passes.
19//
20// Requires a Kokkos build; included only by the device-assembly headers (themselves
21#ifndef PECLET_AMR_CSR_HPP
22#define PECLET_AMR_CSR_HPP
23
24#include "peclet/amr/common.hpp"
25#include "peclet/core/common/types.hpp"
26#include "peclet/core/common/view.hpp"
27
28namespace peclet::amr {
29
33 KOKKOS_INLINE_FUNCTION void operator()(Index /*nbr*/, double /*coef*/) { ++count; }
34};
35
41 Index k = 0;
43 nbr(k) = j;
44 coef(k) = c;
45 ++k;
46 }
47};
48
54template <class CountFn>
56 View<Index> start(Kokkos::view_alloc("peclet::amr::csr_off", Kokkos::WithoutInitializing),
57 static_cast<std::size_t>(n) + 1);
58 Kokkos::parallel_scan(
59 "peclet::amr::csr_off_scan", n + 1,
60 KOKKOS_LAMBDA(const Index i, Index& partial, const bool final_pass) {
61 const Index c = (i < n) ? countFn(i) : Index(0);
62 if (final_pass)
63 start(i) = partial;
64 partial += c;
65 });
66 Kokkos::deep_copy(nTotal, Kokkos::subview(start, n));
67 return start;
68}
69
78
88template <class Emit>
90 Csr csr;
91 View<Index> start(Kokkos::view_alloc("peclet::amr::csr_start", Kokkos::WithoutInitializing),
92 static_cast<std::size_t>(n) + 1);
93 Kokkos::parallel_scan(
94 "peclet::amr::csr_scan", n + 1,
95 KOKKOS_LAMBDA(const Index i, Index& partial, const bool final_pass) {
96 Index c = 0;
97 if (i < n) {
99 emit(i, s);
100 c = s.count;
101 }
102 if (final_pass)
103 start(i) = partial; // exclusive prefix: offset before adding this cell
104 partial += c;
105 });
106 Kokkos::deep_copy(csr.nFaces, Kokkos::subview(start, n));
107 csr.start = start;
108 csr.nbr = View<Index>(Kokkos::view_alloc("peclet::amr::csr_nbr", Kokkos::WithoutInitializing),
109 static_cast<std::size_t>(csr.nFaces));
110 csr.coef = View<double>(Kokkos::view_alloc("peclet::amr::csr_coef", Kokkos::WithoutInitializing),
111 static_cast<std::size_t>(csr.nFaces));
112 View<Index> nbr = csr.nbr;
113 View<double> coef = csr.coef;
114 Kokkos::parallel_for(
115 "peclet::amr::csr_fill", n, KOKKOS_LAMBDA(const Index i) {
116 CsrFillSink sink{nbr, coef, start(i)};
117 emit(i, sink);
118 });
119 return csr;
120}
121
122} // namespace peclet::amr
123
124#endif // PECLET_AMR_CSR_HPP
Csr buildFaceCsr(Index n, const Emit &emit)
Build a face-CSR on device from a per-cell emit functor.
Definition csr.hpp:89
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
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
Sink passed to the emit functor during the COUNT pass: just tallies faces.
Definition csr.hpp:31
void operator()(Index, double)
Definition csr.hpp:33
Sink passed to the emit functor during the FILL pass: writes each face into the cell's own slice [sta...
Definition csr.hpp:38
void operator()(Index j, double c)
Definition csr.hpp:42
View< double > coef
Definition csr.hpp:40
View< Index > nbr
Definition csr.hpp:39
An assembled face-CSR: row offsets (size n+1), neighbour index + coefficient per face (size nFaces).
Definition csr.hpp:72
Index nFaces
Definition csr.hpp:76
View< Index > nbr
neighbour leaf per face, size nFaces
Definition csr.hpp:74
View< double > coef
coefficient per face, size nFaces
Definition csr.hpp:75
View< Index > start
CSR row offsets, size n+1; start(n) == nFaces.
Definition csr.hpp:73