use std::io::Write;
use getset::{CopyGetters, Getters, Setters};
use nalgebra::Matrix3;
use crate::auxiliary::{
GRO_MAX_COORDINATE, GRO_MIN_COORDINATE, PDB_MAX_COORDINATE, PDB_MIN_COORDINATE,
};
use crate::errors::{AtomError, PositionError, WriteGroError, WritePdbError, WritePqrError};
use crate::io::pqr_io::PqrPrecision;
use crate::structures::{
container::AtomContainer, dimension::Dimension, simbox::SimBox, vector3d::Vector3D,
};
#[derive(Debug, Clone, Setters, Getters, CopyGetters)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct Atom {
#[getset(get_copy = "pub with_prefix", set = "pub(crate)")]
#[cfg_attr(feature = "serde", serde(skip))]
index: usize,
#[getset(get_copy = "pub with_prefix", set = "pub")]
residue_number: usize,
#[getset(get = "pub with_prefix")]
residue_name: String,
#[getset(get_copy = "pub with_prefix", set = "pub")]
atom_number: usize,
#[getset(get = "pub with_prefix")]
atom_name: String,
#[getset(get_copy = "pub with_prefix")]
chain: Option<char>,
#[getset(get_copy = "pub with_prefix")]
charge: Option<f32>,
#[getset(get_copy = "pub with_prefix")]
mass: Option<f32>,
#[getset(get_copy = "pub with_prefix")]
vdw: Option<f32>,
#[getset(get_copy = "pub with_prefix")]
expected_max_bonds: Option<u8>,
#[getset(get_copy = "pub with_prefix")]
expected_min_bonds: Option<u8>,
element_name: Option<String>,
element_symbol: Option<String>,
position: Option<Vector3D>,
velocity: Option<Vector3D>,
force: Option<Vector3D>,
bonded: AtomContainer,
}
impl Atom {
#[inline(always)]
pub fn new(
residue_number: usize,
residue_name: &str,
atom_number: usize,
atom_name: &str,
) -> Self {
Atom {
index: 0,
residue_number,
residue_name: residue_name.to_string(),
atom_number,
atom_name: atom_name.to_string(),
chain: None,
charge: None,
mass: None,
vdw: None,
expected_max_bonds: None,
expected_min_bonds: None,
element_name: None,
element_symbol: None,
position: None,
velocity: None,
force: None,
bonded: AtomContainer::empty(),
}
}
#[inline(always)]
pub fn with_position(mut self, position: Vector3D) -> Self {
self.set_position(position);
self
}
#[inline(always)]
pub fn with_velocity(mut self, velocity: Vector3D) -> Self {
self.set_velocity(velocity);
self
}
#[inline(always)]
pub fn with_force(mut self, force: Vector3D) -> Self {
self.set_force(force);
self
}
#[inline(always)]
pub fn with_chain(mut self, chain: char) -> Self {
self.set_chain(chain);
self
}
#[inline(always)]
pub fn with_charge(mut self, charge: f32) -> Self {
self.set_charge(charge);
self
}
#[inline(always)]
pub fn with_mass(mut self, mass: f32) -> Self {
self.set_mass(mass);
self
}
#[inline(always)]
pub fn with_vdw(mut self, vdw: f32) -> Self {
self.set_vdw(vdw);
self
}
#[inline(always)]
pub fn with_expected_max_bonds(mut self, expected_max_bonds: u8) -> Self {
self.set_expected_max_bonds(expected_max_bonds);
self
}
#[inline(always)]
pub fn with_expected_min_bonds(mut self, expected_min_bonds: u8) -> Self {
self.set_expected_min_bonds(expected_min_bonds);
self
}
#[inline(always)]
pub fn with_element_name(mut self, name: &str) -> Self {
self.set_element_name(name);
self
}
#[inline(always)]
pub fn with_element_symbol(mut self, symbol: &str) -> Self {
self.set_element_symbol(symbol);
self
}
#[inline(always)]
pub fn set_residue_name(&mut self, resname: &str) {
self.residue_name = resname.to_string();
}
#[inline(always)]
pub fn set_atom_name(&mut self, atomname: &str) {
self.atom_name = atomname.to_string();
}
#[inline(always)]
pub fn set_chain(&mut self, chain: char) {
self.chain = Some(chain);
}
#[inline(always)]
pub fn reset_chain(&mut self) {
self.chain = None;
}
#[inline(always)]
pub fn set_charge(&mut self, charge: f32) {
self.charge = Some(charge);
}
#[inline(always)]
pub fn reset_charge(&mut self) {
self.charge = None;
}
#[inline(always)]
pub fn set_mass(&mut self, mass: f32) {
self.mass = Some(mass);
}
#[inline(always)]
pub fn reset_mass(&mut self) {
self.mass = None;
}
#[inline(always)]
pub fn set_vdw(&mut self, vdw: f32) {
self.vdw = Some(vdw);
}
#[inline(always)]
pub fn reset_vdw(&mut self) {
self.vdw = None;
}
#[inline(always)]
pub fn set_expected_max_bonds(&mut self, expected_max_bonds: u8) {
self.expected_max_bonds = Some(expected_max_bonds);
}
#[inline(always)]
pub fn reset_expected_max_bonds(&mut self) {
self.expected_max_bonds = None;
}
#[inline(always)]
pub fn set_expected_min_bonds(&mut self, expected_min_bonds: u8) {
self.expected_min_bonds = Some(expected_min_bonds);
}
#[inline(always)]
pub fn reset_expected_min_bonds(&mut self) {
self.expected_min_bonds = None;
}
#[inline(always)]
pub fn get_element_name(&self) -> Option<&String> {
self.element_name.as_ref()
}
#[inline(always)]
pub fn set_element_name(&mut self, name: &str) {
self.element_name = Some(name.to_string());
}
#[inline(always)]
pub fn reset_element_name(&mut self) {
self.element_name = None;
}
#[inline(always)]
pub fn get_element_symbol(&self) -> Option<&String> {
self.element_symbol.as_ref()
}
#[inline(always)]
pub fn set_element_symbol(&mut self, symbol: &str) {
self.element_symbol = Some(symbol.to_string());
}
#[inline(always)]
pub fn reset_element_symbol(&mut self) {
self.element_symbol = None;
}
#[inline(always)]
pub fn get_position(&self) -> Option<&Vector3D> {
self.position.as_ref()
}
#[inline(always)]
pub fn get_position_mut(&mut self) -> Option<&mut Vector3D> {
self.position.as_mut()
}
#[inline(always)]
pub fn set_position(&mut self, pos: Vector3D) {
self.position = Some(pos);
}
#[inline(always)]
pub fn reset_position(&mut self) {
self.position = None;
}
#[inline(always)]
pub fn set_position_x(&mut self, x: f32) {
match self.position {
None => self.position = Some(Vector3D::new(x, 0.0, 0.0)),
Some(ref mut pos) => pos.x = x,
}
}
#[inline(always)]
pub fn set_position_y(&mut self, y: f32) {
match self.position {
None => self.position = Some(Vector3D::new(0.0, y, 0.0)),
Some(ref mut pos) => pos.y = y,
}
}
#[inline(always)]
pub fn set_position_z(&mut self, z: f32) {
match self.position {
None => self.position = Some(Vector3D::new(0.0, 0.0, z)),
Some(ref mut pos) => pos.z = z,
}
}
#[inline(always)]
pub fn get_velocity(&self) -> Option<&Vector3D> {
self.velocity.as_ref()
}
#[inline(always)]
pub fn get_velocity_mut(&mut self) -> Option<&mut Vector3D> {
self.velocity.as_mut()
}
#[inline(always)]
pub fn set_velocity(&mut self, vel: Vector3D) {
self.velocity = Some(vel);
}
#[inline(always)]
pub fn reset_velocity(&mut self) {
self.velocity = None;
}
#[inline(always)]
pub fn get_force(&self) -> Option<&Vector3D> {
self.force.as_ref()
}
#[inline(always)]
pub fn get_force_mut(&mut self) -> Option<&mut Vector3D> {
self.force.as_mut()
}
#[inline(always)]
pub fn set_force(&mut self, force: Vector3D) {
self.force = Some(force);
}
#[inline(always)]
pub fn reset_force(&mut self) {
self.force = None;
}
#[inline(always)]
pub fn get_bonded(&self) -> &AtomContainer {
&self.bonded
}
#[inline(always)]
pub unsafe fn set_bonded(&mut self, indices: Vec<usize>) {
self.bonded = AtomContainer::from_indices(indices, usize::MAX);
}
#[inline(always)]
pub unsafe fn add_bonded(&mut self, index: usize) {
self.bonded.add(index, usize::MAX);
}
#[inline(always)]
pub unsafe fn reset_bonded(&mut self) {
self.bonded = AtomContainer::empty();
}
#[inline(always)]
pub fn get_n_bonded(&self) -> usize {
self.bonded.get_n_atoms()
}
#[inline(always)]
pub fn has_position(&self) -> bool {
self.position.is_some()
}
#[inline(always)]
pub fn has_velocity(&self) -> bool {
self.velocity.is_some()
}
#[inline(always)]
pub fn has_force(&self) -> bool {
self.force.is_some()
}
#[inline(always)]
pub fn translate(&mut self, translate: &Vector3D, sbox: &SimBox) -> Result<(), AtomError> {
if let Some(ref mut pos) = self.position {
pos.x += translate.x;
pos.y += translate.y;
pos.z += translate.z;
pos.wrap(sbox);
Ok(())
} else {
Err(AtomError::InvalidPosition(PositionError::NoPosition(
self.get_index(),
)))
}
}
#[inline(always)]
pub fn translate_nopbc(&mut self, translate: &Vector3D) -> Result<(), AtomError> {
if let Some(ref mut pos) = self.position {
pos.0 += translate.0;
Ok(())
} else {
Err(AtomError::InvalidPosition(PositionError::NoPosition(
self.get_index(),
)))
}
}
#[inline(always)]
pub fn wrap(&mut self, sbox: &SimBox) -> Result<(), AtomError> {
match self.position {
None => Err(AtomError::InvalidPosition(PositionError::NoPosition(
self.get_index(),
))),
Some(ref mut pos) => {
pos.wrap(sbox);
Ok(())
}
}
}
pub fn write_gro(
&self,
stream: &mut impl Write,
write_velocities: bool,
) -> Result<(), WriteGroError> {
let binding = Vector3D::default();
let position = self.get_position().unwrap_or(&binding);
let format_atomname = match self.get_atom_name().len() {
0..=5 => format!("{:>5}", self.get_atom_name()),
_ => format!(
"{:>5}",
self.get_atom_name().chars().take(5).collect::<String>()
),
};
let format_resname = match self.get_residue_name().len() {
0..=5 => format!("{:<5}", self.get_residue_name()),
_ => format!(
"{:<5}",
self.get_residue_name().chars().take(5).collect::<String>()
),
};
if [position.x, position.y, position.z]
.into_iter()
.any(|coor| !(GRO_MIN_COORDINATE..=GRO_MAX_COORDINATE).contains(&coor))
{
return Err(WriteGroError::CoordinateTooLarge);
}
if write_velocities {
let velocity = self.get_velocity().unwrap_or(&binding);
writeln!(
stream,
"{:>5}{}{}{:>5}{:>8.3}{:>8.3}{:>8.3}{:>8.4}{:>8.4}{:>8.4}",
self.get_residue_number() % 100_000,
format_resname,
format_atomname,
self.get_atom_number() % 100_000,
position.x,
position.y,
position.z,
velocity.x,
velocity.y,
velocity.z
)
.map_err(|_| WriteGroError::CouldNotWrite)?;
} else {
writeln!(
stream,
"{:>5}{:<5}{:>5}{:>5}{:>8.3}{:>8.3}{:>8.3}",
self.get_residue_number() % 100_000,
format_resname,
format_atomname,
self.get_atom_number() % 100_000,
position.x,
position.y,
position.z
)
.map_err(|_| WriteGroError::CouldNotWrite)?;
}
Ok(())
}
pub fn write_pdb(&self, stream: &mut impl Write) -> Result<(), WritePdbError> {
let binding = Vector3D::default();
let position = self.get_position().unwrap_or(&binding);
let format_resname = match self.get_residue_name().len() {
0..=3 => format!("{:>3} ", self.get_residue_name()),
4 => format!("{:>4}", self.get_residue_name()),
_ => format!(
"{:>4}",
self.get_residue_name().chars().take(4).collect::<String>()
),
};
let format_atomname = match self.get_atom_name().len() {
0..=3 => format!(" {:<3}", self.get_atom_name()),
4 => format!("{:<4}", self.get_atom_name()),
_ => format!(
"{:<4}",
self.get_atom_name().chars().take(4).collect::<String>()
),
};
let format_chain = self.get_chain().unwrap_or(' ');
if [position.x, position.y, position.z]
.into_iter()
.any(|coor| !(PDB_MIN_COORDINATE..=PDB_MAX_COORDINATE).contains(&coor))
{
return Err(WritePdbError::CoordinateTooLarge);
}
writeln!(
stream,
"ATOM {:>5} {} {}{}{:>4} {:>8.3}{:>8.3}{:>8.3} 1.00 0.00 ",
self.get_atom_number() % 100000,
format_atomname,
format_resname,
format_chain,
self.get_residue_number() % 10000,
position.x * 10.0,
position.y * 10.0,
position.z * 10.0,
)
.map_err(|_| WritePdbError::CouldNotWrite)?;
Ok(())
}
pub fn write_pqr(
&self,
stream: &mut impl Write,
precision: &PqrPrecision,
) -> Result<(), WritePqrError> {
let format_resname = match self.get_residue_name().len() {
0..=3 => format!("{:>3} ", self.get_residue_name()),
_ => format!("{} ", self.get_residue_name()),
};
let format_atomname = match self.get_atom_name().len() {
0..=3 => format!(" {:<3}", self.get_atom_name()),
_ => self.get_atom_name().to_string(),
};
let resid = self.get_residue_number();
let format_resid = match resid {
0..=999 => format!("{:>4} ", resid),
1000..=9999 => format!("{:>5} ", resid),
10000..=99999 => format!("{:>6} ", resid),
100000..=999999 => format!("{:>7} ", resid),
1000000..=9999999 => format!("{:>8}", resid),
_ => format!(" {}", resid),
};
let format_atomnum = match self.get_atom_number() {
0..=99999 => format!(" {:>5}", self.get_atom_number()),
_ => format!("{}", self.get_atom_number()),
};
let chain = self.get_chain().unwrap_or(' ');
let binding = Vector3D::default();
let position = self.get_position().unwrap_or(&binding);
let charge = self.get_charge().unwrap_or(0.0);
let vdw = self.get_vdw().unwrap_or(0.0);
writeln!(
stream,
"ATOM {3} {4} {5}{6}{7} {8:>7.0$} {9:>7.0$} {10:>7.0$} {11:>7.1$} {12:>6.2$}",
precision.position,
precision.charge,
precision.vdw,
format_atomnum,
format_atomname,
format_resname,
chain,
format_resid,
position.x * 10.0,
position.y * 10.0,
position.z * 10.0,
charge,
vdw * 10.0,
)
.map_err(|_| WritePqrError::CouldNotWrite)?;
Ok(())
}
pub fn distance(&self, atom: &Atom, dim: Dimension, sbox: &SimBox) -> Result<f32, AtomError> {
match (&self.position, &atom.position) {
(None, Some(_) | None) => Err(AtomError::InvalidPosition(PositionError::NoPosition(
self.get_index(),
))),
(Some(_), None) => Err(AtomError::InvalidPosition(PositionError::NoPosition(
atom.get_index(),
))),
(Some(ref pos1), Some(ref pos2)) => Ok(pos1.distance(pos2, dim, sbox)),
}
}
pub fn distance_naive(&self, atom: &Atom, dim: Dimension) -> Result<f32, AtomError> {
match (&self.position, &atom.position) {
(None, Some(_) | None) => Err(AtomError::InvalidPosition(PositionError::NoPosition(
self.get_index(),
))),
(Some(_), None) => Err(AtomError::InvalidPosition(PositionError::NoPosition(
atom.get_index(),
))),
(Some(ref pos1), Some(ref pos2)) => Ok(pos1.distance_naive(pos2, dim)),
}
}
pub fn distance_from_point(
&self,
point: &Vector3D,
dim: Dimension,
sbox: &SimBox,
) -> Result<f32, AtomError> {
match self.position {
None => Err(AtomError::InvalidPosition(PositionError::NoPosition(
self.get_index(),
))),
Some(ref pos) => Ok(pos.distance(point, dim, sbox)),
}
}
#[inline]
pub fn rotate(
&mut self,
rotation_matrix: &Matrix3<f32>,
simbox: &SimBox,
) -> Result<(), AtomError> {
let pos = self.get_position().cloned().ok_or_else(|| {
AtomError::InvalidPosition(PositionError::NoPosition(self.get_index()))
})?;
let mut rotated = pos.rotate(rotation_matrix);
rotated.wrap(simbox);
self.set_position(rotated);
Ok(())
}
#[inline]
pub fn rotate_nopbc(&mut self, rotation_matrix: &Matrix3<f32>) -> Result<(), AtomError> {
let pos = self.get_position().cloned().ok_or_else(|| {
AtomError::InvalidPosition(PositionError::NoPosition(self.get_index()))
})?;
let rotated = pos.rotate(rotation_matrix);
self.set_position(rotated);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use float_cmp::assert_approx_eq;
fn make_default_atom() -> Atom {
Atom::new(45, "GLY", 123, "BB")
.with_position([15.123, 14.321, 9.834].into())
.with_velocity([-3.432, 0.184, 1.234].into())
.with_force([5.1235, 2.3451, -0.32145].into())
}
#[test]
fn new() {
let atom = make_default_atom();
assert_eq!(atom.get_residue_number(), 45);
assert_eq!(atom.get_residue_name(), "GLY");
assert_eq!(atom.get_atom_number(), 123);
assert_eq!(atom.get_atom_name(), "BB");
let pos = atom.get_position().unwrap();
assert_approx_eq!(f32, pos.x, 15.123);
assert_approx_eq!(f32, pos.y, 14.321);
assert_approx_eq!(f32, pos.z, 9.834);
let vel = atom.get_velocity().unwrap();
assert_approx_eq!(f32, vel.x, -3.432);
assert_approx_eq!(f32, vel.y, 0.184);
assert_approx_eq!(f32, vel.z, 1.234);
let force = atom.get_force().unwrap();
assert_approx_eq!(f32, force.x, 5.1235);
assert_approx_eq!(f32, force.y, 2.3451);
assert_approx_eq!(f32, force.z, -0.32145);
}
#[test]
fn residue_number() {
let mut atom = make_default_atom();
assert_eq!(atom.get_residue_number(), 45);
atom.set_residue_number(187);
assert_eq!(atom.get_residue_number(), 187);
}
#[test]
fn residue_name() {
let mut atom = make_default_atom();
assert_eq!(atom.get_residue_name(), "GLY");
atom.set_residue_name("LYS");
assert_eq!(atom.get_residue_name(), "LYS");
}
#[test]
fn atom_number() {
let mut atom = make_default_atom();
assert_eq!(atom.get_atom_number(), 123);
atom.set_atom_number(13);
assert_eq!(atom.get_atom_number(), 13);
}
#[test]
fn atom_name() {
let mut atom = make_default_atom();
assert_eq!(atom.get_atom_name(), "BB");
atom.set_atom_name("SC1");
assert_eq!(atom.get_atom_name(), "SC1");
}
#[test]
fn chain() {
let mut atom = make_default_atom();
assert_eq!(atom.get_chain(), None);
atom.set_chain('B');
assert_eq!(atom.get_chain().unwrap(), 'B');
atom.reset_chain();
assert_eq!(atom.get_chain(), None);
let atom2 = make_default_atom().with_chain('B');
assert_eq!(atom2.get_chain().unwrap(), 'B');
}
#[test]
fn charge() {
let mut atom = make_default_atom();
assert_eq!(atom.get_charge(), None);
atom.set_charge(0.453);
assert_approx_eq!(f32, atom.get_charge().unwrap(), 0.453);
atom.reset_charge();
assert_eq!(atom.get_charge(), None);
let atom2 = make_default_atom().with_charge(0.453);
assert_approx_eq!(f32, atom2.get_charge().unwrap(), 0.453);
}
#[test]
fn mass() {
let mut atom = make_default_atom();
assert_eq!(atom.get_mass(), None);
atom.set_mass(10.453);
assert_approx_eq!(f32, atom.get_mass().unwrap(), 10.453);
atom.reset_mass();
assert_eq!(atom.get_mass(), None);
let atom2 = make_default_atom().with_mass(10.453);
assert_approx_eq!(f32, atom2.get_mass().unwrap(), 10.453);
}
#[test]
fn vdw() {
let mut atom = make_default_atom();
assert_eq!(atom.get_vdw(), None);
atom.set_vdw(0.19);
assert_approx_eq!(f32, atom.get_vdw().unwrap(), 0.19);
atom.reset_vdw();
assert_eq!(atom.get_vdw(), None);
let atom2 = make_default_atom().with_vdw(0.19);
assert_approx_eq!(f32, atom2.get_vdw().unwrap(), 0.19);
}
#[test]
fn expected_max_bonds() {
let mut atom = make_default_atom();
assert_eq!(atom.get_expected_max_bonds(), None);
atom.set_expected_max_bonds(3);
assert_eq!(atom.get_expected_max_bonds().unwrap(), 3);
atom.reset_expected_max_bonds();
assert_eq!(atom.get_expected_max_bonds(), None);
let atom2 = make_default_atom().with_expected_max_bonds(3);
assert_eq!(atom2.get_expected_max_bonds().unwrap(), 3);
}
#[test]
fn expected_min_bonds() {
let mut atom = make_default_atom();
assert_eq!(atom.get_expected_min_bonds(), None);
atom.set_expected_min_bonds(3);
assert_eq!(atom.get_expected_min_bonds().unwrap(), 3);
atom.reset_expected_min_bonds();
assert_eq!(atom.get_expected_min_bonds(), None);
let atom2 = make_default_atom().with_expected_min_bonds(3);
assert_eq!(atom2.get_expected_min_bonds().unwrap(), 3);
}
#[test]
fn element_name() {
let mut atom = make_default_atom();
assert_eq!(atom.get_element_name(), None);
atom.set_element_name("carbon");
assert_eq!(atom.get_element_name().unwrap(), &String::from("carbon"));
atom.reset_element_name();
assert_eq!(atom.get_element_name(), None);
let atom2 = make_default_atom().with_element_name("carbon");
assert_eq!(atom2.get_element_name().unwrap(), &String::from("carbon"));
}
#[test]
fn element_symbol() {
let mut atom = make_default_atom();
assert_eq!(atom.get_element_symbol(), None);
atom.set_element_symbol("C");
assert_eq!(atom.get_element_symbol().unwrap(), &String::from("C"));
atom.reset_element_symbol();
assert_eq!(atom.get_element_symbol(), None);
let atom2 = make_default_atom().with_element_symbol("C");
assert_eq!(atom2.get_element_symbol().unwrap(), &String::from("C"));
}
#[test]
fn get_position() {
let atom = make_default_atom();
assert_eq!(
*atom.get_position().unwrap(),
Vector3D::new(15.123, 14.321, 9.834)
);
}
#[test]
fn get_position_mut() {
let mut atom = make_default_atom();
atom.get_position_mut().unwrap().x += 3.4;
let pos = atom.get_position().unwrap();
assert_approx_eq!(f32, pos.x, 18.523);
assert_approx_eq!(f32, pos.y, 14.321);
assert_approx_eq!(f32, pos.z, 9.834);
}
#[test]
fn set_position() {
let mut atom = make_default_atom();
let new_pos = Vector3D::new(1.764, 2.134, 19.129);
atom.set_position(new_pos.clone());
assert_eq!(*atom.get_position().unwrap(), new_pos);
}
#[test]
fn set_position_x() {
let mut atom = make_default_atom();
let new_x = 19.129;
let new_pos = Vector3D::new(19.129, 14.321, 9.834);
atom.set_position_x(new_x);
assert_eq!(*atom.get_position().unwrap(), new_pos);
}
#[test]
fn set_position_y() {
let mut atom = make_default_atom();
let new_y = 19.129;
let new_pos = Vector3D::new(15.123, 19.129, 9.834);
atom.set_position_y(new_y);
assert_eq!(*atom.get_position().unwrap(), new_pos);
}
#[test]
fn set_position_z() {
let mut atom = make_default_atom();
let new_z = 19.129;
let new_pos = Vector3D::new(15.123, 14.321, 19.129);
atom.set_position_z(new_z);
assert_eq!(*atom.get_position().unwrap(), new_pos);
}
#[test]
fn get_velocity() {
let atom = make_default_atom();
assert_eq!(
*atom.get_velocity().unwrap(),
Vector3D::new(-3.432, 0.184, 1.234)
);
}
#[test]
fn get_velocity_mut() {
let mut atom = make_default_atom();
atom.get_velocity_mut().unwrap().y += 0.3;
let vel = atom.get_velocity().unwrap();
assert_approx_eq!(f32, vel.x, -3.432);
assert_approx_eq!(f32, vel.y, 0.484);
assert_approx_eq!(f32, vel.z, 1.234);
}
#[test]
fn set_velocity() {
let mut atom = make_default_atom();
let new_vel = Vector3D::new(1.764, 2.134, 19.129);
atom.set_velocity(new_vel.clone());
assert_eq!(*atom.get_velocity().unwrap(), new_vel);
}
#[test]
fn get_force() {
let atom = make_default_atom();
assert_eq!(
*atom.get_force().unwrap(),
Vector3D::new(5.1235, 2.3451, -0.32145)
);
}
#[test]
fn get_force_mut() {
let mut atom = make_default_atom();
atom.get_force_mut().unwrap().z -= 0.13;
let force = atom.get_force().unwrap();
assert_approx_eq!(f32, force.x, 5.1235);
assert_approx_eq!(f32, force.y, 2.3451);
assert_approx_eq!(f32, force.z, -0.45145);
}
#[test]
fn set_force() {
let mut atom = make_default_atom();
let new_for = Vector3D::new(1.764, 2.134, 19.129);
atom.set_force(new_for.clone());
assert_eq!(*atom.get_force().unwrap(), new_for);
}
#[test]
fn get_set_reset_bonded() {
let mut atom = make_default_atom();
assert_eq!(atom.get_n_bonded(), 0);
let bonded = atom.get_bonded();
assert_eq!(bonded, &AtomContainer::empty());
unsafe {
atom.set_bonded(vec![1, 2, 5]);
}
assert_eq!(atom.get_n_bonded(), 3);
let bonded = atom.get_bonded();
assert_eq!(bonded, &AtomContainer::from_indices(vec![1, 2, 5], 10));
unsafe {
atom.reset_bonded();
}
assert_eq!(atom.get_n_bonded(), 0);
assert_eq!(atom.get_bonded(), &AtomContainer::empty());
}
#[test]
fn add_bonded() {
let mut atom = make_default_atom();
assert_eq!(atom.get_n_bonded(), 0);
unsafe {
atom.add_bonded(1);
atom.add_bonded(2);
atom.add_bonded(5);
}
assert_eq!(atom.get_n_bonded(), 3);
let bonded = atom.get_bonded();
assert_eq!(bonded, &AtomContainer::from_indices(vec![1, 2, 5], 10));
}
#[test]
fn has_position() {
let mut atom = make_default_atom();
assert!(atom.has_position());
atom.reset_position();
assert!(!atom.has_position());
}
#[test]
fn has_velocity() {
let mut atom = make_default_atom();
assert!(atom.has_velocity());
atom.reset_velocity();
assert!(!atom.has_velocity());
}
#[test]
fn has_force() {
let mut atom = make_default_atom();
assert!(atom.has_force());
atom.reset_force();
assert!(!atom.has_force());
}
#[test]
fn translate_nopbc() {
let mut atom = make_default_atom();
let shift = Vector3D::new(4.5, 2.3, -8.3);
atom.translate_nopbc(&shift).unwrap();
assert_approx_eq!(
f32,
atom.get_position().unwrap().x,
19.623,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom.get_position().unwrap().y,
16.621,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom.get_position().unwrap().z,
1.534,
epsilon = 0.00001
);
}
#[test]
fn translate_nopbc_fail() {
let mut atom = make_default_atom();
atom.reset_position();
let shift = Vector3D::new(4.5, 2.3, -8.3);
match atom.translate_nopbc(&shift) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
}
#[test]
fn translate() {
let mut atom = make_default_atom();
let shift = Vector3D::new(4.5, 2.3, -10.2);
let simbox = SimBox::from([16.0, 16.0, 16.0]);
atom.translate(&shift, &simbox).unwrap();
assert_approx_eq!(
f32,
atom.get_position().unwrap().x,
3.623,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom.get_position().unwrap().y,
0.621,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom.get_position().unwrap().z,
15.634,
epsilon = 0.00001
);
}
#[test]
fn translate_fail() {
let mut atom = make_default_atom();
atom.reset_position();
let shift = Vector3D::new(4.5, 2.3, -8.3);
let simbox = SimBox::from([16.0, 16.0, 16.0]);
match atom.translate(&shift, &simbox) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
}
#[test]
fn wrap() {
let mut atom =
Atom::new(45, "GLY", 123, "BB").with_position([15.123, 14.321, -1.743].into());
let simbox = SimBox::from([15.0, 15.0, 15.0]);
atom.wrap(&simbox).unwrap();
assert_approx_eq!(
f32,
atom.get_position().unwrap().x,
0.123,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom.get_position().unwrap().y,
14.321,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom.get_position().unwrap().z,
13.257,
epsilon = 0.00001
);
}
#[test]
fn wrap_far() {
let mut atom =
Atom::new(45, "GLY", 123, "BB").with_position([60.123, 14.321, -31.743].into());
let simbox = SimBox::from([15.0, 15.0, 15.0]);
atom.wrap(&simbox).unwrap();
assert_approx_eq!(
f32,
atom.get_position().unwrap().x,
0.123,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom.get_position().unwrap().y,
14.321,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom.get_position().unwrap().z,
13.257,
epsilon = 0.00001
);
}
#[test]
fn wrap_fail() {
let mut atom = make_default_atom();
atom.reset_position();
let simbox = SimBox::from([15.0, 15.0, 15.0]);
match atom.wrap(&simbox) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
}
#[test]
fn distance_x() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom1.distance(&atom2, Dimension::X, &simbox).unwrap(),
-0.7,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance(&atom1, Dimension::X, &simbox).unwrap(),
0.7,
epsilon = 0.00001
);
}
#[test]
fn distance_naive_x() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
assert_approx_eq!(
f32,
atom1.distance_naive(&atom2, Dimension::X).unwrap(),
3.3,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance_naive(&atom1, Dimension::X).unwrap(),
-3.3,
epsilon = 0.00001
);
}
#[test]
fn distance_y() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom1.distance(&atom2, Dimension::Y, &simbox).unwrap(),
1.0,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance(&atom1, Dimension::Y, &simbox).unwrap(),
-1.0,
epsilon = 0.00001
);
}
#[test]
fn distance_naive_y() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
assert_approx_eq!(
f32,
atom1.distance_naive(&atom2, Dimension::Y).unwrap(),
1.0,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance_naive(&atom1, Dimension::Y).unwrap(),
-1.0,
epsilon = 0.00001
);
}
#[test]
fn distance_z() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 1.0].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 3.5].into());
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom1.distance(&atom2, Dimension::Z, &simbox).unwrap(),
1.5,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance(&atom1, Dimension::Z, &simbox).unwrap(),
-1.5,
epsilon = 0.00001
);
}
#[test]
fn distance_naive_z() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
assert_approx_eq!(
f32,
atom1.distance_naive(&atom2, Dimension::Z).unwrap(),
2.5,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance_naive(&atom1, Dimension::Z).unwrap(),
-2.5,
epsilon = 0.00001
);
}
#[test]
fn distance_xy() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom1.distance(&atom2, Dimension::XY, &simbox).unwrap(),
1.2206556,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance(&atom1, Dimension::XY, &simbox).unwrap(),
1.2206556,
epsilon = 0.00001
);
}
#[test]
fn distance_naive_xy() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
assert_approx_eq!(
f32,
atom1.distance_naive(&atom2, Dimension::XY).unwrap(),
3.448188,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance_naive(&atom1, Dimension::XY).unwrap(),
3.448188,
epsilon = 0.00001
);
}
#[test]
fn distance_xz() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom1.distance(&atom2, Dimension::XZ, &simbox).unwrap(),
1.6552945,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance(&atom1, Dimension::XZ, &simbox).unwrap(),
1.6552945,
epsilon = 0.00001
);
}
#[test]
fn distance_naive_xz() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
assert_approx_eq!(
f32,
atom1.distance_naive(&atom2, Dimension::XZ).unwrap(),
4.140048,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance_naive(&atom1, Dimension::XZ).unwrap(),
4.140048,
epsilon = 0.00001
);
}
#[test]
fn distance_yz() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom1.distance(&atom2, Dimension::YZ, &simbox).unwrap(),
1.8027756,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance(&atom1, Dimension::YZ, &simbox).unwrap(),
1.8027756,
epsilon = 0.00001
);
}
#[test]
fn distance_naive_yz() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
assert_approx_eq!(
f32,
atom1.distance_naive(&atom2, Dimension::YZ).unwrap(),
2.692582,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance_naive(&atom1, Dimension::YZ).unwrap(),
2.692582,
epsilon = 0.00001
);
}
#[test]
fn distance_xyz() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom1.distance(&atom2, Dimension::XYZ, &simbox).unwrap(),
1.933908,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance(&atom1, Dimension::XYZ, &simbox).unwrap(),
1.933908,
epsilon = 0.00001
);
}
#[test]
fn distance_naive_xyz() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
assert_approx_eq!(
f32,
atom1.distance_naive(&atom2, Dimension::XYZ).unwrap(),
4.259108,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance_naive(&atom1, Dimension::XYZ).unwrap(),
4.259108,
epsilon = 0.00001
);
}
#[test]
fn distance_none() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom1.distance(&atom2, Dimension::None, &simbox).unwrap(),
0.0,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance(&atom1, Dimension::None, &simbox).unwrap(),
0.0,
epsilon = 0.00001
);
}
#[test]
fn distance_naive_none() {
let atom1 = Atom::new(1, "LYS", 1, "BB").with_position([3.8, 2.0, 3.5].into());
let atom2 = Atom::new(1, "LYS", 2, "SC1").with_position([0.5, 1.0, 1.0].into());
assert_approx_eq!(
f32,
atom1.distance_naive(&atom2, Dimension::None).unwrap(),
0.0,
epsilon = 0.00001
);
assert_approx_eq!(
f32,
atom2.distance_naive(&atom1, Dimension::None).unwrap(),
0.0,
epsilon = 0.00001
);
}
#[test]
fn distance_fail() {
let mut atom1 = Atom::new(1, "LYS", 1, "BB");
let mut atom2 = Atom::new(1, "LYS", 2, "SC1");
let simbox = SimBox::from([4.0, 4.0, 4.0]);
match atom1.distance(&atom2, Dimension::XYZ, &simbox) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom1.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
atom2.set_position([1.0, 2.0, 3.0].into());
match atom1.distance(&atom2, Dimension::XYZ, &simbox) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom1.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
atom2.reset_position();
atom1.set_position([1.0, 2.0, 3.0].into());
match atom1.distance(&atom2, Dimension::XYZ, &simbox) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom2.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
}
#[test]
fn distance_naive_fail() {
let mut atom1 = Atom::new(1, "LYS", 1, "BB");
let mut atom2 = Atom::new(1, "LYS", 2, "SC1");
match atom1.distance_naive(&atom2, Dimension::XYZ) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom1.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
atom2.set_position([1.0, 2.0, 3.0].into());
match atom1.distance_naive(&atom2, Dimension::XYZ) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom1.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
atom2.reset_position();
atom1.set_position([1.0, 2.0, 3.0].into());
match atom1.distance_naive(&atom2, Dimension::XYZ) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom2.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
}
#[test]
fn distance_from_point_x() {
let atom = Atom::new(1, "LYS", 1, "BB").with_position([2.0, 3.8, 3.5].into());
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom.distance_from_point(&point, Dimension::X, &simbox)
.unwrap(),
1.0,
epsilon = 0.00001
);
}
#[test]
fn distance_from_point_y() {
let atom = Atom::new(1, "LYS", 1, "BB").with_position([2.0, 3.8, 3.5].into());
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom.distance_from_point(&point, Dimension::Y, &simbox)
.unwrap(),
-0.7,
epsilon = 0.00001
);
}
#[test]
fn distance_from_point_z() {
let atom = Atom::new(1, "LYS", 1, "BB").with_position([2.0, 3.8, 3.5].into());
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom.distance_from_point(&point, Dimension::Z, &simbox)
.unwrap(),
1.5,
epsilon = 0.00001
);
}
#[test]
fn distance_from_point_xy() {
let atom = Atom::new(1, "LYS", 1, "BB").with_position([2.0, 3.8, 3.5].into());
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom.distance_from_point(&point, Dimension::XY, &simbox)
.unwrap(),
1.220656,
epsilon = 0.00001
);
}
#[test]
fn distance_from_point_xz() {
let atom = Atom::new(1, "LYS", 1, "BB").with_position([2.0, 3.8, 3.5].into());
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom.distance_from_point(&point, Dimension::XZ, &simbox)
.unwrap(),
1.802776,
epsilon = 0.00001
);
}
#[test]
fn distance_from_point_yz() {
let atom = Atom::new(1, "LYS", 1, "BB").with_position([2.0, 3.8, 3.5].into());
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom.distance_from_point(&point, Dimension::YZ, &simbox)
.unwrap(),
1.6552945,
epsilon = 0.00001
);
}
#[test]
fn distance_from_point_xyz() {
let atom = Atom::new(1, "LYS", 1, "BB").with_position([2.0, 3.8, 3.5].into());
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom.distance_from_point(&point, Dimension::XYZ, &simbox)
.unwrap(),
1.933908,
epsilon = 0.00001
);
}
#[test]
fn distance_from_point_none() {
let atom = Atom::new(1, "LYS", 1, "BB").with_position([2.0, 3.8, 3.5].into());
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert_approx_eq!(
f32,
atom.distance_from_point(&point, Dimension::None, &simbox)
.unwrap(),
0.0,
epsilon = 0.00001
);
}
#[test]
fn distance_from_point_fail() {
let atom = Atom::new(1, "LYS", 1, "BB");
let point = Vector3D::new(1.0, 0.5, 2.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
match atom.distance_from_point(&point, Dimension::XYZ, &simbox) {
Ok(_) => panic!("Function should have failed."),
Err(AtomError::InvalidPosition(PositionError::NoPosition(x))) => {
assert_eq!(x, atom.get_index())
}
Err(e) => {
panic!("Function failed successfully, but incorrect error type `{e}` was returned.")
}
}
}
#[test]
fn rotate() {
let mut atom = Atom::new(1, "LYS", 1, "BB").with_position(Vector3D::new(1.0, 2.0, 3.0));
let rotation = Matrix3::new(0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
atom.rotate(&rotation, &SimBox::from([10.0, 10.0, 10.0]))
.unwrap();
let pos = atom.get_position().unwrap();
assert_approx_eq!(f32, pos.x, 8.0);
assert_approx_eq!(f32, pos.y, 1.0);
assert_approx_eq!(f32, pos.z, 3.0);
}
#[test]
fn rotate_nopbc() {
let mut atom = Atom::new(1, "LYS", 1, "BB").with_position(Vector3D::new(1.0, 2.0, 3.0));
let rotation = Matrix3::new(0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
atom.rotate_nopbc(&rotation).unwrap();
let pos = atom.get_position().unwrap();
assert_approx_eq!(f32, pos.x, -2.0);
assert_approx_eq!(f32, pos.y, 1.0);
assert_approx_eq!(f32, pos.z, 3.0);
}
}
#[cfg(test)]
#[cfg(feature = "serde")]
mod serde_tests {
use std::fs::read_to_string;
use float_cmp::assert_approx_eq;
use super::*;
#[test]
fn atom_to_yaml() {
let mut atom = Atom::new(10, "CYS", 24, "CA")
.with_position(Vector3D::new(10.4, 7.5, 2.6))
.with_velocity(Vector3D::new(-0.4332, 0.3221, 1.2314))
.with_force(Vector3D::new(14.24898, -13.208472, 8.123864))
.with_chain('B')
.with_charge(-1.0)
.with_mass(32.12)
.with_vdw(0.64)
.with_expected_max_bonds(3)
.with_expected_min_bonds(1)
.with_element_name("carbon")
.with_element_symbol("C");
unsafe {
atom.add_bonded(4);
atom.add_bonded(7);
atom.add_bonded(8);
atom.add_bonded(9);
}
let string = serde_yaml::to_string(&atom).unwrap();
let expected = read_to_string("test_files/serde_atom.yaml").unwrap();
assert_eq!(string, expected);
}
#[test]
fn minimal_atom_to_yaml() {
let atom = Atom::new(10, "CYS", 24, "CA");
let string = serde_yaml::to_string(&atom).unwrap();
let expected = read_to_string("test_files/serde_atom_minimal.yaml").unwrap();
assert_eq!(string, expected);
}
#[test]
fn atom_from_yaml() {
let string = read_to_string("test_files/serde_atom.yaml").unwrap();
let atom: Atom = serde_yaml::from_str(&string).unwrap();
assert_eq!(atom.get_residue_number(), 10);
assert_eq!(atom.get_residue_name(), "CYS");
assert_eq!(atom.get_atom_number(), 24);
assert_eq!(atom.get_atom_name(), "CA");
let pos = atom.get_position().unwrap();
assert_approx_eq!(f32, pos.x, 10.4);
assert_approx_eq!(f32, pos.y, 7.5);
assert_approx_eq!(f32, pos.z, 2.6);
let vel = atom.get_velocity().unwrap();
assert_approx_eq!(f32, vel.x, -0.4332);
assert_approx_eq!(f32, vel.y, 0.3221);
assert_approx_eq!(f32, vel.z, 1.2314);
let force = atom.get_force().unwrap();
assert_approx_eq!(f32, force.x, 14.24898);
assert_approx_eq!(f32, force.y, -13.208472);
assert_approx_eq!(f32, force.z, 8.123864);
assert_eq!(atom.get_chain().unwrap(), 'B');
assert_approx_eq!(f32, atom.get_charge().unwrap(), -1.0);
assert_approx_eq!(f32, atom.get_mass().unwrap(), 32.12);
assert_approx_eq!(f32, atom.get_vdw().unwrap(), 0.64);
assert_eq!(atom.get_expected_max_bonds().unwrap(), 3);
assert_eq!(atom.get_expected_min_bonds().unwrap(), 1);
assert_eq!(atom.get_element_name().unwrap(), "carbon");
assert_eq!(atom.get_element_symbol().unwrap(), "C");
assert_eq!(
atom.get_bonded(),
&AtomContainer::from_indices(vec![4, 7, 8, 9], 100)
);
}
#[test]
fn minimal_atom_from_yaml() {
let string = read_to_string("test_files/serde_atom_minimal.yaml").unwrap();
let atom: Atom = serde_yaml::from_str(&string).unwrap();
assert_eq!(atom.get_residue_number(), 10);
assert_eq!(atom.get_residue_name(), "CYS");
assert_eq!(atom.get_atom_number(), 24);
assert_eq!(atom.get_atom_name(), "CA");
assert!(atom.get_position().is_none());
assert!(atom.get_velocity().is_none());
assert!(atom.get_force().is_none());
assert!(atom.get_chain().is_none());
assert!(atom.get_charge().is_none());
assert!(atom.get_mass().is_none());
assert!(atom.get_vdw().is_none());
assert!(atom.get_expected_max_bonds().is_none());
assert!(atom.get_expected_min_bonds().is_none());
assert!(atom.get_element_name().is_none());
assert!(atom.get_element_symbol().is_none());
assert_eq!(atom.get_bonded(), &AtomContainer::from_indices(vec![], 100));
}
#[test]
fn atom_from_yaml_unknown_field() {
let string = read_to_string("test_files/serde_atom_unknown_field.yaml").unwrap();
let err = serde_yaml::from_str::<Atom>(&string).unwrap_err();
assert!(err.to_string().contains("unknown field"));
}
}