Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

jsplugin.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2016 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.86 $       $Date: 2019/12/02 16:04:45 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *   This plugin implements a high-performance binary molecular structure
00019  *   and trajectory storage format.  This file format currently uses a simple 
00020  *   non-redundant hash table approach for compression of per-atom
00021  *   character strings, properties, and tags.  Trajectory data is stored 
00022  *   with a file structure that avoids the need to transpose or convert
00023  *   dense blocks of cartesian coordinates into the most commonly used
00024  *   interleaved  x/y/z ordering.  The file structure also enables zero-copy 
00025  *   vectorized I/O methods to be used high-performance reads for 
00026  *   visualization and analysis with reduced operating system overhead.
00027  *   The plugin optionally supports the use of a block-based file structure
00028  *   and block-aligned memory buffers for direct I/O that bypasses the 
00029  *   OS filesystem buffer caches for multi-gigabyte-per-second read rates
00030  *   from SSD RAID arrays.
00031  *
00032  *   At present, only VMD, NAMD, and psfgen make use of this format.
00033  *   It started out as a test/example code and is slowly becoming
00034  *   more robust and featureful.
00035  *
00036  *   We should be able to implement a selective read approach that gathers
00037  *   discontiguous blocks of the trajectory using the POSIX lio_listio()
00038  *   APIs.  On Unix we currently use I/O wrappers that are based on the 
00039  *   lseek() and readv() APIs.  By using lio_listio() we could eliminate
00040  *   the separate lseek calls and service multiple timestep reads in a 
00041  *   single request, even included cases with discontiguous requests.
00042  *
00043  *   VMD test results for Linux host with an 8-way RAID0 of commodity 
00044  *   Intel 510 SSDs with SATA III 6Gbit/sec interfaces:
00045  *     Non-direct I/O using standard readv(): 1203 MB/sec
00046  *     Direct I/O, readv(), 4KB blocked file: 2130 MB/sec
00047  ***************************************************************************/
00048 /***
00049  ** Standalone test binary compilation flags for 64-bit Linux:
00050     cc -O3 -m64 -I../../include -DTEST_JSPLUGIN jsplugin.c \
00051       -o ~/bin/readjs -lm
00052  **
00053  ** Standalone test binary compilation flags for 64-bit Linux w/ CUDA:
00054     cc -O3 -m64 -I../../include -I/usr/local/cuda/include \
00055       -DTEST_JSPLUGIN -DENABLECUDATESTS jsplugin.c \
00056       -o ~/bin/readjs -L/usr/local/cuda/lib64 -lcudart -lm
00057  **
00058  ** Standalone test binary compilation flags for 64-bit Linux w/ CUDA+GDS:
00059     cc -O3 -m64 -I../../include -I/usr/local/cuda/include \
00060       -I/Projects/vmd/cuda/johns/gds/gds-alpha/lib \
00061       -DTEST_JSPLUGIN -DENABLECUDATESTS -DENABLECUDAGDS jsplugin.c \
00062       -o ~/bin/readjs -L/Projects/vmd/cuda/johns/gds/gds-alpha/lib -lcufile \
00063       -L/usr/local/cuda/lib64 -lcudart -lm
00064  **
00065  ** Standalone test binary compilation flags for Solaris:
00066     cc -fast -xarch=v9a -I../../include -DTEST_JSPLUGIN jsplugin.c \
00067       -o ~/bin/readjs -lm
00068  **
00069  ** Profiling flags for Solaris:
00070     cc -xpg -fast -xarch=v9a -g -I../../include -DTEST_JSPLUGIN jsplugin.c \
00071       -o ~/bin/readjs -lm
00072  **
00073  ** Test run for DGX-2:
00074     ~/bin/readjs /raid/scratch/solvatebar1204kb.js
00075  ***************************************************************************/
00076 
00077 #define INFOMSGS  1
00078 
00079 #if 1
00080 #define ENABLEJSSHORTREADS 1
00081 #endif
00082 
00083 #define VMDPLUGIN_STATIC
00084 #include "largefiles.h"   /* platform dependent 64-bit file I/O defines */
00085 #include "fastio.h"       /* must come before others, for O_DIRECT...   */
00086 
00087 #include <sys/stat.h>
00088 #include <sys/types.h>
00089 #include <stdio.h>
00090 #include <stdlib.h>
00091 #include <string.h>
00092 #include <math.h>
00093 
00094 #include "hash.h"
00095 #include "endianswap.h"
00096 #include "molfile_plugin.h"
00097 
00098 
00099 /* allocate memory and return a pointer that is aligned on a given   */
00100 /* byte boundary, to be used for page- or sector-aligned I/O buffers */
00101 /* We use this if posix_memalign() is not available...               */
00102 #if 1 /* sizeof(unsigned long) == sizeof(void*) */
00103 #define myintptrtype unsigned long
00104 #elif 1   /* sizeof(size_t) == sizeof(void*) */
00105 #define myintptrtype size_t
00106 #else
00107 #define myintptrtype uintptr_t  /* C99 */
00108 #endif
00109 /*
00110  * XXX On MSVC we get warnings about type conversions for 
00111  *     size_t vs. fio_size_t
00112  */
00113 static void *alloc_aligned_ptr(size_t sz, size_t blocksz, void **unalignedptr) {
00114   /* pad the allocation to an even multiple of the block size */
00115   size_t padsz = (sz + (blocksz - 1)) & (~(blocksz - 1));
00116   void * ptr = malloc(padsz + blocksz);
00117   *unalignedptr = ptr;
00118   return (void *) ((((myintptrtype) ptr) + (blocksz-1)) & (~(blocksz-1)));
00119 }
00120 
00121 
00122 #ifndef M_PI_2
00123 #define M_PI_2 1.57079632679489661922
00124 #endif
00125 
00126 #define JSHEADERSTRING   "JS Binary Structure and Trajectory File Format"                
00127 #define JSMAGICNUMBER    0x31337
00128 #define JSENDIANISM      0x12345678
00129 
00130 #define JSMAJORVERSION   2
00131 #define JSMINORVERSION   17
00132 
00133 #define JSNFRAMESOFFSET  (strlen(JSHEADERSTRING) + 20)
00134 
00135 #define JSNOERR             0
00136 #define JSBADFILE           1
00137 #define JSBADFORMAT         2
00138 
00139 
00140 /* Threshold atom count beyond which block-based I/O is used by default */
00141 /* The overhead from block-alignment padding bytes becomes essentially  */
00142 /* inconsequential (< 1%) for structures with more than 50,000 atoms.   */
00143 #define JSBLOCKIO_THRESH    50000
00144 
00145 
00146 /* Option flag macros and their meanings */
00147 #define JSOPT_NOOPTIONS     0x00000000  /* no structure, only coords    */
00148 
00149 /* Timesteps are block-size padded and page- or sector-aligned for      */
00150 /* direct I/O, using  OS-specific APIs that completely bypass the OS    */
00151 /* kernel filesystem buffer cache.                                      */
00152 /* The use of direct I/O APIs can raise performance tremendously on     */
00153 /* high-end RAIDs.  Tests on an 8-way RAID0 of Intel 510 SSDs raise the */
00154 /* peak I/O rate from 1100 MB/sec up to 2020 MB/sec with direct I/O.    */
00155 #define JSOPT_TS_BLOCKIO    0x10000000
00156 
00157 /* large data blocks */
00158 #define JSOPT_STRUCTURE     0x00000001  /* file contains structure data */
00159 #define JSOPT_BONDS         0x00000002  /* file contains bond info      */
00160 #define JSOPT_BONDORDERS    0x00000004  /* file contains bond orders    */
00161 #define JSOPT_ANGLES        0x00000008  /* file contains angle info     */
00162 #define JSOPT_CTERMS        0x00000010  /* file contains cross-terms    */
00163 
00164 /* optional per-atom fields */
00165 #define JSOPT_OCCUPANCY     0x00000100  /* file contains occupancy      */
00166 #define JSOPT_BFACTOR       0x00000200  /* file contains b-factor       */
00167 #define JSOPT_MASS          0x00000400  /* file contains masses         */
00168 #define JSOPT_CHARGE        0x00000800  /* file contains charges        */
00169 #define JSOPT_RADIUS        0x00001000  /* file contains radii          */
00170 #define JSOPT_ATOMICNUMBER  0x00002000  /* file contains atomic numbers */
00171 
00172 typedef struct {
00173   int verbose;                 /* flag to enable console info output    */
00174   fio_fd fd;                   /* main file descriptor                  */
00175   long natoms;                 /* handle uses a long type for natoms to */
00176                                /* help force promotion of file offset   */
00177                                /* arithmetic to long types              */
00178 
00179 #if JSMAJORVERSION > 1
00180   int parsed_structure;        /* flag indicating structure is parsed   */
00181   char *path;                  /* path to file                          */
00182 
00183   /* info for block-based direct I/O */ 
00184   int directio_pgsize_queried; /* caller has queried page/blocksz       */
00185   int directio_enabled;        /* block-based direct I/O is available   */
00186   fio_fd directio_fd;          /* block-based direct I/O using O_DIRECT */
00187   int directio_block_size;     /* block size to use for direct ts I/O   */
00188   void *directio_ucell_ptr;    /* unaligned unit cell buffer ptr        */
00189   void *directio_ucell_blkbuf; /* block-aligned unit cell buffer pt r   */
00190 
00191   /* timestep file offset, block padding, and stride information */
00192   fio_size_t ts_file_offset;   /* file offset to first timestep         */
00193   fio_size_t ts_crd_sz;        /* size of TS coordinates                */
00194   fio_size_t ts_crd_padsz;     /* size of TS block-padded coordinates   */
00195   fio_size_t ts_ucell_sz;      /* size of TS unit cell                  */
00196   fio_size_t ts_ucell_padsz;   /* size of TS block-padded unit cell     */
00197   
00198   /* structure info */
00199   int optflags;
00200   molfile_atom_t *atomlist;
00201   molfile_metadata_t *meta;
00202 
00203   /* bond info */
00204   int nbonds;
00205   int *bondfrom;
00206   int *bondto;
00207   float *bondorders;
00208 
00209   /* angle/dihedral/improper/cross-term info */
00210   int numangles, *angles;
00211   int numdihedrals, *dihedrals;
00212   int numimpropers, *impropers;
00213   int numcterms, *cterms;
00214 #endif
00215 
00216   /* trajectory info */
00217   int nframes;
00218   double tsdelta;
00219   int reverseendian;
00220   int with_unitcell;
00221 
00222   /* convenient buffer full of zeros for block-multiple padding */
00223   unsigned char blockpad[MOLFILE_DIRECTIO_MAX_BLOCK_SIZE];
00224 } jshandle;
00225 
00226 
00227 /* report the block size required to read this JS file */
00228 static int read_js_timestep_pagealign_size(void *v, int *pagealignsz) {
00229   jshandle *js = (jshandle *)v;
00230 
00231   // mark that the caller has queried the page alignment size
00232   js->directio_pgsize_queried = 1;
00233 
00234   /* assigne page alignment size based on file contents */
00235   if (js->optflags & JSOPT_TS_BLOCKIO) 
00236     *pagealignsz = js->directio_block_size;
00237   else 
00238     *pagealignsz = 1;
00239 
00240   return 0;
00241 }
00242 
00243 
00244 /* Use block-based I/O by default when writing structures larger */
00245 /* than JSBLOCKIO_THRESH atoms, or when directed by the user and */
00246 /* not otherwise prohibited...                                   */
00247 static void js_blockio_check_and_set(jshandle *js) {
00248   if ((getenv("VMDJSNOBLOCKIO") == NULL) && 
00249       ((js->natoms > JSBLOCKIO_THRESH) || getenv("VMDJSBLOCKIO"))) {
00250     js->optflags |= JSOPT_TS_BLOCKIO;
00251     js->directio_block_size = MOLFILE_DIRECTIO_MIN_BLOCK_SIZE; 
00252   }
00253 }
00254 
00255 
00256 static void *open_js_read(const char *path, const char *filetype, int *natoms) {
00257   jshandle *js;
00258   int jsmagicnumber, jsendianism, jsmajorversion, jsminorversion;
00259   struct stat stbuf;
00260   char strbuf[1024];
00261   int tmpnatoms=0;
00262 
00263   if (!path) return NULL;
00264 
00265   /* See if the file exists, and get its size */
00266   memset(&stbuf, 0, sizeof(struct stat));
00267   if (stat(path, &stbuf)) {
00268     printf("jsplugin) Could not access file '%s'.\n", path);
00269     perror("jsplugin) stat: ");
00270 /*    return NULL; */
00271   }
00272 
00273   js = (jshandle *)malloc(sizeof(jshandle));
00274   memset(js, 0, sizeof(jshandle));
00275   js->verbose = (getenv("VMDJSVERBOSE") != NULL);
00276 #if JSMAJORVERSION > 1
00277   js->parsed_structure=0;
00278   js->directio_block_size=1;
00279   js->directio_ucell_ptr = NULL;
00280   js->directio_ucell_blkbuf = NULL;
00281 
00282   js->directio_pgsize_queried=0;
00283   js->directio_enabled=0;
00284   js->ts_file_offset=0;
00285   js->ts_crd_sz=0;
00286   js->ts_ucell_sz=0;
00287   js->ts_crd_padsz=0;
00288   js->ts_ucell_padsz=0;
00289 #endif
00290 
00291   if (fio_open(path, FIO_READ, &js->fd) < 0) {
00292     printf("jsplugin) Could not open file '%s' for reading.\n", path);
00293     free(js);
00294     return NULL;
00295   }
00296 
00297   /* emit header information */
00298   fio_fread(strbuf, strlen(JSHEADERSTRING), 1, js->fd);
00299   strbuf[strlen(JSHEADERSTRING)] = '\0';
00300   if (strcmp(strbuf, JSHEADERSTRING)) {
00301     printf("jsplugin) Bad trajectory header!\n");
00302     printf("jsplugin) Read string: %s\n", strbuf);
00303     fio_fclose(js->fd);
00304     free(js);
00305     return NULL;
00306   }
00307 
00308   fio_read_int32(js->fd, &jsmagicnumber);
00309   fio_read_int32(js->fd, &jsendianism);
00310   fio_read_int32(js->fd, &jsmajorversion);
00311   fio_read_int32(js->fd, &jsminorversion);
00312   fio_read_int32(js->fd, &tmpnatoms); /* handle-internal natoms is a long */
00313   fio_read_int32(js->fd, &js->nframes);
00314   if ((jsmagicnumber != JSMAGICNUMBER) || (jsendianism != JSENDIANISM)) {
00315 #if defined(INFOMSGS)
00316     if (js->verbose)
00317       printf("jsplugin) opposite endianism file, enabling byte swapping\n");
00318 #endif
00319     js->reverseendian = 1;
00320     swap4_aligned(&jsmagicnumber, 1);
00321     swap4_aligned(&jsendianism, 1);
00322     swap4_aligned(&jsmajorversion, 1);
00323     swap4_aligned(&jsminorversion, 1);
00324     swap4_aligned(&tmpnatoms, 1);
00325     swap4_aligned(&js->nframes, 1);
00326   } else {
00327 #if defined(INFOMSGS)
00328     if (js->verbose)
00329       printf("jsplugin) native endianism file\n");
00330 #endif
00331   }
00332 
00333   if ((jsmagicnumber != JSMAGICNUMBER) || (jsendianism != JSENDIANISM)) {
00334     fio_fclose(js->fd);
00335     free(js);
00336     return NULL;
00337   }
00338  
00339   if (jsmajorversion != JSMAJORVERSION) {
00340     printf("jsplugin) major version mismatch\n");
00341     printf("jsplugin)   file version: %d\n", jsmajorversion);
00342     printf("jsplugin)   plugin version: %d\n", JSMAJORVERSION);
00343     fio_fclose(js->fd);
00344     free(js);
00345     return NULL;
00346   }
00347 
00348   /* Copy integer natoms to handle natoms, could be a long. */
00349   /* The handle natoms uses long to help force promotion of */
00350   /* integer file offset calculations to long types...      */
00351   js->natoms = tmpnatoms;
00352   *natoms = tmpnatoms;
00353 
00354   /* copy path if we succeeded in opening the file */
00355   js->path = (char *) calloc(strlen(path)+1, 1);
00356   strcpy(js->path, path);
00357 
00358 #if 1
00359   /* read flags data from the file */
00360   fio_read_int32(js->fd, &js->optflags); 
00361   if (js->reverseendian)
00362     swap4_aligned(&js->optflags, 1);
00363 
00364 #if defined(INFOMSGS)
00365   if (js->verbose)
00366     printf("jsplugin) read option flags: %0x08x\n", js->optflags);
00367 #endif
00368 
00369   /* Check to see if block-based trajectory I/O is used  */
00370   /* and read in the block size for this file.           */
00371   if (js->optflags & JSOPT_TS_BLOCKIO) {
00372     fio_fread(&js->directio_block_size, sizeof(int), 1, js->fd);
00373     if (js->reverseendian)
00374       swap4_aligned(&js->directio_block_size, 1);
00375 
00376 #if defined(INFOMSGS)
00377     if (js->verbose) {
00378       printf("jsplugin) File uses direct I/O block size: %d bytes\n", 
00379              js->directio_block_size);
00380     }
00381 #endif
00382 
00383     /* Check to ensure that we can handle the block size used by the */
00384     /* file we are reading.  We may use variable block sizes in      */
00385     /* the future as more high-end filesystems begin to support      */
00386     /* 8KB, 16KB, or larger block sizes for enhanced sequential I/O  */
00387     /* performance on very large files.                              */
00388     if (js->directio_block_size > MOLFILE_DIRECTIO_MAX_BLOCK_SIZE) {
00389       printf("jsplugin) File block size exceeds jsplugin block size limit.\n");
00390       printf("jsplugin) Direct I/O unavailable for file '%s'\n", js->path);
00391     } else {
00392       if (fio_open(js->path, FIO_READ | FIO_DIRECT, &js->directio_fd) < 0) {
00393         printf("jsplugin) Direct I/O unavailable for file '%s'\n", js->path);
00394       } else {
00395         js->directio_enabled = 1;
00396       } 
00397     }
00398   }
00399 
00400 #if defined(ENABLEJSSHORTREADS)
00401   /* test code for an implementation that does short reads that */
00402   /* skip bulk solvent, useful for faster loading of very large */
00403   /* structures                                                 */
00404   if (getenv("VMDJSMAXATOMIDX") != NULL) {
00405     long maxatomidx = atoi(getenv("VMDJSMAXATOMIDX"));
00406     if (maxatomidx < 0)
00407       maxatomidx = 0;
00408     if (maxatomidx >= js->natoms)
00409       maxatomidx = js->natoms - 1;
00410 
00411     printf("jsplugin) Short-reads of timesteps enabled: %ld / %ld atoms (%.2f%%)\n",
00412            maxatomidx, js->natoms, 100.0*(maxatomidx+1) / ((double) js->natoms));
00413   }
00414 #endif
00415 #endif
00416 
00417   return js;
00418 }
00419 
00420 
00421 #if JSMAJORVERSION > 1
00422 
00423 /* Compute the file offset for the first timestep and move */
00424 /* the file pointer to the correct position to read/write  */
00425 /* the first timestep.  Takes care of block alignment when */
00426 /* needed.                                                 */ 
00427 static int js_calc_timestep_blocking_info(void *mydata) {
00428   fio_size_t ts_block_offset, bszmask;
00429   jshandle *js = (jshandle *) mydata;
00430   int iorc=0;
00431 
00432   /* Record the current file offset so we can use it to */
00433   /* compute the absolute offset to the first timestep. */
00434   js->ts_file_offset = fio_ftell(js->fd);
00435 
00436   /* pad current offset to the start of the next block  */ 
00437   bszmask = js->directio_block_size - 1;
00438   ts_block_offset = (js->ts_file_offset + bszmask) & (~bszmask);
00439 
00440 #if defined(INFOMSGS)
00441   if (js->verbose) {
00442     printf("jsplugin) TS block size %ld  curpos: %ld  blockpos: %ld\n", 
00443            (long) js->directio_block_size, 
00444            (long) js->ts_file_offset, 
00445            (long) ts_block_offset);
00446   }
00447 #endif
00448 
00449   /* seek to the first block of the first timestep */
00450   js->ts_file_offset = ts_block_offset;
00451   if (js->directio_enabled)
00452     iorc = fio_fseek(js->directio_fd, js->ts_file_offset, FIO_SEEK_SET);
00453   else
00454     iorc = fio_fseek(js->fd, js->ts_file_offset, FIO_SEEK_SET);
00455   if (iorc < 0) {
00456     perror("jsplugin) fseek(): ");
00457   }
00458 
00459   /* compute timestep block padding/skipping for both */
00460   /* coordinate blocks and unit cell blocks           */
00461   js->ts_crd_sz = js->natoms * 3L * sizeof(float);
00462   js->ts_crd_padsz = (js->ts_crd_sz + bszmask) & (~bszmask);
00463 
00464   js->ts_ucell_sz = 6L * sizeof(double);
00465   js->ts_ucell_padsz = (js->ts_ucell_sz + bszmask) & (~bszmask);
00466 
00467   /* allocate TS unit cell buffer in an aligned, block-size-multiple buffer */
00468   /* unaligned unit cell buffer ptr */
00469 #if defined(USE_POSIX_MEMALIGN)
00470   if (posix_memalign((void**) &js->directio_ucell_ptr, 
00471       js->directio_block_size, js->ts_ucell_padsz)) {
00472     printf("jsplugin) Couldn't allocate aligned unit cell block buffer!\n");
00473   }
00474   /* the returned pointer is already block-aligned, and can free() */
00475   js->directio_ucell_blkbuf = js->directio_ucell_ptr;
00476 #else
00477   js->directio_ucell_blkbuf = (float *) 
00478     alloc_aligned_ptr(js->ts_ucell_padsz, js->directio_block_size, 
00479                       (void**) &js->directio_ucell_ptr);
00480 #endif
00481 
00482 #if defined(INFOMSGS)
00483   if (js->verbose) {
00484     printf("jsplugin) TS crds sz: %ld psz: %ld  ucell sz: %ld psz: %ld\n",
00485            (long) js->ts_crd_sz,
00486            (long) js->ts_crd_padsz, 
00487            (long) js->ts_ucell_sz, 
00488            (long) js->ts_ucell_padsz);
00489   }
00490 #endif
00491 
00492   return MOLFILE_SUCCESS;
00493 }
00494 
00495 
00496 static int read_js_structure(void *mydata, int *optflags,
00497                              molfile_atom_t *atoms) {
00498   jshandle *js = (jshandle *) mydata;
00499   long i;
00500 
00501   if (optflags != NULL)
00502     *optflags = MOLFILE_NOOPTIONS; /* set to no options until we read them */
00503 
00504 #if 0
00505   /* read flags data from the file */
00506   fio_read_int32(js->fd, &js->optflags); 
00507   if (js->reverseendian)
00508     swap4_aligned(&js->optflags, 1);
00509 
00510 #if defined(INFOMSGS)
00511   if (js->verbose)
00512     printf("jsplugin) read option flags: %0x08x\n", js->optflags);
00513 #endif
00514 
00515   /* Check to see if block-based trajectory I/O is used  */
00516   /* and read in the block size for this file.           */
00517   if (js->optflags & JSOPT_TS_BLOCKIO) {
00518     fio_fread(&js->directio_block_size, sizeof(int), 1, js->fd);
00519     if (js->reverseendian)
00520       swap4_aligned(&js->directio_block_size, 1);
00521 
00522 #if defined(INFOMSGS)
00523     if (js->verbose) {
00524       printf("jsplugin) File uses direct I/O block size: %d bytes\n", 
00525              js->directio_block_size);
00526     }
00527 #endif
00528 
00529     /* Check to ensure that we can handle the block size used by the */
00530     /* file we are reading.  We may use variable block sizes in      */
00531     /* the future as more high-end filesystems begin to support      */
00532     /* 8KB, 16KB, or larger block sizes for enhanced sequential I/O  */
00533     /* performance on very large files.                              */
00534     if (js->directio_block_size > MOLFILE_DIRECTIO_MAX_BLOCK_SIZE) {
00535       printf("jsplugin) File block size exceeds jsplugin block size limit.\n");
00536       printf("jsplugin) Direct I/O unavailable for file '%s'\n", js->path);
00537     } else {
00538       if (fio_open(js->path, FIO_READ | FIO_DIRECT, &js->directio_fd) < 0) {
00539         printf("jsplugin) Direct I/O unavailable for file '%s'\n", js->path);
00540       } else {
00541         js->directio_enabled = 1;
00542       } 
00543     }
00544   }
00545 #endif
00546 
00547 
00548   /* emit warning message if the caller didn't check the required */
00549   /* alignment size, but the file supports block based direct I/O */
00550   if (js->directio_enabled && !js->directio_pgsize_queried) {
00551     printf("jsplugin) Warning: File supports block-based direct I/O, but\n");
00552     printf("jsplugin)          caller failed to query required alignment.\n");
00553     printf("jsplugin)          Block-based direct I/O is now disabled.\n");
00554      
00555     js->directio_enabled=0; // ensure we disable direct I/O early on
00556   }
00557 
00558 #if defined(INFOMSGS)
00559   if (js->verbose) {
00560     printf("jsplugin) Direct I/O %sabled for file '%s'\n", 
00561            (js->directio_enabled) ? "en" : "dis", js->path);
00562   }
00563 #endif
00564 
00565 
00566 #if 0
00567 #if defined(ENABLEJSSHORTREADS)
00568   /* test code for an implementation that does short reads that */
00569   /* skip bulk solvent, useful for faster loading of very large */
00570   /* structures                                                 */
00571   if (getenv("VMDJSMAXATOMIDX") != NULL) {
00572     long maxatomidx = atoi(getenv("VMDJSMAXATOMIDX"));
00573     if (maxatomidx < 0)
00574       maxatomidx = 0;
00575     if (maxatomidx >= js->natoms)
00576       maxatomidx = js->natoms - 1;
00577 
00578     printf("jsplugin) Short-reads of timesteps enabled: %ld / %ld atoms (%.2f%%)\n",
00579            maxatomidx, js->natoms, 100.0*(maxatomidx+1) / ((double) js->natoms));
00580   }
00581 #endif
00582 #endif
00583 
00584   /* Mark the handle to indicate we've parsed the structure.             */
00585   /* If any errors occur after this point, they are likely fatal anyway. */
00586   js->parsed_structure = 1;
00587 
00588   /* determine whether or not this file contains structure info or not */
00589   if (js->optflags & JSOPT_STRUCTURE) {
00590     int numatomnames, numatomtypes, numresnames, numsegids, numchains;
00591     char **atomnames = NULL;
00592     char **atomtypes = NULL;
00593     char **resnames = NULL;
00594     char **segids = NULL;
00595     char **chains = NULL;
00596     short *shortbuf = NULL; /* temp buf for decoding atom records */
00597     int *intbuf = NULL;     /* temp buf for decoding atom records */
00598     float *fltbuf = NULL;   /* temp buf for decoding atom records */
00599  
00600     /* read in block of name string table sizes */
00601     fio_read_int32(js->fd, &numatomnames); 
00602     fio_read_int32(js->fd, &numatomtypes); 
00603     fio_read_int32(js->fd, &numresnames);
00604     fio_read_int32(js->fd, &numsegids);
00605     fio_read_int32(js->fd, &numchains); 
00606     if (js->reverseendian) {
00607       swap4_aligned(&numatomnames, 1);
00608       swap4_aligned(&numatomtypes, 1);
00609       swap4_aligned(&numresnames, 1);
00610       swap4_aligned(&numsegids, 1);
00611       swap4_aligned(&numchains, 1);
00612     }
00613 
00614 #if defined(INFOMSGS)
00615     if (js->verbose) {
00616       printf("jsplugin) reading string tables...\n");
00617       printf("jsplugin) %d %d %d %d %d\n",
00618              numatomnames, numatomtypes, numresnames, numsegids, numchains);
00619     }
00620 #endif
00621 
00622     /* skip forward to first TS if the caller gives us NULL ptrs */
00623     if (optflags == NULL && atoms == NULL) {
00624       size_t offset=0;
00625       offset += numatomnames * (16L * sizeof(char));
00626       offset += numatomtypes * (16L * sizeof(char));
00627       offset += numresnames  * (8L * sizeof(char));
00628       offset += numsegids    * (8L * sizeof(char));
00629       offset += numchains    * (2L * sizeof(char));
00630       offset += js->natoms * sizeof(short); /* atom name indices    */
00631       offset += js->natoms * sizeof(short); /* atom type indices    */
00632       offset += js->natoms * sizeof(short); /* residue name indices */
00633       offset += js->natoms * sizeof(short); /* segment name indices */
00634       offset += js->natoms * sizeof(short); /* chain name indices   */
00635       offset += js->natoms * sizeof(int);   /* residue indices      */
00636       
00637       /* optional per-atom fields */
00638       if (js->optflags & JSOPT_OCCUPANCY)
00639         offset += js->natoms * sizeof(float); 
00640       if (js->optflags & JSOPT_BFACTOR)
00641         offset += js->natoms * sizeof(float); 
00642       if (js->optflags & JSOPT_MASS)
00643         offset += js->natoms * sizeof(float); 
00644       if (js->optflags & JSOPT_CHARGE)
00645         offset += js->natoms * sizeof(float); 
00646       if (js->optflags & JSOPT_RADIUS)
00647         offset += js->natoms * sizeof(float); 
00648       if (js->optflags & JSOPT_ATOMICNUMBER)
00649         offset += js->natoms * sizeof(int);
00650 
00651       fio_fseek(js->fd, offset, FIO_SEEK_CUR);
00652       offset=0;
00653 
00654       /* these require actually seeking as we process... */
00655       if (js->optflags & JSOPT_BONDS) {
00656         fio_fread(&js->nbonds, sizeof(int), 1, js->fd);
00657         if (js->reverseendian)
00658           swap4_aligned(&js->nbonds, 1);
00659 #if defined(INFOMSGS)
00660         if (js->verbose) {
00661           printf("jsplugin)   %d bonds...\n", js->nbonds);
00662         }
00663 #endif
00664 
00665         offset += 2L * js->nbonds * sizeof(int);
00666         if (js->optflags & JSOPT_BONDORDERS)
00667           offset += js->nbonds * sizeof(float);
00668 
00669         fio_fseek(js->fd, offset, FIO_SEEK_CUR);
00670         offset=0;
00671       }
00672 
00673       if (js->optflags & JSOPT_ANGLES) {
00674         fio_fread(&js->numangles, sizeof(int), 1, js->fd);
00675         if (js->reverseendian)
00676           swap4_aligned(&js->numangles, 1);
00677 #if defined(INFOMSGS)
00678         if (js->verbose) {
00679           printf("jsplugin)   %d angles...\n", js->numangles);
00680         }
00681 #endif
00682         fio_fseek(js->fd, sizeof(int)*3L*js->numangles, FIO_SEEK_CUR);
00683 
00684         fio_fread(&js->numdihedrals, sizeof(int), 1, js->fd);
00685         if (js->reverseendian)
00686           swap4_aligned(&js->numdihedrals, 1);
00687 #if defined(INFOMSGS)
00688         printf("jsplugin)   %d dihedrals...\n", js->numdihedrals);
00689 #endif
00690         fio_fseek(js->fd, sizeof(int)*4L*js->numdihedrals, FIO_SEEK_CUR);
00691 
00692         fio_fread(&js->numimpropers, sizeof(int), 1, js->fd);
00693         if (js->reverseendian)
00694           swap4_aligned(&js->numimpropers, 1);
00695 #if defined(INFOMSGS)
00696         if (js->verbose) {
00697           printf("jsplugin)   %d impropers...\n", js->numimpropers);
00698         }
00699 #endif
00700         fio_fseek(js->fd, sizeof(int)*4L*js->numimpropers, FIO_SEEK_CUR);
00701       }
00702 
00703       if (js->optflags & JSOPT_CTERMS) {
00704         fio_fread(&js->numcterms, sizeof(int), 1, js->fd);
00705         if (js->reverseendian)
00706           swap4_aligned(&js->numcterms, 1);
00707 #if defined(INFOMSGS)
00708         if (js->verbose) {
00709           printf("jsplugin)   %d cterms...\n", js->numcterms);
00710         }
00711 #endif
00712         fio_fseek(js->fd, sizeof(int)*8L*js->numcterms, FIO_SEEK_CUR);
00713       }
00714   
00715       /* record the file offset for the first timestep */
00716       js_calc_timestep_blocking_info(js);
00717 
00718       return MOLFILE_SUCCESS;
00719     }
00720 
00721 
00722     /* allocate string tables */
00723     atomnames = (char **) malloc(numatomnames * sizeof(char *));
00724     atomtypes = (char **) malloc(numatomtypes * sizeof(char *));
00725     resnames  = (char **) malloc(numresnames  * sizeof(char *));
00726     segids    = (char **) malloc(numsegids    * sizeof(char *));
00727     chains    = (char **) malloc(numchains    * sizeof(char *));
00728 
00729 #if defined(INFOMSGS)
00730     if (js->verbose)
00731       printf("jsplugin)   atom names...\n");
00732 #endif
00733 
00734     /* read in the string tables */
00735     for (i=0; i<numatomnames; i++) {
00736       atomnames[i] = (char *) malloc(16L * sizeof(char));
00737       fio_fread(atomnames[i], 16L * sizeof(char), 1, js->fd);
00738     }
00739 
00740 #if defined(INFOMSGS)
00741     if (js->verbose)
00742       printf("jsplugin)   atom types...\n");
00743 #endif
00744     for (i=0; i<numatomtypes; i++) {
00745       atomtypes[i] = (char *) malloc(16L * sizeof(char));
00746       fio_fread(atomtypes[i], 16L * sizeof(char), 1, js->fd);
00747     }
00748 
00749 #if defined(INFOMSGS)
00750     if (js->verbose)
00751       printf("jsplugin)   residue names...\n");
00752 #endif
00753     for (i=0; i<numresnames; i++) {
00754       resnames[i] = (char *) malloc(8L * sizeof(char));
00755       fio_fread(resnames[i], 8L * sizeof(char), 1, js->fd);
00756     }
00757 
00758 #if defined(INFOMSGS)
00759     if (js->verbose)
00760       printf("jsplugin)   segment names...\n");
00761 #endif
00762     for (i=0; i<numsegids; i++) {
00763       segids[i] = (char *) malloc(8L * sizeof(char));
00764       fio_fread(segids[i], 8L * sizeof(char), 1, js->fd);
00765     }
00766 
00767 #if defined(INFOMSGS)
00768     if (js->verbose)
00769       printf("jsplugin)   chain names...\n");
00770 #endif
00771     for (i=0; i<numchains; i++) {
00772       chains[i] = (char *) malloc(2L * sizeof(char));
00773       fio_fread(chains[i], 2L * sizeof(char), 1, js->fd);
00774     }
00775 
00776 #if defined(INFOMSGS)
00777     if (js->verbose)
00778       printf("jsplugin) reading numeric field tables...\n");
00779 #endif
00780     /* read in all of the atom fields */
00781     shortbuf = (short *) malloc(js->natoms * sizeof(short));
00782 
00783 #if defined(INFOMSGS)
00784     if (js->verbose)
00785       printf("jsplugin)   atom name indices...\n");
00786 #endif
00787     /* read in atom names */
00788     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00789     if (js->reverseendian)
00790       swap2_aligned(shortbuf, js->natoms);
00791     for (i=0; i<js->natoms; i++) {
00792       strcpy(atoms[i].name, atomnames[shortbuf[i]]);
00793     }
00794     for (i=0; i<numatomnames; i++)
00795       free(atomnames[i]);
00796     free(atomnames);
00797 
00798 #if defined(INFOMSGS)
00799     if (js->verbose)
00800       printf("jsplugin)   atom type indices...\n");
00801 #endif
00802     /* read in atom types */
00803     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00804     if (js->reverseendian)
00805       swap2_aligned(shortbuf, js->natoms);
00806     for (i=0; i<js->natoms; i++) {
00807       strcpy(atoms[i].type, atomtypes[shortbuf[i]]);
00808     }
00809     for (i=0; i<numatomtypes; i++)
00810       free(atomtypes[i]);
00811     free(atomtypes);
00812 
00813 #if defined(INFOMSGS)
00814     if (js->verbose)
00815       printf("jsplugin)   residue name indices...\n");
00816 #endif
00817     /* read in resnames */
00818     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00819     if (js->reverseendian)
00820       swap2_aligned(shortbuf, js->natoms);
00821     for (i=0; i<js->natoms; i++) {
00822       strcpy(atoms[i].resname, resnames[shortbuf[i]]);
00823     }
00824     for (i=0; i<numresnames; i++)
00825       free(resnames[i]);
00826     free(resnames);
00827     
00828 #if defined(INFOMSGS)
00829     if (js->verbose)
00830       printf("jsplugin)   segment name indices...\n");
00831 #endif
00832     /* read in segids */
00833     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00834     if (js->reverseendian)
00835       swap2_aligned(shortbuf, js->natoms);
00836     for (i=0; i<js->natoms; i++) {
00837       strcpy(atoms[i].segid, segids[shortbuf[i]]);
00838     }
00839     for (i=0; i<numsegids; i++)
00840       free(segids[i]);
00841     free(segids);
00842 
00843 #if defined(INFOMSGS)
00844     if (js->verbose)
00845       printf("jsplugin)   chain name indices...\n");
00846 #endif
00847     /* read in chains */
00848     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00849     if (js->reverseendian)
00850       swap2_aligned(shortbuf, js->natoms);
00851     for (i=0; i<js->natoms; i++) {
00852       strcpy(atoms[i].chain, chains[shortbuf[i]]);
00853     }
00854     for (i=0; i<numchains; i++)
00855       free(chains[i]);
00856     free(chains);
00857 
00858     if (shortbuf != NULL) {
00859       free(shortbuf);
00860       shortbuf=NULL;
00861     }
00862 
00863     /* 
00864      * read in integer data blocks 
00865      */
00866     intbuf = (int *) malloc(js->natoms * sizeof(int));
00867 
00868 #if defined(INFOMSGS)
00869     if (js->verbose)
00870       printf("jsplugin)   residue indices...\n");
00871 #endif
00872     /* read in resid */
00873     fio_fread(intbuf, js->natoms * sizeof(int), 1, js->fd);
00874     if (js->reverseendian)
00875       swap4_aligned(intbuf, js->natoms);
00876     for (i=0; i<js->natoms; i++) {
00877       atoms[i].resid = intbuf[i];
00878     }    
00879      
00880     if (intbuf != NULL) {
00881       free(intbuf);
00882       intbuf = NULL;
00883     }
00884 
00885 
00886 #if defined(INFOMSGS)
00887     if (js->verbose)
00888       printf("jsplugin) reading optional per-atom tables...\n");
00889 #endif
00890     /*
00891      * read in optional single-precision float data blocks
00892      */ 
00893     if (js->optflags & (JSOPT_OCCUPANCY | JSOPT_BFACTOR | 
00894         JSOPT_MASS | JSOPT_RADIUS | JSOPT_CHARGE)) 
00895       fltbuf = (float *) malloc(js->natoms * sizeof(float));
00896 
00897     /* read in optional data if it exists */
00898     if (js->optflags & JSOPT_OCCUPANCY) {
00899 #if defined(INFOMSGS)
00900       if (js->verbose)
00901         printf("jsplugin)   occupancy...\n");
00902 #endif
00903       *optflags |= MOLFILE_OCCUPANCY;
00904       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00905       if (js->reverseendian)
00906         swap4_aligned(fltbuf, js->natoms);
00907       for (i=0; i<js->natoms; i++) {
00908         atoms[i].occupancy = fltbuf[i];
00909       }    
00910     }
00911 
00912     if (js->optflags & JSOPT_BFACTOR) {
00913 #if defined(INFOMSGS)
00914       if (js->verbose)
00915         printf("jsplugin)   bfactor...\n");
00916 #endif
00917       *optflags |= MOLFILE_BFACTOR;
00918       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00919       if (js->reverseendian)
00920         swap4_aligned(fltbuf, js->natoms);
00921       for (i=0; i<js->natoms; i++) {
00922         atoms[i].bfactor = fltbuf[i];
00923       }    
00924     }
00925 
00926     if (js->optflags & JSOPT_MASS) { 
00927 #if defined(INFOMSGS)
00928       if (js->verbose)
00929         printf("jsplugin)   mass...\n");
00930 #endif
00931       *optflags |= MOLFILE_MASS;
00932       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00933       if (js->reverseendian)
00934         swap4_aligned(fltbuf, js->natoms);
00935       for (i=0; i<js->natoms; i++) {
00936         atoms[i].mass = fltbuf[i];
00937       }    
00938     }
00939 
00940     if (js->optflags & JSOPT_CHARGE) { 
00941 #if defined(INFOMSGS)
00942       if (js->verbose)
00943         printf("jsplugin)   charge...\n");
00944 #endif
00945       *optflags |= MOLFILE_CHARGE;
00946       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00947       if (js->reverseendian)
00948         swap4_aligned(fltbuf, js->natoms);
00949       for (i=0; i<js->natoms; i++) {
00950         atoms[i].charge = fltbuf[i];
00951       }    
00952     }
00953 
00954     if (js->optflags & JSOPT_RADIUS) { 
00955 #if defined(INFOMSGS)
00956       if (js->verbose)
00957         printf("jsplugin)   radius...\n");
00958 #endif
00959       *optflags |= MOLFILE_RADIUS;
00960       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00961       if (js->reverseendian)
00962         swap4_aligned(fltbuf, js->natoms);
00963       for (i=0; i<js->natoms; i++) {
00964         atoms[i].radius = fltbuf[i];
00965       }    
00966     }
00967 
00968     if (fltbuf != NULL) {
00969       free(fltbuf);
00970       fltbuf=NULL;
00971     }
00972 
00973     /*
00974      * read in optional integer data blocks
00975      */ 
00976     if (js->optflags & JSOPT_ATOMICNUMBER)
00977       intbuf = (int *) malloc(js->natoms * sizeof(int));
00978 
00979     if (js->optflags & JSOPT_ATOMICNUMBER) { 
00980 #if defined(INFOMSGS)
00981       if (js->verbose)
00982         printf("jsplugin)   atomic number...\n");
00983 #endif
00984       *optflags |= MOLFILE_ATOMICNUMBER;
00985       fio_fread(intbuf, js->natoms * sizeof(int), 1, js->fd);
00986       if (js->reverseendian)
00987         swap4_aligned(intbuf, js->natoms);
00988       for (i=0; i<js->natoms; i++) {
00989         atoms[i].atomicnumber = intbuf[i];
00990       }    
00991     }
00992 
00993     if (intbuf != NULL) {
00994       free(intbuf);
00995       intbuf = NULL;
00996     }
00997 
00998 
00999     /*
01000      * read in bonds and fractional bond orders
01001      */ 
01002     if (js->optflags & JSOPT_BONDS) {
01003       fio_fread(&js->nbonds, sizeof(int), 1, js->fd);
01004       if (js->reverseendian)
01005         swap4_aligned(&js->nbonds, 1);
01006 #if defined(INFOMSGS)
01007       if (js->verbose)
01008         printf("jsplugin)   %d bonds...\n", js->nbonds);
01009 #endif
01010 
01011       js->bondfrom = (int *) malloc(js->nbonds * sizeof(int));
01012       js->bondto = (int *) malloc(js->nbonds * sizeof(int));
01013       fio_fread(js->bondfrom, js->nbonds * sizeof(int), 1, js->fd);
01014       fio_fread(js->bondto, js->nbonds * sizeof(int), 1, js->fd);
01015       if (js->reverseendian) {
01016         swap4_aligned(js->bondfrom, js->nbonds);
01017         swap4_aligned(js->bondto, js->nbonds);
01018       }
01019 
01020       if (js->optflags & JSOPT_BONDORDERS) {
01021 #if defined(INFOMSGS)
01022         if (js->verbose)
01023           printf("jsplugin)   bond orders...\n");
01024 #endif
01025         js->bondorders = (float *) malloc(js->nbonds * sizeof(float));
01026         fio_fread(js->bondorders, js->nbonds * sizeof(float), 1, js->fd);
01027         if (js->reverseendian)
01028           swap4_aligned(js->bondorders, js->nbonds);
01029       }
01030     }
01031 
01032     if (js->optflags & JSOPT_ANGLES) {
01033       fio_fread(&js->numangles, sizeof(int), 1, js->fd);
01034       if (js->reverseendian)
01035         swap4_aligned(&js->numangles, 1);
01036 #if defined(INFOMSGS)
01037       if (js->verbose)
01038         printf("jsplugin)   %d angles...\n", js->numangles);
01039 #endif
01040       js->angles = (int *) malloc(3L * js->numangles * sizeof(int));
01041       fio_fread(js->angles, sizeof(int)*3L*js->numangles, 1, js->fd);
01042       if (js->reverseendian)
01043         swap4_aligned(js->angles, 3L*js->numangles);
01044 
01045       fio_fread(&js->numdihedrals, sizeof(int), 1, js->fd);
01046       if (js->reverseendian)
01047         swap4_aligned(&js->numdihedrals, 1);
01048 #if defined(INFOMSGS)
01049       if (js->verbose)
01050         printf("jsplugin)   %d dihedrals...\n", js->numdihedrals);
01051 #endif
01052       js->dihedrals = (int *) malloc(4L * js->numdihedrals * sizeof(int));
01053       fio_fread(js->dihedrals, sizeof(int)*4L*js->numdihedrals, 1, js->fd);
01054       if (js->reverseendian)
01055         swap4_aligned(js->dihedrals, 4L*js->numdihedrals);
01056 
01057       fio_fread(&js->numimpropers, sizeof(int), 1, js->fd);
01058       if (js->reverseendian)
01059         swap4_aligned(&js->numimpropers, 1);
01060       js->impropers = (int *) malloc(4L * js->numimpropers * sizeof(int));
01061 #if defined(INFOMSGS)
01062       if (js->verbose)
01063         printf("jsplugin)   %d impropers...\n", js->numimpropers);
01064 #endif
01065       fio_fread(js->impropers, sizeof(int)*4L*js->numimpropers, 1, js->fd);
01066       if (js->reverseendian)
01067         swap4_aligned(js->impropers, 4L*js->numimpropers);
01068     }
01069 
01070     if (js->optflags & JSOPT_CTERMS) {
01071       fio_fread(&js->numcterms, sizeof(int), 1, js->fd);
01072       if (js->reverseendian)
01073         swap4_aligned(&js->numcterms, 1);
01074       js->cterms = (int *) malloc(8L * js->numcterms * sizeof(int));
01075 #if defined(INFOMSGS)
01076       if (js->verbose)
01077         printf("jsplugin)   %d cterms...\n", js->numcterms);
01078 #endif
01079       fio_fread(js->cterms, sizeof(int)*8L*js->numcterms, 1, js->fd);
01080       if (js->reverseendian)
01081         swap4_aligned(js->cterms, 8L*js->numcterms);
01082     }
01083 
01084 #if defined(INFOMSGS)
01085     if (js->verbose) {
01086       printf("jsplugin) final optflags: %08x\n", *optflags);
01087       printf("jsplugin) structure information complete\n");
01088     }
01089 #endif
01090 
01091     /* record the file offset for the first timestep */
01092     js_calc_timestep_blocking_info(js);
01093 
01094     return MOLFILE_SUCCESS;
01095   }
01096 
01097 #if defined(INFOMSGS)
01098   if (js->verbose)
01099     printf("jsplugin) no structure information available\n");
01100 #endif
01101 
01102   /* record the file offset for the first timestep */
01103   js_calc_timestep_blocking_info(js);
01104 
01105   /* else, we have no structure information */
01106   return MOLFILE_NOSTRUCTUREDATA;
01107 }
01108 
01109 
01110 static int read_js_bonds(void *v, int *nbonds, int **fromptr, int **toptr, 
01111                          float **bondorder, int **bondtype, 
01112                          int *nbondtypes, char ***bondtypename) {
01113   jshandle *js = (jshandle *)v;
01114 
01115   *nbonds = 0;
01116   *fromptr = NULL;
01117   *toptr = NULL;
01118   *bondorder = NULL;
01119   *bondtype = NULL;
01120   *nbondtypes = 0;
01121   *bondtypename = NULL;
01122 
01123   if (js->optflags & JSOPT_BONDS) {
01124     *nbonds = js->nbonds;
01125     *fromptr = js->bondfrom;
01126     *toptr = js->bondto;
01127 
01128     if (js->optflags & JSOPT_BONDORDERS) {
01129       *bondorder = js->bondorders;
01130     }
01131   }
01132 
01133   return MOLFILE_SUCCESS;
01134 }
01135 
01136 #if vmdplugin_ABIVERSION > 14
01137 static int read_js_angles(void *v, int *numangles, int **angles, 
01138                           int **angletypes, int *numangletypes, 
01139                           char ***angletypenames, int *numdihedrals,
01140                           int **dihedrals, int **dihedraltypes, 
01141                           int *numdihedraltypes, char ***dihedraltypenames,
01142                           int *numimpropers, int **impropers, 
01143                           int **impropertypes, int *numimpropertypes, 
01144                           char ***impropertypenames, int *numcterms, 
01145                           int **cterms, int *ctermcols, int *ctermrows) {
01146   jshandle *js = (jshandle *)v;
01147 
01148   /* initialize data to zero */
01149   *numangles         = 0;
01150   *angles            = NULL;
01151   *angletypes        = NULL;
01152   *numangletypes     = 0;
01153   *angletypenames    = NULL;
01154   *numdihedrals      = 0;
01155   *dihedrals         = NULL;
01156   *dihedraltypes     = NULL;
01157   *numdihedraltypes  = 0;
01158   *dihedraltypenames = NULL;
01159   *numimpropers      = 0;
01160   *impropers         = NULL;
01161   *impropertypes     = NULL;
01162   *numimpropertypes  = 0;
01163   *impropertypenames = NULL;
01164   *numcterms         = 0;
01165   *cterms            = NULL;
01166   *ctermrows         = 0;
01167   *ctermcols         = 0;
01168 
01169   *numangles = js->numangles;
01170   *angles = js->angles;
01171 
01172   *numdihedrals = js->numdihedrals;
01173   *dihedrals = js->dihedrals;
01174 
01175   *numimpropers = js->numimpropers;
01176   *impropers = js->impropers;
01177 
01178   *numcterms = js->numcterms;
01179   *cterms = js->cterms;
01180   *ctermcols = 0;
01181   *ctermrows = 0;
01182 
01183   return MOLFILE_SUCCESS;
01184 }
01185 #else
01186 static int read_js_angles(void *v,
01187                int *numangles,    int **angles,    double **angleforces,
01188                int *numdihedrals, int **dihedrals, double **dihedralforces,
01189                int *numimpropers, int **impropers, double **improperforces,
01190                int *numcterms,    int **cterms,
01191                int *ctermcols,    int *ctermrows,  double **ctermforces) {
01192   jshandle *js = (jshandle *)v;
01193 
01194   *numangles = js->numangles;
01195   *angles = js->angles;
01196   *angleforces = NULL;
01197 
01198   *numdihedrals = js->numdihedrals;
01199   *dihedrals = js->dihedrals;
01200   *dihedralforces = NULL;
01201 
01202   *numimpropers = js->numimpropers;
01203   *impropers = js->impropers;
01204   *improperforces = NULL;
01205 
01206   *numcterms = js->numcterms;
01207   *cterms = js->cterms;
01208   *ctermcols = 0;
01209   *ctermrows = 0;
01210   *ctermforces = NULL;
01211 
01212   return MOLFILE_SUCCESS;
01213 }
01214 #endif
01215 
01216 #endif
01217 
01218 
01219 #if 1 
01220 // XXX prototypical out-of-core trajectory analysis API
01221 static int read_js_timestep_index_offsets(void *v, int natoms, 
01222                                           long frameindex,
01223                                           int firstatom, int numatoms,
01224                                           fio_fd *directio_fd,
01225                                           long *startoffset,
01226                                           long *fileoffset,
01227                                           long *readlen) {
01228   jshandle *js = (jshandle *)v;
01229   fio_size_t framelen;
01230 
01231 #if JSMAJORVERSION > 1
01232   /* If we haven't yet read (or skipped) the structure data, then we    */
01233   /* need to begin by skipping past it before we try to read the        */
01234   /* first timestep.  In the case of files with block-aligned timesteps,*/
01235   /* this will also get our file pointer to the right block-aligned     */
01236   /* location.                                                          */
01237   if (!js->parsed_structure)
01238     read_js_structure(v, NULL, NULL);
01239 #endif
01240 
01241   /* compute total read/seek size of timestep */
01242   framelen = js->ts_crd_padsz + js->ts_ucell_padsz;
01243 
01244   if (directio_fd != NULL)
01245     *directio_fd = js->directio_fd;
01246 
01247   /* compute file offset for requested timestep */
01248   if (fileoffset != NULL)
01249     *fileoffset = (frameindex * framelen) + js->ts_file_offset;
01250 
01251   /* compute startoffset for first requested atom */
01252   if (startoffset != NULL)
01253     *startoffset = firstatom * 3L * sizeof(float);
01254  
01255   /* compute required read size */ 
01256   if (readlen != NULL)
01257     *readlen = framelen;
01258 
01259   return MOLFILE_SUCCESS;
01260 }
01261 
01262 
01263 #if 0
01264 static int read_js_timestep_index(void *v, int natoms, 
01265                                   long frameindex,
01266                                   molfile_timestep_t *ts) {
01267 }
01268 #endif
01269 
01270 #endif
01271 
01272 
01273 
01274 static int read_js_timestep(void *v, int natoms, molfile_timestep_t *ts) {
01275   jshandle *js = (jshandle *)v;
01276   fio_size_t framelen;
01277 
01278 #if JSMAJORVERSION > 1
01279   /* If we haven't yet read (or skipped) the structure data, then we    */
01280   /* need to begin by skipping past it before we try to read the        */
01281   /* first timestep.  In the case of files with block-aligned timesteps,*/
01282   /* this will also get our file pointer to the right block-aligned     */
01283   /* location.                                                          */
01284   if (!js->parsed_structure)
01285     read_js_structure(v, NULL, NULL);
01286 #endif
01287 
01288   /* compute total read/seek size of timestep */
01289   framelen = js->ts_crd_padsz + js->ts_ucell_padsz;
01290 
01291   /* if we have a valid ts pointer, read the timestep, otherwise skip it */ 
01292   if (ts != NULL) {
01293     fio_size_t readlen=0;
01294     fio_iovec iov[2];
01295 
01296     /* set unit cell pointer to the TS block-aligned buffer area */
01297     double *unitcell = (double *) js->directio_ucell_blkbuf;
01298 
01299     unitcell[0] = unitcell[2] = unitcell[5] = 1.0f;
01300     unitcell[1] = unitcell[3] = unitcell[4] = 90.0f;
01301 
01302 #if defined(ENABLEJSSHORTREADS)
01303     /* test code for an implementation that does short reads that */
01304     /* skip bulk solvent, useful for faster loading of very large */
01305     /* structures                                                 */
01306     if (getenv("VMDJSMAXATOMIDX") != NULL) {
01307       fio_size_t bszmask;
01308       long maxatompadsz, skipatompadsz;
01309 
01310       long maxatomidx = atoi(getenv("VMDJSMAXATOMIDX"));
01311       if (maxatomidx < 0)
01312         maxatomidx = 0;
01313       if (maxatomidx >= js->natoms)
01314         maxatomidx = js->natoms - 1;
01315 
01316       /* pad max read to the start of the next block  */
01317       bszmask = js->directio_block_size - 1;
01318       maxatompadsz = ((maxatomidx*3L*sizeof(float)) + bszmask) & (~bszmask);
01319       skipatompadsz = js->ts_crd_padsz - maxatompadsz;
01320 
01321       readlen=0;
01322       if (js->directio_enabled) {
01323         if (fio_fread(ts->coords, maxatompadsz, 1, js->directio_fd) == 1)
01324           readlen = maxatompadsz;
01325         if (fio_fseek(js->directio_fd, skipatompadsz, FIO_SEEK_CUR) == 0)
01326           readlen += skipatompadsz;
01327         if (fio_fread(unitcell, js->ts_ucell_padsz, 1, js->directio_fd) == 1)
01328           readlen += js->ts_ucell_padsz;
01329       } else {
01330         if (fio_fread(ts->coords, maxatompadsz, 1, js->fd) == 1)
01331           readlen = maxatompadsz;
01332         if (fio_fseek(js->fd, skipatompadsz, FIO_SEEK_CUR) == 0)
01333           readlen += skipatompadsz;
01334         if (fio_fread(unitcell, js->ts_ucell_padsz, 1, js->fd) == 1)
01335           readlen += js->ts_ucell_padsz;
01336       }
01337 
01338 #if 0
01339       /* clear all non-read atom coords to zeros */
01340       memset(ts->coords+3L*maxatomidx,0,3L*sizeof(float)*(js->natoms-maxatomidx));
01341 #endif
01342 
01343     }  else {
01344 #endif
01345  
01346     /* setup the I/O vector */
01347     iov[0].iov_base = (fio_caddr_t) ts->coords;   /* read coordinates    */
01348     iov[1].iov_base = (fio_caddr_t) unitcell;     /* read PBC unit cell  */
01349 
01350     if (js->directio_enabled) {
01351       iov[0].iov_len  = js->ts_crd_padsz;
01352       iov[1].iov_len  = js->ts_ucell_padsz;
01353     } else {
01354       iov[0].iov_len  = js->ts_crd_sz;
01355       iov[1].iov_len  = js->ts_ucell_sz;
01356     }
01357    
01358 #if 1
01359     /* Use fall-back code instead of readv():                            */
01360     /*  Some platforms implement readv() as user level code in libc,     */
01361     /*  and due to POSIX atomicity requirements for readv()/writev(),    */
01362     /*  they may copy data to internal temp buffers, which can kill      */
01363     /*  performance, and in cases when doing single I/O ops on large,    */
01364     /*  buffers, e.g. > 2GB, can fail with shorts reads or writes...     */
01365     /*  On such platforms it is best to avoid using readv()/writev()...  */
01366     {
01367       int readcnt = 0;
01368       readlen = 0;
01369       if (js->directio_enabled) {
01370         readcnt =  fio_fread(iov[0].iov_base, iov[0].iov_len, 1, js->directio_fd);
01371         readcnt += fio_fread(iov[1].iov_base, iov[1].iov_len, 1, js->directio_fd);
01372       } else {
01373         fio_size_t seeklen=0;
01374       
01375         readcnt =  fio_fread(iov[0].iov_base, iov[0].iov_len, 1, js->fd);
01376         seeklen = js->ts_crd_padsz - js->ts_crd_sz;
01377         if (seeklen > 0)
01378           fio_fseek(js->fd, seeklen, FIO_SEEK_CUR);
01379         readcnt += fio_fread(iov[1].iov_base, iov[1].iov_len, 1, js->fd);
01380         seeklen = js->ts_ucell_padsz - js->ts_ucell_sz;
01381         if (seeklen > 0)
01382           fio_fseek(js->fd, seeklen, FIO_SEEK_CUR);
01383       }
01384 
01385       /* if both records read correctly, then the reads are okay */
01386       if (readcnt == 2)
01387         readlen = framelen;
01388     }
01389 #else
01390     /* Do all of the reads with a single syscall, for peak efficiency.   */
01391     /* On smart kernels, readv() causes only one context switch, and     */
01392     /* can effeciently scatter the reads to the various buffers.         */
01393     if (js->directio_enabled) {
01394       readlen = fio_readv(js->directio_fd, &iov[0], 2); 
01395     } else {
01396       // XXX we can't use readv() when not using direct I/O since we 
01397       // can't make intervening seek calls required if the caller
01398       // doesn't provide appropriate buffers.
01399       // readlen = fio_readv(js->fd, &iov[0], 2); 
01400 
01401       fio_size_t seeklen=0;
01402       readcnt =  fio_fread(iov[0].iov_base, iov[0].iov_len, 1, js->fd);
01403       seeklen = js->ts_crd_padsz - js->ts_crd_sz;
01404       if (seeklen > 0)
01405         fio_fseek(js->fd, seeklen, FIO_SEEK_CUR);
01406       readcnt += fio_fread(iov[1].iov_base, iov[1].iov_len, 1, js->fd);
01407       seeklen = js->ts_ucell_padsz - js->ts_ucell_sz;
01408       if (seeklen > 0)
01409         fio_fseek(js->fd, seeklen, FIO_SEEK_CUR);
01410     }
01411 #endif
01412 
01413 #if defined(ENABLEJSSHORTREADS)
01414    }
01415 #endif 
01416  
01417     /* check the number of read bytes versus what we expected */
01418     if (readlen != framelen) {
01419       if (readlen < 0) {
01420         perror("jsplugin) fio_readv(): ");
01421       } else if (readlen != 0) {
01422         printf("jsplugin) mismatched read: %ld, expected %ld\n", 
01423                (long) readlen, (long) framelen);
01424       }
01425 
01426       return MOLFILE_EOF;
01427     }
01428 
01429     /* perform byte swapping if necessary */
01430     if (js->reverseendian) {
01431       swap4_aligned(ts->coords, js->natoms * 3L);
01432       swap8_aligned(unitcell, 6);
01433     }
01434 
01435     /* copy unit cell values into VMD */
01436     ts->A = unitcell[0];
01437     ts->B = unitcell[1];
01438     ts->C = unitcell[2];
01439     ts->alpha = 90.0 - asin(unitcell[3]) * 90.0 / M_PI_2;
01440     ts->beta  = 90.0 - asin(unitcell[4]) * 90.0 / M_PI_2;
01441     ts->gamma = 90.0 - asin(unitcell[5]) * 90.0 / M_PI_2;
01442   } else {
01443     /* skip this frame, seek to the next frame */
01444     if (js->directio_enabled) {
01445       if (fio_fseek(js->directio_fd, framelen, FIO_SEEK_CUR)) 
01446         return MOLFILE_EOF;
01447     } else {
01448       if (fio_fseek(js->fd, framelen, FIO_SEEK_CUR)) 
01449         return MOLFILE_EOF;
01450     }
01451   }
01452  
01453   return MOLFILE_SUCCESS;
01454 }
01455 
01456 
01457 static void close_js_read(void *v) {
01458   jshandle *js = (jshandle *)v;
01459   fio_fclose(js->fd);
01460 
01461 #if JSMAJORVERSION > 1
01462   if (js->path)
01463     free(js->path);
01464 
01465   if (js->directio_enabled)
01466     fio_fclose(js->directio_fd);
01467 
01468   if (js->directio_ucell_ptr)
01469     free(js->directio_ucell_ptr);
01470 
01471   if (js->bondfrom)
01472     free(js->bondfrom);
01473   if (js->bondto)
01474     free(js->bondto);
01475   if (js->bondorders)
01476     free(js->bondorders);
01477 
01478   /* free angle data */
01479   if (js->angles != NULL)
01480     free(js->angles);
01481   if (js->dihedrals != NULL)
01482     free(js->dihedrals);
01483   if (js->impropers != NULL)
01484     free(js->impropers);
01485   if (js->cterms)
01486     free(js->cterms);
01487 #endif
01488 
01489   free(js);
01490 }
01491 
01492 
01493 static void *open_js_write(const char *path, const char *filetype, int natoms) {
01494   jshandle *js;
01495 
01496   js = (jshandle *) malloc(sizeof(jshandle));
01497   memset(js, 0, sizeof(jshandle));
01498 #if JSMAJORVERSION > 1
01499   js->parsed_structure=0;
01500   js->directio_block_size=1;
01501   js->directio_ucell_ptr = NULL;
01502   js->directio_ucell_blkbuf = NULL;
01503 
01504   js->directio_enabled=0;
01505   js->ts_file_offset=0;
01506   js->ts_crd_sz=0;
01507   js->ts_ucell_sz=0;
01508   js->ts_crd_padsz=0;
01509   js->ts_ucell_padsz=0;
01510 #endif
01511 
01512   if (fio_open(path, FIO_WRITE, &js->fd) < 0) {
01513     printf("jsplugin) Could not open file %s for writing\n", path);
01514     free(js);
01515     return NULL;
01516   }
01517 
01518   js->natoms = natoms;
01519   js->with_unitcell = 1;
01520 
01521   /* emit header information */
01522   fio_write_str(js->fd, JSHEADERSTRING);
01523   fio_write_int32(js->fd, JSMAGICNUMBER);
01524   fio_write_int32(js->fd, JSENDIANISM);
01525   fio_write_int32(js->fd, JSMAJORVERSION);
01526   fio_write_int32(js->fd, JSMINORVERSION);
01527 
01528   /* write number of atoms */
01529   fio_write_int32(js->fd, natoms);
01530 
01531   /* write number of frames, to be updated later */
01532   js->nframes = 0;
01533   fio_write_int32(js->fd, js->nframes);
01534 
01535   return js;
01536 }
01537 
01538 
01539 #if JSMAJORVERSION > 1
01540 
01541 static int write_js_structure(void *mydata, int optflags,
01542                               const molfile_atom_t *atoms) {
01543   jshandle *js = (jshandle *) mydata;
01544   long i;
01545 
01546   /* use block-based I/O by default when writing structures larger */
01547   /* than JSBLOCKIO_THRESH atoms, or when directed by the user     */
01548   js_blockio_check_and_set(js);
01549 
01550   js->optflags |= JSOPT_STRUCTURE;
01551 
01552   if (optflags & MOLFILE_OCCUPANCY)
01553     js->optflags |= JSOPT_OCCUPANCY;
01554 
01555   if (optflags & MOLFILE_BFACTOR)
01556     js->optflags |= JSOPT_BFACTOR;
01557 
01558   if (optflags & MOLFILE_BFACTOR)
01559     js->optflags |= JSOPT_BFACTOR;
01560 
01561   if (optflags & MOLFILE_MASS)
01562     js->optflags |= JSOPT_MASS;
01563 
01564   if (optflags & MOLFILE_CHARGE)
01565     js->optflags |= JSOPT_CHARGE;
01566  
01567   if (optflags & MOLFILE_RADIUS)
01568     js->optflags |= JSOPT_RADIUS;
01569 
01570   if (optflags & MOLFILE_ATOMICNUMBER)
01571     js->optflags |= JSOPT_ATOMICNUMBER;
01572 
01573   /* write flags data to the file */
01574   fio_write_int32(js->fd, js->optflags); 
01575 printf("jsplugin) writing option flags: %0x08x\n", js->optflags);
01576 
01577   /* Check to see if block-based trajectory I/O is used  */
01578   /* and write out the block size for this file.         */
01579   if (js->optflags & JSOPT_TS_BLOCKIO) {
01580     fio_fwrite(&js->directio_block_size, sizeof(int), 1, js->fd);
01581     printf("jsplugin) Block-based I/O enabled: block size %d bytes\n", 
01582            js->directio_block_size);
01583   }
01584 
01585 printf("jsplugin) writing structure...\n");
01586   /* determine whether or not this file contains structure info or not */
01587   if (js->optflags & JSOPT_STRUCTURE) {
01588     int numatomnames, numatomtypes, numresnames, numsegids, numchains;
01589     char **atomnames = NULL;
01590     char **atomtypes = NULL;
01591     char **resnames = NULL;
01592     char **segids = NULL;
01593     char **chains = NULL;
01594     short *shortbuf = NULL; /* temp buf for encoding atom records */
01595     int *intbuf = NULL;     /* temp buf for encoding atom records */
01596     float *fltbuf = NULL;   /* temp buf for encoding atom records */
01597 
01598     hash_t tmphash;         /* temporary hash table */
01599     hash_t atomnamehash;
01600     hash_t atomtypehash;
01601     hash_t resnamehash;
01602     hash_t segidhash;
01603     hash_t chainhash;
01604     int hashcnt;
01605 
01606 
01607 printf("jsplugin) counting atom names, types, etc...\n");
01608     /* generate hash tables to count the number of unique strings */
01609     hash_init(&tmphash, 127);
01610     for (i=0; i<js->natoms; i++)
01611       hash_insert(&tmphash, atoms[i].name, 0);
01612     numatomnames = hash_entries(&tmphash);
01613     hash_destroy(&tmphash);
01614 
01615     hash_init(&tmphash, 127);
01616     for (i=0; i<js->natoms; i++)
01617       hash_insert(&tmphash, atoms[i].type, 0);
01618     numatomtypes = hash_entries(&tmphash);
01619     hash_destroy(&tmphash);
01620 
01621     hash_init(&tmphash, 127);
01622     for (i=0; i<js->natoms; i++)
01623       hash_insert(&tmphash, atoms[i].resname, 0);
01624     numresnames = hash_entries(&tmphash);
01625     hash_destroy(&tmphash);
01626 
01627     hash_init(&tmphash, 127);
01628     for (i=0; i<js->natoms; i++)
01629       hash_insert(&tmphash, atoms[i].segid, 0);
01630     numsegids = hash_entries(&tmphash);
01631     hash_destroy(&tmphash);
01632 
01633     hash_init(&tmphash, 127);
01634     for (i=0; i<js->natoms; i++)
01635       hash_insert(&tmphash, atoms[i].chain, 0);
01636     numchains = hash_entries(&tmphash);
01637     hash_destroy(&tmphash);
01638  
01639 printf("jsplugin) writing unique string counts...\n");
01640 printf("jsplugin) %d %d %d %d %d\n",
01641        numatomnames, numatomtypes, numresnames, numsegids, numchains);
01642 
01643     /* write block of name string table sizes */
01644     fio_write_int32(js->fd, numatomnames); 
01645     fio_write_int32(js->fd, numatomtypes); 
01646     fio_write_int32(js->fd, numresnames);
01647     fio_write_int32(js->fd, numsegids);
01648     fio_write_int32(js->fd, numchains); 
01649 
01650 printf("jsplugin) writing string tables...\n");
01651 
01652     atomnames = (char **) malloc(numatomnames * sizeof(char *));
01653     atomtypes = (char **) malloc(numatomtypes * sizeof(char *));
01654     resnames = (char **) malloc(numresnames * sizeof(char *));
01655     segids = (char **) malloc(numsegids * sizeof(char *));
01656     chains = (char **) malloc(numchains * sizeof(char *));
01657 
01658 printf("jsplugin)   atom names...\n");
01659     /* generate and write out the string tables */
01660     hash_init(&atomnamehash, 127);
01661     for (hashcnt=0,i=0; i<js->natoms; i++) {
01662       /* add a new string table entry for hash inserts that don't yet exist */
01663       if (hash_insert(&atomnamehash, atoms[i].name, hashcnt) == HASH_FAIL) {
01664         atomnames[hashcnt] = (char *) calloc(1, 16L * sizeof(char));
01665         strcpy(atomnames[hashcnt], atoms[i].name);
01666         hashcnt++;
01667       }
01668     }
01669     for (i=0; i<numatomnames; i++) {
01670       fio_fwrite(atomnames[i], 16L * sizeof(char), 1, js->fd);
01671     }
01672 
01673 
01674 printf("jsplugin)   atom types...\n");
01675     hash_init(&atomtypehash, 127);
01676     for (hashcnt=0,i=0; i<js->natoms; i++) {
01677       /* add a new string table entry for hash inserts that don't yet exist */
01678       if (hash_insert(&atomtypehash, atoms[i].type, hashcnt) == HASH_FAIL) {
01679         atomtypes[hashcnt] = (char *) calloc(1, 16L * sizeof(char));
01680         strcpy(atomtypes[hashcnt], atoms[i].type);
01681         hashcnt++;
01682       }
01683     }
01684     for (i=0; i<numatomtypes; i++) {
01685       fio_fwrite(atomtypes[i], 16L * sizeof(char), 1, js->fd);
01686     }
01687 
01688 
01689 printf("jsplugin)   residue names...\n");
01690     hash_init(&resnamehash, 127);
01691     for (hashcnt=0,i=0; i<js->natoms; i++) {
01692       /* add a new string table entry for hash inserts that don't yet exist */
01693       if (hash_insert(&resnamehash, atoms[i].resname, hashcnt) == HASH_FAIL) {
01694         resnames[hashcnt] = (char *) calloc(1, 8L * sizeof(char));
01695         strcpy(resnames[hashcnt], atoms[i].resname);
01696         hashcnt++;
01697       }
01698     }
01699     for (i=0; i<numresnames; i++) {
01700       fio_fwrite(resnames[i], 8L * sizeof(char), 1, js->fd);
01701     }
01702 
01703 
01704 printf("jsplugin)   segment names...\n");
01705     hash_init(&segidhash, 127);
01706     for (hashcnt=0,i=0; i<js->natoms; i++) {
01707       /* add a new string table entry for hash inserts that don't yet exist */
01708       if (hash_insert(&segidhash, atoms[i].segid, hashcnt) == HASH_FAIL) {
01709         segids[hashcnt] = (char *) calloc(1, 8L * sizeof(char));
01710         strcpy(segids[hashcnt], atoms[i].segid);
01711         hashcnt++;
01712       }
01713     }
01714     for (i=0; i<numsegids; i++) {
01715       fio_fwrite(segids[i], 8L * sizeof(char), 1, js->fd);
01716     }
01717 
01718 
01719 printf("jsplugin)   chain names...\n");
01720     hash_init(&chainhash, 127);
01721     for (hashcnt=0,i=0; i<js->natoms; i++) {
01722       /* add a new string table entry for hash inserts that don't yet exist */
01723       if (hash_insert(&chainhash, atoms[i].chain, hashcnt) == HASH_FAIL) {
01724         chains[hashcnt] = (char *) calloc(1, 2L * sizeof(char));
01725         strcpy(chains[hashcnt], atoms[i].chain);
01726         hashcnt++;
01727       }
01728     }
01729     for (i=0; i<numchains; i++) {
01730       fio_fwrite(chains[i], 2L * sizeof(char), 1, js->fd);
01731     }
01732 
01733 
01734 printf("jsplugin) writing numeric field tables...\n");
01735     /* write out all of the atom fields */
01736     shortbuf = (short *) malloc(js->natoms * sizeof(short));
01737 
01738     /* write out atom names */
01739     for (i=0; i<js->natoms; i++) {
01740       shortbuf[i] = hash_lookup(&atomnamehash, atoms[i].name);
01741     }    
01742     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01743 
01744     /* write out atom types */
01745     for (i=0; i<js->natoms; i++) {
01746       shortbuf[i] = hash_lookup(&atomtypehash, atoms[i].type);
01747     }    
01748     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01749 
01750     /* write out resnames */
01751     for (i=0; i<js->natoms; i++) {
01752       shortbuf[i] = hash_lookup(&resnamehash, atoms[i].resname);
01753     }    
01754     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01755     
01756     /* write out segids */
01757     for (i=0; i<js->natoms; i++) {
01758       shortbuf[i] = hash_lookup(&segidhash, atoms[i].segid);
01759     }    
01760     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01761 
01762     /* write out chains */
01763     for (i=0; i<js->natoms; i++) {
01764       shortbuf[i] = hash_lookup(&chainhash, atoms[i].chain);
01765     }    
01766     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01767 
01768     if (shortbuf != NULL) {
01769       free(shortbuf);
01770       shortbuf=NULL;
01771     }
01772 
01773     /* done with hash tables */
01774     hash_destroy(&atomnamehash);
01775     hash_destroy(&atomtypehash);
01776     hash_destroy(&resnamehash);
01777     hash_destroy(&segidhash);
01778     hash_destroy(&chainhash);
01779 
01780 
01781     /* 
01782      * write out integer data blocks 
01783      */
01784     intbuf = (int *) malloc(js->natoms * sizeof(int));
01785 
01786 printf("jsplugin)   residue indices...\n");
01787     /* write out resid */
01788     for (i=0; i<js->natoms; i++) {
01789       intbuf[i] = atoms[i].resid;
01790     }    
01791     fio_fwrite(intbuf, js->natoms * sizeof(int), 1, js->fd);
01792      
01793     if (intbuf != NULL) {
01794       free(intbuf);
01795       intbuf = NULL;
01796     }
01797 
01798 printf("jsplugin) writing optional per-atom tables...\n");
01799     /*
01800      * write out optional single-precision float data blocks
01801      */ 
01802     if (js->optflags & (JSOPT_OCCUPANCY | JSOPT_BFACTOR | 
01803         JSOPT_MASS | JSOPT_RADIUS | JSOPT_CHARGE)) 
01804       fltbuf = (float *) malloc(js->natoms * sizeof(float));
01805 
01806     /* write out optional data if it exists */
01807 
01808     if (js->optflags & JSOPT_OCCUPANCY) {
01809 printf("jsplugin)   writing occupancy...\n");
01810       for (i=0; i<js->natoms; i++) {
01811         fltbuf[i] = atoms[i].occupancy;
01812       }    
01813       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01814     }
01815 
01816     if (js->optflags & JSOPT_BFACTOR) {
01817 printf("jsplugin)   writing bfactor...\n");
01818       for (i=0; i<js->natoms; i++) {
01819         fltbuf[i] = atoms[i].bfactor;
01820       }    
01821       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01822     }
01823 
01824     if (js->optflags & JSOPT_MASS) { 
01825 printf("jsplugin)   writing mass...\n");
01826       for (i=0; i<js->natoms; i++) {
01827         fltbuf[i] = atoms[i].mass;
01828       }    
01829       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01830     }
01831 
01832     if (js->optflags & JSOPT_CHARGE) { 
01833 printf("jsplugin)   writing charge...\n");
01834       for (i=0; i<js->natoms; i++) {
01835         fltbuf[i] = atoms[i].charge;
01836       }    
01837       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01838     }
01839 
01840     if (js->optflags & JSOPT_RADIUS) { 
01841 printf("jsplugin)   writing radius...\n");
01842       for (i=0; i<js->natoms; i++) {
01843         fltbuf[i] = atoms[i].radius;
01844       }    
01845       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01846     }
01847 
01848     if (fltbuf != NULL) {
01849       free(fltbuf);
01850       fltbuf=NULL;
01851     }
01852 
01853 
01854     /*
01855      * write out optional integer data blocks
01856      */ 
01857     if (js->optflags & JSOPT_ATOMICNUMBER)
01858       intbuf = (int *) malloc(js->natoms * sizeof(int));
01859 
01860     if (js->optflags & JSOPT_ATOMICNUMBER) { 
01861 printf("jsplugin)   writing atomic number...\n");
01862       for (i=0; i<js->natoms; i++) {
01863         intbuf[i] = atoms[i].atomicnumber;
01864       }    
01865       fio_fwrite(intbuf, js->natoms * sizeof(int), 1, js->fd);
01866     }
01867 
01868     if (intbuf != NULL) {
01869       free(intbuf);
01870       intbuf = NULL;
01871     }
01872 
01873 
01874     /*
01875      * write out bonds and fractional bond orders
01876      */ 
01877     if (js->optflags & JSOPT_BONDS) {
01878 printf("jsplugin) writing bonds...\n");
01879       fio_fwrite(&js->nbonds, sizeof(int), 1, js->fd);
01880       fio_fwrite(js->bondfrom, js->nbonds * sizeof(int), 1, js->fd);
01881       fio_fwrite(js->bondto, js->nbonds * sizeof(int), 1, js->fd);
01882 
01883       if (js->optflags & JSOPT_BONDORDERS) {
01884 printf("jsplugin) writing bond orders...\n");
01885         fio_fwrite(js->bondorders, js->nbonds * sizeof(float), 1, js->fd);
01886       }
01887     }
01888 
01889     /*
01890      * write out angles/dihedrals/impropers/cross-terms
01891      */
01892     if (js->optflags & JSOPT_ANGLES) {
01893 printf("jsplugin) writing angles/dihedrals/impropers...\n");
01894       fio_fwrite(&js->numangles, sizeof(int), 1, js->fd);
01895       fio_fwrite(js->angles, sizeof(int)*3L*js->numangles, 1, js->fd);
01896 
01897       fio_fwrite(&js->numdihedrals, sizeof(int), 1, js->fd);
01898       fio_fwrite(js->dihedrals, sizeof(int)*4L*js->numdihedrals, 1, js->fd);
01899 
01900       fio_fwrite(&js->numimpropers, sizeof(int), 1, js->fd);
01901       fio_fwrite(js->impropers, sizeof(int)*4L*js->numimpropers, 1, js->fd);
01902     }
01903     if (js->optflags & JSOPT_CTERMS) {
01904 printf("jsplugin) writing cross-terms\n");
01905       fio_fwrite(&js->numcterms, sizeof(int), 1, js->fd);
01906       fio_fwrite(js->cterms, sizeof(int)*8L*js->numcterms, 1, js->fd);
01907     }
01908 
01909     /* update the file offset for the first timestep */
01910     js_calc_timestep_blocking_info(js);
01911 
01912     return MOLFILE_SUCCESS;
01913   }
01914 
01915   /* update the file offset for the first timestep */
01916   js_calc_timestep_blocking_info(js);
01917 
01918   /* else, we have no structure information */
01919   return MOLFILE_NOSTRUCTUREDATA;
01920 }
01921 
01922 
01923 static int write_js_bonds(void *mydata, int nbonds, int *fromptr, int *toptr, 
01924                           float *bondorder,  int *bondtype, 
01925                           int nbondtypes, char **bondtypename) {
01926   jshandle *js = (jshandle *) mydata;
01927 
01928 #if defined(INFOMSGS)
01929     if (js->verbose) {
01930       printf("jsplugin) write_js_bonds():\n");
01931       printf("jsplugin) storing bond info for writing...\n");
01932       printf("jsplugin) %d %d\n", nbonds, nbondtypes);
01933     }
01934 #endif
01935 
01936   if (nbonds > 0 && fromptr != NULL && toptr != NULL) {
01937     js->optflags |= JSOPT_BONDS; 
01938 
01939     /* save bond info until we actually write out the structure file */
01940     js->nbonds = nbonds;
01941     js->bondfrom = (int *) malloc(nbonds * sizeof(int));
01942     memcpy(js->bondfrom, fromptr, nbonds * sizeof(int));
01943     js->bondto = (int *) malloc(nbonds * sizeof(int));
01944     memcpy(js->bondto, toptr, nbonds * sizeof(int));
01945 
01946     if (bondorder != NULL) {
01947       js->optflags |= JSOPT_BONDORDERS;
01948       js->bondorders = (float *) malloc(nbonds * sizeof(float));
01949       memcpy(js->bondorders, bondorder, nbonds * sizeof(float));
01950     }
01951   }
01952 
01953   return MOLFILE_SUCCESS;
01954 }
01955 
01956 #if vmdplugin_ABIVERSION > 14
01957 static int write_js_angles(void * v, int numangles, const int *angles,
01958                            const int *angletypes, int numangletypes,
01959                            const char **angletypenames, int numdihedrals, 
01960                            const int *dihedrals, const int *dihedraltype,
01961                            int numdihedraltypes, const char **dihedraltypenames,
01962                            int numimpropers, const int *impropers, 
01963                            const int *impropertypes, int numimpropertypes, 
01964                            const char **impropertypenames, int numcterms, 
01965                            const int *cterms, int ctermcols, int ctermrows) {
01966   jshandle *js = (jshandle *) v;
01967 
01968   /* save info until we actually write out the structure file */
01969   js->numangles = numangles;
01970   js->numdihedrals = numdihedrals;
01971   js->numimpropers = numimpropers;
01972   js->numcterms = numcterms;
01973 
01974 #if defined(INFOMSGS)
01975   if (js->verbose) {
01976     printf("jsplugin) write_js_angles():\n");
01977     printf("jsplugin) storing angles/dihedrals/impropers for writing...\n");
01978     printf("jsplugin) %d %d %d %d\n",
01979            numangles, numdihedrals, numimpropers, numcterms);
01980   }
01981 #endif
01982 
01983   if (js->numangles > 0 || js->numdihedrals > 0 || js->numimpropers > 0) {
01984     js->optflags |= JSOPT_ANGLES;
01985 
01986     js->angles = (int *) malloc(3L*js->numangles*sizeof(int));
01987     memcpy(js->angles, angles, 3L*js->numangles*sizeof(int));
01988     js->dihedrals = (int *) malloc(4L*js->numdihedrals*sizeof(int));
01989     memcpy(js->dihedrals, dihedrals, 4L*js->numdihedrals*sizeof(int));
01990     js->impropers = (int *) malloc(4L*js->numimpropers*sizeof(int));
01991     memcpy(js->impropers, impropers, 4L*js->numimpropers*sizeof(int));
01992   }
01993   if (js->numcterms > 0) {
01994     js->optflags |= JSOPT_CTERMS;
01995 
01996     js->cterms = (int *) malloc(8L*js->numcterms*sizeof(int));
01997     memcpy(js->cterms, cterms, 8L*js->numcterms*sizeof(int));
01998   }
01999 
02000   return MOLFILE_SUCCESS;
02001 }
02002 #else
02003 static int write_js_angles(void * v,
02004         int numangles,    const int *angles,    const double *angleforces,
02005         int numdihedrals, const int *dihedrals, const double *dihedralforces,
02006         int numimpropers, const int *impropers, const double *improperforces,
02007         int numcterms,   const int *cterms,
02008         int ctermcols, int ctermrows, const double *ctermforces) {
02009   jshandle *js = (jshandle *) v;
02010 
02011   /* save info until we actually write out the structure file */
02012   js->numangles = numangles;
02013   js->numdihedrals = numdihedrals;
02014   js->numimpropers = numimpropers;
02015   js->numcterms = numcterms;
02016 
02017   if (js->numangles > 0 || js->numdihedrals > 0 || js->numimpropers > 0) {
02018     js->optflags |= JSOPT_ANGLES;
02019 
02020     js->angles = (int *) malloc(3L*js->numangles*sizeof(int));
02021     memcpy(js->angles, angles, 3L*js->numangles*sizeof(int));
02022     js->dihedrals = (int *) malloc(4L*js->numdihedrals*sizeof(int));
02023     memcpy(js->dihedrals, dihedrals, 4L*js->numdihedrals*sizeof(int));
02024     js->impropers = (int *) malloc(4L*js->numimpropers*sizeof(int));
02025     memcpy(js->impropers, impropers, 4L*js->numimpropers*sizeof(int));
02026   }
02027   if (js->numcterms > 0) {
02028     js->optflags |= JSOPT_CTERMS;
02029 
02030     js->cterms = (int *) malloc(8L*js->numcterms*sizeof(int));
02031     memcpy(js->cterms, cterms, 8L*js->numcterms*sizeof(int));
02032   }
02033 
02034   return MOLFILE_SUCCESS;
02035 }
02036 #endif
02037 #endif
02038 
02039 
02040 static int write_js_timestep(void *v, const molfile_timestep_t *ts) { 
02041   jshandle *js = (jshandle *)v;
02042   double *unitcell=NULL;
02043   long zeropadsz=0;
02044 
02045   /* If no structure data was written and this is the first timestep */
02046   /* we must complete writing the file header and performing the     */
02047   /* seek to the next filesystem block and VM-page boundary when     */
02048   /* using direct I/O APIs...                                        */
02049   if (js->directio_ucell_blkbuf == NULL) {
02050     printf("jsplugin) no structure data, writing timesteps only...\n");
02051 
02052     /* use block-based I/O by default when writing structures larger */
02053     /* than JSBLOCKIO_THRESH atoms, or when directed by the user     */
02054     js_blockio_check_and_set(js);
02055 
02056     /* write flags data to the file */
02057     fio_write_int32(js->fd, js->optflags); 
02058     printf("jsplugin) writing option flags: %0x08x\n", js->optflags);
02059 
02060     /* Check to see if block-based trajectory I/O is used  */
02061     /* and write out the block size for this file.         */
02062     if (js->optflags & JSOPT_TS_BLOCKIO) {
02063       fio_fwrite(&js->directio_block_size, sizeof(int), 1, js->fd);
02064       printf("jsplugin) Block-based I/O enabled: block size %d bytes\n", 
02065              js->directio_block_size);
02066     }
02067 
02068     /* update the file offset for the first timestep */
02069     js_calc_timestep_blocking_info(js);
02070   }
02071 
02072   /* set unit cell pointer to the TS block-aligned buffer area */
02073   unitcell = (double *) js->directio_ucell_blkbuf;
02074 
02075   js->nframes++; /* increment frame count written to the file so far */
02076 
02077   unitcell[0] = ts->A;
02078   unitcell[1] = ts->B;
02079   unitcell[2] = ts->C;
02080   unitcell[3] = sin((M_PI_2 / 90.0) * (90.0 - ts->alpha));
02081   unitcell[4] = sin((M_PI_2 / 90.0) * (90.0 - ts->beta));
02082   unitcell[5] = sin((M_PI_2 / 90.0) * (90.0 - ts->gamma));
02083 
02084   /* coordinates for all atoms */
02085   if (fio_fwrite(ts->coords, js->ts_crd_sz, 1, js->fd) != 1) {
02086     printf("jsplugin) Error writing timestep coords!\n");
02087     return MOLFILE_ERROR;
02088   }
02089 
02090   /* correctly handle block-based direct-I/O output format       */
02091   /* write out coord padding bytes using zero buffer in jshandle */
02092   zeropadsz = js->ts_crd_padsz - js->ts_crd_sz;
02093   if (zeropadsz > 0) {
02094     if ((zeropadsz > MOLFILE_DIRECTIO_MAX_BLOCK_SIZE) ||
02095         (fio_fwrite(js->blockpad, zeropadsz, 1, js->fd) != 1)) {
02096       printf("jsplugin) Error writing timestep coord padding!\n");
02097       return MOLFILE_ERROR;
02098     } 
02099   }
02100 
02101   /* PBC unit cell info */ 
02102   if (fio_fwrite(unitcell, js->ts_ucell_sz, 1, js->fd) != 1) {
02103     printf("jsplugin) Error writing timestep unit cell!\n");
02104     return MOLFILE_ERROR;
02105   }
02106 
02107   /* correctly handle block-based direct-I/O output format       */
02108   /* write out PBC padding bytes using zero buffer in jshandle */
02109   zeropadsz = js->ts_ucell_padsz - js->ts_ucell_sz;
02110   if (zeropadsz > 0) {
02111     if ((zeropadsz > MOLFILE_DIRECTIO_MAX_BLOCK_SIZE) ||
02112         (fio_fwrite(js->blockpad, zeropadsz, 1, js->fd) != 1)) {
02113       printf("jsplugin) Error writing timestep PBC padding!\n");
02114       return MOLFILE_ERROR;
02115     } 
02116   }
02117 
02118   return MOLFILE_SUCCESS;
02119 }
02120 
02121 
02122 static void close_js_write(void *v) {
02123   jshandle *js = (jshandle *)v;
02124 
02125   /* update the trajectory header information */
02126   fio_fseek(js->fd, JSNFRAMESOFFSET, FIO_SEEK_SET);
02127   fio_write_int32(js->fd, js->nframes);
02128   fio_fseek(js->fd, 0, FIO_SEEK_END);
02129 
02130   fio_fclose(js->fd);
02131 
02132 #if JSMAJORVERSION > 1
02133   if (js->directio_ucell_ptr)
02134     free(js->directio_ucell_ptr);
02135 
02136   if (js->bondfrom)
02137     free(js->bondfrom);
02138   if (js->bondto)
02139     free(js->bondto);
02140   if (js->bondorders)
02141     free(js->bondorders);
02142 
02143   if (js->angles)
02144     free(js->angles);
02145   if (js->dihedrals)
02146     free(js->dihedrals);
02147   if (js->impropers)
02148     free(js->impropers);
02149   if (js->cterms)
02150     free(js->cterms);
02151 #endif
02152 
02153   free(js);
02154 }
02155 
02156 
02157 /*
02158  * Initialization stuff here
02159  */
02160 static molfile_plugin_t plugin;
02161 
02162 VMDPLUGIN_API int VMDPLUGIN_init() {
02163   memset(&plugin, 0, sizeof(molfile_plugin_t));
02164   plugin.abiversion = vmdplugin_ABIVERSION;
02165   plugin.type = MOLFILE_PLUGIN_TYPE;
02166   plugin.name = "js";
02167   plugin.prettyname = "js";
02168   plugin.author = "John Stone";
02169   plugin.majorv = JSMAJORVERSION;
02170   plugin.minorv = JSMINORVERSION;
02171   plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
02172   plugin.filename_extension = "js";
02173   plugin.open_file_read = open_js_read;
02174 #if JSMAJORVERSION > 1
02175   plugin.read_structure = read_js_structure;
02176   plugin.read_bonds = read_js_bonds;
02177   plugin.read_angles = read_js_angles;
02178 #endif
02179   plugin.read_next_timestep = read_js_timestep;
02180   plugin.close_file_read = close_js_read;
02181   plugin.open_file_write = open_js_write;
02182 #if JSMAJORVERSION > 1
02183   plugin.write_structure = write_js_structure;
02184   plugin.write_bonds = write_js_bonds;
02185   plugin.write_angles = write_js_angles;
02186 #endif
02187   plugin.write_timestep = write_js_timestep;
02188   plugin.close_file_write = close_js_write;
02189 #if vmdplugin_ABIVERSION > 17
02190   plugin.read_timestep_pagealign_size = read_js_timestep_pagealign_size;
02191 #endif
02192   return VMDPLUGIN_SUCCESS;
02193 }
02194 
02195 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
02196   (*cb)(v, (vmdplugin_t *)&plugin);
02197   return VMDPLUGIN_SUCCESS;
02198 }
02199 
02200 VMDPLUGIN_API int VMDPLUGIN_fini() {
02201   return VMDPLUGIN_SUCCESS;
02202 }
02203 
02204   
02205 #ifdef TEST_JSPLUGIN
02206 
02207 #include <sys/time.h>
02208 
02209 #if defined(ENABLECUDATESTS)
02210 #include <cuda_runtime.h>
02211 
02212 #if defined(ENABLECUDAGDS)
02213 #include <cufile.h>
02214 #endif
02215 #endif
02216 
02217 /* get the time of day from the system clock, and store it (in seconds) */
02218 double time_of_day(void) {
02219 #if defined(_MSC_VER)
02220   double t;
02221 
02222   t = GetTickCount();
02223   t = t / 1000.0;
02224 
02225   return t;
02226 #else
02227   struct timeval tm;
02228   struct timezone tz;
02229 
02230   gettimeofday(&tm, &tz);
02231   return((double)(tm.tv_sec) + (double)(tm.tv_usec)/1000000.0);
02232 #endif
02233 }
02234 
02235 int main(int argc, char *argv[]) {
02236   molfile_timestep_t timestep;
02237   float *coords0=NULL, *aligncoords0=NULL;
02238   float *coords1=NULL, *aligncoords1=NULL;
02239 
02240   void *v;
02241   jshandle *js;
02242   int natoms, i;
02243   long sz, blocksz;
02244   float sizeMB =0.0, totalMB = 0.0;
02245   double starttime, endtime, totaltime = 0.0;
02246   int do_io = 1;
02247   int verbose = 0;
02248   int overlapiogpu = 1;
02249 
02250   printf("Standalone tests for JS plugin:\n");
02251   
02252   if (getenv("VMDJSNOIO") != NULL)
02253     do_io = 0;
02254 
02255   if (getenv("VMDJSVERBOSE") != NULL || getenv("VMDJSTESTVERBOSE"))
02256     verbose = 1;    
02257 
02258   if (do_io)
02259     printf("  Timestep disk I/O enabled.\n");
02260   else
02261     printf("  Timestep disk I/O DISABLED.\n");
02262 
02263 #if defined(ENABLECUDATESTS)
02264   printf("  CUDA GPU support compiled in.\n");
02265 
02266   // If the code is compiled with CUDA support, we benchmark 
02267   // host I/O immediately followed by host-GPU copies of each timestep
02268   cudaError_t crc;
02269   cudaStream_t devstream;
02270   long maxatomidx=-1;
02271   int devcount;
02272   float *devptr=NULL;
02273 
02274   crc = cudaGetDeviceCount(&devcount);
02275   printf("  GPU device count: %d\n", devcount);
02276   if (devcount==0)
02277     printf("  No GPU devices, continuing with host only...\n");
02278 
02279   // Only do the CUDA tests if asked to
02280   if (getenv("VMDJSCUDATESTS") == NULL) {
02281     devcount = 0;
02282     printf("  GPU tests disabled.\n");
02283     printf("  Enable GPU tests with VMDJSCUDATESTS env variable\n");
02284   } else {
02285     printf("  Disable GPU tests by unsetting VMDJSCUDATESTS env variable\n");
02286   }
02287 
02288 #if defined(ENABLEJSSHORTREADS)
02289   /* test code for an implementation that does short reads that */
02290   /* skip bulk solvent, useful for faster loading of very large */
02291   /* structures                                                 */
02292   if (getenv("VMDJSMAXATOMIDX") != NULL) {
02293     fio_size_t bszmask;
02294 
02295     maxatomidx = atoi(getenv("VMDJSMAXATOMIDX"));
02296     if (maxatomidx < 0)
02297       maxatomidx = 0;
02298     if (maxatomidx >= js->natoms)
02299       maxatomidx = js->natoms - 1;
02300 
02301     printf("jsplugin) Short-copies of GPU timesteps enabled: %ld / %ld atoms (%.2f%%)\n",
02302            maxatomidx, js->natoms, 100.0*(maxatomidx+1) / ((float) js->natoms));
02303   }
02304 #endif
02305 #endif
02306 
02307 
02308   while (--argc) {
02309     int syncframe;
02310     ++argv; 
02311     natoms = 0;
02312     v = open_js_read(*argv, "js", &natoms);
02313     if (!v) {
02314       printf("jsplugin) open_js_read failed for file %s\n", *argv);
02315       return 1;
02316     }
02317     js = (jshandle *)v;
02318     sizeMB = ((natoms * 3.0) * js->nframes * 4.0) / (1024.0 * 1024.0);
02319     totalMB += sizeMB; 
02320     printf("jsplugin) file: %s\n", *argv);
02321     printf("jsplugin)   %d atoms, %d frames, size: %6.1fMB\n", natoms, js->nframes, sizeMB);
02322 
02323     starttime = time_of_day();
02324 
02325     /* ensure we have a large enough allocation so we can align */
02326     /* the starting pointer to a blocksz page boundary          */
02327     blocksz = MOLFILE_DIRECTIO_MIN_BLOCK_SIZE;
02328     sz = 3L*sizeof(float)*natoms + blocksz;
02329 
02330     /* pad the allocation to an even multiple of the block size */
02331     size_t blockpadsz = (sz + (blocksz - 1)) & (~(blocksz - 1));
02332 
02333     /* allocate multi buffers so we can have concurrent work/transfers/reads */
02334     aligncoords0 = (float *) alloc_aligned_ptr(sz, blocksz, (void**) &coords0);
02335     aligncoords1 = (float *) alloc_aligned_ptr(sz, blocksz, (void**) &coords1);
02336 
02337 #if vmdplugin_ABIVERSION > 17
02338     int filepgalignsz = 1;
02339     read_js_timestep_pagealign_size(v, &filepgalignsz);
02340     if (filepgalignsz != blocksz) {
02341       printf("jsplugin) Plugin-returned page alignment size doesn't match!\n");
02342     } else {
02343       printf("jsplugin) Page alignment size: %d\n", filepgalignsz);
02344     }
02345 #endif
02346 
02347 #if defined(ENABLECUDATESTS)
02348 #if defined(ENABLECUDAGDS)
02349     int cufileinuse=0;
02350     CUfileHandle_t cfh;
02351     CUfileDescr_t cfhdesc;
02352     CUfileError_t cferr;
02353     memset(&cfh, 0, sizeof(cfh));
02354     memset(&cfhdesc, 0, sizeof(cfhdesc));
02355 #endif
02356 
02357     if (crc == cudaSuccess && devcount > 0) {
02358       cudaSetDevice(0);
02359       printf("jsplugin) allocating GPU memory buffer for CUDA tests...\n");
02360       crc = cudaMalloc((void**) &devptr, blockpadsz);
02361       if (crc != cudaSuccess) {
02362         printf("Failed to allocate GPU buffer!\n");
02363         return -1;
02364       }
02365 
02366       cudaStreamCreate(&devstream);
02367 
02368 #if defined(ENABLECUDAGDS)
02369       cuFileBufRegister(devptr, blockpadsz, 0); 
02370 
02371       cfhdesc.handle.fd = js->directio_fd; // typedef of Unix FD
02372       cfhdesc.type = CU_FILE_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD;
02373       cferr = cuFileImportExternalFile(&cfh, &cfhdesc);
02374       if (cferr.err != CU_FILE_SUCCESS) {
02375         printf("Failed to import file handle for use by cuFile APIs!\n");
02376         return -1;
02377       }
02378       cufileinuse=1;
02379 #endif
02380     }
02381 #endif
02382 
02383     /* loop over all timesteps ... */
02384     for (syncframe=0,i=0; i<js->nframes; i++) {
02385       if (do_io) {
02386         /* read even/odd frame into alternating buffers so     */
02387         /* that we can overlap a read with an ongoing GPU copy */
02388         if (i & 1) 
02389           timestep.coords = aligncoords1;
02390         else  
02391           timestep.coords = aligncoords0;
02392 
02393         /* disk I/O is synchronous */
02394         if (verbose) {
02395           printf("%sreading frame[%d]...", (i!=0) ? "\r" : "", i);
02396           fflush(stdout);
02397         }
02398         int rc=0;
02399         if (cufileinuse) {
02400 #if 0
02401           /* read an even multiple of the block size */
02402           long rsz = natoms * 3L * sizeof(float);
02403           rsz = (rsz + (blocksz - 1)) & (~(blocksz - 1));
02404           long foffset = i * rsz;
02405 #endif
02406           long startoffset, foffset, readlen;
02407           fio_fd directio_fd;
02408           read_js_timestep_index_offsets(v, natoms, i, 0, natoms,
02409                                          &directio_fd,
02410                                          &startoffset,
02411                                          &foffset,
02412                                          &readlen);
02413 
02414 printf("cuFileRead(): offset %ld  readlen: %ld\n", foffset, readlen);
02415           long ret = 0;
02416           ret = cuFileRead(cfh, (char *) devptr, readlen, foffset);
02417           if (ret < 0) {
02418             const char *descp = "unknown error code";
02419 #if 0
02420             // XXX this requires linkage with libcuda.so, which is
02421             //     against convention, so we avoid it for now
02422             if (cuGetErrorName(ret, &descp) != CUDA_SUCCESS)
02423               descp = "unknown cuda error";
02424 #endif
02425 
02426             printf("Error: cuFileRead(): %ld, '%s'\n", ret, descp);
02427             return -1;
02428           }
02429         } else {
02430           rc = read_js_timestep(v, natoms, &timestep);
02431         }
02432         if (rc) {
02433           printf("jsplugin) error in read_js_timestep on frame %d\n", i);
02434           /* return 1; */
02435         }
02436       }
02437 
02438 #if defined(ENABLECUDATESTS)
02439       if (crc == cudaSuccess && devcount > 0) {
02440 #if defined(ENABLECUDAGDS)
02441         if (!cufileinuse) {
02442 #endif
02443           /* allow overlap of async memcpy with next round of direct I/O */
02444           if (overlapiogpu) {
02445             if (verbose) {
02446               printf("sync frame[%d]...", syncframe);
02447               fflush(stdout);
02448             }
02449             cudaStreamSynchronize(devstream);
02450           }
02451 
02452           if (verbose) {
02453             printf("cudaMemcpyAsync() frame[%d]...", i);
02454             fflush(stdout);
02455           }
02456 
02457           size_t bsz = (maxatomidx >= 0) ? (maxatomidx+1) : natoms;
02458           bsz *= 3L*sizeof(float);
02459           crc = cudaMemcpyAsync(devptr, timestep.coords, bsz, cudaMemcpyHostToDevice, devstream);
02460           syncframe=i;
02461 
02462           if (!overlapiogpu) {
02463             if (verbose) {
02464               printf("sync frame[%d]...", syncframe);
02465               fflush(stdout);
02466             }
02467             cudaStreamSynchronize(devstream);
02468           }
02469   
02470           if (verbose) {
02471             printf("       ");
02472             fflush(stdout);
02473           }
02474 #if defined(ENABLECUDAGDS)
02475         }
02476 #endif
02477       }
02478 #endif
02479     }
02480 
02481 #if defined(ENABLECUDATESTS)
02482     /* wait for last GPU memcpy */
02483     cudaStreamSynchronize(devstream);
02484     printf("\n");
02485 
02486     /* wait for any pending GPU calls to complete */
02487     cudaDeviceSynchronize();
02488 
02489 #if defined(ENABLECUDAGDS)
02490     if (cufileinuse) {
02491       cuFileBufDeregister(devptr); 
02492       cuFileDestroyFile(&cfh);
02493     }
02494 #endif
02495 #endif
02496 
02497     endtime = time_of_day();
02498     close_js_read(v);
02499 
02500 #if defined(ENABLECUDATESTS)
02501     cudaStreamDestroy(devstream);
02502     if (crc == cudaSuccess && devcount > 0) {
02503       cudaFree(devptr);
02504     }
02505 #endif
02506     free(coords0);
02507     free(coords1);
02508 
02509     totaltime += endtime - starttime;
02510     printf("jsplugin)  Time: %5.1f seconds\n", endtime - starttime);
02511     printf("jsplugin)  Speed: %5.1f MB/sec, %5.1f timesteps/sec\n", sizeMB / (endtime - starttime), (js->nframes / (endtime - starttime)));
02512   }
02513   printf("jsplugin) Overall Size: %6.1f MB\n", totalMB);
02514   printf("jsplugin) Overall Time: %6.1f seconds\n", totaltime);
02515   printf("jsplugin) Overall Speed: %5.1f MB/sec\n", totalMB / totaltime);
02516   return 0;
02517 }
02518       
02519 #endif
02520 

Generated on Wed Apr 8 03:01:20 2020 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002