Skip to content

Commit 26699bb

Browse files
committed
Implement filtering of particles according to AABB
1 parent 1ecc72c commit 26699bb

7 files changed

Lines changed: 82 additions & 27 deletions

File tree

splashsurf/src/reconstruction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ mod arguments {
411411
compact_support_radius,
412412
cube_size,
413413
iso_surface_threshold: args.surface_threshold,
414-
domain_aabb,
414+
particle_aabb: domain_aabb,
415415
enable_multi_threading: args.parallelize_over_particles.into_bool(),
416416
spatial_decomposition,
417417
};

splashsurf_lib/benches/benches/bench_full.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub fn surface_reconstruction_dam_break(c: &mut Criterion) {
101101
compact_support_radius,
102102
cube_size,
103103
iso_surface_threshold: 0.6,
104-
domain_aabb: None,
104+
particle_aabb: None,
105105
enable_multi_threading: true,
106106
spatial_decomposition: None,
107107
};
@@ -199,7 +199,7 @@ pub fn surface_reconstruction_double_dam_break(c: &mut Criterion) {
199199
compact_support_radius,
200200
cube_size,
201201
iso_surface_threshold: 0.6,
202-
domain_aabb: None,
202+
particle_aabb: None,
203203
enable_multi_threading: true,
204204
spatial_decomposition: None,
205205
};
@@ -297,7 +297,7 @@ pub fn surface_reconstruction_double_dam_break_inplace(c: &mut Criterion) {
297297
compact_support_radius,
298298
cube_size,
299299
iso_surface_threshold: 0.6,
300-
domain_aabb: None,
300+
particle_aabb: None,
301301
enable_multi_threading: true,
302302
spatial_decomposition: None,
303303
};

