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