bempp_octree::geometry

Struct Point

Source
pub struct Point { /* private fields */ }
Expand description

Definition of a point in 3d space.

A point consists of three coordinates and a global id. The global id makes it easier to identify points as they are distributed across MPI nodes.

Implementations§

Source§

impl Point

Source

pub fn new(coords: [f64; 3], global_id: usize) -> Self

Create a new point from coordinates and global id.

Source

pub fn coords(&self) -> [f64; 3]

Return the coordintes of a point.

Examples found in repository?
examples/mpi_complete_tree.rs (line 28)
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
pub fn main() {
    // Initialise MPI
    let universe = mpi::initialize().unwrap();

    // Get the world communicator
    let comm = universe.world();

    // Initialise a seeded Rng.
    let mut rng = ChaCha8Rng::seed_from_u64(comm.rank() as u64);

    // Create `npoints` per rank.
    let npoints = 1000000;

    // Generate random points on the positive octant of the unit sphere.

    let mut points = generate_random_points(npoints, &mut rng, &comm);
    // Make sure that the points live on the unit sphere.
    for point in points.iter_mut() {
        let len = point.coords()[0] * point.coords()[0]
            + point.coords()[1] * point.coords()[1]
            + point.coords()[2] * point.coords()[2];
        let len = len.sqrt();
        point.coords_mut()[0] /= len;
        point.coords_mut()[1] /= len;
        point.coords_mut()[2] /= len;
    }

    let start = Instant::now();
    // The following code will create a complete octree with a maximum level of 16.
    let octree = Octree::new(&points, 16, 50, &comm);
    let duration = start.elapsed();

    let global_number_of_points = octree.global_number_of_points();
    let global_max_level = octree.global_max_level();

    // We now check that each node of the tree has all its neighbors available.

    if comm.rank() == 0 {
        println!(
            "Setup octree with {} points and maximum level {} in {} ms",
            global_number_of_points,
            global_max_level,
            duration.as_millis()
        );
    }
}
More examples
Hide additional examples
examples/mpi_complete_tree_debug.rs (line 31)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
pub fn main() {
    // Initialise MPI
    let universe = mpi::initialize().unwrap();

    // Get the world communicator
    let comm = universe.world();

    // Initialise a seeded Rng.
    let mut rng = ChaCha8Rng::seed_from_u64(comm.rank() as u64);

    // Create `npoints` per rank.
    let npoints = 10000;

    // Generate random points.

    let mut points = generate_random_points(npoints, &mut rng, &comm);
    // Make sure that the points live on the unit sphere.
    for point in points.iter_mut() {
        let len = point.coords()[0] * point.coords()[0]
            + point.coords()[1] * point.coords()[1]
            + point.coords()[2] * point.coords()[2];
        let len = len.sqrt();
        point.coords_mut()[0] /= len;
        point.coords_mut()[1] /= len;
        point.coords_mut()[2] /= len;
    }

    let tree = Octree::new(&points, 15, 50, &comm);

    // We now check that each node of the tree has all its neighbors available.

    let leaf_tree = tree.leaf_keys();
    let all_keys = tree.all_keys();

    assert!(is_complete_linear_and_balanced(leaf_tree, &comm));
    for &key in leaf_tree {
        // We only check interior keys. Leaf keys may not have a neighbor
        // on the same level.
        let mut parent = key.parent();
        while parent.level() > 0 {
            // Check that the key itself is there.
            assert!(all_keys.contains_key(&key));
            // Check that all its neighbours are there.
            for neighbor in parent.neighbours().iter().filter(|&key| key.is_valid()) {
                assert!(all_keys.contains_key(neighbor));
            }
            parent = parent.parent();
            // Check that the parent is there.
            assert!(all_keys.contains_key(&parent));
        }
    }

    // At the end check that the root of the tree is also contained.
    assert!(all_keys.contains_key(&MortonKey::root()));

    // Count the number of ghosts on each rank
    // Count the number of global keys on each rank.

    // Assert that all ghosts are from a different rank and count them.

    let nghosts = all_keys
        .iter()
        .filter_map(|(_, &value)| {
            if let KeyType::Ghost(rank) = value {
                assert!(rank != comm.size() as usize);
                Some(rank)
            } else {
                None
            }
        })
        .count();

    if comm.size() == 1 {
        assert_eq!(nghosts, 0);
    } else {
        assert!(nghosts > 0);
    }

    let nglobal = all_keys
        .iter()
        .filter(|(_, &value)| matches!(value, KeyType::Global))
        .count();

    // Assert that all globals across all ranks have the same count.

    let nglobals = gather_to_all(std::slice::from_ref(&nglobal), &comm);

    assert_eq!(nglobals.iter().unique().count(), 1);

    // Check that the points are associated with the correct leaf keys.
    let mut npoints = 0;
    let leaf_point_map = tree.leaf_keys_to_local_point_indices();

    for (key, point_indices) in leaf_point_map {
        for &index in point_indices {
            assert!(key.is_ancestor(tree.point_keys()[index]));
        }
        npoints += point_indices.len();
    }

    // Make sure that the number of points and point keys lines up
    // with the points stored for each leaf key.
    assert_eq!(npoints, tree.points().len());
    assert_eq!(npoints, tree.point_keys().len());

    // Check the neighbour relationships.

    let all_neighbours = tree.neighbour_map();
    let all_keys = tree.all_keys();

    for (key, key_type) in all_keys {
        // Ghost keys should not be in the neighbour map.
        match key_type {
            KeyType::Ghost(_) => assert!(!all_neighbours.contains_key(key)),
            _ => {
                // If it is not a ghost the key should be in the neighbour map.
                assert!(all_neighbours.contains_key(key));
            }
        }
    }

    if comm.rank() == 0 {
        println!("No errors were found in setting up tree.");
    }
}
Source

