hoomd_spatial/lib.rs
1// Copyright (c) 2024-2026 The Regents of the University of Michigan.
2// Part of hoomd-rs, released under the BSD 3-Clause License.
3
4#![doc(
5 html_favicon_url = "https://raw.githubusercontent.com/glotzerlab/hoomd-rs/7352214172a490cc716492e9724ff42720a0018a/doc/theme/favicon.svg"
6)]
7#![doc(
8 html_logo_url = "https://raw.githubusercontent.com/glotzerlab/hoomd-rs/7352214172a490cc716492e9724ff42720a0018a/doc/theme/favicon.svg"
9)]
10
11//! Spatial data structures.
12//!
13//! Use a spatial data structure to efficiently find points near a position in space.
14//! `Microstate` maintains a spatial data structure internally for use with
15//! pair potential computations. Specifically, `Microstate` interoperates with:
16//! * [`VecCell`] is the highest performance spatial data structure. Use it in typical
17//! simulations where points remain inside a fixed boundary and have a roughly
18//! uniform density throughout.
19//! * [`HashCell`] is only slightly slower than [`VecCell`]. [`HashCell`] will use less
20//! memory in simulations with open boundaries and/or when there are large regions
21//! of space with no points.
22//! * [`AllPairs`] is very slow. Use it only when necessary.
23//!
24//! You can also utilize any of these data structures directly. They operate by
25//! mapping keys (of a generic type) to points in space. Add points to a spatial
26//! data structure with [`PointUpdate::insert`], which also updates the position of
27//! already added points. Remove points with [`PointUpdate::remove`].
28//!
29//! [`PointsNearBall::points_near_ball`] takes a position and a radius
30//! and returns an iterator that will yield all of the inserted points within
31//! the given ball. It *may* yield additional points that you need to filter out.
32//!
33//! # Complete documentation
34//!
35//! `hoomd-spatial` is is a part of *hoomd-rs*. Read the [complete documentation]
36//! for more information.
37//!
38//! [complete documentation]: https://hoomd-rs.readthedocs.io
39
40use hoomd_utility::valid::PositiveReal;
41
42mod all_pairs;
43mod hash_cell;
44mod vec_cell;
45
46pub use all_pairs::AllPairs;
47pub use hash_cell::{HashCell, HashCellBuilder};
48pub use vec_cell::{VecCell, VecCellBuilder};
49
50/// Allow incremental updates to points in the spatial data.
51pub trait PointUpdate<P, K> {
52 /// Insert or update a point identified by a key.
53 ///
54 /// # Example
55 /// ```
56 /// use hoomd_spatial::{PointUpdate, VecCell};
57 ///
58 /// let mut vec_cell = VecCell::default();
59 ///
60 /// vec_cell.insert(0, [1.25, 2.5].into());
61 /// ```
62 fn insert(&mut self, key: K, position: P);
63
64 /// Remove the point with the given key.
65 ///
66 /// # Example
67 /// ```
68 /// use hoomd_spatial::{PointUpdate, VecCell};
69 ///
70 /// let mut vec_cell = VecCell::default();
71 /// vec_cell.insert(0, [1.25, 2.5].into());
72 ///
73 /// vec_cell.remove(&0)
74 /// ```
75 fn remove(&mut self, key: &K);
76
77 /// Get the number of points in the spatial data structure.
78 ///
79 /// # Example
80 /// ```
81 /// use hoomd_spatial::{PointUpdate, VecCell};
82 ///
83 /// let mut vec_cell = VecCell::default();
84 /// vec_cell.insert(0, [1.25, 2.5].into());
85 ///
86 /// assert_eq!(vec_cell.len(), 1)
87 /// ```
88 fn len(&self) -> usize;
89
90 /// Test if the spatial data structure is empty.
91 ///
92 /// # Example
93 /// ```
94 /// use hoomd_spatial::{PointUpdate, VecCell};
95 ///
96 /// let mut vec_cell = VecCell::<usize, 2>::default();
97 ///
98 /// assert!(vec_cell.is_empty());
99 /// ```
100 fn is_empty(&self) -> bool;
101
102 /// Test if the spatial data structure contains a key.
103 /// ```
104 /// use hoomd_spatial::{PointUpdate, VecCell};
105 ///
106 /// let mut vec_cell = VecCell::default();
107 /// vec_cell.insert(0, [1.25, 2.5].into());
108 ///
109 /// assert!(vec_cell.contains_key(&0));
110 /// ```
111 fn contains_key(&self, key: &K) -> bool;
112
113 /// Remove all points.
114 ///
115 /// # Example
116 /// ```
117 /// use hoomd_spatial::{PointUpdate, VecCell};
118 ///
119 /// let mut vec_cell = VecCell::default();
120 /// vec_cell.insert(0, [1.25, 2.5].into());
121 ///
122 /// vec_cell.clear();
123 /// ```
124 fn clear(&mut self);
125}
126
127/// Find all points in the given ball.
128pub trait PointsNearBall<P, K> {
129 /// Find all the points that *might* be in the given ball.
130 ///
131 /// `points_near_ball` will iterate over all points in the given ball *and
132 /// possibly others as well*. The spatial data structure may iterate over
133 /// the points in any order.
134 ///
135 /// # Example
136 /// ```
137 /// use hoomd_spatial::{PointUpdate, PointsNearBall, VecCell};
138 ///
139 /// let mut vec_cell = VecCell::default();
140 /// vec_cell.insert(0, [1.25, 0.0].into());
141 /// vec_cell.insert(1, [3.25, 0.75].into());
142 /// vec_cell.insert(2, [-10.0, 12.0].into());
143 ///
144 /// for key in vec_cell.points_near_ball(&[2.0, 0.0].into(), 1.0) {
145 /// println!("{key}");
146 /// }
147 /// ```
148 /// Prints (in any order):
149 /// ```text
150 /// 0
151 /// 1
152 /// ```
153 fn points_near_ball(&self, position: &P, radius: f64) -> impl Iterator<Item = K>;
154
155 /// Is this spatial data structures [`AllPairs`]?
156 #[must_use]
157 #[inline]
158 fn is_all_pairs() -> bool {
159 false
160 }
161}
162
163/// Construct a spatial data structure capable of searching up to the given radius.
164pub trait WithSearchRadius {
165 /// Construct a spatial data structure that can search *at least* as far as the given radius.
166 fn with_search_radius(radius: PositiveReal) -> Self;
167}
168
169/// Locate the index of a given point.
170///
171/// This is used by `Microstate` to sort for cache coherency.
172pub trait IndexFromPosition<P> {
173 /// Orderable type based on the site's position.
174 type Location: Ord;
175
176 /// Determine the location of a site based on its position.
177 ///
178 /// Many positions can map to the same location. The ideal
179 /// mapping will place points close together in physical space
180 /// close together in the ordering.
181 fn location_from_position(&self, position: &P) -> Self::Location;
182}