00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 #include <stdlib.h>
00028 #include <ctype.h>
00029 #include <string.h>
00030 
00031 #if !defined(_MSC_VER) 
00032 #include <unistd.h>  
00033 #endif
00034 
00035 #include "molfile_plugin.h"
00036 #include "readpdb.h"
00037 #include "vmddir.h"
00038 #include "periodic_table.h"
00039 
00040 typedef struct {
00041   FILE *fd;
00042   int natoms;
00043   char *original_file;
00044   char *current_file;
00045   int babel_num;
00046   int babel_i;
00047 } pdbdata;
00048 
00049 
00050 
00051 
00052 static int vmd_getuid(void) {
00053 #if defined(_MSC_VER)
00054   return 0;
00055 #else
00056   return getuid();
00057 #endif
00058 }
00059 
00060 static int vmd_delete_file(const char * path) {
00061 #if defined(_MSC_VER)
00062   if (DeleteFile(path) == 0)
00063     return -1;
00064   else
00065     return 0;
00066 #else
00067   return unlink(path);
00068 #endif
00069 }
00070 
00071 #define BABEL_TMPDIR "/tmp/"
00072 
00073 
00074 
00075 
00076 
00077 
00078 
00079 static char *file(const char *filename, int idx, int has_multi) {
00080    
00081    int i=0;
00082    char *ptr;
00083    char *tempspace = (char *)malloc(513);
00084    const char *s;
00085    for (s = filename; *s != 0; s++) { 
00086       if ((*s == '/') || (*s == '\\'))
00087         i = s-filename+1;
00088    }
00089    
00090 
00091 
00092 
00093 
00094 
00095    if (has_multi == -1) {
00096       sprintf(tempspace, "%svmdbabel*.u%d.%s", BABEL_TMPDIR,
00097               vmd_getuid(), filename + i);
00098    } else if (has_multi == -2) {
00099       char *reallytemp = (char *)malloc(strlen(filename+i)+1);
00100       strcpy(reallytemp, filename+i);
00101       *(reallytemp + strlen(reallytemp) - 1) = 0;
00102       sprintf(tempspace, "vmdbabel%%[0-9.]u%d.%s%%c",
00103               vmd_getuid(), reallytemp);
00104       free(reallytemp);
00105    } else if (has_multi == 0) {
00106       sprintf(tempspace, "%svmdbabel.u%d.%s", BABEL_TMPDIR,
00107               vmd_getuid(), filename + i);
00108    } else {
00109       sprintf(tempspace, "%svmdbabel%04d.u%d.%s", BABEL_TMPDIR, idx+1,
00110               vmd_getuid(), filename + i);
00111    }
00112    for (ptr = tempspace; *ptr; ptr++) {  
00113       *ptr = tolower(*ptr);              
00114    }
00115    return tempspace;
00116 }
00117 
00118 static void delete_all(const char *filename) {
00119   const char *s;
00120   char *t;
00121 
00122   s = file(filename, 0, -1); 
00123   t = (char *)malloc(strlen(s) + 35);
00124 #if defined(_MSC_VER)
00125    sprintf(t, "del %s", s);
00126 #else
00127    sprintf(t, "/bin/rm -f \"%s\"", s);
00128 #endif
00129   system(t);
00130   free(t);
00131 }
00132  
00133 static void *open_pdb_read(const char *filepath, int *natoms) {
00134   FILE *fd;
00135   pdbdata *pdb;
00136   char pdbstr[PDB_BUFFER_LENGTH];
00137   int indx;
00138   fd = fopen(filepath, "r");
00139   if (!fd) return NULL;
00140   pdb = (pdbdata *)malloc(sizeof(pdbdata));
00141   pdb->fd = fd;
00142   *natoms = 0;
00143   do {
00144     if((indx = read_pdb_record(pdb->fd, pdbstr)) == PDB_ATOM)
00145       *natoms += 1;
00146   } while (indx != PDB_END && indx != PDB_EOF);
00147   rewind(pdb->fd);
00148   pdb->natoms = *natoms;
00149   return pdb;
00150 }
00151 
00152 
00153 
00154 
00155 static const char *babel16filetypes[] = {
00156 "alc",
00157 "prep",
00158 "bs",
00159 "bgf",
00160 "car",
00161 "boog",
00162 "caccrt",
00163 "cadpac",
00164 "charmm",
00165 "c3d1",
00166 "c3d2",
00167 "cssr",
00168 "fdat",
00169 "gstat",
00170 "dock",
00171 "dpdb",
00172 "feat",
00173 "fract",
00174 "gamout",
00175 "gzmat",
00176 "gauout",
00177 "g94",
00178 "gr96A",
00179 "gr96N",
00180 "hin",
00181 "sdf",
00182 "m3d",
00183 "macmol",
00184 "macmod",
00185 "micro",
00186 "mm2in",
00187 "mm2out",
00188 "mm3",
00189 "mmads",
00190 "mdl",
00191 "molen",
00192 "mopcrt",
00193 "mopint",
00194 "mopout",
00195 "pcmod",
00196 "psin",
00197 "psout",
00198 "msf",
00199 "schakal",
00200 "shelx",
00201 "smiles",
00202 "spar",
00203 "semi",
00204 "spmm",
00205 "mol",
00206 "mol2",
00207 "wiz",
00208 "unixyz",
00209 "xyz",  
00210 "xed",
00211 0
00212 };
00213 
00214 
00215 
00216 
00217 static const char *babel16filetypenames[] = {
00218   "Alchemy",          "AMBERPREP",       "BallStick",      
00219   "MSIBGF",           "BiosymCAR",       "Boogie",
00220   "Cacao",            "CADPAC",          "CHARMm",
00221   "Chem3d-1",         "Chem3d-2",        "CSSR",
00222   "FDAT",             "GSTAT",           "Dock",
00223   "DockPDB",          "Feature",         "Fractional",    
00224   "GAMESSoutput",     "GaussianZmatrix", "Gaussian92output", 
00225   "Gaussian94output", "Gromos96A",       "Gromos96N",
00226   "HyperchemHIN",     "IsisSDF",         "M3D",
00227   "MacMolecule",      "Macromodel",      "MicroWorld",
00228   "MM2Input",         "MM2Output",       "MM3",
00229   "MMADS",            "MDLMOL",          "MOLIN",
00230   "MopacCartesian",   "MopacInternal",   "MopacOutput",
00231   "PCModel",          "PSGVBin",         "PSGVBout",
00232   "QuantaMSF",        "Schakal",         "ShelX",
00233   "SMILES",
00234   "Spartan",          "SpartanSE",       "SpartanMM",
00235   "SybylMol",         "SybylMol2",       "Conjure",
00236   "UniChemXYZ",       "XYZ",             "XED", 
00237   0
00238 };
00239 
00240 
00241 
00242 
00243 
00244 static const char *openbabel11filetypes[] = {
00245 "alc",
00246 "prep",
00247 "bs",
00248 "caccrt",
00249 "ccc",
00250 "c3d1",
00251 "c3d2",
00252 "cml",
00253 "crk2d",
00254 "crk3d",
00255 "box",
00256 "dmol",
00257 "feat",
00258 "gam",
00259 "gpr",
00260 "mm1gp",
00261 "qm1gp",
00262 "hin",
00263 "jout",
00264 "bin",
00265 "mmd",
00266 "car",
00267 "sdf",
00268 "mol",
00269 "mopcrt",
00270 "mopout",
00271 "mmads",
00272 "mpqc",
00273 "bgf",
00274 "nwo",
00275 "pqs",
00276 "qcout",
00277 "res",
00278 "smi",
00279 "mol2",
00280 "unixyz",
00281 "vmol",
00282 "xyz",
00283 0
00284 };
00285 
00286 
00287 
00288 
00289 static const char *openbabel11filetypenames[] = {
00290   "Alchemy",          "AMBERPREP",       "BallStick",      
00291   "Cacao",            "CCC",           
00292   "Chem3d-1",         "Chem3d-2",        "ChemicalMarkup"
00293   "CRK2D",            "CRK3D",           "Dock35Box",
00294   "Dmol3Coord",       "Feature",         "GAMESSoutput",     
00295   "GhemicalProj",     "GhemicalMM",      "GhemicalQM",
00296   "HyperchemHIN",     "JaguarOutput",    "OpenEyeBinary",
00297   "Macromodel",       "BiosymCAR",       "IsisSDF",
00298   "MDLMOL",           "MopacCartesian",  "MopacOutput",     
00299   "MMADS",            "MPQC",            "MSIBGF",  
00300   "NWChemOutput",     "PQS",             "QChemOutput",
00301   "ShelX",            "SMILES",          "SybylMol2",   
00302   "UniChemXYZ",       "ViewMol",         "XYZ",
00303   0
00304 };
00305 
00306 
00307 static const char *babel16type_from_name(const char *name) {
00308   const char **ptr = babel16filetypenames;
00309   int i=0; 
00310   while (*ptr) {
00311     if (!strcmp(*ptr, name))
00312       return babel16filetypes[i];
00313     ptr++;
00314     i++;
00315   }
00316   return NULL;
00317 }
00318 
00319 static const char *openbabel11type_from_name(const char *name) {
00320   const char **ptr = openbabel11filetypenames;
00321   int i=0; 
00322   while (*ptr) {
00323     if (!strcmp(*ptr, name))
00324       return openbabel11filetypes[i];
00325     ptr++;
00326     i++;
00327   }
00328   return NULL;
00329 }
00330 
00331 
00332 
00333 
00334 
00335 
00336 static void *open_babel_read(const char *filename, const char *filetypename,
00337     int *natoms) {
00338 
00339   const char *babelbin;
00340   char *current_file;
00341   pdbdata *pdb;
00342   char *s;
00343   const char *fmt;
00344   int count = 0;
00345   VMDDIR *dirp;
00346   char *dp;
00347   char temps[100];
00348   char tempc;
00349   char lastc;
00350   int may_have_multi = 0;
00351   char *tmp_multi = NULL;
00352   const char *filetype;
00353 
00354   babelbin = getenv("VMDBABELBIN");
00355   if (!babelbin) {
00356     fprintf(stderr, "Babel plugin needs VMDBABELBIN environment variable\n"
00357                     "to point to location of Babel executable\n");
00358     return NULL;
00359   }
00360 
00361 #if 0
00362    
00363   filetype = openbabel11type_from_name(filetypename);
00364   if (!filetype) {
00365     fprintf(stderr, "No Open Babel 1.100.2 file type for '%s'\n", filetypename);
00366   }
00367 #endif
00368 
00369    
00370   filetype = babel16type_from_name(filetypename);
00371   if (!filetype) {
00372     fprintf(stderr, "No Babel 1.6 file type for '%s'\n", filetypename);
00373     return NULL;
00374   }
00375   s = (char *)malloc(strlen(babelbin) +               
00376               strlen(" -i       -opdb ") +
00377               strlen(filename) +
00378               strlen(file(filename, 0, 1)) +
00379               20);
00380  
00381   
00382 
00383 
00384 
00385   sprintf(s, "\"%s\" -i%s \"%s\" all -opdb \"%s\"",
00386      babelbin, filetype, filename, (const char *)file(filename, 0, 0));
00387 
00388   delete_all(filename);       
00389   system(s);                  
00390   free(s);
00391 
00392   
00393   fmt = file(filename, 0, -2);
00394   dirp = vmd_opendir(BABEL_TMPDIR);
00395   if (dirp == NULL) {
00396     return NULL; 
00397   }
00398  
00399    lastc = *(filename + strlen(filename) -1);
00400 
00401    while ((dp = vmd_readdir(dirp)) != NULL) {
00402       if (sscanf(dp, fmt, temps, &tempc) > 1 && lastc == tempc) {
00403      count++;
00404      
00405      if (count == 1) {
00406         if (strstr(dp, "0001.")) {
00407            may_have_multi = 1;
00408            tmp_multi = strdup(dp);
00409         }
00410      }
00411       }
00412    }
00413    vmd_closedir(dirp);
00414 
00415    if (may_have_multi && count == 1) {
00416       
00417       char *s2, *t2;
00418       s2 = (char *)malloc(2*(strlen(tmp_multi)+strlen(BABEL_TMPDIR))+40);
00419 
00420 #if defined(_MSC_VER)
00421       sprintf(s2, "move \"%s\\%s\" \"%s\\\"", BABEL_TMPDIR, tmp_multi, BABEL_TMPDIR);
00422 #else
00423       sprintf(s2, "mv \"%s/%s\" \"%s/\"", BABEL_TMPDIR, tmp_multi, BABEL_TMPDIR);
00424 #endif
00425 
00426       t2 = strstr(tmp_multi, "0001.");
00427       *t2 = 0;
00428       strcat(s2, tmp_multi);
00429       strcat(s2, t2 + 4);
00430       fprintf(stderr, "%s\n", s2);
00431       system(s2);
00432       free(s2);
00433    }
00434 
00435    if (tmp_multi) {
00436       free(tmp_multi);
00437    }
00438 
00439   
00440 
00441 
00442 
00443 
00444   if (count == 0) {
00445     fprintf(stderr, "Babel molecule file translation failed!\n");
00446     return NULL;
00447   }
00448   current_file = file(filename, 0, count > 1);
00449   pdb = open_pdb_read(current_file, natoms);
00450   if (!pdb) {
00451     fprintf(stderr, "Couldn't read structure from Babel pdb output\n");
00452     free(current_file);
00453     return NULL;
00454   }
00455   pdb->original_file = strdup(filename); 
00456   pdb->current_file = current_file;
00457   pdb->babel_num = count;
00458   pdb->babel_i = 1;
00459   return pdb;
00460 }
00461 
00462 static int read_pdb_structure(void *mydata, int *optflags, 
00463     molfile_atom_t *atoms) {
00464   pdbdata *pdb = (pdbdata *)mydata;
00465   molfile_atom_t *atom;
00466   char pdbrec[PDB_BUFFER_LENGTH];
00467   int i, rectype, atomserial, pteidx;
00468   char ridstr[8];
00469   char elementsymbol[3];
00470   int badptecount = 0;
00471   long fpos = ftell(pdb->fd);
00472  
00473   *optflags = MOLFILE_INSERTION | MOLFILE_OCCUPANCY | MOLFILE_BFACTOR | 
00474               MOLFILE_ALTLOC | MOLFILE_ATOMICNUMBER;
00475 
00476   i = 0;
00477   do {
00478     rectype = read_pdb_record(pdb->fd, pdbrec);
00479     switch (rectype) {
00480     case PDB_ATOM:
00481       atom = atoms+i;
00482       get_pdb_fields(pdbrec, strlen(pdbrec), &atomserial,
00483           atom->name, atom->resname, atom->chain, atom->segid, 
00484           ridstr, atom->insertion, atom->altloc, elementsymbol,
00485           NULL, NULL, NULL, &atom->occupancy, &atom->bfactor);
00486       atom->resid = atoi(ridstr);
00487 
00488       
00489       pteidx = get_pte_idx_from_string(elementsymbol);
00490       atom->atomicnumber = pteidx;
00491       if (pteidx != 0) {
00492         atom->mass = get_pte_mass(pteidx);
00493         atom->radius = get_pte_vdw_radius(pteidx);
00494       } else {
00495         badptecount++; 
00496       }
00497       strcpy(atom->type, atom->name);
00498       i++;
00499       break;
00500     default:
00501       break;
00502     }
00503   } while (rectype != PDB_END && rectype != PDB_EOF);
00504 
00505   fseek(pdb->fd, fpos, SEEK_SET);
00506 
00507   
00508   
00509   if (badptecount == 0) {
00510     *optflags |= MOLFILE_MASS | MOLFILE_RADIUS;
00511   }
00512 
00513   return MOLFILE_SUCCESS;
00514 }
00515 
00516 static int read_next_timestep(void *v, int natoms, molfile_timestep_t *ts) {
00517   pdbdata *pdb = (pdbdata *)v;
00518   char pdbstr[PDB_BUFFER_LENGTH];
00519   int indx, i;
00520   float *x, *y, *z;
00521   float occup[1], beta[1];
00522   if (ts) {
00523     x = ts->coords;
00524     y = x+1;
00525     z = x+2;
00526   } else {
00527     x = y = z = 0;
00528   }
00529   i = 0;
00530   if (!pdb->fd) 
00531     return MOLFILE_ERROR;
00532 
00533   
00534 
00535 
00536 
00537   
00538   while (i < pdb->natoms) {
00539     indx = read_pdb_record(pdb->fd, pdbstr);
00540     if(indx == PDB_ATOM) {
00541       
00542       if (ts) {
00543         get_pdb_coordinates(pdbstr, x, y, z, occup, beta);
00544         x += 3;
00545         y += 3;
00546         z += 3;
00547         i++;
00548       }
00549     } else if (indx == PDB_CRYST1) {
00550       if (ts) {
00551         get_pdb_cryst1(pdbstr, &ts->alpha, &ts->beta, &ts->gamma,
00552                                &ts->A, &ts->B, &ts->C);
00553       }
00554     } else if (indx == PDB_EOF) {
00555       if (i == 0) {
00556         
00557         fclose(pdb->fd);
00558         pdb->fd = 0;
00559         vmd_delete_file(pdb->current_file);
00560         free(pdb->current_file);
00561         pdb->current_file = 0;
00562         pdb->babel_i++;
00563         if (pdb->babel_i >= pdb->babel_num) 
00564           return MOLFILE_ERROR; 
00565         pdb->current_file = file(pdb->original_file, pdb->babel_i, pdb->babel_num > 1); 
00566         pdb->fd = fopen(pdb->current_file, "r");
00567         if (!pdb->fd) {
00568           fprintf(stderr, 
00569             "Couldn't read babel output file %s\n", pdb->current_file); 
00570           free(pdb->current_file);
00571           pdb->current_file = 0;
00572           return MOLFILE_ERROR; 
00573         } 
00574       } else {
00575         
00576         fprintf(stderr, "PDB file %s contained too few atoms\n", pdb->current_file);
00577         return MOLFILE_ERROR;
00578       }
00579     }
00580   }
00581 
00582   return MOLFILE_SUCCESS; 
00583 }
00584 
00585 
00586 
00587 
00588 static void close_pdb_read(void *v) {
00589   pdbdata *pdb = (pdbdata *)v;
00590   if (!pdb) return;
00591   if (pdb->fd) {
00592     fclose(pdb->fd);
00593     pdb->fd = 0;
00594     vmd_delete_file(pdb->current_file);
00595     free(pdb->current_file);
00596   }
00597   free(pdb);
00598 }
00599 
00600 
00601 
00602 
00603 
00604 
00605 
00606 static molfile_plugin_t *plugins;
00607 static int nplugins;
00608 
00609 VMDPLUGIN_API int VMDPLUGIN_init() {
00610 #if defined(_MSC_VER)
00611   return VMDPLUGIN_SUCCESS;
00612 #else
00613   
00614   const char **s = babel16filetypenames;
00615   int i;
00616   nplugins = 0;
00617   while (*s) { nplugins++; s++; }
00618   plugins = (molfile_plugin_t*)calloc(nplugins, sizeof(molfile_plugin_t));
00619   for (i=0; i<nplugins; i++) {
00620     plugins[i].abiversion = vmdplugin_ABIVERSION;         
00621     plugins[i].type = MOLFILE_CONVERTER_PLUGIN_TYPE;      
00622     plugins[i].name = babel16filetypenames[i];            
00623     plugins[i].prettyname = babel16filetypenames[i];      
00624     plugins[i].author = "Justin Gullingsrud, John Stone"; 
00625     plugins[i].majorv = 1;                                
00626     plugins[i].minorv = 13;                               
00627     plugins[i].is_reentrant = VMDPLUGIN_THREADUNSAFE;     
00628     plugins[i].filename_extension = babel16filetypes[i];  
00629     plugins[i].open_file_read = open_babel_read;
00630     plugins[i].read_structure = read_pdb_structure;
00631     plugins[i].read_next_timestep = read_next_timestep;
00632     plugins[i].close_file_read = close_pdb_read;
00633   }
00634 
00635 #if 0
00636   
00637   const char **s = openbabel11filetypenames;
00638   int i;
00639   nplugins = 0;
00640   while (*s) { nplugins++; s++; }
00641   plugins = (molfile_plugin_t*)calloc(nplugins, sizeof(molfile_plugin_t));
00642   for (i=0; i<nplugins; i++) {
00643     plugins[i].abiversion = vmdplugin_ABIVERSION;         
00644     plugins[i].type = MOLFILE_CONVERTER_PLUGIN_TYPE;      
00645     plugins[i].shortname = openbabel11filetypenames[i];   
00646     plugins[i].prettyname = openbabel11filetypenames[i];  
00647     plugins[i].author = "Justin Gullingsrud, John Stone"; 
00648     plugins[i].majorv = 2;                                
00649     plugins[i].minorv = 12;                               
00650     plugins[i].is_reentrant = VMDPLUGIN_THREADUNSAFE;     
00651     plugins[i].filename_extension = openbabel11filetypes[i];  
00652     plugins[i].open_file_read = open_babel_read;
00653     plugins[i].read_structure = read_pdb_structure;
00654     plugins[i].read_next_timestep = read_next_timestep;
00655     plugins[i].close_file_read = close_pdb_read;
00656   }
00657 #endif
00658 
00659   return VMDPLUGIN_SUCCESS;
00660 #endif
00661 }
00662 
00663 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00664 #if defined(_MSC_VER)
00665   return VMDPLUGIN_SUCCESS;
00666 #else
00667   int i;
00668   for (i=0; i<nplugins; i++) {
00669     (*cb)(v, (vmdplugin_t *)(plugins+i));
00670   }
00671   return VMDPLUGIN_SUCCESS;
00672 #endif
00673 }
00674 
00675 VMDPLUGIN_API int VMDPLUGIN_fini() {
00676 #if defined(_MSC_VER)
00677   return VMDPLUGIN_SUCCESS;
00678 #else
00679   free(plugins);
00680   nplugins = 0;
00681   plugins = 0;
00682   return VMDPLUGIN_SUCCESS;
00683 #endif
00684 }
00685 
00686 
00687 #ifdef TEST_BABEL_PLUGIN
00688 
00689 int main(int argc, char *argv[]) {
00690   molfile_header_t header;
00691   molfile_timestep_t timestep;
00692   void *v;
00693 
00694   while (--argc) {
00695     ++argv;
00696     v = open_babel_read(*argv, "xyz", &header);
00697     if (!v) {
00698       fprintf(stderr, "open_babel_read failed for file %s\n", *argv);
00699       return 1;
00700     }
00701     timestep.coords = (float *)malloc(3*sizeof(float)*header.numatoms);
00702     while (!read_next_timestep(v, ×tep));
00703     close_pdb_read(v);
00704   }
00705   return 0;
00706 }
00707 
00708 
00709 #endif
00710 
00711