ALPSCore reference
archive_write.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT
3  * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4  * For use in publications, see ACKNOWLEDGE.TXT
5  */
6 
7 #include <iostream>
8 
9 #include <hdf5.h>
10 
11 #include <alps/hdf5/archive.hpp>
12 #include <alps/utilities/cast.hpp>
13 
14 #include "common.hpp"
15 #include "archivecontext.hpp"
16 
17 namespace alps {
18  namespace hdf5 {
19 
20  template<typename T>
21  auto archive::write(std::string path, T value) const -> ONLY_NATIVE(T, void) {
23  if (context_ == NULL)
24  throw archive_closed("the archive is closed" + ALPS_STACKTRACE);
25  if (!context_->write_)
26  throw archive_error("the archive is not writeable" + ALPS_STACKTRACE);
27  hid_t data_id;
28  if ((path = complete_path(path)).find_last_of('@') == std::string::npos) {
29  if (is_group(path))
30  delete_group(path);
31  data_id = H5Dopen2(context_->file_id_, path.c_str(), H5P_DEFAULT);
32  if (data_id < 0) {
33  if (path.find_last_of('/') < std::string::npos && path.find_last_of('/') > 0)
34  create_group(path.substr(0, path.find_last_of('/')));
35  } else {
36  H5S_class_t class_type;
37  {
38  detail::space_type current_space_id(H5Dget_space(data_id));
39  class_type = H5Sget_simple_extent_type(current_space_id);
40  }
41  if (class_type != H5S_SCALAR || !is_datatype<T>(path)) {
42  detail::check_data(data_id);
43  if (path.find_last_of('/') < std::string::npos && path.find_last_of('/') > 0) {
44  detail::group_type group_id(H5Gopen2(context_->file_id_, path.substr(0, path.find_last_of('/')).c_str(), H5P_DEFAULT));
45  detail::check_error(H5Ldelete(group_id, path.substr(path.find_last_of('/') + 1).c_str(), H5P_DEFAULT));
46  } else
47  detail::check_error(H5Ldelete(context_->file_id_, path.c_str(), H5P_DEFAULT));
48  data_id = -1;
49  }
50  }
51  detail::type_type type_id(detail::get_native_type(T()));
52  if (data_id < 0) {
53  detail::property_type prop_id(H5Pcreate(H5P_DATASET_CREATE));
54  detail::check_error(H5Pset_attr_creation_order(prop_id, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)));
55  data_id = H5Dcreate2(
56  context_->file_id_
57  , path.c_str()
58  , type_id
59  , detail::space_type(H5Screate(H5S_SCALAR))
60  , H5P_DEFAULT
61  , prop_id
62  , H5P_DEFAULT
63  );
64  }
65  detail::native_ptr_converter<typename std::remove_cv<typename std::remove_reference<T>::type>::type> converter(1);
66  detail::check_error(H5Dwrite(data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, converter.apply(&value)));
67  detail::check_data(data_id);
68  } else {
69  hid_t parent_id;
70  if (is_group(path.substr(0, path.find_last_of('@'))))
71  parent_id = detail::check_error(H5Gopen2(context_->file_id_, path.substr(0, path.find_last_of('@')).c_str(), H5P_DEFAULT));
72  else if (is_data(path.substr(0, path.find_last_of('@'))))
73  parent_id = detail::check_error(H5Dopen2(context_->file_id_, path.substr(0, path.find_last_of('@')).c_str(), H5P_DEFAULT));
74  else
75  throw path_not_found("unknown path: " + path.substr(0, path.find_last_of('@')) + ALPS_STACKTRACE);
76  hid_t data_id = H5Aopen(parent_id, path.substr(path.find_last_of('@') + 1).c_str(), H5P_DEFAULT);
77  if (data_id >= 0) {
78  H5S_class_t class_type;
79  {
80  detail::space_type current_space_id(H5Aget_space(data_id));
81  class_type = H5Sget_simple_extent_type(current_space_id);
82  }
83  if (class_type != H5S_SCALAR || !is_datatype<T>(path)) {
84  detail::check_attribute(data_id);
85  detail::check_error(H5Adelete(parent_id, path.substr(path.find_last_of('@') + 1).c_str()));
86  data_id = -1;
87  }
88  }
89  detail::type_type type_id(detail::get_native_type(T()));
90  if (data_id < 0)
91  data_id = H5Acreate2(
92  parent_id
93  , path.substr(path.find_last_of('@') + 1).c_str()
94  , type_id
95  , detail::space_type(H5Screate(H5S_SCALAR))
96  , H5P_DEFAULT
97  , H5P_DEFAULT
98  );
99  detail::native_ptr_converter<typename std::remove_cv<typename std::remove_reference<T>::type>::type> converter(1);
100  detail::check_error(H5Awrite(data_id, type_id, converter.apply(&value)));
101  detail::attribute_type attr_id(data_id);
102  if (is_group(path.substr(0, path.find_last_of('@'))))
103  detail::check_group(parent_id);
104  else
105  detail::check_data(parent_id);
106  }
107  }
108  #define ALPS_HDF5_WRITE_SCALAR(T) template void archive::write<T>(std::string path, T value) const;
110 
111  template<typename T>
112  auto archive::write(
113  std::string path, T const * value, std::vector<std::size_t> size, std::vector<std::size_t> chunk, std::vector<std::size_t> offset
114  ) const -> ONLY_NATIVE(T, void) {
116  if (context_ == NULL)
117  throw archive_closed("the archive is closed" + ALPS_STACKTRACE);
118  if (!context_->write_)
119  throw archive_error("the archive is not writeable" + ALPS_STACKTRACE);
120  if (chunk.size() == 0)
121  chunk = std::vector<std::size_t>(size.begin(), size.end());
122  if (offset.size() == 0)
123  offset = std::vector<std::size_t>(size.size(), 0);
124  if (size.size() != offset.size())
125  throw archive_error("wrong chunk or offset passed for path: " + path + ALPS_STACKTRACE);
126  hid_t data_id;
127  if ((path = complete_path(path)).find_last_of('@') == std::string::npos) {
128  if (is_group(path))
129  delete_group(path);
130  data_id = H5Dopen2(context_->file_id_, path.c_str(), H5P_DEFAULT);
131  if (data_id < 0) {
132  if (path.find_last_of('/') < std::string::npos && path.find_last_of('/') > 0)
133  create_group(path.substr(0, path.find_last_of('/')));
134  } else {
135  H5S_class_t class_type;
136  {
137  detail::space_type current_space_id(H5Dget_space(data_id));
138  class_type = H5Sget_simple_extent_type(current_space_id);
139  }
140  if (
141  class_type == H5S_SCALAR
142  || dimensions(path) != size.size()
143  || !std::equal(size.begin(), size.end(), extent(path).begin())
144  || !is_datatype<T>(path)
145  ) {
146  detail::check_data(data_id);
147  detail::check_error(H5Ldelete(context_->file_id_, path.c_str(), H5P_DEFAULT));
148  data_id = -1;
149  }
150  }
151  detail::type_type type_id(detail::get_native_type(T()));
152  if (std::accumulate(size.begin(), size.end(), std::size_t(0)) == 0) {
153  if (data_id < 0) {
154  detail::property_type prop_id(H5Pcreate(H5P_DATASET_CREATE));
155  detail::check_error(H5Pset_attr_creation_order(prop_id, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)));
156  detail::check_data(H5Dcreate2(
157  context_->file_id_
158  , path.c_str()
159  , type_id
160  , detail::space_type(H5Screate(H5S_NULL))
161  , H5P_DEFAULT
162  , prop_id
163  , H5P_DEFAULT
164  ));
165  } else
166  detail::check_data(data_id);
167  } else {
168  std::vector<hsize_t> size_hid(size.begin(), size.end())
169  , offset_hid(offset.begin(), offset.end())
170  , chunk_hid(chunk.begin(), chunk.end());
171  if (data_id < 0) {
172  detail::property_type prop_id(H5Pcreate(H5P_DATASET_CREATE));
173  detail::check_error(H5Pset_attr_creation_order(prop_id, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)));
174  if (std::is_same< T , std::string>::value)
175  detail::check_error(data_id = H5Dcreate2(
176  context_->file_id_
177  , path.c_str()
178  , type_id
179  , detail::space_type(H5Screate_simple(static_cast<int>(size_hid.size()), &size_hid.front(), NULL))
180  , H5P_DEFAULT
181  , prop_id
182  , H5P_DEFAULT
183  ));
184  else {
185  detail::check_error(H5Pset_fill_time(prop_id, H5D_FILL_TIME_NEVER));
186  std::size_t dataset_size = std::accumulate(size.begin(), size.end(), std::size_t(sizeof( T )), std::multiplies<std::size_t>());
187  if (dataset_size < ALPS_HDF5_SZIP_BLOCK_SIZE * sizeof( T ))
188  detail::check_error(H5Pset_layout(prop_id, H5D_COMPACT));
189  else if (dataset_size < (1ULL<<32))
190  detail::check_error(H5Pset_layout(prop_id, H5D_CONTIGUOUS));
191  else {
192  detail::check_error(H5Pset_layout(prop_id, H5D_CHUNKED));
193  std::vector<hsize_t> max_chunk(size_hid);
194  std::size_t index = 0;
195  while (std::accumulate(
196  max_chunk.begin()
197  , max_chunk.end()
198  , std::size_t(sizeof( T ))
199  , std::multiplies<std::size_t>()
200  ) > (1ULL<<32) - 1) {
201  max_chunk[index] /= 2;
202  if (max_chunk[index] == 1)
203  ++index;
204  }
205  detail::check_error(H5Pset_chunk(prop_id, static_cast<int>(max_chunk.size()), &max_chunk.front()));
206  }
207  if (context_->compress_ && dataset_size > ALPS_HDF5_SZIP_BLOCK_SIZE * sizeof( T ))
208  detail::check_error(H5Pset_szip(prop_id, H5_SZIP_NN_OPTION_MASK, ALPS_HDF5_SZIP_BLOCK_SIZE));
209  detail::check_error(H5Pset_attr_creation_order(prop_id, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)));
210  detail::check_error(data_id = H5Dcreate2(
211  context_->file_id_
212  , path.c_str()
213  , type_id
214  , detail::space_type(H5Screate_simple(static_cast<int>(size_hid.size()), &size_hid.front(), NULL))
215  , H5P_DEFAULT
216  , prop_id
217  , H5P_DEFAULT
218  ));
219  }
220  }
221  detail::data_type raii_id(data_id);
222  detail::native_ptr_converter<T> converter(std::accumulate(chunk.begin(), chunk.end(), std::size_t(1), std::multiplies<std::size_t>()));
223  if (std::equal(chunk.begin(), chunk.end(), size.begin()))
224  detail::check_error(H5Dwrite(raii_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, converter.apply(value)));
225  else {
226  detail::space_type space_id(H5Dget_space(raii_id));
227  detail::check_error(H5Sselect_hyperslab(space_id, H5S_SELECT_SET, &offset_hid.front(), NULL, &chunk_hid.front(), NULL));
228  detail::space_type mem_id(detail::space_type(H5Screate_simple(static_cast<int>(chunk_hid.size()), &chunk_hid.front(), NULL)));
229  detail::check_error(H5Dwrite(raii_id, type_id, mem_id, space_id, H5P_DEFAULT, converter.apply(value)));
230  }
231  }
232  } else {
233  hid_t parent_id;
234  if (is_group(path.substr(0, path.find_last_of('@'))))
235  parent_id = detail::check_error(H5Gopen2(context_->file_id_, path.substr(0, path.find_last_of('@')).c_str(), H5P_DEFAULT));
236  else if (is_data(path.substr(0, path.find_last_of('@'))))
237  parent_id = detail::check_error(H5Dopen2(context_->file_id_, path.substr(0, path.find_last_of('@')).c_str(), H5P_DEFAULT));
238  else
239  throw path_not_found("unknown path: " + path.substr(0, path.find_last_of('@')) + ALPS_STACKTRACE);
240  hid_t data_id = H5Aopen(parent_id, path.substr(path.find_last_of('@') + 1).c_str(), H5P_DEFAULT);
241  if (data_id >= 0) {
242  H5S_class_t class_type;
243  {
244  detail::space_type current_space_id(H5Aget_space(data_id));
245  class_type = H5Sget_simple_extent_type(current_space_id);
246  }
247  if (class_type != H5S_SCALAR) {
248  detail::check_attribute(data_id);
249  detail::check_error(H5Adelete(parent_id, path.substr(path.find_last_of('@') + 1).c_str()));
250  data_id = -1;
251  }
252  }
253  detail::type_type type_id(detail::get_native_type(T()));
254  if (std::accumulate(size.begin(), size.end(), std::size_t(0)) == 0) {
255  if (data_id < 0)
256  detail::check_attribute(H5Acreate2(
257  parent_id
258  , path.substr(path.find_last_of('@') + 1).c_str()
259  , type_id
260  , detail::space_type(H5Screate(H5S_NULL))
261  , H5P_DEFAULT
262  , H5P_DEFAULT
263  ));
264  else
265  detail::check_attribute(data_id);
266  } else {
267  std::vector<hsize_t> size_hid(size.begin(), size.end())
268  , offset_hid(offset.begin(), offset.end())
269  , chunk_hid(chunk.begin(), chunk.end());
270  if (data_id < 0)
271  data_id = detail::check_error(H5Acreate2(
272  parent_id
273  , path.substr(path.find_last_of('@') + 1).c_str()
274  , type_id
275  , detail::space_type(H5Screate_simple(static_cast<int>(size_hid.size()), &size_hid.front(), NULL))
276  , H5P_DEFAULT
277  , H5P_DEFAULT
278  ));
279  {
280  detail::attribute_type raii_id(data_id);
281  if (std::equal(chunk.begin(), chunk.end(), size.begin())) {
282  detail::native_ptr_converter<T> converter(
283  std::accumulate(chunk.begin(), chunk.end(), std::size_t(1), std::multiplies<std::size_t>())
284  );
285  detail::check_error(H5Awrite(raii_id, type_id, converter.apply(value)));
286  } else
287  throw std::logic_error("Not Implemented, path: " + path + ALPS_STACKTRACE);
288  }
289  }
290  if (is_group(path.substr(0, path.find_last_of('@'))))
291  detail::check_group(parent_id);
292  else
293  detail::check_data(parent_id);
294  }
295  }
296  #define ALPS_HDF5_WRITE_VECTOR(T) template void archive::write<T>( \
297  std::string, T const *, std::vector<std::size_t>, std::vector<std::size_t>, std::vector<std::size_t>) const;
299  }
300 }
index_mesh::index_type index
Definition: mesh.hpp:1247
#define ALPS_HDF5_WRITE_VECTOR(T)
std::enable_if<!is_sequence< T >::value, std::size_t >::type size(T const &)
Definition: size.hpp:20
STL namespace.
#define ALPS_HDF5_SZIP_BLOCK_SIZE
Definition: config.hpp:23
ALPS_FOREACH_NATIVE_HDF5_TYPE(ALPS_HDF5_READ_SCALAR)
#define ONLY_NATIVE(T, R)
Definition: archive.hpp:56
#define ALPS_HDF5_FAKE_THREADSAFETY
Definition: common.hpp:25
#define ALPS_HDF5_WRITE_SCALAR(T)
auto write(std::string path, T const *value, std::vector< std::size_t > size, std::vector< std::size_t > chunk=std::vector< std::size_t >(), std::vector< std::size_t > offset=std::vector< std::size_t >()) const -> typename std::enable_if<!is_native_type< T >::value, void >::type
Definition: archive.hpp:172
#define ALPS_STACKTRACE
Definition: stacktrace.hpp:37