use crate::index::{AnisotropyIndex, AtomIndex};
use std::sync::Arc;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct AnisotropicDisplacement {
pub atom: AtomIndex,
pub u: [f32; 6],
}
#[derive(Clone, Debug)]
pub struct AnisotropyTable {
atom: Arc<Vec<AtomIndex>>,
u: Arc<Vec<[f32; 6]>>,
available: bool,
}
impl Default for AnisotropyTable {
fn default() -> Self {
Self {
atom: Arc::new(Vec::new()),
u: Arc::new(Vec::new()),
available: false,
}
}
}
impl AnisotropyTable {
#[must_use]
pub fn len(&self) -> usize {
self.atom.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.atom.is_empty()
}
#[must_use]
pub const fn is_available(&self) -> bool {
self.available
}
#[must_use]
pub fn get(&self, row: AnisotropyIndex) -> Option<AnisotropicDisplacement> {
let position = row.as_usize();
Some(AnisotropicDisplacement {
atom: *self.atom.get(position)?,
u: *self.u.get(position)?,
})
}
#[must_use]
pub fn for_atom(&self, atom: AtomIndex) -> Option<[f32; 6]> {
let position = self.atom.binary_search(&atom).ok()?;
Some(self.u[position])
}
#[must_use]
pub fn iter(&self) -> impl ExactSizeIterator<Item = AnisotropicDisplacement> + '_ {
self.atom
.iter()
.zip(self.u.iter())
.map(|(atom, u)| AnisotropicDisplacement { atom: *atom, u: *u })
}
}
#[derive(Debug, Default)]
pub struct AnisotropyTableBuilder {
records: Vec<AnisotropicDisplacement>,
}
impl AnisotropyTableBuilder {
#[must_use]
pub const fn new() -> Self {
Self {
records: Vec::new(),
}
}
pub fn push(&mut self, record: AnisotropicDisplacement) {
self.records.push(record);
}
#[must_use]
pub fn finish(self) -> AnisotropyTable {
self.finish_with_availability(true)
}
#[must_use]
pub fn finish_with_availability(mut self, available: bool) -> AnisotropyTable {
self.records.sort_by_key(|record| record.atom.get());
self.records.dedup_by_key(|record| record.atom.get());
let mut atom = Vec::with_capacity(self.records.len());
let mut u = Vec::with_capacity(self.records.len());
for record in self.records {
atom.push(record.atom);
u.push(record.u);
}
AnisotropyTable {
atom: Arc::new(atom),
u: Arc::new(u),
available,
}
}
}
#[cfg(test)]
#[path = "model_tests.rs"]
mod tests;