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.23 $       $Date: 2006/03/17 21:15:44 $
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 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   // 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   xScale = cellDimensions[0] / grid[0];
00183   yScale = cellDimensions[1] / grid[1];
00184   zScale = cellDimensions[2] / grid[2];
00185 
00186   // Allocate and initialize the ccp4 structure
00187   ccp4 = new ccp4_t;
00188   ccp4->fd = fd;
00189   ccp4->vol = NULL;
00190   *natoms = MOLFILE_NUMATOMS_NONE;
00191   ccp4->nsets = 1; // this EDM file contains only one data set
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   // Mapping between CCP4 column, row, section and VMD x, y, z.
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   // calculate non-orthogonal unit cell coordinates
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   // coord = <col, row, sec>
00276   // extent = <colSize, rowSize, secSize>
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       // Read an entire row of data from the file, then write it into the
00288       // datablock with the correct slice ordering.
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  * Initialization stuff here
00329  */
00330 static molfile_plugin_t plugin = {
00331   vmdplugin_ABIVERSION,               // ABI version
00332   MOLFILE_PLUGIN_TYPE,                // plugin type
00333   "ccp4",                             // short file format description
00334   "CCP4",                             // pretty file format description
00335   "Eamon Caddigan, John Stone",       // author(s)
00336   0,                                  // major version
00337   8,                                  // minor version
00338   VMDPLUGIN_THREADSAFE,               // is reentrant
00339   "ccp4,mrc,map"                      // filename extension
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 

Generated on Wed Mar 22 13:15:28 2006 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002