xref: /petsc/src/sys/classes/viewer/impls/hdf5/hdf5v.c (revision 089a50d65739b6c0de1e42c2ddd1a57bf2f06ba1)
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   PetscViewerHDF5IncrementTimestep - Increments the current timestep for the HDF5 output. Fields are stacked in time.
729 
730   Not collective
731 
732   Input Parameter:
733 . viewer - the PetscViewer
734 
735   Level: intermediate
736 
737 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5SetTimestep(), PetscViewerHDF5GetTimestep()
738 @*/
739 PetscErrorCode PetscViewerHDF5IncrementTimestep(PetscViewer viewer)
740 {
741   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
742 
743   PetscFunctionBegin;
744   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
745   ++hdf5->timestep;
746   PetscFunctionReturn(0);
747 }
748 
749 /*@
750   PetscViewerHDF5SetTimestep - Set the current timestep for the HDF5 output. Fields are stacked in time. A timestep
751   of -1 disables blocking with timesteps.
752 
753   Not collective
754 
755   Input Parameters:
756 + viewer - the PetscViewer
757 - timestep - The timestep number
758 
759   Level: intermediate
760 
761 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5GetTimestep()
762 @*/
763 PetscErrorCode  PetscViewerHDF5SetTimestep(PetscViewer viewer, PetscInt timestep)
764 {
765   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
766 
767   PetscFunctionBegin;
768   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
769   hdf5->timestep = timestep;
770   PetscFunctionReturn(0);
771 }
772 
773 /*@
774   PetscViewerHDF5GetTimestep - Get the current timestep for the HDF5 output. Fields are stacked in time.
775 
776   Not collective
777 
778   Input Parameter:
779 . viewer - the PetscViewer
780 
781   Output Parameter:
782 . timestep - The timestep number
783 
784   Level: intermediate
785 
786 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5SetTimestep()
787 @*/
788 PetscErrorCode  PetscViewerHDF5GetTimestep(PetscViewer viewer, PetscInt *timestep)
789 {
790   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
791 
792   PetscFunctionBegin;
793   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
794   PetscValidPointer(timestep,2);
795   *timestep = hdf5->timestep;
796   PetscFunctionReturn(0);
797 }
798 
799 /*@C
800   PetscDataTypeToHDF5DataType - Converts the PETSc name of a datatype to its HDF5 name.
801 
802   Not collective
803 
804   Input Parameter:
805 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
806 
807   Output Parameter:
808 . mtype - the MPI datatype (for example MPI_DOUBLE, ...)
809 
810   Level: advanced
811 
812 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
813 @*/
814 PetscErrorCode PetscDataTypeToHDF5DataType(PetscDataType ptype, hid_t *htype)
815 {
816   PetscFunctionBegin;
817   if (ptype == PETSC_INT)
818 #if defined(PETSC_USE_64BIT_INDICES)
819                                        *htype = H5T_NATIVE_LLONG;
820 #else
821                                        *htype = H5T_NATIVE_INT;
822 #endif
823   else if (ptype == PETSC_DOUBLE)      *htype = H5T_NATIVE_DOUBLE;
824   else if (ptype == PETSC_LONG)        *htype = H5T_NATIVE_LONG;
825   else if (ptype == PETSC_SHORT)       *htype = H5T_NATIVE_SHORT;
826   else if (ptype == PETSC_ENUM)        *htype = H5T_NATIVE_INT;
827   else if (ptype == PETSC_BOOL)        *htype = H5T_NATIVE_INT;
828   else if (ptype == PETSC_FLOAT)       *htype = H5T_NATIVE_FLOAT;
829   else if (ptype == PETSC_CHAR)        *htype = H5T_NATIVE_CHAR;
830   else if (ptype == PETSC_BIT_LOGICAL) *htype = H5T_NATIVE_UCHAR;
831   else if (ptype == PETSC_STRING)      *htype = H5Tcopy(H5T_C_S1);
832   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported PETSc datatype");
833   PetscFunctionReturn(0);
834 }
835 
836 /*@C
837   PetscHDF5DataTypeToPetscDataType - Finds the PETSc name of a datatype from its HDF5 name
838 
839   Not collective
840 
841   Input Parameter:
842 . htype - the HDF5 datatype (for example H5T_NATIVE_DOUBLE, ...)
843 
844   Output Parameter:
845 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
846 
847   Level: advanced
848 
849 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
850 @*/
851 PetscErrorCode PetscHDF5DataTypeToPetscDataType(hid_t htype, PetscDataType *ptype)
852 {
853   PetscFunctionBegin;
854 #if defined(PETSC_USE_64BIT_INDICES)
855   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_LONG;
856   else if (htype == H5T_NATIVE_LLONG)  *ptype = PETSC_INT;
857 #else
858   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_INT;
859 #endif
860   else if (htype == H5T_NATIVE_DOUBLE) *ptype = PETSC_DOUBLE;
861   else if (htype == H5T_NATIVE_LONG)   *ptype = PETSC_LONG;
862   else if (htype == H5T_NATIVE_SHORT)  *ptype = PETSC_SHORT;
863   else if (htype == H5T_NATIVE_FLOAT)  *ptype = PETSC_FLOAT;
864   else if (htype == H5T_NATIVE_CHAR)   *ptype = PETSC_CHAR;
865   else if (htype == H5T_NATIVE_UCHAR)  *ptype = PETSC_CHAR;
866   else if (htype == H5T_C_S1)          *ptype = PETSC_STRING;
867   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported HDF5 datatype");
868   PetscFunctionReturn(0);
869 }
870 
871 /*@C
872  PetscViewerHDF5WriteAttribute - Write an attribute
873 
874   Input Parameters:
875 + viewer - The HDF5 viewer
876 . parent - The parent dataset/group name
877 . name   - The attribute name
878 . datatype - The attribute type
879 - value    - The attribute value
880 
881   Level: advanced
882 
883   Notes:
884   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else the dataset/group is relative to the current pushed group. NULL means the current pushed group.
885 
886 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteObjectAttribute(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
887 @*/
888 PetscErrorCode PetscViewerHDF5WriteAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *value)
889 {
890   char           *parentAbsPath;
891   hid_t          h5, dataspace, obj, attribute, dtype;
892   PetscBool      has;
893   PetscErrorCode ierr;
894 
895   PetscFunctionBegin;
896   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
897   if (parent) PetscValidCharPointer(parent, 2);
898   PetscValidCharPointer(name, 3);
899   PetscValidLogicalCollectiveEnum(viewer,datatype,4);
900   PetscValidPointer(value, 5);
901   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, parent, &parentAbsPath);CHKERRQ(ierr);
902   ierr = PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_TRUE, NULL, NULL);CHKERRQ(ierr);
903   ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, &has);CHKERRQ(ierr);
904   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
905   if (datatype == PETSC_STRING) {
906     size_t len;
907     ierr = PetscStrlen((const char *) value, &len);CHKERRQ(ierr);
908     PetscStackCallHDF5(H5Tset_size,(dtype, len+1));
909   }
910   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
911   PetscStackCallHDF5Return(dataspace,H5Screate,(H5S_SCALAR));
912   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parentAbsPath, H5P_DEFAULT));
913   if (has) {
914     PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
915   } else {
916     PetscStackCallHDF5Return(attribute,H5Acreate2,(obj, name, dtype, dataspace, H5P_DEFAULT, H5P_DEFAULT));
917   }
918   PetscStackCallHDF5(H5Awrite,(attribute, dtype, value));
919   if (datatype == PETSC_STRING) PetscStackCallHDF5(H5Tclose,(dtype));
920   PetscStackCallHDF5(H5Aclose,(attribute));
921   PetscStackCallHDF5(H5Oclose,(obj));
922   PetscStackCallHDF5(H5Sclose,(dataspace));
923   ierr = PetscFree(parentAbsPath);CHKERRQ(ierr);
924   PetscFunctionReturn(0);
925 }
926 
927 /*@C
928  PetscViewerHDF5WriteObjectAttribute - Write an attribute to the dataset matching the given PetscObject by name
929 
930   Input Parameters:
931 + viewer   - The HDF5 viewer
932 . obj      - The object whose name is used to lookup the parent dataset, relative to the current group.
933 . name     - The attribute name
934 . datatype - The attribute type
935 - value    - The attribute value
936 
937   Notes:
938   This fails if currentGroup/objectName doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
939   You might want to check first if it does using PetscViewerHDF5HasObject().
940 
941   Level: advanced
942 
943 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadObjectAttribute(), PetscViewerHDF5HasObjectAttribute(), PetscViewerHDF5HasObject(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
944 @*/
945 PetscErrorCode PetscViewerHDF5WriteObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscDataType datatype, const void *value)
946 {
947   PetscErrorCode ierr;
948 
949   PetscFunctionBegin;
950   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
951   PetscValidHeader(obj,2);
952   PetscValidCharPointer(name,3);
953   PetscValidPointer(value,5);
954   ierr = PetscViewerHDF5CheckNamedObject_Internal(viewer, obj);CHKERRQ(ierr);
955   ierr = PetscViewerHDF5WriteAttribute(viewer, obj->name, name, datatype, value);CHKERRQ(ierr);
956   PetscFunctionReturn(0);
957 }
958 
959 /*@C
960  PetscViewerHDF5ReadAttribute - Read an attribute
961 
962   Input Parameters:
963 + viewer - The HDF5 viewer
964 . parent - The parent dataset/group name
965 . name   - The attribute name
966 . datatype - The attribute type
967 - defaultValue - The pointer to the default value
968 
969   Output Parameter:
970 . value    - The pointer to the read HDF5 attribute value
971 
972   Notes:
973   If defaultValue is NULL and the attribute is not found, an error occurs.
974   If defaultValue is not NULL and the attribute is not found, defaultValue is copied to value.
975   The pointers defaultValue and value can be the same; for instance
976 $  flg = PETSC_FALSE;
977 $  ierr = PetscViewerHDF5ReadAttribute(viewer,name,"attr",PETSC_BOOL,&flg,&flg);CHKERRQ(ierr);
978   is valid, but make sure the default value is initialized.
979 
980   If the datatype is PETSC_STRING, the output string is newly allocated so one must PetscFree() it when no longer needed.
981 
982   Level: advanced
983 
984   Notes:
985   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else the dataset/group is relative to the current pushed group. NULL means the current pushed group.
986 
987 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5ReadObjectAttribute(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5HasObject(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
988 @*/
989 PetscErrorCode PetscViewerHDF5ReadAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, void *defaultValue, void *value)
990 {
991   char           *parentAbsPath;
992   hid_t          h5, obj, attribute, dtype;
993   PetscBool      has;
994   PetscErrorCode ierr;
995 
996   PetscFunctionBegin;
997   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
998   if (parent) PetscValidCharPointer(parent, 2);
999   PetscValidCharPointer(name, 3);
1000   if (defaultValue) PetscValidPointer(defaultValue, 5);
1001   PetscValidPointer(value, 6);
1002   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
1003   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, parent, &parentAbsPath);CHKERRQ(ierr);
1004   ierr = PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_FALSE, &has, NULL);CHKERRQ(ierr);
1005   if (has) {ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, &has);CHKERRQ(ierr);}
1006   if (!has) {
1007     if (defaultValue) {
1008       if (defaultValue != value) {
1009         if (datatype == PETSC_STRING) {
1010           ierr = PetscStrallocpy(*(char**)defaultValue, (char**)value);CHKERRQ(ierr);
1011         } else {
1012           size_t len;
1013           PetscStackCallHDF5Return(len,H5Tget_size,(dtype));
1014           ierr = PetscMemcpy(value, defaultValue, len);CHKERRQ(ierr);
1015         }
1016       }
1017       ierr = PetscFree(parentAbsPath);CHKERRQ(ierr);
1018       PetscFunctionReturn(0);
1019     } else SETERRQ2(PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Attribute %s/%s does not exist and default value not provided", parentAbsPath, name);
1020   }
1021   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1022   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parentAbsPath, H5P_DEFAULT));
1023   PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
1024   if (datatype == PETSC_STRING) {
1025     size_t len;
1026     hid_t  atype;
1027     PetscStackCallHDF5Return(atype,H5Aget_type,(attribute));
1028     PetscStackCallHDF5Return(len,H5Tget_size,(atype));
1029     ierr = PetscMalloc((len+1) * sizeof(char), value);CHKERRQ(ierr);
1030     PetscStackCallHDF5(H5Tset_size,(dtype, len+1));
1031     PetscStackCallHDF5(H5Aread,(attribute, dtype, *(char**)value));
1032   } else {
1033     PetscStackCallHDF5(H5Aread,(attribute, dtype, value));
1034   }
1035   PetscStackCallHDF5(H5Aclose,(attribute));
1036   /* H5Oclose can be used to close groups, datasets, or committed datatypes */
1037   PetscStackCallHDF5(H5Oclose,(obj));
1038   ierr = PetscFree(parentAbsPath);CHKERRQ(ierr);
1039   PetscFunctionReturn(0);
1040 }
1041 
1042 /*@C
1043  PetscViewerHDF5ReadObjectAttribute - Read an attribute from the dataset matching the given PetscObject by name
1044 
1045   Input Parameters:
1046 + viewer   - The HDF5 viewer
1047 . obj      - The object whose name is used to lookup the parent dataset, relative to the current group.
1048 . name     - The attribute name
1049 - datatype - The attribute type
1050 
1051   Output Parameter:
1052 . value    - The attribute value
1053 
1054   Notes:
1055   This fails if current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
1056   You might want to check first if it does using PetscViewerHDF5HasObject().
1057 
1058   Level: advanced
1059 
1060 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5ReadAttribute() PetscViewerHDF5WriteObjectAttribute(), PetscViewerHDF5HasObjectAttribute(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1061 @*/
1062 PetscErrorCode PetscViewerHDF5ReadObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscDataType datatype, void *defaultValue, void *value)
1063 {
1064   PetscErrorCode ierr;
1065 
1066   PetscFunctionBegin;
1067   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1068   PetscValidHeader(obj,2);
1069   PetscValidCharPointer(name,3);
1070   PetscValidPointer(value, 5);
1071   ierr = PetscViewerHDF5CheckNamedObject_Internal(viewer, obj);CHKERRQ(ierr);
1072   ierr = PetscViewerHDF5ReadAttribute(viewer, obj->name, name, datatype, defaultValue, value);CHKERRQ(ierr);
1073   PetscFunctionReturn(0);
1074 }
1075 
1076 PETSC_STATIC_INLINE PetscErrorCode PetscViewerHDF5Traverse_Inner_Internal(hid_t h5, const char name[], PetscBool createGroup, PetscBool *exists_)
1077 {
1078   htri_t exists;
1079   hid_t group;
1080 
1081   PetscFunctionBegin;
1082   PetscStackCallHDF5Return(exists,H5Lexists,(h5, name, H5P_DEFAULT));
1083   if (exists) PetscStackCallHDF5Return(exists,H5Oexists_by_name,(h5, name, H5P_DEFAULT));
1084   if (!exists && createGroup) {
1085     PetscStackCallHDF5Return(group,H5Gcreate2,(h5, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT));
1086     PetscStackCallHDF5(H5Gclose,(group));
1087     exists = PETSC_TRUE;
1088   }
1089   *exists_ = (PetscBool) exists;
1090   PetscFunctionReturn(0);
1091 }
1092 
1093 static PetscErrorCode PetscViewerHDF5Traverse_Internal(PetscViewer viewer, const char name[], PetscBool createGroup, PetscBool *has, H5O_type_t *otype)
1094 {
1095   const char     rootGroupName[] = "/";
1096   hid_t          h5;
1097   PetscBool      exists=PETSC_FALSE;
1098   PetscInt       i;
1099   int            n;
1100   char           **hierarchy;
1101   char           buf[PETSC_MAX_PATH_LEN]="";
1102   PetscErrorCode ierr;
1103 
1104   PetscFunctionBegin;
1105   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1106   if (name) PetscValidCharPointer(name, 2);
1107   else name = rootGroupName;
1108   if (has) {
1109     PetscValidIntPointer(has, 3);
1110     *has = PETSC_FALSE;
1111   }
1112   if (otype) {
1113     PetscValidIntPointer(otype, 4);
1114     *otype = H5O_TYPE_UNKNOWN;
1115   }
1116   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1117 
1118   /*
1119      Unfortunately, H5Oexists_by_name() fails if any object in hierarchy is missing.
1120      Hence, each of them needs to be tested separately:
1121      1) whether it's a valid link
1122      2) whether this link resolves to an object
1123      See H5Oexists_by_name() documentation.
1124   */
1125   ierr = PetscStrToArray(name,'/',&n,&hierarchy);CHKERRQ(ierr);
1126   if (!n) {
1127     /*  Assume group "/" always exists in accordance with HDF5 >= 1.10.0. See H5Lexists() documentation. */
1128     if (has)   *has   = PETSC_TRUE;
1129     if (otype) *otype = H5O_TYPE_GROUP;
1130     ierr = PetscStrToArrayDestroy(n,hierarchy);CHKERRQ(ierr);
1131     PetscFunctionReturn(0);
1132   }
1133   for (i=0; i<n; i++) {
1134     ierr = PetscStrcat(buf,"/");CHKERRQ(ierr);
1135     ierr = PetscStrcat(buf,hierarchy[i]);CHKERRQ(ierr);
1136     ierr = PetscViewerHDF5Traverse_Inner_Internal(h5, buf, createGroup, &exists);CHKERRQ(ierr);
1137     if (!exists) break;
1138   }
1139   ierr = PetscStrToArrayDestroy(n,hierarchy);CHKERRQ(ierr);
1140 
1141   /* If the object exists, get its type */
1142   if (exists && otype) {
1143     H5O_info_t info;
1144 
1145     /* We could use H5Iget_type() here but that would require opening the object. This way we only need its name. */
1146     PetscStackCallHDF5(H5Oget_info_by_name,(h5, name, &info, H5P_DEFAULT));
1147     *otype = info.type;
1148   }
1149   if (has) *has = exists;
1150   PetscFunctionReturn(0);
1151 }
1152 
1153 /*@C
1154  PetscViewerHDF5HasGroup - Check whether the current (pushed) group exists in the HDF5 file
1155 
1156   Input Parameters:
1157 + viewer - The HDF5 viewer
1158 - path - The group path
1159 
1160   Output Parameter:
1161 . has - Flag for group existence
1162 
1163   Level: advanced
1164 
1165   Notes:
1166   If path starts with '/', it is taken as an absolute path overriding currently pushed group, else the dataset/group is relative to the current pushed group. NULL means the current pushed group.
1167   If the path exists but is not a group, PETSC_FALSE is returned.
1168 
1169 .seealso: PetscViewerHDF5HasAttribute(), PetscViewerHDF5HasDataset(), PetscViewerHDF5PushGroup(), PetscViewerHDF5PopGroup(), PetscViewerHDF5GetGroup(), PetscViewerHDF5OpenGroup()
1170 @*/
1171 PetscErrorCode PetscViewerHDF5HasGroup(PetscViewer viewer, const char path[], PetscBool *has)
1172 {
1173   H5O_type_t     type;
1174   char           *abspath;
1175   PetscErrorCode ierr;
1176 
1177   PetscFunctionBegin;
1178   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1179   if (path) PetscValidCharPointer(path,2);
1180   PetscValidBoolPointer(has,3);
1181   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, path, &abspath);CHKERRQ(ierr);
1182   ierr = PetscViewerHDF5Traverse_Internal(viewer, abspath, PETSC_FALSE, NULL, &type);CHKERRQ(ierr);
1183   *has = (PetscBool)(type == H5O_TYPE_GROUP);
1184   ierr = PetscFree(abspath);CHKERRQ(ierr);
1185   PetscFunctionReturn(0);
1186 }
1187 
1188 /*@C
1189  PetscViewerHDF5HasDataset - Check whether a given dataset exists in the HDF5 file
1190 
1191   Input Parameters:
1192 + viewer - The HDF5 viewer
1193 - path - The dataset path
1194 
1195   Output Parameter:
1196 . has - Flag whether dataset exists
1197 
1198   Level: advanced
1199 
1200   Notes:
1201   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else the dataset/group is relative to the current pushed group.
1202   If path is NULL or empty, has is set to PETSC_FALSE.
1203   If the path exists but is not a dataset, has is set to PETSC_FALSE as well.
1204 
1205 .seealso: PetscViewerHDF5HasObject(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5HasGroup(), PetscViewerHDF5PushGroup(), PetscViewerHDF5PopGroup(), PetscViewerHDF5GetGroup()
1206 @*/
1207 PetscErrorCode PetscViewerHDF5HasDataset(PetscViewer viewer, const char path[], PetscBool *has)
1208 {
1209   H5O_type_t     type;
1210   char           *abspath;
1211   PetscErrorCode ierr;
1212 
1213   PetscFunctionBegin;
1214   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1215   if (path) PetscValidCharPointer(path,2);
1216   PetscValidBoolPointer(has,3);
1217   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, path, &abspath);CHKERRQ(ierr);
1218   ierr = PetscViewerHDF5Traverse_Internal(viewer, abspath, PETSC_FALSE, NULL, &type);CHKERRQ(ierr);
1219   *has = (PetscBool)(type == H5O_TYPE_DATASET);
1220   ierr = PetscFree(abspath);CHKERRQ(ierr);
1221   PetscFunctionReturn(0);
1222 }
1223 
1224 /*@
1225  PetscViewerHDF5HasObject - Check whether a dataset with the same name as given object exists in the HDF5 file under current group
1226 
1227   Input Parameters:
1228 + viewer - The HDF5 viewer
1229 - obj    - The named object
1230 
1231   Output Parameter:
1232 . has    - Flag for dataset existence
1233 
1234   Notes:
1235   If the object is unnamed, an error occurs.
1236   If the path currentGroup/objectName exists but is not a dataset, has is set to PETSC_FALSE as well.
1237 
1238   Level: advanced
1239 
1240 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5HasDataset(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5PushGroup(), PetscViewerHDF5PopGroup(), PetscViewerHDF5GetGroup()
1241 @*/
1242 PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, PetscObject obj, PetscBool *has)
1243 {
1244   size_t         len;
1245   PetscErrorCode ierr;
1246 
1247   PetscFunctionBegin;
1248   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1249   PetscValidHeader(obj,2);
1250   PetscValidBoolPointer(has,3);
1251   ierr = PetscStrlen(obj->name, &len);CHKERRQ(ierr);
1252   if (!len) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Object must be named");
1253   ierr = PetscViewerHDF5HasDataset(viewer, obj->name, has);CHKERRQ(ierr);
1254   PetscFunctionReturn(0);
1255 }
1256 
1257 /*@C
1258  PetscViewerHDF5HasAttribute - Check whether an attribute exists
1259 
1260   Input Parameters:
1261 + viewer - The HDF5 viewer
1262 . parent - The parent dataset/group name
1263 - name   - The attribute name
1264 
1265   Output Parameter:
1266 . has    - Flag for attribute existence
1267 
1268   Level: advanced
1269 
1270   Notes:
1271   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else the dataset/group is relative to the current pushed group. NULL means the current pushed group.
1272 
1273 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5HasObjectAttribute(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1274 @*/
1275 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
1276 {
1277   char           *parentAbsPath;
1278   PetscErrorCode ierr;
1279 
1280   PetscFunctionBegin;
1281   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1282   if (parent) PetscValidCharPointer(parent,2);
1283   PetscValidCharPointer(name,3);
1284   PetscValidBoolPointer(has,4);
1285   ierr = PetscViewerHDF5GetAbsolutePath_Internal(viewer, parent, &parentAbsPath);CHKERRQ(ierr);
1286   ierr = PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_FALSE, has, NULL);CHKERRQ(ierr);
1287   if (*has) {ierr = PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, has);CHKERRQ(ierr);}
1288   ierr = PetscFree(parentAbsPath);CHKERRQ(ierr);
1289   PetscFunctionReturn(0);
1290 }
1291 
1292 /*@C
1293  PetscViewerHDF5HasObjectAttribute - Check whether an attribute is attached to the dataset matching the given PetscObject by name
1294 
1295   Input Parameters:
1296 + viewer - The HDF5 viewer
1297 . obj    - The object whose name is used to lookup the parent dataset, relative to the current group.
1298 - name   - The attribute name
1299 
1300   Output Parameter:
1301 . has    - Flag for attribute existence
1302 
1303   Notes:
1304   This fails if current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
1305   You might want to check first if it does using PetscViewerHDF5HasObject().
1306 
1307   Level: advanced
1308 
1309 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5HasAttribute(), PetscViewerHDF5WriteObjectAttribute(), PetscViewerHDF5ReadObjectAttribute(), PetscViewerHDF5HasObject(), PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
1310 @*/
1311 PetscErrorCode PetscViewerHDF5HasObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscBool *has)
1312 {
1313   PetscErrorCode ierr;
1314 
1315   PetscFunctionBegin;
1316   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1317   PetscValidHeader(obj,2);
1318   PetscValidCharPointer(name,3);
1319   PetscValidBoolPointer(has,4);
1320   ierr = PetscViewerHDF5CheckNamedObject_Internal(viewer, obj);CHKERRQ(ierr);
1321   ierr = PetscViewerHDF5HasAttribute(viewer, obj->name, name, has);CHKERRQ(ierr);
1322   PetscFunctionReturn(0);
1323 }
1324 
1325 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
1326 {
1327   hid_t          h5;
1328   htri_t         hhas;
1329   PetscErrorCode ierr;
1330 
1331   PetscFunctionBegin;
1332   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
1333   PetscStackCallHDF5Return(hhas,H5Aexists_by_name,(h5, parent, name, H5P_DEFAULT));
1334   *has = hhas ? PETSC_TRUE : PETSC_FALSE;
1335   PetscFunctionReturn(0);
1336 }
1337 
1338 /*
1339   The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that
1340   is attached to a communicator, in this case the attribute is a PetscViewer.
1341 */
1342 PetscMPIInt Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID;
1343 
1344 /*@C
1345   PETSC_VIEWER_HDF5_ - Creates an HDF5 PetscViewer shared by all processors in a communicator.
1346 
1347   Collective
1348 
1349   Input Parameter:
1350 . comm - the MPI communicator to share the HDF5 PetscViewer
1351 
1352   Level: intermediate
1353 
1354   Options Database Keys:
1355 . -viewer_hdf5_filename <name>
1356 
1357   Environmental variables:
1358 . PETSC_VIEWER_HDF5_FILENAME
1359 
1360   Notes:
1361   Unlike almost all other PETSc routines, PETSC_VIEWER_HDF5_ does not return
1362   an error code.  The HDF5 PetscViewer is usually used in the form
1363 $       XXXView(XXX object, PETSC_VIEWER_HDF5_(comm));
1364 
1365 .seealso: PetscViewerHDF5Open(), PetscViewerCreate(), PetscViewerDestroy()
1366 @*/
1367 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm)
1368 {
1369   PetscErrorCode ierr;
1370   PetscBool      flg;
1371   PetscViewer    viewer;
1372   char           fname[PETSC_MAX_PATH_LEN];
1373   MPI_Comm       ncomm;
1374 
1375   PetscFunctionBegin;
1376   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1377   if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) {
1378     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_HDF5_keyval,NULL);
1379     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1380   }
1381   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void**)&viewer,(int*)&flg);
1382   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1383   if (!flg) { /* PetscViewer not yet created */
1384     ierr = PetscOptionsGetenv(ncomm,"PETSC_VIEWER_HDF5_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
1385     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1386     if (!flg) {
1387       ierr = PetscStrcpy(fname,"output.h5");
1388       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1389     }
1390     ierr = PetscViewerHDF5Open(ncomm,fname,FILE_MODE_WRITE,&viewer);
1391     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1392     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
1393     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1394     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void*)viewer);
1395     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1396   }
1397   ierr = PetscCommDestroy(&ncomm);
1398   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1399   PetscFunctionReturn(viewer);
1400 }
1401