00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifdef _MSC_VER
00017
00018 #define _CRT_SECURE_NO_WARNINGS
00019 #define _CRT_SECURE_NO_DEPRECATE
00020 #endif
00021
00022 #include <molfile_plugin.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <errno.h>
00026 #include <ctype.h>
00027 #include <string.h>
00028
00029 #ifdef _USE_TCL
00030 #include <tcl.h>
00031 #endif
00032 #ifdef _USE_ZLIB
00033 #include <zlib.h>
00034 #define VTFFILE gzFile
00035 #define fopen gzopen
00036 #define feof gzeof
00037 #define fgets(buf,size,file) gzgets(file,buf,size)
00038 #define fclose gzclose
00039 #else
00040 #define VTFFILE FILE*
00041 #endif
00042
00043 #ifdef _MSC_VER
00044 #define strdup _strdup
00045 #endif
00046
00047 #define VERSION_MAJOR 2
00048 #define VERSION_MINOR 4
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 static molfile_atom_t default_atom;
00061 char* default_userdata;
00062 const char *molid;
00063 const char* userdata_varname;
00064 #ifdef _USE_TCL
00065 Tcl_Interp *tcl_interp;
00066 #endif
00067
00068 #define VTF_MOLFILE 0
00069 #define VTF_USERDATA 1
00070
00071
00072 typedef struct {
00073
00074 VTFFILE file;
00075
00076 int return_code;
00077
00078 int read_mode;
00079
00080
00081
00082 int natoms;
00083 molfile_atom_t *atoms;
00084 int optflags;
00085
00086
00087 int nbonds;
00088 int *from;
00089 int *to;
00090
00091
00092 unsigned int timestep;
00093
00094 int timestep_mode;
00095
00096 float A, B, C, alpha, beta, gamma;
00097 float *coords;
00098 } vtf_data;
00099
00100
00101 #define TIMESTEP_INDEXED 0
00102 #define TIMESTEP_ORDERED 1
00103 #define TIMESTEP_VCFSTART 2
00104
00105
00106 static int vtf_lineno = 0;
00107
00108 #ifdef _USE_TCL
00109
00110 void vtf_set_atom_userdata(const int aid, const char* userdata) {
00111 static char array_index[255];
00112 if (userdata == NULL) return;
00113 sprintf(array_index, "%s.atom.%d", molid, aid);
00114 Tcl_SetVar2(tcl_interp, userdata_varname, array_index, userdata, 0);
00115 }
00116
00117
00118 void vtf_set_timestep_userdata(const unsigned int timestep,
00119 const char* userdata) {
00120 static char array_index[255];
00121 if (userdata == NULL || strlen(userdata) == 0) return;
00122 sprintf(array_index, "%s.step%d", molid, timestep);
00123 Tcl_SetVar2(tcl_interp, userdata_varname, array_index, userdata, 0);
00124 }
00125
00126
00127 void vtf_set_coordinate_userdata(const unsigned int timestep,
00128 const int aid,
00129 const char* userdata) {
00130 static char array_index[255];
00131 if (userdata == NULL || strlen(userdata) == 0) return;
00132 sprintf(array_index, "%s.step%d.%d", molid, timestep, aid);
00133 Tcl_SetVar2(tcl_interp, userdata_varname, array_index, userdata, 0);
00134 }
00135 #endif
00136
00137
00138
00139
00140 static void vtf_error(const char *msg, const char *line) {
00141 char message[255];
00142 sprintf(message, "vtfplugin:%d: error: %s: \"%s\"\n",
00143 vtf_lineno, msg, line);
00144
00145
00146
00147
00148
00149
00150 printf("%s", message);
00151
00152 }
00153
00154
00155
00156
00157 static void sfree(void* ptr) {
00158 if (ptr != NULL) free(ptr);
00159 }
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 static char *vtf_getline(VTFFILE file) {
00173 static char *buffer = NULL;
00174 static int buffer_size = 0;
00175 char *s;
00176 int bytes_left;
00177 int l;
00178
00179 if (buffer == NULL) {
00180 buffer_size = 255;
00181 buffer = malloc(buffer_size);
00182
00183 }
00184
00185
00186 s = buffer;
00187 bytes_left = buffer_size;
00188
00189 if (feof(file)) {
00190 sfree(buffer);
00191 buffer = NULL;
00192 return NULL;
00193 }
00194 do {
00195
00196 if (fgets(s, bytes_left, file) == NULL) {
00197 sfree(buffer);
00198 buffer = NULL;
00199 return NULL;
00200 }
00201
00202 vtf_lineno++;
00203
00204
00205 if (feof(file)) break;
00206
00207
00208 l = strlen(s) - 1;
00209 if (l >= 0 && ( s[l] == '\n' || s[l] == '\r')) {
00210 l--;
00211
00212 while (l >= 0 && (s[l] == '\n' || s[l] == '\r')) l--;
00213
00214 s[l+1] = '\0';
00215
00216 if (l >= 0 && s[l] == '\\') {
00217
00218
00219 bytes_left -= l+1;
00220 s += l+1;
00221 } else
00222
00223 break;
00224 } else {
00225
00226
00227 buffer_size += 255;
00228 buffer = realloc(buffer, buffer_size);
00229
00230
00231 l = strlen(buffer);
00232 s = buffer + l;
00233 bytes_left += buffer_size - l;
00234 vtf_lineno--;
00235 }
00236 } while (1);
00237
00238
00239 s = buffer;
00240
00241
00242 while (isspace(s[0])) s++;
00243
00244
00245 if (s[0] == '#') return vtf_getline(file);
00246
00247 l = strlen(s);
00248
00249
00250 if (l == 0) {
00251 if (feof(file)) {
00252 sfree(buffer);
00253 buffer = NULL;
00254 return NULL;
00255 }
00256 else return vtf_getline(file);
00257 }
00258
00259 return s;
00260 }
00261
00262
00263
00264
00265
00266 static void vtf_create_atoms_as_needed(int max_aid, vtf_data *d) {
00267
00268 if (d->natoms < max_aid+1) {
00269 int aid;
00270
00271 d->atoms = realloc(d->atoms, (max_aid+1)*sizeof(molfile_atom_t));
00272 for (aid = d->natoms; aid <= max_aid; aid++)
00273 d->atoms[aid] = default_atom;
00274 d->natoms = max_aid+1;
00275 #ifdef _USE_TCL
00276 if (d->read_mode != VTF_MOLFILE) {
00277
00278 for (aid = d->natoms; aid <= max_aid; aid++)
00279 vtf_set_atom_userdata(aid, default_userdata);
00280 }
00281 #endif
00282 }
00283 }
00284
00285
00286
00287
00288
00289
00290
00291 static int *vtf_parse_aid_specifier(char *s, vtf_data *d) {
00292 int n;
00293 unsigned int aid, from, to, offset;
00294 unsigned int size = 0;
00295 int *aid_list = NULL;
00296
00297 if (s[0] == 'd') {
00298
00299
00300 #ifdef DEBUG
00301 printf("%s", "\tdefine default atom\n");
00302 #endif
00303 } else {
00304
00305 while (1) {
00306 from = d->natoms;
00307
00308 if (sscanf(s, " %u:%u%n", &from, &to, &n) == 2) {
00309
00310 if (from > to) {
00311 vtf_error("bad range specifier (from > to):", s);
00312 sfree(aid_list);
00313 return NULL;
00314 }
00315 vtf_create_atoms_as_needed(to, d);
00316
00317 offset = size;
00318 size += to-from+1;
00319 aid_list = realloc(aid_list, size*sizeof(int));
00320 for (aid = from; aid <= to; aid++) {
00321 aid_list[offset] = aid;
00322 offset++;
00323 }
00324
00325 } else if (sscanf(s, " %u%n", &to, &n) == 1) {
00326
00327 vtf_create_atoms_as_needed(to, d);
00328
00329 size += 1;
00330 aid_list = realloc(aid_list, size*sizeof(int));
00331 aid_list[size - 1] = to;
00332
00333 } else {
00334
00335 vtf_error("bad aid specifier", s);
00336 sfree(aid_list);
00337 return NULL;
00338 }
00339
00340
00341 s += n;
00342
00343
00344 if (s[0] == '\0') break;
00345
00346
00347 if (s[0] != ',') {
00348 vtf_error("bad aid specifier", s);
00349 sfree(aid_list);
00350 return NULL;
00351 }
00352
00353 s++;
00354 };
00355 }
00356
00357
00358 aid_list = realloc(aid_list, (size+1)*sizeof(int));
00359 aid_list[size] = -1;
00360 return aid_list;
00361 }
00362
00363
00364
00365
00366 static int vtf_parse_atom(char *line, vtf_data *d) {
00367 static molfile_atom_t atom;
00368 static char keyword[255];
00369 static char msg[255];
00370 static char aid_specifier[255];
00371 int n;
00372 char *s;
00373 int rest_is_userdata;
00374 int *aid_list = NULL;
00375
00376 atom = default_atom;
00377 s = line;
00378
00379 #ifdef DEBUG
00380 printf("\tatom record\n");
00381 printf("line: %s\n", s);
00382 #endif
00383
00384
00385
00386
00387 if (sscanf(s, " %255s%n", aid_specifier, &n) < 1) {
00388 vtf_error("atom specifier is missing", line);
00389 return MOLFILE_ERROR;
00390 }
00391 s += n;
00392
00393 aid_list = vtf_parse_aid_specifier(aid_specifier, d);
00394 if (aid_list == NULL) return MOLFILE_ERROR;
00395
00396
00397 #define AIDLOOP(assignment) \
00398 { \
00399 int *aid_ptr; \
00400 for (aid_ptr = aid_list; *aid_ptr != -1; aid_ptr++) { \
00401 int aid = *aid_ptr; \
00402 molfile_atom_t *cur_atom = &d->atoms[aid]; \
00403 assignment; \
00404 } \
00405 }
00406
00407
00408 rest_is_userdata = 0;
00409 while (sscanf(s, " %255s%n", keyword, &n) == 1) {
00410 s += n;
00411 #ifdef DEBUG
00412 printf("keyword: \"%s\" rest: \"%s\"\n", keyword, s);
00413 #endif
00414 switch (tolower(keyword[0])) {
00415 case 'n': {
00416
00417 if (sscanf(s, " %16s%n", atom.name, &n) == 1) {
00418 AIDLOOP(strcpy(cur_atom->name, atom.name));
00419 } else {
00420 vtf_error("could not get name in atom record", line);
00421 return MOLFILE_ERROR;
00422 }
00423 s += n;
00424 break;
00425 }
00426 case 't': {
00427
00428 if (sscanf(s, " %16s%n", atom.type, &n) == 1) {
00429 AIDLOOP(strcpy(cur_atom->type, atom.type));
00430 } else {
00431 vtf_error("could not get type in atom record", line);
00432 return MOLFILE_ERROR;
00433 }
00434 s += n;
00435 break;
00436 }
00437 case 'r': {
00438
00439 if (strlen(keyword) == 1 ||
00440 strncmp(keyword, "rad", 3) == 0) {
00441
00442 if (sscanf(s, " %f%n", &atom.radius, &n) == 1) {
00443 AIDLOOP(cur_atom->radius = atom.radius);
00444 } else {
00445 vtf_error("could not get radius in atom record", line);
00446 sfree(aid_list);
00447 return MOLFILE_ERROR;
00448 }
00449 d->optflags |= MOLFILE_RADIUS;
00450 } else if (strcmp(keyword, "resid") == 0) {
00451
00452 if (sscanf(s, " %d%n", &atom.resid, &n) == 1) {
00453 AIDLOOP(cur_atom->resid = atom.resid);
00454 } else {
00455 vtf_error("could not get resid in atom record", line);
00456 sfree(aid_list);
00457 return MOLFILE_ERROR;
00458 }
00459 } else if (strcmp(keyword, "res") == 0 ||
00460 strcmp(keyword, "resname") == 0) {
00461
00462 if (sscanf(s, " %8s%n", atom.resname, &n) == 1) {
00463 AIDLOOP(strcpy(cur_atom->resname, atom.resname));
00464 } else {
00465 vtf_error("could not get resname in atom record", line);
00466 sfree(aid_list);
00467 return MOLFILE_ERROR;
00468 }
00469 } else {
00470 strcpy(msg, "unrecognized keyword in atom record: ");
00471 strncat(msg, keyword, 200);
00472 vtf_error(msg, line);
00473 sfree(aid_list);
00474 return MOLFILE_ERROR;
00475 }
00476 s += n;
00477 break;
00478 }
00479 case 's': {
00480
00481 if (sscanf(s, " %8s%n", atom.segid, &n) == 1) {
00482 AIDLOOP(strcpy(cur_atom->segid, atom.segid));
00483 } else {
00484 vtf_error("could not get segid in atom record", line);
00485 sfree(aid_list);
00486 return MOLFILE_ERROR;
00487 }
00488 s += n;
00489 break;
00490 }
00491 case 'i': {
00492
00493 if (sscanf(s, " %2s%n", atom.insertion, &n) == 1) {
00494 AIDLOOP(strcpy(cur_atom->insertion, atom.insertion));
00495 } else {
00496 vtf_error("could not get insertion in atom record", line);
00497 sfree(aid_list);
00498 return MOLFILE_ERROR;
00499 }
00500 d->optflags |= MOLFILE_INSERTION;
00501 s += n;
00502 break;
00503 }
00504 case 'c': {
00505
00506 if (strlen(keyword) == 1 ||
00507 strcmp(keyword, "chain") == 0) {
00508 if (sscanf(s, " %2s%n", atom.chain, &n) == 1) {
00509 AIDLOOP(strcpy(cur_atom->chain, atom.chain));
00510 s += n;
00511 break;
00512 } else {
00513 vtf_error("could not get chain in atom record", line);
00514 sfree(aid_list);
00515 return MOLFILE_ERROR;
00516 }
00517 }
00518 }
00519 case 'q': {
00520
00521 if (strlen(keyword) == 1 ||
00522 strcmp(keyword, "charge") == 0) {
00523 if (sscanf(s, " %f%n", &atom.charge, &n) == 1) {
00524 AIDLOOP(cur_atom->charge = atom.charge);
00525 } else {
00526 vtf_error("could not get charge in atom record", line);
00527 sfree(aid_list);
00528 return MOLFILE_ERROR;
00529 }
00530 d->optflags |= MOLFILE_CHARGE;
00531 } else {
00532 strcpy(msg, "unrecognized keyword in atom record: ");
00533 strncat(msg, keyword, 200);
00534 vtf_error(msg, line);
00535 sfree(aid_list);
00536 return MOLFILE_ERROR;
00537 }
00538 s += n;
00539 break;
00540 }
00541 case 'a': {
00542
00543 if (strlen(keyword)== 1 ||
00544 strcmp(keyword, "atomicnumber") == 0) {
00545 if (sscanf(s, " %d%n", &atom.atomicnumber, &n) == 1) {
00546 AIDLOOP(cur_atom->atomicnumber = atom.atomicnumber);
00547 } else {
00548 vtf_error("could not get atomicnumber in atom record", line);
00549 sfree(aid_list);
00550 return MOLFILE_ERROR;
00551 }
00552 d->optflags |= MOLFILE_ATOMICNUMBER;
00553 } else if (strcmp(keyword, "altloc")) {
00554 if (sscanf(s, " %2s%n", atom.altloc, &n) == 1) {
00555 AIDLOOP(strcpy(cur_atom->altloc, atom.altloc));
00556 } else {
00557 vtf_error("could not get altloc in atom record", line);
00558 sfree(aid_list);
00559 return MOLFILE_ERROR;
00560 }
00561 d->optflags |= MOLFILE_ALTLOC;
00562 } else {
00563 strcpy(msg, "unrecognized keyword in atom record: ");
00564 strncat(msg, keyword, 200);
00565 vtf_error(msg, line);
00566 sfree(aid_list);
00567 return MOLFILE_ERROR;
00568 }
00569 s += n;
00570 break;
00571 }
00572 case 'o': {
00573
00574 if (sscanf(s, " %f%n", &atom.occupancy, &n) == 1) {
00575 AIDLOOP(cur_atom->occupancy = atom.occupancy);
00576 } else {
00577 vtf_error("could not get occupancy in atom record", line);
00578 sfree(aid_list);
00579 return MOLFILE_ERROR;
00580 }
00581 d->optflags |= MOLFILE_OCCUPANCY;
00582 s += n;
00583 break;
00584 }
00585 case 'b': {
00586
00587 if (sscanf(s, " %f%n", &atom.bfactor, &n) == 1) {
00588 AIDLOOP(cur_atom->bfactor = atom.bfactor);
00589 } else {
00590 vtf_error("could not get bfactor in atom record", line);
00591 sfree(aid_list);
00592 return MOLFILE_ERROR;
00593 }
00594 d->optflags |= MOLFILE_BFACTOR;
00595 s += n;
00596 break;
00597 }
00598 case 'm': {
00599
00600 if (sscanf(s, " %f%n", &atom.mass, &n) == 1) {
00601 AIDLOOP(cur_atom->mass = atom.mass);
00602 } else {
00603 vtf_error("could not get mass in atom record", line);
00604 sfree(aid_list);
00605 return MOLFILE_ERROR;
00606 }
00607 d->optflags |= MOLFILE_MASS;
00608 s += n;
00609 break;
00610 }
00611 case 'u': {
00612
00613 rest_is_userdata = 1;
00614 #ifdef _USE_TCL
00615 if (d->read_mode != VTF_MOLFILE) {
00616 AIDLOOP(vtf_set_atom_userdata(aid, s));
00617 }
00618 #endif
00619 break;
00620 }
00621 default: {
00622
00623 strcpy(msg, "unrecognized keyword in atom record: ");
00624 strncat(msg, keyword, 200);
00625 vtf_error(msg, line);
00626 sfree(aid_list);
00627 return MOLFILE_ERROR;
00628 }
00629 }
00630 if (rest_is_userdata) break;
00631 }
00632
00633
00634 if (*aid_list == -1) {
00635 default_atom = atom;
00636 if (d->read_mode != VTF_MOLFILE) {
00637 sfree(default_userdata);
00638 default_userdata = strdup(s);
00639 }
00640 }
00641
00642 sfree(aid_list);
00643
00644 #ifdef DEBUG
00645 printf("\tparsed keywords\n");
00646 #endif
00647
00648 return MOLFILE_SUCCESS;
00649 }
00650
00651
00652
00653
00654
00655
00656
00657 static int vtf_parse_bond(char *line, vtf_data *d) {
00658 char *s;
00659 int n;
00660 unsigned int from, to, aid, bid;
00661
00662 s = line;
00663
00664 while (1) {
00665 if (sscanf(s, " %u::%u%n", &from, &to, &n) == 2) {
00666
00667 if (from > to) {
00668 vtf_error("bad chain specifier (from > to):", s);
00669 return MOLFILE_ERROR;
00670 }
00671 bid = d->nbonds;
00672 d->nbonds += to-from;
00673 d->from = realloc(d->from, d->nbonds*sizeof(int));
00674 d->to = realloc(d->to, d->nbonds*sizeof(int));
00675
00676 for (aid = from; aid < to; aid++) {
00677
00678 d->from[bid] = aid+1;
00679 d->to[bid] = aid+2;
00680 bid++;
00681 }
00682 } else if (sscanf(s, " %u:%u%n", &from, &to, &n) == 2) {
00683
00684 d->nbonds += 1;
00685 d->from = realloc(d->from, d->nbonds*sizeof(int));
00686 d->to = realloc(d->to, d->nbonds*sizeof(int));
00687
00688 d->from[d->nbonds-1] = from+1;
00689 d->to[d->nbonds-1] = to+1;
00690 } else {
00691 vtf_error("bad bond specifier", s);
00692 return MOLFILE_ERROR;
00693 }
00694
00695 s += n;
00696
00697
00698 if (strlen(s) == 0) break;
00699
00700
00701 if (s[0] != ',') {
00702 vtf_error("bad bond specifier in line", line);
00703 return MOLFILE_ERROR;
00704 }
00705
00706 s++;
00707 }
00708
00709 return MOLFILE_SUCCESS;
00710 }
00711
00712
00713
00714
00715
00716
00717
00718
00719 static int vtf_parse_pbc(char *line, vtf_data *d) {
00720 char *s;
00721 int n = 0;
00722
00723 if (sscanf(line, " %f %f %f%n", &d->A, &d->B, &d->C, &n) < 3) {
00724 s = line;
00725 vtf_error("Couldn't parse unit cell dimensions", s);
00726 return MOLFILE_ERROR;
00727 }
00728 s = line + n;
00729
00730 n = sscanf(s, " %f %f %f", &d->alpha, &d->beta, &d->gamma);
00731 if (n > 0 && n < 3) {
00732 vtf_error("Couldn't parse unit cell angles", line);
00733 return MOLFILE_ERROR;
00734 }
00735 return MOLFILE_SUCCESS;
00736 }
00737
00738
00739
00740
00741 static int vtf_parse_timestep(char *line, vtf_data *d) {
00742 while (strlen(line) > 0 && isspace(line[0])) line++;
00743 if (strlen(line) == 0) {
00744 d->timestep_mode = TIMESTEP_ORDERED;
00745 } else {
00746 switch (tolower(line[0])) {
00747 case 'o': { d->timestep_mode = TIMESTEP_ORDERED; break; }
00748 case 'i': { d->timestep_mode = TIMESTEP_INDEXED; break; }
00749 default: {
00750 vtf_error("bad timestep line", line);
00751 return MOLFILE_ERROR;
00752 }
00753 }
00754 }
00755 return MOLFILE_SUCCESS;
00756 }
00757
00758
00759 static void vtf_parse_structure(vtf_data *d) {
00760 char *line;
00761 char s[255];
00762 int n;
00763
00764
00765 strcpy(default_atom.name, "X");
00766 strcpy(default_atom.type, "X");
00767 strcpy(default_atom.resname, "X");
00768 default_atom.resid = 0;
00769 strcpy(default_atom.segid, "");
00770 strcpy(default_atom.chain, "");
00771
00772 strcpy(default_atom.altloc, "");
00773 strcpy(default_atom.insertion, "");
00774 default_atom.occupancy = 1.0;
00775 default_atom.bfactor = 1.0;
00776 default_atom.mass = 1.0;
00777 default_atom.charge = 0.0;
00778 default_atom.radius = 1.0;
00779
00780 default_userdata = NULL;
00781
00782 do {
00783 line = vtf_getline(d->file);
00784 if (line == NULL) break;
00785 #ifdef DEBUG
00786 printf("parsing line %d: \"%s\"\n", vtf_lineno, line);
00787 #endif
00788 switch (tolower(line[0])) {
00789
00790 case 'a': {
00791
00792 sscanf(line, " %255s%n", s, &n);
00793 line += n;
00794 }
00795 case '0':
00796 case '1':
00797 case '2':
00798 case '3':
00799 case '4':
00800 case '5':
00801 case '6':
00802 case '7':
00803 case '8':
00804 case '9':
00805 case 'd': {
00806
00807 d->return_code = vtf_parse_atom(line, d);
00808 break;
00809 }
00810
00811
00812 case 'b': {
00813
00814 sscanf(line, " %255s%n", s, &n);
00815 line += n;
00816 d->return_code = vtf_parse_bond(line, d);
00817 break;
00818 }
00819
00820
00821 case 'u':
00822 case 'p': {
00823
00824 sscanf(line, " %255s%n", s, &n);
00825 line += n;
00826 d->return_code = vtf_parse_pbc(line, d);
00827 break;
00828 }
00829
00830
00831 case 'c':
00832 case 't': {
00833
00834 sscanf(line, " %255s%n", s, &n);
00835 line += n;
00836 }
00837 case 'i':
00838 case 'o': {
00839 d->return_code = vtf_parse_timestep(line, d);
00840 line = NULL;
00841 break;
00842 }
00843
00844
00845 default: {
00846 vtf_error("unknown line type", line);
00847 d->return_code = MOLFILE_ERROR;
00848 break;
00849 }
00850 }
00851 } while (line != NULL &&
00852 d->return_code == MOLFILE_SUCCESS);
00853
00854
00855 if (d->read_mode == VTF_MOLFILE &&
00856 d->atoms == NULL &&
00857 d->return_code == MOLFILE_SUCCESS) {
00858 d->return_code = MOLFILE_NOSTRUCTUREDATA;
00859 }
00860
00861
00862 if (errno != 0) {
00863 perror("vtfplugin");
00864 d->return_code = MOLFILE_ERROR;
00865 }
00866
00867 sfree(default_userdata);
00868 }
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885 static vtf_data *
00886 _vtf_open_file_read(const char *filepath,
00887 const char *filetype,
00888 int *natoms,
00889 int read_mode) {
00890 vtf_data *d;
00891
00892
00893
00894
00895
00896 d = malloc(sizeof(vtf_data));
00897
00898 errno = 0;
00899
00900 d->return_code = MOLFILE_SUCCESS;
00901 d->read_mode = read_mode;
00902
00903
00904 d->optflags = MOLFILE_NOOPTIONS;
00905 d->natoms = 0;
00906 d->atoms = NULL;
00907 d->nbonds = 0;
00908 d->from = NULL;
00909 d->to = NULL;
00910
00911
00912 d->timestep = 0;
00913 d->timestep_mode = TIMESTEP_ORDERED;
00914 d->coords = NULL;
00915 d->A = 0.0;
00916 d->B = 0.0;
00917 d->C = 0.0;
00918 d->alpha = 90.0;
00919 d->beta = 90.0;
00920 d->gamma = 90.0;
00921
00922
00923 d->file = fopen(filepath, "rb");
00924 if (d->file == NULL) {
00925
00926 char msg[255];
00927 sprintf(msg, "vtfplugin: %s", filepath);
00928 perror(msg);
00929 sfree(d);
00930 return NULL;
00931 }
00932
00933 if (strcmp(filetype, "vcf") == 0) {
00934 d->timestep_mode = TIMESTEP_VCFSTART;
00935 d->natoms = MOLFILE_NUMATOMS_UNKNOWN;
00936 *natoms = MOLFILE_NUMATOMS_UNKNOWN;
00937 d->return_code = MOLFILE_NOSTRUCTUREDATA;
00938 } else {
00939 vtf_parse_structure(d);
00940
00941 if (d->return_code != MOLFILE_SUCCESS) {
00942
00943 fclose(d->file);
00944
00945
00946 sfree(d->atoms);
00947 sfree(d->coords);
00948 sfree(d->from);
00949 sfree(d->to);
00950 sfree(d);
00951 return NULL;
00952 }
00953
00954 *natoms = d->natoms;
00955 }
00956
00957 return d;
00958 }
00959
00960
00961 static void *
00962 vtf_open_file_read(const char *filepath,
00963 const char *filetype,
00964 int *natoms) {
00965 return _vtf_open_file_read(filepath, filetype, natoms, VTF_MOLFILE);
00966 }
00967
00968
00969 static void vtf_close_file_read(void *data) {
00970 vtf_data *d;
00971
00972 if (data == NULL) return;
00973 d = (vtf_data*)data;
00974
00975
00976
00977
00978 fclose(d->file);
00979
00980
00981 sfree(d->coords);
00982 sfree(d->from);
00983 sfree(d->to);
00984 sfree(d);
00985 }
00986
00987
00988
00989 static int vtf_read_next_timestep(void *data,
00990 int natoms,
00991 molfile_timestep_t *ts) {
00992 vtf_data *d;
00993 char *line;
00994 static char s[255];
00995 float x,y,z;
00996 unsigned int aid;
00997 int n;
00998
00999 if (data == NULL) {
01000 vtf_error("Internal error: data==NULL in vtf_read_next_timestep", 0);
01001 return MOLFILE_ERROR;
01002 }
01003
01004 if (natoms <= 0) {
01005 vtf_error("Internal error: natoms <= 0 in vtf_read_next_timestep", 0);
01006 return MOLFILE_ERROR;
01007 }
01008
01009 errno = 0;
01010
01011 d = (vtf_data*)data;
01012
01013 aid = 0;
01014
01015 if (feof(d->file)) return MOLFILE_EOF;
01016
01017 if (d->coords == NULL) {
01018
01019 d->coords = malloc(natoms*3*sizeof(float));
01020
01021 for (n = 0; n < natoms*3; n++)
01022 d->coords[n] = 0.0;
01023 }
01024
01025
01026 do {
01027 line = vtf_getline(d->file);
01028
01029 if (line == NULL) {
01030 if (errno != 0) {
01031 perror("vtfplugin");
01032 return MOLFILE_ERROR;
01033 }
01034 break;
01035 }
01036
01037
01038 if (d->timestep_mode == TIMESTEP_VCFSTART) {
01039 switch (tolower(line[0])) {
01040 case 'c':
01041 case 't':
01042
01043 sscanf(line, " %255s%n", s, &n);
01044 line += n;
01045 case 'i':
01046 case 'o':
01047 if (vtf_parse_timestep(line, d) != MOLFILE_SUCCESS)
01048 return MOLFILE_ERROR;
01049 line = vtf_getline(d->file);
01050 break;
01051 default:
01052
01053 d->timestep_mode = TIMESTEP_ORDERED;
01054 }
01055 }
01056
01057
01058 if (d->timestep_mode == TIMESTEP_ORDERED
01059 && sscanf(line, " %f %f %f%n", &x, &y, &z, &n) == 3) {
01060 if (aid < (unsigned int)natoms) {
01061 d->coords[aid*3] = x;
01062 d->coords[aid*3+1] = y;
01063 d->coords[aid*3+2] = z;
01064 #ifdef _USE_TCL
01065 if (d->read_mode == VTF_USERDATA) {
01066
01067 line += n;
01068 vtf_set_coordinate_userdata(d->timestep, aid, line);
01069 }
01070 #endif
01071 aid++;
01072 } else {
01073 vtf_error("too many atom coordinates in ordered timestep block", line);
01074 return MOLFILE_ERROR;
01075 }
01076 } else if (d->timestep_mode == TIMESTEP_INDEXED
01077 && sscanf(line, " %u %f %f %f%n",
01078 &aid, &x, &y, &z, &n) == 4) {
01079 if (aid < (unsigned int)natoms) {
01080 d->coords[aid*3] = x;
01081 d->coords[aid*3+1] = y;
01082 d->coords[aid*3+2] = z;
01083 #ifdef _USE_TCL
01084 if (d->read_mode == VTF_USERDATA) {
01085
01086 line += n;
01087 vtf_set_coordinate_userdata(d->timestep, aid, line);
01088 }
01089 #endif
01090 } else {
01091 vtf_error("atom id too large in indexed timestep block", line);
01092 return MOLFILE_ERROR;
01093 }
01094 } else switch (tolower(line[0])) {
01095
01096 case 'u':
01097 case 'p': {
01098
01099 sscanf(line, " %255s%n", s, &n);
01100 line += n;
01101 if (vtf_parse_pbc(line, d) != MOLFILE_SUCCESS)
01102 return MOLFILE_ERROR;
01103 break;
01104 }
01105
01106
01107 case 'd': {
01108
01109 sscanf(line, " %255s%n", s, &n);
01110 #ifdef _USE_TCL
01111 if (d->read_mode == VTF_USERDATA) {
01112 line += n;
01113 vtf_set_timestep_userdata(d->timestep, line);
01114 }
01115 #endif
01116 break;
01117 }
01118
01119
01120 case 'c':
01121 case 't': {
01122
01123 sscanf(line, " %255s%n", s, &n);
01124 line += n;
01125 }
01126 case 'i':
01127 case 'o': {
01128 if (vtf_parse_timestep(line, d) != MOLFILE_SUCCESS)
01129 return MOLFILE_ERROR;
01130 line = NULL;
01131 d->timestep++;
01132 break;
01133 }
01134
01135 default: {
01136 if (d->timestep_mode == TIMESTEP_INDEXED)
01137 vtf_error("unknown line in indexed timestep block", line);
01138 else
01139 vtf_error("unknown line in ordered timestep block", line);
01140 return MOLFILE_ERROR;
01141 }
01142 }
01143
01144 if (line == NULL) break;
01145 } while (1);
01146
01147 if (ts != NULL) {
01148
01149 ts->A = d->A;
01150 ts->B = d->B;
01151 ts->C = d->C;
01152 ts->alpha = d->alpha;
01153 ts->beta = d->beta;
01154 ts->gamma = d->gamma;
01155 memcpy(ts->coords, d->coords, natoms*3*sizeof(float));
01156 ts->velocities = NULL;
01157 ts->physical_time = 0.0;
01158 }
01159
01160 return MOLFILE_SUCCESS;
01161 }
01162
01163
01164
01165
01166 static int vtf_read_structure(void *data,
01167 int *optflags,
01168 molfile_atom_t *atoms) {
01169 vtf_data *d;
01170 d = (vtf_data*)data;
01171
01172 if (d->return_code != MOLFILE_SUCCESS)
01173 return d->return_code;
01174
01175 if (d->natoms > 0) {
01176
01177 memcpy(atoms, d->atoms, d->natoms*sizeof(molfile_atom_t));
01178
01179 sfree(d->atoms);
01180 d->atoms = NULL;
01181 }
01182
01183 *optflags = d->optflags;
01184
01185 return MOLFILE_SUCCESS;
01186 }
01187
01188 static int vtf_read_bonds(void *data,
01189 int *nbonds,
01190 int **from,
01191 int **to,
01192 float **bondorder,
01193 int **bondtype,
01194 int *nbondtypes,
01195 char ***bondtypename) {
01196 vtf_data *d;
01197 if (!data) {
01198 vtf_error("Internal error: data==NULL in vtf_read_bonds", 0);
01199 return MOLFILE_ERROR;
01200 }
01201
01202 d = (vtf_data*)data;
01203
01204 *nbonds = d->nbonds;
01205 *from = d->from;
01206 *to = d->to;
01207 *bondorder = NULL;
01208 *bondtype = NULL;
01209 *nbondtypes = 0;
01210 *bondtypename = NULL;
01211
01212 return MOLFILE_SUCCESS;
01213 }
01214
01215
01216
01217
01218 static molfile_plugin_t vsfplugin;
01219 static molfile_plugin_t vtfplugin;
01220 static molfile_plugin_t vcfplugin;
01221
01222 VMDPLUGIN_API int VMDPLUGIN_init() {
01223 memset(&vsfplugin, 0, sizeof(molfile_plugin_t));
01224 vsfplugin.abiversion = vmdplugin_ABIVERSION;
01225 vsfplugin.type = MOLFILE_PLUGIN_TYPE;
01226 vsfplugin.name = "vsf";
01227 vsfplugin.author = "Olaf Lenz";
01228 vsfplugin.majorv = VERSION_MAJOR;
01229 vsfplugin.minorv = VERSION_MINOR;
01230 vsfplugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
01231 vsfplugin.filename_extension = "vsf";
01232 vsfplugin.open_file_read = vtf_open_file_read;
01233 vsfplugin.read_structure = vtf_read_structure;
01234 vsfplugin.read_bonds = vtf_read_bonds;
01235
01236 vsfplugin.close_file_read = vtf_close_file_read;
01237 #if vmdplugin_ABIVERSION >= 9
01238 vsfplugin.prettyname = "VTF structure format";
01239 #endif
01240
01241 memset(&vcfplugin, 0, sizeof(molfile_plugin_t));
01242 vcfplugin.abiversion = vmdplugin_ABIVERSION;
01243 vcfplugin.type = MOLFILE_PLUGIN_TYPE;
01244 vcfplugin.name = "vcf";
01245 vcfplugin.author = "Olaf Lenz";
01246 vcfplugin.majorv = VERSION_MAJOR;
01247 vcfplugin.minorv = VERSION_MINOR;
01248 vcfplugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
01249 vcfplugin.filename_extension = "vcf";
01250 vcfplugin.open_file_read = vtf_open_file_read;
01251 vcfplugin.read_next_timestep = vtf_read_next_timestep;
01252 vcfplugin.close_file_read = vtf_close_file_read;
01253 #if vmdplugin_ABIVERSION >= 9
01254 vcfplugin.prettyname = "VTF coordinate format";
01255 #endif
01256
01257 memset(&vtfplugin, 0, sizeof(molfile_plugin_t));
01258 vtfplugin.abiversion = vmdplugin_ABIVERSION;
01259 vtfplugin.type = MOLFILE_PLUGIN_TYPE;
01260 vtfplugin.name = "vtf";
01261 vtfplugin.author = "Olaf Lenz";
01262 vtfplugin.majorv = VERSION_MAJOR;
01263 vtfplugin.minorv = VERSION_MINOR;
01264 vtfplugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
01265 vtfplugin.filename_extension = "vtf";
01266 vtfplugin.open_file_read = vtf_open_file_read;
01267 vtfplugin.read_structure = vtf_read_structure;
01268 vtfplugin.read_bonds = vtf_read_bonds;
01269 vtfplugin.read_next_timestep = vtf_read_next_timestep;
01270 vtfplugin.close_file_read = vtf_close_file_read;
01271 #if vmdplugin_ABIVERSION >= 9
01272 vtfplugin.prettyname = "VTF trajectory format";
01273 #endif
01274
01275
01276
01277 return VMDPLUGIN_SUCCESS;
01278 }
01279
01280 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
01281 (*cb)(v, (vmdplugin_t *)&vsfplugin);
01282 (*cb)(v, (vmdplugin_t *)&vcfplugin);
01283 (*cb)(v, (vmdplugin_t *)&vtfplugin);
01284 return VMDPLUGIN_SUCCESS;
01285 }
01286
01287 VMDPLUGIN_API int VMDPLUGIN_fini() {
01288 return VMDPLUGIN_SUCCESS;
01289 }
01290
01291 #ifdef _USE_TCL
01292
01293
01294
01295 static int vtf_parse_userdata(ClientData clientData,
01296 Tcl_Interp *interp,
01297 int argc,
01298 const char *argv[]) {
01299
01300 int natoms;
01301 const char *file, *type;
01302 vtf_data *d;
01303 char result[255];
01304 int rc;
01305
01306 if (argc != 5) {
01307 sprintf(result, "wrong # args: should be \"%s fileName fileType varName molId\"", argv[0]);
01308 Tcl_SetResult(interp, result, TCL_VOLATILE);
01309 return TCL_ERROR;
01310 }
01311
01312 file = argv[1];
01313 type = argv[2];
01314 userdata_varname = argv[3];
01315 molid = argv[4];
01316 tcl_interp = interp;
01317
01318 d = _vtf_open_file_read(file, type, &natoms, VTF_USERDATA);
01319 if (d == NULL) {
01320 sprintf(result, "%s: an error occured while reading the structure", argv[0]);
01321 Tcl_SetResult(interp, result, TCL_VOLATILE);
01322 return TCL_ERROR;
01323 }
01324
01325 do {
01326 rc = vtf_read_next_timestep(d, d->natoms, NULL);
01327 } while (rc == MOLFILE_SUCCESS);
01328
01329 sprintf(result, "%s: Read %d atoms and %d timesteps.",
01330 argv[0], d->natoms, d->timestep);
01331 Tcl_SetResult(interp, result, TCL_VOLATILE);
01332 vtf_close_file_read(d);
01333 return TCL_OK;
01334 }
01335
01336 int Vtfplugin_Init(Tcl_Interp *interp) {
01337 char version_string[20];
01338
01339
01340 if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
01341 Tcl_SetResult(interp, "Tcl_InitStubs failed", TCL_STATIC);
01342 return TCL_ERROR;
01343 }
01344
01345 sprintf(version_string, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
01346 if (Tcl_PkgProvide(interp, "vtfplugin", version_string) == TCL_ERROR) {
01347 return TCL_ERROR;
01348 }
01349
01350
01351 Tcl_CreateCommand(interp,
01352 "vtf_parse_userdata", vtf_parse_userdata,
01353 NULL, NULL);
01354 return TCL_OK;
01355 }
01356 #endif