pub fn coords_mut(&mut self) -> &mut [f64; 3]

Return a mutable pointer to the coordinates.

Examples found in repository?
examples/mpi_complete_tree.rs (line 32)
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
pub fn main() {
    // Initialise MPI
    let universe = mpi::initialize().unwrap();

    // Get the world communicator
    let comm = universe.world();

    // Initialise a seeded Rng.
    let mut rng = ChaCha8Rng::seed_from_u64(comm.rank() as u64);

    // Create `npoints` per rank.
    let npoints = 1000000;

    // Generate random points on the positive octant of the unit sphere.

    let mut points = generate_random_points(npoints, &mut rng, &comm);
    // Make sure that the points live on the unit sphere.
    for point in points.iter_mut() {
        let len = point.coords()[0] * point.coords()[0]
            + point.coords()[1] * point.coords()[1]
            + point.coords()[2] * point.coords()[2];
        let len = len.sqrt();
        point.coords_mut()[0] /= len;
        point.coords_mut()[1] /= len;
        point.coords_mut()[2] /= len;
    }

    let start = Instant::now();
    // The following code will create a complete octree with a maximum level of 16.
    let octree = Octree::new(&points, 16, 50, &comm);
    let duration = start.elapsed();

    let global_number_of_points = octree.global_number_of_points();
    let global_max_level = octree.global_max_level();

    // We now check that each node of the tree has all its neighbors available.

    if comm.rank() == 0 {
        println!(
            "Setup octree with {} points and maximum level {} in {} ms",
            global_number_of_points,
            global_max_level,
            duration.as_millis()
        );
    }
}
More examples
Hide additional examples
examples/mpi_complete_tree_debug.rs (line 35)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
pub fn main() {
    // Initialise MPI
    let universe = mpi::initialize().unwrap();

    // Get the world communicator
    let comm = universe.world();

    // Initialise a seeded Rng.
    let mut rng = ChaCha8Rng::seed_from_u64(comm.rank() as u64);

    // Create `npoints` per rank.
    let npoints = 10000;

    // Generate random points.

    let mut points = generate_random_points(npoints, &mut rng, &comm);
    // Make sure that the points live on the unit sphere.
    for point in points.iter_mut() {
        let len = point.coords()[0] * point.coords()[0]
            + point.coords()[1] * point.coords()[1]
            + point.coords()[2] * point.coords()[2];
        let len = len.sqrt();
        point.coords_mut()[0] /= len;
        point.coords_mut()[1] /= len;
        point.coords_mut()[2] /= len;
    }

    let tree = Octree::new(&points, 15, 50, &comm);

    // We now check that each node of the tree has all its neighbors available.

    let leaf_tree = tree.leaf_keys();
    let all_keys = tree.all_keys();

    assert!(is_complete_linear_and_balanced(leaf_tree, &comm));
    for &key in leaf_tree {
        // We only check interior keys. Leaf keys may not have a neighbor
        // on the same level.
        let mut parent = key.parent();
        while parent.level() > 0 {
            // Check that the key itself is there.
            assert!(all_keys.contains_key(&key));
            // Check that all its neighbours are there.
            for neighbor in parent.neighbours().iter().filter(|&key| key.is_valid()) {
                assert!(all_keys.contains_key(neighbor));
            }
            parent = parent.parent();
            // Check that the parent is there.
            assert!(all_keys.contains_key(&parent));
        }
    }

    // At the end check that the root of the tree is also contained.
    assert!(all_keys.contains_key(&MortonKey::root()));

    // Count the number of ghosts on each rank
    // Count the number of global keys on each rank.

    // Assert that all ghosts are from a different rank and count them.

    let nghosts = all_keys
        .iter()
        .filter_map(|(_, &value)| {
            if let KeyType::Ghost(rank) = value {
                assert!(rank != comm.size() as usize);
                Some(rank)
            } else {
                None
            }
        })
        .count();

    if comm.size() == 1 {
        assert_eq!(nghosts, 0);
    } else {
        assert!(nghosts > 0);
    }

    let nglobal = all_keys
        .iter()
        .filter(|(_, &value)| matches!(value, KeyType::Global))
        .count();

    // Assert that all globals across all ranks have the same count.

    let nglobals = gather_to_all(std::slice::from_ref(&nglobal), &comm);

    assert_eq!(nglobals.iter().unique().count(), 1);

    // Check that the points are associated with the correct leaf keys.
    let mut npoints = 0;
    let leaf_point_map = tree.leaf_keys_to_local_point_indices();

    for (key, point_indices) in leaf_point_map {
        for &index in point_indices {
            assert!(key.is_ancestor(tree.point_keys()[index]));
        }
        npoints += point_indices.len();
    }

    // Make sure that the number of points and point keys lines up
    // with the points stored for each leaf key.
    assert_eq!(npoints, tree.points().len());
    assert_eq!(npoints, tree.point_keys().len());

    // Check the neighbour relationships.

    let all_neighbours = tree.neighbour_map();
    let all_keys = tree.all_keys();

    for (key, key_type) in all_keys {
        // Ghost keys should not be in the neighbour map.
        match key_type {
            KeyType::Ghost(_) => assert!(!all_neighbours.contains_key(key)),
            _ => {
                // If it is not a ghost the key should be in the neighbour map.
                assert!(all_neighbours.contains_key(key));
            }
        }
    }

    if comm.rank() == 0 {
        println!("No errors were found in setting up tree.");
    }
}
Source

