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