BELFEM 0.9.0
Berkeley Lab Finite Element Framework
Loading...
Searching...
No Matches
hdf5_tools.hpp
Go to the documentation of this file.
1/*
2 * BELFEM -- The Berkeley Lab Finite Element Framework
3 * Copyright (c) 2026, The Regents of the University of California,
4 * through Lawrence Berkeley National Laboratory (subject to receipt of any required
5 * approvals from the U.S. Dept. of Energy). All rights reserved.
6 *
7 * Developers: Christian Messe, Gregory Giard
8 *
9 * See the top-level LICENSE file for the complete license and disclaimer.
10 */
11
12#ifndef BELFEM_HDF5_TOOLS_HPP
13#define BELFEM_HDF5_TOOLS_HPP
14
15
16#include <cstring>
17
18#include "stringtools.hpp"
19#include "assert.hpp"
20#include "hdf5_types.hpp"
21#include "cl_Vector.hpp"
22#include "cl_Matrix.hpp"
23#include "cl_Cell.hpp"
24
25
26namespace belfem
27{
28 namespace hdf5
29 {
30//------------------------------------------------------------------------------
31
36 inline bool
37 dataset_exists( hid_t aLoc, const std::string & aLabel )
38 {
39#ifdef BELFEM_HDF5
40 hid_t tDataSet = 0;
41 return H5Lexists( aLoc, aLabel.c_str(), tDataSet );
42#else
43 return false;
44#endif
45 }
46
47//------------------------------------------------------------------------------
48
53 inline bool
54 group_exists( hid_t aLoc, const std::string & aLabel )
55 {
56#ifdef BELFEM_HDF5
57 hid_t tGroup = 0;
58 return H5Lexists( aLoc, aLabel.c_str(), tGroup );
59#else
60 return false;
61#endif
62 }
63
64//------------------------------------------------------------------------------
65
66// The whole function is guarded, not just its body: its SIGNATURE names
67// H5L_info2_t, which hdf5_types.hpp does not stub. With the body alone guarded
68// this header stopped compiling under -DUSE_HDF5=OFF, and since cl_HDF5.hpp
69// includes it and src/io always compiles cl_HDF5.cpp, that broke the whole
70// tree rather than only the HDF5 callers
71#ifdef BELFEM_HDF5
72
73// collect_names() and get_groups() below are written against the 1.12 link and
74// object interfaces ( H5L_info2_t, H5O_info2_t, H5Literate2,
75// H5Oget_info_by_name3 ). belfem_find_package carries no version test, so the
76// requirement is stated here, where it is created -- and this header is
77// included across the whole tree, so on an older HDF5 the failure would
78// otherwise be a wall of template errors in every module rather than one line
79#if ! H5_VERSION_GE( 1, 12, 0 )
80#error "BELFEM requires HDF5 1.12 or newer ( hdf5_tools.hpp uses H5Literate2 and H5Oget_info_by_name3 )."
81#endif
82
83 inline herr_t
84 collect_names(
85 hid_t aLoc,
86 const char * aLabel,
87 const H5L_info2_t * aInfo,
88 void * aData )
89 {
90 auto * tLabels = static_cast<std::vector<std::string> *>( aData );
91
92 // GROUPS only. H5Literate2 visits every link at the location,
93 // datasets and named datatypes included, and a caller that opens
94 // each returned name as a group fails on the first one that is not.
95 // A soft or external link is skipped as well rather than followed:
96 // resolving it can leave the location, which is not what listing a
97 // location means
98 if( aInfo != nullptr && aInfo->type != H5L_TYPE_HARD )
99 {
100 return 0;
101 }
102
103 H5O_info2_t tInfo ;
104
105 // a failed query is an ERROR, not an entry to skip. Returning 0
106 // here would let a permission failure or a corrupt object produce a
107 // short list that the caller cannot tell from a complete one. The
108 // callback contract is: negative aborts the iteration and becomes
109 // H5Literate2's return value, which get_groups() checks
110 if( H5Oget_info_by_name3( aLoc, aLabel, & tInfo,
111 H5O_INFO_BASIC, H5P_DEFAULT ) < 0 )
112 {
113 return -1;
114 }
115
116 // not a group is not an error -- it is the thing this filter exists
117 // to drop, so the iteration continues
118 if( tInfo.type != H5O_TYPE_GROUP )
119 {
120 return 0;
121 }
122
123 tLabels->emplace_back( aLabel );
124
125 return 0;
126 }
127
128#endif
129
133 inline Cell< std::string >
135 {
136#ifdef BELFEM_HDF5
137 Cell< std::string > tGroups ;
138
139 hsize_t tIndex = 0 ;
140
141 // H5_ITER_INC, not H5_ITER_NATIVE : native order is documented as
142 // whatever the library finds fastest, and callers that treat the
143 // first entry as a reference ( db2exo picks the grid of the first
144 // table it sees ) would then depend on it
145 const herr_t tStatus = H5Literate2(
146 aLoc,
147 H5_INDEX_NAME,
148 H5_ITER_INC,
149 & tIndex,
150 collect_names,
151 & tGroups.vector_data() );
152
153 // runs once per file, so the always-active tier is affordable and
154 // the message survives a release build. Silently returning a short
155 // list here would be indistinguishable from a location that really
156 // holds fewer groups
157 BELFEM_ERROR( tStatus >= 0,
158 "H5Literate2 failed while listing the groups of an HDF5 location." );
159
160 return tGroups ;
161
162
163#else
164 return {};
165#endif
166 }
167
168//------------------------------------------------------------------------------
169
174 template < typename T >
175 bool
177 {
178#ifdef BELFEM_HDF5
179 return H5Tget_size( datatype<T>() ) == sizeof( T );
180#else
181 return false;
182#endif
183 }
184
185//------------------------------------------------------------------------------
186
207 template < typename T >
208 void
209 check_read_datatype( const hid_t aFileType, const std::string & aLabel )
210 {
211#ifdef BELFEM_HDF5
212 BELFEM_ERROR( H5Tget_class( aFileType ) == H5Tget_class( datatype<T>() ),
213 "datatype class mismatch reading '%s': the file holds class %i, but %s is class %i.\n"
214 "HDF5 can convert between widths, not between classes - this file does not hold what the reader expects.",
215 aLabel.c_str(),
216 ( int ) H5Tget_class( aFileType ),
217 datatype_string<T>().c_str(),
218 ( int ) H5Tget_class( datatype<T>() ) );
219#endif
220 }
221
222//------------------------------------------------------------------------------
223
233 template < typename T >
234 void
236 hid_t & aLoc,
237 const std::string & aLabel,
238 const T & aValue,
239 herr_t & aStatus
240 )
241 {
242#ifdef BELFEM_HDF5
243 // test if dataset exists
244 BELFEM_ERROR( ! hdf5::dataset_exists( aLoc, aLabel ),
245 "Dataset %s of type %s does already exist.",
246 aLabel.c_str(),
247 datatype_string<T>().c_str() );
248
249 // check datatype
251 "Error in datatype size of type %s.",
252 datatype_string<T>().c_str() );
253
254 // FILE type: fixed width and little endian, so the on-disk
255 // layout does not depend on this build's native type widths
256 hid_t tDataType = H5Tcopy( filetype<T>() );
257
258 // matrix dimensions
259 hsize_t tDims[ 1 ] = { 1 };
260
261 // create data space
262 hid_t tDataSpace
263 = H5Screate_simple( 1, tDims, nullptr );
264
265 // create new dataset
266 hid_t tDataSet = H5Dcreate(
267 aLoc,
268 aLabel.c_str(),
269 tDataType,
270 tDataSpace,
271 H5P_DEFAULT,
272 H5P_DEFAULT,
273 H5P_DEFAULT );
274
275 // write data into dataset
276 aStatus = H5Dwrite(
277 tDataSet,
278 datatype< T >(), // MEMORY type: native, not the file type
279 H5S_ALL,
280 H5S_ALL,
281 H5P_DEFAULT,
282 & aValue );
283
284 // close open hids
285 H5Sclose( tDataSpace );
286 H5Tclose( tDataType );
287 H5Dclose( tDataSet );
288
289 // check for error
290 BELFEM_ASSERT( aStatus == 0,
291 "Something went wrong while trying to store scalar %s of type %s",
292 aLabel.c_str(),
293 datatype_string<T>().c_str());
294#endif
295 }
296//------------------------------------------------------------------------------
297
298 template < typename T >
299 void
301 hid_t & aLoc,
302 const std::string & aLabel,
303 T & aValue,
304 herr_t & aStatus
305 )
306 {
307#ifdef BELFEM_HDF5
308 // test if dataset exists
309 BELFEM_ERROR( hdf5::dataset_exists( aLoc, aLabel ),
310 "Dataset %s of type %s does not exist.",
311 aLabel.c_str(),
312 datatype_string<T>().c_str() );
313
314 // check datatype
316 "Error in datatype size of type %s.",
317 datatype_string<T>().c_str() );
318
319 // open the data set
320 hid_t tDataSet = H5Dopen1( aLoc, aLabel.c_str() );
321
322 // get the data type of the set
323 hid_t tDataType = H5Dget_type( tDataSet );
324
325 // the file type must be convertible into T; the read
326 // below then uses datatype<T>() so HDF5 does the conversion
327 check_read_datatype< T >( tDataType, aLabel );
328
329 // get handler to dataspace
330 hid_t tDataSpace = H5Dget_space( tDataSet );
331
332 // read data from file
333 aStatus = H5Dread(
334 tDataSet,
335 datatype< T >(), // MEMORY type: let HDF5 convert
336 H5S_ALL,
337 H5S_ALL,
338 H5P_DEFAULT,
339 &aValue );
340
341 // Close/release resources
342 H5Tclose( tDataType );
343 H5Dclose( tDataSet );
344 H5Sclose( tDataSpace );
345
346 // check for error
347 BELFEM_ASSERT( aStatus == 0,
348 "Something went wrong while trying to load scalar %s of type %s",
349 aLabel.c_str(),
350 datatype_string<T>().c_str() );
351
352#endif
353 }
354
355//------------------------------------------------------------------------------
356
357 void
359 hid_t & aLoc,
360 const std::string & aLabel,
361 const bool & aValue,
362 herr_t & aStatus );
363
364//------------------------------------------------------------------------------
365
366 void
368 hid_t & aLoc,
369 const std::string & aLabel,
370 bool & aValue,
371 herr_t & aStatus );
372
373//------------------------------------------------------------------------------
374
375 void
377 hid_t & aLoc,
378 const std::string & aLabel,
379 const std::string & aValue,
380 herr_t & aStatus );
381
382//------------------------------------------------------------------------------
383
384 void
386 hid_t & aLoc,
387 const std::string & aLabel,
388 std::string & aValue,
389 herr_t & aStatus );
390
391//------------------------------------------------------------------------------
392 template < typename T >
393 void
395 hid_t & aLoc,
396 const std::string & aLabel,
397 const T * aData,
398 const hsize_t & aLength,
399 herr_t & aStatus )
400 {
401#ifdef BELFEM_HDF5
402 // test if dataset exists
403 BELFEM_ERROR( ! hdf5::dataset_exists( aLoc, aLabel ),
404 "Dataset %s of type Vector<%s> does already exist.",
405 aLabel.c_str(),
406 datatype_string<T>().c_str() );
407
408 // check datatype
410 "Error in datatype size of type %s.",
411 datatype_string<T>().c_str() );
412
413 // FILE type: fixed width and little endian, so the on-disk
414 // layout does not depend on this build's native type widths
415 hid_t tDataType = H5Tcopy( filetype<T>() );
416
417 // matrix dimensions
418 hsize_t tDims[ 1 ];
419 tDims[ 0 ] = aLength;
420
421 // create data space
422 hid_t tDataSpace
423 = H5Screate_simple( 1, tDims, nullptr );
424
425 // create new dataset
426 hid_t tDataSet = H5Dcreate(
427 aLoc,
428 aLabel.c_str(),
429 tDataType,
430 tDataSpace,
431 H5P_DEFAULT,
432 H5P_DEFAULT,
433 H5P_DEFAULT );
434
435 // test if vector is not empty
436 if( aLength > 0 )
437 {
438 // write data into dataset
439 aStatus = H5Dwrite(
440 tDataSet,
441 datatype< T >(), // MEMORY type: native, not the file type
442 H5S_ALL,
443 H5S_ALL,
444 H5P_DEFAULT,
445 &aData[ 0 ] );
446 }
447
448 // close open hids
449 H5Sclose( tDataSpace );
450 H5Tclose( tDataType );
451 H5Dclose( tDataSet );
452
453 // check for error
454 BELFEM_ASSERT( aStatus == 0,
455 "Something went wrong while trying to store vector %s of type %s",
456 aLabel.c_str(),
457 datatype_string<T>().c_str() );
458#endif
459 }
460
461//------------------------------------------------------------------------------
462
463 hsize_t
465 hid_t & aLoc,
466 const std::string & aLabel );
467
468//------------------------------------------------------------------------------
469
470 template < typename T >
471 void
473 hid_t & aLoc,
474 const std::string & aLabel,
475 T * aData,
476 const hsize_t aLength,
477 herr_t & aStatus )
478 {
479#ifdef BELFEM_HDF5
480
481 // test if dataset exists
482 BELFEM_ERROR( hdf5::dataset_exists( aLoc, aLabel ),
483 "Dataset %s of type Vector<%s> does not exist.",
484 aLabel.c_str(),
485 datatype_string<T>().c_str() );
486
487 // check datatype
489 "Error in datatype size of type %s.",
490 datatype_string<T>().c_str() );
491
492 // open the data set
493 hid_t tDataSet = H5Dopen1( aLoc, aLabel.c_str() );
494
495 // get the data type of the set
496 hid_t tDataType = H5Dget_type( tDataSet );
497
498 // the file type must be convertible into T; the read
499 // below then uses datatype<T>() so HDF5 does the conversion
500 check_read_datatype< T >( tDataType, aLabel );
501
502 // get handler to dataspace
503 hid_t tDataSpace = H5Dget_space( tDataSet );
504
505 // matrix dimensions
506 hsize_t tDims[ 1 ];
507
508 // ask hdf for dimensions
509 aStatus = H5Sget_simple_extent_dims( tDataSpace, tDims, nullptr );
510
511 // get length
512 BELFEM_ERROR( tDims[ 0 ] == aLength, "Lengths do not match: is %lu, expect %lu.",
513 ( long unsigned int ) tDims[ 0 ], ( long unsigned int ) aLength );
514
515 // test if vector is empty
516 if( aLength > 0 )
517 {
518 // read data from file
519 aStatus = H5Dread(
520 tDataSet,
521 datatype< T >(), // MEMORY type: let HDF5 convert
522 H5S_ALL,
523 H5S_ALL,
524 H5P_DEFAULT,
525 &aData[ 0 ] );
526 }
527 else
528 {
529 // all good. reset status
530 aStatus = 0;
531 }
532
533 // Close/release resources
534 H5Tclose( tDataType );
535 H5Dclose( tDataSet );
536 H5Sclose( tDataSpace );
537
538 // check for error
539 BELFEM_ASSERT( aStatus == 0,
540 "Something went wrong while trying to load vector %s of type %s",
541 aLabel.c_str(),
542 datatype_string<T>().c_str() );
543#endif
544 }
545//------------------------------------------------------------------------------
546
547 template < typename T >
548 void
550 hid_t & aLoc,
551 const std::string & aLabel,
552 const Vector< T > & aVector,
553 herr_t & aStatus )
554 {
555#ifdef BELFEM_HDF5
556
557 // test if dataset exists
558 BELFEM_ERROR( ! hdf5::dataset_exists( aLoc, aLabel ),
559 "Dataset %s of type Vector<%s> does already exist.",
560 aLabel.c_str(),
561 datatype_string<T>().c_str() );
562
563 // check datatype
565 "Error in datatype size of type %s.",
566 datatype_string<T>().c_str() );
567
568 // FILE type: fixed width and little endian, so the on-disk
569 // layout does not depend on this build's native type widths
570 hid_t tDataType = H5Tcopy( filetype<T>() );
571 hid_t tDataSet = 0;
572
573 // matrix dimensions
574 hsize_t tLength = aVector.length();
575 hsize_t tDims[ 1 ];
576 tDims[ 0 ] = tLength;
577
578 // create data space
579 hid_t tDataSpace
580 = H5Screate_simple( 1, tDims, nullptr );
581
582 // create new dataset
583 tDataSet = H5Dcreate(
584 aLoc,
585 aLabel.c_str(),
586 tDataType,
587 tDataSpace,
588 H5P_DEFAULT,
589 H5P_DEFAULT,
590 H5P_DEFAULT );
591
592 // test if vector is not empty
593 if( tLength > 0 )
594 {
595 // allocate memory for data
596 T* tData = ( T* ) malloc( tLength * sizeof( T ) );
597
598 // copy vector to data
599 std::memcpy(
600 tData,
601 aVector.data(),
602 tLength * sizeof( T ) );
603
604 // write data into dataset
605 aStatus = H5Dwrite(
606 tDataSet,
607 datatype< T >(), // MEMORY type: native, not the file type
608 H5S_ALL,
609 H5S_ALL,
610 H5P_DEFAULT,
611 & tData[ 0 ]);
612
613 // tidy up memory
614 free( tData );
615 }
616
617 // close open hids
618 H5Sclose( tDataSpace );
619 H5Tclose( tDataType );
620 H5Dclose( tDataSet );
621
622 // check for error
623 BELFEM_ASSERT( aStatus == 0,
624 "Something went wrong while trying to store vector %s of type %s",
625 aLabel.c_str(),
626 datatype_string<T>().c_str() );
627#endif
628 }
629
630//------------------------------------------------------------------------------
631
632 template < typename T >
633 void
635 hid_t & aLoc,
636 const std::string & aLabel,
637 Vector< T > & aVector,
638 herr_t & aStatus )
639 {
640#ifdef BELFEM_HDF5
641 // test if dataset exists
642 BELFEM_ERROR( hdf5::dataset_exists( aLoc, aLabel ),
643 "Dataset %s of type Vector<%s> does not exist.",
644 aLabel.c_str(),
645 datatype_string<T>().c_str() );
646
647 // check datatype
649 "Error in datatype size of type %s.",
650 datatype_string<T>().c_str() );
651
652 // open the data set
653 hid_t tDataSet = H5Dopen1( aLoc, aLabel.c_str() );
654
655 // get the data type of the set
656 hid_t tDataType = H5Dget_type( tDataSet );
657
658 // the file type must be convertible into T; the read
659 // below then uses datatype<T>() so HDF5 does the conversion
660 check_read_datatype< T >( tDataType, aLabel );
661
662 // get handler to dataspace
663 hid_t tDataSpace = H5Dget_space( tDataSet );
664
665 // matrix dimensions
666 hsize_t tDims[ 1 ];
667
668 // ask hdf for dimensions
669 aStatus = H5Sget_simple_extent_dims( tDataSpace, tDims, nullptr );
670
671 // get length
672 hsize_t tLength = tDims[ 0 ];
673
674 // allocate length of output vector
675 aVector.set_size( tLength );
676
677 // test if vector is empty
678 if( tLength > 0 )
679 {
680 // allocate buffer
681 T* tData = ( T* ) malloc( tLength * sizeof( T ) );
682
683 // read data from file
684 aStatus = H5Dread(
685 tDataSet,
686 datatype< T >(), // MEMORY type: let HDF5 convert
687 H5S_ALL,
688 H5S_ALL,
689 H5P_DEFAULT,
690 &tData[ 0 ] );
691
692 // copy data to vector
693 std::memcpy(
694 aVector.data(),
695 tData,
696 tLength * sizeof( T ) );
697
698 // tidy up memory
699 free( tData );
700 }
701 else
702 {
703 // all good. reset status
704 aStatus = 0;
705 }
706
707 // Close/release resources
708 H5Tclose( tDataType );
709 H5Dclose( tDataSet );
710 H5Sclose( tDataSpace );
711
712 // check for error
713 BELFEM_ASSERT( aStatus == 0,
714 "Something went wrong while trying to load vector %s of type %s",
715 aLabel.c_str(),
716 datatype_string<T>().c_str() );
717#endif
718 }
719//------------------------------------------------------------------------------
720
721 template < typename T >
722 void
724 hid_t & aLoc,
725 const std::string & aLabel,
726 const Matrix< T > & aMatrix,
727 herr_t & aStatus,
728 const bool aTranspose = false )
729 {
730#ifdef BELFEM_HDF5
731 // test if dataset exists
732 BELFEM_ERROR( ! hdf5::dataset_exists( aLoc, aLabel ),
733 "Dataset %s of type Matrix<%s> does already exist.",
734 aLabel.c_str(),
735 datatype_string<T>().c_str() );
736
737 // check datatype
739 "Error in datatype size of type %s.",
740 datatype_string<T>().c_str() );
741
742 // FILE type: fixed width and little endian, so the on-disk
743 // layout does not depend on this build's native type widths
744 hid_t tDataType = H5Tcopy( filetype<T>() );
745 hid_t tDataSet = 0;
746
747 // matrix dimensions
748 hsize_t tDims[ 2 ];
749
750 if ( aTranspose )
751 {
752 tDims[ 0 ] = aMatrix.n_cols();
753 tDims[ 1 ] = aMatrix.n_rows();
754
755 }
756 else
757 {
758 tDims[ 0 ] = aMatrix.n_rows();
759 tDims[ 1 ] = aMatrix.n_cols();
760 }
761
762 // create data space
763 hid_t tDataSpace
764 = H5Screate_simple( 2, tDims, nullptr );
765
766 // create new dataset
767 tDataSet = H5Dcreate(
768 aLoc,
769 aLabel.c_str(),
770 tDataType,
771 tDataSpace,
772 H5P_DEFAULT,
773 H5P_DEFAULT,
774 H5P_DEFAULT );
775
776 // test if vector is not empty
777 if( tDims[ 0 ]*tDims[ 1 ] > 0 )
778 {
779 // allocate memory for data
780 T** tData = ( T** ) malloc( tDims[ 0 ] * sizeof( T * ) );
781 tData[ 0 ] = ( T* ) malloc( tDims[ 0 ]*tDims[ 1 ] * sizeof( T ) );
782
783 // loop over all rows and allocate colums
784 for( hsize_t i=0; i<tDims[ 0 ]; ++i )
785 {
786 tData[ i ] = tData[ 0 ]+ i*tDims[ 1 ];
787 }
788
789 if ( aTranspose )
790 {
791 for ( hsize_t i = 0; i < tDims[ 0 ]; ++i )
792 {
793 for ( hsize_t j = 0; j < tDims[ 1 ]; ++j )
794 {
795 tData[ i ][ j ] = aMatrix( j, i );
796 }
797 }
798 }
799 else
800 {
801 // convert matrix to array
802 for ( hsize_t i = 0; i < tDims[ 0 ]; ++i )
803 {
804 for ( hsize_t j = 0; j < tDims[ 1 ]; ++j )
805 {
806 tData[ i ][ j ] = aMatrix( i, j );
807 }
808 }
809 }
810 // write data into dataset
811 aStatus = H5Dwrite(
812 tDataSet,
813 datatype< T >(), // MEMORY type: native, not the file type
814 H5S_ALL,
815 H5S_ALL,
816 H5P_DEFAULT,
817 & tData[ 0 ][ 0 ]);
818
819 // tidy up memory
820 free( tData[ 0 ] );
821 free( tData );
822 }
823
824 // close open hids
825 H5Sclose( tDataSpace );
826 H5Tclose( tDataType );
827 H5Dclose( tDataSet );
828
829 // check for error
830 BELFEM_ASSERT( aStatus == 0,
831 "Something went wrong while trying to store matrix %s of type %s",
832 aLabel.c_str(),
833 datatype_string<T>().c_str() );
834#endif
835 }
836
837//------------------------------------------------------------------------------
838
839 template < typename T >
840 void
842 hid_t & aLoc,
843 const std::string & aLabel,
844 Matrix< T > & aMatrix,
845 herr_t & aStatus,
846 const bool aTranspose = false )
847 {
848#ifdef BELFEM_HDF5
849
850 // test if dataset exists
851 BELFEM_ERROR( hdf5::dataset_exists( aLoc, aLabel ),
852 "Dataset %s of type Matrix<%s> does not exist.",
853 aLabel.c_str(),
854 datatype_string<T>().c_str() );
855
856 // check datatype
858 "Error in datatype size of type %s.",
859 datatype_string<T>().c_str() );
860
861
862 // open the data set
863 hid_t tDataSet = H5Dopen1( aLoc, aLabel.c_str() );
864
865 // get the data type of the set
866 hid_t tDataType = H5Dget_type( tDataSet );
867
868 // the file type must be convertible into T; the read
869 // below then uses datatype<T>() so HDF5 does the conversion
870 check_read_datatype< T >( tDataType, aLabel );
871
872 // test datatype compatibility
873 BELFEM_ASSERT( H5Tget_class( tDataType )
874 == H5Tget_class( datatype<T>() ),
875 "Dataset %s does not seem to be %s.",
876 aLabel.c_str(),
877 datatype_string<T>().c_str() );
878
879 // get handler to dataspace
880 hid_t tDataSpace = H5Dget_space( tDataSet );
881
882 // matrix dimensions
883 hsize_t tDims[ 2 ];
884
885 // ask hdf for dimensions
886 aStatus = H5Sget_simple_extent_dims( tDataSpace, tDims, nullptr );
887
888 // allocate memory for output (transpose swaps the on-disk dimensions)
889 if ( aTranspose )
890 {
891 aMatrix.set_size( tDims[ 1 ], tDims[ 0 ] );
892 }
893 else
894 {
895 aMatrix.set_size( tDims[ 0 ], tDims[ 1 ] );
896 }
897
898 // test if matrix is not empty
899 if( tDims[ 0 ]*tDims[ 1 ] > 0 )
900 {
901 // allocate top level array which contains rows
902 T** tData = ( T** )
903 malloc( tDims[ 0 ]*sizeof( T* ) );
904
905 // allocate memory for data
906 tData[ 0 ] = ( T* )
907 malloc( tDims[ 0 ]* tDims[ 1 ] * sizeof( T ) );
908
909 // loop over all rows and allocate colums
910 for( hsize_t i=1; i<tDims[ 0 ]; ++i )
911 {
912 tData[ i ] = tData[ 0 ]+ i*tDims[ 1 ];
913 }
914
915
916 // read data from file
917 aStatus = H5Dread(
918 tDataSet,
919 datatype< T >(), // MEMORY type: let HDF5 convert
920 H5S_ALL,
921 H5S_ALL,
922 H5P_DEFAULT,
923 &tData[ 0 ][ 0 ] );
924
925 // write values into matrix
926 if ( aTranspose )
927 {
928 // on-disk (tDims[0] x tDims[1]) -> memory (tDims[1] x tDims[0])
929 for ( hsize_t i = 0; i < tDims[ 0 ]; ++i )
930 {
931 for ( hsize_t j = 0; j < tDims[ 1 ]; ++j )
932 {
933 aMatrix( j, i ) = tData[ i ][ j ];
934 }
935 }
936 }
937 else
938 {
939 for ( hsize_t j = 0; j < tDims[ 1 ]; ++j )
940 {
941 for ( hsize_t i = 0; i < tDims[ 0 ]; ++i )
942 {
943 aMatrix( i, j ) = tData[ i ][ j ];
944 }
945 }
946 }
947 // tidy up memory
948 free( tData[ 0 ] );
949 free( tData );
950 }
951 else if( aStatus == 2 )
952 {
953 // all good, reset status
954 aStatus = 0;
955 }
956
957 // Close/release resources
958 H5Tclose( tDataType );
959 H5Dclose( tDataSet );
960 H5Sclose( tDataSpace );
961
962 // check for error
963 BELFEM_ASSERT( aStatus == 0,
964 "Something went wrong while trying to load matrix %s of type %s",
965 aLabel.c_str(),
966 datatype_string<T>().c_str() );
967#endif
968 }
969
970 inline void
972 const std::string & aLabel,
973 const Cell< string > & aCell,
974 herr_t & aStatus )
975 {
976#ifdef BELFEM_HDF5
977
978 // create the dataspace
979 hsize_t tNumStrings = aCell.size();
980 hsize_t tDim[ 1 ] = { tNumStrings };
981 hid_t tDataSpace = H5Screate_simple( 1, tDim, NULL );
982
983 // Create variable-length string datatype.
984 hid_t tType = H5Tcopy( H5T_C_S1 );
985 H5Tset_size( tType, H5T_VARIABLE );
986
987 // create the dataset
988 hid_t tDataset = H5Dcreate2(
989 aLoc,
990 aLabel.c_str(),
991 tType,
992 tDataSpace,
993 H5P_DEFAULT,
994 H5P_DEFAULT,
995 H5P_DEFAULT );
996
997 BELFEM_ERROR( tDataset > -1, "Error creating dataset" );
998
999 // populate a buffer
1000 Cell< const char * > tBuffer( tNumStrings, nullptr );
1001 for ( hsize_t i=0; i<tNumStrings; ++i )
1002 {
1003 tBuffer( i ) = aCell( i ).c_str();
1004 }
1005
1006 aStatus = H5Dwrite(
1007 tDataset,
1008 tType,
1009 H5S_ALL,
1010 H5S_ALL,
1011 H5P_DEFAULT,
1012 tBuffer.data() );
1013
1014 BELFEM_ERROR( aStatus ==0, "Error writing data" );
1015
1016 H5Dclose( tDataset );
1017 H5Tclose( tType );
1018 H5Sclose( tDataSpace );
1019#endif
1020 }
1021
1022 inline void
1024 const std::string & aLabel,
1025 Cell< string > & aCell,
1026 herr_t & aStatus )
1027 {
1028#ifdef BELFEM_HDF5
1029 // make sure that cell is clean
1030 aCell.clear();
1031
1032 BELFEM_ERROR( hdf5::dataset_exists( aLoc, aLabel ),
1033 "Dataset %s does not exist at expected location.", aLabel.c_str() );
1034
1035 // open the dataset
1036 hid_t tDataset = H5Dopen1( aLoc, aLabel.c_str() );
1037
1038 // get the dataspace
1039 hid_t tDataSpace = H5Dget_space( tDataset );
1040
1041 // determine number of strings
1042 hsize_t tDim[ 1 ] ;
1043 BELFEM_ERROR( H5Sget_simple_extent_dims( tDataSpace, tDim, nullptr ) > -1 ,
1044 "Error getting dataspace dimensions" );
1045
1046 // get the number of strings
1047 hsize_t tNumStrings = tDim[ 0 ];
1048
1049 // Create the memory datatype for variable-length strings.
1050 // This must match the datatype used in writing -- INCLUDING the
1051 // character set: H5T_C_S1 defaults to ASCII, but h5py writes
1052 // vlen strings as UTF-8, and HDF5 refuses the UTF-8 -> ASCII
1053 // conversion path, failing the H5Dread below with no better
1054 // diagnostic than a nonzero status. Copy the cset from the
1055 // dataset itself so BELFEM-written ASCII files behave as before
1056 // and Python-written UTF-8 files become readable.
1057 hid_t tType = H5Tcopy( H5T_C_S1 );
1058 H5Tset_size( tType, H5T_VARIABLE );
1059
1060 hid_t tFileType = H5Dget_type( tDataset );
1061 H5Tset_cset( tType, H5Tget_cset( tFileType ) );
1062 H5Tclose( tFileType );
1063
1064 // Allocate a temporary buffer to hold the array of char*.
1065 // HDF5 will allocate the actual strings when reading.
1066 char ** tBuffer = new char *[ tNumStrings ];
1067
1068 // read the dataset
1069 BELFEM_ERROR( H5Dread( tDataset, tType, H5S_ALL, H5S_ALL, H5P_DEFAULT, tBuffer ) == 0,
1070 "Failed to read strings from file." );
1071
1072 // allocate the container
1073 aCell.set_size( tNumStrings, "" );
1074
1075 // populate the cell
1076 for ( hsize_t i=0; i<tNumStrings; ++i )
1077 {
1078 aCell( i ) = std::string( tBuffer[ i ] );
1079 }
1080
1081 // tidy up memory
1082 H5Dvlen_reclaim( tType, tDataSpace, H5P_DEFAULT, tBuffer );
1083 delete [] tBuffer;
1084
1085 H5Tclose( tType );
1086 H5Sclose( tDataSpace );
1087 H5Dclose( tDataset );
1088#endif
1089 }
1090//------------------------------------------------------------------------------
1091
1092 inline hid_t
1093 open_group( const std::string & aLabel, hid_t aParent )
1094 {
1095#ifdef BELFEM_HDF5
1096 if ( hdf5::group_exists( aParent, aLabel ) )
1097 {
1098 // add backslash to label
1099 //std::string tLabel = "/" + aLabel;
1100
1101 return H5Gopen2(
1102 aParent,
1103 aLabel.c_str(),
1104 H5P_DEFAULT );
1105 }
1106 else
1107 {
1108 BELFEM_ERROR( false,
1109 "Group %s does not exist.",
1110 aLabel.c_str() );
1111
1112 return -1;
1113 }
1114#else
1115 return 0 ;
1116#endif
1117 }
1118
1119//------------------------------------------------------------------------------
1120
1121 inline herr_t
1123 {
1124#ifdef BELFEM_HDF5
1125 return H5Gclose( aGroup );
1126#else
1127 return 0 ;
1128#endif
1129 }
1130
1131//------------------------------------------------------------------------------
1132
1133 string
1134 create_tree( const Cell< string > & aTree, const string & aLabel );
1135
1136
1137//------------------------------------------------------------------------------
1138
1139
1140
1141//------------------------------------------------------------------------------
1142 } /* namespace hdf5 */
1143} /* namespace belfem */
1144
1145#endif //BELFEM_HDF5_TOOLS_HPP
#define BELFEM_ERROR(aCheck,...)
Definition assert.hpp:264
#define BELFEM_ASSERT(aCheck,...)
Definition assert.hpp:244
Cell is a wrapper around the standard vector.
Definition cl_Cell.hpp:42
void set_size(const size_t aSize)
Definition cl_Cell.hpp:189
size_t size() const
return the size of the Cell
Definition cl_Cell.hpp:181
void clear()
clear the memory
Definition cl_Cell.hpp:240
std::vector< T > & vector_data()
Definition cl_Cell.hpp:135
T * data()
Definition cl_Cell.hpp:120
Dense column-major matrix.
Definition cl_BZ_Matrix.hpp:28
void set_size(const size_t aNumRows, const size_t aNumCols)
Definition cl_AR_Matrix.hpp:186
size_t n_rows() const
Definition cl_AR_Matrix.hpp:205
size_t n_cols() const
Definition cl_AR_Matrix.hpp:213
Column vector.
Definition cl_BZ_Vector.hpp:41
T * data()
expose the underlying raw pointer ( writable version )
Definition cl_AR_Vector.hpp:182
void set_size(const size_t aNumRows)
change the size of the vector
Definition cl_AR_Vector.hpp:237
size_t length() const
get the length of the vector
Definition cl_AR_Vector.hpp:257
Definition cl_HDF5_Dataset.hpp:21
void save_vector_to_file(hid_t &aLoc, const std::string &aLabel, const Vector< T > &aVector, herr_t &aStatus)
Definition hdf5_tools.hpp:549
bool group_exists(hid_t aLoc, const std::string &aLabel)
test if a group exists ( tests for a link of that name; the link type is not checked )
Definition hdf5_tools.hpp:54
void save_string_to_file(hid_t &aFileID, const std::string &aLabel, const std::string &aValue, herr_t &aStatus)
Definition hdf5_tools.cpp:140
void load_scalar_from_file(hid_t &aLoc, const std::string &aLabel, T &aValue, herr_t &aStatus)
Definition hdf5_tools.hpp:300
void save_array_to_file(hid_t &aLoc, const std::string &aLabel, const T *aData, const hsize_t &aLength, herr_t &aStatus)
Definition hdf5_tools.hpp:394
void load_bool_from_file(hid_t &aFileID, const std::string &aLabel, bool &aValue, herr_t &aStatus)
Definition hdf5_tools.cpp:83
void save_strings_to_file(hid_t &aLoc, const std::string &aLabel, const Cell< string > &aCell, herr_t &aStatus)
Definition hdf5_tools.hpp:971
void save_scalar_to_file(hid_t &aLoc, const std::string &aLabel, const T &aValue, herr_t &aStatus)
saves a scalar value to a file file must be open
Definition hdf5_tools.hpp:235
hid_t open_group(const std::string &aLabel, hid_t aParent)
Definition hdf5_tools.hpp:1093
void load_strings_from_file(hid_t &aLoc, const std::string &aLabel, Cell< string > &aCell, herr_t &aStatus)
Definition hdf5_tools.hpp:1023
void load_matrix_from_file(hid_t &aLoc, const std::string &aLabel, Matrix< T > &aMatrix, herr_t &aStatus, const bool aTranspose=false)
Definition hdf5_tools.hpp:841
void save_matrix_to_file(hid_t &aLoc, const std::string &aLabel, const Matrix< T > &aMatrix, herr_t &aStatus, const bool aTranspose=false)
Definition hdf5_tools.hpp:723
bool check_datatye_size()
this function returns true of both the HDF5 datatype and the passed datatype have the same size
Definition hdf5_tools.hpp:176
hid_t datatype()
Definition hdf5_types.hpp:36
Cell< std::string > get_groups(hid_t aLoc)
list groups that exist in location
Definition hdf5_tools.hpp:134
hid_t filetype()
Definition hdf5_types.hpp:56
hsize_t get_array_size(hid_t &aFileID, const std::string &aLabel)
Definition hdf5_tools.cpp:264
bool dataset_exists(hid_t aLoc, const std::string &aLabel)
test if a dataset exists ( tests for a link of that name; the link type is not checked )
Definition hdf5_tools.hpp:37
string create_tree(const Cell< string > &aTree, const string &aLabel)
Definition hdf5_tools.cpp:305
void load_vector_from_file(hid_t &aLoc, const std::string &aLabel, Vector< T > &aVector, herr_t &aStatus)
Definition hdf5_tools.hpp:634
void check_read_datatype(const hid_t aFileType, const std::string &aLabel)
Guard for every read: the FILE datatype must be convertible into T.
Definition hdf5_tools.hpp:209
void load_string_from_file(hid_t &aFileID, const std::string &aLabel, std::string &aValue, herr_t &aStatus)
Definition hdf5_tools.cpp:206
void load_array_from_file(hid_t &aLoc, const std::string &aLabel, T *aData, const hsize_t aLength, herr_t &aStatus)
Definition hdf5_tools.hpp:472
void save_bool_to_file(hid_t &aFileID, const std::string &aLabel, const bool &aValue, herr_t &aStatus)
Definition hdf5_tools.cpp:21
herr_t close_group(hid_t aGroup)
Definition hdf5_tools.hpp:1122
USER GUIDES:
Definition cl_Capacitor.cpp:16
std::string datatype_string()
Definition stringtools.hpp:64
int hsize_t
Definition hdf5_types.hpp:22
int hid_t
Definition hdf5_types.hpp:20
int herr_t
Definition hdf5_types.hpp:21