Logo Search packages:      
Sourcecode: pymol version File versions  Download package

Gromacs.h

/***************************************************************************
 *cr
 *cr            (C) Copyright 1995-2009 The Board of Trustees of the
 *cr                        University of Illinois
 *cr                         All Rights Reserved
 *cr
 ***************************************************************************/
/***************************************************************************
 * RCS INFORMATION:
 *      $RCSfile: Gromacs.h,v $
 *      $Author: johns $       $Locker:  $             $State: Exp $
 *      $Revision: 1.27 $       $Date: 2009/04/29 15:45:27 $
 ***************************************************************************/

/*
 * GROMACS file format reader for VMD
 *
 * This code provides a high level I/O library for reading
 * and writing the following file formats:
 *    gro   GROMACS format or trajectory
 *    g96   GROMOS-96 format or trajectory
 *    trj   Trajectory - x, v and f (binary, full precision)
 *    trr   Trajectory - x, v and f (binary, full precision, portable)
 *    xtc   Trajectory - x only (compressed, portable, any precision)
 *      top
 * Currently supported: gro trj trr g96 [xtc]
 *
 * TODO list
 *   o  velocities are ignored because VMD doesn't use them, but some other 
 *      program might ...
 *   o  gro_rec() assumes positions in .gro files are nanometers and
 *      converts to angstroms, whereas they really could be any unit
 */

#ifndef GROMACS_H
#define GROMACS_H

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#if defined(_AIX)
#include <strings.h>
#endif

#include "endianswap.h"

#if defined(WIN32) || defined(WIN64)
#define strcasecmp stricmp
#endif

#ifndef M_PI_2
#define M_PI_2 1.57079632679489661922
#endif

// Error codes for mdio_errno
#define MDIO_SUCCESS          0
#define MDIO_BADFORMAT        1
#define MDIO_EOF        2
#define MDIO_BADPARAMS        3
#define MDIO_IOERROR          4
#define MDIO_BADPRECISION     5
#define MDIO_BADMALLOC        6
#define MDIO_CANTOPEN         7
#define MDIO_BADEXTENSION     8
#define MDIO_UNKNOWNFMT       9
#define MDIO_CANTCLOSE        10
#define MDIO_WRONGFORMAT      11
#define MDIO_SIZEERROR        12
#define MDIO_UNKNOWNERROR     1000

#define MDIO_READ 0
#define MDIO_WRITE      1

#define MDIO_MAX_ERRVAL       11

// Format extensions
const char *mdio_fmtexts[] = {
    "",
    ".gro",
    ".trr",
    ".g96",
    ".trj",
    ".xtc",
    NULL
};


static int mdio_errcode;      // Last error code

#define TRX_MAGIC 1993  // Magic number for .trX files
#define XTC_MAGIC 1995  // Magic number for .xtc files
#define MAX_GRO_LINE    500   // Maximum line length of .gro files
#define MAX_G96_LINE    500   // Maximum line length of .g96 files
#define MAX_TRX_TITLE   80    // Maximum length of a title in .trX
#define MAX_MDIO_TITLE  80    // Maximum supported title length
#define ANGS_PER_NM     10    // Unit conversion factor
#define ANGS2_PER_NM2   100   // Unit conversion factor


// All the supported file types and their respective extensions
#define MDFMT_GRO       1
#define MDFMT_TRR       2
#define MDFMT_G96       3
#define MDFMT_TRJ       4
#define MDFMT_XTC       5


// A structure to hold .trX file format header information. This
// is an optional member of the md_file structure that is used
// when .trX files are being dealt with.
typedef struct {
      int version;            // File version number
      char title[MAX_TRX_TITLE + 1];      // File title
      int ir_size;
      int e_size;
      int box_size;
      int vir_size;
      int pres_size;
      int top_size;
      int sym_size;
      int x_size;       // Positions of atoms
      int v_size;       // Velocities of atoms
      int f_size;
      int natoms;       // Number of atoms in the system
      int step;
      int nre;
      float t;
      float lambda;
} trx_hdr;


// A generic i/o structure that contains information about the
// file itself and the input/output state
typedef struct {
      FILE *      f;    // Pointer to the file
      int   fmt;  // The file format
      int   prec; // Real number precision
      int   rev;  // Reverse endiannism?
      trx_hdr * trx;    // Trx files require a great deal more
                  // header data to be stored.
} md_file;


// A format-independent structure to hold header data from files
typedef struct {
      char title[MAX_MDIO_TITLE + 1];
      int natoms;
      float timeval;
} md_header;


// A format-independent structure to hold unit cell data
typedef struct {
  float A, B, C, alpha, beta, gamma;
} md_box;


// Timestep information
typedef struct {
      float *pos; // Position array (3 * natoms)
      //float *vel;     // Velocity array ** (VMD doesn't use this) **
      //float *f; // Force array ** (VMD doesn't use this) **
      //float *box;     // Computational box ** (VMD doesn't use this) **
      int natoms; // Number of atoms
      int step;   // Simulation step
      float time; // Time of simulation
  md_box *box;
} md_ts;


// Atom information
typedef struct {
      char resid[7];          // Residue index number
      char resname[7];  // Residue name
      int atomnum;            // Atom index number
      char atomname[7]; // Atom name
      float pos[3];           // Position array (3 * natoms)
      //float vel[3];   // Velocity array ** (VMD doesn't use this) **
} md_atom;


// Open a molecular dynamics file. The second parameter specifies
// the format of the file. If it is zero, the format is determined
// from the file extension. the third argument (if given) decides
// whether to read (==0) or to write (!= 0).
// using a default argument set to read for backward compatibility.
static md_file *mdio_open(const char *, const int, const int=MDIO_READ);

// Closes a molecular dynamics file.
static int mdio_close(md_file *);


// Format-independent file I/O routines
static int mdio_header(md_file *, md_header *);
static int mdio_timestep(md_file *, md_ts *);


// .gro file functions
static int gro_header(md_file *, char *, int, float *, int *, int = 1);
static int gro_rec(md_file *, md_atom *);
static int gro_timestep(md_file *, md_ts *);


// .trX file functions
static int trx_header(md_file *, int = 0);
static int trx_int(md_file *, int *);
static int trx_real(md_file *, float *);

static int trx_rvector(md_file *, float *);
static int trx_string(md_file *, char *, int);
static int trx_timestep(md_file *, md_ts *);

// .g96 file functions
static int g96_header(md_file *, char *, int, float *);
static int g96_timestep(md_file *, md_ts *);
static int g96_rec(md_file *, md_atom *);
static int g96_countatoms(md_file *);


// .xtc file functions
static int xtc_int(md_file *, int *);
static int xtc_float(md_file *, float *);
/* 
static int xtc_receivebits(int *, int);
static void xtc_receiveints(int *, int, int, const unsigned *, int *);
*/
static int xtc_timestep(md_file *, md_ts *);
static int xtc_3dfcoord(md_file *, float *, int *, float *);


// Error reporting functions
static int mdio_errno(void);
static const char *mdio_errmsg(int);
static int mdio_seterror(int);


// Miscellaneous functions
static int strip_white(char *);
static int mdio_readline(md_file *, char *, int, int = 1);
static int mdio_tsfree(md_ts *, int = 0);
static int mdio_readbox(md_box *, float *, float *, float *);



static int xtc_receivebits(int *, int);

// Error descriptions for mdio_errno
static const char *mdio_errdescs[] = {
      "no error",
      "file does not match format",
      "unexpected end-of-file reached",
      "function called with bad parameters",
      "file i/o error",
      "unsupported precision",
      "out of memory",
      "cannot open file",
      "bad file extension",
      "unknown file format",
      "cannot close file",
      "wrong file format for this function",
      "binary i/o error: sizeof(int) != 4",
      NULL
};

