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.88 $       $Date: 2020/07/03 06:13:07 $
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   18
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         if (js->verbose) {
00689           printf("jsplugin)   %d dihedrals...\n", js->numdihedrals);
00690         }
00691 #endif
00692         fio_fseek(js->fd, sizeof(int)*4L*js->numdihedrals, FIO_SEEK_CUR);
00693 
00694         fio_fread(&js->numimpropers, sizeof(int), 1, js->fd);
00695         if (js->reverseendian)
00696           swap4_aligned(&js->numimpropers, 1);
00697 #if defined(INFOMSGS)
00698         if (js->verbose) {
00699           printf("jsplugin)   %d impropers...\n", js->numimpropers);
00700         }
00701 #endif
00702         fio_fseek(js->fd, sizeof(int)*4L*js->numimpropers, FIO_SEEK_CUR);
00703       }
00704 
00705       if (js->optflags & JSOPT_CTERMS) {
00706         fio_fread(&js->numcterms, sizeof(int), 1, js->fd);
00707         if (js->reverseendian)
00708           swap4_aligned(&js->numcterms, 1);
00709 #if defined(INFOMSGS)
00710         if (js->verbose) {
00711           printf("jsplugin)   %d cterms...\n", js->numcterms);
00712         }
00713 #endif
00714         fio_fseek(js->fd, sizeof(int)*8L*js->numcterms, FIO_SEEK_CUR);
00715       }
00716   
00717       /* record the file offset for the first timestep */
00718       js_calc_timestep_blocking_info(js);
00719 
00720       return MOLFILE_SUCCESS;
00721     }
00722 
00723 
00724     /* allocate string tables */
00725     atomnames = (char **) malloc(numatomnames * sizeof(char *));
00726     atomtypes = (char **) malloc(numatomtypes * sizeof(char *));
00727     resnames  = (char **) malloc(numresnames  * sizeof(char *));
00728     segids    = (char **) malloc(numsegids    * sizeof(char *));
00729     chains    = (char **) malloc(numchains    * sizeof(char *));
00730 
00731 #if defined(INFOMSGS)
00732     if (js->verbose)
00733       printf("jsplugin)   atom names...\n");
00734 #endif
00735 
00736     /* read in the string tables */
00737     for (i=0; i<numatomnames; i++) {
00738       atomnames[i] = (char *) malloc(16L * sizeof(char));
00739       fio_fread(atomnames[i], 16L * sizeof(char), 1, js->fd);
00740     }
00741 
00742 #if defined(INFOMSGS)
00743     if (js->verbose)
00744       printf("jsplugin)   atom types...\n");
00745 #endif
00746     for (i=0; i<numatomtypes; i++) {
00747       atomtypes[i] = (char *) malloc(16L * sizeof(char));
00748       fio_fread(atomtypes[i], 16L * sizeof(char), 1, js->fd);
00749     }
00750 
00751 #if defined(INFOMSGS)
00752     if (js->verbose)
00753       printf("jsplugin)   residue names...\n");
00754 #endif
00755     for (i=0; i<numresnames; i++) {
00756       resnames[i] = (char *) malloc(8L * sizeof(char));
00757       fio_fread(resnames[i], 8L * sizeof(char), 1, js->fd);
00758     }
00759 
00760 #if defined(INFOMSGS)
00761     if (js->verbose)
00762       printf("jsplugin)   segment names...\n");
00763 #endif
00764     for (i=0; i<numsegids; i++) {
00765       segids[i] = (char *) malloc(8L * sizeof(char));
00766       fio_fread(segids[i], 8L * sizeof(char), 1, js->fd);
00767     }
00768 
00769 #if defined(INFOMSGS)
00770     if (js->verbose)
00771       printf("jsplugin)   chain names...\n");
00772 #endif
00773     for (i=0; i<numchains; i++) {
00774       chains[i] = (char *) malloc(2L * sizeof(char));
00775       fio_fread(chains[i], 2L * sizeof(char), 1, js->fd);
00776     }
00777 
00778 #if defined(INFOMSGS)
00779     if (js->verbose)
00780       printf("jsplugin) reading numeric field tables...\n");
00781 #endif
00782     /* read in all of the atom fields */
00783     shortbuf = (short *) malloc(js->natoms * sizeof(short));
00784 
00785 #if defined(INFOMSGS)
00786     if (js->verbose)
00787       printf("jsplugin)   atom name indices...\n");
00788 #endif
00789     /* read in atom names */
00790     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00791     if (js->reverseendian)
00792       swap2_aligned(shortbuf, js->natoms);
00793     for (i=0; i<js->natoms; i++) {
00794       strcpy(atoms[i].name, atomnames[shortbuf[i]]);
00795     }
00796     for (i=0; i<numatomnames; i++)
00797       free(atomnames[i]);
00798     free(atomnames);
00799 
00800 #if defined(INFOMSGS)
00801     if (js->verbose)
00802       printf("jsplugin)   atom type indices...\n");
00803 #endif
00804     /* read in atom types */
00805     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00806     if (js->reverseendian)
00807       swap2_aligned(shortbuf, js->natoms);
00808     for (i=0; i<js->natoms; i++) {
00809       strcpy(atoms[i].type, atomtypes[shortbuf[i]]);
00810     }
00811     for (i=0; i<numatomtypes; i++)
00812       free(atomtypes[i]);
00813     free(atomtypes);
00814 
00815 #if defined(INFOMSGS)
00816     if (js->verbose)
00817       printf("jsplugin)   residue name indices...\n");
00818 #endif
00819     /* read in resnames */
00820     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00821     if (js->reverseendian)
00822       swap2_aligned(shortbuf, js->natoms);
00823     for (i=0; i<js->natoms; i++) {
00824       strcpy(atoms[i].resname, resnames[shortbuf[i]]);
00825     }
00826     for (i=0; i<numresnames; i++)
00827       free(resnames[i]);
00828     free(resnames);
00829     
00830 #if defined(INFOMSGS)
00831     if (js->verbose)
00832       printf("jsplugin)   segment name indices...\n");
00833 #endif
00834     /* read in segids */
00835     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00836     if (js->reverseendian)
00837       swap2_aligned(shortbuf, js->natoms);
00838     for (i=0; i<js->natoms; i++) {
00839       strcpy(atoms[i].segid, segids[shortbuf[i]]);
00840     }
00841     for (i=0; i<numsegids; i++)
00842       free(segids[i]);
00843     free(segids);
00844 
00845 #if defined(INFOMSGS)
00846     if (js->verbose)
00847       printf("jsplugin)   chain name indices...\n");
00848 #endif
00849     /* read in chains */
00850     fio_fread(shortbuf, js->natoms * sizeof(short), 1, js->fd);
00851     if (js->reverseendian)
00852       swap2_aligned(shortbuf, js->natoms);
00853     for (i=0; i<js->natoms; i++) {
00854       strcpy(atoms[i].chain, chains[shortbuf[i]]);
00855     }
00856     for (i=0; i<numchains; i++)
00857       free(chains[i]);
00858     free(chains);
00859 
00860     if (shortbuf != NULL) {
00861       free(shortbuf);
00862       shortbuf=NULL;
00863     }
00864 
00865     /* 
00866      * read in integer data blocks 
00867      */
00868     intbuf = (int *) malloc(js->natoms * sizeof(int));
00869 
00870 #if defined(INFOMSGS)
00871     if (js->verbose)
00872       printf("jsplugin)   residue indices...\n");
00873 #endif
00874     /* read in resid */
00875     fio_fread(intbuf, js->natoms * sizeof(int), 1, js->fd);
00876     if (js->reverseendian)
00877       swap4_aligned(intbuf, js->natoms);
00878     for (i=0; i<js->natoms; i++) {
00879       atoms[i].resid = intbuf[i];
00880     }    
00881      
00882     if (intbuf != NULL) {
00883       free(intbuf);
00884       intbuf = NULL;
00885     }
00886 
00887 
00888 #if defined(INFOMSGS)
00889     if (js->verbose)
00890       printf("jsplugin) reading optional per-atom tables...\n");
00891 #endif
00892     /*
00893      * read in optional single-precision float data blocks
00894      */ 
00895     if (js->optflags & (JSOPT_OCCUPANCY | JSOPT_BFACTOR | 
00896         JSOPT_MASS | JSOPT_RADIUS | JSOPT_CHARGE)) 
00897       fltbuf = (float *) malloc(js->natoms * sizeof(float));
00898 
00899     /* read in optional data if it exists */
00900     if (js->optflags & JSOPT_OCCUPANCY) {
00901 #if defined(INFOMSGS)
00902       if (js->verbose)
00903         printf("jsplugin)   occupancy...\n");
00904 #endif
00905       *optflags |= MOLFILE_OCCUPANCY;
00906       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00907       if (js->reverseendian)
00908         swap4_aligned(fltbuf, js->natoms);
00909       for (i=0; i<js->natoms; i++) {
00910         atoms[i].occupancy = fltbuf[i];
00911       }    
00912     }
00913 
00914     if (js->optflags & JSOPT_BFACTOR) {
00915 #if defined(INFOMSGS)
00916       if (js->verbose)
00917         printf("jsplugin)   bfactor...\n");
00918 #endif
00919       *optflags |= MOLFILE_BFACTOR;
00920       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00921       if (js->reverseendian)
00922         swap4_aligned(fltbuf, js->natoms);
00923       for (i=0; i<js->natoms; i++) {
00924         atoms[i].bfactor = fltbuf[i];
00925       }    
00926     }
00927 
00928     if (js->optflags & JSOPT_MASS) { 
00929 #if defined(INFOMSGS)
00930       if (js->verbose)
00931         printf("jsplugin)   mass...\n");
00932 #endif
00933       *optflags |= MOLFILE_MASS;
00934       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00935       if (js->reverseendian)
00936         swap4_aligned(fltbuf, js->natoms);
00937       for (i=0; i<js->natoms; i++) {
00938         atoms[i].mass = fltbuf[i];
00939       }    
00940     }
00941 
00942     if (js->optflags & JSOPT_CHARGE) { 
00943 #if defined(INFOMSGS)
00944       if (js->verbose)
00945         printf("jsplugin)   charge...\n");
00946 #endif
00947       *optflags |= MOLFILE_CHARGE;
00948       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00949       if (js->reverseendian)
00950         swap4_aligned(fltbuf, js->natoms);
00951       for (i=0; i<js->natoms; i++) {
00952         atoms[i].charge = fltbuf[i];
00953       }    
00954     }
00955 
00956     if (js->optflags & JSOPT_RADIUS) { 
00957 #if defined(INFOMSGS)
00958       if (js->verbose)
00959         printf("jsplugin)   radius...\n");
00960 #endif
00961       *optflags |= MOLFILE_RADIUS;
00962       fio_fread(fltbuf, js->natoms * sizeof(float), 1, js->fd);
00963       if (js->reverseendian)
00964         swap4_aligned(fltbuf, js->natoms);
00965       for (i=0; i<js->natoms; i++) {
00966         atoms[i].radius = fltbuf[i];
00967       }    
00968     }
00969 
00970     if (fltbuf != NULL) {
00971       free(fltbuf);
00972       fltbuf=NULL;
00973     }
00974 
00975     /*
00976      * read in optional integer data blocks
00977      */ 
00978     if (js->optflags & JSOPT_ATOMICNUMBER)
00979       intbuf = (int *) malloc(js->natoms * sizeof(int));
00980 
00981     if (js->optflags & JSOPT_ATOMICNUMBER) { 
00982 #if defined(INFOMSGS)
00983       if (js->verbose)
00984         printf("jsplugin)   atomic number...\n");
00985 #endif
00986       *optflags |= MOLFILE_ATOMICNUMBER;
00987       fio_fread(intbuf, js->natoms * sizeof(int), 1, js->fd);
00988       if (js->reverseendian)
00989         swap4_aligned(intbuf, js->natoms);
00990       for (i=0; i<js->natoms; i++) {
00991         atoms[i].atomicnumber = intbuf[i];
00992       }    
00993     }
00994 
00995     if (intbuf != NULL) {
00996       free(intbuf);
00997       intbuf = NULL;
00998     }
00999 
01000 
01001     /*
01002      * read in bonds and fractional bond orders
01003      */ 
01004     if (js->optflags & JSOPT_BONDS) {
01005       fio_fread(&js->nbonds, sizeof(int), 1, js->fd);
01006       if (js->reverseendian)
01007         swap4_aligned(&js->nbonds, 1);
01008 #if defined(INFOMSGS)
01009       if (js->verbose)
01010         printf("jsplugin)   %d bonds...\n", js->nbonds);
01011 #endif
01012 
01013       js->bondfrom = (int *) malloc(js->nbonds * sizeof(int));
01014       js->bondto = (int *) malloc(js->nbonds * sizeof(int));
01015       fio_fread(js->bondfrom, js->nbonds * sizeof(int), 1, js->fd);
01016       fio_fread(js->bondto, js->nbonds * sizeof(int), 1, js->fd);
01017       if (js->reverseendian) {
01018         swap4_aligned(js->bondfrom, js->nbonds);
01019         swap4_aligned(js->bondto, js->nbonds);
01020       }
01021 
01022       if (js->optflags & JSOPT_BONDORDERS) {
01023 #if defined(INFOMSGS)
01024         if (js->verbose)
01025           printf("jsplugin)   bond orders...\n");
01026 #endif
01027         js->bondorders = (float *) malloc(js->nbonds * sizeof(float));
01028         fio_fread(js->bondorders, js->nbonds * sizeof(float), 1, js->fd);
01029         if (js->reverseendian)
01030           swap4_aligned(js->bondorders, js->nbonds);
01031       }
01032     }
01033 
01034     if (js->optflags & JSOPT_ANGLES) {
01035       fio_fread(&js->numangles, sizeof(int), 1, js->fd);
01036       if (js->reverseendian)
01037         swap4_aligned(&js->numangles, 1);
01038 #if defined(INFOMSGS)
01039       if (js->verbose)
01040         printf("jsplugin)   %d angles...\n", js->numangles);
01041 #endif
01042       js->angles = (int *) malloc(3L * js->numangles * sizeof(int));
01043       fio_fread(js->angles, sizeof(int)*3L*js->numangles, 1, js->fd);
01044       if (js->reverseendian)
01045         swap4_aligned(js->angles, 3L*js->numangles);
01046 
01047       fio_fread(&js->numdihedrals, sizeof(int), 1, js->fd);
01048       if (js->reverseendian)
01049         swap4_aligned(&js->numdihedrals, 1);
01050 #if defined(INFOMSGS)
01051       if (js->verbose)
01052         printf("jsplugin)   %d dihedrals...\n", js->numdihedrals);
01053 #endif
01054       js->dihedrals = (int *) malloc(4L * js->numdihedrals * sizeof(int));
01055       fio_fread(js->dihedrals, sizeof(int)*4L*js->numdihedrals, 1, js->fd);
01056       if (js->reverseendian)
01057         swap4_aligned(js->dihedrals, 4L*js->numdihedrals);
01058 
01059       fio_fread(&js->numimpropers, sizeof(int), 1, js->fd);
01060       if (js->reverseendian)
01061         swap4_aligned(&js->numimpropers, 1);
01062       js->impropers = (int *) malloc(4L * js->numimpropers * sizeof(int));
01063 #if defined(INFOMSGS)
01064       if (js->verbose)
01065         printf("jsplugin)   %d impropers...\n", js->numimpropers);
01066 #endif
01067       fio_fread(js->impropers, sizeof(int)*4L*js->numimpropers, 1, js->fd);
01068       if (js->reverseendian)
01069         swap4_aligned(js->impropers, 4L*js->numimpropers);
01070     }
01071 
01072     if (js->optflags & JSOPT_CTERMS) {
01073       fio_fread(&js->numcterms, sizeof(int), 1, js->fd);
01074       if (js->reverseendian)
01075         swap4_aligned(&js->numcterms, 1);
01076       js->cterms = (int *) malloc(8L * js->numcterms * sizeof(int));
01077 #if defined(INFOMSGS)
01078       if (js->verbose)
01079         printf("jsplugin)   %d cterms...\n", js->numcterms);
01080 #endif
01081       fio_fread(js->cterms, sizeof(int)*8L*js->numcterms, 1, js->fd);
01082       if (js->reverseendian)
01083         swap4_aligned(js->cterms, 8L*js->numcterms);
01084     }
01085 
01086 #if defined(INFOMSGS)
01087     if (js->verbose) {
01088       printf("jsplugin) final optflags: %08x\n", *optflags);
01089       printf("jsplugin) structure information complete\n");
01090     }
01091 #endif
01092 
01093     /* record the file offset for the first timestep */
01094     js_calc_timestep_blocking_info(js);
01095 
01096     return MOLFILE_SUCCESS;
01097   }
01098 
01099 #if defined(INFOMSGS)
01100   if (js->verbose)
01101     printf("jsplugin) no structure information available\n");
01102 #endif
01103 
01104   /* record the file offset for the first timestep */
01105   js_calc_timestep_blocking_info(js);
01106 
01107   /* else, we have no structure information */
01108   return MOLFILE_NOSTRUCTUREDATA;
01109 }
01110 
01111 
01112 static int read_js_bonds(void *v, int *nbonds, int **fromptr, int **toptr, 
01113                          float **bondorder, int **bondtype, 
01114                          int *nbondtypes, char ***bondtypename) {
01115   jshandle *js = (jshandle *)v;
01116 
01117   *nbonds = 0;
01118   *fromptr = NULL;
01119   *toptr = NULL;
01120   *bondorder = NULL;
01121   *bondtype = NULL;
01122   *nbondtypes = 0;
01123   *bondtypename = NULL;
01124 
01125   if (js->optflags & JSOPT_BONDS) {
01126     *nbonds = js->nbonds;
01127     *fromptr = js->bondfrom;
01128     *toptr = js->bondto;
01129 
01130     if (js->optflags & JSOPT_BONDORDERS) {
01131       *bondorder = js->bondorders;
01132     }
01133   }
01134 
01135   return MOLFILE_SUCCESS;
01136 }
01137 
01138 #if vmdplugin_ABIVERSION > 14
01139 static int read_js_angles(void *v, int *numangles, int **angles, 
01140                           int **angletypes, int *numangletypes, 
01141                           char ***angletypenames, int *numdihedrals,
01142                           int **dihedrals, int **dihedraltypes, 
01143                           int *numdihedraltypes, char ***dihedraltypenames,
01144                           int *numimpropers, int **impropers, 
01145                           int **impropertypes, int *numimpropertypes, 
01146                           char ***impropertypenames, int *numcterms, 
01147                           int **cterms, int *ctermcols, int *ctermrows) {
01148   jshandle *js = (jshandle *)v;
01149 
01150   /* initialize data to zero */
01151   *numangles         = 0;
01152   *angles            = NULL;
01153   *angletypes        = NULL;
01154   *numangletypes     = 0;
01155   *angletypenames    = NULL;
01156   *numdihedrals      = 0;
01157   *dihedrals         = NULL;
01158   *dihedraltypes     = NULL;
01159   *numdihedraltypes  = 0;
01160   *dihedraltypenames = NULL;
01161   *numimpropers      = 0;
01162   *impropers         = NULL;
01163   *impropertypes     = NULL;
01164   *numimpropertypes  = 0;
01165   *impropertypenames = NULL;
01166   *numcterms         = 0;
01167   *cterms            = NULL;
01168   *ctermrows         = 0;
01169   *ctermcols         = 0;
01170 
01171   *numangles = js->numangles;
01172   *angles = js->angles;
01173 
01174   *numdihedrals = js->numdihedrals;
01175   *dihedrals = js->dihedrals;
01176 
01177   *numimpropers = js->numimpropers;
01178   *impropers = js->impropers;
01179 
01180   *numcterms = js->numcterms;
01181   *cterms = js->cterms;
01182   *ctermcols = 0;
01183   *ctermrows = 0;
01184 
01185   return MOLFILE_SUCCESS;
01186 }
01187 #else
01188 static int read_js_angles(void *v,
01189                int *numangles,    int **angles,    double **angleforces,
01190                int *numdihedrals, int **dihedrals, double **dihedralforces,
01191                int *numimpropers, int **impropers, double **improperforces,
01192                int *numcterms,    int **cterms,
01193                int *ctermcols,    int *ctermrows,  double **ctermforces) {
01194   jshandle *js = (jshandle *)v;
01195 
01196   *numangles = js->numangles;
01197   *angles = js->angles;
01198   *angleforces = NULL;
01199 
01200   *numdihedrals = js->numdihedrals;
01201   *dihedrals = js->dihedrals;
01202   *dihedralforces = NULL;
01203 
01204   *numimpropers = js->numimpropers;
01205   *impropers = js->impropers;
01206   *improperforces = NULL;
01207 
01208   *numcterms = js->numcterms;
01209   *cterms = js->cterms;
01210   *ctermcols = 0;
01211   *ctermrows = 0;
01212   *ctermforces = NULL;
01213 
01214   return MOLFILE_SUCCESS;
01215 }
01216 #endif
01217 
01218 #endif
01219 
01220 
01221 #if 1 
01222 // XXX prototypical out-of-core trajectory analysis API
01223 static int read_js_timestep_index_offsets(void *v, int natoms, 
01224                                           long frameindex,
01225                                           int firstatom, int numatoms,
01226                                           fio_fd *directio_fd,
01227                                           long *startoffset,
01228                                           long *fileoffset,
01229                                           long *readlen) {
01230   jshandle *js = (jshandle *)v;
01231   fio_size_t framelen;
01232 
01233 #if JSMAJORVERSION > 1
01234   /* If we haven't yet read (or skipped) the structure data, then we    */
01235   /* need to begin by skipping past it before we try to read the        */
01236   /* first timestep.  In the case of files with block-aligned timesteps,*/
01237   /* this will also get our file pointer to the right block-aligned     */
01238   /* location.                                                          */
01239   if (!js->parsed_structure)
01240     read_js_structure(v, NULL, NULL);
01241 #endif
01242 
01243   /* compute total read/seek size of timestep */
01244   framelen = js->ts_crd_padsz + js->ts_ucell_padsz;
01245 
01246   if (directio_fd != NULL)
01247     *directio_fd = js->directio_fd;
01248 
01249   /* compute file offset for requested timestep */
01250   if (fileoffset != NULL)
01251     *fileoffset = (frameindex * framelen) + js->ts_file_offset;
01252 
01253   /* compute startoffset for first requested atom */
01254   if (startoffset != NULL)
01255     *startoffset = firstatom * 3L * sizeof(float);
01256  
01257   /* compute required read size */ 
01258   if (readlen != NULL)
01259     *readlen = framelen;
01260 
01261   return MOLFILE_SUCCESS;
01262 }
01263 
01264 
01265 #if 0
01266 static int read_js_timestep_index(void *v, int natoms, 
01267                                   long frameindex,
01268                                   molfile_timestep_t *ts) {
01269 }
01270 #endif
01271 
01272 #endif
01273 
01274 
01275 
01276 static int read_js_timestep(void *v, int natoms, molfile_timestep_t *ts) {
01277   jshandle *js = (jshandle *)v;
01278   fio_size_t framelen;
01279 
01280 #if JSMAJORVERSION > 1
01281   /* If we haven't yet read (or skipped) the structure data, then we    */
01282   /* need to begin by skipping past it before we try to read the        */
01283   /* first timestep.  In the case of files with block-aligned timesteps,*/
01284   /* this will also get our file pointer to the right block-aligned     */
01285   /* location.                                                          */
01286   if (!js->parsed_structure)
01287     read_js_structure(v, NULL, NULL);
01288 #endif
01289 
01290   /* compute total read/seek size of timestep */
01291   framelen = js->ts_crd_padsz + js->ts_ucell_padsz;
01292 
01293   /* if we have a valid ts pointer, read the timestep, otherwise skip it */ 
01294   if (ts != NULL) {
01295     fio_size_t readlen=0;
01296     fio_iovec iov[2];
01297 
01298     /* set unit cell pointer to the TS block-aligned buffer area */
01299     double *unitcell = (double *) js->directio_ucell_blkbuf;
01300 
01301     unitcell[0] = unitcell[2] = unitcell[5] = 1.0f;
01302     unitcell[1] = unitcell[3] = unitcell[4] = 90.0f;
01303 
01304 #if defined(ENABLEJSSHORTREADS)
01305     /* test code for an implementation that does short reads that */
01306     /* skip bulk solvent, useful for faster loading of very large */
01307     /* structures                                                 */
01308     if (getenv("VMDJSMAXATOMIDX") != NULL) {
01309       fio_size_t bszmask;
01310       long maxatompadsz, skipatompadsz;
01311 
01312       long maxatomidx = atoi(getenv("VMDJSMAXATOMIDX"));
01313       if (maxatomidx < 0)
01314         maxatomidx = 0;
01315       if (maxatomidx >= js->natoms)
01316         maxatomidx = js->natoms - 1;
01317 
01318       /* pad max read to the start of the next block  */
01319       bszmask = js->directio_block_size - 1;
01320       maxatompadsz = ((maxatomidx*3L*sizeof(float)) + bszmask) & (~bszmask);
01321       skipatompadsz = js->ts_crd_padsz - maxatompadsz;
01322 
01323       readlen=0;
01324       if (js->directio_enabled) {
01325         if (fio_fread(ts->coords, maxatompadsz, 1, js->directio_fd) == 1)
01326           readlen = maxatompadsz;
01327         if (fio_fseek(js->directio_fd, skipatompadsz, FIO_SEEK_CUR) == 0)
01328           readlen += skipatompadsz;
01329         if (fio_fread(unitcell, js->ts_ucell_padsz, 1, js->directio_fd) == 1)
01330           readlen += js->ts_ucell_padsz;
01331       } else {
01332         if (fio_fread(ts->coords, maxatompadsz, 1, js->fd) == 1)
01333           readlen = maxatompadsz;
01334         if (fio_fseek(js->fd, skipatompadsz, FIO_SEEK_CUR) == 0)
01335           readlen += skipatompadsz;
01336         if (fio_fread(unitcell, js->ts_ucell_padsz, 1, js->fd) == 1)
01337           readlen += js->ts_ucell_padsz;
01338       }
01339 
01340 #if 0
01341       /* clear all non-read atom coords to zeros */
01342       memset(ts->coords+3L*maxatomidx,0,3L*sizeof(float)*(js->natoms-maxatomidx));
01343 #endif
01344 
01345     }  else {
01346 #endif
01347  
01348     /* setup the I/O vector */
01349     iov[0].iov_base = (fio_caddr_t) ts->coords;   /* read coordinates    */
01350     iov[1].iov_base = (fio_caddr_t) unitcell;     /* read PBC unit cell  */
01351 
01352     if (js->directio_enabled) {
01353       iov[0].iov_len  = js->ts_crd_padsz;
01354       iov[1].iov_len  = js->ts_ucell_padsz;
01355     } else {
01356       iov[0].iov_len  = js->ts_crd_sz;
01357       iov[1].iov_len  = js->ts_ucell_sz;
01358     }
01359    
01360 #if 1
01361     /* Use fall-back code instead of readv():                            */
01362     /*  Some platforms implement readv() as user level code in libc,     */
01363     /*  and due to POSIX atomicity requirements for readv()/writev(),    */
01364     /*  they may copy data to internal temp buffers, which can kill      */
01365     /*  performance, and in cases when doing single I/O ops on large,    */
01366     /*  buffers, e.g. > 2GB, can fail with shorts reads or writes...     */
01367     /*  On such platforms it is best to avoid using readv()/writev()...  */
01368     {
01369       int readcnt = 0;
01370       readlen = 0;
01371       if (js->directio_enabled) {
01372         readcnt =  fio_fread(iov[0].iov_base, iov[0].iov_len, 1, js->directio_fd);
01373         readcnt += fio_fread(iov[1].iov_base, iov[1].iov_len, 1, js->directio_fd);
01374       } else {
01375         fio_size_t seeklen=0;
01376       
01377         readcnt =  fio_fread(iov[0].iov_base, iov[0].iov_len, 1, js->fd);
01378         seeklen = js->ts_crd_padsz - js->ts_crd_sz;
01379         if (seeklen > 0)
01380           fio_fseek(js->fd, seeklen, FIO_SEEK_CUR);
01381         readcnt += fio_fread(iov[1].iov_base, iov[1].iov_len, 1, js->fd);
01382         seeklen = js->ts_ucell_padsz - js->ts_ucell_sz;
01383         if (seeklen > 0)
01384           fio_fseek(js->fd, seeklen, FIO_SEEK_CUR);
01385       }
01386 
01387       /* if both records read correctly, then the reads are okay */
01388       if (readcnt == 2)
01389         readlen = framelen;
01390     }
01391 #else
01392     /* Do all of the reads with a single syscall, for peak efficiency.   */
01393     /* On smart kernels, readv() causes only one context switch, and     */
01394     /* can effeciently scatter the reads to the various buffers.         */
01395     if (js->directio_enabled) {
01396       readlen = fio_readv(js->directio_fd, &iov[0], 2); 
01397     } else {
01398       // XXX we can't use readv() when not using direct I/O since we 
01399       // can't make intervening seek calls required if the caller
01400       // doesn't provide appropriate buffers.
01401       // readlen = fio_readv(js->fd, &iov[0], 2); 
01402 
01403       fio_size_t seeklen=0;
01404       readcnt =  fio_fread(iov[0].iov_base, iov[0].iov_len, 1, js->fd);
01405       seeklen = js->ts_crd_padsz - js->ts_crd_sz;
01406       if (seeklen > 0)
01407         fio_fseek(js->fd, seeklen, FIO_SEEK_CUR);
01408       readcnt += fio_fread(iov[1].iov_base, iov[1].iov_len, 1, js->fd);
01409       seeklen = js->ts_ucell_padsz - js->ts_ucell_sz;
01410       if (seeklen > 0)
01411         fio_fseek(js->fd, seeklen, FIO_SEEK_CUR);
01412     }
01413 #endif
01414 
01415 #if defined(ENABLEJSSHORTREADS)
01416    }
01417 #endif 
01418  
01419     /* check the number of read bytes versus what we expected */
01420     if (readlen != framelen) {
01421       if (readlen < 0) {
01422         perror("jsplugin) fio_readv(): ");
01423       } else if (readlen != 0) {
01424         printf("jsplugin) mismatched read: %ld, expected %ld\n", 
01425                (long) readlen, (long) framelen);
01426       }
01427 
01428       return MOLFILE_EOF;
01429     }
01430 
01431     /* perform byte swapping if necessary */
01432     if (js->reverseendian) {
01433       swap4_aligned(ts->coords, js->natoms * 3L);
01434       swap8_aligned(unitcell, 6);
01435     }
01436 
01437     /* copy unit cell values into VMD */
01438     ts->A = unitcell[0];
01439     ts->B = unitcell[1];
01440     ts->C = unitcell[2];
01441     ts->alpha = 90.0 - asin(unitcell[3]) * 90.0 / M_PI_2;
01442     ts->beta  = 90.0 - asin(unitcell[4]) * 90.0 / M_PI_2;
01443     ts->gamma = 90.0 - asin(unitcell[5]) * 90.0 / M_PI_2;
01444   } else {
01445     /* skip this frame, seek to the next frame */
01446     if (js->directio_enabled) {
01447       if (fio_fseek(js->directio_fd, framelen, FIO_SEEK_CUR)) 
01448         return MOLFILE_EOF;
01449     } else {
01450       if (fio_fseek(js->fd, framelen, FIO_SEEK_CUR)) 
01451         return MOLFILE_EOF;
01452     }
01453   }
01454  
01455   return MOLFILE_SUCCESS;
01456 }
01457 
01458 
01459 static void close_js_read(void *v) {
01460   jshandle *js = (jshandle *)v;
01461   fio_fclose(js->fd);
01462 
01463 #if JSMAJORVERSION > 1
01464   if (js->path)
01465     free(js->path);
01466 
01467   if (js->directio_enabled)
01468     fio_fclose(js->directio_fd);
01469 
01470   if (js->directio_ucell_ptr)
01471     free(js->directio_ucell_ptr);
01472 
01473   if (js->bondfrom)
01474     free(js->bondfrom);
01475   if (js->bondto)
01476     free(js->bondto);
01477   if (js->bondorders)
01478     free(js->bondorders);
01479 
01480   /* free angle data */
01481   if (js->angles != NULL)
01482     free(js->angles);
01483   if (js->dihedrals != NULL)
01484     free(js->dihedrals);
01485   if (js->impropers != NULL)
01486     free(js->impropers);
01487   if (js->cterms)
01488     free(js->cterms);
01489 #endif
01490 
01491   free(js);
01492 }
01493 
01494 
01495 static void *open_js_write(const char *path, const char *filetype, int natoms) {
01496   jshandle *js;
01497 
01498   js = (jshandle *) malloc(sizeof(jshandle));
01499   memset(js, 0, sizeof(jshandle));
01500 #if JSMAJORVERSION > 1
01501   js->parsed_structure=0;
01502   js->directio_block_size=1;
01503   js->directio_ucell_ptr = NULL;
01504   js->directio_ucell_blkbuf = NULL;
01505 
01506   js->directio_enabled=0;
01507   js->ts_file_offset=0;
01508   js->ts_crd_sz=0;
01509   js->ts_ucell_sz=0;
01510   js->ts_crd_padsz=0;
01511   js->ts_ucell_padsz=0;
01512 #endif
01513 
01514   if (fio_open(path, FIO_WRITE, &js->fd) < 0) {
01515     printf("jsplugin) Could not open file %s for writing\n", path);
01516     free(js);
01517     return NULL;
01518   }
01519 
01520   js->natoms = natoms;
01521   js->with_unitcell = 1;
01522 
01523   /* emit header information */
01524   fio_write_str(js->fd, JSHEADERSTRING);
01525   fio_write_int32(js->fd, JSMAGICNUMBER);
01526   fio_write_int32(js->fd, JSENDIANISM);
01527   fio_write_int32(js->fd, JSMAJORVERSION);
01528   fio_write_int32(js->fd, JSMINORVERSION);
01529 
01530   /* write number of atoms */
01531   fio_write_int32(js->fd, natoms);
01532 
01533   /* write number of frames, to be updated later */
01534   js->nframes = 0;
01535   fio_write_int32(js->fd, js->nframes);
01536 
01537   return js;
01538 }
01539 
01540 
01541 #if JSMAJORVERSION > 1
01542 
01543 static int write_js_structure(void *mydata, int optflags,
01544                               const molfile_atom_t *atoms) {
01545   jshandle *js = (jshandle *) mydata;
01546   long i;
01547 
01548   /* use block-based I/O by default when writing structures larger */
01549   /* than JSBLOCKIO_THRESH atoms, or when directed by the user     */
01550   js_blockio_check_and_set(js);
01551 
01552   js->optflags |= JSOPT_STRUCTURE;
01553 
01554   if (optflags & MOLFILE_OCCUPANCY)
01555     js->optflags |= JSOPT_OCCUPANCY;
01556 
01557   if (optflags & MOLFILE_BFACTOR)
01558     js->optflags |= JSOPT_BFACTOR;
01559 
01560   if (optflags & MOLFILE_BFACTOR)
01561     js->optflags |= JSOPT_BFACTOR;
01562 
01563   if (optflags & MOLFILE_MASS)
01564     js->optflags |= JSOPT_MASS;
01565 
01566   if (optflags & MOLFILE_CHARGE)
01567     js->optflags |= JSOPT_CHARGE;
01568  
01569   if (optflags & MOLFILE_RADIUS)
01570     js->optflags |= JSOPT_RADIUS;
01571 
01572   if (optflags & MOLFILE_ATOMICNUMBER)
01573     js->optflags |= JSOPT_ATOMICNUMBER;
01574 
01575   /* write flags data to the file */
01576   fio_write_int32(js->fd, js->optflags); 
01577 printf("jsplugin) writing option flags: %0x08x\n", js->optflags);
01578 
01579   /* Check to see if block-based trajectory I/O is used  */
01580   /* and write out the block size for this file.         */
01581   if (js->optflags & JSOPT_TS_BLOCKIO) {
01582     fio_fwrite(&js->directio_block_size, sizeof(int), 1, js->fd);
01583     printf("jsplugin) Block-based I/O enabled: block size %d bytes\n", 
01584            js->directio_block_size);
01585   }
01586 
01587 printf("jsplugin) writing structure...\n");
01588   /* determine whether or not this file contains structure info or not */
01589   if (js->optflags & JSOPT_STRUCTURE) {
01590     int numatomnames, numatomtypes, numresnames, numsegids, numchains;
01591     char **atomnames = NULL;
01592     char **atomtypes = NULL;
01593     char **resnames = NULL;
01594     char **segids = NULL;
01595     char **chains = NULL;
01596     short *shortbuf = NULL; /* temp buf for encoding atom records */
01597     int *intbuf = NULL;     /* temp buf for encoding atom records */
01598     float *fltbuf = NULL;   /* temp buf for encoding atom records */
01599 
01600     hash_t tmphash;         /* temporary hash table */
01601     hash_t atomnamehash;
01602     hash_t atomtypehash;
01603     hash_t resnamehash;
01604     hash_t segidhash;
01605     hash_t chainhash;
01606     int hashcnt;
01607 
01608 
01609 printf("jsplugin) counting atom names, types, etc...\n");
01610     /* generate hash tables to count the number of unique strings */
01611     hash_init(&tmphash, 127);
01612     for (i=0; i<js->natoms; i++)
01613       hash_insert(&tmphash, atoms[i].name, 0);
01614     numatomnames = hash_entries(&tmphash);
01615     hash_destroy(&tmphash);
01616 
01617     hash_init(&tmphash, 127);
01618     for (i=0; i<js->natoms; i++)
01619       hash_insert(&tmphash, atoms[i].type, 0);
01620     numatomtypes = hash_entries(&tmphash);
01621     hash_destroy(&tmphash);
01622 
01623     hash_init(&tmphash, 127);
01624     for (i=0; i<js->natoms; i++)
01625       hash_insert(&tmphash, atoms[i].resname, 0);
01626     numresnames = hash_entries(&tmphash);
01627     hash_destroy(&tmphash);
01628 
01629     hash_init(&tmphash, 127);
01630     for (i=0; i<js->natoms; i++)
01631       hash_insert(&tmphash, atoms[i].segid, 0);
01632     numsegids = hash_entries(&tmphash);
01633     hash_destroy(&tmphash);
01634 
01635     hash_init(&tmphash, 127);
01636     for (i=0; i<js->natoms; i++)
01637       hash_insert(&tmphash, atoms[i].chain, 0);
01638     numchains = hash_entries(&tmphash);
01639     hash_destroy(&tmphash);
01640  
01641 printf("jsplugin) writing unique string counts...\n");
01642 printf("jsplugin) %d %d %d %d %d\n",
01643        numatomnames, numatomtypes, numresnames, numsegids, numchains);
01644 
01645     /* write block of name string table sizes */
01646     fio_write_int32(js->fd, numatomnames); 
01647     fio_write_int32(js->fd, numatomtypes); 
01648     fio_write_int32(js->fd, numresnames);
01649     fio_write_int32(js->fd, numsegids);
01650     fio_write_int32(js->fd, numchains); 
01651 
01652 printf("jsplugin) writing string tables...\n");
01653 
01654     atomnames = (char **) malloc(numatomnames * sizeof(char *));
01655     atomtypes = (char **) malloc(numatomtypes * sizeof(char *));
01656     resnames = (char **) malloc(numresnames * sizeof(char *));
01657     segids = (char **) malloc(numsegids * sizeof(char *));
01658     chains = (char **) malloc(numchains * sizeof(char *));
01659 
01660 printf("jsplugin)   atom names...\n");
01661     /* generate and write out the string tables */
01662     hash_init(&atomnamehash, 127);
01663     for (hashcnt=0,i=0; i<js->natoms; i++) {
01664       /* add a new string table entry for hash inserts that don't yet exist */
01665       if (hash_insert(&atomnamehash, atoms[i].name, hashcnt) == HASH_FAIL) {
01666         atomnames[hashcnt] = (char *) calloc(1, 16L * sizeof(char));
01667         strcpy(atomnames[hashcnt], atoms[i].name);
01668         hashcnt++;
01669       }
01670     }
01671     for (i=0; i<numatomnames; i++) {
01672       fio_fwrite(atomnames[i], 16L * sizeof(char), 1, js->fd);
01673     }
01674 
01675 
01676 printf("jsplugin)   atom types...\n");
01677     hash_init(&atomtypehash, 127);
01678     for (hashcnt=0,i=0; i<js->natoms; i++) {
01679       /* add a new string table entry for hash inserts that don't yet exist */
01680       if (hash_insert(&atomtypehash, atoms[i].type, hashcnt) == HASH_FAIL) {
01681         atomtypes[hashcnt] = (char *) calloc(1, 16L * sizeof(char));
01682         strcpy(atomtypes[hashcnt], atoms[i].type);
01683         hashcnt++;
01684       }
01685     }
01686     for (i=0; i<numatomtypes; i++) {
01687       fio_fwrite(atomtypes[i], 16L * sizeof(char), 1, js->fd);
01688     }
01689 
01690 
01691 printf("jsplugin)   residue names...\n");
01692     hash_init(&resnamehash, 127);
01693     for (hashcnt=0,i=0; i<js->natoms; i++) {
01694       /* add a new string table entry for hash inserts that don't yet exist */
01695       if (hash_insert(&resnamehash, atoms[i].resname, hashcnt) == HASH_FAIL) {
01696         resnames[hashcnt] = (char *) calloc(1, 8L * sizeof(char));
01697         strcpy(resnames[hashcnt], atoms[i].resname);
01698         hashcnt++;
01699       }
01700     }
01701     for (i=0; i<numresnames; i++) {
01702       fio_fwrite(resnames[i], 8L * sizeof(char), 1, js->fd);
01703     }
01704 
01705 
01706 printf("jsplugin)   segment names...\n");
01707     hash_init(&segidhash, 127);
01708     for (hashcnt=0,i=0; i<js->natoms; i++) {
01709       /* add a new string table entry for hash inserts that don't yet exist */
01710       if (hash_insert(&segidhash, atoms[i].segid, hashcnt) == HASH_FAIL) {
01711         segids[hashcnt] = (char *) calloc(1, 8L * sizeof(char));
01712         strcpy(segids[hashcnt], atoms[i].segid);
01713         hashcnt++;
01714       }
01715     }
01716     for (i=0; i<numsegids; i++) {
01717       fio_fwrite(segids[i], 8L * sizeof(char), 1, js->fd);
01718     }
01719 
01720 
01721 printf("jsplugin)   chain names...\n");
01722     hash_init(&chainhash, 127);
01723     for (hashcnt=0,i=0; i<js->natoms; i++) {
01724       /* add a new string table entry for hash inserts that don't yet exist */
01725       if (hash_insert(&chainhash, atoms[i].chain, hashcnt) == HASH_FAIL) {
01726         chains[hashcnt] = (char *) calloc(1, 2L * sizeof(char));
01727         strcpy(chains[hashcnt], atoms[i].chain);
01728         hashcnt++;
01729       }
01730     }
01731     for (i=0; i<numchains; i++) {
01732       fio_fwrite(chains[i], 2L * sizeof(char), 1, js->fd);
01733     }
01734 
01735 
01736 printf("jsplugin) writing numeric field tables...\n");
01737     /* write out all of the atom fields */
01738     shortbuf = (short *) malloc(js->natoms * sizeof(short));
01739 
01740     /* write out atom names */
01741     for (i=0; i<js->natoms; i++) {
01742       shortbuf[i] = hash_lookup(&atomnamehash, atoms[i].name);
01743     }    
01744     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01745 
01746     /* write out atom types */
01747     for (i=0; i<js->natoms; i++) {
01748       shortbuf[i] = hash_lookup(&atomtypehash, atoms[i].type);
01749     }    
01750     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01751 
01752     /* write out resnames */
01753     for (i=0; i<js->natoms; i++) {
01754       shortbuf[i] = hash_lookup(&resnamehash, atoms[i].resname);
01755     }    
01756     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01757     
01758     /* write out segids */
01759     for (i=0; i<js->natoms; i++) {
01760       shortbuf[i] = hash_lookup(&segidhash, atoms[i].segid);
01761     }    
01762     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01763 
01764     /* write out chains */
01765     for (i=0; i<js->natoms; i++) {
01766       shortbuf[i] = hash_lookup(&chainhash, atoms[i].chain);
01767     }    
01768     fio_fwrite(shortbuf, js->natoms * sizeof(short), 1, js->fd);
01769 
01770     if (shortbuf != NULL) {
01771       free(shortbuf);
01772       shortbuf=NULL;
01773     }
01774 
01775     /* done with hash tables */
01776     hash_destroy(&atomnamehash);
01777     hash_destroy(&atomtypehash);
01778     hash_destroy(&resnamehash);
01779     hash_destroy(&segidhash);
01780     hash_destroy(&chainhash);
01781 
01782 
01783     /* 
01784      * write out integer data blocks 
01785      */
01786     intbuf = (int *) malloc(js->natoms * sizeof(int));
01787 
01788 printf("jsplugin)   residue indices...\n");
01789     /* write out resid */
01790     for (i=0; i<js->natoms; i++) {
01791       intbuf[i] = atoms[i].resid;
01792     }    
01793     fio_fwrite(intbuf, js->natoms * sizeof(int), 1, js->fd);
01794      
01795     if (intbuf != NULL) {
01796       free(intbuf);
01797       intbuf = NULL;
01798     }
01799 
01800 printf("jsplugin) writing optional per-atom tables...\n");
01801     /*
01802      * write out optional single-precision float data blocks
01803      */ 
01804     if (js->optflags & (JSOPT_OCCUPANCY | JSOPT_BFACTOR | 
01805         JSOPT_MASS | JSOPT_RADIUS | JSOPT_CHARGE)) 
01806       fltbuf = (float *) malloc(js->natoms * sizeof(float));
01807 
01808     /* write out optional data if it exists */
01809 
01810     if (js->optflags & JSOPT_OCCUPANCY) {
01811 printf("jsplugin)   writing occupancy...\n");
01812       for (i=0; i<js->natoms; i++) {
01813         fltbuf[i] = atoms[i].occupancy;
01814       }    
01815       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01816     }
01817 
01818     if (js->optflags & JSOPT_BFACTOR) {
01819 printf("jsplugin)   writing bfactor...\n");
01820       for (i=0; i<js->natoms; i++) {
01821         fltbuf[i] = atoms[i].bfactor;
01822       }    
01823       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01824     }
01825 
01826     if (js->optflags & JSOPT_MASS) { 
01827 printf("jsplugin)   writing mass...\n");
01828       for (i=0; i<js->natoms; i++) {
01829         fltbuf[i] = atoms[i].mass;
01830       }    
01831       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01832     }
01833 
01834     if (js->optflags & JSOPT_CHARGE) { 
01835 printf("jsplugin)   writing charge...\n");
01836       for (i=0; i<js->natoms; i++) {
01837         fltbuf[i] = atoms[i].charge;
01838       }    
01839       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01840     }
01841 
01842     if (js->optflags & JSOPT_RADIUS) { 
01843 printf("jsplugin)   writing radius...\n");
01844       for (i=0; i<js->natoms; i++) {
01845         fltbuf[i] = atoms[i].radius;
01846       }    
01847       fio_fwrite(fltbuf, js->natoms * sizeof(float), 1, js->fd);
01848     }
01849 
01850     if (fltbuf != NULL) {
01851       free(fltbuf);
01852       fltbuf=NULL;
01853     }
01854 
01855 
01856     /*
01857      * write out optional integer data blocks
01858      */ 
01859     if (js->optflags & JSOPT_ATOMICNUMBER)
01860       intbuf = (int *) malloc(js->natoms * sizeof(int));
01861 
01862     if (js->optflags & JSOPT_ATOMICNUMBER) { 
01863 printf("jsplugin)   writing atomic number...\n");
01864       for (i=0; i<js->natoms; i++) {
01865         intbuf[i] = atoms[i].atomicnumber;
01866       }    
01867       fio_fwrite(intbuf, js->natoms * sizeof(int), 1, js->fd);
01868     }
01869 
01870     if (intbuf != NULL) {
01871       free(intbuf);
01872       intbuf = NULL;
01873     }
01874 
01875 
01876     /*
01877      * write out bonds and fractional bond orders
01878      */ 
01879     if (js->optflags & JSOPT_BONDS) {
01880 printf("jsplugin) writing bonds...\n");
01881       fio_fwrite(&js->nbonds, sizeof(int), 1, js->fd);
01882       fio_fwrite(js->bondfrom, js->nbonds * sizeof(int), 1, js->fd);
01883       fio_fwrite(js->bondto, js->nbonds * sizeof(int), 1, js->fd);
01884 
01885       if (js->optflags & JSOPT_BONDORDERS) {
01886 printf("jsplugin) writing bond orders...\n");
01887         fio_fwrite(js->bondorders, js->nbonds * sizeof(float), 1, js->fd);
01888       }
01889     }
01890 
01891     /*
01892      * write out angles/dihedrals/impropers/cross-terms
01893      */
01894     if (js->optflags & JSOPT_ANGLES) {
01895 printf("jsplugin) writing angles/dihedrals/impropers...\n");
01896       fio_fwrite(&js->numangles, sizeof(int), 1, js->fd);
01897       fio_fwrite(js->angles, sizeof(int)*3L*js->numangles, 1, js->fd);
01898 
01899       fio_fwrite(&js->numdihedrals, sizeof(int), 1, js->fd);
01900       fio_fwrite(js->dihedrals, sizeof(int)*4L*js->numdihedrals, 1, js->fd);
01901 
01902       fio_fwrite(&js->numimpropers, sizeof(int), 1, js->fd);
01903       fio_fwrite(js->impropers, sizeof(int)*4L*js->numimpropers, 1, js->fd);
01904     }
01905     if (js->optflags & JSOPT_CTERMS) {
01906 printf("jsplugin) writing cross-terms\n");
01907       fio_fwrite(&js->numcterms, sizeof(int), 1, js->fd);
01908       fio_fwrite(js->cterms, sizeof(int)*8L*js->numcterms, 1, js->fd);
01909     }
01910 
01911     /* update the file offset for the first timestep */
01912     js_calc_timestep_blocking_info(js);
01913 
01914     return MOLFILE_SUCCESS;
01915   }
01916 
01917   /* update the file offset for the first timestep */
01918   js_calc_timestep_blocking_info(js);
01919 
01920   /* else, we have no structure information */
01921   return MOLFILE_NOSTRUCTUREDATA;
01922 }
01923 
01924 
01925 static int write_js_bonds(void *mydata, int nbonds, int *fromptr, int *toptr, 
01926                           float *bondorder,  int *bondtype, 
01927                           int nbondtypes, char **bondtypename) {
01928   jshandle *js = (jshandle *) mydata;
01929 
01930 #if defined(INFOMSGS)
01931     if (js->verbose) {
01932       printf("jsplugin) write_js_bonds():\n");
01933       printf("jsplugin) storing bond info for writing...\n");
01934       printf("jsplugin) %d %d\n", nbonds, nbondtypes);
01935     }
01936 #endif
01937 
01938   if (nbonds > 0 && fromptr != NULL && toptr != NULL) {
01939     js->optflags |= JSOPT_BONDS; 
01940 
01941     /* save bond info until we actually write out the structure file */
01942     js->nbonds = nbonds;
01943     js->bondfrom = (int *) malloc(nbonds * sizeof(int));
01944     memcpy(js->bondfrom, fromptr, nbonds * sizeof(int));
01945     js->bondto = (int *) malloc(nbonds * sizeof(int));
01946     memcpy(js->bondto, toptr, nbonds * sizeof(int));
01947 
01948     if (bondorder != NULL) {
01949       js->optflags |= JSOPT_BONDORDERS;
01950       js->bondorders = (float *) malloc(nbonds * sizeof(float));
01951       memcpy(js->bondorders, bondorder, nbonds * sizeof(float));
01952     }
01953   }
01954 
01955   return MOLFILE_SUCCESS;
01956 }
01957 
01958 #if vmdplugin_ABIVERSION > 14
01959 static int write_js_angles(void * v, int numangles, const int *angles,
01960                            const int *angletypes, int numangletypes,
01961                            const char **angletypenames, int numdihedrals, 
01962                            const int *dihedrals, const int *dihedraltype,
01963                            int numdihedraltypes, const char **dihedraltypenames,
01964                            int numimpropers, const int *impropers, 
01965                            const int *impropertypes, int numimpropertypes, 
01966                            const char **impropertypenames, int numcterms, 
01967                            const int *cterms, int ctermcols, int ctermrows) {
01968   jshandle *js = (jshandle *) v;
01969 
01970   /* save info until we actually write out the structure file */
01971   js->numangles = numangles;
01972   js->numdihedrals = numdihedrals;
01973   js->numimpropers = numimpropers;
01974   js->numcterms = numcterms;
01975 
01976 #if defined(INFOMSGS)
01977   if (js->verbose) {
01978     printf("jsplugin) write_js_angles():\n");
01979     printf("jsplugin) storing angles/dihedrals/impropers for writing...\n");
01980     printf("jsplugin) %d %d %d %d\n",
01981            numangles, numdihedrals, numimpropers, numcterms);
01982   }
01983 #endif
01984 
01985   if (js->numangles > 0 || js->numdihedrals > 0 || js->numimpropers > 0) {
01986     js->optflags |= JSOPT_ANGLES;
01987 
01988     js->angles = (int *) malloc(3L*js->numangles*sizeof(int));
01989     memcpy(js->angles, angles, 3L*js->numangles*sizeof(int));
01990     js->dihedrals = (int *) malloc(4L*js->numdihedrals*sizeof(int));
01991     memcpy(js->dihedrals, dihedrals, 4L*js->numdihedrals*sizeof(int));
01992     js->impropers = (int *) malloc(4L*js->numimpropers*sizeof(int));
01993     memcpy(js->impropers, impropers, 4L*js->numimpropers*sizeof(int));
01994   }
01995   if (js->numcterms > 0) {
01996     js->optflags |= JSOPT_CTERMS;
01997 
01998     js->cterms = (int *) malloc(8L*js->numcterms*sizeof(int));
01999     memcpy(js->cterms, cterms, 8L*js->numcterms*sizeof(int));
02000   }
02001 
02002   return MOLFILE_SUCCESS;
02003 }
02004 #else
02005 static int write_js_angles(void * v,
02006         int numangles,    const int *angles,    const double *angleforces,
02007         int numdihedrals, const int *dihedrals, const double *dihedralforces,
02008         int numimpropers, const int *impropers, const double *improperforces,
02009         int numcterms,   const int *cterms,
02010         int ctermcols, int ctermrows, const double *ctermforces) {
02011   jshandle *js = (jshandle *) v;
02012 
02013   /* save info until we actually write out the structure file */
02014   js->numangles = numangles;
02015   js->numdihedrals = numdihedrals;
02016   js->numimpropers = numimpropers;
02017   js->numcterms = numcterms;
02018 
02019   if (js->numangles > 0 || js->numdihedrals > 0 || js->numimpropers > 0) {
02020     js->optflags |= JSOPT_ANGLES;
02021 
02022     js->angles = (int *) malloc(3L*js->numangles*sizeof(int));
02023     memcpy(js->angles, angles, 3L*js->numangles*sizeof(int));
02024     js->dihedrals = (int *) malloc(4L*js->numdihedrals*sizeof(int));
02025     memcpy(js->dihedrals, dihedrals, 4L*js->numdihedrals*sizeof(int));
02026     js->impropers = (int *) malloc(4L*js->numimpropers*sizeof(int));
02027     memcpy(js->impropers, impropers, 4L*js->numimpropers*sizeof(int));
02028   }
02029   if (js->numcterms > 0) {
02030     js->optflags |= JSOPT_CTERMS;
02031 
02032     js->cterms = (int *) malloc(8L*js->numcterms*sizeof(int));
02033     memcpy(js->cterms, cterms, 8L*js->numcterms*sizeof(int));
02034   }
02035 
02036   return MOLFILE_SUCCESS;
02037 }
02038 #endif
02039 #endif
02040 
02041 
02042 static int write_js_timestep(void *v, const molfile_timestep_t *ts) { 
02043   jshandle *js = (jshandle *)v;
02044   double *unitcell=NULL;
02045   long zeropadsz=0;
02046 
02047   /* If no structure data was written and this is the first timestep */
02048   /* we must complete writing the file header and performing the     */
02049   /* seek to the next filesystem block and VM-page boundary when     */
02050   /* using direct I/O APIs...                                        */
02051   if (js->directio_ucell_blkbuf == NULL) {
02052     printf("jsplugin) no structure data, writing timesteps only...\n");
02053 
02054     /* use block-based I/O by default when writing structures larger */
02055     /* than JSBLOCKIO_THRESH atoms, or when directed by the user     */
02056     js_blockio_check_and_set(js);
02057 
02058     /* write flags data to the file */
02059     fio_write_int32(js->fd, js->optflags); 
02060     printf("jsplugin) writing option flags: %0x08x\n", js->optflags);
02061 
02062     /* Check to see if block-based trajectory I/O is used  */
02063     /* and write out the block size for this file.         */
02064     if (js->optflags & JSOPT_TS_BLOCKIO) {
02065       fio_fwrite(&js->directio_block_size, sizeof(int), 1, js->fd);
02066       printf("jsplugin) Block-based I/O enabled: block size %d bytes\n", 
02067              js->directio_block_size);
02068     }
02069 
02070     /* update the file offset for the first timestep */
02071     js_calc_timestep_blocking_info(js);
02072   }
02073 
02074   /* set unit cell pointer to the TS block-aligned buffer area */
02075   unitcell = (double *) js->directio_ucell_blkbuf;
02076 
02077   js->nframes++; /* increment frame count written to the file so far */
02078 
02079   unitcell[0] = ts->A;
02080   unitcell[1] = ts->B;
02081   unitcell[2] = ts->C;
02082   unitcell[3] = sin((M_PI_2 / 90.0) * (90.0 - ts->alpha));
02083   unitcell[4] = sin((M_PI_2 / 90.0) * (90.0 - ts->beta));
02084   unitcell[5] = sin((M_PI_2 / 90.0) * (90.0 - ts->gamma));
02085 
02086   /* coordinates for all atoms */
02087   if (fio_fwrite(ts->coords, js->ts_crd_sz, 1, js->fd) != 1) {
02088     printf("jsplugin) Error writing timestep coords!\n");
02089     return MOLFILE_ERROR;
02090   }
02091 
02092   /* correctly handle block-based direct-I/O output format       */
02093   /* write out coord padding bytes using zero buffer in jshandle */
02094   zeropadsz = js->ts_crd_padsz - js->ts_crd_sz;
02095   if (zeropadsz > 0) {
02096     if ((zeropadsz > MOLFILE_DIRECTIO_MAX_BLOCK_SIZE) ||
02097         (fio_fwrite(js->blockpad, zeropadsz, 1, js->fd) != 1)) {
02098       printf("jsplugin) Error writing timestep coord padding!\n");
02099       return MOLFILE_ERROR;
02100     } 
02101   }
02102 
02103   /* PBC unit cell info */ 
02104   if (fio_fwrite(unitcell, js->ts_ucell_sz, 1, js->fd) != 1) {
02105     printf("jsplugin) Error writing timestep unit cell!\n");
02106     return MOLFILE_ERROR;
02107   }
02108 
02109   /* correctly handle block-based direct-I/O output format       */
02110   /* write out PBC padding bytes using zero buffer in jshandle */
02111   zeropadsz = js->ts_ucell_padsz - js->ts_ucell_sz;
02112   if (zeropadsz > 0) {
02113     if ((zeropadsz > MOLFILE_DIRECTIO_MAX_BLOCK_SIZE) ||
02114         (fio_fwrite(js->blockpad, zeropadsz, 1, js->fd) != 1)) {
02115       printf("jsplugin) Error writing timestep PBC padding!\n");
02116       return MOLFILE_ERROR;
02117     } 
02118   }
02119 
02120   return MOLFILE_SUCCESS;
02121 }
02122 
02123 
02124 static void close_js_write(void *v) {
02125   jshandle *js = (jshandle *)v;
02126 
02127   /* update the trajectory header information */
02128   fio_fseek(js->fd, JSNFRAMESOFFSET, FIO_SEEK_SET);
02129   fio_write_int32(js->fd, js->nframes);
02130   fio_fseek(js->fd, 0, FIO_SEEK_END);
02131 
02132   fio_fclose(js->fd);
02133 
02134 #if JSMAJORVERSION > 1
02135   if (js->directio_ucell_ptr)
02136     free(js->directio_ucell_ptr);
02137 
02138   if (js->bondfrom)
02139     free(js->bondfrom);
02140   if (js->bondto)
02141     free(js->bondto);
02142   if (js->bondorders)
02143     free(js->bondorders);
02144 
02145   if (js->angles)
02146     free(js->angles);
02147   if (js->dihedrals)
02148     free(js->dihedrals);
02149   if (js->impropers)
02150     free(js->impropers);
02151   if (js->cterms)
02152     free(js->cterms);
02153 #endif
02154 
02155   free(js);
02156 }
02157 
02158 
02159 /*
02160  * Initialization stuff here
02161  */
02162 static molfile_plugin_t plugin;
02163 
02164 #if !defined(VMDJSPLUGININCLUDESRC)
02165 
02166 VMDPLUGIN_API int VMDPLUGIN_init() {
02167   memset(&plugin, 0, sizeof(molfile_plugin_t));
02168   plugin.abiversion = vmdplugin_ABIVERSION;
02169   plugin.type = MOLFILE_PLUGIN_TYPE;
02170   plugin.name = "js";
02171   plugin.prettyname = "js";
02172   plugin.author = "John Stone";
02173   plugin.majorv = JSMAJORVERSION;
02174   plugin.minorv = JSMINORVERSION;
02175   plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
02176   plugin.filename_extension = "js";
02177   plugin.open_file_read = open_js_read;
02178 #if JSMAJORVERSION > 1
02179   plugin.read_structure = read_js_structure;
02180   plugin.read_bonds = read_js_bonds;
02181   plugin.read_angles = read_js_angles;
02182 #endif
02183   plugin.read_next_timestep = read_js_timestep;
02184   plugin.close_file_read = close_js_read;
02185   plugin.open_file_write = open_js_write;
02186 #if JSMAJORVERSION > 1
02187   plugin.write_structure = write_js_structure;
02188   plugin.write_bonds = write_js_bonds;
02189   plugin.write_angles = write_js_angles;
02190 #endif
02191   plugin.write_timestep = write_js_timestep;
02192   plugin.close_file_write = close_js_write;
02193 #if vmdplugin_ABIVERSION > 17
02194   plugin.read_timestep_pagealign_size = read_js_timestep_pagealign_size;
02195 #endif
02196   return VMDPLUGIN_SUCCESS;
02197 }
02198 
02199 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
02200   (*cb)(v, (vmdplugin_t *)&plugin);
02201   return VMDPLUGIN_SUCCESS;
02202 }
02203 
02204 VMDPLUGIN_API int VMDPLUGIN_fini() {
02205   return VMDPLUGIN_SUCCESS;
02206 }
02207 
02208 #endif
02209   
02210 #ifdef TEST_JSPLUGIN
02211 
02212 #include <sys/time.h>
02213 
02214 #if defined(ENABLECUDATESTS)
02215 #include <cuda_runtime.h>
02216 
02217 #if defined(ENABLECUDAGDS)
02218 #include <cufile.h>
02219 #endif
02220 #endif
02221 
02222 /* get the time of day from the system clock, and store it (in seconds) */
02223 double time_of_day(void) {
02224 #if defined(_MSC_VER)
02225   double t;
02226 
02227   t = GetTickCount();
02228   t = t / 1000.0;
02229 
02230   return t;
02231 #else
02232   struct timeval tm;
02233   struct timezone tz;
02234 
02235   gettimeofday(&tm, &tz);
02236   return((double)(tm.tv_sec) + (double)(tm.tv_usec)/1000000.0);
02237 #endif
02238 }
02239 
02240 int main(int argc, char *argv[]) {
02241   molfile_timestep_t timestep;
02242   float *coords0=NULL, *aligncoords0=NULL;
02243   float *coords1=NULL, *aligncoords1=NULL;
02244 
02245   void *v;
02246   jshandle *js;
02247   int natoms, i;
02248   long sz, blocksz;
02249   float sizeMB =0.0, totalMB = 0.0;
02250   double starttime, endtime, totaltime = 0.0;
02251   int do_io = 1;
02252   int verbose = 0;
02253   int overlapiogpu = 1;
02254 
02255   printf("Standalone tests for JS plugin:\n");
02256   
02257   if (getenv("VMDJSNOIO") != NULL)
02258     do_io = 0;
02259 
02260   if (getenv("VMDJSVERBOSE") != NULL || getenv("VMDJSTESTVERBOSE"))
02261     verbose = 1;    
02262 
02263   if (do_io)
02264     printf("  Timestep disk I/O enabled.\n");
02265   else
02266     printf("  Timestep disk I/O DISABLED.\n");
02267 
02268 #if defined(ENABLECUDATESTS)
02269   printf("  CUDA GPU support compiled in.\n");
02270 
02271   // If the code is compiled with CUDA support, we benchmark 
02272   // host I/O immediately followed by host-GPU copies of each timestep
02273   cudaError_t crc;
02274   cudaStream_t devstream;
02275   long maxatomidx=-1;
02276   int devcount;
02277   float *devptr=NULL;
02278 
02279   crc = cudaGetDeviceCount(&devcount);
02280   printf("  GPU device count: %d\n", devcount);
02281   if (devcount==0)
02282     printf("  No GPU devices, continuing with host only...\n");
02283 
02284   // Only do the CUDA tests if asked to
02285   if (getenv("VMDJSCUDATESTS") == NULL) {
02286     devcount = 0;
02287     printf("  GPU tests disabled.\n");
02288     printf("  Enable GPU tests with VMDJSCUDATESTS env variable\n");
02289   } else {
02290     printf("  Disable GPU tests by unsetting VMDJSCUDATESTS env variable\n");
02291   }
02292 
02293 #if defined(ENABLEJSSHORTREADS)
02294   /* test code for an implementation that does short reads that */
02295   /* skip bulk solvent, useful for faster loading of very large */
02296   /* structures                                                 */
02297   if (getenv("VMDJSMAXATOMIDX") != NULL) {
02298     fio_size_t bszmask;
02299 
02300     maxatomidx = atoi(getenv("VMDJSMAXATOMIDX"));
02301     if (maxatomidx < 0)
02302       maxatomidx = 0;
02303     if (maxatomidx >= js->natoms)
02304       maxatomidx = js->natoms - 1;
02305 
02306     printf("jsplugin) Short-copies of GPU timesteps enabled: %ld / %ld atoms (%.2f%%)\n",
02307            maxatomidx, js->natoms, 100.0*(maxatomidx+1) / ((float) js->natoms));
02308   }
02309 #endif
02310 #endif
02311 
02312 
02313   while (--argc) {
02314     int syncframe;
02315     ++argv; 
02316     natoms = 0;
02317     v = open_js_read(*argv, "js", &natoms);
02318     if (!v) {
02319       printf("jsplugin) open_js_read failed for file %s\n", *argv);
02320       return 1;
02321     }
02322     js = (jshandle *)v;
02323     sizeMB = ((natoms * 3.0) * js->nframes * 4.0) / (1024.0 * 1024.0);
02324     totalMB += sizeMB; 
02325     printf("jsplugin) file: %s\n", *argv);
02326     printf("jsplugin)   %d atoms, %d frames, size: %6.1fMB\n", natoms, js->nframes, sizeMB);
02327 
02328     starttime = time_of_day();
02329 
02330     /* ensure we have a large enough allocation so we can align */
02331     /* the starting pointer to a blocksz page boundary          */
02332     blocksz = MOLFILE_DIRECTIO_MIN_BLOCK_SIZE;
02333     sz = 3L*sizeof(float)*natoms + blocksz;
02334 
02335     /* pad the allocation to an even multiple of the block size */
02336     size_t blockpadsz = (sz + (blocksz - 1)) & (~(blocksz - 1));
02337 
02338     /* allocate multi buffers so we can have concurrent work/transfers/reads */
02339     aligncoords0 = (float *) alloc_aligned_ptr(sz, blocksz, (void**) &coords0);
02340     aligncoords1 = (float *) alloc_aligned_ptr(sz, blocksz, (void**) &coords1);
02341 
02342 #if vmdplugin_ABIVERSION > 17
02343     int filepgalignsz = 1;
02344     read_js_timestep_pagealign_size(v, &filepgalignsz);
02345     if (filepgalignsz != blocksz) {
02346       printf("jsplugin) Plugin-returned page alignment size doesn't match!\n");
02347     } else {
02348       printf("jsplugin) Page alignment size: %d\n", filepgalignsz);
02349     }
02350 #endif
02351 
02352 #if defined(ENABLECUDATESTS)
02353 #if defined(ENABLECUDAGDS)
02354     int cufileinuse=0;
02355     CUfileHandle_t cfh;
02356     CUfileDescr_t cfhdesc;
02357     CUfileError_t cferr;
02358     memset(&cfh, 0, sizeof(cfh));
02359     memset(&cfhdesc, 0, sizeof(cfhdesc));
02360 #endif
02361 
02362     if (crc == cudaSuccess && devcount > 0) {
02363       cudaSetDevice(0);
02364       printf("jsplugin) allocating GPU memory buffer for CUDA tests...\n");
02365       crc = cudaMalloc((void**) &devptr, blockpadsz);
02366       if (crc != cudaSuccess) {
02367         printf("Failed to allocate GPU buffer!\n");
02368         return -1;
02369       }
02370 
02371       cudaStreamCreate(&devstream);
02372 
02373 #if defined(ENABLECUDAGDS)
02374       cuFileBufRegister(devptr, blockpadsz, 0); 
02375 
02376       cfhdesc.handle.fd = js->directio_fd; // typedef of Unix FD
02377       cfhdesc.type = CU_FILE_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD;
02378       cferr = cuFileImportExternalFile(&cfh, &cfhdesc);
02379       if (cferr.err != CU_FILE_SUCCESS) {
02380         printf("Failed to import file handle for use by cuFile APIs!\n");
02381         return -1;
02382       }
02383       cufileinuse=1;
02384 #endif
02385     }
02386 #endif
02387 
02388     /* loop over all timesteps ... */
02389     for (syncframe=0,i=0; i<js->nframes; i++) {
02390       if (do_io) {
02391         /* read even/odd frame into alternating buffers so     */
02392         /* that we can overlap a read with an ongoing GPU copy */
02393         if (i & 1) 
02394           timestep.coords = aligncoords1;
02395         else  
02396           timestep.coords = aligncoords0;
02397 
02398         /* disk I/O is synchronous */
02399         if (verbose) {
02400           printf("%sreading frame[%d]...", (i!=0) ? "\r" : "", i);
02401           fflush(stdout);
02402         }
02403         int rc=0;
02404         if (cufileinuse) {
02405 #if 0
02406           /* read an even multiple of the block size */
02407           long rsz = natoms * 3L * sizeof(float);
02408           rsz = (rsz + (blocksz - 1)) & (~(blocksz - 1));
02409           long foffset = i * rsz;
02410 #endif
02411           long startoffset, foffset, readlen;
02412           fio_fd directio_fd;
02413           read_js_timestep_index_offsets(v, natoms, i, 0, natoms,
02414                                          &directio_fd,
02415                                          &startoffset,
02416                                          &foffset,
02417                                          &readlen);
02418 
02419 printf("cuFileRead(): offset %ld  readlen: %ld\n", foffset, readlen);
02420           long ret = 0;
02421           ret = cuFileRead(cfh, (char *) devptr, readlen, foffset);
02422           if (ret < 0) {
02423             const char *descp = "unknown error code";
02424 #if 0
02425             // XXX this requires linkage with libcuda.so, which is
02426             //     against convention, so we avoid it for now
02427             if (cuGetErrorName(ret, &descp) != CUDA_SUCCESS)
02428               descp = "unknown cuda error";
02429 #endif
02430 
02431             printf("Error: cuFileRead(): %ld, '%s'\n", ret, descp);
02432             return -1;
02433           }
02434         } else {
02435           rc = read_js_timestep(v, natoms, &timestep);
02436         }
02437         if (rc) {
02438           printf("jsplugin) error in read_js_timestep on frame %d\n", i);
02439           /* return 1; */
02440         }
02441       }
02442 
02443 #if defined(ENABLECUDATESTS)
02444       if (crc == cudaSuccess && devcount > 0) {
02445 #if defined(ENABLECUDAGDS)
02446         if (!cufileinuse) {
02447 #endif
02448           /* allow overlap of async memcpy with next round of direct I/O */
02449           if (overlapiogpu) {
02450             if (verbose) {
02451               printf("sync frame[%d]...", syncframe);
02452               fflush(stdout);
02453             }
02454             cudaStreamSynchronize(devstream);
02455           }
02456 
02457           if (verbose) {
02458             printf("cudaMemcpyAsync() frame[%d]...", i);
02459             fflush(stdout);
02460           }
02461 
02462           size_t bsz = (maxatomidx >= 0) ? (maxatomidx+1) : natoms;
02463           bsz *= 3L*sizeof(float);
02464           crc = cudaMemcpyAsync(devptr, timestep.coords, bsz, cudaMemcpyHostToDevice, devstream);
02465           syncframe=i;
02466 
02467           if (!overlapiogpu) {
02468             if (verbose) {
02469               printf("sync frame[%d]...", syncframe);
02470               fflush(stdout);
02471             }
02472             cudaStreamSynchronize(devstream);
02473           }
02474   
02475           if (verbose) {
02476             printf("       ");
02477             fflush(stdout);
02478           }
02479 #if defined(ENABLECUDAGDS)
02480         }
02481 #endif
02482       }
02483 #endif
02484     }
02485 
02486 #if defined(ENABLECUDATESTS)
02487     /* wait for last GPU memcpy */
02488     cudaStreamSynchronize(devstream);
02489     printf("\n");
02490 
02491     /* wait for any pending GPU calls to complete */
02492     cudaDeviceSynchronize();
02493 
02494 #if defined(ENABLECUDAGDS)
02495     if (cufileinuse) {
02496       cuFileBufDeregister(devptr); 
02497       cuFileDestroyFile(&cfh);
02498     }
02499 #endif
02500 #endif
02501 
02502     endtime = time_of_day();
02503     close_js_read(v);
02504 
02505 #if defined(ENABLECUDATESTS)
02506     cudaStreamDestroy(devstream);
02507     if (crc == cudaSuccess && devcount > 0) {
02508       cudaFree(devptr);
02509     }
02510 #endif
02511     free(coords0);
02512     free(coords1);
02513 
02514     totaltime += endtime - starttime;
02515     printf("jsplugin)  Time: %5.1f seconds\n", endtime - starttime);
02516     printf("jsplugin)  Speed: %5.1f MB/sec, %5.1f timesteps/sec\n", sizeMB / (endtime - starttime), (js->nframes / (endtime - starttime)));
02517   }
02518   printf("jsplugin) Overall Size: %6.1f MB\n", totalMB);
02519   printf("jsplugin) Overall Time: %6.1f seconds\n", totaltime);
02520   printf("jsplugin) Overall Speed: %5.1f MB/sec\n", totalMB / totaltime);
02521   return 0;
02522 }
02523       
02524 #endif
02525 

Generated on Mon Aug 10 03:06:04 2020 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002