28static std::vector<float>
to_sdf(nb::ndarray<float, nb::c_contig> a, std::array<int, 3>& res) {
30 throw std::runtime_error(
"SDF array must be 3D (Nz,Ny,Nx)");
31 res = {(int)a.shape(2), (int)a.shape(1), (int)a.shape(0)};
32 return peclet::core::python::ndarray_to_vector<float>(nb::ndarray<>(a));
36 m.attr(
"__doc__") =
"pnm — pore-network extraction from SDF geometry (Kokkos)";
37 if (!Kokkos::is_initialized())
42 nb::module_::import_(
"atexit").attr(
"register")(nb::cpp_function([]() {
43 if (Kokkos::is_initialized() && !Kokkos::is_finalized())
46 m.attr(
"execution_space") = nb::str(Kokkos::DefaultExecutionSpace::name());
49 nb::class_<SDFReader>(m,
"SDFReader")
52 [](
const std::string& filename) {
54 std::size_t shape[3]{(std::size_t)data->resolution[2], (std::size_t)data->resolution[1],
55 (std::size_t)data->resolution[0]};
56 std::vector<double> org{data->origin[2], data->origin[1], data->origin[0]};
57 std::vector<double> spc{data->spacing[2], data->spacing[1], data->spacing[0]};
60 nb::capsule owner(data, [](
void* p)
noexcept {
delete static_cast<SDFData*
>(p); });
61 nb::ndarray<nb::numpy, float> sdf_3d(data->sdf_values.data(), 3, shape, owner);
62 return nb::make_tuple(sdf_3d, org, spc);
64 "Reads VTI; returns (sdf_3d[nz,ny,nx], origin_zyx, spacing_zyx)");
66 nb::class_<Pore>(m,
"Pore")
74 [](nb::ndarray<float, nb::c_contig> sdf, std::vector<double> origin_zyx,
75 std::vector<double> spacing_zyx) {
76 std::array<int, 3> res;
78 std::array<float, 3> org{(float)origin_zyx[2], (
float)origin_zyx[1], (float)origin_zyx[0]};
79 std::array<float, 3> spc{(float)spacing_zyx[2], (
float)spacing_zyx[1],
80 (float)spacing_zyx[0]};
83 nb::arg(
"sdf"), nb::arg(
"origin_zyx"), nb::arg(
"spacing_zyx"));
87 [](nb::ndarray<float, nb::c_contig> sdf, std::vector<double> spacing_zyx) {
88 std::array<int, 3> res;
90 std::array<float, 3> spc{(float)spacing_zyx[2], (
float)spacing_zyx[1],
91 (float)spacing_zyx[0]};
94 nb::arg(
"sdf"), nb::arg(
"spacing_zyx"));
97 "extract_topology_gpu",
98 [](std::vector<int> segmentation, std::vector<int> shape_zyx) {
99 std::array<int, 3> res{shape_zyx[2], shape_zyx[1], shape_zyx[0]};
102 nb::arg(
"segmentation"), nb::arg(
"shape"));
106 "extract_pore_network",
107 [](nb::ndarray<float, nb::c_contig> sdf, std::vector<double> origin_zyx,
108 std::vector<double> spacing_zyx) {
109 std::array<int, 3> res;
110 auto v =
to_sdf(sdf, res);
111 std::array<float, 3> org{(float)origin_zyx[2], (
float)origin_zyx[1], (float)origin_zyx[0]};
112 std::array<float, 3> spc{(float)spacing_zyx[2], (
float)spacing_zyx[1],
113 (float)spacing_zyx[0]};
117 nb::arg(
"sdf"), nb::arg(
"origin_zyx"), nb::arg(
"spacing_zyx"),
118 "Fused extraction (SDF uploaded once, segmentation device-resident across stages): returns "
119 "(pores, segmentation_flat, connections).");
std::vector< Pore > extract_pores_k(const std::vector< float > &sdf_h, std::array< int, 3 > resolution, std::array< float, 3 > origin, std::array< float, 3 > spacing)
PoreNetwork extract_pore_network_k(const std::vector< float > &sdf_h, std::array< int, 3 > resolution, std::array< float, 3 > origin, std::array< float, 3 > spacing)