/*! \fn static inline bool host_is_little_endian(void)
 * detect endiannes of host machine. returns true on little endian machines. */
static inline int host_is_little_endian(void) 
{
  const union { unsigned char c[4]; unsigned int i; } 
  fixed = { { 0x10 , 0x20 , 0x40 , 0x80 } };
  const unsigned int i = 0x80402010U;
        
  if (fixed.i == i) {
    return 1;
  }
  return 0;
}



// Open a molecular dynamics file. The second parameter specifies
// the format of the file. If it is zero, the format is determined
// from the file extension.
md_file *mdio_open(const char *fn, const int fmt, const int rw) {
      md_file *mf;

      if (!fn) {
            mdio_seterror(MDIO_BADPARAMS);
            return NULL;
      }

      // Allocate memory
      mf = (md_file *) malloc(sizeof(md_file));
      if (!mf) {
            mdio_seterror(MDIO_BADMALLOC);
            return NULL;
      }

      // Zero out the structure
      memset(mf, 0, sizeof(md_file));

      // Determine the file type from the extension
      if (!fmt) {
            char *p;
            int n;

            // Seek to the extension part of the filename
            for (p = (char *) &fn[strlen(fn) - 1]; *p != '.' && p > fn; p--);
            if (p == fn) {
                  free(mf);
                  mdio_seterror(MDIO_BADEXTENSION);
                  return NULL;
            }

            // Check the extension against known extensions
            for (n = 1; mdio_fmtexts[n]; n++)
                  if (!strcasecmp(p, mdio_fmtexts[n])) break;

            // If !mdio_fmtexts[n], we failed (unknown ext)
            if (!mdio_fmtexts[n]) {
                  free(mf);
                  mdio_seterror(MDIO_UNKNOWNFMT);
                  return NULL;
            }

            // All set
            mf->fmt = n;
      }
      else {
            mf->fmt = fmt;
      }

      // Differentiate between binary and ascii files. Also,
      // .trX files need a header information structure allocated.
      switch (mf->fmt) {
    case MDFMT_GRO:
      case MDFMT_G96: /* fallthrough */
        if (rw) 
            mf->f = fopen(fn, "wt");
        else
            mf->f = fopen(fn, "rt");

            break;
      case MDFMT_TRR:
      case MDFMT_TRJ: /* fallthrough */
            // Allocate the trx header data struct
            mf->trx = (trx_hdr *) malloc(sizeof(trx_hdr));
            if (!mf->trx) {
                  free(mf);
                  mdio_seterror(MDIO_BADMALLOC);
                  return NULL;
            }
            memset(mf->trx, 0, sizeof(trx_hdr));
      case MDFMT_XTC:  /* fallthrough */
            // Finally, open the file
        if (rw)
            mf->f = fopen(fn, "wb");
        else
            mf->f = fopen(fn, "rb");

            break;
      default:
            free(mf);
            mdio_seterror(MDIO_UNKNOWNFMT);
            return NULL;
      }

      // Check for opening error
      if (!mf->f) {
            if (mf->trx) free(mf->trx);
            free(mf);
            mdio_seterror(MDIO_CANTOPEN);
            return NULL;
      }

      // File is opened, we're all set!
      mdio_seterror(MDIO_SUCCESS);
      return mf;
}


// Closes a molecular dynamics file.
static int mdio_close(md_file *mf) {
      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      if (fclose(mf->f) == EOF) return mdio_seterror(MDIO_CANTCLOSE);

      // Free the dynamically allocated memory
      if (mf->trx) free(mf->trx);
      free(mf);
      return mdio_seterror(MDIO_SUCCESS);
}


// Returns the last error code reported by any of the mdio functions
static int mdio_errno(void) {
      return mdio_errcode;
}


// Returns a textual message regarding an mdio error code
static const char *mdio_errmsg(int n) {
      if (n < 0 || n > MDIO_MAX_ERRVAL) return (char *) "unknown error";
      else return mdio_errdescs[n];
}


// Sets the error code and returns an appropriate return value
// for the calling function to return to its parent
static int mdio_seterror(int code) {
      mdio_errcode = code;
      return code ? -1 : 0;
}


// Reads a line from the text file, strips leading/trailing whitespace
// and newline, checks for errors, and returns the number of characters
// in the string on success or -1 on error.
static int mdio_readline(md_file *mf, char *buf, int n, int strip) {
      if (!buf || n < 1 || !mf) return mdio_seterror(MDIO_BADPARAMS);

      // Read the line
      fgets(buf, n, mf->f);

      // End of file reached?
      if (feof(mf->f)) return mdio_seterror(MDIO_EOF);

      // File I/O error?
      if (ferror(mf->f)) return mdio_seterror(MDIO_IOERROR);

        // comment line?
        if (buf[0] == '#') return mdio_readline(mf,buf,n,strip);

      // Strip whitespace
      if (strip) strip_white(buf);

      return strlen(buf);
}


// Strips leading and trailing whitespace from a string. Tabs,
// spaces, newlines and carriage returns are stripped. Example:
// "\n   hello\t \r" becomes "hello".
static int strip_white(char *buf) {
      int i, j, k;

      // Protect against NULL pointer
      if (!buf) return -1;
      if (!strlen(buf)) return -1;

      // Kill trailing whitespace first
      for (i = strlen(buf) - 1;
           buf[i] == ' ' || buf[i] == '\t' ||
           buf[i] == '\n' || buf[i] == '\r';
           i--)
            buf[i] = 0;

      // Skip past leading whitespace
      for (i = 0; buf[i] == ' ' || buf[i] == '\t' ||
           buf[i] == '\n' || buf[i] == '\r'; i++);
      if (i) {
            k = 0;
            for (j = i; buf[j]; j++)
                  buf[k++] = buf[j];
            buf[k] = 0;
      }

      return strlen(buf);
}


// Frees the memory allocated in a ts structure. The holderror
// parameter defaults to zero. Programs that are calling this
// function because of an error reported by another function should
// set holderror so that mdio_tsfree() does not overwrite the error
// code with mdio_seterror().
static int mdio_tsfree(md_ts *ts, int holderror) {
      if (!ts) {
            if (holderror) return -1;
            else return mdio_seterror(MDIO_BADPARAMS);
      }

      if (ts->pos && ts->natoms > 0) free(ts->pos);

  if (ts->box) free(ts->box);

      if (holderror) return -1;
      else return mdio_seterror(MDIO_SUCCESS);
}


// Converts box basis vectors to A, B, C, alpha, beta, and gamma.  
// Stores values in md_box struct, which should be allocated before calling
// this function.
static int mdio_readbox(md_box *box, float *x, float *y, float *z) {
  float A, B, C;

  if (!box) {
    return mdio_seterror(MDIO_BADPARAMS);
  }

  // A, B, C are the lengths of the x, y, z vectors, respectively
  A = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] ) * ANGS_PER_NM;
  B = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] ) * ANGS_PER_NM;
  C = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] ) * ANGS_PER_NM;
  if ((A<=0) || (B<=0) || (C<=0)) {
    /* Use zero-length box size and set angles to 90. */
    box->A = box->B = box->C = 0;
    box->alpha = box->beta = box->gamma = 90;
  } else {
    box->A = A;
    box->B = B;
    box->C = C;
  
    // gamma, beta, alpha are the angles between the x & y, x & z, y & z
    // vectors, respectively
    box->gamma = acos( (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])*ANGS2_PER_NM2/(A*B) ) * 90.0/M_PI_2;
    box->beta = acos( (x[0]*z[0]+x[1]*z[1]+x[2]*z[2])*ANGS2_PER_NM2/(A*C) ) * 90.0/M_PI_2;
    box->alpha = acos( (y[0]*z[0]+y[1]*z[1]+y[2]*z[2])*ANGS2_PER_NM2/(B*C) ) * 90.0/M_PI_2; 
  }
  return mdio_seterror(MDIO_SUCCESS);
}


