FLAME  devel
 All Classes Functions Variables Typedefs Enumerations Pages
h5writer.cpp
1 
2 
3 #include <sstream>
4 
5 #include <boost/foreach.hpp>
6 
7 #include <H5Cpp.h>
8 
9 #include "flame/h5writer.h"
10 #include "flame/h5loader.h"
11 
12 // H5::Exception doesn't derive from std::exception
13 // so translate to some type which does.
14 // TODO: sub-class mixing H5::Exception and std::exception?
15 #define CATCH() catch(H5::Exception& he) { \
16  std::ostringstream strm; \
17  strm<<"H5 Error "<<he.getDetailMsg(); \
18  throw std::runtime_error(strm.str()); \
19  }
20 
21 namespace {
22 struct StateElement {
23  unsigned idx;
25  H5::DataSet dset;
26  size_t nextrow;
27  StateElement() :idx((unsigned)-1), nextrow(0u) {}
28 };
29 }
30 
31 struct H5StateWriter::Pvt {
32  H5::H5File file;
33  H5::Group group;
34  std::vector<StateElement> elements;
35 };
36 
37 H5StateWriter::H5StateWriter() :pvt(new Pvt) {}
38 
39 H5StateWriter::H5StateWriter(const char *spec) :pvt(new Pvt)
40 {
41  open(spec);
42 }
43 
44 H5StateWriter::H5StateWriter(const std::string& spec) :pvt(new Pvt)
45 {
46  open(spec);
47 }
48 
49 H5StateWriter::~H5StateWriter()
50 {
51  try{
52  close();
53  } catch(std::runtime_error& e) {
54  std::cerr<<"H5StateWriter is ignoring exception in dtor : "<<e.what()<<"\n";
55  }
56  delete pvt;
57 }
58 
59 void H5StateWriter::open(const char *spec)
60 {
61  open(std::string(spec));
62 }
63 
64 void H5StateWriter::open(const std::string& spec)
65 {
66  try {
67  close();
68  /* The provided spec may contain both file path and group(s)
69  * seperated by '/' which is ambigious as the file path
70  * may contain '/' as well...
71  * so do as h5ls does and strip off from the right hand side until
72  * and try to open while '/' remain.
73  */
74  size_t sep = spec.npos;
75 
76  while(true) {
77  sep = spec.find_last_of('/', sep-1);
78 
79  std::string fname(spec.substr(0, sep));
80 
81  try {
82  pvt->file.openFile(fname, H5F_ACC_RDWR|H5F_ACC_CREAT);
83  } catch(H5::FileIException& e) {
84  if(sep==spec.npos) {
85  // no more '/' so this is failure
86  throw std::runtime_error("Unable to open file");
87  }
88  continue; // keep trying
89  } CATCH()
90 
91  if(sep!=spec.npos) {
92  std::string group(spec.substr(sep+1));
93  // delete group if it already exists
94  try{
95  H5G_stat_t stat;
96  pvt->file.getObjinfo(group, stat);
97  pvt->file.unlink(group);
98  } catch(H5::FileIException&) {
99  // ignore non-existant
100  }
101 
102  pvt->group = pvt->file.createGroup(group);
103  } else {
104  //TODO: cleanup root?
105 
106  pvt->group = pvt->file.openGroup("/");
107  }
108 
109  return;
110  }
111  } CATCH()
112 }
113 
114 void H5StateWriter::close()
115 {
116  try{
117  pvt->group.close();
118  pvt->file.close();
119  }CATCH()
120 }
121 
122 void H5StateWriter::prepare(const StateBase *RS)
123 {
124  try {
125  // hack since getArray() is non-const
126  // we won't actually modify the state
127  StateBase *S = const_cast<StateBase*>(RS);
128 
129  assert(pvt->elements.empty());
130 
131  for(unsigned idx=0; true; idx++) {
133 
134  if(!S->getArray(idx, info))
135  break;
136 
137  H5::DataType dtype;
138  switch(info.type) {
139  case StateBase::ArrayInfo::Double:
140  dtype = H5::DataType(H5::PredType::NATIVE_DOUBLE);
141  break;
142  case StateBase::ArrayInfo::Sizet:
143  if(sizeof(size_t)==8)
144  dtype = H5::DataType(H5::PredType::NATIVE_UINT64);
145  else if(sizeof(size_t)==4)
146  dtype = H5::DataType(H5::PredType::NATIVE_UINT32);
147  else
148  throw std::logic_error("unsupported size_t");
149  break;
150  default:
151  continue; // TODO string
152  }
153 
154  StateElement elem;
155  elem.idx = idx;
156  elem.info = info;
157 
158  // first dim is simulation "time"
159  hsize_t dims[StateBase::ArrayInfo::maxdims+1],
160  maxdims[StateBase::ArrayInfo::maxdims+1];
161  std::fill(maxdims, maxdims+info.ndim+1, H5S_UNLIMITED);
162  std::copy(info.dim,
163  info.dim+info.ndim,
164  dims+1);
165 
166  // size w/ first dim==0
167  dims[0] = 0;
168 
169  H5::DataSpace dspace(info.ndim+1, &dims[0], &maxdims[0]);
170 
171  dims[0] = 1024; // chunk size in "time" steps (arbitrary)
172  // other chunk sizes are multiple of initial size
173  H5::DSetCreatPropList props;
174  props.setChunk(info.ndim+1, &dims[0]);
175 
176  // memspace is simple from origin to [1,shape]
177  dims[0] = 1;
178 
179  elem.dset = pvt->group.createDataSet(info.name, dtype, dspace, props);
180 
181  pvt->elements.push_back(elem);
182  }
183 
184  if(pvt->elements.empty()) {
185  throw std::logic_error("state type has not elements to store?");
186  }
187  } CATCH()
188 }
189 
190 void H5StateWriter::append(const StateBase *RS)
191 {
192  try {
193  StateBase *S = const_cast<StateBase*>(RS);
194 
195  if(pvt->elements.empty())
196  prepare(RS);
197 
198  BOOST_FOREACH(StateElement& elem, pvt->elements)
199  {
201 
202  if(!S->getArray(elem.idx, info))
203  throw std::logic_error("can't re-fetch state parameter?");
204 
205  assert((elem.info.ndim==info.ndim) && (elem.info.type==info.type));
206 
207  hsize_t shape[StateBase::ArrayInfo::maxdims+1];
208  shape[0] = ++elem.nextrow;
209  std::copy(info.dim,
210  info.dim+info.ndim,
211  shape+1);
212 
213  // resize
214  // always in time, maybe in other dimensions
215  elem.dset.extend(shape);
216 
217  // filespace is hyper from [index,0...] to [index,shape]
218  hsize_t start[StateBase::ArrayInfo::maxdims+1];
219  start[0] = shape[0]-1;
220  std::fill(start+1, start+info.ndim+1, 0);
221 
222  shape[0] = 1; // reuse as count
223  H5::DataSpace memspace(info.ndim+1, shape);
224 
225  H5::DataSpace filespace(elem.dset.getSpace());
226  filespace.selectHyperslab(H5S_SELECT_SET, shape, start);
227 
228  H5::DataType dtype(elem.dset.getDataType());
229 
230  elem.dset.write(info.ptr, dtype, memspace, filespace);
231 
232  }
233  } CATCH()
234 }
235 
236 void H5StateWriter::setAttr(const char *name, const char *val)
237 {
238  try {
239  if(H5Aexists(pvt->group.getId(), name)>0)
240  //if(pvt->group.attrExists(name)) // H5Aexists was added in 1.8.0, c++ wrapper wasn't added until later...
241  {
242  pvt->group.removeAttr(name);
243  }
244 
245  {
246  H5::DataSpace scalar;
247  H5::StrType dtype(H5::PredType::C_S1, std::max((size_t)16u, strlen(val)));
248  H5::Attribute attr(pvt->group.createAttribute(name, dtype, scalar));
249  attr.write(dtype, val);
250  }
251  } CATCH()
252 }
253 
254 void H5StateWriter::dontPrint()
255 {
256  try {
257  H5::Exception::dontPrint();
258  }CATCH()
259 }
The abstract base class for all simulation state objects.
Definition: base.h:28
Used with StateBase::getArray() to describe a single parameter.
Definition: base.h:48
size_t dim[maxdims]
Array dimensions in elements.
Definition: base.h:66
virtual bool getArray(unsigned index, ArrayInfo &Info)
Introspect named parameter of the derived class.
Definition: base.cpp:35
const char * name
The parameter name.
Definition: base.h:52
unsigned ndim
Definition: base.h:64