vox_geometry_rust/
particle_system_data3.rs

1/*
2 * // Copyright (c) 2021 Feng Yang
3 * //
4 * // I am making my contributions/submissions to this project solely in my
5 * // personal capacity and am not conveying any rights to any intellectual
6 * // property of any third parties.
7 */
8
9use crate::vector3::Vector3D;
10use crate::point_neighbor_searcher3::*;
11use crate::point_parallel_hash_grid_searcher3::*;
12use crate::usize3::USize3;
13use std::sync::{RwLock, Arc};
14
15///
16/// # 3-D particle system data.
17///
18/// This class is the key data structure for storing particle system data. A
19/// single particle has position, velocity, and force attributes by default. But
20/// it can also have additional custom scalar or vector attributes.
21///
22pub struct ParticleSystemData3 {
23    _radius: f64,
24    _mass: f64,
25    _number_of_particles: usize,
26    _position_idx: usize,
27    _velocity_idx: usize,
28    _force_idx: usize,
29
30    _scalar_data_list: Vec<Vec<f64>>,
31    _vector_data_list: Vec<Vec<Vector3D>>,
32
33    _neighbor_searcher: PointParallelHashGridSearcher3Ptr,
34    _neighbor_lists: Vec<Vec<usize>>,
35}
36
37impl ParticleSystemData3 {
38    /// Default constructor.
39    pub fn new_default() -> ParticleSystemData3 {
40        return ParticleSystemData3 {
41            _radius: 1.0e-3,
42            _mass: 1.0e-3,
43            _number_of_particles: 0,
44            _position_idx: 0,
45            _velocity_idx: 0,
46            _force_idx: 0,
47            _scalar_data_list: vec![],
48            _vector_data_list: vec![],
49            _neighbor_searcher: PointParallelHashGridSearcher3::builder()
50                .with_resolution(USize3::new(64, 64, 64))
51                .with_grid_spacing(2.0 * 1.0e-3)
52                .make_shared(),
53            _neighbor_lists: vec![],
54        };
55    }
56
57    /// Constructs particle system data with given number of particles.
58    pub fn new(number_of_particles: usize) -> ParticleSystemData3 {
59        let mut system = ParticleSystemData3::new_default();
60        system._position_idx = system.add_vector_data(None);
61        system._velocity_idx = system.add_vector_data(None);
62        system._force_idx = system.add_vector_data(None);
63        system.resize(number_of_particles);
64        return system;
65    }
66}
67
68impl ParticleSystemData3 {
69    ///
70    /// \brief      Resizes the number of particles of the container.
71    ///
72    /// This function will resize internal containers to store newly given
73    /// number of particles including custom data layers. However, this will
74    /// invalidate neighbor searcher and neighbor lists. It is users
75    /// responsibility to call ParticleSystemData3::build_neighbor_searcher and
76    /// ParticleSystemData3::build_neighbor_lists to refresh those data.
77    ///
78    /// - parameter:   new_number_of_particles    New number of particles.
79    ///
80    pub fn resize(&mut self, new_number_of_particles: usize) {
81        self._number_of_particles = new_number_of_particles;
82
83        for attr in &mut self._scalar_data_list {
84            attr.resize(new_number_of_particles, 0.0);
85        }
86
87        for attr in &mut self._vector_data_list {
88            attr.resize(new_number_of_particles, Vector3D::new_default());
89        }
90    }
91
92    /// Returns the number of particles.
93    pub fn number_of_particles(&self) -> usize {
94        return self._number_of_particles;
95    }
96
97    ///
98    /// \brief      Adds a scalar data layer and returns its index.
99    ///
100    /// This function adds a new scalar data layer to the system. It can be used
101    /// for adding a scalar attribute, such as temperature, to the particles.
102    ///
103    /// - parameter:  initial_val  Initial value of the new scalar data.
104    ///
105    pub fn add_scalar_data(&mut self, initial_val: Option<f64>) -> usize {
106        let attr_idx = self._scalar_data_list.len();
107        let mut data: Vec<f64> = Vec::new();
108        data.resize(self.number_of_particles(), initial_val.unwrap_or(0.0));
109        self._scalar_data_list.push(data);
110        return attr_idx;
111    }
112
113    ///
114    /// \brief      Adds a vector data layer and returns its index.
115    ///
116    /// This function adds a new vector data layer to the system. It can be used
117    /// for adding a vector attribute, such as vortex, to the particles.
118    ///
119    /// - parameter:  initial_val  Initial value of the new vector data.
120    ///
121    pub fn add_vector_data(&mut self, initial_val: Option<Vector3D>) -> usize {
122        let attr_idx = self._vector_data_list.len();
123        let mut data: Vec<Vector3D> = Vec::new();
124        data.resize(self.number_of_particles(), initial_val.unwrap_or(Vector3D::new_default()));
125        self._vector_data_list.push(data);
126        return attr_idx;
127    }
128
129    /// Returns the radius of the particles.
130    pub fn radius(&self) -> f64 {
131        return self._radius;
132    }
133
134    /// Sets the radius of the particles.
135    pub fn set_radius(&mut self, new_radius: f64) {
136        self._radius = f64::max(new_radius, 0.0);
137    }
138
139    /// Returns the mass of the particles.
140    pub fn mass(&self) -> f64 {
141        return self._mass;
142    }
143
144    /// Sets the mass of the particles.
145    pub fn set_mass(&mut self, new_mass: f64) {
146        self._mass = f64::max(new_mass, 0.0);
147    }
148
149    /// Returns the position array (immutable).
150    pub fn positions(&self) -> &Vec<Vector3D> {
151        return self.vector_data_at(self._position_idx);
152    }
153
154    /// Returns the position array (mutable).
155    pub fn positions_mut(&mut self) -> &mut Vec<Vector3D> {
156        return self.vector_data_at_mut(self._position_idx);
157    }
158
159    /// Returns the velocity array (immutable).
160    pub fn velocities(&self) -> &Vec<Vector3D> {
161        return self.vector_data_at(self._velocity_idx);
162    }
163
164    /// Returns the velocity array (mutable).
165    pub fn velocities_mut(&mut self) -> &mut Vec<Vector3D> {
166        return self.vector_data_at_mut(self._velocity_idx);
167    }
168
169    /// Returns the force array (immutable).
170    pub fn forces(&self) -> &Vec<Vector3D> {
171        return self.vector_data_at(self._force_idx);
172    }
173
174    /// Returns the force array (mutable).
175    pub fn forces_mut(&mut self) -> &mut Vec<Vector3D> {
176        return self.vector_data_at_mut(self._force_idx);
177    }
178
179    /// Returns custom scalar data layer at given index (immutable).
180    pub fn scalar_data_at(&self, idx: usize) -> &Vec<f64> {
181        return &self._scalar_data_list[idx];
182    }
183
184    /// Returns custom scalar data layer at given index (mutable).
185    pub fn scalar_data_at_mut(&mut self, idx: usize) -> &mut Vec<f64> {
186        return &mut self._scalar_data_list[idx];
187    }
188
189    /// Returns custom vector data layer at given index (immutable).
190    pub fn vector_data_at(&self, idx: usize) -> &Vec<Vector3D> {
191        return &self._vector_data_list[idx];
192    }
193
194    /// Returns custom vector data layer at given index (mutable).
195    pub fn vector_data_at_mut(&mut self, idx: usize) -> &mut Vec<Vector3D> {
196        return &mut self._vector_data_list[idx];
197    }
198
199    ///
200    /// \brief      Adds a particle to the data structure.
201    ///
202    /// This function will add a single particle to the data structure. For
203    /// custom data layers, zeros will be assigned for new particles.
204    /// However, this will invalidate neighbor searcher and neighbor lists. It
205    /// is users responsibility to call
206    /// ParticleSystemData3::build_neighbor_searcher and
207    /// ParticleSystemData3::build_neighbor_lists to refresh those data.
208    ///
209    /// - parameter:   new_position The new position.
210    /// - parameter:   new_velocity The new velocity.
211    /// - parameter:   new_force    The new force.
212    ///
213    pub fn add_particle(&mut self,
214                        new_position: &Vector3D,
215                        new_velocity: Option<Vector3D>,
216                        new_force: Option<Vector3D>) {
217        let new_positions = vec![*new_position];
218        let new_velocities = vec![new_velocity.unwrap_or(Vector3D::new_default())];
219        let new_forces = vec![new_force.unwrap_or(Vector3D::new_default())];
220
221        self.add_particles(&new_positions,
222                           Some(&new_velocities),
223                           Some(&new_forces));
224    }
225
226    ///
227    /// \brief      Adds particles to the data structure.
228    ///
229    /// This function will add particles to the data structure. For custom data
230    /// layers, zeros will be assigned for new particles. However, this will
231    /// invalidate neighbor searcher and neighbor lists. It is users
232    /// responsibility to call ParticleSystemData3::build_neighbor_searcher and
233    /// ParticleSystemData3::build_neighbor_lists to refresh those data.
234    ///
235    /// - parameter:   new_positions  The new positions.
236    /// - parameter:   new_velocities The new velocities.
237    /// - parameter:   new_forces     The new forces.
238    ///
239    pub fn add_particles(&mut self,
240                         new_positions: &Vec<Vector3D>,
241                         new_velocities: Option<&Vec<Vector3D>>,
242                         new_forces: Option<&Vec<Vector3D>>) {
243        let old_number_of_particles = self.number_of_particles();
244        let new_number_of_particles = old_number_of_particles + new_positions.len();
245
246        self.resize(new_number_of_particles);
247
248        let pos = self.positions_mut();
249        pos.append(&mut new_positions.clone());
250        let vel = self.velocities_mut();
251        vel.append(&mut new_velocities.unwrap_or(&vec![]).clone());
252        let frc = self.forces_mut();
253        frc.append(&mut new_forces.unwrap_or(&vec![]).clone());
254    }
255
256    ///
257    /// \brief      Returns neighbor searcher.
258    ///
259    /// This function returns currently set neighbor searcher object. By
260    /// default, PointParallelHashGridSearcher2 is used.
261    ///
262    /// \return     Current neighbor searcher.
263    ///
264    pub fn neighbor_searcher(&self) -> PointParallelHashGridSearcher3Ptr {
265        return self._neighbor_searcher.clone();
266    }
267
268    ///
269    /// \brief      Returns neighbor lists.
270    ///
271    /// This function returns neighbor lists which is available after calling
272    /// PointParallelHashGridSearcher3::build_neighbor_lists. Each list stores
273    /// indices of the neighbors.
274    ///
275    /// \return     Neighbor lists.
276    ///
277    pub fn neighbor_lists(&self) -> &Vec<Vec<usize>> {
278        return &self._neighbor_lists;
279    }
280
281    /// Builds neighbor searcher with given search radius.
282    pub fn build_neighbor_searcher(&mut self, max_search_radius: f64) {
283        // Use PointParallelHashGridSearcher3 by default
284        self._neighbor_searcher = PointParallelHashGridSearcher3::builder()
285            .with_resolution(USize3::new(64, 64, 64))
286            .with_grid_spacing(2.0 * max_search_radius)
287            .make_shared();
288
289        self._neighbor_searcher.write().unwrap().build(self.positions());
290    }
291
292    /// Builds neighbor lists with given search radius.
293    pub fn build_neighbor_lists(&mut self, max_search_radius: f64) {
294        self._neighbor_lists.resize(self.number_of_particles(), vec![]);
295
296        for i in 0..self.number_of_particles() {
297            let origin = self.positions()[i];
298            self._neighbor_lists[i].clear();
299
300            self._neighbor_searcher.clone().read().unwrap().for_each_nearby_point(
301                &origin, max_search_radius,
302                &mut |j: usize, _: &Vector3D| {
303                    if i != j {
304                        self._neighbor_lists[i].push(j);
305                    }
306                });
307        }
308    }
309}
310
311/// Shared pointer type of ParticleSystemData3.
312pub type ParticleSystemData3Ptr = Arc<RwLock<ParticleSystemData3>>;