// Reads the header of a file (format independent)
static int mdio_header(md_file *mf, md_header *mdh) {
      int n;
      if (!mf || !mdh) return mdio_seterror(MDIO_BADPARAMS);
      if (!mf->f) return mdio_seterror(MDIO_BADPARAMS);

      switch (mf->fmt) {
      case MDFMT_GRO:
            if (gro_header(mf, mdh->title, MAX_MDIO_TITLE,
            &mdh->timeval, &mdh->natoms, 1) < 0)
                  return -1;
            return 0;

      case MDFMT_TRR: 
      case MDFMT_TRJ: /* fallthrough */
            if (trx_header(mf, 1) < 0) return -1;
            mdh->natoms = mf->trx->natoms;
            mdh->timeval = (float) mf->trx->t;
            strncpy(mdh->title, mf->trx->title, MAX_MDIO_TITLE);
            return 0;

      case MDFMT_G96:
            if (g96_header(mf, mdh->title, MAX_MDIO_TITLE,
            &mdh->timeval) < 0) return -1;
            mdh->natoms = -1;
            return 0;

      case MDFMT_XTC:
            memset(mdh, 0, sizeof(md_header));
            // Check magic number
            if (xtc_int(mf, &n) < 0) return -1;
            if (n != XTC_MAGIC) return mdio_seterror(MDIO_BADFORMAT);

            // Get number of atoms
            if (xtc_int(mf, &n) < 0) return -1;
            mdh->natoms = n;
            rewind(mf->f);
            return 0;

      default:
            return mdio_seterror(MDIO_UNKNOWNFMT);
      }
}


// Reads in a timestep from a file (format independent)
static int mdio_timestep(md_file *mf, md_ts *ts) {
      if (!mf || !ts) return mdio_seterror(MDIO_BADPARAMS);
      if (!mf->f) return mdio_seterror(MDIO_BADPARAMS);

      switch (mf->fmt) {
      case MDFMT_GRO:
            return gro_timestep(mf, ts);

      case MDFMT_TRR:
      case MDFMT_TRJ: /* fallthrough */
            return trx_timestep(mf, ts);

      case MDFMT_G96:
            return g96_timestep(mf, ts);

      case MDFMT_XTC:
            return xtc_timestep(mf, ts);

      default:
            return mdio_seterror(MDIO_UNKNOWNFMT);
      }
}



static int g96_header(md_file *mf, char *title, int titlelen, float *timeval) {
      char buf[MAX_G96_LINE + 1];
      char *p;

      // Check parameters
      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      // The header consists of blocks. The title block
      // is mandatory, and a TIMESTEP block is optional.
      // Example:
      //
      // TITLE
      // Generated by trjconv :  t=  90.00000
      // more title info
      // .
      // .
      // .
      // END
      // .
      // .
      // .

      if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;
      if (strcasecmp(buf, "TITLE")) return mdio_seterror(MDIO_BADFORMAT);

      // Read in the title itself
      if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;

        // The timevalue can be included in the title string
        // after a "t=" prefix.
        if ((p = (char *) strstr(buf, "t="))) {
                char *q = p;
                *(q--) = 0;

                // Skip the `t=' and strip whitespace from
                // the resulting strings
                p += 2;
                strip_white(p);
                strip_white(buf);

                // Grab the timevalue from the title string
                if (timeval) *timeval = (float) atof(p);
        }
        else {
                // No timevalue - just copy the string and strip
                // any leading/trailing whitespace
                if (timeval) *timeval = 0;
                strip_white(buf);
        }

      // Copy the title string
      if (title && titlelen) strncpy(title, buf, titlelen);

      // Now ignore subsequent title lines and get the END string
      while (strcasecmp(buf, "END"))
            if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;

      // Done!
      return mdio_seterror(MDIO_SUCCESS);
}


// Used to determine the number of atoms in a g96 file, because
// VMD needs to know this for some reason.
static int g96_countatoms(md_file *mf) {
      char buf[MAX_G96_LINE + 1];
      int natoms;
      int n;
      long fpos;
      float lastf;

      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      fpos = ftell(mf->f);

      natoms = 0;
      for (;;) {
            if (mdio_readline(mf, buf, MAX_G96_LINE + 1, 0) < 0)
                  break;
            n = sscanf(buf, "%*6c%*6c%*6c%*6c %*f %*f %f", &lastf);
            if (n == 1) natoms++;
            else {
                  strip_white(buf);
                  if (!strcasecmp(buf, "END")) break;
            }
      }

      fseek(mf->f, fpos, SEEK_SET);
      return natoms;
}


// Reads an atom line from the G96 file
static int g96_rec(md_file *mf, md_atom *ma) {
      char buf[MAX_G96_LINE + 1];
      char atomnum[7];
      int n;

      // Check parameters
      if (!mf || !ma) return mdio_seterror(MDIO_BADPARAMS);

      // Read in a line, assuming it is an atom line
      do {
            if (mdio_readline(mf, buf, MAX_G96_LINE + 1, 0) < 0) return -1;
      } while (buf[0] == '#' || strlen(buf) == 0);

      n = sscanf(buf, "%6c%6c%6c%6c %f %f %f",
            ma->resid, ma->resname, ma->atomname, atomnum,
            &ma->pos[0], &ma->pos[1], &ma->pos[2]);
      if (n == 7) {
            atomnum[6] = 0;
            ma->resid[6] = 0;
            ma->resname[6] = 0;
            ma->atomname[6] = 0;

            strip_white(atomnum);
            strip_white(ma->resid);
            strip_white(ma->resname);
            strip_white(ma->atomname);

            ma->atomnum = atoi(atomnum);

            ma->pos[0] *= ANGS_PER_NM;
            ma->pos[1] *= ANGS_PER_NM;
            ma->pos[2] *= ANGS_PER_NM;

            return 0;
      }

      return mdio_seterror(MDIO_BADFORMAT);
}


