Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

mrcio.cpp

Go to the documentation of this file.
00001 
00005 /*
00006  * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
00007  * Copyright (c) 2000-2006 Baylor College of Medicine
00008  *
00009  * This software is issued under a joint BSD/GNU license. You may use the
00010  * source code in this file under either license. However, note that the
00011  * complete EMAN2 and SPARX software packages have some GPL dependencies,
00012  * so you are responsible for compliance with the licenses of these packages
00013  * if you opt to use BSD licensing. The warranty disclaimer below holds
00014  * in either instance.
00015  *
00016  * This complete copyright notice must be included in any revised version of the
00017  * source code. Additional authorship citations may be added, but existing
00018  * author citations must be preserved.
00019  *
00020  * This program is free software; you can redistribute it and/or modify
00021  * it under the terms of the GNU General Public License as published by
00022  * the Free Software Foundation; either version 2 of the License, or
00023  * (at your option) any later version.
00024  *
00025  * This program is distributed in the hope that it will be useful,
00026  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00027  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00028  * GNU General Public License for more details.
00029  *
00030  * You should have received a copy of the GNU General Public License
00031  * along with this program; if not, write to the Free Software
00032  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00033  *
00034  * */
00035 
00036 #include <cstring>
00037 #include <climits>
00038 
00039 #include "mrcio.h"
00040 #include "portable_fileio.h"
00041 #include "geometry.h"
00042 #include "util.h"
00043 #include "ctf.h"
00044 #include "transform.h"
00045 
00046 using namespace EMAN;
00047 
00048 const char *MrcIO::CTF_MAGIC = "!-";
00049 const char *MrcIO::SHORT_CTF_MAGIC = "!$";
00050 
00051 MrcIO::MrcIO(const string & mrc_filename, IOMode rw)
00052 :       filename(mrc_filename), rw_mode(rw), mrcfile(0), mode_size(0),
00053                 isFEI(false), is_ri(0), is_new_file(false), initialized(false)
00054 {
00055         memset(&mrch, 0, sizeof(MrcHeader));
00056         is_big_endian = ByteOrder::is_host_big_endian();
00057 }
00058 
00059 MrcIO::~MrcIO()
00060 {
00061         if (mrcfile) {
00062                 fclose(mrcfile);
00063                 mrcfile = 0;
00064         }
00065 }
00066 
00067 void MrcIO::init()
00068 {
00069         ENTERFUNC;
00070 
00071         if (initialized) {
00072                 return;
00073         }
00074 
00075         initialized = true;
00076         mrcfile = sfopen(filename, rw_mode, &is_new_file);
00077 
00078         if (!is_new_file) {
00079                 if (fread(&mrch, sizeof(MrcHeader), 1, mrcfile) != 1) {
00080                         throw ImageReadException(filename, "MRC header");
00081                 }
00082 
00083                 if (!is_valid(&mrch)) {
00084                         throw ImageReadException(filename, "invalid MRC");
00085                 }
00086 
00087                 is_big_endian = ByteOrder::is_data_big_endian(&mrch.nz);
00088                 if (is_big_endian != ByteOrder::is_host_big_endian()) {
00089                         swap_header(mrch);
00090                 }
00091                 //become_host_endian((int *) &mrch, NUM_4BYTES_PRE_MAP);
00092                 //become_host_endian((int *) &mrch.machinestamp, NUM_4BYTES_AFTER_MAP);
00093                 mode_size = get_mode_size(mrch.mode);
00094                 if(is_complex_mode()) {
00095                         is_ri = 1;
00096                 }
00097 
00098                 if (mrch.nxstart != 0 || mrch.nystart != 0 || mrch.nzstart != 0) {
00099                         LOGWARN("nx/ny/nz start not zero");
00100                 }
00101 
00102                 if (is_complex_mode()) {
00103                         mrch.nx *= 2;
00104                 }
00105 
00106                 if (mrch.xlen == 0) {
00107                         mrch.xlen = 1.0;
00108                 }
00109 
00110                 if (mrch.ylen == 0) {
00111                         mrch.ylen = 1.0;
00112                 }
00113 
00114                 if (mrch.zlen == 0) {
00115                         mrch.zlen = 1.0;
00116                 }
00117 
00118                 if(mrch.nlabels>0) {
00119                         if( string(mrch.labels[0],3) == "Fei") {
00120                                 isFEI = true;
00121                         }
00122                 }
00123         }
00124         EXITFUNC;
00125 }
00126 
00127 
00128 bool MrcIO::is_image_big_endian()
00129 {
00130         init();
00131         return is_big_endian;
00132 }
00133 
00134 bool MrcIO::is_valid(const void *first_block, off_t file_size)
00135 {
00136         ENTERFUNC;
00137 
00138         if (!first_block) {
00139                 return false;
00140         }
00141 
00142         const int *data = static_cast < const int *>(first_block);
00143         int nx = data[0];
00144         int ny = data[1];
00145         int nz = data[2];
00146         int mrcmode = data[3];
00147         int nsymbt = data[23];  //this field specify the extra bytes for symmetry information
00148 
00149         bool data_big_endian = ByteOrder::is_data_big_endian(&nz);
00150 
00151         if (data_big_endian != ByteOrder::is_host_big_endian()) {
00152                 ByteOrder::swap_bytes(&nx);
00153                 ByteOrder::swap_bytes(&ny);
00154                 ByteOrder::swap_bytes(&nz);
00155                 ByteOrder::swap_bytes(&mrcmode);
00156                 ByteOrder::swap_bytes(&nsymbt);
00157         }
00158 
00159         if (mrcmode == MRC_SHORT_COMPLEX || mrcmode == MRC_FLOAT_COMPLEX) {
00160                 nx *= 2;
00161         }
00162 
00163         const int max_dim = 1 << 20;
00164 
00165         if ((mrcmode >= MRC_UCHAR && mrcmode < MRC_UNKNOWN) &&
00166                 (nx > 1 && nx < max_dim) && (ny > 0 && ny < max_dim) && (nz > 0 && nz < max_dim)) {
00167 //#ifndef SPIDERMRC // Spider MRC files don't satisfy the following test
00168                 if (file_size > 0) {
00169                         off_t file_size1 = (off_t)nx * (off_t)ny * (off_t)nz * (off_t)get_mode_size(mrcmode) + (off_t)sizeof(MrcHeader) + nsymbt;
00170                         if (file_size == file_size1) {
00171                                 return true;
00172                         }
00173 //                      return false;
00174                         LOGWARN("image size check fails, still try to read it...");     //when size doesn't match, print error message instead of make it fail
00175                 }
00176                 else {
00177                         return true;
00178                 }
00179 //#endif // SPIDERMRC
00180                 return true;
00181         }
00182         EXITFUNC;
00183         return false;
00184 }
00185 
00186 int MrcIO::read_header(Dict & dict, int image_index, const Region * area, bool is_3d)
00187 {
00188         init();
00189 
00190         if(isFEI) {
00191                 return read_fei_header(dict, image_index, area, is_3d);
00192         }
00193         else {
00194                 return read_mrc_header(dict, image_index, area, is_3d);
00195         }
00196 }
00197 
00198 int MrcIO::read_mrc_header(Dict & dict, int image_index, const Region * area, bool)
00199 {
00200         ENTERFUNC;
00201 
00202         //single image format, index can only be zero
00203         if(image_index < 0) {
00204                 image_index = 0;
00205         }
00206         if(image_index != 0) {
00207                 throw ImageReadException(filename, "no stack allowed for MRC image. For take 2D slice out of 3D image, read the 3D image first, then use get_clip().");
00208         }
00209 
00210         check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file,false);
00211 
00212         int xlen = 0, ylen = 0, zlen = 0;
00213         EMUtil::get_region_dims(area, mrch.nx, &xlen, mrch.ny, &ylen, mrch.nz, &zlen);
00214 
00215         dict["nx"] = xlen;
00216         dict["ny"] = ylen;
00217         dict["nz"] = zlen;
00218         dict["MRC.nx"] = mrch.nx;
00219         dict["MRC.ny"] = mrch.ny;
00220         dict["MRC.nz"] = mrch.nz;
00221 
00222         dict["datatype"] = to_em_datatype(mrch.mode);
00223 
00224         dict["MRC.nxstart"] = mrch.nxstart;
00225         dict["MRC.nystart"] = mrch.nystart;
00226         dict["MRC.nzstart"] = mrch.nzstart;
00227 
00228         dict["MRC.mx"] = mrch.mx;
00229         dict["MRC.my"] = mrch.my;
00230         dict["MRC.mz"] = mrch.mz;
00231 
00232         dict["MRC.xlen"] = mrch.xlen;
00233         dict["MRC.ylen"] = mrch.ylen;
00234         dict["MRC.zlen"] = mrch.zlen;
00235 
00236         dict["MRC.alpha"] = mrch.alpha;
00237         dict["MRC.beta"] = mrch.beta;
00238         dict["MRC.gamma"] = mrch.gamma;
00239 
00240         dict["MRC.mapc"] = mrch.mapc;
00241         dict["MRC.mapr"] = mrch.mapr;
00242         dict["MRC.maps"] = mrch.maps;
00243 
00244         dict["MRC.minimum"] = mrch.amin;
00245         dict["MRC.maximum"] = mrch.amax;
00246         dict["MRC.mean"] = mrch.amean;
00247         dict["mean"] = mrch.amean;
00248 
00249         dict["MRC.ispg"] = mrch.ispg;
00250         dict["MRC.nsymbt"] = mrch.nsymbt;
00251 
00252         dict["apix_x"] = mrch.xlen / mrch.mx;
00253         dict["apix_y"] = mrch.ylen / mrch.my;
00254         dict["apix_z"] = mrch.zlen / mrch.mz;
00255 
00256         if (area) {
00257                 dict["origin_x"] = mrch.xorigin + mrch.xlen * area->origin[0];
00258                 dict["origin_y"] = mrch.yorigin + mrch.xlen * area->origin[1];
00259 
00260                 if (area->get_ndim() == 3 && mrch.nz > 1) {
00261                         dict["origin_z"] = mrch.zorigin + mrch.xlen * area->origin[2];
00262                 }
00263                 else {
00264                         dict["origin_z"] = mrch.zorigin;
00265                 }
00266         }
00267         else {
00268                 dict["origin_x"] = mrch.xorigin;
00269                 dict["origin_y"] = mrch.yorigin;
00270                 dict["origin_z"] = mrch.zorigin;
00271         }
00272 
00273         if (is_complex_mode()) {
00274                 dict["is_complex"] = 1;
00275                 dict["is_complex_ri"] = 1;
00276         }
00277 
00278         dict["MRC.machinestamp"] = mrch.machinestamp;
00279 
00280         dict["MRC.rms"] = mrch.rms;
00281         dict["sigma"] = mrch.rms;
00282         dict["MRC.nlabels"] = mrch.nlabels;
00283         for (int i = 0; i < mrch.nlabels; i++) {
00284                 char label[32];
00285                 sprintf(label, "MRC.label%d", i);
00286                 dict[string(label)] = string(mrch.labels[i],80);
00287         }
00288 
00289         EMAN1Ctf ctf_;
00290         if(read_ctf(ctf_) == 0) {
00291                 vector<float> vctf = ctf_.to_vector();
00292                 dict["ctf"] = vctf;
00293         }
00294 
00295         Dict dic;
00296         dic.put("type", "imagic");
00297         dic.put("alpha", mrch.alpha);
00298         dic.put("beta", mrch.beta);
00299         dic.put("gamma", mrch.gamma);
00300         dic.put("tx", mrch.xorigin);
00301         dic.put("ty", mrch.yorigin);
00302         dic.put("tz", mrch.zorigin);
00303         Transform * trans = new Transform(dic);
00304         if(zlen<=1) {
00305                 dict["xform.projection"] = trans;
00306         }
00307         else {
00308                 dict["xform.align3d"] = trans;
00309         }
00310 
00311         if(trans) {delete trans; trans=0;}
00312 
00313         EXITFUNC;
00314         return 0;
00315 }
00316 
00317 int MrcIO::read_fei_header(Dict & dict, int image_index, const Region * area, bool)
00318 {
00319         ENTERFUNC;
00320 
00321         if(image_index < 0) {
00322                 image_index = 0;
00323         }
00324 
00325         if(area && area->get_depth() > 1) {
00326                 throw ImageDimensionException("FEI MRC image is 2D tile series, only 2D regional reading accepted.");
00327         }
00328 
00329         init();
00330 
00331         check_region(area, FloatSize(feimrch.nx, feimrch.ny, feimrch.nz), is_new_file,false);
00332 
00333         int xlen = 0, ylen = 0, zlen = 0;
00334         EMUtil::get_region_dims(area, feimrch.nx, &xlen, feimrch.ny, &ylen, feimrch.nz, &zlen);
00335 
00336         dict["nx"] = xlen;
00337         dict["ny"] = ylen;
00338         dict["nz"] = 1; //only read one 2D image from a tilt series
00339         dict["FEIMRC.nx"] = feimrch.nx;
00340         dict["FEIMRC.ny"] = feimrch.ny;
00341         dict["FEIMRC.nz"] = feimrch.nz;
00342 
00343         dict["datatype"] = to_em_datatype(feimrch.mode);        //=1, FEI-MRC file always use short for data type
00344 
00345         dict["FEIMRC.nxstart"] = feimrch.nxstart;
00346         dict["FEIMRC.nystart"] = feimrch.nystart;
00347         dict["FEIMRC.nzstart"] = feimrch.nzstart;
00348 
00349         dict["FEIMRC.mx"] = feimrch.mx;
00350         dict["FEIMRC.my"] = feimrch.my;
00351         dict["FEIMRC.mz"] = feimrch.mz;
00352 
00353         dict["FEIMRC.xlen"] = feimrch.xlen;
00354         dict["FEIMRC.ylen"] = feimrch.ylen;
00355         dict["FEIMRC.zlen"] = feimrch.zlen;
00356 
00357         dict["FEIMRC.alpha"] = feimrch.alpha;
00358         dict["FEIMRC.beta"] = feimrch.beta;
00359         dict["FEIMRC.gamma"] = feimrch.gamma;
00360 
00361         dict["FEIMRC.mapc"] = feimrch.mapc;
00362         dict["FEIMRC.mapr"] = feimrch.mapr;
00363         dict["FEIMRC.maps"] = feimrch.maps;
00364 
00365         dict["FEIMRC.minimum"] = feimrch.amin;
00366         dict["FEIMRC.maximum"] = feimrch.amax;
00367         dict["FEIMRC.mean"] = feimrch.amean;
00368         dict["mean"] = feimrch.amean;
00369 
00370         dict["FEIMRC.ispg"] = feimrch.ispg;
00371         dict["FEIMRC.nsymbt"] = feimrch.nsymbt;
00372 
00373         dict["apix_x"] = feimrch.xlen / feimrch.mx;
00374         dict["apix_y"] = feimrch.ylen / feimrch.my;
00375         dict["apix_z"] = feimrch.zlen / feimrch.mz;
00376 
00377         dict["FEIMRC.next"] = feimrch.next;     //offset from end of header to the first dataset
00378         dict["FEIMRC.dvid"] = feimrch.dvid;
00379         dict["FEIMRC.numintegers"] = feimrch.numintegers;
00380         dict["FEIMRC.numfloats"] = feimrch.numfloats;
00381         dict["FEIMRC.sub"] = feimrch.sub;
00382         dict["FEIMRC.zfac"] = feimrch.zfac;
00383 
00384         dict["FEIMRC.min2"] = feimrch.min2;
00385         dict["FEIMRC.max2"] = feimrch.max2;
00386         dict["FEIMRC.min3"] = feimrch.min3;
00387         dict["FEIMRC.max3"] = feimrch.max3;
00388         dict["FEIMRC.min4"] = feimrch.min4;
00389         dict["FEIMRC.max4"] = feimrch.max4;
00390 
00391         dict["FEIMRC.idtype"] = feimrch.idtype;
00392         dict["FEIMRC.lens"] = feimrch.lens;
00393         dict["FEIMRC.nd1"] = feimrch.nd1;
00394         dict["FEIMRC.nd2"] = feimrch.nd2;
00395         dict["FEIMRC.vd1"] = feimrch.vd1;
00396         dict["FEIMRC.vd2"] = feimrch.vd2;
00397 
00398         for(int i=0; i<9; i++) {        //9 tilt angles
00399                 char label[32];
00400                 sprintf(label, "MRC.tiltangles%d", i);
00401                 dict[string(label)] = feimrch.tiltangles[i];
00402         }
00403 
00404         dict["FEIMRC.zorg"] = feimrch.zorg;
00405         dict["FEIMRC.xorg"] = feimrch.xorg;
00406         dict["FEIMRC.yorg"] = feimrch.yorg;
00407 
00408         dict["FEIMRC.nlabl"] = feimrch.nlabl;
00409         for (int i = 0; i < feimrch.nlabl; i++) {
00410                 char label[32];
00411                 sprintf(label, "MRC.label%d", i);
00412                 dict[string(label)] = string(feimrch.labl[i], 80);
00413         }
00414 
00415         /* Read extended image header by specified image index*/
00416         FeiMrcExtHeader feiexth;
00417         portable_fseek(mrcfile, sizeof(FeiMrcHeader)+sizeof(FeiMrcExtHeader)*image_index, SEEK_SET);
00418         if (fread(&feiexth, sizeof(FeiMrcExtHeader), 1, mrcfile) != 1) {
00419                 throw ImageReadException(filename, "FEI MRC extended header");
00420         }
00421 
00422         dict["FEIMRC.a_tilt"] = feiexth.a_tilt;
00423         dict["FEIMRC.b_tilt"] = feiexth.b_tilt;
00424 
00425         dict["FEIMRC.x_stage"] = feiexth.x_stage;
00426         dict["FEIMRC.y_stage"] = feiexth.y_stage;
00427         dict["FEIMRC.z_stage"] = feiexth.z_stage;
00428 
00429         dict["FEIMRC.x_shift"] = feiexth.x_shift;
00430         dict["FEIMRC.y_shift"] = feiexth.y_shift;
00431 
00432         dict["FEIMRC.defocus"] = feiexth.defocus;
00433         dict["FEIMRC.exp_time"] = feiexth.exp_time;
00434         dict["FEIMRC.mean_int"] = feiexth.mean_int;
00435         dict["FEIMRC.tilt_axis"] = feiexth.tilt_axis;
00436 
00437         dict["FEIMRC.pixel_size"] = feiexth.pixel_size;
00438         dict["FEIMRC.magnification"] = feiexth.magnification;
00439         dict["FEIMRC.ht"] = feiexth.ht;
00440         dict["FEIMRC.binning"] = feiexth.binning;
00441         dict["FEIMRC.appliedDefocus"] = feiexth.appliedDefocus;
00442 
00443         //remainder 16 4-byte floats not used
00444 
00445         EXITFUNC;
00446         return 0;
00447 }
00448 
00449 int MrcIO::write_header(const Dict & dict, int image_index, const Region* area,
00450                                                 EMUtil::EMDataType filestoragetype, bool use_host_endian)
00451 {
00452         ENTERFUNC;
00453 
00454         //single image format, index can only be zero
00455         if(image_index == -1) {
00456                 image_index = 0;
00457         }
00458         if(image_index != 0) {
00459                 throw ImageWriteException(filename, "MRC file does not support stack.");
00460         }
00461         check_write_access(rw_mode, image_index, 1);
00462         if (area) {
00463                 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file);
00464                 EXITFUNC;
00465                 return 0;
00466         }
00467 
00468         int new_mode = to_mrcmode(filestoragetype, (int) dict["is_complex"]);
00469         int nx = dict["nx"];
00470         int ny = dict["ny"];
00471         int nz = dict["nz"];
00472         is_ri =  dict["is_complex_ri"];
00473 
00474         bool opposite_endian = false;
00475 
00476         if (!is_new_file) {
00477                 if (is_big_endian != ByteOrder::is_host_big_endian()) {
00478                         opposite_endian = true;
00479                 }
00480 #if 0
00481                 if (new_mode != mrch.mode) {
00482                         LOGERR("cannot write to different mode file %s", filename.c_str());
00483                         return 1;
00484                 }
00485 #endif
00486                 portable_fseek(mrcfile, 0, SEEK_SET);
00487         }
00488         else {
00489                 mrch.alpha = mrch.beta = mrch.gamma = 90.0f;
00490                 mrch.mapc = 1;
00491                 mrch.mapr = 2;
00492                 mrch.maps = 3;
00493                 mrch.nxstart = mrch.nystart = mrch.nzstart = 0;
00494         }
00495 
00496         if(nz<=1 && dict.has_key("xform.projection") && !dict.has_key("UCSF.chimera")) {
00497                 Transform * t = dict["xform.projection"];
00498                 Dict d = t->get_params("imagic");
00499                 mrch.alpha = d["alpha"];
00500                 mrch.beta = d["beta"];
00501                 mrch.gamma = d["gamma"];
00502                 mrch.xorigin = d["tx"];
00503                 mrch.yorigin = d["ty"];
00504                 mrch.zorigin = d["tz"];
00505                 if(t) {delete t; t=0;}
00506         }
00507         else if(nz>1 && dict.has_key("xform.align3d") && !dict.has_key("UCSF.chimera")) {
00508                 Transform * t = dict["xform.align3d"];
00509                 Dict d = t->get_params("imagic");
00510                 mrch.alpha = d["alpha"];
00511                 mrch.beta = d["beta"];
00512                 mrch.gamma = d["gamma"];
00513                 mrch.xorigin = d["tx"];
00514                 mrch.yorigin = d["ty"];
00515                 mrch.zorigin = d["tz"];
00516                 if(t) {delete t; t=0;}
00517         }
00518 
00519         if(dict.has_key("origin_x") && dict.has_key("origin_y") && dict.has_key("origin_z")){
00520                 mrch.xorigin = (float)dict["origin_x"];
00521                 mrch.yorigin = (float)dict["origin_y"];
00522 
00523                 if (is_new_file) {
00524                         mrch.zorigin = (float)dict["origin_z"];
00525                 }
00526                 else {
00527                         mrch.zorigin = (float) dict["origin_z"] - (float) dict["apix_z"] * image_index;
00528                 }
00529         }
00530 
00531         if (dict.has_key("MRC.nlabels")) {
00532                 mrch.nlabels = dict["MRC.nlabels"];
00533         }
00534 
00535         for (int i = 0; i < MRC_NUM_LABELS; i++) {
00536                 char label[32];
00537                 sprintf(label, "MRC.label%d", i);
00538                 if (dict.has_key(label)) {
00539                         sprintf(&mrch.labels[i][0], "%s", (const char *) dict[label]);
00540                         mrch.nlabels = i + 1;
00541                 }
00542         }
00543 
00544         if (mrch.nlabels < (MRC_NUM_LABELS - 1)) {
00545                 sprintf(&mrch.labels[mrch.nlabels][0], "EMAN %s", Util::get_time_label().c_str());
00546                 mrch.nlabels++;
00547         }
00548 
00549         mrch.labels[mrch.nlabels][0] = '\0';
00550         mrch.mode = new_mode;
00551 
00552         if (is_complex_mode()) {
00553                 mrch.nx = nx / 2;
00554         }
00555         else {
00556                 mrch.nx = nx;
00557         }
00558         mrch.ny = ny;
00559 
00560         if (is_new_file) {
00561                 mrch.nz = nz;
00562         }
00563         else if (image_index >= mrch.nz) {
00564                 mrch.nz = image_index + 1;
00565         }
00566 
00567         mrch.ispg = 0;
00568         mrch.nsymbt = 0;
00569         mrch.amin = dict["minimum"];
00570         mrch.amax = dict["maximum"];
00571         mrch.amean = dict["mean"];
00572         mrch.rms = dict["sigma"];
00573 
00576 //      if(dict.has_key("MRC.mx")) {
00577 //              mrch.mx = dict["MRC.mx"];
00578 //      }
00579 //      else {
00580                 mrch.mx = nx;
00581 //      }
00582 //      if(dict.has_key("MRC.my")) {
00583 //              mrch.my = dict["MRC.my"];
00584 //      }
00585 //      else {
00586                 mrch.my = ny;
00587 //      }
00588 //      if(dict.has_key("MRC.mz")) {
00589 //              mrch.mz = dict["MRC.mz"];
00590 //      }
00591 //      else {
00592                 mrch.mz = nz;
00593 //      }
00594 
00595         mrch.xlen = mrch.mx * (float) dict["apix_x"];
00596         mrch.ylen = mrch.my * (float) dict["apix_y"];
00597         mrch.zlen = mrch.mz * (float) dict["apix_z"];
00598 
00599         if(dict.has_key("MRC.nxstart")) {
00600                 mrch.nxstart = dict["MRC.nxstart"];
00601         }
00602         else {
00603                 mrch.nxstart = -nx / 2;
00604         }
00605         if(dict.has_key("MRC.nystart")) {
00606                 mrch.nystart = dict["MRC.nystart"];
00607         }
00608         else {
00609                 mrch.nystart = -ny / 2;
00610         }
00611         if(dict.has_key("MRC.nzstart")) {
00612                 mrch.nzstart = dict["MRC.nzstart"];
00613         }
00614         else {
00615                 mrch.nzstart = -nz / 2;
00616         }
00617 
00618         sprintf(mrch.map, "MAP ");
00619         mrch.machinestamp = generate_machine_stamp();
00620 
00621         MrcHeader mrch2 = mrch;
00622 
00623         if (opposite_endian || !use_host_endian) {
00624                 swap_header(mrch2);
00625         }
00626 
00627         if (fwrite(&mrch2, sizeof(MrcHeader), 1, mrcfile) != 1) {
00628                 throw ImageWriteException(filename, "MRC header");
00629         }
00630 
00631         mode_size = get_mode_size(mrch.mode);
00632         is_new_file = false;
00633 
00634         if( dict.has_key("ctf") ) {
00635                 vector<float> vctf = dict["ctf"];
00636                 EMAN1Ctf ctf_;
00637                 ctf_.from_vector(vctf);
00638                 write_ctf(ctf_);
00639         }
00640 
00641         EXITFUNC;
00642         return 0;
00643 }
00644 
00645 int MrcIO::read_data(float *rdata, int image_index, const Region * area, bool )
00646 {
00647         ENTERFUNC;
00648 
00649         if(!isFEI) {
00650                 //single image format, index can only be zero
00651                 image_index = 0;
00652         }
00653 
00654         check_read_access(image_index, rdata);
00655 
00656         if (area && is_complex_mode()) {
00657                 LOGERR("Error: cannot read a region of a complex image.");
00658                 return 1;
00659         }
00660 
00661         unsigned char *cdata = (unsigned char *) rdata;
00662         short *sdata = (short *) rdata;
00663         unsigned short *usdata = (unsigned short *) rdata;
00664 
00665         size_t size = 0;
00666         int xlen = 0, ylen = 0, zlen = 0;
00667         if(isFEI) {     //FEI extended MRC, read one 2D image from a tilt series
00668                 check_region(area, FloatSize(mrch.nx, mrch.ny, 1), is_new_file, false);
00669                 portable_fseek(mrcfile, sizeof(MrcHeader)+feimrch.next, SEEK_SET);
00670 
00671                 Region * new_area;
00672                 if(area) {
00673                         new_area = new Region(area->x_origin(), area->y_origin(), (float)image_index, area->get_width(), area->get_height(), 1.0f);
00674                 }
00675                 else {
00676                         new_area = new Region(0, 0, image_index, feimrch.nx, feimrch.ny, 1);
00677                 }
00678                 EMUtil::process_region_io(cdata, mrcfile, READ_ONLY,
00679                                                                   image_index, mode_size,
00680                                                                   feimrch.nx, feimrch.ny, feimrch.nz, new_area);
00681 
00682                 EMUtil::get_region_dims(new_area, feimrch.nx, &xlen, feimrch.ny, &ylen, feimrch.nz, &zlen);
00683 
00684                 size = xlen * ylen * zlen;
00685 
00686                 delete new_area;
00687         }
00688         else {  //regular MRC
00689                 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file, false);
00690                 portable_fseek(mrcfile, sizeof(MrcHeader)+mrch.nsymbt, SEEK_SET);
00691 
00692                 EMUtil::process_region_io(cdata, mrcfile, READ_ONLY,
00693                                                                   image_index, mode_size,
00694                                                                   mrch.nx, mrch.ny, mrch.nz, area);
00695 
00696                 EMUtil::get_region_dims(area, mrch.nx, &xlen, mrch.ny, &ylen, mrch.nz, &zlen);
00697 
00698                 size = xlen * ylen * zlen;
00699         }
00700 
00701         if (mrch.mode != MRC_UCHAR) {
00702                 if (mode_size == sizeof(short)) {
00703                         become_host_endian < short >(sdata, size);
00704                 }
00705                 else if (mode_size == sizeof(float)) {
00706                         become_host_endian < float >(rdata, size);
00707                 }
00708         }
00709 
00710         if (mrch.mode == MRC_UCHAR) {
00711                 for (size_t i = 0; i < size; ++i) {
00712                         size_t j = size - 1 - i;
00713                         //rdata[i] = static_cast<float>(cdata[i]/100.0f - 1.28f);
00714                         rdata[j] = static_cast < float >(cdata[j]);
00715                 }
00716         }
00717         else if (mrch.mode == MRC_SHORT ) {
00718                 for (size_t i = 0; i < size; ++i) {
00719                         size_t j = size - 1 - i;
00720                         rdata[j] = static_cast < float >(sdata[j]);
00721                 }
00722         }
00723         else if (mrch.mode == MRC_USHORT) {
00724                 for (size_t i = 0; i < size; ++i) {
00725                         size_t j = size - 1 - i;
00726                         rdata[j] = static_cast < float >(usdata[j]);
00727                 }
00728         }
00729 
00730         if (is_complex_mode()) {
00731                 if(!is_ri) Util::ap2ri(rdata, size);
00732                 Util::flip_complex_phase(rdata, size);
00733                 Util::rotate_phase_origin(rdata, xlen, ylen, zlen);
00734         }
00735         EXITFUNC;
00736         return 0;
00737 }
00738 
00739 int MrcIO::write_data(float *data, int image_index, const Region* area,
00740                                           EMUtil::EMDataType, bool use_host_endian)
00741 {
00742         ENTERFUNC;
00743         //single image format, index can only be zero
00744         image_index = 0;
00745         check_write_access(rw_mode, image_index, 1, data);
00746         check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file);
00747 
00748         int nx = mrch.nx;
00749         int ny = mrch.ny;
00750         int nz = mrch.nz;
00751         size_t size = (size_t)nx * ny * nz;
00752 
00753         if (is_complex_mode()) {
00754                 nx *= 2;
00755                 if (!is_ri) {
00756                         Util::ap2ri(data, size);
00757                         is_ri = 1;
00758                 }
00759                 Util::flip_complex_phase(data, size);
00760                 Util::rotate_phase_origin(data, nx, ny, nz);
00761         }
00762 
00763         portable_fseek(mrcfile, sizeof(MrcHeader), SEEK_SET);
00764 
00765         if ( (is_big_endian != ByteOrder::is_host_big_endian()) || !use_host_endian) {
00766                 if (mrch.mode != MRC_UCHAR) {
00767                         if (mode_size == sizeof(short)) {
00768                                 ByteOrder::swap_bytes((short*) data, size);
00769                         }
00770                         else if (mode_size == sizeof(float)) {
00771                                 ByteOrder::swap_bytes((float*) data, size);
00772                         }
00773                 }
00774         }
00775         mode_size = get_mode_size(mrch.mode);
00776 
00777 //      int xlen = 0, ylen = 0, zlen = 0;
00778 //      EMUtil::get_region_dims(area, nx, &xlen, mrch.ny, &ylen, mrch.nz, &zlen);
00779 //      int size = xlen * ylen * zlen;
00780         void * ptr_data = data;
00781 
00782         float rendermin = 0.0f;
00783         float rendermax = 0.0f;
00784         EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax, nz);
00785 
00786         unsigned char *cdata = 0;
00787         short *sdata = 0;
00788         unsigned short *usdata = 0;
00789         if (mrch.mode == MRC_UCHAR) {
00790                 cdata = new unsigned char[size];
00791                 for (size_t i = 0; i < size; ++i) {
00792                         if(data[i] <= rendermin) {
00793                                 cdata[i] = 0;
00794                         }
00795                         else if(data[i] >= rendermax){
00796                                 cdata[i] = UCHAR_MAX;
00797                         }
00798                         else {
00799                                 cdata[i]=(unsigned char)((data[i]-rendermin)/(rendermax-rendermin)*UCHAR_MAX);
00800                         }
00801                 }
00802                 ptr_data = cdata;
00803                 update_stat((void *)cdata);
00804         }
00805         else if (mrch.mode == MRC_SHORT || mrch.mode == MRC_SHORT_COMPLEX) {
00806                 sdata = new short[size];
00807                 for (size_t i = 0; i < size; ++i) {
00808                         if(data[i] <= rendermin) {
00809                                 sdata[i] = SHRT_MIN;
00810                         }
00811                         else if(data[i] >= rendermax) {
00812                                 sdata[i] = SHRT_MAX;
00813                         }
00814                         else {
00815                                 sdata[i]=(short)(((data[i]-rendermin)/(rendermax-rendermin))*(SHRT_MAX-SHRT_MIN) - SHRT_MAX);
00816                         }
00817                 }
00818                 ptr_data = sdata;
00819                 update_stat((void *)sdata);
00820         }
00821         else if (mrch.mode == MRC_USHORT) {
00822                 usdata = new unsigned short[size];
00823                 for (size_t i = 0; i < size; ++i) {
00824                         if(data[i] <= rendermin) {
00825                                 usdata[i] = 0;
00826                         }
00827                         else if(data[i] >= rendermax) {
00828                                 usdata[i] = USHRT_MAX;
00829                         }
00830                         else {
00831                                 usdata[i]=(unsigned short)((data[i]-rendermin)/(rendermax-rendermin)*USHRT_MAX);
00832                         }
00833                 }
00834                 ptr_data = usdata;
00835                 update_stat((void *)usdata);
00836         }
00837 
00838         // New way to write data which includes region writing.
00839         // If it is tested to be OK, remove the old code in the
00840         // #if 0  ... #endif block.
00841         EMUtil::process_region_io(ptr_data, mrcfile, WRITE_ONLY, image_index,
00842                                                           mode_size, nx, mrch.ny, mrch.nz, area);
00843 
00844         if(cdata) {delete [] cdata; cdata=0;}
00845         if(sdata) {delete [] sdata; sdata=0;}
00846         if(usdata) {delete [] usdata; usdata=0;}
00847 
00848 #if 0
00849         int row_size = nx * get_mode_size(mrch.mode);
00850         int sec_size = nx * ny;
00851 
00852         unsigned char *cbuf = new unsigned char[row_size];
00853         unsigned short *sbuf = (unsigned short *) cbuf;
00854 
00855         for (int i = 0; i < nz; i++) {
00856                 int i2 = i * sec_size;
00857                 for (int j = 0; j < ny; j++) {
00858                         int k = i2 + j * nx;
00859                         void *pbuf = 0;
00860 
00861                         switch (mrch.mode) {
00862                         case MRC_UCHAR:
00863                                 for (int l = 0; l < nx; l++) {
00864                                         cbuf[l] = static_cast < unsigned char >(data[k + l]);
00865                                 }
00866                                 pbuf = cbuf;
00867                                 fwrite(cbuf, row_size, 1, mrcfile);
00868                                 break;
00869 
00870                         case MRC_SHORT:
00871                         case MRC_SHORT_COMPLEX:
00872                                 for (int l = 0; l < nx; l++) {
00873                                         sbuf[l] = static_cast < short >(data[k + l]);
00874                                 }
00875                                 pbuf = sbuf;
00876                                 fwrite(sbuf, row_size, 1, mrcfile);
00877                                 break;
00878 
00879                         case MRC_USHORT:
00880                                 for (int l = 0; l < nx; l++) {
00881                                         sbuf[l] = static_cast < unsigned short >(data[k + l]);
00882                                 }
00883                                 pbuf = sbuf;
00884                                 fwrite(sbuf, row_size, 1, mrcfile);
00885                                 break;
00886 
00887                         case MRC_FLOAT:
00888                         case MRC_FLOAT_COMPLEX:
00889                                 pbuf = &data[k];
00890                                 break;
00891                         }
00892                         if (pbuf) {
00893                                 fwrite(pbuf, row_size, 1, mrcfile);
00894                         }
00895                 }
00896         }
00897 
00898         if(cbuf)
00899         {
00900                 delete[]cbuf;
00901                 cbuf = 0;
00902         }
00903 #endif
00904 
00905         EXITFUNC;
00906         return 0;
00907 }
00908 
00909 void MrcIO::update_stat(void* data)
00910 {
00911         size_t size =  mrch.nx * mrch.ny * mrch.nz;
00912         float v = 0.0f; //variable to hold pixel value
00913         double sum = 0.0;
00914         double square_sum = 0.0;
00915         double mean = 0.0;
00916         float min, max;
00917         
00918         unsigned char * cdata = 0;
00919         short * sdata = 0;
00920         unsigned short * usdata = 0;
00921         
00922         if (mrch.mode == MRC_UCHAR) {
00923                 max = 0.0f;
00924                 min = UCHAR_MAX;
00925                 cdata = (unsigned char *)data;
00926                 
00927                 for (size_t i = 0; i < size; ++i) {
00928                         v = (float)(cdata[i]);
00929 #ifdef _WIN32
00930                         max = _cpp_max(max,v);
00931                         min = _cpp_min(min,v);
00932 #else
00933                         max=std::max<float>(max,v);
00934                         min=std::min<float>(min,v);
00935 #endif  //_WIN32
00936                         
00937                         sum += v;
00938                         square_sum += v * v;
00939                 }
00940         }
00941         else if (mrch.mode == MRC_SHORT || mrch.mode == MRC_SHORT_COMPLEX) {
00942                 max = (float)SHRT_MIN;
00943                 min = (float)SHRT_MAX;
00944                 sdata = (short *)data;
00945                 
00946                 for (size_t i = 0; i < size; ++i) {
00947                         v = (float)(sdata[i]);
00948 #ifdef _WIN32
00949                         max = _cpp_max(max,v);
00950                         min = _cpp_min(min,v);
00951 #else
00952                         max=std::max<float>(max,v);
00953                         min=std::min<float>(min,v);
00954 #endif  //_WIN32
00955                         
00956                         sum += v;
00957                         square_sum += v * v;
00958                 }
00959         }
00960         else if (mrch.mode == MRC_USHORT) {
00961                 max = 0.0f;
00962                 min = (float)USHRT_MAX;
00963                 usdata = (unsigned short*)data;
00964                 
00965                 for (size_t i = 0; i < size; ++i) {
00966                         v = (float)(usdata[i]);
00967 #ifdef _WIN32
00968                         max = _cpp_max(max,v);
00969                         min = _cpp_min(min,v);
00970 #else
00971                         max=std::max<float>(max,v);
00972                         min=std::min<float>(min,v);
00973 #endif  //_WIN32
00974                         
00975                         sum += v;
00976                         square_sum += v * v;
00977                 }
00978         }
00979         else {
00980                 throw InvalidCallException("This function is used to write 8bit/16bit mrc file only.");
00981         }
00982         
00983         mean = sum/size;
00984 #ifdef _WIN32
00985         float sigma = (float)std::sqrt( _cpp_max(0.0,(square_sum - sum*sum / size)/(size-1)));
00986 #else
00987         float sigma = (float)std::sqrt(std::max<float>(0.0,(square_sum - sum*sum / size)/(size-1)));
00988 #endif  //_WIN32
00989 
00990         /*change mrch.amin/amax/amean.rms here*/
00991         mrch.amin = min;
00992         mrch.amax = max;
00993         mrch.amean = (float)mean;
00994         mrch.rms = sigma;
00995         
00996         MrcHeader mrch2 = mrch;
00997 
00998 //endian issue, can't get use_host_endian argument
00999 //      bool opposite_endian = false;
01000 
01001 //      if (!is_new_file) {
01002 //              if (is_big_endian != ByteOrder::is_host_big_endian()) {
01003 //                      opposite_endian = true;
01004 //              }
01005 //
01006 //              portable_fseek(mrcfile, 0, SEEK_SET);
01007 //      }
01008 //      
01009 //      if (opposite_endian || !use_host_endian) {
01010 //              swap_header(mrch2);
01011 //      }
01012 
01013         portable_fseek(mrcfile, 0, SEEK_SET);
01014         
01015         if (fwrite(&mrch2, sizeof(MrcHeader), 1, mrcfile) != 1) {
01016                 throw ImageWriteException(filename, "MRC header");
01017         }
01018         
01019         portable_fseek(mrcfile, sizeof(MrcHeader), SEEK_SET);
01020 }
01021 
01022 bool MrcIO::is_complex_mode()
01023 {
01024         init();
01025         if (mrch.mode == MRC_SHORT_COMPLEX || mrch.mode == MRC_FLOAT_COMPLEX) {
01026                 return true;
01027         }
01028         return false;
01029 }
01030 
01031 
01032 int MrcIO::read_ctf(Ctf & ctf, int)
01033 {
01034         ENTERFUNC;
01035         init();
01036         size_t n = strlen(CTF_MAGIC);
01037 
01038         int err = 1;
01039         if (strncmp(&mrch.labels[0][0], CTF_MAGIC, n) == 0) {
01040                 err = ctf.from_string(string(&mrch.labels[0][n]));
01041         }
01042         EXITFUNC;
01043         return err;
01044 }
01045 
01046 void MrcIO::write_ctf(const Ctf & ctf, int)
01047 {
01048         ENTERFUNC;
01049         init();
01050 
01051         string ctf_str = ctf.to_string();
01052         sprintf(&mrch.labels[0][0], "%s%s", CTF_MAGIC, ctf_str.c_str());
01053         rewind(mrcfile);
01054 
01055         if (fwrite(&mrch, sizeof(MrcHeader), 1, mrcfile) != 1) {
01056                 throw ImageWriteException(filename, "write CTF info to header failed");
01057         }
01058         EXITFUNC;
01059 }
01060 
01061 void MrcIO::flush()
01062 {
01063         fflush(mrcfile);
01064 }
01065 
01066 
01067 int MrcIO::get_mode_size(int mm)
01068 {
01069         MrcIO::MrcMode m = static_cast < MrcMode > (mm);
01070 
01071         int msize = 0;
01072         switch (m) {
01073         case MRC_UCHAR:
01074                 msize = sizeof(char);
01075                 break;
01076         case MRC_SHORT:
01077         case MRC_USHORT:
01078         case MRC_SHORT_COMPLEX:
01079                 msize = sizeof(short);
01080                 break;
01081         case MRC_FLOAT:
01082         case MRC_FLOAT_COMPLEX:
01083                 msize = sizeof(float);
01084                 break;
01085         default:
01086                 msize = 0;
01087         }
01088 
01089         return msize;
01090 }
01091 
01092 int MrcIO::to_em_datatype(int m)
01093 {
01094         EMUtil::EMDataType e = EMUtil::EM_UNKNOWN;
01095 
01096         switch (m) {
01097         case MRC_UCHAR:
01098                 e = EMUtil::EM_UCHAR;
01099                 break;
01100         case MRC_SHORT:
01101                 e = EMUtil::EM_SHORT;
01102                 break;
01103         case MRC_USHORT:
01104                 e = EMUtil::EM_USHORT;
01105                 break;
01106         case MRC_SHORT_COMPLEX:
01107                 e = EMUtil::EM_SHORT_COMPLEX;
01108                 break;
01109         case MRC_FLOAT:
01110                 e = EMUtil::EM_FLOAT;
01111                 break;
01112         case MRC_FLOAT_COMPLEX:
01113                 e = EMUtil::EM_FLOAT_COMPLEX;
01114                 break;
01115         default:
01116                 e = EMUtil::EM_UNKNOWN;
01117         }
01118         return e;
01119 }
01120 
01121 
01122 int MrcIO::to_mrcmode(int e, int is_complex)
01123 {
01124         MrcMode m = MRC_UNKNOWN;
01125         EMUtil::EMDataType em_type = static_cast < EMUtil::EMDataType > (e);
01126 
01127         switch (em_type) {
01128         case EMUtil::EM_UCHAR:
01129                 m = MRC_UCHAR;
01130                 break;
01131         case EMUtil::EM_USHORT:
01132                 if (is_complex) {
01133                         m = MRC_SHORT_COMPLEX;
01134                 }
01135                 else {
01136                         m = MRC_USHORT;
01137                 }
01138                 break;
01139         case EMUtil::EM_SHORT:
01140                 if (is_complex) {
01141                         m = MRC_SHORT_COMPLEX;
01142                 }
01143                 else {
01144                         m = MRC_SHORT;
01145                 }
01146                 break;
01147         case EMUtil::EM_SHORT_COMPLEX:
01148         case EMUtil::EM_USHORT_COMPLEX:
01149                 m = MRC_SHORT_COMPLEX;
01150                 break;
01151         case EMUtil::EM_CHAR:
01152         case EMUtil::EM_INT:
01153         case EMUtil::EM_UINT:
01154         case EMUtil::EM_FLOAT:
01155                 if (is_complex) {
01156                         m = MRC_FLOAT_COMPLEX;
01157                 }
01158                 else {
01159                         m = MRC_FLOAT;
01160                 }
01161                 break;
01162         case EMUtil::EM_FLOAT_COMPLEX:
01163                 m = MRC_FLOAT_COMPLEX;
01164                 break;
01165         default:
01166                 m = MRC_FLOAT;
01167         }
01168 
01169         return m;
01170 }
01171 
01172 
01173 
01174 int MrcIO::generate_machine_stamp()
01175 {
01176         int stamp = 0;
01177         char *p = (char *) (&stamp);
01178 
01179         if (ByteOrder::is_host_big_endian()) {
01180                 p[0] = 0x11;
01181                 p[1] = 0x11;
01182                 p[2] = 0;
01183                 p[3] = 0;
01184         }
01185         else {
01186                 p[0] = 0x44;
01187                 p[1] = 0x41;
01188                 p[2] = 0;
01189                 p[3] = 0;
01190         }
01191         return stamp;
01192 }
01193 
01194 void MrcIO::swap_header(MrcHeader& mrch)
01195 {
01196         ByteOrder::swap_bytes((int *) &mrch, NUM_4BYTES_PRE_MAP);
01197         ByteOrder::swap_bytes((int *) &mrch.machinestamp, NUM_4BYTES_AFTER_MAP);
01198 }
01199 
01200 int MrcIO::get_nimg()
01201 {
01202         init();
01203 
01204         if(isFEI) {
01205                 return feimrch.nz;
01206         }
01207         else {
01208                 return 1;
01209         }
01210 }

Generated on Mon May 2 13:27:39 2011 for EMAN2 by  doxygen 1.3.9.1