Vulcan
Aerospace Engineering Utilities Built on Janus
Loading...
Searching...
No Matches
HDF5Writer.hpp
Go to the documentation of this file.
1
8
9#pragma once
10
11#include <highfive/H5Easy.hpp>
12#include <highfive/H5File.hpp>
13#include <memory>
14#include <string>
15#include <vector>
16
17#include <vulcan/io/Frame.hpp>
19
20namespace vulcan::io {
21
57 public:
63 HDF5Writer(const std::string &filename, const TelemetrySchema &schema)
64 : impl_(std::make_unique<Impl>(filename, schema)) {}
65
66 ~HDF5Writer() = default;
67
68 // Non-copyable, movable
69 HDF5Writer(const HDF5Writer &) = delete;
70 HDF5Writer &operator=(const HDF5Writer &) = delete;
71 HDF5Writer(HDF5Writer &&) noexcept = default;
72 HDF5Writer &operator=(HDF5Writer &&) noexcept = default;
73
78 void write_frame(const Frame &frame) { impl_->write_frame(frame); }
79
84 void write_frames(const std::vector<Frame> &frames) {
85 for (const auto &frame : frames) {
86 impl_->write_frame(frame);
87 }
88 }
89
91 size_t frame_count() const { return impl_->frame_count(); }
92
94 void flush() { impl_->flush(); }
95
97 void close() { impl_->close(); }
98
99 private:
100 struct Impl {
101 HighFive::File file;
102 TelemetrySchema schema;
103 size_t frames_written = 0;
104 static constexpr size_t CHUNK_SIZE = 1000;
105
106 // Datasets
107 std::vector<HighFive::DataSet> signal_datasets;
108 HighFive::DataSet time_dataset;
109
110 Impl(const std::string &filename, const TelemetrySchema &sch)
111 : file(filename, HighFive::File::Truncate), schema(sch),
112 time_dataset(setup_file()) {}
113
114 HighFive::DataSet setup_file() {
115 // Create groups
116 file.createGroup("signals");
117 file.createGroup("metadata");
118
119 // Create time dataset (chunked, unlimited)
120 HighFive::DataSpace time_space({0},
121 {HighFive::DataSpace::UNLIMITED});
122 HighFive::DataSetCreateProps time_props;
123 time_props.add(HighFive::Chunking({CHUNK_SIZE}));
124 auto time_ds =
125 file.createDataSet<double>("time", time_space, time_props);
126
127 // Create signal datasets
128 for (const auto &sig : schema.signals()) {
129 HighFive::DataSpace space({0},
130 {HighFive::DataSpace::UNLIMITED});
131 HighFive::DataSetCreateProps props;
132 props.add(HighFive::Chunking({CHUNK_SIZE}));
133
134 std::string path = "signals/" + sig.name;
135
136 switch (sig.type) {
137 case SignalType::Double: {
138 auto ds = file.createDataSet<double>(path, space, props);
139 if (!sig.unit.empty()) {
140 ds.createAttribute<std::string>("unit", sig.unit);
141 }
142 if (!sig.semantic.empty()) {
143 ds.createAttribute<std::string>("semantic",
144 sig.semantic);
145 }
146 signal_datasets.push_back(std::move(ds));
147 break;
148 }
149 case SignalType::Int32: {
150 auto ds = file.createDataSet<int32_t>(path, space, props);
151 if (!sig.unit.empty()) {
152 ds.createAttribute<std::string>("unit", sig.unit);
153 }
154 if (!sig.semantic.empty()) {
155 ds.createAttribute<std::string>("semantic",
156 sig.semantic);
157 }
158 signal_datasets.push_back(std::move(ds));
159 break;
160 }
161 case SignalType::Int64: {
162 auto ds = file.createDataSet<int64_t>(path, space, props);
163 if (!sig.unit.empty()) {
164 ds.createAttribute<std::string>("unit", sig.unit);
165 }
166 if (!sig.semantic.empty()) {
167 ds.createAttribute<std::string>("semantic",
168 sig.semantic);
169 }
170 signal_datasets.push_back(std::move(ds));
171 break;
172 }
173 }
174 }
175
176 // Store schema JSON as metadata
177 auto metadata = file.getGroup("metadata");
178 metadata.createAttribute<std::string>("schema", schema.to_json());
179
180 // Store creation timestamp
181 auto now = std::time(nullptr);
182 char buf[32];
183 std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ",
184 std::gmtime(&now));
185 metadata.createAttribute<std::string>("created_at",
186 std::string(buf));
187
188 return time_ds;
189 }
190
191 void write_frame(const Frame &frame) {
192 // Extend and write time
193 time_dataset.resize({frames_written + 1});
194 time_dataset.select({frames_written}, {1}).write(frame.time());
195
196 // Write each signal
197 for (size_t i = 0; i < schema.signals().size(); ++i) {
198 const auto &sig = schema.signals()[i];
199 auto &ds = signal_datasets[i];
200
201 ds.resize({frames_written + 1});
202
203 switch (sig.type) {
204 case SignalType::Double: {
205 double val = frame.get_double(sig.name);
206 ds.select({frames_written}, {1}).write(val);
207 break;
208 }
209 case SignalType::Int32: {
210 int32_t val = frame.get_int32(sig.name);
211 ds.select({frames_written}, {1}).write(val);
212 break;
213 }
214 case SignalType::Int64: {
215 int64_t val = frame.get_int64(sig.name);
216 ds.select({frames_written}, {1}).write(val);
217 break;
218 }
219 }
220 }
221
222 ++frames_written;
223 }
224
225 size_t frame_count() const { return frames_written; }
226
227 void flush() { file.flush(); }
228
229 void close() {
230 flush();
231 // File will be closed when Impl is destroyed
232 }
233 };
234
235 std::unique_ptr<Impl> impl_;
236};
237
238} // namespace vulcan::io
Telemetry frame data container for Vulcan I/O.
Telemetry signal schema definition for Vulcan I/O.
Single timestep of telemetry data.
Definition Frame.hpp:39
void flush()
Flush buffered data to disk.
Definition HDF5Writer.hpp:94
HDF5Writer & operator=(const HDF5Writer &)=delete
HDF5Writer(HDF5Writer &&) noexcept=default
HDF5Writer(const HDF5Writer &)=delete
void write_frame(const Frame &frame)
Write a single frame.
Definition HDF5Writer.hpp:78
void close()
Close file (called automatically on destruction).
Definition HDF5Writer.hpp:97
size_t frame_count() const
Get number of frames written so far.
Definition HDF5Writer.hpp:91
HDF5Writer(const std::string &filename, const TelemetrySchema &schema)
Create HDF5 writer.
Definition HDF5Writer.hpp:63
void write_frames(const std::vector< Frame > &frames)
Write multiple frames.
Definition HDF5Writer.hpp:84
Telemetry schema builder and container.
Definition TelemetrySchema.hpp:41
Definition CSVExport.hpp:20
@ Int32
4 bytes + 4 padding - modes, phases, counters
Definition Signal.hpp:20
@ Double
8 bytes - physical quantities
Definition Signal.hpp:19
@ Int64
8 bytes - timestamps, large counters
Definition Signal.hpp:21