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

Generated on Thu Mar 28 03:08:21 2024 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002