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

psfplugin.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: psfplugin.c,v $
00013  *      $Author: johns $       $Locker:  $             $State: Exp $
00014  *      $Revision: 1.33 $       $Date: 2006/02/23 19:36:45 $
00015  *
00016  ***************************************************************************/
00017 
00018 #include "molfile_plugin.h"
00019 
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <stdlib.h>
00023 
00024 #define PSF_RECORD_LENGTH   160  /* extended to handle Charmm CMAP/CHEQ */ 
00025 
00026 typedef struct {
00027   FILE *fp;
00028   int numatoms;
00029   int charmmfmt;  /* whether psf was written in charmm format          */
00030   int charmmcmap; /* stuff used by charmm for polarizable force fields */
00031   int charmmcheq; /* stuff used by charmm for polarizable force fields */
00032   int charmmext;  /* flag used by charmm for IOFOrmat EXTEnded         */
00033   int nbonds;
00034   int *from, *to;
00035 } psfdata;
00036 
00037 
00038 
00039 /* Read in the next atom info into the given storage areas; this assumes
00040    that file has already been moved to the beginning of the atom records.
00041    Returns the serial number of the atom. If there is an error, returns -1.*/
00042 static int get_psf_atom(FILE *f, char *name, char *atype, char *resname,
00043    char *segname, int *resid, float *q, float *m, int charmmext) {
00044   char inbuf[PSF_RECORD_LENGTH+2];
00045   int i,num;
00046 
00047   if (inbuf != fgets(inbuf, PSF_RECORD_LENGTH+1, f)) {
00048     return(-1); /* failed to read in an atom */
00049   }
00050 
00051   if (strlen(inbuf) < 50) {
00052     fprintf(stderr, "Line too short in psf file: \n%s\n", inbuf);
00053     return -1;
00054   }
00055 
00056   num = atoi(inbuf); /* atom index */
00057 
00058   if (charmmext == 1) {
00059     strncpy(segname, inbuf+11, 7); 
00060     segname[7] = '\0';
00061     strncpy(resname, inbuf+29, 7);  
00062     resname[7] = '\0';
00063     strncpy(name, inbuf+38, 7);
00064     name[7] = '\0';
00065     strncpy(atype, inbuf+46, 7);
00066     atype[7] = '\0';
00067     
00068     /* null terminate any extraneous spaces */
00069     for (i=7; i >= 0; i--) {
00070       if (segname[i] == ' ')   
00071         segname[i] = '\0';
00072       if (resname[i] == ' ')   
00073         resname[i] = '\0';
00074       if (name[i] == ' ')      
00075         name[i] = '\0';
00076       if (atype[i] == ' ')     
00077         atype[i] = '\0';
00078     }
00079 
00080     *resid = atoi(inbuf+20);
00081     *q = (float) atof(inbuf+52);
00082     *m = (float) atof(inbuf+68);
00083   } else {
00084     strncpy(segname, inbuf+9, 4); 
00085     segname[4] = '\0';
00086     strncpy(resname, inbuf+19, 4);  
00087     resname[4] = '\0';
00088     strncpy(name, inbuf+24, 4);  
00089     name[4] = '\0';
00090     strncpy(atype, inbuf+29, 4); 
00091     atype[4] = '\0';
00092 
00093     /* null terminate any extraneous spaces */
00094     for (i=3; i >= 0; i--) {
00095       if (segname[i] == ' ')   
00096         segname[i] = '\0';
00097       if (resname[i] == ' ')   
00098         resname[i] = '\0';
00099       if (name[i] == ' ')      
00100         name[i] = '\0';
00101       if (atype[i] == ' ')     
00102         atype[i] = '\0';
00103     }
00104 
00105     *resid = atoi(inbuf+13);
00106     *q = (float) atof(inbuf+34);
00107     *m = (float) atof(inbuf+50);
00108   }
00109 
00110 #if 0
00111   /* if this is a Charmm31 PSF file, there may be two extra */
00112   /* columns containing polarizable force field data.       */
00113   if (psf->charmmcheq) {
00114     /* do something to read in these columns here */
00115   }
00116 #endif
00117 
00118   return num;
00119 }
00120 
00121 /* Read in the beginning of the bond information, but don't read in the
00122    bonds.  Returns the number of bonds in molecule.  If error, returns (-1). */
00123 static int start_psf_bonds(FILE *f) {
00124   char inbuf[PSF_RECORD_LENGTH+2];
00125   int nbond = -1;
00126 
00127   /* keep reading the next line until a line with NBOND appears */
00128   do {
00129     if (inbuf != fgets(inbuf, PSF_RECORD_LENGTH+1, f)) {
00130       /* EOF encountered with no NBOND line found ==> error, return (-1) */
00131       return (-1);
00132     }
00133     if (strlen(inbuf) > 0 && strstr(inbuf,"NBOND"))
00134       nbond = atoi(inbuf);
00135   } while (nbond == -1);
00136 
00137   return nbond;
00138 }
00139 
00140 
00141 /* Read in the bond info into the given integer arrays, one for 'from' and
00142    one for 'to' atoms; remember that .psf files use 1-based indices,
00143    not 0-based.  Returns 1 if all nbond bonds found; 0 otherwise.  */
00144 static int get_psf_bonds(FILE *f, int nbond, int fromAtom[], int toAtom[], int charmmext) {
00145   char *bondptr=NULL;
00146   char inbuf[PSF_RECORD_LENGTH+2];
00147   int i=0;
00148   size_t minlinesize;
00149 
00150   while (i < nbond) {
00151     if ((i % 4) == 0) {
00152       /* must read next line */
00153       if (!fgets(inbuf, PSF_RECORD_LENGTH+2, f)) {
00154         /* early EOF encountered */
00155         break;
00156       }
00157       /* Check that there is enough space in the line we are about to read */
00158       if (nbond-i >= 4) {
00159         if(charmmext == 1) minlinesize = 20*4 ; else minlinesize = 16*4;
00160       } else {
00161         if(charmmext == 1) minlinesize = 20*(nbond-i); else minlinesize = 16*(nbond-i);
00162       }
00163       if (strlen(inbuf) < minlinesize) {
00164         fprintf(stderr, "Bonds line too short in psf file: \n%s\n", inbuf);
00165         break;
00166       }
00167       bondptr = inbuf;
00168     }
00169     if ((fromAtom[i] = atoi(bondptr)) < 1)
00170       break;
00171     if(charmmext == 1) bondptr += 10; else bondptr += 8;
00172     if ((toAtom[i] = atoi(bondptr)) < 1)
00173       break;
00174     if(charmmext == 1) bondptr += 10; else bondptr += 8;
00175     i++;
00176   }
00177 
00178   return (i == nbond);
00179 }
00180 
00181 /*
00182  * API functions
00183  */
00184 
00185 static void *open_psf_read(const char *path, const char *filetype, 
00186     int *natoms) {
00187   FILE *fp;
00188   char inbuf[PSF_RECORD_LENGTH*8+2];
00189   psfdata *psf;
00190   
00191   /* Open the .psf file and skip past the remarks to the first data section.
00192    * Returns the file pointer, or NULL if error.  Also puts the number of
00193    * atoms in the molecule into the given integer.  
00194    */
00195   if (!path)
00196     return NULL;
00197 
00198   if ((fp = fopen(path, "r")) == NULL) {
00199     fprintf(stderr, "Couldn't open psf file %s\n", path);
00200     return NULL;
00201   }
00202 
00203   *natoms = MOLFILE_NUMATOMS_NONE; /* initialize to none */
00204 
00205   psf = (psfdata *) malloc(sizeof(psfdata));
00206   memset(psf, 0, sizeof(psfdata));
00207   psf->fp = fp;
00208   psf->charmmfmt = 0; /* off unless we discover otherwise */
00209   psf->charmmext = 0; /* off unless we discover otherwise */
00210 
00211   /* read lines until a line with NATOM and without REMARKS appears    */
00212   do {
00213     /* be prepared for long lines from CNS remarks */
00214     if (inbuf != fgets(inbuf, PSF_RECORD_LENGTH*8+1, fp)) {
00215       /* EOF encountered with no NATOM line found ==> error, return null */
00216       *natoms = MOLFILE_NUMATOMS_NONE;
00217       fclose(fp);
00218       free(psf);
00219       return NULL;
00220     }
00221 
00222     if (strlen(inbuf) > 0) {
00223       if (!strstr(inbuf, "REMARKS")) {
00224         if (strstr(inbuf, "PSF")) {
00225           if (strstr(inbuf, "EXT")) {
00226             psf->charmmfmt = 1; 
00227             psf->charmmext = 1;      
00228           }
00229           if (strstr(inbuf, "CHEQ")) {
00230             psf->charmmfmt = 1; 
00231             psf->charmmcheq = 1;      
00232           }
00233           if (strstr(inbuf, "CMAP")) {
00234             psf->charmmfmt = 1; 
00235             psf->charmmcmap = 1;      
00236           }
00237         } else if (strstr(inbuf, "NATOM")) {
00238           *natoms = atoi(inbuf);
00239         }
00240       } 
00241     }
00242   } while (*natoms == MOLFILE_NUMATOMS_NONE);
00243 
00244   if (psf->charmmcheq || psf->charmmcmap) {
00245     printf("psfplugin) Detected a Charmm31 PSF file\n");
00246   }
00247   if (psf->charmmext) {
00248     printf("psfplugin) Detected a Charmm31 PSF EXTEnded file\n");
00249   }
00250 
00251   psf->numatoms = *natoms;
00252 
00253   return psf;
00254 }
00255 
00256 static int read_psf(void *v, int *optflags, molfile_atom_t *atoms) {
00257   psfdata *psf = (psfdata *)v;
00258   int i;
00259   
00260   /* we read in the optional mass and charge data */
00261   *optflags = MOLFILE_MASS | MOLFILE_CHARGE;
00262 
00263   for (i=0; i<psf->numatoms; i++) {
00264     molfile_atom_t *atom = atoms+i; 
00265     if (get_psf_atom(psf->fp, atom->name, atom->type, 
00266                      atom->resname, atom->segid, 
00267                      &atom->resid, &atom->charge, &atom->mass, psf->charmmext) < 0) {
00268       fprintf(stderr, "couldn't read atom %d\n", i);
00269       fclose(psf->fp);
00270       psf->fp = NULL;
00271       return MOLFILE_ERROR;
00272     }
00273     atom->chain[0] = atom->segid[0];
00274     atom->chain[1] = '\0';
00275   }
00276 
00277   return MOLFILE_SUCCESS;
00278 }
00279 
00280 static int read_bonds(void *v, int *nbonds, int **fromptr, int **toptr, float **bondorder) {
00281   psfdata *psf = (psfdata *)v;
00282 
00283   /* now read bond data */
00284   *nbonds = start_psf_bonds(psf->fp);
00285 
00286   if (*nbonds > 0) {
00287     psf->from = (int *) malloc(*nbonds*sizeof(int));
00288     psf->to = (int *) malloc(*nbonds*sizeof(int));
00289 
00290     if (!get_psf_bonds(psf->fp, *nbonds, psf->from, psf->to, psf->charmmext)) {
00291       fclose(psf->fp);
00292       psf->fp = NULL;
00293       return MOLFILE_ERROR;
00294     }
00295     *fromptr = psf->from;
00296     *toptr = psf->to;
00297     *bondorder = NULL; /* PSF files don't provide bond order information */
00298   } else {
00299     printf("psfplugin) WARNING: no bonds defined in PSF file.\n");
00300   }
00301 
00302   return MOLFILE_SUCCESS;
00303 }
00304 
00305 
00306 static void close_psf_read(void *mydata) {
00307   psfdata *psf = (psfdata *)mydata;
00308   if (psf) {
00309     if (psf->fp != NULL) 
00310       fclose(psf->fp);
00311     if (psf->from != NULL) 
00312       free(psf->from);
00313     if (psf->to != NULL) 
00314       free(psf->to);
00315     free(psf);
00316   }
00317 }  
00318 
00319 
00320 static void *open_psf_write(const char *path, const char *filetype,
00321     int natoms) {
00322   FILE *fp;
00323   psfdata *psf;
00324 
00325   fp = fopen(path, "w");
00326   if (!fp) {
00327     fprintf(stderr, "Unable to open file %s for writing\n", path);
00328     return NULL;
00329   }
00330   psf = (psfdata *) malloc(sizeof(psfdata));
00331   psf->fp = fp; 
00332   psf->numatoms = natoms;
00333   psf->charmmfmt = 0; /* initialize to off for now */
00334   psf->nbonds = 0;
00335   psf->to = NULL;
00336   psf->from = NULL;
00337 
00338   return psf;
00339 }
00340 
00341 static int write_psf_structure(void *v, int optflags,
00342     const molfile_atom_t *atoms) {
00343   psfdata *psf = (psfdata *)v;
00344   const molfile_atom_t *atom;
00345   int i;
00346 
00347   printf("psfplugin) WARNING: PSF file is incomplete, no angles, dihedrals,\n");
00348   printf("psfplugin)          or impropers will be written. \n");
00349 
00350   fprintf(psf->fp, "PSF\n\n%8d !NTITLE\n", 1);
00351 
00352   if (psf->charmmfmt) {
00353     fprintf(psf->fp," REMARKS %s\n","VMD generated structure charmm psf file");
00354 
00355     printf("psfplugin) WARNING: Charmm format PSF file is incomplete, atom type ID\n");
00356     printf("psfplugin)          codes have been emitted as '0'. \n");
00357   } else {
00358     fprintf(psf->fp," REMARKS %s\n","VMD generated structure x-plor psf file");
00359   }
00360   fprintf(psf->fp, "\n");
00361 
00362   /* write out total number of atoms */
00363   fprintf(psf->fp, "%8d !NATOM\n", psf->numatoms);
00364 
00365   /* write out all of the atom records */
00366   for (i=0; i<psf->numatoms; i++) {
00367     const char *atomname; 
00368     atom = &atoms[i];
00369     atomname = atom->name;
00370 
00371     /* skip any leading space characters given to us by VMD */ 
00372     while (*atomname == ' ')
00373       atomname++;
00374 
00375     if (psf->charmmfmt) {
00376       /* XXX replace hard-coded 0 with proper atom type ID code */
00377       fprintf(psf->fp, "%8d %-4s %-4d %-4s %-4s %4d %10.6f     %9.4f  %10d\n",
00378               i+1, atom->segid, atom->resid, atom->resname,
00379               atomname, /* atom->typeid */ 0, atom->charge, atom->mass, 0);
00380     } else {
00381       fprintf(psf->fp, "%8d %-4s %-4d %-4s %-4s %-4s %10.6f     %9.4f  %10d\n",
00382               i+1, atom->segid, atom->resid, atom->resname,
00383               atomname, atom->type, atom->charge, atom->mass, 0);
00384     }
00385   } 
00386   fprintf(psf->fp, "\n");
00387 
00388   /* write out bonds if we have bond information */
00389   if (psf->nbonds > 0 && psf->from != NULL && psf->to != NULL) {
00390     fprintf(psf->fp, "%8d !NBOND: bonds\n", psf->nbonds);
00391     for (i=0; i<psf->nbonds; i++) {
00392       fprintf(psf->fp, "%8d%8d", psf->from[i], psf->to[i]);
00393       if ((i % 4) == 3) 
00394         fprintf(psf->fp, "\n");
00395     }
00396     if ((i % 4) != 0) 
00397       fprintf(psf->fp, "\n");
00398     fprintf(psf->fp, "\n");
00399   } else {
00400     fprintf(psf->fp, "%8d !NBOND: bonds\n", 0);
00401     fprintf(psf->fp, "\n\n");
00402   }
00403 
00404   fprintf(psf->fp, "%8d !NTHETA: angles\n", 0);
00405   /* XXX put in code to emit angles here */
00406   fprintf(psf->fp, "\n\n");
00407 
00408   fprintf(psf->fp, "%8d !NPHI: dihedrals\n", 0);
00409   /* XXX put in code to emit dihedrals here */
00410   fprintf(psf->fp, "\n\n");
00411 
00412   fprintf(psf->fp, "%8d !NIMPHI: impropers\n", 0);
00413   /* XXX put in code to emit impropers here */
00414   fprintf(psf->fp, "\n\n");
00415 
00416   fprintf(psf->fp, "%8d !NDON: donors\n", 0);
00417   fprintf(psf->fp, "\n\n");
00418 
00419   fprintf(psf->fp, "%8d !NACC: acceptors\n", 0);
00420   fprintf(psf->fp, "\n\n");
00421 
00422   fprintf(psf->fp, "%8d !NNB\n\n", 0);
00423   /* Pad with zeros, one for every atom */
00424   {
00425     int i, fullrows;
00426     fullrows = psf->numatoms/8;
00427     for (i=0; i<fullrows; ++i)
00428       fprintf(psf->fp, "%8d%8d%8d%8d%8d%8d%8d%8d\n", 0, 0, 0, 0, 0, 0, 0, 0);
00429     for (i=psf->numatoms - fullrows*8; i; --i)
00430       fprintf(psf->fp, "%8d", 0);
00431   }
00432   fprintf(psf->fp, "\n\n");
00433 
00434   fprintf(psf->fp, "%8d %7d !NGRP\n%8d%8d%8d\n", 1, 0, 0, 0, 0);
00435   fprintf(psf->fp, "\n");
00436 
00437   return MOLFILE_SUCCESS;
00438 }
00439 
00440 static int write_bonds(void *v, int nbonds, int *fromptr, int *toptr, float *bondorderptr) {
00441   psfdata *psf = (psfdata *)v;
00442   int i;
00443 
00444   /* save bond info until we actually write out the structure file */
00445   psf->nbonds = nbonds;
00446   psf->from = (int *) malloc(nbonds * sizeof(int));
00447   memcpy(psf->from, fromptr, nbonds * sizeof(int));
00448   psf->to = (int *) malloc(nbonds * sizeof(int));
00449   memcpy(psf->to, toptr, nbonds * sizeof(int));
00450 
00451   return MOLFILE_SUCCESS;
00452 }
00453 
00454 static void close_psf_write(void *v) {
00455   psfdata *psf = (psfdata *)v;
00456   fclose(psf->fp);
00457 
00458   /* free bonds if we have them */
00459   if (psf->from != NULL) 
00460     free(psf->from);
00461   if (psf->to != NULL) 
00462     free(psf->to);
00463   free(psf);
00464 }
00465 
00466 
00467 /*
00468  * Initialization stuff down here
00469  */
00470 
00471 static molfile_plugin_t plugin = {
00472   vmdplugin_ABIVERSION,              /* ABI version              */
00473   MOLFILE_PLUGIN_TYPE,               /* type                     */
00474   "psf",                             /* short name               */
00475   "CHARMM,NAMD,XPLOR PSF",           /* pretty name              */
00476   "Justin Gullingsrud, John Stone",  /* author                   */
00477   0,                                 /* major version            */
00478   7,                                 /* minor version            */
00479   VMDPLUGIN_THREADSAFE,              /* is_reentrant             */
00480   "psf",                             /* filename extension       */
00481   open_psf_read,                     /* open_file_read           */
00482   read_psf,                          /* read_structure           */
00483   read_bonds,                        /* read bond list           */
00484   0,                                 /* read_next_timestep       */
00485   close_psf_read,                    /* close_file_read          */
00486   open_psf_write,                    /* open file for writing    */
00487   write_psf_structure,               /* write structure          */
00488   0,                                 /* write timestep           */
00489   close_psf_write,                   /* close file for writing   */
00490   0,                                 /* read volumetric metadata */
00491   0,                                 /* read volumetric data     */
00492   0,                                 /* read rawgraphics         */
00493   0,                                 /* read molecule metadata   */
00494   write_bonds                        /* write bonds              */
00495 };
00496 
00497 VMDPLUGIN_API int VMDPLUGIN_init() {
00498   return VMDPLUGIN_SUCCESS;
00499 }
00500 
00501 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00502   (*cb)(v, (vmdplugin_t *)&plugin);
00503   return VMDPLUGIN_SUCCESS;
00504 }
00505 
00506 VMDPLUGIN_API int VMDPLUGIN_fini() {
00507   return VMDPLUGIN_SUCCESS;
00508 }

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