use molrs::Block;
use molrs::Frame;
use molrs::spatial::region::simbox::{BoxKind, SimBox};
use molrs::store::block::BlockDtype;
use molrs::store::frame_access::FrameAccess;
use molrs::types::F;
use ndarray::array;
use super::error::ComputeError;
pub fn get_f_slice<'a>(
block: &'a Block,
block_name: &'static str,
col_name: &'static str,
) -> Result<&'a [F], ComputeError> {
let col = block.get(col_name).ok_or(ComputeError::MissingColumn {
block: block_name,
col: col_name,
})?;
let arr = <F as BlockDtype>::from_column(col).ok_or(ComputeError::MissingColumn {
block: block_name,
col: col_name,
})?;
arr.as_slice().ok_or(ComputeError::MissingColumn {
block: block_name,
col: col_name,
})
}
#[derive(Debug, Clone, Copy)]
pub enum MicHelper<'a> {
Free,
Ortho {
len: [F; 3],
inv_len: [F; 3],
pbc: [bool; 3],
},
Triclinic(&'a SimBox),
}
impl<'a> MicHelper<'a> {
#[inline]
pub fn from_simbox(sb: Option<&'a SimBox>) -> Self {
match sb {
None => MicHelper::Free,
Some(sb) => {
let pbc = sb.pbc();
if !pbc.iter().any(|&p| p) {
return MicHelper::Free;
}
match sb.kind() {
BoxKind::Ortho { len, inv_len } => MicHelper::Ortho {
len: [len[0], len[1], len[2]],
inv_len: [inv_len[0], inv_len[1], inv_len[2]],
pbc,
},
BoxKind::Triclinic => MicHelper::Triclinic(sb),
}
}
}
}
#[inline(always)]
pub fn disp(&self, from: [F; 3], to: [F; 3]) -> [F; 3] {
match *self {
MicHelper::Free => [to[0] - from[0], to[1] - from[1], to[2] - from[2]],
MicHelper::Ortho { len, inv_len, pbc } => {
let mut dr = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];
if pbc[0] {
dr[0] -= (dr[0] * inv_len[0]).round() * len[0];
}
if pbc[1] {
dr[1] -= (dr[1] * inv_len[1]).round() * len[1];
}
if pbc[2] {
dr[2] -= (dr[2] * inv_len[2]).round() * len[2];
}
dr
}
MicHelper::Triclinic(sb) => {
let a = array![from[0], from[1], from[2]];
let b = array![to[0], to[1], to[2]];
let dr = sb.shortest_vector(a.view(), b.view());
[dr[0], dr[1], dr[2]]
}
}
}
}
#[inline]
pub fn mic_disp(simbox: Option<&SimBox>, from: [F; 3], to: [F; 3]) -> [F; 3] {
MicHelper::from_simbox(simbox).disp(from, to)
}
pub type PositionSlices<'a> = (&'a [F], &'a [F], &'a [F]);
pub fn get_positions(frame: &Frame) -> Result<PositionSlices<'_>, ComputeError> {
let atoms = frame
.get("atoms")
.ok_or(ComputeError::MissingBlock { name: "atoms" })?;
let xs = get_f_slice(atoms, "atoms", "x")?;
let ys = get_f_slice(atoms, "atoms", "y")?;
let zs = get_f_slice(atoms, "atoms", "z")?;
Ok((xs, ys, zs))
}
#[derive(Debug)]
pub enum Positions<'a> {
Borrowed(&'a [F]),
Owned(Vec<F>),
}
impl<'a> Positions<'a> {
#[inline]
pub fn slice(&self) -> &[F] {
match self {
Positions::Borrowed(s) => s,
Positions::Owned(v) => v.as_slice(),
}
}
}
fn column_to_positions<'a, FA: FrameAccess>(
frame: &'a FA,
col: &'static str,
) -> Result<Positions<'a>, ComputeError> {
let view = frame
.get_float("atoms", col)
.ok_or(ComputeError::MissingColumn {
block: "atoms",
col,
})?;
match view.as_slice() {
Some(s) => {
let ptr = s.as_ptr();
let len = s.len();
let slice: &'a [F] = unsafe { std::slice::from_raw_parts(ptr, len) };
Ok(Positions::Borrowed(slice))
}
None => Ok(Positions::Owned(view.iter().copied().collect())),
}
}
pub fn get_positions_ref<'a, FA: FrameAccess>(
frame: &'a FA,
) -> Result<(Positions<'a>, Positions<'a>, Positions<'a>), ComputeError> {
let xs = column_to_positions(frame, "x")?;
let ys = column_to_positions(frame, "y")?;
let zs = column_to_positions(frame, "z")?;
Ok((xs, ys, zs))
}