TRIQS/triqs_modest 3.3.0
Brillouin zone summation
Loading...
Searching...
No Matches
h5_proxy.hpp
Go to the documentation of this file.
1// Copyright (c) 2025--present, The Simons Foundation
2// This file is part of TRIQS/modest and is licensed under the terms of GPLv3 or later.
3// SPDX-License-Identifier: GPL-3.0-or-later
4// See LICENSE in the root of this distribution for details.
5
6#pragma once
7#include <cassert>
8#include <ranges>
9#include <memory>
10#include <type_traits>
11#include <utility>
12#include <triqs/utility/generator.hpp>
13#include <h5/h5.hpp>
14
15// mv to cpp
16#include <fmt/core.h>
17// We need to move the IS function into the h5
18#include <hdf5.h>
19
20namespace h5 {
21
22 using dcomplex = std::complex<double>;
23
24 // It is a proxy to an h5::file, with the same interface as h5::file
25 // A proxy to an element of the h5 tree, i.e.
26 // its parent group and key string.
27 // It can be a dataset, a group: its kind is determined at runtime
28 class proxy {
29 group g;
30 std::string _key;
31 std::string g_path; // for error messages
32 char mode; // same as h5::file
33
34 proxy(group g, std::string const &key, std::string const &g_path, char mode) : g{std::move(g)}, _key{key}, g_path{g_path}, mode{mode} {}
35
36 public:
37 friend std::ostream &operator<<(std::ostream &out, proxy const &p) {
38 return out << fmt::format("h5 proxy {} : path = {}, key ={}. ", (p.is_group() ? "[Group]" : "Dataset"), p.g_path, p._key);
39 }
40
41 // I would prefer to construct from file, but I can not access mode from file.
42 // Fix it ?
43 // Same constructor as h5::file
44 // Ideally, add operator [string] to h5::file --> proxy
45 // then we can write f = h5::file(...); auto root = f["/"];
46 proxy(std::string const &name, char mode) : g{file(name, mode)}, _key{"/"}, mode{mode} {}
47
48 // Do we need this accessor ?
49 //[[nodiscard]] std::string const &key() const { return _key; }
50
51 private: // do we need it public ??
52 // Full path (group + key)
53 [[nodiscard]] std::string path() const { return g_path + "/" + _key; }
54
55 public:
56 // ======================= group related functions ==========================
57
59 [[nodiscard]] bool is_group() const { return g.has_subgroup(_key); }
60
62 [[nodiscard]] bool has_group(const std::string &name) const { return g.has_subgroup(name); }
63
64 // Assert is_group() is true or throw
65 void assert_is_group() const {
66 if (not is_group()) {
67 std::cerr << fmt::format("{} is not a group", g_path) << std::endl;
68 throw std::runtime_error{fmt::format("{} is not a group", g_path)};
69 }
70 }
71
72 // Returns h5::group corresponding to the location.
73 // throws if it is not a group.
74 // In writing mode, create the group if necessary
75 operator group() const {
77 if ((mode == 'r') or (g.has_key(_key))) return g.open_group(_key);
78 return g.create_group(_key);
79 }
80
81 // ======================= The [] operator ==========================
82
83 // Creates a proxy on a element of this.
84 // Throws if this does not point to a group.
85 // If 'r' mode : check that the key actually exits.
86 //
87 proxy operator[](std::string const &key) const {
88 auto gg = group(*this);
89 if (!gg.has_key(key)) throw std::runtime_error{fmt::format("{} is not a key of {}", key, g_path)};
90 return {std::move(gg), key, path(), mode};
91 }
92
93 // ======================= READING from the proxy ==========================
94
95 // as<T>(g["a"]) read the dataset at the location pointed to by g["a"]
96 // as a T
97 template <typename T> [[nodiscard]] T as() const {
98 static_assert(not std::is_reference_v<T>); //
99 if constexpr (std::is_same_v<T, group>) // just in case, for generic code ? as<group>(X) is group(X)
100 return group(*this);
101 else
102 return ::h5::read<T>(g, _key); // :: full qualify just to be sure, read is quite common...
103 }
104
105 // Keep both ? It is UFC !
106 // as<T>(g["a"]) is equivalent to h5::read<T>(g, "a");
107 template <typename T> [[nodiscard]] friend T as(proxy const &x) { return x.as<T>(); }
108
109 //
110 template <typename T> friend bool is(proxy const &x) {
111 dataset ds = x.g.open_dataset(x._key);
112 datatype ty = H5Dget_type(ds);
113 return ty == h5::detail::hid_t_of<T>();
114 }
115
116 // x << g["a"] is equivalent to h5_read(g, "a", x);
117 //
118 template <typename T> friend void operator<<(T &&lhs, proxy const &x) { ::h5::read(x.g, x._key, lhs); }
119
120 // ======================= Writing from the proxy ==========================
121
122 // Writing
123 // g["a"] = X is equivalent to h5::write(g, "a", X);
124 // throws in 'r' mode
125 proxy &operator<<(auto &&x) {
126 if (mode == 'r') throw std::runtime_error{"Read only file. Can not write."};
127 ::h5::write(g, _key, x);
128 }
129
130 // Predefined cast operators
131 // Keep or not ? It is convenient for common case to say
132 // F(, ...long(g["A"]) , ...)
133 // as<T> is the default. Do not use nda objects here, to avoid dependencies.
134 // the explicit is crucial here, no implicit conversion
135 explicit operator int() const { return as<int>(); }
136 explicit operator long() const { return as<long>(); }
137 explicit operator double() const { return as<double>(); }
138 explicit operator dcomplex() const { return as<dcomplex>(); }
139
140 // ============== Iterator =============================
141 // iterating on *this yields proxy for all elements, dataset and groups
142 // impl note Need to keep the range or generator alive after begin call
143 // seems hard with ranges, the type is much simpler with a simple coroutine.
144 //
145 private:
146 generator<proxy> get_children() const {
147 for (auto key : group(*this).get_all_subgroup_dataset_names()) co_yield (*this)[key];
148 }
149 mutable std::shared_ptr<generator<proxy>> children; // generator can not be copy-constructed
150 // can make it unique_ptr and then redo the copy constructor ...
151
152 public:
153 // If a group, we iterate over all elements, dataset and subgroups
154 [[nodiscard]] auto begin() const {
156 if (not children) children = std::make_shared<generator<proxy>>(get_children());
157 return children->begin();
158 }
159 [[nodiscard]] auto end() const {
160 assert(children);
161 return children->end();
162 }
163
164 // ============== Other iterations =============================
165
166 private:
167 [[nodiscard]] auto _read_transform() const {
168 // need to capture a copy cf sort_keys later
169 return std::views::transform([self = *this](auto &&key) { return self[key]; });
170 }
171
172 public:
173 // FIXME should we make them free function
174 // for (auto gg : groups(g["a"]))
175 // for (auto gg : g["a"].groups())) ??
176 // If a group, iterate on subgroups only
177 [[nodiscard]] auto groups() const { return group(*this).get_all_subgroup_names() | _read_transform(); }
178
179 // If a group, iterate on datasets only
180 [[nodiscard]] auto datasets() const { return group(*this).get_all_dataset_names() | _read_transform(); }
181
182 // Returns the keys if a group
183 [[nodiscard]] auto keys() const { return group(*this).get_all_subgroup_dataset_names(); }
184
185 // for (auto gg : sort_keys(g["a"], p))
186 // iterates on the keys sorted by the predicate p
187 // Should we name it sorted_keys ?
188 friend auto sort_keys(proxy const &x, auto pred) {
189 auto y = group(x).get_all_subgroup_dataset_names();
190 std::ranges::sort(y, pred);
191 return std::move(y) | x._read_transform();
192 }
193 };
194
195 // ---------------------------------------------------
196 inline auto sort_keys_as_int(proxy const &x) {
197 return sort_keys(x, [](auto &&a, auto &&b) { return std::stoi(a) < std::stoi(b); });
198 }
199
200} // namespace h5
auto end() const
Definition h5_proxy.hpp:159
friend auto sort_keys(proxy const &x, auto pred)
Definition h5_proxy.hpp:188
friend T as(proxy const &x)
Definition h5_proxy.hpp:107
friend std::ostream & operator<<(std::ostream &out, proxy const &p)
Definition h5_proxy.hpp:37
proxy(std::string const &name, char mode)
Definition h5_proxy.hpp:46
proxy operator[](std::string const &key) const
Definition h5_proxy.hpp:87
proxy & operator<<(auto &&x)
Definition h5_proxy.hpp:125
void assert_is_group() const
Definition h5_proxy.hpp:65
auto begin() const
Definition h5_proxy.hpp:154
bool is_group() const
Does the proxy point to a subgroup ?
Definition h5_proxy.hpp:59
auto groups() const
Definition h5_proxy.hpp:177
bool has_group(const std::string &name) const
Does the proxy contain the subgroup name.
Definition h5_proxy.hpp:62
auto keys() const
Definition h5_proxy.hpp:183
friend void operator<<(T &&lhs, proxy const &x)
Definition h5_proxy.hpp:118
friend bool is(proxy const &x)
Definition h5_proxy.hpp:110
auto datasets() const
Definition h5_proxy.hpp:180
T as() const
Definition h5_proxy.hpp:97
Definition h5_proxy.cpp:7
std::complex< double > dcomplex
Definition h5_proxy.hpp:22
auto sort_keys_as_int(proxy const &x)
Definition h5_proxy.hpp:196