Theoretica
Mathematical Library
Loading...
Searching...
No Matches
hdf5.h
1
7
8#ifndef THEORETICA_IO_HDF5_H
9#define THEORETICA_IO_HDF5_H
10
11#include <hdf5.h>
12
13#include <string>
14#include <vector>
15#include <unordered_map>
16#include <stdexcept>
17#include <cstring>
18#include <sstream>
19#include <algorithm>
20
21#include "./error.h"
22#include "../core/constants.h"
23#include "../algebra/vec.h"
24#include "../algebra/mat.h"
25
26
27namespace theoretica {
28namespace io {
29
30
31 // Data structures and representations
32
34 enum class HDF5NodeType {
35
37 UNKNOWN,
38
40 GROUP,
41
44 };
45
46
49 struct hdf5_node {
50
52 std::string name;
53
56 std::string path;
57
60
62 std::vector<size_t> dimensions;
63
65 std::vector<std::string> attributes;
66
68 std::unordered_map<std::string, hdf5_node> children;
69
70
72 inline bool is_group() const noexcept {
73 return type == HDF5NodeType::GROUP;
74 }
75
76
78 inline bool is_dataset() const noexcept {
80 }
81
82
87 inline hdf5_node& operator[](const std::string& child_name) {
88 return children[child_name];
89 }
90
91
96 inline const hdf5_node& operator[](const std::string& child_name) const {
97 return children.at(child_name);
98 }
99 };
100
101
104 struct hdf5_handle {
105
109
110
115
116
119
120 if (id == H5I_INVALID_HID || !H5Iis_valid(id)) return;
121 switch (H5Iget_type(id)) {
122 case H5I_FILE: H5Fclose(id); break;
123 case H5I_GROUP: H5Gclose(id); break;
124 case H5I_DATASET: H5Dclose(id); break;
125 case H5I_DATATYPE: H5Tclose(id); break;
126 case H5I_DATASPACE: H5Sclose(id); break;
127 case H5I_ATTR: H5Aclose(id); break;
128 case H5I_GENPROP_LST: H5Pclose(id); break;
129 default: H5Idec_ref(id); break;
130 }
131 }
132
133
135 hdf5_handle(const hdf5_handle&) = delete;
136 hdf5_handle& operator=(const hdf5_handle&) = delete;
137
138
143
144
147
148 if (this != &other) {
149
150 if (id >= 0 && H5Iis_valid(id))
151 H5Idec_ref(id);
152
153 id = other.id;
155 }
156
157 return *this;
158 }
159
160
162 operator hid_t() const {
163 return id;
164 }
165 };
166
167
168 namespace _internal {
169
173 template<typename Type>
174 inline hid_t hdf5_type() {
175 TH_IO_ERROR("io::_internal::hdf5_type", "hdf5_type<Type>", IoError::FormatError);
176 return H5I_INVALID_HID;
177 }
178
179 template<> inline hid_t hdf5_type<double>() { return H5T_NATIVE_DOUBLE; }
180 template<> inline hid_t hdf5_type<float>() { return H5T_NATIVE_FLOAT; }
181 template<> inline hid_t hdf5_type<int>() { return H5T_NATIVE_INT; }
182 template<> inline hid_t hdf5_type<long>() { return H5T_NATIVE_LONG; }
183 template<> inline hid_t hdf5_type<unsigned int>() { return H5T_NATIVE_UINT; }
184
185
187 inline void suppress_errors() {
188 H5Eset_auto(H5E_DEFAULT, nullptr, nullptr);
189 }
190
191
195 inline void remove_link(const hdf5_handle& id, const std::string& path) {
196
197 suppress_errors();
198 if (H5Lexists(id, path.c_str(), H5P_DEFAULT) > 0) {
199 H5Ldelete(id, path.c_str(), H5P_DEFAULT);
200 }
201 }
202
203
204 // Attributes
205
206 // Count attributes callback for H5Aiterate2
207 static herr_t attribute_callback(hid_t id, const char* attr_name, const H5A_info_t* info_ptr, void* op_data) {
208
209 auto* attrs = (std::vector<std::string>*) op_data;
210 attrs->emplace_back(attr_name);
211 return 0;
212 }
213
214
215 // Load all attributes for a given object into a vector of strings
216 inline void load_attributes(hid_t obj_id, std::vector<std::string>& attributes) {
217 H5Aiterate2(obj_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, attribute_callback, &attributes);
218 }
219
220
221 // Read and write attributes of various types, with error handling
222 template<typename Type>
223 inline void read_attribute(hid_t attr_id, Type& value) {
224
225 if (H5Aread(attr_id, hdf5_type<Type>(), &value) < 0) {
226 TH_IO_ERROR("io::read_attribute", "attribute_id", IoError::FormatError);
227 value = Type();
228 }
229 }
230
231
232 // Read a string attribute
233 inline void read_attribute(hid_t attr_id, std::string& value) {
234
235 hdf5_handle type_id = H5Aget_type(attr_id);
237 TH_IO_ERROR("io::read_attribute", "attribute_id", IoError::FormatError);
238 value = std::string();
239 return;
240 }
241
243 if (is_varstring > 0) {
244
245 char* buf = nullptr;
246 hdf5_handle mem_type = H5Tcopy(H5T_C_S1);
248
249 if (H5Aread(attr_id, mem_type, &buf) < 0) {
250 TH_IO_ERROR("io::read_attribute", "attribute_id", IoError::ReadError);
251 value = std::string();
252 return;
253 }
254
255 value = buf ? std::string(buf) : std::string();
256 if (buf)
258
259 } else if (is_varstring == 0) {
260
261 const size_t size = H5Tget_size(type_id);
262 std::vector<char> buf (size + 1, '\0');
263
264 hdf5_handle mem_type = H5Tcopy(H5T_C_S1);
265 H5Tset_size(mem_type, size);
266 if (H5Aread(attr_id, mem_type, buf.data()) < 0) {
267 TH_IO_ERROR("io::read_attribute", "attribute_id", IoError::ReadError);
268 value = std::string();
269 return;
270 }
271
272 value = std::string(buf.data());
273
274 } else {
275 TH_IO_ERROR("io::read_attribute", "attribute_id", IoError::FormatError);
276 value = std::string();
277 return;
278 }
279 }
280
281
282 // Write an attribute of a generic type, creating it if it doesn't exist
283 template<typename Type>
284 inline void write_attribute(hid_t obj_id, const std::string& name, const Type& value) {
285
286 hdf5_handle space_id = H5Screate(H5S_SCALAR);
287 hdf5_handle attr_id = H5Acreate2(obj_id, name.c_str(), hdf5_type<Type>(), space_id, H5P_DEFAULT, H5P_DEFAULT);
288
289 if (attr_id < 0) {
290 TH_IO_ERROR("io::write_attribute", "attribute_id", IoError::WriteError);
291 return;
292 }
293
294 if (H5Awrite(attr_id, hdf5_type<Type>(), &value) < 0)
295 TH_IO_ERROR("io::write_attribute", "attribute_id", IoError::WriteError);
296 }
297
298
299 // Write a string attribute
300 inline void write_attribute(hid_t obj_id, const std::string& name, const std::string& value) {
301
302 hdf5_handle space_id = H5Screate(H5S_SCALAR);
303 hdf5_handle type_id = H5Tcopy(H5T_C_S1);
304 H5Tset_size(type_id, value.empty() ? 1 : value.length());
306
307 hdf5_handle attr_id = H5Acreate2(obj_id, name.c_str(), type_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
308 if (attr_id < 0) {
309 TH_IO_ERROR("io::write_attribute", "attribute_id", IoError::WriteError);
310 return;
311 }
312
313 if (H5Awrite(attr_id, type_id, value.c_str()) < 0) {
314 TH_IO_ERROR("io::write_attribute", "attribute_id", IoError::WriteError);
315 }
316 }
317
318
319 // Write a C-style string attribute
320 inline void write_attribute(hid_t obj_id, const std::string& name, const char* str) {
321 write_attribute(obj_id, name, std::string(str));
322 }
323
324
325 // Recursively iterates over group members to build the hdf5_node tree structure
326 inline herr_t iter_callback(hid_t id, const char* name, const H5L_info_t* info, void* opdata) {
327
328 hdf5_node* parent = (hdf5_node*) opdata;
329 hdf5_node child;
330 child.name = name;
331
332 // Build full child path
333 if (parent->path == "/")
334 child.path = "/" + std::string(name);
335 else
336 child.path = parent->path + "/" + std::string(name);
337
338 // Open object by absolute child path from current location
339 hdf5_handle obj_id = H5Oopen(id, name, H5P_DEFAULT);
340 if (obj_id < 0) {
342 parent->children.emplace(child.name, std::move(child));
343 return 0;
344 }
345
347 if (obj_type == H5I_GROUP) {
348
350
351 // Read group attributes
352 load_attributes(obj_id, child.attributes);
353
354 // Recursion by opening the group and iterating inside it
355 hdf5_handle gid = H5Gopen2(id, name, H5P_DEFAULT);
356 if (gid >= 0)
357 H5Literate(gid, H5_INDEX_NAME, H5_ITER_INC, NULL, iter_callback, &child);
358
359 } else if (obj_type == H5I_DATASET) {
360
362
363 // Dataset shape
364 hdf5_handle space_id = H5Dget_space(obj_id);
366 if (ndims > 0) {
367 std::vector<hsize_t> dims (static_cast<size_t>(ndims));
369 child.dimensions = dims;
370 }
371
372 // Dataset attributes
373 load_attributes(obj_id, child.attributes);
374
375 } else {
376
378 load_attributes(obj_id, child.attributes);
379 }
380
381 parent->children.emplace(child.name, std::move(child));
382 return 0;
383 }
384
385
386 // Helper function to recursively build a formatted
387 // tree string representation of the HDF5 structure
388 inline void build_tree(
389 std::ostringstream& oss, const hdf5_node& node,
390 const std::string& prefix, bool is_last, bool is_root) {
391
392 // Current node line
393 if (is_root)
394 oss << (node.name.empty() ? "/" : node.name);
395 else
396 oss << prefix << (is_last ? "└── " : "├── ") << node.name;
397
398
399 // Print dataset
400 if (node.is_dataset()) {
401
402 oss << " [";
403 for (size_t i = 0; i < node.dimensions.size(); ++i) {
404 oss << node.dimensions[i];
405 if (i + 1 < node.dimensions.size())
406 oss << ", ";
407 }
408 oss << "]";
409 }
410
411
412 // Show attribute count
413 if (!node.attributes.empty()) {
414 oss << " (@" << node.attributes.size() << " attrs)";
415 }
416 oss << "\n";
417
418
419 if (node.children.empty())
420 return;
421
422 // Print group children recursively
423 size_t i = 0;
424 const std::string child_prefix = is_root ? "" : (prefix + (is_last ? " " : "│ "));
425 for (auto& pair : node.children) {
426
427 const bool is_last_child = (node.children.size() == i + 1);
428 build_tree(
429 oss,
430 pair.second,
433 false
434 );
435
436 i++;
437 }
438 }
439 }
440
441
442 // Output formatting
443
448 inline std::string to_string(const hdf5_node& node) {
449 std::ostringstream oss;
450 _internal::build_tree(oss, node, "", true, true);
451 return oss.str();
452 }
453
454
460 inline std::ostream& operator<<(std::ostream& os, const hdf5_node& node) {
461 return os << to_string(node);
462 }
463
464
465 // Public API using handles, for continued operations on an open file or group
466
472 inline hdf5_handle hdf5_open(const std::string& filename, bool write = false) {
473
474 _internal::suppress_errors();
476
477 // Open the file with write permissions,
478 // creating it if it doesn't exist.
479 if (write) {
480
481 file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
482
483 if (file_id < 0) {
484
486
487 if (file_id < 0) {
488 TH_IO_ERROR("io::hdf5_open", filename, IoError::WriteError);
489 return H5I_INVALID_HID;
490 }
491 }
492
493 } else {
494
495 // Open with read-only access.
496 file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
497
498 if (file_id < 0) {
499 TH_IO_ERROR("io::hdf5_open", filename, IoError::FileNotFound);
500 return H5I_INVALID_HID;
501 }
502 }
503
504 return hdf5_handle(file_id);
505 }
506
507
512 inline bool hdf5_is_valid(const hdf5_handle& handle) {
513 return H5Iis_valid(handle.id);
514 }
515
516
521 inline hdf5_node hdf5_load(const hdf5_handle& id) {
522
523 _internal::suppress_errors();
524
526 root.name = "/";
527 root.path = "/";
529 root.dimensions.clear();
530 root.attributes.clear();
531 root.children.clear();
532
533 _internal::load_attributes(id, root.attributes);
534 H5Literate(id, H5_INDEX_NAME, H5_ITER_INC, NULL, _internal::iter_callback, &root);
535
536 return root;
537 }
538
539
544 inline void hdf5_create_group(const hdf5_handle& id, const std::string& path) {
545
546 _internal::suppress_errors();
547
548 // Already exists, do nothing
549 if (H5Lexists(id, path.c_str(), H5P_DEFAULT) > 0)
550 return;
551
552 hid_t gid = H5Gcreate2(id, path.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
553 if (gid < 0) {
554 TH_IO_ERROR("io::hdf5_create_group", path, IoError::WriteError);
555 return;
556 }
557
559 }
560
561
566 inline void hdf5_delete_group(const hdf5_handle& id, const std::string& path) {
567
568 _internal::suppress_errors();
569
570 // Do nothing if it doesn't exist
571 if (H5Lexists(id, path.c_str(), H5P_DEFAULT) <= 0)
572 return;
573
574 if (H5Ldelete(id, path.c_str(), H5P_DEFAULT) < 0) {
575 TH_IO_ERROR("io::hdf5_delete_group", path, IoError::WriteError);
576 }
577 }
578
579
580 // Metadata handling
581
589 template<typename Type>
590 inline Type hdf5_read_attribute(const hdf5_handle& id, const std::string& path, const std::string& attr_name) {
591
592 _internal::suppress_errors();
593
594 hid_t obj_id = H5Oopen(id, path.c_str(), H5P_DEFAULT);
595 if (obj_id < 0) {
596 TH_IO_ERROR("io::read_attribute", path, IoError::FileNotFound);
597 return Type();
598 }
599
602 if (attr_id < 0) {
603 TH_IO_ERROR("io::read_attribute", path + "@" + attr_name, IoError::FileNotFound);
604 return Type();
605 }
607
608 Type value;
609 _internal::read_attribute(attr_id, value);
610 return value;
611 }
612
613
619 inline void hdf5_delete_attribute(const hdf5_handle& id, const std::string& path, const std::string& attr_name) {
620
621 _internal::suppress_errors();
622
623 hid_t obj_id = H5Oopen(id, path.c_str(), H5P_DEFAULT);
624 if (obj_id < 0) {
625 TH_IO_ERROR("io::delete_attribute", path, IoError::FileNotFound);
626 return;
627 }
628
630
631 if (H5Aexists(obj_id, attr_name.c_str()) > 0) {
632 if (H5Adelete(obj_id, attr_name.c_str()) < 0) {
633 TH_IO_ERROR("io::delete_attribute", path + "@" + attr_name, IoError::WriteError);
634 }
635 }
636 }
637
638
646 template<typename Type>
647 inline void hdf5_write_attribute(const hdf5_handle& id, const std::string& path, const std::string& attr_name, const Type& value) {
648
649 _internal::suppress_errors();
650 hid_t obj_id = H5Oopen(id, path.c_str(), H5P_DEFAULT);
651 if (obj_id < 0) {
652 TH_IO_ERROR("io::write_attribute", path, IoError::FileNotFound);
653 return;
654 }
655
657 if (H5Aexists(obj_id, attr_name.c_str()) > 0)
658 H5Adelete(obj_id, attr_name.c_str());
659
660 _internal::write_attribute(obj_id, attr_name, value);
661 }
662
663
664 // Dataset IO for vectors and matrices
665
666
673 template<typename Vector = vec<real>>
674 inline Vector& hdf5_read_vec(const hdf5_handle& id, const std::string& path, Vector& v) {
675
676 using Type = vector_element_t<Vector>;
677
678 _internal::suppress_errors();
679 hid_t data_id = H5Dopen2(id, path.c_str(), H5P_DEFAULT);
680 if (data_id < 0) {
681 TH_IO_ERROR("io::hdf5_read_vec", path, IoError::FileNotFound);
682 return algebra::vec_error(v);
683 }
685
687
688 // Dataset must be 1D to read into a vector
690 TH_IO_ERROR("io::hdf5_read_vec", path, IoError::FormatError);
691 return algebra::vec_error(v);
692 }
693
694 hsize_t dims[1];
696
697 v.resize(dims[0], nan());
698 if (v.size() != dims[0]) {
699 TH_IO_ERROR("io::hdf5_read_vec", path, IoError::FormatError);
700 return algebra::vec_error(v);
701 }
702
703 if (H5Dread(data_id, _internal::hdf5_type<Type>(), H5S_ALL, H5S_ALL, H5P_DEFAULT, v.data()) < 0) {
704 TH_IO_ERROR("io::hdf5_read_vec", path, IoError::ReadError);
705 return algebra::vec_error(v);
706 }
707
708 return v;
709 }
710
711
718 template<typename Vector = vec<real>>
719 inline Vector hdf5_read_vec(const hdf5_handle& id, const std::string& path) {
720 Vector v;
721 return hdf5_read_vec(id, path, v);
722 }
723
724
731 template<typename Vector>
732 inline void hdf5_write_vec(const hdf5_handle& id, const std::string& path, const Vector& v) {
733
734 using Type = vector_element_t<Vector>;
735 _internal::remove_link(id, path);
736
737 hsize_t dims[1] = { (hsize_t) v.size() };
739
740 hid_t data_id = H5Dcreate2(id, path.c_str(), _internal::hdf5_type<Type>(), h_space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
741 if (data_id < 0) {
742 TH_IO_ERROR("io::hdf5_write_vec", path, IoError::WriteError);
743 return;
744 }
746
747 if (H5Dwrite(data_id, _internal::hdf5_type<Type>(), H5S_ALL, H5S_ALL, H5P_DEFAULT, v.data()) < 0) {
748 TH_IO_ERROR("io::hdf5_write_vec", path, IoError::WriteError);
749 }
750 }
751
752
757 inline void hdf5_delete_dataset(const hdf5_handle& id, const std::string& path) {
758
759 _internal::suppress_errors();
760
761 if (H5Lexists(id, path.c_str(), H5P_DEFAULT) > 0) {
762 if (H5Ldelete(id, path.c_str(), H5P_DEFAULT) < 0) {
763 TH_IO_ERROR("io::hdf5_delete_dataset", path, IoError::WriteError);
764 }
765 }
766 }
767
768
775 template<typename Matrix = mat<real>>
776 inline Matrix hdf5_read_mat(const hdf5_handle& id, const std::string& path, Matrix& m) {
777
778 using Type = matrix_element_t<Matrix>;
779 _internal::suppress_errors();
780
781 hid_t data_id = H5Dopen2(id, path.c_str(), H5P_DEFAULT);
782 if (data_id < 0) {
783 TH_IO_ERROR("io::hdf5_read_mat", path, IoError::FileNotFound);
784 return algebra::mat_error(m);
785 }
787
790 TH_IO_ERROR("io::hdf5_read_mat", path, IoError::FormatError);
791 return algebra::mat_error(m);
792 }
793
794 hsize_t dims[2];
796
797 m.resize(dims[0], dims[1]);
798 if (m.rows() != dims[0] || m.cols() != dims[1]) {
799 TH_IO_ERROR("io::hdf5_read_mat", path, IoError::FormatError);
800 return algebra::mat_error(m);
801 }
802
803 if (H5Dread(data_id, _internal::hdf5_type<Type>(), H5S_ALL, H5S_ALL, H5P_DEFAULT, m.data()) < 0) {
804 TH_IO_ERROR("io::hdf5_read_mat", path, IoError::ReadError);
805 return algebra::mat_error(m);
806 }
807
808 return m;
809 }
810
811
818 template<typename Matrix = mat<real>>
819 inline Matrix hdf5_read_mat(const hdf5_handle& id, const std::string& path) {
820 Matrix m;
821 return hdf5_read_mat(id, path, m);
822 }
823
824
831 template<typename Matrix>
832 inline void hdf5_write_mat(const hdf5_handle& id, const std::string& path, const Matrix& m) {
833
834 using Type = matrix_element_t<Matrix>;
835 _internal::remove_link(id, path);
836
837 hsize_t dims[2] = { hsize_t(m.rows()), hsize_t(m.cols()) };
839
840 hid_t data_id = H5Dcreate2(id, path.c_str(), _internal::hdf5_type<Type>(), h_space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
841 if (data_id < 0) {
842 TH_IO_ERROR("io::hdf5_write_mat", "dataset_path", IoError::FormatError);
843 return;
844 }
845
847 if (H5Dwrite(data_id, _internal::hdf5_type<Type>(), H5S_ALL, H5S_ALL, H5P_DEFAULT, m.data()) < 0) {
848 TH_IO_ERROR("io::hdf5_write_mat", "dataset_path", IoError::WriteError);
849 }
850 }
851
852
855 class hdf5_file {
856 private:
857
859 std::string m_filename;
860
862 hdf5_handle m_file_id;
863
865 hdf5_node m_root;
866
867 public:
868
873 explicit hdf5_file(const std::string& filename, bool write = false) : m_filename(filename) {
874 m_file_id = hdf5_open(m_filename, write);
875
876 if (hdf5_is_valid(m_file_id))
877 refresh();
878 }
879
880
882 void refresh() {
883
884 // Always rebuild from scratch
885 m_root = hdf5_node{};
886 m_root.name = "/";
887 m_root.path = "/";
888 m_root.type = HDF5NodeType::GROUP;
889 m_root.dimensions.clear();
890 m_root.attributes.clear();
891 m_root.children.clear();
892
893 // Rebuild root from open file handle
894 m_root = hdf5_load(m_file_id);
895
896 // Keep root name as filename
897 m_root.name = m_filename;
898 }
899
900
902 void close() {
903
904 H5Fclose(m_file_id);
905 m_file_id = H5I_INVALID_HID;
906
907 // Clear cached structure
908 m_root = hdf5_node();
909 }
910
911
913 const std::string& filename() const {
914 return m_filename;
915 }
916
917
920 const hdf5_node& root() const {
921 return m_root;
922 }
923
924
927 hid_t id() const {
928 return m_file_id;
929 }
930
931
934 hdf5_node& operator[](const std::string& child_name) {
935 return m_root[child_name];
936 }
937
938
941 const hdf5_node& operator[](const std::string& child_name) const {
942 return m_root[child_name];
943 }
944
945
948 inline void create_group(const std::string& path) {
949 hdf5_create_group(m_file_id, path);
950 }
951
952
956 inline void create_group(const hdf5_node& parent, const std::string& child_name) {
957
958 const std::string path = (parent.path == "/")
959 ? ("/" + child_name)
960 : (parent.path + "/" + child_name);
961
962 hdf5_create_group(m_file_id, path);
963 }
964
965
968 inline void delete_group(const std::string& path) {
969 hdf5_delete_group(m_file_id, path);
970 }
971
972
975 inline void delete_group(const hdf5_node& node) {
976 hdf5_delete_group(m_file_id, node.path);
977 }
978
979
980 // Vector operations
981
988 template<typename Vector = vec<real>>
989 Vector read_vec(const std::string& path) const {
990 return hdf5_read_vec<Vector>(m_file_id, path);
991 }
992
993
1000 template<typename Vector = vec<real>>
1002 return hdf5_read_vec<Vector>(m_file_id, node.path);
1003 }
1004
1005
1011 template<typename Vector>
1012 void write_vec(const std::string& path, const Vector& v) {
1013 hdf5_write_vec(m_file_id, path, v);
1014 }
1015
1021 template<typename Vector>
1022 void write_vec(const hdf5_node& node, const Vector& v) {
1023 hdf5_write_vec(m_file_id, node.path, v);
1024 }
1025
1026
1027 // Matrix operations
1028
1034 template<typename Matrix = mat<real>>
1035 Matrix read_mat(const std::string& path) const {
1036 return hdf5_read_mat<Matrix>(m_file_id, path);
1037 }
1038
1039
1045 template<typename Matrix = mat<real>>
1047 return hdf5_read_mat<Matrix>(m_file_id, node.path);
1048 }
1049
1050
1056 template<typename Matrix>
1057 void write_mat(const std::string& path, const Matrix& m) {
1058 hdf5_write_mat(m_file_id, path, m);
1059 }
1060
1061
1067 template<typename Matrix>
1068 void write_mat(const hdf5_node& node, const Matrix& m) {
1069 hdf5_write_mat(m_file_id, node.path, m);
1070 }
1071
1072
1076 void delete_dataset(const std::string& path) {
1077 hdf5_delete_dataset(m_file_id, path);
1078 }
1079
1080
1085 hdf5_delete_dataset(m_file_id, node.path);
1086 }
1087
1088
1089 // Metadata operations
1090
1097 template<typename Type>
1098 Type read_attribute(const std::string& path, const std::string& attr_name) const {
1099 return hdf5_read_attribute<Type>(m_file_id, path, attr_name);
1100 }
1101
1102
1109 template<typename Type>
1110 Type read_attribute(const hdf5_node& node, const std::string& attr_name) const {
1111 return hdf5_read_attribute<Type>(m_file_id, node.path, attr_name);
1112 }
1113
1114
1121 template<typename Type>
1122 void write_attribute(const std::string& path, const std::string& attr_name, const Type& value) {
1123 hdf5_write_attribute<Type>(m_file_id, path, attr_name, value);
1124 }
1125
1126
1133 template<typename Type>
1134 void write_attribute(const hdf5_node& node, const std::string& attr_name, const Type& value) {
1135 hdf5_write_attribute<Type>(m_file_id, node.path, attr_name, value);
1136 }
1137
1138
1143 void delete_attribute(const std::string& path, const std::string& attr_name) {
1144 hdf5_delete_attribute(m_file_id, path, attr_name);
1145 }
1146
1147
1152 void delete_attribute(const hdf5_node& node, const std::string& attr_name) {
1153 hdf5_delete_attribute(m_file_id, node.path, attr_name);
1154 }
1155
1156
1161 inline std::string to_string() const {
1162 return io::to_string(m_root);
1163 }
1164
1165
1171 inline friend std::ostream& operator<<(std::ostream& os, const hdf5_file& file) {
1172 return os << file.to_string();
1173 }
1174 };
1175
1176}}
1177
1178#endif
High-level interface for managing an HDF5 file, its structure, and operations.
Definition hdf5.h:855
hid_t id() const
Get the raw ID of the HDF5 file handle for direct API access.
Definition hdf5.h:927
Matrix read_mat(const std::string &path) const
Read a 2D dataset array into a matrix from the given path.
Definition hdf5.h:1035
void write_vec(const std::string &path, const Vector &v)
Writes a 1D vector to an HDF5 dataset at the given path, overwriting if it exists.
Definition hdf5.h:1012
Type read_attribute(const hdf5_node &node, const std::string &attr_name) const
Read metadata (attribute) attached to a specific node by reference.
Definition hdf5.h:1110
void write_mat(const hdf5_node &node, const Matrix &m)
Write a 2D matrix to an HDF5 dataset at the given node, overwriting if it exists.
Definition hdf5.h:1068
void delete_attribute(const std::string &path, const std::string &attr_name)
Delete an attribute attached to a specific node by path, if it exists.
Definition hdf5.h:1143
void delete_group(const hdf5_node &node)
Delete a group referenced by a node.
Definition hdf5.h:975
const hdf5_node & root() const
Get the base node containing the entire loaded file structure.
Definition hdf5.h:920
void delete_dataset(const std::string &path)
Delete a dataset at the given path if it exists.
Definition hdf5.h:1076
void create_group(const std::string &path)
Create a new group inside the file.
Definition hdf5.h:948
void create_group(const hdf5_node &parent, const std::string &child_name)
Create a new group using a parent node and a child name.
Definition hdf5.h:956
void write_attribute(const std::string &path, const std::string &attr_name, const Type &value)
Write or overwrite metadata (attribute) attached to a specific node by path.
Definition hdf5.h:1122
void write_attribute(const hdf5_node &node, const std::string &attr_name, const Type &value)
Write or overwrite metadata (attribute) attached to a specific node by reference.
Definition hdf5.h:1134
void write_mat(const std::string &path, const Matrix &m)
Write a 2D matrix to an HDF5 dataset at the given path, overwriting if it exists.
Definition hdf5.h:1057
void delete_dataset(const hdf5_node &node)
Delete a dataset at the given node if it exists.
Definition hdf5.h:1084
void delete_group(const std::string &path)
Delete a group inside the file.
Definition hdf5.h:968
void close()
Close the HDF5 file immediately.
Definition hdf5.h:902
Vector read_vec(const hdf5_node &node) const
Loads a 1D dataset array into a vector from the given node inside the HDF5 file.
Definition hdf5.h:1001
hdf5_file(const std::string &filename, bool write=false)
Open the file persistently.
Definition hdf5.h:873
void write_vec(const hdf5_node &node, const Vector &v)
Writes a 1D vector to the HDF5 dataset represented by the given node, overwriting if it exists.
Definition hdf5.h:1022
Matrix read_mat(const hdf5_node &node) const
Read a 2D dataset array into a matrix from the given node.
Definition hdf5.h:1046
hdf5_node & operator[](const std::string &child_name)
Access children of the root node by reference using dictionary-like syntax.
Definition hdf5.h:934
void refresh()
Refresh the cached tree structure from disk.
Definition hdf5.h:882
Type read_attribute(const std::string &path, const std::string &attr_name) const
Read metadata (attribute) attached to a specific node by path.
Definition hdf5.h:1098
const std::string & filename() const
Get the name of the file.
Definition hdf5.h:913
Vector read_vec(const std::string &path) const
Loads a 1D dataset array into a vector from the given path inside the HDF5 file.
Definition hdf5.h:989
std::string to_string() const
Converts an entire HDF5 file structure into a formatted tree string.
Definition hdf5.h:1161
friend std::ostream & operator<<(std::ostream &os, const hdf5_file &file)
Print the HDF5 file structure to a stream in a formatted tree representation.
Definition hdf5.h:1171
const hdf5_node & operator[](const std::string &child_name) const
Access children of the root node by const reference using dictionary-like syntax.
Definition hdf5.h:941
void delete_attribute(const hdf5_node &node, const std::string &attr_name)
Delete an attribute attached to a specific node by path, if it exists.
Definition hdf5.h:1152
Error handling for IO operations.
Matrix & mat_error(Matrix &m)
Overwrite the given matrix with the error matrix with NaN values on the diagonal and zeroes everywher...
Definition algebra.h:40
Vector & vec_error(Vector &v)
Overwrite the given vector with the error vector with NaN values.
Definition algebra.h:58
hdf5_node hdf5_load(const hdf5_handle &id)
Recursively loads the structure of an active HDF5 group or file.
Definition hdf5.h:521
void hdf5_create_group(const hdf5_handle &id, const std::string &path)
Create a new group at the given path under an already open HDF5 location.
Definition hdf5.h:544
void hdf5_delete_dataset(const hdf5_handle &id, const std::string &path)
Deletes a dataset at the given path if it exists.
Definition hdf5.h:757
void hdf5_delete_group(const hdf5_handle &id, const std::string &path)
Delete a group (link) at the given path under an already open HDF5 location.
Definition hdf5.h:566
std::ostream & operator<<(std::ostream &os, const hdf5_node &node)
Prints the HDF5 file tree to a stream.
Definition hdf5.h:460
bool hdf5_is_valid(const hdf5_handle &handle)
Check whether a given HDF5 handle is valid.
Definition hdf5.h:512
Matrix hdf5_read_mat(const hdf5_handle &id, const std::string &path, Matrix &m)
Loads a 2D dataset array into a matrix.
Definition hdf5.h:776
@ FileNotFound
File or directory not found.
@ WriteError
Error occurred while writing to the file or stream.
@ FormatError
The file format is invalid or the data is corrupted.
@ ReadError
Error occurred while reading from the file or stream.
Type hdf5_read_attribute(const hdf5_handle &id, const std::string &path, const std::string &attr_name)
Reads an attribute attached to a specific node.
Definition hdf5.h:590
void hdf5_write_vec(const hdf5_handle &id, const std::string &path, const Vector &v)
Writes a 1D vector to an HDF5 dataset, overwriting if it exists.
Definition hdf5.h:732
void hdf5_delete_attribute(const hdf5_handle &id, const std::string &path, const std::string &attr_name)
Deletes an attribute attached to a specific node, if it exists.
Definition hdf5.h:619
Vector & hdf5_read_vec(const hdf5_handle &id, const std::string &path, Vector &v)
Loads a 1D dataset array into a vector.
Definition hdf5.h:674
HDF5NodeType
Type of node inside an HDF5 file.
Definition hdf5.h:34
@ DATASET
A node containing multi-dimensional array data.
@ UNKNOWN
An unsupported node type.
@ GROUP
A structural grouping containing other groups or datasets.
void hdf5_write_mat(const hdf5_handle &id, const std::string &path, const Matrix &m)
Writes a 2D matrix to an HDF5 dataset, overwriting if it exists.
Definition hdf5.h:832
void hdf5_write_attribute(const hdf5_handle &id, const std::string &path, const std::string &attr_name, const Type &value)
Writes or overwrites an attribute attached to a specific node.
Definition hdf5.h:647
hdf5_handle hdf5_open(const std::string &filename, bool write=false)
Open an HDF5 file with the given filename, returning a file handle.
Definition hdf5.h:472
Main namespace of the library which contains all functions and objects.
Definition algebra.h:27
TH_CONSTEXPR Type make_error()
Create a number representing an error state, constructed from a NaN value.
Definition real_analysis.h:1322
TH_CONSTEXPR real nan()
Return a quiet NaN number in floating point representation.
Definition error.h:78
std::string to_string(MathError err)
Convert a MathError class enum to a string description.
Definition error.h:72
real root(real x, int n)
Compute the n-th root of x.
Definition real_analysis.h:812
RAII wrapper for managing HDF5 C-style handles, allowing direct API usage.
Definition hdf5.h:104
hid_t id
Underlying ID obtained by opening a file or group.
Definition hdf5.h:108
hdf5_handle(const hdf5_handle &)=delete
Prevent copying.
hdf5_handle(hdf5_handle &&other) noexcept
Move constructor.
Definition hdf5.h:140
hdf5_handle & operator=(hdf5_handle &&other) noexcept
Move assignment.
Definition hdf5.h:146
~hdf5_handle()
Safely decrements reference count and closes the handle if valid.
Definition hdf5.h:118
hdf5_handle(hid_t id=H5I_INVALID_HID)
Initialize the handle with a given HDF5 ID, for example obtained by opening a file or group,...
Definition hdf5.h:114
Represents a single node (group or dataset) in the HDF5 file hierarchy.
Definition hdf5.h:49
std::unordered_map< std::string, hdf5_node > children
For groups, the child nodes indexed by their local name.
Definition hdf5.h:68
std::vector< std::string > attributes
List of metadata attribute names attached to the node.
Definition hdf5.h:65
bool is_group() const noexcept
Check whether the node is a group.
Definition hdf5.h:72
std::vector< size_t > dimensions
For datasets, the dimensions of the array.
Definition hdf5.h:62
bool is_dataset() const noexcept
Check whether the node is a dataset.
Definition hdf5.h:78
HDF5NodeType type
The type of the node.
Definition hdf5.h:59
const hdf5_node & operator[](const std::string &child_name) const
Read-only dictionary-like access to child nodes by name.
Definition hdf5.h:96
std::string name
The local name of the node (e.g. "my_dataset")
Definition hdf5.h:52
hdf5_node & operator[](const std::string &child_name)
Dictionary-like access to child nodes by name.
Definition hdf5.h:87
std::string path
The absolute internal path to the node (e.g.
Definition hdf5.h:56