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

vtfplugin.c

Go to the documentation of this file.
00001 /* VTF plugin by Olaf Lenz <olaf@lenz.name> and Henri Menke */
00002 /* $Id: vtfplugin.c,v 1.15 2013/01/09 19:55:44 johns Exp $ */
00003 
00004 /*
00005 VMD file reader plugin for:
00006 - VTF structure format (VSF)
00007 - VTF coordinate format (VCF)
00008 - VTF trajectory format (VTF)
00009 
00010 This code has two main entry points. The functions used in
00011 VMDPLUGIN_init() are the entry points for the VMD plugin API, while
00012 the function vtf_parse_userdata is the entry point when the plugin is
00013 called from the Tcl module "vtftools.tcl" to allow reading in userdata
00014 into Tcl data structures.
00015 */
00016 #include <molfile_plugin.h>
00017 #include <stdlib.h>
00018 #include <stdio.h>
00019 #include <errno.h>
00020 #include <ctype.h>
00021 #include <string.h>
00022 #include <tcl.h>
00023 
00024 #ifdef _USE_ZLIB
00025 #include <zlib.h>
00026 #define VTFFILE gzFile
00027 #define fopen gzopen
00028 #define feof gzeof
00029 #define fgets(buf,size,file) gzgets(file,buf,size)
00030 #define fclose gzclose
00031 #else
00032 #define VTFFILE FILE*
00033 #endif
00034 
00035 #define VERSION_MAJOR 2
00036 #define VERSION_MINOR 2
00037 
00038 /* TODO:
00039 - volumetric/graphics format
00040 - file write support
00041 */
00042 
00043 /***************************************************
00044  * Data structures
00045  ***************************************************/
00046 /* Default atom. 
00047    Used by vtf_parse_atom to initialize new atoms. */
00048 static molfile_atom_t default_atom;
00049 char* default_userdata;
00050 const char *molid;
00051 Tcl_Interp *tcl_interp;
00052 const char* userdata_varname;
00053 
00054 #define VTF_MOLFILE 0
00055 #define VTF_USERDATA 1
00056 
00057 /* Plugin data structure to communciate data between the functions. */
00058 typedef struct {
00059   /* opened file */
00060   VTFFILE file;
00061   /* return code */
00062   int return_code;
00063   /* read mode */
00064   int read_mode;
00065 
00066   /* STRUCTURE DATA (used by read_structure) */
00067   /* atom info */
00068   int natoms;
00069   molfile_atom_t *atoms;
00070   int optflags;
00071 
00072   /* bond info */
00073   int nbonds;
00074   int *from;
00075   int *to;
00076 
00077   /* TIMESTEP DATA (used by read_next_timestep) */
00078   unsigned int timestep;
00079   /* reading mode for the next timestep */
00080   int timestep_mode;
00081   /* last timestep data */
00082   float A, B, C, alpha, beta, gamma;
00083   float *coords;
00084 } vtf_data;
00085 
00086 /* constants for timestep_mode */
00087 #define TIMESTEP_INDEXED 0
00088 #define TIMESTEP_ORDERED 1
00089 #define TIMESTEP_VCFSTART 2
00090 
00091 /* global variable: contains the line number of the file */
00092 static int vtf_lineno = 0;
00093 
00094 /* Make the atom userdata available to Tcl. */
00095 void vtf_set_atom_userdata(const int aid, const char* userdata) {
00096   static char array_index[255];
00097   if (userdata == NULL) return;
00098   sprintf(array_index, "%s.atom.%d", molid, aid);
00099   Tcl_SetVar2(tcl_interp, userdata_varname, array_index, userdata, 0);
00100 }
00101 
00102 /* Make the timestep userdata available to Tcl. */
00103 void vtf_set_timestep_userdata(const unsigned int timestep,
00104                                const char* userdata) {
00105   static char array_index[255];
00106   if (userdata == NULL || strlen(userdata) == 0) return;
00107   sprintf(array_index, "%s.step%d", molid, timestep);
00108   Tcl_SetVar2(tcl_interp, userdata_varname, array_index, userdata, 0);
00109 }
00110 
00111 /* Make the coordinate userdata available to Tcl. */
00112 void vtf_set_coordinate_userdata(const unsigned int timestep, 
00113                                  const int aid, 
00114                                  const char* userdata) {
00115   static char array_index[255];
00116   if (userdata == NULL || strlen(userdata) == 0) return;
00117   sprintf(array_index, "%s.step%d.%d", molid, timestep, aid);
00118   Tcl_SetVar2(tcl_interp, userdata_varname, array_index, userdata, 0);
00119 }
00120 
00121 /***************************************************
00122  * Print an error message.
00123  ***************************************************/
00124 static void vtf_error(const char *msg, const char *line) {
00125   char message[255];
00126   sprintf(message, "vtfplugin:%d: error: %s: \"%s\"\n",    
00127           vtf_lineno, msg, line);
00128 
00129 /* #if vmdplugin_ABIVERSION > 13 */
00130 /*   if (cons_fputs) */
00131 /*     cons_fputs(VMDCON_ERROR, message); */
00132 /*   else */
00133 /* #else */
00134   printf("%s", message);
00135 /* #endif */
00136 }
00137 
00138 /***************************************************
00139  * Free malloced memory, checking for NULL
00140  ***************************************************/
00141 static void sfree(void* ptr) {
00142   if (ptr != NULL) free(ptr);
00143 }
00144 
00145 /***************************************************
00146  * Read a line
00147  ***************************************************/
00148 
00149 /* Read a whole line from the file. 
00150    The line may have arbitrary length and continuation lines ending
00151    with '\' are heeded.
00152    The function will return a pointer to a buffer or NULL if an
00153    error occured or eof occurs while no characters have been read.
00154    The function will set the global variable lineno.
00155 */
00156 static char *vtf_getline(VTFFILE file) {
00157   static char *buffer = NULL;
00158   static int buffer_size = 0;
00159   char *s;   /* pointer to the place where the line will be read to */
00160   int bytes_left;              /* the number of bytes that are left */
00161   int l;
00162 
00163   if (buffer == NULL) {
00164     buffer_size = 255;
00165     buffer = malloc(buffer_size);
00166     /* TODO: error handling */
00167   }
00168 
00169   /* Point s to the beginning of buffer. */
00170   s = buffer;
00171   bytes_left = buffer_size;
00172 
00173   if (feof(file)) {
00174     sfree(buffer);
00175     buffer = NULL;
00176     return NULL;
00177   }
00178   do {
00179     /* read a line */
00180     if (fgets(s, bytes_left, file) == NULL) {
00181       sfree(buffer);
00182       buffer = NULL;
00183       return NULL;
00184     }
00185 
00186     vtf_lineno++;
00187 
00188     /* if we reached eof, finish */
00189     if (feof(file)) break;
00190 
00191     /* pos of the last char */
00192     l = strlen(s) - 1;
00193     if (l >= 0 && ( s[l] == '\n' || s[l] == '\r')) {
00194       l--;
00195       /* remove all line endings */
00196       while (l >= 0 && (s[l] == '\n' || s[l] == '\r')) l--;
00197       /* overwrite the first line ending char */
00198       s[l+1] = '\0';
00199       /* check the previous char, whether it is '\' */
00200       if (l >= 0 && s[l] == '\\') {
00201         /* last char before is continuation char */
00202         /* position s to the continuation char */
00203         bytes_left -= l+1;
00204         s += l+1;
00205       } else 
00206         /* otherwise, the line is complete */
00207         break;
00208     } else {
00209       /* last char is not a newline */
00210       /* enlarge the buffer */
00211       buffer_size += 255;
00212       buffer = realloc(buffer, buffer_size);
00213       /* TODO: error handling */
00214       /* reposition s */
00215       l = strlen(buffer);
00216       s = buffer + l;
00217       bytes_left += buffer_size - l;
00218       vtf_lineno--;
00219     }
00220   } while (1);
00221 
00222   /* now check the whole string */
00223   s = buffer;
00224   
00225   /* skip all leading whitespace */
00226   while (isspace(s[0])) s++;
00227 
00228   /* ignore comment lines */
00229   if (s[0] == '#') return vtf_getline(file);
00230 
00231   l = strlen(s);
00232 
00233   /* handle empty lines */
00234   if (l == 0) {
00235     if (feof(file)) {
00236       sfree(buffer);
00237       buffer = NULL;
00238       return NULL;
00239     }
00240     else return vtf_getline(file);
00241   }
00242 
00243   return s;
00244 }
00245 
00246 /***************************************************
00247  * Parse ATOM
00248  ***************************************************/
00249 /* Create new atoms so that after the call max_aid atoms are there */
00250 static void vtf_create_atoms_as_needed(int max_aid, vtf_data *d) {
00251   /* create new atoms as needed */
00252   if (d->natoms < max_aid+1) {
00253     int aid;
00254       /* fill up with default atoms */
00255       d->atoms = realloc(d->atoms, (max_aid+1)*sizeof(molfile_atom_t));
00256       for (aid = d->natoms; aid <= max_aid; aid++)
00257         d->atoms[aid] = default_atom;
00258       d->natoms = max_aid+1;
00259     if (d->read_mode != VTF_MOLFILE) {
00260       /* fill up with default userdata */
00261       for (aid = d->natoms; aid <= max_aid; aid++)
00262         vtf_set_atom_userdata(aid, default_userdata);
00263     }
00264   }
00265 }
00266 
00267 /* Parse the aid specifier.
00268    Return an integer list of the aids that need to be modifed. The
00269    list is terminated by -1. If the list is NULL, an error occured. If
00270    the list is empty (i.e. it only contains -1), the default atom is
00271    to be modified.
00272  */
00273 static int *vtf_parse_aid_specifier(char *s, vtf_data *d) {
00274   int n;
00275   unsigned int aid, from, to, offset;
00276   unsigned int size = 0;
00277   int *aid_list = NULL;
00278 
00279   if (s[0] == 'd') {
00280     /* DEFAULT */
00281     /* if the specifier is "default", just leave the list empty! */
00282 #ifdef DEBUG
00283     printf("%s", "\tdefine default atom\n");
00284 #endif
00285   } else {
00286     /* otherwise parse the aid specifier */
00287     while (1) {
00288       from = d->natoms;
00289 
00290       if (sscanf(s, "%u:%u%n", &from, &to, &n) == 2) {
00291         /* RANGE */
00292         if (from > to) { 
00293           vtf_error("bad range specifier (from > to):", s); 
00294           sfree(aid_list);
00295           return NULL;
00296         }
00297         vtf_create_atoms_as_needed(to, d);
00298         /* add the range to the aid list */
00299         offset = size;
00300         size += to-from+1;
00301         aid_list = realloc(aid_list, size*sizeof(int));
00302         for (aid = from; aid <= to; aid++) {
00303           aid_list[offset] = aid;
00304           offset++;
00305         }
00306 
00307       } else if (sscanf(s, "%u%n", &to, &n) == 1) {
00308         /* SINGLE AID */
00309         vtf_create_atoms_as_needed(to, d);
00310         /* add the aid to the aid_list */
00311         size += 1;
00312         aid_list = realloc(aid_list, size*sizeof(int));
00313         aid_list[size - 1] = to;
00314 
00315       } else {
00316         /* ERROR */
00317         vtf_error("bad aid specifier", s);
00318         sfree(aid_list);
00319         return NULL;
00320       }
00321 
00322       /* advance s */
00323       s += n;
00324 
00325       /* if there is no more to parse, break */
00326       if (s[0] == '\0') break;
00327 
00328       /* otherwise the next char should be a ',' */
00329       if (s[0] != ',') {
00330         vtf_error("bad aid specifier", s);
00331         sfree(aid_list);
00332         return NULL;
00333       }
00334       /* skip the ',' */
00335       s++;
00336     };
00337   }
00338 
00339   /* Terminate the list with -1 */
00340   aid_list = realloc(aid_list, (size+1)*sizeof(int));
00341   aid_list[size] = -1;
00342   return aid_list;
00343 }
00344 
00345 /* Parse atom data from line. 
00346    Return MOLFILE_SUCCESS, if data was sucessfully parsed, 
00347    MOLFILE_ERROR if an error occured. */
00348 static int vtf_parse_atom(char *line, vtf_data *d) {
00349   static molfile_atom_t atom;
00350   static char keyword[255];
00351   static char msg[255];
00352   static char aid_specifier[255];
00353   int n;
00354   char *s;
00355   int rest_is_userdata;
00356   int *aid_list = NULL;
00357 
00358   atom = default_atom;
00359   s = line;
00360 
00361 #ifdef DEBUG
00362   printf("\tatom record\n");
00363   printf("line: %s\n", s);
00364 #endif
00365 
00366   /* HANDLE THE AID SPECIFIER */
00367 
00368   /* save the aid specifier */
00369   if (sscanf(s, "%255s %n", aid_specifier, &n) < 1) {
00370     vtf_error("atom specifier is missing", line);
00371     return MOLFILE_ERROR;
00372   }
00373   s += n;
00374 
00375   aid_list = vtf_parse_aid_specifier(aid_specifier, d);
00376   if (aid_list == NULL) return MOLFILE_ERROR;
00377 
00378 #ifdef DEBUG
00379   printf("Rest: %s\n", s);
00380 #endif
00381 
00382   /* A -1 in the aid_list denotes the end of the list */
00383 #define AIDLOOP(assignment)                                             \
00384   {                                                                     \
00385     int *aid_ptr;                                                       \
00386     for (aid_ptr = aid_list; *aid_ptr != -1; aid_ptr++) {               \
00387       int aid = *aid_ptr;                                               \
00388       molfile_atom_t *cur_atom = &d->atoms[aid];                        \
00389       assignment;                                                       \
00390     }                                                                   \
00391   }
00392   
00393   /* handle the keywords */
00394   rest_is_userdata = 0;
00395   while (sscanf(s, "%255s %n", keyword, &n) == 1) {
00396     s += n;
00397 #ifdef DEBUG
00398     printf("keyword: %s\n", keyword);
00399 #endif
00400     switch (tolower(keyword[0])) {
00401     case 'n': {
00402       /* name */
00403       if (sscanf(s, "%16s %n", atom.name, &n) == 1) {
00404         AIDLOOP(strcpy(cur_atom->name, atom.name));
00405       } else {
00406         vtf_error("could not get name in atom record", line);
00407         return MOLFILE_ERROR;
00408       }
00409       s += n;
00410       break;
00411     }
00412     case 't': {
00413       /* type */
00414       if (sscanf(s, "%16s %n", atom.type, &n) == 1) {
00415         AIDLOOP(strcpy(cur_atom->type, atom.type));
00416       } else {
00417         vtf_error("could not get type in atom record", line);
00418         return MOLFILE_ERROR;
00419       }
00420       s += n;
00421       break;
00422     }
00423     case 'r': {
00424       /* resname, resid, radius */
00425       if (strlen(keyword) == 1 || 
00426           strncmp(keyword, "rad", 3) == 0) { 
00427         /* radius */
00428         if (sscanf(s, "%f %n", &atom.radius, &n) == 1) {
00429           AIDLOOP(cur_atom->radius = atom.radius);
00430         } else {
00431           vtf_error("could not get radius in atom record", line);
00432           sfree(aid_list);
00433           return MOLFILE_ERROR;
00434         }
00435         d->optflags |= MOLFILE_RADIUS;
00436       } else if (strcmp(keyword, "resid") == 0) {
00437         /* resid */
00438         if (sscanf(s, "%d %n", &atom.resid, &n) == 1) {
00439           AIDLOOP(cur_atom->resid = atom.resid);
00440         } else {
00441           vtf_error("could not get resid in atom record", line);
00442           sfree(aid_list);
00443           return MOLFILE_ERROR;
00444         }
00445       } else if (strcmp(keyword, "res") == 0 || 
00446                  strcmp(keyword, "resname") == 0) {
00447         /* resname */
00448         if (sscanf(s, "%8s %n", atom.resname, &n) == 1) {
00449           AIDLOOP(strcpy(cur_atom->resname, atom.resname));
00450         } else {
00451           vtf_error("could not get resname in atom record", line);
00452           sfree(aid_list);
00453           return MOLFILE_ERROR;
00454         }
00455       } else {
00456         strcpy(msg, "unrecognized keyword in atom record: ");
00457         strncat(msg, keyword, 200);
00458         vtf_error(msg, line);
00459         sfree(aid_list);
00460         return MOLFILE_ERROR;
00461       }
00462       s += n;
00463       break;
00464     }
00465     case 's': {
00466       /* segid */
00467       if (sscanf(s, "%8s %n", atom.segid, &n) == 1) {
00468         AIDLOOP(strcpy(cur_atom->segid, atom.segid));
00469       } else {
00470         vtf_error("could not get segid in atom record", line);
00471         sfree(aid_list);
00472         return MOLFILE_ERROR;
00473       }
00474       s += n;
00475       break;
00476     }
00477     case 'i': {
00478       /* insertion */
00479       if (sscanf(s, "%2s %n", atom.insertion, &n) == 1) {
00480         AIDLOOP(strcpy(cur_atom->insertion, atom.insertion));
00481       } else {
00482         vtf_error("could not get insertion in atom record", line);
00483         sfree(aid_list);
00484         return MOLFILE_ERROR;
00485       }
00486       d->optflags |= MOLFILE_INSERTION;
00487       s += n;
00488       break;
00489     }
00490     case 'c': {
00491       /* chain, charge */
00492       if (strlen(keyword) == 1 || 
00493           strcmp(keyword, "chain") == 0) {
00494         if (sscanf(s, "%2s %n", atom.chain, &n) == 1) {
00495           AIDLOOP(strcpy(cur_atom->chain, atom.chain));
00496         } else {
00497           vtf_error("could not get chain in atom record", line);
00498           sfree(aid_list);
00499           return MOLFILE_ERROR;
00500         }
00501       }
00502     } /* if "chain" is not recognized, continue with next case */
00503     case 'q': {
00504       /* q and charge */
00505       if (strlen(keyword) == 1 ||
00506           strcmp(keyword, "charge") == 0) {
00507         if (sscanf(s, "%f %n", &atom.charge, &n) == 1) {
00508           AIDLOOP(cur_atom->charge = atom.charge);
00509         } else {
00510           vtf_error("could not get charge in atom record", line);
00511           sfree(aid_list);
00512           return MOLFILE_ERROR;
00513         }
00514         d->optflags |= MOLFILE_CHARGE;
00515       } else {
00516         strcpy(msg, "unrecognized keyword in atom record: ");
00517         strncat(msg, keyword, 200);
00518         vtf_error(msg, line);
00519         sfree(aid_list);
00520         return MOLFILE_ERROR;
00521       }
00522       s += n;
00523       break;
00524     }
00525     case 'a': {
00526       /* altloc, atomicnumber */
00527       if (strlen(keyword)== 1 || 
00528           strcmp(keyword, "atomicnumber") == 0) {
00529         if (sscanf(s, "%d %n", &atom.atomicnumber, &n) == 1) {
00530           AIDLOOP(cur_atom->atomicnumber = atom.atomicnumber);
00531         } else {
00532           vtf_error("could not get atomicnumber in atom record", line);
00533           sfree(aid_list);
00534           return MOLFILE_ERROR;
00535         }
00536         d->optflags |= MOLFILE_ATOMICNUMBER;
00537       } else if (strcmp(keyword, "altloc")) {
00538         if (sscanf(s, "%2s %n", atom.altloc, &n) == 1) {
00539           AIDLOOP(strcpy(cur_atom->altloc, atom.altloc));
00540         } else {
00541           vtf_error("could not get altloc in atom record", line);
00542           sfree(aid_list);
00543           return MOLFILE_ERROR;
00544         }
00545         d->optflags |= MOLFILE_ALTLOC;
00546       } else { 
00547         strcpy(msg, "unrecognized keyword in atom record: ");
00548         strncat(msg, keyword, 200);
00549         vtf_error(msg, line);
00550           sfree(aid_list);
00551         return MOLFILE_ERROR;
00552       }
00553       s += n;
00554       break;
00555     }
00556     case 'o': {
00557       /* occupancy */
00558       if (sscanf(s, "%f %n", &atom.occupancy, &n) == 1) {
00559         AIDLOOP(cur_atom->occupancy = atom.occupancy);
00560       } else {
00561         vtf_error("could not get occupancy in atom record", line);
00562         sfree(aid_list);
00563         return MOLFILE_ERROR;
00564       }
00565       d->optflags |= MOLFILE_OCCUPANCY;
00566       s += n;
00567       break;
00568     }
00569     case 'b': {
00570       /* bfactor */
00571       if (sscanf(s, "%f %n", &atom.bfactor, &n) == 1) {
00572         AIDLOOP(cur_atom->bfactor = atom.bfactor);
00573       } else {
00574         vtf_error("could not get bfactor in atom record", line);
00575         sfree(aid_list);
00576         return MOLFILE_ERROR;
00577       }
00578       d->optflags |= MOLFILE_BFACTOR;
00579       s += n;
00580       break;
00581     }
00582     case 'm': {
00583       /* mass */
00584       if (sscanf(s, "%f %n", &atom.mass, &n) == 1) {
00585         AIDLOOP(cur_atom->mass = atom.mass);
00586       } else {
00587         vtf_error("could not get mass in atom record", line);
00588         sfree(aid_list);
00589         return MOLFILE_ERROR;
00590       }
00591       d->optflags |= MOLFILE_MASS;
00592       s += n;
00593       break;
00594     }
00595     case 'u': {
00596       /* userdata: the rest of the line is user data */
00597       rest_is_userdata = 1;
00598       if (d->read_mode != VTF_MOLFILE) {
00599         AIDLOOP(vtf_set_atom_userdata(aid, s));
00600       }
00601       break;
00602     }
00603     default: { 
00604       /* unrecognized */
00605       strcpy(msg, "unrecognized keyword in atom record: ");
00606       strncat(msg, keyword, 200);
00607       vtf_error(msg, line);
00608       sfree(aid_list);
00609       return MOLFILE_ERROR;
00610     }
00611     }
00612     if (rest_is_userdata) break;
00613   }
00614 
00615   /* if the aid_list is empty, modify the default atom */
00616   if (*aid_list == -1) {
00617       default_atom = atom;
00618       if (d->read_mode != VTF_MOLFILE) {
00619         sfree(default_userdata);
00620         default_userdata = strdup(s);
00621       }
00622   }
00623 
00624   sfree(aid_list);
00625 
00626 #ifdef DEBUG
00627   printf("\tparsed keywords\n");
00628 #endif
00629 
00630   return MOLFILE_SUCCESS;
00631 }
00632 
00633 /***************************************************
00634  * Parse BOND
00635  ***************************************************/
00636 /* Parse bond data from line.  Called by vtf_parse_structure(). Return
00637    MOLFILE_SUCCESS, if data was sucessfully parsed, MOLFILE_ERROR if
00638    an error occured. */
00639 static int vtf_parse_bond(char *line, vtf_data *d) {
00640   char *s;
00641   int n;
00642   unsigned int from, to, aid, bid;
00643 
00644   s = line;
00645 
00646   while (1) {
00647     if (sscanf(s, "%u::%u%n", &from, &to, &n) == 2) {
00648       /* chain specifier */
00649       if (from > to) {
00650         vtf_error("bad chain specifier (from > to):", s); 
00651         return MOLFILE_ERROR;
00652       }
00653       bid = d->nbonds;
00654       d->nbonds += to-from;
00655       d->from = realloc(d->from, d->nbonds*sizeof(int));
00656       d->to = realloc(d->to, d->nbonds*sizeof(int));
00657       /* TODO: error handling */
00658       for (aid = from; aid < to; aid++) {
00659         /*printf("creating bond from %d to %d\n", aid, aid+1);*/
00660         d->from[bid] = aid+1;
00661         d->to[bid] = aid+2;
00662         bid++;
00663       }
00664     } else if (sscanf(s, "%u:%u%n", &from, &to, &n) == 2) {
00665       /* single bond specifier */
00666       d->nbonds += 1;
00667       d->from = realloc(d->from, d->nbonds*sizeof(int));
00668       d->to = realloc(d->to, d->nbonds*sizeof(int));
00669       /* TODO: error handling */
00670       d->from[d->nbonds-1] = from+1;
00671       d->to[d->nbonds-1] = to+1;
00672     } else {
00673       vtf_error("bad bond specifier", s);
00674       return MOLFILE_ERROR;
00675     }
00676 
00677     s += n;
00678     
00679     /* if there is no more to parse, break */
00680     if (strlen(s) == 0) break;
00681     
00682     /* otherwise the next char should be a ',' */
00683     if (s[0] != ',') {
00684       vtf_error("bad bond specifier in line", line);
00685       return MOLFILE_ERROR;
00686     }
00687     /* skip the ',' */
00688     s++;
00689   }
00690 
00691   return MOLFILE_SUCCESS;
00692 }
00693 
00694 
00695 /***************************************************
00696  * Parse PBC
00697  ***************************************************/
00698 /* Parse periodic boundary condition data from line. Called by
00699    vtf_parse_structure().  Return MOLFILE_SUCCESS, if data was
00700    sucessfully parsed, MOLFILE_ERROR if an error occured. */
00701 static int vtf_parse_pbc(char *line, vtf_data *d) {
00702   char *s;
00703   int n;
00704 
00705   if (sscanf(line, "%f %f %f %n", 
00706     &d->A, &d->B, &d->C, &n) < 3) {
00707     s = line;
00708     vtf_error("Couldn't parse unit cell dimensions", s);
00709     return MOLFILE_ERROR;
00710   }
00711   s = line+n;
00712 
00713   n = sscanf(s, "%f %f %f", &d->alpha, &d->beta, &d->gamma);
00714   if (n > 0 && n < 3) {
00715     vtf_error("Couldn't parse unit cell angles", line);
00716     return MOLFILE_ERROR;
00717   }
00718   return MOLFILE_SUCCESS;
00719 } 
00720 
00721 /* Parse timestep command from line. Called by vtf_parse_structure().
00722    Return MOLFILE_SUCCESS, if it was sucessfully parsed, MOLFILE_ERROR
00723    if an error occured. */
00724 static int vtf_parse_timestep(char *line, vtf_data *d) {
00725   if (strlen(line) == 0) {
00726     d->timestep_mode = TIMESTEP_ORDERED;
00727   } else {
00728     switch (tolower(line[0])) {
00729     case 'o': { d->timestep_mode = TIMESTEP_ORDERED; break; }
00730     case 'i': { d->timestep_mode = TIMESTEP_INDEXED; break; }
00731     default: {
00732       vtf_error("bad timestep line", line);
00733       return MOLFILE_ERROR;
00734     }
00735     }
00736   }
00737   return MOLFILE_SUCCESS;
00738 }
00739 
00740 /* Called by _vtf_open_file_read() to parse the structure data. */
00741 static void vtf_parse_structure(vtf_data *d) {
00742   char *line;                   /* next line in the file */
00743   char s[255];
00744   int n;
00745   
00746   /* initialize the default atom */
00747   strcpy(default_atom.name, "X");
00748   strcpy(default_atom.type, "X");
00749   strcpy(default_atom.resname, "X");
00750   default_atom.resid = 0;
00751   strcpy(default_atom.segid, "");
00752   strcpy(default_atom.chain, "");
00753 
00754   strcpy(default_atom.altloc, "");
00755   strcpy(default_atom.insertion, "");
00756   default_atom.occupancy = 1.0;
00757   default_atom.bfactor = 1.0;
00758   default_atom.mass = 1.0;
00759   default_atom.charge = 0.0;
00760   default_atom.radius = 1.0;
00761 
00762   default_userdata = NULL;
00763 
00764   do {
00765     line = vtf_getline(d->file);
00766     if (line == NULL) break;
00767 #ifdef DEBUG
00768     printf("parsing line %d: \"%s\"\n", vtf_lineno, line);
00769 #endif
00770     switch (tolower(line[0])) {
00771       /* ATOM RECORD */
00772     case 'a': {
00773       /* Remove the "atom" keyword" */
00774       sscanf(line, "%255s %n", s, &n);
00775       line += n;
00776     }
00777     case '0':
00778     case '1':
00779     case '2':
00780     case '3':
00781     case '4':
00782     case '5':
00783     case '6':
00784     case '7':
00785     case '8':
00786     case '9':   
00787     case 'd': { 
00788       /* parse atom */
00789       d->return_code = vtf_parse_atom(line, d);
00790       break; 
00791     }
00792 
00793       /* BOND RECORD */
00794     case 'b': {
00795       /* Remove the "bond" keyword" */
00796       sscanf(line, "%255s %n", s, &n);
00797       line += n;
00798       d->return_code = vtf_parse_bond(line, d);
00799       break;
00800     }
00801 
00802       /* PBC/UNITCELL RECORD */
00803     case 'u':
00804     case 'p': {
00805       /* Remove the "pbc"/"unitcell" keyword */
00806       sscanf(line, "%255s %n", s, &n);
00807       line += n;
00808       d->return_code = vtf_parse_pbc(line, d);
00809       break;
00810     }
00811 
00812       /* TIMESTEP RECORD*/
00813     case 'c': 
00814     case 't': {
00815       /* Remove the "timestep" or "coordinates" keyword */
00816       sscanf(line, "%255s %n", s, &n);
00817       line += n;
00818     }
00819     case 'i': 
00820     case 'o': { 
00821       d->return_code = vtf_parse_timestep(line, d);
00822       line = NULL; /* indicate the end of the structure block */
00823       break; 
00824     }
00825 
00826       /* UNKNOWN RECORD */
00827     default: {
00828       vtf_error("unknown line type", line);
00829       d->return_code = MOLFILE_ERROR;
00830       break;
00831     }
00832     }
00833   } while (line != NULL && 
00834            d->return_code == MOLFILE_SUCCESS);
00835 
00836   /* test if structure data was parsed */
00837   if (d->read_mode == VTF_MOLFILE &&
00838       d->atoms == NULL && 
00839       d->return_code == MOLFILE_SUCCESS) {
00840     d->return_code = MOLFILE_NOSTRUCTUREDATA;
00841   }
00842 
00843   /* test whether another error has occured */
00844   if (errno != 0) {
00845     perror("vtfplugin");
00846     d->return_code = MOLFILE_ERROR;
00847   }
00848 
00849   sfree(default_userdata);
00850 }
00851 
00852 /***************************************************
00853  * Open file and parse structure info
00854  ***************************************************/
00855 /* Opens the file for reading.  To determine the number of atoms in
00856    the file, it is necessary to parse the structure information,
00857    anyway. Therefore, this function will parse the structure data and
00858    save the information in the plugin's data structure.
00859 
00860    The read_mode defines whether the file is read from VMD via the
00861    plugin API (VTF_MOLFILE) to read structure and timestep data, or
00862    via the vtftools to read userdata (VTF_USERDATA).
00863 
00864    The function vtf_open_file_read() that is actually called by the
00865    molfile reader plugin is defined below this function.
00866 */
00867 static vtf_data *
00868 _vtf_open_file_read(const char *filepath, 
00869                     const char *filetype, 
00870                     int *natoms,
00871                     int read_mode) {
00872   vtf_data *d;
00873 
00874   /* printf("Loading file %s\n  of type %s using vtfplugin v%i.%i.\n",
00875      filepath, filetype, VERSION_MAJOR, VERSION_MINOR); */
00876 
00877   /* initialize the data structure */
00878   d = malloc(sizeof(vtf_data));
00879   
00880   errno = 0;
00881 
00882   d->return_code = MOLFILE_SUCCESS;
00883   d->read_mode = read_mode;
00884 
00885   /* initialize structure data */
00886   d->optflags = MOLFILE_NOOPTIONS;
00887   d->natoms = 0;
00888   d->atoms = NULL;
00889   d->nbonds = 0;
00890   d->from = NULL;
00891   d->to = NULL;
00892 
00893   /* initialize timestep data */
00894   d->timestep = 0;
00895   d->timestep_mode = TIMESTEP_ORDERED;
00896   d->coords = NULL;
00897   d->A = 0.0;
00898   d->B = 0.0;
00899   d->C = 0.0;
00900   d->alpha = 90.0;
00901   d->beta = 90.0;
00902   d->gamma = 90.0;
00903 
00904   /* Open the file */
00905   d->file = fopen(filepath, "r");
00906   if (d->file == NULL) {
00907     /* Could not open file */
00908     char msg[255];
00909     sprintf(msg, "vtfplugin: %s", filepath);
00910     perror(msg);
00911     sfree(d);
00912     return NULL;
00913   }
00914 
00915   if (strcmp(filetype, "vcf") == 0) {
00916     d->timestep_mode = TIMESTEP_VCFSTART;
00917     d->natoms = MOLFILE_NUMATOMS_UNKNOWN;
00918     *natoms = MOLFILE_NUMATOMS_UNKNOWN;
00919     d->return_code = MOLFILE_NOSTRUCTUREDATA;
00920   } else {
00921     vtf_parse_structure(d);
00922     
00923     if (d->return_code != MOLFILE_SUCCESS) {
00924       /* close the file */
00925       fclose(d->file);
00926 
00927       /* free the data */
00928       sfree(d->atoms);
00929       sfree(d->coords);
00930       sfree(d->from);
00931       sfree(d->to);
00932       sfree(d);
00933       return NULL;
00934     }
00935    
00936     *natoms = d->natoms;
00937   }
00938 
00939   return d;
00940 }
00941 
00942 /* This is the function actually called by the molfile reader plugin */
00943 static void *
00944 vtf_open_file_read(const char *filepath, 
00945                    const char *filetype, 
00946                    int *natoms) {
00947   return _vtf_open_file_read(filepath, filetype, natoms, VTF_MOLFILE);
00948 }
00949 
00950 /* */
00951 static void vtf_close_file_read(void *data) {
00952   vtf_data *d;
00953 
00954   if (data == NULL) return;
00955   d = (vtf_data*)data;
00956 
00957   /* printf("Finished reading file.\n"); */
00958 
00959   /* close the file */
00960   fclose(d->file);
00961 
00962   /* free the data */
00963   sfree(d->coords);
00964   sfree(d->from);
00965   sfree(d->to);
00966   sfree(d);
00967 }
00968 
00969 /* Read the next timestep from the file and store what has been read
00970    into the ts datastructure. */
00971 static int vtf_read_next_timestep(void *data, 
00972                                   int natoms, 
00973                                   molfile_timestep_t *ts) {
00974   vtf_data *d;
00975   char *line;
00976   static char s[255];
00977   float x,y,z;
00978   unsigned int aid;
00979   int n;
00980 
00981   if (data == NULL) {
00982     vtf_error("Internal error: data==NULL in vtf_read_next_timestep", 0);
00983     return MOLFILE_ERROR;
00984   }
00985 
00986   if (natoms <= 0) {
00987     vtf_error("Internal error: natoms <= 0 in vtf_read_next_timestep", 0);
00988     return MOLFILE_ERROR;
00989   }
00990 
00991   errno = 0;
00992 
00993   d = (vtf_data*)data;
00994 
00995   aid = 0;
00996 
00997   if (feof(d->file)) return MOLFILE_EOF;
00998 
00999   if (d->coords == NULL) {
01000     /* initialize coords */
01001     d->coords = malloc(natoms*3*sizeof(float));
01002     /* TODO: error handling */
01003     for (n = 0; n < natoms*3; n++)
01004       d->coords[n] = 0.0;
01005   } 
01006   
01007   /* read in the data, until the next timestep or EOF is reached */
01008   do {
01009     line = vtf_getline(d->file);
01010 
01011     if (line == NULL) {
01012       if (errno != 0) {
01013         perror("vtfplugin");
01014         return MOLFILE_ERROR;
01015       }
01016       break;
01017     } 
01018 
01019     /* At the beginning of a vcf file, skip a timestep line */
01020     if (d->timestep_mode == TIMESTEP_VCFSTART) {
01021       switch (tolower(line[0])) {
01022       case 'c': 
01023       case 't':
01024         /* Remove the "timestep" or "coordinates" keyword */
01025         sscanf(line, "%255s %n", s, &n);
01026         line += n;
01027       case 'i': 
01028       case 'o': 
01029         if (vtf_parse_timestep(line, d) != MOLFILE_SUCCESS)
01030           return MOLFILE_ERROR;
01031         line = vtf_getline(d->file);
01032         break;
01033       default:
01034         /* if this is already a coordinate line, expect an ordered block */
01035         d->timestep_mode = TIMESTEP_ORDERED;
01036       }
01037     }
01038 
01039     /* parse timestep data */
01040     if (d->timestep_mode == TIMESTEP_ORDERED 
01041         && sscanf(line, " %f %f %f %n", &x, &y, &z, &n) == 3) {
01042       if (aid < natoms) {
01043         d->coords[aid*3] = x;
01044         d->coords[aid*3+1] = y;
01045         d->coords[aid*3+2] = z;
01046         if (d->read_mode == VTF_USERDATA) {
01047           /* the rest of the line is userdata */
01048           line += n;
01049           vtf_set_coordinate_userdata(d->timestep, aid, line);
01050         }
01051         aid++;
01052       } else {
01053         vtf_error("too many atom coordinates in ordered timestep block", line);
01054         return MOLFILE_ERROR;
01055       }
01056     } else if (d->timestep_mode == TIMESTEP_INDEXED 
01057                && sscanf(line, " %u %f %f %f %n", 
01058                          &aid, &x, &y, &z, &n) == 4) {
01059       if (aid < natoms) {
01060         d->coords[aid*3] = x;
01061         d->coords[aid*3+1] = y;
01062         d->coords[aid*3+2] = z;
01063         if (d->read_mode == VTF_USERDATA) {
01064           /* the rest of the line is userdata */
01065           line += n;
01066           vtf_set_coordinate_userdata(d->timestep, aid, line);
01067         }
01068       } else {
01069         vtf_error("atom id too large in indexed timestep block", line);
01070         return MOLFILE_ERROR;
01071       }
01072     } else switch (tolower(line[0])) {
01073         /* PBC/UNITCELL RECORD */
01074       case 'u':
01075       case 'p': {
01076         /* Remove the "pbc"/"unitcell" keyword */
01077         sscanf(line, "%255s %n", s, &n);
01078         line += n;
01079         if (vtf_parse_pbc(line, d) != MOLFILE_SUCCESS) 
01080           return MOLFILE_ERROR;
01081         break;
01082       }
01083 
01084         /* USER DATA RECORD */
01085       case 'd': {
01086         /* Remove the "data" keyword */
01087         sscanf(line, "%255s %n", s, &n);
01088         if (d->read_mode == VTF_USERDATA) {
01089           line += n;
01090           vtf_set_timestep_userdata(d->timestep, line);
01091         }
01092         break;
01093       }
01094         
01095         /* TIMESTEP RECORD */
01096       case 'c': 
01097       case 't': {
01098         /* Remove the "timestep" or "coordinates" keyword */
01099         sscanf(line, "%255s %n", s, &n);
01100         line += n;
01101       }
01102       case 'i': 
01103       case 'o': { 
01104         if (vtf_parse_timestep(line, d) != MOLFILE_SUCCESS)
01105           return MOLFILE_ERROR;
01106         line = NULL; /* indicate end of this timestep */
01107         d->timestep++;
01108         break;
01109       }
01110         
01111       default: { 
01112         if (d->timestep_mode == TIMESTEP_INDEXED)
01113           vtf_error("unknown line in indexed timestep block", line);
01114         else
01115           vtf_error("unknown line in ordered timestep block", line);
01116         return MOLFILE_ERROR;
01117       }
01118       }
01119 
01120     if (line == NULL) break;
01121   } while (1);
01122 
01123   if (ts != NULL) {
01124     /* copy the ts data */
01125     ts->A = d->A;
01126     ts->B = d->B;
01127     ts->C = d->C;
01128     ts->alpha = d->alpha;
01129     ts->beta = d->beta;
01130     ts->gamma = d->gamma;
01131     memcpy(ts->coords, d->coords, natoms*3*sizeof(float));
01132     ts->velocities = NULL;
01133     ts->physical_time = 0.0;
01134   }
01135 
01136   return MOLFILE_SUCCESS;
01137 }
01138 
01139 /***************************************************
01140  * Copy the info collected in vtf_open_file_read
01141  ***************************************************/
01142 static int vtf_read_structure(void *data, 
01143                               int *optflags, 
01144                               molfile_atom_t *atoms) {
01145   vtf_data *d;
01146   d = (vtf_data*)data;
01147 
01148   if (d->return_code != MOLFILE_SUCCESS) 
01149     return d->return_code;
01150 
01151   if (d->natoms > 0) {
01152     /* copy the data parsed in vtf_open_file_read() */
01153     memcpy(atoms, d->atoms, d->natoms*sizeof(molfile_atom_t));
01154     /* free the data parsed in vtf_open_file_read() */
01155     sfree(d->atoms);
01156     d->atoms = NULL;
01157   }
01158 
01159   *optflags = d->optflags;
01160 
01161   return MOLFILE_SUCCESS;
01162 }
01163 
01164 static int vtf_read_bonds(void *data, 
01165                           int *nbonds, 
01166                           int **from, 
01167                           int **to,
01168                           float **bondorder, 
01169                           int **bondtype, 
01170                           int *nbondtypes, 
01171                           char ***bondtypename) {
01172   vtf_data *d;
01173   if (!data) {
01174     vtf_error("Internal error: data==NULL in vtf_read_bonds", 0);
01175     return MOLFILE_ERROR;
01176   }
01177 
01178   d = (vtf_data*)data;
01179 
01180   *nbonds = d->nbonds;
01181   *from = d->from;
01182   *to = d->to;
01183   *bondorder = NULL;
01184   *bondtype = NULL;
01185   *nbondtypes = 0;
01186   *bondtypename = NULL;
01187 
01188   return MOLFILE_SUCCESS;
01189 }
01190 
01191 /***************************************************/
01192 /* MOLFILE READER PLUGIN PART */
01193 /***************************************************/
01194 static molfile_plugin_t vsfplugin;
01195 static molfile_plugin_t vtfplugin;
01196 static molfile_plugin_t vcfplugin;
01197 
01198 VMDPLUGIN_API int VMDPLUGIN_init() {
01199   memset(&vsfplugin, 0, sizeof(molfile_plugin_t));
01200   vsfplugin.abiversion = vmdplugin_ABIVERSION;
01201   vsfplugin.type = MOLFILE_PLUGIN_TYPE;
01202   vsfplugin.name = "vsf";
01203   vsfplugin.author = "Olaf Lenz";
01204   vsfplugin.majorv = VERSION_MAJOR;
01205   vsfplugin.minorv = VERSION_MINOR;
01206   vsfplugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
01207   vsfplugin.filename_extension = "vsf";
01208   vsfplugin.open_file_read = vtf_open_file_read;
01209   vsfplugin.read_structure = vtf_read_structure;
01210   vsfplugin.read_bonds = vtf_read_bonds;
01211   /* plugin.read_next_timestep = vtf_read_next_timestep; */
01212   vsfplugin.close_file_read = vtf_close_file_read;
01213 #if vmdplugin_ABIVERSION >= 9
01214   vsfplugin.prettyname = "VTF structure format";
01215 #endif
01216 
01217   memset(&vcfplugin, 0, sizeof(molfile_plugin_t));
01218   vcfplugin.abiversion = vmdplugin_ABIVERSION;
01219   vcfplugin.type = MOLFILE_PLUGIN_TYPE;
01220   vcfplugin.name = "vcf";
01221   vcfplugin.author = "Olaf Lenz";
01222   vcfplugin.majorv = VERSION_MAJOR;
01223   vcfplugin.minorv = VERSION_MINOR;
01224   vcfplugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
01225   vcfplugin.filename_extension = "vcf";
01226   vcfplugin.open_file_read = vtf_open_file_read;
01227   vcfplugin.read_next_timestep = vtf_read_next_timestep;
01228   vcfplugin.close_file_read = vtf_close_file_read;
01229 #if vmdplugin_ABIVERSION >= 9
01230   vcfplugin.prettyname = "VTF coordinate format";
01231 #endif
01232 
01233   memset(&vtfplugin, 0, sizeof(molfile_plugin_t));
01234   vtfplugin.abiversion = vmdplugin_ABIVERSION;
01235   vtfplugin.type = MOLFILE_PLUGIN_TYPE;
01236   vtfplugin.name = "vtf";
01237   vtfplugin.author = "Olaf Lenz";
01238   vtfplugin.majorv = VERSION_MAJOR;
01239   vtfplugin.minorv = VERSION_MINOR;
01240   vtfplugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
01241   vtfplugin.filename_extension = "vtf";
01242   vtfplugin.open_file_read = vtf_open_file_read;
01243   vtfplugin.read_structure = vtf_read_structure;
01244   vtfplugin.read_bonds = vtf_read_bonds;
01245   vtfplugin.read_next_timestep = vtf_read_next_timestep;
01246   vtfplugin.close_file_read = vtf_close_file_read;
01247 #if vmdplugin_ABIVERSION >= 9
01248   vtfplugin.prettyname = "VTF trajectory format";
01249 #endif
01250 
01251   /*printf("Loaded VTF/VSF/VCF plugins v%i.%i.\n", VERSION_MAJOR, VERSION_MINOR); */
01252 
01253   return VMDPLUGIN_SUCCESS;
01254 }
01255 
01256 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
01257   (*cb)(v, (vmdplugin_t *)&vsfplugin);
01258   (*cb)(v, (vmdplugin_t *)&vcfplugin);
01259   (*cb)(v, (vmdplugin_t *)&vtfplugin);
01260   return VMDPLUGIN_SUCCESS;
01261 }
01262 
01263 VMDPLUGIN_API int VMDPLUGIN_fini() {
01264   return VMDPLUGIN_SUCCESS;
01265 }
01266 
01267 /***************************************************/
01268 /* VTFTOOLS USERDATA PART */
01269 /***************************************************/
01270 static int vtf_parse_userdata(ClientData clientData, 
01271                               Tcl_Interp *interp, 
01272                               int argc, 
01273                               const char *argv[]) {
01274   /* Usage: vtf_parse_userdata path type */
01275   int natoms;
01276   const char *file, *type;
01277   vtf_data *d;
01278   char result[255];
01279   int rc;
01280 
01281   if (argc != 5) {
01282     sprintf(result, "wrong # args: should be \"%s fileName fileType varName molId\"", argv[0]);
01283     Tcl_SetResult(interp, result, TCL_VOLATILE);
01284     return TCL_ERROR;
01285   }
01286 
01287   file = argv[1];
01288   type = argv[2];
01289   userdata_varname = argv[3];
01290   molid = argv[4];
01291   tcl_interp = interp;
01292   
01293   d = _vtf_open_file_read(file, type, &natoms, VTF_USERDATA);
01294   if (d == NULL) {
01295     sprintf(result, "%s: an error occured while reading the structure", argv[0]);
01296     Tcl_SetResult(interp, result, TCL_VOLATILE);
01297     return TCL_ERROR;
01298   }
01299   
01300   do {
01301     rc = vtf_read_next_timestep(d, d->natoms, NULL);
01302   } while (rc == MOLFILE_SUCCESS);
01303 
01304   sprintf(result, "%s: Read %d atoms and %d timesteps.", 
01305           argv[0], d->natoms, d->timestep);
01306   Tcl_SetResult(interp, result, TCL_VOLATILE);
01307   vtf_close_file_read(d);
01308   return TCL_OK;
01309 }
01310 
01311 int Vtfplugin_Init(Tcl_Interp *interp) {
01312   char version_string[20];
01313 
01314   /* Set up for stubs. */
01315   if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
01316     Tcl_SetResult(interp, "Tcl_InitStubs failed", TCL_STATIC);
01317     return TCL_ERROR;
01318   }
01319 
01320   sprintf(version_string, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
01321   if (Tcl_PkgProvide(interp, "vtfplugin", version_string) == TCL_ERROR) {
01322     return TCL_ERROR;
01323   }
01324 
01325   /* Create the Tcl command. */
01326   Tcl_CreateCommand(interp, 
01327                     "vtf_parse_userdata", vtf_parse_userdata, 
01328                     NULL, NULL);
01329   return TCL_OK;
01330 }

Generated on Sun May 19 02:07:59 2013 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002