bempp_octree/lib.rs
1//! A Rust based Octree library
2//!
3//! This library provides a single [Octree] data structure and utility routines
4//! to work with Morton keys used for indexing Octrees.
5//!
6//! An Octree is a tree data structure in which each internal node has exactly eight children.
7//! Octrees are most often used to partition a three-dimensional space by recursively subdividing it into
8//! eight octants. Octrees are the 3D analog of quadtrees.
9//!
10//! The library supports Octrees on single processes and distributed across multiple processes via MPI.
11//! Each node inside on Octree is indexed through a [MortonKey]. A Morton key is a
12//! 64 bit integer value that uniquely represents a node in an Octree.
13//!
14//! The library is designed to only provide the Octree data structure itself by storing Morton keys, their relationship
15//! and the association of keys associated with leaf nodes to actual physical points.
16//!
17//! It is up to the user to build algorithms around the data structure.
18//!
19//! The Octrees provides by this library are adaptive and 2:1 balanced by default. This means that no neighbour of a node can be more than
20//! one level below or above the level of the node. This is a common property of Octrees used in scientific computing.
21//! The adaptivity ensures that refined where it is needed.
22//!
23//! A heuristic strategic ensures that the tree is approximately load-balanced. The implementation of the load-balancing and the 2:1
24//! balancing are modeled after the paper *[Bottom-Up Construction and 2:1 Balance Refinement of Linear Octrees in Parallel](https://epubs.siam.org/doi/10.1137/070681727)*
25//! by Sundar et. al. The underlying implementation relies on parallel sorting of Morton keys, which is done using a simple bucket sort algorithm
26//! in this library.
27//!
28//! ## Using the library.
29//!
30//! A new Octree is generated from a list of points using the [Octree::new](crate::octree::Octree::new) function.
31//! ```
32//! use bempp_octree::{Octree, generate_random_points};
33//! use rand::prelude::*;
34//! use rand_chacha::ChaCha8Rng;
35//! use mpi::traits::Communicator;
36//!
37//! let universe = mpi::initialize().unwrap();
38//!
39//! let comm = universe.world();
40//! let mut rng = ChaCha8Rng::seed_from_u64(comm.rank() as u64);
41//! let npoints = 10000;
42//! let max_level = 15;
43//! let max_leaf_points = 50;
44//!
45//! let points = generate_random_points(npoints, &mut rng, &comm);
46//! let octree = Octree::new(&points, max_level, max_leaf_points, &comm);
47//! ```
48//! In this code we first initialize MPI and generate random points in the unit cube.
49//! We then create an Octree with a maximum level of 15 and a maximum of 50 points per leaf node.
50//! Note that when the code is run with in `debug` mode a number of expensive assertion checks are
51//! performed during tree construction which cost noticeable time for larger trees and involve
52//! communication across MPI nodes. These checks are disabled in `release` mode.
53//!
54//! An octree is constructed by definining and load balancing a coarse tree and then refining
55//! the coarse tree as long as the number of points per leaf node exceeds the maximum. Once sufficiently
56//! refined the tree is 2:1 balanced again. The `octree` data structure stores the coarse tree and the
57//! fine leaf nodes of the octree.
58//!
59//! To now obtain the leaf nodes of the octree use
60//! ```ignore
61//! let leaf_keys = octree.leaf_keys();
62//! ```
63//! We can get the leaf nodes and interior nodes by calling
64//! ```ignore
65//! let all_keys = octree.all_keys();
66//! ```
67//! `all_keys` is a hash map marking a key as one of
68//! - [LocalLeaf](crate::octree::KeyType::LocalLeaf): A leaf key that is stored on the local node.
69//! - [LocalInterior](crate::octree::KeyType::LocalInterior): An interior key that is stored on the local node.
70//! - [Ghost(rank)](crate::octree::KeyType::Ghost): A ghost key that is adjacent to the local node and originates on the process with rank `rank`.
71//! - [Global](crate::octree::KeyType::Global): A global key that is stored on all processes. These are the ancestors of the coarse tree leafs.
72//!
73//! An important property in octrees is the neighbour relationship. To get a hash map that stores the neighbours for each non-ghost key
74//! use
75//! ```ignore
76//! let neighbour_map = octree.neighbour_map();
77//! ```
78//! The `neighbour_map` stores for each non-ghost key a vector of keys that are adjacent to the neighbour. Neighbours need not
79//! necesssarily be at the same level in the tree. Only for interior keys neighbours are guaranteed to be at the same level. For leaf keys
80//! neighbours may be one level higher or lower.
81//!
82//! Each key in this library is a [Morton Key](MortonKey). For details of Morton keys see the description in the [morton] module.
83#![cfg_attr(feature = "strict", deny(warnings), deny(unused_crate_dependencies))]
84#![warn(missing_docs)]
85
86pub mod constants;
87pub mod geometry;
88pub mod morton;
89pub mod octree;
90pub mod parsort;
91pub mod tools;
92pub mod types;
93
94pub use crate::geometry::{PhysicalBox, Point};
95pub use crate::octree::Octree;
96pub use crate::tools::generate_random_points;
97pub use morton::MortonKey;