Merge pull request #1 from Yoshanuikabundi/remove-failure

Remove failure
This commit is contained in:
Daniel Bauer
2020-11-07 11:53:07 +01:00
committed by GitHub
10 changed files with 275 additions and 193 deletions

View File

@@ -8,7 +8,6 @@ description = "Wrapper around the gromacs libxdrfile library. Can be used to rea
build = "build.rs"
[dependencies]
failure = "0.1"
lazy-init = "0.3"
[dev-dependencies]

View File

@@ -1,5 +1,6 @@
#[allow(non_upper_case_globals)]
#![allow(non_upper_case_globals, non_camel_case_types)]
pub mod xdr_seek;
pub mod xdrfile;
pub mod xdrfile_trr;
pub mod xdrfile_xtc;
pub mod xdr_seek;

View File

@@ -103,12 +103,11 @@ extern "C" {
pub fn xdr_flush(xd: *mut XDRFILE) -> ::std::os::raw::c_int;
}
#[cfg(test)]
mod tests {
use super::*;
use super::super::xdrfile_xtc::*;
use super::*;
use std::ffi::CString;
#[test]
@@ -119,8 +118,8 @@ mod tests {
let mut step: i32 = 5;
let box_vec = [[0.0; 3]; 3];
let x_p = std::ptr::null_mut();
let mut prec: f32 = 0.0;
let mut prec: f32 = 0.0;
unsafe {
let mode = CString::new("r").unwrap();
let xdr = xdrfile_open(path.as_ptr(), mode.as_ptr());
@@ -129,20 +128,25 @@ mod tests {
let tell = xdr_tell(xdr);
assert!(tell == 0, "{}", tell);
read_xtc(xdr, num_atoms, &mut step, &mut time,
read_xtc(
xdr,
num_atoms,
&mut step,
&mut time,
box_vec.as_ptr() as *mut Matrix,
x_p,
&mut prec);
&mut prec,
);
let tell = xdr_tell(xdr);
assert!(tell > 0, "{}", tell);
}
}
}
#[test]
fn test_xdr_seek() {
let path = CString::new("tests/1l2y.xtc").unwrap();
unsafe {
let mode = CString::new("r").unwrap();
let xdr = xdrfile_open(path.as_ptr(), mode.as_ptr());
@@ -152,9 +156,9 @@ mod tests {
assert!(tell == 0, "{}", tell);
xdr_seek(xdr, 500, 0);
let tell = xdr_tell(xdr);
assert!(tell == 500, "{}", tell);
}
}
}
}
}

View File

@@ -1,4 +1,3 @@
pub const DIM: u32 = 3;
#[repr(C)]
@@ -7,7 +6,6 @@ pub struct XDRFILE {
_unused: [u8; 0],
}
pub type BindgenTy1 = u32;
pub const exdrOK: BindgenTy1 = 0;
pub const exdrHEADER: BindgenTy1 = 1;

View File

