peclet.voro 1.0.0
Device-native moving-particle Voronoi dynamics
Loading...
Searching...
No Matches
sdf.hpp
Go to the documentation of this file.
1
20#ifndef PECLET_VORO_SDF_HPP
21#define PECLET_VORO_SDF_HPP
22
23#include <Kokkos_Core.hpp>
24#include <type_traits>
25
26#include "peclet/core/common/view.hpp"
28
29namespace peclet::voro {
30
33constexpr int kBoundaryFacet = -2;
34
36struct NoSdf {};
37
39template <class Real>
40struct SdfSphere {
41 Real cx = 0, cy = 0, cz = 0, radius = 1;
42 KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const {
43 Real dx = x - cx, dy = y - cy, dz = z - cz;
44 return Kokkos::sqrt(dx * dx + dy * dy + dz * dz) - radius;
45 }
46 KOKKOS_INLINE_FUNCTION Real gradH() const { return Real(1e-4); }
47};
48
50template <class Real>
51struct SdfBox {
52 Real cx = 0, cy = 0, cz = 0, hx = Real(0.5), hy = Real(0.5), hz = Real(0.5);
53 KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const {
54 Real qx = Kokkos::fabs(x - cx) - hx, qy = Kokkos::fabs(y - cy) - hy,
55 qz = Kokkos::fabs(z - cz) - hz;
56 Real ox = qx > 0 ? qx : 0, oy = qy > 0 ? qy : 0, oz = qz > 0 ? qz : 0;
57 Real outside = Kokkos::sqrt(ox * ox + oy * oy + oz * oz);
58 Real mx = qx > qy ? qx : qy;
59 mx = mx > qz ? mx : qz;
60 Real inside = mx < 0 ? mx : 0;
61 return outside + inside;
62 }
63 KOKKOS_INLINE_FUNCTION Real gradH() const { return Real(1e-4); }
64};
65
68template <class Real>
70 Real cx = 0, cy = 0, cz = 0, rOuter = 1, rInner = Real(0.5), height = 1;
71 int axis = 2;
72 KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const {
73 Real d[3] = {x - cx, y - cy, z - cz};
74 int a0 = (axis + 1) % 3, a1 = (axis + 2) % 3;
75 Real r = Kokkos::sqrt(d[a0] * d[a0] + d[a1] * d[a1]);
76 Real zz = d[axis];
77 Real m = r - rOuter;
78 Real b = rInner - r;
79 if (b > m)
80 m = b;
81 Real c = Kokkos::fabs(zz) - height * Real(0.5);
82 if (c > m)
83 m = c;
84 return m;
85 }
86 KOKKOS_INLINE_FUNCTION Real gradH() const { return Real(1e-4); }
87};
88
91template <class Real>
92struct SdfGrid {
93 Kokkos::View<const float*, peclet::core::MemSpace> values; // i + nx*(j + ny*k)
94 int nx = 0, ny = 0, nz = 0;
95 Real ox = 0, oy = 0, oz = 0, sx = 1, sy = 1, sz = 1;
96 KOKKOS_INLINE_FUNCTION Real at(int i, int j, int k) const {
97 return static_cast<Real>(values(i + nx * (j + ny * k)));
98 }
99 KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const {
100 Real p[3] = {x, y, z};
101 Real o[3] = {ox, oy, oz}, s[3] = {sx, sy, sz};
102 int dims[3] = {nx, ny, nz};
103 int i0[3], i1[3];
104 Real f[3];
105 for (int d = 0; d < 3; ++d) {
106 Real c = (p[d] - o[d]) / s[d];
107 Real hi = static_cast<Real>(dims[d] - 1);
108 c = c < 0 ? Real(0) : (c > hi ? hi : c);
109 i0[d] = static_cast<int>(Kokkos::floor(c));
110 i1[d] = i0[d] + 1 < dims[d] ? i0[d] + 1 : dims[d] - 1;
111 f[d] = c - static_cast<Real>(i0[d]);
112 }
113 Real c000 = at(i0[0], i0[1], i0[2]), c100 = at(i1[0], i0[1], i0[2]);
114 Real c010 = at(i0[0], i1[1], i0[2]), c110 = at(i1[0], i1[1], i0[2]);
115 Real c001 = at(i0[0], i0[1], i1[2]), c101 = at(i1[0], i0[1], i1[2]);
116 Real c011 = at(i0[0], i1[1], i1[2]), c111 = at(i1[0], i1[1], i1[2]);
117 Real c00 = c000 * (1 - f[0]) + c100 * f[0];
118 Real c10 = c010 * (1 - f[0]) + c110 * f[0];
119 Real c01 = c001 * (1 - f[0]) + c101 * f[0];
120 Real c11 = c011 * (1 - f[0]) + c111 * f[0];
121 Real c0 = c00 * (1 - f[1]) + c10 * f[1];
122 Real c1 = c01 * (1 - f[1]) + c11 * f[1];
123 return c0 * (1 - f[2]) + c1 * f[2];
124 }
125 KOKKOS_INLINE_FUNCTION Real gradH() const {
126 Real m = sx < sy ? sx : sy;
127 m = m < sz ? m : sz;
128 return Real(0.25) * m;
129 }
130};
131
136template <class Real>
138 Kokkos::View<const Real*, peclet::core::MemSpace> cen; // 3*M
139 Kokkos::View<const Real*, peclet::core::MemSpace> rad; // M
140 int n = 0;
141 Real L = 0;
142 KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const {
143 Real m = Real(1e30);
144 for (int i = 0; i < n; ++i) {
145 Real dx = x - cen(3 * i), dy = y - cen(3 * i + 1), dz = z - cen(3 * i + 2);
146 if (L > Real(0)) {
147 dx -= L * Kokkos::round(dx / L);
148 dy -= L * Kokkos::round(dy / L);
149 dz -= L * Kokkos::round(dz / L);
150 }
151 const Real d = Kokkos::sqrt(dx * dx + dy * dy + dz * dz) - rad(i);
152 if (d < m) m = d;
153 }
154 return m;
155 }
156 KOKKOS_INLINE_FUNCTION Real gradH() const { return Real(1e-4); }
157};
158
160template <class Real, class Sdf>
161KOKKOS_INLINE_FUNCTION void sdfGradient(const Sdf& s, Real x, Real y, Real z, Real g[3]) {
162 const Real h = s.gradH();
163 g[0] = (s.eval(x + h, y, z) - s.eval(x - h, y, z)) / (2 * h);
164 g[1] = (s.eval(x, y + h, z) - s.eval(x, y - h, z)) / (2 * h);
165 g[2] = (s.eval(x, y, z + h) - s.eval(x, y, z - h)) / (2 * h);
166}
167
170template <class Real, class Sdf>
171KOKKOS_INLINE_FUNCTION void sdfHessian(const Sdf& s, Real x, Real y, Real z, Real H[3][3]) {
172 const Real h = s.gradH();
173 Real gp[3], gm[3];
174 sdfGradient<Real>(s, x + h, y, z, gp);
175 sdfGradient<Real>(s, x - h, y, z, gm);
176 for (int r = 0; r < 3; ++r) H[r][0] = (gp[r] - gm[r]) / (2 * h);
177 sdfGradient<Real>(s, x, y + h, z, gp);
178 sdfGradient<Real>(s, x, y - h, z, gm);
179 for (int r = 0; r < 3; ++r) H[r][1] = (gp[r] - gm[r]) / (2 * h);
180 sdfGradient<Real>(s, x, y, z + h, gp);
181 sdfGradient<Real>(s, x, y, z - h, gm);
182 for (int r = 0; r < 3; ++r) H[r][2] = (gp[r] - gm[r]) / (2 * h);
183 for (int a = 0; a < 3; ++a)
184 for (int b = a + 1; b < 3; ++b) {
185 const Real m = Real(0.5) * (H[a][b] + H[b][a]);
186 H[a][b] = H[b][a] = m;
187 }
188}
189
199template <class Real, int MAXP, int MAXT, bool TrackAdj, class Sdf>
200KOKKOS_INLINE_FUNCTION void addSdfWallForce(const ConvexCell<Real, MAXP, MAXT, TrackAdj>& c,
201 const Real seed[3], const Sdf& sdf, const Real* gx,
202 const Real* gy, const Real* gz, Real fSelf[3]) {
203 if constexpr (std::is_same_v<Sdf, NoSdf>) {
204 (void)c;
205 (void)seed;
206 (void)sdf;
207 (void)gx;
208 (void)gy;
209 (void)gz;
210 (void)fSelf;
211 return;
212 } else {
213 // Aggregate the wall facets' geometry gradients (all move together under the seed-foot model).
214 Real gw[3] = {Real(0), Real(0), Real(0)};
215 bool any = false;
216 for (int k = 0; k < c.np; ++k)
217 if (c.pnbr[k] == kBoundaryFacet) {
218 gw[0] += gx[k];
219 gw[1] += gy[k];
220 gw[2] += gz[k];
221 any = true;
222 }
223 if (!any) return;
224 const Real phi = sdf.eval(seed[0], seed[1], seed[2]);
225 Real g[3];
226 sdfGradient<Real>(sdf, seed[0], seed[1], seed[2], g);
227 const Real gn = Kokkos::sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
228 if (gn <= Real(1e-12)) return; // degenerate gradient (box crease/corner) — no wall force (guard)
229 const Real u[3] = {g[0] / gn, g[1] / gn, g[2] / gn};
230 Real H[3][3];
231 sdfHessian<Real>(sdf, seed[0], seed[1], seed[2], H);
232 const Real ug = u[0] * gw[0] + u[1] * gw[1] + u[2] * gw[2];
233 const Real perp[3] = {gw[0] - ug * u[0], gw[1] - ug * u[1], gw[2] - ug * u[2]};
234 const Real Hp[3] = {H[0][0] * perp[0] + H[0][1] * perp[1] + H[0][2] * perp[2],
235 H[1][0] * perp[0] + H[1][1] * perp[1] + H[1][2] * perp[2],
236 H[2][0] * perp[0] + H[2][1] * perp[1] + H[2][2] * perp[2]};
237 const Real cH = phi / gn;
238 for (int d = 0; d < 3; ++d) fSelf[d] += -gn * ug * u[d] - cH * Hp[d];
239 }
240}
241
252template <class Real, int MAXP, int MAXT, bool TrackAdj, class Sdf>
254 const Real seed[3], const Sdf& sdf) {
255 const Real tol = Real(1e-8);
256 const int maxCuts = 24;
257 const Real phiCenter = sdf.eval(seed[0], seed[1], seed[2]);
258 if (phiCenter <= Real(0)) { // seed inside solid -> no cell
259 for (int t = 0; t < c.nt; ++t)
260 c.alive[t] = false;
261 return true;
262 }
263 // cell circumradius (dual vertices are seed-relative)
264 const Real maxRsq = c.maxVertexRsq();
265 const Real radius = Kokkos::sqrt(maxRsq > 0 ? maxRsq : Real(0));
266 if (phiCenter > radius + tol)
267 return false; // cell fully in fluid
268
269 bool seedPlaneApplied = false;
270 for (int iter = 0; iter < maxCuts; ++iter) {
271 Real probe[3] = {seed[0], seed[1], seed[2]};
272 Real probePhi = phiCenter;
273 if (seedPlaneApplied) {
274 bool found = false;
275 for (int t = 0; t < c.nt; ++t) {
276 if (!c.alive[t])
277 continue;
278 Real x = seed[0] + c.vx[t], y = seed[1] + c.vy[t], z = seed[2] + c.vz[t];
279 Real phi = sdf.eval(x, y, z);
280 if (!found || phi < probePhi) {
281 probe[0] = x;
282 probe[1] = y;
283 probe[2] = z;
284 probePhi = phi;
285 found = true;
286 }
287 }
288 if (!found || probePhi >= -tol)
289 break;
290 }
291 // closest point on sdf=0 + outward normal
292 Real g[3];
293 sdfGradient<Real>(sdf, probe[0], probe[1], probe[2], g);
294 Real gsq = g[0] * g[0] + g[1] * g[1] + g[2] * g[2];
295 if (gsq <= Real(0))
296 break;
297 Real phi = sdf.eval(probe[0], probe[1], probe[2]);
298 Real invGsq = Real(1) / gsq, invG = Real(1) / Kokkos::sqrt(gsq);
299 Real surf[3], normal[3];
300 for (int k = 0; k < 3; ++k) {
301 surf[k] = probe[k] - phi * g[k] * invGsq;
302 normal[k] = g[k] * invG;
303 }
304 // orient the normal into the fluid (positive side)
305 Real eps = Real(1e-3) * (radius + Real(1));
306 if (eps < Real(1e-6))
307 eps = Real(1e-6);
308 if (sdf.eval(surf[0] + eps * normal[0], surf[1] + eps * normal[1], surf[2] + eps * normal[2]) <=
309 Real(0))
310 for (int k = 0; k < 3; ++k)
311 normal[k] = -normal[k];
312 // plane in seed-relative coords: dist(v) = v·pv - off; vertices in the solid (off the fluid
313 // side) get dist > 0 and are removed.
314 Real pv[3] = {-normal[0], -normal[1], -normal[2]};
315 Real off =
316 pv[0] * (surf[0] - seed[0]) + pv[1] * (surf[1] - seed[1]) + pv[2] * (surf[2] - seed[2]);
317 c.clip(pv, off, kBoundaryFacet);
318 seedPlaneApplied = true;
319 if (c.empty())
320 break;
321 }
322 return false;
323}
324
325} // namespace peclet::voro
326
327#endif // PECLET_VORO_SDF_HPP
Definition convex_cell.hpp:40
KOKKOS_INLINE_FUNCTION void sdfHessian(const Sdf &s, Real x, Real y, Real z, Real H[3][3])
Definition sdf.hpp:171
KOKKOS_INLINE_FUNCTION void addSdfWallForce(const ConvexCell< Real, MAXP, MAXT, TrackAdj > &c, const Real seed[3], const Sdf &sdf, const Real *gx, const Real *gy, const Real *gz, Real fSelf[3])
Definition sdf.hpp:200
constexpr int kBoundaryFacet
Definition sdf.hpp:33
KOKKOS_INLINE_FUNCTION bool clipCellAgainstSdf(ConvexCell< Real, MAXP, MAXT, TrackAdj > &c, const Real seed[3], const Sdf &sdf)
Definition sdf.hpp:253
KOKKOS_INLINE_FUNCTION void sdfGradient(const Sdf &s, Real x, Real y, Real z, Real g[3])
Central-difference gradient of any provider with eval() (matches peclet::core::geom::gradient).
Definition sdf.hpp:161
Definition convex_cell.hpp:139
int nt
triangle high-water mark
Definition convex_cell.hpp:153
Real vy[MAXT]
Definition convex_cell.hpp:151
KOKKOS_INLINE_FUNCTION bool empty() const
Definition convex_cell.hpp:775
int pnbr[MAXP]
neighbour seed id per plane (<0 => bounding box)
Definition convex_cell.hpp:148
KOKKOS_INLINE_FUNCTION Real maxVertexRsq() const
Largest squared dual-vertex radius over live triangles (drives the security radius).
Definition convex_cell.hpp:490
KOKKOS_INLINE_FUNCTION bool clip(const Real pdir[3], Real d, int nbr)
Definition convex_cell.hpp:584
Real vx[MAXT]
Definition convex_cell.hpp:151
int np
number of planes
Definition convex_cell.hpp:149
bool alive[MAXT]
triangle live flag
Definition convex_cell.hpp:152
Real vz[MAXT]
cached dual-vertex position per triangle
Definition convex_cell.hpp:151
Sentinel "no geometry" provider — the default; the clip stage is skipped.
Definition sdf.hpp:36
Axis-aligned solid box of half-extents (hx,hy,hz). eval ported from peclet::core::geom::Box.
Definition sdf.hpp:51
Real hx
Definition sdf.hpp:52
KOKKOS_INLINE_FUNCTION Real gradH() const
Definition sdf.hpp:63
Real cz
Definition sdf.hpp:52
Real cy
Definition sdf.hpp:52
Real cx
Definition sdf.hpp:52
Real hz
Definition sdf.hpp:52
Real hy
Definition sdf.hpp:52
KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const
Definition sdf.hpp:53
Definition sdf.hpp:92
Real sx
Definition sdf.hpp:95
Kokkos::View< const float *, peclet::core::MemSpace > values
Definition sdf.hpp:93
Real oy
Definition sdf.hpp:95
Real oz
Definition sdf.hpp:95
int ny
Definition sdf.hpp:94
KOKKOS_INLINE_FUNCTION Real gradH() const
Definition sdf.hpp:125
int nz
Definition sdf.hpp:94
KOKKOS_INLINE_FUNCTION Real at(int i, int j, int k) const
Definition sdf.hpp:96
KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const
Definition sdf.hpp:99
Real sz
Definition sdf.hpp:95
Real ox
Definition sdf.hpp:95
Real sy
Definition sdf.hpp:95
int nx
Definition sdf.hpp:94
Definition sdf.hpp:69
KOKKOS_INLINE_FUNCTION Real gradH() const
Definition sdf.hpp:86
Real cx
Definition sdf.hpp:70
Real rInner
Definition sdf.hpp:70
int axis
Definition sdf.hpp:71
Real height
Definition sdf.hpp:70
Real cy
Definition sdf.hpp:70
Real rOuter
Definition sdf.hpp:70
Real cz
Definition sdf.hpp:70
KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const
Definition sdf.hpp:72
Solid ball (negative inside). eval ported from peclet::core::geom::Sphere.
Definition sdf.hpp:40
Real radius
Definition sdf.hpp:41
Real cy
Definition sdf.hpp:41
Real cz
Definition sdf.hpp:41
KOKKOS_INLINE_FUNCTION Real gradH() const
Definition sdf.hpp:46
KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const
Definition sdf.hpp:42
Real cx
Definition sdf.hpp:41
Definition sdf.hpp:137
Real L
Definition sdf.hpp:141
int n
Definition sdf.hpp:140
Kokkos::View< const Real *, peclet::core::MemSpace > rad
Definition sdf.hpp:139
Kokkos::View< const Real *, peclet::core::MemSpace > cen
Definition sdf.hpp:138
KOKKOS_INLINE_FUNCTION Real gradH() const
Definition sdf.hpp:156
KOKKOS_INLINE_FUNCTION Real eval(Real x, Real y, Real z) const
Definition sdf.hpp:142