// Reads a timestep from a G96 file and stores the data in
// the generic md_ts structure. Returns 0 on success or a
// negative number on error and sets mdio_errcode.
static int g96_timestep(md_file *mf, md_ts *ts) {
      char        buf[MAX_G96_LINE + 1];
      char        stripbuf[MAX_G96_LINE + 1];
      float       pos[3], x[3], y[3], z[3], *currAtom;
      long        fpos;
      int         n, i, boxItems;

      // Check parameters
      if (!mf || !ts) return mdio_seterror(MDIO_BADPARAMS);

  // Allocate data space for the timestep, using the number of atoms
  // determined by open_g96_read().
      ts->pos = (float *) malloc(sizeof(float) * 3 * ts->natoms);
      if (!ts->pos) {
            return mdio_seterror(MDIO_BADMALLOC);
      }
  currAtom = ts->pos;

      // The timesteps follow the header in a fixed block
      // format:
      //
      // TIMESTEP
      //         <step number> <time value>
      // END
      // POSITIONRED
      //     <x float> <y float> <z float>
      //     .         .         .
      //     .         .         .
      //     .         .         .
      // END
      // VELOCITYRED
      //     <x float> <y float> <z float>
      //     .         .         .
      //     .         .         .
      //     .         .         .
      // END
      // BOX
      //     <x float> <y float> <z float>
      // END
      //
      // -----
      //
      // The TIMESTEP, VELOCITY and BOX blocks are optional.
      // Floats are written in 15.9 precision.
      //
      // Reference: GROMACS 2.0 user manual
      //            http://rugmd4.chem.rug.nl/~gmx/online2.0/g96.html

      // First, look for an (optional) title block and skip it
      if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;

  if (!strcasecmp(buf, "TITLE")) {
    // skip over the text until we reach 'END'
    while (strcasecmp(buf, "END")) {
      if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;
    }

    // Read in the next line
    if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;
  }

      // Next, look for a timestep block
      if (!strcasecmp(buf, "TIMESTEP")) {
            // Read in the value line
            if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;

            // Extract the time value and the timestep index
            n = sscanf(buf, "%d %f", &ts->step, &ts->time);
            if (n != 2) return mdio_seterror(MDIO_BADFORMAT);

            // Read the "END" line
            if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;
            if (strcasecmp(buf, "END"))
                  return mdio_seterror(MDIO_BADFORMAT);

            // Read in the next line
            if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;
      }
      else {
            // No timestep specified -- set to zero
            ts->step = 0;
            ts->time = 0;
      }

      // At this point a POSITION or POSITIONRED block
      // is REQUIRED by the format
      if (!strcasecmp(buf, "POSITIONRED")) {

    // So now we read in some atoms
    i = 0;
            while (i < ts->natoms) {
                  // Read in an atom
                  if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0)
                        return -1;
 
      // We shouldn't reach the end yet
      if (!strcasecmp(buf, "END"))
        return mdio_seterror(MDIO_BADFORMAT);

                  // Get the x,y,z coordinates
                  n = sscanf(buf, "%f %f %f", &pos[0], &pos[1], &pos[2]);
      
      // Ignore improperly formatted lines
                  if (n == 3) {
                        pos[0] *= ANGS_PER_NM;
                        pos[1] *= ANGS_PER_NM;
                        pos[2] *= ANGS_PER_NM;

                        // Copy the atom data into the array
                        memcpy(currAtom, pos, sizeof(float) * 3);
        currAtom += 3;
        i++;
                  }
            }
      }
      else if (!strcasecmp(buf, "POSITION") || !strcasecmp(buf, "REFPOSITION")) {
            /*
            char resnum[7];
            char resname[7];
            char atomname[7];
            char atomnum[7];
            */

            // So now we read in some atoms
    i = 0;
            while (i < ts->natoms) {
                  // Read in the first line
                  if (mdio_readline(mf, buf, MAX_G96_LINE + 1, 0) < 0)
                        return -1;
 
      // We shouldn't reach the end yet
      strcpy(stripbuf, buf);
      strip_white(stripbuf); 
      if (!strcasecmp(stripbuf, "END"))
        return mdio_seterror(MDIO_BADFORMAT);

                  // Get the x,y,z coordinates and name data
                  n = sscanf(buf, "%*6c%*6c%*6c%*6c %f %f %f",
                        &pos[0], &pos[1], &pos[2]);

      // Ignore improperly formatted lines
                  if (n == 3) {
                        pos[0] *= ANGS_PER_NM;
                        pos[1] *= ANGS_PER_NM;
                        pos[2] *= ANGS_PER_NM;

                        // Copy the atom data into the linked list item
                        memcpy(currAtom, pos, sizeof(float) * 3);
                        currAtom += 3;
        i++;
                  }
            }
      }
      else {
            return mdio_seterror(MDIO_BADFORMAT);
      }

  // Read the END keyword
  if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0)
    return -1;
  if (strcasecmp(buf, "END"))
    return mdio_seterror(MDIO_BADFORMAT);

      // ... another problem: there may or may not be a VELOCITY
      // block or a BOX block, so we need to read one line beyond
      // the POSITION block to determine this. If neither VEL. nor
      // BOX are present we've read a line too far and infringed
      // on the next timestep, so we need to keep track of the
      // position now for a possible fseek() later to backtrack.
      fpos = ftell(mf->f);

      // Now we must read in the velocities and the box, if present
      if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) {
    // It's okay if we end the file here; any other errors need to be
    // reported.
    if (mdio_errcode == MDIO_EOF) 
      return mdio_seterror(MDIO_SUCCESS);
    else 
      return -1;
  }

      // Is there a velocity block present ?
      if (!strcasecmp(buf, "VELOCITY") || !strcasecmp(buf, "VELOCITYRED")) {
            // Ignore all the coordinates - VMD doesn't use them
            for (;;) {
                  if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0)
                        return -1;
                  if (!strcasecmp(buf, "END")) break;
            }

            // Again, record our position because we may need
            // to fseek here later if we read too far.
            fpos = ftell(mf->f);

            // Go ahead and read the next line.
            if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;
      }

      // Is there a box present ?
      if (!strcasecmp(buf, "BOX")) {
            if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) return -1;
    boxItems = sscanf(buf, " %f %f %f %f %f %f %f %f %f", 
               &x[0], &y[1], &z[2], &x[1], &x[2], &y[0], &y[2], &z[0], &z[1]);
    if (boxItems == 3) {
      x[1] = x[2] = 0;
      y[0] = y[2] = 0;
      z[0] = z[1] = 0;
    }
    else if (boxItems != 9) 
      return mdio_seterror(MDIO_BADFORMAT);

    // Allocate the box and convert the vectors.
    ts->box = (md_box *) malloc(sizeof(md_box));
    if (mdio_readbox(ts->box, x, y, z) < 0) {
      free(ts->box);
      ts->box = NULL;
      return mdio_seterror(MDIO_BADFORMAT);
    }

            if (mdio_readline(mf, buf, MAX_G96_LINE + 1) < 0) {
      free(ts->box);
      ts->box = NULL;
      return -1;
    }
            if (strcasecmp(buf, "END")) {
      free(ts->box);
      ts->box = NULL;
                  return mdio_seterror(MDIO_BADFORMAT);
    }
      }
      else {
            // We have read too far, so fseek back to the
            // last known safe position so we don't return
            // with the file pointer set infringing on the
            // next timestep data.
            fseek(mf->f, fpos, SEEK_SET);
      }

      // We're done!
      return mdio_seterror(MDIO_SUCCESS);
}


// Attempts to read header data from a GROMACS structure file
// The GROMACS header format is as follows (fixed, 2 lines ASCII):
// <title> [ n= <timevalue> ]
//     <num atoms>
static int gro_header(md_file *mf, char *title, int titlelen, float *timeval,
               int *natoms, int rewind) {
      char buf[MAX_GRO_LINE + 1];
      long fpos;
      char *p;

      // Check parameters
      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      // Get the current file position for rewinding later
      fpos = ftell(mf->f);

      // The header consists of 2 lines - get the first line
      if (mdio_readline(mf, buf, MAX_GRO_LINE + 1) < 0) return -1;

      // The timevalue can be included in the title string
      // after a "t=" prefix.
      if ((p = (char *) strstr(buf, "t="))) {
            char *q = p;
            *(q--) = 0;

            // Skip the `t=' and strip whitespace from
            // the resulting strings
            p += 2;
            strip_white(p);
            strip_white(buf);

            // Grab the timevalue from the title string
            if (timeval) *timeval = (float) atof(p);
      }
      else {
            // No timevalue - just copy the string
            if (timeval) *timeval = 0;
      }

      // Copy the title string
      if (title && titlelen) strncpy(title, buf, titlelen);

      // Get the second line and grab the number of atoms
      if (mdio_readline(mf, buf, MAX_GRO_LINE + 1) < 0) return -1;

      // Store the number of atoms
      if (natoms) if (!(*natoms = atoi(buf)))
            return mdio_seterror(MDIO_BADFORMAT);

      // Now we rewind the file so that subsequent calls to
      // gro_timestep() will succeed. gro_timestep() requires
      // the header to be at the current file pointer.
      if (rewind) fseek(mf->f, fpos, SEEK_SET);

      // Done!
      return 0;
}