splashsurf_lib/benches/benches/bench_mesh.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn reconstruct_particles<P: AsRef<Path>>(particle_file: P) -> SurfaceReconstruct
2222
compact_support_radius,
2323
cube_size,
2424
iso_surface_threshold: 0.6,
25-
domain_aabb: None,
25+
particle_aabb: None,
2626
enable_multi_threading: true,
2727
spatial_decomposition: Some(SpatialDecomposition::Octree(
2828
OctreeDecompositionParameters {

splashsurf_lib/benches/benches/bench_subdomain_grid.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn parameters_canyon() -> Parameters<f32> {
1818
compact_support_radius,
1919
cube_size,
2020
iso_surface_threshold: 0.6,
21-
domain_aabb: None,
21+
particle_aabb: None,
2222
enable_multi_threading: true,
2323
spatial_decomposition: Some(SpatialDecomposition::UniformGrid(
2424
GridDecompositionParameters {

splashsurf_lib/src/lib.rs

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use log::info;
2727
/// Re-export the version of `nalgebra` used by this crate
2828
pub use nalgebra;
2929
use nalgebra::Vector3;
30+
use std::borrow::Cow;
3031
use std::hash::Hash;
3132
use thiserror::Error as ThisError;
3233
/// Re-export the version of `vtkio` used by this crate, if vtk support is enabled
@@ -258,7 +259,7 @@ pub struct Parameters<R: Real> {
258259
/// The surface reconstruction always results in a closed mesh around the particles.
259260
/// The final mesh can extend beyond this AABB due to the smoothing of the kernel.
260261
/// If not provided, the smallest AABB enclosing all particles is computed instead.
261-
pub domain_aabb: Option<Aabb3d<R>>,
262+
pub particle_aabb: Option<Aabb3d<R>>,
262263
/// Whether to allow multi threading within the surface reconstruction procedure
263264
pub enable_multi_threading: bool,
264265
/// Parameters for the spatial decomposition of the surface reconstruction
@@ -275,7 +276,7 @@ impl<R: Real> Parameters<R> {
275276
compact_support_radius: self.compact_support_radius.try_convert()?,
276277
cube_size: self.cube_size.try_convert()?,
277278
iso_surface_threshold: self.iso_surface_threshold.try_convert()?,
278-
domain_aabb: map_option!(&self.domain_aabb, aabb => aabb.try_convert()?),
279+
particle_aabb: map_option!(&self.particle_aabb, aabb => aabb.try_convert()?),
279280
enable_multi_threading: self.enable_multi_threading,
280281
spatial_decomposition: map_option!(&self.spatial_decomposition, sd => sd.try_convert()?),
281282
})
@@ -287,12 +288,14 @@ impl<R: Real> Parameters<R> {
287288
pub struct SurfaceReconstruction<I: Index, R: Real> {
288289
/// Background grid that was used as a basis for generating the density map for marching cubes
289290
grid: UniformGrid<I, R>,
290-
/// Octree constructed for domain decomposition
291+
/// Octree constructed for domain decomposition (if octree-based spatial decomposition was enabled)
291292
octree: Option<Octree<I, R>>,
292293
/// Point-based density map generated from the particles that was used as input to marching cubes
293294
density_map: Option<DensityMap<I, R>>,
294-
/// Per particle densities
295+
/// Per particle densities (contains only data of particles inside the domain)
295296
particle_densities: Option<Vec<R>>,
297+
/// If an AABB was specified to restrict the reconstruction, this stores per input particle whether they were inside
298+
particle_inside_aabb: Option<Vec<bool>>,
296299
/// Surface mesh that is the result of the surface reconstruction
297300
mesh: TriMesh3d<R>,
298301
/// Workspace with allocated memory for subsequent surface reconstructions
@@ -307,6 +310,7 @@ impl<I: Index, R: Real> Default for SurfaceReconstruction<I, R> {
307310
octree: None,
308311
density_map: None,
309312
particle_densities: None,
313+
particle_inside_aabb: None,
310314
mesh: TriMesh3d::default(),
311315
workspace: ReconstructionWorkspace::default(),
312316
}
@@ -409,13 +413,52 @@ pub fn reconstruct_surface_inplace<'a, I: Index, R: Real>(
409413
// Clear the existing mesh
410414
output_surface.mesh.clear();
411415

416+
// Filter out particles
417+
let filtered_particle_positions = if let Some(particle_aabb) = &parameters.particle_aabb {
418+
profile!("filtering particles");
419+
420+
use rayon::prelude::*;
421+
let mut particle_inside = output_surface
422+
.particle_inside_aabb
423+
.take()
424+
.unwrap_or_default();
425+
utils::reserve_total(&mut particle_inside, particle_positions.len());
426+
particle_positions
427+
.par_iter()
428+
.map(|p| particle_aabb.contains_point(p))
429+
.collect_into_vec(&mut particle_inside);
430+
let particle_inside_count = particle_inside.par_iter().copied().filter(|i| *i).count();
431+
432+
// Take temporary storage for filtered particles from workspace
433+
let mut filtered_particles =
434+
std::mem::take(output_surface.workspace.filtered_particles_mut());
435+
filtered_particles.clear();
436+
utils::reserve_total(&mut filtered_particles, particle_inside_count);
437+
438+
// Collect filtered particles
439+
filtered_particles.extend(
440+
particle_positions
441+
.iter()
442+
.zip(particle_inside.iter().copied())
443+
.filter(|(_, is_inside)| *is_inside)
444+
.map(|(p, _)| p)
445+
.cloned(),
446+
);
447+
448+
output_surface.particle_inside_aabb = Some(particle_inside);
449+
Cow::Owned(filtered_particles)
450+
} else {
451+
Cow::Borrowed(particle_positions)
452+
};
453+
let particle_positions = filtered_particle_positions.as_ref();
454+
412455
// Initialize grid for the reconstruction
413456
output_surface.grid = grid_for_reconstruction(
414457
particle_positions,
415458
parameters.particle_radius,
416459
parameters.compact_support_radius,
417460
parameters.cube_size,
418-
parameters.domain_aabb.as_ref(),
461+
parameters.particle_aabb.as_ref(),
419462
parameters.enable_multi_threading,
420463
)?;
421464

@@ -443,6 +486,12 @@ pub fn reconstruct_surface_inplace<'a, I: Index, R: Real>(
443486
)?,
444487
}
445488

489+
// Put back temporary storage for filtered particles for next reconstruction
490+
if let Cow::Owned(mut filtered_particles) = filtered_particle_positions {
491+
filtered_particles.clear();
492+
*output_surface.workspace.filtered_particles_mut() = filtered_particles;
493+
}
494+
446495
Ok(())
447496
}
448497

@@ -458,39 +507,38 @@ pub fn grid_for_reconstruction<I: Index, R: Real>(
458507
particle_radius: R,
459508
compact_support_radius: R,
460509
cube_size: R,
461-
domain_aabb: Option<&Aabb3d<R>>,
510+
particle_aabb: Option<&Aabb3d<R>>,
462511
enable_multi_threading: bool,
463512
) -> Result<UniformGrid<I, R>, ReconstructionError<I, R>> {
464-
let domain_aabb = if let Some(domain_aabb) = domain_aabb {
465-
domain_aabb.clone()
513+
let mut particle_aabb = if let Some(particle_aabb) = particle_aabb {
514+
particle_aabb.clone()
466515
} else {
467516
profile!("compute minimum enclosing aabb");
468517

469-
let mut domain_aabb = {
518+
let particle_aabb = {
470519
let mut aabb = if enable_multi_threading {
471520
Aabb3d::par_from_points(particle_positions)
472521
} else {
473522
Aabb3d::from_points(particle_positions)
474523
};
524+
// TODO: Is this really necessary?
475525
aabb.grow_uniformly(particle_radius);
476526
aabb
477527
};
478528

479529
info!(
480530
"Minimal enclosing bounding box of particles was computed as: {:?}",
481-
domain_aabb
531+
particle_aabb
482532
);
483533

484-
// Ensure that we have enough margin around the particles such that the every particle's kernel support is completely in the domain
485-
let kernel_margin = density_map::compute_kernel_evaluation_radius::<I, R>(
486-
compact_support_radius,
487-
cube_size,
488-
)
489-
.kernel_evaluation_radius;
490-
domain_aabb.grow_uniformly(kernel_margin);
491-
492-
domain_aabb
534+
particle_aabb
493535
};
494536

495-
Ok(UniformGrid::from_aabb(&domain_aabb, cube_size)?)
537+
// Ensure that we have enough margin around the particles such that the every particle's kernel support is completely in the domain
538+
let kernel_margin =
539+
density_map::compute_kernel_evaluation_radius::<I, R>(compact_support_radius, cube_size)
540+
.kernel_evaluation_radius;
541+
particle_aabb.grow_uniformly(kernel_margin);
542+
543+
Ok(UniformGrid::from_aabb(&particle_aabb, cube_size)?)
496544
}

splashsurf_lib/src/workspace.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use thread_local::ThreadLocal;
1212
#[derive(Default)]
1313
pub struct ReconstructionWorkspace<I: Index, R: Real> {
1414
global_densities: Vec<R>,
15+
/// Temporary storage for storing a filtered set of the user provided particles
16+
filtered_particles: Vec<Vector3<R>>,
1517
local_workspaces: ThreadLocal<RefCell<LocalReconstructionWorkspace<I, R>>>,
1618
}
1719

@@ -26,6 +28,11 @@ impl<I: Index, R: Real> ReconstructionWorkspace<I, R> {
2628
&mut self.global_densities
2729
}
2830

31+
/// Returns a mutable reference to the global filtered particles vector
32+
pub(crate) fn filtered_particles_mut(&mut self) -> &mut Vec<Vector3<R>> {
33+
&mut self.filtered_particles
34+
}
35+
2936
/// Returns a reference to a thread local workspace
3037
pub(crate) fn get_local(&self) -> &RefCell<LocalReconstructionWorkspace<I, R>> {
3138
self.local_workspaces.get_or_default()

splashsurf_lib/tests/integration_tests/test_full.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ fn params_with_aabb<R: Real>(
3636
compact_support_radius,
3737
cube_size,
3838
iso_surface_threshold,
39-
domain_aabb,
39+
particle_aabb: domain_aabb,
4040
enable_multi_threading: false,
4141
spatial_decomposition: None,
4242
};

0 commit comments

Comments
 (0)