00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "largefiles.h"
00024
00025 #include "molfile_plugin.h"
00026 #include "readpdb.h"
00027 #include "periodic_table.h"
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031
00032
00033
00034
00035
00036 typedef struct {
00037 FILE *fd;
00038 int first_frame;
00039 int natoms;
00040 molfile_atom_t *atomlist;
00041 molfile_metadata_t *meta;
00042 int nconect;
00043 int nbonds, maxbnum;
00044 int *from, *to, *idxmap;
00045 } pdbdata;
00046
00047 static void *open_pdb_read(const char *filepath, const char *filetype,
00048 int *natoms) {
00049 FILE *fd;
00050 pdbdata *pdb;
00051 char pdbstr[PDB_BUFFER_LENGTH];
00052 int indx, nconect;
00053
00054 fd = fopen(filepath, "r");
00055 if (!fd)
00056 return NULL;
00057 pdb = (pdbdata *)malloc(sizeof(pdbdata));
00058 pdb->fd = fd;
00059 pdb->meta = (molfile_metadata_t *) malloc(sizeof(molfile_metadata_t));
00060 memset(pdb->meta, 0, sizeof(molfile_metadata_t));
00061
00062 pdb->meta->remarklen = 0;
00063 pdb->meta->remarks = NULL;
00064
00065 *natoms=0;
00066 nconect=0;
00067 do {
00068 indx = read_pdb_record(pdb->fd, pdbstr);
00069 if (indx == PDB_ATOM) {
00070 *natoms += 1;
00071 } else if (indx == PDB_CONECT) {
00072 nconect++;
00073 } else if (indx == PDB_HEADER) {
00074 get_pdb_header(pdbstr, pdb->meta->accession, pdb->meta->date, NULL);
00075 if (strlen(pdb->meta->accession) > 0)
00076 strcpy(pdb->meta->database, "PDB");
00077 } else if (indx == PDB_REMARK || indx == PDB_CONECT || indx == PDB_UNKNOWN) {
00078 int len=strlen(pdbstr);
00079 int newlen = len + pdb->meta->remarklen;
00080
00081 char *newstr=realloc(pdb->meta->remarks, newlen + 1);
00082 if (newstr != NULL) {
00083 pdb->meta->remarks = newstr;
00084 pdb->meta->remarks[pdb->meta->remarklen] = '\0';
00085 memcpy(pdb->meta->remarks + pdb->meta->remarklen, pdbstr, len);
00086 pdb->meta->remarks[newlen] = '\0';
00087 pdb->meta->remarklen = newlen;
00088 }
00089 }
00090
00091 } while (indx != PDB_END && indx != PDB_EOF);
00092
00093
00094 if (!*natoms) {
00095 fprintf(stderr, "PDB file '%s' contains no atoms.\n", filepath);
00096 if (pdb->meta->remarks != NULL)
00097 free(pdb->meta->remarks);
00098 if (pdb->meta != NULL)
00099 free(pdb->meta);
00100 free(pdb);
00101 return NULL;
00102 }
00103
00104 rewind(pdb->fd);
00105 pdb->natoms = *natoms;
00106 pdb->nconect = nconect;
00107 pdb->nbonds = 0;
00108 pdb->maxbnum = 0;
00109 pdb->from = NULL;
00110 pdb->to = NULL;
00111 pdb->idxmap = NULL;
00112 pdb->atomlist = NULL;
00113
00114 #if defined(VMDUSECONECTRECORDS)
00115
00116
00117 if (pdb->natoms < 100000 && pdb->nconect > 0) {
00118 pdb->idxmap = (int *) malloc(100000 * sizeof(int));
00119 memset(pdb->idxmap, 0, 100000 * sizeof(int));
00120 }
00121 #endif
00122
00123 return pdb;
00124 }
00125
00126 static int read_pdb_structure(void *mydata, int *optflags,
00127 molfile_atom_t *atoms) {
00128 pdbdata *pdb = (pdbdata *)mydata;
00129 molfile_atom_t *atom;
00130 char pdbrec[PDB_BUFFER_LENGTH];
00131 int i, rectype, atomserial, pteidx;
00132 char ridstr[8];
00133 char elementsymbol[3];
00134 int badptecount = 0;
00135 long fpos = ftell(pdb->fd);
00136
00137 *optflags = MOLFILE_INSERTION | MOLFILE_OCCUPANCY | MOLFILE_BFACTOR |
00138 MOLFILE_ALTLOC | MOLFILE_ATOMICNUMBER | MOLFILE_BONDSSPECIAL;
00139
00140 i = 0;
00141 do {
00142 rectype = read_pdb_record(pdb->fd, pdbrec);
00143 switch (rectype) {
00144 case PDB_ATOM:
00145 atom = atoms+i;
00146 get_pdb_fields(pdbrec, strlen(pdbrec), &atomserial,
00147 atom->name, atom->resname, atom->chain, atom->segid,
00148 ridstr, atom->insertion, atom->altloc, elementsymbol,
00149 NULL, NULL, NULL, &atom->occupancy, &atom->bfactor);
00150
00151 if (pdb->idxmap != NULL && atomserial < 100000) {
00152 pdb->idxmap[atomserial] = i;
00153 }
00154
00155 atom->resid = atoi(ridstr);
00156
00157
00158 pteidx = get_pte_idx_from_string(elementsymbol);
00159 atom->atomicnumber = pteidx;
00160 if (pteidx != 0) {
00161 atom->mass = get_pte_mass(pteidx);
00162 atom->radius = get_pte_vdw_radius(pteidx);
00163 } else {
00164 badptecount++;
00165 }
00166
00167 strcpy(atom->type, atom->name);
00168 i++;
00169 break;
00170
00171 case PDB_CONECT:
00172
00173
00174 if (pdb->idxmap != NULL) {
00175 get_pdb_conect(pdbrec, pdb->natoms, pdb->idxmap,
00176 &pdb->maxbnum, &pdb->nbonds, &pdb->from, &pdb->to);
00177 }
00178 break;
00179
00180 default:
00181
00182
00183 break;
00184 }
00185 } while (rectype != PDB_END && rectype != PDB_EOF);
00186
00187 fseek(pdb->fd, fpos, SEEK_SET);
00188
00189
00190
00191 if (badptecount == 0) {
00192 *optflags |= MOLFILE_MASS | MOLFILE_RADIUS;
00193 }
00194
00195 return MOLFILE_SUCCESS;
00196 }
00197
00198 static int read_bonds(void *v, int *nbonds, int **fromptr, int **toptr, float **
00199 bondorder) {
00200 pdbdata *pdb = (pdbdata *)v;
00201
00202 *nbonds = 0;
00203 *fromptr = NULL;
00204 *toptr = NULL;
00205 *bondorder = NULL;
00206
00207
00208
00209
00210
00211 #if !defined(MOLFILE_BONDSSPECIAL)
00212 if (pdb->natoms >= 100000) {
00213 printf("pdbplugin) Warning: more than 99,999 atoms, ignored CONECT records\n");
00214 return MOLFILE_SUCCESS;
00215 } else if (((float) pdb->nconect / (float) pdb->natoms) <= 0.85) {
00216 printf("pdbplugin) Warning: Probable incomplete bond structure specified,\n");
00217 printf("pdbplugin) ignoring CONECT records\n");
00218 return MOLFILE_SUCCESS;
00219 } else if (pdb->nconect == 0) {
00220 return MOLFILE_SUCCESS;
00221 }
00222 #endif
00223
00224 *nbonds = pdb->nbonds;
00225 *fromptr = pdb->from;
00226 *toptr = pdb->to;
00227
00228 return MOLFILE_SUCCESS;
00229 }
00230
00231
00232
00233
00234
00235 static int read_next_timestep(void *v, int natoms, molfile_timestep_t *ts) {
00236 pdbdata *pdb = (pdbdata *)v;
00237 char pdbstr[PDB_BUFFER_LENGTH];
00238 int indx, i;
00239 float *x, *y, *z;
00240 float occup, bfac;
00241 if (pdb->natoms == 0)
00242 return MOLFILE_ERROR;
00243 if (ts) {
00244 x = ts->coords;
00245 y = x+1;
00246 z = x+2;
00247 } else {
00248 x = y = z = 0;
00249 }
00250 i = 0;
00251 do {
00252 indx = read_pdb_record(pdb->fd, pdbstr);
00253 if((indx == PDB_END || indx == PDB_EOF) && (i < pdb->natoms)) {
00254 return MOLFILE_ERROR;
00255 } else if(indx == PDB_ATOM) {
00256 if(i++ >= pdb->natoms) {
00257 break;
00258 }
00259
00260 if (ts) {
00261 get_pdb_coordinates(pdbstr, x, y, z, &occup, &bfac);
00262 x += 3;
00263 y += 3;
00264 z += 3;
00265 }
00266 } else if (indx == PDB_CRYST1) {
00267 if (ts) {
00268 get_pdb_cryst1(pdbstr, &ts->alpha, &ts->beta, &ts->gamma,
00269 &ts->A, &ts->B, &ts->C);
00270 }
00271 }
00272 } while(!(indx == PDB_END || indx == PDB_EOF));
00273
00274 return MOLFILE_SUCCESS;
00275 }
00276
00277 static void close_pdb_read(void *v) {
00278 pdbdata *pdb = (pdbdata *)v;
00279 if (pdb->fd != NULL)
00280 fclose(pdb->fd);
00281 if (pdb->idxmap != NULL)
00282 free(pdb->idxmap);
00283 if (pdb->meta->remarks != NULL)
00284 free(pdb->meta->remarks);
00285 if (pdb->meta != NULL)
00286 free(pdb->meta);
00287 free(pdb);
00288 }
00289
00290 static void *open_file_write(const char *path, const char *filetype,
00291 int natoms) {
00292
00293 FILE *fd;
00294 pdbdata *pdb;
00295 fd = fopen(path, "w");
00296 if (!fd) {
00297 fprintf(stderr, "Unable to open file %s for writing\n", path);
00298 return NULL;
00299 }
00300 pdb = (pdbdata *)malloc(sizeof(pdbdata));
00301 pdb->fd = fd;
00302 pdb->natoms = natoms;
00303 pdb->atomlist = NULL;
00304 pdb->first_frame = 1;
00305 return pdb;
00306 }
00307
00308 static int write_structure(void *v, int optflags,
00309 const molfile_atom_t *atoms) {
00310
00311 int i;
00312 pdbdata *pdb = (pdbdata *)v;
00313 int natoms = pdb->natoms;
00314 pdb->atomlist = (molfile_atom_t *)malloc(natoms*sizeof(molfile_atom_t));
00315 memcpy(pdb->atomlist, atoms, natoms*sizeof(molfile_atom_t));
00316
00317
00318 if (!(optflags & MOLFILE_OCCUPANCY)) {
00319 for (i=0; i<natoms; i++) pdb->atomlist[i].occupancy = 0.0f;
00320 }
00321 if (!(optflags & MOLFILE_BFACTOR)) {
00322 for (i=0; i<natoms; i++) pdb->atomlist[i].bfactor= 0.0f;
00323 }
00324 if (!(optflags & MOLFILE_INSERTION)) {
00325 for (i=0; i<natoms; i++) {
00326 pdb->atomlist[i].insertion[0] =' ';
00327 pdb->atomlist[i].insertion[1] ='\0';
00328 }
00329 }
00330 if (!(optflags & MOLFILE_ALTLOC)) {
00331 for (i=0; i<natoms; i++) {
00332 pdb->atomlist[i].altloc[0]=' ';
00333 pdb->atomlist[i].altloc[1]='\0';
00334 }
00335 }
00336 if (!(optflags & MOLFILE_ATOMICNUMBER)) {
00337 for (i=0; i<natoms; i++) pdb->atomlist[i].atomicnumber = 0;
00338 }
00339
00340
00341 return MOLFILE_SUCCESS;
00342 }
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407 #if 0
00408 static void write_seqres(FILE * fd, int natoms, const molfile_atom_t *atomlist) {
00409 int i=0;
00410 while (i < natoms) {
00411 int k, serNum;
00412 int j = i;
00413 int ires, nres = 1;
00414 int resid = atomlist[i].resid;
00415
00416 const char *chain = atomlist[i].chain;
00417 while (j < natoms && !strcmp(chain, atomlist[j].chain)) {
00418 if (resid != atomlist[j].resid) {
00419 nres++;
00420 resid = atomlist[j].resid;
00421 }
00422 j++;
00423 }
00424
00425 serNum = 1;
00426 ires = 1;
00427 resid = atomlist[i].resid;
00428 fprintf(fd, "SEQRES %2d %c %4d ", serNum, chain[0], nres);
00429 serNum = 2;
00430 fprintf(fd, "%3s ", atomlist[i].resname);
00431 for (k=i; k<j; k++) {
00432 if (resid != atomlist[k].resid) {
00433 resid = atomlist[k].resid;
00434 if (!(ires % 13)) {
00435 fprintf(fd, "\nSEQRES %2d %c %4d ", serNum, chain[0], nres);
00436 serNum++;
00437 }
00438 fprintf(fd, "%3s ", atomlist[k].resname);
00439 ires++;
00440 }
00441 }
00442 i = j;
00443 fprintf(fd, "\n");
00444 }
00445 }
00446 #endif
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 static void write_cryst1(FILE *fd, const molfile_timestep_t *ts) {
00485 fprintf(fd, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f P 1 1\n",
00486 ts->A, ts->B, ts->C, ts->alpha, ts->beta, ts->gamma);
00487 }
00488
00489
00490 static int write_timestep(void *v, const molfile_timestep_t *ts) {
00491 pdbdata *pdb = (pdbdata *)v;
00492 const molfile_atom_t *atom;
00493 const float *pos;
00494 int i;
00495 char elementsymbol[3];
00496
00497 if (pdb->natoms == 0)
00498 return MOLFILE_SUCCESS;
00499
00500 if (pdb->first_frame) {
00501
00502
00503
00504 write_cryst1(pdb->fd, ts);
00505 pdb->first_frame = 0;
00506 }
00507 atom = pdb->atomlist;
00508 pos = ts->coords;
00509 for (i=0; i<pdb->natoms; i++) {
00510
00511
00512
00513
00514
00515
00516
00517 #define PDBBAD(x) ((x) < -999.9994f || (x) > 9999.9994f)
00518 if (PDBBAD(pos[0]) || PDBBAD(pos[1]) || PDBBAD(pos[2]) ||
00519 PDBBAD(atom->occupancy) || PDBBAD(atom->bfactor)) {
00520 fprintf(stderr, "PDB WRITE ERROR: Position, occupancy, or b-factor (beta) for atom %d\n", i);
00521 fprintf(stderr, " cannot be written in PDB format.\n");
00522 fprintf(stderr, " File will be truncated.\n");
00523 return MOLFILE_ERROR;
00524 }
00525
00526
00527 strcpy(elementsymbol, (atom->atomicnumber < 1) ? " " : get_pte_label(atom->atomicnumber));
00528 elementsymbol[0] = toupper(elementsymbol[0]);
00529 elementsymbol[1] = toupper(elementsymbol[1]);
00530
00531 if (!write_raw_pdb_record(pdb->fd,
00532 "ATOM ", i+1, atom->name, atom->resname, atom->resid,
00533 atom->insertion, atom->altloc, elementsymbol,
00534 pos[0], pos[1], pos[2],
00535 atom->occupancy, atom->bfactor, atom->chain, atom->segid)) {
00536 fprintf(stderr,
00537 "PDB: Error encoutered writing atom %d; file may be incomplete.\n",
00538 i+1);
00539 return MOLFILE_ERROR;
00540 }
00541 ++atom;
00542 pos += 3;
00543 }
00544 fprintf(pdb->fd, "END\n");
00545
00546 return MOLFILE_SUCCESS;
00547 }
00548
00549 static void close_file_write(void *v) {
00550 pdbdata *pdb = (pdbdata *)v;
00551 fclose(pdb->fd);
00552 free(pdb->atomlist);
00553 free(pdb);
00554 }
00555
00556 static int read_molecule_metadata(void *v, molfile_metadata_t **metadata) {
00557 pdbdata *pdb = (pdbdata *)v;
00558 *metadata = pdb->meta;
00559 return MOLFILE_SUCCESS;
00560 }
00561
00562
00563
00564
00565
00566 static molfile_plugin_t plugin = {
00567 vmdplugin_ABIVERSION,
00568 MOLFILE_PLUGIN_TYPE,
00569 "pdb",
00570 "PDB",
00571 "Justin Gullingsrud, John Stone",
00572 1,
00573 11,
00574 VMDPLUGIN_THREADSAFE,
00575 "pdb,ent",
00576 open_pdb_read,
00577 read_pdb_structure,
00578 read_bonds,
00579 read_next_timestep,
00580 close_pdb_read,
00581 open_file_write,
00582 write_structure,
00583 write_timestep,
00584 close_file_write,
00585 0,
00586 0,
00587 0,
00588 read_molecule_metadata,
00589 };
00590
00591 VMDPLUGIN_API int VMDPLUGIN_init() {
00592 return VMDPLUGIN_SUCCESS;
00593 }
00594
00595 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00596 (*cb)(v, (vmdplugin_t *)&plugin);
00597 return VMDPLUGIN_SUCCESS;
00598 }
00599
00600 VMDPLUGIN_API int VMDPLUGIN_fini() {
00601 return VMDPLUGIN_SUCCESS;
00602 }
00603