xref: /petsc/src/sys/classes/viewer/impls/hdf5/hdf5v.c (revision 6c132bc181f224cef6bd4fbff825886028df0bd6)
1 #include <petsc/private/viewerimpl.h>    /*I   "petscsys.h"   I*/
2 #include <petscviewerhdf5.h>    /*I   "petscviewerhdf5.h"   I*/
3 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE < 10800)
4 #error "PETSc needs HDF5 version >= 1.8.0"
5 #endif
6 
7 static PetscErrorCode PetscViewerHDF5Traverse_Internal(PetscViewer, const char[], PetscBool, PetscBool*, H5O_type_t*);
8 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer, const char[], const char[], PetscBool*);
9 
10 typedef struct GroupList {
11   const char       *name;
12   struct GroupList *next;
13 } GroupList;
14 
15 typedef struct {
16   char          *filename;
17   PetscFileMode btype;
18   hid_t         file_id;
19   PetscInt      timestep;
20   GroupList     *groups;
21   PetscBool     basedimension2;  /* save vectors and DMDA vectors with a dimension of at least 2 even if the bs/dof is 1 */
22   PetscBool     spoutput;  /* write data in single precision even if PETSc is compiled with double precision PetscReal */
23   char          *mataij_iname;
24   char          *mataij_jname;
25   char          *mataij_aname;
26   char          *mataij_cname;
27 } PetscViewer_HDF5;
28 
29 struct _n_HDF5ReadCtx {
30   hid_t file, group, dataset, dataspace, plist;
31   PetscInt timestep;
32   PetscBool complexVal, dim2, horizontal;
33 };
34 typedef struct _n_HDF5ReadCtx* HDF5ReadCtx;
35 
36 static PetscErrorCode PetscViewerHDF5GetAbsolutePath_Internal(PetscViewer viewer, const char objname[], char **fullpath)
37 {
38   const char *group;
39   char buf[PETSC_MAX_PATH_LEN]="";
40   PetscErrorCode ierr;
41 
42   PetscFunctionBegin;
43   ierr = PetscViewerHDF5GetGroup(viewer, &group);CHKERRQ(ierr);
44   ierr = PetscStrcat(buf, group);CHKERRQ(ierr);
45   ierr = PetscStrcat(buf, "/");CHKERRQ(ierr);
46   ierr = PetscStrcat(buf, objname);CHKERRQ(ierr);
47   ierr = PetscStrallocpy(buf, fullpath);CHKERRQ(ierr);
48   PetscFunctionReturn(0);
49 }
50 
51 static PetscErrorCode PetscViewerSetFromOptions_HDF5(PetscOptionItems *PetscOptionsObject,PetscViewer v)
52 {
53   PetscErrorCode   ierr;
54   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*)v->data;
55 
56   PetscFunctionBegin;
57   ierr = PetscOptionsHead(PetscOptionsObject,"HDF5 PetscViewer Options");CHKERRQ(ierr);
58   ierr = PetscOptionsBool("-viewer_hdf5_base_dimension2","1d Vectors get 2 dimensions in HDF5","PetscViewerHDF5SetBaseDimension2",hdf5->basedimension2,&hdf5->basedimension2,NULL);CHKERRQ(ierr);
59   ierr = PetscOptionsBool("-viewer_hdf5_sp_output","Force data to be written in single precision","PetscViewerHDF5SetSPOutput",hdf5->spoutput,&hdf5->spoutput,NULL);CHKERRQ(ierr);
60   ierr = PetscOptionsTail();CHKERRQ(ierr);
61   PetscFunctionReturn(0);
62 }
63 
64 static PetscErrorCode PetscViewerFileClose_HDF5(PetscViewer viewer)
65 {
66   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*)viewer->data;
67   PetscErrorCode   ierr;
68 
69   PetscFunctionBegin;
70   ierr = PetscFree(hdf5->filename);CHKERRQ(ierr);
71   if (hdf5->file_id) PetscStackCallHDF5(H5Fclose,(hdf5->file_id));
72   PetscFunctionReturn(0);
73 }
74 
75 PetscErrorCode PetscViewerDestroy_HDF5(PetscViewer viewer)
76 {
77   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
78   PetscErrorCode   ierr;
79 
80   PetscFunctionBegin;
81   ierr = PetscViewerFileClose_HDF5(viewer);CHKERRQ(ierr);
82   while (hdf5->groups) {
83     GroupList *tmp = hdf5->groups->next;
84 
85     ierr         = PetscFree(hdf5->groups->name);CHKERRQ(ierr);
86     ierr         = PetscFree(hdf5->groups);CHKERRQ(ierr);
87     hdf5->groups = tmp;
88   }
89   ierr = PetscFree(hdf5->mataij_iname);CHKERRQ(ierr);
90   ierr = PetscFree(hdf5->mataij_jname);CHKERRQ(ierr);
91   ierr = PetscFree(hdf5->mataij_aname);CHKERRQ(ierr);
92   ierr = PetscFree(hdf5->mataij_cname);CHKERRQ(ierr);
93   ierr = PetscFree(hdf5);CHKERRQ(ierr);
94   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL);CHKERRQ(ierr);
95   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileGetName_C",NULL);CHKERRQ(ierr);
96   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetMode_C",NULL);CHKERRQ(ierr);
97   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerHDF5SetBaseDimension2_C",NULL);CHKERRQ(ierr);
98   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerHDF5SetSPOutput_C",NULL);CHKERRQ(ierr);
99   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerHDF5SetAIJNames_C",NULL);CHKERRQ(ierr);
100   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerHDF5GetAIJNames_C",NULL);CHKERRQ(ierr);
101   PetscFunctionReturn(0);
102 }
103 
104 PetscErrorCode  PetscViewerFileSetMode_HDF5(PetscViewer viewer, PetscFileMode type)
105 {
106   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
107 
108   PetscFunctionBegin;
109   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
110   hdf5->btype = type;
111   PetscFunctionReturn(0);
112 }
113 
114 PetscErrorCode  PetscViewerHDF5SetBaseDimension2_HDF5(PetscViewer viewer, PetscBool flg)
115 {
116   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
117 
118   PetscFunctionBegin;
119   hdf5->basedimension2 = flg;
120   PetscFunctionReturn(0);
121 }
122 
123 /*@
124      PetscViewerHDF5SetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
125        dimension of 2.
126 
127     Logically Collective on PetscViewer
128 
129   Input Parameters:
130 +  viewer - the PetscViewer; if it is not hdf5 then this command is ignored
131 -  flg - if PETSC_TRUE the vector will always have at least a dimension of 2 even if that first dimension is of size 1
132 
133   Options Database:
134 .  -viewer_hdf5_base_dimension2 - turns on (true) or off (false) using a dimension of 2 in the HDF5 file even if the bs/dof of the vector is 1
135 
136 
137   Notes:
138     Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
139          of one when the dimension is lower. Others think the option is crazy.
140 
141   Level: intermediate
142 
143 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen()
144 
145 @*/
146 PetscErrorCode PetscViewerHDF5SetBaseDimension2(PetscViewer viewer,PetscBool flg)
147 {
148   PetscErrorCode ierr;
149 
150   PetscFunctionBegin;
151   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
152   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetBaseDimension2_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
153   PetscFunctionReturn(0);
154 }
155 
156 /*@
157      PetscViewerHDF5GetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
158        dimension of 2.
159 
160     Logically Collective on PetscViewer
161 
162   Input Parameter:
163 .  viewer - the PetscViewer, must be of type HDF5
164 
165   Output Parameter:
166 .  flg - if PETSC_TRUE the vector will always have at least a dimension of 2 even if that first dimension is of size 1
167 
168   Notes:
169     Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
170          of one when the dimension is lower. Others think the option is crazy.
171 
172   Level: intermediate
173 
174 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen()
175 
176 @*/
177 PetscErrorCode PetscViewerHDF5GetBaseDimension2(PetscViewer viewer,PetscBool *flg)
178 {
179   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
180 
181   PetscFunctionBegin;
182   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
183   *flg = hdf5->basedimension2;
184   PetscFunctionReturn(0);
185 }
186 
187 PetscErrorCode  PetscViewerHDF5SetSPOutput_HDF5(PetscViewer viewer, PetscBool flg)
188 {
189   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
190 
191   PetscFunctionBegin;
192   hdf5->spoutput = flg;
193   PetscFunctionReturn(0);
194 }
195 
196 /*@
197      PetscViewerHDF5SetSPOutput - Data is written to disk in single precision even if PETSc is
198        compiled with double precision PetscReal.
199 
200     Logically Collective on PetscViewer
201 
202   Input Parameters:
203 +  viewer - the PetscViewer; if it is not hdf5 then this command is ignored
204 -  flg - if PETSC_TRUE the data will be written to disk with single precision
205 
206   Options Database:
207 .  -viewer_hdf5_sp_output - turns on (true) or off (false) output in single precision
208 
209 
210   Notes:
211     Setting this option does not make any difference if PETSc is compiled with single precision
212          in the first place. It does not affect reading datasets (HDF5 handle this internally).
213 
214   Level: intermediate
215 
216 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen(),
217           PetscReal
218 
219 @*/
220 PetscErrorCode PetscViewerHDF5SetSPOutput(PetscViewer viewer,PetscBool flg)
221 {
222   PetscErrorCode ierr;
223 
224   PetscFunctionBegin;
225   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
226   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetSPOutput_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
227   PetscFunctionReturn(0);
228 }
229 
230 /*@
231      PetscViewerHDF5GetSPOutput - Data is written to disk in single precision even if PETSc is
232        compiled with double precision PetscReal.
233 
234     Logically Collective on PetscViewer
235 
236   Input Parameter:
237 .  viewer - the PetscViewer, must be of type HDF5
238 
239   Output Parameter:
240 .  flg - if PETSC_TRUE the data will be written to disk with single precision
241 
242   Notes:
243     Setting this option does not make any difference if PETSc is compiled with single precision
244          in the first place. It does not affect reading datasets (HDF5 handle this internally).
245 
246   Level: intermediate
247 
248 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen(),
249           PetscReal
250 
251 @*/
252 PetscErrorCode PetscViewerHDF5GetSPOutput(PetscViewer viewer,PetscBool *flg)
253 {
254   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
255 
256   PetscFunctionBegin;
257   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
258   *flg = hdf5->spoutput;
259   PetscFunctionReturn(0);
260 }
261 
262 PetscErrorCode  PetscViewerFileSetName_HDF5(PetscViewer viewer, const char name[])
263 {
264   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
265 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
266   MPI_Info          info = MPI_INFO_NULL;
267 #endif
268   hid_t             plist_id;
269   PetscErrorCode    ierr;
270 
271   PetscFunctionBegin;
272   if (hdf5->file_id) PetscStackCallHDF5(H5Fclose,(hdf5->file_id));
273   if (hdf5->filename) {ierr = PetscFree(hdf5->filename);CHKERRQ(ierr);}
274   ierr = PetscStrallocpy(name, &hdf5->filename);CHKERRQ(ierr);
275   /* Set up file access property list with parallel I/O access */
276   PetscStackCallHDF5Return(plist_id,H5Pcreate,(H5P_FILE_ACCESS));
277 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
278   PetscStackCallHDF5(H5Pset_fapl_mpio,(plist_id, PetscObjectComm((PetscObject)viewer), info));
279 #endif
280   /* Create or open the file collectively */
281   switch (hdf5->btype) {
282   case FILE_MODE_READ:
283     PetscStackCallHDF5Return(hdf5->file_id,H5Fopen,(name, H5F_ACC_RDONLY, plist_id));
284     break;
285   case FILE_MODE_APPEND:
286     PetscStackCallHDF5Return(hdf5->file_id,H5Fopen,(name, H5F_ACC_RDWR, plist_id));
287     break;
288   case FILE_MODE_WRITE:
289     PetscStackCallHDF5Return(hdf5->file_id,H5Fcreate,(name, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id));
290     break;
291   default:
292     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
293   }
294   if (hdf5->file_id < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB, "H5Fcreate failed for %s", name);
295   PetscStackCallHDF5(H5Pclose,(plist_id));
296   PetscFunctionReturn(0);
297 }
298 
299 static PetscErrorCode PetscViewerFileGetName_HDF5(PetscViewer viewer,const char **name)
300 {
301   PetscViewer_HDF5 *vhdf5 = (PetscViewer_HDF5*)viewer->data;
302 
303   PetscFunctionBegin;
304   *name = vhdf5->filename;
305   PetscFunctionReturn(0);
306 }
307 
308 PetscErrorCode  PetscViewerHDF5SetAIJNames_HDF5(PetscViewer viewer, const char iname[], const char jname[], const char aname[], const char cname[])
309 {
310   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
311   PetscErrorCode ierr;
312 
313   PetscFunctionBegin;
314   ierr = PetscFree(hdf5->mataij_iname);CHKERRQ(ierr);
315   ierr = PetscFree(hdf5->mataij_jname);CHKERRQ(ierr);
316   ierr = PetscFree(hdf5->mataij_aname);CHKERRQ(ierr);
317   ierr = PetscFree(hdf5->mataij_cname);CHKERRQ(ierr);
318   ierr = PetscStrallocpy(iname,&hdf5->mataij_iname);CHKERRQ(ierr);
319   ierr = PetscStrallocpy(jname,&hdf5->mataij_jname);CHKERRQ(ierr);
320   ierr = PetscStrallocpy(aname,&hdf5->mataij_aname);CHKERRQ(ierr);
321   ierr = PetscStrallocpy(cname,&hdf5->mataij_cname);CHKERRQ(ierr);
322   PetscFunctionReturn(0);
323 }
324 
325 /*@C
326   PetscViewerHDF5SetAIJNames - Set the names of the datasets representing the three AIJ (CRS) arrays and the name of the attribute storing the number of columns within the HDF5 file.
327 
328   Collective on PetscViewer
329 
330   Input Parameters:
331 +  viewer - the PetscViewer; either ASCII or binary
332 .  iname - name of dataset i representing row pointers; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix
333 .  jname - name of dataset j representing column indices
334 .  aname - name of dataset a representing matrix values
335 -  cname - name of attribute stoting column count
336 
337   Level: advanced
338 
339   Notes:
340   Current defaults are (iname, jname, aname, cname) = ("jc", "ir", "data", "MATLAB_sparse") so that MAT files can be readily loaded.
341 
342 .seealso: MatLoad(), PetscViewerCreate(), PetscViewerSetType(), PETSCVIEWERHDF5, PetscViewerHDF5GetAIJNames()
343 @*/
344 PetscErrorCode  PetscViewerHDF5SetAIJNames(PetscViewer viewer, const char iname[], const char jname[], const char aname[], const char cname[])
345 {
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
350   PetscValidCharPointer(iname,2);
351   PetscValidCharPointer(jname,3);
352   PetscValidCharPointer(aname,4);
353   PetscValidCharPointer(cname,5);
354   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetAIJNames_C",(PetscViewer,const char[],const char[],const char[],const char[]),(viewer,iname,jname,aname,cname));CHKERRQ(ierr);
355   PetscFunctionReturn(0);
356 }
357 
358 PetscErrorCode  PetscViewerHDF5GetAIJNames_HDF5(PetscViewer viewer, const char *iname[], const char *jname[], const char *aname[], const char *cname[])
359 {
360   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
361 
362   PetscFunctionBegin;
363   *iname = hdf5->mataij_iname;
364   *jname = hdf5->mataij_jname;
365   *aname = hdf5->mataij_aname;
366   *cname = hdf5->mataij_cname;
367   PetscFunctionReturn(0);
368 }
369 
370 /*@C
371   PetscViewerHDF5GetAIJNames - Get the names of the datasets representing the three AIJ (CRS) arrays and the name of the attribute storing the number of columns within the HDF5 file.
372 
373   Collective on PetscViewer
374 
375   Input Parameters:
376 .  viewer - the PetscViewer; either ASCII or binary
377 
378   Output Parameters:
379 +  iname - name of dataset i representing row pointers; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix
380 .  jname - name of dataset j representing column indices
381 .  aname - name of dataset a representing matrix values
382 -  cname - name of attribute stoting column count
383 
384   Level: advanced
385 
386   Notes:
387   Current defaults are (iname, jname, aname, cname) = ("jc", "ir", "data", "MATLAB_sparse") so that MAT files can be readily loaded.
388 
389 .seealso: MatLoad(), PetscViewerCreate(), PetscViewerSetType(), PETSCVIEWERHDF5, PetscViewerHDF5SetAIJNames()
390 @*/
391 PetscErrorCode  PetscViewerHDF5GetAIJNames(PetscViewer viewer, const char *iname[], const char *jname[], const char *aname[], const char *cname[])
392 {
393   PetscErrorCode ierr;
394 
395   PetscFunctionBegin;
396   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
397   PetscValidPointer(iname,2);
398   PetscValidPointer(jname,3);
399   PetscValidPointer(aname,4);
400   PetscValidPointer(cname,5);
401   ierr = PetscUseMethod(viewer,"PetscViewerHDF5GetAIJNames_C",(PetscViewer,const char*[],const char*[],const char*[],const char*[]),(viewer,iname,jname,aname,cname));CHKERRQ(ierr);
402   PetscFunctionReturn(0);
403 }
404 
405 /*MC
406    PETSCVIEWERHDF5 - A viewer that writes to an HDF5 file
407 
408 
409 .seealso:  PetscViewerHDF5Open(), PetscViewerStringSPrintf(), PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSCVIEWERSOCKET,
410            PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW, PETSCVIEWERSTRING,
411            PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
412            PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()
413 
414   Level: beginner
415 M*/
416 
417 PETSC_EXTERN PetscErrorCode PetscViewerCreate_HDF5(PetscViewer v)
418 {
419   PetscViewer_HDF5 *hdf5;
420   PetscErrorCode   ierr;
421 
422   PetscFunctionBegin;
423   ierr = PetscNewLog(v,&hdf5);CHKERRQ(ierr);
424 
425   v->data                = (void*) hdf5;
426   v->ops->destroy        = PetscViewerDestroy_HDF5;
427   v->ops->setfromoptions = PetscViewerSetFromOptions_HDF5;
428   v->ops->flush          = 0;
429   hdf5->btype            = (PetscFileMode) -1;
430   hdf5->filename         = 0;
431   hdf5->timestep         = -1;
432   hdf5->groups           = NULL;
433 
434   /* ir and jc are deliberately swapped as MATLAB uses column-major format */
435   ierr = PetscStrallocpy("jc",  &hdf5->mataij_iname);CHKERRQ(ierr);
436   ierr = PetscStrallocpy("ir",  &hdf5->mataij_jname);CHKERRQ(ierr);
437   ierr = PetscStrallocpy("data",&hdf5->mataij_aname);CHKERRQ(ierr);
438   ierr = PetscStrallocpy("MATLAB_sparse", &hdf5->mataij_cname);CHKERRQ(ierr);
439 
440   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetName_C",PetscViewerFileSetName_HDF5);CHKERRQ(ierr);
441   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetName_C",PetscViewerFileGetName_HDF5);CHKERRQ(ierr);
442   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetMode_C",PetscViewerFileSetMode_HDF5);CHKERRQ(ierr);
443   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetBaseDimension2_C",PetscViewerHDF5SetBaseDimension2_HDF5);CHKERRQ(ierr);
444   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetSPOutput_C",PetscViewerHDF5SetSPOutput_HDF5);CHKERRQ(ierr);
445   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetAIJNames_C",PetscViewerHDF5SetAIJNames_HDF5);CHKERRQ(ierr);
446   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5GetAIJNames_C",PetscViewerHDF5GetAIJNames_HDF5);CHKERRQ(ierr);
447   PetscFunctionReturn(0);
448 }
449 
450 /*@C
451    PetscViewerHDF5Open - Opens a file for HDF5 input/output.
452 
453    Collective on MPI_Comm
454 
455    Input Parameters:
456 +  comm - MPI communicator
457 .  name - name of file
458 -  type - type of file
459 $    FILE_MODE_WRITE - create new file for binary output
460 $    FILE_MODE_READ - open existing file for binary input
461 $    FILE_MODE_APPEND - open existing file for binary output
462 
463    Output Parameter:
464 .  hdf5v - PetscViewer for HDF5 input/output to use with the specified file
465 
466   Options Database:
467 .  -viewer_hdf5_base_dimension2 - turns on (true) or off (false) using a dimension of 2 in the HDF5 file even if the bs/dof of the vector is 1
468 .  -viewer_hdf5_sp_output - forces (if true) the viewer to write data in single precision independent on the precision of PetscReal
469 
470    Level: beginner
471 
472    Note:
473    This PetscViewer should be destroyed with PetscViewerDestroy().
474 
475    Concepts: HDF5 files
476    Concepts: PetscViewerHDF5^creating
477 
478 .seealso: PetscViewerASCIIOpen(), PetscViewerPushFormat(), PetscViewerDestroy(), PetscViewerHDF5SetBaseDimension2(),
479           PetscViewerHDF5SetSPOutput(), PetscViewerHDF5GetBaseDimension2(), VecView(), MatView(), VecLoad(),
480           MatLoad(), PetscFileMode, PetscViewer, PetscViewerSetType(), PetscViewerFileSetMode(), PetscViewerFileSetName()
481 @*/
482 PetscErrorCode  PetscViewerHDF5Open(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *hdf5v)
483 {
484   PetscErrorCode ierr;
485 
486   PetscFunctionBegin;
487   ierr = PetscViewerCreate(comm, hdf5v);CHKERRQ(ierr);
488   ierr = PetscViewerSetType(*hdf5v, PETSCVIEWERHDF5);CHKERRQ(ierr);
489   ierr = PetscViewerFileSetMode(*hdf5v, type);CHKERRQ(ierr);
490   ierr = PetscViewerFileSetName(*hdf5v, name);CHKERRQ(ierr);
491   PetscFunctionReturn(0);
492 }
493 
494 /*@C
495   PetscViewerHDF5GetFileId - Retrieve the file id, this file ID then can be used in direct HDF5 calls
496 
497   Not collective
498 
499   Input Parameter:
500 . viewer - the PetscViewer
501 
502   Output Parameter:
503 . file_id - The file id
504 
505   Level: intermediate
506 
507 .seealso: PetscViewerHDF5Open()
508 @*/
509 PetscErrorCode  PetscViewerHDF5GetFileId(PetscViewer viewer, hid_t *file_id)
510 {
511   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
512 
513   PetscFunctionBegin;
514   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
515   if (file_id) *file_id = hdf5->file_id;
516   PetscFunctionReturn(0);
517 }
518 
519 /*@C
520   PetscViewerHDF5PushGroup - Set the current HDF5 group for output
521 
522   Not collective
523 
524   Input Parameters:
525 + viewer - the PetscViewer
526 - name - The group name
527 
528   Level: intermediate
529 
530 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup(),PetscViewerHDF5OpenGroup()
531 @*/
532 PetscErrorCode  PetscViewerHDF5PushGroup(PetscViewer viewer, const char *name)
533 {
534   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
535   GroupList        *groupNode;
536   PetscErrorCode   ierr;
537 
538   PetscFunctionBegin;
539   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
540   PetscValidCharPointer(name,2);
541   ierr = PetscNew(&groupNode);CHKERRQ(ierr);
542   ierr = PetscStrallocpy(name, (char**) &groupNode->name);CHKERRQ(ierr);
543 
544   groupNode->next = hdf5->groups;
545   hdf5->groups    = groupNode;
546   PetscFunctionReturn(0);
547 }
548 
549 /*@
550   PetscViewerHDF5PopGroup - Return the current HDF5 group for output to the previous value
551 
552   Not collective
553 
554   Input Parameter:
555 . viewer - the PetscViewer
556 
557   Level: intermediate
558 
559 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5GetGroup(),PetscViewerHDF5OpenGroup()
560 @*/
561 PetscErrorCode  PetscViewerHDF5PopGroup(PetscViewer viewer)
562 {
563   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
564   GroupList        *groupNode;
565   PetscErrorCode   ierr;
566 
567   PetscFunctionBegin;
568   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
569   if (!hdf5->groups) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "HDF5 group stack is empty, cannot pop");
570   groupNode    = hdf5->groups;
571   hdf5->groups = hdf5->groups->next;
572   ierr         = PetscFree(groupNode->name);CHKERRQ(ierr);
573   ierr         = PetscFree(groupNode);CHKERRQ(ierr);
574   PetscFunctionReturn(0);
575 }
576 
577 /*@C
578   PetscViewerHDF5GetGroup - Get the current HDF5 group name (full path), set with PetscViewerHDF5PushGroup()/PetscViewerHDF5PopGroup().
579   If none has been assigned, returns NULL.
580 
581   Not collective
582 
583   Input Parameter:
584 . viewer - the PetscViewer
585 
586   Output Parameter:
587 . name - The group name
588 
589   Level: intermediate
590 
591 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5OpenGroup()
592 @*/
593 PetscErrorCode  PetscViewerHDF5GetGroup(PetscViewer viewer, const char **name)
594 {
595   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *) viewer->data;
596 
597   PetscFunctionBegin;
598   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
599   PetscValidPointer(name,2);
600   if (hdf5->groups) *name = hdf5->groups->name;
601   else *name = NULL;
602   PetscFunctionReturn(0);
603 }
604 
605 /*@
606   PetscViewerHDF5OpenGroup - Open the HDF5 group with the name (full path) returned by PetscViewerHDF5GetGroup(),
607   and return this group's ID and file ID.
608   If PetscViewerHDF5GetGroup() yields NULL, then group ID is file ID.
609 
610   Not collective
611 
612   Input Parameter:
613 . viewer - the PetscViewer
614 
615   Output Parameter:
616 + fileId - The HDF5 file ID
617 - groupId - The HDF5 group ID
618 
619   Level: intermediate
620 
621 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
622 @*/
623 PetscErrorCode PetscViewerHDF5OpenGroup(PetscViewer viewer, hid_t *fileId, hid_t *groupId)
624 {
625   hid_t          file_id, group;
626   htri_t         found;
627   const char     *groupName = NULL;
628   PetscErrorCode ierr;
629 
630   PetscFunctionBegin;
631   ierr = PetscViewerHDF5GetFileId(viewer, &file_id);CHKERRQ(ierr);
632   ierr = PetscViewerHDF5GetGroup(viewer, &groupName);CHKERRQ(ierr);
633   /* Open group */
634   if (groupName) {
635     PetscBool root;
636 
637     ierr = PetscStrcmp(groupName, "/", &root);CHKERRQ(ierr);
638     PetscStackCall("H5Lexists",found = H5Lexists(file_id, groupName, H5P_DEFAULT));
639     if (!root && (found <= 0)) {
640       PetscStackCallHDF5Return(group,H5Gcreate2,(file_id, groupName, 0, H5P_DEFAULT, H5P_DEFAULT));
641       PetscStackCallHDF5(H5Gclose,(group));
642     }
643     PetscStackCallHDF5Return(group,H5Gopen2,(file_id, groupName, H5P_DEFAULT));
644   } else group = file_id;
645 
646   *fileId  = file_id;
647   *groupId = group;
648   PetscFunctionReturn(0);
649 }
650 
651 /*@
652   PetscViewerHDF5IncrementTimestep - Increments the current timestep for the HDF5 output. Fields are stacked in time.
653 
654   Not collective
655 
656   Input Parameter:
657 . viewer - the PetscViewer
658 
659   Level: intermediate
660 
661 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5SetTimestep(), PetscViewerHDF5GetTimestep()
662 @*/
663 PetscErrorCode PetscViewerHDF5IncrementTimestep(PetscViewer viewer)
664 {
665   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
666 
667   PetscFunctionBegin;
668   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
669   ++hdf5->timestep;
670   PetscFunctionReturn(0);
671 }
672 
673 /*@
674   PetscViewerHDF5SetTimestep - Set the current timestep for the HDF5 output. Fields are stacked in time. A timestep
675   of -1 disables blocking with timesteps.
676 
677   Not collective
678 
679   Input Parameters:
680 + viewer - the PetscViewer
681 - timestep - The timestep number
682 
683   Level: intermediate
684 
685 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5GetTimestep()
686 @*/
687 PetscErrorCode  PetscViewerHDF5SetTimestep(PetscViewer viewer, PetscInt timestep)
688 {
689   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
690 
691   PetscFunctionBegin;
692   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
693   hdf5->timestep = timestep;
694   PetscFunctionReturn(0);
695 }
696 
697 /*@
698   PetscViewerHDF5GetTimestep - Get the current timestep for the HDF5 output. Fields are stacked in time.
699 
700   Not collective
701 
702   Input Parameter:
703 . viewer - the PetscViewer
704 
705   Output Parameter:
706 . timestep - The timestep number
707 
708   Level: intermediate
709 
710 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5SetTimestep()
711 @*/
712 PetscErrorCode  PetscViewerHDF5GetTimestep(PetscViewer viewer, PetscInt *timestep)
713 {
714   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
715 
716   PetscFunctionBegin;
717   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
718   PetscValidPointer(timestep,2);
719   *timestep = hdf5->timestep;
720   PetscFunctionReturn(0);
721 }
722 
723 /*@C
724   PetscDataTypeToHDF5DataType - Converts the PETSc name of a datatype to its HDF5 name.
725 
726   Not collective
727 
728   Input Parameter:
729 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
730 
731   Output Parameter:
732 . mtype - the MPI datatype (for example MPI_DOUBLE, ...)
733 
734   Level: advanced
735 
736 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
737 @*/
738 PetscErrorCode PetscDataTypeToHDF5DataType(PetscDataType ptype, hid_t *htype)
739 {
740   PetscFunctionBegin;
741   if (ptype == PETSC_INT)
742 #if defined(PETSC_USE_64BIT_INDICES)
743                                        *htype = H5T_NATIVE_LLONG;
744 #else
745                                        *htype = H5T_NATIVE_INT;
746 #endif
747   else if (ptype == PETSC_DOUBLE)      *htype = H5T_NATIVE_DOUBLE;
748   else if (ptype == PETSC_LONG)        *htype = H5T_NATIVE_LONG;
749   else if (ptype == PETSC_SHORT)       *htype = H5T_NATIVE_SHORT;
750   else if (ptype == PETSC_ENUM)        *htype = H5T_NATIVE_DOUBLE;
751   else if (ptype == PETSC_BOOL)        *htype = H5T_NATIVE_DOUBLE;
752   else if (ptype == PETSC_FLOAT)       *htype = H5T_NATIVE_FLOAT;
753   else if (ptype == PETSC_CHAR)        *htype = H5T_NATIVE_CHAR;
754   else if (ptype == PETSC_BIT_LOGICAL) *htype = H5T_NATIVE_UCHAR;
755   else if (ptype == PETSC_STRING)      *htype = H5Tcopy(H5T_C_S1);
756   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported PETSc datatype");
757   PetscFunctionReturn(0);
758 }
759 
760 /*@C
761   PetscHDF5DataTypeToPetscDataType - Finds the PETSc name of a datatype from its HDF5 name
762 
763   Not collective
764 
765   Input Parameter:
766 . htype - the HDF5 datatype (for example H5T_NATIVE_DOUBLE, ...)
767 
768   Output Parameter:
769 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
770 
771   Level: advanced
772 
773 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
774 @*/
775 PetscErrorCode PetscHDF5DataTypeToPetscDataType(hid_t htype, PetscDataType *ptype)
776 {
777   PetscFunctionBegin;
778 #if defined(PETSC_USE_64BIT_INDICES)
779   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_LONG;
780   else if (htype == H5T_NATIVE_LLONG)  *ptype = PETSC_INT;
781 #else
782   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_INT;
783 #endif
784   else if (htype == H5T_NATIVE_DOUBLE) *ptype = PETSC_DOUBLE;
785   else if (htype == H5T_NATIVE_LONG)   *ptype = PETSC_LONG;
786   else if (htype == H5T_NATIVE_SHORT)  *ptype = PETSC_SHORT;
787   else if (htype == H5T_NATIVE_FLOAT)  *ptype = PETSC_FLOAT;
788   else if (htype == H5T_NATIVE_CHAR)   *ptype = PETSC_CHAR;
789   else if (htype == H5T_NATIVE_UCHAR)  *ptype = PETSC_CHAR;
790   else if (htype == H5T_C_S1)          *ptype = PETSC_STRING;
791   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported HDF5 datatype");
792   PetscFunctionReturn(0);
793 }
794 
795 /*@C
796  PetscViewerHDF5WriteAttribute - Write an attribute
797 
798   Input Parameters:
799 + viewer - The HDF5 viewer
800 . parent - The parent name
801 . name   - The attribute name
802 . datatype - The attribute type
803 - value    - The attribute value
804 
805   Level: advanced
806 
807 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5HasAttribute()
808 @*/
809 PetscErrorCode PetscViewerHDF5WriteAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *value)
810 {
811   hid_t          h5, dataspace, obj, attribute, dtype;
812   PetscBool      has;
813   PetscErrorCode ierr;
814 
815   PetscFunctionBegin;
816   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
817   PetscValidCharPointer(parent, 2);
818   PetscValidCharPointer(name, 3);
819   PetscValidPointer(value, 4);
820 
821   ierr = PetscViewerHDF5Traverse_Internal(viewer, parent, PETSC_TRUE, NULL, NULL);CHKERRQ(ierr);
822   ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parent, name, &has);CHKERRQ(ierr);
823   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
824   if (datatype == PETSC_STRING) {
825     size_t len;
826     ierr = PetscStrlen((const char *) value, &len);CHKERRQ(ierr);
827     PetscStackCallHDF5(H5Tset_size,(dtype, len+1));
828   }
829   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
830   PetscStackCallHDF5Return(dataspace,H5Screate,(H5S_SCALAR));
831   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parent, H5P_DEFAULT));
832   if (has) {
833     PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
834   } else {
835     PetscStackCallHDF5Return(attribute,H5Acreate2,(obj, name, dtype, dataspace, H5P_DEFAULT, H5P_DEFAULT));
836   }
837   PetscStackCallHDF5(H5Awrite,(attribute, dtype, value));
838   if (datatype == PETSC_STRING) PetscStackCallHDF5(H5Tclose,(dtype));
839   PetscStackCallHDF5(H5Aclose,(attribute));
840   PetscStackCallHDF5(H5Oclose,(obj));
841   PetscStackCallHDF5(H5Sclose,(dataspace));
842   PetscFunctionReturn(0);
843 }
844 
845 /*@C
846  PetscViewerHDF5ReadAttribute - Read an attribute
847 
848   Input Parameters:
849 + viewer - The HDF5 viewer
850 . parent - The parent name
851 . name   - The attribute name
852 - datatype - The attribute type
853 
854   Output Parameter:
855 . value    - The attribute value
856 
857   Level: advanced
858 
859 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5HasAttribute()
860 @*/
861 PetscErrorCode PetscViewerHDF5ReadAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, void *value)
862 {
863   hid_t          h5, obj, attribute, atype, dtype;
864   PetscErrorCode ierr;
865 
866   PetscFunctionBegin;
867   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
868   PetscValidCharPointer(parent, 2);
869   PetscValidCharPointer(name, 3);
870   PetscValidPointer(value, 4);
871   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
872   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
873   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parent, H5P_DEFAULT));
874   PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
875   if (datatype == PETSC_STRING) {
876     size_t len;
877     PetscStackCallHDF5Return(atype,H5Aget_type,(attribute));
878     PetscStackCallHDF5Return(len,H5Tget_size,(atype));
879     PetscStackCallHDF5(H5Tclose,(atype));
880     ierr = PetscMalloc((len+1) * sizeof(char *), &value);CHKERRQ(ierr);
881   }
882   PetscStackCallHDF5(H5Aread,(attribute, dtype, value));
883   PetscStackCallHDF5(H5Aclose,(attribute));
884   /* H5Oclose can be used to close groups, datasets, or committed datatypes */
885   PetscStackCallHDF5(H5Oclose,(obj));
886   PetscFunctionReturn(0);
887 }
888 
889 PETSC_STATIC_INLINE PetscErrorCode PetscViewerHDF5Traverse_Inner_Internal(hid_t h5, const char name[], PetscBool createGroup, PetscBool *exists_)
890 {
891   htri_t exists;
892   hid_t group;
893 
894   PetscFunctionBegin;
895   PetscStackCallHDF5Return(exists,H5Lexists,(h5, name, H5P_DEFAULT));
896   if (exists) PetscStackCallHDF5Return(exists,H5Oexists_by_name,(h5, name, H5P_DEFAULT));
897   if (!exists && createGroup) {
898     PetscStackCallHDF5Return(group,H5Gcreate2,(h5, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT));
899     PetscStackCallHDF5(H5Gclose,(group));
900     exists = PETSC_TRUE;
901   }
902   *exists_ = (PetscBool) exists;
903   PetscFunctionReturn(0);
904 }
905 
906 static PetscErrorCode PetscViewerHDF5Traverse_Internal(PetscViewer viewer, const char name[], PetscBool createGroup, PetscBool *has, H5O_type_t *otype)
907 {
908   hid_t          h5;
909   PetscBool      exists;
910   PetscInt       i,n;
911   char           **hierarchy;
912   char           buf[PETSC_MAX_PATH_LEN]="";
913   PetscErrorCode ierr;
914 
915   PetscFunctionBegin;
916   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
917   PetscValidCharPointer(name, 2);
918   if (has) {
919     PetscValidIntPointer(has, 3);
920     *has = PETSC_FALSE;
921   }
922   if (otype) {
923     PetscValidIntPointer(otype, 4);
924     *otype = H5O_TYPE_UNKNOWN;
925   }
926   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
927 
928   /*
929      Unfortunately, H5Oexists_by_name() fails if any object in hierarchy is missing.
930      Hence, each of them needs to be tested separately:
931      1) whether it's a valid link
932      2) whether this link resolves to an object
933      See H5Oexists_by_name() documentation.
934   */
935   ierr = PetscStrToArray(name,'/',&n,&hierarchy);CHKERRQ(ierr);
936   if (!n) {
937     /*  Assume group "/" always exists in accordance with HDF5 >= 1.10.0. See H5Lexists() documentation. */
938     if (has)   *has   = PETSC_TRUE;
939     if (otype) *otype = H5O_TYPE_GROUP;
940     ierr = PetscStrToArrayDestroy(n,hierarchy);CHKERRQ(ierr);
941     PetscFunctionReturn(0);
942   }
943   for (i=0; i<n; i++) {
944     ierr = PetscStrcat(buf,"/");CHKERRQ(ierr);
945     ierr = PetscStrcat(buf,hierarchy[i]);CHKERRQ(ierr);
946     ierr = PetscViewerHDF5Traverse_Inner_Internal(h5, buf, createGroup, &exists);CHKERRQ(ierr);
947     if (!exists) break;
948   }
949   ierr = PetscStrToArrayDestroy(n,hierarchy);CHKERRQ(ierr);
950 
951   /* If the object exists, get its type */
952   if (exists && otype) {
953     H5O_info_t info;
954 
955     PetscStackCallHDF5(H5Oget_info_by_name,(h5, name, &info, H5P_DEFAULT));
956     *otype = info.type;
957   }
958   if (has) *has = exists;
959   PetscFunctionReturn(0);
960 }
961 
962 /*@
963  PetscViewerHDF5HasGroup - Check whether the current (pushed) group exists in the HDF5 file
964 
965   Input Parameters:
966 . viewer - The HDF5 viewer
967 
968   Output Parameter:
969 . has    - Flag for group existence
970 
971   Notes:
972   If the path exists but is not a group, this returns PETSC_FALSE as well.
973 
974   Level: advanced
975 
976 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5PushGroup(), PetscViewerHDF5PopGroup(), PetscViewerHDF5OpenGroup()
977 @*/
978 PetscErrorCode PetscViewerHDF5HasGroup(PetscViewer viewer, PetscBool *has)
979 {
980   H5O_type_t type;
981   const char *name;
982   PetscErrorCode ierr;
983 
984   PetscFunctionBegin;
985   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
986   PetscValidIntPointer(has,2);
987   ierr = PetscViewerHDF5GetGroup(viewer, &name);CHKERRQ(ierr);
988   ierr = PetscViewerHDF5Traverse_Internal(viewer, name, PETSC_FALSE, has, &type);CHKERRQ(ierr);
989   *has = (type == H5O_TYPE_GROUP) ? PETSC_TRUE : PETSC_FALSE;
990   PetscFunctionReturn(0);
991 }
992 
993 /*@
994  PetscViewerHDF5HasObject - Check whether a dataset with the same name as given object exists in the HDF5 file under current group
995 
996   Input Parameters:
997 + viewer - The HDF5 viewer
998 - obj    - The named object
999 
1000   Output Parameter:
1001 . has    - Flag for dataset existence; PETSC_FALSE for unnamed object
1002 
1003   Notes:
1004   If the path exists but is not a dataset, this returns PETSC_FALSE as well.
1005 
1006   Level: advanced
1007 
1008 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1009 @*/
1010 PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, PetscObject obj, PetscBool *has)
1011 {
1012   H5O_type_t type;
1013   char *path;
1014   PetscErrorCode ierr;
1015 
1016   PetscFunctionBegin;
1017   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1018   PetscValidHeader(obj,2);
1019   PetscValidIntPointer(has,3);
1020   *has = PETSC_FALSE;
1021   if (!obj->name) PetscFunctionReturn(0);
1022   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, obj->name, &path);CHKERRQ(ierr);
1023   ierr = PetscViewerHDF5Traverse_Internal(viewer, path, PETSC_FALSE, has, &type);CHKERRQ(ierr);
1024   *has = (type == H5O_TYPE_DATASET) ? PETSC_TRUE : PETSC_FALSE;
1025   ierr = PetscFree(path);CHKERRQ(ierr);
1026   PetscFunctionReturn(0);
1027 }
1028 
1029 /*@C
1030  PetscViewerHDF5HasAttribute - Check whether an attribute exists
1031 
1032   Input Parameters:
1033 + viewer - The HDF5 viewer
1034 . parent - The parent name
1035 - name   - The attribute name
1036 
1037   Output Parameter:
1038 . has    - Flag for attribute existence
1039 
1040   Level: advanced
1041 
1042 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5HasObject()
1043 @*/
1044 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
1045 {
1046   PetscErrorCode ierr;
1047 
1048   PetscFunctionBegin;
1049   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1050   PetscValidCharPointer(parent,2);
1051   PetscValidCharPointer(name,3);
1052   PetscValidIntPointer(has,4);
1053   *has = PETSC_FALSE;
1054   ierr = PetscViewerHDF5Traverse_Internal(viewer, parent, PETSC_FALSE, has, NULL);CHKERRQ(ierr);
1055   if (!*has) PetscFunctionReturn(0);
1056   ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parent, name, has);CHKERRQ(ierr);
1057   PetscFunctionReturn(0);
1058 }
1059 
1060 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
1061 {
1062   hid_t          h5;
1063   htri_t         hhas;
1064   PetscErrorCode ierr;
1065 
1066   PetscFunctionBegin;
1067   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1068   PetscStackCallHDF5Return(hhas,H5Aexists_by_name,(h5, parent, name, H5P_DEFAULT));
1069   *has = hhas ? PETSC_TRUE : PETSC_FALSE;
1070   PetscFunctionReturn(0);
1071 }
1072 
1073 static PetscErrorCode PetscViewerHDF5ReadInitialize_Private(PetscViewer viewer, const char name[], HDF5ReadCtx *ctx)
1074 {
1075   HDF5ReadCtx    h=NULL;
1076   const char    *groupname=NULL;
1077   char           vecgroup[PETSC_MAX_PATH_LEN];
1078   PetscErrorCode ierr;
1079 
1080   PetscFunctionBegin;
1081   ierr = PetscNew(&h);CHKERRQ(ierr);
1082   ierr = PetscViewerHDF5OpenGroup(viewer, &h->file, &h->group);CHKERRQ(ierr);
1083   PetscStackCallHDF5Return(h->dataset,H5Dopen2,(h->group, name, H5P_DEFAULT));
1084   PetscStackCallHDF5Return(h->dataspace,H5Dget_space,(h->dataset));
1085   ierr = PetscViewerHDF5GetTimestep(viewer, &h->timestep);CHKERRQ(ierr);
1086   ierr = PetscViewerHDF5GetGroup(viewer,&groupname);CHKERRQ(ierr);
1087   ierr = PetscSNPrintf(vecgroup,PETSC_MAX_PATH_LEN,"%s/%s",groupname ? groupname : "",name);CHKERRQ(ierr);
1088   ierr = PetscViewerHDF5HasAttribute(viewer,vecgroup,"complex",&h->complexVal);CHKERRQ(ierr);
1089   /* MATLAB stores column vectors horizontally */
1090   ierr = PetscViewerHDF5HasAttribute(viewer,vecgroup,"MATLAB_class",&h->horizontal);CHKERRQ(ierr);
1091   /* Create property list for collective dataset read */
1092   PetscStackCallHDF5Return(h->plist,H5Pcreate,(H5P_DATASET_XFER));
1093 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
1094   PetscStackCallHDF5(H5Pset_dxpl_mpio,(h->plist, H5FD_MPIO_COLLECTIVE));
1095 #endif
1096   /* To write dataset independently use H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_INDEPENDENT) */
1097   *ctx = h;
1098   PetscFunctionReturn(0);
1099 }
1100 
1101 static PetscErrorCode PetscViewerHDF5ReadFinalize_Private(PetscViewer viewer, HDF5ReadCtx *ctx)
1102 {
1103   HDF5ReadCtx    h;
1104   PetscErrorCode ierr;
1105 
1106   PetscFunctionBegin;
1107   h = *ctx;
1108   PetscStackCallHDF5(H5Pclose,(h->plist));
1109   if (h->group != h->file) PetscStackCallHDF5(H5Gclose,(h->group));
1110   PetscStackCallHDF5(H5Sclose,(h->dataspace));
1111   PetscStackCallHDF5(H5Dclose,(h->dataset));
1112   ierr = PetscFree(*ctx);CHKERRQ(ierr);
1113   PetscFunctionReturn(0);
1114 }
1115 
1116 static PetscErrorCode PetscViewerHDF5ReadSizes_Private(PetscViewer viewer, HDF5ReadCtx ctx, PetscLayout *map_)
1117 {
1118   int            rdim, dim;
1119   hsize_t        dims[4];
1120   PetscInt       bsInd, lenInd, bs, len, N;
1121   PetscLayout    map;
1122   PetscErrorCode ierr;
1123 
1124   PetscFunctionBegin;
1125   if (!(*map_)) {
1126     ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)viewer),map_);CHKERRQ(ierr);
1127   }
1128   map = *map_;
1129   /* calculate expected number of dimensions */
1130   dim = 0;
1131   if (ctx->timestep >= 0) ++dim;
1132   ++dim; /* length in blocks */
1133   if (ctx->complexVal) ++dim;
1134   /* get actual number of dimensions in dataset */
1135   PetscStackCallHDF5Return(rdim,H5Sget_simple_extent_dims,(ctx->dataspace, dims, NULL));
1136   /* calculate expected dimension indices */
1137   lenInd = 0;
1138   if (ctx->timestep >= 0) ++lenInd;
1139   bsInd = lenInd + 1;
1140   ctx->dim2 = PETSC_FALSE;
1141   if (rdim == dim) {
1142     bs = 1; /* support vectors stored as 1D array */
1143   } else if (rdim == dim+1) {
1144     bs = (PetscInt) dims[bsInd];
1145     if (bs == 1) ctx->dim2 = PETSC_TRUE; /* vector with blocksize of 1, still stored as 2D array */
1146   } else {
1147     SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Dimension of array in file %d not %d as expected", rdim, dim);
1148   }
1149   len = dims[lenInd];
1150   if (ctx->horizontal) {
1151     if (len != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot have horizontal array with number of rows > 1. In case of MATLAB MAT-file, vectors must be saved as column vectors.");
1152     len = bs;
1153     bs = 1;
1154   }
1155   N = (PetscInt) len*bs;
1156 
1157   /* Set Vec sizes,blocksize,and type if not already set */
1158   if (map->bs < 0) {
1159     ierr = PetscLayoutSetBlockSize(map, bs);CHKERRQ(ierr);
1160   } else if (map->bs != bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_UNEXPECTED, "Block size of array in file is %D, not %D as expected",bs,map->bs);
1161   if (map->N < 0) {
1162     ierr = PetscLayoutSetSize(map, N);CHKERRQ(ierr);
1163   } else if (map->N != N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_UNEXPECTED, "Global size of array in file is %D, not %D as expected",N,map->N);
1164   PetscFunctionReturn(0);
1165 }
1166 
1167 static PetscErrorCode PetscViewerHDF5ReadSelectHyperslab_Private(PetscViewer viewer, HDF5ReadCtx ctx, PetscLayout map, hid_t *memspace)
1168 {
1169   hsize_t        count[4], offset[4];
1170   int            dim;
1171   PetscInt       bs, n, low;
1172   PetscErrorCode ierr;
1173 
1174   PetscFunctionBegin;
1175   /* Compute local size and ownership range */
1176   ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1177   ierr = PetscLayoutGetBlockSize(map, &bs);CHKERRQ(ierr);
1178   ierr = PetscLayoutGetLocalSize(map, &n);CHKERRQ(ierr);
1179   ierr = PetscLayoutGetRange(map, &low, NULL);CHKERRQ(ierr);
1180 
1181   /* Each process defines a dataset and reads it from the hyperslab in the file */
1182   dim  = 0;
1183   if (ctx->timestep >= 0) {
1184     count[dim]  = 1;
1185     offset[dim] = ctx->timestep;
1186     ++dim;
1187   }
1188   if (ctx->horizontal) {
1189     count[dim]  = 1;
1190     offset[dim] = 0;
1191     ++dim;
1192   }
1193   {
1194     ierr = PetscHDF5IntCast(n/bs, &count[dim]);CHKERRQ(ierr);
1195     ierr = PetscHDF5IntCast(low/bs, &offset[dim]);CHKERRQ(ierr);
1196     ++dim;
1197   }
1198   if (bs > 1 || ctx->dim2) {
1199     if (PetscUnlikely(ctx->horizontal)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "cannot have horizontal array with blocksize > 1");
1200     count[dim]  = bs;
1201     offset[dim] = 0;
1202     ++dim;
1203   }
1204   if (ctx->complexVal) {
1205     count[dim]  = 2;
1206     offset[dim] = 0;
1207     ++dim;
1208   }
1209   PetscStackCallHDF5Return(*memspace,H5Screate_simple,(dim, count, NULL));
1210   PetscStackCallHDF5(H5Sselect_hyperslab,(ctx->dataspace, H5S_SELECT_SET, offset, NULL, count, NULL));
1211   PetscFunctionReturn(0);
1212 }
1213 
1214 static PetscErrorCode PetscViewerHDF5ReadArray_Private(PetscViewer viewer, HDF5ReadCtx h, hid_t datatype, hid_t memspace, void *arr)
1215 {
1216   PetscFunctionBegin;
1217   PetscStackCallHDF5(H5Dread,(h->dataset, datatype, memspace, h->dataspace, h->plist, arr));
1218   PetscFunctionReturn(0);
1219 }
1220 
1221 PetscErrorCode PetscViewerHDF5Load(PetscViewer viewer, const char *name, PetscLayout map, hid_t datatype, void **newarr)
1222 {
1223   HDF5ReadCtx     h=NULL;
1224   hid_t           memspace=0;
1225   size_t          unitsize;
1226   void            *arr;
1227   PetscErrorCode  ierr;
1228 
1229   PetscFunctionBegin;
1230   ierr = PetscViewerHDF5ReadInitialize_Private(viewer, name, &h);CHKERRQ(ierr);
1231   ierr = PetscViewerHDF5ReadSizes_Private(viewer, h, &map);CHKERRQ(ierr);
1232   ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1233   ierr = PetscViewerHDF5ReadSelectHyperslab_Private(viewer, h, map, &memspace);CHKERRQ(ierr);
1234 
1235 #if defined(PETSC_USE_COMPLEX)
1236   if (!h->complexVal) {
1237     H5T_class_t clazz = H5Tget_class(datatype);
1238     if (clazz == H5T_FLOAT) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"File contains real numbers but PETSc is configured for complex. The conversion is not yet implemented. Configure with --with-scalar-type=real.");
1239   }
1240 #else
1241   if (h->complexVal) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"File contains complex numbers but PETSc not configured for them. Configure with --with-scalar-type=complex.");
1242 #endif
1243   unitsize = H5Tget_size(datatype);
1244   if (h->complexVal) unitsize *= 2;
1245   if (unitsize <= 0 || unitsize > PetscMax(sizeof(PetscInt),sizeof(PetscScalar))) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Sanity check failed: HDF5 function H5Tget_size(datatype) returned suspicious value %D",unitsize);
1246   ierr = PetscMalloc(map->n*unitsize, &arr);CHKERRQ(ierr);
1247 
1248   ierr = PetscViewerHDF5ReadArray_Private(viewer, h, datatype, memspace, arr);CHKERRQ(ierr);
1249   PetscStackCallHDF5(H5Sclose,(memspace));
1250   ierr = PetscViewerHDF5ReadFinalize_Private(viewer, &h);CHKERRQ(ierr);
1251   *newarr = arr;
1252   PetscFunctionReturn(0);
1253 }
1254 
1255 /*@C
1256  PetscViewerHDF5ReadSizes - Read block size and global size of a vector (Vec or IS) stored in an HDF5 file.
1257 
1258   Input Parameters:
1259 + viewer - The HDF5 viewer
1260 - name   - The vector name
1261 
1262   Output Parameter:
1263 + bs     - block size
1264 - N      - global size
1265 
1266   Note:
1267   A vector is stored as an HDF5 dataspace with 1-4 dimensions in this order:
1268   1) # timesteps (optional), 2) # blocks, 3) # elements per block (optional), 4) real and imaginary part (only for complex).
1269 
1270   A vectors can be stored as a 2D dataspace even if its blocksize is 1; see PetscViewerHDF5SetBaseDimension2().
1271 
1272   Level: advanced
1273 
1274 .seealso: PetscViewerHDF5Open(), VecLoad(), ISLoad(), VecGetSize(), ISGetSize(), PetscViewerHDF5SetBaseDimension2()
1275 @*/
1276 PetscErrorCode PetscViewerHDF5ReadSizes(PetscViewer viewer, const char name[], PetscInt *bs, PetscInt *N)
1277 {
1278   HDF5ReadCtx    h=NULL;
1279   PetscLayout    map=NULL;
1280   PetscErrorCode ierr;
1281 
1282   PetscFunctionBegin;
1283   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1284   ierr = PetscViewerHDF5ReadInitialize_Private(viewer, name, &h);CHKERRQ(ierr);
1285   ierr = PetscViewerHDF5ReadSizes_Private(viewer, h, &map);CHKERRQ(ierr);
1286   ierr = PetscViewerHDF5ReadFinalize_Private(viewer, &h);CHKERRQ(ierr);
1287   if (bs) *bs = map->bs;
1288   if (N) *N = map->N;
1289   ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1290   PetscFunctionReturn(0);
1291 }
1292 
1293 /*
1294   The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that
1295   is attached to a communicator, in this case the attribute is a PetscViewer.
1296 */
1297 PetscMPIInt Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID;
1298 
1299 /*@C
1300   PETSC_VIEWER_HDF5_ - Creates an HDF5 PetscViewer shared by all processors in a communicator.
1301 
1302   Collective on MPI_Comm
1303 
1304   Input Parameter:
1305 . comm - the MPI communicator to share the HDF5 PetscViewer
1306 
1307   Level: intermediate
1308 
1309   Options Database Keys:
1310 . -viewer_hdf5_filename <name>
1311 
1312   Environmental variables:
1313 . PETSC_VIEWER_HDF5_FILENAME
1314 
1315   Notes:
1316   Unlike almost all other PETSc routines, PETSC_VIEWER_HDF5_ does not return
1317   an error code.  The HDF5 PetscViewer is usually used in the form
1318 $       XXXView(XXX object, PETSC_VIEWER_HDF5_(comm));
1319 
1320 .seealso: PetscViewerHDF5Open(), PetscViewerCreate(), PetscViewerDestroy()
1321 @*/
1322 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm)
1323 {
1324   PetscErrorCode ierr;
1325   PetscBool      flg;
1326   PetscViewer    viewer;
1327   char           fname[PETSC_MAX_PATH_LEN];
1328   MPI_Comm       ncomm;
1329 
1330   PetscFunctionBegin;
1331   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1332   if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) {
1333     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_HDF5_keyval,0);
1334     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1335   }
1336   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void**)&viewer,(int*)&flg);
1337   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1338   if (!flg) { /* PetscViewer not yet created */
1339     ierr = PetscOptionsGetenv(ncomm,"PETSC_VIEWER_HDF5_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
1340     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1341     if (!flg) {
1342       ierr = PetscStrcpy(fname,"output.h5");
1343       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1344     }
1345     ierr = PetscViewerHDF5Open(ncomm,fname,FILE_MODE_WRITE,&viewer);
1346     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1347     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
1348     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1349     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void*)viewer);
1350     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1351   }
1352   ierr = PetscCommDestroy(&ncomm);
1353   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1354   PetscFunctionReturn(viewer);
1355 }
1356