Unverified Commit eda091f2 authored by Raul's avatar Raul Committed by GitHub
Browse files

Adding an XTC reporter (#4001)

* Preliminary work on XTC reporter
1. Move and adapt xtc writer/reader from moleculekit (explicit permission
granted by the authors to do so)
2. Create XTCTrajectoryFile
3. Create XTCReporter

* Add licence and attribution to c++ xtc library
Apply clang-format to it
Remove some unused functions and document the rest

* Add attribution and licence to cython wrappers for the xtc library
Remove some unused functions

* Change XTCTrajectoryFile to XTCFile
Simplify the interface and document the class

* Add test for the xtc file parser

* Update XTC reporter with new parser name

* Fix incorrect function name in XTCReporter

* XTCFile:
	* Add function to get number of frames
	* Add function to read a group of frames from a file
	* Add tests for the above

* Ensure data is passed as float32 in XTC file

* Add XTCReporter and tests

* Add more tests to XTCReporter

* Remove unnecessary pdb reporter in XTC tests

* Copy test xtc file in python/tests/systems to build directory for testing

* Remove XTC file reading from the interface
Make XTCFile mimic DCDFile more closely

* Use xtc_read to test the correctness of the XTC reporter

* Add a test for reporting triclinic boxes

* Make XTC library compatible with triclinic boxes.
Adapt XTCFile to triclinic boxes

* Change XTCFile to take a file as argument instead of a filename

* Match DCDFile handling of the box

* Fix comment

* Revert "Change XTCFile to take a file as argument instead of a filename"

This reverts commit 9815d4790b3886cc8a741586792268e80a227ba0.

* Fix dangling file name issue

* Remove index file functionality from XTC parser.
Remove unused define switch PLATFORM_Linux

* Fix formatting

* Remove inconsistent variable naming in xtcfile.py

* Change file argument name to match other reporters

* Do not turn off error checking in cython wrappers

* Fix leftover fileName in reporter

* Rewrite wrapper to xtclib in C++

* Small changes to wrapper code

* Small changes to wrapper code

* Small changes to wrapper code

* XTCFile: Get number of atoms directly from topology

* DCDFile: Get number of atoms directly from topology

* Change constexpr to const

* Check precision in XTC file matches the written one

* Add a write function to XTCFrame.
Make write check for errors C++ side.

* Rewrite large trajectory files without loading the whole file to memory

* Remove unused code in XTC test

* Avoid spurious copy of the positions array when calling xtc_write_frame

* Pass box as reference

* Remove unnecessary imports and definitions

* Fix formatting

* Use std::string instead of char*

* Use .c_str()  instead of .data()

* Fix crash in Mac by correctly checking precision

* Use TemporaryDirectory for tests instead of NamedTemporaryFile (Fixes windows ci)

* Remove unnecessary file creation

* Propagate exceptions via cython

* Switch to TemporaryDirectory in xtcfile.py

* Remove unnecessary include

* Update some comments and document functions

* Add XTC reporter to the docs
parent 3c7eef3d
......@@ -1379,13 +1379,14 @@ Writing Trajectories
====================
OpenMM can save simulation trajectories to disk in three formats: PDB_,
`PDBx/mmCIF`_, and DCD_. All of these are widely supported formats, so you
OpenMM can save simulation trajectories to disk in four formats: PDB_,
`PDBx/mmCIF`_, DCD_ and XTC_. All of these are widely supported formats, so you
should be able to read them into most analysis and visualization programs.
.. _PDB: http://www.wwpdb.org/documentation/format33/v3.3.html
.. _PDBx/mmCIF: http://mmcif.wwpdb.org
.. _DCD: http://www.ks.uiuc.edu/Research/vmd/plugins/molfile/dcdplugin.html
.. _XTC: https://manual.gromacs.org/archive/5.0.4/online/xtc.html
To save a trajectory, just add a “reporter” to the simulation, as shown in the
example scripts above:
......@@ -1394,9 +1395,9 @@ example scripts above:
simulation.reporters.append(PDBReporter('output.pdb', 1000))
The two parameters of the :class:`PDBReporter` are the output filename and how often (in
number of time steps) output structures should be written. To use PDBx/mmCIF or
DCD format, just replace :class:`PDBReporter` with :class:`PDBxReporter` or
:class:`DCDReporter`. The parameters represent the same values:
number of time steps) output structures should be written. To use PDBx/mmCIF,
DCD or XTC format, just replace :class:`PDBReporter` with :class:`PDBxReporter`,
:class:`DCDReporter` or :class:`XTCReporter`. The parameters represent the same values:
::
simulation.reporters.append(DCDReporter('output.dcd', 1000))
......
......@@ -51,10 +51,14 @@ foreach(SUBDIR ${SUBDIRS})
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*README.txt"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.py"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.pyx"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.pxd"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.i"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.ini"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.sh"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.xml"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.xtc"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.pdb"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.pdbx"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.cif"
......
......@@ -14,10 +14,12 @@ __email__ = "peastman@stanford.edu"
from .topology import Topology, Chain, Residue, Atom
from .pdbfile import PDBFile
from .xtcfile import XTCFile
from .pdbxfile import PDBxFile
from .forcefield import ForceField
from .simulation import Simulation
from .pdbreporter import PDBReporter, PDBxReporter
from .xtcreporter import XTCReporter
from .amberprmtopfile import AmberPrmtopFile, HCT, OBC1, OBC2, GBn, GBn2
from .amberinpcrdfile import AmberInpcrdFile
from .dcdfile import DCDFile
......@@ -53,4 +55,3 @@ Double = topology.Double
Triple = topology.Triple
Aromatic = topology.Aromatic
Amide = topology.Amide
......@@ -117,7 +117,7 @@ class DCDFile(object):
periodicBoxVectors : tuple of Vec3=None
The vectors defining the periodic box.
"""
if len(list(self._topology.atoms())) != len(positions):
if self._topology.getNumAtoms() != len(positions):
raise ValueError('The number of positions must match the number of atoms')
if is_quantity(positions):
positions = positions.value_in_unit(nanometers)
......
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
*
* $Id: xdrfile.h,v 1.6 2009/05/18 09:06:38 spoel Exp $
*
* Copyright (c) Erik Lindahl, David van der Spoel 2003,2004.
* Coordinate compression (c) by Frans van Hoesel.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*/
#ifndef __XXX
#define __XXX 1
//#include "rpc/types.h"
//#include "rpc/xdr.h"
#include <inttypes.h>
#include<cstdio>
enum xdr_op
{
XDR_ENCODE = 0,
XDR_DECODE = 1,
XDR_FREE = 2
};
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;
};
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 */
};
/*! \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!
#include "rpc/types.h"
#include "rpc/xdr.h"
*
* 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, exdrDUFF, exdrNR };
extern const 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_ */
#endif
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
*
* $Id: xdrfile_xtc.h,v 1.5 2009/05/18 09:06:38 spoel Exp $
*
* Copyright (c) Erik Lindahl, David van der Spoel 2003,2004.
* Coordinate compression (c) by Frans van Hoesel.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*/
#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);
/* 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
/*
MIT License
Copyright (c) 2023 Accellera
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Contributors: Stefan Doerr, Raul P. Pelaez
*/
#ifndef XTC
#define XTC
#include "xdrfile.h"
#include<string>
// Get the number of frames in a trajectory file
int xtc_nframes(std::string filename);
// Get the number of atoms in a trajectory file
int xtc_natoms(std::string filename);
// Reads nframes from an xtc file, fills the arrays in the input with
// the data. Each array must be allocated with the correct size.
void xtc_read(std::string filename, float* coords_arr, float* box_arr, float* time_arr, int* step_arr, int natoms, int nframes);
// Appends a trajectory to a file.
void xtc_write(std::string filename, int natoms, int nframes, int* step, float* timex, float* pos, float* box);
// Rewrites a trajectory file with a new timestep and starting step number.
// Useful when the step number is larger than 2^32.
void xtc_rewrite_with_new_timestep(std::string filename_in, std::string filename_out, int first_step, int interval, float dt);
#endif
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
*
* $Id: xdrfile.c,v 1.3 2009/05/18 09:06:38 spoel Exp $
*
* Copyright (c) Erik Lindahl, David van der Spoel 2003,2004.
* Coordinate compression (c) by Frans van Hoesel.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*/
/* Get HAVE_RPC_XDR_H, F77_FUNC from config.h if available */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static void * condfree( void*p) {
if(p) { free(p); }
else {
fprintf( stderr, "Double free detected\n" );
abort();
}
return NULL;
}
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>
/* get fixed-width types if we are using ANSI C99 */
#ifdef HAVE_STDINT_H
# include <stdint.h>
#elif (defined HAVE_INTTYPES_H)
# include <inttypes.h>
#endif
#ifdef HAVE_RPC_XDR_H
# include <rpc/rpc.h>
# include <rpc/xdr.h>
#endif
#include "xdrfile.h"
/* Default FORTRAN name mangling is: lower case name, append underscore */
#ifndef F77_FUNC
#define F77_FUNC(name,NAME) name ## _
#endif
const 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)
/* 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
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.
*/
/*************************************************************
* 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)
{
xfp=(XDRFILE *)condfree(xfp);
return NULL;
}
if((xfp->xdr=(XDR *)malloc(sizeof(XDR)))==NULL)
{
fclose(xfp->fp);
xfp=(XDRFILE *)condfree(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));
xfp->xdr=(XDR *)condfree(xfp->xdr);
/* close the file */
ret=fclose(xfp->fp);
if(xfp->buf1size)
xfp->buf1=(int *)condfree(xfp->buf1);
if(xfp->buf2size)
xfp->buf2=(int *)condfree(xfp->buf2);
xfp=(XDRFILE *)condfree(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(i<ndata && xdr_int((XDR *)(xfp->xdr),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(i<ndata && xdr_int((XDR *)(xfp->xdr),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(i<ndata && xdr_u_int((XDR *)(xfp->xdr),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(i<ndata && xdr_u_int((XDR *)(xfp->xdr),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(i<ndata && xdr_char((XDR *)(xfp->xdr),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(i<ndata && xdr_char((XDR *)(xfp->xdr),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(i<ndata && xdr_u_char((XDR *)(xfp->xdr),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(i<ndata && xdr_u_char((XDR *)(xfp->xdr),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(i<ndata && xdr_short((XDR *)(xfp->xdr),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(i<ndata && xdr_short((XDR *)(xfp->xdr),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(i<ndata && xdr_u_short((XDR *)(xfp->xdr),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(i<ndata && xdr_u_short((XDR *)(xfp->xdr),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(i<ndata && xdr_float((XDR *)(xfp->xdr),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(i<ndata && xdr_float((XDR *)(xfp->xdr),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(i<ndata && xdr_double((XDR *)(xfp->xdr),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(i<ndata && xdr_double((XDR *)(xfp->xdr),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(i<maxlen && ptr[i]!=0)
i++;
if(i==maxlen)
return maxlen;
else
return i+1;
} else
return 0;
}
int
xdrfile_write_string(char *ptr, XDRFILE* xfp)
{
int len=strlen(ptr)+1;
if(xdr_string((XDR *)(xfp->xdr),&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,"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.
*
*/
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];
switch( sizes[i] ) {
case 645: p = num / 645; break;
case 512: p = num / 512; break;
case 203: p = num / 203; break;
default: p = num / sizes[i];
}
//printf("%d\n", 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;
int errval=1;
int countmjh=0;
sizeint[0] = sizeint[1] = sizeint[2] = 0;
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, "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(4096 + sizeof(int)*size3))==NULL)
{
fprintf(stderr,"Cannot allocate memory for decompressing coordinates.\n");
return -1;
}
xfp->buf1size=size3;
xfp->buf2size=size3*1.2;
if((xfp->buf2=(int *)malloc(4096 + sizeof(int)*xfp->buf2size))==NULL)
{
fprintf(stderr,"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;
if( !sizeint[0] || !sizeint[1] || !sizeint[2] ) {
//fprintf( stderr, "XTC file corrupt\n" );
return exdrDUFF;
}
/* 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; /* not sure what has happened here or why we return... */
tmp=smallidx+8;
maxidx = (LASTIDX<tmp) ? LASTIDX : tmp;
minidx = maxidx - 8; /* often this equal smallidx */
tmp = smallidx-1;
tmp = (FIRSTIDX>tmp) ? FIRSTIDX : tmp;
smaller = magicints[tmp] / 2;
smallnum = magicints[smallidx] / 2;
sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx] ;
larger = magicints[maxidx];
if( !sizesmall[0] || !sizesmall[1] || !sizesmall[2] ) {
//fprintf(stderr, "XTC file corrupt\n");
return exdrDUFF;
}
/* 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;
countmjh++; if( countmjh> 3* *size) { return -1; }
*lfp++ = prevcoord[1] * inv_precision;
countmjh++; if( countmjh> 3* *size) { return -1; }
*lfp++ = prevcoord[2] * inv_precision;
countmjh++; if( countmjh> 3* *size) { return -1; }
} else {
prevcoord[0] = thiscoord[0];
prevcoord[1] = thiscoord[1];
prevcoord[2] = thiscoord[2];
}
if(countmjh >= size3 ) { return -1; }
*lfp++ = thiscoord[0] * inv_precision;
countmjh++; if( countmjh> 3* *size) { return -1; }
if(countmjh >= size3 ) { return -1; }
*lfp++ = thiscoord[1] * inv_precision;
countmjh++; if( countmjh> 3* *size) { return -1; }
if(countmjh >= size3 ) { return -1; }
*lfp++ = thiscoord[2] * inv_precision;
countmjh++; if( countmjh> 3* *size) { return -1; }
}
}
else
{
if(countmjh >= size3 ) { return -1; }
*lfp++ = thiscoord[0] * inv_precision;
countmjh++; if( countmjh> 3* *size) { return -1; }
if(countmjh >= size3 ) { return -1; }
*lfp++ = thiscoord[1] * inv_precision;
countmjh++; if( countmjh> 3* *size) { return -1; }
if(countmjh >= size3 ) { return -1; }
*lfp++ = thiscoord[2] * inv_precision;
countmjh++; if( countmjh> 3* *size) { return -1; }
}
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] || !sizesmall[1] || !sizesmall[2] ) {
//fprintf( stderr, "XTC file corrupt\n");
return exdrDUFF;
}
}
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=0, tmpsum=0, *thiscoord=NULL, prevcoord[3]={0,0,0};
unsigned int tmpcoord[30];
unsigned int bitsize;
int countmjh=0;
int errval;
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,"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,"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,"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++;
countmjh++; if( countmjh> size3) { return -1; }
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,"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++;
countmjh++; if( countmjh> size3) { return -1; }
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++;
countmjh++; if( countmjh> size3) { return -1; }
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,"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 = (LASTIDX<tmp) ? LASTIDX : tmp;
minidx = maxidx - 8; /* often this equal smallidx */
tmp=smallidx-1;
tmp= (FIRSTIDX>tmp) ? 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, maxidx, minidx;
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;
int errval=1;
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, "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,"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,"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;
if( !sizeint[0] || !sizeint[1] || !sizeint[2] ) {
//fprintf( stderr, "XTC file corrupt\n" );
return exdrDUFF;
}
/* 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 = (LASTIDX<tmp) ? LASTIDX : tmp;
minidx = maxidx - 8; /* often this equal smallidx */
tmp = smallidx-1;
tmp = (FIRSTIDX>tmp) ? 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=0, tmpsum=0, *thiscoord=NULL, prevcoord[3]={0,0,0};
unsigned int tmpcoord[30];
unsigned int bitsize;
int errval=1;
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,"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,"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,"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,"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,"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 = (LASTIDX<tmp) ? LASTIDX : tmp;
minidx = maxidx - 8; /* often this equal smallidx */
tmp=smallidx-1;
tmp= (FIRSTIDX>tmp) ? 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<MAX_FORTRAN_XDR;i++)
f77xdr[i]=NULL;
f77init=0;
}
i=0;
/* nf77xdr is always smaller or equal to MAX_FORTRAN_XDR */
while(i<MAX_FORTRAN_XDR && f77xdr[i]!=NULL)
i++;
if(i==MAX_FORTRAN_XDR) {
*fid = -1;
} else if (ftocstr(cfilename, sizeof(cfilename), filename, fn_len)) {
*fid = -1;
} else if (ftocstr(cmode, sizeof(cmode), mode,mode_len)) {
*fid = -1;
} else {
f77xdr[i]=xdrfile_open(cfilename,cmode);
/* return the index in the array as a fortran file handle */
*fid=i;
}
}
void
F77_FUNC(xdrclose,XDRCLOSE)(int *fid)
{
/* first close it */
xdrfile_close(f77xdr[*fid]);
/* the remove it from file handle list */
f77xdr[*fid]=NULL;
}
void
F77_FUNC(xdrrint,XDRRINT)(int *fid, int *data, int *ndata, int *ret)
{
*ret = xdrfile_read_int(data,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrwint,XDRWINT)(int *fid, int *data, int *ndata, int *ret)
{
*ret = xdrfile_write_int(data,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrruint,XDRRUINT)(int *fid, unsigned int *data, int *ndata, int *ret)
{
*ret = xdrfile_read_uint(data,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrwuint,XDRWUINT)(int *fid, unsigned int *data, int *ndata, int *ret)
{
*ret = xdrfile_write_uint(data,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrrchar,XDRRCHAR)(int *fid, char *ip, int *ndata, int *ret)
{
*ret = xdrfile_read_char(ip,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrwchar,XDRWCHAR)(int *fid, char *ip, int *ndata, int *ret)
{
*ret = xdrfile_write_char(ip,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrruchar,XDRRUCHAR)(int *fid, unsigned char *ip, int *ndata, int *ret)
{
*ret = xdrfile_read_uchar(ip,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrwuchar,XDRWUCHAR)(int *fid, unsigned char *ip, int *ndata, int *ret)
{
*ret = xdrfile_write_uchar(ip,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrrshort,XDRRSHORT)(int *fid, short *ip, int *ndata, int *ret)
{
*ret = xdrfile_read_short(ip,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrwshort,XDRWSHORT)(int *fid, short *ip, int *ndata, int *ret)
{
*ret = xdrfile_write_short(ip,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrrushort,XDRRUSHORT)(int *fid, unsigned short *ip, int *ndata, int *ret)
{
*ret = xdrfile_read_ushort(ip,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrwushort,XDRWUSHORT)(int *fid, unsigned short *ip, int *ndata, int *ret)
{
*ret = xdrfile_write_ushort(ip,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrrsingle,XDRRSINGLE)(int *fid, float *data, int *ndata, int *ret)
{
*ret = xdrfile_read_float(data,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrwsingle,XDRWSINGLE)(int *fid, float *data, int *ndata, int *ret)
{
*ret = xdrfile_write_float(data,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrrdouble,XDRRDOUBLE)(int *fid, double *data, int *ndata, int *ret)
{
*ret = xdrfile_read_double(data,*ndata,f77xdr[*fid]);
}
void
F77_FUNC(xdrwdouble,XDRWDOUBLE)(int *fid, double *data, int *ndata, int *ret)
{
*ret = xdrfile_write_double(data,*ndata,f77xdr[*fid]);
}
static int ftocstr(char *dest, int destlen, char *src, int srclen)
{
char *p;
p = src + srclen;
while ( --p >= 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;
cstr=(char *)condfree(cstr);
return;
}
*ret = xdrfile_read_string(cstr, len+1,f77xdr[*fid]);
ctofstr( str, len , cstr);
cstr=(char *)condfree(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;
cstr=(char *)condfree(cstr);
return;
}
*ret = xdrfile_write_string(cstr, f77xdr[*fid]);
ctofstr( str, len , cstr);
cstr=(char *)condfree(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
// Apple clang does not support thread_local
#ifdef __APPLE__
static __thread char xdr_zero[BYTES_PER_XDR_UNIT] = {0, 0, 0, 0};
#else
thread_local char xdr_zero[BYTES_PER_XDR_UNIT] = {0, 0, 0, 0};
#endif
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 = 0 ;
unsigned int nodesize = 0;
/*
* 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:
sp=(char *)condfree (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::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::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 */
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
*
* $Id: xdrfile_xtc.c,v 1.5 2009/05/18 09:06:38 spoel Exp $
*
* Copyright (c) Erik Lindahl, David van der Spoel 2003,2004.
* Coordinate compression (c) by Frans van Hoesel.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*/
#include <stdio.h>
#include <stdlib.h>
#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 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(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;
}
/*
MIT License
Copyright (c) 2023 Accellera
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Contributors: Stefan Doerr, Raul P. Pelaez
*/
#include "xtc.h"
#include "xdrfile_xtc.h"
#include <vector>
#include <string>
#include <stdexcept>
// Helper functions to convert between atom/frame and x/y/z indices
static size_t Xf(size_t atom, size_t frame, size_t nframes) {
return atom * 3 * nframes + frame;
}
static size_t Yf(size_t xidx, size_t nframes) {
return xidx + nframes;
}
static size_t Zf(size_t yidx, size_t nframes) {
return yidx + nframes;
}
// Helper struct to manage the XDRFILE pointer
struct XDRFILE_RAII {
XDRFILE* xd;
XDRFILE_RAII(std::string filename, std::string mode) : xd(xdrfile_open(filename.c_str(), mode.c_str())) {
if (!xd) {
throw std::runtime_error("xtc file: Could not open file");
}
}
~XDRFILE_RAII() {
if (xd)
xdrfile_close(xd);
}
operator XDRFILE*() const {
return xd;
}
};
int xtc_natoms(std::string filename) {
int natoms = 0;
if (exdrOK != read_xtc_natoms(const_cast<char*>(filename.c_str()), &natoms)) {
throw std::runtime_error("xtc_read(): could not get natoms\n");
}
return natoms;
}
struct XTCFrame {
int step;
float time;
matrix box;
std::vector<float> positions;
int natoms;
const float prec = 1000.0;
XTCFrame(int natoms) : positions(3 * natoms), natoms(natoms) {
}
// Read the next frame from the XTC file and store it in this object
int readNextFrame(XDRFILE* xd) {
float in_prec;
auto* p_ptr = reinterpret_cast<rvec*>(positions.data());
int status = read_xtc(xd, natoms, &step, &time, box, p_ptr, &in_prec);
if (status == exdrOK && prec != in_prec) {
throw std::runtime_error("xtc_read(): precision mismatch\n");
}
if (status == exdr3DX) {
throw std::runtime_error("xtc_read(): XTC file is corrupt\n");
}
return status;
}
// Write the current frame to the XTC file
int appendFrameToFile(XDRFILE* xd) {
auto* p_ptr = reinterpret_cast<rvec*>(positions.data());
int err = write_xtc(xd, natoms, step, time, box, p_ptr, prec);
if (err != exdrOK) {
throw std::runtime_error("xtc_write(): could not write frame\n");
}
return err;
}
};
int xtc_nframes(std::string filename) {
int nframes = 0;
int natoms = xtc_natoms(filename);
if (!natoms) {
throw std::runtime_error("xtc_read(): natoms is 0\n");
}
XDRFILE_RAII xd(filename, "r");
XTCFrame frame(natoms);
while (exdrOK == frame.readNextFrame(xd)) {
nframes++;
}
return nframes;
}
void xtc_read(std::string filename, float* coords_arr, float* box_arr, float* time_arr, int* step_arr, int natoms, int nframes) {
if (natoms == 0) {
throw std::runtime_error("xtc_read(): natoms is 0\n");
}
XDRFILE_RAII xd(filename, "r");
int fidx = 0;
XTCFrame frame(natoms);
while (exdrOK == frame.readNextFrame(xd)) {
time_arr[fidx] = frame.time;
step_arr[fidx] = frame.step;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
box_arr[fidx + (3 * i + j) * nframes] = frame.box[i][j];
}
}
for (int aidx = 0; aidx < natoms; aidx++) {
int xidx = Xf(aidx, fidx, nframes);
int yidx = Yf(xidx, nframes);
int zidx = Zf(yidx, nframes);
coords_arr[xidx] = frame.positions[3 * aidx + 0];
coords_arr[yidx] = frame.positions[3 * aidx + 1];
coords_arr[zidx] = frame.positions[3 * aidx + 2];
}
fidx++;
}
}
static void box_from_array(matrix& matrix_box, float* box, int frame, int nframes) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
matrix_box[i][j] = box[(3 * i + j) * nframes + frame];
}
}
}
void xtc_write(std::string filename, int natoms, int nframes, int* step, float* timex, float* pos, float* box) {
XDRFILE_RAII xd(filename, "a");
XTCFrame frame(natoms);
for (int f = 0; f < nframes; f++) {
box_from_array(frame.box, box, f, nframes);
for (int i = 0; i < natoms; i++) {
int xidx = Xf(i, f, nframes);
int yidx = Yf(xidx, nframes);
int zidx = Zf(yidx, nframes);
frame.positions[3 * i + 0] = pos[xidx];
frame.positions[3 * i + 1] = pos[yidx];
frame.positions[3 * i + 2] = pos[zidx];
}
frame.step = step[f];
frame.time = timex[f];
frame.appendFrameToFile(xd);
}
}
void xtc_rewrite_with_new_timestep(std::string filename_in, std::string filename_out, int first_step, int interval, float dt) {
int natoms = xtc_natoms(filename_in);
if (natoms == 0) {
throw std::runtime_error("xtc_read(): natoms is 0\n");
}
XDRFILE_RAII xd_in(filename_in, "r");
XDRFILE_RAII xd_out(filename_out, "a");
XTCFrame frame(natoms);
int i = 0;
while (exdrOK == frame.readNextFrame(xd_in)) {
frame.step = first_step + i * interval;
frame.time = frame.step * dt;
frame.appendFrameToFile(xd_out);
i++;
}
}
# MIT License
# Copyright (c) 2023 Accellera
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Contributors: Stefan Doerr, Raul P. Pelaez
import numpy as np
cimport numpy as np
cimport xtclib
from libcpp.string cimport string
ctypedef np.float32_t FLOAT32_t
def get_xtc_nframes(string filename):
"""
Get the number of frames in a xtc file.
Parameters
----------
filename: string
The filename of the xtc file. You need to pass the string with filename.encode("UTF-8") to this function
Returns
-------
nframes: int
The number of frames in the xtc file
"""
return xtclib.xtc_nframes(filename)
def get_xtc_natoms(string filename):
"""
Get the number of atoms in a xtc file.
Parameters
----------
filename: string
The filename of the xtc file. You need to pass the string with filename.encode("UTF-8") to this function
Returns
-------
natoms: int
The number of atoms in the xtc file
"""
return xtclib.xtc_natoms(filename)
def read_xtc(string filename):
"""
Reads a xtc file and return its contents.
Parameters
----------
filename: string
The filename of the xtc file. You need to pass the string with filename.encode("UTF-8") to this function
Returns
-------
coords: np.ndarray
The coordinates of the atoms in the xtc file. Shape: (n_atoms, 3, n_frames)
box: np.ndarray
The box vectors of the xtc file. Shape: (3, 3, n_frames)
time: np.ndarray
The time of each frame. Shape: (n_frames,)
step: np.ndarray
The step of each frame. Shape: (n_frames,)
"""
cdef int natoms = get_xtc_natoms(filename)
cdef int nframes = get_xtc_nframes(filename)
cdef FLOAT32_t[:, :, ::1] coords = np.zeros((natoms, 3, nframes), dtype=np.float32)
cdef FLOAT32_t[:, :, ::1] box = np.zeros((3, 3, nframes), dtype=np.float32)
cdef FLOAT32_t[::1] time = np.zeros(nframes, dtype=np.float32)
cdef int[::1] step = np.zeros(nframes, dtype=np.int32)
xtclib.xtc_read(
filename,
&coords[0, 0, 0],
&box[0, 0, 0],
&time[0],
&step[0],
natoms,
nframes,
)
return np.asarray(coords), np.asarray(box), np.asarray(time), np.asarray(step)
def xtc_write_frame(string filename, float[:, :] coords, float[:, :] box, float time, int step):
"""
Appends a single frame to a xtc file (if the file does not exist it is created by this function).
Parameters
----------
filename: string
The filename of the xtc file. You need to pass the string with filename.encode("UTF-8") to this function
coords: np.ndarray
The coordinates of the atoms in the frame. Shape: (n_atoms, 3)
box: np.ndarray
The box vectors of the frame. Shape: (3, 3)
time: float
The time of the frame
step: int
The step of the frame
"""
cdef int natoms = coords.shape[0]
cdef int nframes = 1
xtclib.xtc_write(
filename,
natoms,
nframes,
&step,
&time,
&coords[0, 0],
&box[0, 0]
)
def xtc_rewrite_with_new_timestep(string filename_in, string filename_out,
int first_step, int interval, float dt):
"""
Rewrites a trajectory file with a new timestep and starting step number.
Parameters
----------
filename_in: string
The filename of the input xtc file. You need to pass the string with filename.encode("UTF-8") to this function
filename_out: string
The filename of the output xtc file. You need to pass the string with filename.encode("UTF-8") to this function
first_step: int
The first step to be written to the output file
interval: int
The interval between steps to be written to the output file
dt: float
The timestep of the output file
"""
xtclib.xtc_rewrite_with_new_timestep(filename_in, filename_out, first_step, interval, dt)
# MIT License
# Copyright (c) 2023 Accellera
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Contributors: Stefan Doerr, Raul P. Pelaez
from libcpp.string cimport string
cdef extern from "include/xtc.h":
cdef int xtc_nframes(string filename) except +
cdef int xtc_natoms(string filename) except +
cdef void xtc_read(string filename, float *coords_arr, float *box_arr, float *time_arr, int *step_arr, int natoms, int nframes) except +
cdef void xtc_write(string filename, int natoms, int nframes, int *step, float *timex, float *pos, float *box) except +
cdef void xtc_rewrite_with_new_timestep(string filename_in, string filename_out,
int first_step, int interval, float dt) except +
from __future__ import print_function, division, absolute_import
__author__ = "Raul P. Pelaez"
__version__ = "1.0"
from openmm.app.internal.xtc_utils import (
xtc_rewrite_with_new_timestep,
xtc_write_frame,
get_xtc_nframes,
get_xtc_natoms,
)
import numpy as np
import os
from openmm import Vec3
from openmm.unit import nanometers, femtoseconds, is_quantity, norm
import math
import tempfile
import shutil
class XTCFile(object):
"""XTCFile provides methods for creating XTC files.
To use this class, create a XTCFile object, then call writeModel() once for each model in the file.
"""
def __init__(self, fileName, topology, dt, firstStep=0, interval=1, append=False):
"""Create a XTC file, or open an existing file to append.
Parameters
----------
fileName : str
A file name to write to
topology : Topology
The Topology defining the molecular system being written
dt : time
The time step used in the trajectory
firstStep : int=0
The index of the first step in the trajectory
interval : int=1
The frequency (measured in time steps) at which states are written
to the trajectory
append : bool=False
If True, open an existing XTC file to append to. If False, create a new file.
"""
if not isinstance(fileName, str):
raise TypeError("fileName must be a string")
self._filename = fileName
self._topology = topology
self._firstStep = firstStep
self._interval = interval
self._modelCount = 0
if is_quantity(dt):
dt = dt.value_in_unit(femtoseconds)
self._dt = dt
if append:
if not os.path.isfile(self._filename):
raise FileNotFoundError(f"The file '{self._filename}' does not exist.")
self._modelCount = get_xtc_nframes(self._filename.encode("utf-8"))
natoms = get_xtc_natoms(self._filename.encode("utf-8"))
if natoms != len(list(topology.atoms())):
raise ValueError(
f"The number of atoms in the topology ({len(list(topology.atoms()))}) does not match the number of atoms in the XTC file ({natoms})"
)
else:
if os.path.isfile(self._filename) and os.path.getsize(self._filename) > 0:
raise FileExistsError(f"The file '{self._filename}' already exists.")
def _getNumFrames(self):
return get_xtc_nframes(self._filename.encode("utf-8"))
def writeModel(self, positions, unitCellDimensions=None, periodicBoxVectors=None):
"""Write out a model to the XTC file.
The periodic box can be specified either by the unit cell dimensions
(for a rectangular box), or the full set of box vectors (for an
arbitrary triclinic box). If neither is specified, the box vectors
specified in the Topology will be used. Regardless of the value
specified, no dimensions will be written if the Topology does not
represent a periodic system.
Parameters
----------
positions : list
The list of atomic positions to write
unitCellDimensions : Vec3=None
The dimensions of the crystallographic unit cell.
periodicBoxVectors : tuple of Vec3=None
The vectors defining the periodic box.
"""
if self._topology.getNumAtoms() != len(positions):
raise ValueError("The number of positions must match the number of atoms")
if is_quantity(positions):
positions = positions.value_in_unit(nanometers)
if any(math.isnan(norm(pos)) for pos in positions):
raise ValueError(
"Particle position is NaN. For more information, see https://github.com/openmm/openmm/wiki/Frequently-Asked-Questions#nan"
)
if any(math.isinf(norm(pos)) for pos in positions):
raise ValueError(
"Particle position is infinite. For more information, see https://github.com/openmm/openmm/wiki/Frequently-Asked-Questions#nan"
)
self._modelCount += 1
if (
self._interval > 1
and self._firstStep + self._modelCount * self._interval > 1 << 31
):
# This will exceed the range of a 32 bit integer. To avoid crashing or producing a corrupt file,
# update the file to say the trajectory consisted of a smaller number of larger steps (so the
# total trajectory length remains correct).
self._firstStep //= self._interval
self._dt *= self._interval
self._interval = 1
with tempfile.TemporaryDirectory() as temp:
fname = os.path.join(temp, "temp.xtc")
xtc_rewrite_with_new_timestep(
self._filename.encode("utf-8"),
fname.encode("utf-8"),
self._firstStep,
self._interval,
self._dt,
)
shutil.copyfile(fname, self._filename)
boxVectors = self._topology.getPeriodicBoxVectors()
if boxVectors is not None:
if periodicBoxVectors is not None:
boxVectors = periodicBoxVectors
if is_quantity(boxVectors):
boxVectors = boxVectors.value_in_unit(nanometers)
elif unitCellDimensions is not None:
if is_quantity(unitCellDimensions):
unitCellDimensions = unitCellDimensions.value_in_unit(nanometers)
boxVectors = (
Vec3(unitCellDimensions[0], 0, 0),
Vec3(0, unitCellDimensions[1], 0),
Vec3(0, 0, unitCellDimensions[2]),
)
boxVectors = np.array(
[[vec.x, vec.y, vec.z] for vec in boxVectors], dtype=np.float32
)
else:
boxVectors = np.zeros((3, 3)).astype(np.float32)
step = self._modelCount * self._interval + self._firstStep
time = step * self._dt
xtc_write_frame(
self._filename.encode("utf-8"),
np.array(positions, dtype=np.float32),
boxVectors,
np.float32(time),
np.int32(step),
)
__author__ = "Raul P. Pelaez"
from openmm.app import XTCFile
class XTCReporter(object):
"""XTCReporter outputs a series of frames from a Simulation to a XTC file.
To use it, create a XTCReporter, then add it to the Simulation's list of reporters.
"""
def __init__(self, file, reportInterval, append=False, enforcePeriodicBox=None):
"""Create a XTCReporter.
Parameters
----------
file : string
The file to write to
reportInterval : int
The interval (in time steps) at which to write frames
append : bool=False
If True, open an existing XTC file to append to. If False, create a new file.
enforcePeriodicBox: bool
Specifies whether particle positions should be translated so the center of every molecule
lies in the same periodic box. If None (the default), it will automatically decide whether
to translate molecules based on whether the system being simulated uses periodic boundary
conditions.
"""
self._reportInterval = reportInterval
self._append = append
self._enforcePeriodicBox = enforcePeriodicBox
self._fileName = file
self._xtc = None
def describeNextReport(self, simulation):
"""Get information about the next report this object will generate.
Parameters
----------
simulation : Simulation
The Simulation to generate a report for
Returns
-------
tuple
A six element tuple. The first element is the number of steps
until the next report. The next four elements specify whether
that report will require positions, velocities, forces, and
energies respectively. The final element specifies whether
positions should be wrapped to lie in a single periodic box.
"""
steps = self._reportInterval - simulation.currentStep % self._reportInterval
return (steps, True, False, False, False, self._enforcePeriodicBox)
def report(self, simulation, state):
"""Generate a report.
Parameters
----------
simulation : Simulation
The Simulation to generate a report for
state : State
The current state of the simulation
"""
if self._xtc is None:
self._xtc = XTCFile(
self._fileName,
simulation.topology,
simulation.integrator.getStepSize(),
simulation.currentStep,
self._reportInterval,
self._append,
)
self._xtc.writeModel(
state.getPositions(), periodicBoxVectors=state.getPeriodicBoxVectors()
)
......@@ -229,6 +229,22 @@ def buildKeywordDictionary(major_version_num=MAJOR_VERSION_NUM,
setupKeywords["ext_modules"] = [Extension(**extensionArgs)]
setupKeywords["ext_modules"] += cythonize('openmm/app/internal/*.pyx')
setupKeywords["ext_modules"] +=cythonize(Extension(
"openmm.app.internal.xtc_utils",
sources=[
"openmm/app/internal/xtc_utils/src/xdrfile_xtc.cpp",
"openmm/app/internal/xtc_utils/src/xdrfile.cpp",
"openmm/app/internal/xtc_utils/src/xtc.cpp",
"openmm/app/internal/xtc_utils/xtc.pyx",
],
include_dirs=include_dirs +[
"openmm/app/internal/xtc_utils/include",
"openmm/app/internal/xtc_utils/",
numpy.get_include(),
],
language="c++",
))
outputString = ''
firstTab = 40
secondTab = 60
......
__author__ = "Raul P. Pelaez"
import sys
import os
import unittest
from openmm import unit
import tempfile
from openmm import app
from random import random
import openmm as mm
import numpy as np
from openmm.app.internal.xtc_utils import read_xtc
class TestXtcFile(unittest.TestCase):
def test_xtc_triclinic(self):
"""Test the XTC file by writing a trajectory and reading it back. Using a triclinic box"""
with tempfile.TemporaryDirectory() as temp:
fname = os.path.join(temp, 'traj.xtc')
pdbfile = app.PDBFile("systems/alanine-dipeptide-implicit.pdb")
# Set some arbitrary size for the unit cell so that a box is included in the trajectory
pdbfile.topology.setUnitCellDimensions([10, 10, 10])
natom = len(list(pdbfile.topology.atoms()))
nframes = 20
xtc = app.XTCFile(fname, pdbfile.topology, 0.001)
coords = []
box = []
for i in range(nframes):
coords.append(
[mm.Vec3(random(), random(), random()) for j in range(natom)]
* unit.nanometers
)
box_i = (
mm.Vec3(random(), random(), random()) * unit.nanometers,
mm.Vec3(random(), random(), random()) * unit.nanometers,
mm.Vec3(random(), random(), random()) * unit.nanometers,
)
box.append(np.array([[vec.x, vec.y, vec.z] for vec in box_i]))
xtc.writeModel(coords[i], periodicBoxVectors=box_i)
# The XTCFile class does not provide a way to read the
# trajectory back, but the underlying XTC library does
coords_read, box_read, time, step = read_xtc(fname.encode("utf-8"))
self.assertEqual(coords_read.shape, (natom, 3, nframes))
self.assertEqual(box_read.shape, (3, 3, nframes))
self.assertEqual(len(time), nframes)
self.assertEqual(len(step), nframes)
coords = np.array(
[c.value_in_unit(unit.nanometers) for c in coords]
).transpose(1, 2, 0)
self.assertTrue(np.allclose(coords_read, coords, atol=1e-3))
box = np.array(box).transpose(1, 2, 0)
self.assertTrue(np.allclose(box_read, box, atol=1e-3))
self.assertTrue(
np.allclose(time, np.arange(1, nframes + 1) * 0.001, atol=1e-5)
)
self.assertTrue(np.allclose(step, np.arange(1, nframes + 1), atol=1e-5))
def test_xtc_cubic(self):
"""Test the XTC file by writing a trajectory and reading it back. Using a cubic box"""
with tempfile.TemporaryDirectory() as temp:
fname = os.path.join(temp, 'traj.xtc')
pdbfile = app.PDBFile("systems/alanine-dipeptide-implicit.pdb")
# Set some arbitrary size for the unit cell so that a box is included in the trajectory
pdbfile.topology.setUnitCellDimensions([10, 10, 10])
natom = len(list(pdbfile.topology.atoms()))
nframes=20
xtc = app.XTCFile(fname, pdbfile.topology, 0.001)
coords = []
box = []
for i in range(nframes):
coords.append(
[mm.Vec3(random(), random(), random()) for j in range(natom)]
* unit.nanometers
)
box_i = mm.Vec3(random(), random(), random()) * unit.nanometers
box.append(np.diag(box_i[:3].value_in_unit(unit.nanometers)))
xtc.writeModel(coords[i], unitCellDimensions=box_i)
#The XTCFile class does not provide a way to read the
#trajectory back, but the underlying XTC library does
coords_read, box_read, time, step = read_xtc(fname.encode("utf-8"))
self.assertEqual(coords_read.shape, (natom,3,nframes))
self.assertEqual(box_read.shape, (3,3,nframes))
self.assertEqual(len(time), nframes)
self.assertEqual(len(step), nframes)
coords = np.array(
[c.value_in_unit(unit.nanometers) for c in coords]
).transpose(1, 2, 0)
self.assertTrue(np.allclose(coords_read, coords, atol=1e-3))
box = np.array(box).transpose(1, 2, 0)
self.assertTrue(np.allclose(box_read, box, atol=1e-3))
self.assertTrue(
np.allclose(time, np.arange(1, nframes + 1) * 0.001, atol=1e-5)
)
self.assertTrue(np.allclose(step, np.arange(1, nframes + 1), atol=1e-5))
def test_xtc_box_from_topology(self):
"""Test the XTC file by writing a trajectory and reading it back. Letting the box be set from the topology"""
with tempfile.TemporaryDirectory() as temp:
fname = os.path.join(temp, 'traj.xtc')
pdbfile = app.PDBFile("systems/alanine-dipeptide-implicit.pdb")
# Set some arbitrary size for the unit cell so that a box is included in the trajectory
unitCell = mm.Vec3(random(), random(), random()) * unit.nanometers
pdbfile.topology.setUnitCellDimensions(unitCell)
natom = len(list(pdbfile.topology.atoms()))
nframes = 20
xtc = app.XTCFile(fname, pdbfile.topology, 0.001)
coords = []
for i in range(nframes):
coords.append(
[mm.Vec3(random(), random(), random()) for j in range(natom)]
* unit.nanometers
)
xtc.writeModel(coords[i])
# The XTCFile class does not provide a way to read the
# trajectory back, but the underlying XTC library does
coords_read, box_read, time, step = read_xtc(fname.encode("utf-8"))
self.assertEqual(coords_read.shape, (natom, 3, nframes))
self.assertEqual(box_read.shape, (3, 3, nframes))
self.assertEqual(len(time), nframes)
self.assertEqual(len(step), nframes)
coords = np.array(
[c.value_in_unit(unit.nanometers) for c in coords]
).transpose(1, 2, 0)
self.assertTrue(np.allclose(coords_read, coords, atol=1e-3))
boxVectors = (
mm.Vec3(unitCell[0].value_in_unit(unit.nanometers), 0, 0),
mm.Vec3(0, unitCell[1].value_in_unit(unit.nanometers), 0),
mm.Vec3(0, 0, unitCell[2].value_in_unit(unit.nanometers)),
)
boxVectors = np.array(
[[vec.x, vec.y, vec.z] for vec in boxVectors], dtype=np.float32
)
box = np.array(np.tile(boxVectors, (nframes, 1, 1))).transpose(1, 2, 0)
self.assertTrue(np.allclose(box_read, box, atol=1e-3))
self.assertTrue(
np.allclose(time, np.arange(1, nframes + 1) * 0.001, atol=1e-5)
)
self.assertTrue(np.allclose(step, np.arange(1, nframes + 1), atol=1e-5))
def testLongTrajectory(self):
"""Test writing a trajectory that has more than 2^31 steps."""
with tempfile.TemporaryDirectory() as temp:
fname = os.path.join(temp, 'traj.xtc')
pdbfile = app.PDBFile("systems/alanine-dipeptide-implicit.pdb")
natom = len(list(pdbfile.topology.atoms()))
xtc = app.XTCFile(fname, pdbfile.topology, 0.001, interval=1000000000)
for i in range(5):
xtc.writeModel(
[mm.Vec3(random(), random(), random()) for j in range(natom)]
* unit.angstroms
)
def testAppend(self):
"""Test appending to an existing trajectory."""
with tempfile.TemporaryDirectory() as temp:
fname = os.path.join(temp, 'traj.xtc')
pdb = app.PDBFile("systems/alanine-dipeptide-implicit.pdb")
ff = app.ForceField("amber99sb.xml", "tip3p.xml")
system = ff.createSystem(pdb.topology)
# Create a simulation and write some frames to a XTC file.
integrator = mm.VerletIntegrator(0.001 * unit.picoseconds)
simulation = app.Simulation(
pdb.topology,
system,
integrator,
mm.Platform.getPlatformByName("Reference"),
)
xtc = app.XTCReporter(fname, 2)
simulation.reporters.append(xtc)
simulation.context.setPositions(pdb.positions)
simulation.context.setVelocitiesToTemperature(300 * unit.kelvin)
simulation.step(10)
self.assertEqual(5, xtc._xtc._modelCount)
self.assertEqual(5, xtc._xtc._getNumFrames())
del simulation
del xtc
# Create a new simulation and have it append some more frames.
integrator = mm.VerletIntegrator(0.001 * unit.picoseconds)
simulation = app.Simulation(
pdb.topology,
system,
integrator,
mm.Platform.getPlatformByName("Reference"),
)
xtc = app.XTCReporter(fname, 2, append=True)
simulation.reporters.append(xtc)
simulation.context.setPositions(pdb.positions)
simulation.context.setVelocitiesToTemperature(300 * unit.kelvin)
simulation.step(10)
self.assertEqual(10, xtc._xtc._modelCount)
self.assertEqual(10, xtc._xtc._getNumFrames())
del simulation
del xtc
if __name__ == "__main__":
unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment