core
Shared MPI block decomposition + asynchronous ghost-layer exchange (header-only C++20)
Loading...
Searching...
No Matches
sdf.hpp
Go to the documentation of this file.
1// core — signed-distance geometry for solids (see suite/docs/CONVENTIONS.md §2).
2//
3// Sign convention (load-bearing, shared across the suite): sdf < 0 inside solid, > 0 in fluid/void,
4// 0 on the surface; the gradient points outward (into the fluid). Analytic primitives mirror the
5// shapes packing-gpu already uses (sphere, box, hollow cylinder); a generic finite-difference
6// gradient covers any shape, and a `Sdf` concept lets solvers accept analytic or grid SDFs
7// uniformly.
8//
9// C++17-clean below the concept so this header can be pulled into CUDA translation units; the
10// concept itself is guarded for C++20 host use.
11#ifndef PECLET_CORE_GEOM_SDF_HPP
12#define PECLET_CORE_GEOM_SDF_HPP
13
14#include <algorithm>
15#include <cmath>
16
18
19namespace peclet::core::geom {
20
21namespace detail {
22inline Vec<3> sub(const Vec<3>& a, const Vec<3>& b) {
23 return {a[0] - b[0], a[1] - b[1], a[2] - b[2]};
24}
25inline double norm(const Vec<3>& a) {
26 return std::sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
27}
28} // namespace detail
29
31struct Sphere {
33 double radius = 1.0;
34 double eval(const Vec<3>& p) const { return detail::norm(detail::sub(p, center)) - radius; }
35};
36
38struct Box {
40 Vec<3> half{0.5, 0.5, 0.5};
41 double eval(const Vec<3>& p) const {
43 Vec<3> q{std::fabs(d[0]) - half[0], std::fabs(d[1]) - half[1], std::fabs(d[2]) - half[2]};
44 double outside = detail::norm({std::max(q[0], 0.0), std::max(q[1], 0.0), std::max(q[2], 0.0)});
45 double inside = std::min(std::max(q[0], std::max(q[1], q[2])), 0.0);
46 return outside + inside;
47 }
48};
49
55 double rOuter = 1.0;
56 double rInner = 0.5;
57 double height = 1.0;
58 int axis = 2;
59 double eval(const Vec<3>& p) const {
61 int a0 = (axis + 1) % 3, a1 = (axis + 2) % 3;
62 double r = std::sqrt(d[a0] * d[a0] + d[a1] * d[a1]);
63 double z = d[axis];
64 return std::max({r - rOuter, rInner - r, std::fabs(z) - height * 0.5});
65 }
66};
67
70template <typename S>
71struct Complement {
73 double eval(const Vec<3>& p) const { return -shape.eval(p); }
74};
75
77template <typename S>
78Vec<3> gradient(const S& shape, const Vec<3>& p, double h = 1e-4) {
79 Vec<3> g{};
80 for (int i = 0; i < 3; ++i) {
81 Vec<3> pp = p, pm = p;
82 pp[i] += h;
83 pm[i] -= h;
84 g[i] = (shape.eval(pp) - shape.eval(pm)) / (2.0 * h);
85 }
86 return g;
87}
88
89#if defined(__cpp_concepts)
91template <typename S>
92concept Sdf = requires(const S s, Vec<3> p) {
93 { s.eval(p) } -> std::convertible_to<double>;
94};
95#endif
96
97} // namespace peclet::core::geom
98
99#endif // PECLET_CORE_GEOM_SDF_HPP
double norm(const Vec< 3 > &a)
Definition sdf.hpp:25
Vec< 3 > sub(const Vec< 3 > &a, const Vec< 3 > &b)
Definition sdf.hpp:22
Vec< 3 > gradient(const S &shape, const Vec< 3 > &p, double h=1e-4)
Generic outward normal via central differences; works for any shape with eval().
Definition sdf.hpp:78
Kokkos::View< T *, MemSpace > View
1D device array.
Definition view.hpp:26
Axis-aligned solid box of half-extents half: standard exact box SDF, negative inside.
Definition sdf.hpp:38
double eval(const Vec< 3 > &p) const
Definition sdf.hpp:41
Negation: the solid and the void swap (sdf -> -sdf).
Definition sdf.hpp:71
double eval(const Vec< 3 > &p) const
Definition sdf.hpp:73
Solid hollow cylinder (a tube wall) of given outer/inner radius and height about axis.
Definition sdf.hpp:53
double eval(const Vec< 3 > &p) const
Definition sdf.hpp:59
Solid ball: negative inside.
Definition sdf.hpp:31
double eval(const Vec< 3 > &p) const
Definition sdf.hpp:34