rusty_tree/octree/
regular_octree.rs

1//! Data structures and functions for regular octrees.
2//! 
3//! This module implements a regular Octree data structure.
4//! A regular tree subdivides uniformly on all levels. To avoid
5//! dealing with many empty boxes only the non-empty leaf boxes
6//! are actually being stored.
7
8use super::{Statistics, Octree, OctreeType};
9use ndarray::{ArrayView2, Axis};
10use rusty_kernel_tools::RealType;
11use std::time::Instant;
12
13
14/// Create a regular Octree.
15///
16/// Returns a `RegularOctree` struct describing a regular octree.
17///
18/// # Arguments
19/// * `particles` - A (3, N) array of particles of type f32 or f64.
20/// * `max_level` - The maximum level of the tree.
21pub fn regular_octree<T: RealType>(
22    particles: ArrayView2<T>,
23    max_level: usize,
24) -> Octree<'_, T> {
25    use crate::helpers::compute_bounds;
26
27    const TOL: f64 = 1E-5;
28
29    let bounds = compute_bounds(particles);
30    let diameter = [
31        (bounds[0][1] - bounds[0][0]).to_f64().unwrap() * (1.0 + TOL),
32        (bounds[1][1] - bounds[1][0]).to_f64().unwrap() * (1.0 + TOL),
33        (bounds[2][1] - bounds[2][0]).to_f64().unwrap() * (1.0 + TOL),
34    ];
35
36    let origin = [
37        bounds[0][0].to_f64().unwrap(),
38        bounds[1][0].to_f64().unwrap(),
39        bounds[2][0].to_f64().unwrap(),
40    ];
41
42    regular_octree_with_bounding_box(particles, max_level, origin, diameter)
43}
44
45/// Create a regular Octree with given bounding box.
46///
47/// Returns a `RegularOctree` struct describing a regular octree.
48///
49/// # Arguments
50/// * `particles` - A (3, N) array of particles of type f32 or f64.
51/// * `max_level` - The maximum level of the tree.
52/// `origin` - The origin of the bounding box.
53/// `diameter` - The diameter of the bounding box in each dimension.
54pub fn regular_octree_with_bounding_box<T: RealType>(
55    particles: ArrayView2<T>,
56    max_level: usize,
57    origin: [f64; 3],
58    diameter: [f64; 3],
59) -> Octree<'_, T> {
60    use crate::morton::encode_points;
61    use super::{compute_near_field_map, compute_interaction_list_map, compute_leaf_map, compute_level_information};
62
63    let now = Instant::now();
64
65
66    let leaf_keys = encode_points(particles, max_level, &origin, &diameter);
67    let (max_level, all_keys, level_keys) = compute_level_information(leaf_keys.view());
68    let leaf_key_to_particles = compute_leaf_map(leaf_keys.view());
69
70    let near_field = compute_near_field_map(&all_keys);
71    let interaction_list = compute_interaction_list_map(&all_keys);
72
73    let duration = now.elapsed();
74
75    let statistics = Statistics {
76        number_of_particles: particles.len_of(Axis(1)),
77        max_level,
78        number_of_leafs: leaf_key_to_particles.keys().len(),
79        number_of_keys: all_keys.len(),
80        creation_time: duration,
81        minimum_number_of_particles_in_leaf: leaf_key_to_particles
82            .values()
83            .map(|item| item.len())
84            .reduce(std::cmp::min)
85            .unwrap(),
86        maximum_number_of_particles_in_leaf: leaf_key_to_particles
87            .values()
88            .map(|item| item.len())
89            .reduce(std::cmp::max)
90            .unwrap(),
91        average_number_of_particles_in_leaf: (leaf_key_to_particles
92            .values()
93            .map(|item| item.len())
94            .sum::<usize>() as f64)
95            / (leaf_key_to_particles.keys().len() as f64),
96    };
97
98    Octree {
99        particles,
100        max_level,
101        origin,
102        diameter,
103        level_keys,
104        particle_keys: leaf_keys,
105        near_field,
106        interaction_list,
107        leaf_key_to_particles,
108        all_keys,
109        octree_type: OctreeType::Regular,
110        statistics,
111    }
112}