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

corplugin.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2006 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: corplugin.c,v $
00013  *      $Author: johns $       $Locker:  $             $State: Exp $
00014  *      $Revision: 1.26 $       $Date: 2006/02/23 19:36:44 $
00015  *
00016  ***************************************************************************/
00017 
00018 /*
00019  * This plugin reads molecular coordinate data stored in 
00020  * CHARMM Cartesian Coordinate format (ascii text format, not binary).
00021  *    http://www.charmm.org/
00022  *    http://brooks.scripps.edu/charmm_docs/TSRI_docs-list.htm
00023  */
00024 
00025 #include "molfile_plugin.h"
00026 
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 
00031 #define COR_RECORD_LENGTH   141 /* 80 */
00032 
00033 /* Remove leading and trailing whitespace from the string str of size n */
00034 static void strip_whitespace(char *str, int n) {
00035   char *beg, *end;
00036 
00037   beg = str;
00038   end = str + (n-2); /* Point to the last non-null character in the string */
00039 
00040   /* Remove leading whitespace */
00041   while(beg <= end && *beg == ' ') {
00042     beg++;
00043   }
00044 
00045   /* Remove trailing whitespace */
00046   while(end >= str && *end == ' ') {
00047     end--;
00048   }
00049 
00050   if (beg < end) {
00051     /* Shift the string */
00052     *(end+1) = '\0';
00053     memmove(str, beg, (end - beg + 2));
00054   } else {
00055     str[0] = '\0';
00056   }
00057 
00058   return;
00059 }
00060 
00061 /* Get a string from a stream, printing any errors that occur */
00062 static char *corgets(char *s, int n, FILE *stream) {
00063   char *returnVal;
00064 
00065   if (feof(stream)) {
00066     printf("corplugin) Unexpected end-of-file.\n");
00067     returnVal = NULL;
00068   } else if (ferror(stream)) {
00069     printf("corplugin) Error reading file.\n");
00070     return NULL;
00071   } else {
00072     returnVal = fgets(s, n, stream);
00073     if (returnVal == NULL) {
00074       printf("corplugin) Error reading line.\n");
00075     }
00076   }
00077 
00078   return returnVal;
00079 }
00080 
00081 
00082 /* Open the .cor file and skip past the remarks to the first data section.
00083  * Returns the file pointer, or NULL if error.  Also puts the number of
00084  * atoms in the molecule into the given integer.  
00085  */
00086 static FILE *open_cor_file(const char *fname, int *natom, int *iofoext) {
00087   char inbuf[COR_RECORD_LENGTH+2], header[11];
00088   FILE *f;
00089 
00090   *natom = MOLFILE_NUMATOMS_NONE;
00091 
00092   if (!fname) {
00093     printf("corplugin) Error opening file: no filename given.\n");
00094     return NULL;
00095   }
00096 
00097   if ((f = fopen(fname, "r")) == NULL) {
00098     printf("corplugin) Error opening file.\n");
00099     return NULL;
00100   }
00101 
00102   /* Read and discard the header */
00103   do {
00104     if (fgets(inbuf, COR_RECORD_LENGTH+1, f) == NULL) {
00105       fclose(f);
00106       printf("corplugin) Error opening file: cannot read line.\n");
00107       return NULL;
00108     }
00109 
00110     if (sscanf(inbuf, "%10c", header) != 1) {
00111       fclose(f);
00112       printf("corplugin) Error opening file: improperly formatted line.\n");
00113       return NULL;
00114     }
00115 
00116   } while (header[0]=='*');
00117 
00118   /* check for EXT keyword */
00119   *iofoext = 0 ;
00120   if (strstr(inbuf,"EXT") != NULL) 
00121     *iofoext = 1;
00122 
00123   /* check atom count */
00124   header[10] = '\0';
00125   *natom = atoi(header);
00126   if (*natom > 99999) 
00127     *iofoext = 1;
00128 
00129   if (*iofoext == 1)
00130     printf("corplugin) Using EXTended CHARMM coordinates file\n");
00131 
00132   return f;
00133 }
00134 
00135 /* Read in the next atom info into the given storage areas; this assumes
00136    that file has already been moved to the beginning of the atom records.
00137    Returns the serial number of the atom. If there is an error, returns -1.*/
00138 static int get_cor_atom(FILE *f, char *atomName, char *atomType, char
00139     *resName, char *segName, int *resId, int ioext) {
00140   char inbuf[COR_RECORD_LENGTH+2], numAtomStr[11], resNStr[11], resIdStr[11];
00141   char atomNameStr[11], segNameStr[11], resNameStr[11];
00142   int numAtom;
00143 
00144   if (corgets(inbuf, COR_RECORD_LENGTH+1, f) == NULL) {
00145     return -1;
00146   }
00147 
00148   if (strlen(inbuf) < 60) {
00149     printf("corplugin) Line too short: \n%s\n", inbuf);
00150     return -1;
00151   }
00152 
00153   memset(numAtomStr, 0, sizeof(numAtomStr));
00154   memset(resNStr, 0, sizeof(resNStr));
00155   memset(resIdStr, 0, sizeof(resIdStr));
00156   memset(resNameStr, 0, sizeof(resNameStr));
00157   memset(segNameStr, 0, sizeof(segNameStr));
00158   memset(atomNameStr, 0, sizeof(atomNameStr));
00159 
00160   /*
00161 
00162     CHARMM has a variety of input formats for the
00163        read coor card
00164     command. In order to support all of them the simplest would be to replace 
00165 
00166     if (sscanf(inbuf, "%5c%5c%5c%5c%*10c%*10c%*10c%5c", 
00167 
00168     with
00169 
00170     if (sscanf(inbuf, "%s %s %s %s %*s %*s %*s %s", 
00171 
00172     However this solution has 2 problems:
00173      1. buffer overruns
00174      2. it doesn't handle the cases where X,Y,Z values have no spaces in-between
00175 
00176     In this fix we handle only two most important cases, depending on
00177      the value of IOFOrmat command (either EXTEnded or NOEXtended):
00178      EXT:    2I10,2X,A8,2X,A8,3F20.10,2X,A8,2X,A8,F20.10
00179      NOEXT:  2I5,1X,A4,1X,A4,3F10.5,1X,A4,1X,A4,F10.5
00180 
00181     This implementation introduces new flag iofoext in cordata
00182     structure, which can choose between the 2 formats. Note that
00183     CHARMM adds EXT keyword in the coordinate and psf files in the
00184     case of IOFO EXTE command in the input script, or automatically
00185     when there are 100,000 or more atoms in the system!
00186 
00187   */
00188 
00189   if (ioext == 1 ) {
00190     if (sscanf(inbuf, "%10c%10c%10c%10c%*20c%*20c%*20c%10c%10c",
00191                numAtomStr, resNStr, resNameStr, atomNameStr, segNameStr, resIdStr) != 6) {
00192       printf("corplugin) Improperly formatted line: \n%s\n", inbuf);
00193       return -1;
00194     }
00195     strip_whitespace(resName, sizeof(resName));  // strip from long original
00196     strip_whitespace(atomName, sizeof(atomName));
00197     strip_whitespace(segName, sizeof(segName));
00198     memcpy(resName, resNameStr, 7);              // XXX truncate extra chars
00199     memcpy(atomName, atomNameStr, 7);
00200     memcpy(segName, segNameStr, 7);
00201     resName[7] = '\0';                           // NUL terminate strings..
00202     atomName[7] = '\0';
00203     segName[7] = '\0';
00204   } else {
00205     if (sscanf(inbuf, "%5c%5c%5c%5c%*10c%*10c%*10c%5c%5c",
00206                numAtomStr, resNStr, resName, atomName, segName, resIdStr) != 6) {
00207       printf("corplugin) Improperly formatted line: \n%s\n", inbuf);
00208       return -1;
00209     }
00210     strip_whitespace(resName, 8);
00211     strip_whitespace(atomName, 8);
00212     strip_whitespace(segName, 8);
00213   }
00214 
00215   numAtom = atoi(numAtomStr);
00216   *resId = atoi(resIdStr);
00217   strcpy(atomType, atomName);
00218 
00219   return numAtom;
00220 }
00221 
00222 
00223 /*
00224  * API functions
00225  */
00226 
00227 typedef struct {
00228   FILE *file;
00229   int numatoms;
00230   int iofoext;      /* flag for extended CHARMM c31 version support */
00231 } cordata;
00232 
00233 static void *open_cor_read(const char *path, const char *filetype, 
00234     int *natoms) {
00235   int ioext ;
00236   FILE *fd;
00237   cordata *cor;
00238 
00239   if (!(fd = open_cor_file(path, natoms, &ioext))) {
00240     return NULL;
00241   } 
00242   cor = (cordata *) malloc(sizeof(cordata));
00243   memset(cor, 0, sizeof(cordata));
00244   cor->numatoms = *natoms;
00245   cor->file = fd;
00246   cor->iofoext = ioext ;
00247   return cor;
00248 }
00249 
00250 static int read_cor_structure(void *v, int *optflags, molfile_atom_t *atoms) {
00251   cordata *data = (cordata *)v;
00252   int i;
00253   
00254   /* we don't read any optional data */
00255   *optflags = MOLFILE_NOOPTIONS;
00256 
00257   for (i=0; i<data->numatoms; i++) {
00258     molfile_atom_t *atom = atoms+i; 
00259     if (get_cor_atom(data->file, atom->name, atom->type, 
00260                      atom->resname, atom->segid, 
00261                      &atom->resid, data->iofoext) < 0) {
00262       printf("corplugin) couldn't read atom %d\n", i);
00263       return MOLFILE_ERROR;
00264     }
00265     atom->chain[0] = atom->segid[0];
00266     atom->chain[1] = '\0';
00267   }
00268 
00269   rewind(data->file);
00270   return MOLFILE_SUCCESS;
00271 }
00272 
00273 static int read_cor_timestep(void *v, int natoms, molfile_timestep_t *ts) {
00274   cordata *cor = (cordata *)v;
00275   char inbuf[COR_RECORD_LENGTH+2], header[6];
00276   char xStr[21], yStr[21], zStr[21];
00277   int i;
00278 
00279   xStr[20] = '\0';
00280   yStr[20] = '\0';
00281   zStr[20] = '\0';
00282 
00283   /* Skip the header */
00284   do {
00285     /* Return -1 on EOF */
00286     if (feof(cor->file) || ferror(cor->file) || 
00287         (fgets(inbuf, COR_RECORD_LENGTH+1, cor->file) == NULL)) {
00288       return MOLFILE_ERROR;
00289     }
00290 
00291     if (sscanf(inbuf, " %5c", header) != 1) {
00292       printf("corplugin) Improperly formatted line.\n");
00293       return MOLFILE_ERROR;
00294     }
00295 
00296   } while (header[0]=='*');
00297 
00298 
00299   /* read the coordinates */
00300   for (i = 0; i < natoms; i++) {
00301     if (corgets(inbuf, COR_RECORD_LENGTH+1, cor->file) == NULL) {
00302       return MOLFILE_ERROR;
00303     }
00304     
00305     if (cor->iofoext == 1 ) {
00306       if (sscanf(inbuf, "%*10c%*10c%*10c%*10c%20c%20c%20c%*10c", 
00307                  xStr, yStr, zStr) != 3) {
00308         printf("corplugin) Error reading coordinates on line %d.\n%s\n", i, inbuf);
00309         return MOLFILE_ERROR;
00310       } else if (ts != NULL) {
00311         /* We have a timestep -- save the coordinates */
00312         ts->coords[3*i  ] = atof(xStr);
00313         ts->coords[3*i+1] = atof(yStr);
00314         ts->coords[3*i+2] = atof(zStr);
00315       }
00316     } else {
00317       if (sscanf(inbuf, "%*5c%*5c%*5c%*5c%10c%10c%10c%*5c", 
00318                  xStr, yStr, zStr) != 3) {
00319         printf("corplugin) Error reading coordinates on line %d.\n%s\n", i, inbuf);
00320         return MOLFILE_ERROR;
00321       } else if (ts != NULL) {
00322         /* We have a timestep -- save the coordinates */
00323         ts->coords[3*i  ] = atof(xStr);
00324         ts->coords[3*i+1] = atof(yStr);
00325         ts->coords[3*i+2] = atof(zStr);
00326       }
00327     }
00328   }
00329 
00330   return MOLFILE_SUCCESS;
00331 }
00332 
00333 static void close_cor_read(void *mydata) {
00334   cordata *data = (cordata *)mydata;
00335   if (data) {
00336     if (data->file) fclose(data->file);
00337     free(data);
00338   }
00339 }  
00340 
00341 /*
00342  * Initialization stuff down here
00343  */
00344 
00345 static molfile_plugin_t plugin = {
00346   vmdplugin_ABIVERSION,         /* ABI version */
00347   MOLFILE_PLUGIN_TYPE,          /* type */
00348   "cor",                        /* short name */
00349   "CHARMM Coordinates",         /* pretty name */
00350   "Eamon Caddigan, John Stone", /* author */
00351   0,                            /* major version */
00352   7,                            /* minor version */
00353   VMDPLUGIN_THREADSAFE,         /* is_reentrant  */
00354   "cor",                        /* filename extensions */
00355   open_cor_read,                /* open_file_read     */
00356   read_cor_structure,           /* read_structure     */
00357   0,                            /* read bond list     */
00358   read_cor_timestep,            /* read_next_timestep */
00359   close_cor_read                /* close_file_read    */
00360 };
00361 
00362 VMDPLUGIN_API int VMDPLUGIN_init() {
00363   return VMDPLUGIN_SUCCESS;
00364 }
00365 
00366 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00367   (*cb)(v, (vmdplugin_t *)&plugin);
00368   return VMDPLUGIN_SUCCESS;
00369 }
00370 
00371 VMDPLUGIN_API int VMDPLUGIN_fini() {
00372   return VMDPLUGIN_SUCCESS;
00373 }

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