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

jsplugin.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: jsplugin.c,v $
00013  *      $Author: johns $       $Locker:  $             $State: Exp $
00014  *      $Revision: 1.10 $       $Date: 2006/02/23 19:36:45 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *   Code for reading and writing John's molecular dynamics trajectory files
00019  *   for I/O performance testing and as a simple example plugin.
00020  *
00021  *   No programs actually use this format, so it's only a test/example code.
00022  *
00023  *   This plugin reads and writes mostly the same data that a DCD file 
00024  *   contains, but the ordering of I/O operations avoids having to do
00025  *   scatter/gather passes on the buffers, so it ends up performing 
00026  *   two to three times faster than the DCD format for the same data set.
00027  *
00028  *   Best measured I/O performance in VMD so far is 631 MB/sec on a Sun V880z 
00029  *   Best standalone I/O performance so far is 688 MB/sec.
00030  *
00031  *  Standalone test binary compilation flags:
00032  *  cc -fast -xarch=v9a -I../../include -DTEST_JSPLUGIN jsplugin.c \
00033  *    -o ~/bin/readjs -lm
00034  *
00035  *  Profiling flags:
00036  *  cc -xpg -fast -xarch=v9a -g -I../../include -DTEST_JSPLUGIN jsplugin.c \
00037  *    -o ~/bin/readjs -lm
00038  *
00039  ***************************************************************************/
00040 
00041 #include "largefiles.h"   /* platform dependent 64-bit file I/O defines */
00042 
00043 #include <sys/stat.h>
00044 #include <sys/types.h>
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include <string.h>
00048 #include <math.h>
00049 
00050 #include "fastio.h"
00051 #include "endianswap.h"
00052 
00053 #include "molfile_plugin.h"
00054 
00055 #ifndef M_PI_2
00056 #define M_PI_2 1.57079632679489661922
00057 #endif
00058 
00059 #define JSHEADERSTRING   "JS Binary Trajectory File Format"                
00060 #define JSMAGICNUMBER    0x31337
00061 #define JSENDIANISM      0x12345678
00062 #define JSMAJORVERSION   1
00063 #define JSMINORVERSION   0
00064 
00065 #define JSNFRAMESOFFSET  (strlen(JSHEADERSTRING) + 20)
00066 
00067 #define JSNOERR          0
00068 #define JSBADFILE        1
00069 #define JSBADFORMAT      2
00070 
00071 typedef struct {
00072   fio_fd fd;
00073   int natoms;
00074   int nframes;
00075   double tsdelta;
00076   int reverse;
00077   int with_unitcell;
00078 } jshandle;
00079 
00080 static void *open_js_read(const char *path, const char *filetype, int *natoms) {
00081   jshandle *js;
00082   int jsmagicnumber, jsendianism, jsmajorversion, jsminorversion;
00083   struct stat stbuf;
00084   char strbuf[1024];
00085   int rc = 0;
00086 
00087   if (!path) return NULL;
00088 
00089   /* See if the file exists, and get its size */
00090   memset(&stbuf, 0, sizeof(struct stat));
00091   if (stat(path, &stbuf)) {
00092     fprintf(stderr, "Could not access file '%s'.\n", path);
00093     return NULL;
00094   }
00095 
00096   js = (jshandle *)malloc(sizeof(jshandle));
00097   memset(js, 0, sizeof(jshandle));
00098   if (fio_open(path, FIO_READ, &js->fd) < 0) {
00099     fprintf(stderr, "Could not open file '%s' for reading.\n", path);
00100     free(js);
00101     return NULL;
00102   }
00103 
00104   /* emit header information */
00105   fio_fread(strbuf, strlen(JSHEADERSTRING), 1, js->fd);
00106   strbuf[strlen(JSHEADERSTRING)] = '\0';
00107   if (strcmp(strbuf, JSHEADERSTRING)) {
00108     fprintf(stderr, "Bad trajectory header!\n");
00109     fprintf(stderr, "Read string: %s\n", strbuf);
00110     return NULL;
00111   }
00112 
00113   fio_read_int32(js->fd, &jsmagicnumber);
00114   fio_read_int32(js->fd, &jsendianism);
00115   fio_read_int32(js->fd, &jsmajorversion);
00116   fio_read_int32(js->fd, &jsminorversion);
00117   fio_read_int32(js->fd, &js->natoms);
00118   fio_read_int32(js->fd, &js->nframes);
00119 
00120   if ((jsmagicnumber != JSMAGICNUMBER) || (jsendianism != JSENDIANISM)) {
00121     fprintf(stderr, "Opposite endianism trajectory file, enabling byte swapping\n");
00122     js->reverse = 1;
00123     swap4_aligned(&jsmagicnumber, 1);
00124     swap4_aligned(&jsendianism, 1);
00125     swap4_aligned(&jsmajorversion, 1);
00126     swap4_aligned(&jsminorversion, 1);
00127     swap4_aligned(&js->natoms, 1);
00128     swap4_aligned(&js->nframes, 1);
00129   }
00130 
00131   if ((jsmagicnumber != JSMAGICNUMBER) || (jsendianism != JSENDIANISM)) {
00132     fprintf(stderr, "read_jsreader returned %d\n", rc);
00133     fio_fclose(js->fd);
00134     free(js);
00135     return NULL;
00136   }
00137 
00138   *natoms = js->natoms;
00139   return js;
00140 }
00141 
00142 
00143 static int read_js_timestep(void *v, int natoms, molfile_timestep_t *ts) {
00144   jshandle *js = (jshandle *)v;
00145   int framelen = (natoms * 3 * sizeof(float)) + (6 * sizeof(double));;
00146 
00147   /* if we have a valid ts pointer, read the timestep, otherwise skip it */ 
00148   if (ts != NULL) {
00149     int readlen; 
00150     fio_iovec iov[2];
00151     double unitcell[6];
00152     unitcell[0] = unitcell[2] = unitcell[5] = 1.0f;
00153     unitcell[1] = unitcell[3] = unitcell[4] = 90.0f;
00154   
00155     /* setup the I/O vector */
00156     iov[0].iov_base = (fio_caddr_t) ts->coords;   /* read coordinates    */
00157     iov[0].iov_len  = natoms * 3 * sizeof(float);
00158     iov[1].iov_base = (fio_caddr_t) &unitcell[0]; /* read PBC unit cell  */
00159     iov[1].iov_len  = 6 * sizeof(double);
00160 
00161     /* Do all of the reads with a single syscall, for peak efficiency. */
00162     /* On smart kernels, readv() causes only one context switch, and   */
00163     /* can effeciently scatter the reads to the various buffers.       */
00164     readlen = fio_readv(js->fd, &iov[0], 2); 
00165   
00166     /* check the number of read bytes versus what we expected */
00167     if (readlen != framelen)
00168       return MOLFILE_EOF;
00169 
00170     /* perform byte swapping if necessary */
00171     if (js->reverse) {
00172       swap4_aligned(ts->coords, natoms * 3);
00173       swap8_aligned(unitcell, 6);
00174     }
00175 
00176     /* copy unit cell values into VMD */
00177     ts->A = unitcell[0];
00178     ts->B = unitcell[1];
00179     ts->C = unitcell[2];
00180     ts->alpha = 90.0 - asin(unitcell[3]) * 90.0 / M_PI_2;
00181     ts->beta  = 90.0 - asin(unitcell[4]) * 90.0 / M_PI_2;
00182     ts->gamma = 90.0 - asin(unitcell[5]) * 90.0 / M_PI_2;
00183   } else {
00184     /* skip this frame, seek to the next frame */
00185     if (fio_fseek(js->fd, framelen, FIO_SEEK_CUR)) 
00186       return MOLFILE_EOF;
00187   }
00188  
00189   return MOLFILE_SUCCESS;
00190 }
00191  
00192 
00193 static void close_js_read(void *v) {
00194   jshandle *js = (jshandle *)v;
00195   fio_fclose(js->fd);
00196   free(js); 
00197 }
00198 
00199 
00200 static void *open_js_write(const char *path, const char *filetype, int natoms) {
00201   jshandle *js;
00202 
00203   js = (jshandle *)malloc(sizeof(jshandle));
00204   memset(js, 0, sizeof(jshandle));
00205   if (fio_open(path, FIO_WRITE, &js->fd) < 0) {
00206     fprintf(stderr, "Could not open file %s for writing\n", path);
00207     free(js);
00208     return NULL;
00209   }
00210 
00211   js->natoms = natoms;
00212   js->with_unitcell = 1;
00213 
00214   /* emit header information */
00215   fio_write_str(js->fd, JSHEADERSTRING);
00216   fio_write_int32(js->fd, JSMAGICNUMBER);
00217   fio_write_int32(js->fd, JSENDIANISM);
00218   fio_write_int32(js->fd, JSMAJORVERSION);
00219   fio_write_int32(js->fd, JSMINORVERSION);
00220 
00221   /* write number of atoms */
00222   fio_write_int32(js->fd, natoms);
00223 
00224   /* write number of frames, to be updated later */
00225   js->nframes = 0;
00226   fio_write_int32(js->fd, js->nframes);
00227 
00228   return js;
00229 }
00230 
00231 static int write_js_timestep(void *v, const molfile_timestep_t *ts) { 
00232   jshandle *js = (jshandle *)v;
00233   double unitcell[6];
00234 
00235   js->nframes++; /* increment frame count written to the file so far */
00236 
00237   unitcell[0] = ts->A;
00238   unitcell[1] = ts->B;
00239   unitcell[2] = ts->C;
00240   unitcell[3] = sin((M_PI_2 / 90.0) * (90.0 - ts->alpha));
00241   unitcell[4] = sin((M_PI_2 / 90.0) * (90.0 - ts->beta));
00242   unitcell[5] = sin((M_PI_2 / 90.0) * (90.0 - ts->gamma));
00243 
00244   /* coordinates for all atoms */
00245   fio_fwrite(ts->coords, js->natoms * 3 * sizeof(float), 1, js->fd);
00246 
00247   /* PBC unit cell info */ 
00248   fio_fwrite(&unitcell[0], 6 * sizeof(double), 1, js->fd);
00249 
00250   return MOLFILE_SUCCESS;
00251 }
00252 
00253 static void close_js_write(void *v) {
00254   jshandle *js = (jshandle *)v;
00255 
00256   /* update the trajectory header information */
00257   fio_fseek(js->fd, JSNFRAMESOFFSET, FIO_SEEK_SET);
00258   fio_write_int32(js->fd, js->nframes);
00259   fio_fseek(js->fd, 0, FIO_SEEK_END);
00260 
00261   fio_fclose(js->fd);
00262   free(js);
00263 }
00264 
00265 
00266 /*
00267  * Initialization stuff here
00268  */
00269 static molfile_plugin_t jsplugin = {
00270   vmdplugin_ABIVERSION,                         /* ABI version */
00271   MOLFILE_PLUGIN_TYPE,                          /* type */
00272   "js",                                         /* name */
00273   "js",                                         /* name */
00274   "John Stone",                                 /* author */
00275   0,                                            /* major version */
00276   8,                                            /* minor version */
00277   VMDPLUGIN_THREADSAFE,                         /* is reentrant  */
00278   "js",                                         /* filename extension */
00279   open_js_read,
00280   0,
00281   0,
00282   read_js_timestep,
00283   close_js_read,
00284   open_js_write,
00285   0,
00286   write_js_timestep,
00287   close_js_write,
00288   0,                            /* read_volumetric_metadata */
00289   0,                            /* read_volumetric_data */
00290   0                             /* read_rawgraphics */
00291 };
00292 
00293 VMDPLUGIN_API int VMDPLUGIN_init() {
00294   return VMDPLUGIN_SUCCESS;
00295 }
00296 
00297 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00298   (*cb)(v, (vmdplugin_t *)&jsplugin);
00299   return VMDPLUGIN_SUCCESS;
00300 }
00301 
00302 VMDPLUGIN_API int VMDPLUGIN_fini() {
00303   return VMDPLUGIN_SUCCESS;
00304 }
00305 
00306   
00307 #ifdef TEST_JSPLUGIN
00308 
00309 #include <sys/time.h>
00310 
00311 /* get the time of day from the system clock, and store it (in seconds) */
00312 double time_of_day(void) {
00313 #if defined(_MSC_VER)
00314   double t;
00315 
00316   t = GetTickCount();
00317   t = t / 1000.0;
00318 
00319   return t;
00320 #else
00321   struct timeval tm;
00322   struct timezone tz;
00323 
00324   gettimeofday(&tm, &tz);
00325   return((double)(tm.tv_sec) + (double)(tm.tv_usec)/1000000.0);
00326 #endif
00327 }
00328 
00329 int main(int argc, char *argv[]) {
00330   molfile_timestep_t timestep;
00331   void *v;
00332   jshandle *js;
00333   int i, natoms;
00334   float sizeMB =0.0, totalMB = 0.0;
00335   double starttime, endtime, totaltime = 0.0;
00336 
00337   while (--argc) {
00338     ++argv; 
00339     natoms = 0;
00340     v = open_js_read(*argv, "js", &natoms);
00341     if (!v) {
00342       fprintf(stderr, "open_js_read failed for file %s\n", *argv);
00343       return 1;
00344     }
00345     js = (jshandle *)v;
00346     sizeMB = ((natoms * 3.0) * js->nframes * 4.0) / (1024.0 * 1024.0);
00347     totalMB += sizeMB; 
00348     printf("file: %s\n", *argv);
00349     printf("  %d atoms, %d frames, size: %6.1fMB\n", natoms, js->nframes, sizeMB);
00350 
00351     starttime = time_of_day();
00352     timestep.coords = (float *)malloc(3*sizeof(float)*natoms);
00353     for (i=0; i<js->nframes; i++) {
00354       int rc = read_js_timestep(v, natoms, &timestep);
00355       if (rc) {
00356         fprintf(stderr, "error in read_js_timestep on frame %d\n", i);
00357         return 1;
00358       }
00359     }
00360     endtime = time_of_day();
00361     close_js_read(v);
00362     totaltime += endtime - starttime;
00363     printf("  Time: %5.1f seconds\n", endtime - starttime);
00364     printf("  Speed: %5.1f MB/sec, %5.1f timesteps/sec\n", sizeMB / (endtime - starttime), (js->nframes / (endtime - starttime)));
00365   }
00366   printf("Overall Size: %6.1f MB\n", totalMB);
00367   printf("Overall Time: %6.1f seconds\n", totaltime);
00368   printf("Overall Speed: %5.1f MB/sec\n", totalMB / totaltime);
00369   return 0;
00370 }
00371       
00372 #endif
00373 

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