Skip to content

Commit 590c965

Browse files
committed
Implemented kernel switching in pysplashsurf
1 parent e847828 commit 590c965

File tree

8 files changed

+128
-21
lines changed

8 files changed

+128
-21
lines changed

pysplashsurf/pysplashsurf/pysplashsurf.pyi

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,11 @@ class NeighborhoodLists:
185185

186186
class SphInterpolator:
187187
r"""
188-
Interpolator of per-particle quantities to arbitrary points using SPH interpolation (with cubic kernel)
188+
Interpolator of per-particle quantities to arbitrary points using SPH interpolation
189189
"""
190-
def __new__(cls, particle_positions:numpy.typing.NDArray[typing.Any], particle_densities:numpy.typing.NDArray[typing.Any], particle_rest_mass:builtins.float, compact_support_radius:builtins.float) -> SphInterpolator:
190+
def __new__(cls, particle_positions:numpy.typing.NDArray[typing.Any], particle_densities:numpy.typing.NDArray[typing.Any], particle_rest_mass:builtins.float, compact_support_radius:builtins.float, kernel_type:KernelType) -> SphInterpolator:
191191
r"""
192-
Constructs an SPH interpolator (with cubic kernels) for the given particles
192+
Constructs an SPH interpolator for the given particles
193193
194194
Parameters
195195
----------
@@ -200,7 +200,9 @@ class SphInterpolator:
200200
particle_rest_mass
201201
The rest mass of each particle (assumed to be the same for all particles).
202202
compact_support_radius
203-
The compact support radius of the cubic spline kernel used for interpolation.
203+
The compact support radius of the kernel used for interpolation.
204+
kernel_type
205+
The kernel function used for interpolation
204206
"""
205207
def interpolate_quantity(self, particle_quantity:numpy.typing.NDArray[typing.Any], interpolation_points:numpy.typing.NDArray[typing.Any], *, first_order_correction:builtins.bool=False) -> numpy.typing.NDArray[typing.Any]:
206208
r"""
@@ -315,6 +317,15 @@ class VertexVertexConnectivity:
315317
Returns the wrapped connectivity data by moving it out of this object (zero copy)
316318
"""
317319

320+
class KernelType(Enum):
321+
r"""
322+
Enum for specifying the Kernel function used for the reconstruction
323+
"""
324+
CubicSpline = ...
325+
Poly6 = ...
326+
Spiky = ...
327+
WendlandQuinticC2 = ...
328+
318329
class MeshType(Enum):
319330
r"""
320331
Enum specifying the type of mesh wrapped by a ``MeshWithData``
@@ -497,7 +508,7 @@ def neighborhood_search_spatial_hashing_parallel(particle_positions:numpy.typing
497508
The radius per particle where other particles are considered neighbors.
498509
"""
499510

500-
def reconstruct_surface(particles:numpy.typing.NDArray[typing.Any], *, particle_radius:builtins.float, rest_density:builtins.float=1000.0, smoothing_length:builtins.float, cube_size:builtins.float, iso_surface_threshold:builtins.float=0.6, aabb_min:typing.Optional[typing.Sequence[builtins.float]]=None, aabb_max:typing.Optional[typing.Sequence[builtins.float]]=None, multi_threading:builtins.bool=True, global_neighborhood_list:builtins.bool=False, subdomain_grid:builtins.bool=True, subdomain_grid_auto_disable:builtins.bool=True, subdomain_num_cubes_per_dim:builtins.int=64) -> SurfaceReconstruction:
511+
def reconstruct_surface(particles:numpy.typing.NDArray[typing.Any], *, particle_radius:builtins.float, rest_density:builtins.float=1000.0, smoothing_length:builtins.float, cube_size:builtins.float, iso_surface_threshold:builtins.float=0.6, aabb_min:typing.Optional[typing.Sequence[builtins.float]]=None, aabb_max:typing.Optional[typing.Sequence[builtins.float]]=None, multi_threading:builtins.bool=True, simd:builtins.bool=True, kernel_type:KernelType=..., global_neighborhood_list:builtins.bool=False, subdomain_grid:builtins.bool=True, subdomain_grid_auto_disable:builtins.bool=True, subdomain_num_cubes_per_dim:builtins.int=64) -> SurfaceReconstruction:
501512
r"""
502513
Performs a surface reconstruction from the given particles without additional post-processing
503514
@@ -523,6 +534,8 @@ def reconstruct_surface(particles:numpy.typing.NDArray[typing.Any], *, particle_
523534
Upper corner of the AABB of particles to consider in the reconstruction.
524535
multi_threading
525536
Flag to enable multi-threading for the reconstruction and post-processing steps.
537+
simd
538+
Flag to enable SIMD vectorization for the reconstruction if supported by the CPU architecture.
526539
subdomain_grid
527540
Flag to enable spatial decomposition by dividing the domain into subdomains with dense marching cube grids for efficient multi-threading.
528541
subdomain_grid_auto_disable
@@ -531,7 +544,7 @@ def reconstruct_surface(particles:numpy.typing.NDArray[typing.Any], *, particle_
531544
Number of marching cubes voxels along each coordinate axis in each subdomain if the subdomain grid is enabled.
532545
"""
533546