// Reads one atom record from a GROMACS file. Returns GMX_SUCCESS
// on success or a negative number on error.
//
// Record format (one line, fixed):
//    rrrrrRRRRRaaaaaAAAAA <x pos> <y pos> <z pos> <x vel> <y vel> <z vel>
//
//    r = residue number
//    R = residue name
//    a = atom name
//    A = atom number
//
static int gro_rec(md_file *mf, md_atom *ma) {
      char  buf[MAX_GRO_LINE + 1];
      char  atomnum[6];
      int   n;

      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      do {
            if (mdio_readline(mf, buf, MAX_GRO_LINE + 1, 0) < 0) return -1;
      } while (buf[0] == '#' || !strlen(buf));

      // Read in the fields
      n = sscanf(buf, "%5c%5c%5c%5c%f %f %f", ma->resid,
            ma->resname, ma->atomname, atomnum, ma->pos,
            &ma->pos[1], &ma->pos[2]);
      if (n != 7) return mdio_seterror(MDIO_BADFORMAT);

      // Null terminate the strings
      ma->resname[5] = 0;
      ma->atomname[5] = 0;
      ma->resid[5] = 0;
      atomnum[5] = 0;

      // Convert strings to numbers
      strip_white(atomnum);
      ma->atomnum = atoi(atomnum);

      // Convert nanometers to angstroms
      ma->pos[0] *= ANGS_PER_NM;
      ma->pos[1] *= ANGS_PER_NM;
      ma->pos[2] *= ANGS_PER_NM;

      // Strip leading and trailing whitespace
      strip_white(ma->atomname);
      strip_white(ma->resname);
      strip_white(ma->resid);

      return 0;
}


// Reads in a timestep from a .gro file. Ignores the data
// not needed for a timestep, so is a little faster than
// calling gro_rec() for each atom. Also reads in the
// header block.
//
static int gro_timestep(md_file *mf, md_ts *ts) {
      char buf[MAX_GRO_LINE + 1];
      long coord;
      int i, n, boxItems;
  float x[3], y[3], z[3];

      if (!mf || !ts) return mdio_seterror(MDIO_BADPARAMS);

      if (gro_header(mf, NULL, 0, &ts->time, &ts->natoms, 0) < 0)
            return -1;
      ts->pos = (float *) malloc(3 * sizeof(float) * ts->natoms);
      if (!ts->pos)
            return mdio_seterror(MDIO_BADMALLOC);

      coord = 0;
      for (i = 0; i < ts->natoms; i++) {
            if (mdio_readline(mf, buf, MAX_GRO_LINE + 1, 0) < 0) {
                  free(ts->pos);
                  return -1;
            }
      
            n = sscanf(buf, "%*5c%*5c%*5c%*5c%f %f %f",
                  &ts->pos[coord], &ts->pos[coord + 1],
                  &ts->pos[coord + 2]);

            ts->pos[coord] *= ANGS_PER_NM;
            ts->pos[coord + 1] *= ANGS_PER_NM;
            ts->pos[coord + 2] *= ANGS_PER_NM;

            if (n != 3) return mdio_seterror(MDIO_BADFORMAT);
            coord += 3;
      }

      // Read the box, stored as three vectors representing its edges
      if (mdio_readline(mf, buf, MAX_GRO_LINE + 1, 0) < 0) {
            free(ts->pos);
            return -1;
      }
  boxItems = sscanf(buf, " %f %f %f %f %f %f %f %f %f", 
             &x[0], &y[1], &z[2], &x[1], &x[2], &y[0], &y[2], &z[0], &z[1]);
  // File may only include three scalars for the box information -- if
  // that's the case, the box is orthoganal.
  if (boxItems == 3) {
    x[1] = x[2] = 0;
    y[0] = y[2] = 0;
    z[0] = z[1] = 0;
  }
  else if (boxItems != 9) {
    free(ts->pos);
    return -1;
  }

  // Allocate the box and convert the vectors.
  ts->box = (md_box *) malloc(sizeof(md_box));
  if (mdio_readbox(ts->box, x, y, z) < 0) {
    free(ts->pos);
    free(ts->box);
    ts->box = NULL;
    return -1;
  }

      return 0;
}


// Attempts to read header data from a .trX trajectory file
//
// The .trX header format is as follows:
//
//    4 bytes           - magic number (0x07C9)
//    ...
//
static int trx_header(md_file *mf, int rewind) {
      int magic;
      trx_hdr *hdr;
      long fpos;

      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      // In case we need to rewind
      fpos = ftell(mf->f);

      // We need to store some data to the trX header data
      // structure inside the md_file structure
      hdr = mf->trx;
      if (!mf->trx) return mdio_seterror(MDIO_BADPARAMS);

      // Read the magic number
      if (trx_int(mf, &magic) < 0) return -1;
      if (magic != TRX_MAGIC) {
            // Try reverse endianism
            swap4_aligned(&magic, 1);
            if (magic != TRX_MAGIC) return mdio_seterror(MDIO_BADFORMAT);

            // Enable byte swapping (actually works, too!)
            mf->rev = 1;
      }

      // Read the version number. 
        // XXX. this is not the version number, but the storage size
      // of the following XDR encoded string.
      // the 'title' string is in fact the version identifier.
      // since VMD does not use any of that, it does no harm,
      // but is should still be fixed occasionally. AK 2005/01/08.

      if(mf->fmt!=MDFMT_TRJ) {
            // It appears that TRJ files either don't contain a version
            // number or don't have a length-delimiter on the string,
            // whereas TRR files do contain both.  Thus, with TRJ, we just
            // assume that the version number is the string length and 
            // just hope for the best. -- WLD 2006/07/09
            if (trx_int(mf, &hdr->version) < 0) return -1;
      }

      // Read in the title string
      if (trx_string(mf, hdr->title, MAX_TRX_TITLE) < 0)
            return -1;

      // Read in some size data
      if (trx_int(mf, &hdr->ir_size) < 0) return -1;
      if (trx_int(mf, &hdr->e_size) < 0) return -1;
      if (trx_int(mf, &hdr->box_size) < 0) return -1;
      if (trx_int(mf, &hdr->vir_size) < 0) return -1;
      if (trx_int(mf, &hdr->pres_size) < 0) return -1;
      if (trx_int(mf, &hdr->top_size) < 0) return -1;
      if (trx_int(mf, &hdr->sym_size) < 0) return -1;
      if (trx_int(mf, &hdr->x_size) < 0) return -1;
      if (trx_int(mf, &hdr->v_size) < 0) return -1;
      if (trx_int(mf, &hdr->f_size) < 0) return -1;
      if (trx_int(mf, &hdr->natoms) < 0) return -1;
      if (trx_int(mf, &hdr->step) < 0) return -1;
      if (trx_int(mf, &hdr->nre) < 0) return -1;

      // Make sure there are atoms...
      if (!hdr->natoms) return mdio_seterror(MDIO_BADFORMAT);

      // Try to determine precision (float? double?)
      if (hdr->x_size) mf->prec = hdr->x_size / (hdr->natoms * 3);
      else if (hdr->v_size) mf->prec = hdr->v_size / (hdr->natoms * 3);
      else if (hdr->f_size) mf->prec = hdr->f_size / (hdr->natoms * 3);
      else return mdio_seterror(MDIO_BADPRECISION);

      if (mf->prec != sizeof(float) && mf->prec != sizeof(double)) {
            // We have no data types this size! The
            // file must've been generated on another
            // platform
            return mdio_seterror(MDIO_BADPRECISION);
      }

      // Read in timestep and lambda
      if (trx_real(mf, &hdr->t) < 0) return -1;
      if (trx_real(mf, &hdr->lambda) < 0) return -1;

      // Rewind if necessary
      if (rewind) fseek(mf->f, fpos, SEEK_SET);

      return 0;
}


