vox_geometry_rust/
sph_system_data3.rs1use crate::particle_system_data3::*;
10use crate::vector3::Vector3D;
11use crate::sph_kernels3::*;
12use crate::point_neighbor_searcher3::PointNeighborSearcher3;
13use crate::bounding_box3::BoundingBox3D;
14use crate::point_generator3::PointGenerator3;
15use rayon::prelude::*;
16use crate::bcc_lattice_point_generator::BccLatticePointGenerator;
17use std::sync::{RwLock, Arc};
18
19pub struct SphSystemData3 {
27 _target_density: f64,
29
30 _target_spacing: f64,
32
33 _kernel_radius_over_target_spacing: f64,
36
37 _kernel_radius: f64,
39
40 _pressure_idx: usize,
41
42 _density_idx: usize,
43
44 _base_data: ParticleSystemData3,
45}
46
47impl SphSystemData3 {
48 pub fn new_default() -> SphSystemData3 {
50 return SphSystemData3 {
51 _target_density: crate::constants::K_WATER_DENSITY,
52 _target_spacing: 0.1,
53 _kernel_radius_over_target_spacing: 1.8,
54 _kernel_radius: 0.0,
55 _pressure_idx: 0,
56 _density_idx: 0,
57 _base_data: ParticleSystemData3::new(0),
58 };
59 }
60
61 pub fn new(number_of_particles: usize) -> SphSystemData3 {
63 let mut data = SphSystemData3 {
64 _target_density: crate::constants::K_WATER_DENSITY,
65 _target_spacing: 0.1,
66 _kernel_radius_over_target_spacing: 1.8,
67 _kernel_radius: 0.0,
68 _pressure_idx: 0,
69 _density_idx: 0,
70 _base_data: ParticleSystemData3::new(number_of_particles),
71 };
72
73 data._density_idx = data._base_data.add_scalar_data(None);
74 data._pressure_idx = data._base_data.add_scalar_data(None);
75
76 data.set_target_spacing(0.1);
77
78 return data;
79 }
80}
81
82impl SphSystemData3 {
83 pub fn set_radius(&mut self, new_radius: f64) {
90 self.set_target_spacing(new_radius);
92 }
93
94 pub fn set_mass(&mut self, new_mass: f64) {
102 let inc_ratio = new_mass / self._base_data.mass();
103 self._target_density *= inc_ratio;
104 self._base_data.set_mass(new_mass);
105 }
106
107 pub fn densities(&self) -> &Vec<f64> {
109 return self._base_data.scalar_data_at(self._density_idx);
110 }
111
112 pub fn densities_mut(&mut self) -> &mut Vec<f64> {
114 return self._base_data.scalar_data_at_mut(self._density_idx);
115 }
116
117 pub fn pressures(&self) -> &Vec<f64> {
119 return self._base_data.scalar_data_at(self._pressure_idx);
120 }
121
122 pub fn pressures_mut(&mut self) -> &mut Vec<f64> {
124 return self._base_data.scalar_data_at_mut(self._pressure_idx);
125 }
126
127 pub fn update_densities(&mut self) {
137 let m = self._base_data.mass();
138
139 let mut density: Vec<f64> = self._base_data.positions().into_par_iter().map(|pos| {
140 let sum = self.sum_of_kernel_nearby(pos);
141 return m * sum;
142 }).collect();
143 self.densities_mut().clear();
144 self.densities_mut().append(&mut density);
145 }
146
147 pub fn set_target_density(&mut self, target_density: f64) {
149 self._target_density = target_density;
150
151 self.compute_mass();
152 }
153
154 pub fn target_density(&self) -> f64 {
156 return self._target_density;
157 }
158
159 pub fn set_target_spacing(&mut self, spacing: f64) {
166 self._base_data.set_radius(spacing);
167
168 self._target_spacing = spacing;
169 self._kernel_radius = self._kernel_radius_over_target_spacing * self._target_spacing;
170
171 self.compute_mass();
172 }
173
174 pub fn target_spacing(&self) -> f64 {
176 return self._target_spacing;
177 }
178
179 pub fn set_relative_kernel_radius(&mut self, relative_radius: f64) {
188 self._kernel_radius_over_target_spacing = relative_radius;
189 self._kernel_radius = self._kernel_radius_over_target_spacing * self._target_spacing;
190
191 self.compute_mass();
192 }
193
194 pub fn relative_kernel_radius(&self) -> f64 {
201 return self._kernel_radius_over_target_spacing;
202 }
203
204 pub fn set_kernel_radius(&mut self, kernel_radius: f64) {
213 self._kernel_radius = kernel_radius;
214 self._target_spacing = kernel_radius / self._kernel_radius_over_target_spacing;
215
216 self.compute_mass();
217 }
218
219 pub fn kernel_radius(&self) -> f64 {
221 return self._kernel_radius;
222 }
223 pub fn sum_of_kernel_nearby(&self, origin: &Vector3D) -> f64 {
225 let mut sum = 0.0;
226 let kernel = SphStdKernel3::new(self._kernel_radius);
227 self._base_data.neighbor_searcher().read().unwrap().for_each_nearby_point(
228 origin, self._kernel_radius, &mut |_: usize, neighbor_position: &Vector3D| {
229 let dist = origin.distance_to(*neighbor_position);
230 sum += kernel.apply(dist);
231 });
232 return sum;
233 }
234
235 pub fn interpolate_scalar(&self, origin: &Vector3D,
247 values: &Vec<f64>) -> f64 {
248 let mut sum = 0.0;
249 let d = self.densities();
250 let kernel = SphStdKernel3::new(self._kernel_radius);
251 let m = self._base_data.mass();
252
253 self._base_data.neighbor_searcher().read().unwrap().for_each_nearby_point(
254 origin, self._kernel_radius, &mut |i: usize, neighbor_position: &Vector3D| {
255 let dist = origin.distance_to(*neighbor_position);
256 let weight = m / d[i] * kernel.apply(dist);
257 sum += weight * values[i];
258 });
259
260 return sum;
261 }
262
263 pub fn interpolate_vec(&self, origin: &Vector3D,
275 values: &Vec<Vector3D>) -> Vector3D {
276 let mut sum = Vector3D::new_default();
277 let d = self.densities();
278 let kernel = SphStdKernel3::new(self._kernel_radius);
279 let m = self._base_data.mass();
280
281 self._base_data.neighbor_searcher().read().unwrap().for_each_nearby_point(
282 origin, self._kernel_radius, &mut |i: usize, neighbor_position: &Vector3D| {
283 let dist = origin.distance_to(*neighbor_position);
284 let weight = m / d[i] * kernel.apply(dist);
285 sum += values[i] * weight;
286 });
287
288 return sum;
289 }
290
291 pub fn gradient_at(&self, i: usize,
298 values: &Vec<f64>) -> Vector3D {
299 let mut sum = Vector3D::new_default();
300 let p = self._base_data.positions();
301 let d = self.densities();
302 let neighbors = &self._base_data.neighbor_lists()[i];
303 let origin = p[i];
304 let kernel = SphSpikyKernel3::new(self._kernel_radius);
305 let m = self._base_data.mass();
306
307 for j in neighbors {
308 let neighbor_position = p[*j];
309 let dist = origin.distance_to(neighbor_position);
310 if dist > 0.0 {
311 let dir = (neighbor_position - origin) / dist;
312 sum += kernel.gradient_dir(dist, &dir) * d[i] * m * (values[i] / crate::math_utils::square(d[i])
313 + values[*j] / crate::math_utils::square(d[*j]));
314 }
315 }
316
317 return sum;
318 }
319
320 pub fn laplacian_at_scalar(&self, i: usize,
327 values: &Vec<f64>) -> f64 {
328 let mut sum = 0.0;
329 let p = self._base_data.positions();
330 let d = self.densities();
331 let neighbors = &self._base_data.neighbor_lists()[i];
332 let origin = p[i];
333 let kernel = SphSpikyKernel3::new(self._kernel_radius);
334 let m = self._base_data.mass();
335
336 for j in neighbors {
337 let neighbor_position = p[*j];
338 let dist = origin.distance_to(neighbor_position);
339 sum += m * (values[*j] - values[i]) / d[*j] * kernel.second_derivative(dist);
340 }
341
342 return sum;
343 }
344
345 pub fn laplacian_at_vec(&self, i: usize,
352 values: &Vec<Vector3D>) -> Vector3D {
353 let mut sum = Vector3D::new_default();
354 let p = self._base_data.positions();
355 let d = self.densities();
356 let neighbors = &self._base_data.neighbor_lists()[i];
357 let origin = p[i];
358 let kernel = SphSpikyKernel3::new(self._kernel_radius);
359 let m = self._base_data.mass();
360
361 for j in neighbors {
362 let neighbor_position = p[*j];
363 let dist = origin.distance_to(neighbor_position);
364 sum += (values[*j] - values[i]) * m / d[*j] * kernel.second_derivative(dist);
365 }
366
367 return sum;
368 }
369
370 pub fn build_neighbor_searcher(&mut self) {
372 self._base_data.build_neighbor_searcher(self._kernel_radius);
373 }
374
375 pub fn build_neighbor_lists(&mut self) {
377 self._base_data.build_neighbor_lists(self._kernel_radius);
378 }
379
380 fn compute_mass(&mut self) {
382 let mut points: Vec<Vector3D> = Vec::new();
383 let points_generator = BccLatticePointGenerator {};
384 let sample_bound = BoundingBox3D::new(
385 Vector3D::new(-1.5 * self._kernel_radius, -1.5 * self._kernel_radius, -1.5 * self._kernel_radius),
386 Vector3D::new(1.5 * self._kernel_radius, 1.5 * self._kernel_radius, 1.5 * self._kernel_radius));
387
388 points_generator.generate(&sample_bound, self._target_spacing, &mut points);
389
390 let mut max_number_density = 0.0;
391 let kernel = SphStdKernel3::new(self._kernel_radius);
392
393 for i in 0..points.len() {
394 let point = points[i];
395 let mut sum = 0.0;
396
397 for j in 0..points.len() {
398 let neighbor_point = points[j];
399 sum += kernel.apply(neighbor_point.distance_to(point));
400 }
401
402 max_number_density = f64::max(max_number_density, sum);
403 }
404
405 debug_assert!(max_number_density > 0.0);
406
407 let new_mass = self._target_density / max_number_density;
408 self._base_data.set_mass(new_mass);
409 }
410}
411
412impl SphSystemData3 {
413 pub fn radius(&self) -> f64 {
415 return self._base_data.radius();
416 }
417
418 pub fn mass(&self) -> f64 {
420 return self._base_data.mass();
421 }
422
423 pub fn positions(&self) -> &Vec<Vector3D> {
425 return self._base_data.positions();
426 }
427
428 pub fn positions_mut(&mut self) -> &mut Vec<Vector3D> {
430 return self._base_data.positions_mut();
431 }
432
433 pub fn velocities(&self) -> &Vec<Vector3D> {
435 return self._base_data.velocities();
436 }
437
438 pub fn velocities_mut(&mut self) -> &mut Vec<Vector3D> {
440 return self._base_data.velocities_mut();
441 }
442
443 pub fn forces(&self) -> &Vec<Vector3D> {
445 return self._base_data.forces();
446 }
447
448 pub fn forces_mut(&mut self) -> &mut Vec<Vector3D> {
450 return self._base_data.forces_mut();
451 }
452
453 pub fn number_of_particles(&self) -> usize {
455 return self._base_data.number_of_particles();
456 }
457
458 pub fn neighbor_lists(&self) -> &Vec<Vec<usize>> {
468 return self._base_data.neighbor_lists();
469 }
470}
471
472pub type SphSystemData3Ptr = Arc<RwLock<SphSystemData3>>;