peclet.voro 1.0.4
Device-native moving-particle Voronoi dynamics
Loading...
Searching...
No Matches
mesh.hpp
Go to the documentation of this file.
1
20#ifndef PECLET_VORO_FV_MESH_HPP
21#define PECLET_VORO_FV_MESH_HPP
22
23#include <Kokkos_Core.hpp>
24#include <string>
25
26#include "peclet/core/common/view.hpp"
29
30namespace peclet::voro::fv {
31
32template <class Real>
33struct FaceMesh {
34 using Mem = peclet::core::MemSpace;
35 int nCells = 0, nFaces = 0, nInterior = 0;
36 int nCombined = 0; // owned + ghost cells (distributed; == nCells on one rank): cell fields are
37 // sized nCombined, cell loops run over the nCells owned cells
38 int nDropped = 0; // non-reciprocal fluid facets dropped (degenerate edge/vertex contacts)
39 // faces [0, nInterior) are interior (two cells), [nInterior, nFaces) boundary (wall / box).
40 Kokkos::View<int*, Mem> faceCellA, faceCellB; // nFaces; B = -1 on a boundary face
41 Kokkos::View<int*, Mem> faceFacet; // nFaces: owner (A-side) facet index in the view
42 Kokkos::View<Real*, Mem> faceArea; // nFaces: |A|
43 Kokkos::View<Real*, Mem> faceNormal; // 3*nFaces: unit, A → B (outward from A)
44 Kokkos::View<Real*, Mem> faceDist; // nFaces: seed distance d (interior); h_A (boundary)
45 Kokkos::View<Real*, Mem> faceHa, faceHb; // nFaces: seed-to-plane distances (h_B = 0 boundary)
46 Kokkos::View<Real*, Mem> faceCentroid; // 3*nFaces: centroid, A-seed-relative
47 Kokkos::View<Real*, Mem> faceConn; // 3*nFaces: connector A → B (min-image), 0 boundary
48 Kokkos::View<int*, Mem> cellFaceOffset; // nCells+1
49 Kokkos::View<int*, Mem> cellFace; // 2*nInterior + nBoundary
50 Kokkos::View<Real*, Mem> cellFaceSign; // same: +1 if the cell is A, -1 if B
51 Kokkos::View<Real*, Mem> cellVolume; // nCells (alias of the view's)
52
53 KOKKOS_INLINE_FUNCTION int cellFacesBegin(int i) const { return cellFaceOffset(i); }
54 KOKKOS_INLINE_FUNCTION int cellFacesEnd(int i) const { return cellFaceOffset(i + 1); }
55 KOKKOS_INLINE_FUNCTION Real normal(int f, int c) const { return faceNormal(3 * f + c); }
56 KOKKOS_INLINE_FUNCTION Real centroid(int f, int c) const { return faceCentroid(3 * f + c); }
57 KOKKOS_INLINE_FUNCTION Real conn(int f, int c) const { return faceConn(3 * f + c); }
58};
59
67template <class Real>
69 int nOwned = -1) {
70 using Mem = peclet::core::MemSpace;
71 using Exec = peclet::core::ExecSpace;
72 using Kokkos::view_alloc;
73 using Kokkos::WithoutInitializing;
75 const int N = view.numCells(), nF = view.numFacets();
76 const int nOwn = (nOwned >= 0 && nOwned < N) ? nOwned : N;
77 m.nCells = nOwn;
78 m.nCombined = N;
79 auto recip = aux.recip;
80 auto cellOf = aux.cellOfFacet;
81 // classify facets: 1 = interior owner, 2 = boundary, 0 = twin (not owned)
82 Kokkos::View<int*, Mem> kind("fv.kind", nF);
83 Kokkos::parallel_for(
84 "fv.kind", Kokkos::RangePolicy<Exec>(0, nF), KOKKOS_LAMBDA(const int f) {
85 const int j = view.facetNbr(f);
86 if (j < 0)
87 kind(f) = 2;
88 else if (j >= nOwn)
89 kind(f) = 1; // interface face toward a ghost cell: owned here
90 else if (recip(f) >= 0)
91 kind(f) = (f < recip(f)) ? 1 : 0;
92 else
93 kind(f) = 3; // no reciprocal: a degenerate (zero-area) edge/vertex contact of a
94 // symmetric lattice, seen from one side only — not a face, dropped
95 });
96 {
97 int nd = 0;
98 Kokkos::parallel_reduce(
99 "fv.dropped", Kokkos::RangePolicy<Exec>(0, nF),
100 KOKKOS_LAMBDA(const int f, int& acc) { acc += kind(f) == 3 ? 1 : 0; }, nd);
101 m.nDropped = nd;
102 }
103 // enumerate: interior first, then boundary (two scans)
104 Kokkos::View<int*, Mem> idxI(view_alloc(std::string("fv.idxI"), WithoutInitializing), nF);
105 Kokkos::View<int*, Mem> idxB(view_alloc(std::string("fv.idxB"), WithoutInitializing), nF);
106 int nI = 0, nB = 0;
107 Kokkos::parallel_scan(
108 "fv.scanI", nF,
109 KOKKOS_LAMBDA(const int f, int& upd, const bool fin) {
110 if (fin)
111 idxI(f) = upd;
112 upd += (kind(f) == 1) ? 1 : 0;
113 },
114 nI);
115 Kokkos::parallel_scan(
116 "fv.scanB", nF,
117 KOKKOS_LAMBDA(const int f, int& upd, const bool fin) {
118 if (fin)
119 idxB(f) = upd;
120 upd += (kind(f) == 2) ? 1 : 0;
121 },
122 nB);
123 m.nInterior = nI;
124 m.nFaces = nI + nB;
125 const int nFaces = m.nFaces;
126 m.faceCellA =
127 Kokkos::View<int*, Mem>(view_alloc(std::string("fv.A"), WithoutInitializing), nFaces);
128 m.faceCellB =
129 Kokkos::View<int*, Mem>(view_alloc(std::string("fv.B"), WithoutInitializing), nFaces);
130 m.faceFacet =
131 Kokkos::View<int*, Mem>(view_alloc(std::string("fv.facet"), WithoutInitializing), nFaces);
132 m.faceArea =
133 Kokkos::View<Real*, Mem>(view_alloc(std::string("fv.area"), WithoutInitializing), nFaces);
134 m.faceNormal = Kokkos::View<Real*, Mem>(view_alloc(std::string("fv.normal"), WithoutInitializing),
135 3 * (size_t)nFaces);
136 m.faceDist =
137 Kokkos::View<Real*, Mem>(view_alloc(std::string("fv.dist"), WithoutInitializing), nFaces);
138 m.faceHa =
139 Kokkos::View<Real*, Mem>(view_alloc(std::string("fv.ha"), WithoutInitializing), nFaces);
140 m.faceHb =
141 Kokkos::View<Real*, Mem>(view_alloc(std::string("fv.hb"), WithoutInitializing), nFaces);
142 m.faceCentroid = Kokkos::View<Real*, Mem>(view_alloc(std::string("fv.cen"), WithoutInitializing),
143 3 * (size_t)nFaces);
144 m.faceConn = Kokkos::View<Real*, Mem>(view_alloc(std::string("fv.conn"), WithoutInitializing),
145 3 * (size_t)nFaces);
146 {
147 auto A = m.faceCellA;
148 auto B = m.faceCellB;
149 auto FF = m.faceFacet;
150 auto AR = m.faceArea;
151 auto NM = m.faceNormal;
152 auto DS = m.faceDist;
153 auto HA = m.faceHa;
154 auto HB = m.faceHb;
155 auto CE = m.faceCentroid;
156 auto CN = m.faceConn;
157 Kokkos::parallel_for(
158 "fv.fill", Kokkos::RangePolicy<Exec>(0, nF), KOKKOS_LAMBDA(const int f) {
159 const int k = kind(f);
160 if (k == 0 || k == 3)
161 return;
162 const int g = (k == 1) ? idxI(f) : nI + idxB(f);
163 const int i = cellOf(f);
164 A(g) = i;
165 // interior: the reciprocal facet's cell; interface (no reciprocal): the ghost index
166 B(g) = (k == 1) ? (recip(f) >= 0 ? cellOf(recip(f)) : view.facetNbr(f)) : -1;
167 FF(g) = f;
168 const Real ax = view.area(f, 0), ay = view.area(f, 1), az = view.area(f, 2);
169 const Real ar = Kokkos::sqrt(ax * ax + ay * ay + az * az);
170 AR(g) = ar;
171 const Real iar = ar > Real(0) ? Real(1) / ar : Real(0);
172 NM(3 * g) = ax * iar;
173 NM(3 * g + 1) = ay * iar;
174 NM(3 * g + 2) = az * iar;
175 const Real rx = view.connVec(f, 0), ry = view.connVec(f, 1), rz = view.connVec(f, 2);
176 const Real rl = Kokkos::sqrt(rx * rx + ry * ry + rz * rz);
177 // foot distance of the owner seed to the plane: |n| = |conn|/2 (conn = 2n)
178 const Real ha = Real(0.5) * rl;
179 // centroid: dV/dr = (|A|/|r|)(r − c) ⇒ c = r − dV·|r|/|A|
180 const Real dvx = view.connect(f, 0), dvy = view.connect(f, 1), dvz = view.connect(f, 2);
181 const Real s = (ar > Real(0)) ? rl / ar : Real(0);
182 CE(3 * g) = rx - dvx * s;
183 CE(3 * g + 1) = ry - dvy * s;
184 CE(3 * g + 2) = rz - dvz * s;
185 if (k == 1) {
186 CN(3 * g) = rx;
187 CN(3 * g + 1) = ry;
188 CN(3 * g + 2) = rz;
189 DS(g) = rl; // Voronoi: seed distance == |conn|
190 HA(g) = ha;
191 HB(g) = rl - ha;
192 } else {
193 CN(3 * g) = CN(3 * g + 1) = CN(3 * g + 2) = Real(0);
194 DS(g) = ha;
195 HA(g) = ha;
196 HB(g) = Real(0);
197 }
198 });
199 }
200 // cell -> faces CSR (each interior face in two cells, boundary in one)
201 Kokkos::View<int*, Mem> cnt("fv.cnt", N + 1);
202 {
203 auto A = m.faceCellA;
204 auto B = m.faceCellB;
205 Kokkos::parallel_for(
206 "fv.count", Kokkos::RangePolicy<Exec>(0, nFaces), KOKKOS_LAMBDA(const int g) {
207 Kokkos::atomic_inc(&cnt(A(g)));
208 if (B(g) >= 0 && B(g) < nOwn)
209 Kokkos::atomic_inc(&cnt(B(g)));
210 });
211 }
212 m.cellFaceOffset = Kokkos::View<int*, Mem>("fv.cellFaceOffset", N + 1);
213 {
214 auto off = m.cellFaceOffset;
215 Kokkos::parallel_scan(
216 "fv.scanCells", N + 1, KOKKOS_LAMBDA(const int i, int& upd, const bool fin) {
217 if (fin)
218 off(i) = upd;
219 upd += (i < N) ? cnt(i) : 0;
220 });
221 }
222 const int nEntries = 2 * nI + nB;
223 m.cellFace = Kokkos::View<int*, Mem>(view_alloc(std::string("fv.cellFace"), WithoutInitializing),
224 nEntries);
225 m.cellFaceSign = Kokkos::View<Real*, Mem>(
226 view_alloc(std::string("fv.cellFaceSign"), WithoutInitializing), nEntries);
227 {
228 Kokkos::View<int*, Mem> cursor("fv.cursor", N);
229 auto off = m.cellFaceOffset;
230 auto CF = m.cellFace;
231 auto CS = m.cellFaceSign;
232 auto A = m.faceCellA;
233 auto B = m.faceCellB;
234 Kokkos::parallel_for(
235 "fv.fillCells", Kokkos::RangePolicy<Exec>(0, nFaces), KOKKOS_LAMBDA(const int g) {
236 const int a = A(g);
237 const int pa = off(a) + Kokkos::atomic_fetch_add(&cursor(a), 1);
238 CF(pa) = g;
239 CS(pa) = Real(1);
240 const int b = B(g);
241 if (b >= 0 && b < nOwn) {
242 const int pb = off(b) + Kokkos::atomic_fetch_add(&cursor(b), 1);
243 CF(pb) = g;
244 CS(pb) = Real(-1);
245 }
246 });
247 }
248 m.cellVolume = view.cellVolume;
249 Kokkos::fence();
250 return m;
251}
252
253} // namespace peclet::voro::fv
254
255#endif // PECLET_VORO_FV_MESH_HPP
Definition collocated.hpp:38
FaceMesh< Real > buildFaceMesh(const TessellationView< Real > &view, const AuxMaps< Real > &aux, int nOwned=-1)
Definition mesh.hpp:68
Definition transpose.hpp:26
Kokkos::View< int *, peclet::core::MemSpace > recip
Definition transpose.hpp:27
Kokkos::View< int *, peclet::core::MemSpace > cellOfFacet
Definition transpose.hpp:28
Definition tessellation_view.hpp:111
KOKKOS_INLINE_FUNCTION Real area(int f, int c) const
Definition tessellation_view.hpp:186
KOKKOS_INLINE_FUNCTION gid_t facetNbr(int f) const
Definition tessellation_view.hpp:185
KOKKOS_INLINE_FUNCTION Real connVec(int f, int c) const
Definition tessellation_view.hpp:188
Kokkos::View< Real *, peclet::core::MemSpace > cellVolume
Definition tessellation_view.hpp:120
KOKKOS_INLINE_FUNCTION int numFacets() const
Definition tessellation_view.hpp:178
KOKKOS_INLINE_FUNCTION int numCells() const
Definition tessellation_view.hpp:173
KOKKOS_INLINE_FUNCTION Real connect(int f, int c) const
Definition tessellation_view.hpp:187
Definition mesh.hpp:33
Kokkos::View< Real *, Mem > faceNormal
Definition mesh.hpp:43
Kokkos::View< int *, Mem > cellFace
Definition mesh.hpp:49
Kokkos::View< Real *, Mem > faceCentroid
Definition mesh.hpp:46
Kokkos::View< Real *, Mem > faceHb
Definition mesh.hpp:45
int nInterior
Definition mesh.hpp:35
Kokkos::View< int *, Mem > faceFacet
Definition mesh.hpp:41
Kokkos::View< int *, Mem > faceCellB
Definition mesh.hpp:40
KOKKOS_INLINE_FUNCTION Real conn(int f, int c) const
Definition mesh.hpp:57
Kokkos::View< Real *, Mem > faceDist
Definition mesh.hpp:44
KOKKOS_INLINE_FUNCTION Real normal(int f, int c) const
Definition mesh.hpp:55
Kokkos::View< int *, Mem > faceCellA
Definition mesh.hpp:40
int nCombined
Definition mesh.hpp:36
int nCells
Definition mesh.hpp:35
KOKKOS_INLINE_FUNCTION Real centroid(int f, int c) const
Definition mesh.hpp:56
KOKKOS_INLINE_FUNCTION int cellFacesBegin(int i) const
Definition mesh.hpp:53
int nDropped
Definition mesh.hpp:38
Kokkos::View< Real *, Mem > cellFaceSign
Definition mesh.hpp:50
KOKKOS_INLINE_FUNCTION int cellFacesEnd(int i) const
Definition mesh.hpp:54
Kokkos::View< Real *, Mem > cellVolume
Definition mesh.hpp:51
int nFaces
Definition mesh.hpp:35
Kokkos::View< Real *, Mem > faceConn
Definition mesh.hpp:47
Kokkos::View< Real *, Mem > faceArea
Definition mesh.hpp:42
Kokkos::View< Real *, Mem > faceHa
Definition mesh.hpp:45
peclet::core::MemSpace Mem
Definition mesh.hpp:34
Kokkos::View< int *, Mem > cellFaceOffset
Definition mesh.hpp:48
Published, read-only device data layer for the tessellation (migration §2.1, §3).