// Reads in an integer and stores it in y. Returns GMX_SUCCESS
// on success or a negative number on error.
static int trx_int(md_file *mf, int *y) {
      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

        // sanity check.
        if (sizeof(int) != 4) return mdio_seterror(MDIO_SIZEERROR);

      if (y) {
            if (fread(y, 4, 1, mf->f) != 1)
                  return mdio_seterror(MDIO_IOERROR);
            if (mf->rev) swap4_aligned(y, 1);
      }
      else if (fseek(mf->f, 4, SEEK_CUR) != 0)
            return mdio_seterror(MDIO_IOERROR);

      return mdio_seterror(MDIO_SUCCESS);
}


// Reads in either a float or a double, depending on the
// precision, and stores that number in y. Returns
// GMX_SUCCESS on success or a negative number on error.
static int trx_real(md_file *mf, float *y) {
      double x;

      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      switch (mf->prec) {
            case sizeof(float):
                  if (!y) {
                        if (fseek(mf->f, mf->prec, SEEK_CUR) != 0)
                              return mdio_seterror(MDIO_IOERROR);
                  } else {
                        if (fread(y, mf->prec, 1, mf->f) != 1)
                              return mdio_seterror(MDIO_IOERROR);
                        if (mf->rev) swap4_aligned(y, 1);
                  }
                  return mdio_seterror(MDIO_SUCCESS);

            case sizeof(double):
                  if (!y) {
                        if (fseek(mf->f, mf->prec, SEEK_CUR) != 0)
                              return mdio_seterror(MDIO_IOERROR);
                  } else {
                        if (fread(&x, mf->prec, 1, mf->f) != 1)
                              return mdio_seterror(MDIO_IOERROR);
                        if (mf->rev) swap8_aligned(&x, 1);
                        *y = (float) x;
                  }
                  return mdio_seterror(MDIO_SUCCESS);

            default:
                  return mdio_seterror(MDIO_BADPRECISION);
      }

}


// Reads in a real-valued vector (taking precision into account).
// Stores the vector in vec, and returns GMX_SUCCESS on success
// or a negative number on error.
static int trx_rvector(md_file *mf, float *vec) {
      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      if (!vec) {
            if (trx_real(mf, NULL) < 0) return -1;
            if (trx_real(mf, NULL) < 0) return -1;
            if (trx_real(mf, NULL) < 0) return -1;
            return mdio_seterror(MDIO_SUCCESS);
      } else {
            if (trx_real(mf, &vec[0]) < 0) return -1;
            if (trx_real(mf, &vec[1]) < 0) return -1;
            if (trx_real(mf, &vec[2]) < 0) return -1;
            return mdio_seterror(MDIO_SUCCESS);
      }
}


// Reads in a string by first reading an integer containing the
// string's length, then reading in the string itself and storing
// it in str. If the length is greater than max, it is truncated
// and the rest of the string is skipped in the file. Returns the
// length of the string on success or a negative number on error.
static int trx_string(md_file *mf, char *str, int max) {
      int size;
  size_t ssize;

      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      if (trx_int(mf, &size) < 0) return -1;
  ssize = (size_t)size;

      if (str && size <= max) {
            if (fread(str, 1, size, mf->f) != ssize)
                  return mdio_seterror(MDIO_IOERROR);
            str[size] = 0;
            return size;
      } else if (str) {
            if (fread(str, 1, max, mf->f) != ssize)
                  return mdio_seterror(MDIO_IOERROR);
            if (fseek(mf->f, size - max, SEEK_CUR) != 0)
                  return mdio_seterror(MDIO_IOERROR);
            str[max] = 0;
            return max;
      } else {
            if (fseek(mf->f, size, SEEK_CUR) != 0)
                  return mdio_seterror(MDIO_IOERROR);
            return 0;
      }
}


// Reads in a timestep frame from the .trX file and returns the
// data in a timestep structure. Returns NULL on error.
static int trx_timestep(md_file *mf, md_ts *ts) {
      int i;
  float x[3], y[3], z[3];
      trx_hdr *hdr;

      if (!mf || !ts) return mdio_seterror(MDIO_BADPARAMS);
      if (mf->fmt != MDFMT_TRJ && mf->fmt != MDFMT_TRR)
            return mdio_seterror(MDIO_WRONGFORMAT);

      // Read the header
      if (trx_header(mf) < 0) return -1;

      // We need some data from the trX header
      hdr = mf->trx;
      if (!hdr) return mdio_seterror(MDIO_BADPARAMS);

      if (hdr->box_size) { // XXX need to check value of box_size!!
            if (trx_rvector(mf, x) < 0) return -1;
            if (trx_rvector(mf, y) < 0) return -1;
            if (trx_rvector(mf, z) < 0) return -1;
    // Allocate the box and convert the vectors.
    ts->box = (md_box *) malloc(sizeof(md_box));
    if (mdio_readbox(ts->box, x, y, z) < 0) {
      free(ts->box);
      ts->box = NULL;
      return -1;
    }
      }

      if (hdr->vir_size) {
            if (trx_rvector(mf, NULL) < 0) return -1;
            if (trx_rvector(mf, NULL) < 0) return -1;
            if (trx_rvector(mf, NULL) < 0) return -1;
      }

        if (hdr->pres_size) {
                if (trx_rvector(mf, NULL) < 0) return -1;
                if (trx_rvector(mf, NULL) < 0) return -1;
                if (trx_rvector(mf, NULL) < 0) return -1;
        }

        if (hdr->x_size) {
                ts->pos = (float *) malloc(sizeof(float) * 3 * hdr->natoms);
                if (!ts->pos) return mdio_seterror(MDIO_BADMALLOC);

            ts->natoms = hdr->natoms;

            for (i = 0; i < hdr->natoms; i++) {
                  if (trx_rvector(mf, &ts->pos[i * 3]) < 0) {
                        mdio_tsfree(ts, 1);
                        return -1;
                  }
                  ts->pos[i * 3] *= ANGS_PER_NM;
                  ts->pos[i * 3 + 1] *= ANGS_PER_NM;
                  ts->pos[i * 3 + 2] *= ANGS_PER_NM;
            }
        }

        if (hdr->v_size) {
            for (i = 0; i < hdr->natoms; i++) {
                  if (trx_rvector(mf, NULL) < 0) {
                        mdio_tsfree(ts, 1);
                        return -1;
                  }
            }
        }

        if (hdr->f_size) {
            for (i = 0; i < hdr->natoms; i++) {
                  if (trx_rvector(mf, NULL) < 0) {
                        mdio_tsfree(ts, 1);
                        return -1;
                  }
            }
        }

      return mdio_seterror(MDIO_SUCCESS);
}


// writes an int in big endian. Returns GMX_SUCCESS
// on success or a negative number on error.
static int put_trx_int(md_file *mf, int y) {
      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      // sanity check.
      if (sizeof(int) != 4) return mdio_seterror(MDIO_SIZEERROR);

      if (mf->rev) swap4_aligned(&y, 1);
      if (fwrite(&y, 4, 1, mf->f) != 1)
    return mdio_seterror(MDIO_IOERROR);

  return mdio_seterror(MDIO_SUCCESS);
}

