VPTissue Reference Manual
Hdf5File.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 included on platforms with libhdf5
21 // Dummy placeholders defined in Hdf5File.h will be used if libhdf5 is
22 // unavailable on compile time
23 
24 #include "Hdf5File.h"
25 
26 #include "ptree2hdf5.h"
27 #include "bio/AttributeContainer.h"
28 #include "bio/MeshState.h"
29 #include "sim/Sim.h"
30 #include "sim/SimState.h"
31 #include "util/misc/log_debug.h"
33 
34 #include <boost/algorithm/string/predicate.hpp>
35 #include <boost/property_tree/ptree.hpp>
36 #include <boost/property_tree/xml_parser.hpp>
37 
38 #include <algorithm>
39 #include <iomanip>
40 #include <iostream>
41 #include <sstream>
42 #include <stdexcept>
43 #include <string>
44 
45 using namespace std;
46 using namespace boost::property_tree;
47 using namespace boost::property_tree::xml_parser;
48 using namespace SimPT_Sim::Util;
49 
50 namespace {
51  // TODO: Document!
52  bool write_array_rank1(hid_t loc_id, string name, void const* data, hid_t type_id, hsize_t dim_1);
53  bool write_array_rank1(hid_t loc_id, string name, const vector<string>& data);
54  bool write_array_rank2(hid_t loc_id, string name, void const* data, hid_t type_id, hsize_t dim_1, hsize_t dim_2);
55  // Not used for now
56  // bool write_array_rank3(hid_t loc_id, string name, void const* data, hid_t type_id, hsize_t dim_1, hsize_t dim_2, hsize_t dim_3);
57 
58  template <typename T>
59  bool read_array_rank1(hid_t loc_id, string name, T** data, hid_t type_id, size_t* dim_1, bool optional = false);
60 
61  template <typename T>
62  bool read_array_rank2(hid_t loc_id, string name, T** data, hid_t type_id, size_t* dim_1, size_t* dim_2, bool optional = false);
63 
65  list<string> find_matching_links(hid_t loc_id, function<bool(string)> match);
66 
67 }
68 
69 namespace {
70  bool write_array_rank1(hid_t loc_id, string name, void const* data, hid_t type_id, hsize_t dim_1) {
71  // No writing if something called 'name' already exists in loc_id
72  if (0 == H5Lexists(loc_id, name.c_str(), H5P_DEFAULT)) {
73  // Create rank 1 dataspace
74  hid_t dspace = H5Screate_simple(1, &dim_1, 0);
75  // Create dataset 'name' of provided simple type using the rank 1 dataspace created before
76  hid_t dset = H5Dcreate(loc_id, name.c_str(), type_id, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
77  // Write data using the native datatype corresponding to the provided type_id
78  hid_t mem_type_id = H5Tget_native_type(type_id, H5T_DIR_ASCEND);
79  H5Dwrite(dset, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
80  // Clean up HDF5 handles
81  H5Tclose(mem_type_id);
82  H5Dclose(dset);
83  H5Sclose(dspace);
84  return true;
85  } else {
86  return false;
87  }
88  }
89 
90  bool write_array_rank1(hid_t loc_id, string name, const vector<string>& data) {
91  // No writing if something called 'name' already exists in loc_id
92  if (0 == H5Lexists(loc_id, name.c_str(), H5P_DEFAULT)) {
93  // Use C-style string datatype
94  hid_t dtype = H5Tcopy(H5T_C_S1);
95  H5Tset_size(dtype, H5T_VARIABLE);
96  // Create rank 1 dataspace
97  hsize_t dim_1 = data.size();
98  hid_t dspace = H5Screate_simple(1, &dim_1, 0);
99  // Create dataset 'name' of provided simple type using the rank 1 dataspace created before
100  hid_t dset = H5Dcreate(loc_id, name.c_str(), dtype, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
101  // Write data as an array of pointers to the C-string representation of the strings
102  vector<const char*> raw_string_ptrs;
103  for (const string & s : data) raw_string_ptrs.push_back(s.c_str());
104  H5Dwrite(dset, dtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, raw_string_ptrs.data());
105  // Clean up HDF5 handles
106  H5Dclose(dset);
107  H5Sclose(dspace);
108  H5Tclose(dtype);
109  return true;
110  } else {
111  return false;
112  }
113  }
114 
115  bool write_array_rank2(hid_t loc_id, string name, void const* data, hid_t type_id, hsize_t dim_1, hsize_t dim_2) {
116  // No writing if something called 'name' already exists in loc_id
117  if (0 == H5Lexists(loc_id, name.c_str(), H5P_DEFAULT)) {
118  // Create rank 2 dataspace
119  hsize_t dims[2] = {dim_1, dim_2};
120  hid_t dspace = H5Screate_simple(2, dims, 0);
121  // Create dataset 'name' of provided simple type using the rank 2 dataspace created before
122  hid_t dset = H5Dcreate(loc_id, name.c_str(), type_id, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
123  // Write data
124  hid_t mem_type_id = H5Tget_native_type(type_id, H5T_DIR_ASCEND);
125  H5Dwrite(dset, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
126  // Clean up HDF5 handles
127  H5Tclose(mem_type_id);
128  H5Dclose(dset);
129  H5Sclose(dspace);
130  return true;
131  } else {
132  return false;
133  }
134  }
135 
136  // Not used for now
137  /*
138  bool write_array_rank3(hid_t loc_id, string name, void const* data, hid_t type_id, hsize_t dim_1, hsize_t dim_2, hsize_t dim_3) {
139  // No writing if something called 'name' already exists in loc_id
140  if (0 == H5Lexists(loc_id, name.c_str(), H5P_DEFAULT)) {
141  // Create rank 3 dataspace
142  hsize_t dims[3] = {dim_1, dim_2, dim_3};
143  hid_t dspace = H5Screate_simple(3, dims, 0);
144  // Create dataset 'name' of provided simple type using the rank 3 dataspace created before
145  hid_t dset = H5Dcreate(loc_id, name.c_str(), type_id, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
146  // Write data
147  hid_t mem_type_id = H5Tget_native_type(type_id, H5T_DIR_ASCEND);
148  H5Dwrite(dset, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
149  // Clean up HDF5 handles
150  H5Tclose(mem_type_id);
151  H5Dclose(dset);
152  H5Sclose(dspace);
153  return true;
154  } else {
155  return false;
156  }
157  }
158  */
159 
160  template <typename T>
161  bool read_array_rank1(hid_t loc_id, string name, T** data, hid_t mem_type_id, size_t* dim_1, bool optional) {
162  // HDF5 error status. Used to check if bad things are happening.
163  herr_t h5_status;
164 
165  // Quickly check for existence of a link called 'name'
166  if (0 == H5Lexists(loc_id, name.c_str(), H5P_DEFAULT)) {
167  if (optional) {
168  return false;
169  } else {
170  string errmsg = string("No dataset \'") + name + string("\'");
171  throw runtime_error(errmsg);
172  }
173  }
174 
175  // Try to open the dataset
176  hid_t dset = H5Dopen(loc_id, name.c_str(), H5P_DEFAULT);
177  if (dset < 0) {
178  if (optional) {
179  return false;
180  } else {
181  string errmsg = string("Could not open dataset \'") + name + string("\'");
182  throw runtime_error(errmsg);
183  }
184  }
185 
186  // Get the associated dataspace
187  hid_t dspace = H5Dget_space(dset);
188  int ndims = H5Sget_simple_extent_ndims(dspace);
189  if (ndims != 1) {
190  string errmsg = string("Dataset \'") + name + string("\' must be rank 1");
191  throw runtime_error(errmsg);
192  }
193 
194  // Number of elements in data
195  hsize_t _dim_1;
196  H5Sget_simple_extent_dims(dspace, &_dim_1, 0);
197  *dim_1 = static_cast<size_t>(_dim_1);
198 
199  // Allocate space for data
200  *data = new T[_dim_1];
201 
202  // Read the data
203  h5_status = H5Dread(dset, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, *data);
204  if (h5_status < 0) {
205  string errmsg = string("Could not read dataset \'") + name + string("\'");
206  throw runtime_error(errmsg);
207  }
208 
209  // TODO: is type-checking feasible?
210 
211  // Clean up HDF5 handles
212  H5Sclose(dspace);
213  H5Dclose(dset);
214  return true;
215  }
216 
217  template <typename T>
218  bool read_array_rank2(hid_t loc_id, string name, T** data, hid_t mem_type_id, size_t* dim_1, size_t* dim_2, bool optional) {
219  // HDF5 error status. Used to check if bad things are happening.
220  herr_t h5_status;
221 
222  // Quickly check for existence of a link called 'name'
223  if (0 == H5Lexists(loc_id, name.c_str(), H5P_DEFAULT)) {
224  if (optional) {
225  return false;
226  } else {
227  string errmsg = string("No dataset \'") + name + string("\'");
228  throw runtime_error(errmsg);
229  }
230  }
231 
232  // Try to open the dataset
233  hid_t dset = H5Dopen(loc_id, name.c_str(), H5P_DEFAULT);
234  if (dset < 0) {
235  if (optional) {
236  return false;
237  } else {
238  string errmsg = string("Could not open dataset \'") + name + string("\'");
239  throw runtime_error(errmsg);
240  }
241  }
242 
243  // Get the associated dataspace
244  hid_t dspace = H5Dget_space(dset);
245  int ndims = H5Sget_simple_extent_ndims(dspace);
246  if (ndims != 2) {
247  string errmsg = string("Dataset \'") + name + string("\' must be rank 2");
248  throw runtime_error(errmsg);
249  }
250 
251  // Number of elements in data
252  hsize_t _dims[2];
253  H5Sget_simple_extent_dims(dspace, _dims, 0);
254  *dim_1 = static_cast<size_t>(_dims[0]);
255  *dim_2 = static_cast<size_t>(_dims[1]);
256 
257  // Allocate space for data
258  *data = new T[_dims[0] * _dims[1]];
259 
260  // Read the data
261  h5_status = H5Dread(dset, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, *data);
262  if (h5_status < 0) {
263  string errmsg = string("Could not read dataset \'") + name + string("\'");
264  throw runtime_error(errmsg);
265  }
266 
267  // TODO: is type-checking feasible?
268 
269  // Clean up HDF5 handles
270  H5Sclose(dspace);
271  H5Dclose(dset);
272  return true;
273  }
274 
275  //herr_t (*H5L_iterate_t)( hid_t g_id, const char *name, const H5L_info_t *info, void *op_data)
276  herr_t collect_link_names(hid_t , const char* name, const H5L_info_t* , void* op_data) {
277  list<string>* link_names = static_cast<list<string>*>(op_data);
278  link_names->push_back(string(name));
279  return 0;
280  }
281 
282  list<string> find_matching_links(hid_t loc_id, function<bool(string)> match) {
283  // Collect all link names at location loc_id
284  list<string> link_names;
285  H5Literate(loc_id, H5_INDEX_NAME, H5_ITER_NATIVE, 0, &collect_link_names, &link_names);
286  // Remove link names that DON'T match the 'match' predicate
287  link_names.remove_if([&](string name)->bool{ return !match(name); });
288  return link_names;
289  }
290 }
291 
292 namespace SimPT_Shell {
293 
294 using namespace std;
295 using boost::property_tree::ptree;
296 using SimPT_Sim::Sim;
297 using SimPT_Sim::SimState;
299 
300 // Note that a hid_t identifier -1 for m_file_id represents a closed file
301 Hdf5File::Hdf5File()
302  : m_file_id(-1), m_file_path("") {}
303 
304 Hdf5File::Hdf5File(const string& file_path)
305  : m_file_id(-1), m_file_path("")
306 {
307  // Open resets m_file_id and m_file_path iff successful
308  Open(file_path);
309 }
310 
312 {
313  if (IsOpen()) {
314  Close();
315  }
316 }
317 
319 {
320  bool status = false;
321  if (m_file_id >= 0) {
322  H5Fclose(m_file_id);
323  m_file_path = "";
324  status = true;
325  }
326  return status;
327 }
328 
330 {
331  return "h5";
332 }
333 
335 {
336  return m_file_path;
337 }
338 
340 {
341  return (m_file_path != "") && (m_file_id != -1);
342 }
343 
344 bool Hdf5File::Open(const string& file_path)
345 {
346  string const here = string(VL_HERE) + "> ";
347  // Did we succeed in providing a valid HDF5 file, either by opening an
348  // existing one or by creating a new one?
349  bool successful = true;
350  bool new_file = false;
351 
352  // Close the storage if any was open
353  if (IsOpen()) Close();
354 
355  // Open or create the file if file name is not empty
356  if (file_path != "") {
357  // Try to open the file if it exists and is an HDF5 file
358  // Save old error handler and turn off error handling temporarily since this function
359  // fail and will clutter up the stdout.
360  herr_t (*old_func)(hid_t, void*);
361  void *old_client_data;
362  H5Eget_auto(H5E_DEFAULT, &old_func, &old_client_data);
363  H5Eset_auto(H5E_DEFAULT, NULL, NULL);
364  htri_t is_hdf5 = H5Fis_hdf5(file_path.c_str());
365  // Restore previous error handler
366  H5Eset_auto(H5E_DEFAULT, old_func, old_client_data);
367  if (0 < is_hdf5) {
368  // File exists and is in HDF5 format, open it
369  m_file_id = H5Fopen(file_path.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
370  if (m_file_id < 0) {
371  // File exists and is HDF5 but can not be opened, pretty strange: bail out!
372  cerr << here << "[Hdf5File] Error: \'" << file_path << "\' seems to be valid HDF5 but could not be opened.\
373  Might be you don\'t have r/w permissions." << endl;
374  successful = false;
375  } else {
376  successful = true;
377  new_file = false;
378  m_file_path = file_path;
379  }
380  } else if (0 == is_hdf5) {
381  // File exists but is not in HDF5 format: bail out!
382  cerr << here << "[Hdf5File] Error: \'" << file_path << "\' is not a valid HDF5 file.\
383  I can neither open it, nor will I truncate it." << endl;
384  successful = false;
385  } else {
386  // File does not exist, create a new one
387  m_file_id = H5Fcreate(file_path.c_str(), H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT);
388  if (m_file_id < 0) {
389  // Probably no permissions to create a file
390  cerr << here << "[Hdf5File] Error: \'" << file_path << "\' could not be created nor opened.\
391  Check your r/w permissions." << endl;
392  successful = false;
393  } else {
394  successful = true;
395  new_file = true;
396  m_file_path = file_path;
397  }
398  }
399  }
400 
401  // Populate the new HDF5 file with the basic skeleton to keep time-series of simulation steps
402  // - /time_steps
403  // - /time_steps_idx
404  if (successful && new_file) {
405  // Create two extendable 1D double precision and integer array datasets
406  // to hold the simulation time steps in seconds (double precision floats)
407  // to hold the simulation time steps indices (integers)
408  // This data set must be extendable to allow appending time steps during the simulation
409  hsize_t time_steps_dims = 0; // Initial size: no elements
410  hsize_t time_steps_max_dims = H5S_UNLIMITED; // Can extend with no bounds
411 
412  // Create the data space, first argument 'rank' is 1 (i.e. 1 dimensional array)
413  hid_t time_steps_dspace = H5Screate_simple(1, &time_steps_dims, &time_steps_max_dims);
414 
415  // Create properties for dataset creation: chunking is necessary for extendable data sets
416  hid_t time_steps_dset_props = H5Pcreate(H5P_DATASET_CREATE);
417  hsize_t time_steps_chunk_dims = 10; // Rather arbitrary chunk size
418  H5Pset_chunk(time_steps_dset_props, 1, &time_steps_chunk_dims); // 1 is the rank of a 1D array
419 
420  // Create data set '/time_steps' (link creation and data access properties are default)
421  hid_t time_steps_dset = H5Dcreate(m_file_id, "/time_steps", H5T_IEEE_F64LE,
422  time_steps_dspace, H5P_DEFAULT, time_steps_dset_props, H5P_DEFAULT);
423  if (time_steps_dset < 0) {
424  cerr << here << "[Hdf5File] Error: could not create \'/time_steps\' dataset." << endl;
425  successful = false;
426  }
427 
428  // Create data set '/time_steps_idx' (link creation and data access properties are default)
429  hid_t time_steps_idx_dset = H5Dcreate(m_file_id, "/time_steps_idx", H5T_STD_I32LE,
430  time_steps_dspace, H5P_DEFAULT, time_steps_dset_props, H5P_DEFAULT);
431  if (time_steps_idx_dset < 0) {
432  cerr << here << "[Hdf5File] Error: could not create \'/time_steps_idx\' dataset." << endl;
433  successful = false;
434  }
435 
436  // Clean up
437  H5Dclose(time_steps_dset);
438  H5Dclose(time_steps_idx_dset);
439  H5Sclose(time_steps_dspace);
440  H5Pclose(time_steps_dset_props);
441  }
442 
443  return successful;
444 }
445 
446 SimState Hdf5File::Read(int step_idx)
447 {
448  if (!IsOpen()) {
449  throw runtime_error("[Hdf5File]: File needs to be open prior to reading.");
450  }
451 
452  // The Sim/MeshState that will be filled up with information form HDF5 and returned
453  MeshState mstate;
454  SimState sstate;
455 
456  // =========================================================================
457  // Read information about time steps contained in the file
458  double* time_steps_data = nullptr;
459  size_t time_steps_dim1 = 0;
460  read_array_rank1(m_file_id, "time_steps", &time_steps_data, H5T_NATIVE_DOUBLE, &time_steps_dim1);
461 
462  int* time_steps_idx_data = nullptr;
463  size_t time_steps_idx_dim1 = 0;
464  read_array_rank1(m_file_id, "time_steps_idx", &time_steps_idx_data, H5T_NATIVE_INT, &time_steps_idx_dim1);
465 
466  // Check size consistency of /time_steps and /time_step_idx
467  if (time_steps_dim1 != time_steps_idx_dim1) {
468  string errmsg = string("Error reading file \'") + m_file_path
469  + string("\': The /time_steps and /time_steps_idx datasets must be the same size. File might be corrupted.");
470  // Clean up temp storage
471  delete[] time_steps_data;
472  delete[] time_steps_idx_data;
473  throw runtime_error(errmsg);
474  }
475 
476  if (-1 == step_idx) {
477  // Use the last time step if no step was requested
478  step_idx = time_steps_idx_dim1 - 1;
479  }
480 
481  const size_t sim_step = time_steps_idx_data[step_idx];
482  const double sim_time = time_steps_data[step_idx];
483 
484  // Try to open the requested time step
485  string step_grp_name = string("/step_") + to_string(sim_step);
486  hid_t step_grp_id = H5Gopen(m_file_id, step_grp_name.c_str(), H5P_DEFAULT);
487  if (step_grp_id < 0) {
488  string errmsg = string("Error reading file \'") + m_file_path
489  + string("\': The group /step_") + to_string(sim_step)
490  + string(" does not exist. File might be corrupted.");
491  // Clean up temp storage
492  delete[] time_steps_data;
493  delete[] time_steps_idx_data;
494  throw runtime_error(errmsg);
495  }
496 
497  // Clean up temp storage
498  delete[] time_steps_data;
499  delete[] time_steps_idx_data;
500 
501  // =========================================================================
502 
503  ReadNodes(step_grp_id, mstate);
504  ReadCells(step_grp_id, mstate);
505  ReadBPNodes(step_grp_id, mstate);
506  // In the very special case of just one cell (e.g. in the beginning of
507  // a simulation, there's no walls. Hence: don't read walls in that case)
508  if (1 < mstate.GetNumCells()) {
509  ReadWalls(step_grp_id, mstate);
510  ReadBPWalls(step_grp_id, mstate);
511  }
512  //ptree params = ReadParameters(step_grp_id);
513  ptree params = ReadPtreeFromStringAttribute(step_grp_id, "parameters");
514  ptree re_state = ReadPtreeFromStringAttribute(step_grp_id, "random_engine");
515 
516  sstate.SetTimeStep(sim_step);
517  sstate.SetTime(sim_time);
518  sstate.SetParameters(params);
519  sstate.SetRandomEngineState(re_state);
520  sstate.SetMeshState(mstate);
521 
522  return sstate;
523 }
524 
525 void Hdf5File::ReadNodes(hid_t loc_id, MeshState& mstate)
526 {
527  // Reading nodes_id
528  int* nodes_id_data = nullptr;
529  size_t nodes_id_dim1 = 0;
530  read_array_rank1(loc_id, "nodes_id", &nodes_id_data, H5T_NATIVE_INT, &nodes_id_dim1);
531  // Will be used as reference size to validate other sizes
532  const size_t& num_nodes = nodes_id_dim1;
533 
534  // Reading nodes_xy
535  double* nodes_xy_data = nullptr;
536  size_t nodes_xy_dim1 = 0;
537  size_t nodes_xy_dim2 = 0;
538  read_array_rank2(loc_id, "nodes_xy", &nodes_xy_data, H5T_NATIVE_DOUBLE, &nodes_xy_dim1, &nodes_xy_dim2);
539 
540  // Verify dimensions
541  if (2 != nodes_xy_dim2) {
542  string errmsg = string("Error reading file \'") + m_file_path
543  + string("\': Second dimension of the /step_*/nodes_xy dataset must equal 2. File might be corrupted.");
544  // Clean up temp storage
545  delete[] nodes_id_data;
546  delete[] nodes_xy_data;
547  throw runtime_error(errmsg);
548  }
549  if (num_nodes != nodes_xy_dim1) {
550  string errmsg = string("Error reading file \'") + m_file_path
551  + string("\': Dimensions of \'nodes_xy\' and \'nodes_id\' datasets don\'t match. File might be corrupted.");
552  // Clean up temp storage
553  delete[] nodes_id_data;
554  delete[] nodes_xy_data;
555  throw runtime_error(errmsg);
556  }
557 
558  // Build nodes from data read before
559  mstate.SetNumNodes(num_nodes);
560  for (size_t node_idx = 0; node_idx < num_nodes; ++node_idx) {
561  assert( node_idx == static_cast<unsigned int>(nodes_id_data[node_idx]) && "Error for node ids");
562  mstate.SetNodeID(node_idx, nodes_id_data[node_idx]);
563  mstate.SetNodeX(node_idx, nodes_xy_data[2 * node_idx]);
564  mstate.SetNodeY(node_idx, nodes_xy_data[2 * node_idx + 1]);
565  }
566 
567  // Clean up temp storage
568  delete[] nodes_id_data;
569  delete[] nodes_xy_data;
570 
571  // Find datasets that are called 'nodes_attr_<name>' (I.e.: node attributes)
572  list<string> attr_names = find_matching_links(loc_id, [](string name)->bool{
573  return boost::starts_with(name, "nodes_attr_");
574  });
575 
576  // Try to read all matching node attribute datasets
577  for (string long_name : attr_names) {
578  // Magic number 11 is the length of the prefix "nodes_attr_" that needs top be stripped away
579  string short_name = long_name.substr(11, string::npos);
580 
581  // Check if "long_name" refers to a valid rank-1 dataset in loc_id
582  H5O_info_t obj_info;
583  H5Oget_info_by_name(loc_id, long_name.c_str(), &obj_info, H5P_DEFAULT);
584  if (H5O_TYPE_DATASET == obj_info.type) {
585  // Open the dataset to get all info
586  hid_t dset = H5Dopen(loc_id, long_name.c_str(), H5P_DEFAULT);
587 
588  // Make sure dimensions match
589  hid_t dspace = H5Dget_space(dset);
590  // Check if rank = 1
591  const int ndims = H5Sget_simple_extent_ndims(dspace);
592  if (1 != ndims) {
593  H5Sclose(dspace);
594  break;
595  }
596  // Check if number of attribute values = number of nodes
597  hsize_t dims = 0;
598  H5Sget_simple_extent_dims(dspace, &dims, 0);
599  if (num_nodes != dims) {
600  H5Sclose(dspace);
601  break;
602  }
603 
604  // Get the type of the attribute from HDF5 (either int or double)
605  hid_t dtype = H5Dget_type(dset);
606  H5T_class_t dtype_class = H5Tget_class(dtype);
607  H5Tclose(dtype);
608  if (H5T_INTEGER == dtype_class) {
609  // Read the data directly into a vector
610  vector<int> attr_values(num_nodes);
611  H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, attr_values.data());
612  // Add attribute and its values to the nodes
613  mstate.NodeAttributeContainer().Add<int>(short_name);
614  mstate.NodeAttributeContainer().SetAll<int>(short_name, attr_values);
615  } else if (H5T_FLOAT == dtype_class) {
616  // Read the data directly into a vector
617  vector<double> attr_values(num_nodes);
618  H5Dread(dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, attr_values.data());
619  // Add attribute and its values to the nodes
620  mstate.NodeAttributeContainer().Add<double>(short_name);
621  mstate.NodeAttributeContainer().SetAll<double>(short_name, attr_values);
622  } else if (H5T_STRING == dtype_class) {
623  // Read the raw string data directly into a vector of C-style strings
624  vector<char*> raw_attr_values(num_nodes);
625  hid_t ntype = H5Tcopy(H5T_C_S1);
626  H5Tset_size(ntype, H5T_VARIABLE);
627  H5Dread(dset, ntype, H5S_ALL, H5S_ALL, H5P_DEFAULT, raw_attr_values.data());
628  H5Tclose(ntype);
629 
630  // Convert the C-style strings to a C++ string vector
631  vector<string> attr_values(raw_attr_values.begin(), raw_attr_values.end());
632 
633  // Add attribute and its values to the nodes
634  mstate.NodeAttributeContainer().Add<string>(short_name);
635  mstate.NodeAttributeContainer().SetAll<string>(short_name, attr_values);
636  } else {
637  // Unsupported datatype: ignore (or generate a warning)
638  }
639 
640  // Clean up
641  H5Dclose(dset);
642  }
643  }
644 }
645 
646 void Hdf5File::ReadCells(hid_t loc_id, MeshState& mstate)
647 {
648  // Reading 'cells_id'
649  int* cells_id_data = nullptr;
650  size_t cells_id_dim1 = 0;
651  read_array_rank1(loc_id, "cells_id", &cells_id_data, H5T_NATIVE_INT, &cells_id_dim1);
652  // Will be used as reference size to validate other sizes
653  const size_t & num_cells = cells_id_dim1;
654 
655  // Reading 'cells_num_nodes'
656  int* cells_num_nodes_data = nullptr;
657  size_t cells_num_nodes_dim1 = 0;
658  read_array_rank1(loc_id, "cells_num_nodes", &cells_num_nodes_data, H5T_NATIVE_INT, &cells_num_nodes_dim1);
659 
660  // Reading 'cells_nodes'
661  int* cells_nodes_data = nullptr;
662  size_t cells_nodes_dim1 = 0, cells_nodes_dim2 = 0;
663  read_array_rank2(loc_id, "cells_nodes", &cells_nodes_data, H5T_NATIVE_INT, &cells_nodes_dim1, &cells_nodes_dim2);
664  const size_t & max_num_cell_nodes = cells_nodes_dim2;
665 
666  // Reading 'cells_num_walls'
667  int* cells_num_walls_data = nullptr;
668  size_t cells_num_walls_dim1 = 0;
669  read_array_rank1(loc_id, "cells_num_walls", &cells_num_walls_data, H5T_NATIVE_INT, &cells_num_walls_dim1);
670 
671  // Reading 'cells_walls'
672  // (Don't read 'cells_walls' in the special case of one cell, which has no walls)
673  int* cells_walls_data = nullptr;
674  size_t cells_walls_dim1 = 0, cells_walls_dim2 = 0;
675  if (1 != num_cells) {
676  read_array_rank2(loc_id, "cells_walls", &cells_walls_data, H5T_NATIVE_INT, &cells_walls_dim1, &cells_walls_dim2);
677  }
678  const size_t & max_num_cell_walls = cells_walls_dim2;
679 
680  // Verify dimensions
681  if (num_cells != cells_num_nodes_dim1) {
682  string errmsg = string("Error reading file \'") + m_file_path
683  + string("\': Dimensions of \'cells_num_nodes\' and \'cells_id\' datasets don\'t match. File might be corrupted.");
684  // Clean up temp storage
685  delete[] cells_id_data;
686  delete[] cells_num_nodes_data;
687  delete[] cells_nodes_data;
688  delete[] cells_num_walls_data;
689  delete[] cells_walls_data;
690  throw runtime_error(errmsg);
691  }
692  if (num_cells != cells_nodes_dim1) {
693  string errmsg = string("Error reading file \'") + m_file_path
694  + string("\': Dimensions of \'cells_nodes\' and \'cells_id\' datasets don\'t match. File might be corrupted.");
695  // Clean up temp storage
696  delete[] cells_id_data;
697  delete[] cells_num_nodes_data;
698  delete[] cells_nodes_data;
699  delete[] cells_num_walls_data;
700  delete[] cells_walls_data;
701  throw runtime_error(errmsg);
702  }
703  if (num_cells != cells_num_walls_dim1) {
704  string errmsg = string("Error reading file \'") + m_file_path
705  + string("\': Dimensions of \'cells_num_walls\' and \'cells_id\' datasets don\'t match. File might be corrupted.");
706  // Clean up temp storage
707  delete[] cells_id_data;
708  delete[] cells_num_nodes_data;
709  delete[] cells_nodes_data;
710  delete[] cells_num_walls_data;
711  delete[] cells_walls_data;
712  throw runtime_error(errmsg);
713  }
714  // Don't pay attention to anything related to 'cells_walls'
715  // in the special case of one cell, which has no walls
716  if (1 != num_cells && num_cells != cells_walls_dim1) {
717  string errmsg = string("Error reading file \'") + m_file_path
718  + string("\': Dimensions of \'cells_walls\' and \'cells_id\' datasets don\'t match. File might be corrupted.");
719  // Clean up temp storage
720  delete[] cells_id_data;
721  delete[] cells_num_nodes_data;
722  delete[] cells_nodes_data;
723  delete[] cells_num_walls_data;
724  delete[] cells_walls_data;
725  throw runtime_error(errmsg);
726  }
727 
728  // Build cells from data read before (new API)
729  mstate.SetNumCells(num_cells);
730  for (size_t cell_idx = 0; cell_idx < num_cells; ++cell_idx) {
731  // ID of the cell
732  assert(cell_idx == static_cast<unsigned int>(cells_id_data[cell_idx]) && "Error for cell ids");
733  mstate.SetCellID(cell_idx, cells_id_data[cell_idx]);
734  // List of node IDs that make up this cell's polygon
735  vector<int> cell_nodes;
736  for (size_t cell_node_idx = 0; cell_node_idx < static_cast<size_t>(cells_num_nodes_data[cell_idx]);
737  ++cell_node_idx) {
738  // Data from 2D HDF5 dataset '/step_n/cells_nodes' is stored row-wise
739  // in the C++ array called 'cells_nodes_data'. This means that:
740  // - first dimension is: cell node ids
741  // - second dimension is: cells
742  // and hence the index is:
743  size_t idx = cell_node_idx + (cell_idx * max_num_cell_nodes);
744  cell_nodes.push_back(cells_nodes_data[idx]);
745  }
746  // Set the current cell's nodes in MeshState
747  mstate.SetCellNodes(cell_idx, cell_nodes);
748  // List of wall IDs that connect this cell to its neighbors
749  vector<int> cell_walls;
750  for (size_t cell_wall_idx = 0; cell_wall_idx < static_cast<size_t>(cells_num_walls_data[cell_idx]);
751  ++cell_wall_idx) {
752  // Data from 2D HDF5 dataset '/step_n/cells_walls' is stored row-wise
753  // in the C++ array called 'cells_walls_data'. This means that:
754  // - first dimension is: cell wall ids
755  // - second dimension is: cells
756  // and hence the index is:
757  size_t idx = cell_wall_idx + (cell_idx * max_num_cell_walls);
758  cell_walls.push_back(cells_walls_data[idx]);
759  }
760  // Set the current cell's walls in MeshState
761  mstate.SetCellWalls(cell_idx, cell_walls);
762  }
763 
764  // Clean up temp storage
765  delete[] cells_id_data;
766  delete[] cells_num_nodes_data;
767  delete[] cells_nodes_data;
768  delete[] cells_num_walls_data;
769  delete[] cells_walls_data;
770 
771  // Find datasets that are called 'cells_attr_<name>' (I.e.: cell attributes)
772  list<string> attr_names = find_matching_links(loc_id, [](string name)->bool {
773  return boost::starts_with(name, "cells_attr_");
774  });
775 
776  // Try to read all matching cell attribute datasets
777  for (string long_name : attr_names) {
778  // Magic number 11 is the length of the prefix "cells_attr_" that needs top be stripped away
779  string short_name = long_name.substr(11, string::npos);
780 
781  // Check if "long_name" refers to a valid rank-1 dataset in loc_id
782  H5O_info_t obj_info;
783  H5Oget_info_by_name(loc_id, long_name.c_str(), &obj_info, H5P_DEFAULT);
784  if (H5O_TYPE_DATASET == obj_info.type) {
785  // Open the dataset to get all info
786  hid_t dset = H5Dopen(loc_id, long_name.c_str(), H5P_DEFAULT);
787 
788  // Make sure dimensions match
789  hid_t dspace = H5Dget_space(dset);
790  // Check if rank = 1
791  const int ndims = H5Sget_simple_extent_ndims(dspace);
792  if (1 != ndims) {
793  H5Sclose(dspace);
794  break;
795  }
796  // Check if number of attribute values = number of cells
797  hsize_t dims = 0;
798  H5Sget_simple_extent_dims(dspace, &dims, 0);
799  if (num_cells != dims) {
800  H5Sclose(dspace);
801  break;
802  }
803 
804  // Get the type of the attribute from HDF5 (either int or double)
805  hid_t dtype = H5Dget_type(dset);
806  H5T_class_t dtype_class = H5Tget_class(dtype);
807  H5Tclose(dtype);
808  if (H5T_INTEGER == dtype_class) {
809  // Read the data directly into a vector
810  vector<int> attr_values(num_cells);
811  H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, attr_values.data());
812  // Add attribute and its values to the cells
813  mstate.CellAttributeContainer().Add<int>(short_name);
814  mstate.CellAttributeContainer().SetAll<int>(short_name, attr_values);
815  } else if (H5T_FLOAT == dtype_class) {
816  // Read the data directly into a vector
817  vector<double> attr_values(num_cells);
818  H5Dread(dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, attr_values.data());
819  // Add attribute and its values to the cells
820  mstate.CellAttributeContainer().Add<double>(short_name);
821  mstate.CellAttributeContainer().SetAll<double>(short_name, attr_values);
822  } else if (H5T_STRING == dtype_class) {
823  // Read the raw string data directly into a vector of C-style strings
824  vector<char*> raw_attr_values(num_cells);
825  hid_t ntype = H5Tcopy(H5T_C_S1);
826  H5Tset_size(ntype, H5T_VARIABLE);
827  H5Dread(dset, ntype, H5S_ALL, H5S_ALL, H5P_DEFAULT, raw_attr_values.data());
828  H5Tclose(ntype);
829 
830  // Convert the C-style strings to a C++ string vector
831  vector < string > attr_values(raw_attr_values.begin(), raw_attr_values.end());
832 
833  // Add attribute and its values to the cells
834  mstate.CellAttributeContainer().Add<string>(short_name);
835  mstate.CellAttributeContainer().SetAll<string>(short_name, attr_values);
836  } else {
837  // Unsupported datatype: ignore (or generate a warning)
838  }
839 
840  // Clean up
841  H5Dclose(dset);
842  }
843  }
844 }
845 
846 void Hdf5File::ReadBPNodes(hid_t loc_id, MeshState& mstate)
847 {
848  // Reading 'bp_nodes'
849  int* bp_nodes_data = 0;
850  size_t bp_nodes_dim1 = 0;
851  read_array_rank1(loc_id, "bp_nodes", &bp_nodes_data, H5T_NATIVE_INT, &bp_nodes_dim1);
852 
853  // Copy to temporary vectors
854  vector<int> bp_nodes(bp_nodes_dim1);
855  for (size_t node_idx = 0; node_idx < bp_nodes_dim1; ++node_idx) {
856  bp_nodes[node_idx] = bp_nodes_data[node_idx];
857  }
858 
859  // Use temp vectors to set boundary polygon in the mesh state
860  mstate.SetBoundaryPolygonNodes(bp_nodes);
861 
862  // Clean up temp storage
863  delete[] bp_nodes_data;
864 }
865 
866 void Hdf5File::ReadBPWalls(hid_t loc_id, MeshState& mstate)
867 {
868  // Reading 'bp_walls'
869  int* bp_walls_data = nullptr;
870  size_t bp_walls_dim1 = 0;
871  read_array_rank1(loc_id, "bp_walls", &bp_walls_data, H5T_NATIVE_INT, &bp_walls_dim1);
872 
873  // Copy to temporary vectors
874  vector<int> bp_walls(bp_walls_dim1);
875  for (size_t wall_idx = 0; wall_idx < bp_walls_dim1; ++wall_idx) {
876  bp_walls[wall_idx] = bp_walls_data[wall_idx];
877  }
878 
879  // Use temp vectors to set boundary polygon in the mesh state
880  mstate.SetBoundaryPolygonWalls(bp_walls);
881 
882  // Clean up temp storage
883  delete[] bp_walls_data;
884 }
885 
886 void Hdf5File::ReadWalls(hid_t loc_id, MeshState& mstate)
887 {
888  // Reading 'walls_id'
889  int* walls_id_data = nullptr;
890  size_t walls_id_dim1 = 0;
891  read_array_rank1(loc_id, "walls_id", &walls_id_data, H5T_NATIVE_INT, &walls_id_dim1);
892  // Will be used as reference size to validate other sizes
893  const size_t & num_walls = walls_id_dim1;
894 
895  // Reading 'walls_cells'
896  int* walls_cells_data = nullptr;
897  size_t walls_cells_dim1 = 0, walls_cells_dim2 = 0;
898  read_array_rank2(loc_id, "walls_cells", &walls_cells_data, H5T_NATIVE_INT, &walls_cells_dim1,
899  &walls_cells_dim2);
900 
901  // Reading 'walls_nodes'
902  int* walls_nodes_data = nullptr;
903  size_t walls_nodes_dim1 = 0, walls_nodes_dim2 = 0;
904  read_array_rank2(loc_id, "walls_nodes", &walls_nodes_data, H5T_NATIVE_INT, &walls_nodes_dim1,
905  &walls_nodes_dim2);
906 
907  // Verify dimensions
908  if (2 != walls_cells_dim2) {
909  string errmsg = string("Error reading file \'") + m_file_path
910  + string("\': Second dimension of the /step_*/walls_cells dataset must equal 2. File might be corrupted.");
911  // Clean up temp storage
912  delete[] walls_id_data;
913  delete[] walls_cells_data;
914  delete[] walls_nodes_data;
915  throw runtime_error(errmsg);
916  }
917  if (2 != walls_nodes_dim2) {
918  string errmsg = string("Error reading file \'") + m_file_path
919  + string("\': Second dimension of the /step_*/walls_nodes dataset must equal 2. File might be corrupted.");
920  // Clean up temp storage
921  delete[] walls_id_data;
922  delete[] walls_cells_data;
923  delete[] walls_nodes_data;
924  throw runtime_error(errmsg);
925  }
926  if (num_walls != walls_cells_dim1) {
927  string errmsg = string("Error reading file \'") + m_file_path
928  + string("\': Dimensions of \'walls_id\' and \'walls_cells\' datasets don\'t match. File might be corrupted.");
929  // Clean up temp storage
930  delete[] walls_id_data;
931  delete[] walls_cells_data;
932  delete[] walls_nodes_data;
933  throw runtime_error(errmsg);
934  }
935  if (num_walls != walls_nodes_dim1) {
936  string errmsg = string("Error reading file \'") + m_file_path
937  + string("\': Dimensions of \'walls_id\' and \'walls_nodes\' datasets don\'t match. File might be corrupted.");
938  // Clean up temp storage
939  delete[] walls_id_data;
940  delete[] walls_cells_data;
941  delete[] walls_nodes_data;
942  throw runtime_error(errmsg);
943  }
944 
945  // Build walls from data read before (new API)
946  mstate.SetNumWalls(num_walls);
947  for (size_t wall_idx = 0; wall_idx < num_walls; ++wall_idx) {
948  // ID of the wall
949  assert(wall_idx == static_cast<unsigned int>(walls_id_data[wall_idx]) && "Error for wall ids");
950  mstate.SetWallID(wall_idx, walls_id_data[wall_idx]);
951  // - IDs of the two cells the wall is connecting
952  // - IDs of the two nodes that are the endpoints of the wall
953  // (the IDs of cells and nodes are stored row-major in C++:
954  // * first dimension is: IDs of cells / nodes
955  // * second dimension is: walls)
956  mstate.SetWallCells(wall_idx,
957  make_pair(walls_cells_data[2 * wall_idx], walls_cells_data[2 * wall_idx + 1]));
958  mstate.SetWallNodes(wall_idx,
959  make_pair(walls_nodes_data[2 * wall_idx], walls_nodes_data[2 * wall_idx + 1]));
960  }
961 
962  // Clean up temp storage
963  delete[] walls_id_data;
964  delete[] walls_cells_data;
965  delete[] walls_nodes_data;
966 
967  // Find datasets that are called 'walls_attr_<name>' (I.e.: wall attributes)
968  list < string > attr_names = find_matching_links(loc_id, [](string name)->bool {
969  return boost::starts_with(name, "walls_attr_");
970  });
971 
972  // Try to read all matching wall attribute datasets
973  for (string long_name : attr_names) {
974  // Magic number 11 is the length of the prefix "cells_attr_" that needs top be stripped away
975  string short_name = long_name.substr(11, string::npos);
976 
977  // Check if "long_name" refers to a valid rank-1 dataset in loc_id
978  H5O_info_t obj_info;
979  H5Oget_info_by_name(loc_id, long_name.c_str(), &obj_info, H5P_DEFAULT);
980  if (H5O_TYPE_DATASET == obj_info.type) {
981  // Open the dataset to get all info
982  hid_t dset = H5Dopen(loc_id, long_name.c_str(), H5P_DEFAULT);
983 
984  // Make sure dimensions match
985  hid_t dspace = H5Dget_space(dset);
986  // Check if rank = 1
987  const int ndims = H5Sget_simple_extent_ndims(dspace);
988  if (1 != ndims) {
989  H5Sclose(dspace);
990  break;
991  }
992  // Check if number of attribute values = number of walls
993  hsize_t dims = 0;
994  H5Sget_simple_extent_dims(dspace, &dims, 0);
995  if (num_walls != dims) {
996  H5Sclose(dspace);
997  break;
998  }
999 
1000  // Get the type of the attribute from HDF5 (either int or double)
1001  hid_t dtype = H5Dget_type(dset);
1002  H5T_class_t dtype_class = H5Tget_class(dtype);
1003  H5Tclose(dtype);
1004  if (H5T_INTEGER == dtype_class) {
1005  // Read the data directly into a vector
1006  vector<int> attr_values(num_walls);
1007  H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, attr_values.data());
1008  // Add attribute and its values to the walls
1009  mstate.WallAttributeContainer().Add<int>(short_name);
1010  mstate.WallAttributeContainer().SetAll<int>(short_name, attr_values);
1011  } else if (H5T_FLOAT == dtype_class) {
1012  // Read the data directly into a vector
1013  vector<double> attr_values(num_walls);
1014  H5Dread(dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, attr_values.data());
1015  // Add attribute and its values to the walls
1016  mstate.WallAttributeContainer().Add<double>(short_name);
1017  mstate.WallAttributeContainer().SetAll<double>(short_name, attr_values);
1018  } else if (H5T_STRING == dtype_class) {
1019  // Read the raw string data directly into a vector of C-style strings
1020  vector<char*> raw_attr_values(num_walls);
1021  hid_t ntype = H5Tcopy(H5T_C_S1);
1022  H5Tset_size(ntype, H5T_VARIABLE);
1023  H5Dread(dset, ntype, H5S_ALL, H5S_ALL, H5P_DEFAULT, raw_attr_values.data());
1024  H5Tclose(ntype);
1025 
1026  // Convert the C-style strings to a C++ string vector
1027  vector < string > attr_values(raw_attr_values.begin(), raw_attr_values.end());
1028 
1029  // Add attribute and its values to the walls
1030  mstate.WallAttributeContainer().Add<string>(short_name);
1031  mstate.WallAttributeContainer().SetAll<string>(short_name, attr_values);
1032  } else {
1033  // Unsupported datatype: ignore (or generate a warning)
1034  }
1035 
1036  // Clean up
1037  H5Dclose(dset);
1038  }
1039  }
1040 }
1041 
1042 ptree Hdf5File::ReadParameters(hid_t loc_id)
1043 {
1044  hid_t param_grp_id = H5Gopen(loc_id, "parameters", H5P_DEFAULT);
1045  if (param_grp_id < 0) {
1046  string errmsg = string("Error reading file \'") + m_file_path
1047  + string("\': The group \'/step_*/parameters\' does not exist. File might be corrupted.");
1048  throw runtime_error(errmsg);
1049  }
1050  ptree params = hdf52ptree(param_grp_id);
1051  H5Gclose(param_grp_id);
1052  return params;
1053 }
1054 
1055 ptree Hdf5File::ReadPtreeFromStringAttribute(hid_t loc_id, const string& attr_name)
1056 {
1057  // Empty ptree to be filled with the contents of attr_name
1058  ptree pt;
1059 
1060  // Try to open the requested attribute at loc_id
1061  hid_t attr_id = H5Aopen(loc_id, attr_name.c_str(), H5P_DEFAULT);
1062 
1063  // If attribute was not found, an empty ptree will be returned
1064  if (attr_id > 0) {
1065  hid_t attr_dtype = H5Aget_type(attr_id);
1066  hid_t attr_dspace = H5Aget_space(attr_id);
1067 
1068  // Check if 'attr_name' is a string attribute indeed
1069  if (H5T_STRING == H5Tget_class(attr_dtype)) {
1070  // Note that H5T_STRING attributes are scalars so one does not check for ndims and dims.
1071  // Just read the attribute as a C string.
1072  char* attr_value;
1073  hid_t attr_ntype = H5Tcopy(H5T_C_S1);
1074  H5Tset_size(attr_ntype, H5T_VARIABLE);
1075  H5Aread(attr_id, attr_ntype, &attr_value);
1076  H5Tclose(attr_ntype);
1077 
1078  // Convert the attribute value from a C string into a stream to be translated to a ptree.
1079  stringstream pt_strm;
1080  pt_strm << attr_value;
1081  read_xml(pt_strm, pt, trim_whitespace);
1082 
1083  // Cleanup
1084  H5Dvlen_reclaim(attr_ntype, attr_dspace, H5P_DEFAULT, attr_value);
1085  }
1086 
1087  // Clean up handles and signal success to the calling function
1088  H5Sclose(attr_dspace);
1089  H5Tclose(attr_dtype);
1090  H5Aclose(attr_id);
1091  }
1092 
1093  return pt;
1094 }
1095 
1096 vector<pair<int, double>> Hdf5File::TimeSteps()
1097 {
1098  if (!IsOpen()) {
1099  throw runtime_error("[Hdf5File]: File needs to be open prior to reading.");
1100  }
1101 
1102  // =========================================================================
1103  // Read information about time steps contained in the file
1104  double* time_steps_data = nullptr;
1105  size_t time_steps_dim1 = 0;
1106  read_array_rank1(m_file_id, "time_steps", &time_steps_data, H5T_NATIVE_DOUBLE, &time_steps_dim1);
1107 
1108  int* time_steps_idx_data = nullptr;
1109  size_t time_steps_idx_dim1 = 0;
1110  read_array_rank1(m_file_id, "time_steps_idx", &time_steps_idx_data, H5T_NATIVE_INT, &time_steps_idx_dim1);
1111 
1112  // Check size consistency of /time_steps and /time_step_idx
1113  if (time_steps_dim1 != time_steps_idx_dim1) {
1114  string errmsg = string("Error reading file \'") + m_file_path
1115  + string("\': The /time_steps and /time_steps_idx datasets must be the same size. File might be corrupted.");
1116  // Clean up temp storage
1117  delete[] time_steps_data;
1118  delete[] time_steps_idx_data;
1119  throw runtime_error(errmsg);
1120  }
1121 
1122  vector<pair<int, double>> time_steps(time_steps_dim1);
1123  for (size_t i = 0; i < time_steps_dim1; ++i) {
1124  time_steps[i] = make_pair(time_steps_idx_data[i], time_steps_data[i]);
1125  }
1126 
1127  // Clean up temp storage
1128  delete[] time_steps_data;
1129  delete[] time_steps_idx_data;
1130 
1131  return time_steps;
1132 }
1133 
1134 void Hdf5File::Write(shared_ptr<const SimPT_Sim::Sim> sim)
1135 {
1136  // Just a wrapper around Write() to comply with the interface of FileViewer.
1137  // (could be replaced with WriteState such that Sim doesn't have to be passed around)
1138  WriteState(sim->GetState());
1139 }
1140 
1141 void Hdf5File::WriteCells(hid_t loc_id, const MeshState& mstate)
1142 {
1143  const size_t num_cells = mstate.GetNumCells();
1144  // Cell information is stored in a variety of arrays and matrices that
1145  // keep geometric information as well as other cell attributes.
1146  // All arrays have length 'num_cells', unless explicitly specified otherwise.
1147  // All matrices are stored as row-major C-style arrays.
1148  //
1149  // Each cell has a unique ID, these are stored in the array 'cells_id'
1150  //
1151  // Geometric information of a cell consists of:
1152  // - Number of nodes used to define a cell: stored in the 'cells_num_nodes' array.
1153  // - IDs of the nodes that define the cell's polygon: 'cells_nodes' matrix
1154  // Each row in this matrix represents a cell. Elements of each row are
1155  // IDs of the nodes (cfr.: 'nodes_id') that make up the cell's polygon.
1156  // Since not all cells have the same number of nodes, some storage space is lost.
1157  // Although cell's polygons are well-defined by both 'cells_nodes' and
1158  // 'cells_num_nodes' combined, padding (-1) is used to make the
1159  // 'cells_nodes' array easier to read and interpret.
1160  //
1161  // Attributes of cells might be for instance:
1162  // - Values of cell-based chemicals.
1163  // - Area and target area of each cell.
1164  // - Type of each cell.
1165  // - And many others ...
1166 
1167  // Cell IDs
1168  const vector<int> cells_id = mstate.GetCellsID();
1169  write_array_rank1(loc_id, "cells_id", cells_id.data(), H5T_STD_I32LE, num_cells);
1170 
1171  // Max number of nodes in a cell
1172  size_t max_cells_num_nodes = 0;
1173  const vector<size_t> cells_num_nodes = mstate.GetCellsNumNodes();
1174  for (size_t cell_num_nodes : cells_num_nodes) {
1175  if (cell_num_nodes > max_cells_num_nodes) {
1176  max_cells_num_nodes = cell_num_nodes;
1177  }
1178  }
1179 
1180  // Max number of walls in a cell
1181  size_t max_cells_num_walls = 0;
1182  const vector<size_t> cells_num_walls = mstate.GetCellsNumWalls();
1183  for (size_t cell_num_walls : cells_num_walls) {
1184  if (cell_num_walls > max_cells_num_walls) {
1185  max_cells_num_walls = cell_num_walls;
1186  }
1187  }
1188 
1189  // Allocate space for geometric data and copy that from the state
1190  int* cells_num_nodes_data = new int[num_cells];
1191  int* cells_nodes_data = new int[num_cells * max_cells_num_nodes];
1192  int* cells_num_walls_data = new int[num_cells];
1193  int* cells_walls_data = new int[num_cells * max_cells_num_walls];
1194 
1195  for (size_t cell_idx = 0; cell_idx < num_cells; ++cell_idx) {
1196  // Number of nodes in the cell
1197  cells_num_nodes_data[cell_idx] = cells_num_nodes[cell_idx];
1198  // Nodes of the cells (i.e.: polygonal geometry information)
1199  size_t cell_node_idx = 0;
1200  for (const int cell_node_id : mstate.GetCellNodes(cell_idx)) {
1201  cells_nodes_data[(cell_idx * max_cells_num_nodes) + cell_node_idx] = cell_node_id;
1202  ++cell_node_idx;
1203  }
1204  // Pad the remaining positions in the row with -1
1205  while (cell_node_idx < max_cells_num_nodes) {
1206  cells_nodes_data[(cell_idx * max_cells_num_nodes) + cell_node_idx] = -1;
1207  ++cell_node_idx;
1208  }
1209 
1210  // Number of walls in the cell
1211  cells_num_walls_data[cell_idx] = cells_num_walls[cell_idx];
1212  // Walls of the cells (i.e.: connectivity information)
1213  size_t cell_wall_idx = 0;
1214  for (const int cell_wall_id : mstate.GetCellWalls(cell_idx)) {
1215  cells_walls_data[(cell_idx * max_cells_num_walls) + cell_wall_idx] = cell_wall_id;
1216  ++cell_wall_idx;
1217  }
1218  // Pad the remaining positions in the row with -1
1219  while (cell_wall_idx < max_cells_num_walls) {
1220  cells_walls_data[(cell_idx * max_cells_num_walls) + cell_wall_idx] = -1;
1221  ++cell_wall_idx;
1222  }
1223  }
1224 
1225  // Write data arrays to HDF5
1226  // (Don't write cells_walls in the special case of one cell, which has no walls)
1227  write_array_rank1(loc_id, "cells_num_nodes", cells_num_nodes_data, H5T_STD_I32LE, num_cells);
1228  write_array_rank2(loc_id, "cells_nodes", cells_nodes_data, H5T_STD_I32LE, num_cells, max_cells_num_nodes);
1229  write_array_rank1(loc_id, "cells_num_walls", cells_num_walls_data, H5T_STD_I32LE, num_cells);
1230  if (1 != num_cells) {
1231  write_array_rank2(loc_id, "cells_walls", cells_walls_data, H5T_STD_I32LE, num_cells, max_cells_num_walls);
1232  }
1233 
1234  // Clean up temporary arrays
1235  delete[] cells_num_nodes_data;
1236  delete[] cells_nodes_data;
1237  delete[] cells_num_walls_data;
1238  delete[] cells_walls_data;
1239 
1240  // Cell attributes (int)
1241  for (string attr_name : mstate.CellAttributeContainer().GetNames<int>()) {
1242  const vector<int> attr_values = mstate.CellAttributeContainer().GetAll<int>(attr_name);
1243  string attr_name_hdf5 = string("cells_attr_") + attr_name;
1244  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values.data(), H5T_STD_I32LE, num_cells);
1245  }
1246 
1247  // Cell attributes (double)
1248  for (string attr_name : mstate.CellAttributeContainer().GetNames<double>()) {
1249  const vector<double> attr_values = mstate.CellAttributeContainer().GetAll<double>(attr_name);
1250  string attr_name_hdf5 = string("cells_attr_") + attr_name;
1251  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values.data(), H5T_IEEE_F64LE, num_cells);
1252  }
1253 
1254  // Cell attributes (string)
1255  for (string attr_name : mstate.CellAttributeContainer().GetNames<string>()) {
1256  const vector<string> attr_values = mstate.CellAttributeContainer().GetAll<string>(attr_name);
1257  string attr_name_hdf5 = string("cells_attr_") + attr_name;
1258  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values);
1259  }
1260 }
1261 
1262 void Hdf5File::WriteBPNodes(hid_t loc_id, const MeshState& mstate)
1263 {
1264  vector<int> bp_nodes = mstate.GetBoundaryPolygonNodes();
1265  write_array_rank1(loc_id, "bp_nodes", bp_nodes.data(), H5T_STD_I32LE, bp_nodes.size());
1266 }
1267 
1268 void Hdf5File::WriteBPWalls(hid_t loc_id, const MeshState& mstate)
1269 {
1270  vector<int> bp_walls = mstate.GetBoundaryPolygonWalls();
1271  write_array_rank1(loc_id, "bp_walls", bp_walls.data(), H5T_STD_I32LE, bp_walls.size());
1272 }
1273 
1274 void Hdf5File::WriteMesh(hid_t loc_id, const MeshState& mstate)
1275 {
1276  string const here = string(VL_HERE) + "> ";
1277  // Split up in three parts for readability
1278  WriteNodes(loc_id, mstate);
1279  WriteCells(loc_id, mstate);
1280  WriteBPNodes(loc_id, mstate);
1281  // In the very special case of just one cell (e.g. in the beginning of
1282  // a simulation, there's no walls. Hence: don't write walls in that case)
1283  const size_t num_cells = mstate.GetNumCells();
1284  const size_t num_walls = mstate.GetNumWalls();
1285  if (num_cells > 1 && num_walls > 0) {
1286  WriteWalls(loc_id, mstate);
1287  WriteBPWalls(loc_id, mstate);
1288  } else if ((num_cells == 1 && num_walls != 0) || (num_cells > 1 && num_walls == 0)) {
1289  cerr << here
1290  << "[Hdf5File] Error: inconsistent number of cells and walls: (#cells > 1) iff (#walls > 0)"
1291  << endl;
1292  }
1293  // The case (#cells == 1) && (#walls == 0) means that no walls should be written, which is handled silently
1294 }
1295 
1296 void Hdf5File::WriteNodes(hid_t loc_id, const MeshState& mstate)
1297 {
1298  const size_t num_nodes = mstate.GetNumNodes();
1299  // TODO: Document how nodes are written to HDF5
1300 
1301  // Node IDs
1302  vector<int> nodes_id = mstate.GetNodesID();
1303  write_array_rank1(loc_id, "nodes_id", nodes_id.data(), H5T_STD_I32LE, num_nodes);
1304 
1305  // Node xy coordinates
1306  double* nodes_xy_data = new double[2 * num_nodes];
1307  for (size_t node_idx = 0; node_idx < num_nodes; ++node_idx) {
1308  nodes_xy_data[2 * node_idx] = mstate.GetNodeX(node_idx);
1309  nodes_xy_data[2 * node_idx + 1] = mstate.GetNodeY(node_idx);
1310  }
1311  write_array_rank2(loc_id, "nodes_xy", nodes_xy_data, H5T_IEEE_F64LE, num_nodes, 2);
1312  delete[] nodes_xy_data;
1313 
1314  // Node attributes (int)
1315  for (string attr_name : mstate.NodeAttributeContainer().GetNames<int>()) {
1316  vector<int> attr_values = mstate.NodeAttributeContainer().GetAll<int>(attr_name);
1317  string attr_name_hdf5 = string("nodes_attr_") + attr_name;
1318  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values.data(), H5T_STD_I32LE, num_nodes);
1319  }
1320 
1321  // Node attributes (double)
1322  for (string attr_name : mstate.NodeAttributeContainer().GetNames<double>()) {
1323  vector<double> attr_values = mstate.NodeAttributeContainer().GetAll<double>(attr_name);
1324  string attr_name_hdf5 = string("nodes_attr_") + attr_name;
1325  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values.data(), H5T_IEEE_F64LE, num_nodes);
1326  }
1327 
1328  // Node attributes (string)
1329  for (string attr_name : mstate.NodeAttributeContainer().GetNames<string>()) {
1330  vector < string > attr_values = mstate.NodeAttributeContainer().GetAll<string>(attr_name);
1331  string attr_name_hdf5 = string("nodes_attr_") + attr_name;
1332  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values);
1333  }
1334 }
1335 
1336 void Hdf5File::WriteParameters(hid_t loc_id, const ptree& params)
1337 {
1338  // Create a HDF5 group /step_n/parameters where the subtrees aof param
1339  // will be stored as subgroups
1340  hid_t param_grp = H5Gcreate(loc_id, "parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1341  // Transform the ptree structure to HDF5 subgroups and named attributes
1342  // with parameter values inside the group [loc_id]/parameters
1343  ptree2hdf5(params, param_grp);
1344  // Clean up HDF5 handles
1345  H5Gclose(param_grp);
1346 }
1347 
1348 void Hdf5File::WritePtreeToStringAttribute(hid_t loc_id, const string& attr_name, const ptree& pt)
1349 {
1350  // Get the ptree in a C style string
1351  stringstream pt_strm;
1352  write_xml(pt_strm, pt, XmlWriterSettings::GetTab());
1353  string pt_str = pt_strm.str();
1354  const char* pt_cstr = pt_str.c_str();
1355 
1356  // Write pt_str to HDF5 attribute attr_name as a variable-length string
1357  hid_t attr_dspace = H5Screate(H5S_SCALAR);
1358  hid_t attr_dtype = H5Tcopy(H5T_C_S1);
1359  H5Tset_size(attr_dtype, H5T_VARIABLE);
1360  hid_t attr_id = H5Acreate(loc_id, attr_name.c_str(), attr_dtype, attr_dspace, H5P_DEFAULT, H5P_DEFAULT);
1361  H5Awrite(attr_id, attr_dtype, &pt_cstr);
1362  H5Aclose(attr_id);
1363  H5Sclose(attr_dspace);
1364  H5Tclose(attr_dtype);
1365 }
1366 
1367 void Hdf5File::WriteState(const SimState& sstate)
1368 {
1369  const string here = string(VL_HERE) + "> ";
1370 
1371  // ========================================================================
1372  // First do the following checks
1373  // - Can '/time_steps' be opened & are the dimensions correct?
1374  // -> fatal if condition not met
1375  // - Can '/time_steps_idx' be opened & are the dimensions correct?
1376  // -> fatal if condition not met
1377  // - Is sstate.GetTimeStep() already present in 'time_steps_idx' OR are there any time steps beyond?
1378  // -> remove all time steps(_idx) beyond that point, then add new time step
1379  // - Is the group '/step_n' already present for the current step?
1380  // -> remove all /step_n groups starting from that point, then add new time step group
1381  // ========================================================================
1382 
1383  double* time_steps_data = nullptr;
1384  size_t time_steps_dim1 = 0;
1385  read_array_rank1(m_file_id, "time_steps", &time_steps_data, H5T_NATIVE_DOUBLE, &time_steps_dim1);
1386 
1387  int* time_steps_idx_data = nullptr;
1388  size_t time_steps_idx_dim1 = 0;
1389  read_array_rank1(m_file_id, "time_steps_idx", &time_steps_idx_data, H5T_NATIVE_INT, &time_steps_idx_dim1);
1390 
1391  // Sanity check: dimensions of 'time_steps' and 'time_steps_idx' must match
1392  if (time_steps_dim1 != time_steps_idx_dim1) {
1393  // Clean up temporary structures for time_steps
1394  delete[] time_steps_data;
1395  delete[] time_steps_idx_data;
1396  throw runtime_error("[Hdf5File] Error: dim of time_steps and time_steps_idx do not match.");
1397  }
1398 
1399  // Shorthand notations
1400  size_t& num_time_steps = time_steps_dim1;
1401  const double sim_time = sstate.GetTime();
1402  const int sim_step = sstate.GetTimeStep();
1403  string step_grp_name = string("/step_") + to_string(sim_step);
1404 
1405  //cout << "HDF5: trying to write " << step_grp_name << endl;
1406 
1407  // Safe cases where no truncation is done are:
1408  // num_time_steps = 0
1409  // sim_step > time_steps_idx[end]
1410  // Hence truncation must be performed in the following case:
1411  if (num_time_steps != 0 && sim_step <= time_steps_idx_data[num_time_steps - 1]) {
1412  // cout << "[Hdf5File] File will be truncated." << endl;
1413  // To find the last step in time_steps_idx BEFORE sim_step loop over
1414  // the time_steps_idx values backwards until sim_step is reached
1415  size_t i = num_time_steps - 1;
1416  // cout << "[Hdf5File] Removing /step_[";
1417  while (static_cast<int>(i) >= 0 && sim_step <= time_steps_idx_data[i]) {
1418  // cout << time_steps_idx_data[i] << ' ';
1419  string name = string("step_") + to_string(time_steps_idx_data[i]);
1420  // Read: http://www.hdfgroup.org/HDF5/doc/H5.user/Performance.html#Freespace
1421  // to see why your data files are getting bigger while being truncated.
1422  H5Ldelete(m_file_id, name.c_str(), H5P_DEFAULT);
1423  --i;
1424  }
1425  //cout << ']' << endl;
1426  // Now i is the index of the last time_steps_idx BEFORE sim_step
1427  // cout << "HDF5: i = " << i << " time_steps_idx[i] = " << time_steps_idx_data[i] << endl;
1428  // Remove elements with index i+1 -> num_time_steps-1 from time_steps(_idx)
1429  // by resizing both datasets to contain i + 1 elements.
1430  {
1431  hid_t dset = H5Dopen(m_file_id, "time_steps", H5P_DEFAULT);
1432  hsize_t dims;
1433  hid_t dspace = H5Dget_space(dset);
1434  H5Sget_simple_extent_dims(dspace, &dims, 0);
1435  dims = i + 1;
1436  H5Dset_extent(dset, &dims);
1437  H5Sclose(dspace);
1438  H5Dclose(dset);
1439  }
1440  {
1441  hid_t dset = H5Dopen(m_file_id, "time_steps_idx", H5P_DEFAULT);
1442  hsize_t dims;
1443  hid_t dspace = H5Dget_space(dset);
1444  H5Sget_simple_extent_dims(dspace, &dims, 0);
1445  dims = i + 1;
1446  H5Dset_extent(dset, &dims);
1447  H5Sclose(dspace);
1448  H5Dclose(dset);
1449  }
1450  }
1451 
1452  // Clean up temporary structures for time_steps
1453  delete[] time_steps_data;
1454  delete[] time_steps_idx_data;
1455 
1456  // ========================================================================
1457 
1458  // Proceed with saving the current sim state
1459  // (HDF5 checks are limited to the minimum since they are already caught above)
1460  // Extending /time_steps with current step =============================
1461  hid_t time_steps_dset = H5Dopen(m_file_id, "time_steps", H5P_DEFAULT);
1462 
1463  // Get the current size of /time_steps, increase the size by one
1464  // and extend the /time_steps dataset to accomodate the new time step value
1465  hsize_t time_steps_dims;
1466  hid_t time_steps_dspace = H5Dget_space(time_steps_dset);
1467  H5Sget_simple_extent_dims(time_steps_dspace, &time_steps_dims, 0);
1468  time_steps_dims++;
1469  H5Dset_extent(time_steps_dset, &time_steps_dims);
1470 
1471  // To append the current time value to /time_steps properly:
1472  // 1. create the destination dataspace to append the current time step value
1473  // to the newly extended /time_steps
1474  // (i.e. select the last point of /time_steps)
1475  // H5S_SELECT_SET overwrites any previous selection
1476  // 1 is the number of elements that are selected
1477  // last_time_step_coord is the index of the last /time_steps element after expansion
1478  // 2. create the source dataspace for the current time step value
1479  // (i.e. just a simple dataspace curr_time_step_dspace for one element)
1480  // 3. Write the current time value with the previously defined source/destination spaces
1481 
1482  // 1.
1483  hsize_t last_time_step_coord = time_steps_dims - 1;
1484  H5Sselect_elements(time_steps_dspace, H5S_SELECT_SET, 1, &last_time_step_coord);
1485  // 2.
1486  hsize_t curr_time_step_dims[] = { 1 };
1487  hid_t curr_time_step_dspace = H5Screate_simple(1, curr_time_step_dims, NULL);
1488  // 3.
1489  H5Dwrite(time_steps_dset, H5T_IEEE_F64LE, curr_time_step_dspace, time_steps_dspace, H5P_DEFAULT, &sim_time);
1490  // Clean up HDF5 handles
1491  H5Sclose(curr_time_step_dspace);
1492  H5Sclose(time_steps_dspace);
1493  H5Dclose(time_steps_dset);
1494  // End of extending /time_steps ========================================
1495 
1496  // Extending /time_steps_idx with current step index ===================
1497  hid_t time_steps_idx_dset = H5Dopen(m_file_id, "time_steps_idx", H5P_DEFAULT);
1498 
1499  // Get the current size of /time_steps_idx, increase the size by one
1500  // and extend the /time_steps_idx data set to accommodate the new time step value
1501  hsize_t time_steps_idx_dims;
1502  hid_t time_steps_idx_dspace = H5Dget_space(time_steps_idx_dset);
1503  H5Sget_simple_extent_dims(time_steps_idx_dspace, &time_steps_idx_dims, 0);
1504  time_steps_idx_dims++;
1505  H5Dset_extent(time_steps_idx_dset, &time_steps_idx_dims);
1506 
1507  // To append the current step index to /time_steps_idx properly:
1508  // 1. create the destination data space to append the current time step index
1509  // to the newly extended /time_steps_idx
1510  // (i.e. select the last point of /time_steps_idx)
1511  // H5S_SELECT_SET overwrites any previous selection
1512  // 1 is the number of elements that are selected
1513  // last_time_step_coord is the index of the last /time_steps_idx element after expansion
1514  // 2. create the source data space for the current step index
1515  // (i.e. just a simple data space curr_time_step_idx_dspace for one element)
1516  // 3. Write the current step index value with the previously defined source/destination spaces
1517 
1518  // 1.
1519  hsize_t last_time_step_idx_coord = time_steps_idx_dims - 1;
1520  H5Sselect_elements(time_steps_idx_dspace, H5S_SELECT_SET, 1, &last_time_step_idx_coord);
1521  // 2.
1522  hsize_t curr_time_step_idx_dims[] = { 1 };
1523  hid_t curr_time_step_idx_dspace = H5Screate_simple(1, curr_time_step_idx_dims, NULL);
1524  // 3.
1525  H5Dwrite(time_steps_idx_dset, H5T_STD_I32LE, curr_time_step_idx_dspace, time_steps_idx_dspace, H5P_DEFAULT,
1526  &sim_step);
1527  // Clean up HDF5 handles
1528  H5Sclose(curr_time_step_idx_dspace);
1529  H5Sclose(time_steps_idx_dspace);
1530  H5Dclose(time_steps_idx_dset);
1531  // End of extending /time_steps_idx ====================================
1532 
1533  // Creating & writing the '/step_n' group ==============================
1534  hid_t step_grp = H5Gcreate(m_file_id, step_grp_name.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1535  // Save the mesh: Nodes, Cells & Walls to '/step_n' group
1536  WriteMesh(step_grp, sstate.GetMeshState());
1537  // Get and write the ptree of current simulation parameters
1538  // TODO: Naively write the whole parameters ptree as a serialized XML version of the ptree
1539  // TODO: to an attribute of the current '/step_n' group called 'parameters'
1540  // TODO: This is a quick fix for something that should be resolved by rethinking
1541  // TODO: the format for saving data in XML which I believe is flawed atm.
1542  WritePtreeToStringAttribute(step_grp, "parameters", sstate.GetParameters());
1543  // Get and write the ptree with the current random engine state
1544  WritePtreeToStringAttribute(step_grp, "random_engine", sstate.GetRandomEngineState());
1545  // Close the '/step_n' group
1546  H5Gclose(step_grp);
1547  // End of creating & writing the '/step_n' group =======================
1548 }
1549 
1550 void Hdf5File::WriteWalls(hid_t loc_id, const MeshState& mstate)
1551 {
1552  const size_t num_walls = mstate.GetNumWalls();
1553  // TODO: Document how walls are written to HDF5
1554  // - 'walls_id'
1555  // IDs of the walls. These are being used by cells to refer to their walls
1556  // - 'walls_cells' array keeps the 'neighbor cells' information
1557  // ie, which cells are connected by a specific wall
1558  // rows are walls, the two cols are the cells that are connected
1559  // - 'walls_nodes' array keeps the wall end-nodes information
1560  // rows are walls, the two cols are the nodes n1 and n2, the endpoints of the wall
1561 
1562  // Wall IDs
1563  const vector<int> walls_id = mstate.GetWallsID();
1564  write_array_rank1(loc_id, "walls_id", walls_id.data(), H5T_STD_I32LE, num_walls);
1565 
1566  // Copy wall properties into temporary arrays used for saving to HDF5
1567  int* walls_cells_data = new int[2 * num_walls];
1568  int* walls_nodes_data = new int[2 * num_walls];
1569 
1570  for (size_t wall_idx = 0; wall_idx < num_walls; ++wall_idx) {
1571  // IDs of the two cells connected by the wall
1572  pair<int, int> cells_ids = mstate.GetWallCells(wall_idx);
1573  walls_cells_data[2 * wall_idx] = cells_ids.first;
1574  walls_cells_data[2 * wall_idx + 1] = cells_ids.second;
1575  // IDs of the two endpoints of the wall
1576  pair<int, int> nodes_ids = mstate.GetWallNodes(wall_idx);
1577  walls_nodes_data[2 * wall_idx] = nodes_ids.first;
1578  walls_nodes_data[2 * wall_idx + 1] = nodes_ids.second;
1579  }
1580 
1581  // Write data arrays to HDF5
1582  write_array_rank2(loc_id, "walls_cells", walls_cells_data, H5T_STD_I32LE, num_walls, 2);
1583  write_array_rank2(loc_id, "walls_nodes", walls_nodes_data, H5T_STD_I32LE, num_walls, 2);
1584 
1585  // Clean up temporary arrays
1586  delete[] walls_cells_data;
1587  delete[] walls_nodes_data;
1588 
1589  // Wall attributes (int)
1590  for (string attr_name : mstate.WallAttributeContainer().GetNames<int>()) {
1591  const vector<int> attr_values = mstate.WallAttributeContainer().GetAll<int>(attr_name);
1592  string attr_name_hdf5 = string("walls_attr_") + attr_name;
1593  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values.data(), H5T_STD_I32LE, num_walls);
1594  }
1595 
1596  // Wall attributes (double)
1597  for (string attr_name : mstate.WallAttributeContainer().GetNames<double>()) {
1598  const vector<double> attr_values = mstate.WallAttributeContainer().GetAll<double>(attr_name);
1599  string attr_name_hdf5 = string("walls_attr_") + attr_name;
1600  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values.data(), H5T_IEEE_F64LE, num_walls);
1601  }
1602 
1603  // Wall attributes (string)
1604  for (string attr_name : mstate.WallAttributeContainer().GetNames<string>()) {
1605  const vector<string> attr_values = mstate.WallAttributeContainer().GetAll<string>(attr_name);
1606  string attr_name_hdf5 = string("walls_attr_") + attr_name;
1607  write_array_rank1(loc_id, attr_name_hdf5.c_str(), attr_values);
1608  }
1609 }
1610 
1611 } // namespace
1612 
size_t GetNumCells() const
Returns the number of cells in the mesh.
Definition: MeshState.cpp:131
STL namespace.
Header for ptree2hdf5.
Interface of MeshState.
std::vector< T > GetAll(const std::string &name) const
Returns all values of a named attribute.
Namespace for miscellaneous utilities.
Definition: PTreeFile.cpp:44
Simulator: mesh & parameters, model & algorithms.
Definition: Sim.h:50
void Write(std::shared_ptr< const SimPT_Sim::Sim > sim)
Writes the mesh state to the HDF5 file currently associated with exporter object. ...
Definition: Hdf5File.cpp:1134
Namespace for SimPT shell package.
Definition: Client.cpp:50
Interface for VirtualLeaf::Hdf5File.
Macro defs for debug and logging.
std::vector< size_t > GetCellsNumNodes() const
Returns the number of nodes for all cells.
Definition: MeshState.cpp:191
Header for SimState.
std::vector< std::pair< int, double > > TimeSteps()
Reads the time steps contained in the HDF5 file.
Definition: Hdf5File.cpp:1096
std::vector< int > GetCellNodes(size_t cell_idx) const
Returns the IDs of the nodes that form the polygon of a particular cell.
Definition: MeshState.cpp:156
std::vector< int > GetCellsID() const
Returns the IDs of all cells.
Definition: MeshState.cpp:186
bool IsOpen()
Returns true if exporter is associated with a HDF5 file that has been successfully opened...
Definition: Hdf5File.cpp:339
virtual ~Hdf5File()
Cleans up HDF5 storage: makes sure files are closed properly.
Definition: Hdf5File.cpp:311
std::vector< size_t > GetCellsNumWalls() const
Returns the number of walls for all cells.
Definition: MeshState.cpp:201
Sim, the actual simulator.
bool Close()
Closes the HDF5 file associated with exporter, dissociates it from this exporter object and returns t...
Definition: Hdf5File.cpp:318
Contains the state of the whole Simulator at a given simulation step.
Definition: SimState.h:33
Interface of AttributeContainer.
bool Open(const std::string &file_path)
Creates an HDF5 file and binds the exporter object to it.
Definition: Hdf5File.cpp:344
std::vector< std::string > GetNames() const
Returns a vector containing the names of attributes of type T.
ptree hdf52ptree(hid_t loc_id)
Return the ptree that represents the groups of attributes in HDF5.
Definition: ptree2hdf5.cpp:244
Contains the state of the whole Mesh at a given simulation step.
Definition: MeshState.h:41
Hdf5File()
Creates an empty HDF5 mesh exporter with no file association.
Definition: Hdf5File.cpp:301
Xml writer settings class.
std::string GetFilePath()
Return file path for HDF5 file associated with the exporter object, if any.
Definition: Hdf5File.cpp:334
AttributeContainer & CellAttributeContainer()
Adds a new named attribute of type T for the nodes.
Definition: MeshState.h:166
static std::string GetFileExtension()
Return file extension for HDF5 format.
Definition: Hdf5File.cpp:329
std::vector< int > GetCellWalls(size_t cell_idx) const
Returns the IDs of walls of a particular cell.
Definition: MeshState.cpp:166