From 43d2d74468b8ee17668a2cf1500761ade16e2905 Mon Sep 17 00:00:00 2001 From: daniel Date: Thu, 16 Apr 2020 13:03:33 +0200 Subject: [PATCH] c_abi --- .gitignore | 2 + Cargo.toml | 18 + build.rs | 17 + external/xdrfile/README | 21 + external/xdrfile/include/ms_stdint.h | 259 +++ external/xdrfile/include/trr_header.h | 30 + external/xdrfile/include/xdr_seek.h | 17 + external/xdrfile/include/xdrfile.h | 632 ++++++ external/xdrfile/include/xdrfile_trr.h | 61 + external/xdrfile/include/xdrfile_xtc.h | 61 + external/xdrfile/src/xdr_seek.c | 55 + external/xdrfile/src/xdrfile.c | 2634 ++++++++++++++++++++++++ external/xdrfile/src/xdrfile_trr.c | 533 +++++ external/xdrfile/src/xdrfile_xtc.c | 164 ++ src/c_abi/mod.rs | 5 + src/c_abi/xdr_seek.rs | 160 ++ src/c_abi/xdrfile.rs | 520 +++++ src/c_abi/xdrfile_trr.rs | 133 ++ src/c_abi/xdrfile_xtc.rs | 114 + src/lib.rs | 1 + tests/1l2y.trr | Bin 0 -> 143184 bytes tests/1l2y.xtc | Bin 0 -> 62496 bytes 22 files changed, 5437 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 build.rs create mode 100644 external/xdrfile/README create mode 100644 external/xdrfile/include/ms_stdint.h create mode 100644 external/xdrfile/include/trr_header.h create mode 100644 external/xdrfile/include/xdr_seek.h create mode 100644 external/xdrfile/include/xdrfile.h create mode 100644 external/xdrfile/include/xdrfile_trr.h create mode 100644 external/xdrfile/include/xdrfile_xtc.h create mode 100644 external/xdrfile/src/xdr_seek.c create mode 100644 external/xdrfile/src/xdrfile.c create mode 100644 external/xdrfile/src/xdrfile_trr.c create mode 100644 external/xdrfile/src/xdrfile_xtc.c create mode 100644 src/c_abi/mod.rs create mode 100644 src/c_abi/xdr_seek.rs create mode 100644 src/c_abi/xdrfile.rs create mode 100644 src/c_abi/xdrfile_trr.rs create mode 100644 src/c_abi/xdrfile_xtc.rs create mode 100644 src/lib.rs create mode 100644 tests/1l2y.trr create mode 100644 tests/1l2y.xtc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f1c63cd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "xdrfile" +version = "0.1.0" +authors = ["Daniel Bauer "] +license = "GNU" +edition = "2018" +description = "Wrapper around the gromacs libxdrfile library. Can be used to read and write gromacs trajectories in xtc and trr format." +build = "build.rs" + +[dependencies] +failure = "0.1" +lazy-init = "0.3" + +[dev-dependencies] +tempfile = "3.1.0" + +[build-dependencies] +cc = { version = "1.0", features = ["parallel" ]} diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..59de77d --- /dev/null +++ b/build.rs @@ -0,0 +1,17 @@ +extern crate cc; + +use std::fs; + +fn main() { + // This builds gromacs' xdrfile library + let source_files: Vec<_> = fs::read_dir("external/xdrfile/src") + .unwrap() + .map(|f| f.unwrap()) + .map(|f| f.path()) + .collect(); + cc::Build::new() + .files(source_files) + .include("external/xdrfile/include") + .warnings(false) + .compile("libxdrfile.a") +} diff --git a/external/xdrfile/README b/external/xdrfile/README new file mode 100644 index 0000000..d6d3f42 --- /dev/null +++ b/external/xdrfile/README @@ -0,0 +1,21 @@ +Low-level C libraries for manipulating GROMACS XTC and TRR files. +This code is is taken from mdtraj library which is available at + +https://github.com/mdtraj/mdtraj + +and originally derived from xdrfile-1.1.4, available at + +http://www.gromacs.org/Developer_Zone/Programming_Guide/XTC_Library +ftp://ftp.gromacs.org/pub/contrib/xdrfile-1.1.4.tar.gz + +These files are licensed under a BSD 2-clause license, and copyright +Erik Lindahl, David van der Spoel, Robert T. McGibbon. + +Changes from upsteam's xdrfile-1.1.4 include: + - More descriptive error strings printed inside xdrfile.c + - Fix for a segfault on malformed xtc files inside xdrfile_decompress_coord_float (https://github.com/mdtraj/mdtraj/pull/607, https://mailman-1.sys.kth.se/pipermail/gromacs.org_gmx-developers/2014-September/007942.html) + - Addition of read_xtc_nframes function in xdrfile_xtc.c + - Addition of read_trr_nframes function in xdrfile_trr.c + - Bugfix in do_trnheader to return the appropriate error code when reading magic, and properly check the value of the magic in xdrfile_trr.c + - Bugfix of float exception (divide by zero) in xdrfile.c, see https://github.com/SimTk/mdtraj/issues/616 + - Implemented efficient seeking pattern inspired by xdrlib2 (part of MDAnalysis) \ No newline at end of file diff --git a/external/xdrfile/include/ms_stdint.h b/external/xdrfile/include/ms_stdint.h new file mode 100644 index 0000000..cb2acd9 --- /dev/null +++ b/external/xdrfile/include/ms_stdint.h @@ -0,0 +1,259 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include +#else // ] _MSC_VER >= 1600 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/external/xdrfile/include/trr_header.h b/external/xdrfile/include/trr_header.h new file mode 100644 index 0000000..dedfc77 --- /dev/null +++ b/external/xdrfile/include/trr_header.h @@ -0,0 +1,30 @@ +#ifndef _trr_header_h_ +#define _trr_header_h_ + +typedef struct /* This struct describes the order and the */ +/* sizes of the structs in a trjfile, sizes are given in bytes. */ +{ + int bDouble; /* Double precision? */ + int ir_size; /* Backward compatibility */ + int e_size; /* Backward compatibility */ + int box_size; /* Non zero if a box is present */ + int vir_size; /* Backward compatibility */ + int pres_size; /* Backward compatibility */ + int top_size; /* Backward compatibility */ + int sym_size; /* Backward compatibility */ + int x_size; /* Non zero if coordinates are present */ + int v_size; /* Non zero if velocities are present */ + int f_size; /* Non zero if forces are present */ + + int natoms; /* The total number of atoms */ + int step; /* Current step number */ + int nre; /* Backward compatibility */ + float tf; /* Current time */ + float lambdaf; /* Current value of lambda */ + double td; /* Current time */ + double lambdad; /* Current value of lambda */ +} t_trnheader; + +int do_trnheader(XDRFILE *xd, char bRead, t_trnheader *sh); + +#endif diff --git a/external/xdrfile/include/xdr_seek.h b/external/xdrfile/include/xdr_seek.h new file mode 100644 index 0000000..9cadbbb --- /dev/null +++ b/external/xdrfile/include/xdr_seek.h @@ -0,0 +1,17 @@ +#ifndef _xdr_seek_h +#define _xdr_seek_h + +// for int64_t on older M$ Visual Studio +#if _MSC_VER && _MSVC_VER < 1600 && !__INTEL_COMPILER + #include "ms_stdint.h" +#else + #include +#endif + +#include "xdrfile.h" + +int64_t xdr_tell(XDRFILE *xd); +int xdr_seek(XDRFILE *xd, int64_t pos, int whence); +int xdr_flush(XDRFILE* xd); + +#endif diff --git a/external/xdrfile/include/xdrfile.h b/external/xdrfile/include/xdrfile.h new file mode 100644 index 0000000..5272f7d --- /dev/null +++ b/external/xdrfile/include/xdrfile.h @@ -0,0 +1,632 @@ + /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- + * + * $Id$ + * + * Copyright (c) 2009-2014, Erik Lindahl & David van der Spoel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*! \file xdrfile.h + * \brief Interface to read/write portabile binary files using XDR. + * + * This file provides an interface to read & write portably binary files, + * using XDR - the external data representation standard defined in RFC 1014. + * + * There are several advantages to the XDR approach: + * + * -# It is portable. And not just portable between big/small integer endian, + * but truly portable if you have system XDR routines. For example: + * - It doesn't matter if the character representation is ASCII or EBCDIC. + * - Some systems are small endian but use big endian order of the two + * dword in a double precision floating-point variable. The system XDR + * libraries will read/write this correctly. + * - Some systems (VAX...) don't use IEEE floating point. Their system + * XDR libraries will convert to/from this automatically. + * -# XDR libraries are required for NFS and lots of other network functions. + * This means there isn't a single Unix-like system that doesn't have them. + * -# There is NO extra metadata whatsoever, and we write plain XDR files. + * If you write a float, it will take exactly 4 bytes in the file. + * (All basic datatypes are 4 bytes, double fp 8 bytes). + * -# You can read/write the files by calling the system XDR routines directly + * too - you don't have to use the routines defined in this file. + * -# It is no problem if your system doesn't have XDR libraries (MS Windows). + * We have written our own versions of the necessary routines that work if + * your system uses ASCII for strings and IEEE floating-point. All types + * of byte and dword endian for integer and floating-point are supported. + * -# You can use these routines for any type of data, but since we designed + * them for Gromacs we also provide a special routine to write coordinates + * with (adjustable) lossy compression. The default precision will give you + * three decimals guaranteed accuracy, and reduces the filesize to 1/10th + * of normal binary data. + * + * We do not support getting or setting positions in XDR files, since it can + * break in horrible ways for large (64-bit) files, resulting in silent data + * corruption. Note that it works great to open/read/write 64-bit files if + * your system supports it; it is just the random access we cannot trust! + * + * We also provide wrapper routines so this module can be used from FORTRAN - + * see the file xdrfile_fortran.txt in the Gromacs distribution for + * documentation on the FORTRAN interface! + */ + +#ifndef _XDRFILE_H_ +#define _XDRFILE_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + /*! \brief Abstract datatype for an portable binary file handle + * + * This datatype essentially works just like the standard FILE type in C. + * The actual contents is hidden in the implementation, so you can only + * define pointers to it, for use with the xdrfile routines. + * + * If you \a really need to see the definition it is in xdrfile.c, but you + * cannot access elements of the structure outside that file. + * + * \warning The implementation is completely different from the C standard + * library FILE, so don't even think about using an XDRFILE pointer as an + * argument to a routine that needs a standard FILE pointer. + */ + typedef struct XDRFILE XDRFILE; + + enum { exdrOK, exdrHEADER, exdrSTRING, exdrDOUBLE, + exdrINT, exdrFLOAT, exdrUINT, exdr3DX, exdrCLOSE, exdrMAGIC, + exdrNOMEM, exdrENDOFFILE, exdrFILENOTFOUND, exdrNR }; + + extern char *exdr_message[exdrNR]; + +#define DIM 3 + typedef float matrix[DIM][DIM]; + typedef float rvec[DIM]; + typedef int mybool; + + + /*! \brief Open a portable binary file, just like fopen() + * + * Use this routine much like calls to the standard library function + * fopen(). The only difference is that the returned pointer should only + * be used with routines defined in this header. + * + * \param path Full or relative path (including name) of the file + * \param mode "r" for reading, "w" for writing, "a" for append. + * + * \return Pointer to abstract xdr file datatype, or NULL if an error occurs. + * + */ + XDRFILE * + xdrfile_open (const char * path, + const char * mode); + + + /*! \brief Close a previously opened portable binary file, just like fclose() + * + * Use this routine much like calls to the standard library function + * fopen(). The only difference is that it is used for an XDRFILE handle + * instead of a FILE handle. + * + * \param xfp Pointer to an abstract XDRFILE datatype + * + * \return 0 on success, non-zero on error. + */ + int + xdrfile_close (XDRFILE * xfp); + + + + + /*! \brief Read one or more \a char type variable(s) + * + * \param ptr Pointer to memory where data should be written + * \param ndata Number of characters to read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of characters read + */ + int + xdrfile_read_char(char * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Write one or more \a characters type variable(s) + * + * \param ptr Pointer to memory where data should be read + * \param ndata Number of characters to write. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of characters written + */ + int + xdrfile_write_char(char * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Read one or more \a unsigned \a char type variable(s) + * + * \param ptr Pointer to memory where data should be written + * \param ndata Number of unsigned characters to read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of unsigned characters read + */ + int + xdrfile_read_uchar(unsigned char * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Write one or more \a unsigned \a characters type variable(s) + * + * \param ptr Pointer to memory where data should be read + * \param ndata Number of unsigned characters to write. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of unsigned characters written + */ + int + xdrfile_write_uchar(unsigned char * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Read one or more \a short type variable(s) + * + * \param ptr Pointer to memory where data should be written + * \param ndata Number of shorts to read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of shorts read + */ + int + xdrfile_read_short(short * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Write one or more \a short type variable(s) + * + * \param ptr Pointer to memory where data should be read + * \param ndata Number of shorts to write. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of shorts written + */ + int + xdrfile_write_short(short * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Read one or more \a unsigned \a short type variable(s) + * + * \param ptr Pointer to memory where data should be written + * \param ndata Number of unsigned shorts to read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of unsigned shorts read + */ + int + xdrfile_read_ushort(unsigned short * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Write one or more \a unsigned \a short type variable(s) + * + * \param ptr Pointer to memory where data should be read + * \param ndata Number of unsigned shorts to write. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of unsigned shorts written + */ + int + xdrfile_write_ushort(unsigned short * ptr, + int ndata, + XDRFILE * xfp); + + + /*! \brief Read one or more \a integer type variable(s) + * + * \param ptr Pointer to memory where data should be written + * \param ndata Number of integers to read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of integers read + * + * The integer data type is assumed to be less than or equal to 32 bits. + * + * We do not provide any routines for reading/writing 64-bit integers, since + * - Not all XDR implementations support it + * - Not all machines have 64-bit integers + * + * Split your 64-bit data into two 32-bit integers for portability! + */ + int + xdrfile_read_int(int * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Write one or more \a integer type variable(s) + * + * \param ptr Pointer to memory where data should be read + * \param ndata Number of integers to write. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of integers written + * + * The integer data type is assumed to be less than or equal to 32 bits. + * + * We do not provide any routines for reading/writing 64-bit integers, since + * - Not all XDR implementations support it + * - Not all machines have 64-bit integers + * + * Split your 64-bit data into two 32-bit integers for portability! + */ + int + xdrfile_write_int(int * ptr, + int ndata, + XDRFILE * xfp); + + /*! \brief Read one or more \a unsigned \a integers type variable(s) + * + * \param ptr Pointer to memory where data should be written + * \param ndata Number of unsigned integers to read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of unsigned integers read + * + * The integer data type is assumed to be less than or equal to 32 bits. + * + * We do not provide any routines for reading/writing 64-bit integers, since + * - Not all XDR implementations support it + * - Not all machines have 64-bit integers + * + * Split your 64-bit data into two 32-bit integers for portability! + */ + int + xdrfile_read_uint(unsigned int * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Write one or more \a unsigned \a integer type variable(s) + * + * \param ptr Pointer to memory where data should be read + * \param ndata Number of unsigned integers to write. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of unsigned integers written + * + * The integer data type is assumed to be less than or equal to 32 bits. + * + * We do not provide any routines for reading/writing 64-bit integers, since + * - Not all XDR implementations support it + * - Not all machines have 64-bit integers + * + * Split your 64-bit data into two 32-bit integers for portability! + */ + int + xdrfile_write_uint(unsigned int * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Read one or more \a float type variable(s) + * + * \param ptr Pointer to memory where data should be written + * \param ndata Number of floats to read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of floats read + */ + int + xdrfile_read_float(float * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Write one or more \a float type variable(s) + * + * \param ptr Pointer to memory where data should be read + * \param ndata Number of floats to write. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of floats written + */ + int + xdrfile_write_float(float * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Read one or more \a double type variable(s) + * + * \param ptr Pointer to memory where data should be written + * \param ndata Number of doubles to read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of doubles read + */ + int + xdrfile_read_double(double * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Write one or more \a double type variable(s) + * + * \param ptr Pointer to memory where data should be read + * \param ndata Number of double to write. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of doubles written + */ + int + xdrfile_write_double(double * ptr, + int ndata, + XDRFILE * xfp); + + + + /*! \brief Read a string (array of characters) + * + * \param ptr Pointer to memory where data should be written + * \param maxlen Maximum length of string. If no end-of-string is encountered, + * one byte less than this is read and end-of-string appended. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of characters read, including end-of-string + */ + int + xdrfile_read_string(char * ptr, + int maxlen, + XDRFILE * xfp); + + + + /*! \brief Write a string (array of characters) + * + * \param ptr Pointer to memory where data should be read + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of characters written, including end-of-string + */ + int + xdrfile_write_string(char * ptr, + XDRFILE * xfp); + + + + /*! \brief Read raw bytes from file (unknown datatype) + * + * \param ptr Pointer to memory where data should be written + * \param nbytes Number of bytes to read. No conversion whatsoever is done. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of bytes read from file + */ + int + xdrfile_read_opaque(char * ptr, + int nbytes, + XDRFILE * xfp); + + + + + /*! \brief Write raw bytes to file (unknown datatype) + * + * \param ptr Pointer to memory where data should be read + * \param nbytes Number of bytes to write. No conversion whatsoever is done. + * \param xfp Handle to portable binary file, created with xdrfile_open() + * + * \return Number of bytes written to file + */ + int + xdrfile_write_opaque(char * ptr, + int nbytes, + XDRFILE * xfp); + + + + + + + /*! \brief Compress coordiates in a float array to XDR file + * + * This routine will perform \a lossy compression on the three-dimensional + * coordinate data data specified and store it in the XDR file. + * + * The lossy part of the compression consists of multiplying each + * coordinate with the precision argument and then rounding to integers. + * We suggest a default value of 1000.0, which means you are guaranteed + * three decimals of accuracy. The only limitation is that scaled coordinates + * must still fit in an integer variable, so if the precision is 1000.0 the + * coordinate magnitudes must be less than +-2e6. + * + * \param ptr Pointer to coordinates to compress (length 3*ncoord) + * \param ncoord Number of coordinate triplets in data + * \param precision Scaling factor for lossy compression. If it is <=0, + * the default value of 1000.0 is used. + * \param xfp Handle to portably binary file + * + * \return Number of coordinate triplets written. + * IMPORTANT: Check that this is equal to ncoord - if it is + * negative, an error occured. This should not happen with + * normal data, but if your coordinates are NaN or very + * large (>1e6) it is not possible to use the compression. + * + * \warning The compression algorithm is not part of the XDR standard, + * and very complicated, so you will need this xdrfile module + * to read it later. + */ + int + xdrfile_compress_coord_float(float * ptr, + int ncoord, + float precision, + XDRFILE * xfp); + + + + + /*! \brief Decompress coordiates from XDR file to array of floats + * + * This routine will decompress three-dimensional coordinate data previously + * stored in an XDR file and store it in the specified array of floats. + * + * The precision used during the earlier compression is read from the file + * and returned - you cannot adjust the accuracy at this stage. + * + * \param ptr Pointer to coordinates to compress (length>= 3*ncoord) + * \param ncoord Max number of coordinate triplets to read on input, actual + * number of coordinate triplets read on return. If this + * is smaller than the number of coordinates in the frame an + * error will occur. + * \param precision The precision used in the previous compression will be + * written to this variable on return. + * \param xfp Handle to portably binary file + * + * \return Number of coordinate triplets read. If this is negative, + * an error occured. + * + * \warning Since we cannot count on being able to set/get the + * position of large files (>2Gb), it is not possible to + * recover from errors by re-reading the frame if the + * storage area you provided was too small. To avoid this + * from happening, we recommend that you store the number of + * coordinates triplet as an integer either in a header or + * just before the compressed coordinate data, so you can + * read it first and allocated enough memory. + */ + int + xdrfile_decompress_coord_float(float * ptr, + int * ncoord, + float * precision, + XDRFILE * xfp); + + + + + /*! \brief Compress coordiates in a double array to XDR file + * + * This routine will perform \a lossy compression on the three-dimensional + * coordinate data data specified and store it in the XDR file. Double will + * NOT give you any extra precision since the coordinates are compressed. This + * routine just avoids allocating a temporary array of floats. + * + * The lossy part of the compression consists of multiplying each + * coordinate with the precision argument and then rounding to integers. + * We suggest a default value of 1000.0, which means you are guaranteed + * three decimals of accuracy. The only limitation is that scaled coordinates + * must still fit in an integer variable, so if the precision is 1000.0 the + * coordinate magnitudes must be less than +-2e6. + * + * \param ptr Pointer to coordinates to compress (length 3*ncoord) + * \param ncoord Number of coordinate triplets in data + * \param precision Scaling factor for lossy compression. If it is <=0, the + * default value of 1000.0 is used. + * \param xfp Handle to portably binary file + * + * \return Number of coordinate triplets written. + * IMPORTANT: Check that this is equal to ncoord - if it is + * negative, an error occured. This should not happen with + * normal data, but if your coordinates are NaN or very + * large (>1e6) it is not possible to use the compression. + * + * \warning The compression algorithm is not part of the XDR standard, + * and very complicated, so you will need this xdrfile module + * to read it later. + */ + int + xdrfile_compress_coord_double(double * ptr, + int ncoord, + double precision, + XDRFILE * xfp); + + + + + /*! \brief Decompress coordiates from XDR file to array of doubles + * + * This routine will decompress three-dimensional coordinate data previously + * stored in an XDR file and store it in the specified array of doubles. + * Double will NOT give you any extra precision since the coordinates are + * compressed. This routine just avoids allocating a temporary array of floats. + * + * The precision used during the earlier compression is read from the file + * and returned - you cannot adjust the accuracy at this stage. + * + * \param ptr Pointer to coordinates to compress (length>= 3*ncoord) + * \param ncoord Max number of coordinate triplets to read on input, actual + * number of coordinate triplets read on return. If this + * is smaller than the number of coordinates in the frame an + * error will occur. + * \param precision The precision used in the previous compression will be + * written to this variable on return. + * \param xfp Handle to portably binary file + * + * \return Number of coordinate triplets read. If this is negative, + * an error occured. + * + * \warning Since we cannot count on being able to set/get the + * position of large files (>2Gb), it is not possible to + * recover from errors by re-reading the frame if the + * storage area you provided was too small. To avoid this + * from happening, we recommend that you store the number of + * coordinates triplet as an integer either in a header or + * just before the compressed coordinate data, so you can + * read it first and allocated enough memory. + */ + int + xdrfile_decompress_coord_double(double * ptr, + int * ncoord, + double * precision, + XDRFILE * xfp); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _XDRFILE_H_ */ + diff --git a/external/xdrfile/include/xdrfile_trr.h b/external/xdrfile/include/xdrfile_trr.h new file mode 100644 index 0000000..14fe105 --- /dev/null +++ b/external/xdrfile/include/xdrfile_trr.h @@ -0,0 +1,61 @@ + /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- + * + * $Id$ + * + * Copyright (c) 2009-2014, Erik Lindahl & David van der Spoel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xdrfile_trr_h +#define _xdrfile_trr_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xdrfile.h" + + /* All functions return exdrOK if successful. + * (error codes defined in xdrfile.h). + */ + + /* This function returns the number of atoms in the xtc file in *natoms */ + extern int read_trr_natoms(char *fn,int *natoms); + extern int read_trr_nframes(char* fn, unsigned long *nframes); + + /* Read one frame of an open xtc file. If either of x,v,f,box are + NULL the arrays will be read from the file but not used. */ + extern int read_trr(XDRFILE *xd,int natoms,int *step,float *t,float *lambda, + matrix box,rvec *x,rvec *v,rvec *f); + + /* Write a frame to xtc file */ + extern int write_trr(XDRFILE *xd,int natoms,int step,float t,float lambda, + matrix box,rvec *x,rvec *v,rvec *f); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/xdrfile/include/xdrfile_xtc.h b/external/xdrfile/include/xdrfile_xtc.h new file mode 100644 index 0000000..ff6f4bd --- /dev/null +++ b/external/xdrfile/include/xdrfile_xtc.h @@ -0,0 +1,61 @@ + /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- + * + * $Id$ + * + * Copyright (c) 2009-2014, Erik Lindahl & David van der Spoel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xdrfile_xtc_h +#define _xdrfile_xtc_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xdrfile.h" + + /* All functions return exdrOK if succesfull. + * (error codes defined in xdrfile.h). + */ + + /* This function returns the number of atoms in the xtc file in *natoms */ + extern int read_xtc_natoms(char *fn,int *natoms); + + int read_xtc_nframes(char* fn, unsigned long *nframes); + + /* Read one frame of an open xtc file */ + extern int read_xtc(XDRFILE *xd,int natoms,int *step,float *time, + matrix box,rvec *x,float *prec); + + /* Write a frame to xtc file */ + extern int write_xtc(XDRFILE *xd, + int natoms,int step,float time, + matrix box,rvec *x,float prec); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/xdrfile/src/xdr_seek.c b/external/xdrfile/src/xdr_seek.c new file mode 100644 index 0000000..17602ae --- /dev/null +++ b/external/xdrfile/src/xdr_seek.c @@ -0,0 +1,55 @@ +/* 64 bit fileseek operations */ +#define _FILE_OFFSETS_BITS 64 +#include "xdr_seek.h" +#include + +/// copied from xtcfile.c (version 1.1.4) +struct XDRFILE +{ + FILE * fp; /**< pointer to standard C library file handle */ + void * /*this used to be (XDR*) */ xdr; /**< pointer to corresponding XDR handle */ + char mode; /**< r=read, w=write, a=append */ + int * buf1; /**< Buffer for internal use */ + int buf1size; /**< Current allocated length of buf1 */ + int * buf2; /**< Buffer for internal use */ + int buf2size; /**< Current allocated length of buf2 */ +}; +//// end of copied + +int64_t xdr_tell(XDRFILE *xd) +{ + FILE* fptr = xd->fp; + +#ifndef _WIN32 + // use posix 64 bit ftell version + return ftello(fptr); +#elif defined(_MSVC_VER) && !__INTEL_COMPILER + return _ftelli64(fptr); +#else + return ftell(fptr); +#endif +} + +int xdr_seek(XDRFILE *xd, int64_t pos, int whence) +{ + int result = 1; + FILE* fptr = xd->fp; + +#ifndef _WIN32 + // use posix 64 bit ftell version + result = fseeko(fptr, pos, whence) < 0 ? exdrNR : exdrOK; +#elif _MSVC_VER && !__INTEL_COMPILER + result = _fseeki64(fptr, pos, whence) < 0 ? exdrNR : exdrOK; +#else + result = fseek(fptr, pos, whence) < 0 ? exdrNR : exdrOK; +#endif + if (result != exdrOK) + return result; + + return exdrOK; +} + +int xdr_flush(XDRFILE* xdr) +{ + return fflush(xdr->fp); +} diff --git a/external/xdrfile/src/xdrfile.c b/external/xdrfile/src/xdrfile.c new file mode 100644 index 0000000..24285f3 --- /dev/null +++ b/external/xdrfile/src/xdrfile.c @@ -0,0 +1,2634 @@ + /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- + * + * $Id$ + * + * Copyright (c) 2009-2014, Erik Lindahl & David van der Spoel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Get HAVE_RPC_XDR_H, F77_FUNC from config.h if available */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#define _FILE_OFFSET_BITS 64 + +/* get fixed-width types if we are using ANSI C99 */ +#ifdef HAVE_STDINT_H +# include +#elif (defined HAVE_INTTYPES_H) +# include +#endif + + +#ifdef HAVE_RPC_XDR_H +# include +# include +#endif + +#include "xdrfile.h" + +/* Default FORTRAN name mangling is: lower case name, append underscore */ +#ifndef F77_FUNC +#define F77_FUNC(name,NAME) name ## _ +#endif + +char *exdr_message[exdrNR] = { + "OK", + "Header", + "String", + "Double", + "Integer", + "Float", + "Unsigned integer", + "Compressed 3D coordinate", + "Closing file", + "Magic number", + "Not enough memory", + "End of file", + "File not found" +}; + +/* + * Declare our own XDR routines statically if no libraries are present. + * Actual implementation is at the end of this file. + * + * We don't want the low-level XDR implementation as part of the Gromacs + * documentation, so skip it for doxygen too... + */ +#if (!defined HAVE_RPC_XDR_H && !defined DOXYGEN) + +enum xdr_op +{ + XDR_ENCODE = 0, + XDR_DECODE = 1, + XDR_FREE = 2 +}; + + +/* We need integer types that are guaranteed to be 4 bytes wide. + * If ANSI C99 headers were included they are already defined + * as int32_t and uint32_t. Check, and if not define them ourselves. + * Since it is just our workaround for missing ANSI C99 types, avoid adding + * it to the doxygen documentation. + */ +#if !(defined INT32_MAX || defined DOXYGEN) +# if (INT_MAX == 2147483647) +# define int32_t int +# define uint32_t unsigned int +# define INT32_MAX 2147483647 +# elif (LONG_MAX == 2147483647) +# define int32_t long +# define uint32_t unsigned long +# define INT32_MAX 2147483647L +# else +# error ERROR: No 32 bit wide integer type found! +# error Use system XDR libraries instead, or update xdrfile.c +# endif +#endif + +typedef struct XDR XDR; + +struct XDR +{ + enum xdr_op x_op; + struct xdr_ops + { + int (*x_getlong) (XDR *__xdrs, int32_t *__lp); + int (*x_putlong) (XDR *__xdrs, int32_t *__lp); + int (*x_getbytes) (XDR *__xdrs, char *__addr, unsigned int __len); + int (*x_putbytes) (XDR *__xdrs, char *__addr, unsigned int __len); + /* two next routines are not 64-bit IO safe - don't use! */ + unsigned int (*x_getpostn) (XDR *__xdrs); + int (*x_setpostn) (XDR *__xdrs, unsigned int __pos); + void (*x_destroy) (XDR *__xdrs); + } + *x_ops; + char *x_private; +}; + +static int xdr_char (XDR *xdrs, char *ip); +static int xdr_u_char (XDR *xdrs, unsigned char *ip); +static int xdr_short (XDR *xdrs, short *ip); +static int xdr_u_short (XDR *xdrs, unsigned short *ip); +static int xdr_int (XDR *xdrs, int *ip); +static int xdr_u_int (XDR *xdrs, unsigned int *ip); +static int xdr_float (XDR *xdrs, float *ip); +static int xdr_double (XDR *xdrs, double *ip); +static int xdr_string (XDR *xdrs, char **ip, unsigned int maxsize); +static int xdr_opaque (XDR *xdrs, char *cp, unsigned int cnt); +static void xdrstdio_create (XDR *xdrs, FILE *fp, enum xdr_op xop); + +#define xdr_getpos(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) +#define xdr_setpos(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) +#define xdr_destroy(xdrs) \ + do { \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs); \ + } while (0) +#endif /* end of our own XDR declarations */ + + + + + +/** Contents of the abstract XDRFILE data structure. + * + * @internal + * + * This structure is used to provide an XDR file interface that is + * virtual identical to the standard UNIX fopen/fread/fwrite/fclose. + */ +struct XDRFILE +{ + FILE * fp; /**< pointer to standard C library file handle */ + XDR * xdr; /**< pointer to corresponding XDR handle */ + char mode; /**< r=read, w=write, a=append */ + int * buf1; /**< Buffer for internal use */ + int buf1size; /**< Current allocated length of buf1 */ + int * buf2; /**< Buffer for internal use */ + int buf2size; /**< Current allocated length of buf2 */ +}; + + + + +/************************************************************* + * Implementation of higher-level routines to read/write * + * portable data based on the XDR standard. These should be * + * called from C - see further down for Fortran77 wrappers. * + *************************************************************/ + +XDRFILE * +xdrfile_open(const char *path, const char *mode) +{ + char newmode[5]; + enum xdr_op xdrmode; + XDRFILE *xfp; + + /* make sure XDR files are opened in binary mode... */ + if(*mode=='w' || *mode=='W') + { + sprintf(newmode,"wb+"); + xdrmode=XDR_ENCODE; + } else if(*mode == 'a' || *mode == 'A') + { + sprintf(newmode,"ab+"); + xdrmode = XDR_ENCODE; + } else if(*mode == 'r' || *mode == 'R') + { + sprintf(newmode,"rb"); + xdrmode = XDR_DECODE; + } else /* cannot determine mode */ + return NULL; + + if((xfp=(XDRFILE *)malloc(sizeof(XDRFILE)))==NULL) + return NULL; + if((xfp->fp=fopen(path,newmode))==NULL) + { + free(xfp); + return NULL; + } + if((xfp->xdr=(XDR *)malloc(sizeof(XDR)))==NULL) + { + fclose(xfp->fp); + free(xfp); + return NULL; + } + xfp->mode=*mode; + xdrstdio_create((XDR *)(xfp->xdr),xfp->fp,xdrmode); + xfp->buf1 = xfp->buf2 = NULL; + xfp->buf1size = xfp->buf2size = 0; + return xfp; +} + +int +xdrfile_close(XDRFILE *xfp) +{ + int ret=exdrCLOSE; + if(xfp) + { + /* flush and destroy XDR stream */ + if(xfp->xdr) + xdr_destroy((XDR *)(xfp->xdr)); + free(xfp->xdr); + /* close the file */ + ret=fclose(xfp->fp); + if(xfp->buf1size) + free(xfp->buf1); + if(xfp->buf2size) + free(xfp->buf2); + free(xfp); + } + return ret; /* return 0 if ok */ +} + + + +int +xdrfile_read_int(int *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + + return i; +} + +int +xdrfile_write_int(int *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + + +int +xdrfile_read_uint(unsigned int *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + + return i; +} + +int +xdrfile_write_uint(unsigned int *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + +int +xdrfile_read_char(char *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + + return i; +} + +int +xdrfile_write_char(char *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + + +int +xdrfile_read_uchar(unsigned char *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + + return i; +} + +int +xdrfile_write_uchar(unsigned char *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + +int +xdrfile_read_short(short *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + + return i; +} + +int +xdrfile_write_short(short *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + + +int +xdrfile_read_ushort(unsigned short *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + + return i; +} + +int +xdrfile_write_ushort(unsigned short *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + +int +xdrfile_read_float(float *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + +int +xdrfile_write_float(float *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + +int +xdrfile_read_double(double *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + +int +xdrfile_write_double(double *ptr, int ndata, XDRFILE* xfp) +{ + int i=0; + /* read write is encoded in the XDR struct */ + while(ixdr),ptr+i)) + i++; + return i; +} + +int +xdrfile_read_string(char *ptr, int maxlen, XDRFILE* xfp) +{ + int i; + if(xdr_string((XDR *)(xfp->xdr),&ptr,maxlen)) { + i=0; + while(ixdr),&ptr,len)) + return len; + else + return 0; +} + + +int +xdrfile_read_opaque(char *ptr, int cnt, XDRFILE* xfp) +{ + if(xdr_opaque((XDR *)(xfp->xdr),ptr,cnt)) + return cnt; + else + return 0; +} + + +int +xdrfile_write_opaque(char *ptr, int cnt, XDRFILE* xfp) +{ + if(xdr_opaque((XDR *)(xfp->xdr),ptr,cnt)) + return cnt; + else + return 0; +} + + +/* Internal support routines for reading/writing compressed coordinates + * sizeofint - calculate smallest number of bits necessary + * to represent a certain integer. + */ +static int +sizeofint(int size) { + unsigned int num = 1; + int num_of_bits = 0; + + while (size >= num && num_of_bits < 32) + { + num_of_bits++; + num <<= 1; + } + return num_of_bits; +} + + +/* + * sizeofints - calculate 'bitsize' of compressed ints + * + * given a number of small unsigned integers and the maximum value + * return the number of bits needed to read or write them with the + * routines encodeints/decodeints. You need this parameter when + * calling those routines. + * (However, in some cases we can just use the variable 'smallidx' + * which is the exact number of bits, and them we dont need to call + * this routine). + */ +static int +sizeofints(int num_of_ints, unsigned int sizes[]) +{ + int i, num; + unsigned int num_of_bytes, num_of_bits, bytes[32], bytecnt, tmp; + num_of_bytes = 1; + bytes[0] = 1; + num_of_bits = 0; + for (i=0; i < num_of_ints; i++) + { + tmp = 0; + for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) + { + tmp = bytes[bytecnt] * sizes[i] + tmp; + bytes[bytecnt] = tmp & 0xff; + tmp >>= 8; + } + while (tmp != 0) + { + bytes[bytecnt++] = tmp & 0xff; + tmp >>= 8; + } + num_of_bytes = bytecnt; + } + num = 1; + num_of_bytes--; + while (bytes[num_of_bytes] >= num) + { + num_of_bits++; + num *= 2; + } + return num_of_bits + num_of_bytes * 8; + +} + + +/* + * encodebits - encode num into buf using the specified number of bits + * + * This routines appends the value of num to the bits already present in + * the array buf. You need to give it the number of bits to use and you had + * better make sure that this number of bits is enough to hold the value. + * Num must also be positive. + */ +static void +encodebits(int buf[], int num_of_bits, int num) +{ + + unsigned int cnt, lastbyte; + int lastbits; + unsigned char * cbuf; + + cbuf = ((unsigned char *)buf) + 3 * sizeof(*buf); + cnt = (unsigned int) buf[0]; + lastbits = buf[1]; + lastbyte =(unsigned int) buf[2]; + while (num_of_bits >= 8) + { + lastbyte = (lastbyte << 8) | ((num >> (num_of_bits -8)) /* & 0xff*/); + cbuf[cnt++] = lastbyte >> lastbits; + num_of_bits -= 8; + } + if (num_of_bits > 0) + { + lastbyte = (lastbyte << num_of_bits) | num; + lastbits += num_of_bits; + if (lastbits >= 8) + { + lastbits -= 8; + cbuf[cnt++] = lastbyte >> lastbits; + } + } + buf[0] = cnt; + buf[1] = lastbits; + buf[2] = lastbyte; + if (lastbits>0) + { + cbuf[cnt] = lastbyte << (8 - lastbits); + } +} + +/* + * encodeints - encode a small set of small integers in compressed format + * + * this routine is used internally by xdr3dfcoord, to encode a set of + * small integers to the buffer for writing to a file. + * Multiplication with fixed (specified maximum) sizes is used to get + * to one big, multibyte integer. Allthough the routine could be + * modified to handle sizes bigger than 16777216, or more than just + * a few integers, this is not done because the gain in compression + * isn't worth the effort. Note that overflowing the multiplication + * or the byte buffer (32 bytes) is unchecked and whould cause bad results. + * THese things are checked in the calling routines, so make sure not + * to remove those checks... + */ + +static void +encodeints(int buf[], int num_of_ints, int num_of_bits, + unsigned int sizes[], unsigned int nums[]) +{ + + int i; + unsigned int bytes[32], num_of_bytes, bytecnt, tmp; + + tmp = nums[0]; + num_of_bytes = 0; + do + { + bytes[num_of_bytes++] = tmp & 0xff; + tmp >>= 8; + } while (tmp != 0); + + for (i = 1; i < num_of_ints; i++) + { + if (nums[i] >= sizes[i]) + { + fprintf(stderr,"(xdrfile error) major breakdown in encodeints - num %u doesn't " + "match size %u\n", nums[i], sizes[i]); + abort(); + } + /* use one step multiply */ + tmp = nums[i]; + for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) + { + tmp = bytes[bytecnt] * sizes[i] + tmp; + bytes[bytecnt] = tmp & 0xff; + tmp >>= 8; + } + while (tmp != 0) + { + bytes[bytecnt++] = tmp & 0xff; + tmp >>= 8; + } + num_of_bytes = bytecnt; + } + if (num_of_bits >= num_of_bytes * 8) + { + for (i = 0; i < num_of_bytes; i++) + { + encodebits(buf, 8, bytes[i]); + } + encodebits(buf, num_of_bits - num_of_bytes * 8, 0); + } + else + { + for (i = 0; i < num_of_bytes-1; i++) + { + encodebits(buf, 8, bytes[i]); + } + encodebits(buf, num_of_bits- (num_of_bytes -1) * 8, bytes[i]); + } +} + + +/* + * decodebits - decode number from buf using specified number of bits + * + * extract the number of bits from the array buf and construct an integer + * from it. Return that value. + * + */ + +static int +decodebits(int buf[], int num_of_bits) +{ + + int cnt, num; + unsigned int lastbits, lastbyte; + unsigned char * cbuf; + int mask = (1 << num_of_bits) -1; + + cbuf = ((unsigned char *)buf) + 3 * sizeof(*buf); + cnt = buf[0]; + lastbits = (unsigned int) buf[1]; + lastbyte = (unsigned int) buf[2]; + + num = 0; + while (num_of_bits >= 8) + { + lastbyte = ( lastbyte << 8 ) | cbuf[cnt++]; + num |= (lastbyte >> lastbits) << (num_of_bits - 8); + num_of_bits -=8; + } + if (num_of_bits > 0) + { + if (lastbits < num_of_bits) + { + lastbits += 8; + lastbyte = (lastbyte << 8) | cbuf[cnt++]; + } + lastbits -= num_of_bits; + num |= (lastbyte >> lastbits) & ((1 << num_of_bits) -1); + } + num &= mask; + buf[0] = cnt; + buf[1] = lastbits; + buf[2] = lastbyte; + return num; +} + +/* + * decodeints - decode 'small' integers from the buf array + * + * this routine is the inverse from encodeints() and decodes the small integers + * written to buf by calculating the remainder and doing divisions with + * the given sizes[]. You need to specify the total number of bits to be + * used from buf in num_of_bits. + * + */ + +static void +decodeints(int buf[], int num_of_ints, int num_of_bits, + unsigned int sizes[], int nums[]) +{ + + int bytes[32]; + int i, j, num_of_bytes, p, num; + + bytes[1] = bytes[2] = bytes[3] = 0; + num_of_bytes = 0; + while (num_of_bits > 8) + { + bytes[num_of_bytes++] = decodebits(buf, 8); + num_of_bits -= 8; + } + if (num_of_bits > 0) + { + bytes[num_of_bytes++] = decodebits(buf, num_of_bits); + } + for (i = num_of_ints-1; i > 0; i--) + { + num = 0; + for (j = num_of_bytes-1; j >=0; j--) + { + num = (num << 8) | bytes[j]; + p = num / sizes[i]; + bytes[j] = p; + num = num - p * sizes[i]; + } + nums[i] = num; + } + nums[0] = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); +} + + +static const int magicints[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 12, 16, 20, 25, 32, 40, 50, 64, + 80, 101, 128, 161, 203, 256, 322, 406, 512, 645, 812, 1024, 1290, + 1625, 2048, 2580, 3250, 4096, 5060, 6501, 8192, 10321, 13003, + 16384, 20642, 26007, 32768, 41285, 52015, 65536,82570, 104031, + 131072, 165140, 208063, 262144, 330280, 416127, 524287, 660561, + 832255, 1048576, 1321122, 1664510, 2097152, 2642245, 3329021, + 4194304, 5284491, 6658042, 8388607, 10568983, 13316085, 16777216 +}; + +#define FIRSTIDX 9 +/* note that magicints[FIRSTIDX-1] == 0 */ +#define LASTIDX (sizeof(magicints) / sizeof(*magicints)) + +/* Compressed coordinate routines - modified from the original + * implementation by Frans v. Hoesel to make them threadsafe. + */ +int +xdrfile_decompress_coord_float(float *ptr, + int *size, + float *precision, + XDRFILE* xfp) +{ + int minint[3], maxint[3], *lip; + int smallidx, minidx, maxidx; + unsigned sizeint[3], sizesmall[3], bitsizeint[3], size3; + int k, *buf1, *buf2, lsize, flag; + int smallnum, smaller, larger, i, is_smaller, run; + float *lfp, inv_precision; + int tmp, *thiscoord, prevcoord[3]; + unsigned int bitsize; + const float* ptrstart = ptr; + + bitsizeint[0] = 0; + bitsizeint[1] = 0; + bitsizeint[2] = 0; + + if(xfp==NULL || ptr==NULL) { + fprintf(stderr, "(xdrfile error) Null pointer issue\n"); + return -1; + } + tmp=xdrfile_read_int(&lsize,1,xfp); + if(tmp==0) { + fprintf(stderr, "(xdrfile error) Size could not be read\n"); + return -1; /* return if we could not read size */ + } + if (*size < lsize) + { + fprintf(stderr, "(xdrfile error) Requested to decompress %d coords, file contains %d\n", + *size, lsize); + return -1; + } + *size = lsize; + size3 = *size * 3; + if(size3>xfp->buf1size) + { + if((xfp->buf1=(int *)malloc(sizeof(int)*size3))==NULL) + { + fprintf(stderr, "(xdrfile error) Cannot allocate memory for decompressing coordinates.\n"); + return -1; + } + xfp->buf1size=size3; + xfp->buf2size=size3*1.2; + if((xfp->buf2=(int *)malloc(sizeof(int)*xfp->buf2size))==NULL) + { + fprintf(stderr, "(xdrfile error) Cannot allocate memory for decompressing coordinates.\n"); + return -1; + } + } + /* Dont bother with compression for three atoms or less */ + if(*size<=9) + { + return xdrfile_read_float(ptr,size3,xfp)/3; + /* return number of coords, not floats */ + } + /* Compression-time if we got here. Read precision first */ + xdrfile_read_float(precision,1,xfp); + + /* avoid repeated pointer dereferencing. */ + buf1=xfp->buf1; + buf2=xfp->buf2; + /* buf2[0-2] are special and do not contain actual data */ + buf2[0] = buf2[1] = buf2[2] = 0; + xdrfile_read_int(minint,3,xfp); + xdrfile_read_int(maxint,3,xfp); + + sizeint[0] = maxint[0] - minint[0]+1; + sizeint[1] = maxint[1] - minint[1]+1; + sizeint[2] = maxint[2] - minint[2]+1; + + /* check if one of the sizes is to big to be multiplied */ + if ((sizeint[0] | sizeint[1] | sizeint[2] ) > 0xffffff) + { + bitsizeint[0] = sizeofint(sizeint[0]); + bitsizeint[1] = sizeofint(sizeint[1]); + bitsizeint[2] = sizeofint(sizeint[2]); + bitsize = 0; /* flag the use of large sizes */ + } + else + { + bitsize = sizeofints(3, sizeint); + } + + if (xdrfile_read_int(&smallidx,1,xfp) == 0) { + fprintf(stderr,"(xdrfile error) Undocumented error 1"); + return 0; /* not sure what has happened here or why we return... */ + } + tmp=smallidx+8; + maxidx = (LASTIDXtmp) ? FIRSTIDX : tmp; + smaller = magicints[tmp] / 2; + smallnum = magicints[smallidx] / 2; + sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx] ; + larger = magicints[maxidx]; + + /* buf2[0] holds the length in bytes */ + + if (xdrfile_read_int(buf2,1,xfp) == 0) { + fprintf(stderr, "(xdrfile error) Undocumented error 2"); + return 0; + } + if (xdrfile_read_opaque((char *)&(buf2[3]),(unsigned int)buf2[0],xfp) == 0) { + fprintf(stderr, "(xdrfile error) Undocumented error 3"); + return 0; + } + buf2[0] = buf2[1] = buf2[2] = 0; + + lfp = ptr; + inv_precision = 1.0 / * precision; + run = 0; + i = 0; + lip = buf1; + while ( i < lsize ) + { + thiscoord = (int *)(lip) + i * 3; + + if (bitsize == 0) + { + thiscoord[0] = decodebits(buf2, bitsizeint[0]); + thiscoord[1] = decodebits(buf2, bitsizeint[1]); + thiscoord[2] = decodebits(buf2, bitsizeint[2]); + } + else + { + decodeints(buf2, 3, bitsize, sizeint, thiscoord); + } + + i++; + thiscoord[0] += minint[0]; + thiscoord[1] += minint[1]; + thiscoord[2] += minint[2]; + + prevcoord[0] = thiscoord[0]; + prevcoord[1] = thiscoord[1]; + prevcoord[2] = thiscoord[2]; + + flag = decodebits(buf2, 1); + is_smaller = 0; + if (flag == 1) + { + run = decodebits(buf2, 5); + is_smaller = run % 3; + run -= is_smaller; + is_smaller--; + } + if ((lfp-ptrstart)+run > size3) + { + fprintf(stderr, "(xdrfile error) Buffer overrun during decompression.\n"); + return 0; + } + if (run > 0) + { + thiscoord += 3; + for (k = 0; k < run; k+=3) + { + decodeints(buf2, 3, smallidx, sizesmall, thiscoord); + i++; + thiscoord[0] += prevcoord[0] - smallnum; + thiscoord[1] += prevcoord[1] - smallnum; + thiscoord[2] += prevcoord[2] - smallnum; + if (k == 0) { + /* interchange first with second atom for better + * compression of water molecules + */ + tmp = thiscoord[0]; thiscoord[0] = prevcoord[0]; + prevcoord[0] = tmp; + tmp = thiscoord[1]; thiscoord[1] = prevcoord[1]; + prevcoord[1] = tmp; + tmp = thiscoord[2]; thiscoord[2] = prevcoord[2]; + prevcoord[2] = tmp; + *lfp++ = prevcoord[0] * inv_precision; + *lfp++ = prevcoord[1] * inv_precision; + *lfp++ = prevcoord[2] * inv_precision; + } else { + prevcoord[0] = thiscoord[0]; + prevcoord[1] = thiscoord[1]; + prevcoord[2] = thiscoord[2]; + } + *lfp++ = thiscoord[0] * inv_precision; + *lfp++ = thiscoord[1] * inv_precision; + *lfp++ = thiscoord[2] * inv_precision; + } + } + else + { + *lfp++ = thiscoord[0] * inv_precision; + *lfp++ = thiscoord[1] * inv_precision; + *lfp++ = thiscoord[2] * inv_precision; + } + smallidx += is_smaller; + if (is_smaller < 0) + { + smallnum = smaller; + + if (smallidx > FIRSTIDX) + { + smaller = magicints[smallidx - 1] /2; + } + else + { + smaller = 0; + } + } + else if (is_smaller > 0) + { + smaller = smallnum; + smallnum = magicints[smallidx] / 2; + } + sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx]; + if (sizesmall[0]==0 || sizesmall[1]==0 || sizesmall[2]==0) + { + fprintf(stderr, "(xdrfile error) Undefined error.\n"); + return 0; + } + } + return *size; +} + +int +xdrfile_compress_coord_float(float *ptr, + int size, + float precision, + XDRFILE* xfp) +{ + int minint[3], maxint[3], mindiff, *lip, diff; + int lint1, lint2, lint3, oldlint1, oldlint2, oldlint3, smallidx; + int minidx, maxidx; + unsigned sizeint[3], sizesmall[3], bitsizeint[3], size3, *luip; + int k, *buf1, *buf2; + int smallnum, smaller, larger, i, j, is_small, is_smaller, run, prevrun; + float *lfp, lf; + int tmp, tmpsum, *thiscoord, prevcoord[3]; + unsigned int tmpcoord[30]; + int errval=1; + unsigned int bitsize; + + if(xfp==NULL) + return -1; + size3=3*size; + + bitsizeint[0] = 0; + bitsizeint[1] = 0; + bitsizeint[2] = 0; + + if(size3>xfp->buf1size) + { + if((xfp->buf1=(int *)malloc(sizeof(int)*size3))==NULL) + { + fprintf(stderr, "(xdrfile error) Cannot allocate memory for compressing coordinates.\n"); + return -1; + } + xfp->buf1size=size3; + xfp->buf2size=size3*1.2; + if((xfp->buf2=(int *)malloc(sizeof(int)*xfp->buf2size))==NULL) + { + fprintf(stderr, "(xdrfile error) Cannot allocate memory for compressing coordinates.\n"); + return -1; + } + } + if(xdrfile_write_int(&size,1,xfp)==0) + return -1; /* return if we could not write size */ + /* Dont bother with compression for three atoms or less */ + if(size<=9) + { + return xdrfile_write_float(ptr,size3,xfp)/3; + /* return number of coords, not floats */ + } + /* Compression-time if we got here. Write precision first */ + if (precision <= 0) + precision = 1000; + xdrfile_write_float(&precision,1,xfp); + /* avoid repeated pointer dereferencing. */ + buf1=xfp->buf1; + buf2=xfp->buf2; + /* buf2[0-2] are special and do not contain actual data */ + buf2[0] = buf2[1] = buf2[2] = 0; + minint[0] = minint[1] = minint[2] = INT_MAX; + maxint[0] = maxint[1] = maxint[2] = INT_MIN; + prevrun = -1; + lfp = ptr; + lip = buf1; + mindiff = INT_MAX; + oldlint1 = oldlint2 = oldlint3 = 0; + while(lfp < ptr + size3 ) + { + /* find nearest integer */ + if (*lfp >= 0.0) + lf = *lfp * precision + 0.5; + else + lf = *lfp * precision - 0.5; + if (fabs(lf) > INT_MAX-2) + { + /* scaling would cause overflow */ + fprintf(stderr, "(xdrfile error) Internal overflow compressing coordinates.\n"); + errval=0; + } + lint1 = lf; + if (lint1 < minint[0]) minint[0] = lint1; + if (lint1 > maxint[0]) maxint[0] = lint1; + *lip++ = lint1; + lfp++; + if (*lfp >= 0.0) + lf = *lfp * precision + 0.5; + else + lf = *lfp * precision - 0.5; + if (fabs(lf) > INT_MAX-2) + { + /* scaling would cause overflow */ + fprintf(stderr, "(xdrfile error) Internal overflow compressing coordinates.\n"); + errval=0; + } + lint2 = lf; + if (lint2 < minint[1]) minint[1] = lint2; + if (lint2 > maxint[1]) maxint[1] = lint2; + *lip++ = lint2; + lfp++; + if (*lfp >= 0.0) + lf = *lfp * precision + 0.5; + else + lf = *lfp * precision - 0.5; + if (fabs(lf) > INT_MAX-2) + { + errval=0; + } + lint3 = lf; + if (lint3 < minint[2]) minint[2] = lint3; + if (lint3 > maxint[2]) maxint[2] = lint3; + *lip++ = lint3; + lfp++; + diff = abs(oldlint1-lint1)+abs(oldlint2-lint2)+abs(oldlint3-lint3); + if (diff < mindiff && lfp > ptr + 3) + mindiff = diff; + oldlint1 = lint1; + oldlint2 = lint2; + oldlint3 = lint3; + } + xdrfile_write_int(minint,3,xfp); + xdrfile_write_int(maxint,3,xfp); + + if ((float)maxint[0] - (float)minint[0] >= INT_MAX-2 || + (float)maxint[1] - (float)minint[1] >= INT_MAX-2 || + (float)maxint[2] - (float)minint[2] >= INT_MAX-2) { + /* turning value in unsigned by subtracting minint + * would cause overflow + */ + fprintf(stderr, "(xdrfile error) Internal overflow compressing coordinates.\n"); + errval=0; + } + sizeint[0] = maxint[0] - minint[0]+1; + sizeint[1] = maxint[1] - minint[1]+1; + sizeint[2] = maxint[2] - minint[2]+1; + + /* check if one of the sizes is to big to be multiplied */ + if ((sizeint[0] | sizeint[1] | sizeint[2] ) > 0xffffff) + { + bitsizeint[0] = sizeofint(sizeint[0]); + bitsizeint[1] = sizeofint(sizeint[1]); + bitsizeint[2] = sizeofint(sizeint[2]); + bitsize = 0; /* flag the use of large sizes */ + } + else + { + bitsize = sizeofints(3, sizeint); + } + lip = buf1; + luip = (unsigned int *) buf1; + smallidx = FIRSTIDX; + while (smallidx < LASTIDX && magicints[smallidx] < mindiff) + { + smallidx++; + } + xdrfile_write_int(&smallidx,1,xfp); + tmp=smallidx+8; + maxidx = (LASTIDXtmp) ? FIRSTIDX : tmp; + smaller = magicints[tmp] / 2; + smallnum = magicints[smallidx] / 2; + sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx]; + larger = magicints[maxidx] / 2; + i = 0; + while (i < size) + { + is_small = 0; + thiscoord = (int *)(luip) + i * 3; + if (smallidx < maxidx && i >= 1 && + abs(thiscoord[0] - prevcoord[0]) < larger && + abs(thiscoord[1] - prevcoord[1]) < larger && + abs(thiscoord[2] - prevcoord[2]) < larger) { + is_smaller = 1; + } + else if (smallidx > minidx) + { + is_smaller = -1; + } + else + { + is_smaller = 0; + } + if (i + 1 < size) + { + if (abs(thiscoord[0] - thiscoord[3]) < smallnum && + abs(thiscoord[1] - thiscoord[4]) < smallnum && + abs(thiscoord[2] - thiscoord[5]) < smallnum) + { + /* interchange first with second atom for better + * compression of water molecules + */ + tmp = thiscoord[0]; thiscoord[0] = thiscoord[3]; + thiscoord[3] = tmp; + tmp = thiscoord[1]; thiscoord[1] = thiscoord[4]; + thiscoord[4] = tmp; + tmp = thiscoord[2]; thiscoord[2] = thiscoord[5]; + thiscoord[5] = tmp; + is_small = 1; + } + } + tmpcoord[0] = thiscoord[0] - minint[0]; + tmpcoord[1] = thiscoord[1] - minint[1]; + tmpcoord[2] = thiscoord[2] - minint[2]; + if (bitsize == 0) + { + encodebits(buf2, bitsizeint[0], tmpcoord[0]); + encodebits(buf2, bitsizeint[1], tmpcoord[1]); + encodebits(buf2, bitsizeint[2], tmpcoord[2]); + } + else + { + encodeints(buf2, 3, bitsize, sizeint, tmpcoord); + } + prevcoord[0] = thiscoord[0]; + prevcoord[1] = thiscoord[1]; + prevcoord[2] = thiscoord[2]; + thiscoord = thiscoord + 3; + i++; + + run = 0; + if (is_small == 0 && is_smaller == -1) + is_smaller = 0; + while (is_small && run < 8*3) + { + tmpsum=0; + for(j=0;j<3;j++) + { + tmp=thiscoord[j] - prevcoord[j]; + tmpsum+=tmp*tmp; + } + if (is_smaller == -1 && tmpsum >= smaller * smaller) + { + is_smaller = 0; + } + + tmpcoord[run++] = thiscoord[0] - prevcoord[0] + smallnum; + tmpcoord[run++] = thiscoord[1] - prevcoord[1] + smallnum; + tmpcoord[run++] = thiscoord[2] - prevcoord[2] + smallnum; + + prevcoord[0] = thiscoord[0]; + prevcoord[1] = thiscoord[1]; + prevcoord[2] = thiscoord[2]; + + i++; + thiscoord = thiscoord + 3; + is_small = 0; + if (i < size && + abs(thiscoord[0] - prevcoord[0]) < smallnum && + abs(thiscoord[1] - prevcoord[1]) < smallnum && + abs(thiscoord[2] - prevcoord[2]) < smallnum) + { + is_small = 1; + } + } + if (run != prevrun || is_smaller != 0) + { + prevrun = run; + encodebits(buf2, 1, 1); /* flag the change in run-length */ + encodebits(buf2, 5, run+is_smaller+1); + } + else + { + encodebits(buf2, 1, 0); /* flag the fact that runlength did not change */ + } + for (k=0; k < run; k+=3) + { + encodeints(buf2, 3, smallidx, sizesmall, &tmpcoord[k]); + } + if (is_smaller != 0) + { + smallidx += is_smaller; + if (is_smaller < 0) + { + smallnum = smaller; + smaller = magicints[smallidx-1] / 2; + } + else + { + smaller = smallnum; + smallnum = magicints[smallidx] / 2; + } + sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx]; + } + } + if (buf2[1] != 0) buf2[0]++; + xdrfile_write_int(buf2,1,xfp); /* buf2[0] holds the length in bytes */ + tmp=xdrfile_write_opaque((char *)&(buf2[3]),(unsigned int)buf2[0],xfp); + if(tmp==(unsigned int)buf2[0]) + return size; + else + return -1; +} + + +int +xdrfile_decompress_coord_double(double *ptr, + int *size, + double *precision, + XDRFILE* xfp) +{ + int minint[3], maxint[3], *lip; + int smallidx, minidx, maxidx; + unsigned sizeint[3], sizesmall[3], bitsizeint[3], size3; + int k, *buf1, *buf2, lsize, flag; + int smallnum, smaller, larger, i, is_smaller, run; + double *lfp, inv_precision; + float float_prec, tmpdata[30]; + int tmp, *thiscoord, prevcoord[3]; + unsigned int bitsize; + + bitsizeint[0] = 0; + bitsizeint[1] = 0; + bitsizeint[2] = 0; + + if(xfp==NULL || ptr==NULL) + return -1; + tmp=xdrfile_read_int(&lsize,1,xfp); + if(tmp==0) + return -1; /* return if we could not read size */ + if (*size < lsize) + { + fprintf(stderr, "(xdrfile error) Requested to decompress %d coords, file contains %d\n", + *size, lsize); + return -1; + } + *size = lsize; + size3 = *size * 3; + if(size3>xfp->buf1size) + { + if((xfp->buf1=(int *)malloc(sizeof(int)*size3))==NULL) + { + fprintf(stderr, "(xdrfile error) Cannot allocate memory for decompression coordinates.\n"); + return -1; + } + xfp->buf1size=size3; + xfp->buf2size=size3*1.2; + if((xfp->buf2=(int *)malloc(sizeof(int)*xfp->buf2size))==NULL) + { + fprintf(stderr, "(xdrfile error) Cannot allocate memory for decompressing coordinates.\n"); + return -1; + } + } + /* Dont bother with compression for three atoms or less */ + if(*size<=9) + { + tmp=xdrfile_read_float(tmpdata,size3,xfp); + for(i=0;i<9*3;i++) + ptr[i]=tmpdata[i]; + return tmp/3; + /* return number of coords, not floats */ + } + /* Compression-time if we got here. Read precision first */ + xdrfile_read_float(&float_prec,1,xfp); + *precision=float_prec; + /* avoid repeated pointer dereferencing. */ + buf1=xfp->buf1; + buf2=xfp->buf2; + /* buf2[0-2] are special and do not contain actual data */ + buf2[0] = buf2[1] = buf2[2] = 0; + xdrfile_read_int(minint,3,xfp); + xdrfile_read_int(maxint,3,xfp); + + sizeint[0] = maxint[0] - minint[0]+1; + sizeint[1] = maxint[1] - minint[1]+1; + sizeint[2] = maxint[2] - minint[2]+1; + + /* check if one of the sizes is to big to be multiplied */ + if ((sizeint[0] | sizeint[1] | sizeint[2] ) > 0xffffff) + { + bitsizeint[0] = sizeofint(sizeint[0]); + bitsizeint[1] = sizeofint(sizeint[1]); + bitsizeint[2] = sizeofint(sizeint[2]); + bitsize = 0; /* flag the use of large sizes */ + } + else + { + bitsize = sizeofints(3, sizeint); + } + + if (xdrfile_read_int(&smallidx,1,xfp) == 0) + return 0; + tmp=smallidx+8; + maxidx = (LASTIDXtmp) ? FIRSTIDX : tmp; + smaller = magicints[tmp] / 2; + smallnum = magicints[smallidx] / 2; + sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx] ; + larger = magicints[maxidx]; + + /* buf2[0] holds the length in bytes */ + + if (xdrfile_read_int(buf2,1,xfp) == 0) + return 0; + if (xdrfile_read_opaque((char *)&(buf2[3]),(unsigned int)buf2[0],xfp) == 0) + return 0; + buf2[0] = buf2[1] = buf2[2] = 0; + + lfp = ptr; + inv_precision = 1.0 / * precision; + run = 0; + i = 0; + lip = buf1; + while ( i < lsize ) + { + thiscoord = (int *)(lip) + i * 3; + + if (bitsize == 0) + { + thiscoord[0] = decodebits(buf2, bitsizeint[0]); + thiscoord[1] = decodebits(buf2, bitsizeint[1]); + thiscoord[2] = decodebits(buf2, bitsizeint[2]); + } else { + decodeints(buf2, 3, bitsize, sizeint, thiscoord); + } + + i++; + thiscoord[0] += minint[0]; + thiscoord[1] += minint[1]; + thiscoord[2] += minint[2]; + + prevcoord[0] = thiscoord[0]; + prevcoord[1] = thiscoord[1]; + prevcoord[2] = thiscoord[2]; + + flag = decodebits(buf2, 1); + is_smaller = 0; + if (flag == 1) + { + run = decodebits(buf2, 5); + is_smaller = run % 3; + run -= is_smaller; + is_smaller--; + } + if (run > 0) + { + thiscoord += 3; + for (k = 0; k < run; k+=3) + { + decodeints(buf2, 3, smallidx, sizesmall, thiscoord); + i++; + thiscoord[0] += prevcoord[0] - smallnum; + thiscoord[1] += prevcoord[1] - smallnum; + thiscoord[2] += prevcoord[2] - smallnum; + if (k == 0) + { + /* interchange first with second atom for better + * compression of water molecules + */ + tmp = thiscoord[0]; thiscoord[0] = prevcoord[0]; + prevcoord[0] = tmp; + tmp = thiscoord[1]; thiscoord[1] = prevcoord[1]; + prevcoord[1] = tmp; + tmp = thiscoord[2]; thiscoord[2] = prevcoord[2]; + prevcoord[2] = tmp; + *lfp++ = prevcoord[0] * inv_precision; + *lfp++ = prevcoord[1] * inv_precision; + *lfp++ = prevcoord[2] * inv_precision; + } + else + { + prevcoord[0] = thiscoord[0]; + prevcoord[1] = thiscoord[1]; + prevcoord[2] = thiscoord[2]; + } + *lfp++ = thiscoord[0] * inv_precision; + *lfp++ = thiscoord[1] * inv_precision; + *lfp++ = thiscoord[2] * inv_precision; + } + } else { + *lfp++ = thiscoord[0] * inv_precision; + *lfp++ = thiscoord[1] * inv_precision; + *lfp++ = thiscoord[2] * inv_precision; + } + smallidx += is_smaller; + if (is_smaller < 0) { + smallnum = smaller; + if (smallidx > FIRSTIDX) { + smaller = magicints[smallidx - 1] /2; + } else { + smaller = 0; + } + } else if (is_smaller > 0) { + smaller = smallnum; + smallnum = magicints[smallidx] / 2; + } + sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx] ; + } + return *size; +} + +int +xdrfile_compress_coord_double(double *ptr, + int size, + double precision, + XDRFILE* xfp) +{ + int minint[3], maxint[3], mindiff, *lip, diff; + int lint1, lint2, lint3, oldlint1, oldlint2, oldlint3, smallidx; + int minidx, maxidx; + unsigned sizeint[3], sizesmall[3], bitsizeint[3], size3, *luip; + int k, *buf1, *buf2; + int smallnum, smaller, larger, i, j, is_small, is_smaller, run, prevrun; + double *lfp; + float float_prec, lf,tmpdata[30]; + int tmp, tmpsum, *thiscoord, prevcoord[3]; + unsigned int tmpcoord[30]; + int errval=1; + unsigned int bitsize; + + bitsizeint[0] = 0; + bitsizeint[1] = 0; + bitsizeint[2] = 0; + + if(xfp==NULL) + return -1; + size3=3*size; + if(size3>xfp->buf1size) { + if((xfp->buf1=(int *)malloc(sizeof(int)*size3))==NULL) { + fprintf(stderr, "(xdrfile error) Cannot allocate memory for compressing coordinates.\n"); + return -1; + } + xfp->buf1size=size3; + xfp->buf2size=size3*1.2; + if((xfp->buf2=(int *)malloc(sizeof(int)*xfp->buf2size))==NULL) { + fprintf(stderr, "(xdrfile error) Cannot allocate memory for compressing coordinates.\n"); + return -1; + } + } + if(xdrfile_write_int(&size,1,xfp)==0) + return -1; /* return if we could not write size */ + /* Dont bother with compression for three atoms or less */ + if(size<=9) { + for(i=0;i<9*3;i++) + tmpdata[i]=ptr[i]; + return xdrfile_write_float(tmpdata,size3,xfp)/3; + /* return number of coords, not floats */ + } + /* Compression-time if we got here. Write precision first */ + if (precision <= 0) + precision = 1000; + float_prec=precision; + xdrfile_write_float(&float_prec,1,xfp); + /* avoid repeated pointer dereferencing. */ + buf1=xfp->buf1; + buf2=xfp->buf2; + /* buf2[0-2] are special and do not contain actual data */ + buf2[0] = buf2[1] = buf2[2] = 0; + minint[0] = minint[1] = minint[2] = INT_MAX; + maxint[0] = maxint[1] = maxint[2] = INT_MIN; + prevrun = -1; + lfp = ptr; + lip = buf1; + mindiff = INT_MAX; + oldlint1 = oldlint2 = oldlint3 = 0; + while(lfp < ptr + size3 ) { + /* find nearest integer */ + if (*lfp >= 0.0) + lf = (float)*lfp * float_prec + 0.5; + else + lf = (float)*lfp * float_prec - 0.5; + if (fabs(lf) > INT_MAX-2) { + /* scaling would cause overflow */ + fprintf(stderr, "(xdrfile error) Internal overflow compressing coordinates.\n"); + errval=0; + } + lint1 = lf; + if (lint1 < minint[0]) minint[0] = lint1; + if (lint1 > maxint[0]) maxint[0] = lint1; + *lip++ = lint1; + lfp++; + if (*lfp >= 0.0) + lf = (float)*lfp * float_prec + 0.5; + else + lf = (float)*lfp * float_prec - 0.5; + if (fabs(lf) > INT_MAX-2) { + /* scaling would cause overflow */ + fprintf(stderr, "(xdrfile error) Internal overflow compressing coordinates.\n"); + errval=0; + } + lint2 = lf; + if (lint2 < minint[1]) minint[1] = lint2; + if (lint2 > maxint[1]) maxint[1] = lint2; + *lip++ = lint2; + lfp++; + if (*lfp >= 0.0) + lf = (float)*lfp * float_prec + 0.5; + else + lf = (float)*lfp * float_prec - 0.5; + if (fabs(lf) > INT_MAX-2) { + errval=0; + } + lint3 = lf; + if (lint3 < minint[2]) minint[2] = lint3; + if (lint3 > maxint[2]) maxint[2] = lint3; + *lip++ = lint3; + lfp++; + diff = abs(oldlint1-lint1)+abs(oldlint2-lint2)+abs(oldlint3-lint3); + if (diff < mindiff && lfp > ptr + 3) + mindiff = diff; + oldlint1 = lint1; + oldlint2 = lint2; + oldlint3 = lint3; + } + xdrfile_write_int(minint,3,xfp); + xdrfile_write_int(maxint,3,xfp); + + if ((float)maxint[0] - (float)minint[0] >= INT_MAX-2 || + (float)maxint[1] - (float)minint[1] >= INT_MAX-2 || + (float)maxint[2] - (float)minint[2] >= INT_MAX-2) { + /* turning value in unsigned by subtracting minint + * would cause overflow + */ + fprintf(stderr, "(xdrfile error) Internal overflow compressing coordinates.\n"); + errval=0; + } + sizeint[0] = maxint[0] - minint[0]+1; + sizeint[1] = maxint[1] - minint[1]+1; + sizeint[2] = maxint[2] - minint[2]+1; + + /* check if one of the sizes is to big to be multiplied */ + if ((sizeint[0] | sizeint[1] | sizeint[2] ) > 0xffffff) { + bitsizeint[0] = sizeofint(sizeint[0]); + bitsizeint[1] = sizeofint(sizeint[1]); + bitsizeint[2] = sizeofint(sizeint[2]); + bitsize = 0; /* flag the use of large sizes */ + } else { + bitsize = sizeofints(3, sizeint); + } + lip = buf1; + luip = (unsigned int *) buf1; + smallidx = FIRSTIDX; + while (smallidx < LASTIDX && magicints[smallidx] < mindiff) { + smallidx++; + } + xdrfile_write_int(&smallidx,1,xfp); + tmp=smallidx+8; + maxidx = (LASTIDXtmp) ? FIRSTIDX : tmp; + smaller = magicints[tmp] / 2; + smallnum = magicints[smallidx] / 2; + sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx]; + larger = magicints[maxidx] / 2; + i = 0; + while (i < size) { + is_small = 0; + thiscoord = (int *)(luip) + i * 3; + if (smallidx < maxidx && i >= 1 && + abs(thiscoord[0] - prevcoord[0]) < larger && + abs(thiscoord[1] - prevcoord[1]) < larger && + abs(thiscoord[2] - prevcoord[2]) < larger) { + is_smaller = 1; + } else if (smallidx > minidx) { + is_smaller = -1; + } else { + is_smaller = 0; + } + if (i + 1 < size) { + if (abs(thiscoord[0] - thiscoord[3]) < smallnum && + abs(thiscoord[1] - thiscoord[4]) < smallnum && + abs(thiscoord[2] - thiscoord[5]) < smallnum) { + /* interchange first with second atom for better + * compression of water molecules + */ + tmp = thiscoord[0]; thiscoord[0] = thiscoord[3]; + thiscoord[3] = tmp; + tmp = thiscoord[1]; thiscoord[1] = thiscoord[4]; + thiscoord[4] = tmp; + tmp = thiscoord[2]; thiscoord[2] = thiscoord[5]; + thiscoord[5] = tmp; + is_small = 1; + } + } + tmpcoord[0] = thiscoord[0] - minint[0]; + tmpcoord[1] = thiscoord[1] - minint[1]; + tmpcoord[2] = thiscoord[2] - minint[2]; + if (bitsize == 0) { + encodebits(buf2, bitsizeint[0], tmpcoord[0]); + encodebits(buf2, bitsizeint[1], tmpcoord[1]); + encodebits(buf2, bitsizeint[2], tmpcoord[2]); + } else { + encodeints(buf2, 3, bitsize, sizeint, tmpcoord); + } + prevcoord[0] = thiscoord[0]; + prevcoord[1] = thiscoord[1]; + prevcoord[2] = thiscoord[2]; + thiscoord = thiscoord + 3; + i++; + + run = 0; + if (is_small == 0 && is_smaller == -1) + is_smaller = 0; + while (is_small && run < 8*3) { + tmpsum=0; + for(j=0;j<3;j++) { + tmp=thiscoord[j] - prevcoord[j]; + tmpsum+=tmp*tmp; + } + if (is_smaller == -1 && tmpsum >= smaller * smaller) { + is_smaller = 0; + } + + tmpcoord[run++] = thiscoord[0] - prevcoord[0] + smallnum; + tmpcoord[run++] = thiscoord[1] - prevcoord[1] + smallnum; + tmpcoord[run++] = thiscoord[2] - prevcoord[2] + smallnum; + + prevcoord[0] = thiscoord[0]; + prevcoord[1] = thiscoord[1]; + prevcoord[2] = thiscoord[2]; + + i++; + thiscoord = thiscoord + 3; + is_small = 0; + if (i < size && + abs(thiscoord[0] - prevcoord[0]) < smallnum && + abs(thiscoord[1] - prevcoord[1]) < smallnum && + abs(thiscoord[2] - prevcoord[2]) < smallnum) { + is_small = 1; + } + } + if (run != prevrun || is_smaller != 0) { + prevrun = run; + encodebits(buf2, 1, 1); /* flag the change in run-length */ + encodebits(buf2, 5, run+is_smaller+1); + } else { + encodebits(buf2, 1, 0); /* flag the fact that runlength did not change */ + } + for (k=0; k < run; k+=3) { + encodeints(buf2, 3, smallidx, sizesmall, &tmpcoord[k]); + } + if (is_smaller != 0) { + smallidx += is_smaller; + if (is_smaller < 0) { + smallnum = smaller; + smaller = magicints[smallidx-1] / 2; + } else { + smaller = smallnum; + smallnum = magicints[smallidx] / 2; + } + sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx]; + } + } + if (buf2[1] != 0) buf2[0]++; + xdrfile_write_int(buf2,1,xfp); /* buf2[0] holds the length in bytes */ + tmp=xdrfile_write_opaque((char *)&(buf2[3]),(unsigned int)buf2[0],xfp); + if(tmp==(unsigned int)buf2[0]) + return size; + else + return -1; +} + + +/* Dont try do document Fortran interface, since + * Doxygen barfs at the F77_FUNC macro + */ +#ifndef DOXYGEN + +/************************************************************* + * Fortran77 interface for reading/writing portable data * + * The routine are not threadsafe when called from Fortran * + * (as they are when called from C) unless you compile with * + * this file with posix thread support. * + * Note that these are not multithread-safe. * + *************************************************************/ +#define MAX_FORTRAN_XDR 1024 +static XDRFILE *f77xdr[MAX_FORTRAN_XDR]; /* array of file handles */ +static int f77init = 1; /* zero array first time */ + +/* internal to this file: C<-->Fortran string conversion */ +static int ftocstr(char *dest, int dest_len, char *src, int src_len); +static int ctofstr(char *dest, int dest_len, char *src); + + +void +F77_FUNC(xdropen,XDROPEN)(int *fid, char *filename, char *mode, + int fn_len, int mode_len) +{ + char cfilename[512]; + char cmode[5]; + int i; + + /* zero array at first invocation */ + if(f77init) { + for(i=0;i= src && *p == ' ' ); + srclen = p - src + 1; + destlen--; + dest[0] = 0; + if (srclen > destlen) + return 1; + while (srclen--) + (*dest++ = *src++); + *dest = '\0'; + return 0; +} + + +static int ctofstr(char *dest, int destlen, char *src) +{ + while (destlen && *src) { + *dest++ = *src++; + destlen--; + } + while (destlen--) + *dest++ = ' '; + return 0; +} + + +void +F77_FUNC(xdrrstring,XDRRSTRING)(int *fid, char *str, int *ret, int len) +{ + char *cstr; + + if((cstr=(char*)malloc((len+1)*sizeof(char)))==NULL) { + *ret = 0; + return; + } + if (ftocstr(cstr, len+1, str, len)) { + *ret = 0; + free(cstr); + return; + } + + *ret = xdrfile_read_string(cstr, len+1,f77xdr[*fid]); + ctofstr( str, len , cstr); + free(cstr); +} + +void +F77_FUNC(xdrwstring,XDRWSTRING)(int *fid, char *str, int *ret, int len) +{ + char *cstr; + + if((cstr=(char*)malloc((len+1)*sizeof(char)))==NULL) { + *ret = 0; + return; + } + if (ftocstr(cstr, len+1, str, len)) { + *ret = 0; + free(cstr); + return; + } + + *ret = xdrfile_write_string(cstr, f77xdr[*fid]); + ctofstr( str, len , cstr); + free(cstr); +} + +void +F77_FUNC(xdrropaque,XDRROPAQUE)(int *fid, char *data, int *ndata, int *ret) +{ + *ret = xdrfile_read_opaque(data,*ndata,f77xdr[*fid]); +} + +void +F77_FUNC(xdrwopaque,XDRWOPAQUE)(int *fid, char *data, int *ndata, int *ret) +{ + *ret = xdrfile_write_opaque(data,*ndata,f77xdr[*fid]); +} + + +/* Write single-precision compressed 3d coordinates */ +void +F77_FUNC(xdrccs,XDRCCS)(int *fid, float *data, int *ncoord, + float *precision, int *ret) +{ + *ret = xdrfile_compress_coord_float(data,*ncoord,*precision,f77xdr[*fid]); +} + + +/* Read single-precision compressed 3d coordinates */ +void +F77_FUNC(xdrdcs,XDRDCS)(int *fid, float *data, int *ncoord, + float *precision, int *ret) +{ + *ret = xdrfile_decompress_coord_float(data,ncoord,precision,f77xdr[*fid]); +} + + +/* Write compressed 3d coordinates from double precision data */ +void +F77_FUNC(xdrccd,XDRCCD)(int *fid, double *data, int *ncoord, + double *precision, int *ret) +{ + *ret = xdrfile_compress_coord_double(data,*ncoord,*precision,f77xdr[*fid]); +} + +/* Read compressed 3d coordinates into double precision data */ +void +F77_FUNC(xddcd,XDRDCD)(int *fid, double *data, int *ncoord, + double *precision, int *ret) +{ + *ret = xdrfile_decompress_coord_double(data,ncoord,precision,f77xdr[*fid]); +} + + + + + + + +#endif /* DOXYGEN */ + +/************************************************************* + * End of higher-level routines - dont change things below! * + *************************************************************/ + + + + + + + + + + + + + + + + + + + + +/************************************************************* + * The rest of this file contains our own implementation * + * of the XDR calls in case you are compiling without them. * + * You do NOT want to change things here since it would make * + * things incompatible with the standard RPC/XDR routines. * + *************************************************************/ +#ifndef HAVE_RPC_XDR_H + +/* + * What follows is a modified version of the Sun XDR code. For reference + * we include their copyright and license: + * + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* INT_MAX is defined in limits.h according to ANSI C */ +#if (INT_MAX > 2147483647) +# error Error: Cannot use builtin XDR support when size of int +# error is larger than 4 bytes. Use your system XDR libraries +# error instead, or modify the source code in xdrfile.c +#endif /* Check for 4 byte int type */ + + + + + +typedef int (*xdrproc_t) (XDR *, void *,...); + +#define xdr_getlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) +#define xdr_putlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) +#define xdr_getbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) +#define xdr_putbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) + +#define BYTES_PER_XDR_UNIT 4 +static char xdr_zero[BYTES_PER_XDR_UNIT] = {0, 0, 0, 0}; + +static int32_t +xdr_swapbytes(int32_t x) +{ + int32_t y,i; + char *px=(char *)&x; + char *py=(char *)&y; + + for(i=0;i<4;i++) + py[i]=px[3-i]; + + return y; +} + +static int32_t +xdr_htonl(int32_t x) +{ + int s=0x1234; + if( *((char *)&s)==(char)0x34) { + /* smallendian,swap bytes */ + return xdr_swapbytes(x); + } else { + /* bigendian, do nothing */ + return x; + } +} + +static int32_t +xdr_ntohl(int x) +{ + int s=0x1234; + if( *((char *)&s)==(char)0x34) { + /* smallendian, swap bytes */ + return xdr_swapbytes(x); + } else { + /* bigendian, do nothing */ + return x; + } +} + +static int +xdr_int (XDR *xdrs, int *ip) +{ + int32_t i32; + + switch (xdrs->x_op) + { + case XDR_ENCODE: + i32 = (int32_t) *ip; + return xdr_putlong (xdrs, &i32); + + case XDR_DECODE: + if (!xdr_getlong (xdrs, &i32)) + { + return 0; + } + *ip = (int) i32; + case XDR_FREE: + return 1; + } + return 0; +} + +static int +xdr_u_int (XDR *xdrs, unsigned int *up) +{ + uint32_t ui32; + + switch (xdrs->x_op) + { + case XDR_ENCODE: + ui32 = (uint32_t) * up; + return xdr_putlong (xdrs, (int32_t *)&ui32); + + case XDR_DECODE: + if (!xdr_getlong (xdrs, (int32_t *)&ui32)) + { + return 0; + } + *up = (uint32_t) ui32; + case XDR_FREE: + return 1; + } + return 0; +} + +static int +xdr_short (XDR *xdrs, short *sp) +{ + int32_t i32; + + switch (xdrs->x_op) + { + case XDR_ENCODE: + i32 = (int32_t) *sp; + return xdr_putlong (xdrs, &i32); + + case XDR_DECODE: + if (!xdr_getlong (xdrs, &i32)) + { + return 0; + } + *sp = (short) i32; + return 1; + + case XDR_FREE: + return 1; + } + return 0; +} + +static int +xdr_u_short (XDR *xdrs, unsigned short *sp) +{ + uint32_t ui32; + + switch (xdrs->x_op) + { + case XDR_ENCODE: + ui32 = (uint32_t) *sp; + return xdr_putlong (xdrs, (int32_t *)&ui32); + + case XDR_DECODE: + if (!xdr_getlong (xdrs, (int32_t *)&ui32)) + { + return 0; + } + *sp = (unsigned short) ui32; + return 1; + + case XDR_FREE: + return 1; + } + return 0; +} + +static int +xdr_char (XDR *xdrs, char *cp) +{ + int i; + + i = (*cp); + if (!xdr_int (xdrs, &i)) + { + return 0; + } + *cp = i; + return 1; +} + +static int +xdr_u_char (XDR *xdrs, unsigned char *cp) +{ + unsigned int u; + + u = (*cp); + if (!xdr_u_int (xdrs, &u)) + { + return 0; + } + *cp = u; + return 1; +} + +/* + * XDR opaque data + * Allows the specification of a fixed size sequence of opaque bytes. + * cp points to the opaque object and cnt gives the byte length. + */ +static int +xdr_opaque (XDR *xdrs, char *cp, unsigned int cnt) +{ + unsigned int rndup; + static char crud[BYTES_PER_XDR_UNIT]; + + /* + * if no data we are done + */ + if (cnt == 0) + return 1; + + /* + * round byte count to full xdr units + */ + rndup = cnt % BYTES_PER_XDR_UNIT; + if (rndup > 0) + rndup = BYTES_PER_XDR_UNIT - rndup; + + switch (xdrs->x_op) + { + case XDR_DECODE: + if (!xdr_getbytes (xdrs, cp, cnt)) + { + return 0; + } + if (rndup == 0) + return 1; + return xdr_getbytes (xdrs, (char *)crud, rndup); + + case XDR_ENCODE: + if (!xdr_putbytes (xdrs, cp, cnt)) + { + return 0; + } + if (rndup == 0) + return 1; + return xdr_putbytes (xdrs, xdr_zero, rndup); + + case XDR_FREE: + return 1; + } +#undef BYTES_PER_XDR_UNIT + return 0; +} + + +/* + * XDR null terminated ASCII strings + */ +static int +xdr_string (XDR *xdrs, char **cpp, unsigned int maxsize) +{ + char *sp = *cpp; /* sp is the actual string pointer */ + unsigned int size; + unsigned int nodesize; + + /* + * first deal with the length since xdr strings are counted-strings + */ + switch (xdrs->x_op) + { + case XDR_FREE: + if (sp == NULL) + { + return 1; /* already free */ + } + /* fall through... */ + case XDR_ENCODE: + if (sp == NULL) + return 0; + size = strlen (sp); + break; + case XDR_DECODE: + break; + } + if (!xdr_u_int (xdrs, &size)) + { + return 0; + } + if (size > maxsize) + { + return 0; + } + nodesize = size + 1; + + /* + * now deal with the actual bytes + */ + switch (xdrs->x_op) + { + case XDR_DECODE: + if (nodesize == 0) + { + return 1; + } + if (sp == NULL) + *cpp = sp = (char *) malloc (nodesize); + if (sp == NULL) + { + (void) fputs ("xdr_string: out of memory\n", stderr); + return 0; + } + sp[size] = 0; + /* fall into ... */ + + case XDR_ENCODE: + return xdr_opaque (xdrs, sp, size); + + case XDR_FREE: + free (sp); + *cpp = NULL; + return 1; + } + return 0; +} + + + +/* Floating-point stuff */ + +static int +xdr_float(XDR *xdrs, float *fp) +{ + switch (xdrs->x_op) { + + case XDR_ENCODE: + if (sizeof(float) == sizeof(int32_t)) + return (xdr_putlong(xdrs, (int32_t *)fp)); + else if (sizeof(float) == sizeof(int)) { + int32_t tmp = *(int *)fp; + return (xdr_putlong(xdrs, &tmp)); + } + break; + + case XDR_DECODE: + if (sizeof(float) == sizeof(int32_t)) + return (xdr_getlong(xdrs, (int32_t *)fp)); + else if (sizeof(float) == sizeof(int)) { + int32_t tmp; + if (xdr_getlong(xdrs, &tmp)) { + *(int *)fp = tmp; + return (1); + } + } + break; + + case XDR_FREE: + return (1); + } + return (0); +} + + +static int +xdr_double(XDR *xdrs, double *dp) +{ + /* Gromacs detects floating-point stuff at compile time, which is faster */ +#ifdef GROMACS +# ifndef FLOAT_FORMAT_IEEE754 +# error non-IEEE floating point system, or you defined GROMACS yourself... +# endif + int LSW; +# ifdef IEEE754_BIG_ENDIAN_WORD_ORDER + int LSW=1; +# else + int LSW=0; +# endif /* Big endian word order */ +#else + /* Outside Gromacs we rely on dynamic detection of FP order. */ + int LSW; /* Least significant fp word */ + + double x=0.987654321; /* Just a number */ + unsigned char ix = *((char *)&x); + + /* Possible representations in IEEE double precision: + * (S=small endian, B=big endian) + * + * Byte order, Word order, Hex + * S S b8 56 0e 3c dd 9a ef 3f + * B S 3c 0e 56 b8 3f ef 9a dd + * S B dd 9a ef 3f b8 56 0e 3c + * B B 3f ef 9a dd 3c 0e 56 b8 + */ + if(ix==0xdd || ix==0x3f) + LSW=1; /* Big endian word order */ + else if(ix==0xb8 || ix==0x3c) + LSW=0; /* Small endian word order */ + else { /* Catch strange errors */ + fprintf(stderr,"Cannot detect floating-point word order.\n" + "Do you have a non-IEEE system?\n" + "Use system XDR libraries or fix xdr_double().\n"); + abort(); + } +#endif /* end of dynamic detection of fp word order */ + + switch (xdrs->x_op) { + + case XDR_ENCODE: + if (2*sizeof(int32_t) == sizeof(double)) { + int32_t *lp = (int32_t *)dp; + return (xdr_putlong(xdrs, lp+!LSW) && + xdr_putlong(xdrs, lp+LSW)); + } else if (2*sizeof(int) == sizeof(double)) { + int *ip = (int *)dp; + int32_t tmp[2]; + tmp[0] = ip[!LSW]; + tmp[1] = ip[LSW]; + return (xdr_putlong(xdrs, tmp) && + xdr_putlong(xdrs, tmp+1)); + } + break; + + case XDR_DECODE: + if (2*sizeof(int32_t) == sizeof(double)) { + int32_t *lp = (int32_t *)dp; + return (xdr_getlong(xdrs, lp+!LSW) && + xdr_getlong(xdrs, lp+LSW)); + } else if (2*sizeof(int) == sizeof(double)) { + int *ip = (int *)dp; + int32_t tmp[2]; + if (xdr_getlong(xdrs, tmp+!LSW) && + xdr_getlong(xdrs, tmp+LSW)) { + ip[0] = tmp[0]; + ip[1] = tmp[1]; + return (1); + } + } + break; + + case XDR_FREE: + return (1); + } + return (0); +} + + +static int xdrstdio_getlong (XDR *, int32_t *); +static int xdrstdio_putlong (XDR *, int32_t *); +static int xdrstdio_getbytes (XDR *, char *, unsigned int); +static int xdrstdio_putbytes (XDR *, char *, unsigned int); +static unsigned int xdrstdio_getpos (XDR *); +static int xdrstdio_setpos (XDR *, unsigned int); +static void xdrstdio_destroy (XDR *); + +/* + * Ops vector for stdio type XDR + */ +static const struct xdr_ops xdrstdio_ops = + { + xdrstdio_getlong, /* deserialize a long int */ + xdrstdio_putlong, /* serialize a long int */ + xdrstdio_getbytes, /* deserialize counted bytes */ + xdrstdio_putbytes, /* serialize counted bytes */ + xdrstdio_getpos, /* get offset in the stream */ + xdrstdio_setpos, /* set offset in the stream */ + xdrstdio_destroy, /* destroy stream */ + }; + +/* + * Initialize a stdio xdr stream. + * Sets the xdr stream handle xdrs for use on the stream file. + * Operation flag is set to op. + */ +static void +xdrstdio_create (XDR *xdrs, FILE *file, enum xdr_op op) +{ + xdrs->x_op = op; + + xdrs->x_ops = (struct xdr_ops *) &xdrstdio_ops; + xdrs->x_private = (char *) file; +} + +/* + * Destroy a stdio xdr stream. + * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create. + */ +static void +xdrstdio_destroy (XDR *xdrs) +{ + (void) fflush ((FILE *) xdrs->x_private); + /* xx should we close the file ?? */ +} + +static int +xdrstdio_getlong (XDR *xdrs, int32_t *lp) +{ + int32_t mycopy; + + if (fread ((char *) & mycopy, 4, 1, (FILE *) xdrs->x_private) != 1) + return 0; + *lp = (int32_t) xdr_ntohl (mycopy); + return 1; +} + +static int +xdrstdio_putlong (XDR *xdrs, int32_t *lp) +{ + int32_t mycopy = xdr_htonl (*lp); + lp = &mycopy; + if (fwrite ((char *) lp, 4, 1, (FILE *) xdrs->x_private) != 1) + return 0; + return 1; +} + +static int +xdrstdio_getbytes (XDR *xdrs, char *addr, unsigned int len) +{ + if ((len != 0) && (fread (addr, (int) len, 1, + (FILE *) xdrs->x_private) != 1)) + return 0; + return 1; +} + +static int +xdrstdio_putbytes (XDR *xdrs, char *addr, unsigned int len) +{ + if ((len != 0) && (fwrite (addr, (int) len, 1, + (FILE *) xdrs->x_private) != 1)) + return 0; + return 1; +} + +/* 32 bit fileseek operations */ +static unsigned int +xdrstdio_getpos (XDR *xdrs) +{ + return (unsigned int) ftell ((FILE *) xdrs->x_private); +} + +static int +xdrstdio_setpos (XDR *xdrs, unsigned int pos) +{ + return fseek ((FILE *) xdrs->x_private, pos, 0) < 0 ? 0 : 1; +} + + + +#endif /* HAVE_RPC_XDR_H not defined */ diff --git a/external/xdrfile/src/xdrfile_trr.c b/external/xdrfile/src/xdrfile_trr.c new file mode 100644 index 0000000..71e27e3 --- /dev/null +++ b/external/xdrfile/src/xdrfile_trr.c @@ -0,0 +1,533 @@ + /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- + * + * $Id$ + * + * Copyright (c) 2009-2014, Erik Lindahl & David van der Spoel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xdrfile.h" +#include "xdrfile_trr.h" + +#define BUFSIZE 128 +#define GROMACS_MAGIC 1993 + +typedef struct /* This struct describes the order and the */ +/* sizes of the structs in a trjfile, sizes are given in bytes. */ +{ + mybool bDouble; /* Double precision? */ + int ir_size; /* Backward compatibility */ + int e_size; /* Backward compatibility */ + int box_size; /* Non zero if a box is present */ + int vir_size; /* Backward compatibility */ + int pres_size; /* Backward compatibility */ + int top_size; /* Backward compatibility */ + int sym_size; /* Backward compatibility */ + int x_size; /* Non zero if coordinates are present */ + int v_size; /* Non zero if velocities are present */ + int f_size; /* Non zero if forces are present */ + + int natoms; /* The total number of atoms */ + int step; /* Current step number */ + int nre; /* Backward compatibility */ + float tf; /* Current time */ + float lambdaf; /* Current value of lambda */ + double td; /* Current time */ + double lambdad; /* Current value of lambda */ +} t_trnheader; + +static int nFloatSize(t_trnheader *sh,int *nflsz) +{ + int nflsize=0; + + if (sh->box_size) + nflsize = sh->box_size/(DIM*DIM); + else if (sh->x_size) + nflsize = sh->x_size/(sh->natoms*DIM); + else if (sh->v_size) + nflsize = sh->v_size/(sh->natoms*DIM); + else if (sh->f_size) + nflsize = sh->f_size/(sh->natoms*DIM); + else + return exdrHEADER; + + if (((nflsize != sizeof(float)) && (nflsize != sizeof(double)))) + return exdrHEADER; + + *nflsz = nflsize; + + return exdrOK; +} + +extern int do_trnheader(XDRFILE *xd,mybool bRead,t_trnheader *sh) +{ + int magic=GROMACS_MAGIC; + int nflsz,slen,result; + char *version = "GMX_trn_file"; + char buf[BUFSIZE]; + + if (xdrfile_read_int(&magic,1,xd) != 1) { + /* modification by RTM to return the right EOF code + this is what's happening in the XTC code */ + if (bRead) + return exdrENDOFFILE; + else + return exdrINT; + } + if (magic != GROMACS_MAGIC) + return exdrMAGIC; + if (bRead) + { + if (xdrfile_read_int(&slen,1,xd) != 1) + return exdrINT; + if (slen != strlen(version)+1) + return exdrSTRING; + if (xdrfile_read_string(buf,BUFSIZE,xd) <= 0) + return exdrSTRING; + } + else + { + slen = strlen(version)+1; + if (xdrfile_read_int(&slen,1,xd) != 1) + return exdrINT; + if (xdrfile_write_string(version,xd) != (strlen(version)+1) ) + return exdrSTRING; + } + if (xdrfile_read_int(&sh->ir_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->e_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->box_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->vir_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->pres_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->top_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->sym_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->x_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->v_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->f_size,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->natoms,1,xd) != 1) + return exdrINT; + + if ((result = nFloatSize(sh,&nflsz)) != exdrOK) + return result; + sh->bDouble = (nflsz == sizeof(double)); + + if (xdrfile_read_int(&sh->step,1,xd) != 1) + return exdrINT; + if (xdrfile_read_int(&sh->nre,1,xd) != 1) + return exdrINT; + if (sh->bDouble) + { + if (xdrfile_read_double(&sh->td,1,xd) != 1) + return exdrDOUBLE; + sh->tf = sh->td; + if (xdrfile_read_double(&sh->lambdad,1,xd) != 1) + return exdrDOUBLE; + sh->lambdaf = sh->lambdad; + } + else + { + if (xdrfile_read_float(&sh->tf,1,xd) != 1) + return exdrFLOAT; + sh->td = sh->tf; + if (xdrfile_read_float(&sh->lambdaf,1,xd) != 1) + return exdrFLOAT; + sh->lambdad = sh->lambdaf; + } + + return exdrOK; +} + +static int do_htrn(XDRFILE *xd,mybool bRead,t_trnheader *sh, + matrix box,rvec *x,rvec *v,rvec *f) +{ + double pvd[DIM*DIM]; + double *dx=NULL; + float pvf[DIM*DIM]; + float *fx=NULL; + int i,j; + + if (sh->bDouble) + { + if (sh->box_size != 0) + { + if (!bRead) + { + for(i=0; (ivir_size != 0) + { + if (xdrfile_read_double(pvd,DIM*DIM,xd) != DIM*DIM) + return exdrDOUBLE; + } + + if (sh->pres_size!= 0) + { + if (xdrfile_read_double(pvd,DIM*DIM,xd) != DIM*DIM) + return exdrDOUBLE; + } + + if ((sh->x_size != 0) || (sh->v_size != 0) || (sh->f_size != 0)) { + dx = (double *)calloc(sh->natoms*DIM,sizeof(dx[0])); + if (NULL == dx) + return exdrNOMEM; + } + if (sh->x_size != 0) + { + if (!bRead) + { + for(i=0; (inatoms); i++) + for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) + { + if (bRead) + { + for(i=0; (inatoms); i++) + for(j=0; (jv_size != 0) + { + if (!bRead) + { + for(i=0; (inatoms); i++) + for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) + { + for(i=0; (inatoms); i++) + for(j=0; (jf_size != 0) + { + if (!bRead) + { + for(i=0; (inatoms); i++) + for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) + { + for(i=0; (inatoms); i++) + { + for(j=0; (jx_size != 0) || (sh->v_size != 0) || (sh->f_size != 0)) { + free(dx); + } + } + else + /* Float */ + { + if (sh->box_size != 0) + { + if (!bRead) + { + for(i=0; (ivir_size != 0) + { + if (xdrfile_read_float(pvf,DIM*DIM,xd) != DIM*DIM) + return exdrFLOAT; + } + + if (sh->pres_size!= 0) + { + if (xdrfile_read_float(pvf,DIM*DIM,xd) != DIM*DIM) + return exdrFLOAT; + } + + if ((sh->x_size != 0) || (sh->v_size != 0) || (sh->f_size != 0)) { + fx = (float *)calloc(sh->natoms*DIM,sizeof(fx[0])); + if (NULL == fx) + return exdrNOMEM; + } + if (sh->x_size != 0) + { + if (!bRead) + { + for(i=0; (inatoms); i++) + for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) + { + if (bRead) + { + for(i=0; (inatoms); i++) + for(j=0; (jv_size != 0) + { + if (!bRead) + { + for(i=0; (inatoms); i++) + for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) + { + for(i=0; (inatoms); i++) + for(j=0; (jf_size != 0) + { + if (!bRead) + { + for(i=0; (inatoms); i++) + for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) + { + for(i=0; (inatoms); i++) + for(j=0; (jx_size != 0) || (sh->v_size != 0) || (sh->f_size != 0)) { + free(fx); + } + } + return exdrOK; +} + +static int do_trn(XDRFILE *xd,mybool bRead,int *step,float *t,float *lambda, + matrix box,int *natoms,rvec *x,rvec *v,rvec *f) +{ + t_trnheader *sh; + int result; + + sh = (t_trnheader *)calloc(1,sizeof(*sh)); + + if (!bRead) { + sh->box_size = (NULL != box) ? sizeof(matrix):0; + sh->x_size = ((NULL != x) ? (*natoms*sizeof(x[0])):0); + sh->v_size = ((NULL != v) ? (*natoms*sizeof(v[0])):0); + sh->f_size = ((NULL != f) ? (*natoms*sizeof(f[0])):0); + sh->natoms = *natoms; + sh->step = *step; + sh->nre = 0; + sh->td = *t; + sh->lambdad = *lambda; + sh->tf = *t; + sh->lambdaf = *lambda; + } + if ((result = do_trnheader(xd,bRead,sh)) != exdrOK) + return result; + + if (bRead) { + *natoms = sh->natoms; + *step = sh->step; + *t = sh->td; + *lambda = sh->lambdad; + } + if ((result = do_htrn(xd,bRead,sh,box,x,v,f)) != exdrOK) + return result; + + free(sh); + + return exdrOK; +} + +/************************************************************ + * + * The following routines are the exported ones + * + ************************************************************/ + +int read_trr_natoms(char *fn,int *natoms) +{ + XDRFILE *xd; + t_trnheader sh; + int result; + + xd = xdrfile_open(fn,"r"); + if (NULL == xd) + return exdrFILENOTFOUND; + if ((result = do_trnheader(xd,1,&sh)) != exdrOK) { + xdrfile_close(xd); + return result; + } + xdrfile_close(xd); + *natoms = sh.natoms; + + return exdrOK; +} + +int read_trr_nframes(char *fn, unsigned long *nframes) { + XDRFILE *xd; + int result, step; + float time, lambda; + int natoms; + matrix box; + rvec *x; + *nframes = 0; + + read_trr_natoms(fn, &natoms); + x = malloc(natoms * sizeof(*x)); + + xd = xdrfile_open(fn, "r"); + if (NULL == xd) + return exdrFILENOTFOUND; + + do { + result = read_trr(xd, natoms, &step, &time, &lambda, + box, x, NULL, NULL); + if (exdrENDOFFILE != result) { + (*nframes)++; + } + } while (result == exdrOK); + + xdrfile_close(xd); + free(x); + return exdrOK; +} + +int write_trr(XDRFILE *xd,int natoms,int step,float t,float lambda, + matrix box,rvec *x,rvec *v,rvec *f) +{ + return do_trn(xd,0,&step,&t,&lambda,box,&natoms,x,v,f); +} + +int read_trr(XDRFILE *xd,int natoms,int *step,float *t,float *lambda, + matrix box,rvec *x,rvec *v,rvec *f) +{ + return do_trn(xd,1,step,t,lambda,box,&natoms,x,v,f); +} + diff --git a/external/xdrfile/src/xdrfile_xtc.c b/external/xdrfile/src/xdrfile_xtc.c new file mode 100644 index 0000000..c0c5bdb --- /dev/null +++ b/external/xdrfile/src/xdrfile_xtc.c @@ -0,0 +1,164 @@ +/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- + * + * $Id$ + * + * Copyright (c) 2009-2014, Erik Lindahl & David van der Spoel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "xdrfile.h" +#include "xdrfile_xtc.h" + +#define MAGIC 1995 + +enum { FALSE, TRUE }; + +static int xtc_header(XDRFILE *xd,int *natoms,int *step,float *time,mybool bRead) +{ + int result,magic,n=1; + + /* Note: read is same as write. He he he */ + magic = MAGIC; + if ((result = xdrfile_write_int(&magic,n,xd)) != n) + { + if (bRead) + return exdrENDOFFILE; + else + return exdrINT; + } + if (magic != MAGIC) + return exdrMAGIC; + if ((result = xdrfile_write_int(natoms,n,xd)) != n) + return exdrINT; + if ((result = xdrfile_write_int(step,n,xd)) != n) + return exdrINT; + if ((result = xdrfile_write_float(time,n,xd)) != n) + return exdrFLOAT; + + return exdrOK; +} + +static int xtc_coord(XDRFILE *xd,int *natoms,matrix box,rvec *x,float *prec, + mybool bRead) +{ + int i,j,result; + + /* box */ + result = xdrfile_read_float(box[0],DIM*DIM,xd); + if (DIM*DIM != result) + return exdrFLOAT; + else + { + if (bRead) + { + result = xdrfile_decompress_coord_float(x[0],natoms,prec,xd); + if (result != *natoms) + return exdr3DX; + } + else + { + result = xdrfile_compress_coord_float(x[0],*natoms,*prec,xd); + if (result != *natoms) + return exdr3DX; + } + } + return exdrOK; +} + +int read_xtc_natoms(char *fn,int *natoms) +{ + XDRFILE *xd; + int step,result; + float time; + + xd = xdrfile_open(fn,"r"); + if (NULL == xd) + return exdrFILENOTFOUND; + result = xtc_header(xd,natoms,&step,&time,TRUE); + xdrfile_close(xd); + + return result; +} + +int read_xtc_nframes(char* fn, unsigned long *nframes) { + XDRFILE *xd; + int result, step; + float time; + int natoms; + matrix box; + rvec *x; + float prec; + *nframes = 0; + + read_xtc_natoms(fn, &natoms); + x = malloc(natoms * sizeof(*x)); + + xd = xdrfile_open(fn, "r"); + if (NULL == xd) + return exdrFILENOTFOUND; + + do { + result = read_xtc(xd, natoms, &step, &time, box, x, &prec); + if (exdrENDOFFILE != result) { + (*nframes)++; + } + } while (result == exdrOK); + + xdrfile_close(xd); + free(x); + return exdrOK; +} + +int read_xtc(XDRFILE *xd, + int natoms,int *step,float *time, + matrix box,rvec *x,float *prec) +/* Read subsequent frames */ +{ + int result; + + if ((result = xtc_header(xd,&natoms,step,time,TRUE)) != exdrOK) + return result; + + if ((result = xtc_coord(xd,&natoms,box,x,prec,1)) != exdrOK) + return result; + + return exdrOK; +} + +int write_xtc(XDRFILE *xd, + int natoms,int step,float time, + matrix box,rvec *x,float prec) +/* Write a frame to xtc file */ +{ + int result; + + if ((result = xtc_header(xd,&natoms,&step,&time,FALSE)) != exdrOK) + return result; + + if ((result = xtc_coord(xd,&natoms,box,x,&prec,0)) != exdrOK) + return result; + + return exdrOK; +} diff --git a/src/c_abi/mod.rs b/src/c_abi/mod.rs new file mode 100644 index 0000000..3a71f91 --- /dev/null +++ b/src/c_abi/mod.rs @@ -0,0 +1,5 @@ +#[allow(non_upper_case_globals)] +pub mod xdrfile; +pub mod xdrfile_trr; +pub mod xdrfile_xtc; +pub mod xdr_seek; \ No newline at end of file diff --git a/src/c_abi/xdr_seek.rs b/src/c_abi/xdr_seek.rs new file mode 100644 index 0000000..a9db92e --- /dev/null +++ b/src/c_abi/xdr_seek.rs @@ -0,0 +1,160 @@ +use super::xdrfile::*; + +pub const _STDINT_H: u32 = 1; +pub const _FEATURES_H: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const __USE_ISOC11: u32 = 1; +pub const __USE_ISOC99: u32 = 1; +pub const __USE_ISOC95: u32 = 1; +pub const __USE_POSIX_IMPLICITLY: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const __USE_POSIX: u32 = 1; +pub const __USE_POSIX2: u32 = 1; +pub const __USE_POSIX199309: u32 = 1; +pub const __USE_POSIX199506: u32 = 1; +pub const __USE_XOPEN2K: u32 = 1; +pub const __USE_XOPEN2K8: u32 = 1; +pub const _ATFILE_SOURCE: u32 = 1; +pub const __USE_MISC: u32 = 1; +pub const __USE_ATFILE: u32 = 1; +pub const __USE_FORTIFY_LEVEL: u32 = 0; +pub const _STDC_PREDEF_H: u32 = 1; +pub const __STDC_IEC_559__: u32 = 1; +pub const __STDC_IEC_559_COMPLEX__: u32 = 1; +pub const __STDC_ISO_10646__: u32 = 201605; +pub const __STDC_NO_THREADS__: u32 = 1; +pub const __GNU_LIBRARY__: u32 = 6; +pub const __GLIBC__: u32 = 2; +pub const __GLIBC_MINOR__: u32 = 24; +pub const _SYS_CDEFS_H: u32 = 1; +pub const __WORDSIZE: u32 = 64; +pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; +pub const __SYSCALL_WORDSIZE: u32 = 64; +pub const _BITS_WCHAR_H: u32 = 1; +pub const INT8_MIN: i32 = -128; +pub const INT16_MIN: i32 = -32768; +pub const INT32_MIN: i32 = -2147483648; +pub const INT8_MAX: u32 = 127; +pub const INT16_MAX: u32 = 32767; +pub const INT32_MAX: u32 = 2147483647; +pub const UINT8_MAX: u32 = 255; +pub const UINT16_MAX: u32 = 65535; +pub const UINT32_MAX: u32 = 4294967295; +pub const INT_LEAST8_MIN: i32 = -128; +pub const INT_LEAST16_MIN: i32 = -32768; +pub const INT_LEAST32_MIN: i32 = -2147483648; +pub const INT_LEAST8_MAX: u32 = 127; +pub const INT_LEAST16_MAX: u32 = 32767; +pub const INT_LEAST32_MAX: u32 = 2147483647; +pub const UINT_LEAST8_MAX: u32 = 255; +pub const UINT_LEAST16_MAX: u32 = 65535; +pub const UINT_LEAST32_MAX: u32 = 4294967295; +pub const INT_FAST8_MIN: i32 = -128; +pub const INT_FAST16_MIN: i64 = -9223372036854775808; +pub const INT_FAST32_MIN: i64 = -9223372036854775808; +pub const INT_FAST8_MAX: u32 = 127; +pub const INT_FAST16_MAX: u64 = 9223372036854775807; +pub const INT_FAST32_MAX: u64 = 9223372036854775807; +pub const UINT_FAST8_MAX: u32 = 255; +pub const UINT_FAST16_MAX: i32 = -1; +pub const UINT_FAST32_MAX: i32 = -1; +pub const INTPTR_MIN: i64 = -9223372036854775808; +pub const INTPTR_MAX: u64 = 9223372036854775807; +pub const UINTPTR_MAX: i32 = -1; +pub const PTRDIFF_MIN: i64 = -9223372036854775808; +pub const PTRDIFF_MAX: u64 = 9223372036854775807; +pub const SIG_ATOMIC_MIN: i32 = -2147483648; +pub const SIG_ATOMIC_MAX: u32 = 2147483647; +pub const SIZE_MAX: i32 = -1; +pub const WINT_MIN: u32 = 0; +pub const WINT_MAX: u32 = 4294967295; +pub const DIM: u32 = 3; +pub type int_least8_t = ::std::os::raw::c_schar; +pub type int_least16_t = ::std::os::raw::c_short; +pub type int_least32_t = ::std::os::raw::c_int; +pub type int_least64_t = ::std::os::raw::c_long; +pub type uint_least8_t = ::std::os::raw::c_uchar; +pub type uint_least16_t = ::std::os::raw::c_ushort; +pub type uint_least32_t = ::std::os::raw::c_uint; +pub type uint_least64_t = ::std::os::raw::c_ulong; +pub type int_fast8_t = ::std::os::raw::c_schar; +pub type int_fast16_t = ::std::os::raw::c_long; +pub type int_fast32_t = ::std::os::raw::c_long; +pub type int_fast64_t = ::std::os::raw::c_long; +pub type uint_fast8_t = ::std::os::raw::c_uchar; +pub type uint_fast16_t = ::std::os::raw::c_ulong; +pub type uint_fast32_t = ::std::os::raw::c_ulong; +pub type uint_fast64_t = ::std::os::raw::c_ulong; +pub type intmax_t = ::std::os::raw::c_long; +pub type uintmax_t = ::std::os::raw::c_ulong; + +extern "C" { + pub fn xdr_tell(xd: *mut XDRFILE) -> i64; +} +extern "C" { + pub fn xdr_seek( + xd: *mut XDRFILE, + pos: i64, + whence: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +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 std::ffi::CString; + + #[test] + fn test_xdr_tell() { + let path = CString::new("tests/1l2y.xtc").unwrap(); + let num_atoms = 304; + let mut time: f32 = 2.0; + 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; + + unsafe { + let mode = CString::new("r").unwrap(); + let xdr = xdrfile_open(path.as_ptr(), mode.as_ptr()); + assert!(!xdr.is_null()); + + let tell = xdr_tell(xdr); + assert!(tell == 0, "{}", tell); + + read_xtc(xdr, num_atoms, &mut step, &mut time, + box_vec.as_ptr() as *mut Matrix, + x_p, + &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()); + assert!(!xdr.is_null()); + + let tell = xdr_tell(xdr); + assert!(tell == 0, "{}", tell); + + xdr_seek(xdr, 500, 0); + + let tell = xdr_tell(xdr); + assert!(tell == 500, "{}", tell); + } + } +} \ No newline at end of file diff --git a/src/c_abi/xdrfile.rs b/src/c_abi/xdrfile.rs new file mode 100644 index 0000000..e3721d3 --- /dev/null +++ b/src/c_abi/xdrfile.rs @@ -0,0 +1,520 @@ + +pub const DIM: u32 = 3; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct XDRFILE { + _unused: [u8; 0], +} + + +pub type BindgenTy1 = u32; +pub const exdrOK: BindgenTy1 = 0; +pub const exdrHEADER: BindgenTy1 = 1; +pub const exdrSTRING: BindgenTy1 = 2; +pub const exdrDOUBLE: BindgenTy1 = 3; +pub const exdrINT: BindgenTy1 = 4; +pub const exdrFLOAT: BindgenTy1 = 5; +pub const exdrUINT: BindgenTy1 = 6; +pub const exdr3DX: BindgenTy1 = 7; +pub const exdrCLOSE: BindgenTy1 = 8; +pub const exdrMAGIC: BindgenTy1 = 9; +pub const exdrNOMEM: BindgenTy1 = 10; +pub const exdrENDOFFILE: BindgenTy1 = 11; +pub const exdrFILENOTFOUND: BindgenTy1 = 12; +pub const exdrNR: BindgenTy1 = 13; + +extern "C" { + pub static mut exdr_message: [*mut ::std::os::raw::c_char; 13usize]; +} + +pub type Matrix = [[::std::os::raw::c_float; 3usize]; 3usize]; +pub type Rvec = [::std::os::raw::c_float; 3usize]; +pub type Mybool = ::std::os::raw::c_int; + +extern "C" { + #[doc = " \\brief Open a portable binary file, just like fopen()"] + #[doc = ""] + #[doc = " Use this routine much like calls to the standard library function"] + #[doc = " fopen(). The only difference is that the returned pointer should only"] + #[doc = " be used with routines defined in this header."] + #[doc = ""] + #[doc = " \\param path Full or relative path (including name) of the file"] + #[doc = " \\param mode \"r\" for reading, \"w\" for writing, \"a\" for append."] + #[doc = ""] + #[doc = " \\return Pointer to abstract xdr file datatype, or NULL if an error occurs."] + #[doc = ""] + pub fn xdrfile_open( + path: *const ::std::os::raw::c_char, + mode: *const ::std::os::raw::c_char, + ) -> *mut XDRFILE; +} +extern "C" { + #[doc = " \\brief Close a previously opened portable binary file, just like fclose()"] + #[doc = ""] + #[doc = " Use this routine much like calls to the standard library function"] + #[doc = " fopen(). The only difference is that it is used for an XDRFILE handle"] + #[doc = " instead of a FILE handle."] + #[doc = ""] + #[doc = " \\param xfp Pointer to an abstract XDRFILE datatype"] + #[doc = ""] + #[doc = " \\return 0 on success, non-zero on error."] + pub fn xdrfile_close(xfp: *mut XDRFILE) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read one or more \\a char type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param ndata Number of characters to read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of characters read"] + pub fn xdrfile_read_char( + ptr: *mut ::std::os::raw::c_char, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write one or more \\a characters type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param ndata Number of characters to write."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of characters written"] + pub fn xdrfile_write_char( + ptr: *mut ::std::os::raw::c_char, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read one or more \\a unsigned \\a char type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param ndata Number of unsigned characters to read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of unsigned characters read"] + pub fn xdrfile_read_uchar( + ptr: *mut ::std::os::raw::c_uchar, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write one or more \\a unsigned \\a characters type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param ndata Number of unsigned characters to write."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of unsigned characters written"] + pub fn xdrfile_write_uchar( + ptr: *mut ::std::os::raw::c_uchar, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read one or more \\a short type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param ndata Number of shorts to read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of shorts read"] + pub fn xdrfile_read_short( + ptr: *mut ::std::os::raw::c_short, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write one or more \\a short type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param ndata Number of shorts to write."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of shorts written"] + pub fn xdrfile_write_short( + ptr: *mut ::std::os::raw::c_short, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read one or more \\a unsigned \\a short type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param ndata Number of unsigned shorts to read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of unsigned shorts read"] + pub fn xdrfile_read_ushort( + ptr: *mut ::std::os::raw::c_ushort, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write one or more \\a unsigned \\a short type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param ndata Number of unsigned shorts to write."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of unsigned shorts written"] + pub fn xdrfile_write_ushort( + ptr: *mut ::std::os::raw::c_ushort, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read one or more \\a integer type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param ndata Number of integers to read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of integers read"] + #[doc = ""] + #[doc = " The integer data type is assumed to be less than or equal to 32 bits."] + #[doc = ""] + #[doc = " We do not provide any routines for reading/writing 64-bit integers, since"] + #[doc = " - Not all XDR implementations support it"] + #[doc = " - Not all machines have 64-bit integers"] + #[doc = ""] + #[doc = " Split your 64-bit data into two 32-bit integers for portability!"] + pub fn xdrfile_read_int( + ptr: *mut ::std::os::raw::c_int, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write one or more \\a integer type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param ndata Number of integers to write."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of integers written"] + #[doc = ""] + #[doc = " The integer data type is assumed to be less than or equal to 32 bits."] + #[doc = ""] + #[doc = " We do not provide any routines for reading/writing 64-bit integers, since"] + #[doc = " - Not all XDR implementations support it"] + #[doc = " - Not all machines have 64-bit integers"] + #[doc = ""] + #[doc = " Split your 64-bit data into two 32-bit integers for portability!"] + pub fn xdrfile_write_int( + ptr: *mut ::std::os::raw::c_int, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read one or more \\a unsigned \\a integers type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param ndata Number of unsigned integers to read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of unsigned integers read"] + #[doc = ""] + #[doc = " The integer data type is assumed to be less than or equal to 32 bits."] + #[doc = ""] + #[doc = " We do not provide any routines for reading/writing 64-bit integers, since"] + #[doc = " - Not all XDR implementations support it"] + #[doc = " - Not all machines have 64-bit integers"] + #[doc = ""] + #[doc = " Split your 64-bit data into two 32-bit integers for portability!"] + pub fn xdrfile_read_uint( + ptr: *mut ::std::os::raw::c_uint, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write one or more \\a unsigned \\a integer type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param ndata Number of unsigned integers to write."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of unsigned integers written"] + #[doc = ""] + #[doc = " The integer data type is assumed to be less than or equal to 32 bits."] + #[doc = ""] + #[doc = " We do not provide any routines for reading/writing 64-bit integers, since"] + #[doc = " - Not all XDR implementations support it"] + #[doc = " - Not all machines have 64-bit integers"] + #[doc = ""] + #[doc = " Split your 64-bit data into two 32-bit integers for portability!"] + pub fn xdrfile_write_uint( + ptr: *mut ::std::os::raw::c_uint, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read one or more \\a float type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param ndata Number of floats to read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of floats read"] + pub fn xdrfile_read_float( + ptr: *mut ::std::os::raw::c_float, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write one or more \\a float type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param ndata Number of floats to write."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of floats written"] + pub fn xdrfile_write_float( + ptr: *mut ::std::os::raw::c_float, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read one or more \\a double type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param ndata Number of doubles to read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of doubles read"] + pub fn xdrfile_read_double( + ptr: *mut ::std::os::raw::c_double, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write one or more \\a double type variable(s)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param ndata Number of double to write."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of doubles written"] + pub fn xdrfile_write_double( + ptr: *mut ::std::os::raw::c_double, + ndata: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read a string (array of characters)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param maxlen Maximum length of string. If no end-of-string is encountered,"] + #[doc = " one byte less than this is read and end-of-string appended."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of characters read, including end-of-string"] + pub fn xdrfile_read_string( + ptr: *mut ::std::os::raw::c_char, + maxlen: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write a string (array of characters)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of characters written, including end-of-string"] + pub fn xdrfile_write_string( + ptr: *mut ::std::os::raw::c_char, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Read raw bytes from file (unknown datatype)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be written"] + #[doc = " \\param nbytes Number of bytes to read. No conversion whatsoever is done."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of bytes read from file"] + pub fn xdrfile_read_opaque( + ptr: *mut ::std::os::raw::c_char, + nbytes: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Write raw bytes to file (unknown datatype)"] + #[doc = ""] + #[doc = " \\param ptr Pointer to memory where data should be read"] + #[doc = " \\param nbytes Number of bytes to write. No conversion whatsoever is done."] + #[doc = " \\param xfp Handle to portable binary file, created with xdrfile_open()"] + #[doc = ""] + #[doc = " \\return Number of bytes written to file"] + pub fn xdrfile_write_opaque( + ptr: *mut ::std::os::raw::c_char, + nbytes: ::std::os::raw::c_int, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Compress coordiates in a float array to XDR file"] + #[doc = ""] + #[doc = " This routine will perform \\a lossy compression on the three-dimensional"] + #[doc = " coordinate data data specified and store it in the XDR file."] + #[doc = ""] + #[doc = " The lossy part of the compression consists of multiplying each"] + #[doc = " coordinate with the precision argument and then rounding to integers."] + #[doc = " We suggest a default value of 1000.0, which means you are guaranteed"] + #[doc = " three decimals of accuracy. The only limitation is that scaled coordinates"] + #[doc = " must still fit in an integer variable, so if the precision is 1000.0 the"] + #[doc = " coordinate magnitudes must be less than +-2e6."] + #[doc = ""] + #[doc = " \\param ptr Pointer to coordinates to compress (length 3*ncoord)"] + #[doc = " \\param ncoord Number of coordinate triplets in data"] + #[doc = " \\param precision Scaling factor for lossy compression. If it is <=0,"] + #[doc = " the default value of 1000.0 is used."] + #[doc = " \\param xfp Handle to portably binary file"] + #[doc = ""] + #[doc = " \\return Number of coordinate triplets written."] + #[doc = " IMPORTANT: Check that this is equal to ncoord - if it is"] + #[doc = " negative, an error occured. This should not happen with"] + #[doc = "\t \t normal data, but if your coordinates are NaN or very"] + #[doc = " large (>1e6) it is not possible to use the compression."] + #[doc = ""] + #[doc = " \\warning The compression algorithm is not part of the XDR standard,"] + #[doc = " and very complicated, so you will need this xdrfile module"] + #[doc = " to read it later."] + pub fn xdrfile_compress_coord_float( + ptr: *mut ::std::os::raw::c_float, + ncoord: ::std::os::raw::c_int, + precision: ::std::os::raw::c_float, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Decompress coordiates from XDR file to array of floats"] + #[doc = ""] + #[doc = " This routine will decompress three-dimensional coordinate data previously"] + #[doc = " stored in an XDR file and store it in the specified array of floats."] + #[doc = ""] + #[doc = " The precision used during the earlier compression is read from the file"] + #[doc = " and returned - you cannot adjust the accuracy at this stage."] + #[doc = ""] + #[doc = " \\param ptr Pointer to coordinates to compress (length>= 3*ncoord)"] + #[doc = " \\param ncoord Max number of coordinate triplets to read on input, actual"] + #[doc = " number of coordinate triplets read on return. If this"] + #[doc = " is smaller than the number of coordinates in the frame an"] + #[doc = " error will occur."] + #[doc = " \\param precision The precision used in the previous compression will be"] + #[doc = " written to this variable on return."] + #[doc = " \\param xfp Handle to portably binary file"] + #[doc = ""] + #[doc = " \\return Number of coordinate triplets read. If this is negative,"] + #[doc = " an error occured."] + #[doc = ""] + #[doc = " \\warning Since we cannot count on being able to set/get the"] + #[doc = " position of large files (>2Gb), it is not possible to"] + #[doc = " recover from errors by re-reading the frame if the"] + #[doc = " storage area you provided was too small. To avoid this"] + #[doc = " from happening, we recommend that you store the number of"] + #[doc = " coordinates triplet as an integer either in a header or"] + #[doc = " just before the compressed coordinate data, so you can"] + #[doc = " read it first and allocated enough memory."] + pub fn xdrfile_decompress_coord_float( + ptr: *mut ::std::os::raw::c_float, + ncoord: *mut ::std::os::raw::c_int, + precision: *mut ::std::os::raw::c_float, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Compress coordiates in a double array to XDR file"] + #[doc = ""] + #[doc = " This routine will perform \\a lossy compression on the three-dimensional"] + #[doc = " coordinate data data specified and store it in the XDR file. Double will"] + #[doc = " NOT give you any extra precision since the coordinates are compressed. This"] + #[doc = " routine just avoids allocating a temporary array of floats."] + #[doc = ""] + #[doc = " The lossy part of the compression consists of multiplying each"] + #[doc = " coordinate with the precision argument and then rounding to integers."] + #[doc = " We suggest a default value of 1000.0, which means you are guaranteed"] + #[doc = " three decimals of accuracy. The only limitation is that scaled coordinates"] + #[doc = " must still fit in an integer variable, so if the precision is 1000.0 the"] + #[doc = " coordinate magnitudes must be less than +-2e6."] + #[doc = ""] + #[doc = " \\param ptr Pointer to coordinates to compress (length 3*ncoord)"] + #[doc = " \\param ncoord Number of coordinate triplets in data"] + #[doc = " \\param precision Scaling factor for lossy compression. If it is <=0, the"] + #[doc = " default value of 1000.0 is used."] + #[doc = " \\param xfp Handle to portably binary file"] + #[doc = ""] + #[doc = " \\return Number of coordinate triplets written."] + #[doc = " IMPORTANT: Check that this is equal to ncoord - if it is"] + #[doc = " negative, an error occured. This should not happen with"] + #[doc = " normal data, but if your coordinates are NaN or very"] + #[doc = " large (>1e6) it is not possible to use the compression."] + #[doc = ""] + #[doc = " \\warning The compression algorithm is not part of the XDR standard,"] + #[doc = " and very complicated, so you will need this xdrfile module"] + #[doc = " to read it later."] + pub fn xdrfile_compress_coord_double( + ptr: *mut ::std::os::raw::c_double, + ncoord: ::std::os::raw::c_int, + precision: ::std::os::raw::c_double, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " \\brief Decompress coordiates from XDR file to array of doubles"] + #[doc = ""] + #[doc = " This routine will decompress three-dimensional coordinate data previously"] + #[doc = " stored in an XDR file and store it in the specified array of doubles."] + #[doc = " Double will NOT give you any extra precision since the coordinates are"] + #[doc = " compressed. This routine just avoids allocating a temporary array of floats."] + #[doc = ""] + #[doc = " The precision used during the earlier compression is read from the file"] + #[doc = " and returned - you cannot adjust the accuracy at this stage."] + #[doc = ""] + #[doc = " \\param ptr Pointer to coordinates to compress (length>= 3*ncoord)"] + #[doc = " \\param ncoord Max number of coordinate triplets to read on input, actual"] + #[doc = " number of coordinate triplets read on return. If this"] + #[doc = " is smaller than the number of coordinates in the frame an"] + #[doc = " error will occur."] + #[doc = " \\param precision The precision used in the previous compression will be"] + #[doc = " written to this variable on return."] + #[doc = " \\param xfp Handle to portably binary file"] + #[doc = ""] + #[doc = " \\return Number of coordinate triplets read. If this is negative,"] + #[doc = " an error occured."] + #[doc = ""] + #[doc = " \\warning Since we cannot count on being able to set/get the"] + #[doc = " position of large files (>2Gb), it is not possible to"] + #[doc = " recover from errors by re-reading the frame if the"] + #[doc = " storage area you provided was too small. To avoid this"] + #[doc = " from happening, we recommend that you store the number of"] + #[doc = " coordinates triplet as an integer either in a header or"] + #[doc = " just before the compressed coordinate data, so you can"] + #[doc = " read it first and allocated enough memory."] + pub fn xdrfile_decompress_coord_double( + ptr: *mut ::std::os::raw::c_double, + ncoord: *mut ::std::os::raw::c_int, + precision: *mut ::std::os::raw::c_double, + xfp: *mut XDRFILE, + ) -> ::std::os::raw::c_int; +} diff --git a/src/c_abi/xdrfile_trr.rs b/src/c_abi/xdrfile_trr.rs new file mode 100644 index 0000000..d80effb --- /dev/null +++ b/src/c_abi/xdrfile_trr.rs @@ -0,0 +1,133 @@ +use super::xdrfile::*; + + +extern "C" { + pub fn read_trr_natoms( + fn_: *const ::std::os::raw::c_char, + natoms: *const ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn read_trr_nframes( + fn_: *const ::std::os::raw::c_char, + nframes: *const ::std::os::raw::c_ulong, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn read_trr( + xd: *mut XDRFILE, + natoms: ::std::os::raw::c_int, + step: *mut ::std::os::raw::c_int, + t: *mut ::std::os::raw::c_float, + lambda: *mut ::std::os::raw::c_float, + box_vec: *mut Matrix, + x: *mut Rvec, + v: *mut Rvec, + f: *mut Rvec, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn write_trr( + xd: *mut XDRFILE, + natoms: ::std::os::raw::c_int, + step: ::std::os::raw::c_int, + t: ::std::os::raw::c_float, + lambda: ::std::os::raw::c_float, + box_vec: *const Matrix, + x: *const Rvec, + v: *const Rvec, + f: *const Rvec, + ) -> ::std::os::raw::c_int; +} + +#[cfg(test)] +mod tests { + + use super::*; + use std::ffi::CString; + use tempfile::NamedTempFile; + + #[test] + fn test_read_trr_natoms() { + let path = CString::new("tests/1l2y.trr").unwrap(); + + let mut natoms = 0; + unsafe { + read_trr_natoms(path.as_ptr() as *const i8, &mut natoms); + } + assert!(natoms == 304); + } + + #[test] + fn test_read_trr_nframes() { + let path = CString::new("tests/1l2y.trr").unwrap(); + let mut nframes: u64 = 0; + + unsafe { + let code = read_trr_nframes(path.as_ptr() as *const i8, &mut nframes); + assert!(code as u32 == exdrOK); + } + assert!(nframes == 38, "{:?}", nframes); + } + + #[test] + fn test_read_write_trr() { + let tempfile = NamedTempFile::new().unwrap(); + let tmp_path = CString::new(tempfile.path().to_str().unwrap()).unwrap(); + + // write atoms to tempfile + let natoms: i32 = 2; + let time: f32 = 2.0; + let lambda: f32 = 1.0; + 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 = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]; + let v: Vec = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]; + let f: Vec = 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, + 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); + assert!(write_code as u32 == exdrOK); + xdrfile_close(xdr); + } + + // read atoms from tempfile + let mut time2: f32 = 0.0; + let mut lambda2: f32 = 0.0; + let mut step2: i32 = 0; + + let box_vec2: Matrix = [[0.0, 0.0, 0.0]; 3]; + let x2: Vec = vec![[0.0, 0.0, 0.0]; 2]; + let v2: Vec = vec![[0.0, 0.0, 0.0]; 2]; + let f2: Vec = vec![[0.0, 0.0, 0.0]; 2]; + + 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, + x2.as_ptr() as *mut Rvec, + v2.as_ptr() as *mut Rvec, + f2.as_ptr() as *mut Rvec); + assert!(read_code as u32 == exdrOK); + xdrfile_close(xdr); + } + + // make sure everything is still the same + assert!(step2 == step); + assert!(time2 == time); + assert!(lambda == lambda2); + assert!(box_vec2 == box_vec); + assert!(x2 == x); + assert!(v2 == v); + assert!(f2 == f); + } + +} \ No newline at end of file diff --git a/src/c_abi/xdrfile_xtc.rs b/src/c_abi/xdrfile_xtc.rs new file mode 100644 index 0000000..e074d51 --- /dev/null +++ b/src/c_abi/xdrfile_xtc.rs @@ -0,0 +1,114 @@ +use super::xdrfile::*; + + +extern "C" { + pub fn read_xtc_natoms( + fn_: *const ::std::os::raw::c_char, + natoms: *const ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn read_xtc_nframes( + fn_: *const ::std::os::raw::c_char, + nframes: *const ::std::os::raw::c_ulong, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn read_xtc( + xd: *mut XDRFILE, + natoms: ::std::os::raw::c_int, + step: *mut ::std::os::raw::c_int, + time: *mut ::std::os::raw::c_float, + box_vec: *mut Matrix, + x: *mut Rvec, + prec: *mut ::std::os::raw::c_float, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn write_xtc( + xd: *mut XDRFILE, + natoms: ::std::os::raw::c_int, + step: ::std::os::raw::c_int, + time: ::std::os::raw::c_float, + box_vec: *mut Matrix, + x: *mut Rvec, + prec: ::std::os::raw::c_float, + ) -> ::std::os::raw::c_int; +} + +#[cfg(test)] +mod tests { + + use super::*; + use std::ffi::CString; + use tempfile::NamedTempFile; + + #[test] + fn test_read_xtc_natoms() { + let path = CString::new("tests/1l2y.xtc").unwrap(); + + let mut natoms = 0; + unsafe { + read_xtc_natoms(path.as_ptr() as *mut i8, &mut natoms); + } + assert!(natoms == 304); + } + + #[test] + fn test_read_xtc_nframes() { + let path = CString::new("tests/1l2y.xtc").unwrap(); + let mut nframes: u64 = 0; + + unsafe { + let code = read_xtc_nframes(path.as_ptr() as *const i8, &mut nframes); + assert!(code as u32 == exdrOK); + } + assert!(nframes == 38, "{:?}", nframes); + } + + #[test] + fn test_read_write_xtc() { + let tempfile = NamedTempFile::new().unwrap(); + let tmp_path = CString::new(tempfile.path().to_str().unwrap()).unwrap(); + + // write atoms to tempfile + let natoms: i32 = 2; + let time: f32 = 2.0; + 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 = 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); + assert!(write_code as u32 == exdrOK); + xdrfile_close(xdr); + } + + // read atoms from tempfile + let mut time2: f32 = 0.0; + let mut step2: i32 = 0; + let box_vec2: Matrix = [[0.0, 0.0, 0.0]; 3]; + let x2: Vec = vec![[0.0, 0.0, 0.0]; 2]; + let mut prec: f32 = 0.0; + + 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); + assert!(read_code as u32 == exdrOK); + xdrfile_close(xdr); + } + + // make sure everything is still the same + assert!(step2 == step); + assert!(time2 == time); + assert!(box_vec2 == box_vec); + assert!(x2 == x); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..268972c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod c_abi; diff --git a/tests/1l2y.trr b/tests/1l2y.trr new file mode 100644 index 0000000000000000000000000000000000000000..89dc66b6a3fd179734311025b0cd883c7a5a6622 GIT binary patch literal 143184 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 literal 0 HcmV?d00001