00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <math.h>
00028 #include <string.h>
00029
00030 #include "molfile_plugin.h"
00031 #include "unit_conversion.h"
00032
00033 #ifndef M_PI_2
00034 #define M_PI_2 1.57079632679489661922
00035 #endif
00036
00037 #include "periodic_table.h"
00038
00039 #define THISPLUGIN plugin
00040 #include "vmdconio.h"
00041
00042 static const float bohr = BOHR_TO_ANGS;
00043
00044
00045 typedef struct {
00046 float A, B, C, alpha, beta, gamma;
00047 } cube_box;
00048
00049 typedef struct {
00050 FILE *fd;
00051 int nsets;
00052 int numatoms;
00053 bool coord;
00054 long crdpos, datapos;
00055 char *file_name;
00056 float *datacache;
00057 molfile_volumetric_t *vol;
00058 float origin[3];
00059 float rotmat[3][3];
00060 cube_box box;
00061 } cube_t;
00062
00063
00064
00065
00066 static int cube_readbox(cube_box *box, float *x, float *y, float *z) {
00067 float A, B, C;
00068
00069 if (!box) {
00070 return 1;
00071 }
00072
00073
00074 box->A = 10.0;
00075 box->B = 10.0;
00076 box->C = 10.0;
00077 box->alpha = 90.0;
00078 box->beta = 90.0;
00079 box->gamma = 90.0;
00080
00081
00082 A = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] );
00083 B = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] );
00084 C = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] );
00085 if ((A<=0) || (B<=0) || (C<=0)) {
00086 return 1;
00087 }
00088 box->A = A;
00089 box->B = B;
00090 box->C = C;
00091
00092
00093
00094 box->gamma = acos( (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])/(A*B) ) * 90.0/M_PI_2;
00095 box->beta = acos( (x[0]*z[0]+x[1]*z[1]+x[2]*z[2])/(A*C) ) * 90.0/M_PI_2;
00096 box->alpha = acos( (y[0]*z[0]+y[1]*z[1]+y[2]*z[2])/(B*C) ) * 90.0/M_PI_2;
00097
00098 return 0;
00099 }
00100
00101
00102 static void cube_buildrotmat(cube_t *cube, float *o, float *a, float *b)
00103 {
00104
00105 const double len = sqrt(a[0]*a[0] + a[1]*a[1]);
00106 const double phi = atan2((double) a[2], (double) len);
00107 const double theta = atan2((double) a[1], (double) a[0]);
00108
00109 const double cph = cos(phi);
00110 const double cth = cos(theta);
00111 const double sph = sin(phi);
00112 const double sth = sin(theta);
00113
00114
00115 const double psi = atan2(-sph*cth*b[0] - sph*sth*b[1] + cph*b[2],-sth*b[0] + cth*b[1]);
00116 const double cps = cos(psi);
00117 const double sps = sin(psi);
00118
00119 const double r[3][3] = {
00120 { cph*cth, cph*sth, sph},
00121 {-sth*cps - sph*cth*sps, cth*cps - sph*sth*sps, cph*sps},
00122 { sth*sps - sph*cth*cps, -cth*sps - sph*sth*cps, cph*cps}
00123 };
00124
00125 for (int i=0; i<3; ++i) {
00126 cube->origin[i] = o[i];
00127 for (int j=0; j<3; ++j) {
00128 cube->rotmat[i][j] = r[i][j];
00129 }
00130 }
00131 }
00132
00133
00134 static void eatline(FILE * fd) {
00135 char readbuf[1025];
00136 fgets(readbuf, 1024, fd);
00137 }
00138
00139
00140 static void close_cube_read(void *v);
00141
00142 static void *open_cube_read(const char *filepath, const char *filetype,
00143 int *natoms) {
00144 FILE *fd;
00145 cube_t *cube;
00146 int xsize, ysize, zsize;
00147 float a[3], b[3], c[3];
00148 int i;
00149
00150 fd = fopen(filepath, "rb");
00151 if (!fd)
00152 return NULL;
00153
00154 cube = new cube_t;
00155 cube->fd = fd;
00156 cube->vol = NULL;
00157 cube->coord = false;
00158 cube->file_name = strdup(filepath);
00159 cube->datacache = NULL;
00160
00161
00162 for (i=0; i<3; ++i) {
00163 for (int j=0; j<3; ++j) {
00164 cube->rotmat[i][j] = 0.0;
00165 }
00166 }
00167 for (i=0; i<3; ++i) {
00168 cube->origin[i] = 0.0;
00169 cube->rotmat[i][i] = 1.0;
00170 }
00171
00172 molfile_volumetric_t voltmpl;
00173
00174
00175 char readbuf[256];
00176 fgets(readbuf, 256, cube->fd);
00177
00178
00179 strcpy(voltmpl.dataname, "Gaussian Cube: ");
00180 strncat(voltmpl.dataname, readbuf, 240);
00181
00182 eatline(cube->fd);
00183
00184
00185 if (fscanf(cube->fd, "%d", &cube->numatoms) != 1) {
00186 close_cube_read(cube);
00187 return NULL;
00188 }
00189
00190 if (cube->numatoms > 0) {
00191 cube->nsets = 1;
00192 } else {
00193
00194 cube->numatoms = - cube->numatoms;
00195 cube->nsets = 0;
00196 }
00197 *natoms = cube->numatoms;
00198
00199
00200 if ( fscanf(cube->fd, "%f %f %f",
00201 &voltmpl.origin[0],
00202 &voltmpl.origin[1],
00203 &voltmpl.origin[2]) != 3 ) {
00204 close_cube_read(cube);
00205 return NULL;
00206 }
00207
00208
00209 if ((fscanf(cube->fd, "%d", &xsize) != 1) ||
00210 (fscanf(cube->fd, "%f %f %f", &a[0], &a[1], &a[2]) != 3)) {
00211 close_cube_read(cube);
00212 return NULL;
00213 }
00214
00215 if ((fscanf(cube->fd, "%d", &ysize) != 1) ||
00216 (fscanf(cube->fd, "%f %f %f", &b[0], &b[1], &b[2]) != 3)) {
00217 close_cube_read(cube);
00218 return NULL;
00219 }
00220
00221 if ((fscanf(cube->fd, "%d", &zsize) != 1) ||
00222 (fscanf(cube->fd, "%f %f %f", &c[0], &c[1], &c[2]) != 3)) {
00223 close_cube_read(cube);
00224 return NULL;
00225 }
00226
00227
00228 voltmpl.xsize = xsize;
00229 voltmpl.ysize = ysize;
00230 voltmpl.zsize = zsize;
00231 voltmpl.has_color = 0;
00232
00233 eatline(cube->fd);
00234
00235
00236
00237
00238
00239 cube_buildrotmat(cube, voltmpl.origin, a, b);
00240
00241 if ((fabs((double) a[1]) + fabs((double) a[2]) + fabs((double) b[2]))
00242 > 0.001) {
00243 vmdcon_printf(VMDCON_WARN,
00244 "cubeplugin) Coordinates will be rotated to comply \n");
00245 vmdcon_printf(VMDCON_WARN,
00246 "cubeplugin) with VMD's conventions for periodic display.\n");
00247 }
00248
00249
00250
00251
00252 voltmpl.origin[0] *= bohr;
00253 voltmpl.origin[1] *= bohr;
00254 voltmpl.origin[2] *= bohr;
00255
00256
00257 for (i=0; i<3; ++i) {
00258 voltmpl.xaxis[i] = cube->rotmat[i][0] * a[0]
00259 + cube->rotmat[i][1] * a[1] + cube->rotmat[i][2] * a[2];
00260
00261 voltmpl.yaxis[i] = cube->rotmat[i][0] * b[0]
00262 + cube->rotmat[i][1] * b[1] + cube->rotmat[i][2] * b[2];
00263
00264 voltmpl.zaxis[i] = cube->rotmat[i][0] * c[0]
00265 + cube->rotmat[i][1] * c[1] + cube->rotmat[i][2] * c[2];
00266 }
00267
00268 voltmpl.xaxis[0] *= bohr * xsize;
00269 voltmpl.xaxis[1] *= bohr * xsize;
00270 voltmpl.xaxis[2] *= bohr * xsize;
00271
00272 voltmpl.yaxis[0] *= bohr * ysize;
00273 voltmpl.yaxis[1] *= bohr * ysize;
00274 voltmpl.yaxis[2] *= bohr * ysize;
00275
00276 voltmpl.zaxis[0] *= bohr * zsize;
00277 voltmpl.zaxis[1] *= bohr * zsize;
00278 voltmpl.zaxis[2] *= bohr * zsize;
00279
00280 #if 1
00281
00282
00283
00284
00285
00286
00287
00288
00289 voltmpl.origin[0] -= 0.5 * ( voltmpl.xaxis[0] / (double) xsize
00290 + voltmpl.yaxis[0] / (double) ysize
00291 + voltmpl.zaxis[0] / (double) zsize);
00292 voltmpl.origin[1] -= 0.5 * ( voltmpl.xaxis[1] / (double) xsize
00293 + voltmpl.yaxis[1] / (double) ysize
00294 + voltmpl.zaxis[1] / (double) zsize);
00295 voltmpl.origin[2] -= 0.5 * ( voltmpl.xaxis[2] / (double) xsize
00296 + voltmpl.yaxis[2] / (double) ysize
00297 + voltmpl.zaxis[2] / (double) zsize);
00298 #endif
00299
00300 #if defined(TEST_PLUGIN)
00301 printf("cell before rotation:\n");
00302 printf("a: %12.8f %12.8f %12.8f\n", a[0]*xsize*bohr, a[1]*ysize*bohr, a[2]*zsize*bohr);
00303 printf("b: %12.8f %12.8f %12.8f\n", b[0]*xsize*bohr, b[1]*ysize*bohr, b[2]*zsize*bohr);
00304 printf("c: %12.8f %12.8f %12.8f\n", c[0]*xsize*bohr, c[1]*ysize*bohr, c[2]*zsize*bohr);
00305
00306 printf("cell after rotation:\n");
00307 printf("x: %12.8f %12.8f %12.8f\n", voltmpl.xaxis[0], voltmpl.xaxis[1], voltmpl.xaxis[2]);
00308 printf("y: %12.8f %12.8f %12.8f\n", voltmpl.yaxis[0], voltmpl.yaxis[1], voltmpl.yaxis[2]);
00309 printf("z: %12.8f %12.8f %12.8f\n", voltmpl.zaxis[0], voltmpl.zaxis[1], voltmpl.zaxis[2]);
00310 #endif
00311
00312
00313 if (cube_readbox(&(cube->box), voltmpl.xaxis, voltmpl.yaxis, voltmpl.zaxis)) {
00314 vmdcon_printf(VMDCON_WARN, "cubeplugin) Calculation of unit cell "
00315 "size failed. Continuing anyways...\n");
00316 }
00317
00318 cube->crdpos = ftell(cube->fd);
00319
00320
00321
00322 if (cube->nsets >0) {
00323 int i;
00324
00325
00326 cube->vol = new molfile_volumetric_t[1];
00327 memcpy(cube->vol, &voltmpl, sizeof(voltmpl));
00328
00329
00330 for (i=0; i < cube->numatoms; i++) {
00331 eatline(cube->fd);
00332 }
00333
00334 cube->datapos = ftell(cube->fd);
00335
00336
00337 } else {
00338 int i;
00339
00340
00341
00342 for (i=0; i < cube->numatoms; i++) {
00343 eatline(cube->fd);
00344 }
00345
00346 fscanf(cube->fd, "%d", &cube->nsets);
00347 vmdcon_printf(VMDCON_INFO, "cubeplugin) found %d orbitals\n", cube->nsets);
00348 cube->vol = new molfile_volumetric_t[cube->nsets];
00349 for (i=0; i < cube->nsets; ++i) {
00350 int orb;
00351 fscanf(cube->fd, "%d", &orb);
00352 memcpy(&cube->vol[i], &voltmpl, sizeof(voltmpl));
00353 sprintf(cube->vol[i].dataname, "Gaussian Cube: Orbital %d", orb);
00354 }
00355
00356 eatline(cube->fd);
00357 cube->datapos = ftell(cube->fd);
00358
00359
00360 }
00361
00362 return cube;
00363 }
00364
00365
00366 static int read_cube_structure(void *v, int *optflags, molfile_atom_t *atoms) {
00367 int i, j;
00368 char *k;
00369 molfile_atom_t *atom;
00370
00371 cube_t *cube = (cube_t *)v;
00372
00373
00374 fseek(cube->fd, cube->crdpos, SEEK_SET);
00375
00376
00377
00378
00379 *optflags = MOLFILE_ATOMICNUMBER | MOLFILE_MASS | MOLFILE_RADIUS | MOLFILE_CHARGE;
00380
00381 for(i=0;i<cube->numatoms;i++) {
00382 int idx;
00383 float chrg;
00384 char fbuffer[1024];
00385
00386 atom = atoms + i;
00387
00388 k = fgets(fbuffer, 1024, cube->fd);
00389 j=sscanf(fbuffer, "%d %f %*f %*f %*f", &idx, &chrg);
00390 if (k == NULL) {
00391 vmdcon_printf(VMDCON_ERROR, "cube structure) missing atom(s) in "
00392 "file '%s'\n",cube->file_name);
00393 vmdcon_printf(VMDCON_ERROR, "cube structure) expecting '%d' atoms,"
00394 " found only '%d'\n",cube->numatoms,i+1);
00395 return MOLFILE_ERROR;
00396 } else if (j < 2) {
00397 vmdcon_printf(VMDCON_INFO, "cube structure) missing atom data in file"
00398 " '%s' for atom '%d'\n",cube->file_name,i+1);
00399 return MOLFILE_ERROR;
00400 }
00401
00402
00403 atom->atomicnumber = idx;
00404 strncpy(atom->name, get_pte_label(idx), sizeof(atom->name));
00405 strncpy(atom->type, atom->name, sizeof(atom->type));
00406 atom->mass = get_pte_mass(idx);
00407 atom->radius = get_pte_vdw_radius(idx);
00408 atom->resname[0] = '\0';
00409 atom->resid = 1;
00410 atom->chain[0] = '\0';
00411 atom->segid[0] = '\0';
00412 atom->charge = chrg;
00413
00414 }
00415
00416 return MOLFILE_SUCCESS;
00417 }
00418
00419
00420 static int read_cube_timestep(void *v, int natoms, molfile_timestep_t *ts) {
00421 int i, j, n;
00422 char fbuffer[1024];
00423 float x, y, z;
00424 char *k;
00425
00426 cube_t *cube = (cube_t *)v;
00427
00428
00429 if (cube->coord) return MOLFILE_EOF;
00430 cube->coord = true;
00431
00432
00433 fseek(cube->fd, cube->crdpos, SEEK_SET);
00434
00435
00436
00437
00438 for (i=0; i<cube->numatoms; i++) {
00439 k = fgets(fbuffer, 1024, cube->fd);
00440 j = sscanf(fbuffer, "%*d %*f %f %f %f", &x, &y, &z);
00441
00442 if (k == NULL) {
00443 return MOLFILE_ERROR;
00444 } else if (j < 3) {
00445 vmdcon_printf(VMDCON_ERROR, "cube timestep) missing type or coordinate(s)"
00446 " in file '%s' for atom '%d'\n",cube->file_name,i+1);
00447 return MOLFILE_ERROR;
00448 } else if (j>=3) {
00449 if (ts != NULL) {
00450
00451
00452
00453
00454
00455
00456
00457 x -= cube->origin[0];
00458 y -= cube->origin[1];
00459 z -= cube->origin[2];
00460
00461 for (n=0; n<3; ++n) {
00462 ts->coords[3*i + n] = bohr*(cube->origin[n]
00463 + cube->rotmat[n][0] * x
00464 + cube->rotmat[n][1] * y
00465 + cube->rotmat[n][2] * z);
00466 }
00467 }
00468 } else {
00469 break;
00470 }
00471 }
00472
00473 if (ts != NULL) {
00474 ts->A = cube->box.A;
00475 ts->B = cube->box.B;
00476 ts->C = cube->box.C;
00477 ts->alpha = cube->box.alpha;
00478 ts->beta = cube->box.beta;
00479 ts->gamma = cube->box.gamma;
00480 }
00481
00482 return MOLFILE_SUCCESS;
00483 }
00484
00485 static int read_cube_metadata(void *v, int *nsets,
00486 molfile_volumetric_t **metadata) {
00487 cube_t *cube = (cube_t *)v;
00488 *nsets = cube->nsets;
00489 *metadata = cube->vol;
00490
00491 return MOLFILE_SUCCESS;
00492 }
00493
00494 static int read_cube_data(void *v, int set, float *datablock, float *colorblock) {
00495 cube_t *cube = (cube_t *)v;
00496
00497 vmdcon_printf(VMDCON_INFO, "cubeplugin) trying to read cube data set %d\n", set);
00498
00499 int xsize = cube->vol[set].xsize;
00500 int ysize = cube->vol[set].ysize;
00501 int zsize = cube->vol[set].zsize;
00502 int xysize = xsize*ysize;
00503 int nsize = cube->nsets;
00504 int nzsize = nsize*zsize;
00505 int nyzsize = nsize*zsize*ysize;
00506 int x, y, z;
00507
00508
00509 fseek(cube->fd, cube->datapos, SEEK_SET);
00510
00511
00512
00513
00514 if (cube->nsets == 1) {
00515 for (x=0; x<xsize; x++) {
00516 for (y=0; y<ysize; y++) {
00517 for (z=0; z<zsize; z++) {
00518 if (fscanf(cube->fd, "%f", &datablock[z*xysize + y*xsize + x]) != 1) {
00519 return MOLFILE_ERROR;
00520 }
00521 }
00522 }
00523 }
00524 } else {
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534 if (cube->datacache == NULL) {
00535 int points = xsize*ysize*zsize * nsize;
00536 int i;
00537
00538
00539 vmdcon_printf(VMDCON_INFO, "cubeplugin) creating %d MByte cube orbital"
00540 " cache.\n", (int) (points*sizeof(float)) / 1048576);
00541 cube->datacache = new float[points];
00542
00543 for (i=0; i < points; ++i) {
00544 if (fscanf(cube->fd, "%f", &cube->datacache[i]) != 1) {
00545 return MOLFILE_ERROR;
00546 }
00547
00548
00549
00550
00551 if ((i % (1048576/sizeof(float))) == 0) {
00552 fprintf(stderr, ".");
00553 }
00554 }
00555 }
00556
00557 for (x=0; x<xsize; x++) {
00558 for (y=0; y<ysize; y++) {
00559 for (z=0; z<zsize; z++) {
00560 datablock[z*xysize + y*xsize + x] = cube->datacache[x*nyzsize + y*nzsize + z*nsize + set];
00561 }
00562 }
00563 }
00564 }
00565
00566 return MOLFILE_SUCCESS;
00567 }
00568
00569 static void close_cube_read(void *v) {
00570 cube_t *cube = (cube_t *)v;
00571
00572 fclose(cube->fd);
00573 if (cube->vol) {
00574 delete[] cube->vol;
00575 }
00576 free(cube->file_name);
00577 if (cube->datacache) {
00578 vmdcon_printf(VMDCON_INFO, "cubeplugin) freeing cube orbital cache.\n");
00579 delete[] cube->datacache;
00580 }
00581
00582 delete cube;
00583 }
00584
00585
00586
00587
00588
00589 int VMDPLUGIN_init(void) {
00590 memset(&plugin, 0, sizeof(molfile_plugin_t));
00591 plugin.abiversion = vmdplugin_ABIVERSION;
00592 plugin.type = MOLFILE_PLUGIN_TYPE;
00593 plugin.name = "cube";
00594 plugin.prettyname = "Gaussian Cube";
00595 plugin.author = "Axel Kohlmeyer, John Stone";
00596 plugin.majorv = 1;
00597 plugin.minorv = 1;
00598 plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
00599 plugin.filename_extension = "cub,cube";
00600 plugin.open_file_read = open_cube_read;
00601 plugin.read_structure = read_cube_structure;
00602 plugin.read_next_timestep = read_cube_timestep;
00603 plugin.close_file_read = close_cube_read;
00604 plugin.read_volumetric_metadata = read_cube_metadata;
00605 plugin.read_volumetric_data = read_cube_data;
00606 return VMDPLUGIN_SUCCESS;
00607 }
00608
00609 int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00610 (*cb)(v, (vmdplugin_t *)&plugin);
00611 return VMDPLUGIN_SUCCESS;
00612 }
00613
00614 int VMDPLUGIN_fini(void) { return VMDPLUGIN_SUCCESS; }
00615
00616
00617
00618 #ifdef TEST_PLUGIN
00619
00620 int main(int argc, char *argv[]) {
00621 int natoms;
00622 void *v;
00623 int i, nsets, set;
00624 molfile_volumetric_t * meta;
00625
00626 while (--argc) {
00627 ++argv;
00628 v = open_cube_read(*argv, "cube", &natoms);
00629 if (!v) {
00630 fprintf(stderr, "open_cube_read failed for file %s\n", *argv);
00631 return 1;
00632 }
00633 fprintf(stderr, "open_cube_read succeeded for file %s\n", *argv);
00634
00635
00636 if (read_cube_metadata(v, &nsets, &meta)) {
00637 return 1;
00638 }
00639 fprintf(stderr, "read_cube_metadata succeeded for file %s\n", *argv);
00640
00641 for (set=0; set<nsets; set++) {
00642 printf("Loading volume set: %d\n", set);
00643
00644 int elements = meta[set].xsize * meta[set].ysize * meta[set].zsize;
00645 printf(" Grid Elements: %d\n", elements);
00646 printf(" Grid dimensions: X: %d Y: %d Z: %d\n",
00647 meta[set].xsize, meta[set].ysize, meta[set].zsize);
00648
00649 float * voldata = (float *) malloc(sizeof(float) * elements);
00650 float * coldata = NULL;
00651
00652 if (meta[set].has_color) {
00653 coldata = (float *) malloc(sizeof(float) * elements * 3);
00654 }
00655
00656
00657 if (read_cube_data(v, set, voldata, coldata)) {
00658 return 1;
00659 }
00660
00661 printf("First 6 elements:\n ");
00662 for (i=0; i<6; i++) {
00663 printf("%g, ", voldata[i]);
00664 }
00665 printf("\n");
00666
00667 printf("Last 6 elements:\n ");
00668 for (i=elements - 6; i<elements; i++) {
00669 printf("%g, ", voldata[i]);
00670 }
00671 printf("\n");
00672 }
00673
00674 close_cube_read(v);
00675 }
00676 return 0;
00677 }
00678
00679 #endif