00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "molfile_plugin.h"
00019
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <stdlib.h>
00023 #include <ctype.h>
00024
00025 #include "fortread.h"
00026
00027 #define PSF_RECORD_LENGTH 256
00028
00029 typedef struct {
00030 FILE *fp;
00031 int numatoms;
00032 int namdfmt;
00033 int charmmfmt;
00034 int charmmcmap;
00035 int charmmcheq;
00036 int charmmext;
00037 int charmmdrude;
00038 int nbonds;
00039 int *from, *to;
00040 int numangles, *angles;
00041 int numdihedrals, *dihedrals;
00042 int numimpropers, *impropers;
00043 int numcterms, *cterms;
00044 } psfdata;
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 static int strnwscpy_shift(char *target, const char *source,
00062 const int len, const int maxlen) {
00063 int i, c;
00064
00065 for (i=0, c=0; i<maxlen; ++i) {
00066 if (*source == '\0' || (c > 0 && *source == ' ') || (c == 0 && i == len)) {
00067 break;
00068 }
00069
00070 if (*source == ' ') {
00071 source++;
00072 } else {
00073 *target++ = *source++;
00074 c++;
00075 }
00076 }
00077 *target = '\0';
00078 return ( i > len ? i - len : 0 );
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088 static int atoifw(char **ptr, int fw) {
00089 char *op = *ptr;
00090 int ival = 0;
00091 int iws = 0;
00092 char tmpc;
00093
00094 sscanf(op, "%d%n", &ival, &iws);
00095 if ( iws == fw ) {
00096 *ptr += iws;
00097 } else if ( iws < fw ) {
00098 while ( iws < fw && op[iws] == ' ' ) ++iws;
00099 *ptr += iws;
00100 } else if ( iws < 2*fw ) {
00101 *ptr += iws;
00102 } else {
00103 tmpc = op[fw]; op[fw] = '\0';
00104 ival = atoi(op);
00105 op[fw] = tmpc;
00106 *ptr += fw;
00107 }
00108 return ival;
00109 }
00110
00111
00112
00113
00114
00115 static int get_psf_atom(FILE *f, char *name, char *atype, char *resname,
00116 char *segname, int *resid, char *insertion, float *q, float *m,
00117 int namdfmt, int charmmext, int charmmdrude) {
00118 char inbuf[PSF_RECORD_LENGTH+2];
00119 int num;
00120
00121 if (inbuf != fgets(inbuf, PSF_RECORD_LENGTH+1, f)) {
00122 return(-1);
00123 }
00124
00125 if (strlen(inbuf) < 50) {
00126 fprintf(stderr, "Line too short in psf file: \n%s\n", inbuf);
00127 return -1;
00128 }
00129
00130 num = atoi(inbuf);
00131
00132 if (namdfmt == 1) {
00133 int cnt, rcnt;
00134 char residstr[12], trash;
00135 cnt = sscanf(inbuf, "%d %7s %10s %7s %7s %7s %f %f",
00136 &num, segname, residstr, resname, name, atype, q, m);
00137 insertion[0] = ' '; insertion[1] = '\0';
00138 rcnt = sscanf(residstr, "%d%c%c", resid, insertion, &trash);
00139 if (cnt != 8 || rcnt < 1 || rcnt > 2) {
00140 printf("psfplugin) Failed to parse atom line in NAMD PSF file:\n");
00141 printf("psfplugin) '%s'\n", inbuf);
00142 return -1;
00143 }
00144 } else if (charmmdrude == 1 || charmmext == 1) {
00145 int xplorshift;
00146
00147
00148
00149 if ( inbuf[10] != ' ' ||
00150 inbuf[19] != ' ' ||
00151 inbuf[28] != ' ' ||
00152 inbuf[37] != ' ' ||
00153 inbuf[46] != ' ' ) {
00154 printf("psfplugin) Failed to parse atom line in PSF file:\n");
00155 printf("psfplugin) '%s'\n", inbuf);
00156 return -1;
00157 }
00158
00159 strnwscpy(segname, inbuf+11, 7);
00160 strnwscpy(resname, inbuf+29, 7);
00161 strnwscpy(name, inbuf+38, 7);
00162
00163 xplorshift = 0;
00164 strnwscpy(atype, inbuf+47, 4);
00165 if ( ! isdigit(atype[0]) ) {
00166 strnwscpy(atype, inbuf+47, 6);
00167 xplorshift = 2;
00168 }
00169
00170 if ( inbuf[51+xplorshift] != ' ' ) {
00171 printf("psfplugin) Failed to parse atom line in PSF file:\n");
00172 printf("psfplugin) '%s'\n", inbuf);
00173 return -1;
00174 }
00175
00176 insertion[0] = ' '; insertion[1] = '\0';
00177 sscanf(inbuf+20, "%d%c", resid, insertion);
00178 *q = (float) atof(inbuf+52+xplorshift);
00179 *m = (float) atof(inbuf+66+xplorshift);
00180
00181
00182
00183
00184
00185
00186
00187
00188 } else {
00189
00190
00191
00192 const char *rdbuf = inbuf;
00193 char intbuf[16];
00194
00195 intbuf[0] = '\0';
00196 rdbuf += strnwscpy_shift(intbuf, rdbuf, 8, 10);
00197 if ( rdbuf[8] != ' ' ) {
00198 printf("psfplugin) Failed to parse atom index in PSF file:\n");
00199 printf("psfplugin) '%s'\n", inbuf);
00200 return -1;
00201 }
00202 rdbuf += strnwscpy_shift(segname, rdbuf+9, 4, 7);
00203 if ( rdbuf[13] != ' ' ) {
00204 printf("psfplugin) Failed to parse segname in PSF file:\n");
00205 printf("psfplugin) '%s'\n", inbuf);
00206 return -1;
00207 }
00208 intbuf[0] = '\0';
00209 rdbuf += strnwscpy_shift(intbuf, rdbuf+14, 4, 8);
00210 insertion[0] = ' '; insertion[1] = '\0';
00211 sscanf(intbuf, "%d%c", resid, insertion);
00212 if ( rdbuf[18] != ' ' ) {
00213 printf("psfplugin) Failed to parse resid in PSF file:\n");
00214 printf("psfplugin) '%s'\n", inbuf);
00215 return -1;
00216 }
00217 rdbuf += strnwscpy_shift(resname, rdbuf+19, 4, 7);
00218 if ( rdbuf[23] != ' ' ) {
00219 printf("psfplugin) Failed to parse resname in PSF file:\n");
00220 printf("psfplugin) '%s'\n", inbuf);
00221 return -1;
00222 }
00223 rdbuf += strnwscpy_shift(name, rdbuf+24, 4, 7);
00224 if ( rdbuf[28] != ' ' ) {
00225 printf("psfplugin) Failed to parse atom name in PSF file:\n");
00226 printf("psfplugin) '%s'\n", inbuf);
00227 return -1;
00228 }
00229 rdbuf += strnwscpy_shift(atype, rdbuf+29, 4, 7);
00230 if ( rdbuf[33] != ' ' ) {
00231 printf("psfplugin) Failed to parse atom type in PSF file:\n");
00232 printf("psfplugin) '%s'\n", inbuf);
00233 return -1;
00234 }
00235 *q = (float) atof(rdbuf+34);
00236 *m = (float) atof(rdbuf+48);
00237 }
00238
00239 #if 0
00240
00241
00242 if (psf->charmmcheq) {
00243
00244 }
00245 #endif
00246
00247 return num;
00248 }
00249
00250
00251
00252
00253
00254
00255
00256 static int psf_start_block(FILE *file, const char *blockname) {
00257 char inbuf[PSF_RECORD_LENGTH+2];
00258 int nrec = -1;
00259
00260
00261
00262 if (!file)
00263 return -1;
00264
00265
00266 do {
00267 if(inbuf != fgets(inbuf, PSF_RECORD_LENGTH+1, file)) {
00268
00269 return -1;
00270 }
00271 if(strlen(inbuf) > 0 && strstr(inbuf, blockname))
00272 nrec = atoi(inbuf);
00273 } while (nrec == -1);
00274
00275 return nrec;
00276 }
00277
00278
00279
00280
00281
00282 static int psf_get_bonds(FILE *f, int nbond, int fromAtom[], int toAtom[], int charmmext, int namdfmt) {
00283 char *bondptr=NULL;
00284 int fw = charmmext ? 10 : 8;
00285 char inbuf[PSF_RECORD_LENGTH+2];
00286 int i=0;
00287 size_t minlinesize;
00288 int rc=0;
00289
00290 while (i < nbond) {
00291 if (namdfmt) {
00292
00293 int cnt = fscanf(f, "%d %d", &fromAtom[i], &toAtom[i]);
00294 if (cnt < 2) {
00295 fprintf(stderr, "Bonds line too short in NAMD psf file.\n");
00296 break;
00297 }
00298 } else {
00299 if ((i % 4) == 0) {
00300
00301 if (!fgets(inbuf, PSF_RECORD_LENGTH+2, f)) {
00302
00303 break;
00304 }
00305
00306
00307 if (nbond-i >= 4) {
00308 minlinesize = 2*fw*4;
00309 } else {
00310 minlinesize = 2*fw*(nbond-i);
00311 }
00312
00313 if (strlen(inbuf) < minlinesize) {
00314 fprintf(stderr, "Bonds line too short in psf file: \n%s\n", inbuf);
00315 break;
00316 }
00317 bondptr = inbuf;
00318 }
00319
00320 if ((fromAtom[i] = atoifw(&bondptr,fw)) < 1) {
00321 printf("psfplugin) ERROR: Bond %d references atom with index < 1!\n", i);
00322 rc=-1;
00323 break;
00324 }
00325
00326 if ((toAtom[i] = atoifw(&bondptr,fw)) < 1) {
00327 printf("psfplugin) ERROR: Bond %d references atom with index < 1!\n", i);
00328 rc=-1;
00329 break;
00330 }
00331 }
00332
00333 i++;
00334 }
00335
00336 if (rc == -1) {
00337 printf("psfplugin) ERROR: skipping bond info due to bad atom indices\n");
00338 } else if (i != nbond) {
00339 printf("psfplugin) ERROR: unable to read the specified number of bonds!\n");
00340 printf("psfplugin) Expected %d bonds but only read %d\n", nbond, i);
00341 }
00342
00343 return (i == nbond);
00344 }
00345
00346
00347
00348
00349
00350
00351 static void *open_psf_read(const char *path, const char *filetype,
00352 int *natoms) {
00353 FILE *fp;
00354 char inbuf[PSF_RECORD_LENGTH*8+2];
00355 psfdata *psf;
00356 const char *progname = "Charmm";
00357
00358
00359
00360
00361
00362 if (!path)
00363 return NULL;
00364
00365 if ((fp = fopen(path, "r")) == NULL) {
00366 fprintf(stderr, "Couldn't open psf file %s\n", path);
00367 return NULL;
00368 }
00369
00370 *natoms = MOLFILE_NUMATOMS_NONE;
00371
00372 psf = (psfdata *) malloc(sizeof(psfdata));
00373 memset(psf, 0, sizeof(psfdata));
00374 psf->fp = fp;
00375 psf->namdfmt = 0;
00376 psf->charmmfmt = 0;
00377 psf->charmmext = 0;
00378
00379
00380 do {
00381
00382 if (inbuf != fgets(inbuf, PSF_RECORD_LENGTH*8+1, fp)) {
00383
00384 *natoms = MOLFILE_NUMATOMS_NONE;
00385 fclose(fp);
00386 free(psf);
00387 return NULL;
00388 }
00389
00390 if (strlen(inbuf) > 0) {
00391 if (!strstr(inbuf, "REMARKS")) {
00392 if (strstr(inbuf, "PSF")) {
00393 if (strstr(inbuf, "NAMD")) {
00394 psf->namdfmt = 1;
00395 }
00396 if (strstr(inbuf, "EXT")) {
00397 psf->charmmfmt = 1;
00398 psf->charmmext = 1;
00399 }
00400 if (strstr(inbuf, "CHEQ")) {
00401 psf->charmmfmt = 1;
00402 psf->charmmcheq = 1;
00403 }
00404 if (strstr(inbuf, "CMAP")) {
00405 psf->charmmfmt = 1;
00406 psf->charmmcmap = 1;
00407 }
00408 if (strstr(inbuf, "DRUDE")) {
00409 psf->charmmfmt = 1;
00410 psf->charmmdrude = 1;
00411 }
00412 } else if (strstr(inbuf, "NATOM")) {
00413 *natoms = atoi(inbuf);
00414 }
00415 }
00416 }
00417 } while (*natoms == MOLFILE_NUMATOMS_NONE);
00418
00419 if (psf->namdfmt) {
00420 progname = "NAMD";
00421 } else {
00422 progname = "Charmm";
00423 }
00424 if (psf->charmmcheq || psf->charmmcmap) {
00425 printf("psfplugin) Detected a %s PSF file\n", progname);
00426 }
00427 if (psf->charmmext) {
00428 printf("psfplugin) Detected a %s PSF EXTEnded file\n", progname);
00429 }
00430 if (psf->charmmdrude) {
00431 printf("psfplugin) Detected a %s Drude polarizable force field file\n", progname);
00432 printf("psfplugin) WARNING: Support for Drude FF is currently experimental\n");
00433 }
00434
00435 psf->numatoms = *natoms;
00436
00437 return psf;
00438 }
00439
00440 static int read_psf(void *v, int *optflags, molfile_atom_t *atoms) {
00441 psfdata *psf = (psfdata *)v;
00442 int i;
00443
00444
00445 *optflags = MOLFILE_INSERTION | MOLFILE_MASS | MOLFILE_CHARGE;
00446
00447 for (i=0; i<psf->numatoms; i++) {
00448 molfile_atom_t *atom = atoms+i;
00449 if (get_psf_atom(psf->fp, atom->name, atom->type,
00450 atom->resname, atom->segid,
00451 &atom->resid, atom->insertion, &atom->charge, &atom->mass,
00452 psf->namdfmt, psf->charmmext, psf->charmmdrude) < 0) {
00453 fprintf(stderr, "couldn't read atom %d\n", i);
00454 fclose(psf->fp);
00455 psf->fp = NULL;
00456 return MOLFILE_ERROR;
00457 }
00458 atom->chain[0] = atom->segid[0];
00459 atom->chain[1] = '\0';
00460 }
00461
00462 return MOLFILE_SUCCESS;
00463 }
00464
00465
00466 static int read_bonds(void *v, int *nbonds, int **fromptr, int **toptr,
00467 float **bondorder, int **bondtype,
00468 int *nbondtypes, char ***bondtypename) {
00469 psfdata *psf = (psfdata *)v;
00470
00471 *nbonds = psf_start_block(psf->fp, "NBOND");
00472
00473 if (*nbonds > 0) {
00474 psf->from = (int *) malloc(*nbonds*sizeof(int));
00475 psf->to = (int *) malloc(*nbonds*sizeof(int));
00476
00477 if (!psf_get_bonds(psf->fp, *nbonds, psf->from, psf->to,
00478 psf->charmmext, psf->namdfmt)) {
00479 fclose(psf->fp);
00480 psf->fp = NULL;
00481 return MOLFILE_ERROR;
00482 }
00483 *fromptr = psf->from;
00484 *toptr = psf->to;
00485 *bondorder = NULL;
00486 *bondtype = NULL;
00487 *nbondtypes = 0;
00488 *bondtypename = NULL;
00489 } else {
00490 *fromptr = NULL;
00491 *toptr = NULL;
00492 *bondorder = NULL;
00493 *bondtype = NULL;
00494 *nbondtypes = 0;
00495 *bondtypename = NULL;
00496 printf("psfplugin) WARNING: no bonds defined in PSF file.\n");
00497 }
00498
00499 return MOLFILE_SUCCESS;
00500 }
00501
00502
00503 static int psf_get_angles(FILE *f, int n, int *angles, int charmmext) {
00504 char inbuf[PSF_RECORD_LENGTH+2];
00505 char *bondptr = NULL;
00506 int fw = charmmext ? 10 : 8;
00507 int i=0;
00508 while (i<n) {
00509 if((i % 3) == 0) {
00510
00511 if(!fgets(inbuf,PSF_RECORD_LENGTH+2,f)) {
00512
00513 break;
00514 }
00515 bondptr = inbuf;
00516 }
00517 if((angles[3*i] = atoifw(&bondptr,fw)) < 1)
00518 break;
00519 if((angles[3*i+1] = atoifw(&bondptr,fw)) < 1)
00520 break;
00521 if((angles[3*i+2] = atoifw(&bondptr,fw)) < 1)
00522 break;
00523 i++;
00524 }
00525
00526 return (i != n);
00527 }
00528
00529
00530 static int psf_get_dihedrals_impropers(FILE *f, int n, int *dihedrals, int charmmext) {
00531 char inbuf[PSF_RECORD_LENGTH+2];
00532 char *bondptr = NULL;
00533 int fw = charmmext ? 10 : 8;
00534 int i=0;
00535 while (i<n) {
00536 if((i % 2) == 0) {
00537
00538 if(!fgets(inbuf,PSF_RECORD_LENGTH+2,f)) {
00539
00540 break;
00541 }
00542 bondptr = inbuf;
00543 }
00544 if((dihedrals[4*i] = atoifw(&bondptr,fw)) < 1)
00545 break;
00546 if((dihedrals[4*i+1] = atoifw(&bondptr,fw)) < 1)
00547 break;
00548 if((dihedrals[4*i+2] = atoifw(&bondptr,fw)) < 1)
00549 break;
00550 if((dihedrals[4*i+3] = atoifw(&bondptr,fw)) < 1)
00551 break;
00552 i++;
00553 }
00554
00555 return (i != n);
00556 }
00557
00558 #if vmdplugin_ABIVERSION > 14
00559 static int read_angles(void *v, int *numangles, int **angles,
00560 int **angletypes, int *numangletypes,
00561 char ***angletypenames, int *numdihedrals,
00562 int **dihedrals, int **dihedraltypes,
00563 int *numdihedraltypes, char ***dihedraltypenames,
00564 int *numimpropers, int **impropers,
00565 int **impropertypes, int *numimpropertypes,
00566 char ***impropertypenames, int *numcterms,
00567 int **cterms, int *ctermcols, int *ctermrows) {
00568 psfdata *psf = (psfdata *)v;
00569
00570
00571 *numangles = 0;
00572 *angles = NULL;
00573 *angletypes = NULL;
00574 *numangletypes = 0;
00575 *angletypenames = NULL;
00576 *numdihedrals = 0;
00577 *dihedrals = NULL;
00578 *dihedraltypes = NULL;
00579 *numdihedraltypes = 0;
00580 *dihedraltypenames = NULL;
00581 *numimpropers = 0;
00582 *impropers = NULL;
00583 *impropertypes = NULL;
00584 *numimpropertypes = 0;
00585 *impropertypenames = NULL;
00586 *numcterms = 0;
00587 *cterms = NULL;
00588 *ctermrows = 0;
00589 *ctermcols = 0;
00590
00591 psf->numangles = psf_start_block(psf->fp, "NTHETA");
00592 if (psf->numangles > 0) {
00593 psf->angles = (int *) malloc(3*psf->numangles*sizeof(int));
00594 psf_get_angles(psf->fp, psf->numangles, psf->angles, psf->charmmext);
00595 } else {
00596 printf("psfplugin) WARNING: no angles defined in PSF file.\n");
00597 }
00598
00599 psf->numdihedrals = psf_start_block(psf->fp, "NPHI");
00600 if (psf->numdihedrals > 0) {
00601 psf->dihedrals = (int *) malloc(4*psf->numdihedrals*sizeof(int));
00602 psf_get_dihedrals_impropers(psf->fp, psf->numdihedrals, psf->dihedrals, psf->charmmext);
00603 } else {
00604 printf("psfplugin) WARNING: no dihedrals defined in PSF file.\n");
00605 }
00606
00607 psf->numimpropers = psf_start_block(psf->fp, "NIMPHI");
00608 if (psf->numimpropers > 0) {
00609 psf->impropers = (int *) malloc(4*psf->numimpropers*sizeof(int));
00610 psf_get_dihedrals_impropers(psf->fp, psf->numimpropers, psf->impropers, psf->charmmext);
00611 } else {
00612 printf("psfplugin) WARNING: no impropers defined in PSF file.\n");
00613 }
00614
00615 psf->numcterms = psf_start_block(psf->fp, "NCRTERM");
00616 if (psf->numcterms > 0) {
00617 psf->cterms = (int *) malloc(8*psf->numcterms*sizeof(int));
00618
00619
00620 psf_get_dihedrals_impropers(psf->fp, psf->numcterms * 2, psf->cterms, psf->charmmext);
00621 } else {
00622 printf("psfplugin) no cross-terms defined in PSF file.\n");
00623 }
00624
00625 *numangles = psf->numangles;
00626 *angles = psf->angles;
00627
00628 *numdihedrals = psf->numdihedrals;
00629 *dihedrals = psf->dihedrals;
00630
00631 *numimpropers = psf->numimpropers;
00632 *impropers = psf->impropers;
00633
00634 *numcterms = psf->numcterms;
00635 *cterms = psf->cterms;
00636
00637 *ctermcols = 0;
00638 *ctermrows = 0;
00639
00640 return MOLFILE_SUCCESS;
00641 }
00642 #else
00643 static int read_angles(void *v,
00644 int *numangles, int **angles, double **angleforces,
00645 int *numdihedrals, int **dihedrals, double **dihedralforces,
00646 int *numimpropers, int **impropers, double **improperforces,
00647 int *numcterms, int **cterms,
00648 int *ctermcols, int *ctermrows, double **ctermforces) {
00649 psfdata *psf = (psfdata *)v;
00650
00651 psf->numangles = psf_start_block(psf->fp, "NTHETA");
00652 if (psf->numangles > 0) {
00653 psf->angles = (int *) malloc(3*psf->numangles*sizeof(int));
00654 psf_get_angles(psf->fp, psf->numangles, psf->angles);
00655 } else {
00656 printf("psfplugin) WARNING: no angles defined in PSF file.\n");
00657 }
00658
00659 psf->numdihedrals = psf_start_block(psf->fp, "NPHI");
00660 if (psf->numdihedrals > 0) {
00661 psf->dihedrals = (int *) malloc(4*psf->numdihedrals*sizeof(int));
00662 psf_get_dihedrals_impropers(psf->fp, psf->numdihedrals, psf->dihedrals);
00663 } else {
00664 printf("psfplugin) WARNING: no dihedrals defined in PSF file.\n");
00665 }
00666
00667 psf->numimpropers = psf_start_block(psf->fp, "NIMPHI");
00668 if (psf->numimpropers > 0) {
00669 psf->impropers = (int *) malloc(4*psf->numimpropers*sizeof(int));
00670 psf_get_dihedrals_impropers(psf->fp, psf->numimpropers, psf->impropers);
00671 } else {
00672 printf("psfplugin) WARNING: no impropers defined in PSF file.\n");
00673 }
00674
00675 psf->numcterms = psf_start_block(psf->fp, "NCRTERM");
00676 if (psf->numcterms > 0) {
00677 psf->cterms = (int *) malloc(8*psf->numcterms*sizeof(int));
00678
00679
00680 psf_get_dihedrals_impropers(psf->fp, psf->numcterms * 2, psf->cterms);
00681 } else {
00682 printf("psfplugin) no cross-terms defined in PSF file.\n");
00683 }
00684
00685 *numangles = psf->numangles;
00686 *angles = psf->angles;
00687 *angleforces = NULL;
00688
00689 *numdihedrals = psf->numdihedrals;
00690 *dihedrals = psf->dihedrals;
00691 *dihedralforces = NULL;
00692
00693 *numimpropers = psf->numimpropers;
00694 *impropers = psf->impropers;
00695 *improperforces = NULL;
00696
00697 *numcterms = psf->numcterms;
00698 *cterms = psf->cterms;
00699
00700 *ctermcols = 0;
00701 *ctermrows = 0;
00702 *ctermforces = NULL;
00703
00704 return MOLFILE_SUCCESS;
00705 }
00706 #endif
00707
00708 static void close_psf_read(void *mydata) {
00709 psfdata *psf = (psfdata *)mydata;
00710 if (psf) {
00711 if (psf->fp != NULL)
00712 fclose(psf->fp);
00713
00714
00715 if (psf->from != NULL)
00716 free(psf->from);
00717 if (psf->to != NULL)
00718 free(psf->to);
00719
00720
00721 if (psf->angles != NULL)
00722 free(psf->angles);
00723 if (psf->dihedrals != NULL)
00724 free(psf->dihedrals);
00725 if (psf->impropers != NULL)
00726 free(psf->impropers);
00727
00728
00729 if (psf->cterms != NULL)
00730 free(psf->cterms);
00731
00732 free(psf);
00733 }
00734 }
00735
00736
00737 static void *open_psf_write(const char *path, const char *filetype,
00738 int natoms) {
00739 FILE *fp;
00740 psfdata *psf;
00741
00742 fp = fopen(path, "w");
00743 if (!fp) {
00744 fprintf(stderr, "Unable to open file %s for writing\n", path);
00745 return NULL;
00746 }
00747 psf = (psfdata *) malloc(sizeof(psfdata));
00748 memset(psf, 0, sizeof(psfdata));
00749 psf->fp = fp;
00750 psf->numatoms = natoms;
00751 psf->namdfmt = 0;
00752 psf->charmmfmt = 0;
00753 psf->charmmext = 0;
00754 psf->charmmcmap = 0;
00755 psf->charmmcheq = 0;
00756 psf->charmmdrude = 0;
00757 psf->nbonds = 0;
00758 psf->to = NULL;
00759 psf->from = NULL;
00760 return psf;
00761 }
00762
00763 static int write_psf_structure(void *v, int optflags,
00764 const molfile_atom_t *atoms) {
00765 psfdata *psf = (psfdata *)v;
00766 const molfile_atom_t *atom;
00767 int i, fullrows;
00768 int xplorfmt = 0;
00769
00770 for (i=0; i<psf->numatoms; i++) {
00771 if ( ! isdigit(atoms[i].type[0]) ) xplorfmt = 1;
00772 }
00773
00774
00775
00776 if (psf->namdfmt == 0) {
00777 int fw = xplorfmt ? 6 : 4;
00778 for (i=0; i<psf->numatoms; i++) {
00779 if (strlen(atoms[i].type) > fw) {
00780 psf->namdfmt = 1;
00781
00782 }
00783 }
00784 }
00785 if (psf->namdfmt) {
00786 psf->charmmext = 0;
00787 } else {
00788 if (psf->numatoms > 9999999) {
00789 psf->charmmext = 1;
00790 }
00791 if (psf->charmmext == 0) {
00792 for (i=0; i<psf->numatoms; i++) {
00793 if (strlen(atoms[i].name) > 4) {
00794 psf->charmmext = 1;
00795 }
00796 if (xplorfmt && strlen(atoms[i].type) > 4) {
00797 psf->charmmext = 1;
00798 }
00799 }
00800 }
00801 }
00802 if (psf->namdfmt == 1) {
00803 printf("psfplugin) Structure requires space-delimited NAMD PSF format\n");
00804 } else if (psf->charmmext == 1) {
00805 printf("psfplugin) Structure requires EXTended PSF format\n");
00806 }
00807
00808
00809 if (psf->numcterms > 0) {
00810 psf->charmmcmap = 1;
00811 }
00812
00813
00814 fprintf(psf->fp, "PSF");
00815 if (psf->namdfmt == 1)
00816 fprintf(psf->fp, " NAMD");
00817 if (psf->charmmext == 1)
00818 fprintf(psf->fp, " EXT");
00819 if (psf->charmmcmap == 1)
00820 fprintf(psf->fp, " CMAP");
00821 fprintf(psf->fp, psf->charmmext ? "\n\n%10d !NTITLE\n" : "\n\n%8d !NTITLE\n", 1);
00822
00823 if (psf->charmmfmt) {
00824 fprintf(psf->fp," REMARKS %s\n","VMD-generated Charmm PSF structure file");
00825
00826 printf("psfplugin) WARNING: Charmm format PSF file is incomplete, atom type ID\n");
00827 printf("psfplugin) codes have been emitted as '0'. \n");
00828 } else {
00829 fprintf(psf->fp," REMARKS %s\n","VMD-generated NAMD/X-Plor PSF structure file");
00830 }
00831 fprintf(psf->fp, "\n");
00832
00833
00834 fprintf(psf->fp, psf->charmmext ? "%10d !NATOM\n" : "%8d !NATOM\n", psf->numatoms);
00835
00836
00837 for (i=0; i<psf->numatoms; i++) {
00838 const char *atomname;
00839 atom = &atoms[i];
00840 atomname = atom->name;
00841
00842
00843 while (*atomname == ' ')
00844 atomname++;
00845
00846 if (psf->charmmext) {
00847
00848
00849 fprintf(psf->fp, xplorfmt ?
00850 "%10d %-8s %-8d %-8s %-8s %-6s %14.6g %13.6g %7d\n"
00851 : "%10d %-8s %-8d %-8s %-8s %-4s %14.6g %13.6g %7d\n",
00852 i+1, atom->segid, atom->resid, atom->resname,
00853 atomname, atom->type, atom->charge, atom->mass, 0);
00854 } else if (psf->charmmfmt) {
00855
00856
00857 fprintf(psf->fp, "%8d %-4s %-4d %-4s %-4s %4d %14.6g %13.6g %7d\n",
00858 i+1, atom->segid, atom->resid, atom->resname,
00859 atomname, 0, atom->charge, atom->mass, 0);
00860 } else {
00861
00862 fprintf(psf->fp, "%8d %-4s %-4d %-4s %-4s %-4s %14.6g %13.6g %7d\n",
00863 i+1, atom->segid, atom->resid, atom->resname,
00864 atomname, atom->type, atom->charge, atom->mass, 0);
00865 }
00866 }
00867 fprintf(psf->fp, "\n");
00868
00869
00870
00871
00872
00873 if (psf->nbonds > 0 && psf->from != NULL && psf->to != NULL) {
00874 fprintf(psf->fp, psf->charmmext ? "%10d !NBOND: bonds\n" : "%8d !NBOND: bonds\n", psf->nbonds);
00875 for (i=0; i<psf->nbonds; i++) {
00876 if (psf->namdfmt)
00877 fprintf(psf->fp, " %7d %7d", psf->from[i], psf->to[i]);
00878 else if (psf->charmmext)
00879 fprintf(psf->fp, "%10d%10d", psf->from[i], psf->to[i]);
00880 else
00881 fprintf(psf->fp, "%8d%8d", psf->from[i], psf->to[i]);
00882
00883 if ((i % 4) == 3)
00884 fprintf(psf->fp, "\n");
00885 }
00886 if ((i % 4) != 0)
00887 fprintf(psf->fp, "\n");
00888 fprintf(psf->fp, "\n");
00889 } else {
00890 fprintf(psf->fp, psf->charmmext ? "%10d !NBOND: bonds\n" : "%8d !NBOND: bonds\n", 0);
00891 fprintf(psf->fp, "\n\n");
00892 }
00893
00894 if (psf->numangles == 0 && psf->numdihedrals == 0 && psf->numimpropers == 0 && psf->numcterms == 0) {
00895 printf("psfplugin) WARNING: PSF file is incomplete, no angles, dihedrals,\n");
00896 printf("psfplugin) impropers, or cross-terms will be written. \n");
00897
00898 fprintf(psf->fp, psf->charmmext ? "%10d !NTHETA: angles\n\n\n" : "%8d !NTHETA: angles\n\n\n", 0);
00899 fprintf(psf->fp, psf->charmmext ? "%10d !NPHI: dihedrals\n\n\n" : "%8d !NPHI: dihedrals\n\n\n", 0);
00900 fprintf(psf->fp, psf->charmmext ? "%10d !NIMPHI: impropers\n\n\n" : "%8d !NIMPHI: impropers\n\n\n", 0);
00901 } else {
00902 int i, numinline;
00903
00904 printf("psfplugin) Writing angles/dihedrals/impropers...\n");
00905
00906 fprintf(psf->fp, psf->charmmext ? "%10d !NTHETA: angles\n" : "%8d !NTHETA: angles\n", psf->numangles);
00907 for (numinline=0,i=0; i<psf->numangles; i++) {
00908 if ( numinline == 3 ) { fprintf(psf->fp, "\n"); numinline = 0; }
00909 fprintf(psf->fp, psf->charmmext ? "%10d%10d%10d" : " %7d %7d %7d",
00910 psf->angles[i*3], psf->angles[i*3+1], psf->angles[i*3+2]);
00911 numinline++;
00912 }
00913 fprintf(psf->fp, "\n\n");
00914
00915 fprintf(psf->fp, psf->charmmext ? "%10d !NPHI: dihedrals\n" : "%8d !NPHI: dihedrals\n", psf->numdihedrals);
00916 for (numinline=0,i=0; i<psf->numdihedrals; i++) {
00917 if ( numinline == 2 ) { fprintf(psf->fp, "\n"); numinline = 0; }
00918 fprintf(psf->fp, psf->charmmext ? "%10d%10d%10d%10d" : " %7d %7d %7d %7d",
00919 psf->dihedrals[i*4], psf->dihedrals[i*4+1],
00920 psf->dihedrals[i*4+2], psf->dihedrals[i*4+3]);
00921 numinline++;
00922 }
00923 fprintf(psf->fp, "\n\n");
00924
00925 fprintf(psf->fp, psf->charmmext ? "%10d !NIMPHI: impropers\n" : "%8d !NIMPHI: impropers\n", psf->numimpropers);
00926 for (numinline=0,i=0; i<psf->numimpropers; i++) {
00927 if ( numinline == 2 ) { fprintf(psf->fp, "\n"); numinline = 0; }
00928 fprintf(psf->fp, psf->charmmext ? "%10d%10d%10d%10d" : " %7d %7d %7d %7d",
00929 psf->impropers[i*4 ], psf->impropers[i*4+1],
00930 psf->impropers[i*4+2], psf->impropers[i*4+3]);
00931 numinline++;
00932 }
00933 fprintf(psf->fp, "\n\n");
00934 }
00935
00936
00937
00938
00939
00940
00941 if (psf->charmmext) {
00942 fprintf(psf->fp, "%10d !NDON: donors\n\n\n", 0);
00943 fprintf(psf->fp, "%10d !NACC: acceptors\n\n\n", 0);
00944 fprintf(psf->fp, "%10d !NNB\n\n", 0);
00945 } else {
00946 fprintf(psf->fp, "%8d !NDON: donors\n\n\n", 0);
00947 fprintf(psf->fp, "%8d !NACC: acceptors\n\n\n", 0);
00948 fprintf(psf->fp, "%8d !NNB\n\n", 0);
00949 }
00950
00951
00952
00953 fullrows = psf->numatoms/8;
00954 for (i=0; i<fullrows; ++i)
00955 fprintf(psf->fp, psf->charmmext ? "%10d%10d%10d%10d%10d%10d%10d%10d\n" :
00956 "%8d%8d%8d%8d%8d%8d%8d%8d\n", 0, 0, 0, 0, 0, 0, 0, 0);
00957 for (i=psf->numatoms - fullrows*8; i; --i)
00958 fprintf(psf->fp, psf->charmmext ? "%10d" : "%8d", 0);
00959 fprintf(psf->fp, "\n\n");
00960 fprintf(psf->fp, psf->charmmext ? "%8d %7d !NGRP\n%10d%10d%10d\n\n" :
00961 "%8d %7d !NGRP\n%8d%8d%8d\n\n", 1, 0, 0, 0, 0);
00962
00963
00964
00965 if (psf->numcterms > 0) {
00966 fprintf(psf->fp, psf->charmmext ? "%10d !NCRTERM: cross-terms\n" : "%8d !NCRTERM: cross-terms\n", psf->numcterms);
00967 for (i=0; i<psf->numcterms; i++) {
00968 fprintf(psf->fp, psf->charmmext ? "%10d%10d%10d%10d%10d%10d%10d%10d\n" :
00969 " %7d %7d %7d %7d %7d %7d %7d %7d\n",
00970 psf->cterms[i*8 ], psf->cterms[i*8+1],
00971 psf->cterms[i*8+2], psf->cterms[i*8+3],
00972 psf->cterms[i*8+4], psf->cterms[i*8+5],
00973 psf->cterms[i*8+6], psf->cterms[i*8+7]);
00974 }
00975 fprintf(psf->fp, "\n\n");
00976 }
00977
00978 return MOLFILE_SUCCESS;
00979 }
00980
00981 static int write_bonds(void *v, int nbonds, int *fromptr, int *toptr,
00982 float *bondorderptr, int *bondtype,
00983 int nbondtypes, char **bondtypename) {
00984 psfdata *psf = (psfdata *)v;
00985
00986
00987 psf->nbonds = nbonds;
00988 psf->from = (int *) malloc(nbonds * sizeof(int));
00989 memcpy(psf->from, fromptr, nbonds * sizeof(int));
00990 psf->to = (int *) malloc(nbonds * sizeof(int));
00991 memcpy(psf->to, toptr, nbonds * sizeof(int));
00992
00993 return MOLFILE_SUCCESS;
00994 }
00995
00996 #if vmdplugin_ABIVERSION > 14
00997 static int write_angles(void * v, int numangles, const int *angles,
00998 const int *angletypes, int numangletypes,
00999 const char **angletypenames, int numdihedrals,
01000 const int *dihedrals, const int *dihedraltype,
01001 int numdihedraltypes, const char **dihedraltypenames,
01002 int numimpropers, const int *impropers,
01003 const int *impropertypes, int numimpropertypes,
01004 const char **impropertypenames, int numcterms,
01005 const int *cterms, int ctermcols, int ctermrows) {
01006 psfdata *psf = (psfdata *)v;
01007
01008
01009 psf->numangles = numangles;
01010 psf->numdihedrals = numdihedrals;
01011 psf->numimpropers = numimpropers;
01012 psf->numcterms = numcterms;
01013
01014 psf->angles = (int *) malloc(3*psf->numangles*sizeof(int));
01015 memcpy(psf->angles, angles, 3*psf->numangles*sizeof(int));
01016
01017 psf->dihedrals = (int *) malloc(4*psf->numdihedrals*sizeof(int));
01018 memcpy(psf->dihedrals, dihedrals, 4*psf->numdihedrals*sizeof(int));
01019
01020 psf->impropers = (int *) malloc(4*psf->numimpropers*sizeof(int));
01021 memcpy(psf->impropers, impropers, 4*psf->numimpropers*sizeof(int));
01022
01023 psf->cterms = (int *) malloc(8*psf->numcterms*sizeof(int));
01024 memcpy(psf->cterms, cterms, 8*psf->numcterms*sizeof(int));
01025
01026 return MOLFILE_SUCCESS;
01027 }
01028 #else
01029 static int write_angles(void * v,
01030 int numangles, const int *angles, const double *angleforces,
01031 int numdihedrals, const int *dihedrals, const double *dihedralforces,
01032 int numimpropers, const int *impropers, const double *improperforces,
01033 int numcterms, const int *cterms,
01034 int ctermcols, int ctermrows, const double *ctermforces) {
01035 psfdata *psf = (psfdata *)v;
01036
01037
01038 psf->numangles = numangles;
01039 psf->numdihedrals = numdihedrals;
01040 psf->numimpropers = numimpropers;
01041 psf->numcterms = numcterms;
01042
01043 psf->angles = (int *) malloc(3*psf->numangles*sizeof(int));
01044 memcpy(psf->angles, angles, 3*psf->numangles*sizeof(int));
01045
01046 psf->dihedrals = (int *) malloc(4*psf->numdihedrals*sizeof(int));
01047 memcpy(psf->dihedrals, dihedrals, 4*psf->numdihedrals*sizeof(int));
01048
01049 psf->impropers = (int *) malloc(4*psf->numimpropers*sizeof(int));
01050 memcpy(psf->impropers, impropers, 4*psf->numimpropers*sizeof(int));
01051
01052 psf->cterms = (int *) malloc(8*psf->numcterms*sizeof(int));
01053 memcpy(psf->cterms, cterms, 8*psf->numcterms*sizeof(int));
01054
01055 return MOLFILE_SUCCESS;
01056 }
01057 #endif
01058
01059 static void close_psf_write(void *v) {
01060 psfdata *psf = (psfdata *)v;
01061 fclose(psf->fp);
01062
01063
01064 if (psf->from != NULL)
01065 free(psf->from);
01066 if (psf->to != NULL)
01067 free(psf->to);
01068
01069
01070 if (psf->angles)
01071 free(psf->angles);
01072 if (psf->dihedrals)
01073 free(psf->dihedrals);
01074 if (psf->impropers)
01075 free(psf->impropers);
01076
01077
01078 if (psf->cterms)
01079 free(psf->cterms);
01080
01081 free(psf);
01082 }
01083
01084
01085
01086
01087
01088
01089 static molfile_plugin_t plugin;
01090
01091 VMDPLUGIN_API int VMDPLUGIN_init() {
01092 memset(&plugin, 0, sizeof(molfile_plugin_t));
01093 plugin.abiversion = vmdplugin_ABIVERSION;
01094 plugin.type = MOLFILE_PLUGIN_TYPE;
01095 plugin.name = "psf";
01096 plugin.prettyname = "CHARMM,NAMD,XPLOR PSF";
01097 plugin.author = "Justin Gullingsrud, John Stone";
01098 plugin.majorv = 1;
01099 plugin.minorv = 9;
01100 plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
01101 plugin.filename_extension = "psf";
01102 plugin.open_file_read = open_psf_read;
01103 plugin.read_structure = read_psf;
01104 plugin.read_bonds = read_bonds;
01105 #if vmdplugin_ABIVERSION > 9
01106 plugin.read_angles = read_angles;
01107 #endif
01108 plugin.close_file_read = close_psf_read;
01109 plugin.open_file_write = open_psf_write;
01110 plugin.write_structure = write_psf_structure;
01111 plugin.close_file_write = close_psf_write;
01112 plugin.write_bonds = write_bonds;
01113 #if vmdplugin_ABIVERSION > 9
01114 plugin.write_angles = write_angles;
01115 #endif
01116 return VMDPLUGIN_SUCCESS;
01117 }
01118
01119 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
01120 (*cb)(v, (vmdplugin_t *)&plugin);
01121 return VMDPLUGIN_SUCCESS;
01122 }
01123
01124 VMDPLUGIN_API int VMDPLUGIN_fini() {
01125 return VMDPLUGIN_SUCCESS;
01126 }