// writes a real in big-endian. Returns GMX_SUCCESS
// on success or a negative number on error.
static int put_trx_real(md_file *mf, float y) {
      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      if (mf->rev) swap4_aligned(&y, 1);
      if (fwrite(&y, 4, 1, mf->f) != 1)
        return mdio_seterror(MDIO_IOERROR);

      return mdio_seterror(MDIO_SUCCESS);
}


// writes an xdr encoded string. Returns GMX_SUCCESS
// on success or a negative number on error.
static int put_trx_string(md_file *mf, const char *s) {
      if (!mf || !s) return mdio_seterror(MDIO_BADPARAMS);
        
        // write: size of object, string length, string data
        size_t len = strlen(s);
        if ( put_trx_int(mf, len+1)
             || put_trx_int(mf, len)
             || (fwrite(s, len, 1, mf->f) != 1))
          return mdio_seterror(MDIO_IOERROR);

      return mdio_seterror(MDIO_SUCCESS);
}


// xtc_int() - reads an integer from an xtc file
static int xtc_int(md_file *mf, int *i) {
      unsigned char c[4];

      if (!mf) return mdio_seterror(MDIO_BADPARAMS);
        // sanity check.
        if (sizeof(int) != 4) return mdio_seterror(MDIO_SIZEERROR);

      if (fread(c, 1, 4, mf->f) != 4) {
            if (feof(mf->f)) return mdio_seterror(MDIO_EOF);
            else if (ferror(mf->f)) return mdio_seterror(MDIO_IOERROR);
            else return mdio_seterror(MDIO_UNKNOWNERROR);
      }

      if (i) *i = c[3] + (c[2] << 8) + (c[1] << 16) + (c[0] << 24);
      return mdio_seterror(MDIO_SUCCESS);
}


// xtc_float() - reads a float from an xtc file
static int xtc_float(md_file *mf, float *f) {
      unsigned char c[4];
      int i;

      if (!mf) return mdio_seterror(MDIO_BADPARAMS);

      if (fread(c, 1, 4, mf->f) != 4) {
            if (feof(mf->f)) return mdio_seterror(MDIO_EOF);
            else if (ferror(mf->f)) return mdio_seterror(MDIO_IOERROR);
            else return mdio_seterror(MDIO_UNKNOWNERROR);
      }

      if (f) {
            // By reading the number in as an integer and then
            // copying it to a floating point number we can
            // ensure proper endianness
            i = c[3] + (c[2] << 8) + (c[1] << 16) + (c[0] << 24);
            memcpy(f, &i, 4);
      }
      return mdio_seterror(MDIO_SUCCESS);
}


// xtc_data() - reads a specific amount of data from an xtc
// file using the xdr format.
static int xtc_data(md_file *mf, char *buf, int len) {
      if (!mf || len < 1) return mdio_seterror(MDIO_BADPARAMS);
  size_t slen = (size_t)len;
      if (buf) {
            if (fread(buf, 1, slen, mf->f) != slen) {
                  if (feof(mf->f)) return mdio_seterror(MDIO_EOF);
                  if (ferror(mf->f)) return mdio_seterror(MDIO_IOERROR);
                  else return mdio_seterror(MDIO_UNKNOWNERROR);
            }
            if (len % 4) {
                  if (fseek(mf->f, 4 - (len % 4), SEEK_CUR)) {
                        if (feof(mf->f)) return mdio_seterror(MDIO_EOF);
                        if (ferror(mf->f)) return mdio_seterror(MDIO_IOERROR);
                        else return mdio_seterror(MDIO_UNKNOWNERROR);
                  }
            }
      }
      else {
            int newlen;
            newlen = len;
            if (len % 4) newlen += (4 - (len % 4));
            if (fseek(mf->f, newlen, SEEK_CUR)) {
                  if (feof(mf->f)) return mdio_seterror(MDIO_EOF);
                  if (ferror(mf->f)) return mdio_seterror(MDIO_IOERROR);
                  else return mdio_seterror(MDIO_UNKNOWNERROR);
            }
      }
      return len;
}


// xtc_timestep() - reads a timestep from an .xtc file.
static int xtc_timestep(md_file *mf, md_ts *ts) {
      int n;
      float f, x[3], y[3], z[3];

      int size = 0; // explicitly initialized to zero.
      float precision;

      if (!mf || !ts) return mdio_seterror(MDIO_BADPARAMS);
      if (!mf->f) return mdio_seterror(MDIO_BADPARAMS);
      if (mf->fmt != MDFMT_XTC) return mdio_seterror(MDIO_WRONGFORMAT);

      // Check magic number
      if (xtc_int(mf, &n) < 0) return -1;
      if (n != XTC_MAGIC) return mdio_seterror(MDIO_BADFORMAT);

      // Get number of atoms
      if (xtc_int(mf, &n) < 0) return -1;
      ts->natoms = n;

      // Get the simulation step
      if (xtc_int(mf, &n) < 0) return -1;
      ts->step = n;

      // Get the time value
      if (xtc_float(mf, &f) < 0) return -1;
      ts->time = f;

      // Read the basis vectors of the box
  if ( (xtc_float(mf, &x[0]) < 0) ||
       (xtc_float(mf, &x[1]) < 0) ||
       (xtc_float(mf, &x[2]) < 0) ||
       (xtc_float(mf, &y[0]) < 0) ||
       (xtc_float(mf, &y[1]) < 0) ||
       (xtc_float(mf, &y[2]) < 0) ||
       (xtc_float(mf, &z[0]) < 0) ||
       (xtc_float(mf, &z[1]) < 0) ||
       (xtc_float(mf, &z[2]) < 0) )
    return -1;
  // Allocate the box and convert the vectors.
  ts->box = (md_box *) malloc(sizeof(md_box));
  if (mdio_readbox(ts->box, x, y, z) < 0) {
    free(ts->box);
    ts->box = NULL;
    return -1;
  }

      ts->pos = (float *) malloc(sizeof(float) * 3 * ts->natoms);
      if (!ts->pos) return mdio_seterror(MDIO_BADMALLOC);
      n = xtc_3dfcoord(mf, ts->pos, &size, &precision);
      if (n < 0) return -1;

      /* Now we're left with the job of scaling... */
      for (n = 0; n < ts->natoms * 3; n++)
            ts->pos[n] *= ANGS_PER_NM;

      return mdio_seterror(MDIO_SUCCESS);
}


///////////////////////////////////////////////////////////////////////
// This algorithm is an implementation of the 3dfcoord algorithm
// written by Frans van Hoesel (hoesel@chem.rug.nl) as part of the
// Europort project in 1995.
///////////////////////////////////////////////////////////////////////

// integer table used in decompression
static int xtc_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(xtc_magicints) / sizeof(*xtc_magicints))


// returns the number of bits in the binary expansion of
// the given integer.
static int xtc_sizeofint(int size) {
      unsigned int num = 1;
  unsigned int ssize = (unsigned int)size;
      int nbits = 0;

      while (ssize >= num && nbits < 32) {
            nbits++;
            num <<= 1;
      }
      return nbits;
}

