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