molframe_spatial/backends/cell/
budget.rs1use super::{CellGrid, CellId, CellList, Layout, choose_layout, finite_bounds, periodic_grid};
4use crate::{CellGridOptions, PeriodicBox, SpatialError};
5use molframe_core::ExecutionContext;
6
7impl<'a> CellList<'a> {
8 pub fn build_in(
16 positions: &'a [[f32; 3]],
17 targets: &[u32],
18 cutoff: f32,
19 periodic: Option<PeriodicBox>,
20 options: CellGridOptions,
21 context: &ExecutionContext,
22 ) -> Result<Self, SpatialError> {
23 if context.cancellation().is_cancelled() {
24 return Err(SpatialError::Cancelled);
25 }
26 super::validate_cutoff(cutoff)?;
27 super::validate_indices(targets, positions.len())?;
28 options.validate()?;
29 let bytes = workspace_bytes(positions, targets, cutoff, periodic.as_ref(), options)?;
30 let mut reservation = context.try_reserve(bytes)?;
31 let mut index = Self::build_with_options(positions, targets, cutoff, periodic, options)?;
32 let retained = match &index.grid {
33 Some(CellGrid::Cartesian(grid)) => grid.retained_bytes(),
34 Some(CellGrid::Periodic(grid)) => grid.retained_bytes(),
35 None => 0,
36 };
37 reservation.shrink_to(retained);
38 index.reservation = Some(reservation);
39 Ok(index)
40 }
41}
42
43fn workspace_bytes(
44 positions: &[[f32; 3]],
45 targets: &[u32],
46 cutoff: f32,
47 periodic: Option<&PeriodicBox>,
48 options: CellGridOptions,
49) -> Result<usize, SpatialError> {
50 let (cells, atoms, occupied) = if let Some(periodic) = periodic {
51 let dims = periodic_grid::periodic_dimensions(periodic, cutoff, options)?;
52 (periodic_grid::cell_count(dims)?, targets.len(), 0)
53 } else if let Some(bounds) = finite_bounds(positions, targets) {
54 match choose_layout(&bounds, cutoff, options)? {
55 Layout::Dense { cells, .. } => {
56 (cells, bounds.finite_count, cells.min(bounds.finite_count))
57 }
58 Layout::Sparse { .. } => {
61 return bounds
62 .finite_count
63 .checked_mul(
64 size_of::<(CellId, u32)>()
65 + size_of::<u32>()
66 + size_of::<usize>()
67 + size_of::<CellId>(),
68 )
69 .and_then(|bytes| bytes.checked_add(size_of::<usize>()))
70 .ok_or(SpatialError::NumericRangeExceeded);
71 }
72 }
73 } else {
74 return Ok(0);
75 };
76 cells
79 .checked_mul(2)
80 .and_then(|count| count.checked_add(1))
81 .and_then(|count| count.checked_mul(size_of::<usize>()))
82 .and_then(|bytes| {
83 occupied
84 .checked_mul(size_of::<CellId>())
85 .and_then(|ids| bytes.checked_add(ids))
86 })
87 .and_then(|bytes| {
88 atoms
89 .checked_mul(size_of::<u32>())
90 .and_then(|members| bytes.checked_add(members))
91 })
92 .ok_or(SpatialError::NumericRangeExceeded)
93}
94
95#[cfg(test)]
96#[path = "budget_tests.rs"]
97mod tests;
98
99impl super::Grid {
100 fn retained_bytes(&self) -> usize {
101 self.offsets.capacity() * size_of::<usize>()
102 + self.non_empty_cells.capacity() * size_of::<super::CellId>()
103 + self.members.capacity() * size_of::<u32>()
104 }
105}