pub fn global_id(&self) -> usize

Return the global id of the point.

Trait Implementations§

Source§

impl Clone for Point

Source§

fn clone(&self) -> Point

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Equivalence for Point

Source§

type Out = DatatypeRef<'static>

The type of the equivalent MPI datatype (e.g. SystemDatatype or UserDatatype)
Source§

fn equivalent_datatype() -> Self::Out

The MPI datatype that is equivalent to this Rust type
Source§

impl Copy for Point

Auto Trait Implementations§

§

impl Freeze for Point

§

impl RefUnwindSafe for Point

§

impl Send for Point

§

impl Sync for Point

§

impl Unpin for Point

§

impl UnwindSafe for Point

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<Src, Scheme> ApproxFrom<Src, Scheme> for Src
where Scheme: ApproxScheme,

§

type Err = NoError

The error type produced by a failed conversion.
§

fn approx_from(src: Src) -> Result<Src, <Src as ApproxFrom<Src, Scheme>>::Err>

Convert the given value into an approximately equivalent representation.
§

impl<Dst, Src, Scheme> ApproxInto<Dst, Scheme> for Src
where Dst: ApproxFrom<Src, Scheme>, Scheme: ApproxScheme,

§

type Err = <Dst as ApproxFrom<Src, Scheme>>::Err

