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