xref: /petsc/src/sys/classes/viewer/impls/hdf5/hdf5v.c (revision d1232d7f6ecea0371a82271e3f53008cf19b8ea5)
1 #include <petsc/private/viewerimpl.h>    /*I   "petscsys.h"   I*/
2 #include <petscviewerhdf5.h>    /*I   "petscviewerhdf5.h"   I*/
3 
4 typedef struct GroupList {
5   const char       *name;
6   struct GroupList *next;
7 } GroupList;
8 
9 typedef struct {
10   char          *filename;
11   PetscFileMode btype;
12   hid_t         file_id;
13   PetscInt      timestep;
14   GroupList     *groups;
15   PetscBool     basedimension2;  /* save vectors and DMDA vectors with a dimension of at least 2 even if the bs/dof is 1 */
16   PetscBool     spoutput;  /* write data in single precision even if PETSc is compiled with double precision PetscReal */
17 } PetscViewer_HDF5;
18 
19 #undef __FUNCT__
20 #define __FUNCT__ "PetscViewerSetFromOptions_HDF5"
21 static PetscErrorCode PetscViewerSetFromOptions_HDF5(PetscOptionItems *PetscOptionsObject,PetscViewer v)
22 {
23   PetscErrorCode   ierr;
24   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*)v->data;
25 
26   PetscFunctionBegin;
27   ierr = PetscOptionsHead(PetscOptionsObject,"HDF5 PetscViewer Options");CHKERRQ(ierr);
28   ierr = PetscOptionsBool("-viewer_hdf5_base_dimension2","1d Vectors get 2 dimensions in HDF5","PetscViewerHDF5SetBaseDimension2",hdf5->basedimension2,&hdf5->basedimension2,NULL);CHKERRQ(ierr);
29   ierr = PetscOptionsBool("-viewer_hdf5_sp_output","Force data to be written in single precision","PetscViewerHDF5SetSPOutput",hdf5->spoutput,&hdf5->spoutput,NULL);CHKERRQ(ierr);
30   ierr = PetscOptionsTail();CHKERRQ(ierr);
31   PetscFunctionReturn(0);
32 }
33 
34 #undef __FUNCT__
35 #define __FUNCT__ "PetscViewerFileClose_HDF5"
36 static PetscErrorCode PetscViewerFileClose_HDF5(PetscViewer viewer)
37 {
38   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*)viewer->data;
39   PetscErrorCode   ierr;
40 
41   PetscFunctionBegin;
42   ierr = PetscFree(hdf5->filename);CHKERRQ(ierr);
43   if (hdf5->file_id) PetscStackCallHDF5(H5Fclose,(hdf5->file_id));
44   PetscFunctionReturn(0);
45 }
46 
47 #undef __FUNCT__
48 #define __FUNCT__ "PetscViewerDestroy_HDF5"
49 PetscErrorCode PetscViewerDestroy_HDF5(PetscViewer viewer)
50 {
51   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
52   PetscErrorCode   ierr;
53 
54   PetscFunctionBegin;
55   ierr = PetscViewerFileClose_HDF5(viewer);CHKERRQ(ierr);
56   while (hdf5->groups) {
57     GroupList *tmp = hdf5->groups->next;
58 
59     ierr         = PetscFree(hdf5->groups->name);CHKERRQ(ierr);
60     ierr         = PetscFree(hdf5->groups);CHKERRQ(ierr);
61     hdf5->groups = tmp;
62   }
63   ierr = PetscFree(hdf5);CHKERRQ(ierr);
64   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL);CHKERRQ(ierr);
65   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileGetName_C",NULL);CHKERRQ(ierr);
66   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetMode_C",NULL);CHKERRQ(ierr);
67   PetscFunctionReturn(0);
68 }
69 
70 #undef __FUNCT__
71 #define __FUNCT__ "PetscViewerFileSetMode_HDF5"
72 PetscErrorCode  PetscViewerFileSetMode_HDF5(PetscViewer viewer, PetscFileMode type)
73 {
74   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
75 
76   PetscFunctionBegin;
77   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
78   hdf5->btype = type;
79   PetscFunctionReturn(0);
80 }
81 
82 #undef __FUNCT__
83 #define __FUNCT__ "PetscViewerHDF5SetBaseDimension2_HDF5"
84 PetscErrorCode  PetscViewerHDF5SetBaseDimension2_HDF5(PetscViewer viewer, PetscBool flg)
85 {
86   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
87 
88   PetscFunctionBegin;
89   hdf5->basedimension2 = flg;
90   PetscFunctionReturn(0);
91 }
92 
93 #undef __FUNCT__
94 #define __FUNCT__ "PetscViewerHDF5SetBaseDimension2"
95 /*@
96      PetscViewerHDF5SetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
97        dimension of 2.
98 
99     Logically Collective on PetscViewer
100 
101   Input Parameters:
102 +  viewer - the PetscViewer; if it is not hdf5 then this command is ignored
103 -  flg - if PETSC_TRUE the vector will always have at least a dimension of 2 even if that first dimension is of size 1
104 
105   Options Database:
106 .  -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
107 
108 
109   Notes: Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
110          of one when the dimension is lower. Others think the option is crazy.
111 
112   Level: intermediate
113 
114 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen()
115 
116 @*/
117 PetscErrorCode PetscViewerHDF5SetBaseDimension2(PetscViewer viewer,PetscBool flg)
118 {
119   PetscErrorCode ierr;
120 
121   PetscFunctionBegin;
122   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
123   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetBaseDimension2_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
124   PetscFunctionReturn(0);
125 }
126 
127 #undef __FUNCT__
128 #define __FUNCT__ "PetscViewerHDF5GetBaseDimension2"
129 /*@
130      PetscViewerHDF5GetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
131        dimension of 2.
132 
133     Logically Collective on PetscViewer
134 
135   Input Parameter:
136 .  viewer - the PetscViewer, must be of type HDF5
137 
138   Output Parameter:
139 .  flg - if PETSC_TRUE the vector will always have at least a dimension of 2 even if that first dimension is of size 1
140 
141   Notes: Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
142          of one when the dimension is lower. Others think the option is crazy.
143 
144   Level: intermediate
145 
146 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen()
147 
148 @*/
149 PetscErrorCode PetscViewerHDF5GetBaseDimension2(PetscViewer viewer,PetscBool *flg)
150 {
151   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
152 
153   PetscFunctionBegin;
154   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
155   *flg = hdf5->basedimension2;
156   PetscFunctionReturn(0);
157 }
158 
159 #undef __FUNCT__
160 #define __FUNCT__ "PetscViewerHDF5SetSPOutput_HDF5"
161 PetscErrorCode  PetscViewerHDF5SetSPOutput_HDF5(PetscViewer viewer, PetscBool flg)
162 {
163   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
164 
165   PetscFunctionBegin;
166   hdf5->spoutput = flg;
167   PetscFunctionReturn(0);
168 }
169 
170 #undef __FUNCT__
171 #define __FUNCT__ "PetscViewerHDF5SetSPOutput"
172 /*@
173      PetscViewerHDF5SetSPOutput - Data is written to disk in single precision even if PETSc is
174        compiled with double precision PetscReal.
175 
176     Logically Collective on PetscViewer
177 
178   Input Parameters:
179 +  viewer - the PetscViewer; if it is not hdf5 then this command is ignored
180 -  flg - if PETSC_TRUE the data will be written to disk with single precision
181 
182   Options Database:
183 .  -viewer_hdf5_sp_output - turns on (true) or off (false) output in single precision
184 
185 
186   Notes: Setting this option does not make any difference if PETSc is compiled with single precision
187          in the first place. It does not affect reading datasets (HDF5 handle this internally).
188 
189   Level: intermediate
190 
191 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen(),
192           PetscReal
193 
194 @*/
195 PetscErrorCode PetscViewerHDF5SetSPOutput(PetscViewer viewer,PetscBool flg)
196 {
197   PetscErrorCode ierr;
198 
199   PetscFunctionBegin;
200   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
201   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetSPOutput_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
202   PetscFunctionReturn(0);
203 }
204 
205 #undef __FUNCT__
206 #define __FUNCT__ "PetscViewerHDF5GetSPOutput"
207 /*@
208      PetscViewerHDF5GetSPOutput - Data is written to disk in single precision even if PETSc is
209        compiled with double precision PetscReal.
210 
211     Logically Collective on PetscViewer
212 
213   Input Parameter:
214 .  viewer - the PetscViewer, must be of type HDF5
215 
216   Output Parameter:
217 .  flg - if PETSC_TRUE the data will be written to disk with single precision
218 
219   Notes: Setting this option does not make any difference if PETSc is compiled with single precision
220          in the first place. It does not affect reading datasets (HDF5 handle this internally).
221 
222   Level: intermediate
223 
224 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen(),
225           PetscReal
226 
227 @*/
228 PetscErrorCode PetscViewerHDF5GetSPOutput(PetscViewer viewer,PetscBool *flg)
229 {
230   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
231 
232   PetscFunctionBegin;
233   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
234   *flg = hdf5->spoutput;
235   PetscFunctionReturn(0);
236 }
237 
238 #undef __FUNCT__
239 #define __FUNCT__ "PetscViewerFileSetName_HDF5"
240 PetscErrorCode  PetscViewerFileSetName_HDF5(PetscViewer viewer, const char name[])
241 {
242   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
243 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
244   MPI_Info          info = MPI_INFO_NULL;
245 #endif
246   hid_t             plist_id;
247   PetscErrorCode    ierr;
248 
249   PetscFunctionBegin;
250   ierr = PetscStrallocpy(name, &hdf5->filename);CHKERRQ(ierr);
251   /* Set up file access property list with parallel I/O access */
252   PetscStackCallHDF5Return(plist_id,H5Pcreate,(H5P_FILE_ACCESS));
253 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
254   PetscStackCallHDF5(H5Pset_fapl_mpio,(plist_id, PetscObjectComm((PetscObject)viewer), info));
255 #endif
256   /* Create or open the file collectively */
257   switch (hdf5->btype) {
258   case FILE_MODE_READ:
259     PetscStackCallHDF5Return(hdf5->file_id,H5Fopen,(name, H5F_ACC_RDONLY, plist_id));
260     break;
261   case FILE_MODE_APPEND:
262     PetscStackCallHDF5Return(hdf5->file_id,H5Fopen,(name, H5F_ACC_RDWR, plist_id));
263     break;
264   case FILE_MODE_WRITE:
265     PetscStackCallHDF5Return(hdf5->file_id,H5Fcreate,(name, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id));
266     break;
267   default:
268     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
269   }
270   if (hdf5->file_id < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB, "H5Fcreate failed for %s", name);
271   PetscStackCallHDF5(H5Pclose,(plist_id));
272   PetscFunctionReturn(0);
273 }
274 
275 #undef __FUNCT__
276 #define __FUNCT__ "PetscViewerFileGetName_HDF5"
277 static PetscErrorCode PetscViewerFileGetName_HDF5(PetscViewer viewer,const char **name)
278 {
279   PetscViewer_HDF5 *vhdf5 = (PetscViewer_HDF5*)viewer->data;
280 
281   PetscFunctionBegin;
282   *name = vhdf5->filename;
283   PetscFunctionReturn(0);
284 }
285 
286 
287 #undef __FUNCT__
288 #define __FUNCT__ "PetscViewerCreate_HDF5"
289 PETSC_EXTERN PetscErrorCode PetscViewerCreate_HDF5(PetscViewer v)
290 {
291   PetscViewer_HDF5 *hdf5;
292   PetscErrorCode   ierr;
293 
294   PetscFunctionBegin;
295   ierr = PetscNewLog(v,&hdf5);CHKERRQ(ierr);
296 
297   v->data                = (void*) hdf5;
298   v->ops->destroy        = PetscViewerDestroy_HDF5;
299   v->ops->setfromoptions = PetscViewerSetFromOptions_HDF5;
300   v->ops->flush          = 0;
301   hdf5->btype            = (PetscFileMode) -1;
302   hdf5->filename         = 0;
303   hdf5->timestep         = -1;
304   hdf5->groups           = NULL;
305 
306   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetName_C",PetscViewerFileSetName_HDF5);CHKERRQ(ierr);
307   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetName_C",PetscViewerFileGetName_HDF5);CHKERRQ(ierr);
308   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetMode_C",PetscViewerFileSetMode_HDF5);CHKERRQ(ierr);
309   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetBaseDimension2_C",PetscViewerHDF5SetBaseDimension2_HDF5);CHKERRQ(ierr);
310   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetSPOutput_C",PetscViewerHDF5SetSPOutput_HDF5);CHKERRQ(ierr);
311   PetscFunctionReturn(0);
312 }
313 
314 #undef __FUNCT__
315 #define __FUNCT__ "PetscViewerHDF5Open"
316 /*@C
317    PetscViewerHDF5Open - Opens a file for HDF5 input/output.
318 
319    Collective on MPI_Comm
320 
321    Input Parameters:
322 +  comm - MPI communicator
323 .  name - name of file
324 -  type - type of file
325 $    FILE_MODE_WRITE - create new file for binary output
326 $    FILE_MODE_READ - open existing file for binary input
327 $    FILE_MODE_APPEND - open existing file for binary output
328 
329    Output Parameter:
330 .  hdf5v - PetscViewer for HDF5 input/output to use with the specified file
331 
332   Options Database:
333 .  -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
334 .  -viewer_hdf5_sp_output - forces (if true) the viewer to write data in single precision independent on the precision of PetscReal
335 
336    Level: beginner
337 
338    Note:
339    This PetscViewer should be destroyed with PetscViewerDestroy().
340 
341    Concepts: HDF5 files
342    Concepts: PetscViewerHDF5^creating
343 
344 .seealso: PetscViewerASCIIOpen(), PetscViewerPushFormat(), PetscViewerDestroy(), PetscViewerHDF5SetBaseDimension2(),
345           PetscViewerHDF5SetSPOutput(), PetscViewerHDF5GetBaseDimension2(), VecView(), MatView(), VecLoad(),
346           MatLoad(), PetscFileMode, PetscViewer
347 @*/
348 PetscErrorCode  PetscViewerHDF5Open(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *hdf5v)
349 {
350   PetscErrorCode ierr;
351 
352   PetscFunctionBegin;
353   ierr = PetscViewerCreate(comm, hdf5v);CHKERRQ(ierr);
354   ierr = PetscViewerSetType(*hdf5v, PETSCVIEWERHDF5);CHKERRQ(ierr);
355   ierr = PetscViewerFileSetMode(*hdf5v, type);CHKERRQ(ierr);
356   ierr = PetscViewerFileSetName(*hdf5v, name);CHKERRQ(ierr);
357   PetscFunctionReturn(0);
358 }
359 
360 #undef __FUNCT__
361 #define __FUNCT__ "PetscViewerHDF5GetFileId"
362 /*@C
363   PetscViewerHDF5GetFileId - Retrieve the file id, this file ID then can be used in direct HDF5 calls
364 
365   Not collective
366 
367   Input Parameter:
368 . viewer - the PetscViewer
369 
370   Output Parameter:
371 . file_id - The file id
372 
373   Level: intermediate
374 
375 .seealso: PetscViewerHDF5Open()
376 @*/
377 PetscErrorCode  PetscViewerHDF5GetFileId(PetscViewer viewer, hid_t *file_id)
378 {
379   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
380 
381   PetscFunctionBegin;
382   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
383   if (file_id) *file_id = hdf5->file_id;
384   PetscFunctionReturn(0);
385 }
386 
387 #undef __FUNCT__
388 #define __FUNCT__ "PetscViewerHDF5PushGroup"
389 /*@C
390   PetscViewerHDF5PushGroup - Set the current HDF5 group for output
391 
392   Not collective
393 
394   Input Parameters:
395 + viewer - the PetscViewer
396 - name - The group name
397 
398   Level: intermediate
399 
400 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
401 @*/
402 PetscErrorCode  PetscViewerHDF5PushGroup(PetscViewer viewer, const char *name)
403 {
404   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
405   GroupList        *groupNode;
406   PetscErrorCode   ierr;
407 
408   PetscFunctionBegin;
409   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
410   PetscValidCharPointer(name,2);
411   ierr = PetscMalloc(sizeof(GroupList), &groupNode);CHKERRQ(ierr);
412   ierr = PetscStrallocpy(name, (char**) &groupNode->name);CHKERRQ(ierr);
413 
414   groupNode->next = hdf5->groups;
415   hdf5->groups    = groupNode;
416   PetscFunctionReturn(0);
417 }
418 
419 #undef __FUNCT__
420 #define __FUNCT__ "PetscViewerHDF5PopGroup"
421 /*@
422   PetscViewerHDF5PopGroup - Return the current HDF5 group for output to the previous value
423 
424   Not collective
425 
426   Input Parameter:
427 . viewer - the PetscViewer
428 
429   Level: intermediate
430 
431 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5GetGroup()
432 @*/
433 PetscErrorCode  PetscViewerHDF5PopGroup(PetscViewer viewer)
434 {
435   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
436   GroupList        *groupNode;
437   PetscErrorCode   ierr;
438 
439   PetscFunctionBegin;
440   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
441   if (!hdf5->groups) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "HDF5 group stack is empty, cannot pop");
442   groupNode    = hdf5->groups;
443   hdf5->groups = hdf5->groups->next;
444   ierr         = PetscFree(groupNode->name);CHKERRQ(ierr);
445   ierr         = PetscFree(groupNode);CHKERRQ(ierr);
446   PetscFunctionReturn(0);
447 }
448 
449 #undef __FUNCT__
450 #define __FUNCT__ "PetscViewerHDF5GetGroup"
451 /*@C
452   PetscViewerHDF5GetGroup - Get the current HDF5 group for output. If none has been assigned, returns NULL.
453 
454   Not collective
455 
456   Input Parameter:
457 . viewer - the PetscViewer
458 
459   Output Parameter:
460 . name - The group name
461 
462   Level: intermediate
463 
464 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup()
465 @*/
466 PetscErrorCode  PetscViewerHDF5GetGroup(PetscViewer viewer, const char **name)
467 {
468   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *) viewer->data;
469 
470   PetscFunctionBegin;
471   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
472   PetscValidPointer(name,2);
473   if (hdf5->groups) *name = hdf5->groups->name;
474   else *name = NULL;
475   PetscFunctionReturn(0);
476 }
477 
478 #undef __FUNCT__
479 #define __FUNCT__ "PetscViewerHDF5IncrementTimestep"
480 /*@
481   PetscViewerHDF5IncrementTimestep - Increments the current timestep for the HDF5 output. Fields are stacked in time.
482 
483   Not collective
484 
485   Input Parameter:
486 . viewer - the PetscViewer
487 
488   Level: intermediate
489 
490 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5SetTimestep(), PetscViewerHDF5GetTimestep()
491 @*/
492 PetscErrorCode PetscViewerHDF5IncrementTimestep(PetscViewer viewer)
493 {
494   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
495 
496   PetscFunctionBegin;
497   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
498   ++hdf5->timestep;
499   PetscFunctionReturn(0);
500 }
501 
502 #undef __FUNCT__
503 #define __FUNCT__ "PetscViewerHDF5SetTimestep"
504 /*@
505   PetscViewerHDF5SetTimestep - Set the current timestep for the HDF5 output. Fields are stacked in time. A timestep
506   of -1 disables blocking with timesteps.
507 
508   Not collective
509 
510   Input Parameters:
511 + viewer - the PetscViewer
512 - timestep - The timestep number
513 
514   Level: intermediate
515 
516 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5GetTimestep()
517 @*/
518 PetscErrorCode  PetscViewerHDF5SetTimestep(PetscViewer viewer, PetscInt timestep)
519 {
520   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
521 
522   PetscFunctionBegin;
523   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
524   hdf5->timestep = timestep;
525   PetscFunctionReturn(0);
526 }
527 
528 #undef __FUNCT__
529 #define __FUNCT__ "PetscViewerHDF5GetTimestep"
530 /*@
531   PetscViewerHDF5GetTimestep - Get the current timestep for the HDF5 output. Fields are stacked in time.
532 
533   Not collective
534 
535   Input Parameter:
536 . viewer - the PetscViewer
537 
538   Output Parameter:
539 . timestep - The timestep number
540 
541   Level: intermediate
542 
543 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5SetTimestep()
544 @*/
545 PetscErrorCode  PetscViewerHDF5GetTimestep(PetscViewer viewer, PetscInt *timestep)
546 {
547   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
548 
549   PetscFunctionBegin;
550   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
551   PetscValidPointer(timestep,2);
552   *timestep = hdf5->timestep;
553   PetscFunctionReturn(0);
554 }
555 
556 #undef __FUNCT__
557 #define __FUNCT__ "PetscDataTypeToHDF5DataType"
558 /*@C
559   PetscDataTypeToHDF5DataType - Converts the PETSc name of a datatype to its HDF5 name.
560 
561   Not collective
562 
563   Input Parameter:
564 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
565 
566   Output Parameter:
567 . mtype - the MPI datatype (for example MPI_DOUBLE, ...)
568 
569   Level: advanced
570 
571 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
572 @*/
573 PetscErrorCode PetscDataTypeToHDF5DataType(PetscDataType ptype, hid_t *htype)
574 {
575   PetscFunctionBegin;
576   if (ptype == PETSC_INT)
577 #if defined(PETSC_USE_64BIT_INDICES)
578                                        *htype = H5T_NATIVE_LLONG;
579 #else
580                                        *htype = H5T_NATIVE_INT;
581 #endif
582   else if (ptype == PETSC_DOUBLE)      *htype = H5T_NATIVE_DOUBLE;
583   else if (ptype == PETSC_LONG)        *htype = H5T_NATIVE_LONG;
584   else if (ptype == PETSC_SHORT)       *htype = H5T_NATIVE_SHORT;
585   else if (ptype == PETSC_ENUM)        *htype = H5T_NATIVE_DOUBLE;
586   else if (ptype == PETSC_BOOL)        *htype = H5T_NATIVE_DOUBLE;
587   else if (ptype == PETSC_FLOAT)       *htype = H5T_NATIVE_FLOAT;
588   else if (ptype == PETSC_CHAR)        *htype = H5T_NATIVE_CHAR;
589   else if (ptype == PETSC_BIT_LOGICAL) *htype = H5T_NATIVE_UCHAR;
590   else if (ptype == PETSC_STRING)      *htype = H5Tcopy(H5T_C_S1);
591   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported PETSc datatype");
592   PetscFunctionReturn(0);
593 }
594 
595 #undef __FUNCT__
596 #define __FUNCT__ "PetscHDF5DataTypeToPetscDataType"
597 /*@C
598   PetscHDF5DataTypeToPetscDataType - Finds the PETSc name of a datatype from its HDF5 name
599 
600   Not collective
601 
602   Input Parameter:
603 . htype - the HDF5 datatype (for example H5T_NATIVE_DOUBLE, ...)
604 
605   Output Parameter:
606 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
607 
608   Level: advanced
609 
610 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
611 @*/
612 PetscErrorCode PetscHDF5DataTypeToPetscDataType(hid_t htype, PetscDataType *ptype)
613 {
614   PetscFunctionBegin;
615 #if defined(PETSC_USE_64BIT_INDICES)
616   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_LONG;
617   else if (htype == H5T_NATIVE_LLONG)  *ptype = PETSC_INT;
618 #else
619   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_INT;
620 #endif
621   else if (htype == H5T_NATIVE_DOUBLE) *ptype = PETSC_DOUBLE;
622   else if (htype == H5T_NATIVE_LONG)   *ptype = PETSC_LONG;
623   else if (htype == H5T_NATIVE_SHORT)  *ptype = PETSC_SHORT;
624   else if (htype == H5T_NATIVE_FLOAT)  *ptype = PETSC_FLOAT;
625   else if (htype == H5T_NATIVE_CHAR)   *ptype = PETSC_CHAR;
626   else if (htype == H5T_NATIVE_UCHAR)  *ptype = PETSC_CHAR;
627   else if (htype == H5T_C_S1)          *ptype = PETSC_STRING;
628   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported HDF5 datatype");
629   PetscFunctionReturn(0);
630 }
631 
632 #undef __FUNCT__
633 #define __FUNCT__ "PetscViewerHDF5WriteAttribute"
634 /*@C
635  PetscViewerHDF5WriteAttribute - Write a scalar attribute
636 
637   Input Parameters:
638 + viewer - The HDF5 viewer
639 . parent - The parent name
640 . name   - The attribute name
641 . datatype - The attribute type
642 - value    - The attribute value
643 
644   Level: advanced
645 
646 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5HasAttribute()
647 @*/
648 PetscErrorCode PetscViewerHDF5WriteAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *value)
649 {
650   hid_t          h5, dataspace, dataset, attribute, dtype;
651   PetscErrorCode ierr;
652 
653   PetscFunctionBegin;
654   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
655   PetscValidPointer(parent, 2);
656   PetscValidPointer(name, 3);
657   PetscValidPointer(value, 4);
658   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
659   if (datatype == PETSC_STRING) {
660     size_t len;
661     ierr = PetscStrlen((const char *) value, &len);CHKERRQ(ierr);
662     PetscStackCallHDF5(H5Tset_size,(dtype, len+1));
663   }
664   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
665   PetscStackCallHDF5Return(dataspace,H5Screate,(H5S_SCALAR));
666 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
667   PetscStackCallHDF5Return(dataset,H5Dopen2,(h5, parent, H5P_DEFAULT));
668   PetscStackCallHDF5Return(attribute,H5Acreate2,(dataset, name, dtype, dataspace, H5P_DEFAULT, H5P_DEFAULT));
669 #else
670   PetscStackCallHDF5Return(dataset,H5Dopen,(h5, parent));
671   PetscStackCallHDF5Return(attribute,H5Acreate,(dataset, name, dtype, dataspace, H5P_DEFAULT));
672 #endif
673   PetscStackCallHDF5(H5Awrite,(attribute, dtype, value));
674   if (datatype == PETSC_STRING) PetscStackCallHDF5(H5Tclose,(dtype));
675   PetscStackCallHDF5(H5Aclose,(attribute));
676   PetscStackCallHDF5(H5Dclose,(dataset));
677   PetscStackCallHDF5(H5Sclose,(dataspace));
678   PetscFunctionReturn(0);
679 }
680 
681 #undef __FUNCT__
682 #define __FUNCT__ "PetscViewerHDF5ReadAttribute"
683 /*@C
684  PetscViewerHDF5ReadAttribute - Read a scalar attribute
685 
686   Input Parameters:
687 + viewer - The HDF5 viewer
688 . parent - The parent name
689 . name   - The attribute name
690 - datatype - The attribute type
691 
692   Output Parameter:
693 . value    - The attribute value
694 
695   Level: advanced
696 
697 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5HasAttribute()
698 @*/
699 PetscErrorCode PetscViewerHDF5ReadAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, void *value)
700 {
701   hid_t          h5, dataspace, dataset, attribute, dtype;
702   PetscErrorCode ierr;
703 
704   PetscFunctionBegin;
705   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
706   PetscValidPointer(parent, 2);
707   PetscValidPointer(name, 3);
708   PetscValidPointer(value, 4);
709   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
710   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
711   PetscStackCallHDF5Return(dataspace,H5Screate,(H5S_SCALAR));
712 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
713   PetscStackCallHDF5Return(dataset,H5Dopen2,(h5, parent, H5P_DEFAULT));
714 #else
715   PetscStackCallHDF5Return(dataset,H5Dopen,(h5, parent));
716 #endif
717   PetscStackCallHDF5Return(attribute,H5Aopen_name,(dataset, name));
718   PetscStackCallHDF5(H5Aread,(attribute, dtype, value));
719   PetscStackCallHDF5(H5Aclose,(attribute));
720   PetscStackCallHDF5(H5Dclose,(dataset));
721   PetscStackCallHDF5(H5Sclose,(dataspace));
722   PetscFunctionReturn(0);
723 }
724 
725 #undef __FUNCT__
726 #define __FUNCT__ "PetscViewerHDF5HasObject"
727 static PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, const char name[], H5O_type_t otype, PetscBool *has)
728 {
729   hid_t          h5;
730   PetscErrorCode ierr;
731 
732   PetscFunctionBegin;
733   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
734   PetscValidPointer(name, 2);
735   PetscValidPointer(has, 3);
736   *has = PETSC_FALSE;
737   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
738   if (H5Lexists(h5, name, H5P_DEFAULT)) {
739     H5O_info_t info;
740     hid_t      obj;
741 
742     PetscStackCallHDF5Return(obj,H5Oopen,(h5, name, H5P_DEFAULT));
743     PetscStackCallHDF5(H5Oget_info,(obj, &info));
744     if (otype == info.type) *has = PETSC_TRUE;
745     PetscStackCallHDF5(H5Oclose,(obj));
746   }
747   PetscFunctionReturn(0);
748 }
749 
750 #undef __FUNCT__
751 #define __FUNCT__ "PetscViewerHDF5HasAttribute"
752 /*@C
753  PetscViewerHDF5HasAttribute - Check whether a scalar attribute exists
754 
755   Input Parameters:
756 + viewer - The HDF5 viewer
757 . parent - The parent name
758 - name   - The attribute name
759 
760   Output Parameter:
761 . has    - Flag for attribute existence
762 
763   Level: advanced
764 
765 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadAttribute()
766 @*/
767 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
768 {
769   hid_t          h5, dataset;
770   htri_t         hhas;
771   PetscBool      exists;
772   PetscErrorCode ierr;
773 
774   PetscFunctionBegin;
775   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
776   PetscValidPointer(parent, 2);
777   PetscValidPointer(name, 3);
778   PetscValidPointer(has, 4);
779   *has = PETSC_FALSE;
780   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
781   ierr = PetscViewerHDF5HasObject(viewer, parent, H5O_TYPE_DATASET, &exists);CHKERRQ(ierr);
782   if (exists) {
783 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
784     PetscStackCall("H5Dopen2",dataset = H5Dopen2(h5, parent, H5P_DEFAULT));
785 #else
786     PetscStackCall("H5Dopen",dataset = H5Dopen(h5, parent));
787 #endif
788     if (dataset < 0) PetscFunctionReturn(0);
789     PetscStackCall("H5Aexists",hhas = H5Aexists(dataset, name));
790     if (hhas < 0) {
791       PetscStackCallHDF5(H5Dclose,(dataset));
792       PetscFunctionReturn(0);
793     }
794     PetscStackCallHDF5(H5Dclose,(dataset));
795     *has = hhas ? PETSC_TRUE : PETSC_FALSE;
796   }
797   PetscFunctionReturn(0);
798 }
799 
800 /*
801   The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that
802   is attached to a communicator, in this case the attribute is a PetscViewer.
803 */
804 static int Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID;
805 
806 #undef __FUNCT__
807 #define __FUNCT__ "PETSC_VIEWER_HDF5_"
808 /*@C
809   PETSC_VIEWER_HDF5_ - Creates an HDF5 PetscViewer shared by all processors in a communicator.
810 
811   Collective on MPI_Comm
812 
813   Input Parameter:
814 . comm - the MPI communicator to share the HDF5 PetscViewer
815 
816   Level: intermediate
817 
818   Options Database Keys:
819 . -viewer_hdf5_filename <name>
820 
821   Environmental variables:
822 . PETSC_VIEWER_HDF5_FILENAME
823 
824   Notes:
825   Unlike almost all other PETSc routines, PETSC_VIEWER_HDF5_ does not return
826   an error code.  The HDF5 PetscViewer is usually used in the form
827 $       XXXView(XXX object, PETSC_VIEWER_HDF5_(comm));
828 
829 .seealso: PetscViewerHDF5Open(), PetscViewerCreate(), PetscViewerDestroy()
830 @*/
831 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm)
832 {
833   PetscErrorCode ierr;
834   PetscBool      flg;
835   PetscViewer    viewer;
836   char           fname[PETSC_MAX_PATH_LEN];
837   MPI_Comm       ncomm;
838 
839   PetscFunctionBegin;
840   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
841   if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) {
842     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_HDF5_keyval,0);
843     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
844   }
845   ierr = MPI_Attr_get(ncomm,Petsc_Viewer_HDF5_keyval,(void**)&viewer,(int*)&flg);
846   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
847   if (!flg) { /* PetscViewer not yet created */
848     ierr = PetscOptionsGetenv(ncomm,"PETSC_VIEWER_HDF5_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
849     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
850     if (!flg) {
851       ierr = PetscStrcpy(fname,"output.h5");
852       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
853     }
854     ierr = PetscViewerHDF5Open(ncomm,fname,FILE_MODE_WRITE,&viewer);
855     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
856     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
857     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
858     ierr = MPI_Attr_put(ncomm,Petsc_Viewer_HDF5_keyval,(void*)viewer);
859     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
860   }
861   ierr = PetscCommDestroy(&ncomm);
862   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
863   PetscFunctionReturn(viewer);
864 }
865