The error type produced by a failed conversion.
§

fn approx_into(self) -> Result<Dst, <Src as ApproxInto<Dst, Scheme>>::Err>

Convert the subject into an approximately equivalent representation.
§

impl<T> AsDatatype for T
where T: Equivalence,

§

type Out = <T as Equivalence>::Out

The type of the associated MPI datatype (e.g. SystemDatatype or UserDatatype)
§

fn as_datatype(&self) -> <T as AsDatatype>::Out

The associated MPI datatype
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
§

impl<T> Collection for T
where T: Equivalence,

§

fn count(&self) -> i32

How many things are in this collection.
§

impl<T, Dst> ConvAsUtil<Dst> for T

§

fn approx(self) -> Result<Dst, Self::Err>
where Self: Sized + ApproxInto<Dst>,

Approximate the subject with the default scheme.
§

fn approx_by<Scheme>(self) -> Result<Dst, Self::Err>
where Self: Sized + ApproxInto<Dst, Scheme>, Scheme: ApproxScheme,

Approximate the subject with a specific scheme.
§

impl<T> ConvUtil for T

§

fn approx_as<Dst>(self) -> Result<Dst, Self::Err>
where Self: Sized + ApproxInto<Dst>,

Approximate the subject to a given type with the default scheme.
§

fn approx_as_by<Dst, Scheme>(self) -> Result<Dst, Self::Err>
where Self: Sized + ApproxInto<Dst, Scheme>, Scheme: ApproxScheme,

Approximate the subject to a given type with a specific scheme.
§

fn into_as<Dst>(self) -> Dst
where Self: Sized + Into<Dst>,

Convert the subject to a given type.
§

fn try_as<Dst>(self) -> Result<Dst, Self::Err>
where Self: Sized + TryInto<Dst>,

Attempt to convert the subject to a given type.
§

fn value_as<Dst>(self) -> Result<Dst, Self::Err>
where Self: Sized + ValueInto<Dst>,

Attempt a value conversion of the subject to a given type.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointer for T
where T: Equivalence,

§

fn pointer(&self) -> *const c_void

A pointer to the starting address in memory
§

impl<T> PointerMut for T
where T: Equivalence,

§

fn pointer_mut(&mut self) -> *mut c_void

A mutable pointer to the starting address in memory
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
§

impl<Src> TryFrom<Src> for Src

§

type Err = NoError

The error type produced by a failed conversion.
§

fn try_from(src: Src) -> Result<Src, <Src as TryFrom<Src>>::Err>

Convert the given value into the subject type.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<Src, Dst> TryInto<Dst> for Src
where Dst: TryFrom<Src>,

§

type Err = <Dst as TryFrom<Src>>::Err

The error type produced by a failed conversion.
§

fn try_into(self) -> Result<Dst, <Src as TryInto<Dst>>::Err>

Convert the subject into the destination type.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<Src> ValueFrom<Src> for Src

§

type Err = NoError

The error type produced by a failed conversion.
§

fn value_from(src: Src) -> Result<Src, <Src as ValueFrom<Src>>::Err>

Convert the given value into an exactly equivalent representation.
§

impl<Src, Dst> ValueInto<Dst> for Src
where Dst: ValueFrom<Src>,

§

type Err = <Dst as ValueFrom<Src>>::Err

The error type produced by a failed conversion.
§

fn value_into(self) -> Result<Dst, <Src as ValueInto<Dst>>::Err>

Convert the subject into an exactly equivalent representation.
§

impl<T> Buffer for T
where T: Equivalence,

§

impl<T> BufferMut for T
where T: Equivalence,