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