// calculates the number of bits a set of integers, when compressed,
// will take up.
static int xtc_sizeofints(int nints, unsigned int *sizes) {
      int i;
  unsigned int num;
      unsigned int nbytes, nbits, bytes[32], bytecnt, tmp;
      nbytes = 1;
      bytes[0] = 1;
      nbits = 0;
      for (i=0; i < nints; i++) {   
            tmp = 0;
            for (bytecnt = 0; bytecnt < nbytes; bytecnt++) {
                  tmp = bytes[bytecnt] * sizes[i] + tmp;
                  bytes[bytecnt] = tmp & 0xff;
                  tmp >>= 8;
            }
            while (tmp != 0) {
                  bytes[bytecnt++] = tmp & 0xff;
                  tmp >>= 8;
            }
            nbytes = bytecnt;
      }
      num = 1;
      nbytes--;
      while (bytes[nbytes] >= num) {
            nbits++;
            num *= 2;
      }
      return nbits + nbytes * 8;
}

// reads bits from a buffer.    
static int xtc_receivebits(int *buf, int nbits) {
      int cnt, num; 
      unsigned int lastbits, lastbyte;
      unsigned char * cbuf;
      int mask = (1 << nbits) -1;

      cbuf = ((unsigned char *)buf) + 3 * sizeof(*buf);
      cnt = buf[0];
      lastbits = (unsigned int) buf[1];
      lastbyte = (unsigned int) buf[2];

      num = 0;
      while (nbits >= 8) {
            lastbyte = ( lastbyte << 8 ) | cbuf[cnt++];
            num |=  (lastbyte >> lastbits) << (nbits - 8);
            nbits -=8;
      }
      if (nbits > 0) {
            if (lastbits < (unsigned int)nbits) {
                  lastbits += 8;
                  lastbyte = (lastbyte << 8) | cbuf[cnt++];
            }
            lastbits -= nbits;
            num |= (lastbyte >> lastbits) & ((1 << nbits) -1);
      }
      num &= mask;
      buf[0] = cnt;
      buf[1] = lastbits;
      buf[2] = lastbyte;
      return num; 
}

// decompresses small integers from the buffer
static void xtc_receiveints(int *buf, const int nints, int nbits,
                  unsigned int *sizes, int *nums) {
      int bytes[32];
      int i, j, nbytes, p, num;

      bytes[1] = bytes[2] = bytes[3] = 0;
      nbytes = 0;
      while (nbits > 8) {
            bytes[nbytes++] = xtc_receivebits(buf, 8);
            nbits -= 8;
      }
      if (nbits > 0) {
            bytes[nbytes++] = xtc_receivebits(buf, nbits);
      }
      for (i = nints-1; i > 0; i--) {
            num = 0;
            for (j = nbytes-1; j >=0; j--) {
                  num = (num << 8) | bytes[j];
                  p = num / sizes[i];
                  bytes[j] = p;
                  num = num - p * sizes[i];
            }
            nums[i] = num;
      }
      nums[0] = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
}

// function that actually reads and writes compressed coordinates    
static int xtc_3dfcoord(md_file *mf, float *fp, int *size, float *precision) {
      static int *ip = NULL;
      static int oldsize;
      static int *buf;

      int minint[3], maxint[3], *lip;
      int smallidx;
      unsigned sizeint[3], sizesmall[3], bitsizeint[3], size3;
      int flag, k;
      int small, smaller, i, is_smaller, run;
      float *lfp;
      int tmp, *thiscoord,  prevcoord[3];

      int bufsize, lsize;
      unsigned int bitsize;
      float inv_precision;


      if (xtc_int(mf, &lsize) < 0) return -1;

      if (*size != 0 && lsize != *size) return mdio_seterror(MDIO_BADFORMAT);

      *size = lsize;
      size3 = *size * 3;
      if (*size <= 9) {
            for (i = 0; i < *size; i++) {
                  if (xtc_float(mf, fp + (3 * i)) < 0) return -1;
                  if (xtc_float(mf, fp + (3 * i) + 1) < 0) return -1;
                  if (xtc_float(mf, fp + (3 * i) + 2) < 0) return -1;
            }
            return *size;
      }
      xtc_float(mf, precision);
      if (ip == NULL) {
            ip = (int *)malloc(size3 * sizeof(*ip));
            if (ip == NULL) return mdio_seterror(MDIO_BADMALLOC);
            bufsize = (int) (size3 * 1.2);
            buf = (int *)malloc(bufsize * sizeof(*buf));
            if (buf == NULL) return mdio_seterror(MDIO_BADMALLOC);
            oldsize = *size;
      } else if (*size > oldsize) {
            ip = (int *)realloc(ip, size3 * sizeof(*ip));
            if (ip == NULL) return mdio_seterror(MDIO_BADMALLOC);
            bufsize = (int) (size3 * 1.2);
            buf = (int *)realloc(buf, bufsize * sizeof(*buf));
            if (buf == NULL) return mdio_seterror(MDIO_BADMALLOC);
            oldsize = *size;
      }
      buf[0] = buf[1] = buf[2] = 0;

      xtc_int(mf, &(minint[0]));
      xtc_int(mf, &(minint[1]));
      xtc_int(mf, &(minint[2]));

      xtc_int(mf, &(maxint[0]));
      xtc_int(mf, &(maxint[1]));
      xtc_int(mf, &(maxint[2]));
            
      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] = xtc_sizeofint(sizeint[0]);
            bitsizeint[1] = xtc_sizeofint(sizeint[1]);
            bitsizeint[2] = xtc_sizeofint(sizeint[2]);
            bitsize = 0; /* flag the use of large sizes */
      } else {
            bitsize = xtc_sizeofints(3, sizeint);
      }

      xtc_int(mf, &smallidx);
      smaller = xtc_magicints[FIRSTIDX > smallidx - 1 ? FIRSTIDX : smallidx - 1] / 2;
      small = xtc_magicints[smallidx] / 2;
      sizesmall[0] = sizesmall[1] = sizesmall[2] = xtc_magicints[smallidx] ;

      /* buf[0] holds the length in bytes */

      if (xtc_int(mf, &(buf[0])) < 0) return -1;

      if (xtc_data(mf, (char *) &buf[3], (int) buf[0]) < 0) return -1;

      buf[0] = buf[1] = buf[2] = 0;

      lfp = fp;
      inv_precision = 1.0f / (*precision);
      run = 0;
      i = 0;
      lip = ip;
      while (i < lsize) {
            thiscoord = (int *)(lip) + i * 3;

            if (bitsize == 0) {
                  thiscoord[0] = xtc_receivebits(buf, bitsizeint[0]);
                  thiscoord[1] = xtc_receivebits(buf, bitsizeint[1]);
                  thiscoord[2] = xtc_receivebits(buf, bitsizeint[2]);
            } else {
                  xtc_receiveints(buf, 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 = xtc_receivebits(buf, 1);
            is_smaller = 0;
            if (flag == 1) {
                  run = xtc_receivebits(buf, 5);
                  is_smaller = run % 3;
                  run -= is_smaller;
                  is_smaller--;
            }
            if (run > 0) {
                  thiscoord += 3;
                  for (k = 0; k < run; k+=3) {
                        xtc_receiveints(buf, 3, smallidx, sizesmall, thiscoord);
                        i++;
                        thiscoord[0] += prevcoord[0] - small;
                        thiscoord[1] += prevcoord[1] - small;
                        thiscoord[2] += prevcoord[2] - small;
                        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) {
                  small = smaller;
                  if (smallidx > FIRSTIDX) {
                        smaller = xtc_magicints[smallidx - 1] /2;
                  } else {
                        smaller = 0;
                  }
            } else if (is_smaller > 0) {
                  smaller = small;
                  small = xtc_magicints[smallidx] / 2;
            }
            sizesmall[0] = sizesmall[1] = sizesmall[2] = xtc_magicints[smallidx] ;
      }
      return 1;
}
#endif

Generated by  Doxygen 1.6.0   Back to index