xref: /petsc/src/sys/classes/viewer/impls/hdf5/hdf5v.c (revision bb286ee1a7457ebb8f9baeff16f33b0409115ae2)
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   PetscValidPointer(parent, 2);
803   PetscValidPointer(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   PetscValidPointer(parent, 2);
854   PetscValidPointer(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  PetscViewerHDF5HasObject - Check whether a dataset with the same name as given object exists in the HDF5 file
940 
941   Input Parameters:
942 + viewer - The HDF5 viewer
943 - obj    - The named object
944 
945   Output Parameter:
946 . has    - Flag for dataset existence; PETSC_FALSE for unnamed object
947 
948   Level: advanced
949 
950 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5HasAttribute()
951 @*/
952 PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, PetscObject obj, PetscBool *has)
953 {
954   H5O_type_t type;
955   PetscErrorCode ierr;
956 
957   PetscFunctionBegin;
958   *has = PETSC_FALSE;
959   if (obj->name) {
960     ierr = PetscViewerHDF5Traverse_Internal(viewer, obj->name, PETSC_FALSE, has, &type);CHKERRQ(ierr);
961     *has = (type == H5O_TYPE_DATASET) ? PETSC_TRUE : PETSC_FALSE;
962   }
963   PetscFunctionReturn(0);
964 }
965 
966 /*@C
967  PetscViewerHDF5HasAttribute - Check whether an attribute exists
968 
969   Input Parameters:
970 + viewer - The HDF5 viewer
971 . parent - The parent name
972 - name   - The attribute name
973 
974   Output Parameter:
975 . has    - Flag for attribute existence
976 
977   Level: advanced
978 
979 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5HasObject()
980 @*/
981 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
982 {
983   PetscErrorCode ierr;
984 
985   PetscFunctionBegin;
986   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
987   PetscValidPointer(parent, 2);
988   PetscValidPointer(name, 3);
989   PetscValidPointer(has, 4);
990   *has = PETSC_FALSE;
991   ierr = PetscViewerHDF5Traverse_Internal(viewer, parent, PETSC_FALSE, has, NULL);CHKERRQ(ierr);
992   if (!*has) PetscFunctionReturn(0);
993   ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parent, name, has);CHKERRQ(ierr);
994   PetscFunctionReturn(0);
995 }
996 
997 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
998 {
999   hid_t          h5;
1000   htri_t         hhas;
1001   PetscErrorCode ierr;
1002 
1003   PetscFunctionBegin;
1004   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1005   PetscStackCallHDF5Return(hhas,H5Aexists_by_name,(h5, parent, name, H5P_DEFAULT));
1006   *has = hhas ? PETSC_TRUE : PETSC_FALSE;
1007   PetscFunctionReturn(0);
1008 }
1009 
1010 static PetscErrorCode PetscViewerHDF5ReadInitialize_Private(PetscViewer viewer, const char name[], HDF5ReadCtx *ctx)
1011 {
1012   HDF5ReadCtx    h=NULL;
1013   const char    *groupname=NULL;
1014   char           vecgroup[PETSC_MAX_PATH_LEN];
1015   PetscErrorCode ierr;
1016 
1017   PetscFunctionBegin;
1018   ierr = PetscNew(&h);CHKERRQ(ierr);
1019   ierr = PetscViewerHDF5OpenGroup(viewer, &h->file, &h->group);CHKERRQ(ierr);
1020   PetscStackCallHDF5Return(h->dataset,H5Dopen2,(h->group, name, H5P_DEFAULT));
1021   PetscStackCallHDF5Return(h->dataspace,H5Dget_space,(h->dataset));
1022   ierr = PetscViewerHDF5GetTimestep(viewer, &h->timestep);CHKERRQ(ierr);
1023   ierr = PetscViewerHDF5GetGroup(viewer,&groupname);CHKERRQ(ierr);
1024   ierr = PetscSNPrintf(vecgroup,PETSC_MAX_PATH_LEN,"%s/%s",groupname ? groupname : "",name);CHKERRQ(ierr);
1025   ierr = PetscViewerHDF5HasAttribute(viewer,vecgroup,"complex",&h->complexVal);CHKERRQ(ierr);
1026   /* MATLAB stores column vectors horizontally */
1027   ierr = PetscViewerHDF5HasAttribute(viewer,vecgroup,"MATLAB_class",&h->horizontal);CHKERRQ(ierr);
1028   /* Create property list for collective dataset read */
1029   PetscStackCallHDF5Return(h->plist,H5Pcreate,(H5P_DATASET_XFER));
1030 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
1031   PetscStackCallHDF5(H5Pset_dxpl_mpio,(h->plist, H5FD_MPIO_COLLECTIVE));
1032 #endif
1033   /* To write dataset independently use H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_INDEPENDENT) */
1034   *ctx = h;
1035   PetscFunctionReturn(0);
1036 }
1037 
1038 static PetscErrorCode PetscViewerHDF5ReadFinalize_Private(PetscViewer viewer, HDF5ReadCtx *ctx)
1039 {
1040   HDF5ReadCtx    h;
1041   PetscErrorCode ierr;
1042 
1043   PetscFunctionBegin;
1044   h = *ctx;
1045   PetscStackCallHDF5(H5Pclose,(h->plist));
1046   if (h->group != h->file) PetscStackCallHDF5(H5Gclose,(h->group));
1047   PetscStackCallHDF5(H5Sclose,(h->dataspace));
1048   PetscStackCallHDF5(H5Dclose,(h->dataset));
1049   ierr = PetscFree(*ctx);CHKERRQ(ierr);
1050   PetscFunctionReturn(0);
1051 }
1052 
1053 static PetscErrorCode PetscViewerHDF5ReadSizes_Private(PetscViewer viewer, HDF5ReadCtx ctx, PetscLayout *map_)
1054 {
1055   int            rdim, dim;
1056   hsize_t        dims[4];
1057   PetscInt       bsInd, lenInd, bs, len, N;
1058   PetscLayout    map;
1059   PetscErrorCode ierr;
1060 
1061   PetscFunctionBegin;
1062   if (!(*map_)) {
1063     ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)viewer),map_);CHKERRQ(ierr);
1064   }
1065   map = *map_;
1066   /* calculate expected number of dimensions */
1067   dim = 0;
1068   if (ctx->timestep >= 0) ++dim;
1069   ++dim; /* length in blocks */
1070   if (ctx->complexVal) ++dim;
1071   /* get actual number of dimensions in dataset */
1072   PetscStackCallHDF5Return(rdim,H5Sget_simple_extent_dims,(ctx->dataspace, dims, NULL));
1073   /* calculate expected dimension indices */
1074   lenInd = 0;
1075   if (ctx->timestep >= 0) ++lenInd;
1076   bsInd = lenInd + 1;
1077   ctx->dim2 = PETSC_FALSE;
1078   if (rdim == dim) {
1079     bs = 1; /* support vectors stored as 1D array */
1080   } else if (rdim == dim+1) {
1081     bs = (PetscInt) dims[bsInd];
1082     if (bs == 1) ctx->dim2 = PETSC_TRUE; /* vector with blocksize of 1, still stored as 2D array */
1083   } else {
1084     SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Dimension of array in file %d not %d as expected", rdim, dim);
1085   }
1086   len = dims[lenInd];
1087   if (ctx->horizontal) {
1088     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.");
1089     len = bs;
1090     bs = 1;
1091   }
1092   N = (PetscInt) len*bs;
1093 
1094   /* Set Vec sizes,blocksize,and type if not already set */
1095   if (map->bs < 0) {
1096     ierr = PetscLayoutSetBlockSize(map, bs);CHKERRQ(ierr);
1097   } 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);
1098   if (map->N < 0) {
1099     ierr = PetscLayoutSetSize(map, N);CHKERRQ(ierr);
1100   } 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);
1101   PetscFunctionReturn(0);
1102 }
1103 
1104 static PetscErrorCode PetscViewerHDF5ReadSelectHyperslab_Private(PetscViewer viewer, HDF5ReadCtx ctx, PetscLayout map, hid_t *memspace)
1105 {
1106   hsize_t        count[4], offset[4];
1107   int            dim;
1108   PetscInt       bs, n, low;
1109   PetscErrorCode ierr;
1110 
1111   PetscFunctionBegin;
1112   /* Compute local size and ownership range */
1113   ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1114   ierr = PetscLayoutGetBlockSize(map, &bs);CHKERRQ(ierr);
1115   ierr = PetscLayoutGetLocalSize(map, &n);CHKERRQ(ierr);
1116   ierr = PetscLayoutGetRange(map, &low, NULL);CHKERRQ(ierr);
1117 
1118   /* Each process defines a dataset and reads it from the hyperslab in the file */
1119   dim  = 0;
1120   if (ctx->timestep >= 0) {
1121     count[dim]  = 1;
1122     offset[dim] = ctx->timestep;
1123     ++dim;
1124   }
1125   if (ctx->horizontal) {
1126     count[dim]  = 1;
1127     offset[dim] = 0;
1128     ++dim;
1129   }
1130   {
1131     ierr = PetscHDF5IntCast(n/bs, &count[dim]);CHKERRQ(ierr);
1132     ierr = PetscHDF5IntCast(low/bs, &offset[dim]);CHKERRQ(ierr);
1133     ++dim;
1134   }
1135   if (bs > 1 || ctx->dim2) {
1136     if (PetscUnlikely(ctx->horizontal)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "cannot have horizontal array with blocksize > 1");
1137     count[dim]  = bs;
1138     offset[dim] = 0;
1139     ++dim;
1140   }
1141   if (ctx->complexVal) {
1142     count[dim]  = 2;
1143     offset[dim] = 0;
1144     ++dim;
1145   }
1146   PetscStackCallHDF5Return(*memspace,H5Screate_simple,(dim, count, NULL));
1147   PetscStackCallHDF5(H5Sselect_hyperslab,(ctx->dataspace, H5S_SELECT_SET, offset, NULL, count, NULL));
1148   PetscFunctionReturn(0);
1149 }
1150 
1151 static PetscErrorCode PetscViewerHDF5ReadArray_Private(PetscViewer viewer, HDF5ReadCtx h, hid_t datatype, hid_t memspace, void *arr)
1152 {
1153   PetscFunctionBegin;
1154   PetscStackCallHDF5(H5Dread,(h->dataset, datatype, memspace, h->dataspace, h->plist, arr));
1155   PetscFunctionReturn(0);
1156 }
1157 
1158 PetscErrorCode PetscViewerHDF5Load(PetscViewer viewer, const char *name, PetscLayout map, hid_t datatype, void **newarr)
1159 {
1160   HDF5ReadCtx     h=NULL;
1161   hid_t           memspace=0;
1162   size_t          unitsize;
1163   void            *arr;
1164   PetscErrorCode  ierr;
1165 
1166   PetscFunctionBegin;
1167   ierr = PetscViewerHDF5ReadInitialize_Private(viewer, name, &h);CHKERRQ(ierr);
1168   ierr = PetscViewerHDF5ReadSizes_Private(viewer, h, &map);CHKERRQ(ierr);
1169   ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1170   ierr = PetscViewerHDF5ReadSelectHyperslab_Private(viewer, h, map, &memspace);CHKERRQ(ierr);
1171 
1172 #if defined(PETSC_USE_COMPLEX)
1173   if (!h->complexVal) {
1174     H5T_class_t clazz = H5Tget_class(datatype);
1175     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.");
1176   }
1177 #else
1178   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.");
1179 #endif
1180   unitsize = H5Tget_size(datatype);
1181   if (h->complexVal) unitsize *= 2;
1182   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);
1183   ierr = PetscMalloc(map->n*unitsize, &arr);CHKERRQ(ierr);
1184 
1185   ierr = PetscViewerHDF5ReadArray_Private(viewer, h, datatype, memspace, arr);CHKERRQ(ierr);
1186   PetscStackCallHDF5(H5Sclose,(memspace));
1187   ierr = PetscViewerHDF5ReadFinalize_Private(viewer, &h);CHKERRQ(ierr);
1188   *newarr = arr;
1189   PetscFunctionReturn(0);
1190 }
1191 
1192 /*@C
1193  PetscViewerHDF5ReadSizes - Read block size and global size of a vector (Vec or IS) stored in an HDF5 file.
1194 
1195   Input Parameters:
1196 + viewer - The HDF5 viewer
1197 - name   - The vector name
1198 
1199   Output Parameter:
1200 + bs     - block size
1201 - N      - global size
1202 
1203   Note:
1204   A vector is stored as an HDF5 dataspace with 1-4 dimensions in this order:
1205   1) # timesteps (optional), 2) # blocks, 3) # elements per block (optional), 4) real and imaginary part (only for complex).
1206 
1207   A vectors can be stored as a 2D dataspace even if its blocksize is 1; see PetscViewerHDF5SetBaseDimension2().
1208 
1209   Level: advanced
1210 
1211 .seealso: PetscViewerHDF5Open(), VecLoad(), ISLoad(), VecGetSize(), ISGetSize(), PetscViewerHDF5SetBaseDimension2()
1212 @*/
1213 PetscErrorCode PetscViewerHDF5ReadSizes(PetscViewer viewer, const char name[], PetscInt *bs, PetscInt *N)
1214 {
1215   HDF5ReadCtx    h=NULL;
1216   PetscLayout    map=NULL;
1217   PetscErrorCode ierr;
1218 
1219   PetscFunctionBegin;
1220   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1221   ierr = PetscViewerHDF5ReadInitialize_Private(viewer, name, &h);CHKERRQ(ierr);
1222   ierr = PetscViewerHDF5ReadSizes_Private(viewer, h, &map);CHKERRQ(ierr);
1223   ierr = PetscViewerHDF5ReadFinalize_Private(viewer, &h);CHKERRQ(ierr);
1224   if (bs) *bs = map->bs;
1225   if (N) *N = map->N;
1226   ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1227   PetscFunctionReturn(0);
1228 }
1229 
1230 /*
1231   The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that
1232   is attached to a communicator, in this case the attribute is a PetscViewer.
1233 */
1234 PetscMPIInt Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID;
1235 
1236 /*@C
1237   PETSC_VIEWER_HDF5_ - Creates an HDF5 PetscViewer shared by all processors in a communicator.
1238 
1239   Collective on MPI_Comm
1240 
1241   Input Parameter:
1242 . comm - the MPI communicator to share the HDF5 PetscViewer
1243 
1244   Level: intermediate
1245 
1246   Options Database Keys:
1247 . -viewer_hdf5_filename <name>
1248 
1249   Environmental variables:
1250 . PETSC_VIEWER_HDF5_FILENAME
1251 
1252   Notes:
1253   Unlike almost all other PETSc routines, PETSC_VIEWER_HDF5_ does not return
1254   an error code.  The HDF5 PetscViewer is usually used in the form
1255 $       XXXView(XXX object, PETSC_VIEWER_HDF5_(comm));
1256 
1257 .seealso: PetscViewerHDF5Open(), PetscViewerCreate(), PetscViewerDestroy()
1258 @*/
1259 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm)
1260 {
1261   PetscErrorCode ierr;
1262   PetscBool      flg;
1263   PetscViewer    viewer;
1264   char           fname[PETSC_MAX_PATH_LEN];
1265   MPI_Comm       ncomm;
1266 
1267   PetscFunctionBegin;
1268   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1269   if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) {
1270     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_HDF5_keyval,0);
1271     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1272   }
1273   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void**)&viewer,(int*)&flg);
1274   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1275   if (!flg) { /* PetscViewer not yet created */
1276     ierr = PetscOptionsGetenv(ncomm,"PETSC_VIEWER_HDF5_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
1277     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1278     if (!flg) {
1279       ierr = PetscStrcpy(fname,"output.h5");
1280       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1281     }
1282     ierr = PetscViewerHDF5Open(ncomm,fname,FILE_MODE_WRITE,&viewer);
1283     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1284     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
1285     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1286     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void*)viewer);
1287     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1288   }
1289   ierr = PetscCommDestroy(&ncomm);
1290   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1291   PetscFunctionReturn(viewer);
1292 }
1293