@@ -20,9 +20,6 @@ pub use uniform_grid::{GridConstructionError, UniformGrid};
2020
2121use crate :: mesh:: TriMesh3d ;
2222use crate :: octree:: Octree ;
23- use crate :: reconstruction:: {
24- reconstruct_single_surface_append, SurfaceReconstructionOctreeVisitor ,
25- } ;
2623use crate :: workspace:: ReconstructionWorkspace ;
2724
2825#[ cfg( feature = "profiling" ) ]
@@ -103,6 +100,50 @@ pub struct SpatialDecompositionParameters<R: Real> {
103100 pub ghost_particle_safety_factor : Option < R > ,
104101 /// Whether to enable stitching of all disjoint subdomain meshes to a global manifold mesh
105102 pub enable_stitching : bool ,
103+ /// Which method to use for computing the densities of the particles
104+ pub particle_density_computation : ParticleDensityComputationStrategy ,
105+ }
106+
107+ /// Available strategies for the computation of the particle densities
108+ #[ derive( Copy , Clone , Debug ) ]
109+ pub enum ParticleDensityComputationStrategy {
110+ /// Compute the particle densities globally before performing domain decomposition.
111+ ///
112+ /// With this approach the particle densities are computed globally on all particles before any
113+ /// domain decomposition is performed.
114+ ///
115+ /// This approach is guaranteed to lead to consistent results and does not depend on the following
116+ /// decomposition. However, it is also by far the *slowest method* as global operations (especially
117+ /// the global neighborhood search) are much slower.
118+ Global ,
119+ /// Compute particle densities for all particles locally followed by a synchronization step.
120+ ///
121+ /// **This is the recommended approach.**
122+ /// The particle densities will be evaluated for all particles per subdomain, possibly in parallel.
123+ /// Afterwards, the values for all non-ghost particles are written to a global array.
124+ /// This happens in a separate step before performing any reconstructions
125+ /// For the following reconstruction procedure, each subdomain will update the densities of its ghost particles
126+ /// from this global array. This ensures that all ghost-particles receive correct density values
127+ /// without requiring to double the width of the ghost-particle margin just to ensure correct values
128+ /// for the actual inner ghost-particles (i.e. in contrast to the completely local approach).
129+ ///
130+ /// The actual synchronization overhead is relatively low and this approach is often the fastest method.
131+ ///
132+ /// This approach should always lead consistent results. Only in very rare cases when a particle is not
133+ /// uniquely assigned during domain decomposition this might lead to problems. If you encounter such
134+ /// problems with this approach please report it as a bug.
135+ SynchronizeSubdomains ,
136+ /// Compute densities locally per subdomain without global synchronization.
137+ ///
138+ /// The particle densities will be evaluated per subdomain on-the-fly just before the reconstruction
139+ /// of the subdomain happens. In order to compute correct densities for the ghost particles of each
140+ /// subdomain it is required that the ghost-particle margin is at least two times the kernel compact
141+ /// support radius. This may add a lot of additional ghost-particles to each subdomain.
142+ ///
143+ /// If the ghost-particle margin is not set wide enough, this may lead to density differences on subdomain
144+ /// boundaries. Otherwise this approach robust with respect to the classification of particles into the
145+ /// subdomains.
146+ IndependentSubdomains ,
106147}
107148
108149impl < R : Real > SpatialDecompositionParameters < R > {
@@ -115,6 +156,7 @@ impl<R: Real> SpatialDecompositionParameters<R> {
115156 r => r. try_convert( ) ?
116157 ) ,
117158 enable_stitching : self . enable_stitching ,
159+ particle_density_computation : self . particle_density_computation ,
118160 } )
119161 }
120162}
@@ -266,7 +308,6 @@ pub fn reconstruct_surface<I: Index, R: Real>(
266308 particle_positions : & [ Vector3 < R > ] ,
267309 parameters : & Parameters < R > ,
268310) -> Result < SurfaceReconstruction < I , R > , ReconstructionError < I , R > > {
269- profile ! ( "reconstruct_surface" ) ;
270311 let mut surface = SurfaceReconstruction :: default ( ) ;
271312 reconstruct_surface_inplace ( particle_positions, parameters, & mut surface) ?;
272313 Ok ( surface)
@@ -290,55 +331,17 @@ pub fn reconstruct_surface_inplace<'a, I: Index, R: Real>(
290331 parameters. domain_aabb . as_ref ( ) ,
291332 parameters. enable_multi_threading ,
292333 ) ?;
293- let grid = & output_surface . grid ;
294- grid. log_grid_info ( ) ;
334+
335+ output_surface . grid . log_grid_info ( ) ;
295336
296337 if parameters. spatial_decomposition . is_some ( ) {
297- SurfaceReconstructionOctreeVisitor :: new ( particle_positions, parameters, output_surface)
298- . unwrap ( )
299- . run ( particle_positions, output_surface) ;
300- } else {
301- profile ! ( "reconstruct_surface_inplace" ) ;
302-
303- let mut workspace = output_surface
304- . workspace
305- . get_local_with_capacity ( particle_positions. len ( ) )
306- . borrow_mut ( ) ;
307-
308- // Clear the current mesh, as reconstruction will be appended to output
309- output_surface. mesh . clear ( ) ;
310- // Perform global reconstruction without octree
311- reconstruct_single_surface_append (
312- & mut * workspace,
313- grid,
314- None ,
338+ reconstruction:: reconstruct_surface_domain_decomposition (
315339 particle_positions,
316340 parameters,
317- & mut output_surface. mesh ,
341+ output_surface,
318342 ) ;
319-
320- /*
321- let particle_indices = splash_detection_radius.map(|splash_detection_radius| {
322- let neighborhood_list = neighborhood_search::search::<I, R>(
323- &grid.aabb(),
324- particle_positions,
325- splash_detection_radius,
326- enable_multi_threading,
327- );
328-
329- let mut active_particles = Vec::new();
330- for (particle_i, neighbors) in neighborhood_list.iter().enumerate() {
331- if !neighbors.is_empty() {
332- active_particles.push(particle_i);
333- }
334- }
335-
336- active_particles
337- });
338- */
339-
340- // TODO: Set this correctly
341- output_surface. density_map = None ;
343+ } else {
344+ reconstruction:: reconstruct_surface_global ( particle_positions, parameters, output_surface) ;
342345 }
343346
344347 Ok ( ( ) )
0 commit comments