core
Shared MPI block decomposition + asynchronous ghost-layer exchange (header-only C++20)
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// PECLET_CORE_HAVE_MORTON).
22#ifndef PECLET_CORE_AMR_CSR_HPP
23#define PECLET_CORE_AMR_CSR_HPP
24
27
28namespace peclet::core::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::core::amr::csr_off", Kokkos::WithoutInitializing),
57 static_cast<std::size_t>(n) + 1);
58 Kokkos::parallel_scan(
59 "peclet::core::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::core::amr::csr_start", Kokkos::WithoutInitializing),
92 static_cast<std::size_t>(n) + 1);
93 Kokkos::parallel_scan(
94 "peclet::core::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 =
109 View<Index>(Kokkos::view_alloc("peclet::core::amr::csr_nbr", Kokkos::WithoutInitializing),
110 static_cast<std::size_t>(csr.nFaces));
111 csr.coef =
112 View<double>(Kokkos::view_alloc("peclet::core::amr::csr_coef", Kokkos::WithoutInitializing),
113 static_cast<std::size_t>(csr.nFaces));
114 View<Index> nbr = csr.nbr;
115 View<double> coef = csr.coef;
116 Kokkos::parallel_for(
117 "peclet::core::amr::csr_fill", n, KOKKOS_LAMBDA(const Index i) {
118 CsrFillSink sink{nbr, coef, start(i)};
119 emit(i, sink);
120 });
121 return csr;
122}
123
124} // namespace peclet::core::amr
125
126#endif // PECLET_CORE_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
Kokkos::View< T *, MemSpace > View
1D device array.
Definition view.hpp:26
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
Definition types.hpp:15
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
An assembled face-CSR: row offsets (size n+1), neighbour index + coefficient per face (size nFaces).
Definition csr.hpp:72
View< double > coef
coefficient per face, size nFaces
Definition csr.hpp:75
View< Index > nbr
neighbour leaf per face, size nFaces
Definition csr.hpp:74
View< Index > start
CSR row offsets, size n+1; start(n) == nFaces.
Definition csr.hpp:73