peclet-dem 1.1.0
Performance-portable XPBD Discrete Element Method (Kokkos + ArborX)
Loading...
Searching...
No Matches
shapes_portable.hpp
Go to the documentation of this file.
1
9#ifndef DEM_SHAPES_PORTABLE_HPP
10#define DEM_SHAPES_PORTABLE_HPP
11
12#include <cmath>
13#include <vector>
14
15#include "dem_portable.hpp" // peclet::dem::F3
16
17namespace peclet::dem {
18
19// M_PI is a POSIX extension, not standard C++: MSVC leaves it undefined unless _USE_MATH_DEFINES is
20// set before <cmath>, which a header cannot rely on (measured on the 2026-09-13 Windows wheel
21// probe: eight C2065s here, the only ones in the package). These are the digits glibc's M_PI
22// carries, so every value below is bit-identical to what the Linux build has always produced.
23inline constexpr double kPi = 3.14159265358979323846;
24
25// Surface point shell of a hollow cylinder (outer wall + inner wall if thick + top/bottom annulus
26// caps). Faithful copy of generate_cylinder_points.
27inline std::vector<F3> genCylinderShell(float radius, float height, float thickness,
28 float spacing) {
29 std::vector<F3> points;
30
31 float r_outer = radius;
32 float r_inner = radius - thickness;
33 float h = height;
34
35 // 1. Outer surface
36 float circumference = 2.0f * kPi * r_outer;
37 int n_angular = std::ceil(circumference / spacing);
38 int n_vertical = std::ceil(h / spacing);
39
40 for (int i = 0; i < n_angular; ++i) {
41 float theta = 2.0f * kPi * i / n_angular;
42 for (int j = 0; j <= n_vertical; ++j) {
43 float y = -0.5f * h + h * j / n_vertical;
44 float x = r_outer * std::cos(theta);
45 float z = r_outer * std::sin(theta);
46 points.push_back(F3{x, y, z});
47 }
48 }
49
50 // 2. Inner surface (if thick)
51 if (thickness > 0.0f) {
52 circumference = 2.0f * kPi * r_inner;
53 n_angular = std::ceil(circumference / spacing);
54 for (int i = 0; i < n_angular; ++i) {
55 float theta = 2.0f * kPi * i / n_angular;
56 for (int j = 0; j <= n_vertical; ++j) {
57 float y = -0.5f * h + h * j / n_vertical;
58 float x = r_inner * std::cos(theta);
59 float z = r_inner * std::sin(theta);
60 points.push_back(F3{x, y, z});
61 }
62 }
63 }
64
65 // 3. Caps (annulus) — top and bottom
66 float dr = spacing;
67 int n_radial = std::ceil(thickness / dr);
68 for (int i = 0; i <= n_radial; ++i) {
69 float r = r_inner + (r_outer - r_inner) * i / n_radial;
70 circumference = 2.0f * kPi * r;
71 n_angular = std::ceil(circumference / spacing);
72 for (int j = 0; j < n_angular; ++j) {
73 float theta = 2.0f * kPi * j / n_angular;
74 float x = r * std::cos(theta);
75 float z = r * std::sin(theta);
76 points.push_back(F3{x, 0.5f * h, z}); // top
77 points.push_back(F3{x, -0.5f * h, z}); // bottom
78 }
79 }
80
81 return points;
82}
83
84// Surface points of an axis-aligned box: each of the 6 faces sampled on a grid whose endpoints land
85// on the box edges (so the 8 corners are present). Faithful copy of generate_box_points.
86inline std::vector<F3> genBoxShell(float hx, float hy, float hz, float spacing) {
87 std::vector<F3> points;
88 auto nseg = [&](float half) {
89 int n = (int)std::ceil(2.0f * half / spacing);
90 return n < 1 ? 1 : n;
91 };
92 int nx = nseg(hx), ny = nseg(hy), nz = nseg(hz);
93 auto lin = [](float half, int i, int n) { return -half + 2.0f * half * (float)i / (float)n; };
94
95 // +/- x faces (vary y,z)
96 for (int j = 0; j <= ny; ++j)
97 for (int k = 0; k <= nz; ++k) {
98 float y = lin(hy, j, ny), z = lin(hz, k, nz);
99 points.push_back(F3{hx, y, z});
100 points.push_back(F3{-hx, y, z});
101 }
102 // +/- y faces (vary x,z)
103 for (int i = 0; i <= nx; ++i)
104 for (int k = 0; k <= nz; ++k) {
105 float x = lin(hx, i, nx), z = lin(hz, k, nz);
106 points.push_back(F3{x, hy, z});
107 points.push_back(F3{x, -hy, z});
108 }
109 // +/- z faces (vary x,y)
110 for (int i = 0; i <= nx; ++i)
111 for (int j = 0; j <= ny; ++j) {
112 float x = lin(hx, i, nx), y = lin(hy, j, ny);
113 points.push_back(F3{x, y, hz});
114 points.push_back(F3{x, y, -hz});
115 }
116 return points;
117}
118
119} // namespace peclet::dem
120
121#endif // DEM_SHAPES_PORTABLE_HPP
dem — portable POD types + math + analytic SDFs shared by the Kokkos kernel ports.
std::vector< F3 > genCylinderShell(float radius, float height, float thickness, float spacing)
constexpr double kPi
std::vector< F3 > genBoxShell(float hx, float hy, float hz, float spacing)