@@ -1,6 +1,5 @@
use super::xdrfile::*;
extern "C" {
pub fn read_trr_natoms(
fn_: *const ::std::os::raw::c_char,
@@ -10,7 +9,7 @@ extern "C" {
extern "C" {
pub fn read_trr_nframes(
fn_: *const ::std::os::raw::c_char,
nframes: *const ::std::os::raw::c_ulong,
nframes: *const ::std::os::raw::c_ulong,
) -> ::std::os::raw::c_int;
}
extern "C" {
@@ -61,7 +60,7 @@ mod tests {
#[test]
fn test_read_trr_nframes() {
let path = CString::new("tests/1l2y.trr").unwrap();
let mut nframes: u64 = 0;
let mut nframes: u64 = 0;
unsafe {
let code = read_trr_nframes(path.as_ptr() as *const i8, &mut nframes);
@@ -83,19 +82,25 @@ mod tests {
let box_vec: Matrix = [[1.0, 2.0, 3.0], [2.0, 1.0, 3.0], [3.0, 2.0, 1.0]];
let x: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
let v: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
let v: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
let f: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
unsafe {
let mode = CString::new("w").unwrap();
let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr());
let write_code = write_trr(xdr, natoms, step, time, lambda,
let write_code = write_trr(
xdr,
natoms,
step,
time,
lambda,
box_vec.as_ptr() as *mut Matrix,
x.as_ptr() as *mut Rvec,
v.as_ptr() as *mut Rvec,
f.as_ptr() as *mut Rvec);
f.as_ptr() as *mut Rvec,
);
assert!(write_code as u32 == exdrOK);
xdrfile_close(xdr);
xdrfile_close(xdr);
}
// read atoms from tempfile
@@ -111,13 +116,19 @@ mod tests {
unsafe {
let mode = CString::new("r").unwrap();
let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr());
let read_code = read_trr(xdr, natoms, &mut step2, &mut time2,
&mut lambda2, box_vec2.as_ptr() as *mut Matrix,
let read_code = read_trr(
xdr,
natoms,
&mut step2,
&mut time2,
&mut lambda2,
box_vec2.as_ptr() as *mut Matrix,
x2.as_ptr() as *mut Rvec,
v2.as_ptr() as *mut Rvec,
f2.as_ptr() as *mut Rvec);
f2.as_ptr() as *mut Rvec,
);
assert!(read_code as u32 == exdrOK);
xdrfile_close(xdr);
xdrfile_close(xdr);
}
// make sure everything is still the same
@@ -129,5 +140,4 @@ mod tests {
assert!(v2 == v);
assert!(f2 == f);
}
}
}

View File

@@ -1,6 +1,5 @@
use super::xdrfile::*;
extern "C" {
pub fn read_xtc_natoms(
fn_: *const ::std::os::raw::c_char,
@@ -10,7 +9,7 @@ extern "C" {
extern "C" {
pub fn read_xtc_nframes(
fn_: *const ::std::os::raw::c_char,
nframes: *const ::std::os::raw::c_ulong,
nframes: *const ::std::os::raw::c_ulong,
) -> ::std::os::raw::c_int;
}
extern "C" {
@@ -57,7 +56,7 @@ mod tests {
#[test]
fn test_read_xtc_nframes() {
let path = CString::new("tests/1l2y.xtc").unwrap();
let mut nframes: u64 = 0;
let mut nframes: u64 = 0;
unsafe {
let code = read_xtc_nframes(path.as_ptr() as *const i8, &mut nframes);
@@ -77,15 +76,21 @@ mod tests {
let step: i32 = 5;
let box_vec: Matrix = [[1.0, 2.0, 3.0], [2.0, 1.0, 3.0], [3.0, 2.0, 1.0]];
let x: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
unsafe {
let mode = CString::new("w").unwrap();
let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr());
let write_code = write_xtc(xdr, natoms, step, time,
box_vec.as_ptr() as *mut Matrix, x.as_ptr() as *mut Rvec,
1000.0);
let write_code = write_xtc(
xdr,
natoms,
step,
time,
box_vec.as_ptr() as *mut Matrix,
x.as_ptr() as *mut Rvec,
1000.0,
);
assert!(write_code as u32 == exdrOK);
xdrfile_close(xdr);
xdrfile_close(xdr);
}
// read atoms from tempfile
@@ -98,11 +103,17 @@ mod tests {
unsafe {
let mode = CString::new("r").unwrap();
let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr());
let read_code = read_xtc(xdr, natoms, &mut step2, &mut time2,
box_vec2.as_ptr() as *mut Matrix, x2.as_ptr() as *mut Rvec,
&mut prec);
let read_code = read_xtc(
xdr,
natoms,
&mut step2,
&mut time2,
box_vec2.as_ptr() as *mut Matrix,
x2.as_ptr() as *mut Rvec,
&mut prec,
);
assert!(read_code as u32 == exdrOK);
xdrfile_close(xdr);
xdrfile_close(xdr);
}
// make sure everything is still the same
@@ -111,4 +122,4 @@ mod tests {
assert!(box_vec2 == box_vec);
assert!(x2 == x);
}
}
}

View File

@@ -12,68 +12,72 @@ pub struct Frame {
/// Time step (usually in picoseconds)
pub time: f32,
/// 3x3 box vector
/// 3x3 box vector
pub box_vector: [[f32; 3usize]; 3usize],
/// 3D coordinates for N atoms where N is num_atoms
/// 3D coordinates for N atoms where N is num_atoms
pub coords: Vec<[f32; 3usize]>,
}
impl Default for Frame {
fn default() -> Frame {
Frame {
Frame {
num_atoms: 0,
step: 0,
time: 0.0,
box_vector: [[0.0; 3]; 3],
coords: Vec::with_capacity(0)
coords: Vec::with_capacity(0),
}
}
}
impl fmt::Debug for Frame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Frame {{ atoms: {}, step: {}, time: {}, \
box: {:?}, coords: {:?} }}", self.num_atoms, self.step, self.time,
self.box_vector, self.coords)
write!(
f,
"Frame {{ atoms: {}, step: {}, time: {}, \
box: {:?}, coords: {:?} }}",
self.num_atoms, self.step, self.time, self.box_vector, self.coords
)
}
}
impl Frame {
/// Creates an empty frame with a capacity of 0
pub fn new() -> Frame {
Frame{ ..Default::default() }
Frame {
..Default::default()
}
}
/// Creates a frame with the given capacity
pub fn with_capacity(num_atoms: u32) -> Frame {
Frame {
num_atoms: num_atoms,
num_atoms,
coords: vec![[0.0, 0.0, 0.0]; num_atoms as usize],
..Default::default()
}
}
/// Filters the frame by removing all atoms not matching the given indeces.
/// Filters the frame by removing all atoms not matching the given indeces.
pub fn filter_coords(self: &mut Frame, indeces: &[usize]) {
self.coords = self.coords.iter()
self.coords = self
.coords
.iter()
.map(|elem| elem.clone())
.enumerate()
.filter(|&(i, _)| indeces.contains(&i))
.map(|(_, elem)| elem)
.collect();
self.num_atoms = self.coords.len() as u32;
}
}
/// Length of the frame (number of atoms)
pub fn len(self: &Frame) -> usize {
self.num_atoms as usize
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -91,12 +95,12 @@ mod tests {
frame.coords[0] = [1.0, 2.0, 3.0];
frame.coords[1] = [4.0, 5.0, 6.0];
frame.coords[2] = [7.0, 8.0, 9.0];
let filter: Vec<usize> = vec![1,2];
let filter: Vec<usize> = vec![1, 2];
let mut frame_new = frame.clone();
frame_new.filter_coords(&filter);
assert!(frame_new.num_atoms as usize == filter.len());
assert!(frame_new.coords[0] == frame.coords[1]);
assert!(frame_new.coords[1] == frame.coords[2]);
assert!(frame_new.coords[1] == frame.coords[2]);
}
#[test]

View File

@@ -1,10 +1,9 @@
use crate::*;
use crate::c_abi::xdrfile::exdrENDOFFILE;
use failure::Error;
use crate::*;
use std::rc::Rc;
impl IntoIterator for XTCTrajectory {
type Item = Result<Rc<Frame>, Error>;
type Item = Result<Rc<Frame>>;
type IntoIter = XTCTrajectoryIterator;
fn into_iter(mut self) -> Self::IntoIter {
@@ -13,14 +12,14 @@ impl IntoIterator for XTCTrajectory {
XTCTrajectoryIterator {
trajectory: self,
item: Rc::new(Frame::with_capacity(num_atoms)),
has_error: false
has_error: false,
}
}
}
/*
/*
Iterator for trajectories. This iterator yields a Result<Frame, Error>
for each frame in the trajectory file and stops with yielding None once the
for each frame in the trajectory file and stops with yielding None once the
trajectory is finished. Also yields None after the first occurence of an error
*/
pub struct XTCTrajectoryIterator {
@@ -30,20 +29,21 @@ pub struct XTCTrajectoryIterator {
}
impl Iterator for XTCTrajectoryIterator {
type Item = Result<Rc<Frame>, Error>;
type Item = Result<Rc<Frame>>;
fn next(&mut self) -> Option<Self::Item> { // Reuse old frame
fn next(&mut self) -> Option<Self::Item> {
// Reuse old frame
if self.has_error {
return None;
}
let item: &mut Frame = match Rc::get_mut(&mut self.item) {
Some(item) => item,
None => { // caller kept frame. Create new one
None => {
// caller kept frame. Create new one
self.item = Rc::new(Frame::with_capacity(self.item.num_atoms));
Rc::get_mut(&mut self.item).unwrap()
}
};
match self.trajectory.read(item) {
Ok(()) => Some(Ok(Rc::clone(&self.item))),
@@ -55,12 +55,12 @@ impl Iterator for XTCTrajectoryIterator {
Some(Err(msg))
}
}
}
}
}
}
impl IntoIterator for TRRTrajectory {
type Item = Result<Rc<Frame>, Error>;
type Item = Result<Rc<Frame>>;
type IntoIter = TRRTrajectoryIterator;
fn into_iter(mut self) -> Self::IntoIter {
@@ -69,14 +69,14 @@ impl IntoIterator for TRRTrajectory {
TRRTrajectoryIterator {
trajectory: self,
item: Rc::new(Frame::with_capacity(num_atoms)),
has_error: false
has_error: false,
}
}
}
/*
/*
Iterator for trajectories. This iterator yields a Result<Frame, Error>
for each frame in the trajectory file and stops with yielding None once the
for each frame in the trajectory file and stops with yielding None once the
trajectory is finished. Also yields None after the first occurence of an error
*/
pub struct TRRTrajectoryIterator {
@@ -86,20 +86,21 @@ pub struct TRRTrajectoryIterator {
}
impl Iterator for TRRTrajectoryIterator {
type Item = Result<Rc<Frame>, Error>;
type Item = Result<Rc<Frame>>;
fn next(&mut self) -> Option<Self::Item> { // Reuse old frame
fn next(&mut self) -> Option<Self::Item> {
// Reuse old frame
if self.has_error {
return None;
}
let item: &mut Frame = match Rc::get_mut(&mut self.item) {
Some(item) => item,
None => { // caller kept frame. Create new one
None => {
// caller kept frame. Create new one
self.item = Rc::new(Frame::with_capacity(self.item.num_atoms));
Rc::get_mut(&mut self.item).unwrap()
}
};
match self.trajectory.read(item) {
Ok(()) => Some(Ok(Rc::clone(&self.item))),
@@ -111,7 +112,7 @@ impl Iterator for TRRTrajectoryIterator {
Some(Err(msg))
}
}
}
}
}
}
@@ -136,4 +137,4 @@ mod tests {
assert!(frames[0].step == 1, frames[0].step);
assert!(frames[37].step == 38);
}
}
}

View File

@@ -8,7 +8,7 @@
//! # Basic usage example
//! ```rust
//! use xdrfile::*;
//! use std::path::Path;
//! use std::path::Path;
//!
//! let mut path = Path::new("tests/1l2y.xtc");
//! // get a handle to the file
@@ -16,23 +16,23 @@
//!
//! // find number of atoms in the file
//! let num_atoms = trj.get_num_atoms().unwrap();
//!
//!
//! // a frame object is used to get to read or write from a trajectory
//! // without instantiating data arrays for every step
//! let mut frame = Frame::with_capacity(num_atoms);
//!
//!
//! // read the first frame of the trajectory
//! let result = trj.read(&mut frame);
//! match result {
//! Ok(_) => {
//! assert_eq!(frame.step, 1);
//! assert_eq!(frame.num_atoms, num_atoms);
//!
//!
//! let first_atom_coords = frame.coords[0];
//! assert_eq!(first_atom_coords, [-0.8901, 0.4127, -0.055499997]);
//! }
//! Err(msg) => {
//! panic!("Something went wrong: {}", msg);
//! panic!("Something went wrong: {}", msg);
//! }
//! }
//! ```
@@ -45,12 +45,12 @@
//!
//! ```rust
//! use xdrfile::*;
//! use std::path::Path;
//! use std::path::Path;
//!
//! let mut path = Path::new("tests/1l2y.xtc");
//! // get a handle to the file
//! let trj = XTCTrajectory::open(path, FileMode::Read).unwrap();
//!
//!
//! // iterate over all frames
//! for (idx, frame) in trj.into_iter().filter_map(Result::ok).enumerate() {
//! println!("{}", frame.time);
@@ -58,33 +58,80 @@
//! }
//! ```
#[cfg(test)]
#[macro_use] extern crate assert_approx_eq;
#[macro_use]
extern crate assert_approx_eq;
extern crate lazy_init;
pub mod c_abi;
mod frame;
mod iterator;
pub mod c_abi;
pub use frame::Frame;
pub use iterator::*;
use c_abi::xdr_seek;
use c_abi::xdrfile;
use c_abi::xdrfile::XDRFILE;
use c_abi::xdr_seek;
use c_abi::xdrfile_xtc;
use c_abi::xdrfile_trr;
use c_abi::xdrfile_xtc;
use lazy_init::Lazy;
use std::cell::Cell;
use std::ffi::CString;
use std::path::Path;
use failure::{Error,err_msg};
use std::cell::Cell;
use lazy_init::Lazy;
#[derive(Debug, Clone)]
pub enum Error {
CouldNotOpenFile(std::path::PathBuf, FileMode),
CouldNotReadAtomNumber(u32),
CouldNotRead(u32),
CouldNotWrite(u32),
CouldNotFlush(u32),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Error::*;
match self {
CouldNotOpenFile(path, mode) => write!(
f,
"Failed to open file at {path:?} with mode {mode:?}",
path = path,
mode = mode
),
CouldNotReadAtomNumber(code) => write!(
f,
"Failed to read atom number from trajectory: C API returned error code {}",
code
),
CouldNotRead(code) => write!(
f,
"Failed to read trajectory: C API returned error code {}",
code
),
CouldNotWrite(code) => write!(
f,
"Failed to write trajectory: C API returned error code {}",
code
),
CouldNotFlush(code) => write!(
f,
"Failed to flush trajectory: C API returned error code {}",
code
),
}
}
}
impl std::error::Error for Error {}
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub enum FileMode {
Write,
Append,
Read
Read,
}
impl FileMode {
@@ -98,30 +145,35 @@ impl FileMode {
}
fn path_to_cstring(path: &Path) -> CString {
CString::new(path.to_str().unwrap()).unwrap()
}
CString::new(path.to_str().unwrap()).unwrap()
}
/// A safe wrapper around the c implementation of an XDRFile
struct XDRFile {
xdrfile: *mut XDRFILE,
#[allow(dead_code)]
filemode: FileMode,
path: String,
}
impl XDRFile {
pub fn open(path: &Path, filemode: FileMode) -> Result<XDRFile, Error> {
pub fn open(path: &Path, filemode: FileMode) -> Result<XDRFile> {
let path_p = path_to_cstring(path).into_raw();
let mode_p = CString::new(filemode.value()).unwrap().into_raw();
unsafe {
let xdrfile = xdrfile::xdrfile_open(path_p, mode_p);
if ! xdrfile.is_null() {
if !xdrfile.is_null() {
let path = String::from(path.to_str().unwrap());
Ok(XDRFile { xdrfile, filemode, path })
} else { // Something went wrong. But the C api does not tell us what
Err(err_msg("Failed to open trajectory file"))
Ok(XDRFile {
xdrfile,
filemode,
path,
})
} else {
// Something went wrong. But the C api does not tell us what
Err(Error::CouldNotOpenFile(path.into(), filemode))
}
}
}
@@ -133,127 +185,131 @@ impl Drop for XDRFile {
unsafe {
xdrfile::xdrfile_close(self.xdrfile);
}
}
}
}
/// The trajectory trait defines shared methods for xtc and trr trajectories
pub trait Trajectory {
/// Read the next step of the trajectory into the frame object
fn read(&mut self, frame: &mut Frame) -> Result<(), Error>;
fn read(&mut self, frame: &mut Frame) -> Result<()>;
/// Write the frame to the trajectory file
fn write(&mut self, frame: &Frame) -> Result<(), Error>;
fn write(&mut self, frame: &Frame) -> Result<()>;
/// Flush the trajectory file
fn flush(&mut self) -> Result<(), Error>;
fn flush(&mut self) -> Result<()>;
/// Get the number of atoms from the give trajectory
fn get_num_atoms(&mut self) -> Result<u32, Error>;
fn get_num_atoms(&mut self) -> Result<u32>;
}
/// Read/Write XTC Trajectories
pub struct XTCTrajectory {
handle: XDRFile,
precision: Cell<f32>, // internal mutability required for read method
num_atoms: Lazy<Result<u32, Error>>
precision: Cell<f32>, // internal mutability required for read method
num_atoms: Lazy<Result<u32>>,
}
impl XTCTrajectory {
pub fn open(path: &Path, filemode: FileMode) -> Result<XTCTrajectory, Error> {
pub fn open(path: &Path, filemode: FileMode) -> Result<XTCTrajectory> {
let xdr = XDRFile::open(path, filemode)?;
Ok(XTCTrajectory { handle: xdr, precision: Cell::new(1000.0), num_atoms: Lazy::new() })
Ok(XTCTrajectory {
handle: xdr,
precision: Cell::new(1000.0),
num_atoms: Lazy::new(),
})
}
}
impl Trajectory for XTCTrajectory {
fn read(&mut self, frame: &mut Frame) -> Result<(), Error> {
fn read(&mut self, frame: &mut Frame) -> Result<()> {
unsafe {
// C lib requires an i32 to be passed, but step is exposed it as u32
// (A step cannot be negative, can it?). So we need to create a step
// variable to pass to read_xtc and cast it afterwards to u32
let mut step: i32 = 0;
let code = xdrfile_xtc::read_xtc(self.handle.xdrfile,
let code = xdrfile_xtc::read_xtc(
self.handle.xdrfile,
frame.num_atoms as i32,
&mut step,
&mut frame.time,
&mut frame.box_vector,
frame.coords.as_ptr() as *mut [f32; 3],
&mut self.precision.get(),
) as u32;
) as u32;
frame.step = step as u32;
match code {
xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to read trajectory. Error code: {}", code))),
_ => Err(Error::CouldNotRead(code)),
}
}
}
fn write(&mut self, frame: &Frame) -> Result<(), Error> {
fn write(&mut self, frame: &Frame) -> Result<()> {
unsafe {
let code = xdrfile_xtc::write_xtc(self.handle.xdrfile,
let code = xdrfile_xtc::write_xtc(
self.handle.xdrfile,
frame.num_atoms as i32,
frame.step as i32,
frame.time,
frame.box_vector.as_ptr() as *mut [[f32; 3]; 3],
frame.coords[..].as_ptr() as *mut [f32; 3],
1000.0) as u32;
1000.0,
) as u32;
match code {
xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to write trajectory. Error code: {}", code)))
_ => Err(Error::CouldNotWrite(code)),
}
}
}
fn flush(&mut self) -> Result<(), Error> {
fn flush(&mut self) -> Result<()> {
unsafe {
let code = xdr_seek::xdr_flush(self.handle.xdrfile) as u32;
match code {
xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to flush trajectory. Error code: {}", code)))
_ => Err(Error::CouldNotFlush(code)),
}
}
}
fn get_num_atoms(&mut self) -> Result<u32, Error> {
let result = self.num_atoms.get_or_create(|| {
let mut num_atoms: i32 = 0;
unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw();
let code = xdrfile_xtc::read_xtc_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code {
xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(err_msg(format!("Failed to read atom number from trajectory. Error code: {}", code)))
}
}
});
match result {
Ok(val) => Ok(*val),
// ugly hack because failure::Error is not "Clone"
Err(err) => Err(err_msg(format!("{}", err)))
}
}
}
fn get_num_atoms(&mut self) -> Result<u32> {
self.num_atoms
.get_or_create(|| {
let mut num_atoms: i32 = 0;
unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw();
let code =
xdrfile_xtc::read_xtc_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code {
xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(Error::CouldNotReadAtomNumber(code)),
}
}
})
.clone()
}
}
/// Read/Write TRR Trajectories
pub struct TRRTrajectory {
handle: XDRFile,
num_atoms: Lazy<Result<u32, Error>>
num_atoms: Lazy<Result<u32>>,
}
impl TRRTrajectory {
pub fn open(path: &Path, filemode: FileMode) -> Result<TRRTrajectory, Error> {
pub fn open(path: &Path, filemode: FileMode) -> Result<TRRTrajectory> {
let xdr = XDRFile::open(path, filemode)?;
Ok(TRRTrajectory { handle: xdr, num_atoms: Lazy::new() })
Ok(TRRTrajectory {
handle: xdr,
num_atoms: Lazy::new(),
})
}
}
impl Trajectory for TRRTrajectory {
fn read(&mut self, frame: &mut Frame) -> Result<(), Error> {
fn read(&mut self, frame: &mut Frame) -> Result<()> {
unsafe {
// C lib requires an i32 to be passed, but step is exposed it as u32
// (A step cannot be negative, can it?). So we need to create a step
@@ -261,7 +317,8 @@ impl Trajectory for TRRTrajectory {
// Similar for lambda.
let mut step: i32 = 0;
let mut lambda: f32 = 0.0;
let code = xdrfile_trr::read_trr(self.handle.xdrfile,
let code = xdrfile_trr::read_trr(
self.handle.xdrfile,
frame.num_atoms as i32,
&mut step,
&mut frame.time,
@@ -269,19 +326,20 @@ impl Trajectory for TRRTrajectory {
&mut frame.box_vector,
frame.coords.as_ptr() as *mut [f32; 3],
std::ptr::null_mut(),
std::ptr::null_mut()
) as u32;
std::ptr::null_mut(),
) as u32;
frame.step = step as u32;
match code {
xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to read trajectory. Error code: {}", code)))
_ => Err(Error::CouldNotRead(code)),
}
}
}
fn write(&mut self, frame: &Frame) -> Result<(), Error> {
fn write(&mut self, frame: &Frame) -> Result<()> {
unsafe {
let code = xdrfile_trr::write_trr(self.handle.xdrfile,
let code = xdrfile_trr::write_trr(
self.handle.xdrfile,
frame.num_atoms as i32,
frame.step as i32,
frame.time,
@@ -289,51 +347,49 @@ impl Trajectory for TRRTrajectory {
frame.box_vector.as_ptr() as *mut [[f32; 3]; 3],
frame.coords[..].as_ptr() as *mut [f32; 3],
std::ptr::null_mut(),
std::ptr::null_mut()) as u32;
std::ptr::null_mut(),
) as u32;
match code {
xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to write trajectory. Error code: {}", code)))
_ => Err(Error::CouldNotWrite(code)),
}
}
}
fn flush(&mut self) -> Result<(), Error> {
fn flush(&mut self) -> Result<()> {
unsafe {
let code = xdr_seek::xdr_flush(self.handle.xdrfile) as u32;
match code {
xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to flush trajectory. Error code: {}", code)))
_ => Err(Error::CouldNotFlush(code)),
}
}
}
fn get_num_atoms(&mut self) -> Result<u32, Error> {
let result = self.num_atoms.get_or_create(|| {
let mut num_atoms: i32 = 0;
unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw();
let code = xdrfile_trr::read_trr_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code {
xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(err_msg(format!("Failed to read atom number from trajectory. Error code: {}", code)))
}
}
});
match result {
Ok(val) => Ok(*val),
// ugly hack because failure::Error is not "Clone"
Err(err) => Err(err_msg(format!("{}", err)))
}
}
}
fn get_num_atoms(&mut self) -> Result<u32> {
self.num_atoms
.get_or_create(|| {
let mut num_atoms: i32 = 0;
unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw();
let code =
xdrfile_trr::read_trr_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code {
xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(Error::CouldNotReadAtomNumber(code)),
}
}
})
.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::NamedTempFile;
use tempfile::NamedTempFile;
#[test]
fn test_read_write_xtc() {
@@ -413,4 +469,3 @@ mod tests {
assert_eq!(new_frame.coords, frame.coords);
}
}

View File

@@ -1,9 +1,9 @@
#[cfg(test)]
mod integration {
use std::path::Path;
use std::rc::Rc;
use xdrfile::*;
use std::path::Path;
#[test]
fn test_use_library() {
@@ -25,8 +25,7 @@ mod integration {
let trj = XTCTrajectory::open(path, FileMode::Read).unwrap();
let frames: Vec<Rc<Frame>> = trj.into_iter().filter_map(Result::ok).collect();
for (idx, frame) in frames.iter().enumerate() {
assert_eq!(frame.step as usize, idx+1);
assert_eq!(frame.step as usize, idx + 1);
}
}
}
}