Dune-Fufem 2.11-git
Loading...
Searching...
No Matches
sequenceio.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright © DUNE-FUFEM Project contributors, see file AUTHORS.md
2// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
3
4#ifndef DUNE_FUFEM_HDF5_SEQUENCEIO_HH
5#define DUNE_FUFEM_HDF5_SEQUENCEIO_HH
6
7#include <array>
8#include <functional>
9#include <numeric>
10#include <vector>
11
12#if __has_include(<hdf5.h>)
13
14#include <hdf5.h>
15#include <hdf5_hl.h>
16
18#include <dune/istl/bvector.hh>
19#include <dune/istl/matrix.hh>
20
21#include "file.hh"
22#include "frombuffer.hh"
23#include "tobuffer.hh"
24#include "typetraits.hh"
25
26namespace HDF5 {
27template <int spatialDimensions, typename ctype = double, typename T = hsize_t>
28class SequenceIO {
29 int static const dimensions = 1 + spatialDimensions;
30
31public:
32 template <typename... Args>
33 SequenceIO(Grouplike &file, std::string datasetname, Args... args)
34 : file_(file), capacity_{{T(args)...}} {
35 static_assert(sizeof...(args) == spatialDimensions,
36 "wrong number of arguments");
37
38 if (file_.hasDataset(datasetname)) {
39 dset_ = file_.openDataset(datasetname);
40 checkDatatype();
41 checkDimensions();
42 checkChunkSize();
43 } else {
44 if (file_.isReadOnly())
45 DUNE_THROW(Dune::Exception, "Dataset not found: " << datasetname);
46
47 auto const initial_dims = maxExtent(0);
48 auto const max_dims = maxExtent(H5S_UNLIMITED);
49 hid_t file_space =
50 H5Screate_simple(dimensions, initial_dims.data(), max_dims.data());
51
52 hid_t plist = H5Pcreate(H5P_DATASET_CREATE);
53 H5Pset_layout(plist, H5D_CHUNKED);
54 auto const chunk_dims = maxExtent(1);
55 H5Pset_chunk(plist, dimensions, chunk_dims.data());
56
57 dset_ = file_.createDataset(datasetname, file_space, plist,
58 TypeTraits<ctype>::getType());
59
60 H5Pclose(plist);
61 H5Sclose(file_space);
62 }
63 }
64
65 ~SequenceIO() { H5Dclose(dset_); }
66
67 void add(size_t timeStep, std::vector<ctype> const &buffer) {
68 if (buffer.size() != entrySize())
69 DUNE_THROW(Dune::Exception, "Buffer size incorrect");
70
71 auto dims = getExtent();
72 if (timeStep >= dims[0]) {
73 dims[0] = timeStep + 1;
74 H5Dset_extent(dset_, dims.data());
75 }
76 auto const start = minExtent(timeStep);
77 H5DOwrite_chunk(dset_, H5P_DEFAULT, 0, start.data(),
78 entrySize() * sizeof(ctype), buffer.data());
79 }
80
81#if H5_VERSION_GE(1, 10, 0)
82 void append(std::vector<ctype> const &buffer, size_t skip = 0) {
83 if (buffer.size() != entrySize())
84 DUNE_THROW(Dune::Exception, "Buffer size incorrect");
85
86 H5DOappend(dset_, H5P_DEFAULT, skip, 1, TypeTraits<ctype>::getType(),
87 buffer.data());
88 }
89#endif
90
91 void read(size_t timeStep, std::vector<ctype> &buffer,
93 buffer.resize(entrySize());
94
95 hid_t file_space = H5Dget_space(dset_);
96
98 H5Sget_simple_extent_dims(file_space, dims.data(), NULL);
99 if (timeStep >= dims[0])
100 DUNE_THROW(Dune::Exception, "Tried to read past final entry");
101
102 auto const start = minExtent(timeStep);
103 auto const count = maxExtent(1);
104 H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start.data(), NULL,
105 count.data(), NULL);
106
107 hid_t mem_space = H5Screate_simple(dimensions, count.data(), NULL);
108 H5Dread(dset_, TypeTraits<ctype>::getType(), mem_space, file_space,
109 H5P_DEFAULT, buffer.data());
110 H5Sclose(mem_space);
111
112 H5Sclose(file_space);
113 capacity = capacity_;
114 }
115
116private:
117 std::array<T, dimensions> getExtent() const {
118 hid_t file_space = H5Dget_space(dset_);
120 H5Sget_simple_extent_dims(file_space, dims.data(), NULL);
121 H5Sclose(file_space);
122 return dims;
123 }
124
125 size_t entrySize() {
126 return std::accumulate(capacity_.begin(), capacity_.end(), 1,
128 }
129
130 void checkChunkSize() {
131 hid_t plist = H5Dget_create_plist(dset_);
132 H5D_layout_t layout = H5Pget_layout(plist);
133 if (layout != H5D_CHUNKED)
134 DUNE_THROW(Dune::Exception, "Layout not chunked");
135
136 std::array<T, dimensions> chunk_dims;
137 int const rank = H5Pget_chunk(plist, dimensions, chunk_dims.data());
138 if (rank != dimensions)
139 DUNE_THROW(Dune::Exception, "Unexpected chunk rank");
140 if (!std::equal(capacity_.begin(), capacity_.end(), chunk_dims.begin() + 1))
141 DUNE_THROW(Dune::Exception, "Unexpected chunk dimensions");
142 if (chunk_dims[0] != 1)
143 DUNE_THROW(Dune::Exception, "Unexpected chunk length");
144
145 H5Pclose(plist);
146 }
147
148 void checkDimensions() {
149 hid_t file_space = H5Dget_space(dset_);
151 int const rank = H5Sget_simple_extent_dims(file_space, dims.data(), NULL);
152
153 if (rank != dimensions)
154 DUNE_THROW(Dune::Exception, "Unexpected dataset rank");
155 if (!std::equal(capacity_.begin(), capacity_.end(), dims.begin() + 1))
156 DUNE_THROW(Dune::Exception, "Unexpected dataset dimensions");
157
158 H5Sclose(file_space);
159 }
160
161 void checkDatatype() {
162 if (!H5Tequal(H5Dget_type(dset_), TypeTraits<ctype>::getType()))
163 DUNE_THROW(Dune::Exception, "Unexpected data type");
164 }
165
166 std::array<T, dimensions> minExtent(T timeSteps) {
168 ret[0] = timeSteps;
169 std::fill(ret.begin() + 1, ret.end(), 0);
170 return ret;
171 }
172
173 std::array<T, dimensions> maxExtent(T timeSteps) {
175 ret[0] = timeSteps;
176 std::copy(capacity_.begin(), capacity_.end(), ret.begin() + 1);
177 return ret;
178 }
179
180 Grouplike &file_;
181 std::array<T, spatialDimensions> const capacity_;
182
183 hid_t dset_;
184};
185
186template <int spatialDimensions, typename ctype, typename T, class Data>
187void addEntry(SequenceIO<spatialDimensions, ctype, T> &writer, size_t timeStep,
188 Data const &data) {
189 std::vector<ctype> buffer;
190 toBuffer(data, buffer);
191 writer.add(timeStep, buffer);
192}
193
194#if H5_VERSION_GE(1, 10, 0)
195template <int spatialDimensions, typename ctype, typename T, class Data>
196void appendEntry(SequenceIO<spatialDimensions, ctype, T> &writer,
197 Data const &data) {
198 std::vector<ctype> buffer;
199 toBuffer(data, buffer);
200 writer.append(buffer);
201}
202#endif
203
204template <int spatialDimensions, typename ctype, typename T, class Data>
205void readEntry(SequenceIO<spatialDimensions, ctype, T> &reader, size_t timeStep,
206 Data &data) {
207 std::vector<ctype> buffer;
209 reader.read(timeStep, buffer, dimensions);
210 fromBuffer(buffer, dimensions, data);
211}
212}
213
214#else
215 #warning Including the hdf5/sequenceio.hh but hdf5.h is missing.
216#endif // __has_include(<hdf5.h>)
217
218#endif
void add(const Vertex &vertex)
void fromBuffer(std::vector< ctype > const &buffer, std::array< T, 3 > dimensions, Dune::Matrix< Dune::FieldVector< ctype, k > > &data)
Definition frombuffer.hh:14
void toBuffer(Dune::Matrix< Dune::FieldVector< ctype, k > > const &data, std::vector< ctype > &buffer)
Definition tobuffer.hh:12
#define DUNE_THROW(E,...)
void start()
Start embedded python interpreter.
Definition common.hh:130
T accumulate(T... args)
T begin(T... args)
T copy(T... args)
T count(T... args)
T data(T... args)
T end(T... args)
T equal(T... args)
T fill(T... args)
T resize(T... args)
T size(T... args)