pnm 1.0.3
peclet.pnm — pore-network extraction from SDF geometry (Kokkos)
Loading...
Searching...
No Matches
synthetic_sdf.hpp
Go to the documentation of this file.
1// peclet-pnm — deterministic synthetic SDFs shared by the single-rank (tests/kokkos) and the
2// distributed (tests/kokkos_mpi) tests. Sign convention: NEGATIVE inside solid, positive in the
3// pore space (suite-wide). Every generator is a pure function of the integer voxel coordinates so
4// a block sampled on one rank equals the corresponding slice of the full grid sampled on another.
5#ifndef PECLET_PNM_TESTS_SYNTHETIC_SDF_HPP
6#define PECLET_PNM_TESTS_SYNTHETIC_SDF_HPP
7
8#include <algorithm>
9#include <array>
10#include <cmath>
11#include <cstddef>
12#include <vector>
13
14namespace pnm::test {
15
18inline float sphereLatticeSdf(int gx, int gy, int gz, std::array<int, 3> gd) {
19 const float R = 0.22f * std::min(gd[0], std::min(gd[1], gd[2]));
20 float best = 1e30f;
21 for (int cz = 0; cz < 2; ++cz)
22 for (int cy = 0; cy < 2; ++cy)
23 for (int cx = 0; cx < 2; ++cx) {
24 const float ccx = gd[0] * (2 * cx + 1) / 4.0f, ccy = gd[1] * (2 * cy + 1) / 4.0f,
25 ccz = gd[2] * (2 * cz + 1) / 4.0f;
26 float dx = std::fabs(gx - ccx), dy = std::fabs(gy - ccy), dz = std::fabs(gz - ccz);
27 dx = std::min(dx, gd[0] - dx);
28 dy = std::min(dy, gd[1] - dy);
29 dz = std::min(dz, gd[2] - dz);
30 best = std::min(best, std::sqrt(dx * dx + dy * dy + dz * dz) - R);
31 }
32 return best; // negative INSIDE the spheres (solid), positive at the interstices (pore)
33}
34
36inline float trigSdf(int gx, int gy, int gz, std::array<int, 3> gd) {
37 const float x = 2.0f * float(M_PI) * gx / gd[0], y = 2.0f * float(M_PI) * gy / gd[1],
38 z = 2.0f * float(M_PI) * gz / gd[2];
39 return std::sin(x) * std::cos(y) + 0.7f * std::sin(2.0f * z) - 0.1f;
40}
41
44inline float spherePoreSdf(int gx, int gy, int gz, std::array<int, 3> c, float radius) {
45 const float dx = float(gx - c[0]), dy = float(gy - c[1]), dz = float(gz - c[2]);
46 return radius - std::sqrt(dx * dx + dy * dy + dz * dz);
47}
48
51inline float twoSpherePoresSdf(int gx, int gy, int gz, std::array<int, 3> c1, std::array<int, 3> c2,
52 float radius) {
53 return std::max(spherePoreSdf(gx, gy, gz, c1, radius), spherePoreSdf(gx, gy, gz, c2, radius));
54}
55
57template <class SdfFn>
58std::vector<float> sampleGrid(std::array<int, 3> gd, const SdfFn& fn) {
59 std::vector<float> v(std::size_t(gd[0]) * gd[1] * gd[2]);
60 for (int z = 0; z < gd[2]; ++z)
61 for (int y = 0; y < gd[1]; ++y)
62 for (int x = 0; x < gd[0]; ++x)
63 v[(std::size_t(z) * gd[1] + y) * gd[0] + x] = fn(x, y, z);
64 return v;
65}
66
67} // namespace pnm::test
68
69#endif // PECLET_PNM_TESTS_SYNTHETIC_SDF_HPP
float sphereLatticeSdf(int gx, int gy, int gz, std::array< int, 3 > gd)
2x2x2 lattice of SOLID spheres in a periodic box (min-image distance); pores at the interstices.
std::vector< float > sampleGrid(std::array< int, 3 > gd, const SdfFn &fn)
Sample fn(gx, gy, gz) over the whole gd grid in pnm's flat x-fastest layout.
float trigSdf(int gx, int gy, int gz, std::array< int, 3 > gd)
Smooth trigonometric field with wrap-around components (exercises the periodic images).
float twoSpherePoresSdf(int gx, int gy, int gz, std::array< int, 3 > c1, std::array< int, 3 > c2, float radius)
Two overlapping spherical pores (the union = max of the two SDFs); a throat at the mid-plane when the...
float spherePoreSdf(int gx, int gy, int gz, std::array< int, 3 > c, float radius)
One spherical PORE (SDF > 0 inside) of radius radius centred on the integer voxel c; solid everywhere...