Skip to main content

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}