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
00026
00027
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <math.h>
00031 #include <string.h>
00032
00033 #ifndef M_PI
00034 #define M_PI 3.14159265358979323846
00035 #endif
00036
00037 #include "molfile_plugin.h"
00038 #include "endianswap.h"
00039
00040 #define CCP4HDSIZE 1024
00041
00042 typedef struct {
00043 FILE *fd;
00044 int nsets;
00045 int swap;
00046 int xyz2crs[3];
00047 long dataOffset;
00048 molfile_volumetric_t *vol;
00049 } ccp4_t;
00050
00051 static void *open_ccp4_read(const char *filepath, const char *filetype,
00052 int *natoms) {
00053 FILE *fd;
00054 ccp4_t *ccp4;
00055 char mapString[4], symData[81];
00056 int origin[3], extent[3], grid[3], crs2xyz[3], mode, symBytes;
00057 int swap, i, xIndex, yIndex, zIndex;
00058 long dataOffset, filesize;
00059 float cellDimensions[3], cellAngles[3], xaxis[3], yaxis[3], zaxis[3];
00060 float alpha, beta, gamma, xScale, yScale, zScale, z1, z2, z3;
00061
00062 fd = fopen(filepath, "rb");
00063 if (!fd) {
00064 printf("ccp4plugin) Error opening file %s\n", filepath);
00065 return NULL;
00066 }
00067
00068 if ( (fread(extent, sizeof(int), 3, fd) != 3) ||
00069 (fread(&mode, sizeof(int), 1, fd) != 1) ||
00070 (fread(origin, sizeof(int), 3, fd) != 3) ||
00071 (fread(grid, sizeof(int), 3, fd) != 3) ||
00072 (fread(cellDimensions, sizeof(float), 3, fd) != 3) ||
00073 (fread(cellAngles, sizeof(float), 3, fd) != 3) ||
00074 (fread(crs2xyz, sizeof(int), 3, fd) != 3) ) {
00075 printf("ccp4plugin) Error: Improperly formatted line.\n");
00076 return NULL;
00077 }
00078
00079
00080 fseek(fd, 92, SEEK_SET);
00081 if ((fread(&symBytes, sizeof(int), 1, fd) != 1) ) {
00082 printf("ccp4plugin) Error: Failed reading symmetry bytes record.\n");
00083 return NULL;
00084 }
00085
00086
00087 fseek(fd, 208, SEEK_SET);
00088 if ( (fgets(mapString, 4, fd) == NULL) ||
00089 (strcmp(mapString, "MAP") != 0) ) {
00090 printf("ccp4plugin) Error: 'MAP' string missing, not a valid CCP4 file.\n");
00091 return NULL;
00092 }
00093
00094 swap = 0;
00095
00096 if (mode != 2) {
00097
00098 swap4_aligned(&mode, 1);
00099 if (mode != 2) {
00100 printf("ccp4plugin) Error: Non-real (32-bit float) data types are unsupported.\n");
00101 return NULL;
00102 } else {
00103 swap = 1;
00104 }
00105 }
00106
00107
00108 if (swap == 1) {
00109 swap4_aligned(extent, 3);
00110 swap4_aligned(origin, 3);
00111 swap4_aligned(grid, 3);
00112 swap4_aligned(cellDimensions, 3);
00113 swap4_aligned(cellAngles, 3);
00114 swap4_aligned(crs2xyz, 3);
00115 swap4_aligned(&symBytes, 1);
00116 }
00117
00118
00119 #if 0
00120 printf("ccp4plugin) extent: %d x %d x %d\n", extent[0], extent[1], extent[2]);
00121 printf("ccp4plugin) origin: %d x %d x %d\n", origin[0], origin[1], origin[2]);
00122 printf("ccp4plugin) grid: %d x %d x %d\n", grid[0], grid[1], grid[2]);
00123 printf("ccp4plugin) celldim: %f x %f x %f\n",
00124 cellDimensions[0], cellDimensions[1], cellDimensions[2]);
00125 printf("cpp4plugin)cellangles: %f, %f, %f\n",
00126 cellAngles[0], cellAngles[1], cellAngles[2]);
00127 printf("ccp4plugin) crs2xyz: %f %f %f\n",
00128 crs2xyz[0], crs2xyz[1], crs2xyz[2]);
00129 printf("ccp4plugin) symBytes: %d\n", symBytes);
00130 #endif
00131
00132
00133
00134
00135 fseek(fd, 0, SEEK_END);
00136 filesize = ftell(fd);
00137 dataOffset = filesize - 4*(extent[0]*extent[1]*extent[2]);
00138 if (dataOffset != (CCP4HDSIZE + symBytes)) {
00139 if (dataOffset == CCP4HDSIZE) {
00140
00141 printf("ccp4plugin) Warning: file contains bogus symmetry record.\n");
00142 symBytes = 0;
00143 } else if (dataOffset < CCP4HDSIZE) {
00144 printf("ccp4plugin) Error: File appears truncated and doesn't match header.\n");
00145 return NULL;
00146 } else if ((dataOffset > CCP4HDSIZE) && (dataOffset < (1024*1024))) {
00147
00148
00149 dataOffset = CCP4HDSIZE + symBytes;
00150 printf("ccp4plugin) Warning: File is larger than expected and doesn't match header.\n");
00151 printf("ccp4plugin) Warning: Continuing file load, good luck!\n");
00152 } else {
00153 printf("ccp4plugin) Error: File is MUCH larger than expected and doesn't match header.\n");
00154 return NULL;
00155 }
00156 }
00157
00158
00159 if (symBytes != 0) {
00160 printf("ccp4plugin) Symmetry records found:\n");
00161 fseek(fd, CCP4HDSIZE, SEEK_SET);
00162 for (i = 0; i < symBytes/80; i++) {
00163 fgets(symData, 81, fd);
00164 printf("ccp4plugin) %s\n", symData);
00165 }
00166 }
00167
00168
00169 if (grid[0] == 0 && extent[0] > 0) {
00170 grid[0] = extent[0] - 1;
00171 printf("ccp4plugin) Warning: Fixed X interval count\n");
00172 }
00173 if (grid[1] == 0 && extent[1] > 0) {
00174 grid[1] = extent[1] - 1;
00175 printf("ccp4plugin) Warning: Fixed Y interval count\n");
00176 }
00177 if (grid[2] == 0 && extent[2] > 0) {
00178 grid[2] = extent[2] - 1;
00179 printf("ccp4plugin) Warning: Fixed Z interval count\n");
00180 }
00181
00182 xScale = cellDimensions[0] / grid[0];
00183 yScale = cellDimensions[1] / grid[1];
00184 zScale = cellDimensions[2] / grid[2];
00185
00186
00187 ccp4 = new ccp4_t;
00188 ccp4->fd = fd;
00189 ccp4->vol = NULL;
00190 *natoms = MOLFILE_NUMATOMS_NONE;
00191 ccp4->nsets = 1;
00192 ccp4->swap = swap;
00193 ccp4->dataOffset = dataOffset;
00194
00195 ccp4->vol = new molfile_volumetric_t[1];
00196 strcpy(ccp4->vol[0].dataname, "CCP4 Electron Density Map");
00197
00198
00199 ccp4->xyz2crs[crs2xyz[0]-1] = 0;
00200 ccp4->xyz2crs[crs2xyz[1]-1] = 1;
00201 ccp4->xyz2crs[crs2xyz[2]-1] = 2;
00202 xIndex = ccp4->xyz2crs[0];
00203 yIndex = ccp4->xyz2crs[1];
00204 zIndex = ccp4->xyz2crs[2];
00205
00206
00207 alpha = (M_PI / 180.0) * cellAngles[0];
00208 beta = (M_PI / 180.0) * cellAngles[1];
00209 gamma = (M_PI / 180.0) * cellAngles[2];
00210
00211 xaxis[0] = xScale;
00212 xaxis[1] = 0;
00213 xaxis[2] = 0;
00214
00215 yaxis[0] = cos(gamma) * yScale;
00216 yaxis[1] = sin(gamma) * yScale;
00217 yaxis[2] = 0;
00218
00219 z1 = cos(beta);
00220 z2 = (cos(alpha) - cos(beta)*cos(gamma)) / sin(gamma);
00221 z3 = sqrt(1.0 - z1*z1 - z2*z2);
00222 zaxis[0] = z1 * zScale;
00223 zaxis[1] = z2 * zScale;
00224 zaxis[2] = z3 * zScale;
00225
00226 ccp4->vol[0].origin[0] = xaxis[0] * origin[xIndex] +
00227 yaxis[0] * origin[yIndex] +
00228 zaxis[0] * origin[zIndex];
00229 ccp4->vol[0].origin[1] = yaxis[1] * origin[yIndex] +
00230 zaxis[1] * origin[zIndex];
00231 ccp4->vol[0].origin[2] = zaxis[2] * origin[zIndex];
00232
00233 ccp4->vol[0].xaxis[0] = xaxis[0] * (extent[xIndex]-1);
00234 ccp4->vol[0].xaxis[1] = 0;
00235 ccp4->vol[0].xaxis[2] = 0;
00236
00237 ccp4->vol[0].yaxis[0] = yaxis[0] * (extent[yIndex]-1);
00238 ccp4->vol[0].yaxis[1] = yaxis[1] * (extent[yIndex]-1);
00239 ccp4->vol[0].yaxis[2] = 0;
00240
00241 ccp4->vol[0].zaxis[0] = zaxis[0] * (extent[zIndex]-1);
00242 ccp4->vol[0].zaxis[1] = zaxis[1] * (extent[zIndex]-1);
00243 ccp4->vol[0].zaxis[2] = zaxis[2] * (extent[zIndex]-1);
00244
00245 ccp4->vol[0].xsize = extent[xIndex];
00246 ccp4->vol[0].ysize = extent[yIndex];
00247 ccp4->vol[0].zsize = extent[zIndex];
00248
00249 ccp4->vol[0].has_color = 0;
00250
00251 return ccp4;
00252 }
00253
00254 static int read_ccp4_metadata(void *v, int *nsets,
00255 molfile_volumetric_t **metadata) {
00256 ccp4_t *ccp4 = (ccp4_t *)v;
00257 *nsets = ccp4->nsets;
00258 *metadata = ccp4->vol;
00259
00260 return MOLFILE_SUCCESS;
00261 }
00262
00263 static int read_ccp4_data(void *v, int set, float *datablock,
00264 float *colorblock) {
00265 ccp4_t *ccp4 = (ccp4_t *)v;
00266 float *rowdata;
00267 int x, y, z, xSize, ySize, zSize, xySize, extent[3], coord[3];
00268 FILE *fd = ccp4->fd;
00269
00270 xSize = ccp4->vol[0].xsize;
00271 ySize = ccp4->vol[0].ysize;
00272 zSize = ccp4->vol[0].zsize;
00273 xySize = xSize * ySize;
00274
00275
00276
00277 extent[ccp4->xyz2crs[0]] = xSize;
00278 extent[ccp4->xyz2crs[1]] = ySize;
00279 extent[ccp4->xyz2crs[2]] = zSize;
00280
00281 rowdata = new float[extent[0]];
00282
00283 fseek(fd, ccp4->dataOffset, SEEK_SET);
00284
00285 for (coord[2] = 0; coord[2] < extent[2]; coord[2]++) {
00286 for (coord[1] = 0; coord[1] < extent[1]; coord[1]++) {
00287
00288
00289 if (feof(fd)) {
00290 printf("ccp4plugin) Unexpected end-of-file.\n");
00291 return MOLFILE_ERROR;
00292 }
00293 if (ferror(fd)) {
00294 printf("ccp4plugin) Problem reading the file.\n");
00295 return MOLFILE_ERROR;
00296 }
00297 if ( fread(rowdata, sizeof(float), extent[0], fd) != extent[0] ) {
00298 printf("ccp4plugin) Error reading data row.\n");
00299 return MOLFILE_ERROR;
00300 }
00301
00302 for (coord[0] = 0; coord[0] < extent[0]; coord[0]++) {
00303 x = coord[ccp4->xyz2crs[0]];
00304 y = coord[ccp4->xyz2crs[1]];
00305 z = coord[ccp4->xyz2crs[2]];
00306 datablock[x + y*xSize + z*xySize] = rowdata[coord[0]];
00307 }
00308 }
00309 }
00310
00311 if (ccp4->swap == 1)
00312 swap4_aligned(datablock, xySize * zSize);
00313
00314 delete [] rowdata;
00315
00316 return MOLFILE_SUCCESS;
00317 }
00318
00319 static void close_ccp4_read(void *v) {
00320 ccp4_t *ccp4 = (ccp4_t *)v;
00321
00322 fclose(ccp4->fd);
00323 delete [] ccp4->vol;
00324 delete ccp4;
00325 }
00326
00327
00328
00329
00330 static molfile_plugin_t plugin = {
00331 vmdplugin_ABIVERSION,
00332 MOLFILE_PLUGIN_TYPE,
00333 "ccp4",
00334 "CCP4",
00335 "Eamon Caddigan, John Stone",
00336 0,
00337 8,
00338 VMDPLUGIN_THREADSAFE,
00339 "ccp4,mrc,map"
00340 };
00341
00342 VMDPLUGIN_API int VMDPLUGIN_init(void) { return VMDPLUGIN_SUCCESS; }
00343 VMDPLUGIN_API int VMDPLUGIN_fini(void) { return VMDPLUGIN_SUCCESS; }
00344 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00345 plugin.open_file_read = open_ccp4_read;
00346 plugin.read_volumetric_metadata = read_ccp4_metadata;
00347 plugin.read_volumetric_data = read_ccp4_data;
00348 plugin.close_file_read = close_ccp4_read;
00349 (*cb)(v, (vmdplugin_t *)&plugin);
00350 return VMDPLUGIN_SUCCESS;
00351 }
00352