xref: /petsc/src/sys/classes/viewer/impls/hdf5/hdf5v.c (revision 2065540a855ff9f9c49aa4d22d544ff2b07d8a79)
1 #include <petsc/private/viewerimpl.h>
2 #include <petsc/private/viewerhdf5impl.h>
3 #include <petscviewerhdf5.h>    /*I   "petscviewerhdf5.h"   I*/
4 
5 static PetscErrorCode PetscViewerHDF5Traverse_Internal(PetscViewer, const char[], PetscBool, PetscBool*, H5O_type_t*);
6 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer, const char[], const char[], PetscBool*);
7 
8 static PetscErrorCode PetscViewerHDF5GetAbsolutePath_Internal(PetscViewer viewer, const char path[], char *abspath[])
9 {
10   PetscBool      relative = PETSC_FALSE;
11   const char     *group;
12   char           buf[PETSC_MAX_PATH_LEN] = "";
13   PetscErrorCode ierr;
14 
15   PetscFunctionBegin;
16   ierr = PetscViewerHDF5GetGroup(viewer, &group);CHKERRQ(ierr);
17   ierr = PetscViewerHDF5PathIsRelative(path, PETSC_TRUE, &relative);CHKERRQ(ierr);
18   if (relative) {
19     ierr = PetscStrcpy(buf, group);CHKERRQ(ierr);
20     ierr = PetscStrcat(buf, "/");CHKERRQ(ierr);
21     ierr = PetscStrcat(buf, path);CHKERRQ(ierr);
22     ierr = PetscStrallocpy(buf, abspath);CHKERRQ(ierr);
23   } else {
24     ierr = PetscStrallocpy(path, abspath);CHKERRQ(ierr);
25   }
26   PetscFunctionReturn(0);
27 }
28 
29 static PetscErrorCode PetscViewerHDF5CheckNamedObject_Internal(PetscViewer viewer, PetscObject obj)
30 {
31   PetscBool      has;
32   PetscErrorCode ierr;
33 
34   PetscFunctionBegin;
35   ierr = PetscViewerHDF5HasObject(viewer, obj, &has);CHKERRQ(ierr);
36   if (!has) {
37     const char *group;
38     ierr = PetscViewerHDF5GetGroup(viewer, &group);CHKERRQ(ierr);
39     SETERRQ2(PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Object (dataset) \"%s\" not stored in group %s", obj->name, group ? group : "/");
40   }
41   PetscFunctionReturn(0);
42 }
43 
44 static PetscErrorCode PetscViewerSetFromOptions_HDF5(PetscOptionItems *PetscOptionsObject,PetscViewer v)
45 {
46   PetscErrorCode   ierr;
47   PetscBool        flg = PETSC_FALSE, set;
48   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*)v->data;
49 
50   PetscFunctionBegin;
51   ierr = PetscOptionsHead(PetscOptionsObject,"HDF5 PetscViewer Options");CHKERRQ(ierr);
52   ierr = PetscOptionsBool("-viewer_hdf5_base_dimension2","1d Vectors get 2 dimensions in HDF5","PetscViewerHDF5SetBaseDimension2",hdf5->basedimension2,&hdf5->basedimension2,NULL);CHKERRQ(ierr);
53   ierr = PetscOptionsBool("-viewer_hdf5_sp_output","Force data to be written in single precision","PetscViewerHDF5SetSPOutput",hdf5->spoutput,&hdf5->spoutput,NULL);CHKERRQ(ierr);
54   ierr = PetscOptionsBool("-viewer_hdf5_collective","Enable collective transfer mode","PetscViewerHDF5SetCollective",flg,&flg,&set);CHKERRQ(ierr);
55   if (set) {ierr = PetscViewerHDF5SetCollective(v,flg);CHKERRQ(ierr);}
56   ierr = PetscOptionsTail();CHKERRQ(ierr);
57   PetscFunctionReturn(0);
58 }
59 
60 static PetscErrorCode PetscViewerView_HDF5(PetscViewer v,PetscViewer viewer)
61 {
62   PetscViewer_HDF5  *hdf5 = (PetscViewer_HDF5*)v->data;
63   PetscBool         flg;
64   PetscErrorCode    ierr;
65 
66   PetscFunctionBegin;
67   if (hdf5->filename) {
68     ierr = PetscViewerASCIIPrintf(viewer,"Filename: %s\n",hdf5->filename);CHKERRQ(ierr);
69   }
70   ierr = PetscViewerASCIIPrintf(viewer,"Vectors with blocksize 1 saved as 2D datasets: %s\n",PetscBools[hdf5->basedimension2]);CHKERRQ(ierr);
71   ierr = PetscViewerASCIIPrintf(viewer,"Enforce single precision storage: %s\n",PetscBools[hdf5->spoutput]);CHKERRQ(ierr);
72   ierr = PetscViewerHDF5GetCollective(v,&flg);CHKERRQ(ierr);
73   ierr = PetscViewerASCIIPrintf(viewer,"MPI-IO transfer mode: %s\n",flg ? "collective" : "independent");CHKERRQ(ierr);
74   PetscFunctionReturn(0);
75 }
76 
77 static PetscErrorCode PetscViewerFileClose_HDF5(PetscViewer viewer)
78 {
79   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*)viewer->data;
80   PetscErrorCode   ierr;
81 
82   PetscFunctionBegin;
83   ierr = PetscFree(hdf5->filename);CHKERRQ(ierr);
84   if (hdf5->file_id) PetscStackCallHDF5(H5Fclose,(hdf5->file_id));
85   PetscFunctionReturn(0);
86 }
87 
88 static PetscErrorCode PetscViewerDestroy_HDF5(PetscViewer viewer)
89 {
90   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
91   PetscErrorCode   ierr;
92 
93   PetscFunctionBegin;
94   PetscStackCallHDF5(H5Pclose,(hdf5->dxpl_id));
95   ierr = PetscViewerFileClose_HDF5(viewer);CHKERRQ(ierr);
96   while (hdf5->groups) {
97     PetscViewerHDF5GroupList *tmp = hdf5->groups->next;
98 
99     ierr         = PetscFree(hdf5->groups->name);CHKERRQ(ierr);
100     ierr         = PetscFree(hdf5->groups);CHKERRQ(ierr);
101     hdf5->groups = tmp;
102   }
103   ierr = PetscFree(hdf5);CHKERRQ(ierr);
104   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL);CHKERRQ(ierr);
105   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileGetName_C",NULL);CHKERRQ(ierr);
106   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetMode_C",NULL);CHKERRQ(ierr);
107   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerHDF5SetBaseDimension2_C",NULL);CHKERRQ(ierr);
108   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerHDF5SetSPOutput_C",NULL);CHKERRQ(ierr);
109   PetscFunctionReturn(0);
110 }
111 
112 static PetscErrorCode  PetscViewerFileSetMode_HDF5(PetscViewer viewer, PetscFileMode type)
113 {
114   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
115 
116   PetscFunctionBegin;
117   hdf5->btype = type;
118   PetscFunctionReturn(0);
119 }
120 
121 static PetscErrorCode  PetscViewerFileGetMode_HDF5(PetscViewer viewer, PetscFileMode *type)
122 {
123   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
124 
125   PetscFunctionBegin;
126   *type = hdf5->btype;
127   PetscFunctionReturn(0);
128 }
129 
130 static PetscErrorCode  PetscViewerHDF5SetBaseDimension2_HDF5(PetscViewer viewer, PetscBool flg)
131 {
132   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
133 
134   PetscFunctionBegin;
135   hdf5->basedimension2 = flg;
136   PetscFunctionReturn(0);
137 }
138 
139 /*@
140      PetscViewerHDF5SetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
141        dimension of 2.
142 
143     Logically Collective on PetscViewer
144 
145   Input Parameters:
146 +  viewer - the PetscViewer; if it is not hdf5 then this command is ignored
147 -  flg - if PETSC_TRUE the vector will always have at least a dimension of 2 even if that first dimension is of size 1
148 
149   Options Database:
150 .  -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
151 
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 PetscViewerHDF5SetBaseDimension2(PetscViewer viewer,PetscBool flg)
163 {
164   PetscErrorCode ierr;
165 
166   PetscFunctionBegin;
167   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
168   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetBaseDimension2_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
169   PetscFunctionReturn(0);
170 }
171 
172 /*@
173      PetscViewerHDF5GetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
174        dimension of 2.
175 
176     Logically Collective on PetscViewer
177 
178   Input Parameter:
179 .  viewer - the PetscViewer, must be of type HDF5
180 
181   Output Parameter:
182 .  flg - if PETSC_TRUE the vector will always have at least a dimension of 2 even if that first dimension is of size 1
183 
184   Notes:
185     Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
186          of one when the dimension is lower. Others think the option is crazy.
187 
188   Level: intermediate
189 
190 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen()
191 
192 @*/
193 PetscErrorCode PetscViewerHDF5GetBaseDimension2(PetscViewer viewer,PetscBool *flg)
194 {
195   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
196 
197   PetscFunctionBegin;
198   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
199   *flg = hdf5->basedimension2;
200   PetscFunctionReturn(0);
201 }
202 
203 static PetscErrorCode  PetscViewerHDF5SetSPOutput_HDF5(PetscViewer viewer, PetscBool flg)
204 {
205   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
206 
207   PetscFunctionBegin;
208   hdf5->spoutput = flg;
209   PetscFunctionReturn(0);
210 }
211 
212 /*@
213      PetscViewerHDF5SetSPOutput - Data is written to disk in single precision even if PETSc is
214        compiled with double precision PetscReal.
215 
216     Logically Collective on PetscViewer
217 
218   Input Parameters:
219 +  viewer - the PetscViewer; if it is not hdf5 then this command is ignored
220 -  flg - if PETSC_TRUE the data will be written to disk with single precision
221 
222   Options Database:
223 .  -viewer_hdf5_sp_output - turns on (true) or off (false) output in single precision
224 
225 
226   Notes:
227     Setting this option does not make any difference if PETSc is compiled with single precision
228          in the first place. It does not affect reading datasets (HDF5 handle this internally).
229 
230   Level: intermediate
231 
232 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen(),
233           PetscReal
234 
235 @*/
236 PetscErrorCode PetscViewerHDF5SetSPOutput(PetscViewer viewer,PetscBool flg)
237 {
238   PetscErrorCode ierr;
239 
240   PetscFunctionBegin;
241   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
242   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetSPOutput_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
243   PetscFunctionReturn(0);
244 }
245 
246 /*@
247      PetscViewerHDF5GetSPOutput - Data is written to disk in single precision even if PETSc is
248        compiled with double precision PetscReal.
249 
250     Logically Collective on PetscViewer
251 
252   Input Parameter:
253 .  viewer - the PetscViewer, must be of type HDF5
254 
255   Output Parameter:
256 .  flg - if PETSC_TRUE the data will be written to disk with single precision
257 
258   Notes:
259     Setting this option does not make any difference if PETSc is compiled with single precision
260          in the first place. It does not affect reading datasets (HDF5 handle this internally).
261 
262   Level: intermediate
263 
264 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen(),
265           PetscReal
266 
267 @*/
268 PetscErrorCode PetscViewerHDF5GetSPOutput(PetscViewer viewer,PetscBool *flg)
269 {
270   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
271 
272   PetscFunctionBegin;
273   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
274   *flg = hdf5->spoutput;
275   PetscFunctionReturn(0);
276 }
277 
278 static PetscErrorCode  PetscViewerHDF5SetCollective_HDF5(PetscViewer viewer, PetscBool flg)
279 {
280   PetscFunctionBegin;
281   /* H5FD_MPIO_COLLECTIVE is wrong in hdf5 1.10.2, and is the same as H5FD_MPIO_INDEPENDENT in earlier versions
282      - see e.g. https://gitlab.cosma.dur.ac.uk/swift/swiftsim/issues/431 */
283 #if H5_VERSION_GE(1,10,3) && defined(H5_HAVE_PARALLEL)
284   {
285     PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
286     PetscStackCallHDF5(H5Pset_dxpl_mpio,(hdf5->dxpl_id, flg ? H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT));
287   }
288 #else
289   if (flg) {
290     PetscErrorCode ierr;
291     ierr = PetscPrintf(PetscObjectComm((PetscObject)viewer), "Warning: PetscViewerHDF5SetCollective(viewer,PETSC_TRUE) is ignored for HDF5 versions prior to 1.10.3 or if built without MPI support\n");CHKERRQ(ierr);
292   }
293 #endif
294   PetscFunctionReturn(0);
295 }
296 
297 /*@
298   PetscViewerHDF5SetCollective - Use collective MPI-IO transfer mode for HDF5 reads and writes.
299 
300   Logically Collective; flg must contain common value
301 
302   Input Parameters:
303 + viewer - the PetscViewer; if it is not hdf5 then this command is ignored
304 - flg - PETSC_TRUE for collective mode; PETSC_FALSE for independent mode (default)
305 
306   Options Database:
307 . -viewer_hdf5_collective - turns on (true) or off (false) collective transfers
308 
309   Notes:
310   Collective mode gives the MPI-IO layer underneath HDF5 a chance to do some additional collective optimizations and hence can perform better.
311   However, this works correctly only since HDF5 1.10.3 and if HDF5 is installed for MPI; hence, we ignore this setting for older versions.
312 
313   Developer notes:
314   In the HDF5 layer, PETSC_TRUE / PETSC_FALSE means H5Pset_dxpl_mpio() is called with H5FD_MPIO_COLLECTIVE / H5FD_MPIO_INDEPENDENT, respectively.
315   This in turn means use of MPI_File_{read,write}_all /  MPI_File_{read,write} in the MPI-IO layer, respectively.
316   See HDF5 documentation and MPI-IO documentation for details.
317 
318   Level: intermediate
319 
320 .seealso: PetscViewerHDF5GetCollective(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerHDF5Open()
321 
322 @*/
323 PetscErrorCode PetscViewerHDF5SetCollective(PetscViewer viewer,PetscBool flg)
324 {
325   PetscErrorCode ierr;
326 
327   PetscFunctionBegin;
328   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
329   PetscValidLogicalCollectiveBool(viewer,flg,2);
330   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetCollective_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
331   PetscFunctionReturn(0);
332 }
333 
334 static PetscErrorCode  PetscViewerHDF5GetCollective_HDF5(PetscViewer viewer, PetscBool *flg)
335 {
336 #if defined(H5_HAVE_PARALLEL)
337   PetscViewer_HDF5  *hdf5 = (PetscViewer_HDF5*) viewer->data;
338   H5FD_mpio_xfer_t  mode;
339 #endif
340 
341   PetscFunctionBegin;
342 #if !defined(H5_HAVE_PARALLEL)
343   *flg = PETSC_FALSE;
344 #else
345   PetscStackCallHDF5(H5Pget_dxpl_mpio,(hdf5->dxpl_id, &mode));
346   *flg = (mode == H5FD_MPIO_COLLECTIVE) ? PETSC_TRUE : PETSC_FALSE;
347 #endif
348   PetscFunctionReturn(0);
349 }
350 
351 /*@
352   PetscViewerHDF5GetCollective - Return flag whether collective MPI-IO transfer mode is used for HDF5 reads and writes.
353 
354   Not Collective
355 
356   Input Parameters:
357 . viewer - the HDF5 PetscViewer
358 
359   Output Parameters:
360 . flg - the flag
361 
362   Level: intermediate
363 
364   Notes:
365   This setting works correctly only since HDF5 1.10.3 and if HDF5 was installed for MPI. For older versions, PETSC_FALSE will be always returned.
366   For more details, see PetscViewerHDF5SetCollective().
367 
368 .seealso: PetscViewerHDF5SetCollective(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerHDF5Open()
369 
370 @*/
371 PetscErrorCode PetscViewerHDF5GetCollective(PetscViewer viewer,PetscBool *flg)
372 {
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
377   PetscValidBoolPointer(flg,2);
378 
379   ierr = PetscUseMethod(viewer,"PetscViewerHDF5GetCollective_C",(PetscViewer,PetscBool*),(viewer,flg));CHKERRQ(ierr);
380   PetscFunctionReturn(0);
381 }
382 
383 static PetscErrorCode  PetscViewerFileSetName_HDF5(PetscViewer viewer, const char name[])
384 {
385   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
386   hid_t             plist_id;
387   PetscErrorCode    ierr;
388 
389   PetscFunctionBegin;
390   if (hdf5->file_id) PetscStackCallHDF5(H5Fclose,(hdf5->file_id));
391   if (hdf5->filename) {ierr = PetscFree(hdf5->filename);CHKERRQ(ierr);}
392   ierr = PetscStrallocpy(name, &hdf5->filename);CHKERRQ(ierr);
393   /* Set up file access property list with parallel I/O access */
394   PetscStackCallHDF5Return(plist_id,H5Pcreate,(H5P_FILE_ACCESS));
395 #if defined(H5_HAVE_PARALLEL)
396   PetscStackCallHDF5(H5Pset_fapl_mpio,(plist_id, PetscObjectComm((PetscObject)viewer), MPI_INFO_NULL));
397 #endif
398   /* Create or open the file collectively */
399   switch (hdf5->btype) {
400   case FILE_MODE_READ:
401     PetscStackCallHDF5Return(hdf5->file_id,H5Fopen,(name, H5F_ACC_RDONLY, plist_id));
402     break;
403   case FILE_MODE_APPEND:
404   case FILE_MODE_UPDATE:
405   {
406     PetscBool flg;
407     ierr = PetscTestFile(hdf5->filename, 'r', &flg);CHKERRQ(ierr);
408     if (flg) PetscStackCallHDF5Return(hdf5->file_id,H5Fopen,(name, H5F_ACC_RDWR, plist_id));
409     else     PetscStackCallHDF5Return(hdf5->file_id,H5Fcreate,(name, H5F_ACC_EXCL, H5P_DEFAULT, plist_id));
410     break;
411   }
412   case FILE_MODE_WRITE:
413     PetscStackCallHDF5Return(hdf5->file_id,H5Fcreate,(name, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id));
414     break;
415   case FILE_MODE_UNDEFINED:
416     SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
417   default:
418     SETERRQ1(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP, "Unsupported file mode %s",PetscFileModes[hdf5->btype]);
419   }
420   if (hdf5->file_id < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB, "H5Fcreate failed for %s", name);
421   PetscStackCallHDF5(H5Pclose,(plist_id));
422   PetscFunctionReturn(0);
423 }
424 
425 static PetscErrorCode PetscViewerFileGetName_HDF5(PetscViewer viewer,const char **name)
426 {
427   PetscViewer_HDF5 *vhdf5 = (PetscViewer_HDF5*)viewer->data;
428 
429   PetscFunctionBegin;
430   *name = vhdf5->filename;
431   PetscFunctionReturn(0);
432 }
433 
434 static PetscErrorCode PetscViewerSetUp_HDF5(PetscViewer viewer)
435 {
436   /*
437   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
438   PetscErrorCode   ierr;
439   */
440 
441   PetscFunctionBegin;
442   PetscFunctionReturn(0);
443 }
444 
445 /*MC
446    PETSCVIEWERHDF5 - A viewer that writes to an HDF5 file
447 
448 
449 .seealso:  PetscViewerHDF5Open(), PetscViewerStringSPrintf(), PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSCVIEWERSOCKET,
450            PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW, PETSCVIEWERSTRING,
451            PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
452            PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()
453 
454   Level: beginner
455 M*/
456 
457 PETSC_EXTERN PetscErrorCode PetscViewerCreate_HDF5(PetscViewer v)
458 {
459   PetscViewer_HDF5 *hdf5;
460   PetscErrorCode   ierr;
461 
462   PetscFunctionBegin;
463   ierr = PetscNewLog(v,&hdf5);CHKERRQ(ierr);
464 
465   v->data                = (void*) hdf5;
466   v->ops->destroy        = PetscViewerDestroy_HDF5;
467   v->ops->setfromoptions = PetscViewerSetFromOptions_HDF5;
468   v->ops->setup          = PetscViewerSetUp_HDF5;
469   v->ops->view           = PetscViewerView_HDF5;
470   v->ops->flush          = NULL;
471   hdf5->btype            = FILE_MODE_UNDEFINED;
472   hdf5->filename         = NULL;
473   hdf5->timestep         = -1;
474   hdf5->groups           = NULL;
475 
476   PetscStackCallHDF5Return(hdf5->dxpl_id,H5Pcreate,(H5P_DATASET_XFER));
477 
478   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetName_C",PetscViewerFileSetName_HDF5);CHKERRQ(ierr);
479   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetName_C",PetscViewerFileGetName_HDF5);CHKERRQ(ierr);
480   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetMode_C",PetscViewerFileSetMode_HDF5);CHKERRQ(ierr);
481   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetMode_C",PetscViewerFileGetMode_HDF5);CHKERRQ(ierr);
482   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetBaseDimension2_C",PetscViewerHDF5SetBaseDimension2_HDF5);CHKERRQ(ierr);
483   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetSPOutput_C",PetscViewerHDF5SetSPOutput_HDF5);CHKERRQ(ierr);
484   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetCollective_C",PetscViewerHDF5SetCollective_HDF5);CHKERRQ(ierr);
485   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5GetCollective_C",PetscViewerHDF5GetCollective_HDF5);CHKERRQ(ierr);
486   PetscFunctionReturn(0);
487 }
488 
489 /*@C
490    PetscViewerHDF5Open - Opens a file for HDF5 input/output.
491 
492    Collective
493 
494    Input Parameters:
495 +  comm - MPI communicator
496 .  name - name of file
497 -  type - type of file
498 
499    Output Parameter:
500 .  hdf5v - PetscViewer for HDF5 input/output to use with the specified file
501 
502   Options Database:
503 +  -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
504 -  -viewer_hdf5_sp_output - forces (if true) the viewer to write data in single precision independent on the precision of PetscReal
505 
506    Level: beginner
507 
508    Notes:
509    Reading is always available, regardless of the mode. Available modes are
510 +  FILE_MODE_READ - open existing HDF5 file for read only access, fail if file does not exist [H5Fopen() with H5F_ACC_RDONLY]
511 .  FILE_MODE_WRITE - if file exists, fully overwrite it, else create new HDF5 file [H5FcreateH5Fcreate() with H5F_ACC_TRUNC]
512 .  FILE_MODE_APPEND - if file exists, keep existing contents [H5Fopen() with H5F_ACC_RDWR], else create new HDF5 file [H5FcreateH5Fcreate() with H5F_ACC_EXCL]
513 -  FILE_MODE_UPDATE - same as FILE_MODE_APPEND
514 
515    In case of FILE_MODE_APPEND / FILE_MODE_UPDATE, any stored object (dataset, attribute) can be selectively ovewritten if the same fully qualified name (/group/path/to/object) is specified.
516 
517    This PetscViewer should be destroyed with PetscViewerDestroy().
518 
519 
520 .seealso: PetscViewerASCIIOpen(), PetscViewerPushFormat(), PetscViewerDestroy(), PetscViewerHDF5SetBaseDimension2(),
521           PetscViewerHDF5SetSPOutput(), PetscViewerHDF5GetBaseDimension2(), VecView(), MatView(), VecLoad(),
522           MatLoad(), PetscFileMode, PetscViewer, PetscViewerSetType(), PetscViewerFileSetMode(), PetscViewerFileSetName()
523 @*/
524 PetscErrorCode  PetscViewerHDF5Open(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *hdf5v)
525 {
526   PetscErrorCode ierr;
527 
528   PetscFunctionBegin;
529   ierr = PetscViewerCreate(comm, hdf5v);CHKERRQ(ierr);
530   ierr = PetscViewerSetType(*hdf5v, PETSCVIEWERHDF5);CHKERRQ(ierr);
531   ierr = PetscViewerFileSetMode(*hdf5v, type);CHKERRQ(ierr);
532   ierr = PetscViewerFileSetName(*hdf5v, name);CHKERRQ(ierr);
533   ierr = PetscViewerSetFromOptions(*hdf5v);CHKERRQ(ierr);
534   PetscFunctionReturn(0);
535 }
536 
537 /*@C
538   PetscViewerHDF5GetFileId - Retrieve the file id, this file ID then can be used in direct HDF5 calls
539 
540   Not collective
541 
542   Input Parameter:
543 . viewer - the PetscViewer
544 
545   Output Parameter:
546 . file_id - The file id
547 
548   Level: intermediate
549 
550 .seealso: PetscViewerHDF5Open()
551 @*/
552 PetscErrorCode  PetscViewerHDF5GetFileId(PetscViewer viewer, hid_t *file_id)
553 {
554   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
555 
556   PetscFunctionBegin;
557   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
558   if (file_id) *file_id = hdf5->file_id;
559   PetscFunctionReturn(0);
560 }
561 
562 /*@C
563   PetscViewerHDF5PushGroup - Set the current HDF5 group for output
564 
565   Not collective
566 
567   Input Parameters:
568 + viewer - the PetscViewer
569 - name - The group name
570 
571   Level: intermediate
572 
573   Notes:
574   This is designed to mnemonically resemble the Unix cd command.
575   + If name begins with '/', it is interpreted as an absolute path fully replacing current group, otherwise it is taken as relative to the current group.
576   . NULL, empty string, or any sequence of all slashes (e.g. "///") is interpreted as the root group "/".
577   - "." means the current group is pushed again.
578 
579   Example:
580   Suppose the current group is "/a".
581   + If name is NULL, empty string, or a sequence of all slashes (e.g. "///"), then the new group will be "/".
582   . If name is ".", then the new group will be "/a".
583   . If name is "b", then the new group will be "/a/b".
584   - If name is "/b", then the new group will be "/b".
585 
586   Developer Notes:
587   The root group "/" is internally stored as NULL.
588 
589 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup(),PetscViewerHDF5OpenGroup()
590 @*/
591 PetscErrorCode  PetscViewerHDF5PushGroup(PetscViewer viewer, const char name[])
592 {
593   PetscViewer_HDF5          *hdf5 = (PetscViewer_HDF5*) viewer->data;
594   PetscViewerHDF5GroupList  *groupNode;
595   size_t                    i,len;
596   char                      buf[PETSC_MAX_PATH_LEN];
597   const char                *gname;
598   PetscErrorCode            ierr;
599 
600   PetscFunctionBegin;
601   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
602   if (name) PetscValidCharPointer(name,2);
603   ierr = PetscStrlen(name, &len);CHKERRQ(ierr);
604   gname = NULL;
605   if (len) {
606     if (len == 1 && name[0] == '.') {
607       /* use current name */
608       gname = (hdf5->groups && hdf5->groups->name) ? hdf5->groups->name : NULL;
609     } else if (name[0] == '/') {
610       /* absolute */
611       for (i=1; i<len; i++) {
612         if (name[i] != '/') {
613           gname = name;
614           break;
615         }
616       }
617     } else {
618       /* relative */
619       const char *parent = (hdf5->groups && hdf5->groups->name) ? hdf5->groups->name : "";
620       ierr = PetscSNPrintf(buf, sizeof(buf), "%s/%s", parent, name);CHKERRQ(ierr);
621       gname = buf;
622     }
623   }
624   ierr = PetscNew(&groupNode);CHKERRQ(ierr);
625   ierr = PetscStrallocpy(gname, (char**) &groupNode->name);CHKERRQ(ierr);
626   groupNode->next = hdf5->groups;
627   hdf5->groups    = groupNode;
628   PetscFunctionReturn(0);
629 }
630 
631 /*@
632   PetscViewerHDF5PopGroup - Return the current HDF5 group for output to the previous value
633 
634   Not collective
635 
636   Input Parameter:
637 . viewer - the PetscViewer
638 
639   Level: intermediate
640 
641 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5GetGroup(),PetscViewerHDF5OpenGroup()
642 @*/
643 PetscErrorCode  PetscViewerHDF5PopGroup(PetscViewer viewer)
644 {
645   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
646   PetscViewerHDF5GroupList *groupNode;
647   PetscErrorCode   ierr;
648 
649   PetscFunctionBegin;
650   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
651   if (!hdf5->groups) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "HDF5 group stack is empty, cannot pop");
652   groupNode    = hdf5->groups;
653   hdf5->groups = hdf5->groups->next;
654   ierr         = PetscFree(groupNode->name);CHKERRQ(ierr);
655   ierr         = PetscFree(groupNode);CHKERRQ(ierr);
656   PetscFunctionReturn(0);
657 }
658 
659 /*@C
660   PetscViewerHDF5GetGroup - Get the current HDF5 group name (full path), set with PetscViewerHDF5PushGroup()/PetscViewerHDF5PopGroup().
661   If none has been assigned, returns NULL.
662 
663   Not collective
664 
665   Input Parameter:
666 . viewer - the PetscViewer
667 
668   Output Parameter:
669 . name - The group name
670 
671   Level: intermediate
672 
673 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5OpenGroup()
674 @*/
675 PetscErrorCode  PetscViewerHDF5GetGroup(PetscViewer viewer, const char *name[])
676 {
677   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *) viewer->data;
678 
679   PetscFunctionBegin;
680   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
681   PetscValidPointer(name,2);
682   if (hdf5->groups) *name = hdf5->groups->name;
683   else *name = NULL;
684   PetscFunctionReturn(0);
685 }
686 
687 /*@
688   PetscViewerHDF5OpenGroup - Open the HDF5 group with the name (full path) returned by PetscViewerHDF5GetGroup(),
689   and return this group's ID and file ID.
690   If PetscViewerHDF5GetGroup() yields NULL, then group ID is file ID.
691 
692   Not collective
693 
694   Input Parameter:
695 . viewer - the PetscViewer
696 
697   Output Parameter:
698 + fileId - The HDF5 file ID
699 - groupId - The HDF5 group ID
700 
701   Notes:
702   If the viewer is writable, the group is created if it doesn't exist yet.
703 
704   Level: intermediate
705 
706 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
707 @*/
708 PetscErrorCode PetscViewerHDF5OpenGroup(PetscViewer viewer, hid_t *fileId, hid_t *groupId)
709 {
710   hid_t          file_id;
711   H5O_type_t     type;
712   const char     *groupName = NULL;
713   PetscBool      create;
714   PetscErrorCode ierr;
715 
716   PetscFunctionBegin;
717   ierr = PetscViewerWritable(viewer, &create);CHKERRQ(ierr);
718   ierr = PetscViewerHDF5GetFileId(viewer, &file_id);CHKERRQ(ierr);
719   ierr = PetscViewerHDF5GetGroup(viewer, &groupName);CHKERRQ(ierr);
720   ierr = PetscViewerHDF5Traverse_Internal(viewer, groupName, create, NULL, &type);CHKERRQ(ierr);
721   if (type != H5O_TYPE_GROUP) SETERRQ1(PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Path %s resolves to something which is not a group", groupName);
722   PetscStackCallHDF5Return(*groupId,H5Gopen2,(file_id, groupName ? groupName : "/", H5P_DEFAULT));
723   *fileId  = file_id;
724   PetscFunctionReturn(0);
725 }
726 
727 /*@
728   PetscViewerHDF5PushTimestepping - Activate timestepping mode for subsequent HDF5 reading and writing.
729 
730   Not collective
731 
732   Input Parameter:
733 . viewer - the PetscViewer
734 
735   Level: intermediate
736 
737   Notes:
738   On first PetscViewerHDF5PushTimestepping(), the initial time step is set to 0.
739   Next timesteps can then be set using PetscViewerHDF5IncrementTimestep() or PetscViewerHDF5SetTimestep().
740   Current timestep value determines which timestep is read from or written to any dataset on the next HDF5 I/O operation [e.g. VecView()].
741   Use PetscViewerHDF5PopTimestepping() to deactivate timestepping mode; calling it by the end of the program is NOT mandatory.
742   Current timestep is remembered between PetscViewerHDF5PopTimestepping() and the next PetscViewerHDF5PushTimestepping().
743 
744   If a dataset was stored with timestepping, it can be loaded only in the timestepping mode again.
745   Loading a timestepped dataset with timestepping disabled, or vice-versa results in an error.
746 
747   Developer notes:
748   Timestepped HDF5 dataset has an extra dimension and attribute "timestepping" set to true.
749 
750 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5PopTimestepping(), PetscViewerHDF5IsTimestepping(), PetscViewerHDF5SetTimestep(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5GetTimestep()
751 @*/
752 PetscErrorCode  PetscViewerHDF5PushTimestepping(PetscViewer viewer)
753 {
754   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
755 
756   PetscFunctionBegin;
757   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
758   if (hdf5->timestepping) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping is already pushed");
759   hdf5->timestepping = PETSC_TRUE;
760   if (hdf5->timestep < 0) hdf5->timestep = 0;
761   PetscFunctionReturn(0);
762 }
763 
764 /*@
765   PetscViewerHDF5PopTimestepping - Deactivate timestepping mode for subsequent HDF5 reading and writing.
766 
767   Not collective
768 
769   Input Parameter:
770 . viewer - the PetscViewer
771 
772   Level: intermediate
773 
774   Notes:
775   See PetscViewerHDF5PushTimestepping() for details.
776 
777 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5PushTimestepping(), PetscViewerHDF5IsTimestepping(), PetscViewerHDF5SetTimestep(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5GetTimestep()
778 @*/
779 PetscErrorCode  PetscViewerHDF5PopTimestepping(PetscViewer viewer)
780 {
781   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
782 
783   PetscFunctionBegin;
784   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
785   if (!hdf5->timestepping) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping has not been pushed yet. Call PetscViewerHDF5PushTimestepping() first");
786   hdf5->timestepping = PETSC_FALSE;
787   PetscFunctionReturn(0);
788 }
789 
790 /*@
791   PetscViewerHDF5IsTimestepping - Ask the viewer whether it is in timestepping mode currently.
792 
793   Not collective
794 
795   Input Parameter:
796 . viewer - the PetscViewer
797 
798   Output Parameter:
799 . flg - is timestepping active?
800 
801   Level: intermediate
802 
803   Notes:
804   See PetscViewerHDF5PushTimestepping() for details.
805 
806 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5PushTimestepping(), PetscViewerHDF5PopTimestepping(), PetscViewerHDF5SetTimestep(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5GetTimestep()
807 @*/
808 PetscErrorCode  PetscViewerHDF5IsTimestepping(PetscViewer viewer, PetscBool *flg)
809 {
810   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
811 
812   PetscFunctionBegin;
813   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
814   *flg = hdf5->timestepping;
815   PetscFunctionReturn(0);
816 }
817 
818 /*@
819   PetscViewerHDF5IncrementTimestep - Increments current timestep for the HDF5 output. Fields are stacked in time.
820 
821   Not collective
822 
823   Input Parameter:
824 . viewer - the PetscViewer
825 
826   Level: intermediate
827 
828   Notes:
829   This can be called only if the viewer is in timestepping mode. See PetscViewerHDF5PushTimestepping() for details.
830 
831 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5PushTimestepping(), PetscViewerHDF5SetTimestep(), PetscViewerHDF5GetTimestep()
832 @*/
833 PetscErrorCode PetscViewerHDF5IncrementTimestep(PetscViewer viewer)
834 {
835   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
836 
837   PetscFunctionBegin;
838   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
839   if (!hdf5->timestepping) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping has not been pushed yet. Call PetscViewerHDF5PushTimestepping() first");
840   ++hdf5->timestep;
841   PetscFunctionReturn(0);
842 }
843 
844 /*@
845   PetscViewerHDF5SetTimestep - Set the current timestep for the HDF5 output. Fields are stacked in time.
846 
847   Logically collective
848 
849   Input Parameters:
850 + viewer - the PetscViewer
851 - timestep - The timestep
852 
853   Level: intermediate
854 
855   Notes:
856   This can be called only if the viewer is in timestepping mode. See PetscViewerHDF5PushTimestepping() for details.
857 
858 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5PushTimestepping(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5GetTimestep()
859 @*/
860 PetscErrorCode  PetscViewerHDF5SetTimestep(PetscViewer viewer, PetscInt timestep)
861 {
862   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
863 
864   PetscFunctionBegin;
865   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
866   PetscValidLogicalCollectiveInt(viewer, timestep, 2);
867   if (timestep < 0) SETERRQ1(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestep %D is negative", timestep);
868   if (!hdf5->timestepping) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping has not been pushed yet. Call PetscViewerHDF5PushTimestepping() first");
869   hdf5->timestep = timestep;
870   PetscFunctionReturn(0);
871 }
872 
873 /*@
874   PetscViewerHDF5GetTimestep - Get the current timestep for the HDF5 output. Fields are stacked in time.
875 
876   Not collective
877 
878   Input Parameter:
879 . viewer - the PetscViewer
880 
881   Output Parameter:
882 . timestep - The timestep
883 
884   Level: intermediate
885 
886   Notes:
887   This can be called only if the viewer is in the timestepping mode. See PetscViewerHDF5PushTimestepping() for details.
888 
889 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5PushTimestepping(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5SetTimestep()
890 @*/
891 PetscErrorCode  PetscViewerHDF5GetTimestep(PetscViewer viewer, PetscInt *timestep)
892 {
893   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
894 
895   PetscFunctionBegin;
896   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
897   PetscValidIntPointer(timestep,2);
898   if (!hdf5->timestepping) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping has not been pushed yet. Call PetscViewerHDF5PushTimestepping() first");
899   *timestep = hdf5->timestep;
900   PetscFunctionReturn(0);
901 }
902 
903 /*@C
904   PetscDataTypeToHDF5DataType - Converts the PETSc name of a datatype to its HDF5 name.
905 
906   Not collective
907 
908   Input Parameter:
909 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
910 
911   Output Parameter:
912 . mtype - the MPI datatype (for example MPI_DOUBLE, ...)
913 
914   Level: advanced
915 
916 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
917 @*/
918 PetscErrorCode PetscDataTypeToHDF5DataType(PetscDataType ptype, hid_t *htype)
919 {
920   PetscFunctionBegin;
921   if (ptype == PETSC_INT)
922 #if defined(PETSC_USE_64BIT_INDICES)
923                                        *htype = H5T_NATIVE_LLONG;
924 #else
925                                        *htype = H5T_NATIVE_INT;
926 #endif
927   else if (ptype == PETSC_DOUBLE)      *htype = H5T_NATIVE_DOUBLE;
928   else if (ptype == PETSC_LONG)        *htype = H5T_NATIVE_LONG;
929   else if (ptype == PETSC_SHORT)       *htype = H5T_NATIVE_SHORT;
930   else if (ptype == PETSC_ENUM)        *htype = H5T_NATIVE_INT;
931   else if (ptype == PETSC_BOOL)        *htype = H5T_NATIVE_INT;
932   else if (ptype == PETSC_FLOAT)       *htype = H5T_NATIVE_FLOAT;
933   else if (ptype == PETSC_CHAR)        *htype = H5T_NATIVE_CHAR;
934   else if (ptype == PETSC_BIT_LOGICAL) *htype = H5T_NATIVE_UCHAR;
935   else if (ptype == PETSC_STRING)      *htype = H5Tcopy(H5T_C_S1);
936   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported PETSc datatype");
937   PetscFunctionReturn(0);
938 }
939 
940 /*@C
941   PetscHDF5DataTypeToPetscDataType - Finds the PETSc name of a datatype from its HDF5 name
942 
943   Not collective
944 
945   Input Parameter:
946 . htype - the HDF5 datatype (for example H5T_NATIVE_DOUBLE, ...)
947 
948   Output Parameter:
949 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
950 
951   Level: advanced
952 
953 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
954 @*/
955 PetscErrorCode PetscHDF5DataTypeToPetscDataType(hid_t htype, PetscDataType *ptype)
956 {
957   PetscFunctionBegin;
958 #if defined(PETSC_USE_64BIT_INDICES)
959   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_LONG;
960   else if (htype == H5T_NATIVE_LLONG)  *ptype = PETSC_INT;
961 #else
962   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_INT;
963 #endif
964   else if (htype == H5T_NATIVE_DOUBLE) *ptype = PETSC_DOUBLE;
965   else if (htype == H5T_NATIVE_LONG)   *ptype = PETSC_LONG;
966   else if (htype == H5T_NATIVE_SHORT)  *ptype = PETSC_SHORT;
967   else if (htype == H5T_NATIVE_FLOAT)  *ptype = PETSC_FLOAT;
968   else if (htype == H5T_NATIVE_CHAR)   *ptype = PETSC_CHAR;
969   else if (htype == H5T_NATIVE_UCHAR)  *ptype = PETSC_CHAR;
970   else if (htype == H5T_C_S1)          *ptype = PETSC_STRING;
971   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported HDF5 datatype");
972   PetscFunctionReturn(0);
973 }
974 
975 /*@C
976  PetscViewerHDF5WriteAttribute - Write an attribute
977 
978   Collective
979 
980   Input Parameters:
981 + viewer - The HDF5 viewer
982 . parent - The parent dataset/group name
983 . name   - The attribute name
984 . datatype - The attribute type
985 - value    - The attribute value
986 
987   Level: advanced
988 
989   Notes:
990   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else parent is relative to the current pushed group. NULL means the current pushed group.
991 
992 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteObjectAttribute(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
993 @*/
994 PetscErrorCode PetscViewerHDF5WriteAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *value)
995 {
996   char           *parentAbsPath;
997   hid_t          h5, dataspace, obj, attribute, dtype;
998   PetscBool      has;
999   PetscErrorCode ierr;
1000 
1001   PetscFunctionBegin;
1002   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1003   if (parent) PetscValidCharPointer(parent, 2);
1004   PetscValidCharPointer(name, 3);
1005   PetscValidLogicalCollectiveEnum(viewer,datatype,4);
1006   PetscValidPointer(value, 5);
1007   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, parent, &parentAbsPath);CHKERRQ(ierr);
1008   ierr = PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_TRUE, NULL, NULL);CHKERRQ(ierr);
1009   ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, &has);CHKERRQ(ierr);
1010   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
1011   if (datatype == PETSC_STRING) {
1012     size_t len;
1013     ierr = PetscStrlen((const char *) value, &len);CHKERRQ(ierr);
1014     PetscStackCallHDF5(H5Tset_size,(dtype, len+1));
1015   }
1016   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1017   PetscStackCallHDF5Return(dataspace,H5Screate,(H5S_SCALAR));
1018   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parentAbsPath, H5P_DEFAULT));
1019   if (has) {
1020     PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
1021   } else {
1022     PetscStackCallHDF5Return(attribute,H5Acreate2,(obj, name, dtype, dataspace, H5P_DEFAULT, H5P_DEFAULT));
1023   }
1024   PetscStackCallHDF5(H5Awrite,(attribute, dtype, value));
1025   if (datatype == PETSC_STRING) PetscStackCallHDF5(H5Tclose,(dtype));
1026   PetscStackCallHDF5(H5Aclose,(attribute));
1027   PetscStackCallHDF5(H5Oclose,(obj));
1028   PetscStackCallHDF5(H5Sclose,(dataspace));
1029   ierr = PetscFree(parentAbsPath);CHKERRQ(ierr);
1030   PetscFunctionReturn(0);
1031 }
1032 
1033 /*@C
1034  PetscViewerHDF5WriteObjectAttribute - Write an attribute to the dataset matching the given PetscObject by name
1035 
1036   Collective
1037 
1038   Input Parameters:
1039 + viewer   - The HDF5 viewer
1040 . obj      - The object whose name is used to lookup the parent dataset, relative to the current group.
1041 . name     - The attribute name
1042 . datatype - The attribute type
1043 - value    - The attribute value
1044 
1045   Notes:
1046   This fails if the path current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
1047   You might want to check first if it does using PetscViewerHDF5HasObject().
1048 
1049   Level: advanced
1050 
1051 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadObjectAttribute(), PetscViewerHDF5HasObjectAttribute(), PetscViewerHDF5HasObject(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1052 @*/
1053 PetscErrorCode PetscViewerHDF5WriteObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscDataType datatype, const void *value)
1054 {
1055   PetscErrorCode ierr;
1056 
1057   PetscFunctionBegin;
1058   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1059   PetscValidHeader(obj,2);
1060   PetscValidCharPointer(name,3);
1061   PetscValidPointer(value,5);
1062   ierr = PetscViewerHDF5CheckNamedObject_Internal(viewer, obj);CHKERRQ(ierr);
1063   ierr = PetscViewerHDF5WriteAttribute(viewer, obj->name, name, datatype, value);CHKERRQ(ierr);
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 /*@C
1068  PetscViewerHDF5ReadAttribute - Read an attribute
1069 
1070   Collective
1071 
1072   Input Parameters:
1073 + viewer - The HDF5 viewer
1074 . parent - The parent dataset/group name
1075 . name   - The attribute name
1076 . datatype - The attribute type
1077 - defaultValue - The pointer to the default value
1078 
1079   Output Parameter:
1080 . value    - The pointer to the read HDF5 attribute value
1081 
1082   Notes:
1083   If defaultValue is NULL and the attribute is not found, an error occurs.
1084   If defaultValue is not NULL and the attribute is not found, defaultValue is copied to value.
1085   The pointers defaultValue and value can be the same; for instance
1086 $  flg = PETSC_FALSE;
1087 $  ierr = PetscViewerHDF5ReadAttribute(viewer,name,"attr",PETSC_BOOL,&flg,&flg);CHKERRQ(ierr);
1088   is valid, but make sure the default value is initialized.
1089 
1090   If the datatype is PETSC_STRING, the output string is newly allocated so one must PetscFree() it when no longer needed.
1091 
1092   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else parent is relative to the current pushed group. NULL means the current pushed group.
1093 
1094   Level: advanced
1095 
1096 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5ReadObjectAttribute(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5HasObject(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1097 @*/
1098 PetscErrorCode PetscViewerHDF5ReadAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *defaultValue, void *value)
1099 {
1100   char           *parentAbsPath;
1101   hid_t          h5, obj, attribute, dtype;
1102   PetscBool      has;
1103   PetscErrorCode ierr;
1104 
1105   PetscFunctionBegin;
1106   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1107   if (parent) PetscValidCharPointer(parent, 2);
1108   PetscValidCharPointer(name, 3);
1109   if (defaultValue) PetscValidPointer(defaultValue, 5);
1110   PetscValidPointer(value, 6);
1111   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
1112   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, parent, &parentAbsPath);CHKERRQ(ierr);
1113   ierr = PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_FALSE, &has, NULL);CHKERRQ(ierr);
1114   if (has) {ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, &has);CHKERRQ(ierr);}
1115   if (!has) {
1116     if (defaultValue) {
1117       if (defaultValue != value) {
1118         if (datatype == PETSC_STRING) {
1119           ierr = PetscStrallocpy(*(char**)defaultValue, (char**)value);CHKERRQ(ierr);
1120         } else {
1121           size_t len;
1122           PetscStackCallHDF5Return(len,H5Tget_size,(dtype));
1123           ierr = PetscMemcpy(value, defaultValue, len);CHKERRQ(ierr);
1124         }
1125       }
1126       ierr = PetscFree(parentAbsPath);CHKERRQ(ierr);
1127       PetscFunctionReturn(0);
1128     } else SETERRQ2(PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Attribute %s/%s does not exist and default value not provided", parentAbsPath, name);
1129   }
1130   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1131   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parentAbsPath, H5P_DEFAULT));
1132   PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
1133   if (datatype == PETSC_STRING) {
1134     size_t len;
1135     hid_t  atype;
1136     PetscStackCallHDF5Return(atype,H5Aget_type,(attribute));
1137     PetscStackCallHDF5Return(len,H5Tget_size,(atype));
1138     ierr = PetscMalloc((len+1) * sizeof(char), value);CHKERRQ(ierr);
1139     PetscStackCallHDF5(H5Tset_size,(dtype, len+1));
1140     PetscStackCallHDF5(H5Aread,(attribute, dtype, *(char**)value));
1141   } else {
1142     PetscStackCallHDF5(H5Aread,(attribute, dtype, value));
1143   }
1144   PetscStackCallHDF5(H5Aclose,(attribute));
1145   /* H5Oclose can be used to close groups, datasets, or committed datatypes */
1146   PetscStackCallHDF5(H5Oclose,(obj));
1147   ierr = PetscFree(parentAbsPath);CHKERRQ(ierr);
1148   PetscFunctionReturn(0);
1149 }
1150 
1151 /*@C
1152  PetscViewerHDF5ReadObjectAttribute - Read an attribute from the dataset matching the given PetscObject by name
1153 
1154   Collective
1155 
1156   Input Parameters:
1157 + viewer   - The HDF5 viewer
1158 . obj      - The object whose name is used to lookup the parent dataset, relative to the current group.
1159 . name     - The attribute name
1160 - datatype - The attribute type
1161 
1162   Output Parameter:
1163 . value    - The attribute value
1164 
1165   Notes:
1166   This fails if current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
1167   You might want to check first if it does using PetscViewerHDF5HasObject().
1168 
1169   Level: advanced
1170 
1171 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5ReadAttribute() PetscViewerHDF5WriteObjectAttribute(), PetscViewerHDF5HasObjectAttribute(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1172 @*/
1173 PetscErrorCode PetscViewerHDF5ReadObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscDataType datatype, void *defaultValue, void *value)
1174 {
1175   PetscErrorCode ierr;
1176 
1177   PetscFunctionBegin;
1178   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1179   PetscValidHeader(obj,2);
1180   PetscValidCharPointer(name,3);
1181   PetscValidPointer(value, 5);
1182   ierr = PetscViewerHDF5CheckNamedObject_Internal(viewer, obj);CHKERRQ(ierr);
1183   ierr = PetscViewerHDF5ReadAttribute(viewer, obj->name, name, datatype, defaultValue, value);CHKERRQ(ierr);
1184   PetscFunctionReturn(0);
1185 }
1186 
1187 PETSC_STATIC_INLINE PetscErrorCode PetscViewerHDF5Traverse_Inner_Internal(hid_t h5, const char name[], PetscBool createGroup, PetscBool *exists_)
1188 {
1189   htri_t exists;
1190   hid_t group;
1191 
1192   PetscFunctionBegin;
1193   PetscStackCallHDF5Return(exists,H5Lexists,(h5, name, H5P_DEFAULT));
1194   if (exists) PetscStackCallHDF5Return(exists,H5Oexists_by_name,(h5, name, H5P_DEFAULT));
1195   if (!exists && createGroup) {
1196     PetscStackCallHDF5Return(group,H5Gcreate2,(h5, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT));
1197     PetscStackCallHDF5(H5Gclose,(group));
1198     exists = PETSC_TRUE;
1199   }
1200   *exists_ = (PetscBool) exists;
1201   PetscFunctionReturn(0);
1202 }
1203 
1204 static PetscErrorCode PetscViewerHDF5Traverse_Internal(PetscViewer viewer, const char name[], PetscBool createGroup, PetscBool *has, H5O_type_t *otype)
1205 {
1206   const char     rootGroupName[] = "/";
1207   hid_t          h5;
1208   PetscBool      exists=PETSC_FALSE;
1209   PetscInt       i;
1210   int            n;
1211   char           **hierarchy;
1212   char           buf[PETSC_MAX_PATH_LEN]="";
1213   PetscErrorCode ierr;
1214 
1215   PetscFunctionBegin;
1216   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1217   if (name) PetscValidCharPointer(name, 2);
1218   else name = rootGroupName;
1219   if (has) {
1220     PetscValidIntPointer(has, 3);
1221     *has = PETSC_FALSE;
1222   }
1223   if (otype) {
1224     PetscValidIntPointer(otype, 4);
1225     *otype = H5O_TYPE_UNKNOWN;
1226   }
1227   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1228 
1229   /*
1230      Unfortunately, H5Oexists_by_name() fails if any object in hierarchy is missing.
1231      Hence, each of them needs to be tested separately:
1232      1) whether it's a valid link
1233      2) whether this link resolves to an object
1234      See H5Oexists_by_name() documentation.
1235   */
1236   ierr = PetscStrToArray(name,'/',&n,&hierarchy);CHKERRQ(ierr);
1237   if (!n) {
1238     /*  Assume group "/" always exists in accordance with HDF5 >= 1.10.0. See H5Lexists() documentation. */
1239     if (has)   *has   = PETSC_TRUE;
1240     if (otype) *otype = H5O_TYPE_GROUP;
1241     ierr = PetscStrToArrayDestroy(n,hierarchy);CHKERRQ(ierr);
1242     PetscFunctionReturn(0);
1243   }
1244   for (i=0; i<n; i++) {
1245     ierr = PetscStrcat(buf,"/");CHKERRQ(ierr);
1246     ierr = PetscStrcat(buf,hierarchy[i]);CHKERRQ(ierr);
1247     ierr = PetscViewerHDF5Traverse_Inner_Internal(h5, buf, createGroup, &exists);CHKERRQ(ierr);
1248     if (!exists) break;
1249   }
1250   ierr = PetscStrToArrayDestroy(n,hierarchy);CHKERRQ(ierr);
1251 
1252   /* If the object exists, get its type */
1253   if (exists && otype) {
1254     H5O_info_t info;
1255 
1256     /* We could use H5Iget_type() here but that would require opening the object. This way we only need its name. */
1257     PetscStackCallHDF5(H5Oget_info_by_name,(h5, name, &info, H5P_DEFAULT));
1258     *otype = info.type;
1259   }
1260   if (has) *has = exists;
1261   PetscFunctionReturn(0);
1262 }
1263 
1264 /*@C
1265  PetscViewerHDF5HasGroup - Check whether the current (pushed) group exists in the HDF5 file
1266 
1267   Collective
1268 
1269   Input Parameters:
1270 + viewer - The HDF5 viewer
1271 - path - The group path
1272 
1273   Output Parameter:
1274 . has - Flag for group existence
1275 
1276   Level: advanced
1277 
1278   Notes:
1279   If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group. NULL means the current pushed group.
1280   If path is NULL or empty, has is set to PETSC_FALSE.
1281   If path exists but is not a group, PETSC_FALSE is returned.
1282 
1283 .seealso: PetscViewerHDF5HasAttribute(), PetscViewerHDF5HasDataset(), PetscViewerHDF5PushGroup(), PetscViewerHDF5PopGroup(), PetscViewerHDF5GetGroup(), PetscViewerHDF5OpenGroup()
1284 @*/
1285 PetscErrorCode PetscViewerHDF5HasGroup(PetscViewer viewer, const char path[], PetscBool *has)
1286 {
1287   H5O_type_t     type;
1288   char           *abspath;
1289   PetscErrorCode ierr;
1290 
1291   PetscFunctionBegin;
1292   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1293   if (path) PetscValidCharPointer(path,2);
1294   PetscValidBoolPointer(has,3);
1295   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, path, &abspath);CHKERRQ(ierr);
1296   ierr = PetscViewerHDF5Traverse_Internal(viewer, abspath, PETSC_FALSE, NULL, &type);CHKERRQ(ierr);
1297   *has = (PetscBool)(type == H5O_TYPE_GROUP);
1298   ierr = PetscFree(abspath);CHKERRQ(ierr);
1299   PetscFunctionReturn(0);
1300 }
1301 
1302 /*@C
1303  PetscViewerHDF5HasDataset - Check whether a given dataset exists in the HDF5 file
1304 
1305   Collective
1306 
1307   Input Parameters:
1308 + viewer - The HDF5 viewer
1309 - path - The dataset path
1310 
1311   Output Parameter:
1312 . has - Flag whether dataset exists
1313 
1314   Level: advanced
1315 
1316   Notes:
1317   If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group.
1318   If path is NULL or empty, has is set to PETSC_FALSE.
1319   If path exists but is not a dataset, has is set to PETSC_FALSE as well.
1320 
1321 .seealso: PetscViewerHDF5HasObject(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5HasGroup(), PetscViewerHDF5PushGroup(), PetscViewerHDF5PopGroup(), PetscViewerHDF5GetGroup()
1322 @*/
1323 PetscErrorCode PetscViewerHDF5HasDataset(PetscViewer viewer, const char path[], PetscBool *has)
1324 {
1325   H5O_type_t     type;
1326   char           *abspath;
1327   PetscErrorCode ierr;
1328 
1329   PetscFunctionBegin;
1330   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1331   if (path) PetscValidCharPointer(path,2);
1332   PetscValidBoolPointer(has,3);
1333   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, path, &abspath);CHKERRQ(ierr);
1334   ierr = PetscViewerHDF5Traverse_Internal(viewer, abspath, PETSC_FALSE, NULL, &type);CHKERRQ(ierr);
1335   *has = (PetscBool)(type == H5O_TYPE_DATASET);
1336   ierr = PetscFree(abspath);CHKERRQ(ierr);
1337   PetscFunctionReturn(0);
1338 }
1339 
1340 /*@
1341  PetscViewerHDF5HasObject - Check whether a dataset with the same name as given object exists in the HDF5 file under current group
1342 
1343   Collective
1344 
1345   Input Parameters:
1346 + viewer - The HDF5 viewer
1347 - obj    - The named object
1348 
1349   Output Parameter:
1350 . has    - Flag for dataset existence
1351 
1352   Notes:
1353   If the object is unnamed, an error occurs.
1354   If the path current_group/object_name exists but is not a dataset, has is set to PETSC_FALSE as well.
1355 
1356   Level: advanced
1357 
1358 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5HasDataset(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5PushGroup(), PetscViewerHDF5PopGroup(), PetscViewerHDF5GetGroup()
1359 @*/
1360 PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, PetscObject obj, PetscBool *has)
1361 {
1362   size_t         len;
1363   PetscErrorCode ierr;
1364 
1365   PetscFunctionBegin;
1366   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1367   PetscValidHeader(obj,2);
1368   PetscValidBoolPointer(has,3);
1369   ierr = PetscStrlen(obj->name, &len);CHKERRQ(ierr);
1370   if (!len) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Object must be named");
1371   ierr = PetscViewerHDF5HasDataset(viewer, obj->name, has);CHKERRQ(ierr);
1372   PetscFunctionReturn(0);
1373 }
1374 
1375 /*@C
1376  PetscViewerHDF5HasAttribute - Check whether an attribute exists
1377 
1378   Collective
1379 
1380   Input Parameters:
1381 + viewer - The HDF5 viewer
1382 . parent - The parent dataset/group name
1383 - name   - The attribute name
1384 
1385   Output Parameter:
1386 . has    - Flag for attribute existence
1387 
1388   Level: advanced
1389 
1390   Notes:
1391   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else parent is relative to the current pushed group. NULL means the current pushed group.
1392 
1393 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5HasObjectAttribute(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1394 @*/
1395 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
1396 {
1397   char           *parentAbsPath;
1398   PetscErrorCode ierr;
1399 
1400   PetscFunctionBegin;
1401   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1402   if (parent) PetscValidCharPointer(parent,2);
1403   PetscValidCharPointer(name,3);
1404   PetscValidBoolPointer(has,4);
1405   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, parent, &parentAbsPath);CHKERRQ(ierr);
1406   ierr = PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_FALSE, has, NULL);CHKERRQ(ierr);
1407   if (*has) {ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, has);CHKERRQ(ierr);}
1408   ierr = PetscFree(parentAbsPath);CHKERRQ(ierr);
1409   PetscFunctionReturn(0);
1410 }
1411 
1412 /*@C
1413  PetscViewerHDF5HasObjectAttribute - Check whether an attribute is attached to the dataset matching the given PetscObject by name
1414 
1415   Collective
1416 
1417   Input Parameters:
1418 + viewer - The HDF5 viewer
1419 . obj    - The object whose name is used to lookup the parent dataset, relative to the current group.
1420 - name   - The attribute name
1421 
1422   Output Parameter:
1423 . has    - Flag for attribute existence
1424 
1425   Notes:
1426   This fails if current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
1427   You might want to check first if it does using PetscViewerHDF5HasObject().
1428 
1429   Level: advanced
1430 
1431 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5WriteObjectAttribute(), PetscViewerHDF5ReadObjectAttribute(), PetscViewerHDF5HasObject(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1432 @*/
1433 PetscErrorCode PetscViewerHDF5HasObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscBool *has)
1434 {
1435   PetscErrorCode ierr;
1436 
1437   PetscFunctionBegin;
1438   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1439   PetscValidHeader(obj,2);
1440   PetscValidCharPointer(name,3);
1441   PetscValidBoolPointer(has,4);
1442   ierr = PetscViewerHDF5CheckNamedObject_Internal(viewer, obj);CHKERRQ(ierr);
1443   ierr = PetscViewerHDF5HasAttribute(viewer, obj->name, name, has);CHKERRQ(ierr);
1444   PetscFunctionReturn(0);
1445 }
1446 
1447 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
1448 {
1449   hid_t          h5;
1450   htri_t         hhas;
1451   PetscErrorCode ierr;
1452 
1453   PetscFunctionBegin;
1454   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1455   PetscStackCallHDF5Return(hhas,H5Aexists_by_name,(h5, parent, name, H5P_DEFAULT));
1456   *has = hhas ? PETSC_TRUE : PETSC_FALSE;
1457   PetscFunctionReturn(0);
1458 }
1459 
1460 /*
1461   The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that
1462   is attached to a communicator, in this case the attribute is a PetscViewer.
1463 */
1464 PetscMPIInt Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID;
1465 
1466 /*@C
1467   PETSC_VIEWER_HDF5_ - Creates an HDF5 PetscViewer shared by all processors in a communicator.
1468 
1469   Collective
1470 
1471   Input Parameter:
1472 . comm - the MPI communicator to share the HDF5 PetscViewer
1473 
1474   Level: intermediate
1475 
1476   Options Database Keys:
1477 . -viewer_hdf5_filename <name>
1478 
1479   Environmental variables:
1480 . PETSC_VIEWER_HDF5_FILENAME
1481 
1482   Notes:
1483   Unlike almost all other PETSc routines, PETSC_VIEWER_HDF5_ does not return
1484   an error code.  The HDF5 PetscViewer is usually used in the form
1485 $       XXXView(XXX object, PETSC_VIEWER_HDF5_(comm));
1486 
1487 .seealso: PetscViewerHDF5Open(), PetscViewerCreate(), PetscViewerDestroy()
1488 @*/
1489 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm)
1490 {
1491   PetscErrorCode ierr;
1492   PetscBool      flg;
1493   PetscViewer    viewer;
1494   char           fname[PETSC_MAX_PATH_LEN];
1495   MPI_Comm       ncomm;
1496 
1497   PetscFunctionBegin;
1498   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1499   if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) {
1500     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_HDF5_keyval,NULL);
1501     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1502   }
1503   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void**)&viewer,(int*)&flg);
1504   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1505   if (!flg) { /* PetscViewer not yet created */
1506     ierr = PetscOptionsGetenv(ncomm,"PETSC_VIEWER_HDF5_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
1507     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1508     if (!flg) {
1509       ierr = PetscStrcpy(fname,"output.h5");
1510       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1511     }
1512     ierr = PetscViewerHDF5Open(ncomm,fname,FILE_MODE_WRITE,&viewer);
1513     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1514     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
1515     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1516     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void*)viewer);
1517     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1518   }
1519   ierr = PetscCommDestroy(&ncomm);
1520   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1521   PetscFunctionReturn(viewer);
1522 }
1523