534-
def reconstruction_pipeline(particles:numpy.typing.NDArray[typing.Any], *, attributes_to_interpolate:typing.Optional[dict]=None, particle_radius:builtins.float, rest_density:builtins.float=1000.0, smoothing_length:builtins.float, cube_size:builtins.float, iso_surface_threshold:builtins.float=0.6, aabb_min:typing.Optional[typing.Sequence[builtins.float]]=None, aabb_max:typing.Optional[typing.Sequence[builtins.float]]=None, multi_threading:builtins.bool=True, subdomain_grid:builtins.bool=True, subdomain_grid_auto_disable:builtins.bool=True, subdomain_num_cubes_per_dim:builtins.int=64, check_mesh_closed:builtins.bool=False, check_mesh_manifold:builtins.bool=False, check_mesh_orientation:builtins.bool=False, check_mesh_debug:builtins.bool=False, mesh_cleanup:builtins.bool=False, mesh_cleanup_snap_dist:typing.Optional[builtins.float]=None, decimate_barnacles:builtins.bool=False, keep_vertices:builtins.bool=False, compute_normals:builtins.bool=False, sph_normals:builtins.bool=False, normals_smoothing_iters:typing.Optional[builtins.int]=None, mesh_smoothing_iters:typing.Optional[builtins.int]=None, mesh_smoothing_weights:builtins.bool=True, mesh_smoothing_weights_normalization:builtins.float=13.0, generate_quads:builtins.bool=False, quad_max_edge_diag_ratio:builtins.float=1.75, quad_max_normal_angle:builtins.float=10.0, quad_max_interior_angle:builtins.float=135.0, output_mesh_smoothing_weights:builtins.bool=False, output_raw_normals:builtins.bool=False, output_raw_mesh:builtins.bool=False, mesh_aabb_min:typing.Optional[typing.Sequence[builtins.float]]=None, mesh_aabb_max:typing.Optional[typing.Sequence[builtins.float]]=None, mesh_aabb_clamp_vertices:builtins.bool=True) -> tuple[MeshWithData, SurfaceReconstruction]:
547+
def reconstruction_pipeline(particles:numpy.typing.NDArray[typing.Any], *, attributes_to_interpolate:typing.Optional[dict]=None, particle_radius:builtins.float, rest_density:builtins.float=1000.0, smoothing_length:builtins.float, cube_size:builtins.float, iso_surface_threshold:builtins.float=0.6, aabb_min:typing.Optional[typing.Sequence[builtins.float]]=None, aabb_max:typing.Optional[typing.Sequence[builtins.float]]=None, multi_threading:builtins.bool=True, simd:builtins.bool=True, kernel_type:KernelType=..., subdomain_grid:builtins.bool=True, subdomain_grid_auto_disable:builtins.bool=True, subdomain_num_cubes_per_dim:builtins.int=64, check_mesh_closed:builtins.bool=False, check_mesh_manifold:builtins.bool=False, check_mesh_orientation:builtins.bool=False, check_mesh_debug:builtins.bool=False, mesh_cleanup:builtins.bool=False, mesh_cleanup_snap_dist:typing.Optional[builtins.float]=None, decimate_barnacles:builtins.bool=False, keep_vertices:builtins.bool=False, compute_normals:builtins.bool=False, sph_normals:builtins.bool=False, normals_smoothing_iters:typing.Optional[builtins.int]=None, mesh_smoothing_iters:typing.Optional[builtins.int]=None, mesh_smoothing_weights:builtins.bool=True, mesh_smoothing_weights_normalization:builtins.float=13.0, generate_quads:builtins.bool=False, quad_max_edge_diag_ratio:builtins.float=1.75, quad_max_normal_angle:builtins.float=10.0, quad_max_interior_angle:builtins.float=135.0, output_mesh_smoothing_weights:builtins.bool=False, output_raw_normals:builtins.bool=False, output_raw_mesh:builtins.bool=False, mesh_aabb_min:typing.Optional[typing.Sequence[builtins.float]]=None, mesh_aabb_max:typing.Optional[typing.Sequence[builtins.float]]=None, mesh_aabb_clamp_vertices:builtins.bool=True) -> tuple[MeshWithData, SurfaceReconstruction]:
535548
r"""
536549
Runs the surface reconstruction pipeline for the given particle positions with optional post-processing
537550
@@ -561,6 +574,10 @@ def reconstruction_pipeline(particles:numpy.typing.NDArray[typing.Any], *, attri
561574
Upper corner [x,y,z] of the AABB of particles to consider in the reconstruction.
562575
multi_threading
563576
Flag to enable multi-threading for the reconstruction and post-processing steps.
577+
simd
578+
Flag to enable SIMD vectorization for the reconstruction if supported by the CPU architecture.
579+
kernel_type
580+
Kernel function to use for the reconstruction.
564581
subdomain_grid
565582
Flag to enable spatial decomposition by dividing the domain into subdomains with dense marching cube grids for efficient multi-threading.
566583
subdomain_grid_auto_disable

pysplashsurf/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fn pysplashsurf(m: &Bound<'_, PyModule>) -> PyResult<()> {
3939
m.add_class::<uniform_grid::PyUniformGrid>()?;
4040
m.add_class::<reconstruction::PySurfaceReconstruction>()?;
4141
m.add_class::<sph_interpolation::PySphInterpolator>()?;
42+
m.add_class::<utils::KernelType>()?;
4243

4344
use wrap_pyfunction as wrap;
4445

pysplashsurf/src/pipeline.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::borrow::Cow;
1818

1919
use crate::mesh::PyMeshWithData;
2020
use crate::reconstruction::PySurfaceReconstruction;
21-
use crate::utils::{IndexT, pyerr_unsupported_scalar};
21+
use crate::utils::{IndexT, KernelType, pyerr_unsupported_scalar};
2222

2323
/// Runs the surface reconstruction pipeline for the given particle positions with optional post-processing
2424
///
@@ -49,7 +49,9 @@ use crate::utils::{IndexT, pyerr_unsupported_scalar};
4949
/// multi_threading
5050
/// Flag to enable multi-threading for the reconstruction and post-processing steps.
5151
/// simd
52-
/// Flag to enable SIMD vectorization for the reconstruction if supported by the CPU architecture.
52+
/// Flag to enable SIMD vectorization for the reconstruction if supported by the CPU architecture.
53+
/// kernel_type
54+
/// Kernel function to use for the reconstruction.
5355
/// subdomain_grid
5456
/// Flag to enable spatial decomposition by dividing the domain into subdomains with dense marching cube grids for efficient multi-threading.
5557
/// subdomain_grid_auto_disable
@@ -110,7 +112,7 @@ use crate::utils::{IndexT, pyerr_unsupported_scalar};
110112
#[pyo3(name = "reconstruction_pipeline")]
111113
#[pyo3(signature = (particles, *, attributes_to_interpolate = None,
112114
particle_radius, rest_density = 1000.0, smoothing_length, cube_size, iso_surface_threshold = 0.6,
113-
aabb_min = None, aabb_max = None, multi_threading = true, simd = true,
115+
aabb_min = None, aabb_max = None, multi_threading = true, simd = true, kernel_type = KernelType::CubicSpline,
114116
subdomain_grid = true, subdomain_grid_auto_disable = true, subdomain_num_cubes_per_dim = 64,
115117
check_mesh_closed = false, check_mesh_manifold = false, check_mesh_orientation = false, check_mesh_debug = false,
116118
mesh_cleanup = false, mesh_cleanup_snap_dist = None, decimate_barnacles = false, keep_vertices = false, compute_normals = false, sph_normals = false,
@@ -131,6 +133,7 @@ pub fn reconstruction_pipeline<'py>(
131133
aabb_max: Option<[f64; 3]>,
132134
multi_threading: bool,
133135
simd: bool,
136+
kernel_type: KernelType,
134137
subdomain_grid: bool,
135138
subdomain_grid_auto_disable: bool,
136139
subdomain_num_cubes_per_dim: u32,
@@ -198,7 +201,7 @@ pub fn reconstruction_pipeline<'py>(
198201
enable_simd: simd,
199202
spatial_decomposition,
200203
global_neighborhood_list: false,
201-
kernel_type: splashsurf_lib::kernel::KernelType::CubicSpline,
204+
kernel_type: kernel_type.into_lib_enum(),
202205
};
203206

204207
let postprocessing_args = splashsurf::reconstruct::ReconstructionPostprocessingParameters {

pysplashsurf/src/reconstruction.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::mesh::PyTriMesh3d;
22
use crate::neighborhood_search::PyNeighborhoodLists;
33
use crate::uniform_grid::PyUniformGrid;
4-
use crate::utils;
4+
use crate::utils::{self, KernelType};
55
use anyhow::anyhow;
66
use ndarray::ArrayView1;
77
use numpy as np;
@@ -124,6 +124,8 @@ impl PySurfaceReconstruction {
124124
/// Flag to enable multi-threading for the reconstruction and post-processing steps.
125125
/// simd
126126
/// Flag to enable SIMD vectorization for the reconstruction if supported by the CPU architecture.
127+
/// kernel_type
128+
/// Kernel function to use for the reconstruction.
127129
/// subdomain_grid
128130
/// Flag to enable spatial decomposition by dividing the domain into subdomains with dense marching cube grids for efficient multi-threading.
129131
/// subdomain_grid_auto_disable
@@ -135,8 +137,8 @@ impl PySurfaceReconstruction {
135137
#[pyo3(name = "reconstruct_surface")]
136138
#[pyo3(signature = (particles, *,
137139
particle_radius, rest_density = 1000.0, smoothing_length, cube_size, iso_surface_threshold = 0.6,
138-
aabb_min = None, aabb_max = None,
139-
multi_threading = true, simd = true, global_neighborhood_list = false,
140+
aabb_min = None, aabb_max = None, multi_threading = true, simd = true,
141+
kernel_type = KernelType::CubicSpline, global_neighborhood_list = false,
140142
subdomain_grid = true, subdomain_grid_auto_disable = true, subdomain_num_cubes_per_dim = 64
141143
))]
142144
pub fn reconstruct_surface<'py>(
@@ -150,6 +152,7 @@ pub fn reconstruct_surface<'py>(
150152
aabb_max: Option<[f64; 3]>,
151153
multi_threading: bool,
152154
simd: bool,
155+
kernel_type: KernelType,
153156
global_neighborhood_list: bool,
154157
subdomain_grid: bool,
155158
subdomain_grid_auto_disable: bool,
@@ -181,7 +184,7 @@ pub fn reconstruct_surface<'py>(
181184
enable_simd: simd,
182185
spatial_decomposition,
183186
global_neighborhood_list,
184-
kernel_type: splashsurf_lib::kernel::KernelType::CubicSpline,
187+
kernel_type: kernel_type.into_lib_enum(),
185188
};
186189

187190
let element_type = particles.dtype();

pysplashsurf/src/sph_interpolation.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
use crate::utils::*;
1+
use crate::utils::{KernelType, *};
22
use numpy as np;
33
use numpy::prelude::*;
44
use numpy::{Element, PyArray1, PyArray2, PyUntypedArray};
55
use pyo3::PyResult;
66
use pyo3::exceptions::PyValueError;
77
use pyo3::prelude::*;
88
use pyo3_stub_gen::derive::*;
9-
use splashsurf_lib::kernel::KernelType;
109
use splashsurf_lib::nalgebra::SVector;
1110
use splashsurf_lib::{
1211
Real,
@@ -19,7 +18,7 @@ enum PySphInterpolatorWrapper {
1918
F64(SphInterpolator<f64>),
2019
}
2120

22-
/// Interpolator of per-particle quantities to arbitrary points using SPH interpolation (with cubic kernel)
21+
/// Interpolator of per-particle quantities to arbitrary points using SPH interpolation
2322
#[gen_stub_pyclass]
2423
#[pyclass]
2524
#[pyo3(name = "SphInterpolator")]
@@ -36,6 +35,7 @@ impl PySphInterpolator {
3635
particle_densities: &Bound<'py, PyUntypedArray>,
3736
particle_rest_mass: f64,
3837
compact_support_radius: f64,
38+
kernel_type: KernelType,
3939
) -> PyResult<PySphInterpolator>
4040
where
4141
PySphInterpolator: From<SphInterpolator<R>>,
@@ -55,7 +55,7 @@ impl PySphInterpolator {
5555
densities,
5656
R::from_float(particle_rest_mass),
5757
R::from_float(compact_support_radius),
58-
KernelType::CubicSpline,
58+
kernel_type.into_lib_enum(),
5959
)))
6060
} else {
6161
Err(pyerr_scalar_type_mismatch())
@@ -160,7 +160,7 @@ impl PySphInterpolator {
160160
#[gen_stub_pymethods]
161161
#[pymethods]
162162
impl PySphInterpolator {
163-
/// Constructs an SPH interpolator (with cubic kernels) for the given particles
163+
/// Constructs an SPH interpolator for the given particles
164164
///
165165
/// Parameters
166166
/// ----------
@@ -171,13 +171,16 @@ impl PySphInterpolator {
171171
/// particle_rest_mass
172172
/// The rest mass of each particle (assumed to be the same for all particles).
173173
/// compact_support_radius
174-
/// The compact support radius of the cubic spline kernel used for interpolation.
174+
/// The compact support radius of the kernel used for interpolation.
175+
/// kernel_type
176+
/// The kernel function used for interpolation
175177
#[new]
176178
fn py_new<'py>(
177179
particle_positions: &Bound<'py, PyUntypedArray>,
178180
particle_densities: &Bound<'py, PyUntypedArray>,
179181
particle_rest_mass: f64,
180182
compact_support_radius: f64,
183+
kernel_type: KernelType,
181184
) -> PyResult<Self> {
182185
let py = particle_positions.py();
183186
let element_type = particle_positions.dtype();
@@ -188,13 +191,15 @@ impl PySphInterpolator {
188191
particle_densities,
189192
particle_rest_mass,
190193
compact_support_radius,
194+
kernel_type,
191195
)
192196
} else if element_type.is_equiv_to(&np::dtype::<f64>(py)) {
193197
Self::new_generic::<f64>(
194198
particle_positions,
195199
particle_densities,
196200
particle_rest_mass,
197201
compact_support_radius,
202+
kernel_type,
198203
)
199204
} else {
200205
Err(pyerr_unsupported_scalar())

pysplashsurf/src/utils.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,32 @@ use numpy::{Element, PyArray, PyUntypedArray};
33
use pyo3::exceptions::PyTypeError;
44
use pyo3::prelude::*;
55
use pyo3::{Bound, PyAny, PyErr, PyResult};
6+
use pyo3_stub_gen::derive::gen_stub_pyclass_enum;
67
use splashsurf_lib::Real;
78
use splashsurf_lib::nalgebra::SVector;
89

10+
/// Enum for specifying the Kernel function used for the reconstruction
11+
#[gen_stub_pyclass_enum]
12+
#[pyclass]
13+
#[derive(Clone)]
14+
pub enum KernelType {
15+
CubicSpline,
16+
Poly6,
17+
Spiky,
18+
WendlandQuinticC2,
19+
}
20+
21+
impl KernelType {
22+
pub fn into_lib_enum(&self) -> splashsurf_lib::kernel::KernelType {
23+
match self {
24+
KernelType::CubicSpline => splashsurf_lib::kernel::KernelType::CubicSpline,
25+
KernelType::Poly6 => splashsurf_lib::kernel::KernelType::Poly6,
26+
KernelType::Spiky => splashsurf_lib::kernel::KernelType::Spiky,
27+
KernelType::WendlandQuinticC2 => splashsurf_lib::kernel::KernelType::WendlandQuinticC2,
28+
}
29+
}
30+
}
31+
932
/// The index type used for all grids and reconstructions in this crate
1033
pub(crate) type IndexT = i64;
1134

pysplashsurf/tests/test_basic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ def interpolator_test(dtype):
301301
rest_mass = 1000.0 * 0.025**3
302302

303303
interpolator = pysplashsurf.SphInterpolator(
304-
particles, reconstruction.particle_densities, rest_mass, compact_support
304+
particles, reconstruction.particle_densities, rest_mass, compact_support, pysplashsurf.KernelType.CubicSpline
305305
)
306306

307307
assert type(interpolator) is pysplashsurf.SphInterpolator

0 commit comments

Comments
 (0)