Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

dcdplugin.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2006 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: dcdplugin.c,v $
00013  *      $Author: johns $       $Locker:  $             $State: Exp $
00014  *      $Revision: 1.68 $       $Date: 2006/03/16 21:45:00 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *   Code for reading and writing CHARMM, NAMD, and X-PLOR format 
00019  *   molecular dynamic trajectory files.
00020  *
00021  * TODO:
00022  *   Integrate improvements from the NAMD source tree
00023  *    - NAMD's writer code has better type-correctness for the sizes
00024  *      of "int".  NAMD uses "int32" explicitly, which is required on
00025  *      machines like the T3E.  VMD's version of the code doesn't do that
00026  *      presently.
00027  *
00028  *  Try various alternative I/O API options:
00029  *   - use mmap(), with read-once flags
00030  *   - use O_DIRECT open mode on new revs of Linux kernel 
00031  *   - use directio() call on a file descriptor to enable on Solaris
00032  *   - use aio_open()/read()/write()
00033  *   - use readv/writev() etc.
00034  *
00035  *  Standalone test binary compilation flags:
00036  *  cc -fast -xarch=v9a -I../../include -DTEST_DCDPLUGIN dcdplugin.c \
00037  *    -o ~/bin/readdcd -lm
00038  *
00039  *  Profiling flags:
00040  *  cc -xpg -fast -xarch=v9a -g -I../../include -DTEST_DCDPLUGIN dcdplugin.c \
00041  *    -o ~/bin/readdcd -lm
00042  *
00043  ***************************************************************************/
00044 
00045 #include "largefiles.h"   /* platform dependent 64-bit file I/O defines */
00046 
00047 #include <stdio.h>
00048 #include <sys/stat.h>
00049 #include <sys/types.h>
00050 #include <stdlib.h>
00051 #include <string.h>
00052 #include <math.h>
00053 #include <time.h>
00054 #include "endianswap.h"
00055 #include "fastio.h"
00056 #include "molfile_plugin.h"
00057 
00058 #ifndef M_PI_2
00059 #define M_PI_2 1.57079632679489661922
00060 #endif
00061 
00062 #define RECSCALE32BIT 1
00063 #define RECSCALE64BIT 2
00064 #define RECSCALEMAX   2
00065 
00066 typedef struct {
00067   fio_fd fd;
00068   int natoms;
00069   int nsets;
00070   int setsread;
00071   int istart;
00072   int nsavc;
00073   double delta;
00074   int nfixed;
00075   float *x, *y, *z;
00076   int *freeind;
00077   float *fixedcoords;
00078   int reverse;
00079   int charmm;  
00080   int first;
00081   int with_unitcell;
00082 } dcdhandle;
00083 
00084 /* Define error codes that may be returned by the DCD routines */
00085 #define DCD_SUCCESS      0  /* No problems                     */
00086 #define DCD_EOF         -1  /* Normal EOF                      */
00087 #define DCD_DNE         -2  /* DCD file does not exist         */
00088 #define DCD_OPENFAILED  -3  /* Open of DCD file failed         */
00089 #define DCD_BADREAD     -4  /* read call on DCD file failed    */
00090 #define DCD_BADEOF      -5  /* premature EOF found in DCD file */
00091 #define DCD_BADFORMAT   -6  /* format of DCD file is wrong     */
00092 #define DCD_FILEEXISTS  -7  /* output file already exists      */
00093 #define DCD_BADMALLOC   -8  /* malloc failed                   */
00094 #define DCD_BADWRITE    -9  /* write call on DCD file failed   */
00095 
00096 /* Define feature flags for this DCD file */
00097 #define DCD_IS_CHARMM       0x01
00098 #define DCD_HAS_4DIMS       0x02
00099 #define DCD_HAS_EXTRA_BLOCK 0x04
00100 #define DCD_HAS_64BIT_REC   0x08
00101 
00102 /* defines used by write_dcdstep */
00103 #define NFILE_POS 8L
00104 #define NSTEP_POS 20L
00105 
00106 /* READ Macro to make porting easier */
00107 #define READ(fd, buf, size)  fio_fread(((void *) buf), (size), 1, (fd))
00108 
00109 /* WRITE Macro to make porting easier */
00110 #define WRITE(fd, buf, size) fio_fwrite(((void *) buf), (size), 1, (fd))
00111 
00112 /* XXX This is broken - fread never returns -1 */
00113 #define CHECK_FREAD(X, msg) if (X==-1) { return(DCD_BADREAD); }
00114 #define CHECK_FEOF(X, msg)  if (X==0)  { return(DCD_BADEOF); }
00115 
00116 
00117 /* print DCD error in a human readable way */
00118 static void print_dcderror(const char *func, int errcode) {
00119   const char *errstr;
00120 
00121   switch (errcode) {
00122     case DCD_EOF:         errstr = "end of file"; break;
00123     case DCD_DNE:         errstr = "file not found"; break;
00124     case DCD_OPENFAILED:  errstr = "file open failed"; break;
00125     case DCD_BADREAD:     errstr = "error during read"; break;
00126     case DCD_BADEOF:      errstr = "premature end of file"; break;
00127     case DCD_BADFORMAT:   errstr = "corruption or unrecognized file structure"; break;
00128     case DCD_FILEEXISTS:  errstr = "output file already exists"; break;
00129     case DCD_BADMALLOC:   errstr = "memory allocation failed"; break;
00130     case DCD_BADWRITE:    errstr = "error during write"; break;
00131     case DCD_SUCCESS:     
00132     default:
00133       errstr = "no error";
00134       break;
00135   } 
00136   printf("dcdplugin) %s: %s\n", func, errstr); 
00137 }
00138 
00139 
00140 /*
00141  * Read the header information from a dcd file.
00142  * Input: fd - a file struct opened for binary reading.
00143  * Output: 0 on success, negative error code on failure.
00144  * Side effects: *natoms set to number of atoms per frame
00145  *               *nsets set to number of frames in dcd file
00146  *               *istart set to starting timestep of dcd file
00147  *               *nsavc set to timesteps between dcd saves
00148  *               *delta set to value of trajectory timestep
00149  *               *nfixed set to number of fixed atoms 
00150  *               *freeind may be set to heap-allocated space
00151  *               *reverse set to one if reverse-endian, zero if not.
00152  *               *charmm set to internal code for handling charmm data.
00153  */
00154 static int read_dcdheader(fio_fd fd, int *N, int *NSET, int *ISTART, 
00155                    int *NSAVC, double *DELTA, int *NAMNF, 
00156                    int **FREEINDEXES, float **fixedcoords, int *reverseEndian, 
00157                    int *charmm)
00158 {
00159   unsigned int input_integer[2];  /* buffer space */
00160   int i, ret_val, rec_scale;
00161   char hdrbuf[84];    /* char buffer used to store header */
00162   int NTITLE;
00163   int dcdcordmagic;
00164   char *corp = (char *) &dcdcordmagic;
00165 
00166   /* coordinate dcd file magic string 'CORD' */
00167   corp[0] = 'C';
00168   corp[1] = 'O';
00169   corp[2] = 'R';
00170   corp[3] = 'D';
00171 
00172   /* First thing in the file should be an 84.
00173    * some 64-bit compiles have a 64-bit record length indicator,
00174    * so we have to read two ints and check in a more complicated 
00175    * way. :-( */
00176   ret_val = READ(fd, input_integer, 2*sizeof(unsigned int));
00177   CHECK_FREAD(ret_val, "reading first int from dcd file");
00178   CHECK_FEOF(ret_val, "reading first int from dcd file");
00179 
00180   /* Check magic number in file header and determine byte order*/
00181   if ((input_integer[0]+input_integer[1]) == 84) {
00182     *reverseEndian=0;
00183     rec_scale=RECSCALE64BIT;
00184     printf("dcdplugin) detected CHARMM -i8 64-bit DCD file of native endianness\n");
00185   } else if (input_integer[0] == 84 && input_integer[1] == dcdcordmagic) {
00186     *reverseEndian=0;
00187     rec_scale=RECSCALE32BIT;
00188     printf("dcdplugin) detected standard 32-bit DCD file of native endianness\n");
00189   } else {
00190     /* now try reverse endian */
00191     swap4_aligned(input_integer, 2); /* will have to unswap magic if 32-bit */
00192     if ((input_integer[0]+input_integer[1]) == 84) {
00193       *reverseEndian=1;
00194       rec_scale=RECSCALE64BIT;
00195       printf("dcdplugin) detected CHARMM -i8 64-bit DCD file of opposite endianness\n");
00196     } else {
00197       swap4_aligned(&input_integer[1], 1); /* unswap magic (see above) */
00198       if (input_integer[0] == 84 && input_integer[1] == dcdcordmagic) {
00199         *reverseEndian=1;
00200         rec_scale=RECSCALE32BIT;
00201         printf("dcdplugin) detected standard 32-bit DCD file of opposite endianness\n");
00202       } else {
00203         /* not simply reversed endianism or -i8, something rather more evil */
00204         printf("dcdplugin) unrecognized DCD header:\n");
00205         printf("dcdplugin)   [0]: %10d  [1]: %10d\n", input_integer[0], input_integer[1]);
00206         printf("dcdplugin)   [0]: 0x%08x  [1]: 0x%08x\n", input_integer[0], input_integer[1]);
00207         return DCD_BADFORMAT;
00208 
00209       }
00210     }
00211   }
00212 
00213   /* check for magic string, in case of long record markers */
00214   if (rec_scale == RECSCALE64BIT) { 
00215     ret_val = READ(fd, input_integer, sizeof(unsigned int));
00216     if (input_integer[0] != dcdcordmagic) {
00217       printf("dcdplugin) failed to find CORD magic in CHARMM -i8 64-bit DCD file\n");
00218       return DCD_BADFORMAT;
00219     }
00220   }
00221 
00222   /* Buffer the entire header for random access */
00223   ret_val = READ(fd, hdrbuf, 80);
00224   CHECK_FREAD(ret_val, "buffering header");
00225   CHECK_FEOF(ret_val, "buffering header");
00226 
00227   /* CHARMm-genereate DCD files set the last integer in the     */
00228   /* header, which is unused by X-PLOR, to its version number.  */
00229   /* Checking if this is nonzero tells us this is a CHARMm file */
00230   /* and to look for other CHARMm flags.                        */
00231   if (*((int *) (hdrbuf + 76)) != 0) {
00232     (*charmm) = DCD_IS_CHARMM;
00233     if (*((int *) (hdrbuf + 40)) != 0)
00234       (*charmm) |= DCD_HAS_EXTRA_BLOCK;
00235 
00236     if (*((int *) (hdrbuf + 44)) == 1)
00237       (*charmm) |= DCD_HAS_4DIMS;
00238 
00239     if (rec_scale == RECSCALE64BIT)
00240       (*charmm) |= DCD_HAS_64BIT_REC;
00241   
00242   } else {
00243     (*charmm) = 0;
00244   }
00245 
00246   /* Store the number of sets of coordinates (NSET) */
00247   (*NSET) = *((int *) (hdrbuf));
00248   if (*reverseEndian) swap4_unaligned(NSET, 1);
00249 
00250   /* Store ISTART, the starting timestep */
00251   (*ISTART) = *((int *) (hdrbuf + 4));
00252   if (*reverseEndian) swap4_unaligned(ISTART, 1);
00253 
00254   /* Store NSAVC, the number of timesteps between dcd saves */
00255   (*NSAVC) = *((int *) (hdrbuf + 8));
00256   if (*reverseEndian) swap4_unaligned(NSAVC, 1);
00257 
00258   /* Store NAMNF, the number of fixed atoms */
00259   (*NAMNF) = *((int *) (hdrbuf + 32));
00260   if (*reverseEndian) swap4_unaligned(NAMNF, 1);
00261 
00262   /* Read in the timestep, DELTA */
00263   /* Note: DELTA is stored as a double with X-PLOR but as a float with CHARMm */
00264   if ((*charmm) & DCD_IS_CHARMM) {
00265     float ftmp;
00266     ftmp = *((float *)(hdrbuf+36)); /* is this safe on Alpha? */
00267     if (*reverseEndian)
00268       swap4_aligned(&ftmp, 1);
00269 
00270     *DELTA = (double)ftmp;
00271   } else {
00272     (*DELTA) = *((double *)(hdrbuf + 36));
00273     if (*reverseEndian) swap8_unaligned(DELTA, 1);
00274   }
00275 
00276   /* Get the end size of the first block */
00277   ret_val = READ(fd, input_integer, rec_scale*sizeof(int));
00278   CHECK_FREAD(ret_val, "reading second 84 from dcd file");
00279   CHECK_FEOF(ret_val, "reading second 84 from dcd file");
00280   if (*reverseEndian) swap4_aligned(input_integer, rec_scale);
00281 
00282   if (rec_scale == RECSCALE64BIT) {
00283     if ((input_integer[0]+input_integer[1]) != 84) {
00284       return DCD_BADFORMAT;
00285     }
00286   } else {
00287     if (input_integer[0] != 84) {
00288       return DCD_BADFORMAT;
00289     }
00290   }
00291   
00292   /* Read in the size of the next block */
00293   input_integer[1] = 0;
00294   ret_val = READ(fd, input_integer, rec_scale*sizeof(int));
00295   CHECK_FREAD(ret_val, "reading size of title block");
00296   CHECK_FEOF(ret_val, "reading size of title block");
00297   if (*reverseEndian) swap4_aligned(input_integer, rec_scale);
00298 
00299   if ((((input_integer[0]+input_integer[1])-4) % 80) == 0) {
00300     /* Read NTITLE, the number of 80 character title strings there are */
00301     ret_val = READ(fd, &NTITLE, sizeof(int));
00302     CHECK_FREAD(ret_val, "reading NTITLE");
00303     CHECK_FEOF(ret_val, "reading NTITLE");
00304     if (*reverseEndian) swap4_aligned(&NTITLE, 1);
00305 
00306     for (i=0; i<NTITLE; i++) {
00307       fio_fseek(fd, 80, FIO_SEEK_CUR);
00308       CHECK_FEOF(ret_val, "reading TITLE");
00309     }
00310 
00311     /* Get the ending size for this block */
00312     ret_val = READ(fd, input_integer, rec_scale*sizeof(int));
00313     CHECK_FREAD(ret_val, "reading size of title block");
00314     CHECK_FEOF(ret_val, "reading size of title block");
00315   } else {
00316     return DCD_BADFORMAT;
00317   }
00318 
00319   /* Read in an integer '4' */
00320   input_integer[1] = 0;
00321   ret_val = READ(fd, input_integer, rec_scale*sizeof(int));
00322   
00323   CHECK_FREAD(ret_val, "reading a '4'");
00324   CHECK_FEOF(ret_val, "reading a '4'");
00325   if (*reverseEndian) swap4_aligned(input_integer, rec_scale);
00326 
00327   if ((input_integer[0]+input_integer[1]) != 4) {
00328     return DCD_BADFORMAT;
00329   }
00330 
00331   /* Read in the number of atoms */
00332   ret_val = READ(fd, N, sizeof(int));
00333   CHECK_FREAD(ret_val, "reading number of atoms");
00334   CHECK_FEOF(ret_val, "reading number of atoms");
00335   if (*reverseEndian) swap4_aligned(N, 1);
00336 
00337   /* Read in an integer '4' */
00338   input_integer[1] = 0;
00339   ret_val = READ(fd, input_integer, rec_scale*sizeof(int));
00340   CHECK_FREAD(ret_val, "reading a '4'");
00341   CHECK_FEOF(ret_val, "reading a '4'");
00342   if (*reverseEndian) swap4_aligned(input_integer, rec_scale);
00343 
00344   if ((input_integer[0]+input_integer[1]) != 4) {
00345     return DCD_BADFORMAT;
00346   }
00347 
00348   *FREEINDEXES = NULL;
00349   *fixedcoords = NULL;
00350   if (*NAMNF != 0) {
00351     (*FREEINDEXES) = (int *) calloc(((*N)-(*NAMNF)), sizeof(int));
00352     if (*FREEINDEXES == NULL)
00353       return DCD_BADMALLOC;
00354 
00355     *fixedcoords = (float *) calloc((*N)*4 - (*NAMNF), sizeof(float));
00356     if (*fixedcoords == NULL)
00357       return DCD_BADMALLOC;
00358 
00359     /* Read in index array size */
00360     input_integer[1]=0;
00361     ret_val = READ(fd, input_integer, rec_scale*sizeof(int));
00362     CHECK_FREAD(ret_val, "reading size of index array");
00363     CHECK_FEOF(ret_val, "reading size of index array");
00364     if (*reverseEndian) swap4_aligned(input_integer, rec_scale);
00365 
00366     if ((input_integer[0]+input_integer[1]) != ((*N)-(*NAMNF))*4) {
00367       return DCD_BADFORMAT;
00368     }
00369 
00370     ret_val = READ(fd, (*FREEINDEXES), ((*N)-(*NAMNF))*sizeof(int));
00371     CHECK_FREAD(ret_val, "reading size of index array");
00372     CHECK_FEOF(ret_val, "reading size of index array");
00373 
00374     if (*reverseEndian)
00375       swap4_aligned((*FREEINDEXES), ((*N)-(*NAMNF)));
00376 
00377     input_integer[1]=0;
00378     ret_val = READ(fd, input_integer, rec_scale*sizeof(int));
00379     CHECK_FREAD(ret_val, "reading size of index array");
00380     CHECK_FEOF(ret_val, "reading size of index array");
00381     if (*reverseEndian) swap4_aligned(input_integer, rec_scale);
00382 
00383     if ((input_integer[0]+input_integer[1]) != ((*N)-(*NAMNF))*4) {
00384       return DCD_BADFORMAT;
00385     }
00386   }
00387 
00388   return DCD_SUCCESS;
00389 }
00390 
00391 static int read_charmm_extrablock(fio_fd fd, int charmm, int reverseEndian,
00392                                   float *unitcell) {
00393   int i, input_integer[2], rec_scale;
00394 
00395   if (charmm & DCD_HAS_64BIT_REC) {
00396     rec_scale = RECSCALE64BIT;
00397   } else {
00398     rec_scale = RECSCALE32BIT;
00399   }
00400 
00401   if ((charmm & DCD_IS_CHARMM) && (charmm & DCD_HAS_EXTRA_BLOCK)) {
00402     /* Leading integer must be 48 */
00403     input_integer[1] = 0;
00404     if (fio_fread(input_integer, sizeof(int), rec_scale, fd) != rec_scale)
00405       return DCD_BADREAD; 
00406     if (reverseEndian) swap4_aligned(input_integer, rec_scale);
00407     if ((input_integer[0]+input_integer[1]) == 48) {
00408       double tmp[6];
00409       if (fio_fread(tmp, 48, 1, fd) != 1) return DCD_BADREAD;
00410       if (reverseEndian) 
00411         swap8_aligned(tmp, 6);
00412       for (i=0; i<6; i++) unitcell[i] = (float)tmp[i];
00413     } else {
00414       /* unrecognized block, just skip it */
00415       if (fio_fseek(fd, (input_integer[0]+input_integer[1]), FIO_SEEK_CUR)) return DCD_BADREAD;
00416     }
00417     if (fio_fread(input_integer, sizeof(int), rec_scale, fd) != rec_scale) return DCD_BADREAD; 
00418   } 
00419 
00420   return DCD_SUCCESS;
00421 }
00422 
00423 static int read_fixed_atoms(fio_fd fd, int N, int num_free, const int *indexes,
00424                             int reverseEndian, const float *fixedcoords, 
00425                             float *freeatoms, float *pos, int charmm) {
00426   int i, input_integer[2], rec_scale;
00427   
00428   if(charmm & DCD_HAS_64BIT_REC) {
00429     rec_scale=RECSCALE64BIT;
00430   } else {
00431     rec_scale=RECSCALE32BIT;
00432   }
00433   
00434   /* Read leading integer */
00435   input_integer[1]=0;
00436   if (fio_fread(input_integer, sizeof(int), rec_scale, fd) != rec_scale) return DCD_BADREAD;
00437   if (reverseEndian) swap4_aligned(input_integer, rec_scale);
00438   if ((input_integer[0]+input_integer[1]) != 4*num_free) return DCD_BADFORMAT;
00439   
00440   /* Read free atom coordinates */
00441   if (fio_fread(freeatoms, 4*num_free, 1, fd) != 1) return DCD_BADREAD;
00442   if (reverseEndian)
00443     swap4_aligned(freeatoms, num_free);
00444 
00445   /* Copy fixed and free atom coordinates into position buffer */
00446   memcpy(pos, fixedcoords, 4*N);
00447   for (i=0; i<num_free; i++)
00448     pos[indexes[i]-1] = freeatoms[i];
00449 
00450   /* Read trailing integer */ 
00451   input_integer[1]=0;
00452   if (fio_fread(input_integer, sizeof(int), rec_scale, fd) != rec_scale) return DCD_BADREAD;
00453   if (reverseEndian) swap4_aligned(input_integer, rec_scale);
00454   if ((input_integer[0]+input_integer[1]) != 4*num_free) return DCD_BADFORMAT;
00455 
00456   return DCD_SUCCESS;
00457 }
00458   
00459 static int read_charmm_4dim(fio_fd fd, int charmm, int reverseEndian) {
00460   int input_integer[2],rec_scale;
00461 
00462   if (charmm & DCD_HAS_64BIT_REC) {
00463     rec_scale=RECSCALE64BIT;
00464   } else {
00465     rec_scale=RECSCALE32BIT;
00466   }
00467     
00468   /* If this is a CHARMm file and contains a 4th dimension block, */
00469   /* we must skip past it to avoid problems                       */
00470   if ((charmm & DCD_IS_CHARMM) && (charmm & DCD_HAS_4DIMS)) {
00471     input_integer[1]=0;
00472     if (fio_fread(input_integer, sizeof(int), rec_scale, fd) != rec_scale) return DCD_BADREAD;  
00473     if (reverseEndian) swap4_aligned(input_integer, rec_scale);
00474     if (fio_fseek(fd, (input_integer[0]+input_integer[1]), FIO_SEEK_CUR)) return DCD_BADREAD;
00475     if (fio_fread(input_integer, sizeof(int), rec_scale, fd) != rec_scale) return DCD_BADREAD;  
00476   }
00477 
00478   return DCD_SUCCESS;
00479 }
00480 
00481 /* 
00482  * Read a dcd timestep from a dcd file
00483  * Input: fd - a file struct opened for binary reading, from which the 
00484  *             header information has already been read.
00485  *        natoms, nfixed, first, *freeind, reverse, charmm - the corresponding 
00486  *             items as set by read_dcdheader
00487  *        first - true if this is the first frame we are reading.
00488  *        x, y, z: space for natoms each of floats.
00489  *        unitcell - space for six floats to hold the unit cell data.  
00490  *                   Not set if no unit cell data is present.
00491  * Output: 0 on success, negative error code on failure.
00492  * Side effects: x, y, z contain the coordinates for the timestep read.
00493  *               unitcell holds unit cell data if present.
00494  */
00495 static int read_dcdstep(fio_fd fd, int N, float *X, float *Y, float *Z, 
00496                         float *unitcell, int num_fixed,
00497                         int first, int *indexes, float *fixedcoords, 
00498                         int reverseEndian, int charmm) {
00499   int ret_val, rec_scale;   /* Return value from read */
00500   
00501   if (charmm & DCD_HAS_64BIT_REC) {
00502     rec_scale=RECSCALE64BIT;
00503   } else {
00504     rec_scale=RECSCALE32BIT;
00505   }
00506   
00507   if ((num_fixed==0) || first) {
00508     /* temp storage for reading formatting info */
00509     /* note: has to be max size we'll ever use  */
00510     int tmpbuf[6*RECSCALEMAX]; 
00511 
00512     fio_iovec iov[7];   /* I/O vector for fio_readv() call          */
00513     fio_size_t readlen; /* number of bytes actually read            */
00514     int i;
00515 
00516     /* if there are no fixed atoms or this is the first timestep read */
00517     /* then we read all coordinates normally.                         */
00518 
00519     /* read the charmm periodic cell information */
00520     /* XXX this too should be read together with the other items in a */
00521     /*     single fio_readv() call in order to prevent lots of extra  */
00522     /*     kernel/user context switches.                              */
00523     ret_val = read_charmm_extrablock(fd, charmm, reverseEndian, unitcell);
00524     if (ret_val) return ret_val;
00525 
00526     /* setup the I/O vector for the call to fio_readv() */
00527     iov[0].iov_base = (fio_caddr_t) &tmpbuf[0]; /* read format integer    */
00528     iov[0].iov_len  = rec_scale*sizeof(int);
00529 
00530     iov[1].iov_base = (fio_caddr_t) X;          /* read X coordinates     */
00531     iov[1].iov_len  = sizeof(float)*N;
00532 
00533     iov[2].iov_base = (fio_caddr_t) &tmpbuf[1*rec_scale]; /* read 2 format integers */
00534     iov[2].iov_len  = rec_scale*sizeof(int) * 2;
00535 
00536     iov[3].iov_base = (fio_caddr_t) Y;          /* read Y coordinates     */
00537     iov[3].iov_len  = sizeof(float)*N;
00538 
00539     iov[4].iov_base = (fio_caddr_t) &tmpbuf[3*rec_scale]; /* read 2 format integers */
00540     iov[4].iov_len  = rec_scale*sizeof(int) * 2;
00541 
00542     iov[5].iov_base = (fio_caddr_t) Z;          /* read Y coordinates     */
00543     iov[5].iov_len  = sizeof(float)*N;
00544 
00545     iov[6].iov_base = (fio_caddr_t) &tmpbuf[5*rec_scale]; /* read format integer    */
00546     iov[6].iov_len  = rec_scale*sizeof(int);
00547 
00548     readlen = fio_readv(fd, &iov[0], 7);
00549 
00550     if (readlen != (rec_scale*6*sizeof(int) + 3*N*sizeof(float)))
00551       return DCD_BADREAD;
00552 
00553     /* convert endianism if necessary */
00554     if (reverseEndian) {
00555       swap4_aligned(&tmpbuf[0], rec_scale*6);
00556       swap4_aligned(X, N);
00557       swap4_aligned(Y, N);
00558       swap4_aligned(Z, N);
00559     }
00560 
00561     /* double-check the fortran format size values for safety */
00562     if(rec_scale == 1) {
00563       for (i=0; i<6; i++) {
00564         if (tmpbuf[i] != sizeof(float)*N) return DCD_BADFORMAT;
00565       }
00566     } else {
00567       for (i=0; i<6; i++) {
00568           if ((tmpbuf[2*i]+tmpbuf[2*i+1]) != sizeof(float)*N) return DCD_BADFORMAT;
00569       }
00570     }
00571 
00572     /* copy fixed atom coordinates into fixedcoords array if this was the */
00573     /* first timestep, to be used from now on.  We just copy all atoms.   */
00574     if (num_fixed && first) {
00575       memcpy(fixedcoords, X, N*sizeof(float));
00576       memcpy(fixedcoords+N, Y, N*sizeof(float));
00577       memcpy(fixedcoords+2*N, Z, N*sizeof(float));
00578     }
00579 
00580     /* read in the optional charmm 4th array */
00581     /* XXX this too should be read together with the other items in a */
00582     /*     single fio_readv() call in order to prevent lots of extra  */
00583     /*     kernel/user context switches.                              */
00584     ret_val = read_charmm_4dim(fd, charmm, reverseEndian);
00585     if (ret_val) return ret_val;
00586   } else {
00587     /* if there are fixed atoms, and this isn't the first frame, then we */
00588     /* only read in the non-fixed atoms for all subsequent timesteps.    */
00589     ret_val = read_charmm_extrablock(fd, charmm, reverseEndian, unitcell);
00590     if (ret_val) return ret_val;
00591     ret_val = read_fixed_atoms(fd, N, N-num_fixed, indexes, reverseEndian,
00592                                fixedcoords, fixedcoords+3*N, X, charmm);
00593     if (ret_val) return ret_val;
00594     ret_val = read_fixed_atoms(fd, N, N-num_fixed, indexes, reverseEndian,
00595                                fixedcoords+N, fixedcoords+3*N, Y, charmm);
00596     if (ret_val) return ret_val;
00597     ret_val = read_fixed_atoms(fd, N, N-num_fixed, indexes, reverseEndian,
00598                                fixedcoords+2*N, fixedcoords+3*N, Z, charmm);
00599     if (ret_val) return ret_val;
00600     ret_val = read_charmm_4dim(fd, charmm, reverseEndian);
00601     if (ret_val) return ret_val;
00602   }
00603 
00604   return DCD_SUCCESS;
00605 }
00606 
00607 
00608 /* 
00609  * Skip past a timestep.  If there are fixed atoms, this cannot be used with
00610  * the first timestep.  
00611  * Input: fd - a file struct from which the header has already been read
00612  *        natoms - number of atoms per timestep
00613  *        nfixed - number of fixed atoms
00614  *        charmm - charmm flags as returned by read_dcdheader
00615  * Output: 0 on success, negative error code on failure.
00616  * Side effects: One timestep will be skipped; fd will be positioned at the
00617  *               next timestep.
00618  */
00619 static int skip_dcdstep(fio_fd fd, int natoms, int nfixed, int charmm) {
00620   
00621   int seekoffset = 0;
00622   int rec_scale;
00623 
00624   if (charmm & DCD_HAS_64BIT_REC) {
00625     rec_scale=RECSCALE64BIT;
00626   } else {
00627     rec_scale=RECSCALE32BIT;
00628   }
00629 
00630   /* Skip charmm extra block */
00631   if ((charmm & DCD_IS_CHARMM) && (charmm & DCD_HAS_EXTRA_BLOCK)) {
00632     seekoffset += 4*rec_scale + 48 + 4*rec_scale;
00633   }
00634 
00635   /* For each atom set, seek past an int, the free atoms, and another int. */
00636   seekoffset += 3 * (2*rec_scale + natoms - nfixed) * 4;
00637 
00638   /* Assume that charmm 4th dim is the same size as the other three. */
00639   if ((charmm & DCD_IS_CHARMM) && (charmm & DCD_HAS_4DIMS)) {
00640     seekoffset += (2*rec_scale + natoms - nfixed) * 4;
00641   }
00642  
00643   if (fio_fseek(fd, seekoffset, FIO_SEEK_CUR)) return DCD_BADEOF;
00644 
00645   return DCD_SUCCESS;
00646 }
00647 
00648 
00649 /* 
00650  * Write a timestep to a dcd file
00651  * Input: fd - a file struct for which a dcd header has already been written
00652  *       curframe: Count of frames written to this file, starting with 1.
00653  *       curstep: Count of timesteps elapsed = istart + curframe * nsavc.
00654  *        natoms - number of elements in x, y, z arrays
00655  *        x, y, z: pointers to atom coordinates
00656  * Output: 0 on success, negative error code on failure.
00657  * Side effects: coordinates are written to the dcd file.
00658  */
00659 static int write_dcdstep(fio_fd fd, int curframe, int curstep, int N, 
00660                   const float *X, const float *Y, const float *Z, 
00661                   const double *unitcell, int charmm) {
00662   int out_integer;
00663   int rc;
00664 
00665   if (charmm) {
00666     /* write out optional unit cell */
00667     if (unitcell != NULL) {
00668       out_integer = 48; /* 48 bytes (6 doubles) */
00669       fio_write_int32(fd, out_integer);
00670       WRITE(fd, unitcell, out_integer);
00671       fio_write_int32(fd, out_integer);
00672     }
00673   }
00674 
00675   /* write out coordinates */
00676   out_integer = N*4; /* N*4 bytes per X/Y/Z array (N floats per array) */
00677   fio_write_int32(fd, out_integer);
00678   if (fio_fwrite((void *) X, out_integer, 1, fd) != 1) return DCD_BADWRITE;
00679   fio_write_int32(fd, out_integer);
00680   fio_write_int32(fd, out_integer);
00681   if (fio_fwrite((void *) Y, out_integer, 1, fd) != 1) return DCD_BADWRITE;
00682   fio_write_int32(fd, out_integer);
00683   fio_write_int32(fd, out_integer);
00684   if (fio_fwrite((void *) Z, out_integer, 1, fd) != 1) return DCD_BADWRITE;
00685   fio_write_int32(fd, out_integer);
00686 
00687   /* update the DCD header information */
00688   fio_fseek(fd, NFILE_POS, FIO_SEEK_SET);
00689   fio_write_int32(fd, curframe);
00690   fio_fseek(fd, NSTEP_POS, FIO_SEEK_SET);
00691   fio_write_int32(fd, curstep);
00692   fio_fseek(fd, 0, FIO_SEEK_END);
00693 
00694   return DCD_SUCCESS;
00695 }
00696 
00697 /*
00698  * Write a header for a new dcd file
00699  * Input: fd - file struct opened for binary writing
00700  *        remarks - string to be put in the remarks section of the header.  
00701  *                  The string will be truncated to 70 characters.
00702  *        natoms, istart, nsavc, delta - see comments in read_dcdheader
00703  * Output: 0 on success, negative error code on failure.
00704  * Side effects: Header information is written to the dcd file.
00705  */
00706 static int write_dcdheader(fio_fd fd, const char *remarks, int N, 
00707                     int ISTART, int NSAVC, double DELTA, int with_unitcell,
00708                     int charmm) {
00709   int out_integer;
00710   float out_float;
00711   char title_string[200];
00712   time_t cur_time;
00713   struct tm *tmbuf;
00714   char time_str[81];
00715 
00716   out_integer = 84;
00717   WRITE(fd, (char *) & out_integer, sizeof(int));
00718   strcpy(title_string, "CORD");
00719   WRITE(fd, title_string, 4);
00720   fio_write_int32(fd, 0);      /* Number of frames in file, none written yet   */
00721   fio_write_int32(fd, ISTART); /* Starting timestep                            */
00722   fio_write_int32(fd, NSAVC);  /* Timesteps between frames written to the file */
00723   fio_write_int32(fd, 0);      /* Number of timesteps in simulation            */
00724   fio_write_int32(fd, 0);      /* NAMD writes NSTEP or ISTART - NSAVC here?    */
00725   fio_write_int32(fd, 0);
00726   fio_write_int32(fd, 0);
00727   fio_write_int32(fd, 0);
00728   fio_write_int32(fd, 0);
00729   if (charmm) {
00730     out_float = DELTA;
00731     WRITE(fd, (char *) &out_float, sizeof(float));
00732     if (with_unitcell) {
00733       fio_write_int32(fd, 1);
00734     } else {
00735       fio_write_int32(fd, 0);
00736     }
00737   } else {
00738     WRITE(fd, (char *) &DELTA, sizeof(double));
00739   }
00740   fio_write_int32(fd, 0);
00741   fio_write_int32(fd, 0);
00742   fio_write_int32(fd, 0);
00743   fio_write_int32(fd, 0);
00744   fio_write_int32(fd, 0);
00745   fio_write_int32(fd, 0);
00746   fio_write_int32(fd, 0);
00747   fio_write_int32(fd, 0);
00748   if (charmm) {
00749     fio_write_int32(fd, 24); /* Pretend to be CHARMM version 24 */
00750   } else {
00751     fio_write_int32(fd, 0);
00752   }
00753   fio_write_int32(fd, 84);
00754   fio_write_int32(fd, 164);
00755   fio_write_int32(fd, 2);
00756 
00757   strncpy(title_string, remarks, 80);
00758   title_string[79] = '\0';
00759   WRITE(fd, title_string, 80);
00760 
00761   cur_time=time(NULL);
00762   tmbuf=localtime(&cur_time);
00763   strftime(time_str, 80, "REMARKS Created %d %B, %Y at %R", tmbuf);
00764   WRITE(fd, time_str, 80);
00765 
00766   fio_write_int32(fd, 164);
00767   fio_write_int32(fd, 4);
00768   fio_write_int32(fd, N);
00769   fio_write_int32(fd, 4);
00770 
00771   return DCD_SUCCESS;
00772 }
00773 
00774 
00775 /*
00776  * clean up dcd data
00777  * Input: nfixed, freeind - elements as returned by read_dcdheader
00778  * Output: None
00779  * Side effects: Space pointed to by freeind is freed if necessary.
00780  */
00781 static void close_dcd_read(int *indexes, float *fixedcoords) {
00782   free(indexes);
00783   free(fixedcoords);
00784 }
00785 
00786 
00787 
00788 
00789 
00790 static void *open_dcd_read(const char *path, const char *filetype, 
00791     int *natoms) {
00792   dcdhandle *dcd;
00793   fio_fd fd;
00794   int rc;
00795   struct stat stbuf;
00796 
00797   if (!path) return NULL;
00798 
00799   /* See if the file exists, and get its size */
00800   memset(&stbuf, 0, sizeof(struct stat));
00801   if (stat(path, &stbuf)) {
00802     printf("dcdplugin) Could not access file '%s'.\n", path);
00803     return NULL;
00804   }
00805 
00806   if (fio_open(path, FIO_READ, &fd) < 0) {
00807     printf("dcdplugin) Could not open file '%s' for reading.\n", path);
00808     return NULL;
00809   }
00810 
00811   dcd = (dcdhandle *)malloc(sizeof(dcdhandle));
00812   memset(dcd, 0, sizeof(dcdhandle));
00813   dcd->fd = fd;
00814 
00815   if ((rc = read_dcdheader(dcd->fd, &dcd->natoms, &dcd->nsets, &dcd->istart, 
00816          &dcd->nsavc, &dcd->delta, &dcd->nfixed, &dcd->freeind, 
00817          &dcd->fixedcoords, &dcd->reverse, &dcd->charmm))) {
00818     print_dcderror("read_dcdheader", rc);
00819     fio_fclose(dcd->fd);
00820     free(dcd);
00821     return NULL;
00822   }
00823 
00824   /*
00825    * Check that the file is big enough to really hold the number of sets
00826    * it claims to have.  Then we'll use nsets to keep track of where EOF
00827    * should be.
00828    */
00829   {
00830     fio_size_t ndims, firstframesize, framesize, extrablocksize;
00831     fio_size_t trjsize, filesize, curpos;
00832     int newnsets;
00833 
00834     extrablocksize = dcd->charmm & DCD_HAS_EXTRA_BLOCK ? 48 + 8 : 0;
00835     ndims = dcd->charmm & DCD_HAS_4DIMS ? 4 : 3;
00836     firstframesize = (dcd->natoms+2) * ndims * sizeof(float) + extrablocksize;
00837     framesize = (dcd->natoms-dcd->nfixed+2) * ndims * sizeof(float) 
00838       + extrablocksize;
00839 
00840     /* 
00841      * It's safe to use ftell, even though ftell returns a long, because the 
00842      * header size is < 4GB.
00843      */
00844 
00845     curpos = fio_ftell(dcd->fd); /* save current offset (end of header) */
00846 
00847 #if defined(_MSC_VER) && defined(FASTIO_NATIVEWIN32)
00848     /* the stat() call is not 64-bit savvy on Windows             */
00849     /* so we have to use the fastio fseek/ftell routines for this */
00850     /* until we add a portable filesize routine for this purpose  */
00851     fio_fseek(dcd->fd, 0, FIO_SEEK_END);       /* seek to end of file */
00852     filesize = fio_ftell(dcd->fd);
00853     fio_fseek(dcd->fd, curpos, FIO_SEEK_SET);  /* return to end of header */
00854 #else
00855     filesize = stbuf.st_size; /* this works ok on Unix machines */
00856 #endif
00857     trjsize = filesize - curpos - firstframesize;
00858     if (trjsize < 0) {
00859       printf("dcdplugin) file '%s' appears to contain no timesteps.\n", path);
00860       fio_fclose(dcd->fd);
00861       free(dcd);
00862       return NULL;
00863     }
00864 
00865     newnsets = trjsize / framesize + 1;
00866 
00867     if (dcd->nsets > 0 && newnsets != dcd->nsets) {
00868       printf("dcdplugin) Warning: DCD header claims %d frames, file size indicates there are actually %d frames\n", dcd->nsets, newnsets);
00869     }
00870 
00871     dcd->nsets = newnsets; 
00872     dcd->setsread = 0;
00873   }
00874 
00875   dcd->first = 1;
00876   dcd->x = (float *)malloc(dcd->natoms * sizeof(float));
00877   dcd->y = (float *)malloc(dcd->natoms * sizeof(float));
00878   dcd->z = (float *)malloc(dcd->natoms * sizeof(float));
00879   if (!dcd->x || !dcd->y || !dcd->z) {
00880     printf("dcdplugin) Unable to allocate space for %d atoms.\n", dcd->natoms);
00881     if (dcd->x)
00882       free(dcd->x);
00883     if (dcd->y)
00884       free(dcd->y);
00885     if (dcd->z)
00886       free(dcd->z);
00887     fio_fclose(dcd->fd);
00888     free(dcd);
00889     return NULL;
00890   }
00891   *natoms = dcd->natoms;
00892   return dcd;
00893 }
00894 
00895 
00896 static int read_next_timestep(void *v, int natoms, molfile_timestep_t *ts) {
00897   dcdhandle *dcd;
00898   int i, j, rc;
00899   float unitcell[6];
00900   unitcell[0] = unitcell[2] = unitcell[5] = 1.0f;
00901   unitcell[1] = unitcell[3] = unitcell[4] = 90.0f;
00902   dcd = (dcdhandle *)v;
00903 
00904   /* Check for EOF here; that way all EOF's encountered later must be errors */
00905   if (dcd->setsread == dcd->nsets) return MOLFILE_EOF;
00906   dcd->setsread++;
00907   if (!ts) {
00908     if (dcd->first && dcd->nfixed) {
00909       /* We can't just skip it because we need the fixed atom coordinates */
00910       rc = read_dcdstep(dcd->fd, dcd->natoms, dcd->x, dcd->y, dcd->z, 
00911           unitcell, dcd->nfixed, dcd->first, dcd->freeind, dcd->fixedcoords, 
00912              dcd->reverse, dcd->charmm);
00913       dcd->first = 0;
00914       return rc; /* XXX this needs to be updated */
00915     }
00916     dcd->first = 0;
00917     /* XXX this needs to be changed */
00918     return skip_dcdstep(dcd->fd, dcd->natoms, dcd->nfixed, dcd->charmm);
00919   }
00920   rc = read_dcdstep(dcd->fd, dcd->natoms, dcd->x, dcd->y, dcd->z, unitcell,
00921              dcd->nfixed, dcd->first, dcd->freeind, dcd->fixedcoords, 
00922              dcd->reverse, dcd->charmm);
00923   dcd->first = 0;
00924   if (rc < 0) {  
00925     print_dcderror("read_dcdstep", rc);
00926     return MOLFILE_ERROR;
00927   }
00928 
00929   /* copy timestep data from plugin-local buffers to VMD's buffer */
00930   /* XXX 
00931    *   This code is still the root of all evil.  Just doing this extra copy
00932    *   cuts the I/O rate of the DCD reader from 728 MB/sec down to
00933    *   394 MB/sec when reading from a ram filesystem.  
00934    *   For a physical disk filesystem, the I/O rate goes from 
00935    *   187 MB/sec down to 122 MB/sec.  Clearly this extra copy has to go.
00936    */
00937   {
00938     int natoms = dcd->natoms;
00939     float *nts = ts->coords;
00940     const float *bufx = dcd->x;
00941     const float *bufy = dcd->y;
00942     const float *bufz = dcd->z;
00943 
00944     for (i=0, j=0; i<natoms; i++, j+=3) {
00945       nts[j    ] = bufx[i];
00946       nts[j + 1] = bufy[i];
00947       nts[j + 2] = bufz[i];
00948     }
00949   }
00950 
00951   ts->A = unitcell[0];
00952   ts->B = unitcell[2];
00953   ts->C = unitcell[5];
00954 
00955   if (unitcell[1] >= -1.0 && unitcell[1] <= 1.0 &&
00956       unitcell[3] >= -1.0 && unitcell[3] <= 1.0 &&
00957       unitcell[4] >= -1.0 && unitcell[4] <= 1.0) {
00958     /* This file was generated by CHARMM, or by NAMD > 2.5, with the angle */
00959     /* cosines of the periodic cell angles written to the DCD file.        */ 
00960     /* This formulation improves rounding behavior for orthogonal cells    */
00961     /* so that the angles end up at precisely 90 degrees, unlike acos().   */
00962     ts->alpha = 90.0 - asin(unitcell[4]) * 90.0 / M_PI_2; /* cosBC */
00963     ts->beta  = 90.0 - asin(unitcell[3]) * 90.0 / M_PI_2; /* cosAC */
00964     ts->gamma = 90.0 - asin(unitcell[1]) * 90.0 / M_PI_2; /* cosAB */
00965   } else {
00966     /* This file was likely generated by NAMD 2.5 and the periodic cell    */
00967     /* angles are specified in degrees rather than angle cosines.          */
00968     ts->alpha = unitcell[4]; /* angle between B and C */
00969     ts->beta  = unitcell[3]; /* angle between A and C */
00970     ts->gamma = unitcell[1]; /* angle between A and B */
00971   }
00972  
00973   return MOLFILE_SUCCESS;
00974 }
00975  
00976 
00977 static void close_file_read(void *v) {
00978   dcdhandle *dcd = (dcdhandle *)v;
00979   close_dcd_read(dcd->freeind, dcd->fixedcoords);
00980   fio_fclose(dcd->fd);
00981   free(dcd->x);
00982   free(dcd->y);
00983   free(dcd->z);
00984   free(dcd); 
00985 }
00986 
00987 
00988 static void *open_dcd_write(const char *path, const char *filetype, 
00989     int natoms) {
00990   dcdhandle *dcd;
00991   fio_fd fd;
00992   int rc;
00993   int istart, nsavc;
00994   double delta;
00995   int with_unitcell;
00996   int charmm;
00997 
00998   if (fio_open(path, FIO_WRITE, &fd) < 0) {
00999     printf("dcdplugin) Could not open file '%s' for writing\n", path);
01000     return NULL;
01001   }
01002 
01003   dcd = (dcdhandle *)malloc(sizeof(dcdhandle));
01004   memset(dcd, 0, sizeof(dcdhandle));
01005   dcd->fd = fd;
01006 
01007   istart = 0;             /* starting timestep of DCD file                  */
01008   nsavc = 1;              /* number of timesteps between written DCD frames */
01009   delta = 1.0;            /* length of a timestep                           */
01010   with_unitcell = 1;      /* contains unit cell information (charmm format) */
01011   charmm = DCD_IS_CHARMM; /* charmm-formatted DCD file                      */ 
01012   if (with_unitcell) 
01013     charmm |= DCD_HAS_EXTRA_BLOCK;
01014   
01015   rc = write_dcdheader(dcd->fd, "Created by DCD plugin", natoms, 
01016                        istart, nsavc, delta, with_unitcell, charmm);
01017 
01018   if (rc < 0) {
01019     print_dcderror("write_dcdheader", rc);
01020     fio_fclose(dcd->fd);
01021     free(dcd);
01022     return NULL;
01023   }
01024 
01025   dcd->natoms = natoms;
01026   dcd->nsets = 0;
01027   dcd->istart = istart;
01028   dcd->nsavc = nsavc;
01029   dcd->with_unitcell = with_unitcell;
01030   dcd->charmm = charmm;
01031   dcd->x = (float *)malloc(natoms * sizeof(float));
01032   dcd->y = (float *)malloc(natoms * sizeof(float));
01033   dcd->z = (float *)malloc(natoms * sizeof(float));
01034   return dcd;
01035 }
01036 
01037 
01038 static int write_timestep(void *v, const molfile_timestep_t *ts) { 
01039   dcdhandle *dcd = (dcdhandle *)v;
01040   int i, rc, curstep;
01041   float *pos = ts->coords;
01042   double unitcell[6];
01043   unitcell[0] = unitcell[2] = unitcell[5] = 1.0f;
01044   unitcell[1] = unitcell[3] = unitcell[4] = 90.0f;
01045 
01046   /* copy atom coords into separate X/Y/Z arrays for writing */
01047   for (i=0; i<dcd->natoms; i++) {
01048     dcd->x[i] = *(pos++); 
01049     dcd->y[i] = *(pos++); 
01050     dcd->z[i] = *(pos++); 
01051   }
01052   dcd->nsets++;
01053   curstep = dcd->istart + dcd->nsets * dcd->nsavc;
01054 
01055   unitcell[0] = ts->A;
01056   unitcell[2] = ts->B;
01057   unitcell[5] = ts->C;
01058   unitcell[1] = sin((M_PI_2 / 90.0) * (90.0 - ts->gamma)); /* cosAB */
01059   unitcell[3] = sin((M_PI_2 / 90.0) * (90.0 - ts->beta));  /* cosAC */
01060   unitcell[4] = sin((M_PI_2 / 90.0) * (90.0 - ts->alpha)); /* cosBC */
01061 
01062   rc = write_dcdstep(dcd->fd, dcd->nsets, curstep, dcd->natoms, 
01063                      dcd->x, dcd->y, dcd->z,
01064                      dcd->with_unitcell ? unitcell : NULL,
01065                      dcd->charmm);
01066   if (rc < 0) {
01067     print_dcderror("write_dcdstep", rc);
01068     return MOLFILE_ERROR;
01069   }
01070 
01071   return MOLFILE_SUCCESS;
01072 }
01073 
01074 static void close_file_write(void *v) {
01075   dcdhandle *dcd = (dcdhandle *)v;
01076   fio_fclose(dcd->fd);
01077   free(dcd->x);
01078   free(dcd->y);
01079   free(dcd->z);
01080   free(dcd);
01081 }
01082 
01083 
01084 /*
01085  * Initialization stuff here
01086  */
01087 static molfile_plugin_t dcdplugin = {
01088   vmdplugin_ABIVERSION,                         /* ABI version */
01089   MOLFILE_PLUGIN_TYPE,                          /* type */
01090   "dcd",                                        /* short name */
01091   "CHARMM,NAMD,XPLOR DCD Trajectory",           /* pretty name */
01092   "Justin Gullingsrud, John Stone",             /* author */
01093   1,                                            /* major version */
01094   8,                                            /* minor version */
01095   VMDPLUGIN_THREADSAFE,                         /* is reentrant  */
01096   "dcd",                                        /* filename extension */
01097   open_dcd_read,
01098   0,
01099   0,
01100   read_next_timestep,
01101   close_file_read,
01102   open_dcd_write,
01103   0,
01104   write_timestep,
01105   close_file_write
01106 };
01107 
01108 VMDPLUGIN_API int VMDPLUGIN_init() {
01109   return VMDPLUGIN_SUCCESS;
01110 }
01111 
01112 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
01113   (*cb)(v, (vmdplugin_t *)&dcdplugin);
01114   return VMDPLUGIN_SUCCESS;
01115 }
01116 
01117 VMDPLUGIN_API int VMDPLUGIN_fini() {
01118   return VMDPLUGIN_SUCCESS;
01119 }
01120 
01121   
01122 #ifdef TEST_DCDPLUGIN
01123 
01124 #include <sys/time.h>
01125 
01126 /* get the time of day from the system clock, and store it (in seconds) */
01127 double time_of_day(void) {
01128 #if defined(_MSC_VER)
01129   double t;
01130 
01131   t = GetTickCount();
01132   t = t / 1000.0;
01133 
01134   return t;
01135 #else
01136   struct timeval tm;
01137   struct timezone tz;
01138 
01139   gettimeofday(&tm, &tz);
01140   return((double)(tm.tv_sec) + (double)(tm.tv_usec)/1000000.0);
01141 #endif
01142 }
01143 
01144 int main(int argc, char *argv[]) {
01145   molfile_timestep_t timestep;
01146   void *v;
01147   dcdhandle *dcd;
01148   int i, natoms;
01149   float sizeMB =0.0, totalMB = 0.0;
01150   double starttime, endtime, totaltime = 0.0;
01151 
01152   while (--argc) {
01153     ++argv; 
01154     natoms = 0;
01155     v = open_dcd_read(*argv, "dcd", &natoms);
01156     if (!v) {
01157       fprintf(stderr, "main) open_dcd_read failed for file %s\n", *argv);
01158       return 1;
01159     }
01160     dcd = (dcdhandle *)v;
01161     sizeMB = ((natoms * 3.0) * dcd->nsets * 4.0) / (1024.0 * 1024.0);
01162     totalMB += sizeMB; 
01163     printf("main) file: %s\n", *argv);
01164     printf("  %d atoms, %d frames, size: %6.1fMB\n", natoms, dcd->nsets, sizeMB);
01165 
01166     starttime = time_of_day();
01167     timestep.coords = (float *)malloc(3*sizeof(float)*natoms);
01168     for (i=0; i<dcd->nsets; i++) {
01169       int rc = read_next_timestep(v, natoms, &timestep);
01170       if (rc) {
01171         fprintf(stderr, "error in read_next_timestep on frame %d\n", i);
01172         return 1;
01173       }
01174     }
01175     endtime = time_of_day();
01176     close_file_read(v);
01177     totaltime += endtime - starttime;
01178     printf("  Time: %5.1f seconds\n", endtime - starttime);
01179     printf("  Speed: %5.1f MB/sec, %5.1f timesteps/sec\n", sizeMB / (endtime - starttime), (dcd->nsets / (endtime - starttime)));
01180   }
01181   printf("Overall Size: %6.1f MB\n", totalMB);
01182   printf("Overall Time: %6.1f seconds\n", totaltime);
01183   printf("Overall Speed: %5.1f MB/sec\n", totalMB / totaltime);
01184   return 0;
01185 }
01186       
01187 #endif
01188 

Generated on Wed Mar 22 13:15:28 2006 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002