hdfio2.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 #ifdef EM_HDF5
00037 
00038 //#define DEBUGHDF      1
00039 
00040 #include "hdfio2.h"
00041 #include "geometry.h"
00042 #include "ctf.h"
00043 #include "emassert.h"
00044 #include "transform.h"
00045 #include "ctf.h"
00046 #include <iostream>
00047 #include <cstring>
00048 
00049 #ifndef WIN32
00050         #include <sys/param.h>
00051 #else
00052         #define  MAXPATHLEN (MAX_PATH * 4)
00053 #endif  //WIN32
00054 
00055 using namespace EMAN;
00056 
00057 static const int ATTR_NAME_LEN = 128;
00058 
00059 HdfIO2::HdfIO2(const string & hdf_filename, IOMode rw)
00060 :       file(-1), group(-1), filename(hdf_filename),
00061         rw_mode(rw), initialized(false)
00062 {
00063         accprop=H5Pcreate(H5P_FILE_ACCESS);
00064 
00065         //STDIO file driver has 2G size limit on 32 bit Linux system
00066         H5Pset_fapl_sec2( accprop );
00067         //H5Pset_fapl_stdio( accprop );
00068 
00069 //      H5Pset_fapl_core( accprop, 1048576, 0  );
00070 //      H5Pset_cache(accprop)
00071         hsize_t dims=1;
00072         simple_space=H5Screate_simple(1,&dims,NULL);
00073 }
00074 
00075 HdfIO2::~HdfIO2()
00076 {
00077         H5Sclose(simple_space);
00078         H5Pclose(accprop);
00079     if (group >= 0) {
00080         H5Gclose(group);
00081     }
00082     if (file >= 0) {
00083                 H5Fflush(file,H5F_SCOPE_GLOBAL);        // If there were no resource leaks, this wouldn't be necessary...
00084                 H5Fclose(file);
00085     }
00086 #ifdef DEBUGHDF
00087         printf("HDf close\n");
00088 #endif
00089 }
00090 
00091 // This reads an already opened attribute and returns the results as an EMObject
00092 // The attribute is not closed
00093 EMObject HdfIO2::read_attr(hid_t attr) {
00094         hid_t type = H5Aget_type(attr);
00095         hid_t spc = H5Aget_space(attr);
00096         H5T_class_t cls = H5Tget_class(type);
00097         size_t sz = H5Tget_size(type);                                          // storage size, arrays handled in the 'space'
00098         hssize_t pts = H5Sget_simple_extent_npoints(spc);       // number of points > 1 if an array of floats or integers
00099 
00100         EMObject ret(0);
00101         char c;
00102         int i;
00103 //      unsigned int ui;
00104         float f,*fa;
00105         int * ia;
00106 //      unsigned int * uia;
00107         double d;
00108         char *s;
00109         vector <float> fv((size_t)pts);
00110         vector <int> iv((size_t)pts);
00111 //      vector <unsigned int> uiv(pts);
00112 
00113         float *matrix;
00114         Transform* t;
00115         Ctf* ctf;
00116 //      int r, c, k=0;
00117 
00118         switch (cls) {
00119         case H5T_INTEGER:
00120                 if(sz==1) {
00121                         H5Aread(attr,H5T_NATIVE_CHAR,&c);
00122                         bool b = false;
00123                         if(c=='T') {
00124                                 b = true;
00125                         }
00126                         else if(c=='F') {
00127                                 b = false;
00128                         }
00129                         ret = EMObject(b);
00130                 }
00131                 else if(sz==4) {
00132                         if(pts==1) {
00133                                 H5Aread(attr,H5T_NATIVE_INT,&i);
00134                                 ret=EMObject(i);
00135                         }
00136                         else {
00137                                 ia=(int *)malloc((size_t)pts*sizeof(int));
00138                                 H5Aread(attr,H5T_NATIVE_INT,ia);
00139                                 for (i=0; i<pts; i++) iv[i]=ia[i];
00140                                 free(ia);
00141                                 ret=EMObject(iv);
00142                         }
00143                 }
00144                 break;
00145 //      case H5T_UNSIGNED_INTEGER:
00146 //              if(pts==1) {
00147 //                      H5Aread(attr,H5T_NATIVE_UINT,&ui);
00148 //                      ret=EMObject(ui);
00149 //              }
00150 //              else {
00151 //                      uia=(unsigned int *)malloc(pts*sizeof(unsigned int));
00152 //                      H5Aread(attr,H5T_NATIVE_UINT,uia);
00153 //                      for (i=0; i<pts; i++) uiv[i]=uia[i];
00154 //                      free(uia);
00155 //                      ret=EMObject(uiv);
00156 //              }
00157 //              break;
00158         case H5T_FLOAT:
00159                 if (sz==4) {
00160                         if (pts==1) {
00161                                 H5Aread(attr,H5T_NATIVE_FLOAT,&f);
00162                                 ret=EMObject(f);
00163                         }
00164                         else {
00165                                 fa=(float *)malloc((size_t)pts*sizeof(float));
00166                                 H5Aread(attr,H5T_NATIVE_FLOAT,fa);
00167                                 for (i=0; i<pts; i++) fv[i]=fa[i];
00168                                 free(fa);
00169                                 ret=EMObject(fv);
00170                         }
00171                 }
00172                 else if (sz==8) {
00173                         H5Aread(attr,H5T_NATIVE_DOUBLE,&d);
00174                         ret=EMObject(d);
00175                 }
00176                 break;
00177         case H5T_STRING:
00178                 s=(char *)malloc(sz+1);
00179                 H5Aread(attr,type,s);
00180 //              H5Aread(attr,H5T_NATIVE_CHAR,s);
00181                 if(s[0] == 'O' && isdigit(s[1])) {
00182                         ctf = new EMAN1Ctf();
00183                         ctf->from_string(string(s));
00184                         ret = EMObject(ctf);
00185                         delete ctf;
00186                 }
00187                 else if(s[0] == 'E' && isdigit(s[1])) {
00188                         ctf = new EMAN2Ctf();
00189                         ctf->from_string(string(s));
00190                         ret = EMObject(ctf);
00191                         delete ctf;
00192                 }
00193                 else {
00194                         ret=EMObject(s);
00195                 }
00196                 free(s);
00197                 break;
00198         case H5T_COMPOUND:
00199                 matrix = (float*)malloc(12*sizeof(float));
00200                 H5Aread(attr, type, matrix);
00201 //              ret.create_transform3d_by_array(trans3d);
00202                 t = new Transform(matrix);
00203                 ret = EMObject(t);
00204                 free(matrix);
00205                 delete t; t=0;
00206 
00207 //              trans3d = (float*)malloc(16*sizeof(float));     //16 float for a Transform3D object
00208 //              H5Aread(attr, type, trans3d);
00209 // //           ret.create_transform3d_by_array(trans3d);
00210 //              trans = new Transform3D();
00211 //              for(r=0; r<4; ++r) {
00212 //                      for(c=0; c<4; ++c) {
00213 //                              trans->set(r, c, trans3d[k]);
00214 //                              ++k;
00215 //                      }
00216 //              }
00217 //              ret = EMObject(trans);
00218 //              free(trans3d);
00219                 break;
00220         default:
00221                 LOGERR("Unhandled HDF5 metadata %d", cls);
00222         }
00223 
00224         H5Sclose(spc);
00225         H5Tclose(type);
00226 
00227         return ret;
00228 }
00229 
00230 // This writes an attribute with specified name to a given open object
00231 // The attribute is opened and closed. returns 0 on success
00232 int HdfIO2::write_attr(hid_t loc,const char *name,EMObject obj) {
00233         hid_t type=0;
00234         hid_t spc=0;
00235         hsize_t dims=1;
00236         vector <float> fv;
00237         vector <int> iv;
00238         switch(obj.get_type())
00239         {
00240         case EMObject::BOOL:
00241                 type=H5Tcopy(H5T_NATIVE_CHAR);
00242                 spc=H5Scopy(simple_space);
00243                 break;
00244         case EMObject::INT:
00245                 type=H5Tcopy(H5T_NATIVE_INT);
00246                 spc=H5Scopy(simple_space);
00247                 break;
00248         case EMObject::UNSIGNEDINT:
00249                 type=H5Tcopy(H5T_NATIVE_UINT);
00250                 spc=H5Scopy(simple_space);
00251                 break;
00252         case EMObject::FLOAT:
00253                 type=H5Tcopy(H5T_NATIVE_FLOAT);
00254                 spc=H5Scopy(simple_space);
00255                 break;
00256         case EMObject::DOUBLE:
00257                 type=H5Tcopy(H5T_NATIVE_DOUBLE);
00258                 spc=H5Scopy(simple_space);
00259                 break;
00260         case EMObject::STRING:
00261         case EMObject::CTF:
00262                 type=H5Tcopy(H5T_C_S1);
00263                 H5Tset_size(type,strlen((const char *)obj)+1);
00264                 spc=H5Screate(H5S_SCALAR);
00265                 break;
00266         case EMObject::FLOATARRAY:
00267                 type=H5Tcopy(H5T_NATIVE_FLOAT);
00268                 fv=obj;
00269                 dims=fv.size();
00270                 spc=H5Screate_simple(1,&dims,NULL);
00271                 break;
00272         case EMObject::INTARRAY:
00273                 type=H5Tcopy(H5T_NATIVE_INT);
00274                 iv=obj;
00275                 dims=iv.size();
00276                 spc=H5Screate_simple(1,&dims,NULL);
00277                 break;
00278         case EMObject::TRANSFORM:
00279                 type = H5Tcreate(H5T_COMPOUND, 12 * sizeof(float)); //Transform is a 3x4 matrix
00280                 H5Tinsert(type, "00", 0, H5T_NATIVE_FLOAT);
00281                 H5Tinsert(type, "01", 1*sizeof(float), H5T_NATIVE_FLOAT);
00282                 H5Tinsert(type, "02", 2*sizeof(float), H5T_NATIVE_FLOAT);
00283                 H5Tinsert(type, "03", 3*sizeof(float), H5T_NATIVE_FLOAT);
00284                 H5Tinsert(type, "10", 4*sizeof(float), H5T_NATIVE_FLOAT);
00285                 H5Tinsert(type, "11", 5*sizeof(float), H5T_NATIVE_FLOAT);
00286                 H5Tinsert(type, "12", 6*sizeof(float), H5T_NATIVE_FLOAT);
00287                 H5Tinsert(type, "13", 7*sizeof(float), H5T_NATIVE_FLOAT);
00288                 H5Tinsert(type, "20", 8*sizeof(float), H5T_NATIVE_FLOAT);
00289                 H5Tinsert(type, "21", 9*sizeof(float), H5T_NATIVE_FLOAT);
00290                 H5Tinsert(type, "22", 10*sizeof(float), H5T_NATIVE_FLOAT);
00291                 H5Tinsert(type, "23", 11*sizeof(float), H5T_NATIVE_FLOAT);
00292                 H5Tpack(type);
00293 
00294                 dims = 1;       //one compound type
00295                 spc = H5Screate_simple(1, &dims, NULL);
00296                 break;
00297         case EMObject::STRINGARRAY:
00298         case EMObject::EMDATA:
00299         case EMObject::XYDATA:
00300         case EMObject::FLOAT_POINTER:
00301         case EMObject::INT_POINTER:
00302         case EMObject::VOID_POINTER:
00303                 return -1;
00304                 break;
00305         case EMObject::UNKNOWN:
00306                 break;
00307         }
00308 
00309     //we need this delete attribute call here, even we called erase_header()
00310     //at the biginning of write_header(), since the  "imageid_max" need be updated correctly.
00311         if( H5Adelete(loc,name) < 0 ) {
00312 #ifdef DEBUGHDF
00313                 LOGERR("Attribute %s deletion error in write_attr().\n", name);
00314 #endif
00315         }
00316         else {
00317 #ifdef DEBUGHDF
00318                 printf("delete attribute %s successfully in write_attr().\n", name);
00319 #endif
00320         }
00321         hid_t attr = H5Acreate(loc,name,type,spc,H5P_DEFAULT);
00322 
00323         bool b;
00324         char c;
00325         int i;
00326         float f,*fa;
00327         int * ia;
00328         unsigned int ui;
00329         double d;
00330         const char *s;
00331         Transform * tp;
00332         switch(obj.get_type()) {
00333         case EMObject::BOOL:
00334                 b = (bool)obj;
00335                 if(b) {
00336                         c = 'T';
00337                 } else {
00338                         c = 'F';
00339                 }
00340                 H5Awrite(attr,type,&c);
00341                 break;
00342         case EMObject::INT:
00343                 i=(int)obj;
00344                 H5Awrite(attr,type,&i);
00345                 break;
00346         case EMObject::UNSIGNEDINT:
00347                 ui=(unsigned int)obj;
00348                 H5Awrite(attr,type,&ui);
00349                 break;
00350         case EMObject::FLOAT:
00351                 f=(float)obj;
00352                 H5Awrite(attr,type,&f);
00353                 break;
00354         case EMObject::DOUBLE:
00355                 d=(double)obj;
00356                 H5Awrite(attr,type,&d);
00357                 break;
00358         case EMObject::STRING:
00359         case EMObject::CTF:
00360                 s=(const char *)obj;
00361                 H5Awrite(attr,type,s);
00362                 break;
00363         case EMObject::FLOATARRAY:
00364                 fa=(float *)malloc(fv.size()*sizeof(float));
00365                 for (ui=0; ui<fv.size(); ui++) fa[ui]=fv[ui];
00366                 H5Awrite(attr,type,fa);
00367                 free(fa);
00368                 break;
00369         case EMObject::INTARRAY:
00370                 ia=(int *)malloc(iv.size()*sizeof(int));
00371                 for (ui=0; ui<iv.size(); ui++) ia[ui]=iv[ui];
00372                 H5Awrite(attr,type,ia);
00373                 free(ia);
00374                 break;
00375         case EMObject::TRANSFORM:
00376         {
00377                 tp = (Transform *)obj;
00378                 fa = (float *)malloc(12*sizeof(float));
00379                 int r, c, k=0;
00380                 for(r=0; r<3; ++r) {
00381                         for(c=0; c<4; ++c) {
00382                                 fa[k] = tp->at(r,c);
00383                                 ++k;
00384                         }
00385                 }
00386                 H5Awrite(attr,type,fa);
00387                 free(fa);
00388         }
00389                 break;
00390 //      case EMObject::STRINGARRAY:
00391 //      case EMObject::EMDATA:
00392 //      case EMObject::XYDATA:
00393 //              return -1;
00394 //              break;
00395         default:
00396                 LOGERR("Unhandled HDF5 metadata '%s'", name);
00397 
00398         }
00399 
00400         herr_t ret1 = H5Tclose(type);
00401         herr_t ret2 = H5Sclose(spc);
00402         herr_t ret3 = H5Aclose(attr);
00403         if(ret1>=0 && ret2>=0 && ret3>=0) {
00404                 return 0;
00405         }
00406         else {
00407                 LOGERR("close error in write_attr()\n");
00408                 return -1;
00409         }
00410 }
00411 
00412 // Initializes the file for read-only or read-write access
00413 // Data is stored under /MDF/images
00414 // An attribute named imageid_max stores the number of the highest
00415 // numbered image in the file.
00416 // A group is then made for each individual image, all metadata for the
00417 // individual images is currently associated with the GROUP, not the dataset
00418 // dataset-specific data could also be associated with the dataset in
00419 // future. At the moment, there is only a single dataset in each group.
00420 void HdfIO2::init()
00421 {
00422         ENTERFUNC;
00423         if (initialized) {
00424                 return;
00425         }
00426 #ifdef DEBUGHDF
00427         printf("init\n");
00428 #endif
00429 
00430         H5Eset_auto(0, 0);      // Turn off console error logging.
00431 
00432         if (rw_mode == READ_ONLY) {
00433                 file = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, accprop);
00434                 if (file<0) throw FileAccessException(filename);
00435         }
00436         else {
00437                 file = H5Fopen(filename.c_str(), H5F_ACC_RDWR, accprop);
00438                 if (file < 0) {
00439                         file = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, accprop);
00440                         if (file < 0) {
00441                                 throw FileAccessException(filename);
00442                         }
00443                         else {
00444 #ifdef DEBUGHDF
00445                                 printf("File truncated or new file created\n");
00446 #endif
00447                         }
00448                 }
00449         }
00450 
00451         group=H5Gopen(file,"/MDF/images");
00452         if (group<0) {
00453                 if (rw_mode == READ_ONLY) throw ImageReadException(filename,"HDF5 file has no image data (no /MDF group)");
00454                 group=H5Gcreate(file,"/MDF",64);                // create the group for Macromolecular data
00455                 if (group<0) throw ImageWriteException(filename,"Unable to add image group (/MDF) to HDF5 file");
00456                 H5Gclose(group);
00457                 group=H5Gcreate(file,"/MDF/images",4096);               // create the group for images/volumes
00458                 if (group<0) throw ImageWriteException(filename,"Unable to add image group (/MDF/images) to HDF5 file");
00459                 write_attr(group,"imageid_max",EMObject(-1));
00460         }
00461         initialized = true;
00462         EXITFUNC;
00463 }
00464 
00465 
00466 // If this version of init() returns -1, then we have an old-style HDF5 file
00467 int HdfIO2::init_test()
00468 {
00469         ENTERFUNC;
00470         if (initialized) {
00471                 return 1;
00472         }
00473 #ifdef DEBUGHDF
00474         printf("init_test\n");
00475 #endif
00476 
00477         H5Eset_auto(0, 0);      // Turn off console error logging.
00478 
00479         hid_t fileid = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5Pcreate(H5P_FILE_ACCESS));
00480         hid_t groupid = H5Gopen(fileid, "/");
00481         hid_t attid = H5Aopen_name(groupid, "num_dataset");
00482 
00483         if (attid < 0) {
00484                 H5Gclose(groupid);
00485                 H5Fclose(fileid);
00486                 init();
00487                 EXITFUNC;
00488                 return 0;
00489         }
00490         else {
00491                 H5Aclose(attid);
00492                 H5Gclose(groupid);
00493                 H5Fclose(fileid);
00494                 EXITFUNC;
00495                 return -1;
00496         }
00497 }
00498 
00499 bool HdfIO2::is_valid(const void *first_block)
00500 {
00501         ENTERFUNC;
00502 
00503         if (first_block) {
00504                 char signature[8] = { 137,72,68,70,13,10,26,10 };
00505                 if (strncmp((const char *)first_block,signature,8)==0) return true;
00506                 // const char* f=(const char *)first_block;
00507                 // printf("bad hdf signature %d %d %d %d %d %d %d %d",f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7]);
00508                 return false;
00509         }
00510         EXITFUNC;
00511         return false;
00512 }
00513 
00514 // Reads all of the attributes from the /MDF/images/<imgno> group
00515 int HdfIO2::read_header(Dict & dict, int image_index, const Region * area, bool)
00516 {
00517         ENTERFUNC;
00518         init();
00519 #ifdef DEBUGHDF
00520         printf("read_head %d\n", image_index);
00521 #endif
00522         int i;
00523         // Each image is in a group for later expansion. Open the group
00524         char ipath[50];
00525         sprintf(ipath,"/MDF/images/%d", image_index);
00526         hid_t igrp=H5Gopen(file, ipath);
00527 
00528         int nattr=H5Aget_num_attrs(igrp);
00529 
00530         char name[ATTR_NAME_LEN];
00531         for (i=0; i<nattr; i++) {
00532                 hid_t attr=H5Aopen_idx(igrp, i);
00533                 H5Aget_name(attr,127,name);
00534                 if (strncmp(name,"EMAN.", 5)!=0) {
00535                         H5Aclose(attr);
00536                         continue;
00537                 }
00538                 EMObject val=read_attr(attr);
00539                 dict[name+5]=val;
00540                 H5Aclose(attr);
00541         }
00542 
00543         if(dict.has_key("ctf")) {
00544                 string ctfString = (string)dict["ctf"];
00545                 if(ctfString.substr(0, 1) == "O") {
00546                         Ctf * ctf_ = new EMAN1Ctf();
00547                         ctf_->from_string(ctfString);
00548                         dict.erase("ctf");
00549                         dict["ctf"] = ctf_;
00550                         delete ctf_;
00551                 }
00552                 else if(ctfString.substr(0, 1) == "E") {
00553                         Ctf * ctf_ = new EMAN2Ctf();
00554                         ctf_->from_string(ctfString);
00555                         dict.erase("ctf");
00556                         dict["ctf"] = ctf_;
00557                         delete ctf_;
00558                 }
00559         }
00560 
00561         if(area) {
00562                 check_region(area, IntSize(dict["nx"], dict["ny"], dict["nz"]), false, false);
00563 
00564                 dict["nx"] = area->get_width();
00565                 dict["ny"] = area->get_height();
00566                 dict["nz"] = area->get_depth();
00567 
00568                 if( dict.has_key("apix_x") && dict.has_key("apix_y") && dict.has_key("apix_z") )
00569                 {
00570                         if( dict.has_key("origin_x") && dict.has_key("origin_y") && dict.has_key("origin_z") )
00571                         {
00572                                 float xorigin = dict["origin_x"];
00573                                 float yorigin = dict["origin_y"];
00574                                 float zorigin = dict["origin_z"];
00575 
00576                                 float apix_x = dict["apix_x"];
00577                                 float apix_y = dict["apix_y"];
00578                                 float apix_z = dict["apix_z"];
00579 
00580                                 dict["origin_x"] = xorigin + apix_x * area->origin[0];
00581                                 dict["origin_y"] = yorigin + apix_y * area->origin[1];
00582                                 dict["origin_z"] = zorigin + apix_z * area->origin[2];
00583                         }
00584                 }
00585         }
00586 
00587         H5Gclose(igrp);
00588         EXITFUNC;
00589         return 0;
00590 }
00591 
00592 // This erases any existing attributes from the image group
00593 // prior to writing a new header. For a new image there
00594 // won't be any, so this should be harmless.
00595 int HdfIO2::erase_header(int image_index)
00596 {
00597         ENTERFUNC;
00598 
00599         if(image_index < 0) return 0; //image_index<0 for appending image, no need for erasing
00600 
00601         init();
00602 #ifdef DEBUGHDF
00603         printf("erase_head %d\n",image_index);
00604 #endif
00605         int i;
00606         // Each image is in a group for later expansion. Open the group
00607         char ipath[50];
00608         sprintf(ipath,"/MDF/images/%d", image_index);
00609         hid_t igrp=H5Gopen(file, ipath);
00610 
00611         int nattr=H5Aget_num_attrs(igrp);
00612 
00613         char name[ATTR_NAME_LEN];
00614         for (i=0; i<nattr; i++) {
00615                 hid_t attr = H5Aopen_idx(igrp, 0); //use 0 as index here, since the H5Adelete() will change the index
00616                 H5Aget_name(attr,127,name);
00617                 H5Aclose(attr);
00618                 if( H5Adelete(igrp,name) < 0 ) {
00619                         LOGERR("attribute %s deletion error in erase_header().\n", name);
00620                 }
00621         }
00622 
00623         H5Gclose(igrp);
00624         EXITFUNC;
00625         return 0;
00626 }
00627 
00628 
00629 int HdfIO2::read_data(float *data, int image_index, const Region *area, bool)
00630 {
00631         ENTERFUNC;
00632 #ifdef DEBUGHDF
00633         printf("read_data %d\n",image_index);
00634 #endif
00635 
00636         char ipath[50];
00637         sprintf(ipath,"/MDF/images/%d/image",image_index);
00638         hid_t ds=H5Dopen(file,ipath);
00639         if (ds<0) throw ImageWriteException(filename,"Image does not exist");
00640         hid_t spc=H5Dget_space(ds);
00641 
00642         hsize_t nx = 1, ny = 1, nz = 1;
00643         hsize_t dims_out[3];
00644         hsize_t rank = H5Sget_simple_extent_ndims(spc);
00645 
00646         H5Sget_simple_extent_dims(spc, dims_out, NULL);
00647         if(rank == 1) {
00648                 nx = dims_out[0];
00649                 ny = 1;
00650                 nz = 1;
00651         }
00652         else if(rank == 2) {
00653                 nx = dims_out[1];
00654                 ny = dims_out[0];
00655                 nz = 1;
00656         }
00657         else if(rank == 3) {
00658                 nx = dims_out[2];
00659                 ny = dims_out[1];
00660                 nz = dims_out[0];
00661         }
00662 
00663         if (area) {
00664                 hid_t memoryspace = 0;
00665 
00666                 /*Get the file dataspace - the region we want to read in the file*/
00667                 int x0 = 0, y0 = 0, z0 = 0;             //the coordinates for up left corner, trim to be within image bound
00668                 int x1 = 0, y1 = 0, z1 = 0;             //the coordinates for down right corner, trim to be within image bound
00669                 int nx1 = 1, ny1 = 1, nz1 = 1;  //dimensions of the sub-region, actual region read form file
00670                 if(rank == 3) {
00671                         hsize_t     doffset[3];             /* hyperslab offset in the file */
00672                         doffset[2] = (hsize_t)(area->x_origin() < 0 ? 0 : area->x_origin());
00673                         doffset[1] = (hsize_t)(area->y_origin() < 0 ? 0 : area->y_origin());
00674                         doffset[0] = (hsize_t)(area->z_origin() < 0 ? 0 : area->z_origin());
00675                         x0 = (int)doffset[0];
00676                         y0 = (int)doffset[1];
00677                         z0 = (int)doffset[2];
00678 
00679                         z1 = (int)(area->x_origin() + area->get_width());
00680                         z1 = (int)(z1 > static_cast<int>(nx) ? nx : z1);
00681 
00682                         y1 = (int)(area->y_origin() + area->get_height());
00683                         y1 = (int)(y1 > static_cast<int>(ny) ? ny : y1);
00684                         if(y1 <= 0) {
00685                                 y1 = 1;
00686                         }
00687 
00688                         x1 = (int)(area->z_origin() + area->get_depth());
00689                         x1 = (int)(x1 > static_cast<int>(nz) ? nz : x1);
00690                         if(x1 <= 0) {
00691                                 x1 = 1;
00692                         }
00693 
00694                         if(x1 < x0 || y1< y0 || z1 < z0) return 0; //out of bounds, this is fine, nothing happens
00695 
00696                         hsize_t     dcount[3];              /* size of the hyperslab in the file */
00697                         dcount[0] = x1 - doffset[0];
00698                         dcount[1] = y1 - doffset[1];
00699                         dcount[2] = z1 - doffset[2];
00700 
00701                         H5Sselect_hyperslab (spc, H5S_SELECT_SET, (const hsize_t*)doffset, NULL, (const hsize_t*)dcount, NULL);
00702 
00703                         /*Define memory dataspace - the memory we will created for the region*/
00704                         hsize_t     dims[3];              /* size of the region in the memory */
00705                         dims[0] = dcount[2]?dcount[2]:1;
00706                         dims[1] = dcount[1]?dcount[1]:1;
00707                         dims[2] = dcount[0]?dcount[0]:1;
00708                         nx1 = (int)dims[0];
00709                         ny1 = (int)dims[1];
00710                         nz1 = (int)dims[2];
00711 
00712                         memoryspace = H5Screate_simple(3, dims, NULL);
00713                 }
00714                 else if(rank == 2) {
00715                         hsize_t     doffset[2];             /* hyperslab offset in the file */
00716                         doffset[1] = (hsize_t)(area->x_origin() < 0 ? 0 : area->x_origin());
00717                         doffset[0] = (hsize_t)(area->y_origin() < 0 ? 0 : area->y_origin());
00718                         x0 = (int)doffset[0];
00719                         y0 = (int)doffset[1];
00720                         z0 = 1;
00721 
00722                         y1 = (int)(area->x_origin() + area->get_width());
00723                         y1 = (int)(y1 > static_cast<int>(nx) ? nx : y1);
00724 
00725                         x1 = (int)(area->y_origin() + area->get_height());
00726                         x1 = (int)(x1 > static_cast<int>(ny) ? ny : x1);
00727                         if(x1 <= 0) {
00728                                 x1 = 1;
00729                         }
00730 
00731                         z1 = 1;
00732 
00733                         if(x1 < x0 || y1< y0) return 0; //out of bounds, this is fine, nothing happens
00734 
00735                         hsize_t     dcount[2];              /* size of the hyperslab in the file */
00736                         dcount[0] = x1 - doffset[0];
00737                         dcount[1] = y1 - doffset[1];
00738 
00739                         H5Sselect_none(spc);
00740                         H5Sselect_hyperslab (spc, H5S_SELECT_SET, (const hsize_t*)doffset, NULL, (const hsize_t*)dcount, NULL);
00741 
00742                         /*Define memory dataspace - the memory we will created for the region*/
00743                         hsize_t     dims[2];              /* size of the region in the memory */
00744                         dims[0] = (hsize_t)(dcount[1]?dcount[1]:1);
00745                         dims[1] = (hsize_t)(dcount[0]?dcount[0]:1);
00746                         nx1 = (int)dims[0];
00747                         ny1 = (int)dims[1];
00748                         nz1 = 1;
00749 
00750                         memoryspace = H5Screate_simple(2, dims, NULL);
00751                 }
00752 
00753                 if( (area->x_origin()>=0) && (area->y_origin()>=0) && (area->z_origin()>=0) && ((hsize_t)(area->x_origin() + area->get_width())<=nx) && ((hsize_t)(area->y_origin() + area->get_height())<=ny) && ((hsize_t)(area->z_origin() + area->get_depth())<=nz) ){      //the region is in boundary
00754                         H5Dread(ds,H5T_NATIVE_FLOAT,memoryspace,spc,H5P_DEFAULT,data);
00755                 }
00756                 else {  //the region are partial out of boundary
00757                         /* When the requested region has some part out of image boundary,
00758                          * we need read the sub-area which is within image,
00759                          * and fill the out of boundary part with zero.
00760                          * We actually read the sub-region from HDF by hyperslab I/O,
00761                          * then copy it back to the pre-allocated region.*/
00762                         float * subdata = new float[nx1*ny1*nz1];
00763 
00764 
00765                         H5Dread(ds,H5T_NATIVE_FLOAT,memoryspace,spc,H5P_DEFAULT,subdata);
00766 
00767                         int xd0=0, yd0=0, zd0=0;        //The coordinates of the top-left corner sub-region in region
00768                         size_t clipped_row_size = 0;
00769                         if(rank == 3) {
00770                                 xd0 = (int) (area->x_origin() < 0 ? -area->x_origin() : 0);
00771                                 yd0 = (int) (area->y_origin() < 0 ? -area->y_origin() : 0);
00772                                 zd0 = (int) (area->z_origin() < 0 ? -area->z_origin() : 0);
00773                                 clipped_row_size = (z1-z0)* sizeof(float);
00774                         }
00775                         else if(rank == 2) {
00776                                 xd0 = (int) (area->x_origin() < 0 ? -area->x_origin() : 0);
00777                                 yd0 = (int) (area->y_origin() < 0 ? -area->y_origin() : 0);
00778                                 clipped_row_size = (y1-y0)* sizeof(float);
00779                         }
00780 
00781                         int src_secsize = nx1 * ny1;
00782                         int dst_secsize = (int)(area->get_width())*(int)(area->get_height());
00783 
00784                         float * src = subdata;
00785                         float * dst = data + zd0*dst_secsize + yd0*(int)(area->get_width()) + xd0;
00786 
00787                         int src_gap = src_secsize - (y1-y0) * nx1;
00788                         int dst_gap = dst_secsize - (y1-y0) * (int)(area->get_width());
00789 
00790                         for(int i = 0; i<nz1; ++i) {
00791                                 for(int j = 0; j<ny1; ++j) {
00792                                         EMUtil::em_memcpy(dst, src, clipped_row_size);
00793 
00794                                         src += nx1;
00795                                         dst += (int)(area->get_width());
00796                                 }
00797                                 src += src_gap;
00798                                 dst += dst_gap;
00799                         }
00800 
00801                         delete [] subdata;
00802                 }
00803                 H5Sclose(memoryspace);
00804         } else {
00805                 H5Dread(ds,H5T_NATIVE_FLOAT,spc,spc,H5P_DEFAULT,data);
00806         }
00807 
00808         H5Sclose(spc);
00809         H5Dclose(ds);
00810         EXITFUNC;
00811         return 0;
00812 }
00813 
00814 
00815 // Writes all attributes in 'dict' to the image group
00816 // Creation of the image dataset is also handled here
00817 int HdfIO2::write_header(const Dict & dict, int image_index, const Region* area,
00818                                                 EMUtil::EMDataType, bool)
00819 {
00820 #ifdef DEBUGHDF
00821         printf("write_head %d\n",image_index);
00822 #endif
00823         ENTERFUNC;
00824         init();
00825 
00826         if(image_index<0) {
00827                 image_index = get_nimg();
00828         }
00829 
00830         // If image_index<0 append, and make sure the max value in the file is correct
00831         // though this is normally handled by EMData.write_image()
00832         hid_t attr=H5Aopen_name(group,"imageid_max");
00833         int nimg = read_attr(attr);
00834         H5Aclose(attr);
00835 
00836         unsigned int i;
00837         if (image_index<0) image_index=nimg+1;
00838         if (image_index>nimg) {
00839                 write_attr(group,(const char *)"imageid_max",EMObject(image_index));
00840         }
00841 
00842         // Each image is in a group for later expansion. Open the group, create if necessary
00843         char ipath[50];
00844         sprintf(ipath,"/MDF/images/%d",image_index);
00845         hid_t igrp=H5Gopen(file,ipath);
00846 
00847         if (igrp<0) {   //group not existed
00848                 // Need to create a new image group
00849                 igrp=H5Gcreate(file,ipath,64);          // The image is a group, with attributes on the group
00850                 if (igrp<0) throw ImageWriteException(filename,"Unable to add /MDF/images/# to HDF5 file");
00851 
00852                 sprintf(ipath,"/MDF/images/%d/image",image_index);
00853                 // Now create the actual image dataset
00854                 hid_t space;
00855                 hid_t ds;
00856                 if ((int)dict["nz"]==1)  {
00857                         hsize_t dims[2]= { (int)dict["ny"],(int)dict["nx"] };
00858                         space=H5Screate_simple(2,dims,NULL);
00859                 }
00860                 else {
00861                         hsize_t dims[3]= { (int)dict["nz"],(int)dict["ny"],(int)dict["nx"] };
00862                         space=H5Screate_simple(3,dims,NULL);
00863                 }
00864                 ds=H5Dcreate(file,ipath, H5T_NATIVE_FLOAT, space, H5P_DEFAULT );
00865                 H5Dclose(ds);
00866                 H5Sclose(space);
00867         }
00868         //if group already existed, and the overwiting image is in different size,
00869         //need unlink the existing dataset first
00870         else {
00871                 int nattr=H5Aget_num_attrs(igrp);
00872                 char name[ATTR_NAME_LEN];
00873                 Dict dict2;
00874                 for (int i=0; i<nattr; i++) {
00875                         hid_t attr=H5Aopen_idx(igrp, i);
00876                         H5Aget_name(attr,127,name);
00877                         if (strncmp(name,"EMAN.", 5)!=0) {
00878                                 H5Aclose(attr);
00879                                 continue;
00880                         }
00881                         EMObject val=read_attr(attr);
00882                         dict2[name+5]=val;
00883                         H5Aclose(attr);
00884                 }
00885 
00886                 erase_header(image_index);
00887 
00888                 if((int)dict["nx"]!=(int)dict2["nx"]
00889                                 || (int)dict["ny"]!=(int)dict2["ny"]
00890                                 || (int)dict["nz"]!=(int)dict2["nz"]) {
00891                         sprintf(ipath,"/MDF/images/%d/image",image_index);
00892                         H5Gunlink(igrp, ipath);
00893 
00894                         // Now create the actual image dataset
00895                         hid_t space;
00896                         hid_t ds;
00897                         if ((int)dict["nz"]==1) {
00898                                 hsize_t dims[2]= { (int)dict["ny"],(int)dict["nx"] };
00899                                 space=H5Screate_simple(2,dims,NULL);
00900                         }
00901                         else {
00902                                 hsize_t dims[3]= { (int)dict["nz"],(int)dict["ny"],(int)dict["nx"] };
00903                                 space=H5Screate_simple(3,dims,NULL);
00904                         }
00905                         ds=H5Dcreate(file,ipath, H5T_NATIVE_FLOAT, space, H5P_DEFAULT );
00906                         H5Dclose(ds);
00907                         H5Sclose(space);
00908                 }
00909         }
00910 
00911         if(area) {
00912                 check_region(area, IntSize(dict["nx"], dict["ny"], dict["nz"]), false, true);
00913         }
00914 
00915         // Write the attributes to the group
00916         vector <string> keys=dict.keys();
00917 
00918         for (i=0; i<keys.size(); i++) {
00919                 string s("EMAN.");
00920                 s+=keys[i];
00921                 write_attr(igrp,s.c_str(),dict[keys[i]]);
00922         }
00923 
00924         H5Gclose(igrp);
00925         EXITFUNC;
00926         return 0;
00927 }
00928 
00929 // Writes the actual image data to the corresponding dataset (already created)
00930 int HdfIO2::write_data(float *data, int image_index, const Region* area,
00931                                           EMUtil::EMDataType dt, bool)
00932 {
00933         ENTERFUNC;
00934 
00935 #ifdef DEBUGHDF
00936         printf("write_data %d\n",image_index);
00937 #endif
00938         if (dt!=EMUtil::EM_FLOAT) throw ImageWriteException(filename,"HDF5 write only supports float format");
00939 
00940         if (image_index<0) {
00941                 hid_t attr=H5Aopen_name(group,"imageid_max");
00942                 image_index = read_attr(attr);
00943                 H5Aclose(attr);
00944         }
00945 
00946         char ipath[50];
00947         sprintf(ipath,"/MDF/images/%d/image",image_index);
00948         hid_t ds=H5Dopen(file,ipath);
00949         if (ds<0) throw ImageWriteException(filename,"Image dataset does not exist");
00950 
00951         hid_t spc=H5Dget_space(ds);
00952         if(area) {
00953                 hsize_t doffset[3];             /*hyperslab offset in the file*/
00954                 doffset[0] = (hsize_t)(area->x_origin());
00955                 doffset[1] = (hsize_t)(area->y_origin());
00956                 doffset[2] = (hsize_t)(area->z_origin());
00957 
00958                 hsize_t dcount[3];              /*size of the hyperslab in the file*/
00959                 dcount[0] = (hsize_t)(area->get_width());
00960                 dcount[1] = (hsize_t)(area->get_height()?area->get_height():1);
00961                 dcount[2] = (hsize_t)(area->get_depth()?area->get_depth():1);
00962 
00963                 H5Sselect_hyperslab(spc, H5S_SELECT_SET, (const hsize_t*)doffset, NULL, (const hsize_t*)dcount, NULL);
00964 
00965                 /*Create memory space with size of the region.*/
00966                 hsize_t dims[3];        /*size of the region in the memory*/
00967                 dims[0] = (hsize_t)(area->get_width());
00968                 dims[1] = (hsize_t)(area->get_height()?area->get_height():1);
00969                 dims[2] = (hsize_t)(area->get_depth()?area->get_depth():1);
00970 
00971                 hid_t memoryspace = H5Screate_simple(3, dims, NULL);
00972                 H5Dwrite(ds, H5T_NATIVE_FLOAT, memoryspace, spc, H5P_DEFAULT, data);
00973                 H5Sclose(memoryspace);
00974         }
00975         else {
00976                 H5Dwrite(ds,H5T_NATIVE_FLOAT,spc,spc,H5P_DEFAULT,data);
00977         }
00978 
00979         H5Sclose(spc);
00980         H5Dclose(ds);
00981         EXITFUNC;
00982         return 0;
00983 }
00984 
00985 int HdfIO2::get_nimg()
00986 {
00987         init();
00988         hid_t attr=H5Aopen_name(group,"imageid_max");
00989         int n = read_attr(attr);
00990         H5Aclose(attr);
00991 
00992         return n+1;
00993 }
00994 
00995 void HdfIO2::flush()
00996 {
00997         return;
00998 }
00999 
01000 bool HdfIO2::is_complex_mode()
01001 {
01002         return false;
01003 }
01004 
01005 // always big endian
01006 bool HdfIO2::is_image_big_endian()
01007 {
01008         return true;
01009 }
01010 
01011 
01012 
01013 #endif  //EM_HDF5

Generated on Mon Jul 19 12:40:10 2010 for EMAN2 by  doxygen 1.4.7