Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

ccp4plugin.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2006 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: ccp4plugin.C,v $
00013  *      $Author: johns $       $Locker:  $             $State: Exp $
00014  *      $Revision: 1.29 $       $Date: 2007/08/09 19:58:45 $
00015  *
00016  ***************************************************************************/
00017 
00018 /*
00019  * CCP4 electron density map file format description:
00020  *   http://www.ccp4.ac.uk/html/maplib.html
00021  *   http://iims.ebi.ac.uk/3dem-mrc-maps/distribution/mrc_maps.txt
00022  *
00023  * TODO: Fix translation/scaling problems found when using non-orthogonal
00024  *       unit cells.
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   // Check the number of bytes used for storing symmetry operators
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   // Check for the string "MAP" at byte 208, indicating a CCP4 file.
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   // Check the data type of the file.
00096   if (mode != 2) {
00097     // Check if the byte-order is flipped
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; // enable byte swapping
00104     }
00105   }
00106 
00107   // Swap all the information obtained from the header
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 1
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: %d %d %d\n", 
00128          crs2xyz[0], crs2xyz[1], crs2xyz[2]);
00129   printf("ccp4plugin) symBytes: %d\n", symBytes);
00130 #endif
00131 
00132 
00133   // Check the dataOffset: this fixes the problem caused by files claiming
00134   // to have symmetry records when they do not.
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       // Bogus symmetry record information
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       // Fix for loading SPIDER files which are larger than usual
00148       // In this specific case, we must absolutely trust the symBytes record
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   // Read symmetry records -- organized as 80-byte lines of text.
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   // check extent and grid interval counts
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 
00183   // Allocate and initialize the ccp4 structure
00184   ccp4 = new ccp4_t;
00185   ccp4->fd = fd;
00186   ccp4->vol = NULL;
00187   *natoms = MOLFILE_NUMATOMS_NONE;
00188   ccp4->nsets = 1; // this EDM file contains only one data set
00189   ccp4->swap = swap;
00190   ccp4->dataOffset = dataOffset;
00191 
00192   ccp4->vol = new molfile_volumetric_t[1];
00193   strcpy(ccp4->vol[0].dataname, "CCP4 Electron Density Map");
00194 
00195   // Mapping between CCP4 column, row, section and VMD x, y, z.
00196   if (crs2xyz[0] == 0 && crs2xyz[1] == 0 && crs2xyz[2] == 0) {
00197     printf("ccp4plugin) Warning: All crs2xyz records are zero.\n");
00198     printf("ccp4plugin) Warning: Setting crs2xyz to 1, 2, 3\n");
00199     crs2xyz[0] = 1;
00200     crs2xyz[0] = 2;
00201     crs2xyz[0] = 3;
00202   }
00203 
00204   ccp4->xyz2crs[crs2xyz[0]-1] = 0;
00205   ccp4->xyz2crs[crs2xyz[1]-1] = 1;
00206   ccp4->xyz2crs[crs2xyz[2]-1] = 2;
00207   xIndex = ccp4->xyz2crs[0];
00208   yIndex = ccp4->xyz2crs[1];
00209   zIndex = ccp4->xyz2crs[2];
00210 
00211   // calculate non-orthogonal unit cell coordinates
00212   alpha = (M_PI / 180.0) * cellAngles[0];
00213   beta = (M_PI / 180.0) * cellAngles[1];
00214   gamma = (M_PI / 180.0) * cellAngles[2];
00215 
00216   if (cellDimensions[0] == 0.0 && 
00217       cellDimensions[1] == 0.0 &&
00218       cellDimensions[2] == 0.0) {
00219     printf("ccp4plugin) Warning: Cell dimensions are all zero.\n");
00220     printf("ccp4plugin) Warning: Setting to 1.0, 1.0, 1.0 for viewing.\n");
00221     printf("ccp4plugin) Warning: Map file will not align with other structures.\n");
00222     cellDimensions[0] = 1.0;
00223     cellDimensions[1] = 1.0;
00224     cellDimensions[2] = 1.0;
00225   } 
00226 
00227 
00228   xScale = cellDimensions[0] / grid[0];
00229   yScale = cellDimensions[1] / grid[1];
00230   zScale = cellDimensions[2] / grid[2];
00231 
00232   // calculate non-orthogonal unit cell coordinates
00233   xaxis[0] = xScale;
00234   xaxis[1] = 0;
00235   xaxis[2] = 0;
00236 
00237   yaxis[0] = cos(gamma) * yScale;
00238   yaxis[1] = sin(gamma) * yScale;
00239   yaxis[2] = 0;
00240 
00241   z1 = cos(beta);
00242   z2 = (cos(alpha) - cos(beta)*cos(gamma)) / sin(gamma);
00243   z3 = sqrt(1.0 - z1*z1 - z2*z2);
00244   zaxis[0] = z1 * zScale;
00245   zaxis[1] = z2 * zScale;
00246   zaxis[2] = z3 * zScale;
00247 
00248   ccp4->vol[0].origin[0] = xaxis[0] * origin[xIndex] + 
00249                            yaxis[0] * origin[yIndex] +
00250                            zaxis[0] * origin[zIndex];
00251   ccp4->vol[0].origin[1] = yaxis[1] * origin[yIndex] +
00252                            zaxis[1] * origin[zIndex];
00253   ccp4->vol[0].origin[2] = zaxis[2] * origin[zIndex];
00254 
00255   ccp4->vol[0].xaxis[0] = xaxis[0] * (extent[xIndex]-1);
00256   ccp4->vol[0].xaxis[1] = 0;
00257   ccp4->vol[0].xaxis[2] = 0;
00258 
00259   ccp4->vol[0].yaxis[0] = yaxis[0] * (extent[yIndex]-1);
00260   ccp4->vol[0].yaxis[1] = yaxis[1] * (extent[yIndex]-1);
00261   ccp4->vol[0].yaxis[2] = 0;
00262 
00263   ccp4->vol[0].zaxis[0] = zaxis[0] * (extent[zIndex]-1);
00264   ccp4->vol[0].zaxis[1] = zaxis[1] * (extent[zIndex]-1);
00265   ccp4->vol[0].zaxis[2] = zaxis[2] * (extent[zIndex]-1);
00266 
00267   ccp4->vol[0].xsize = extent[xIndex];
00268   ccp4->vol[0].ysize = extent[yIndex];
00269   ccp4->vol[0].zsize = extent[zIndex];
00270 
00271   ccp4->vol[0].has_color = 0;
00272 
00273   return ccp4;
00274 }
00275 
00276 static int read_ccp4_metadata(void *v, int *nsets, 
00277   molfile_volumetric_t **metadata) {
00278   ccp4_t *ccp4 = (ccp4_t *)v;
00279   *nsets = ccp4->nsets; 
00280   *metadata = ccp4->vol;  
00281 
00282   return MOLFILE_SUCCESS;
00283 }
00284 
00285 static int read_ccp4_data(void *v, int set, float *datablock,
00286                          float *colorblock) {
00287   ccp4_t *ccp4 = (ccp4_t *)v;
00288   float *rowdata;
00289   int x, y, z, xSize, ySize, zSize, xySize, extent[3], coord[3];
00290   FILE *fd = ccp4->fd;
00291 
00292   xSize = ccp4->vol[0].xsize;
00293   ySize = ccp4->vol[0].ysize;
00294   zSize = ccp4->vol[0].zsize;
00295   xySize = xSize * ySize;
00296 
00297   // coord = <col, row, sec>
00298   // extent = <colSize, rowSize, secSize>
00299   extent[ccp4->xyz2crs[0]] = xSize;
00300   extent[ccp4->xyz2crs[1]] = ySize;
00301   extent[ccp4->xyz2crs[2]] = zSize;
00302 
00303   rowdata = new float[extent[0]];
00304 
00305   fseek(fd, ccp4->dataOffset, SEEK_SET);
00306 
00307   for (coord[2] = 0; coord[2] < extent[2]; coord[2]++) {
00308     for (coord[1] = 0; coord[1] < extent[1]; coord[1]++) {
00309       // Read an entire row of data from the file, then write it into the
00310       // datablock with the correct slice ordering.
00311       if (feof(fd)) {
00312         printf("ccp4plugin) Unexpected end-of-file.\n");
00313         return MOLFILE_ERROR;
00314       }
00315       if (ferror(fd)) {
00316         printf("ccp4plugin) Problem reading the file.\n");
00317         return MOLFILE_ERROR;
00318       }
00319       if ( fread(rowdata, sizeof(float), extent[0], fd) != extent[0] ) {
00320         printf("ccp4plugin) Error reading data row.\n");
00321         return MOLFILE_ERROR;
00322       }
00323 
00324       for (coord[0] = 0; coord[0] < extent[0]; coord[0]++) {
00325         x = coord[ccp4->xyz2crs[0]];
00326         y = coord[ccp4->xyz2crs[1]];
00327         z = coord[ccp4->xyz2crs[2]];
00328         datablock[x + y*xSize + z*xySize] = rowdata[coord[0]];
00329       }
00330     }
00331   }
00332 
00333   if (ccp4->swap == 1)
00334     swap4_aligned(datablock, xySize * zSize);
00335 
00336   delete [] rowdata;
00337 
00338   return MOLFILE_SUCCESS;
00339 }
00340 
00341 static void close_ccp4_read(void *v) {
00342   ccp4_t *ccp4 = (ccp4_t *)v;
00343 
00344   fclose(ccp4->fd);
00345   delete [] ccp4->vol; 
00346   delete ccp4;
00347 }
00348 
00349 /*
00350  * Initialization stuff here
00351  */
00352 static molfile_plugin_t plugin;
00353 
00354 VMDPLUGIN_API int VMDPLUGIN_init(void) { 
00355   memset(&plugin, 0, sizeof(molfile_plugin_t));
00356   plugin.abiversion = vmdplugin_ABIVERSION;
00357   plugin.type = MOLFILE_PLUGIN_TYPE;
00358   plugin.name = "ccp4";
00359   plugin.prettyname = "CCP4, MRC Density Map";
00360   plugin.author = "Eamon Caddigan, John Stone";
00361   plugin.majorv = 1;
00362   plugin.minorv = 2;
00363   plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
00364   plugin.filename_extension = "ccp4,mrc,map";
00365   plugin.open_file_read = open_ccp4_read;
00366   plugin.read_volumetric_metadata = read_ccp4_metadata;
00367   plugin.read_volumetric_data = read_ccp4_data;
00368   plugin.close_file_read = close_ccp4_read;
00369   return VMDPLUGIN_SUCCESS; 
00370 }
00371 
00372 
00373 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00374   (*cb)(v, (vmdplugin_t *)&plugin);
00375   return VMDPLUGIN_SUCCESS;
00376 }
00377 
00378 VMDPLUGIN_API int VMDPLUGIN_fini(void) { return VMDPLUGIN_SUCCESS; }

Generated on Thu Sep 4 01:40:40 2008 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002