VPTissue Reference Manual
ptree2hdf5.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
20 // Code only available on platforms with libhdf5
21 #ifdef USE_HDF5
22 
23 #include "ptree2hdf5.h"
24 #include <sstream>
25 #include <iostream>
26 
27 #include <boost/xpressive/xpressive.hpp>
28 #include <boost/lexical_cast.hpp>
29 #include <boost/property_tree/xml_parser.hpp>
30 #include <boost/property_tree/ptree.hpp>
31 
32 using namespace std;
33 using namespace boost::xpressive;
34 
35 using namespace boost::property_tree;
36 using boost::lexical_cast;
37 
38 namespace SimPT_Shell {
39 
40 //template <typename T>
41 //bool from_string(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec)
42 //{
43  //std::istringstream iss(s);
44  //return !(iss >> f >> t).fail();
45 //}
46 
47 
51 bool isFloat(const std::string& str) {
52  // A signed +/- floating point number with a dot either at beginning, end or in the middle of the digits
53  // E.g: 1.0 1.5 .5 -.001 +1. all match but a normal integer does not
54  // The exponential part is optional
55  // TODO: needs a low-priority fix to match expressions like 1e+02
56  // i.e: without decimal point but including an exponential part
57 
58  const sregex match_float = sregex::compile( "^[+-]?(\\d*\\.\\d+|\\d+\\.\\d*)([eE][-+]?\\d+)?$");
59  return regex_match( str, match_float);
60 }
61 
62 
66 bool isInteger(const std::string& str) {
67  // A signed +/- integer with one or more digits
68  const sregex match_integer = sregex::compile("^[+-]?\\d+$");
69  return regex_match( str, match_integer);
70 }
71 
72 
73 void ptree2hdf5(const ptree& pt, hid_t h5_id) {
74  // Loop over the ptree's (key, value) pairs
75  for (auto sub_pt_kv : pt) {
76  // Name of the key
77  string key = sub_pt_kv.first;
78 
79  // Ignore XML comments
80  if (key != "<xmlcomment>") {
81  // Only proceed if no HDF5 link named 'key' exists already
82  // (this would mean the ptree is malformed)
83  if(!H5Lexists(h5_id, key.c_str(), H5P_DEFAULT) && !H5Aexists(h5_id, key.c_str())) {
84 
85  // String representation of the value associated with the key
86  string value = sub_pt_kv.second.get_value<string>();
87 
88  if (key == "value_array") {
89  // TODO: handle this properly
90  //cout << "VALUE_ARRAY!" << endl;
91  }
92  // We're in a ptree node (key, value) without children
93  if (value != "") {
94  if (isFloat(value)) {
95  // Create & write a simple scalar HDF5 attribute of type H5T_NATIVE_DOUBLE
96  double value_double = lexical_cast<double>(value);
97  hid_t attr_dspace = H5Screate(H5S_SCALAR);
98  hid_t attr_id = H5Acreate(h5_id, key.c_str(), H5T_IEEE_F64LE, attr_dspace, H5P_DEFAULT, H5P_DEFAULT);
99  H5Awrite(attr_id, H5T_NATIVE_DOUBLE, &value_double);
100  H5Aclose(attr_id);
101  H5Sclose(attr_dspace);
102  } else if (isInteger(value)) {
103  // Create & write a simple scalar HDF5 attribute of type H5T_NATIVE_INT
104  int value_int = lexical_cast<int>(value);
105  hid_t attr_dspace = H5Screate(H5S_SCALAR);
106  hid_t attr_id = H5Acreate(h5_id, key.c_str(), H5T_STD_I32LE, attr_dspace, H5P_DEFAULT, H5P_DEFAULT);
107  H5Awrite(attr_id, H5T_NATIVE_INT, &value_int);
108  H5Aclose(attr_id);
109  H5Sclose(attr_dspace);
110  } else {
111  // Create HDF5 attribute of type H5T_STRING
112  const char* value_string = value.c_str();
113  hid_t attr_dspace = H5Screate(H5S_SCALAR);
114  hid_t attr_dtype = H5Tcopy(H5T_C_S1);
115  H5Tset_size(attr_dtype, H5T_VARIABLE);
116  hid_t attr_id = H5Acreate(h5_id, key.c_str(), attr_dtype, attr_dspace, H5P_DEFAULT, H5P_DEFAULT);
117  H5Awrite(attr_id, attr_dtype, &value_string);
118  H5Aclose(attr_id);
119  H5Sclose(attr_dspace);
120  H5Tclose(attr_dtype);
121  }
122 
123  // We're in a ptree subtree node (key, value), where value is a subtree
124  } else {
125  // Create a HDF5 subgroup with key's name
126  hid_t h5_sub_id = H5Gcreate(h5_id, key.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
127 
128  // Dive in recursively into subtree
129  const ptree& sub_pt = pt.get_child(key);
130  ptree2hdf5(sub_pt, h5_sub_id);
131 
132  // Close HDF5 subgroup
133  H5Gclose(h5_sub_id);
134  }
135  } else {
136  // TODO: silently ignore, but should be catched by properly saving value_arrays
137  //cout << "Duplicate key names '" << key << endl;
138  }
139  }
140  }
141 }
142 
143 // Callback used by H5Aiterate_by_name when traversing all attributes in a group
144 //
145 // Signature:
146 // herr_t (*H5A_operator2_t)( hid_t location_id, const char *attr_name, const H5A_info_t *ainfo, void *op_data)
147 //
148 // The operation receives the location identifier for the group or dataset being
149 // iterated over, location_id; the name of the current object attribute, attr_name;
150 // the attributes info struct, ainfo; and a pointer to the operator data passed into H5Aiterate_by_name, op_data.
151 herr_t attribute_info(hid_t loc_id, const char* attr_name, const H5A_info_t* , void* data) {
152  // Open currently visited attribute
153  hid_t attr_id = H5Aopen(loc_id, attr_name, H5P_DEFAULT);
154  hid_t attr_dtype = H5Aget_type(attr_id);
155  hid_t attr_dspace = H5Aget_space(attr_id);
156 
157  // Must be 0 (a single scalar) or 1 (a vector) other cases will be ignored
158  const int ndims = H5Sget_simple_extent_ndims(attr_dspace);
159 
160  // The currently visited atribute is a candidate to be put in the ptree passed as raw data
161  ptree* pt_attr = static_cast<ptree*>(data);
162 
163  // Check type class of attribute, either integer, real or string
164  // (other types are silently ignored)
165  H5T_class_t attr_class = H5Tget_class(attr_dtype);
166  if (H5T_INTEGER == attr_class) {
167  if (0 == ndims) { // A scalar int
168  int attr_value = 0;
169  H5Aread(attr_id, H5T_NATIVE_INT, &attr_value);
170  pt_attr->put(attr_name, attr_value);
171  } else if (1 == ndims) { // A vector of ints
172  hsize_t length = 0;
173  H5Sget_simple_extent_dims(attr_dspace, &length, 0);
174  vector<int> attr_values(length);
175  H5Aread(attr_id, H5T_NATIVE_INT, attr_values.data());
176  for (int attr_value : attr_values) {
177  pt_attr->add(string(attr_name) + ".value_array.value", attr_value);
178  }
179  }
180  } else if (H5T_FLOAT == attr_class) {
181  if (0 == ndims) { // A scalar double
182  double attr_value = 0.0;
183  H5Aread(attr_id, H5T_NATIVE_DOUBLE, &attr_value);
184  pt_attr->put(attr_name, attr_value);
185  } else if (1 == ndims) { // A vector of doubles
186  hsize_t length = 0;
187  H5Sget_simple_extent_dims(attr_dspace, &length, 0);
188  vector<double> attr_values(length);
189  H5Aread(attr_id, H5T_NATIVE_DOUBLE, attr_values.data());
190  for (double attr_value : attr_values) {
191  pt_attr->add(string(attr_name) + ".value_array.value", attr_value);
192  }
193  }
194  } else if (H5T_STRING == attr_class) {
195  // Note that parameters of type H5T_STRING are scalars so one does not
196  // check for ndims and dims.
197  char* attr_value;
198  hid_t attr_ntype = H5Tcopy(H5T_C_S1);
199  H5Tset_size(attr_ntype, H5T_VARIABLE);
200  H5Aread(attr_id, attr_ntype, &attr_value);
201  H5Tclose(attr_ntype);
202  //cout << " attribute: " << attr_name << " = " << attr_value << " [H5T_STRING]" << endl;
203  pt_attr->put(attr_name, attr_value);
204  H5Dvlen_reclaim (attr_ntype, attr_dspace, H5P_DEFAULT, attr_value);
205  } else {
206  //cout << " attribute: " << attr_name << " = don\'t know, don\'t care..." << endl;
207  // None of the types we support, carry on.
208  }
209 
210  // Clean up handles and signal success to the calling function
211  H5Sclose(attr_dspace);
212  H5Tclose(attr_dtype);
213  H5Aclose(attr_id);
214  return 0;
215 }
216 
217 // Callback used by H5Ovisit to visit all subgroups of a given group recursively.
218 //
219 // Signature:
220 // herr_t (*H5O_iterate_t)( hid_t g_id, const char *name, const H5O_info_t *info, void *op_data)
221 //
222 // o_id Object that serves as root of the iteration; same value as the H5Ovisit object_id parameter
223 // name Name of object, relative to o_id, being examined at current step of the iteration
224 // object_info H5O_info_t struct containing information regarding that object
225 // op_data User-defined pointer to data required by the application in processing the object;
226 // a pass-through of the op_data pointer provided with the H5Ovisit_by_name function call
227 herr_t visit_group(hid_t loc_id, const char *group_name, const H5O_info_t *obj_info, void *data) {
228  // Only look at groups, ignore other objects
229  // (also, ignore the root of the tree we're traversing)
230  if (*group_name != '.' && H5O_TYPE_GROUP == obj_info->type) {
231  hsize_t n = 0; // Index to start iteration over attributes, must be set to 0
232  ptree pt_attr; // ptree that will be populated by the attributes in current group
233  H5Aiterate_by_name(loc_id, group_name, H5_INDEX_NAME, H5_ITER_NATIVE, &n, &attribute_info, static_cast<void*>(&pt_attr), H5P_DEFAULT);
234 
235  // Append attributes from pt_attr as a subtree with current group name as root name
236  ptree* pt_root = static_cast<ptree*>(data);
237  // Since HDF5 uses '/' as a separator in path names, we need to ask
238  // boost to use that instead of the default '.' to separate paths in a ptree.
239  pt_root->put_child(ptree::path_type(group_name, '/'), pt_attr);
240  }
241  return 0;
242 }
243 
244 ptree hdf52ptree(hid_t loc_id) {
245  // property tree to be filled with subtrees (HDF5 groups) and elements (HDF5 attributes)
246  ptree pt;
247 
248  // Loop recursively through all HDF5 objects starting from loc_id as root
249  // Pass the ptree to be populated as a pointer to raw data.
250  H5Ovisit(loc_id, H5_INDEX_NAME, H5_ITER_NATIVE, &visit_group, static_cast<void*>(&pt));
251 
252  return pt;
253 }
254 
255 } // namespace
256 
257 #endif // end_of_include_guard
258 
STL namespace.
Header for ptree2hdf5.
Namespace for SimPT shell package.
Definition: Client.cpp:50
ptree hdf52ptree(hid_t loc_id)
Return the ptree that represents the groups of attributes in HDF5.
Definition: ptree2hdf5.cpp:244
bool isInteger(const std::string &str)
Returns true if the provided string represents an integer number, false otherwise.
Definition: ptree2hdf5.cpp:66
bool isFloat(const std::string &str)
Returns true if the provided string represents a floating point number, false otherwise.
Definition: ptree2hdf5.cpp:51