votca 2026-dev
Loading...
Searching...
No Matches
checkpoint_utils.h
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 */
16
17#pragma once
18#ifndef VOTCA_XTP_CHECKPOINT_UTILS_H
19#define VOTCA_XTP_CHECKPOINT_UTILS_H
20
21// Standard includes
22#include <cstddef>
23#include <cstring>
24#include <mutex>
25#include <string>
26
27// Third party includes
28#include <H5Cpp.h>
29
30// VOTCA includes
31#include <votca/tools/types.h>
32
33namespace votca {
34namespace xtp {
35
36using CptLoc = H5::Group;
37
39
40inline H5::DataSpace StrScalar() { return H5::DataSpace(H5S_SCALAR); }
41
42/*
43 * ======================= HDF5 THREAD-SAFETY NOTE =======================
44 *
45 * IMPORTANT:
46 * ----------
47 * The HDF5 C++ API (H5::*) as provided by Homebrew and most system builds
48 * is NOT thread-safe, even when different threads operate on different
49 * files. In particular:
50 *
51 * - HDF5 maintains global internal state
52 * - H5::Attribute, H5::DataSet, H5::Group, and H5::H5File call HDF5
53 * close functions (H5Aclose, H5Dclose, H5Gclose, H5Fclose) in their
54 * destructors
55 * - These destructors may run after leaving local scopes and MUST NOT
56 * execute concurrently with other HDF5 calls
57 *
58 * Failure to serialize *all* HDF5 activity (including destruction) leads
59 * to hard-to-debug runtime errors such as:
60 *
61 * - "Attribute::~Attribute - H5Aclose failed"
62 * - sporadic std::runtime_error from HDF5
63 * - segmentation faults under multithreading
64 *
65 * DESIGN DECISION:
66 * ----------------
67 * We enforce process-wide serialization of all HDF5 access using a single
68 * global recursive mutex (Hdf5Mutex).
69 *
70 * - The mutex is recursive because HDF5 calls are layered:
71 * CheckpointWriter -> CptTable -> HDF5
72 * - All HDF5-related code must lock this mutex
73 * - High-level operations (e.g. JobTopology::WriteToHdf5 / ReadFromHdf5)
74 * MUST hold the lock for their entire duration so that all HDF5 object
75 * destructors run while the mutex is held
76 *
77 * RULES FOR DEVELOPERS:
78 * --------------------
79 * 1) Any code that creates, reads, writes, or closes HDF5 objects MUST
80 * hold Hdf5Mutex().
81 *
82 * 2) If a function creates HDF5 objects whose destructors run at function
83 * exit, the lock MUST span the entire function scope.
84 *
85 * 3) Never call HDF5 (directly or indirectly) without holding this lock,
86 * even if the file names differ.
87 *
88 * 4) Do NOT remove or replace this mutex unless the entire HDF5 stack
89 * is redesigned (e.g. single-writer thread or MPI HDF5).
90 *
91 * This policy is REQUIRED for correct behavior under multithreading.
92 * ========================================================================
93 */
94inline std::recursive_mutex& Hdf5Mutex() {
95 static std::recursive_mutex m;
96 return m;
97}
98
99// Declare some HDF5 data type inference stuff:
100// Adapted from
101// https://github.com/garrison/eigen3-hdf5/blob/2c782414251e75a2de9b0441c349f5f18fe929a2/eigen3-hdf5.hpp#L18
102
103template <typename T>
105
106template <>
107struct InferDataType<float> {
108 static const H5::DataType* get(void) { return &H5::PredType::NATIVE_FLOAT; }
109};
110
111template <>
112struct InferDataType<double> {
113 static const H5::DataType* get(void) { return &H5::PredType::NATIVE_DOUBLE; }
114};
115
116// New trait: explicit little-endian type for on-disk storage (used in writes):
117template <typename T>
119 // Default: same as memory type (for integers, strings, etc.)
120 static const H5::DataType* get(void) { return InferDataType<T>::get(); }
121};
122
123template <>
124struct FileDataType<float> {
125 static const H5::DataType* get(void) { return &H5::PredType::IEEE_F32LE; }
126};
127
128template <>
129struct FileDataType<double> {
130 static const H5::DataType* get(void) { return &H5::PredType::IEEE_F64LE; }
131};
132
133template <>
134struct InferDataType<int> {
135 static const H5::DataType* get(void) { return &H5::PredType::NATIVE_INT; }
136};
137
138template <>
139struct InferDataType<long int> {
140 static const H5::DataType* get(void) { return &H5::PredType::NATIVE_LONG; }
141};
142
143template <>
144struct InferDataType<std::uint8_t> {
145 static const H5::DataType* get() { return &H5::PredType::NATIVE_UINT8; }
146};
147
148template <>
149struct InferDataType<unsigned> {
150 static const H5::DataType* get(void) { return &H5::PredType::NATIVE_UINT; }
151};
152
153template <>
154struct FileDataType<int> {
155 static const H5::DataType* get(void) { return &H5::PredType::STD_I32LE; }
156};
157
158template <>
159struct FileDataType<long int> {
160 static const H5::DataType* get(void) { return &H5::PredType::STD_I64LE; }
161};
162
163template <>
164struct FileDataType<unsigned> {
165 static const H5::DataType* get(void) { return &H5::PredType::STD_U32LE; }
166};
167
168template <>
169struct FileDataType<std::uint8_t> {
170 static const H5::DataType* get(void) { return &H5::PredType::STD_U8LE; }
171};
172
173template <>
174struct FileDataType<bool> {
175 static const H5::DataType* get(void) { return &H5::PredType::STD_U8LE; }
176};
177
178// Optional: treat bool on disk as uint8 (recommended)
179template <>
180struct InferDataType<bool> {
181 static const H5::DataType* get() { return &H5::PredType::NATIVE_UINT8; }
182};
183
184template <>
185struct InferDataType<std::string> {
186 static const H5::DataType* get(void) {
187
188#if (defined(__GNUC__) && defined(__clang__))
189#pragma clang diagnostic push
190#pragma clang diagnostic ignored "-Wconversion"
191#elif (defined(__GNUC__) && !defined(__INTEL_COMPILER))
192#pragma GCC diagnostic push
193#pragma GCC diagnostic ignored "-Wconversion"
194#elif (defined(__INTEL_COMPILER))
195#pragma warning push
196#pragma warning(disable : 1682) // implicit conversion of a 64-bit integral
197 // type to a smaller integral type
198#endif
199 static const H5::StrType strtype(H5T_C_S1, H5T_VARIABLE);
200#if (defined(__GNUC__) && defined(__clang__))
201#pragma clang diagnostic pop
202#elif (defined(__GNUC__) && !defined(__INTEL_COMPILER))
203#pragma GCC diagnostic pop
204#elif (defined(__INTEL_COMPILER))
205#pragma warning pop
206#endif
207
208 return &strtype;
209 }
210};
211
212} // namespace checkpoint_utils
213} // namespace xtp
214} // namespace votca
215#endif // VOTCA_XTP_CHECKPOINT_UTILS_H
STL namespace.
std::recursive_mutex & Hdf5Mutex()
H5::Group CptLoc
Provides a means for comparing floating point numbers.
Definition basebead.h:33
static const H5::DataType * get(void)