EMAN2
hdfio.cpp
Go to the documentation of this file.
1/*
2 * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
3 * Copyright (c) 2000-2006 Baylor College of Medicine
4 *
5 * This software is issued under a joint BSD/GNU license. You may use the
6 * source code in this file under either license. However, note that the
7 * complete EMAN2 and SPARX software packages have some GPL dependencies,
8 * so you are responsible for compliance with the licenses of these packages
9 * if you opt to use BSD licensing. The warranty disclaimer below holds
10 * in either instance.
11 *
12 * This complete copyright notice must be included in any revised version of the
13 * source code. Additional authorship citations may be added, but existing
14 * author citations must be preserved.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 * */
31
32#ifdef USE_HDF5
33
34#ifndef _WIN32
35 #include <sys/param.h>
36#else
37 #include <windows.h>
38 #define MAXPATHLEN (MAX_PATH * 4)
39#endif //_WIN32
40
41#include "hdfio.h"
42#include "geometry.h"
43#include "ctf.h"
44#include "emassert.h"
45#include "transform.h"
46#include <iostream>
47#include <cstring>
48
49#ifndef UINT_16_MAX
50/* Minimum of signed integral types. */
51# define INT8_MIN (-128)
52# define INT16_MIN (-32767-1)
53# define INT32_MIN (-2147483647-1)
54
55/* Maximum of signed integral types. */
56# define INT8_MAX (127)
57# define INT16_MAX (32767)
58# define INT32_MAX (2147483647)
59
60/* Maximum of unsigned integral types. */
61# define UINT8_MAX (255)
62# define UINT16_MAX (65535)
63# define UINT32_MAX (4294967295U)
64#endif
65
66using namespace EMAN;
67
68hid_t HdfIO::mapinfo_type = -1;
69const char *HdfIO::HDF5_SIGNATURE = "\211HDF\r\n\032\n";
70
71herr_t attr_info(hid_t dataset, const char *name, void *opdata)
72{
73 hid_t attr = H5Aopen_name(dataset, name);
74 float value_float = 0.0f;
75 int value_int = 0;
76 string value_string = "";
77 char * tmp_string = new char[1024];
78 Dict *dict = (Dict *) opdata;
79
80 if (attr >= 0) {
81 hid_t atype = H5Aget_type(attr);
82 if (H5Tget_class(atype) == H5T_FLOAT) {
83 H5Aread(attr, atype, &value_float);
84 (*dict)[name] = value_float;
85 }
86 else if(H5Tget_class(atype) == H5T_INTEGER) {
87 H5Aread(attr, atype, &value_int);
88 (*dict)[name] = value_int;
89 }
90 else if(H5Tget_class(atype) == H5T_STRING) {
91 H5Aread(attr, atype, tmp_string);
92 value_string = tmp_string;
93 (*dict)[name] = value_string;
94 }
95 else if(H5Tget_class(atype) == H5T_ENUM || H5Tget_class(atype) == H5T_ARRAY) {
96 //for old-style hdf file created by EMAN1, the euler convention is enum
97 //skip those attribute to make EMAN2 read the content of the image
98 }
99 else {
100 LOGERR("can only handle float/int/string parameters in HDF attr_info()");
101 exit(1);
102 }
103 H5Tclose(atype);
104 H5Aclose(attr);
105 }
106
107 return 0;
108}
109
110HdfIO::HdfIO(const string & fname, IOMode rw)
111: ImageIO(fname, rw)
112{
113 is_new_file = false;
114 file = -1;
115 group = -1;
116 cur_dataset = -1;
117 cur_image_index = -1;
118 old_func = 0;
119 old_client_data = 0;
120// printf("HDf open\n");
121}
122
123HdfIO::~HdfIO()
124{
125 close_cur_dataset();
126 if (group >= 0) {
127 H5Gclose(group);
128 }
129 if (file >= 0) {
130 H5Fflush(file,H5F_SCOPE_GLOBAL); // If there were no resource leaks, this wouldn't be necessary...
131 H5Fclose(file);
132 }
133//printf("HDf close\n");
134}
135
136void HdfIO::init()
137{
138 ENTERFUNC;
139 if (initialized) {
140 return;
141 }
142
143 H5dont_atexit();
144 initialized = true;
145
146 FILE *tmp_file = sfopen(filename, rw_mode, &is_new_file);
147
148 if (!is_new_file) {
149 char buf[128];
150 if (fread(buf, sizeof(buf), 1, tmp_file) != 1) {
151 fclose(tmp_file);
152 throw ImageReadException(filename, "read HDF5 first block");
153 }
154 else {
155 if (!is_valid(buf)) {
156 fclose(tmp_file);
157 throw ImageReadException(filename, "invalid HDF5 file");
158 }
159 }
160 }
161
162 fclose(tmp_file);
163 tmp_file = 0;
164
165 if (rw_mode == READ_ONLY) {
166 file = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
167 }
168 else {
169 hdf_err_off();
170 file = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
171 hdf_err_on();
172 if (file < 0) {
173 file = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
174 H5Fclose(file);
175 file = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
176 }
177 }
178
179 if (file < 0) {
180 throw FileAccessException(filename);
181 }
182
183 string root_group_str = get_item_name(ROOT_GROUP);
184 group = H5Gopen(file, root_group_str.c_str());
185 cur_dataset = -1;
186
187 H5Giterate(file, root_group_str.c_str(), NULL, file_info, &image_indices);
188 create_enum_types();
189 EXITFUNC;
190
191}
192
193
194bool HdfIO::is_valid(const void *first_block)
195{
196 ENTERFUNC;
197
198 if (first_block) {
199 char signature[8] = { char(137),char(72),char(68),char(70),char(13),char(10),char(26), char(10) };
200 if (strncmp((const char *)first_block,signature,8)==0) return true;
201 // const char* f=(const char *)first_block;
202 // 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]);
203 return false;
204 }
205 EXITFUNC;
206 return false;
207}
208
209int HdfIO::read_header(Dict & dict, int image_index, const Region * area, bool)
210{
211 ENTERFUNC;
212
213 check_read_access(image_index);
214
215 int nx = 0, ny = 0, nz = 0;
216 if (get_hdf_dims(image_index, &nx, &ny, &nz) != 0) {
217 throw ImageReadException(filename, "invalid image dimensions");
218 }
219
220 check_region(area, IntSize(nx, ny, nz));
221
222 int xlen = 0, ylen = 0, zlen = 0;
223 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen, nz, &zlen);
224
225 set_dataset(image_index);
226 int err = 0;
227 if (cur_dataset < 0) {
228 err = 1;
229 }
230 else {
231 err = H5Aiterate(cur_dataset, 0, attr_info, &dict);
232 if (err < 0) {
233 err = 1;
234 }
235 }
236
237 if(dict.has_key("ctf")) {
238 Ctf * ctf_ = new EMAN1Ctf();
239 ctf_->from_string((string)dict["ctf"]);
240 dict.erase("ctf");
241 dict["ctf"] = ctf_;
242 delete ctf_;
243 }
244
245 dict["nx"] = xlen;
246 dict["ny"] = ylen;
247 dict["nz"] = zlen;
248
249 Dict euler_angles;
250 read_euler_angles(euler_angles, image_index);
251
252 vector<string> euler_names = euler_angles.keys();
253 for (size_t i = 0; i < euler_names.size(); i++) {
254 dict[euler_names[i]] = euler_angles[euler_names[i]];
255 }
256
257 dict["datatype"] = EMUtil::EM_FLOAT;
258 EXITFUNC;
259 return 0;
260}
261
262
263int HdfIO::read_data(float *data, int image_index, const Region * area, bool)
264{
265 ENTERFUNC;
266
267 check_read_access(image_index, data);
268 set_dataset(image_index);
269#if 0
270 if (cur_dataset < 0) {
271 char cur_dataset_name[32];
272 sprintf(cur_dataset_name, "%d", image_index);
273 cur_dataset = H5Dopen(file, cur_dataset_name);
274
275 if (cur_dataset < 0) {
276 char desc[256];
277 sprintf(desc, "no image with id = %d", image_index);
278 throw ImageReadException(filename, desc);
279 }
280 }
281#endif
282 hid_t datatype = H5Dget_type(cur_dataset);
283 H5T_class_t t_class = H5Tget_class(datatype);
284 H5Tclose(datatype);
285
286 if (t_class != H5T_FLOAT) {
287 char desc[256];
288 sprintf(desc, "unsupported HDF5 data type '%d'", (int) t_class);
289 throw ImageReadException(filename, desc);
290 }
291
292 int nx = 0, ny = 0, nz = 0;
293 if (get_hdf_dims(image_index, &nx, &ny, &nz) != 0) {
294 throw ImageReadException(filename, "invalid image dimensions");
295 }
296
297 check_region(area, FloatSize(nx, ny, nz));
298
299 int err = 0;
300 if (!area) {
301 err = H5Dread(cur_dataset, H5T_NATIVE_FLOAT, H5S_ALL,
302 H5S_ALL, H5P_DEFAULT, data);
303 }
304 else {
305 hid_t dataspace_id = 0;
306 hid_t memspace_id = 0;
307
308 err = create_region_space(&dataspace_id, &memspace_id, area,
309 nx, ny, nz, image_index);
310 if (err == 0) {
311 err = H5Dread(cur_dataset, H5T_NATIVE_FLOAT, memspace_id,
312 dataspace_id, H5P_DEFAULT, data);
313 }
314
315 H5Sclose(dataspace_id);
316 H5Sclose(memspace_id);
317 if (err < 0) {
318 throw ImageReadException(filename,
319 "creating memory space or file space id failed");
320 }
321 }
322
323 if (err < 0) {
324 char desc[256];
325 sprintf(desc, "reading %dth HDF5 image failed", image_index);
326 throw ImageReadException(filename, desc);
327 }
328
329 EXITFUNC;
330 return 0;
331}
332
333
334int HdfIO::write_header(const Dict & dict, int image_index, const Region* area,
335 EMUtil::EMDataType, bool)
336{
337 ENTERFUNC;
338 check_write_access(rw_mode, image_index);
339
340 if (area) {
341 int nx0 = 0;
342 int ny0 = 0;
343 int nz0 = 0;
344
345 if (get_hdf_dims(image_index, &nx0, &ny0, &nz0) != 0) {
346 throw ImageReadException(filename, "invalid image dimensions");
347 }
348
349 check_region(area, FloatSize(nx0, ny0, nz0), is_new_file);
350
351 EXITFUNC;
352 return 0;
353 }
354
355 int nx = dict["nx"];
356 int ny = dict["ny"];
357 int nz = dict["nz"];
358
359 create_cur_dataset(image_index, nx, ny, nz);
360 Assert(cur_dataset >= 0);
361
362 vector<string> keys = dict.keys();
363 vector<string>::const_iterator iter;
364 for (iter = keys.begin(); iter != keys.end(); iter++) {
365 //handle special case for euler anglers
366 if(*iter == "orientation_convention") {
367 string eulerstr = (const char*) dict["orientation_convention"];
368 write_string_attr(image_index, "orientation_convention", eulerstr);
369
370 vector<string> euler_names = EMUtil::get_euler_names(eulerstr);
371 Dict euler_dict;
372 for (size_t i = 0; i < euler_names.size(); i++) {
373 euler_dict[euler_names[i]] = dict[euler_names[i]];
374 }
375
376 write_euler_angles(euler_dict, image_index);
377 }
378 //micrograph_id should save as string
379 else if(*iter == "micrograph_id") {
380 write_string_attr(image_index, "micrograph_id", (const char *) dict["micrograph_id"]);
381 }
382 //handle normal attributes
383 else {
384 EMObject attr_val = dict[*iter];
385 //string val_type = EMObject::get_object_type_name(attr_val.get_type());
386 EMObject::ObjectType t = attr_val.get_type();
387 switch(t) {
388
389 case EMObject::INT:
390 write_int_attr(image_index, *iter, attr_val);
391 break;
392 case EMObject::FLOAT:
393 case EMObject::DOUBLE:
394 write_float_attr(image_index, *iter, attr_val);
395 break;
396 case EMObject::STRING:
397 write_string_attr(image_index, *iter, attr_val.to_str());
398 break;
399// case EMObject::EMDATA:
400 case EMObject::XYDATA:
401 case EMObject::FLOATARRAY:
402 case EMObject::STRINGARRAY:
403 throw NotExistingObjectException("EMObject", "unsupported type");
404 break;
405 case EMObject::UNKNOWN:
406 throw NotExistingObjectException("EMObject", "unsupported type");
407 break;
408 default:
409 throw NotExistingObjectException("EMObject", "unsupported type");
410 }
411 }
412 }
413
414
415 //flush();
416 close_cur_dataset();
417
418 EXITFUNC;
419 return 0;
420}
421
422int HdfIO::write_data(float *data, int image_index, const Region* area,
423 EMUtil::EMDataType, bool)
424{
425 ENTERFUNC;
426
427 check_write_access(rw_mode, image_index, 0, data);
428
429 int nx = read_int_attr(image_index, "nx");
430 int ny = read_int_attr(image_index, "ny");
431 int nz = read_int_attr(image_index, "nz");
432
433
434 check_region(area, FloatSize(nx, ny, nz), is_new_file);
435 create_cur_dataset(image_index, nx, ny, nz);
436 Assert(cur_dataset >= 0);
437
438 int err = 0;
439
440 if (!area) {
441 err = H5Dwrite(cur_dataset, H5T_NATIVE_FLOAT, H5S_ALL,
442 H5S_ALL, H5P_DEFAULT, data);
443 //if (err >= 0) {
444 //increase_num_dataset();
445 //image_indices.push_back(image_index);
446 //}
447 }
448 else {
449 hid_t dataspace_id = 0;
450 hid_t memspace_id = 0;
451
452 err = create_region_space(&dataspace_id, &memspace_id, area,
453 nx, ny, nz, image_index);
454 if (err == 0) {
455 err = H5Dwrite(cur_dataset, H5T_NATIVE_FLOAT, memspace_id,
456 dataspace_id, H5P_DEFAULT, data);
457 }
458
459 H5Sclose(dataspace_id);
460 H5Sclose(memspace_id);
461 if (err < 0) {
462 throw ImageReadException(filename,
463 "creating memory space or file space id failed");
464 }
465 }
466
467 if (err < 0) {
468 throw ImageWriteException(filename, "HDF data write failed");
469 }
470
471 //flush();
472 close_cur_dataset();
473
474 EXITFUNC;
475 return 0;
476}
477
478void HdfIO::flush()
479{
480 if (cur_dataset > 0) {
481 H5Fflush(cur_dataset, H5F_SCOPE_LOCAL);
482 }
483}
484
485int *HdfIO::read_dims(int image_index, int *p_ndim)
486{
487 set_dataset(image_index);
488#if 0
489 if (cur_dataset < 0) {
490 char cur_dataset_name[32];
491 sprintf(cur_dataset_name, "%d", image_index);
492 cur_dataset = H5Dopen(file, cur_dataset_name);
493
494 if (cur_dataset < 0) {
495 throw ImageReadException(filename, "reading data dimensions");
496 }
497 }
498#endif
499 hid_t dataspace = H5Dget_space(cur_dataset);
500 int rank = H5Sget_simple_extent_ndims(dataspace);
501 hsize_t *dims = new hsize_t[rank];
502 H5Sget_simple_extent_dims(dataspace, dims, NULL);
503
504 int *dims1 = new int[rank];
505 for (int i = 0; i < rank; i++) {
506 dims1[i] = static_cast < int >(dims[i]);
507 }
508
509 H5Sclose(dataspace);
510 if( dims )
511 {
512 delete[]dims;
513 dims = 0;
514 }
515
516 (*p_ndim) = rank;
517 return dims1;
518}
519
520int HdfIO::read_global_int_attr(const string & attr_name)
521{
522 int value = 0;
523 hid_t attr = H5Aopen_name(group, attr_name.c_str());
524 if (attr < 0) {
525 //LOGWARN("no such hdf attribute '%s'", attr_name.c_str());
526 }
527 else {
528 H5Aread(attr, H5T_NATIVE_INT, &value);
529 H5Aclose(attr);
530 }
531
532 return value;
533}
534
535float HdfIO::read_global_float_attr(const string & attr_name)
536{
537 float value = 0;
538 hid_t attr = H5Aopen_name(group, attr_name.c_str());
539 if (attr >= 0) {
540 H5Aread(attr, H5T_NATIVE_INT, &value);
541 H5Aclose(attr);
542 }
543 return value;
544}
545
546int HdfIO::get_nimg()
547{
548 init();
549 hdf_err_off();
550 int n = read_global_int_attr(get_item_name(NUMDATASET));
551 hdf_err_on();
552 return n;
553}
554
555
556void HdfIO::increase_num_dataset()
557{
558 int n = get_nimg();
559 n++;
560 write_global_int_attr(get_item_name(NUMDATASET), n);
561}
562
563
564void HdfIO::set_dataset(int image_index)
565{
566 int need_update = 0;
567
568 if (cur_image_index >= 0) {
569 if (image_index != cur_image_index) {
570 need_update = 1;
571 }
572 }
573 else {
574 cur_image_index = image_index;
575 need_update = 1;
576 }
577
578 if (need_update || cur_dataset < 0) {
579 char cur_dataset_name[32];
580 sprintf(cur_dataset_name, "%d", image_index);
581 hdf_err_off();
582 close_cur_dataset();
583 cur_dataset = H5Dopen(file, cur_dataset_name);
584 if (cur_dataset < 0) {
585 throw ImageReadException(filename, "open data set failed");
586 }
587 hdf_err_on();
588 cur_image_index = image_index;
589 }
590
591 Assert(cur_dataset >= 0);
592}
593
594
595
596int HdfIO::read_int_attr(int image_index, const string & attr_name)
597{
598 set_dataset(image_index);
599
600 int value = 0;
601 hid_t attr = H5Aopen_name(cur_dataset, attr_name.c_str());
602 if (attr >= 0) {
603 H5Aread(attr, H5T_NATIVE_INT, &value);
604 H5Aclose(attr);
605 }
606 else {
607 //LOGWARN("no such hdf attribute '%s'", attr_name.c_str());
608 }
609
610 return value;
611}
612
613
614float HdfIO::read_float_attr(int image_index, const string & attr_name)
615{
616 set_dataset(image_index);
617 return read_float_attr(attr_name);
618}
619
620
621float HdfIO::read_float_attr(const string & attr_name)
622{
623 float value = 0;
624 hid_t attr = H5Aopen_name(cur_dataset, attr_name.c_str());
625 if (attr >= 0) {
626 H5Aread(attr, H5T_NATIVE_FLOAT, &value);
627 H5Aclose(attr);
628 }
629 else {
630 //LOGWARN("no such hdf attribute '%s'", attr_name.c_str());
631 }
632
633 return value;
634}
635
636
637
638string HdfIO::read_string_attr(int image_index, const string & attr_name)
639{
640 set_dataset(image_index);
641 hid_t attr = H5Aopen_name(cur_dataset, attr_name.c_str());
642
643 string value = "";
644 if (attr < 0) {
645 //LOGWARN("no such hdf attribute '%s'", attr_name.c_str());
646 }
647 else {
648 char *tmp_value = new char[MAXPATHLEN];
649 hid_t datatype = H5Tcopy(H5T_C_S1);
650 H5Tset_size(datatype, MAXPATHLEN);
651 H5Aread(attr, datatype, tmp_value);
652
653 H5Tclose(datatype);
654 H5Aclose(attr);
655
656 value = tmp_value;
657
658 if( tmp_value )
659 {
660 delete[]tmp_value;
661 tmp_value = 0;
662 }
663 }
664
665 return value;
666}
667
668int HdfIO::read_array_attr(int image_index, const string & attr_name, void *value)
669{
670 set_dataset(image_index);
671 int err = 0;
672
673 hid_t attr = H5Aopen_name(cur_dataset, attr_name.c_str());
674 if (attr < 0) {
675 LOGERR("no such hdf attribute '%s'", attr_name.c_str());
676 err = 1;
677 }
678 else {
679 hid_t datatype = H5Aget_type(attr);
680 H5Aread(attr, datatype, value);
681 H5Tclose(datatype);
682 H5Aclose(attr);
683 }
684 return err;
685}
686#if 0
687float HdfIO::read_euler_attr(int image_index, const string &attr_name)
688{
689 string full_attr_name = string(EULER_MAGIC) + attr_name;
690 return read_float_attr(image_index, full_attr_name);
691}
692#endif
693
694int HdfIO::read_mapinfo_attr(int image_index, const string & attr_name)
695{
696 set_dataset(image_index);
697
699 hid_t attr = H5Aopen_name(cur_dataset, attr_name.c_str());
700 if (attr < 0) {
701 LOGERR("no such hdf attribute '%s'", attr_name.c_str());
702 }
703 else {
704 H5Aread(attr, mapinfo_type, &val);
705 H5Aclose(attr);
706 }
707 return static_cast < int >(val);
708}
709
710int HdfIO::write_int_attr(int image_index, const string & attr_name, int value)
711{
712 set_dataset(image_index);
713 return write_int_attr(attr_name, value);
714}
715
716
717int HdfIO::write_int_attr(const string & attr_name, int value)
718{
719 int err = -1;
720 delete_attr(attr_name);
721
722 hid_t dataspace = H5Screate(H5S_SCALAR);
723 hid_t attr = H5Acreate(cur_dataset, attr_name.c_str(), H5T_NATIVE_INT, dataspace, H5P_DEFAULT);
724
725 if (attr >= 0) {
726 err = H5Awrite(attr, H5T_NATIVE_INT, &value);
727 }
728
729 H5Aclose(attr);
730 H5Sclose(dataspace);
731
732 if (err < 0) {
733 return 1;
734 }
735
736 return 0;
737}
738
739int HdfIO::write_float_attr_from_dict(int image_index, const string & attr_name,
740 const Dict & dict)
741{
742 if (dict.has_key(attr_name)) {
743 return write_float_attr(image_index, attr_name, dict[attr_name]);
744 }
745 return 0;
746}
747
748int HdfIO::write_float_attr(int image_index, const string & attr_name, float value)
749{
750 set_dataset(image_index);
751 return write_float_attr(attr_name, value);
752}
753
754int HdfIO::write_float_attr(const string & attr_name, float value)
755{
756 int err = -1;
757 delete_attr(attr_name);
758 hid_t dataspace = H5Screate(H5S_SCALAR);
759 hid_t attr =
760 H5Acreate(cur_dataset, attr_name.c_str(), H5T_NATIVE_FLOAT, dataspace, H5P_DEFAULT);
761
762 if (attr >= 0) {
763 err = H5Awrite(attr, H5T_NATIVE_FLOAT, &value);
764 }
765
766 H5Aclose(attr);
767 H5Sclose(dataspace);
768
769 if (err < 0) {
770 return 1;
771 }
772
773 return 0;
774}
775
776int HdfIO::write_string_attr(int image_index, const string & attr_name,
777 const string & value)
778{
779 set_dataset(image_index);
780
781 int err = -1;
782 delete_attr(attr_name);
783
784 hid_t datatype = H5Tcopy(H5T_C_S1);
785 H5Tset_size(datatype, value.size() + 1);
786 hid_t dataspace = H5Screate(H5S_SCALAR);
787
788 hid_t attr = H5Acreate(cur_dataset, attr_name.c_str(), datatype, dataspace, H5P_DEFAULT);
789 if (attr >= 0) {
790 err = H5Awrite(attr, datatype, (void *) value.c_str());
791 }
792
793 H5Aclose(attr);
794 H5Sclose(dataspace);
795 H5Tclose(datatype);
796
797 if (err < 0) {
798 return 1;
799 }
800
801 return 0;
802}
803
804int HdfIO::write_array_attr(int image_index, const string & attr_name,
805 int nitems, void *data, DataType type)
806{
807 if (nitems <= 0) {
808 return 1;
809 }
810 if (!data) {
811 throw NullPointerException("array data is NULL");
812 }
813
814 set_dataset(image_index);
815 delete_attr(attr_name);
816
817 if (type != INT && type != FLOAT) {
818 fprintf(stderr, "can only write INTEGER and FLOAT array");
819 return 1;
820 }
821
822 int err = -1;
823 hsize_t dim[1];
824 int perm[1];
825 dim[0] = nitems;
826 hsize_t sdim[] = { 1 };
827
828 hid_t datatype = -1;
829
830 if (type == INT) {
831 datatype = H5Tarray_create(H5T_NATIVE_INT, 1, dim, perm);
832 }
833 else if (type == FLOAT) {
834 datatype = H5Tarray_create(H5T_NATIVE_FLOAT, 1, dim, perm);
835 }
836
837 hid_t dataspace = H5Screate_simple(1, sdim, NULL);
838 hid_t attr = H5Acreate(cur_dataset, attr_name.c_str(), datatype, dataspace, H5P_DEFAULT);
839 if (attr >= 0) {
840 err = H5Awrite(attr, datatype, data);
841 }
842
843 H5Tclose(datatype);
844 H5Sclose(dataspace);
845 H5Aclose(attr);
846
847 if (err < 0) {
848 return 1;
849 }
850
851 return 0;
852}
853
854
855int HdfIO::write_global_int_attr(const string & attr_name, int value)
856{
857 hid_t tmp_dataset = cur_dataset;
858 cur_dataset = group;
859 int err = write_int_attr(attr_name, value);
860 cur_dataset = tmp_dataset;
861 return err;
862}
863
864#if 0
865int HdfIO::write_euler_attr(int image_index, const string & attr_name, float value)
866{
867 string full_attr_name = string(EULER_MAGIC) + attr_name;
868 return write_float_attr(image_index, full_attr_name, value);
869}
870#endif
871
872int HdfIO::write_mapinfo_attr(int image_index, const string & attr_name, int value)
873{
874 set_dataset(image_index);
875 delete_attr(attr_name);
876
877 hsize_t dim[] = { 1 };
878 hid_t dataspace = H5Screate_simple(1, dim, NULL);
879 hid_t attr = H5Acreate(cur_dataset, attr_name.c_str(), mapinfo_type, dataspace, H5P_DEFAULT);
880 H5Awrite(attr, mapinfo_type, &value);
881 H5Aclose(attr);
882 H5Sclose(dataspace);
883 return 0;
884}
885
886
887int HdfIO::delete_attr(int image_index, const string & attr_name)
888{
889 set_dataset(image_index);
890
891 hdf_err_off();
892 int err = H5Adelete(cur_dataset, attr_name.c_str());
893 hdf_err_on();
894
895 if (err >= 0) {
896 return 0;
897 }
898 else {
899 return 1;
900 }
901}
902
903int HdfIO::delete_attr(const string & attr_name)
904{
905 hdf_err_off();
906 int err = H5Adelete(cur_dataset, attr_name.c_str());
907 hdf_err_on();
908
909 if (err >= 0) {
910 return 0;
911 }
912 else {
913 return 1;
914 }
915}
916
917string HdfIO::get_compound_name(int id, const string & name)
918{
919 string magic = get_item_name(COMPOUND_DATA_MAGIC);
920 char id_str[32];
921 sprintf(id_str, "%d", id);
922 string compound_name = magic + "." + id_str + "." + name;
923 return compound_name;
924}
925
926
927int HdfIO::create_compound_attr(int image_index, const string & attr_name)
928{
929 string cur_dataset_name = get_compound_name(image_index, attr_name);
930 cur_image_index = -1;
931
932 hsize_t dims[1];
933 dims[0] = 1;
934 hid_t datatype = H5Tcopy(H5T_NATIVE_INT);
935 hid_t dataspace = H5Screate_simple(1, dims, NULL);
936
937 close_cur_dataset();
938 cur_dataset = H5Dcreate(file, cur_dataset_name.c_str(), datatype, dataspace, H5P_DEFAULT);
939
940 H5Tclose(datatype);
941 H5Sclose(dataspace);
942 return 0;
943}
944
945int HdfIO::read_ctf(Ctf & ctf, int image_index)
946{
947 Dict ctf_dict;
948 int err = read_compound_dict(CTFIT, ctf_dict, image_index);
949 if (!err) {
950 ctf.from_dict(ctf_dict);
951 }
952
953 return err;
954}
955
956void HdfIO::write_ctf(const Ctf & ctf, int image_index)
957{
958 Dict ctf_dict = ctf.to_dict();
959 write_compound_dict(CTFIT, ctf_dict, image_index);
960}
961
962int HdfIO::read_euler_angles(Dict & euler_angles, int image_index)
963{
964 int err = read_compound_dict(EULER, euler_angles, image_index);
965 return err;
966}
967
968
969void HdfIO::write_euler_angles(const Dict & euler_angles, int image_index)
970{
971 write_compound_dict(EULER, euler_angles, image_index);
972}
973
974int HdfIO::read_compound_dict(Nametype compound_type,
975 Dict & values, int image_index)
976{
977 ENTERFUNC;
978 init();
979
980 int err = 0;
981
982 hid_t cur_dataset_orig = cur_dataset;
983 string cur_dataset_name = get_compound_name(image_index, get_item_name(compound_type));
984
985 hdf_err_off();
986 cur_dataset = H5Dopen(file, cur_dataset_name.c_str());
987 hdf_err_on();
988
989 if (cur_dataset < 0) {
990 err = 1;
991 }
992 else {
993 err = H5Aiterate(cur_dataset, 0, attr_info, &values);
994 if (err < 0) {
995 err = 1;
996 }
997 }
998
999 H5Dclose(cur_dataset);
1000 cur_dataset = cur_dataset_orig;
1001
1002 cur_image_index = -1;
1003 EXITFUNC;
1004 return err;
1005}
1006
1007
1008void HdfIO::write_compound_dict(Nametype compound_type,
1009 const Dict & values, int image_index)
1010{
1011 ENTERFUNC;
1012 init();
1013
1014 //set_dataset(image_index);
1015 hid_t cur_dataset_orig = cur_dataset;
1016
1017 string attr_name = get_item_name(compound_type);
1018 string cur_dataset_name = get_compound_name(image_index, attr_name);
1019
1020 hdf_err_off();
1021 cur_dataset = H5Dopen(file, cur_dataset_name.c_str());
1022 hdf_err_on();
1023
1024 if (cur_dataset < 0) {
1025 create_compound_attr(image_index, attr_name);
1026 }
1027 else {
1028 // remove all existing attributes first
1029 Dict attr_dict;
1030 H5Aiterate(cur_dataset, 0, attr_info, &attr_dict);
1031 vector <string> attr_keys = attr_dict.keys();
1032 for (size_t i = 0; i < attr_keys.size(); i++) {
1033 H5Adelete(cur_dataset, attr_keys[i].c_str());
1034 }
1035 }
1036
1037 // writing new attributes
1038
1039 vector < string > keys = values.keys();
1040 for (size_t i = 0; i < keys.size(); i++) {
1041 float v = values[keys[i]];
1042 write_float_attr(keys[i].c_str(), v);
1043 }
1044
1045 H5Dclose(cur_dataset);
1046 cur_dataset = cur_dataset_orig;
1047
1048 cur_image_index = -1;
1049 EXITFUNC;
1050}
1051
1052
1053bool HdfIO::is_complex_mode()
1054{
1055 return false;
1056}
1057
1058// always big endian
1059bool HdfIO::is_image_big_endian()
1060{
1061 return true;
1062}
1063
1064
1065string HdfIO::get_item_name(Nametype type)
1066{
1067 switch (type) {
1068 case ROOT_GROUP:
1069 return "/";
1070 case CTFIT:
1071 return "ctfit";
1072 case NUMDATASET:
1073 return "num_dataset";
1074 case COMPOUND_DATA_MAGIC:
1075 return "compound";
1076 case EULER:
1077 return "euler_angles";
1078 }
1079
1080
1081 return "unknown";
1082}
1083
1084void HdfIO::hdf_err_off()
1085{
1086 H5Eget_auto(&old_func, &old_client_data);
1087 H5Eset_auto(0, 0);
1088}
1089
1090void HdfIO::hdf_err_on()
1091{
1092 H5Eset_auto(old_func, old_client_data);
1093}
1094
1095void HdfIO::close_cur_dataset()
1096{
1097 hdf_err_off();
1098 if (cur_dataset >= 0) {
1099 H5Dclose(cur_dataset);
1100 cur_dataset = -1;
1101 cur_image_index = -1;
1102 }
1103 hdf_err_on();
1104}
1105
1106void HdfIO::create_enum_types()
1107{
1108 static int enum_types_created = 0;
1109
1110 if (!enum_types_created) {
1111#if 0
1112// Transform3D::EulerType e;
1113// euler_type = H5Tcreate(H5T_ENUM, sizeof(Transform3D::EulerType));
1114//
1115// H5Tenum_insert(euler_type, "EMAN", (e = Transform3D::EMAN, &e));
1116// H5Tenum_insert(euler_type, "IMAGIC", (e = Transform3D::IMAGIC, &e));
1117// H5Tenum_insert(euler_type, "SPIN", (e = Transform3D::SPIN, &e));
1118// H5Tenum_insert(euler_type, "QUATERNION", (e = Transform3D::QUATERNION, &e));
1119// H5Tenum_insert(euler_type, "SGIROT", (e = Transform3D::SGIROT, &e));
1120// H5Tenum_insert(euler_type, "SPIDER", (e = Transform3D::SPIDER, &e));
1121// H5Tenum_insert(euler_type, "MRC", (e = Transform3D::MRC, &e));
1122//
1123// MapInfoType m;
1124// mapinfo_type = H5Tcreate(H5T_ENUM, sizeof(MapInfoType));
1125//
1126// H5Tenum_insert(mapinfo_type, "NORMAL", (m = NORMAL, &m));
1127// H5Tenum_insert(mapinfo_type, "ICOS2F_FIRST_OCTANT", (m = ICOS2F_FIRST_OCTANT, &m));
1128// H5Tenum_insert(mapinfo_type, "ICOS2F_FULL", (m = ICOS2F_FULL, &m));
1129// H5Tenum_insert(mapinfo_type, "ICOS2F_HALF", (m = ICOS2F_HALF, &m));
1130// H5Tenum_insert(mapinfo_type, "ICOS3F_HALF", (m = ICOS3F_HALF, &m));
1131// H5Tenum_insert(mapinfo_type, "ICOS3F_FULL", (m = ICOS3F_FULL, &m));
1132// H5Tenum_insert(mapinfo_type, "ICOS5F_HALF", (m = ICOS5F_HALF, &m));
1133// H5Tenum_insert(mapinfo_type, "ICOS5F_FULL", (m = ICOS5F_FULL, &m));
1134#endif
1135 enum_types_created = 1;
1136 }
1137}
1138
1139vector < int >HdfIO::get_image_indices()
1140{
1141 return image_indices;
1142}
1143
1144int HdfIO::get_hdf_dims(int image_index, int *p_nx, int *p_ny, int *p_nz)
1145{
1146 *p_nx = read_int_attr(image_index, "nx");
1147 *p_ny = read_int_attr(image_index, "ny");
1148 *p_nz = read_int_attr(image_index, "nz");
1149
1150 if (*p_nx == 0 || *p_ny == 0 || *p_nz == 0) {
1151 int ndim = 0;
1152 int *dims = read_dims(image_index, &ndim);
1153
1154 if (ndim != 2 && ndim != 3) {
1155 LOGERR("only handle 2D/3D HDF5. Your file is %dD.", ndim);
1156 if( dims )
1157 {
1158 delete [] dims;
1159 dims = 0;
1160 }
1161 return 1;
1162 }
1163 else {
1164 *p_nx = dims[0];
1165 *p_ny = dims[1];
1166 if (ndim == 3) {
1167 *p_nz = dims[2];
1168 }
1169 else {
1170 *p_nz = 1;
1171 }
1172 }
1173 if( dims )
1174 {
1175 delete [] dims;
1176 dims = 0;
1177 }
1178 }
1179 return 0;
1180}
1181
1182herr_t HdfIO::file_info(hid_t, const char *name, void *opdata)
1183{
1184// loc_id = loc_id;
1185 vector < int >*image_indices = static_cast < vector < int >*>(opdata);
1186 string magic = HdfIO::get_item_name(HdfIO::COMPOUND_DATA_MAGIC);
1187 const char *magic_str = magic.c_str();
1188
1189 if (strncmp(name, magic_str, strlen(magic_str)) != 0) {
1190 int id = atoi(name);
1191 image_indices->push_back(id);
1192 }
1193
1194 return 0;
1195}
1196
1197void HdfIO::create_cur_dataset(int image_index, int nx, int ny, int nz)
1198{
1199 int ndim = 0;
1200 int dims[3];
1201
1202 if (nz == 1) {
1203 ndim = 2;
1204 }
1205 else {
1206 ndim = 3;
1207 }
1208 dims[0] = nx;
1209 dims[1] = ny;
1210 dims[2] = nz;
1211
1212 char tmp_dataset_name[32];
1213 sprintf(tmp_dataset_name, "%d", image_index);
1214 cur_image_index = image_index;
1215
1216 hdf_err_off();
1217 cur_dataset = H5Dopen(file, tmp_dataset_name);
1218 hdf_err_on();
1219
1220
1221 if (cur_dataset >= 0) {
1222 int ndim1 = 0;
1223 int *dims1 = read_dims(image_index, &ndim1);
1224 Assert(ndim == ndim1);
1225
1226 for (int i = 0; i < ndim; i++) {
1227 Assert(dims[i] == dims1[i]);
1228 }
1229 if( dims1 )
1230 {
1231 delete [] dims1;
1232 dims1 = 0;
1233 }
1234 }
1235 else {
1236 hsize_t *sdims = new hsize_t[ndim];
1237 for (int i = 0; i < ndim; i++) {
1238 sdims[i] = dims[i];
1239 }
1240
1241 hid_t datatype = H5Tcopy(H5T_NATIVE_FLOAT);
1242 hid_t dataspace = H5Screate_simple(ndim, sdims, NULL);
1243
1244 cur_dataset = H5Dcreate(file, tmp_dataset_name, datatype, dataspace, H5P_DEFAULT);
1245
1246 H5Tclose(datatype);
1247 H5Sclose(dataspace);
1248
1249 if( sdims )
1250 {
1251 delete[]sdims;
1252 sdims = 0;
1253 }
1254
1255 if (cur_dataset < 0) {
1256 throw ImageWriteException(filename, "create dataset failed");
1257 }
1258 else {
1259 increase_num_dataset();
1260 image_indices.push_back(image_index);
1261 }
1262 }
1263}
1264
1265int HdfIO::create_region_space(hid_t * p_dataspace_id, hid_t * p_memspace_id,
1266 const Region * area, int nx, int ny, int nz,
1267 int image_index)
1268{
1269 Assert(p_dataspace_id);
1270 Assert(p_memspace_id);
1271 Assert(area);
1272
1273 if (!p_dataspace_id || !p_memspace_id || !area) {
1274 return -1;
1275 }
1276
1277#if H5_VERS_MINOR > 6 || (H5_VERS_MINOR == 6 && H5_VERS_RELEASE >= 4)
1278 hsize_t offset[3];
1279#else
1280 hssize_t offset[3];
1281#endif
1282
1283 hsize_t count[3];
1284
1285 int x0 = 0, y0 = 0, z0 = 0;
1286 int xlen = 0, ylen = 0, zlen = 0;
1287
1288 EMUtil::get_region_origins(area, &x0, &y0, &z0, nz, image_index);
1289 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen, nz, &zlen);
1290
1291 offset[0] = static_cast < hssize_t > (x0);
1292 offset[1] = static_cast < hssize_t > (y0);
1293 offset[2] = static_cast < hssize_t > (z0);
1294
1295 count[0] = static_cast < hsize_t > (xlen);
1296 count[1] = static_cast < hsize_t > (ylen);
1297 count[2] = static_cast < hsize_t > (zlen);
1298
1299 *p_dataspace_id = H5Dget_space(cur_dataset);
1300
1301 int err = H5Sselect_hyperslab(*p_dataspace_id, H5S_SELECT_SET,
1302 offset, NULL, count, NULL);
1303 if (err >= 0) {
1304 *p_memspace_id = H5Screate_simple(3, count, NULL);
1305
1306#if H5_VERS_MINOR > 6 || (H5_VERS_MINOR == 6 && H5_VERS_RELEASE >= 4)
1307 hsize_t offset_out[3];
1308#else
1309 hssize_t offset_out[3];
1310#endif
1311
1312 offset_out[0] = 0;
1313 offset_out[1] = 0;
1314 offset_out[2] = 0;
1315
1316 err = H5Sselect_hyperslab(*p_memspace_id, H5S_SELECT_SET,
1317 offset_out, NULL, count, NULL);
1318 if (err >= 0) {
1319 err = 0;
1320 }
1321 }
1322
1323 return err;
1324}
1325
1326int HdfIO::get_num_dataset()
1327{
1328 hdf_err_off();
1329 int n = read_global_int_attr(get_item_name(NUMDATASET));
1330 hdf_err_on();
1331 return n;
1332}
1333
1334
1335#endif //USE_HDF5
Ctf is the base class for all CTF model.
Definition: ctf.h:60
virtual void from_dict(const Dict &dict)=0
virtual int from_string(const string &ctf)=0
virtual Dict to_dict() const =0
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385
bool has_key(const string &key) const
Ask the Dictionary if it as a particular key.
Definition: emobject.h:511
vector< string > keys() const
Get a vector containing all of the (string) keys in this dictionary.
Definition: emobject.h:475
EMAN1Ctf is the CTF model used in EMAN1.
Definition: ctf.h:120
EMObject is a wrapper class for types including int, float, double, etc as defined in ObjectType.
Definition: emobject.h:123
string to_str() const
Calls to_str( this->type)
Definition: emobject.cpp:684
ObjectType get_type() const
Get the ObjectType This is an enumerated type first declared in the class EMObjectTypes.
Definition: emobject.h:224
EMDataType
Image pixel data type used in EMAN.
Definition: emutil.h:92
FloatSize is used to describe a 1D, 2D or 3D rectangular size in floating numbers.
Definition: geometry.h:105
ImageIO classes are designed for reading/writing various electron micrography image formats,...
Definition: imageio.h:127
IntSize is used to describe a 1D, 2D or 3D rectangular size in integers.
Definition: geometry.h:49
Region defines a 2D or 3D rectangular region specified by its origin coordinates and all edges' sizes...
Definition: geometry.h:497
#define Assert(s)
Define Assert() function that is effective only when -DDEBUG is used.
Definition: emassert.h:42
void read_data(string fsp, size_t loc, const Region *area=0, const int file_nx=0, const int file_ny=0, const int file_nz=0)
Read the image pixel data in native byte order from a disk file.
void write_data(string fsp, size_t loc, const Region *const area=0, const int file_nx=0, const int file_ny=0, const int file_nz=0)
Dump the image pixel data in native byte order to a disk file.
#define ImageReadException(filename, desc)
Definition: exception.h:204
#define NotExistingObjectException(objname, desc)
Definition: exception.h:130
#define FileAccessException(filename)
Definition: exception.h:187
#define ImageWriteException(imagename, desc)
Definition: exception.h:223
#define NullPointerException(desc)
Definition: exception.h:241
#define LOGERR
Definition: log.h:51
#define ENTERFUNC
Definition: log.h:48
#define EXITFUNC
Definition: log.h:49
E2Exception class.
Definition: aligner.h:40
MapInfoType
Definition: emobject.h:94
@ ICOS_UNKNOWN
Definition: emobject.h:103