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