use molframe_core::{AtomSelection, ExecutionContext};
use crate::{SpatialBackend, SpatialError, pairs_within};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CrossPair {
pub first: u32,
pub second: u32,
pub distance_squared: f32,
}
pub fn cross_pairs(
first: &[[f32; 3]],
second: &[[f32; 3]],
cutoff: f32,
backend: SpatialBackend,
context: &ExecutionContext,
) -> Result<Vec<CrossPair>, SpatialError> {
let left_count = u32::try_from(first.len()).map_err(|_| SpatialError::NumericRangeExceeded)?;
let count = first
.len()
.checked_add(second.len())
.ok_or(SpatialError::NumericRangeExceeded)?;
let total = u32::try_from(count).map_err(|_| SpatialError::NumericRangeExceeded)?;
let bytes = count
.checked_mul(size_of::<[f32; 3]>())
.ok_or(SpatialError::NumericRangeExceeded)?;
let _reservation = context.try_reserve(bytes)?;
let mut positions = Vec::with_capacity(count);
positions.extend_from_slice(first);
positions.extend_from_slice(second);
let pairs = pairs_within(
&positions,
&AtomSelection::range(0..left_count),
&AtomSelection::range(left_count..total),
cutoff,
backend,
None,
context,
)?;
Ok(pairs
.into_iter()
.map(|pair| CrossPair {
first: pair.first,
second: pair.second - left_count,
distance_squared: pair.distance_squared,
})
.collect())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cross_indices_remain_local_even_when_the_right_index_is_smaller() {
let first = [[10.0, 0.0, 0.0], [0.0, 0.0, 0.0]];
let second = [[0.5, 0.0, 0.0]];
let pairs = cross_pairs(
&first,
&second,
1.0,
SpatialBackend::BruteForce,
&ExecutionContext::default(),
)
.expect("valid independent coordinate sets");
assert_eq!(
pairs,
vec![CrossPair {
first: 1,
second: 0,
distance_squared: 0.25
}]
);
}
#[test]
fn dense_sets_do_not_emit_within_set_pairs() {
let first = [[0.0; 3]; 4];
let second = [[0.0; 3]; 3];
let pairs = cross_pairs(
&first,
&second,
1.0,
SpatialBackend::CellList,
&ExecutionContext::default(),
)
.expect("valid dense coordinate sets");
assert_eq!(pairs.len(), first.len() * second.len());
assert!(pairs.iter().all(|pair| pair.first < 4 && pair.second < 3));
}
}